From f2361d96621c9d28e4c35696d7da5a108f489bd6 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Fri, 20 Feb 2026 03:20:51 -0800 Subject: [PATCH 01/12] chore: bump mobile app version to 2.9.16 (#1781) Update build numbers and deployment timestamps after successful deployment. Co-authored-by: github-actions[bot] --- app/version.json | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/app/version.json b/app/version.json index 5c2219b5e..c4b7d4377 100644 --- a/app/version.json +++ b/app/version.json @@ -1,10 +1,10 @@ { "ios": { - "build": 215, - "lastDeployed": "2026-02-16T09:17:41.176Z" + "build": 216, + "lastDeployed": "2026-02-20T11:17:57.338Z" }, "android": { - "build": 144, - "lastDeployed": "2026-02-16T09:17:41.176Z" + "build": 145, + "lastDeployed": "2026-02-20T11:17:57.338Z" } } From 63865d200d0f08ecf018770dbb8c5cfc2f142cf7 Mon Sep 17 00:00:00 2001 From: Justin Hernandez Date: Fri, 20 Feb 2026 11:58:14 -0800 Subject: [PATCH 02/12] Update spec guide to improve quality (#1783) * update specs * updates * feedback * clean up docs * fix rule --- AGENTS.md | 2 +- CLAUDE.md | 16 +- noir/AGENTS.md | 2 +- specs/PROJECT-RULES.md | 74 +++++--- specs/SPEC-GUIDE.md | 10 + specs/TEMPLATE-IMPLEMENTATION.md | 304 ------------------------------- specs/TEMPLATE-OVERVIEW.md | 138 -------------- specs/TEMPLATES.md | 35 ++++ 8 files changed, 110 insertions(+), 471 deletions(-) delete mode 100644 specs/TEMPLATE-IMPLEMENTATION.md delete mode 100644 specs/TEMPLATE-OVERVIEW.md diff --git a/AGENTS.md b/AGENTS.md index 240817c03..a19a303ee 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -42,7 +42,7 @@ Before creating a PR, ensure: #### AI Review Preparation -- [ ] Clear commit messages following conventional format +- [ ] Clear, imperative commit messages (e.g. `Fix address validation`) - [ ] PR description includes context for AI reviewers - [ ] Complex changes have inline comments explaining intent - [ ] Security-sensitive changes flagged for special review diff --git a/CLAUDE.md b/CLAUDE.md index 27aff0643..606155f12 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -16,9 +16,19 @@ nvm use && corepack enable && yarn install ## Key Rules - **Package manager:** Yarn (never npm or pnpm) +- **Keep the codebase DRY.** Before writing new code, search for existing utilities/components/flows and reuse or refactor to shared modules. Create new code only if a reusable option does not exist. +- **Extract repeated UI.** If the same UI sub-structure appears in 2+ places, extract a shared component. +- **Reusable UI belongs in shared libraries.** If a UI primitive is broadly reusable, add it to a shared library (e.g., `@selfxyz/euclid` or another shared package) instead of duplicating in feature code. +- **Keep files small.** Aim for <800 LOC per file. If a file approaches 800 LOC, split it into smaller modules. +- **Move static data out of UI.** Large static maps/lookups/constants do not belong in screen/components; move them to `utils/` or `data/` modules. +- **Prefer design tokens over hex.** Use shared color/font/spacing tokens instead of raw hex values in UI code. - **No `react-native` imports in SDK core.** `packages/mobile-sdk-alpha/src/` must be platform-agnostic outside of `src/adapters/react-native/`. - **Native handlers are thin wrappers.** No business logic in Kotlin or Swift. All logic lives in TypeScript. - **Keychain is always native-managed.** No web fallbacks for secure storage. This is a security boundary. +- **No “slop comments.”** Only add comments when they convey non-obvious intent or constraints. Never add generic or chatty comments. +- **Test value over mock wiring.** Prefer tests that validate behavior. Avoid tests that only assert mocks were called unless that is the behavior being validated. +- **PR size target:** 1k–3k LOC changed. Smaller is fine for focused fixes. If >3k, add a brief justification for why it can’t be split. +- **No generated artifacts in source PRs.** Do not commit build outputs or generated assets unless the build system requires them for runtime or distribution. ## Specs & Planning @@ -61,13 +71,13 @@ Quick-start prompts for creating new specs are in [SPEC-GUIDE.md](./specs/SPEC-G ```bash # SDK core -cd packages/mobile-sdk-alpha && npx vitest run && npx tsc --noEmit +cd packages/mobile-sdk-alpha && yarn test && yarn types # Bridge -cd packages/webview-bridge && yarn build && yarn vitest run +cd packages/webview-bridge && yarn build && yarn test # WebView app -cd packages/webview-app && npx tsc --noEmit && npx vite build +cd packages/webview-app && yarn build # KMP cd packages/kmp-sdk && ./gradlew :shared:jvmTest diff --git a/noir/AGENTS.md b/noir/AGENTS.md index 74664500b..85d05b85a 100644 --- a/noir/AGENTS.md +++ b/noir/AGENTS.md @@ -6,7 +6,7 @@ - Install nargo via noirup (pin the version used in CI for reproducibility): - curl -L https://raw.githubusercontent.com/noir-lang/noirup/main/install | bash - - noirup -v # e.g., noirup -v v0.30.0 + - noirup -v # e.g., noirup -v v0.31.0 (>= 0.31.0 required for --package flag) - Verify nargo is on the expected version: - nargo --version - Ensure Rust toolchain is installed and up to date (required by nargo). diff --git a/specs/PROJECT-RULES.md b/specs/PROJECT-RULES.md index 52775ba39..182fd6505 100644 --- a/specs/PROJECT-RULES.md +++ b/specs/PROJECT-RULES.md @@ -2,6 +2,7 @@ > Rules specific to the Self SDK project. Global rules apply to everyone. > Section rules apply to that workstream. Each rule has a one-line rationale. +> Read with [SDK-OVERVIEW.md](./SDK-OVERVIEW.md) when it exists. ## Global Rules @@ -13,48 +14,73 @@ 3. **Native shell work can run in parallel with SDK core work.** They share a contract (bridge protocol), not code. No blocking dependency. +### Reuse & Maintainability + +4. **Keep the codebase DRY.** Before writing new code, search for existing utilities/components/flows and reuse or refactor to shared modules. Create new code only if a reusable option does not exist. + +5. **Extract repeated UI.** If the same UI sub-structure appears in 2+ places, extract a shared component. + +6. **Reusable UI belongs in shared libraries.** If a UI primitive is broadly reusable, add it to a shared library (e.g., `@selfxyz/euclid` or another shared package) instead of duplicating in feature code. + +7. **Keep files small.** Aim for <800 LOC per file. If a file approaches 800 LOC, split it into smaller modules. + +8. **Move static data out of UI.** Large static maps/lookups/constants do not belong in screen/components; move them to `utils/` or `data/` modules. + +9. **Prefer design tokens over hex.** Use shared color/font/spacing tokens instead of raw hex values in UI code. + +10. **No “slop comments.”** Only add comments when they convey non-obvious intent or constraints. Never add generic or chatty comments. + +11. **Test value over mock wiring.** Prefer tests that validate behavior. Avoid tests that only assert mocks were called unless that is the behavior being validated. + +12. **PR size target:** 1k–3k LOC changed. Smaller is fine for focused fixes. If >3k, add a brief justification for why it can’t be split. + +13. **No generated artifacts in source PRs.** Do not commit build outputs or generated assets unless the build system requires them for runtime or distribution. + +14. **Constraint tie-breaker.** If rules conflict, prioritize correctness and security first, then scope/clarity (small PRs, small files), then reuse. Document the tradeoff in the spec. + ### Architecture -4. **TypeScript is the primary surface area. Native code is the minimum.** The WebView carries all core logic: proving machine, state machines, stores, document management, UI. Kotlin and Swift exist only for hardware access (NFC, camera, biometrics) and OS-level APIs (keychain, lifecycle). ZK circuits are the backend; TypeScript is the frontend. If you're writing logic in Kotlin or Swift that could run in the WebView, you're doing it wrong. +15. **TypeScript is the primary surface area. Native code is the minimum.** The WebView carries all core logic: proving machine, state machines, stores, document management, UI. Kotlin and Swift exist only for hardware access (NFC, camera, biometrics) and OS-level APIs (keychain, lifecycle). ZK circuits are the backend; TypeScript is the frontend. If you're writing logic in Kotlin or Swift that could run in the WebView, you're doing it wrong. -5. **"Can this run in the WebView?" gate.** Before writing ANY native code (Kotlin or Swift), answer this question. If the answer is yes — or even maybe — it belongs in TypeScript. Native code is ONLY justified when it requires: hardware APIs (NFC chip, camera sensor, biometric prompt), OS-level APIs (keychain, activity/VC lifecycle), or platform SDKs with no JS equivalent. Parsing, formatting, validation, error mapping, state management, and business logic are NEVER native — they run in the WebView. +16. **"Can this run in the WebView?" gate.** Before writing ANY native code (Kotlin or Swift), answer this question. If the answer is yes — or even maybe — it belongs in TypeScript. Native code is ONLY justified when it requires: hardware APIs (NFC chip, camera sensor, biometric prompt), OS-level APIs (keychain, activity/VC lifecycle), or platform SDKs with no JS equivalent. Parsing, formatting, validation, error mapping, state management, and business logic are NEVER native — they run in the WebView. -6. **Maximize code reuse through `mobile-sdk-alpha`.** Before adding code to `webview-app`, `kmp-sdk`, or `app/`, check if `mobile-sdk-alpha` already has it or should have it. If two packages need the same logic, it belongs in the SDK. Extend the SDK rather than duplicating. Specifically: - - Types, interfaces, constants → `mobile-sdk-alpha` - - Parsing, validation, formatting → `mobile-sdk-alpha` - - State machines, stores → `mobile-sdk-alpha` - - UI components shared between flows → `mobile-sdk-alpha` - - Only screen-level composition and routing belong in `webview-app` +17. **Maximize code reuse through `mobile-sdk-alpha`.** Before adding code to `webview-app`, `kmp-sdk`, or `app/`, check if `mobile-sdk-alpha` already has it or should have it. If two packages need the same logic, it belongs in the SDK. Extend the SDK rather than duplicating. Specifically: -7. **New native handlers MUST follow the bridge protocol exactly.** Every native handler implements the JSON schema defined in SDK-OVERVIEW.md (request/response/event). No custom messaging, no side channels, no platform-specific extensions. The WebView must not know which native shell it's running inside. +- Types, interfaces, constants → `mobile-sdk-alpha` +- Parsing, validation, formatting → `mobile-sdk-alpha` +- State machines, stores → `mobile-sdk-alpha` +- UI components shared between flows → `mobile-sdk-alpha` +- Only screen-level composition and routing belong in `webview-app` + +18. **New native handlers MUST follow the bridge protocol exactly.** Every native handler implements the JSON schema defined in SDK-OVERVIEW.md (request/response/event). No custom messaging, no side channels, no platform-specific extensions. The WebView must not know which native shell it's running inside. ### Code -8. **No `react-native` imports outside `src/adapters/react-native/`.** Core logic, stores, types, and constants must be platform-agnostic. Use adapter interfaces. +19. **No `react-native` imports outside `src/adapters/react-native/`.** Core logic, stores, types, and constants must be platform-agnostic. Use adapter interfaces. -9. **Keychain/SecureStorage is always native-managed.** No web fallbacks for `AuthAdapter` or `StorageAdapter`. The WebView does not get direct keychain access. This is a security boundary. +20. **Keychain/SecureStorage is always native-managed.** No web fallbacks for `AuthAdapter` or `StorageAdapter`. The WebView does not get direct keychain access. This is a security boundary. -10. **Adapter interfaces are the coupling layer.** Person 1 (webview) imports adapter interfaces from Person 4 (SDK core). Person 2 (native shells) implements bridge handlers. Nobody imports code across the bridge boundary. +21. **Adapter interfaces are the coupling layer.** Person 1 (webview) imports adapter interfaces from Person 4 (SDK core). Person 2 (native shells) implements bridge handlers. Nobody imports code across the bridge boundary. -11. **No logic in native shells.** Native handlers are pass-through: receive bridge request → call platform API → return bridge response. No parsing, no formatting, no validation, no error mapping, no state management. If a native handler is growing beyond ~50-100 lines per method, logic is leaking out of the WebView. +22. **No logic in native shells.** Native handlers are pass-through: receive bridge request → call platform API → return bridge response. No parsing, no formatting, no validation, no error mapping, no state management. If a native handler is growing beyond ~50-100 lines per method, logic is leaking out of the WebView. -12. **Fail closed on security-critical boundaries.** For protocol compatibility, remote bundle loading, and verification session lifecycle, default-deny behavior is required. Reject unknown protocol versions, block remote `devServerUrl` in production, and allow only one active verification session at a time. +23. **Fail closed on security-critical boundaries.** For protocol compatibility, remote bundle loading, and verification session lifecycle, default-deny behavior is required. Reject unknown protocol versions, block remote `devServerUrl` in production, and allow only one active verification session at a time. ### Quality -13. **No regressions in the RN app.** Every change to `mobile-sdk-alpha` must be backwards-compatible with the existing Self Wallet app. Validate with `vitest run` and manual testing. +24. **No regressions in the RN app.** Every change to `mobile-sdk-alpha` must be backwards-compatible with the existing Self Wallet app. Validate with `yarn test` and manual testing. -14. **Specs stay current.** When implementation deviates from the spec, update the spec. A stale spec is worse than no spec — it misleads the next person. +25. **Specs stay current.** When implementation deviates from the spec, update the spec. A stale spec is worse than no spec — it misleads the next person. -15. **Review status checklists before starting a work session.** Read the OVERVIEW.md status checklist and SPEC.md chunk status table before doing anything. Verify the status reflects reality. If something is marked "Done" that isn't, or "Pending" that's actually in progress, fix it first. Don't build on stale assumptions. +26. **Review status checklists before starting a work session.** Read the OVERVIEW.md status checklist and SPEC.md chunk status table before doing anything. Verify the status reflects reality. If something is marked "Done" that isn't, or "Pending" that's actually in progress, fix it first. Don't build on stale assumptions. -16. **Update status checklists as you complete work.** When you finish a chunk, check off the corresponding items in both the OVERVIEW.md status checklist and the SPEC.md chunk status table. This is the primary way devs and leads track progress — stale checklists erode trust in the specs. +27. **Update status checklists as you complete work.** When you finish a chunk, check off the corresponding items in both the OVERVIEW.md status checklist and the SPEC.md chunk status table. This is the primary way devs and leads track progress — stale checklists erode trust in the specs. ### Planning -17. **Write plans to disk before executing.** When working on multi-step tasks (multiple chunks, cross-workstream coordination, or anything requiring more than one session), write the plan to a file BEFORE starting implementation. Update WAVE-PLAN.md, the relevant SPEC.md status table, or create a session-specific plan file. A plan that only exists in session memory will be lost to API errors, context overflow, or `/clear`. Writing it to disk enables multiple agents to work from the same plan and creates an audit trail. +28. **Write plans to disk before executing.** When working on multi-step tasks (multiple chunks, cross-workstream coordination, or anything requiring more than one session), write the plan to a file BEFORE starting implementation. Update WAVE-PLAN.md, the relevant SPEC.md status table, or create a session-specific plan file. A plan that only exists in session memory will be lost to API errors, context overflow, or `/clear`. Writing it to disk enables multiple agents to work from the same plan and creates an audit trail. -18. **Update plan files as you go.** When a chunk is completed, mark it done in the plan file immediately. When scope changes, update the plan file. The plan file is the single source of truth for what's been done and what's next — not the session transcript. +29. **Update plan files as you go.** When a chunk is completed, mark it done in the plan file immediately. When scope changes, update the plan file. The plan file is the single source of truth for what's been done and what's next — not the session transcript. --- @@ -85,20 +111,20 @@ Concrete commands that catch violations after code is written. Include these in ```bash # Verify no RN imports leaked into core -grep -r "from 'react-native'" packages/mobile-sdk-alpha/src/ \ +grep -rE "from ['\"]react-native['\"]|require\(['\"]react-native['\"]\)" packages/mobile-sdk-alpha/src/ \ --include="*.ts" --include="*.tsx" \ | grep -v "adapters/react-native" \ | grep -v ".native." && echo "FAIL: RN import in core" || echo "PASS" # Verify browser entry point is clean -npx madge --circular packages/mobile-sdk-alpha/src/browser.ts 2>/dev/null \ +yarn dlx madge --circular packages/mobile-sdk-alpha/src/browser.ts 2>/dev/null \ || echo "Install madge for circular dependency check" # Verify SDK tests still pass (no regressions) -cd packages/mobile-sdk-alpha && npx vitest run +cd packages/mobile-sdk-alpha && yarn test # Verify bridge tests pass -cd packages/webview-bridge && npx vitest run +cd packages/webview-bridge && yarn test ``` --- diff --git a/specs/SPEC-GUIDE.md b/specs/SPEC-GUIDE.md index 23063c036..457f51165 100644 --- a/specs/SPEC-GUIDE.md +++ b/specs/SPEC-GUIDE.md @@ -112,6 +112,16 @@ Templates are useless without a research process. Follow this workflow: 5. **Size and sequence chunks** — estimate tokens, identify dependencies 6. **Run the review checklist** — see below. Don't share the spec until it passes. +## Rules Reminder + +Every spec must respect [PROJECT-RULES.md](./PROJECT-RULES.md). When writing chunk instructions, apply the rules that are relevant to the work — especially the **Reuse & Maintainability** section for UI/component work and the **Architecture** section for native/bridge work. Don’t cargo-cult UI rules into non-UI specs or vice versa. + +Also: + +- Write plans to disk before implementation and keep status checklists current. +- Prefer repository validation commands (Yarn workspaces) over ad hoc `npx` when available. +- Token-budgeted chunks and LOC-based PR sizing are different constraints; satisfy both. + ## Spec Review Checklist Before sharing a spec, verify: diff --git a/specs/TEMPLATE-IMPLEMENTATION.md b/specs/TEMPLATE-IMPLEMENTATION.md deleted file mode 100644 index 8308fc719..000000000 --- a/specs/TEMPLATE-IMPLEMENTATION.md +++ /dev/null @@ -1,304 +0,0 @@ -# [Component/Scope] — Implementation Spec - -> Last updated: [date] -> Owner: [name] -> Parent: [OVERVIEW.md](../OVERVIEW.md) -> Status: [Draft | Active | Complete] - -## North Star - - - -## Overview - - - -## Prerequisites - - - -- Familiarity with [pattern/tool/concept] -- [Term] = [definition] -- Read [OVERVIEW.md](../OVERVIEW.md) for architecture context - -## The Problem - - - -| File | Issue | -| --------------- | -------------- | -| `src/foo.ts:42` | [what's wrong] | - -## Design Principles - - - -1. **[Principle].** [Why.] -2. **[Principle].** [Why.] - -## Definition of Done - - - -> **Done when:** [statement] - -## Scope of Work - - - -### 1. [Task Name — Modify Existing] - -**`file/path.ts`** — Lines X-Y - -```typescript -// BEFORE -[exact current code] -``` - -```typescript -// AFTER -[exact target code] -``` - - - -#### Input / Output - - - -**Input:** - -``` -[concrete example] -``` - -**Expected Output:** - -``` -[concrete example] -``` - -**Edge case — [description]:** - -``` -Input: [edge case] -Output: [expected result] -``` - ---- - -### 2. [Task Name — Create New] - -**Create:** `src/path/to/new-file.ts` - -**Implements:** `[InterfaceName]` from `src/types/[file].ts` - - - -```typescript -// SKELETON -[exports, function signatures, key types — enough to show the shape] -``` - -#### Input / Output - -**Input:** - -``` -[concrete example] -``` - -**Expected Output:** - -``` -[concrete example] -``` - -**Error case — [description]:** - -``` -Input: [error scenario] -Output: [expected error behavior] -``` - ---- - -## Files You Will Modify - -| File | Change | Risk | -| ------------ | -------------- | ------------------------ | -| `src/foo.ts` | [what changes] | **High/Med/Low** — [why] | - -## Files You Will NOT Modify - -| File | Why | -| ------------ | --------------------------------------------------- | -| `src/bar.ts` | [out of scope / owned by another workstream / etc.] | - -## Chunking Guide - - - -### Chunk [ID]: [Name] — [S/M/L ~Xk tokens] - - - -**Goal:** [One sentence.] - -**Steps:** - -1. [Concrete step] -2. [Concrete step] -3. Validate: [specific command or check] - -#### Input / Output — Chunk Validation - - - -**Input:** - -``` -[concrete test: CLI command, function call, etc.] -``` - -**Expected Output:** - -``` -[what you should see] -``` - -#### Tests - -| Test | Type | What it validates | -| ----------------------- | ------------------------------- | ----------------- | -| [test name/description] | Unit / Integration / Build gate | [one sentence] | - ---- - -### Chunk [ID]: [Name] — [S/M/L ~Xk tokens] - -**Depends on:** Chunk [ID] - -**Goal:** [One sentence.] - -**Steps:** - -1. [step] -2. [step] -3. Validate: [check] - -#### Input / Output — Chunk Validation - -**Input:** - -``` -[test] -``` - -**Expected Output:** - -``` -[result] -``` - -#### Tests - -| Test | Type | What it validates | -| ------ | ------ | ----------------- | -| [test] | [type] | [validates] | - ---- - -## Dependency Graph - -``` -Chunk A (no deps) - |---> Chunk B (after A) - | '---> Chunk D (after B) - |---> Chunk C (after A) - '---> Chunk E (after A, optional) -``` - -## Completion Status - -| Chunk | Description | Size | Status | -| ----- | ----------- | ----- | ------------------------------------------------------ | -| [ID] | [name] | S/M/L | **Pending** / **In Progress** / **Done** / **Skipped** | - -## Validation Plan - -```bash -# After every chunk (must pass): -[type-check command] -[test command] - -# After all chunks: -[integration check command] -``` - -## Coordination Notes - - - -- **[Person/Team]:** [what they need from you or you from them] - -## Key Reference Files - -| File | What to Look At | -| ----------------- | ----------------- | -| `path/to/file.ts` | [what's relevant] | - ---- - - - -## What Was Built - - - -### Architecture (brief) - - - -### Deviations from Spec - -| Spec said | We did | Why | -| --------------- | ----------------------- | -------- | -| [original plan] | [actual implementation] | [reason] | - -### Key Files (final) - -| File | Role | -| -------------- | -------------- | -| `src/thing.ts` | [what it does] | - -### Lessons / Gotchas - -- [One-liner that would help the next person] - ---- - -## Follow-Up (Out of Scope) - - - -| Item | Discovered during | Suggested spec | -| ------- | ----------------- | ---------------------- | -| [thing] | Chunk [ID] | [new or existing spec] | - -## Spec Deviations - - - -| Suggestion skipped | Reason | -| ------------------ | ------ | -| [suggestion] | [why] | diff --git a/specs/TEMPLATE-OVERVIEW.md b/specs/TEMPLATE-OVERVIEW.md deleted file mode 100644 index bb562e9db..000000000 --- a/specs/TEMPLATE-OVERVIEW.md +++ /dev/null @@ -1,138 +0,0 @@ -# [Project Name] — Architecture Specification - -> Last updated: [date] -> Owner: [name/team] -> Status: [Draft | Active | Complete] - -## North Star - - - -> **Success metric:** [One measurable outcome] - -## Status Checklist - - - -- [ ] Architecture finalized -- [ ] [Milestone] -- [ ] [Milestone] -- [ ] Integration: [target] - -## Architecture Diagram - - - -``` -[diagram] -``` - -## Design Principles - - - -1. **[Principle].** [Explanation.] -2. **[Principle].** [Explanation.] -3. **[Principle].** [Explanation.] - -## Module Table - - - -| Module | Location | Language | What It Does | Status | % Done | Action Needed | -| ---------- | -------- | -------- | -------------- | ------- | ------ | ------------------ | -| **[Name]** | `path/` | [lang] | [one sentence] | [state] | **X%** | [action or "None"] | - -## Decision Matrix - - - -| Capability | Must be native? | Platform A | Platform B | Web Fallback | -| ---------- | --------------- | --------------------- | --------------------- | -------------------- | -| [thing] | YES / NO | KEEP / BUILD / DELETE | KEEP / BUILD / DELETE | [fallback or "None"] | - -## Impact Summary - - - -| Metric | Current | After | Saved | -| -------- | ------- | ------- | ------- | -| [metric] | [value] | [value] | [delta] | - -## Shared Contracts / Protocols - - - -## Workstreams - - - -``` -Person 1 — [Scope] -> person1-scope/SPEC.md -|- [deliverable] -|- [deliverable] -'- [deliverable] - -Person 2 — [Scope] -> person2-scope/SPEC.md -|- [deliverable] -'- [deliverable] -``` - -## Input / Output — System Level - - - -**Input:** - -``` -[Example: API call, SDK launch call, user action that kicks off the system] -``` - -**Output:** - -``` -[Example: callback result, UI state, observable outcome] -``` - -## Migration Path - - - -1. **Phase 1 (Now):** [what's happening] -2. **Phase 2:** [what comes next and what triggers it] -3. **Phase 3:** [end state] - -## Glossary - - - -| Term | Definition | -| ------ | ------------ | -| [term] | [definition] | - -## Related Specs - - - -| Spec | Audience | What it covers | -| ------------------------------------------------ | ----------- | -------------- | -| [person1-scope/SPEC.md](./person1-scope/SPEC.md) | Implementer | [scope] | -| [person2-scope/SPEC.md](./person2-scope/SPEC.md) | Implementer | [scope] | - -## Spec Deviations - - - -| Suggestion skipped | Reason | -| ------------------ | ------ | -| [suggestion] | [why] | diff --git a/specs/TEMPLATES.md b/specs/TEMPLATES.md index 674c5e8b6..2d9477892 100644 --- a/specs/TEMPLATES.md +++ b/specs/TEMPLATES.md @@ -20,6 +20,14 @@ Three copy-paste templates. Pick the one that matches what you're writing. > Owner: [name/team] > Status: [Draft | Active | Complete] +### Required References + + + +- [PROJECT-RULES.md](./PROJECT-RULES.md) + ### North Star - [ ] [Milestone] - [ ] Integration: [target] +### Rules Reminder + +Apply [PROJECT-RULES.md](./PROJECT-RULES.md) — especially **Reuse & Maintainability** for UI work, **Architecture** for native/bridge work, and **Quality/Planning** for checklist and plan discipline. Prefer repo validation commands and note that token-sized chunks and LOC-sized PRs are different constraints. + ### Architecture Diagram > Implementation: [SPEC.md](./SPEC.md) > Status: [Draft | Active | Complete] +### Required References + + + +- [PROJECT-RULES.md](../PROJECT-RULES.md) +- [SDK-OVERVIEW.md](../SDK-OVERVIEW.md) (if this project has a project overview, link it here) + ### North Star - [ ] [milestone] - [ ] [milestone] +### Rules Reminder + +Apply [PROJECT-RULES.md](../PROJECT-RULES.md) — especially **Reuse & Maintainability** for UI work, **Architecture** for native/bridge work, and **Quality/Planning** for checklist and plan discipline. Prefer repo validation commands and note that token-sized chunks and LOC-sized PRs are different constraints. + ### What You Own > Parent: [OVERVIEW.md](./OVERVIEW.md) > Status: [Draft | Active | Complete] +### Required References + + + +- [PROJECT-RULES.md](../PROJECT-RULES.md) +- [SDK-OVERVIEW.md](../SDK-OVERVIEW.md) (if this project has a project overview, link it here) +- [OVERVIEW.md](./OVERVIEW.md) + +### Rules Reminder + +Apply [PROJECT-RULES.md](../PROJECT-RULES.md) — especially **Reuse & Maintainability** for UI work, **Architecture** for native/bridge work, and **Quality/Planning** for checklist and plan discipline. Include relevant constraints in each chunk's "You will NOT" section, prefer repo validation commands, and note that token-sized chunks and LOC-sized PRs are different constraints. + ### North Star | onResponderStart (cur) |<-----------+\n+-----------+-------------+ | +------------------------+ | |\n | | | +--------+-------+\n | returned true for| false:REJECT +-------->|onResponderReject\n | wantsResponderID | | | +----------------+\n | (now attempt | +------------------+-----+ |\n | handoff) | | onResponder | |\n +------------------->| TerminationRequest | |\n | +------------------+-----+ |\n | | | +----------------+\n | true:GRANT +-------->|onResponderGrant|\n | | +--------+-------+\n | +------------------------+ | |\n | | onResponderTerminate |<-----------+\n | +------------------+-----+ |\n | | | +----------------+\n | +-------->|onResponderStart|\n | | +----------------+\nBubble to find first ID | |\nto return true:wantsResponderID| |\n | |\n +-------------+ | |\n | onTouchMove | | |\n +------+------+ none | |\n | return| |\n+-----------v-------------+true| +------------------------+ |\n|onMoveShouldSetResponder |----->| onResponderMove (cur) |<-----------+\n+-----------+-------------+ | +------------------------+ | |\n | | | +--------+-------+\n | returned true for| false:REJECT +-------->|onResponderReject\n | wantsResponderID | | | +----------------+\n | (now attempt | +------------------+-----+ |\n | handoff) | | onResponder | |\n +------------------->| TerminationRequest| |\n | +------------------+-----+ |\n | | | +----------------+\n | true:GRANT +-------->|onResponderGrant|\n | | +--------+-------+\n | +------------------------+ | |\n | | onResponderTerminate |<-----------+\n | +------------------+-----+ |\n | | | +----------------+\n | +-------->|onResponderMove |\n | | +----------------+\n | |\n | |\n Some active touch started| |\n inside current responder | +------------------------+ |\n +------------------------->| onResponderEnd | |\n | | +------------------------+ |\n +---+---------+ | |\n | onTouchEnd | | |\n +---+---------+ | |\n | | +------------------------+ |\n +------------------------->| onResponderEnd | |\n No active touches started| +-----------+------------+ |\n inside current responder | | |\n | v |\n | +------------------------+ |\n | | onResponderRelease | |\n | +------------------------+ |\n | |\n + + */\n\nimport createResponderEvent from './createResponderEvent';\nimport { isCancelish, isEndish, isMoveish, isScroll, isSelectionChange, isStartish } from './ResponderEventTypes';\nimport { getLowestCommonAncestor, getResponderPaths, hasTargetTouches, hasValidSelection, isPrimaryPointerDown, setResponderId } from './utils';\nimport { ResponderTouchHistoryStore } from './ResponderTouchHistoryStore';\nimport canUseDOM from '../canUseDom';\n\n/* ------------ TYPES ------------ */\n\nvar emptyObject = {};\n\n/* ------------ IMPLEMENTATION ------------ */\n\nvar startRegistration = ['onStartShouldSetResponderCapture', 'onStartShouldSetResponder', {\n bubbles: true\n}];\nvar moveRegistration = ['onMoveShouldSetResponderCapture', 'onMoveShouldSetResponder', {\n bubbles: true\n}];\nvar scrollRegistration = ['onScrollShouldSetResponderCapture', 'onScrollShouldSetResponder', {\n bubbles: false\n}];\nvar shouldSetResponderEvents = {\n touchstart: startRegistration,\n mousedown: startRegistration,\n touchmove: moveRegistration,\n mousemove: moveRegistration,\n scroll: scrollRegistration\n};\nvar emptyResponder = {\n id: null,\n idPath: null,\n node: null\n};\nvar responderListenersMap = new Map();\nvar isEmulatingMouseEvents = false;\nvar trackedTouchCount = 0;\nvar currentResponder = {\n id: null,\n node: null,\n idPath: null\n};\nvar responderTouchHistoryStore = new ResponderTouchHistoryStore();\nfunction changeCurrentResponder(responder) {\n currentResponder = responder;\n}\nfunction getResponderConfig(id) {\n var config = responderListenersMap.get(id);\n return config != null ? config : emptyObject;\n}\n\n/**\n * Process native events\n *\n * A single event listener is used to manage the responder system.\n * All pointers are tracked in the ResponderTouchHistoryStore. Native events\n * are interpreted in terms of the Responder System and checked to see if\n * the responder should be transferred. Each host node that is attached to\n * the Responder System has an ID, which is used to look up its associated\n * callbacks.\n */\nfunction eventListener(domEvent) {\n var eventType = domEvent.type;\n var eventTarget = domEvent.target;\n\n /**\n * Manage emulated events and early bailout.\n * Since PointerEvent is not used yet (lack of support in older Safari), it's\n * necessary to manually manage the mess of browser touch/mouse events.\n * And bailout early for termination events when there is no active responder.\n */\n\n // Flag when browser may produce emulated events\n if (eventType === 'touchstart') {\n isEmulatingMouseEvents = true;\n }\n // Remove flag when browser will not produce emulated events\n if (eventType === 'touchmove' || trackedTouchCount > 1) {\n isEmulatingMouseEvents = false;\n }\n // Ignore various events in particular circumstances\n if (\n // Ignore browser emulated mouse events\n eventType === 'mousedown' && isEmulatingMouseEvents || eventType === 'mousemove' && isEmulatingMouseEvents ||\n // Ignore mousemove if a mousedown didn't occur first\n eventType === 'mousemove' && trackedTouchCount < 1) {\n return;\n }\n // Remove flag after emulated events are finished\n if (isEmulatingMouseEvents && eventType === 'mouseup') {\n if (trackedTouchCount === 0) {\n isEmulatingMouseEvents = false;\n }\n return;\n }\n var isStartEvent = isStartish(eventType) && isPrimaryPointerDown(domEvent);\n var isMoveEvent = isMoveish(eventType);\n var isEndEvent = isEndish(eventType);\n var isScrollEvent = isScroll(eventType);\n var isSelectionChangeEvent = isSelectionChange(eventType);\n var responderEvent = createResponderEvent(domEvent, responderTouchHistoryStore);\n\n /**\n * Record the state of active pointers\n */\n\n if (isStartEvent || isMoveEvent || isEndEvent) {\n if (domEvent.touches) {\n trackedTouchCount = domEvent.touches.length;\n } else {\n if (isStartEvent) {\n trackedTouchCount = 1;\n } else if (isEndEvent) {\n trackedTouchCount = 0;\n }\n }\n responderTouchHistoryStore.recordTouchTrack(eventType, responderEvent.nativeEvent);\n }\n\n /**\n * Responder System logic\n */\n\n var eventPaths = getResponderPaths(domEvent);\n var wasNegotiated = false;\n var wantsResponder;\n\n // If an event occured that might change the current responder...\n if (isStartEvent || isMoveEvent || isScrollEvent && trackedTouchCount > 0) {\n // If there is already a responder, prune the event paths to the lowest common ancestor\n // of the existing responder and deepest target of the event.\n var currentResponderIdPath = currentResponder.idPath;\n var eventIdPath = eventPaths.idPath;\n if (currentResponderIdPath != null && eventIdPath != null) {\n var lowestCommonAncestor = getLowestCommonAncestor(currentResponderIdPath, eventIdPath);\n if (lowestCommonAncestor != null) {\n var indexOfLowestCommonAncestor = eventIdPath.indexOf(lowestCommonAncestor);\n // Skip the current responder so it doesn't receive unexpected \"shouldSet\" events.\n var index = indexOfLowestCommonAncestor + (lowestCommonAncestor === currentResponder.id ? 1 : 0);\n eventPaths = {\n idPath: eventIdPath.slice(index),\n nodePath: eventPaths.nodePath.slice(index)\n };\n } else {\n eventPaths = null;\n }\n }\n if (eventPaths != null) {\n // If a node wants to become the responder, attempt to transfer.\n wantsResponder = findWantsResponder(eventPaths, domEvent, responderEvent);\n if (wantsResponder != null) {\n // Sets responder if none exists, or negotates with existing responder.\n attemptTransfer(responderEvent, wantsResponder);\n wasNegotiated = true;\n }\n }\n }\n\n // If there is now a responder, invoke its callbacks for the lifecycle of the gesture.\n if (currentResponder.id != null && currentResponder.node != null) {\n var _currentResponder = currentResponder,\n id = _currentResponder.id,\n node = _currentResponder.node;\n var _getResponderConfig = getResponderConfig(id),\n onResponderStart = _getResponderConfig.onResponderStart,\n onResponderMove = _getResponderConfig.onResponderMove,\n onResponderEnd = _getResponderConfig.onResponderEnd,\n onResponderRelease = _getResponderConfig.onResponderRelease,\n onResponderTerminate = _getResponderConfig.onResponderTerminate,\n onResponderTerminationRequest = _getResponderConfig.onResponderTerminationRequest;\n responderEvent.bubbles = false;\n responderEvent.cancelable = false;\n responderEvent.currentTarget = node;\n\n // Start\n if (isStartEvent) {\n if (onResponderStart != null) {\n responderEvent.dispatchConfig.registrationName = 'onResponderStart';\n onResponderStart(responderEvent);\n }\n }\n // Move\n else if (isMoveEvent) {\n if (onResponderMove != null) {\n responderEvent.dispatchConfig.registrationName = 'onResponderMove';\n onResponderMove(responderEvent);\n }\n } else {\n var isTerminateEvent = isCancelish(eventType) ||\n // native context menu\n eventType === 'contextmenu' ||\n // window blur\n eventType === 'blur' && eventTarget === window ||\n // responder (or ancestors) blur\n eventType === 'blur' && eventTarget.contains(node) && domEvent.relatedTarget !== node ||\n // native scroll without using a pointer\n isScrollEvent && trackedTouchCount === 0 ||\n // native scroll on node that is parent of the responder (allow siblings to scroll)\n isScrollEvent && eventTarget.contains(node) && eventTarget !== node ||\n // native select/selectionchange on node\n isSelectionChangeEvent && hasValidSelection(domEvent);\n var isReleaseEvent = isEndEvent && !isTerminateEvent && !hasTargetTouches(node, domEvent.touches);\n\n // End\n if (isEndEvent) {\n if (onResponderEnd != null) {\n responderEvent.dispatchConfig.registrationName = 'onResponderEnd';\n onResponderEnd(responderEvent);\n }\n }\n // Release\n if (isReleaseEvent) {\n if (onResponderRelease != null) {\n responderEvent.dispatchConfig.registrationName = 'onResponderRelease';\n onResponderRelease(responderEvent);\n }\n changeCurrentResponder(emptyResponder);\n }\n // Terminate\n if (isTerminateEvent) {\n var shouldTerminate = true;\n\n // Responders can still avoid termination but only for these events.\n if (eventType === 'contextmenu' || eventType === 'scroll' || eventType === 'selectionchange') {\n // Only call this function is it wasn't already called during negotiation.\n if (wasNegotiated) {\n shouldTerminate = false;\n } else if (onResponderTerminationRequest != null) {\n responderEvent.dispatchConfig.registrationName = 'onResponderTerminationRequest';\n if (onResponderTerminationRequest(responderEvent) === false) {\n shouldTerminate = false;\n }\n }\n }\n if (shouldTerminate) {\n if (onResponderTerminate != null) {\n responderEvent.dispatchConfig.registrationName = 'onResponderTerminate';\n onResponderTerminate(responderEvent);\n }\n changeCurrentResponder(emptyResponder);\n isEmulatingMouseEvents = false;\n trackedTouchCount = 0;\n }\n }\n }\n }\n}\n\n/**\n * Walk the event path to/from the target node. At each node, stop and call the\n * relevant \"shouldSet\" functions for the given event type. If any of those functions\n * call \"stopPropagation\" on the event, stop searching for a responder.\n */\nfunction findWantsResponder(eventPaths, domEvent, responderEvent) {\n var shouldSetCallbacks = shouldSetResponderEvents[domEvent.type]; // for Flow\n\n if (shouldSetCallbacks != null) {\n var idPath = eventPaths.idPath,\n nodePath = eventPaths.nodePath;\n var shouldSetCallbackCaptureName = shouldSetCallbacks[0];\n var shouldSetCallbackBubbleName = shouldSetCallbacks[1];\n var bubbles = shouldSetCallbacks[2].bubbles;\n var check = function check(id, node, callbackName) {\n var config = getResponderConfig(id);\n var shouldSetCallback = config[callbackName];\n if (shouldSetCallback != null) {\n responderEvent.currentTarget = node;\n if (shouldSetCallback(responderEvent) === true) {\n // Start the path from the potential responder\n var prunedIdPath = idPath.slice(idPath.indexOf(id));\n return {\n id,\n node,\n idPath: prunedIdPath\n };\n }\n }\n };\n\n // capture\n for (var i = idPath.length - 1; i >= 0; i--) {\n var id = idPath[i];\n var node = nodePath[i];\n var result = check(id, node, shouldSetCallbackCaptureName);\n if (result != null) {\n return result;\n }\n if (responderEvent.isPropagationStopped() === true) {\n return;\n }\n }\n\n // bubble\n if (bubbles) {\n for (var _i = 0; _i < idPath.length; _i++) {\n var _id = idPath[_i];\n var _node = nodePath[_i];\n var _result = check(_id, _node, shouldSetCallbackBubbleName);\n if (_result != null) {\n return _result;\n }\n if (responderEvent.isPropagationStopped() === true) {\n return;\n }\n }\n } else {\n var _id2 = idPath[0];\n var _node2 = nodePath[0];\n var target = domEvent.target;\n if (target === _node2) {\n return check(_id2, _node2, shouldSetCallbackBubbleName);\n }\n }\n }\n}\n\n/**\n * Attempt to transfer the responder.\n */\nfunction attemptTransfer(responderEvent, wantsResponder) {\n var _currentResponder2 = currentResponder,\n currentId = _currentResponder2.id,\n currentNode = _currentResponder2.node;\n var id = wantsResponder.id,\n node = wantsResponder.node;\n var _getResponderConfig2 = getResponderConfig(id),\n onResponderGrant = _getResponderConfig2.onResponderGrant,\n onResponderReject = _getResponderConfig2.onResponderReject;\n responderEvent.bubbles = false;\n responderEvent.cancelable = false;\n responderEvent.currentTarget = node;\n\n // Set responder\n if (currentId == null) {\n if (onResponderGrant != null) {\n responderEvent.currentTarget = node;\n responderEvent.dispatchConfig.registrationName = 'onResponderGrant';\n onResponderGrant(responderEvent);\n }\n changeCurrentResponder(wantsResponder);\n }\n // Negotiate with current responder\n else {\n var _getResponderConfig3 = getResponderConfig(currentId),\n onResponderTerminate = _getResponderConfig3.onResponderTerminate,\n onResponderTerminationRequest = _getResponderConfig3.onResponderTerminationRequest;\n var allowTransfer = true;\n if (onResponderTerminationRequest != null) {\n responderEvent.currentTarget = currentNode;\n responderEvent.dispatchConfig.registrationName = 'onResponderTerminationRequest';\n if (onResponderTerminationRequest(responderEvent) === false) {\n allowTransfer = false;\n }\n }\n if (allowTransfer) {\n // Terminate existing responder\n if (onResponderTerminate != null) {\n responderEvent.currentTarget = currentNode;\n responderEvent.dispatchConfig.registrationName = 'onResponderTerminate';\n onResponderTerminate(responderEvent);\n }\n // Grant next responder\n if (onResponderGrant != null) {\n responderEvent.currentTarget = node;\n responderEvent.dispatchConfig.registrationName = 'onResponderGrant';\n onResponderGrant(responderEvent);\n }\n changeCurrentResponder(wantsResponder);\n } else {\n // Reject responder request\n if (onResponderReject != null) {\n responderEvent.currentTarget = node;\n responderEvent.dispatchConfig.registrationName = 'onResponderReject';\n onResponderReject(responderEvent);\n }\n }\n }\n}\n\n/* ------------ PUBLIC API ------------ */\n\n/**\n * Attach Listeners\n *\n * Use native events as ReactDOM doesn't have a non-plugin API to implement\n * this system.\n */\nvar documentEventsCapturePhase = ['blur', 'scroll'];\nvar documentEventsBubblePhase = [\n// mouse\n'mousedown', 'mousemove', 'mouseup', 'dragstart',\n// touch\n'touchstart', 'touchmove', 'touchend', 'touchcancel',\n// other\n'contextmenu', 'select', 'selectionchange'];\nexport function attachListeners() {\n if (canUseDOM && window.__reactResponderSystemActive == null) {\n window.addEventListener('blur', eventListener);\n documentEventsBubblePhase.forEach(eventType => {\n document.addEventListener(eventType, eventListener);\n });\n documentEventsCapturePhase.forEach(eventType => {\n document.addEventListener(eventType, eventListener, true);\n });\n window.__reactResponderSystemActive = true;\n }\n}\n\n/**\n * Register a node with the ResponderSystem.\n */\nexport function addNode(id, node, config) {\n setResponderId(node, id);\n responderListenersMap.set(id, config);\n}\n\n/**\n * Unregister a node with the ResponderSystem.\n */\nexport function removeNode(id) {\n if (currentResponder.id === id) {\n terminateResponder();\n }\n if (responderListenersMap.has(id)) {\n responderListenersMap.delete(id);\n }\n}\n\n/**\n * Allow the current responder to be terminated from within components to support\n * more complex requirements, such as use with other React libraries for working\n * with scroll views, input views, etc.\n */\nexport function terminateResponder() {\n var _currentResponder3 = currentResponder,\n id = _currentResponder3.id,\n node = _currentResponder3.node;\n if (id != null && node != null) {\n var _getResponderConfig4 = getResponderConfig(id),\n onResponderTerminate = _getResponderConfig4.onResponderTerminate;\n if (onResponderTerminate != null) {\n var event = createResponderEvent({}, responderTouchHistoryStore);\n event.currentTarget = node;\n onResponderTerminate(event);\n }\n changeCurrentResponder(emptyResponder);\n }\n isEmulatingMouseEvents = false;\n trackedTouchCount = 0;\n}\n\n/**\n * Allow unit tests to inspect the current responder in the system.\n * FOR TESTING ONLY.\n */\nexport function getResponderNode() {\n return currentResponder.node;\n}","/**\n * Copyright (c) Nicolas Gallagher\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n * \n */\n\n/**\n * Hook for integrating the Responder System into React\n *\n * function SomeComponent({ onStartShouldSetResponder }) {\n * const ref = useRef(null);\n * useResponderEvents(ref, { onStartShouldSetResponder });\n * return
\n * }\n */\n\nimport * as React from 'react';\nimport * as ResponderSystem from './ResponderSystem';\nvar emptyObject = {};\nvar idCounter = 0;\nfunction useStable(getInitialValue) {\n var ref = React.useRef(null);\n if (ref.current == null) {\n ref.current = getInitialValue();\n }\n return ref.current;\n}\nexport default function useResponderEvents(hostRef, config) {\n if (config === void 0) {\n config = emptyObject;\n }\n var id = useStable(() => idCounter++);\n var isAttachedRef = React.useRef(false);\n\n // This is a separate effects so it doesn't run when the config changes.\n // On initial mount, attach global listeners if needed.\n // On unmount, remove node potentially attached to the Responder System.\n React.useEffect(() => {\n ResponderSystem.attachListeners();\n return () => {\n ResponderSystem.removeNode(id);\n };\n }, [id]);\n\n // Register and unregister with the Responder System as necessary\n React.useEffect(() => {\n var _config = config,\n onMoveShouldSetResponder = _config.onMoveShouldSetResponder,\n onMoveShouldSetResponderCapture = _config.onMoveShouldSetResponderCapture,\n onScrollShouldSetResponder = _config.onScrollShouldSetResponder,\n onScrollShouldSetResponderCapture = _config.onScrollShouldSetResponderCapture,\n onSelectionChangeShouldSetResponder = _config.onSelectionChangeShouldSetResponder,\n onSelectionChangeShouldSetResponderCapture = _config.onSelectionChangeShouldSetResponderCapture,\n onStartShouldSetResponder = _config.onStartShouldSetResponder,\n onStartShouldSetResponderCapture = _config.onStartShouldSetResponderCapture;\n var requiresResponderSystem = onMoveShouldSetResponder != null || onMoveShouldSetResponderCapture != null || onScrollShouldSetResponder != null || onScrollShouldSetResponderCapture != null || onSelectionChangeShouldSetResponder != null || onSelectionChangeShouldSetResponderCapture != null || onStartShouldSetResponder != null || onStartShouldSetResponderCapture != null;\n var node = hostRef.current;\n if (requiresResponderSystem) {\n ResponderSystem.addNode(id, node, config);\n isAttachedRef.current = true;\n } else if (isAttachedRef.current) {\n ResponderSystem.removeNode(id);\n isAttachedRef.current = false;\n }\n }, [config, hostRef, id]);\n React.useDebugValue({\n isResponder: hostRef.current === ResponderSystem.getResponderNode()\n });\n React.useDebugValue(config);\n}","/**\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n * \n */\n\n'use client';\n\nimport { createContext } from 'react';\nvar TextAncestorContext = /*#__PURE__*/createContext(false);\nexport default TextAncestorContext;","/**\n * Copyright (c) Nicolas Gallagher.\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n * \n */\n\n'use client';\n\nimport _objectWithoutPropertiesLoose from \"@babel/runtime/helpers/objectWithoutPropertiesLoose\";\nvar _excluded = [\"hrefAttrs\", \"onLayout\", \"onMoveShouldSetResponder\", \"onMoveShouldSetResponderCapture\", \"onResponderEnd\", \"onResponderGrant\", \"onResponderMove\", \"onResponderReject\", \"onResponderRelease\", \"onResponderStart\", \"onResponderTerminate\", \"onResponderTerminationRequest\", \"onScrollShouldSetResponder\", \"onScrollShouldSetResponderCapture\", \"onSelectionChangeShouldSetResponder\", \"onSelectionChangeShouldSetResponderCapture\", \"onStartShouldSetResponder\", \"onStartShouldSetResponderCapture\"];\nimport * as React from 'react';\nimport createElement from '../createElement';\nimport * as forwardedProps from '../../modules/forwardedProps';\nimport pick from '../../modules/pick';\nimport useElementLayout from '../../modules/useElementLayout';\nimport useMergeRefs from '../../modules/useMergeRefs';\nimport usePlatformMethods from '../../modules/usePlatformMethods';\nimport useResponderEvents from '../../modules/useResponderEvents';\nimport StyleSheet from '../StyleSheet';\nimport TextAncestorContext from '../Text/TextAncestorContext';\nimport { useLocaleContext, getLocaleDirection } from '../../modules/useLocale';\nvar forwardPropsList = Object.assign({}, forwardedProps.defaultProps, forwardedProps.accessibilityProps, forwardedProps.clickProps, forwardedProps.focusProps, forwardedProps.keyboardProps, forwardedProps.mouseProps, forwardedProps.touchProps, forwardedProps.styleProps, {\n href: true,\n lang: true,\n onScroll: true,\n onWheel: true,\n pointerEvents: true\n});\nvar pickProps = props => pick(props, forwardPropsList);\nvar View = /*#__PURE__*/React.forwardRef((props, forwardedRef) => {\n var hrefAttrs = props.hrefAttrs,\n onLayout = props.onLayout,\n onMoveShouldSetResponder = props.onMoveShouldSetResponder,\n onMoveShouldSetResponderCapture = props.onMoveShouldSetResponderCapture,\n onResponderEnd = props.onResponderEnd,\n onResponderGrant = props.onResponderGrant,\n onResponderMove = props.onResponderMove,\n onResponderReject = props.onResponderReject,\n onResponderRelease = props.onResponderRelease,\n onResponderStart = props.onResponderStart,\n onResponderTerminate = props.onResponderTerminate,\n onResponderTerminationRequest = props.onResponderTerminationRequest,\n onScrollShouldSetResponder = props.onScrollShouldSetResponder,\n onScrollShouldSetResponderCapture = props.onScrollShouldSetResponderCapture,\n onSelectionChangeShouldSetResponder = props.onSelectionChangeShouldSetResponder,\n onSelectionChangeShouldSetResponderCapture = props.onSelectionChangeShouldSetResponderCapture,\n onStartShouldSetResponder = props.onStartShouldSetResponder,\n onStartShouldSetResponderCapture = props.onStartShouldSetResponderCapture,\n rest = _objectWithoutPropertiesLoose(props, _excluded);\n if (process.env.NODE_ENV !== 'production') {\n React.Children.toArray(props.children).forEach(item => {\n if (typeof item === 'string') {\n console.error(\"Unexpected text node: \" + item + \". A text node cannot be a child of a .\");\n }\n });\n }\n var hasTextAncestor = React.useContext(TextAncestorContext);\n var hostRef = React.useRef(null);\n var _useLocaleContext = useLocaleContext(),\n contextDirection = _useLocaleContext.direction;\n useElementLayout(hostRef, onLayout);\n useResponderEvents(hostRef, {\n onMoveShouldSetResponder,\n onMoveShouldSetResponderCapture,\n onResponderEnd,\n onResponderGrant,\n onResponderMove,\n onResponderReject,\n onResponderRelease,\n onResponderStart,\n onResponderTerminate,\n onResponderTerminationRequest,\n onScrollShouldSetResponder,\n onScrollShouldSetResponderCapture,\n onSelectionChangeShouldSetResponder,\n onSelectionChangeShouldSetResponderCapture,\n onStartShouldSetResponder,\n onStartShouldSetResponderCapture\n });\n var component = 'div';\n var langDirection = props.lang != null ? getLocaleDirection(props.lang) : null;\n var componentDirection = props.dir || langDirection;\n var writingDirection = componentDirection || contextDirection;\n var supportedProps = pickProps(rest);\n supportedProps.dir = componentDirection;\n supportedProps.style = [styles.view$raw, hasTextAncestor && styles.inline, props.style];\n if (props.href != null) {\n component = 'a';\n if (hrefAttrs != null) {\n var download = hrefAttrs.download,\n rel = hrefAttrs.rel,\n target = hrefAttrs.target;\n if (download != null) {\n supportedProps.download = download;\n }\n if (rel != null) {\n supportedProps.rel = rel;\n }\n if (typeof target === 'string') {\n supportedProps.target = target.charAt(0) !== '_' ? '_' + target : target;\n }\n }\n }\n var platformMethodsRef = usePlatformMethods(supportedProps);\n var setRef = useMergeRefs(hostRef, platformMethodsRef, forwardedRef);\n supportedProps.ref = setRef;\n return createElement(component, supportedProps, {\n writingDirection\n });\n});\nView.displayName = 'View';\nvar styles = StyleSheet.create({\n view$raw: {\n alignItems: 'stretch',\n backgroundColor: 'transparent',\n border: '0 solid black',\n boxSizing: 'border-box',\n display: 'flex',\n flexBasis: 'auto',\n flexDirection: 'column',\n flexShrink: 0,\n listStyle: 'none',\n margin: 0,\n minHeight: 0,\n minWidth: 0,\n padding: 0,\n position: 'relative',\n textDecoration: 'none',\n zIndex: 0\n },\n inline: {\n display: 'inline-flex'\n }\n});\nexport default View;","/**\n * Copyright (c) 2013-present, Facebook, Inc.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n * \n */\n'use strict';\n\nvar validateFormat = process.env.NODE_ENV !== \"production\" ? function (format) {\n if (format === undefined) {\n throw new Error('invariant(...): Second argument must be a string.');\n }\n} : function (format) {};\n/**\n * Use invariant() to assert state which your program assumes to be true.\n *\n * Provide sprintf-style format (only %s is supported) and arguments to provide\n * information about what broke and what you were expecting.\n *\n * The invariant message will be stripped in production, but the invariant will\n * remain to ensure logic does not differ in production.\n */\n\nfunction invariant(condition, format) {\n for (var _len = arguments.length, args = new Array(_len > 2 ? _len - 2 : 0), _key = 2; _key < _len; _key++) {\n args[_key - 2] = arguments[_key];\n }\n\n validateFormat(format);\n\n if (!condition) {\n var error;\n\n if (format === undefined) {\n error = new Error('Minified exception occurred; use the non-minified dev environment ' + 'for the full error message and additional helpful warnings.');\n } else {\n var argIndex = 0;\n error = new Error(format.replace(/%s/g, function () {\n return String(args[argIndex++]);\n }));\n error.name = 'Invariant Violation';\n }\n\n error.framesToPop = 1; // Skip invariant's own stack frame.\n\n throw error;\n }\n}\n\nmodule.exports = invariant;","/**\n * Copyright (c) Nicolas Gallagher.\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n * \n */\n\n'use client';\n\nimport invariant from 'fbjs/lib/invariant';\nimport canUseDOM from '../../modules/canUseDom';\nvar dimensions = {\n window: {\n fontScale: 1,\n height: 0,\n scale: 1,\n width: 0\n },\n screen: {\n fontScale: 1,\n height: 0,\n scale: 1,\n width: 0\n }\n};\nvar listeners = {};\nvar shouldInit = canUseDOM;\nfunction update() {\n if (!canUseDOM) {\n return;\n }\n var win = window;\n var height;\n var width;\n\n /**\n * iOS does not update viewport dimensions on keyboard open/close.\n * window.visualViewport(https://developer.mozilla.org/en-US/docs/Web/API/VisualViewport)\n * is used instead of document.documentElement.clientHeight (which remains as a fallback)\n */\n if (win.visualViewport) {\n var visualViewport = win.visualViewport;\n /**\n * We are multiplying by scale because height and width from visual viewport\n * also react to pinch zoom, and become smaller when zoomed. But it is not desired\n * behaviour, since originally documentElement client height and width were used,\n * and they do not react to pinch zoom.\n */\n height = Math.round(visualViewport.height * visualViewport.scale);\n width = Math.round(visualViewport.width * visualViewport.scale);\n } else {\n var docEl = win.document.documentElement;\n height = docEl.clientHeight;\n width = docEl.clientWidth;\n }\n dimensions.window = {\n fontScale: 1,\n height,\n scale: win.devicePixelRatio || 1,\n width\n };\n dimensions.screen = {\n fontScale: 1,\n height: win.screen.height,\n scale: win.devicePixelRatio || 1,\n width: win.screen.width\n };\n}\nfunction handleResize() {\n update();\n if (Array.isArray(listeners['change'])) {\n listeners['change'].forEach(handler => handler(dimensions));\n }\n}\nexport default class Dimensions {\n static get(dimension) {\n if (shouldInit) {\n shouldInit = false;\n update();\n }\n invariant(dimensions[dimension], \"No dimension set for key \" + dimension);\n return dimensions[dimension];\n }\n static set(initialDimensions) {\n if (initialDimensions) {\n if (canUseDOM) {\n invariant(false, 'Dimensions cannot be set in the browser');\n } else {\n if (initialDimensions.screen != null) {\n dimensions.screen = initialDimensions.screen;\n }\n if (initialDimensions.window != null) {\n dimensions.window = initialDimensions.window;\n }\n }\n }\n }\n static addEventListener(type, handler) {\n listeners[type] = listeners[type] || [];\n listeners[type].push(handler);\n return {\n remove: () => {\n this.removeEventListener(type, handler);\n }\n };\n }\n static removeEventListener(type, handler) {\n if (Array.isArray(listeners[type])) {\n listeners[type] = listeners[type].filter(_handler => _handler !== handler);\n }\n }\n}\nif (canUseDOM) {\n if (window.visualViewport) {\n window.visualViewport.addEventListener('resize', handleResize, false);\n } else {\n window.addEventListener('resize', handleResize, false);\n }\n}","/**\n * Copyright (c) Nicolas Gallagher.\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n * \n */\n\nimport UIManager from '../../exports/UIManager';\n\n/**\n * This class is responsible for coordinating the \"focused\"\n * state for TextInputs. All calls relating to the keyboard\n * should be funneled through here\n */\nvar TextInputState = {\n /**\n * Internal state\n */\n _currentlyFocusedNode: null,\n /**\n * Returns the ID of the currently focused text field, if one exists\n * If no text field is focused it returns null\n */\n currentlyFocusedField() {\n if (document.activeElement !== this._currentlyFocusedNode) {\n this._currentlyFocusedNode = null;\n }\n return this._currentlyFocusedNode;\n },\n /**\n * @param {Object} TextInputID id of the text field to focus\n * Focuses the specified text field\n * noop if the text field was already focused\n */\n focusTextInput(textFieldNode) {\n if (textFieldNode !== null) {\n this._currentlyFocusedNode = textFieldNode;\n if (document.activeElement !== textFieldNode) {\n UIManager.focus(textFieldNode);\n }\n }\n },\n /**\n * @param {Object} textFieldNode id of the text field to focus\n * Unfocuses the specified text field\n * noop if it wasn't focused\n */\n blurTextInput(textFieldNode) {\n if (textFieldNode !== null) {\n this._currentlyFocusedNode = null;\n if (document.activeElement === textFieldNode) {\n UIManager.blur(textFieldNode);\n }\n }\n }\n};\nexport default TextInputState;","/**\n * Copyright (c) Nicolas Gallagher.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n * \n */\n\nimport TextInputState from '../TextInputState';\nvar dismissKeyboard = () => {\n TextInputState.blurTextInput(TextInputState.currentlyFocusedField());\n};\nexport default dismissKeyboard;","import _extends from \"@babel/runtime/helpers/extends\";\nimport _objectWithoutPropertiesLoose from \"@babel/runtime/helpers/objectWithoutPropertiesLoose\";\nvar _excluded = [\"onScroll\", \"onTouchMove\", \"onWheel\", \"scrollEnabled\", \"scrollEventThrottle\", \"showsHorizontalScrollIndicator\", \"showsVerticalScrollIndicator\", \"style\"];\n/**\n * Copyright (c) Nicolas Gallagher.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n * \n */\n\nimport * as React from 'react';\nimport StyleSheet from '../StyleSheet';\nimport View from '../View';\nimport useMergeRefs from '../../modules/useMergeRefs';\nfunction normalizeScrollEvent(e) {\n return {\n nativeEvent: {\n contentOffset: {\n get x() {\n return e.target.scrollLeft;\n },\n get y() {\n return e.target.scrollTop;\n }\n },\n contentSize: {\n get height() {\n return e.target.scrollHeight;\n },\n get width() {\n return e.target.scrollWidth;\n }\n },\n layoutMeasurement: {\n get height() {\n return e.target.offsetHeight;\n },\n get width() {\n return e.target.offsetWidth;\n }\n }\n },\n timeStamp: Date.now()\n };\n}\nfunction shouldEmitScrollEvent(lastTick, eventThrottle) {\n var timeSinceLastTick = Date.now() - lastTick;\n return eventThrottle > 0 && timeSinceLastTick >= eventThrottle;\n}\n\n/**\n * Encapsulates the Web-specific scroll throttling and disabling logic\n */\nvar ScrollViewBase = /*#__PURE__*/React.forwardRef((props, forwardedRef) => {\n var onScroll = props.onScroll,\n onTouchMove = props.onTouchMove,\n onWheel = props.onWheel,\n _props$scrollEnabled = props.scrollEnabled,\n scrollEnabled = _props$scrollEnabled === void 0 ? true : _props$scrollEnabled,\n _props$scrollEventThr = props.scrollEventThrottle,\n scrollEventThrottle = _props$scrollEventThr === void 0 ? 0 : _props$scrollEventThr,\n showsHorizontalScrollIndicator = props.showsHorizontalScrollIndicator,\n showsVerticalScrollIndicator = props.showsVerticalScrollIndicator,\n style = props.style,\n rest = _objectWithoutPropertiesLoose(props, _excluded);\n var scrollState = React.useRef({\n isScrolling: false,\n scrollLastTick: 0\n });\n var scrollTimeout = React.useRef(null);\n var scrollRef = React.useRef(null);\n function createPreventableScrollHandler(handler) {\n return e => {\n if (scrollEnabled) {\n if (handler) {\n handler(e);\n }\n }\n };\n }\n function handleScroll(e) {\n e.stopPropagation();\n if (e.target === scrollRef.current) {\n e.persist();\n // A scroll happened, so the scroll resets the scrollend timeout.\n if (scrollTimeout.current != null) {\n clearTimeout(scrollTimeout.current);\n }\n scrollTimeout.current = setTimeout(() => {\n handleScrollEnd(e);\n }, 100);\n if (scrollState.current.isScrolling) {\n // Scroll last tick may have changed, check if we need to notify\n if (shouldEmitScrollEvent(scrollState.current.scrollLastTick, scrollEventThrottle)) {\n handleScrollTick(e);\n }\n } else {\n // Weren't scrolling, so we must have just started\n handleScrollStart(e);\n }\n }\n }\n function handleScrollStart(e) {\n scrollState.current.isScrolling = true;\n handleScrollTick(e);\n }\n function handleScrollTick(e) {\n scrollState.current.scrollLastTick = Date.now();\n if (onScroll) {\n onScroll(normalizeScrollEvent(e));\n }\n }\n function handleScrollEnd(e) {\n scrollState.current.isScrolling = false;\n if (onScroll) {\n onScroll(normalizeScrollEvent(e));\n }\n }\n var hideScrollbar = showsHorizontalScrollIndicator === false || showsVerticalScrollIndicator === false;\n return /*#__PURE__*/React.createElement(View, _extends({}, rest, {\n onScroll: handleScroll,\n onTouchMove: createPreventableScrollHandler(onTouchMove),\n onWheel: createPreventableScrollHandler(onWheel),\n ref: useMergeRefs(scrollRef, forwardedRef),\n style: [style, !scrollEnabled && styles.scrollDisabled, hideScrollbar && styles.hideScrollbar]\n }));\n});\n\n// Chrome doesn't support e.preventDefault in this case; touch-action must be\n// used to disable scrolling.\n// https://developers.google.com/web/updates/2017/01/scrolling-intervention\nvar styles = StyleSheet.create({\n scrollDisabled: {\n overflowX: 'hidden',\n overflowY: 'hidden',\n touchAction: 'none'\n },\n hideScrollbar: {\n scrollbarWidth: 'none'\n }\n});\nexport default ScrollViewBase;","\"use strict\";\n\n/**\n * Copyright (c) 2013-present, Facebook, Inc.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n * \n */\nfunction makeEmptyFunction(arg) {\n return function () {\n return arg;\n };\n}\n/**\n * This function accepts and discards inputs; it has no side effects. This is\n * primarily useful idiomatically for overridable function endpoints which\n * always need to be callable, since JS lacks a null-call idiom ala Cocoa.\n */\n\n\nvar emptyFunction = function emptyFunction() {};\n\nemptyFunction.thatReturns = makeEmptyFunction;\nemptyFunction.thatReturnsFalse = makeEmptyFunction(false);\nemptyFunction.thatReturnsTrue = makeEmptyFunction(true);\nemptyFunction.thatReturnsNull = makeEmptyFunction(null);\n\nemptyFunction.thatReturnsThis = function () {\n return this;\n};\n\nemptyFunction.thatReturnsArgument = function (arg) {\n return arg;\n};\n\nmodule.exports = emptyFunction;","/**\n * Copyright (c) 2014-present, Facebook, Inc.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n */\n'use strict';\n\nvar emptyFunction = require(\"./emptyFunction\");\n/**\n * Similar to invariant but only logs a warning if the condition is not met.\n * This can be used to log issues in development environments in critical\n * paths. Removing the logging code for production environments will keep the\n * same logic and follow the same code paths.\n */\n\n\nfunction printWarning(format) {\n for (var _len = arguments.length, args = new Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {\n args[_key - 1] = arguments[_key];\n }\n\n var argIndex = 0;\n var message = 'Warning: ' + format.replace(/%s/g, function () {\n return args[argIndex++];\n });\n\n if (typeof console !== 'undefined') {\n console.error(message);\n }\n\n try {\n // --- Welcome to debugging React ---\n // This error was thrown as a convenience so that you can use this stack\n // to find the callsite that caused this warning to fire.\n throw new Error(message);\n } catch (x) {}\n}\n\nvar warning = process.env.NODE_ENV !== \"production\" ? function (condition, format) {\n if (format === undefined) {\n throw new Error('`warning(condition, format, ...args)` requires a warning ' + 'message argument');\n }\n\n if (!condition) {\n for (var _len2 = arguments.length, args = new Array(_len2 > 2 ? _len2 - 2 : 0), _key2 = 2; _key2 < _len2; _key2++) {\n args[_key2 - 2] = arguments[_key2];\n }\n\n printWarning.apply(void 0, [format].concat(args));\n }\n} : emptyFunction;\nmodule.exports = warning;","/**\n * Copyright (c) Nicolas Gallagher.\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n * \n */\n\n'use client';\n\nimport _objectSpread from \"@babel/runtime/helpers/objectSpread2\";\nimport _extends from \"@babel/runtime/helpers/extends\";\nimport _objectWithoutPropertiesLoose from \"@babel/runtime/helpers/objectWithoutPropertiesLoose\";\nvar _excluded = [\"contentContainerStyle\", \"horizontal\", \"onContentSizeChange\", \"refreshControl\", \"stickyHeaderIndices\", \"pagingEnabled\", \"forwardedRef\", \"keyboardDismissMode\", \"onScroll\", \"centerContent\"];\nimport Dimensions from '../Dimensions';\nimport dismissKeyboard from '../../modules/dismissKeyboard';\nimport invariant from 'fbjs/lib/invariant';\nimport mergeRefs from '../../modules/mergeRefs';\nimport Platform from '../Platform';\nimport ScrollViewBase from './ScrollViewBase';\nimport StyleSheet from '../StyleSheet';\nimport TextInputState from '../../modules/TextInputState';\nimport UIManager from '../UIManager';\nimport View from '../View';\nimport React from 'react';\nimport warning from 'fbjs/lib/warning';\nvar emptyObject = {};\nvar IS_ANIMATING_TOUCH_START_THRESHOLD_MS = 16;\nclass ScrollView extends React.Component {\n constructor() {\n super(...arguments);\n this._scrollNodeRef = null;\n this._innerViewRef = null;\n this.isTouching = false;\n this.lastMomentumScrollBeginTime = 0;\n this.lastMomentumScrollEndTime = 0;\n this.observedScrollSinceBecomingResponder = false;\n this.becameResponderWhileAnimating = false;\n this.scrollResponderHandleScrollShouldSetResponder = () => {\n return this.isTouching;\n };\n this.scrollResponderHandleStartShouldSetResponderCapture = e => {\n // First see if we want to eat taps while the keyboard is up\n // var currentlyFocusedTextInput = TextInputState.currentlyFocusedField();\n // if (!this.props.keyboardShouldPersistTaps &&\n // currentlyFocusedTextInput != null &&\n // e.target !== currentlyFocusedTextInput) {\n // return true;\n // }\n return this.scrollResponderIsAnimating();\n };\n this.scrollResponderHandleTerminationRequest = () => {\n return !this.observedScrollSinceBecomingResponder;\n };\n this.scrollResponderHandleTouchEnd = e => {\n var nativeEvent = e.nativeEvent;\n this.isTouching = nativeEvent.touches.length !== 0;\n this.props.onTouchEnd && this.props.onTouchEnd(e);\n };\n this.scrollResponderHandleResponderRelease = e => {\n this.props.onResponderRelease && this.props.onResponderRelease(e);\n\n // By default scroll views will unfocus a textField\n // if another touch occurs outside of it\n var currentlyFocusedTextInput = TextInputState.currentlyFocusedField();\n if (!this.props.keyboardShouldPersistTaps && currentlyFocusedTextInput != null && e.target !== currentlyFocusedTextInput && !this.observedScrollSinceBecomingResponder && !this.becameResponderWhileAnimating) {\n this.props.onScrollResponderKeyboardDismissed && this.props.onScrollResponderKeyboardDismissed(e);\n TextInputState.blurTextInput(currentlyFocusedTextInput);\n }\n };\n this.scrollResponderHandleScroll = e => {\n this.observedScrollSinceBecomingResponder = true;\n this.props.onScroll && this.props.onScroll(e);\n };\n this.scrollResponderHandleResponderGrant = e => {\n this.observedScrollSinceBecomingResponder = false;\n this.props.onResponderGrant && this.props.onResponderGrant(e);\n this.becameResponderWhileAnimating = this.scrollResponderIsAnimating();\n };\n this.scrollResponderHandleScrollBeginDrag = e => {\n this.props.onScrollBeginDrag && this.props.onScrollBeginDrag(e);\n };\n this.scrollResponderHandleScrollEndDrag = e => {\n this.props.onScrollEndDrag && this.props.onScrollEndDrag(e);\n };\n this.scrollResponderHandleMomentumScrollBegin = e => {\n this.lastMomentumScrollBeginTime = Date.now();\n this.props.onMomentumScrollBegin && this.props.onMomentumScrollBegin(e);\n };\n this.scrollResponderHandleMomentumScrollEnd = e => {\n this.lastMomentumScrollEndTime = Date.now();\n this.props.onMomentumScrollEnd && this.props.onMomentumScrollEnd(e);\n };\n this.scrollResponderHandleTouchStart = e => {\n this.isTouching = true;\n this.props.onTouchStart && this.props.onTouchStart(e);\n };\n this.scrollResponderHandleTouchMove = e => {\n this.props.onTouchMove && this.props.onTouchMove(e);\n };\n this.scrollResponderIsAnimating = () => {\n var now = Date.now();\n var timeSinceLastMomentumScrollEnd = now - this.lastMomentumScrollEndTime;\n var isAnimating = timeSinceLastMomentumScrollEnd < IS_ANIMATING_TOUCH_START_THRESHOLD_MS || this.lastMomentumScrollEndTime < this.lastMomentumScrollBeginTime;\n return isAnimating;\n };\n this.scrollResponderScrollTo = (x, y, animated) => {\n if (typeof x === 'number') {\n console.warn('`scrollResponderScrollTo(x, y, animated)` is deprecated. Use `scrollResponderScrollTo({x: 5, y: 5, animated: true})` instead.');\n } else {\n var _ref = x || emptyObject;\n x = _ref.x;\n y = _ref.y;\n animated = _ref.animated;\n }\n var node = this.getScrollableNode();\n var left = x || 0;\n var top = y || 0;\n if (node != null) {\n if (typeof node.scroll === 'function') {\n node.scroll({\n top,\n left,\n behavior: !animated ? 'auto' : 'smooth'\n });\n } else {\n node.scrollLeft = left;\n node.scrollTop = top;\n }\n }\n };\n this.scrollResponderZoomTo = (rect, animated) => {\n if (Platform.OS !== 'ios') {\n invariant('zoomToRect is not implemented');\n }\n };\n this.scrollResponderScrollNativeHandleToKeyboard = (nodeHandle, additionalOffset, preventNegativeScrollOffset) => {\n this.additionalScrollOffset = additionalOffset || 0;\n this.preventNegativeScrollOffset = !!preventNegativeScrollOffset;\n UIManager.measureLayout(nodeHandle, this.getInnerViewNode(), this.scrollResponderTextInputFocusError, this.scrollResponderInputMeasureAndScrollToKeyboard);\n };\n this.scrollResponderInputMeasureAndScrollToKeyboard = (left, top, width, height) => {\n var keyboardScreenY = Dimensions.get('window').height;\n if (this.keyboardWillOpenTo) {\n keyboardScreenY = this.keyboardWillOpenTo.endCoordinates.screenY;\n }\n var scrollOffsetY = top - keyboardScreenY + height + this.additionalScrollOffset;\n\n // By default, this can scroll with negative offset, pulling the content\n // down so that the target component's bottom meets the keyboard's top.\n // If requested otherwise, cap the offset at 0 minimum to avoid content\n // shifting down.\n if (this.preventNegativeScrollOffset) {\n scrollOffsetY = Math.max(0, scrollOffsetY);\n }\n this.scrollResponderScrollTo({\n x: 0,\n y: scrollOffsetY,\n animated: true\n });\n this.additionalOffset = 0;\n this.preventNegativeScrollOffset = false;\n };\n this.scrollResponderKeyboardWillShow = e => {\n this.keyboardWillOpenTo = e;\n this.props.onKeyboardWillShow && this.props.onKeyboardWillShow(e);\n };\n this.scrollResponderKeyboardWillHide = e => {\n this.keyboardWillOpenTo = null;\n this.props.onKeyboardWillHide && this.props.onKeyboardWillHide(e);\n };\n this.scrollResponderKeyboardDidShow = e => {\n // TODO(7693961): The event for DidShow is not available on iOS yet.\n // Use the one from WillShow and do not assign.\n if (e) {\n this.keyboardWillOpenTo = e;\n }\n this.props.onKeyboardDidShow && this.props.onKeyboardDidShow(e);\n };\n this.scrollResponderKeyboardDidHide = e => {\n this.keyboardWillOpenTo = null;\n this.props.onKeyboardDidHide && this.props.onKeyboardDidHide(e);\n };\n this.flashScrollIndicators = () => {\n this.scrollResponderFlashScrollIndicators();\n };\n this.getScrollResponder = () => {\n return this;\n };\n this.getScrollableNode = () => {\n return this._scrollNodeRef;\n };\n this.getInnerViewRef = () => {\n return this._innerViewRef;\n };\n this.getInnerViewNode = () => {\n return this._innerViewRef;\n };\n this.getNativeScrollRef = () => {\n return this._scrollNodeRef;\n };\n this.scrollTo = (y, x, animated) => {\n if (typeof y === 'number') {\n console.warn('`scrollTo(y, x, animated)` is deprecated. Use `scrollTo({x: 5, y: 5, animated: true})` instead.');\n } else {\n var _ref2 = y || emptyObject;\n x = _ref2.x;\n y = _ref2.y;\n animated = _ref2.animated;\n }\n this.scrollResponderScrollTo({\n x: x || 0,\n y: y || 0,\n animated: animated !== false\n });\n };\n this.scrollToEnd = options => {\n // Default to true\n var animated = (options && options.animated) !== false;\n var horizontal = this.props.horizontal;\n var scrollResponderNode = this.getScrollableNode();\n var x = horizontal ? scrollResponderNode.scrollWidth : 0;\n var y = horizontal ? 0 : scrollResponderNode.scrollHeight;\n this.scrollResponderScrollTo({\n x,\n y,\n animated\n });\n };\n this._handleContentOnLayout = e => {\n var _e$nativeEvent$layout = e.nativeEvent.layout,\n width = _e$nativeEvent$layout.width,\n height = _e$nativeEvent$layout.height;\n this.props.onContentSizeChange(width, height);\n };\n this._handleScroll = e => {\n if (process.env.NODE_ENV !== 'production') {\n if (this.props.onScroll && this.props.scrollEventThrottle == null) {\n console.log('You specified `onScroll` on a but not ' + '`scrollEventThrottle`. You will only receive one event. ' + 'Using `16` you get all the events but be aware that it may ' + \"cause frame drops, use a bigger number if you don't need as \" + 'much precision.');\n }\n }\n if (this.props.keyboardDismissMode === 'on-drag') {\n dismissKeyboard();\n }\n this.scrollResponderHandleScroll(e);\n };\n this._setInnerViewRef = node => {\n this._innerViewRef = node;\n };\n this._setScrollNodeRef = node => {\n this._scrollNodeRef = node;\n // ScrollView needs to add more methods to the hostNode in addition to those\n // added by `usePlatformMethods`. This is temporarily until an API like\n // `ScrollView.scrollTo(hostNode, { x, y })` is added to React Native.\n if (node != null) {\n node.getScrollResponder = this.getScrollResponder;\n node.getInnerViewNode = this.getInnerViewNode;\n node.getInnerViewRef = this.getInnerViewRef;\n node.getNativeScrollRef = this.getNativeScrollRef;\n node.getScrollableNode = this.getScrollableNode;\n node.scrollTo = this.scrollTo;\n node.scrollToEnd = this.scrollToEnd;\n node.flashScrollIndicators = this.flashScrollIndicators;\n node.scrollResponderZoomTo = this.scrollResponderZoomTo;\n node.scrollResponderScrollNativeHandleToKeyboard = this.scrollResponderScrollNativeHandleToKeyboard;\n }\n var ref = mergeRefs(this.props.forwardedRef);\n ref(node);\n };\n }\n /**\n * ------------------------------------------------------\n * START SCROLLRESPONDER\n * ------------------------------------------------------\n */\n // Reset to false every time becomes responder. This is used to:\n // - Determine if the scroll view has been scrolled and therefore should\n // refuse to give up its responder lock.\n // - Determine if releasing should dismiss the keyboard when we are in\n // tap-to-dismiss mode (!this.props.keyboardShouldPersistTaps).\n /**\n * Invoke this from an `onScroll` event.\n */\n /**\n * Merely touch starting is not sufficient for a scroll view to become the\n * responder. Being the \"responder\" means that the very next touch move/end\n * event will result in an action/movement.\n *\n * Invoke this from an `onStartShouldSetResponder` event.\n *\n * `onStartShouldSetResponder` is used when the next move/end will trigger\n * some UI movement/action, but when you want to yield priority to views\n * nested inside of the view.\n *\n * There may be some cases where scroll views actually should return `true`\n * from `onStartShouldSetResponder`: Any time we are detecting a standard tap\n * that gives priority to nested views.\n *\n * - If a single tap on the scroll view triggers an action such as\n * recentering a map style view yet wants to give priority to interaction\n * views inside (such as dropped pins or labels), then we would return true\n * from this method when there is a single touch.\n *\n * - Similar to the previous case, if a two finger \"tap\" should trigger a\n * zoom, we would check the `touches` count, and if `>= 2`, we would return\n * true.\n *\n */\n scrollResponderHandleStartShouldSetResponder() {\n return false;\n }\n\n /**\n * There are times when the scroll view wants to become the responder\n * (meaning respond to the next immediate `touchStart/touchEnd`), in a way\n * that *doesn't* give priority to nested views (hence the capture phase):\n *\n * - Currently animating.\n * - Tapping anywhere that is not the focused input, while the keyboard is\n * up (which should dismiss the keyboard).\n *\n * Invoke this from an `onStartShouldSetResponderCapture` event.\n */\n\n /**\n * Invoke this from an `onResponderReject` event.\n *\n * Some other element is not yielding its role as responder. Normally, we'd\n * just disable the `UIScrollView`, but a touch has already began on it, the\n * `UIScrollView` will not accept being disabled after that. The easiest\n * solution for now is to accept the limitation of disallowing this\n * altogether. To improve this, find a way to disable the `UIScrollView` after\n * a touch has already started.\n */\n scrollResponderHandleResponderReject() {\n warning(false, \"ScrollView doesn't take rejection well - scrolls anyway\");\n }\n\n /**\n * We will allow the scroll view to give up its lock iff it acquired the lock\n * during an animation. This is a very useful default that happens to satisfy\n * many common user experiences.\n *\n * - Stop a scroll on the left edge, then turn that into an outer view's\n * backswipe.\n * - Stop a scroll mid-bounce at the top, continue pulling to have the outer\n * view dismiss.\n * - However, without catching the scroll view mid-bounce (while it is\n * motionless), if you drag far enough for the scroll view to become\n * responder (and therefore drag the scroll view a bit), any backswipe\n * navigation of a swipe gesture higher in the view hierarchy, should be\n * rejected.\n */\n\n /**\n * Invoke this from an `onTouchEnd` event.\n *\n * @param {SyntheticEvent} e Event.\n */\n\n /**\n * Invoke this from an `onResponderRelease` event.\n */\n\n /**\n * Invoke this from an `onResponderGrant` event.\n */\n\n /**\n * Unfortunately, `onScrollBeginDrag` also fires when *stopping* the scroll\n * animation, and there's not an easy way to distinguish a drag vs. stopping\n * momentum.\n *\n * Invoke this from an `onScrollBeginDrag` event.\n */\n\n /**\n * Invoke this from an `onScrollEndDrag` event.\n */\n\n /**\n * Invoke this from an `onMomentumScrollBegin` event.\n */\n\n /**\n * Invoke this from an `onMomentumScrollEnd` event.\n */\n\n /**\n * Invoke this from an `onTouchStart` event.\n *\n * Since we know that the `SimpleEventPlugin` occurs later in the plugin\n * order, after `ResponderEventPlugin`, we can detect that we were *not*\n * permitted to be the responder (presumably because a contained view became\n * responder). The `onResponderReject` won't fire in that case - it only\n * fires when a *current* responder rejects our request.\n *\n * @param {SyntheticEvent} e Touch Start event.\n */\n\n /**\n * Invoke this from an `onTouchMove` event.\n *\n * Since we know that the `SimpleEventPlugin` occurs later in the plugin\n * order, after `ResponderEventPlugin`, we can detect that we were *not*\n * permitted to be the responder (presumably because a contained view became\n * responder). The `onResponderReject` won't fire in that case - it only\n * fires when a *current* responder rejects our request.\n *\n * @param {SyntheticEvent} e Touch Start event.\n */\n\n /**\n * A helper function for this class that lets us quickly determine if the\n * view is currently animating. This is particularly useful to know when\n * a touch has just started or ended.\n */\n\n /**\n * A helper function to scroll to a specific point in the scrollview.\n * This is currently used to help focus on child textviews, but can also\n * be used to quickly scroll to any element we want to focus. Syntax:\n *\n * scrollResponderScrollTo(options: {x: number = 0; y: number = 0; animated: boolean = true})\n *\n * Note: The weird argument signature is due to the fact that, for historical reasons,\n * the function also accepts separate arguments as as alternative to the options object.\n * This is deprecated due to ambiguity (y before x), and SHOULD NOT BE USED.\n */\n\n /**\n * A helper function to zoom to a specific rect in the scrollview. The argument has the shape\n * {x: number; y: number; width: number; height: number; animated: boolean = true}\n *\n * @platform ios\n */\n\n /**\n * Displays the scroll indicators momentarily.\n */\n scrollResponderFlashScrollIndicators() {}\n\n /**\n * This method should be used as the callback to onFocus in a TextInputs'\n * parent view. Note that any module using this mixin needs to return\n * the parent view's ref in getScrollViewRef() in order to use this method.\n * @param {any} nodeHandle The TextInput node handle\n * @param {number} additionalOffset The scroll view's top \"contentInset\".\n * Default is 0.\n * @param {bool} preventNegativeScrolling Whether to allow pulling the content\n * down to make it meet the keyboard's top. Default is false.\n */\n\n /**\n * The calculations performed here assume the scroll view takes up the entire\n * screen - even if has some content inset. We then measure the offsets of the\n * keyboard, and compensate both for the scroll view's \"contentInset\".\n *\n * @param {number} left Position of input w.r.t. table view.\n * @param {number} top Position of input w.r.t. table view.\n * @param {number} width Width of the text input.\n * @param {number} height Height of the text input.\n */\n\n scrollResponderTextInputFocusError(e) {\n console.error('Error measuring text field: ', e);\n }\n\n /**\n * Warning, this may be called several times for a single keyboard opening.\n * It's best to store the information in this method and then take any action\n * at a later point (either in `keyboardDidShow` or other).\n *\n * Here's the order that events occur in:\n * - focus\n * - willShow {startCoordinates, endCoordinates} several times\n * - didShow several times\n * - blur\n * - willHide {startCoordinates, endCoordinates} several times\n * - didHide several times\n *\n * The `ScrollResponder` providesModule callbacks for each of these events.\n * Even though any user could have easily listened to keyboard events\n * themselves, using these `props` callbacks ensures that ordering of events\n * is consistent - and not dependent on the order that the keyboard events are\n * subscribed to. This matters when telling the scroll view to scroll to where\n * the keyboard is headed - the scroll responder better have been notified of\n * the keyboard destination before being instructed to scroll to where the\n * keyboard will be. Stick to the `ScrollResponder` callbacks, and everything\n * will work.\n *\n * WARNING: These callbacks will fire even if a keyboard is displayed in a\n * different navigation pane. Filter out the events to determine if they are\n * relevant to you. (For example, only if you receive these callbacks after\n * you had explicitly focused a node etc).\n */\n\n /**\n * ------------------------------------------------------\n * END SCROLLRESPONDER\n * ------------------------------------------------------\n */\n\n /**\n * Returns a reference to the underlying scroll responder, which supports\n * operations like `scrollTo`. All ScrollView-like components should\n * implement this method so that they can be composed while providing access\n * to the underlying scroll responder's methods.\n */\n\n /**\n * Scrolls to a given x, y offset, either immediately or with a smooth animation.\n * Syntax:\n *\n * scrollTo(options: {x: number = 0; y: number = 0; animated: boolean = true})\n *\n * Note: The weird argument signature is due to the fact that, for historical reasons,\n * the function also accepts separate arguments as as alternative to the options object.\n * This is deprecated due to ambiguity (y before x), and SHOULD NOT BE USED.\n */\n\n /**\n * If this is a vertical ScrollView scrolls to the bottom.\n * If this is a horizontal ScrollView scrolls to the right.\n *\n * Use `scrollToEnd({ animated: true })` for smooth animated scrolling,\n * `scrollToEnd({ animated: false })` for immediate scrolling.\n * If no options are passed, `animated` defaults to true.\n */\n\n render() {\n var _this$props = this.props,\n contentContainerStyle = _this$props.contentContainerStyle,\n horizontal = _this$props.horizontal,\n onContentSizeChange = _this$props.onContentSizeChange,\n refreshControl = _this$props.refreshControl,\n stickyHeaderIndices = _this$props.stickyHeaderIndices,\n pagingEnabled = _this$props.pagingEnabled,\n forwardedRef = _this$props.forwardedRef,\n keyboardDismissMode = _this$props.keyboardDismissMode,\n onScroll = _this$props.onScroll,\n centerContent = _this$props.centerContent,\n other = _objectWithoutPropertiesLoose(_this$props, _excluded);\n if (process.env.NODE_ENV !== 'production' && this.props.style) {\n var style = StyleSheet.flatten(this.props.style);\n var childLayoutProps = ['alignItems', 'justifyContent'].filter(prop => style && style[prop] !== undefined);\n invariant(childLayoutProps.length === 0, \"ScrollView child layout (\" + JSON.stringify(childLayoutProps) + \") \" + 'must be applied through the contentContainerStyle prop.');\n }\n var contentSizeChangeProps = {};\n if (onContentSizeChange) {\n contentSizeChangeProps = {\n onLayout: this._handleContentOnLayout\n };\n }\n var hasStickyHeaderIndices = !horizontal && Array.isArray(stickyHeaderIndices);\n var children = hasStickyHeaderIndices || pagingEnabled ? React.Children.map(this.props.children, (child, i) => {\n var isSticky = hasStickyHeaderIndices && stickyHeaderIndices.indexOf(i) > -1;\n if (child != null && (isSticky || pagingEnabled)) {\n return /*#__PURE__*/React.createElement(View, {\n style: [isSticky && styles.stickyHeader, pagingEnabled && styles.pagingEnabledChild]\n }, child);\n } else {\n return child;\n }\n }) : this.props.children;\n var contentContainer = /*#__PURE__*/React.createElement(View, _extends({}, contentSizeChangeProps, {\n children: children,\n collapsable: false,\n ref: this._setInnerViewRef,\n style: [horizontal && styles.contentContainerHorizontal, centerContent && styles.contentContainerCenterContent, contentContainerStyle]\n }));\n var baseStyle = horizontal ? styles.baseHorizontal : styles.baseVertical;\n var pagingEnabledStyle = horizontal ? styles.pagingEnabledHorizontal : styles.pagingEnabledVertical;\n var props = _objectSpread(_objectSpread({}, other), {}, {\n style: [baseStyle, pagingEnabled && pagingEnabledStyle, this.props.style],\n onTouchStart: this.scrollResponderHandleTouchStart,\n onTouchMove: this.scrollResponderHandleTouchMove,\n onTouchEnd: this.scrollResponderHandleTouchEnd,\n onScrollBeginDrag: this.scrollResponderHandleScrollBeginDrag,\n onScrollEndDrag: this.scrollResponderHandleScrollEndDrag,\n onMomentumScrollBegin: this.scrollResponderHandleMomentumScrollBegin,\n onMomentumScrollEnd: this.scrollResponderHandleMomentumScrollEnd,\n onStartShouldSetResponder: this.scrollResponderHandleStartShouldSetResponder,\n onStartShouldSetResponderCapture: this.scrollResponderHandleStartShouldSetResponderCapture,\n onScrollShouldSetResponder: this.scrollResponderHandleScrollShouldSetResponder,\n onScroll: this._handleScroll,\n onResponderGrant: this.scrollResponderHandleResponderGrant,\n onResponderTerminationRequest: this.scrollResponderHandleTerminationRequest,\n onResponderTerminate: this.scrollResponderHandleTerminate,\n onResponderRelease: this.scrollResponderHandleResponderRelease,\n onResponderReject: this.scrollResponderHandleResponderReject\n });\n var ScrollViewClass = ScrollViewBase;\n invariant(ScrollViewClass !== undefined, 'ScrollViewClass must not be undefined');\n var scrollView = /*#__PURE__*/React.createElement(ScrollViewClass, _extends({}, props, {\n ref: this._setScrollNodeRef\n }), contentContainer);\n if (refreshControl) {\n return /*#__PURE__*/React.cloneElement(refreshControl, {\n style: props.style\n }, scrollView);\n }\n return scrollView;\n }\n}\nvar commonStyle = {\n flexGrow: 1,\n flexShrink: 1,\n // Enable hardware compositing in modern browsers.\n // Creates a new layer with its own backing surface that can significantly\n // improve scroll performance.\n transform: 'translateZ(0)',\n // iOS native scrolling\n WebkitOverflowScrolling: 'touch'\n};\nvar styles = StyleSheet.create({\n baseVertical: _objectSpread(_objectSpread({}, commonStyle), {}, {\n flexDirection: 'column',\n overflowX: 'hidden',\n overflowY: 'auto'\n }),\n baseHorizontal: _objectSpread(_objectSpread({}, commonStyle), {}, {\n flexDirection: 'row',\n overflowX: 'auto',\n overflowY: 'hidden'\n }),\n contentContainerHorizontal: {\n flexDirection: 'row'\n },\n contentContainerCenterContent: {\n justifyContent: 'center',\n flexGrow: 1\n },\n stickyHeader: {\n position: 'sticky',\n top: 0,\n zIndex: 10\n },\n pagingEnabledHorizontal: {\n scrollSnapType: 'x mandatory'\n },\n pagingEnabledVertical: {\n scrollSnapType: 'y mandatory'\n },\n pagingEnabledChild: {\n scrollSnapAlign: 'start'\n }\n});\nvar ForwardedScrollView = /*#__PURE__*/React.forwardRef((props, forwardedRef) => {\n return /*#__PURE__*/React.createElement(ScrollView, _extends({}, props, {\n forwardedRef: forwardedRef\n }));\n});\nForwardedScrollView.displayName = 'ScrollView';\nexport default ForwardedScrollView;","import _objectSpread from \"@babel/runtime/helpers/objectSpread2\";\n/**\n * Copyright (c) Nicolas Gallagher.\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n * \n */\n\nimport invariant from 'fbjs/lib/invariant';\nclass TaskQueue {\n constructor(_ref) {\n var onMoreTasks = _ref.onMoreTasks;\n this._onMoreTasks = onMoreTasks;\n this._queueStack = [{\n tasks: [],\n popable: true\n }];\n }\n enqueue(task) {\n this._getCurrentQueue().push(task);\n }\n enqueueTasks(tasks) {\n tasks.forEach(task => this.enqueue(task));\n }\n cancelTasks(tasksToCancel) {\n this._queueStack = this._queueStack.map(queue => _objectSpread(_objectSpread({}, queue), {}, {\n tasks: queue.tasks.filter(task => tasksToCancel.indexOf(task) === -1)\n })).filter((queue, idx) => queue.tasks.length > 0 || idx === 0);\n }\n hasTasksToProcess() {\n return this._getCurrentQueue().length > 0;\n }\n\n /**\n * Executes the next task in the queue.\n */\n processNext() {\n var queue = this._getCurrentQueue();\n if (queue.length) {\n var task = queue.shift();\n try {\n if (typeof task === 'object' && task.gen) {\n this._genPromise(task);\n } else if (typeof task === 'object' && task.run) {\n task.run();\n } else {\n invariant(typeof task === 'function', 'Expected Function, SimpleTask, or PromiseTask, but got:\\n' + JSON.stringify(task, null, 2));\n task();\n }\n } catch (e) {\n e.message = 'TaskQueue: Error with task ' + (task.name || '') + ': ' + e.message;\n throw e;\n }\n }\n }\n _getCurrentQueue() {\n var stackIdx = this._queueStack.length - 1;\n var queue = this._queueStack[stackIdx];\n if (queue.popable && queue.tasks.length === 0 && stackIdx > 0) {\n this._queueStack.pop();\n return this._getCurrentQueue();\n } else {\n return queue.tasks;\n }\n }\n _genPromise(task) {\n var length = this._queueStack.push({\n tasks: [],\n popable: false\n });\n var stackIdx = length - 1;\n var stackItem = this._queueStack[stackIdx];\n task.gen().then(() => {\n stackItem.popable = true;\n this.hasTasksToProcess() && this._onMoreTasks();\n }).catch(ex => {\n setTimeout(() => {\n ex.message = \"TaskQueue: Error resolving Promise in task \" + task.name + \": \" + ex.message;\n throw ex;\n }, 0);\n });\n }\n}\nexport default TaskQueue;","/**\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n * \n * @format\n */\n\n/**\n * EventEmitter manages listeners and publishes events to them.\n *\n * EventEmitter accepts a single type parameter that defines the valid events\n * and associated listener argument(s).\n *\n * @example\n *\n * const emitter = new EventEmitter<{\n * success: [number, string],\n * error: [Error],\n * }>();\n *\n * emitter.on('success', (statusCode, responseText) => {...});\n * emitter.emit('success', 200, '...');\n *\n * emitter.on('error', error => {...});\n * emitter.emit('error', new Error('Resource not found'));\n *\n */\nexport default class EventEmitter {\n constructor() {\n this._registry = {};\n }\n /**\n * Registers a listener that is called when the supplied event is emitted.\n * Returns a subscription that has a `remove` method to undo registration.\n */\n addListener(eventType, listener, context) {\n var registrations = allocate(this._registry, eventType);\n var registration = {\n context,\n listener,\n remove() {\n registrations.delete(registration);\n }\n };\n registrations.add(registration);\n return registration;\n }\n\n /**\n * Emits the supplied event. Additional arguments supplied to `emit` will be\n * passed through to each of the registered listeners.\n *\n * If a listener modifies the listeners registered for the same event, those\n * changes will not be reflected in the current invocation of `emit`.\n */\n emit(eventType) {\n var registrations = this._registry[eventType];\n if (registrations != null) {\n for (var _len = arguments.length, args = new Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {\n args[_key - 1] = arguments[_key];\n }\n for (var _i = 0, _arr = [...registrations]; _i < _arr.length; _i++) {\n var registration = _arr[_i];\n registration.listener.apply(registration.context, args);\n }\n }\n }\n\n /**\n * Removes all registered listeners.\n */\n removeAllListeners(eventType) {\n if (eventType == null) {\n this._registry = {};\n } else {\n delete this._registry[eventType];\n }\n }\n\n /**\n * Returns the number of registered listeners for the supplied event.\n */\n listenerCount(eventType) {\n var registrations = this._registry[eventType];\n return registrations == null ? 0 : registrations.size;\n }\n}\nfunction allocate(registry, eventType) {\n var registrations = registry[eventType];\n if (registrations == null) {\n registrations = new Set();\n registry[eventType] = registrations;\n }\n return registrations;\n}","/**\n * Copyright (c) Nicolas Gallagher.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n * \n */\nimport canUseDOM from '../canUseDom';\nvar _requestIdleCallback = function _requestIdleCallback(cb, options) {\n return setTimeout(() => {\n var start = Date.now();\n cb({\n didTimeout: false,\n timeRemaining() {\n return Math.max(0, 50 - (Date.now() - start));\n }\n });\n }, 1);\n};\nvar _cancelIdleCallback = function _cancelIdleCallback(id) {\n clearTimeout(id);\n};\nvar isSupported = canUseDOM && typeof window.requestIdleCallback !== 'undefined';\nvar requestIdleCallback = isSupported ? window.requestIdleCallback : _requestIdleCallback;\nvar cancelIdleCallback = isSupported ? window.cancelIdleCallback : _cancelIdleCallback;\nexport default requestIdleCallback;\nexport { cancelIdleCallback };","/**\n * Copyright (c) Nicolas Gallagher.\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n * \n */\n\nimport invariant from 'fbjs/lib/invariant';\nimport TaskQueue from './TaskQueue';\nimport EventEmitter from '../../vendor/react-native/vendor/emitter/EventEmitter';\nimport requestIdleCallback from '../../modules/requestIdleCallback';\nvar _emitter = new EventEmitter();\nvar InteractionManager = {\n Events: {\n interactionStart: 'interactionStart',\n interactionComplete: 'interactionComplete'\n },\n /**\n * Schedule a function to run after all interactions have completed.\n */\n runAfterInteractions(task) {\n var tasks = [];\n var promise = new Promise(resolve => {\n _scheduleUpdate();\n if (task) {\n tasks.push(task);\n }\n tasks.push({\n run: resolve,\n name: 'resolve ' + (task && task.name || '?')\n });\n _taskQueue.enqueueTasks(tasks);\n });\n return {\n then: promise.then.bind(promise),\n done: promise.then.bind(promise),\n cancel: () => {\n _taskQueue.cancelTasks(tasks);\n }\n };\n },\n /**\n * Notify manager that an interaction has started.\n */\n createInteractionHandle() {\n _scheduleUpdate();\n var handle = ++_inc;\n _addInteractionSet.add(handle);\n return handle;\n },\n /**\n * Notify manager that an interaction has completed.\n */\n clearInteractionHandle(handle) {\n invariant(!!handle, 'Must provide a handle to clear.');\n _scheduleUpdate();\n _addInteractionSet.delete(handle);\n _deleteInteractionSet.add(handle);\n },\n addListener: _emitter.addListener.bind(_emitter),\n /**\n *\n * @param deadline\n */\n setDeadline(deadline) {\n _deadline = deadline;\n }\n};\nvar _interactionSet = new Set();\nvar _addInteractionSet = new Set();\nvar _deleteInteractionSet = new Set();\nvar _taskQueue = new TaskQueue({\n onMoreTasks: _scheduleUpdate\n});\nvar _nextUpdateHandle = 0;\nvar _inc = 0;\nvar _deadline = -1;\n\n/**\n * Schedule an asynchronous update to the interaction state.\n */\nfunction _scheduleUpdate() {\n if (!_nextUpdateHandle) {\n if (_deadline > 0) {\n _nextUpdateHandle = setTimeout(_processUpdate);\n } else {\n _nextUpdateHandle = requestIdleCallback(_processUpdate);\n }\n }\n}\n\n/**\n * Notify listeners, process queue, etc\n */\nfunction _processUpdate() {\n _nextUpdateHandle = 0;\n var interactionCount = _interactionSet.size;\n _addInteractionSet.forEach(handle => _interactionSet.add(handle));\n _deleteInteractionSet.forEach(handle => _interactionSet.delete(handle));\n var nextInteractionCount = _interactionSet.size;\n if (interactionCount !== 0 && nextInteractionCount === 0) {\n _emitter.emit(InteractionManager.Events.interactionComplete);\n } else if (interactionCount === 0 && nextInteractionCount !== 0) {\n _emitter.emit(InteractionManager.Events.interactionStart);\n }\n if (nextInteractionCount === 0) {\n // It seems that we can't know the running time of the current event loop,\n // we can only calculate the running time of the current task queue.\n var begin = Date.now();\n while (_taskQueue.hasTasksToProcess()) {\n _taskQueue.processNext();\n if (_deadline > 0 && Date.now() - begin >= _deadline) {\n _scheduleUpdate();\n break;\n }\n }\n }\n _addInteractionSet.clear();\n _deleteInteractionSet.clear();\n}\nexport default InteractionManager;","/**\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n * @format\n */\n\nvar TouchHistoryMath = {\n /**\n * This code is optimized and not intended to look beautiful. This allows\n * computing of touch centroids that have moved after `touchesChangedAfter`\n * timeStamp. You can compute the current centroid involving all touches\n * moves after `touchesChangedAfter`, or you can compute the previous\n * centroid of all touches that were moved after `touchesChangedAfter`.\n *\n * @param {TouchHistoryMath} touchHistory Standard Responder touch track\n * data.\n * @param {number} touchesChangedAfter timeStamp after which moved touches\n * are considered \"actively moving\" - not just \"active\".\n * @param {boolean} isXAxis Consider `x` dimension vs. `y` dimension.\n * @param {boolean} ofCurrent Compute current centroid for actively moving\n * touches vs. previous centroid of now actively moving touches.\n * @return {number} value of centroid in specified dimension.\n */\n centroidDimension: function centroidDimension(touchHistory, touchesChangedAfter, isXAxis, ofCurrent) {\n var touchBank = touchHistory.touchBank;\n var total = 0;\n var count = 0;\n var oneTouchData = touchHistory.numberActiveTouches === 1 ? touchHistory.touchBank[touchHistory.indexOfSingleActiveTouch] : null;\n if (oneTouchData !== null) {\n if (oneTouchData.touchActive && oneTouchData.currentTimeStamp > touchesChangedAfter) {\n total += ofCurrent && isXAxis ? oneTouchData.currentPageX : ofCurrent && !isXAxis ? oneTouchData.currentPageY : !ofCurrent && isXAxis ? oneTouchData.previousPageX : oneTouchData.previousPageY;\n count = 1;\n }\n } else {\n for (var i = 0; i < touchBank.length; i++) {\n var touchTrack = touchBank[i];\n if (touchTrack !== null && touchTrack !== undefined && touchTrack.touchActive && touchTrack.currentTimeStamp >= touchesChangedAfter) {\n var toAdd = void 0; // Yuck, program temporarily in invalid state.\n if (ofCurrent && isXAxis) {\n toAdd = touchTrack.currentPageX;\n } else if (ofCurrent && !isXAxis) {\n toAdd = touchTrack.currentPageY;\n } else if (!ofCurrent && isXAxis) {\n toAdd = touchTrack.previousPageX;\n } else {\n toAdd = touchTrack.previousPageY;\n }\n total += toAdd;\n count++;\n }\n }\n }\n return count > 0 ? total / count : TouchHistoryMath.noCentroid;\n },\n currentCentroidXOfTouchesChangedAfter: function currentCentroidXOfTouchesChangedAfter(touchHistory, touchesChangedAfter) {\n return TouchHistoryMath.centroidDimension(touchHistory, touchesChangedAfter, true,\n // isXAxis\n true // ofCurrent\n );\n },\n currentCentroidYOfTouchesChangedAfter: function currentCentroidYOfTouchesChangedAfter(touchHistory, touchesChangedAfter) {\n return TouchHistoryMath.centroidDimension(touchHistory, touchesChangedAfter, false,\n // isXAxis\n true // ofCurrent\n );\n },\n previousCentroidXOfTouchesChangedAfter: function previousCentroidXOfTouchesChangedAfter(touchHistory, touchesChangedAfter) {\n return TouchHistoryMath.centroidDimension(touchHistory, touchesChangedAfter, true,\n // isXAxis\n false // ofCurrent\n );\n },\n previousCentroidYOfTouchesChangedAfter: function previousCentroidYOfTouchesChangedAfter(touchHistory, touchesChangedAfter) {\n return TouchHistoryMath.centroidDimension(touchHistory, touchesChangedAfter, false,\n // isXAxis\n false // ofCurrent\n );\n },\n currentCentroidX: function currentCentroidX(touchHistory) {\n return TouchHistoryMath.centroidDimension(touchHistory, 0,\n // touchesChangedAfter\n true,\n // isXAxis\n true // ofCurrent\n );\n },\n currentCentroidY: function currentCentroidY(touchHistory) {\n return TouchHistoryMath.centroidDimension(touchHistory, 0,\n // touchesChangedAfter\n false,\n // isXAxis\n true // ofCurrent\n );\n },\n noCentroid: -1\n};\nexport default TouchHistoryMath;","/**\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n * \n * @format\n */\n\n'use strict';\n\nimport InteractionManager from '../../../exports/InteractionManager';\nimport TouchHistoryMath from '../TouchHistoryMath';\nvar currentCentroidXOfTouchesChangedAfter = TouchHistoryMath.currentCentroidXOfTouchesChangedAfter;\nvar currentCentroidYOfTouchesChangedAfter = TouchHistoryMath.currentCentroidYOfTouchesChangedAfter;\nvar previousCentroidXOfTouchesChangedAfter = TouchHistoryMath.previousCentroidXOfTouchesChangedAfter;\nvar previousCentroidYOfTouchesChangedAfter = TouchHistoryMath.previousCentroidYOfTouchesChangedAfter;\nvar currentCentroidX = TouchHistoryMath.currentCentroidX;\nvar currentCentroidY = TouchHistoryMath.currentCentroidY;\n\n/**\n * `PanResponder` reconciles several touches into a single gesture. It makes\n * single-touch gestures resilient to extra touches, and can be used to\n * recognize simple multi-touch gestures.\n *\n * By default, `PanResponder` holds an `InteractionManager` handle to block\n * long-running JS events from interrupting active gestures.\n *\n * It provides a predictable wrapper of the responder handlers provided by the\n * [gesture responder system](docs/gesture-responder-system.html).\n * For each handler, it provides a new `gestureState` object alongside the\n * native event object:\n *\n * ```\n * onPanResponderMove: (event, gestureState) => {}\n * ```\n *\n * A native event is a synthetic touch event with the following form:\n *\n * - `nativeEvent`\n * + `changedTouches` - Array of all touch events that have changed since the last event\n * + `identifier` - The ID of the touch\n * + `locationX` - The X position of the touch, relative to the element\n * + `locationY` - The Y position of the touch, relative to the element\n * + `pageX` - The X position of the touch, relative to the root element\n * + `pageY` - The Y position of the touch, relative to the root element\n * + `target` - The node id of the element receiving the touch event\n * + `timestamp` - A time identifier for the touch, useful for velocity calculation\n * + `touches` - Array of all current touches on the screen\n *\n * A `gestureState` object has the following:\n *\n * - `stateID` - ID of the gestureState- persisted as long as there at least\n * one touch on screen\n * - `moveX` - the latest screen coordinates of the recently-moved touch\n * - `moveY` - the latest screen coordinates of the recently-moved touch\n * - `x0` - the screen coordinates of the responder grant\n * - `y0` - the screen coordinates of the responder grant\n * - `dx` - accumulated distance of the gesture since the touch started\n * - `dy` - accumulated distance of the gesture since the touch started\n * - `vx` - current velocity of the gesture\n * - `vy` - current velocity of the gesture\n * - `numberActiveTouches` - Number of touches currently on screen\n *\n * ### Basic Usage\n *\n * ```\n * componentWillMount: function() {\n * this._panResponder = PanResponder.create({\n * // Ask to be the responder:\n * onStartShouldSetPanResponder: (evt, gestureState) => true,\n * onStartShouldSetPanResponderCapture: (evt, gestureState) => true,\n * onMoveShouldSetPanResponder: (evt, gestureState) => true,\n * onMoveShouldSetPanResponderCapture: (evt, gestureState) => true,\n *\n * onPanResponderGrant: (evt, gestureState) => {\n * // The gesture has started. Show visual feedback so the user knows\n * // what is happening!\n *\n * // gestureState.d{x,y} will be set to zero now\n * },\n * onPanResponderMove: (evt, gestureState) => {\n * // The most recent move distance is gestureState.move{X,Y}\n *\n * // The accumulated gesture distance since becoming responder is\n * // gestureState.d{x,y}\n * },\n * onPanResponderTerminationRequest: (evt, gestureState) => true,\n * onPanResponderRelease: (evt, gestureState) => {\n * // The user has released all touches while this view is the\n * // responder. This typically means a gesture has succeeded\n * },\n * onPanResponderTerminate: (evt, gestureState) => {\n * // Another component has become the responder, so this gesture\n * // should be cancelled\n * },\n * onShouldBlockNativeResponder: (evt, gestureState) => {\n * // Returns whether this component should block native components from becoming the JS\n * // responder. Returns true by default. Is currently only supported on android.\n * return true;\n * },\n * });\n * },\n *\n * render: function() {\n * return (\n * \n * );\n * },\n *\n * ```\n *\n * ### Working Example\n *\n * To see it in action, try the\n * [PanResponder example in RNTester](https://github.com/facebook/react-native/blob/master/RNTester/js/PanResponderExample.js)\n */\n\nvar PanResponder = {\n /**\n *\n * A graphical explanation of the touch data flow:\n *\n * +----------------------------+ +--------------------------------+\n * | ResponderTouchHistoryStore | |TouchHistoryMath |\n * +----------------------------+ +----------+---------------------+\n * |Global store of touchHistory| |Allocation-less math util |\n * |including activeness, start | |on touch history (centroids |\n * |position, prev/cur position.| |and multitouch movement etc) |\n * | | | |\n * +----^-----------------------+ +----^---------------------------+\n * | |\n * | (records relevant history |\n * | of touches relevant for |\n * | implementing higher level |\n * | gestures) |\n * | |\n * +----+-----------------------+ +----|---------------------------+\n * | ResponderEventPlugin | | | Your App/Component |\n * +----------------------------+ +----|---------------------------+\n * |Negotiates which view gets | Low level | | High level |\n * |onResponderMove events. | events w/ | +-+-------+ events w/ |\n * |Also records history into | touchHistory| | Pan | multitouch + |\n * |ResponderTouchHistoryStore. +---------------->Responder+-----> accumulative|\n * +----------------------------+ attached to | | | distance and |\n * each event | +---------+ velocity. |\n * | |\n * | |\n * +--------------------------------+\n *\n *\n *\n * Gesture that calculates cumulative movement over time in a way that just\n * \"does the right thing\" for multiple touches. The \"right thing\" is very\n * nuanced. When moving two touches in opposite directions, the cumulative\n * distance is zero in each dimension. When two touches move in parallel five\n * pixels in the same direction, the cumulative distance is five, not ten. If\n * two touches start, one moves five in a direction, then stops and the other\n * touch moves fives in the same direction, the cumulative distance is ten.\n *\n * This logic requires a kind of processing of time \"clusters\" of touch events\n * so that two touch moves that essentially occur in parallel but move every\n * other frame respectively, are considered part of the same movement.\n *\n * Explanation of some of the non-obvious fields:\n *\n * - moveX/moveY: If no move event has been observed, then `(moveX, moveY)` is\n * invalid. If a move event has been observed, `(moveX, moveY)` is the\n * centroid of the most recently moved \"cluster\" of active touches.\n * (Currently all move have the same timeStamp, but later we should add some\n * threshold for what is considered to be \"moving\"). If a palm is\n * accidentally counted as a touch, but a finger is moving greatly, the palm\n * will move slightly, but we only want to count the single moving touch.\n * - x0/y0: Centroid location (non-cumulative) at the time of becoming\n * responder.\n * - dx/dy: Cumulative touch distance - not the same thing as sum of each touch\n * distance. Accounts for touch moves that are clustered together in time,\n * moving the same direction. Only valid when currently responder (otherwise,\n * it only represents the drag distance below the threshold).\n * - vx/vy: Velocity.\n */\n\n _initializeGestureState(gestureState) {\n gestureState.moveX = 0;\n gestureState.moveY = 0;\n gestureState.x0 = 0;\n gestureState.y0 = 0;\n gestureState.dx = 0;\n gestureState.dy = 0;\n gestureState.vx = 0;\n gestureState.vy = 0;\n gestureState.numberActiveTouches = 0;\n // All `gestureState` accounts for timeStamps up until:\n gestureState._accountsForMovesUpTo = 0;\n },\n /**\n * This is nuanced and is necessary. It is incorrect to continuously take all\n * active *and* recently moved touches, find the centroid, and track how that\n * result changes over time. Instead, we must take all recently moved\n * touches, and calculate how the centroid has changed just for those\n * recently moved touches, and append that change to an accumulator. This is\n * to (at least) handle the case where the user is moving three fingers, and\n * then one of the fingers stops but the other two continue.\n *\n * This is very different than taking all of the recently moved touches and\n * storing their centroid as `dx/dy`. For correctness, we must *accumulate\n * changes* in the centroid of recently moved touches.\n *\n * There is also some nuance with how we handle multiple moved touches in a\n * single event. With the way `ReactNativeEventEmitter` dispatches touches as\n * individual events, multiple touches generate two 'move' events, each of\n * them triggering `onResponderMove`. But with the way `PanResponder` works,\n * all of the gesture inference is performed on the first dispatch, since it\n * looks at all of the touches (even the ones for which there hasn't been a\n * native dispatch yet). Therefore, `PanResponder` does not call\n * `onResponderMove` passed the first dispatch. This diverges from the\n * typical responder callback pattern (without using `PanResponder`), but\n * avoids more dispatches than necessary.\n */\n _updateGestureStateOnMove(gestureState, touchHistory) {\n gestureState.numberActiveTouches = touchHistory.numberActiveTouches;\n gestureState.moveX = currentCentroidXOfTouchesChangedAfter(touchHistory, gestureState._accountsForMovesUpTo);\n gestureState.moveY = currentCentroidYOfTouchesChangedAfter(touchHistory, gestureState._accountsForMovesUpTo);\n var movedAfter = gestureState._accountsForMovesUpTo;\n var prevX = previousCentroidXOfTouchesChangedAfter(touchHistory, movedAfter);\n var x = currentCentroidXOfTouchesChangedAfter(touchHistory, movedAfter);\n var prevY = previousCentroidYOfTouchesChangedAfter(touchHistory, movedAfter);\n var y = currentCentroidYOfTouchesChangedAfter(touchHistory, movedAfter);\n var nextDX = gestureState.dx + (x - prevX);\n var nextDY = gestureState.dy + (y - prevY);\n\n // TODO: This must be filtered intelligently.\n var dt = touchHistory.mostRecentTimeStamp - gestureState._accountsForMovesUpTo;\n gestureState.vx = (nextDX - gestureState.dx) / dt;\n gestureState.vy = (nextDY - gestureState.dy) / dt;\n gestureState.dx = nextDX;\n gestureState.dy = nextDY;\n gestureState._accountsForMovesUpTo = touchHistory.mostRecentTimeStamp;\n },\n /**\n * @param {object} config Enhanced versions of all of the responder callbacks\n * that provide not only the typical `ResponderSyntheticEvent`, but also the\n * `PanResponder` gesture state. Simply replace the word `Responder` with\n * `PanResponder` in each of the typical `onResponder*` callbacks. For\n * example, the `config` object would look like:\n *\n * - `onMoveShouldSetPanResponder: (e, gestureState) => {...}`\n * - `onMoveShouldSetPanResponderCapture: (e, gestureState) => {...}`\n * - `onStartShouldSetPanResponder: (e, gestureState) => {...}`\n * - `onStartShouldSetPanResponderCapture: (e, gestureState) => {...}`\n * - `onPanResponderReject: (e, gestureState) => {...}`\n * - `onPanResponderGrant: (e, gestureState) => {...}`\n * - `onPanResponderStart: (e, gestureState) => {...}`\n * - `onPanResponderEnd: (e, gestureState) => {...}`\n * - `onPanResponderRelease: (e, gestureState) => {...}`\n * - `onPanResponderMove: (e, gestureState) => {...}`\n * - `onPanResponderTerminate: (e, gestureState) => {...}`\n * - `onPanResponderTerminationRequest: (e, gestureState) => {...}`\n * - `onShouldBlockNativeResponder: (e, gestureState) => {...}`\n *\n * In general, for events that have capture equivalents, we update the\n * gestureState once in the capture phase and can use it in the bubble phase\n * as well.\n *\n * Be careful with onStartShould* callbacks. They only reflect updated\n * `gestureState` for start/end events that bubble/capture to the Node.\n * Once the node is the responder, you can rely on every start/end event\n * being processed by the gesture and `gestureState` being updated\n * accordingly. (numberActiveTouches) may not be totally accurate unless you\n * are the responder.\n */\n create(config) {\n var interactionState = {\n handle: null,\n shouldCancelClick: false,\n timeout: null\n };\n var gestureState = {\n // Useful for debugging\n stateID: Math.random(),\n moveX: 0,\n moveY: 0,\n x0: 0,\n y0: 0,\n dx: 0,\n dy: 0,\n vx: 0,\n vy: 0,\n numberActiveTouches: 0,\n _accountsForMovesUpTo: 0\n };\n var panHandlers = {\n onStartShouldSetResponder(event) {\n return config.onStartShouldSetPanResponder == null ? false : config.onStartShouldSetPanResponder(event, gestureState);\n },\n onMoveShouldSetResponder(event) {\n return config.onMoveShouldSetPanResponder == null ? false : config.onMoveShouldSetPanResponder(event, gestureState);\n },\n onStartShouldSetResponderCapture(event) {\n // TODO: Actually, we should reinitialize the state any time\n // touches.length increases from 0 active to > 0 active.\n if (event.nativeEvent.touches.length === 1) {\n PanResponder._initializeGestureState(gestureState);\n }\n gestureState.numberActiveTouches = event.touchHistory.numberActiveTouches;\n return config.onStartShouldSetPanResponderCapture != null ? config.onStartShouldSetPanResponderCapture(event, gestureState) : false;\n },\n onMoveShouldSetResponderCapture(event) {\n var touchHistory = event.touchHistory;\n // Responder system incorrectly dispatches should* to current responder\n // Filter out any touch moves past the first one - we would have\n // already processed multi-touch geometry during the first event.\n if (gestureState._accountsForMovesUpTo === touchHistory.mostRecentTimeStamp) {\n return false;\n }\n PanResponder._updateGestureStateOnMove(gestureState, touchHistory);\n return config.onMoveShouldSetPanResponderCapture ? config.onMoveShouldSetPanResponderCapture(event, gestureState) : false;\n },\n onResponderGrant(event) {\n if (!interactionState.handle) {\n interactionState.handle = InteractionManager.createInteractionHandle();\n }\n if (interactionState.timeout) {\n clearInteractionTimeout(interactionState);\n }\n interactionState.shouldCancelClick = true;\n gestureState.x0 = currentCentroidX(event.touchHistory);\n gestureState.y0 = currentCentroidY(event.touchHistory);\n gestureState.dx = 0;\n gestureState.dy = 0;\n if (config.onPanResponderGrant) {\n config.onPanResponderGrant(event, gestureState);\n }\n // TODO: t7467124 investigate if this can be removed\n return config.onShouldBlockNativeResponder == null ? true : config.onShouldBlockNativeResponder(event, gestureState);\n },\n onResponderReject(event) {\n clearInteractionHandle(interactionState, config.onPanResponderReject, event, gestureState);\n },\n onResponderRelease(event) {\n clearInteractionHandle(interactionState, config.onPanResponderRelease, event, gestureState);\n setInteractionTimeout(interactionState);\n PanResponder._initializeGestureState(gestureState);\n },\n onResponderStart(event) {\n var touchHistory = event.touchHistory;\n gestureState.numberActiveTouches = touchHistory.numberActiveTouches;\n if (config.onPanResponderStart) {\n config.onPanResponderStart(event, gestureState);\n }\n },\n onResponderMove(event) {\n var touchHistory = event.touchHistory;\n // Guard against the dispatch of two touch moves when there are two\n // simultaneously changed touches.\n if (gestureState._accountsForMovesUpTo === touchHistory.mostRecentTimeStamp) {\n return;\n }\n // Filter out any touch moves past the first one - we would have\n // already processed multi-touch geometry during the first event.\n PanResponder._updateGestureStateOnMove(gestureState, touchHistory);\n if (config.onPanResponderMove) {\n config.onPanResponderMove(event, gestureState);\n }\n },\n onResponderEnd(event) {\n var touchHistory = event.touchHistory;\n gestureState.numberActiveTouches = touchHistory.numberActiveTouches;\n clearInteractionHandle(interactionState, config.onPanResponderEnd, event, gestureState);\n },\n onResponderTerminate(event) {\n clearInteractionHandle(interactionState, config.onPanResponderTerminate, event, gestureState);\n setInteractionTimeout(interactionState);\n PanResponder._initializeGestureState(gestureState);\n },\n onResponderTerminationRequest(event) {\n return config.onPanResponderTerminationRequest == null ? true : config.onPanResponderTerminationRequest(event, gestureState);\n },\n // We do not want to trigger 'click' activated gestures or native behaviors\n // on any pan target that is under a mouse cursor when it is released.\n // Browsers will natively cancel 'click' events on a target if a non-mouse\n // active pointer moves.\n onClickCapture: event => {\n if (interactionState.shouldCancelClick === true) {\n event.stopPropagation();\n event.preventDefault();\n }\n }\n };\n return {\n panHandlers,\n getInteractionHandle() {\n return interactionState.handle;\n }\n };\n }\n};\nfunction clearInteractionHandle(interactionState, callback, event, gestureState) {\n if (interactionState.handle) {\n InteractionManager.clearInteractionHandle(interactionState.handle);\n interactionState.handle = null;\n }\n if (callback) {\n callback(event, gestureState);\n }\n}\nfunction clearInteractionTimeout(interactionState) {\n clearTimeout(interactionState.timeout);\n}\nfunction setInteractionTimeout(interactionState) {\n interactionState.timeout = setTimeout(() => {\n interactionState.shouldCancelClick = false;\n }, 250);\n}\nexport default PanResponder;","/**\n * Copyright (c) Nicolas Gallagher.\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n * \n */\n\n'use client';\n\nimport _extends from \"@babel/runtime/helpers/extends\";\nimport _objectWithoutPropertiesLoose from \"@babel/runtime/helpers/objectWithoutPropertiesLoose\";\nvar _excluded = [\"animating\", \"color\", \"hidesWhenStopped\", \"size\", \"style\"];\nimport * as React from 'react';\nimport StyleSheet from '../StyleSheet';\nimport View from '../View';\nvar createSvgCircle = style => /*#__PURE__*/React.createElement(\"circle\", {\n cx: \"16\",\n cy: \"16\",\n fill: \"none\",\n r: \"14\",\n strokeWidth: \"4\",\n style: style\n});\nvar ActivityIndicator = /*#__PURE__*/React.forwardRef((props, forwardedRef) => {\n var _props$animating = props.animating,\n animating = _props$animating === void 0 ? true : _props$animating,\n _props$color = props.color,\n color = _props$color === void 0 ? '#1976D2' : _props$color,\n _props$hidesWhenStopp = props.hidesWhenStopped,\n hidesWhenStopped = _props$hidesWhenStopp === void 0 ? true : _props$hidesWhenStopp,\n _props$size = props.size,\n size = _props$size === void 0 ? 'small' : _props$size,\n style = props.style,\n other = _objectWithoutPropertiesLoose(props, _excluded);\n var svg = /*#__PURE__*/React.createElement(\"svg\", {\n height: \"100%\",\n viewBox: \"0 0 32 32\",\n width: \"100%\"\n }, createSvgCircle({\n stroke: color,\n opacity: 0.2\n }), createSvgCircle({\n stroke: color,\n strokeDasharray: 80,\n strokeDashoffset: 60\n }));\n return /*#__PURE__*/React.createElement(View, _extends({}, other, {\n \"aria-valuemax\": 1,\n \"aria-valuemin\": 0,\n ref: forwardedRef,\n role: \"progressbar\",\n style: [styles.container, style]\n }), /*#__PURE__*/React.createElement(View, {\n children: svg,\n style: [typeof size === 'number' ? {\n height: size,\n width: size\n } : indicatorSizes[size], styles.animation, !animating && styles.animationPause, !animating && hidesWhenStopped && styles.hidesWhenStopped]\n }));\n});\nActivityIndicator.displayName = 'ActivityIndicator';\nvar styles = StyleSheet.create({\n container: {\n alignItems: 'center',\n justifyContent: 'center'\n },\n hidesWhenStopped: {\n visibility: 'hidden'\n },\n animation: {\n animationDuration: '0.75s',\n animationKeyframes: [{\n '0%': {\n transform: 'rotate(0deg)'\n },\n '100%': {\n transform: 'rotate(360deg)'\n }\n }],\n animationTimingFunction: 'linear',\n animationIterationCount: 'infinite'\n },\n animationPause: {\n animationPlayState: 'paused'\n }\n});\nvar indicatorSizes = StyleSheet.create({\n small: {\n width: 20,\n height: 20\n },\n large: {\n width: 36,\n height: 36\n }\n});\nexport default ActivityIndicator;","/**\n * Copyright (c) Nicolas Gallagher.\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n * \n */\n\n'use client';\n\nimport * as React from 'react';\nimport createElement from '../createElement';\nimport * as forwardedProps from '../../modules/forwardedProps';\nimport pick from '../../modules/pick';\nimport useElementLayout from '../../modules/useElementLayout';\nimport useLayoutEffect from '../../modules/useLayoutEffect';\nimport useMergeRefs from '../../modules/useMergeRefs';\nimport usePlatformMethods from '../../modules/usePlatformMethods';\nimport useResponderEvents from '../../modules/useResponderEvents';\nimport { getLocaleDirection, useLocaleContext } from '../../modules/useLocale';\nimport StyleSheet from '../StyleSheet';\nimport TextInputState from '../../modules/TextInputState';\n//import { warnOnce } from '../../modules/warnOnce';\n\n/**\n * Determines whether a 'selection' prop differs from a node's existing\n * selection state.\n */\nvar isSelectionStale = (node, selection) => {\n var selectionEnd = node.selectionEnd,\n selectionStart = node.selectionStart;\n var start = selection.start,\n end = selection.end;\n return start !== selectionStart || end !== selectionEnd;\n};\n\n/**\n * Certain input types do no support 'selectSelectionRange' and will throw an\n * error.\n */\nvar setSelection = (node, selection) => {\n if (isSelectionStale(node, selection)) {\n var start = selection.start,\n end = selection.end;\n try {\n node.setSelectionRange(start, end || start);\n } catch (e) {}\n }\n};\nvar forwardPropsList = Object.assign({}, forwardedProps.defaultProps, forwardedProps.accessibilityProps, forwardedProps.clickProps, forwardedProps.focusProps, forwardedProps.keyboardProps, forwardedProps.mouseProps, forwardedProps.touchProps, forwardedProps.styleProps, {\n autoCapitalize: true,\n autoComplete: true,\n autoCorrect: true,\n autoFocus: true,\n defaultValue: true,\n disabled: true,\n lang: true,\n maxLength: true,\n onChange: true,\n onScroll: true,\n placeholder: true,\n pointerEvents: true,\n readOnly: true,\n rows: true,\n spellCheck: true,\n value: true,\n type: true\n});\nvar pickProps = props => pick(props, forwardPropsList);\n\n// If an Input Method Editor is processing key input, the 'keyCode' is 229.\n// https://www.w3.org/TR/uievents/#determine-keydown-keyup-keyCode\nfunction isEventComposing(nativeEvent) {\n return nativeEvent.isComposing || nativeEvent.keyCode === 229;\n}\nvar focusTimeout = null;\nvar TextInput = /*#__PURE__*/React.forwardRef((props, forwardedRef) => {\n var _props$autoCapitalize = props.autoCapitalize,\n autoCapitalize = _props$autoCapitalize === void 0 ? 'sentences' : _props$autoCapitalize,\n autoComplete = props.autoComplete,\n autoCompleteType = props.autoCompleteType,\n _props$autoCorrect = props.autoCorrect,\n autoCorrect = _props$autoCorrect === void 0 ? true : _props$autoCorrect,\n blurOnSubmit = props.blurOnSubmit,\n caretHidden = props.caretHidden,\n clearTextOnFocus = props.clearTextOnFocus,\n dir = props.dir,\n editable = props.editable,\n enterKeyHint = props.enterKeyHint,\n inputMode = props.inputMode,\n keyboardType = props.keyboardType,\n _props$multiline = props.multiline,\n multiline = _props$multiline === void 0 ? false : _props$multiline,\n numberOfLines = props.numberOfLines,\n onBlur = props.onBlur,\n onChange = props.onChange,\n onChangeText = props.onChangeText,\n onContentSizeChange = props.onContentSizeChange,\n onFocus = props.onFocus,\n onKeyPress = props.onKeyPress,\n onLayout = props.onLayout,\n onMoveShouldSetResponder = props.onMoveShouldSetResponder,\n onMoveShouldSetResponderCapture = props.onMoveShouldSetResponderCapture,\n onResponderEnd = props.onResponderEnd,\n onResponderGrant = props.onResponderGrant,\n onResponderMove = props.onResponderMove,\n onResponderReject = props.onResponderReject,\n onResponderRelease = props.onResponderRelease,\n onResponderStart = props.onResponderStart,\n onResponderTerminate = props.onResponderTerminate,\n onResponderTerminationRequest = props.onResponderTerminationRequest,\n onScrollShouldSetResponder = props.onScrollShouldSetResponder,\n onScrollShouldSetResponderCapture = props.onScrollShouldSetResponderCapture,\n onSelectionChange = props.onSelectionChange,\n onSelectionChangeShouldSetResponder = props.onSelectionChangeShouldSetResponder,\n onSelectionChangeShouldSetResponderCapture = props.onSelectionChangeShouldSetResponderCapture,\n onStartShouldSetResponder = props.onStartShouldSetResponder,\n onStartShouldSetResponderCapture = props.onStartShouldSetResponderCapture,\n onSubmitEditing = props.onSubmitEditing,\n placeholderTextColor = props.placeholderTextColor,\n _props$readOnly = props.readOnly,\n readOnly = _props$readOnly === void 0 ? false : _props$readOnly,\n returnKeyType = props.returnKeyType,\n rows = props.rows,\n _props$secureTextEntr = props.secureTextEntry,\n secureTextEntry = _props$secureTextEntr === void 0 ? false : _props$secureTextEntr,\n selection = props.selection,\n selectTextOnFocus = props.selectTextOnFocus,\n showSoftInputOnFocus = props.showSoftInputOnFocus,\n spellCheck = props.spellCheck;\n var type;\n var _inputMode;\n if (inputMode != null) {\n _inputMode = inputMode;\n if (inputMode === 'email') {\n type = 'email';\n } else if (inputMode === 'tel') {\n type = 'tel';\n } else if (inputMode === 'search') {\n type = 'search';\n } else if (inputMode === 'url') {\n type = 'url';\n } else {\n type = 'text';\n }\n } else if (keyboardType != null) {\n // warnOnce('keyboardType', 'keyboardType is deprecated. Use inputMode.');\n switch (keyboardType) {\n case 'email-address':\n type = 'email';\n break;\n case 'number-pad':\n case 'numeric':\n _inputMode = 'numeric';\n break;\n case 'decimal-pad':\n _inputMode = 'decimal';\n break;\n case 'phone-pad':\n type = 'tel';\n break;\n case 'search':\n case 'web-search':\n type = 'search';\n break;\n case 'url':\n type = 'url';\n break;\n default:\n type = 'text';\n }\n }\n if (secureTextEntry) {\n type = 'password';\n }\n var dimensions = React.useRef({\n height: null,\n width: null\n });\n var hostRef = React.useRef(null);\n var prevSelection = React.useRef(null);\n var prevSecureTextEntry = React.useRef(false);\n React.useEffect(() => {\n if (hostRef.current && prevSelection.current) {\n setSelection(hostRef.current, prevSelection.current);\n }\n prevSecureTextEntry.current = secureTextEntry;\n }, [secureTextEntry]);\n var handleContentSizeChange = React.useCallback(hostNode => {\n if (multiline && onContentSizeChange && hostNode != null) {\n var newHeight = hostNode.scrollHeight;\n var newWidth = hostNode.scrollWidth;\n if (newHeight !== dimensions.current.height || newWidth !== dimensions.current.width) {\n dimensions.current.height = newHeight;\n dimensions.current.width = newWidth;\n onContentSizeChange({\n nativeEvent: {\n contentSize: {\n height: dimensions.current.height,\n width: dimensions.current.width\n }\n }\n });\n }\n }\n }, [multiline, onContentSizeChange]);\n var imperativeRef = React.useMemo(() => hostNode => {\n // TextInput needs to add more methods to the hostNode in addition to those\n // added by `usePlatformMethods`. This is temporarily until an API like\n // `TextInput.clear(hostRef)` is added to React Native.\n if (hostNode != null) {\n hostNode.clear = function () {\n if (hostNode != null) {\n hostNode.value = '';\n }\n };\n hostNode.isFocused = function () {\n return hostNode != null && TextInputState.currentlyFocusedField() === hostNode;\n };\n handleContentSizeChange(hostNode);\n }\n }, [handleContentSizeChange]);\n function handleBlur(e) {\n TextInputState._currentlyFocusedNode = null;\n if (onBlur) {\n e.nativeEvent.text = e.target.value;\n onBlur(e);\n }\n }\n function handleChange(e) {\n var hostNode = e.target;\n var text = hostNode.value;\n e.nativeEvent.text = text;\n handleContentSizeChange(hostNode);\n if (onChange) {\n onChange(e);\n }\n if (onChangeText) {\n onChangeText(text);\n }\n }\n function handleFocus(e) {\n var hostNode = e.target;\n if (onFocus) {\n e.nativeEvent.text = hostNode.value;\n onFocus(e);\n }\n if (hostNode != null) {\n TextInputState._currentlyFocusedNode = hostNode;\n if (clearTextOnFocus) {\n hostNode.value = '';\n }\n if (selectTextOnFocus) {\n // Safari requires selection to occur in a setTimeout\n if (focusTimeout != null) {\n clearTimeout(focusTimeout);\n }\n focusTimeout = setTimeout(() => {\n // Check if the input is still focused after the timeout\n // (see #2704)\n if (hostNode != null && document.activeElement === hostNode) {\n hostNode.select();\n }\n }, 0);\n }\n }\n }\n function handleKeyDown(e) {\n var hostNode = e.target;\n // Prevent key events bubbling (see #612)\n e.stopPropagation();\n var blurOnSubmitDefault = !multiline;\n var shouldBlurOnSubmit = blurOnSubmit == null ? blurOnSubmitDefault : blurOnSubmit;\n var nativeEvent = e.nativeEvent;\n var isComposing = isEventComposing(nativeEvent);\n if (onKeyPress) {\n onKeyPress(e);\n }\n if (e.key === 'Enter' && !e.shiftKey &&\n // Do not call submit if composition is occuring.\n !isComposing && !e.isDefaultPrevented()) {\n if ((blurOnSubmit || !multiline) && onSubmitEditing) {\n // prevent \"Enter\" from inserting a newline or submitting a form\n e.preventDefault();\n nativeEvent.text = e.target.value;\n onSubmitEditing(e);\n }\n if (shouldBlurOnSubmit && hostNode != null) {\n setTimeout(() => hostNode.blur(), 0);\n }\n }\n }\n function handleSelectionChange(e) {\n try {\n var _e$target = e.target,\n selectionStart = _e$target.selectionStart,\n selectionEnd = _e$target.selectionEnd;\n var _selection = {\n start: selectionStart,\n end: selectionEnd\n };\n if (onSelectionChange) {\n e.nativeEvent.selection = _selection;\n e.nativeEvent.text = e.target.value;\n onSelectionChange(e);\n }\n if (prevSecureTextEntry.current === secureTextEntry) {\n prevSelection.current = _selection;\n }\n } catch (e) {}\n }\n useLayoutEffect(() => {\n var node = hostRef.current;\n if (node != null && selection != null) {\n setSelection(node, selection);\n }\n if (document.activeElement === node) {\n TextInputState._currentlyFocusedNode = node;\n }\n }, [hostRef, selection]);\n var component = multiline ? 'textarea' : 'input';\n useElementLayout(hostRef, onLayout);\n useResponderEvents(hostRef, {\n onMoveShouldSetResponder,\n onMoveShouldSetResponderCapture,\n onResponderEnd,\n onResponderGrant,\n onResponderMove,\n onResponderReject,\n onResponderRelease,\n onResponderStart,\n onResponderTerminate,\n onResponderTerminationRequest,\n onScrollShouldSetResponder,\n onScrollShouldSetResponderCapture,\n onSelectionChangeShouldSetResponder,\n onSelectionChangeShouldSetResponderCapture,\n onStartShouldSetResponder,\n onStartShouldSetResponderCapture\n });\n var _useLocaleContext = useLocaleContext(),\n contextDirection = _useLocaleContext.direction;\n var supportedProps = pickProps(props);\n supportedProps.autoCapitalize = autoCapitalize;\n supportedProps.autoComplete = autoComplete || autoCompleteType || 'on';\n supportedProps.autoCorrect = autoCorrect ? 'on' : 'off';\n // 'auto' by default allows browsers to infer writing direction\n supportedProps.dir = dir !== undefined ? dir : 'auto';\n /*\n if (returnKeyType != null) {\n warnOnce('returnKeyType', 'returnKeyType is deprecated. Use enterKeyHint.');\n }\n */\n supportedProps.enterKeyHint = enterKeyHint || returnKeyType;\n supportedProps.inputMode = _inputMode;\n supportedProps.onBlur = handleBlur;\n supportedProps.onChange = handleChange;\n supportedProps.onFocus = handleFocus;\n supportedProps.onKeyDown = handleKeyDown;\n supportedProps.onSelect = handleSelectionChange;\n /*\n if (editable != null) {\n warnOnce('editable', 'editable is deprecated. Use readOnly.');\n }\n */\n supportedProps.readOnly = readOnly === true || editable === false;\n /*\n if (numberOfLines != null) {\n warnOnce(\n 'numberOfLines',\n 'TextInput numberOfLines is deprecated. Use rows.'\n );\n }\n */\n supportedProps.rows = multiline ? rows != null ? rows : numberOfLines : 1;\n supportedProps.spellCheck = spellCheck != null ? spellCheck : autoCorrect;\n supportedProps.style = [{\n '--placeholderTextColor': placeholderTextColor\n }, styles.textinput$raw, styles.placeholder, props.style, caretHidden && styles.caretHidden];\n supportedProps.type = multiline ? undefined : type;\n supportedProps.virtualkeyboardpolicy = showSoftInputOnFocus === false ? 'manual' : 'auto';\n var platformMethodsRef = usePlatformMethods(supportedProps);\n var setRef = useMergeRefs(hostRef, platformMethodsRef, imperativeRef, forwardedRef);\n supportedProps.ref = setRef;\n var langDirection = props.lang != null ? getLocaleDirection(props.lang) : null;\n var componentDirection = props.dir || langDirection;\n var writingDirection = componentDirection || contextDirection;\n var element = createElement(component, supportedProps, {\n writingDirection\n });\n return element;\n});\nTextInput.displayName = 'TextInput';\n// $FlowFixMe\nTextInput.State = TextInputState;\nvar styles = StyleSheet.create({\n textinput$raw: {\n MozAppearance: 'textfield',\n WebkitAppearance: 'none',\n backgroundColor: 'transparent',\n border: '0 solid black',\n borderRadius: 0,\n boxSizing: 'border-box',\n font: '14px System',\n margin: 0,\n padding: 0,\n resize: 'none'\n },\n placeholder: {\n placeholderTextColor: 'var(--placeholderTextColor)'\n },\n caretHidden: {\n caretColor: 'transparent'\n }\n});\nexport default TextInput;","import { createContextScope } from \"@tamagui/create-context\";\nimport { SHEET_NAME } from \"./constants.mjs\";\nconst [createSheetContext, createSheetScope] = createContextScope(SHEET_NAME),\n [SheetProvider, useSheetContext] = createSheetContext(SHEET_NAME, {});\nexport { SheetProvider, createSheetContext, createSheetScope, useSheetContext };\n//# sourceMappingURL=SheetContext.mjs.map\n","import React from \"react\";\nconst ParentSheetContext = React.createContext({\n zIndex: 1e5\n }),\n SheetInsideSheetContext = React.createContext(null);\nexport { ParentSheetContext, SheetInsideSheetContext };\n//# sourceMappingURL=contexts.mjs.map\n","function resisted(y, minY, maxOverflow = 25) {\n if (y >= minY) return y;\n const pastBoundary = minY - y,\n resistedDistance = Math.sqrt(pastBoundary) * 2;\n return minY - resistedDistance;\n}\nexport { resisted };\n//# sourceMappingURL=helpers.mjs.map\n","import React from \"react\";\nconst useSheetController = () => {\n const controller = React.useContext(SheetControllerContext),\n isHidden = controller?.hidden,\n isShowingNonSheet = isHidden && controller?.open;\n return {\n controller,\n isHidden,\n isShowingNonSheet,\n disableDrag: controller?.disableDrag\n };\n },\n SheetControllerContext = React.createContext(null);\nexport { SheetControllerContext, useSheetController };\n//# sourceMappingURL=useSheetController.mjs.map\n","import { useControllableState } from \"@tamagui/use-controllable-state\";\nimport { useSheetController } from \"./useSheetController.mjs\";\nconst useSheetOpenState = props => {\n const {\n isHidden,\n controller\n } = useSheetController(),\n onOpenChangeInternal = val => {\n controller?.onOpenChange?.(val), props.onOpenChange?.(val);\n },\n [open, setOpen] = useControllableState({\n prop: controller?.open ?? props.open,\n defaultProp: props.defaultOpen ?? !1,\n onChange: onOpenChangeInternal,\n strategy: \"most-recent-wins\",\n transition: !0\n });\n return {\n open,\n setOpen,\n isHidden,\n controller\n };\n};\nexport { useSheetOpenState };\n//# sourceMappingURL=useSheetOpenState.mjs.map\n","import React from \"react\";\nimport { useConfiguration } from \"@tamagui/core\";\nimport { useConstant } from \"@tamagui/use-constant\";\nimport { useControllableState } from \"@tamagui/use-controllable-state\";\nfunction useSheetProviderProps(props, state, options = {}) {\n const handleRef = React.useRef(null),\n contentRef = React.useRef(null),\n [frameSize, setFrameSize] = React.useState(0),\n [maxContentSize, setMaxContentSize] = React.useState(0),\n snapPointsMode = props.snapPointsMode ?? \"percent\",\n snapPointsProp = props.snapPoints ?? (snapPointsMode === \"percent\" ? [80] : snapPointsMode === \"constant\" ? [256] : [\"fit\"]),\n hasFit = snapPointsProp[0] === \"fit\",\n snapPoints = React.useMemo(() => props.dismissOnSnapToBottom ? [...snapPointsProp, 0] : snapPointsProp, [JSON.stringify(snapPointsProp), props.dismissOnSnapToBottom]),\n [position_, setPositionImmediate] = useControllableState({\n prop: props.position,\n defaultProp: props.defaultPosition || (state.open ? 0 : -1),\n onChange: props.onPositionChange,\n strategy: \"most-recent-wins\",\n transition: !0\n }),\n position = state.open === !1 ? -1 : position_,\n {\n open\n } = state,\n setPosition = React.useCallback(next => {\n props.dismissOnSnapToBottom && next === snapPoints.length - 1 ? state.setOpen(!1) : setPositionImmediate(next);\n }, [props.dismissOnSnapToBottom, snapPoints.length, setPositionImmediate, state.setOpen]);\n process.env.NODE_ENV === \"development\" && (snapPointsMode === \"mixed\" && snapPoints.some(p => {\n if (typeof p == \"string\") {\n if (p === \"fit\") return !1;\n if (p.endsWith(\"%\")) {\n const n = Number(p.slice(0, -1));\n return n < 0 || n > 100;\n }\n return !0;\n }\n return typeof p != \"number\" || p < 0;\n }) && console.warn('\\u26A0\\uFE0F Invalid snapPoint given, snapPoints must be positive numeric values, string percentages between 0-100%, or \"fit\" when snapPointsMode is mixed'), snapPointsMode === \"mixed\" && snapPoints.indexOf(\"fit\") > 0 && console.warn('\\u26A0\\uFE0F Invalid snapPoint given, \"fit\" must be the first/largest snap point when snapPointsMode is mixed'), snapPointsMode === \"fit\" && (snapPoints.length !== (props.dismissOnSnapToBottom ? 2 : 1) || snapPoints[0] !== \"fit\") && console.warn(\"\\u26A0\\uFE0F Invalid snapPoint given, there are no snap points when snapPointsMode is fit\"), snapPointsMode === \"constant\" && snapPoints.some(p => typeof p != \"number\" || p < 0) && console.warn(\"\\u26A0\\uFE0F Invalid snapPoint given, snapPoints must be positive numeric values when snapPointsMode is constant\"), snapPointsMode === \"percent\" && snapPoints.some(p => typeof p != \"number\" || p < 0 || p > 100) && console.warn(\"\\u26A0\\uFE0F Invalid snapPoint given, snapPoints must be numeric values between 0 and 100 when snapPointsMode is percent\")), open && props.dismissOnSnapToBottom && position === snapPoints.length - 1 && setPositionImmediate(0);\n const shouldSetPositionOpen = open && position < 0;\n React.useEffect(() => {\n shouldSetPositionOpen && setPosition(0);\n }, [setPosition, shouldSetPositionOpen]);\n const {\n animationDriver\n } = useConfiguration();\n if (!animationDriver) throw new Error(process.env.NODE_ENV === \"production\" ? \"\\u274C 008\" : \"Must set animations in tamagui.config.ts\");\n const scrollBridge = useConstant(() => ({\n enabled: !1,\n y: 0,\n paneY: 0,\n paneMinY: 0,\n scrollStartY: -1,\n drag: () => {},\n release: () => {},\n scrollLock: !1\n })),\n removeScrollEnabled = props.forceRemoveScrollEnabled ?? (open && props.modal),\n maxSnapPoint = snapPoints[0];\n return {\n screenSize: snapPointsMode === \"percent\" ? frameSize / ((typeof maxSnapPoint == \"number\" ? maxSnapPoint : 100) / 100) : maxContentSize,\n maxSnapPoint,\n removeScrollEnabled,\n scrollBridge,\n modal: !!props.modal,\n open: state.open,\n setOpen: state.setOpen,\n hidden: !!state.isHidden,\n contentRef,\n handleRef,\n frameSize,\n setFrameSize,\n dismissOnOverlayPress: props.dismissOnOverlayPress ?? !0,\n dismissOnSnapToBottom: props.dismissOnSnapToBottom ?? !1,\n onOverlayComponent: options.onOverlayComponent,\n scope: props.__scopeSheet,\n hasFit,\n position,\n snapPoints,\n snapPointsMode,\n setMaxContentSize,\n setPosition,\n setPositionImmediate,\n onlyShowFrame: !1\n };\n}\nexport { useSheetProviderProps };\n//# sourceMappingURL=useSheetProviderProps.mjs.map\n","import { AnimatePresence } from \"@tamagui/animate-presence\";\nimport { useComposedRefs } from \"@tamagui/compose-refs\";\nimport { currentPlatform, isClient, isWeb, useIsomorphicLayoutEffect } from \"@tamagui/constants\";\nimport { Stack, Theme, useConfiguration, useDidFinishSSR, useEvent, useThemeName } from \"@tamagui/core\";\nimport { Portal, USE_NATIVE_PORTAL } from \"@tamagui/portal\";\nimport React, { useRef, useState } from \"react\";\nimport { Dimensions, Keyboard, PanResponder, View } from \"react-native-web\";\nimport { ParentSheetContext, SheetInsideSheetContext } from \"./contexts.mjs\";\nimport { resisted } from \"./helpers.mjs\";\nimport { SheetProvider } from \"./SheetContext.mjs\";\nimport { useSheetOpenState } from \"./useSheetOpenState.mjs\";\nimport { useSheetProviderProps } from \"./useSheetProviderProps.mjs\";\nimport { jsx, jsxs } from \"react/jsx-runtime\";\nconst hiddenSize = 10000.1;\nlet sheetHiddenStyleSheet = null;\nconst relativeDimensionTo = isWeb ? \"window\" : \"screen\",\n SheetImplementationCustom = React.forwardRef(function (props, forwardedRef) {\n const parentSheet = React.useContext(ParentSheetContext),\n {\n animation,\n animationConfig: animationConfigProp,\n modal = !1,\n zIndex = parentSheet.zIndex + 1,\n moveOnKeyboardChange = !1,\n unmountChildrenWhenHidden = !1,\n portalProps,\n containerComponent: ContainerComponent = React.Fragment\n } = props,\n state = useSheetOpenState(props),\n [overlayComponent, setOverlayComponent] = React.useState(null),\n providerProps = useSheetProviderProps(props, state, {\n onOverlayComponent: setOverlayComponent\n }),\n {\n frameSize,\n setFrameSize,\n snapPoints,\n snapPointsMode,\n hasFit,\n position,\n setPosition,\n scrollBridge,\n screenSize,\n setMaxContentSize,\n maxSnapPoint\n } = providerProps,\n {\n open,\n controller,\n isHidden\n } = state,\n sheetRef = React.useRef(null),\n ref = useComposedRefs(forwardedRef, sheetRef, providerProps.contentRef),\n {\n animationDriver\n } = useConfiguration(),\n animationConfig = (() => {\n if (animationDriver.supportsCSSVars) return {};\n const [animationProp, animationPropConfig] = animation ? Array.isArray(animation) ? animation : [animation] : [];\n return animationConfigProp ?? (animationProp ? {\n ...animationDriver.animations[animationProp],\n ...animationPropConfig\n } : null);\n })(),\n [isShowingInnerSheet, setIsShowingInnerSheet] = React.useState(!1),\n shouldHideParentSheet = !isWeb && modal && isShowingInnerSheet &&\n // if not using weird portal limitation we dont need to hide parent sheet\n USE_NATIVE_PORTAL,\n sheetInsideSheet = React.useContext(SheetInsideSheetContext),\n onInnerSheet = React.useCallback(hasChild => {\n setIsShowingInnerSheet(hasChild);\n }, []),\n positions = React.useMemo(() => snapPoints.map(point => getYPositions(snapPointsMode, point, screenSize, frameSize)), [screenSize, frameSize, snapPoints, snapPointsMode]),\n {\n useAnimatedNumber,\n useAnimatedNumberStyle,\n useAnimatedNumberReaction\n } = animationDriver,\n AnimatedView = animationDriver.View ?? Stack;\n useIsomorphicLayoutEffect(() => {\n if (sheetInsideSheet && open) return sheetInsideSheet(!0), () => {\n sheetInsideSheet(!1);\n };\n }, [sheetInsideSheet, open]);\n const nextParentContext = React.useMemo(() => ({\n zIndex\n }), [zIndex]),\n startPosition = useDidFinishSSR() && screenSize ? screenSize : hiddenSize,\n animatedNumber = useAnimatedNumber(startPosition),\n at = React.useRef(startPosition),\n hasntMeasured = at.current === hiddenSize,\n [disableAnimation, setDisableAnimation] = useState(hasntMeasured),\n hasScrollView = React.useRef(!1);\n useAnimatedNumberReaction({\n value: animatedNumber,\n hostRef: sheetRef\n }, React.useCallback(value => {\n at.current = value, scrollBridge.paneY = value;\n }, [animationDriver]));\n function stopSpring() {\n animatedNumber.stop(), scrollBridge.onFinishAnimate && (scrollBridge.onFinishAnimate(), scrollBridge.onFinishAnimate = void 0);\n }\n const animateTo = useEvent(position2 => {\n if (frameSize === 0) return;\n let toValue = isHidden || position2 === -1 ? screenSize : positions[position2];\n at.current !== toValue && (at.current = toValue, stopSpring(), animatedNumber.setValue(toValue, {\n type: \"spring\",\n ...animationConfig\n }));\n });\n useIsomorphicLayoutEffect(() => {\n if (hasntMeasured && screenSize) {\n at.current = screenSize, animatedNumber.setValue(screenSize, {\n type: \"timing\",\n duration: 0\n }, () => {\n setTimeout(() => {\n setDisableAnimation(!1);\n }, 10);\n });\n return;\n }\n disableAnimation || !frameSize || !screenSize || isHidden || hasntMeasured && !open || animateTo(position);\n }, [hasntMeasured, disableAnimation, isHidden, frameSize, screenSize, open, position]);\n const disableDrag = props.disableDrag ?? controller?.disableDrag,\n themeName = useThemeName(),\n [isDragging, setIsDragging] = React.useState(!1),\n scrollEnabled = useRef(!0),\n setScrollEnabled = React.useCallback(val => {\n scrollEnabled.current = val;\n }, []),\n panResponder = React.useMemo(() => {\n if (disableDrag || !frameSize || isShowingInnerSheet) return;\n const minY = positions[0];\n scrollBridge.paneMinY = minY;\n let startY = at.current;\n function setPanning(val) {\n setIsDragging(val), isClient && (sheetHiddenStyleSheet || (sheetHiddenStyleSheet = document.createElement(\"style\"), typeof document.head < \"u\" && document.head.appendChild(sheetHiddenStyleSheet)), val ? sheetHiddenStyleSheet.innerText = \":root * { user-select: none !important; -webkit-user-select: none !important; }\" : sheetHiddenStyleSheet.innerText = \"\");\n }\n const release = ({\n vy,\n dragAt\n }) => {\n isExternalDrag = !1, previouslyScrolling = !1, setPanning(!1);\n const end = dragAt + startY + frameSize * vy * 0.2;\n let closestPoint = 0,\n dist = Number.POSITIVE_INFINITY;\n for (let i = 0; i < positions.length; i++) {\n const position2 = positions[i],\n curDist = end > position2 ? end - position2 : position2 - end;\n curDist < dist && (dist = curDist, closestPoint = i);\n }\n setPosition(closestPoint), animateTo(closestPoint), setScrollEnabled(closestPoint === 0 && dragAt <= 0);\n },\n finish = (_e, state2) => {\n release({\n vy: state2.vy,\n dragAt: state2.dy\n });\n };\n let previouslyScrolling = !1;\n const onMoveShouldSet = (e, {\n dy\n }) => {\n if (e.target === providerProps.handleRef.current || !scrollEnabled.current) return !0;\n const isScrolled = scrollBridge.y !== 0,\n isDraggingUp = dy < 0,\n isNearTop = scrollBridge.paneY - 5 <= scrollBridge.paneMinY;\n return isScrolled ? (previouslyScrolling = !0, !1) : isNearTop && scrollEnabled.current && hasScrollView.current && isDraggingUp ? !1 : Math.abs(dy) > 10;\n },\n grant = () => {\n setScrollEnabled(!1), setPanning(!0), stopSpring(), startY = at.current;\n };\n let isExternalDrag = !1;\n return scrollBridge.drag = dy => {\n isExternalDrag || (isExternalDrag = !0, grant());\n const to = dy + startY;\n animatedNumber.setValue(resisted(to, minY), {\n type: \"direct\"\n });\n }, scrollBridge.release = release, PanResponder.create({\n onMoveShouldSetPanResponder: onMoveShouldSet,\n onPanResponderGrant: grant,\n onPanResponderMove: (_e, {\n dy\n }) => {\n const toFull = dy + startY,\n to = resisted(toFull, minY);\n animatedNumber.setValue(to, {\n type: \"direct\"\n });\n },\n onPanResponderEnd: finish,\n onPanResponderTerminate: finish,\n onPanResponderRelease: finish\n });\n }, [disableDrag, isShowingInnerSheet, animateTo, frameSize, positions, setPosition]),\n handleAnimationViewLayout = React.useCallback(e => {\n const next = Math.min(e.nativeEvent?.layout.height, Dimensions.get(relativeDimensionTo).height);\n next && setFrameSize(next);\n }, []),\n handleMaxContentViewLayout = React.useCallback(e => {\n const next = Math.min(e.nativeEvent?.layout.height, Dimensions.get(relativeDimensionTo).height);\n next && setMaxContentSize(next);\n }, []),\n animatedStyle = useAnimatedNumberStyle(animatedNumber, val => {\n \"worklet\";\n\n return {\n transform: [{\n translateY: frameSize === 0 ? hiddenSize : val\n }]\n };\n }),\n sizeBeforeKeyboard = React.useRef(null);\n React.useEffect(() => {\n if (isWeb || !moveOnKeyboardChange) return;\n const keyboardShowListener = Keyboard.addListener(currentPlatform === \"ios\" ? \"keyboardWillShow\" : \"keyboardDidShow\", e => {\n sizeBeforeKeyboard.current === null && (sizeBeforeKeyboard.current = isHidden || position === -1 ? screenSize : positions[position], animatedNumber.setValue(Math.max(sizeBeforeKeyboard.current - e.endCoordinates.height, 0), {\n type: \"timing\",\n duration: 250\n }));\n }),\n keyboardDidHideListener = Keyboard.addListener(\"keyboardDidHide\", () => {\n sizeBeforeKeyboard.current !== null && (animatedNumber.setValue(sizeBeforeKeyboard.current, {\n type: \"timing\",\n duration: 250\n }), sizeBeforeKeyboard.current = null);\n });\n return () => {\n keyboardDidHideListener.remove(), keyboardShowListener.remove();\n };\n }, [moveOnKeyboardChange, positions, position, isHidden]);\n const [opacity, setOpacity] = React.useState(open ? 1 : 0);\n open && opacity === 0 && setOpacity(1), React.useEffect(() => {\n if (!open) {\n const tm = setTimeout(() => {\n setOpacity(0);\n }, 400);\n return () => {\n clearTimeout(tm);\n };\n }\n }, [open]);\n const forcedContentHeight = hasFit ? void 0 : snapPointsMode === \"percent\" ? `${maxSnapPoint}${isWeb ? \"dvh\" : \"%\"}` : maxSnapPoint,\n setHasScrollView = React.useCallback(val => {\n hasScrollView.current = val;\n }, []);\n let contents = /* @__PURE__ */jsx(ParentSheetContext.Provider, {\n value: nextParentContext,\n children: /* @__PURE__ */jsxs(SheetProvider, {\n ...providerProps,\n scrollEnabled: scrollEnabled.current,\n setHasScrollView,\n children: [/* @__PURE__ */jsx(AnimatePresence, {\n custom: {\n open\n },\n children: shouldHideParentSheet || !open ? null : overlayComponent\n }), snapPointsMode !== \"percent\" && /* @__PURE__ */jsx(View, {\n style: {\n opacity: 0,\n position: \"absolute\",\n top: 0,\n left: 0,\n right: 0,\n bottom: 0,\n pointerEvents: \"none\"\n },\n onLayout: handleMaxContentViewLayout\n }), /* @__PURE__ */jsx(AnimatedView, {\n ref,\n ...panResponder?.panHandlers,\n onLayout: handleAnimationViewLayout,\n ...(!isDragging && {\n // @ts-ignore for CSS driver this is necessary to attach the transition\n animation: disableAnimation ? null : animation\n }),\n disableClassName: !0,\n style: [{\n position: \"absolute\",\n zIndex,\n width: \"100%\",\n height: forcedContentHeight,\n minHeight: forcedContentHeight,\n opacity: shouldHideParentSheet ? 0 : opacity,\n ...((shouldHideParentSheet || !open) && {\n pointerEvents: \"none\"\n })\n }, animatedStyle],\n children: props.children\n })]\n })\n });\n const shouldMountChildren = unmountChildrenWhenHidden ? !!opacity : !0;\n if (modal) {\n const modalContents = /* @__PURE__ */jsx(Portal, {\n stackZIndex: zIndex,\n ...portalProps,\n children: shouldMountChildren && /* @__PURE__ */jsx(ContainerComponent, {\n children: /* @__PURE__ */jsx(Theme, {\n forceClassName: !0,\n name: themeName,\n children: contents\n })\n })\n });\n return isWeb ? modalContents : /* @__PURE__ */jsx(SheetInsideSheetContext.Provider, {\n value: onInnerSheet,\n children: modalContents\n });\n }\n return contents;\n });\nfunction getYPositions(mode, point, screenSize, frameSize) {\n if (!screenSize || !frameSize) return 0;\n if (mode === \"mixed\") {\n if (typeof point == \"number\") return screenSize - Math.min(screenSize, Math.max(0, point));\n if (point === \"fit\") return screenSize - Math.min(screenSize, frameSize);\n if (point.endsWith(\"%\")) {\n const pct2 = Math.min(100, Math.max(0, Number(point.slice(0, -1)))) / 100;\n return Number.isNaN(pct2) ? (console.warn(\"Invalid snapPoint percentage string\"), 0) : Math.round(screenSize - pct2 * screenSize);\n }\n return console.warn(\"Invalid snapPoint unknown value\"), 0;\n }\n if (mode === \"fit\") return point === 0 ? screenSize : screenSize - Math.min(screenSize, frameSize);\n if (mode === \"constant\" && typeof point == \"number\") return screenSize - Math.min(screenSize, Math.max(0, point));\n const pct = Math.min(100, Math.max(0, Number(point))) / 100;\n return Number.isNaN(pct) ? (console.warn(\"Invalid snapPoint percentage\"), 0) : Math.round(screenSize - pct * screenSize);\n}\nexport { SheetImplementationCustom };\n//# sourceMappingURL=SheetImplementationCustom.mjs.map\n","import { fullscreenStyle } from \"@tamagui/stacks\";\nimport { styled } from \"@tamagui/web\";\nimport { ScrollView as ScrollViewNative } from \"react-native-web\";\nconst ScrollView = styled(ScrollViewNative, {\n name: \"ScrollView\",\n scrollEnabled: !0,\n variants: {\n fullscreen: {\n true: fullscreenStyle\n }\n }\n}, {\n accept: {\n contentContainerStyle: \"style\"\n }\n});\nexport { ScrollView };\n//# sourceMappingURL=ScrollView.mjs.map\n","import React, { useEffect } from \"react\";\nimport { composeRefs } from \"@tamagui/compose-refs\";\nimport { ScrollView } from \"@tamagui/scroll-view\";\nimport { useSheetContext } from \"./SheetContext.mjs\";\nimport { jsx } from \"react/jsx-runtime\";\nconst SHEET_SCROLL_VIEW_NAME = \"SheetScrollView\",\n SheetScrollView = React.forwardRef(({\n __scopeSheet,\n children,\n onScroll,\n scrollEnabled,\n ...props\n }, ref) => {\n const context = useSheetContext(SHEET_SCROLL_VIEW_NAME, __scopeSheet),\n {\n scrollBridge,\n scrollEnabled: scrollEnabled_,\n setHasScrollView\n } = context,\n scrollRef = React.useRef(null),\n state = React.useRef({\n lastPageY: 0,\n dragAt: 0,\n dys: [],\n // store a few recent dys to get velocity on release\n isScrolling: !1,\n isDragging: !1\n });\n useEffect(() => (setHasScrollView(!0), () => {\n setHasScrollView(!1);\n }), []);\n const release = () => {\n if (!state.current.isDragging) return;\n state.current.isDragging = !1, scrollBridge.scrollStartY = -1, state.current.isScrolling = !1;\n let vy = 0;\n if (state.current.dys.length) {\n const recentDys = state.current.dys.slice(-10);\n vy = (recentDys.length ? recentDys.reduce((a, b) => a + b, 0) : 0) / recentDys.length * 0.04;\n }\n state.current.dys = [], scrollBridge.release({\n dragAt: state.current.dragAt,\n vy\n });\n },\n scrollable = scrollEnabled ?? scrollEnabled_;\n return /* @__PURE__ */jsx(ScrollView, {\n ref: composeRefs(scrollRef, ref),\n flex: 1,\n scrollEventThrottle: 8,\n onResponderRelease: release,\n className: \"_ovs-contain\",\n scrollEnabled: scrollable,\n onScroll: e => {\n const {\n y\n } = e.nativeEvent.contentOffset;\n scrollBridge.y = y, y > 0 && (scrollBridge.scrollStartY = -1), onScroll?.(e);\n },\n onStartShouldSetResponder: () => (scrollBridge.scrollStartY = -1, state.current.isDragging = !0, scrollable),\n onMoveShouldSetResponder: () => scrollable,\n ...props,\n children\n });\n });\nexport { SheetScrollView };\n//# sourceMappingURL=SheetScrollView.mjs.map\n","const useSheetOffscreenSize = ({\n snapPoints,\n position,\n screenSize,\n frameSize,\n snapPointsMode\n}) => {\n if (snapPointsMode === \"fit\") return 0;\n if (snapPointsMode === \"constant\") {\n const maxSize2 = Number(snapPoints[0]),\n currentSize2 = Number(snapPoints[position] ?? 0);\n return maxSize2 - currentSize2;\n }\n if (snapPointsMode === \"percent\") {\n const maxPercentOpened = Number(snapPoints[0]) / 100,\n percentOpened = Number(snapPoints[position] ?? 0) / 100;\n return (maxPercentOpened - percentOpened) * screenSize;\n }\n const maxSnapPoint = snapPoints[0];\n if (maxSnapPoint === \"fit\") return 0;\n const maxSize = typeof maxSnapPoint == \"string\" ? Number(maxSnapPoint.slice(0, -1)) / 100 * screenSize : maxSnapPoint,\n currentSnapPoint = snapPoints[position] ?? 0,\n currentSize = typeof currentSnapPoint == \"string\" ? Number(currentSnapPoint.slice(0, -1)) / 100 * screenSize : currentSnapPoint,\n offscreenSize = maxSize - currentSize;\n return Number.isNaN(offscreenSize) ? 0 : offscreenSize;\n};\nexport { useSheetOffscreenSize };\n//# sourceMappingURL=useSheetOffscreenSize.mjs.map\n","import { useComposedRefs } from \"@tamagui/compose-refs\";\nimport { useIsomorphicLayoutEffect } from \"@tamagui/constants\";\nimport { Stack } from \"@tamagui/core\";\nimport { composeEventHandlers, withStaticProperties } from \"@tamagui/helpers\";\nimport { resolveViewZIndex } from \"@tamagui/portal\";\nimport { RemoveScroll } from \"@tamagui/remove-scroll\";\nimport { useDidFinishSSR } from \"@tamagui/use-did-finish-ssr\";\nimport { StackZIndexContext } from \"@tamagui/z-index-stack\";\nimport { forwardRef, memo, useMemo } from \"react\";\nimport { Platform } from \"react-native-web\";\nimport { SHEET_HANDLE_NAME, SHEET_NAME, SHEET_OVERLAY_NAME } from \"./constants.mjs\";\nimport { useSheetContext } from \"./SheetContext.mjs\";\nimport { SheetImplementationCustom } from \"./SheetImplementationCustom.mjs\";\nimport { SheetScrollView } from \"./SheetScrollView.mjs\";\nimport { useSheetController } from \"./useSheetController.mjs\";\nimport { useSheetOffscreenSize } from \"./useSheetOffscreenSize.mjs\";\nimport { Fragment, jsx, jsxs } from \"react/jsx-runtime\";\nfunction createSheet({\n Handle,\n Frame,\n Overlay\n}) {\n const SheetHandle = Handle.styleable(({\n __scopeSheet,\n ...props\n }, forwardedRef) => {\n const context = useSheetContext(SHEET_HANDLE_NAME, __scopeSheet),\n composedRef = useComposedRefs(context.handleRef, forwardedRef);\n return context.onlyShowFrame ? null :\n // @ts-ignore\n /* @__PURE__ */\n jsx(Handle, {\n ref: composedRef,\n onPress: () => {\n const max = context.snapPoints.length + (context.dismissOnSnapToBottom ? -1 : 0),\n nextPos = (context.position + 1) % max;\n context.setPosition(nextPos);\n },\n open: context.open,\n ...props\n });\n }),\n SheetOverlay = Overlay.extractable(memo(propsIn => {\n const {\n __scopeSheet,\n ...props\n } = propsIn,\n context = useSheetContext(SHEET_OVERLAY_NAME, __scopeSheet),\n element = useMemo(() =>\n // @ts-ignore\n /* @__PURE__ */\n jsx(Overlay, {\n ...props,\n onPress: composeEventHandlers(props.onPress, context.dismissOnOverlayPress ? () => {\n context.setOpen(!1);\n } : void 0)\n }), [props.onPress, props.opacity, context.dismissOnOverlayPress]);\n return useIsomorphicLayoutEffect(() => {\n context.onOverlayComponent?.(element);\n }, [element]), context.onlyShowFrame, null;\n })),\n SheetFrame = Frame.extractable(forwardRef(({\n __scopeSheet,\n adjustPaddingForOffscreenContent,\n disableHideBottomOverflow,\n children,\n ...props\n }, forwardedRef) => {\n const context = useSheetContext(SHEET_NAME, __scopeSheet),\n {\n hasFit,\n removeScrollEnabled,\n frameSize,\n contentRef,\n open\n } = context,\n composedContentRef = useComposedRefs(forwardedRef, contentRef),\n offscreenSize = useSheetOffscreenSize(context),\n sheetContents = useMemo(() =>\n // @ts-expect-error\n /* @__PURE__ */\n jsxs(Frame, {\n ref: composedContentRef,\n flex: hasFit ? 0 : 1,\n height: hasFit ? void 0 : frameSize,\n pointerEvents: open ? \"auto\" : \"none\",\n ...props,\n children: [/* @__PURE__ */jsx(StackZIndexContext, {\n zIndex: resolveViewZIndex(props.zIndex),\n children\n }), adjustPaddingForOffscreenContent && /* @__PURE__ */jsx(Stack, {\n \"data-sheet-offscreen-pad\": !0,\n height: offscreenSize,\n width: \"100%\"\n })]\n }), [open, props, frameSize, offscreenSize, adjustPaddingForOffscreenContent, hasFit]);\n return /* @__PURE__ */jsxs(Fragment, {\n children: [/* @__PURE__ */jsx(RemoveScroll, {\n forwardProps: !0,\n enabled: removeScrollEnabled,\n allowPinchZoom: !0,\n shards: [contentRef],\n removeScrollBar: !1,\n children: sheetContents\n }), !disableHideBottomOverflow &&\n // @ts-ignore\n /* @__PURE__ */\n jsx(Frame, {\n ...props,\n componentName: \"SheetCover\",\n children: null,\n position: \"absolute\",\n bottom: \"-100%\",\n zIndex: -1,\n height: context.frameSize,\n left: 0,\n right: 0,\n borderWidth: 0,\n borderRadius: 0,\n shadowOpacity: 0\n })]\n });\n })),\n Sheet = forwardRef(function (props, ref) {\n const hydrated = useDidFinishSSR(),\n {\n isShowingNonSheet\n } = useSheetController();\n let SheetImplementation = SheetImplementationCustom;\n return props.native && Platform.OS, isShowingNonSheet || !hydrated ? null : /* @__PURE__ */jsx(SheetImplementation, {\n ref,\n ...props\n });\n }),\n components = {\n Frame: SheetFrame,\n Overlay: SheetOverlay,\n Handle: SheetHandle,\n ScrollView: SheetScrollView\n },\n Controlled = withStaticProperties(Sheet, components);\n return withStaticProperties(Sheet, {\n ...components,\n Controlled\n });\n}\nexport { createSheet };\n//# sourceMappingURL=createSheet.mjs.map\n","import { styled } from \"@tamagui/core\";\nimport { ThemeableStack, XStack, YStack } from \"@tamagui/stacks\";\nimport { SHEET_HANDLE_NAME, SHEET_NAME, SHEET_OVERLAY_NAME } from \"./constants.mjs\";\nimport { createSheet } from \"./createSheet.mjs\";\nimport { createSheetScope } from \"./SheetContext.mjs\";\nexport * from \"./types.mjs\";\nconst Handle = styled(XStack, {\n name: SHEET_HANDLE_NAME,\n variants: {\n open: {\n true: {\n opacity: 1,\n pointerEvents: \"auto\"\n },\n false: {\n opacity: 0,\n pointerEvents: \"none\"\n }\n },\n unstyled: {\n false: {\n height: 10,\n borderRadius: 100,\n backgroundColor: \"$background\",\n zIndex: 10,\n marginHorizontal: \"35%\",\n marginBottom: \"$2\",\n opacity: 0.5,\n hoverStyle: {\n opacity: 0.7\n }\n }\n }\n },\n defaultVariants: {\n unstyled: process.env.TAMAGUI_HEADLESS === \"1\"\n }\n }),\n Overlay = styled(ThemeableStack, {\n name: SHEET_OVERLAY_NAME,\n variants: {\n open: {\n true: {\n pointerEvents: \"auto\"\n },\n false: {\n pointerEvents: \"none\"\n }\n },\n unstyled: {\n false: {\n fullscreen: !0,\n position: \"absolute\",\n backgrounded: !0,\n zIndex: 99999,\n pointerEvents: \"auto\"\n }\n }\n },\n defaultVariants: {\n unstyled: process.env.TAMAGUI_HEADLESS === \"1\"\n }\n }),\n Frame = styled(YStack, {\n name: SHEET_NAME,\n variants: {\n unstyled: {\n false: {\n flex: 1,\n backgroundColor: \"$background\",\n borderTopLeftRadius: \"$true\",\n borderTopRightRadius: \"$true\",\n width: \"100%\",\n maxHeight: \"100%\",\n overflow: \"hidden\"\n }\n }\n },\n defaultVariants: {\n unstyled: process.env.TAMAGUI_HEADLESS === \"1\"\n }\n }),\n Sheet = createSheet({\n Frame,\n Handle,\n Overlay\n }),\n SheetOverlayFrame = Overlay,\n SheetHandleFrame = Handle;\nexport { Frame, Handle, Overlay, Sheet, SheetHandleFrame, SheetOverlayFrame, createSheetScope };\n//# sourceMappingURL=Sheet.mjs.map\n","import React from \"react\";\nimport { useEvent } from \"@tamagui/core\";\nimport { SheetControllerContext } from \"./useSheetController.mjs\";\nimport { jsx } from \"react/jsx-runtime\";\nconst SheetController = ({\n children,\n onOpenChange: onOpenChangeProp,\n ...value\n}) => {\n const onOpenChange = useEvent(onOpenChangeProp),\n memoValue = React.useMemo(() => ({\n open: value.open,\n hidden: value.hidden,\n disableDrag: value.disableDrag,\n onOpenChange\n }), [onOpenChange, value.open, value.hidden, value.disableDrag]);\n return /* @__PURE__ */jsx(SheetControllerContext.Provider, {\n value: memoValue,\n children\n });\n};\nexport { SheetController };\n//# sourceMappingURL=SheetController.mjs.map\n","import { getConfig, isVariable } from \"@tamagui/core\";\nconst getFontSize = (inSize, opts) => {\n const res = getFontSizeVariable(inSize, opts);\n return isVariable(res) ? +res.val : res ? +res : 16;\n },\n getFontSizeVariable = (inSize, opts) => {\n const token = getFontSizeToken(inSize, opts);\n if (!token) return inSize;\n const conf = getConfig();\n return conf.fontsParsed[opts?.font || conf.defaultFontToken]?.size[token];\n },\n getFontSizeToken = (inSize, opts) => {\n if (typeof inSize == \"number\") return null;\n const relativeSize = opts?.relativeSize || 0,\n conf = getConfig(),\n fontSize = conf.fontsParsed[opts?.font || conf.defaultFontToken]?.size ||\n // fallback to size tokens\n conf.tokensParsed.size,\n size = (inSize === \"$true\" && !(\"$true\" in fontSize) ? \"$4\" : inSize) ?? (\"$true\" in fontSize ? \"$true\" : \"$4\"),\n sizeTokens = Object.keys(fontSize);\n let foundIndex = sizeTokens.indexOf(size);\n foundIndex === -1 && size.endsWith(\".5\") && (foundIndex = sizeTokens.indexOf(size.replace(\".5\", \"\"))), process.env.NODE_ENV === \"development\" && foundIndex === -1 && console.warn(\"No font size found\", size, opts, \"in size tokens\", sizeTokens);\n const tokenIndex = Math.min(Math.max(0, foundIndex + relativeSize), sizeTokens.length - 1);\n return sizeTokens[tokenIndex] ?? size;\n };\nexport { getFontSize, getFontSizeToken, getFontSizeVariable };\n//# sourceMappingURL=getFontSize.mjs.map\n","import { getVariable, useTheme } from \"@tamagui/web\";\nconst useCurrentColor = colorProp => {\n const theme = useTheme();\n return colorProp ? getVariable(colorProp) : theme[colorProp]?.get() || theme.color?.get();\n};\nexport { useCurrentColor };\n//# sourceMappingURL=useCurrentColor.mjs.map\n","import React from \"react\";\nimport { useCurrentColor } from \"./useCurrentColor.mjs\";\nconst useGetThemedIcon = props => {\n const color = useCurrentColor(props.color);\n return el => el && (React.isValidElement(el) ? React.cloneElement(el, {\n ...props,\n color,\n // @ts-expect-error\n ...el.props\n }) : React.createElement(el, props));\n};\nexport { useGetThemedIcon };\n//# sourceMappingURL=useGetThemedIcon.mjs.map\n","import { getFontSize } from \"@tamagui/font-size\";\nimport { getButtonSized } from \"@tamagui/get-button-sized\";\nimport { withStaticProperties } from \"@tamagui/helpers\";\nimport { useGetThemedIcon } from \"@tamagui/helpers-tamagui\";\nimport { ButtonNestingContext, ThemeableStack } from \"@tamagui/stacks\";\nimport { SizableText, wrapChildrenInText } from \"@tamagui/text\";\nimport { createStyledContext, getVariableValue, spacedChildren, styled, useProps } from \"@tamagui/web\";\nimport { useContext } from \"react\";\nimport { jsx } from \"react/jsx-runtime\";\nconst ButtonContext = createStyledContext({\n // keeping these here means they work with styled() passing down color to text\n color: void 0,\n ellipse: void 0,\n fontFamily: void 0,\n fontSize: void 0,\n fontStyle: void 0,\n fontWeight: void 0,\n letterSpacing: void 0,\n maxFontSizeMultiplier: void 0,\n size: void 0,\n textAlign: void 0,\n variant: void 0\n }),\n BUTTON_NAME = \"Button\",\n ButtonFrame = styled(ThemeableStack, {\n name: BUTTON_NAME,\n tag: \"button\",\n context: ButtonContext,\n role: \"button\",\n focusable: !0,\n variants: {\n unstyled: {\n false: {\n size: \"$true\",\n justifyContent: \"center\",\n alignItems: \"center\",\n flexWrap: \"nowrap\",\n flexDirection: \"row\",\n cursor: \"pointer\",\n hoverTheme: !0,\n pressTheme: !0,\n backgrounded: !0,\n borderWidth: 1,\n borderColor: \"transparent\",\n focusVisibleStyle: {\n outlineColor: \"$outlineColor\",\n outlineStyle: \"solid\",\n outlineWidth: 2\n }\n }\n },\n variant: {\n outlined: {\n backgroundColor: \"transparent\",\n borderWidth: 2,\n borderColor: \"$borderColor\",\n hoverStyle: {\n backgroundColor: \"transparent\",\n borderColor: \"$borderColorHover\"\n },\n pressStyle: {\n backgroundColor: \"transparent\",\n borderColor: \"$borderColorPress\"\n },\n focusVisibleStyle: {\n backgroundColor: \"transparent\",\n borderColor: \"$borderColorFocus\"\n }\n }\n },\n size: {\n \"...size\": getButtonSized,\n \":number\": getButtonSized\n },\n disabled: {\n true: {\n pointerEvents: \"none\"\n }\n }\n },\n defaultVariants: {\n unstyled: process.env.TAMAGUI_HEADLESS === \"1\"\n }\n }),\n ButtonText = styled(SizableText, {\n name: \"Button\",\n context: ButtonContext,\n variants: {\n unstyled: {\n false: {\n userSelect: \"none\",\n cursor: \"pointer\",\n // flexGrow 1 leads to inconsistent native style where text pushes to start of view\n flexGrow: 0,\n flexShrink: 1,\n ellipse: !0,\n color: \"$color\"\n }\n }\n },\n defaultVariants: {\n unstyled: process.env.TAMAGUI_HEADLESS === \"1\"\n }\n }),\n ButtonIcon = props => {\n const {\n children,\n scaleIcon = 1\n } = props,\n {\n size,\n color\n } = useContext(ButtonContext),\n iconSize = (typeof size == \"number\" ? size * 0.5 : getFontSize(size)) * scaleIcon;\n return useGetThemedIcon({\n size: iconSize,\n color\n })(children);\n },\n ButtonComponent = ButtonFrame.styleable(function (props, ref) {\n const {\n props: buttonProps\n } = useButton(props);\n return /* @__PURE__ */jsx(ButtonFrame, {\n \"data-disable-theme\": !0,\n ...buttonProps,\n ref\n });\n }),\n Button2 = withStaticProperties(ButtonComponent, {\n Text: ButtonText,\n Icon: ButtonIcon\n });\nfunction useButton({\n textProps,\n ...propsIn\n}, {\n Text = Button2.Text\n} = {\n Text: Button2.Text\n}) {\n const isNested = useContext(ButtonNestingContext),\n propsActive = useProps(propsIn, {\n noNormalize: !0,\n noExpand: !0\n }),\n {\n icon,\n iconAfter,\n space,\n spaceFlex,\n scaleIcon = 1,\n scaleSpace = 0.66,\n separator,\n noTextWrap,\n fontFamily,\n fontSize,\n fontWeight,\n fontStyle,\n letterSpacing,\n tag,\n ellipse,\n maxFontSizeMultiplier,\n ...restProps\n } = propsActive,\n size = propsActive.size || (propsActive.unstyled ? void 0 : \"$true\"),\n color = propsActive.color,\n iconSize = (typeof size == \"number\" ? size * 0.5 : getFontSize(size, {\n font: fontFamily?.[0] === \"$\" ? fontFamily : void 0\n })) * scaleIcon,\n getThemedIcon = useGetThemedIcon({\n size: iconSize,\n color\n }),\n [themedIcon, themedIconAfter] = [icon, iconAfter].map(getThemedIcon),\n spaceSize = space ?? getVariableValue(iconSize) * scaleSpace,\n contents = noTextWrap ? [propsIn.children] : wrapChildrenInText(Text, {\n children: propsIn.children,\n fontFamily,\n fontSize,\n textProps,\n fontWeight,\n fontStyle,\n letterSpacing,\n ellipse,\n maxFontSizeMultiplier\n }, Text === ButtonText && propsActive.unstyled !== !0 ? {\n unstyled: process.env.TAMAGUI_HEADLESS === \"1\",\n size\n } : void 0),\n inner = spacedChildren({\n // a bit arbitrary but scaling to font size is necessary so long as button does\n space: spaceSize === !1 ? 0 : spaceSize == !0 ? \"$true\" : spaceSize,\n spaceFlex,\n ensureKeys: !0,\n separator,\n direction: propsActive.flexDirection === \"column\" || propsActive.flexDirection === \"column-reverse\" ? \"vertical\" : \"horizontal\",\n // for keys to stay the same we keep indices as similar a possible\n // so even if icons are undefined we still pass them\n children: [themedIcon, ...contents, themedIconAfter]\n }),\n props = {\n size,\n ...(propsIn.disabled && {\n // in rnw - false still has keyboard tabIndex, undefined = not actually focusable\n focusable: void 0,\n // even with tabIndex unset, it will keep focusVisibleStyle on web so disable it here\n focusVisibleStyle: {\n borderColor: \"$background\"\n }\n }),\n // fixes SSR issue + DOM nesting issue of not allowing button in button\n tag: tag ?? (isNested ? \"span\" :\n // defaults to when accessibilityRole = link\n // see https://github.com/tamagui/tamagui/issues/505\n propsActive.accessibilityRole === \"link\" || propsActive.role === \"link\" ? \"a\" : \"button\"),\n ...restProps,\n children: /* @__PURE__ */jsx(ButtonNestingContext.Provider, {\n value: !0,\n children: inner\n }),\n // forces it to be a runtime pressStyle so it passes through context text colors\n disableClassName: !0\n };\n return {\n spaceSize,\n isNested,\n props\n };\n}\nexport { Button2 as Button, ButtonContext, ButtonFrame, ButtonIcon, ButtonText, useButton };\n//# sourceMappingURL=Button.mjs.map\n","const registerFocusable = (id, input) => () => {},\n unregisterFocusable = id => {},\n focusFocusable = id => {};\nexport { focusFocusable, registerFocusable, unregisterFocusable };\n//# sourceMappingURL=registerFocusable.mjs.map\n","import { composeRefs } from \"@tamagui/compose-refs\";\nimport { useEvent } from \"@tamagui/web\";\nimport React from \"react\";\nimport { registerFocusable } from \"./registerFocusable.mjs\";\nfunction useFocusable({\n isInput,\n props,\n ref\n}) {\n const {\n id,\n onChangeText,\n value,\n defaultValue\n } = props,\n inputValue = React.useRef(value || defaultValue || \"\"),\n unregisterFocusable = React.useRef(),\n focusAndSelect = React.useCallback(input => {\n input.focus(), input.setSelection && typeof inputValue.current == \"string\" && input.setSelection(0, inputValue.current.length);\n }, []),\n registerFocusableHandler = React.useCallback(input => {\n !id || !input || (unregisterFocusable.current?.(), unregisterFocusable.current = registerFocusable(id, {\n focus: input.focus,\n ...(isInput && {\n focusAndSelect: () => focusAndSelect(input)\n })\n }));\n }, [id, isInput, focusAndSelect]),\n inputRef = React.useCallback(input => {\n input && registerFocusableHandler(input);\n }, [registerFocusableHandler]),\n handleChangeText = useEvent(value2 => {\n inputValue.current = value2, onChangeText?.(value2);\n });\n return React.useEffect(() => () => {\n unregisterFocusable.current?.();\n }, []), {\n ref: React.useMemo(() => composeRefs(ref, inputRef), [ref, inputRef]),\n onChangeText: handleChangeText\n };\n}\nexport { useFocusable };\n//# sourceMappingURL=focusableInputHOC.mjs.map\n","import { getFontSize } from \"@tamagui/font-size\";\nimport { getFontSized } from \"@tamagui/get-font-sized\";\nimport { getSize, getSpace } from \"@tamagui/get-token\";\nimport { withStaticProperties } from \"@tamagui/helpers\";\nimport { useGetThemedIcon } from \"@tamagui/helpers-tamagui\";\nimport { ThemeableStack, YStack } from \"@tamagui/stacks\";\nimport { SizableText, wrapChildrenInText } from \"@tamagui/text\";\nimport { Spacer, getTokens, getVariableValue, styled, useProps } from \"@tamagui/web\";\nimport { Fragment, jsx, jsxs } from \"react/jsx-runtime\";\nconst NAME = \"ListItem\",\n ListItemFrame = styled(ThemeableStack, {\n name: NAME,\n tag: \"li\",\n variants: {\n unstyled: {\n false: {\n size: \"$true\",\n alignItems: \"center\",\n justifyContent: \"space-between\",\n flexWrap: \"nowrap\",\n width: \"100%\",\n borderColor: \"$borderColor\",\n maxWidth: \"100%\",\n overflow: \"hidden\",\n flexDirection: \"row\",\n backgroundColor: \"$background\",\n cursor: \"default\"\n }\n },\n size: {\n \"...size\": (val, {\n tokens\n }) => ({\n minHeight: tokens.size[val],\n paddingHorizontal: tokens.space[val],\n paddingVertical: getSpace(tokens.space[val], {\n shift: -4\n })\n })\n },\n active: {\n true: {\n hoverStyle: {\n backgroundColor: \"$background\"\n }\n }\n },\n disabled: {\n true: {\n opacity: 0.5,\n // TODO breaking types\n pointerEvents: \"none\"\n }\n }\n },\n defaultVariants: {\n unstyled: process.env.TAMAGUI_HEADLESS === \"1\"\n }\n }),\n ListItemText = styled(SizableText, {\n name: \"ListItemText\",\n variants: {\n unstyled: {\n false: {\n color: \"$color\",\n size: \"$true\",\n flexGrow: 1,\n flexShrink: 1,\n ellipse: !0,\n cursor: \"inherit\"\n }\n }\n },\n defaultVariants: {\n unstyled: process.env.TAMAGUI_HEADLESS === \"1\"\n }\n }),\n ListItemSubtitle = styled(ListItemText, {\n name: \"ListItemSubtitle\",\n variants: {\n unstyled: {\n false: {\n opacity: 0.6,\n maxWidth: \"100%\",\n color: \"$color\"\n }\n },\n size: {\n \"...size\": (val, extras) => {\n const oneSmaller = getSize(val, {\n shift: -1,\n excludeHalfSteps: !0\n });\n return getFontSized(oneSmaller.key, extras);\n }\n }\n },\n defaultVariants: {\n unstyled: process.env.TAMAGUI_HEADLESS === \"1\"\n }\n }),\n ListItemTitle = styled(ListItemText, {\n name: \"ListItemTitle\"\n }),\n useListItem = (propsIn, {\n Text = ListItemText,\n Subtitle = ListItemSubtitle,\n Title = ListItemTitle\n } = {\n Text: ListItemText,\n Subtitle: ListItemSubtitle,\n Title: ListItemTitle\n }) => {\n const props = useProps(propsIn, {\n resolveValues: \"none\"\n }),\n {\n children,\n icon,\n iconAfter,\n noTextWrap,\n theme: themeName,\n space,\n spaceFlex,\n scaleIcon = 1,\n scaleSpace = 1,\n unstyled = !1,\n subTitle,\n title,\n // text props\n color,\n fontWeight,\n fontSize,\n fontFamily,\n letterSpacing,\n textAlign,\n ellipse,\n ...rest\n } = props,\n textProps = {\n color,\n fontWeight,\n fontSize,\n fontFamily,\n letterSpacing,\n textAlign,\n ellipse,\n children\n },\n size = props.size || \"$true\",\n iconSize = getFontSize(size) * scaleIcon,\n getThemedIcon = useGetThemedIcon({\n size: iconSize,\n color\n }),\n [themedIcon, themedIconAfter] = [icon, iconAfter].map(getThemedIcon),\n sizeToken = getTokens().space[props.space] ?? iconSize,\n spaceSize = getVariableValue(sizeToken) * scaleSpace,\n contents = wrapChildrenInText(Text, textProps);\n return {\n props: {\n ...rest,\n children: /* @__PURE__ */jsxs(Fragment, {\n children: [themedIcon ? /* @__PURE__ */jsxs(Fragment, {\n children: [themedIcon, /* @__PURE__ */jsx(Spacer, {\n size: spaceSize\n })]\n }) : null, title || subTitle ? /* @__PURE__ */jsxs(YStack, {\n flex: 1,\n children: [noTextWrap === \"all\" ? title : /* @__PURE__ */jsx(Title, {\n size,\n children: title\n }), subTitle ? /* @__PURE__ */jsx(Fragment, {\n children: typeof subTitle == \"string\" && noTextWrap !== \"all\" ?\n // TODO can use theme but we need to standardize to alt themes\n // or standardize on subtle colors in themes\n /* @__PURE__ */\n jsx(Subtitle, {\n unstyled,\n size,\n children: subTitle\n }) : subTitle\n }) : null, contents]\n }) : contents, themedIconAfter ? /* @__PURE__ */jsxs(Fragment, {\n children: [/* @__PURE__ */jsx(Spacer, {\n size: spaceSize\n }), themedIconAfter]\n }) : null]\n })\n }\n };\n },\n ListItemComponent = ListItemFrame.styleable(function (props, ref) {\n const {\n props: listItemProps\n } = useListItem(props);\n return /* @__PURE__ */jsx(ListItemFrame, {\n ref,\n ...listItemProps\n });\n }),\n ListItem2 = withStaticProperties(ListItemComponent, {\n Text: ListItemText,\n Subtitle: ListItemSubtitle\n });\nexport { ListItem2 as ListItem, ListItemFrame, ListItemSubtitle, ListItemText, ListItemTitle, useListItem };\n//# sourceMappingURL=ListItem.mjs.map\n","/**\n * Custom positioning reference element.\n * @see https://floating-ui.com/docs/virtual-elements\n */\n\nconst sides = ['top', 'right', 'bottom', 'left'];\nconst alignments = ['start', 'end'];\nconst placements = /*#__PURE__*/sides.reduce((acc, side) => acc.concat(side, side + \"-\" + alignments[0], side + \"-\" + alignments[1]), []);\nconst min = Math.min;\nconst max = Math.max;\nconst round = Math.round;\nconst floor = Math.floor;\nconst createCoords = v => ({\n x: v,\n y: v\n});\nconst oppositeSideMap = {\n left: 'right',\n right: 'left',\n bottom: 'top',\n top: 'bottom'\n};\nconst oppositeAlignmentMap = {\n start: 'end',\n end: 'start'\n};\nfunction clamp(start, value, end) {\n return max(start, min(value, end));\n}\nfunction evaluate(value, param) {\n return typeof value === 'function' ? value(param) : value;\n}\nfunction getSide(placement) {\n return placement.split('-')[0];\n}\nfunction getAlignment(placement) {\n return placement.split('-')[1];\n}\nfunction getOppositeAxis(axis) {\n return axis === 'x' ? 'y' : 'x';\n}\nfunction getAxisLength(axis) {\n return axis === 'y' ? 'height' : 'width';\n}\nconst yAxisSides = /*#__PURE__*/new Set(['top', 'bottom']);\nfunction getSideAxis(placement) {\n return yAxisSides.has(getSide(placement)) ? 'y' : 'x';\n}\nfunction getAlignmentAxis(placement) {\n return getOppositeAxis(getSideAxis(placement));\n}\nfunction getAlignmentSides(placement, rects, rtl) {\n if (rtl === void 0) {\n rtl = false;\n }\n const alignment = getAlignment(placement);\n const alignmentAxis = getAlignmentAxis(placement);\n const length = getAxisLength(alignmentAxis);\n let mainAlignmentSide = alignmentAxis === 'x' ? alignment === (rtl ? 'end' : 'start') ? 'right' : 'left' : alignment === 'start' ? 'bottom' : 'top';\n if (rects.reference[length] > rects.floating[length]) {\n mainAlignmentSide = getOppositePlacement(mainAlignmentSide);\n }\n return [mainAlignmentSide, getOppositePlacement(mainAlignmentSide)];\n}\nfunction getExpandedPlacements(placement) {\n const oppositePlacement = getOppositePlacement(placement);\n return [getOppositeAlignmentPlacement(placement), oppositePlacement, getOppositeAlignmentPlacement(oppositePlacement)];\n}\nfunction getOppositeAlignmentPlacement(placement) {\n return placement.replace(/start|end/g, alignment => oppositeAlignmentMap[alignment]);\n}\nconst lrPlacement = ['left', 'right'];\nconst rlPlacement = ['right', 'left'];\nconst tbPlacement = ['top', 'bottom'];\nconst btPlacement = ['bottom', 'top'];\nfunction getSideList(side, isStart, rtl) {\n switch (side) {\n case 'top':\n case 'bottom':\n if (rtl) return isStart ? rlPlacement : lrPlacement;\n return isStart ? lrPlacement : rlPlacement;\n case 'left':\n case 'right':\n return isStart ? tbPlacement : btPlacement;\n default:\n return [];\n }\n}\nfunction getOppositeAxisPlacements(placement, flipAlignment, direction, rtl) {\n const alignment = getAlignment(placement);\n let list = getSideList(getSide(placement), direction === 'start', rtl);\n if (alignment) {\n list = list.map(side => side + \"-\" + alignment);\n if (flipAlignment) {\n list = list.concat(list.map(getOppositeAlignmentPlacement));\n }\n }\n return list;\n}\nfunction getOppositePlacement(placement) {\n return placement.replace(/left|right|bottom|top/g, side => oppositeSideMap[side]);\n}\nfunction expandPaddingObject(padding) {\n return {\n top: 0,\n right: 0,\n bottom: 0,\n left: 0,\n ...padding\n };\n}\nfunction getPaddingObject(padding) {\n return typeof padding !== 'number' ? expandPaddingObject(padding) : {\n top: padding,\n right: padding,\n bottom: padding,\n left: padding\n };\n}\nfunction rectToClientRect(rect) {\n const {\n x,\n y,\n width,\n height\n } = rect;\n return {\n width,\n height,\n top: y,\n left: x,\n right: x + width,\n bottom: y + height,\n x,\n y\n };\n}\n\nexport { alignments, clamp, createCoords, evaluate, expandPaddingObject, floor, getAlignment, getAlignmentAxis, getAlignmentSides, getAxisLength, getExpandedPlacements, getOppositeAlignmentPlacement, getOppositeAxis, getOppositeAxisPlacements, getOppositePlacement, getPaddingObject, getSide, getSideAxis, max, min, placements, rectToClientRect, round, sides };\n","import { getSideAxis, getAlignmentAxis, getAxisLength, getSide, getAlignment, evaluate, getPaddingObject, rectToClientRect, min, clamp, placements, getAlignmentSides, getOppositeAlignmentPlacement, getOppositePlacement, getExpandedPlacements, getOppositeAxisPlacements, sides, max, getOppositeAxis } from '@floating-ui/utils';\nexport { rectToClientRect } from '@floating-ui/utils';\n\nfunction computeCoordsFromPlacement(_ref, placement, rtl) {\n let {\n reference,\n floating\n } = _ref;\n const sideAxis = getSideAxis(placement);\n const alignmentAxis = getAlignmentAxis(placement);\n const alignLength = getAxisLength(alignmentAxis);\n const side = getSide(placement);\n const isVertical = sideAxis === 'y';\n const commonX = reference.x + reference.width / 2 - floating.width / 2;\n const commonY = reference.y + reference.height / 2 - floating.height / 2;\n const commonAlign = reference[alignLength] / 2 - floating[alignLength] / 2;\n let coords;\n switch (side) {\n case 'top':\n coords = {\n x: commonX,\n y: reference.y - floating.height\n };\n break;\n case 'bottom':\n coords = {\n x: commonX,\n y: reference.y + reference.height\n };\n break;\n case 'right':\n coords = {\n x: reference.x + reference.width,\n y: commonY\n };\n break;\n case 'left':\n coords = {\n x: reference.x - floating.width,\n y: commonY\n };\n break;\n default:\n coords = {\n x: reference.x,\n y: reference.y\n };\n }\n switch (getAlignment(placement)) {\n case 'start':\n coords[alignmentAxis] -= commonAlign * (rtl && isVertical ? -1 : 1);\n break;\n case 'end':\n coords[alignmentAxis] += commonAlign * (rtl && isVertical ? -1 : 1);\n break;\n }\n return coords;\n}\n\n/**\n * Computes the `x` and `y` coordinates that will place the floating element\n * next to a given reference element.\n *\n * This export does not have any `platform` interface logic. You will need to\n * write one for the platform you are using Floating UI with.\n */\nconst computePosition = async (reference, floating, config) => {\n const {\n placement = 'bottom',\n strategy = 'absolute',\n middleware = [],\n platform\n } = config;\n const validMiddleware = middleware.filter(Boolean);\n const rtl = await (platform.isRTL == null ? void 0 : platform.isRTL(floating));\n let rects = await platform.getElementRects({\n reference,\n floating,\n strategy\n });\n let {\n x,\n y\n } = computeCoordsFromPlacement(rects, placement, rtl);\n let statefulPlacement = placement;\n let middlewareData = {};\n let resetCount = 0;\n for (let i = 0; i < validMiddleware.length; i++) {\n const {\n name,\n fn\n } = validMiddleware[i];\n const {\n x: nextX,\n y: nextY,\n data,\n reset\n } = await fn({\n x,\n y,\n initialPlacement: placement,\n placement: statefulPlacement,\n strategy,\n middlewareData,\n rects,\n platform,\n elements: {\n reference,\n floating\n }\n });\n x = nextX != null ? nextX : x;\n y = nextY != null ? nextY : y;\n middlewareData = {\n ...middlewareData,\n [name]: {\n ...middlewareData[name],\n ...data\n }\n };\n if (reset && resetCount <= 50) {\n resetCount++;\n if (typeof reset === 'object') {\n if (reset.placement) {\n statefulPlacement = reset.placement;\n }\n if (reset.rects) {\n rects = reset.rects === true ? await platform.getElementRects({\n reference,\n floating,\n strategy\n }) : reset.rects;\n }\n ({\n x,\n y\n } = computeCoordsFromPlacement(rects, statefulPlacement, rtl));\n }\n i = -1;\n }\n }\n return {\n x,\n y,\n placement: statefulPlacement,\n strategy,\n middlewareData\n };\n};\n\n/**\n * Resolves with an object of overflow side offsets that determine how much the\n * element is overflowing a given clipping boundary on each side.\n * - positive = overflowing the boundary by that number of pixels\n * - negative = how many pixels left before it will overflow\n * - 0 = lies flush with the boundary\n * @see https://floating-ui.com/docs/detectOverflow\n */\nasync function detectOverflow(state, options) {\n var _await$platform$isEle;\n if (options === void 0) {\n options = {};\n }\n const {\n x,\n y,\n platform,\n rects,\n elements,\n strategy\n } = state;\n const {\n boundary = 'clippingAncestors',\n rootBoundary = 'viewport',\n elementContext = 'floating',\n altBoundary = false,\n padding = 0\n } = evaluate(options, state);\n const paddingObject = getPaddingObject(padding);\n const altContext = elementContext === 'floating' ? 'reference' : 'floating';\n const element = elements[altBoundary ? altContext : elementContext];\n const clippingClientRect = rectToClientRect(await platform.getClippingRect({\n element: ((_await$platform$isEle = await (platform.isElement == null ? void 0 : platform.isElement(element))) != null ? _await$platform$isEle : true) ? element : element.contextElement || (await (platform.getDocumentElement == null ? void 0 : platform.getDocumentElement(elements.floating))),\n boundary,\n rootBoundary,\n strategy\n }));\n const rect = elementContext === 'floating' ? {\n x,\n y,\n width: rects.floating.width,\n height: rects.floating.height\n } : rects.reference;\n const offsetParent = await (platform.getOffsetParent == null ? void 0 : platform.getOffsetParent(elements.floating));\n const offsetScale = (await (platform.isElement == null ? void 0 : platform.isElement(offsetParent))) ? (await (platform.getScale == null ? void 0 : platform.getScale(offsetParent))) || {\n x: 1,\n y: 1\n } : {\n x: 1,\n y: 1\n };\n const elementClientRect = rectToClientRect(platform.convertOffsetParentRelativeRectToViewportRelativeRect ? await platform.convertOffsetParentRelativeRectToViewportRelativeRect({\n elements,\n rect,\n offsetParent,\n strategy\n }) : rect);\n return {\n top: (clippingClientRect.top - elementClientRect.top + paddingObject.top) / offsetScale.y,\n bottom: (elementClientRect.bottom - clippingClientRect.bottom + paddingObject.bottom) / offsetScale.y,\n left: (clippingClientRect.left - elementClientRect.left + paddingObject.left) / offsetScale.x,\n right: (elementClientRect.right - clippingClientRect.right + paddingObject.right) / offsetScale.x\n };\n}\n\n/**\n * Provides data to position an inner element of the floating element so that it\n * appears centered to the reference element.\n * @see https://floating-ui.com/docs/arrow\n */\nconst arrow = options => ({\n name: 'arrow',\n options,\n async fn(state) {\n const {\n x,\n y,\n placement,\n rects,\n platform,\n elements,\n middlewareData\n } = state;\n // Since `element` is required, we don't Partial<> the type.\n const {\n element,\n padding = 0\n } = evaluate(options, state) || {};\n if (element == null) {\n return {};\n }\n const paddingObject = getPaddingObject(padding);\n const coords = {\n x,\n y\n };\n const axis = getAlignmentAxis(placement);\n const length = getAxisLength(axis);\n const arrowDimensions = await platform.getDimensions(element);\n const isYAxis = axis === 'y';\n const minProp = isYAxis ? 'top' : 'left';\n const maxProp = isYAxis ? 'bottom' : 'right';\n const clientProp = isYAxis ? 'clientHeight' : 'clientWidth';\n const endDiff = rects.reference[length] + rects.reference[axis] - coords[axis] - rects.floating[length];\n const startDiff = coords[axis] - rects.reference[axis];\n const arrowOffsetParent = await (platform.getOffsetParent == null ? void 0 : platform.getOffsetParent(element));\n let clientSize = arrowOffsetParent ? arrowOffsetParent[clientProp] : 0;\n\n // DOM platform can return `window` as the `offsetParent`.\n if (!clientSize || !(await (platform.isElement == null ? void 0 : platform.isElement(arrowOffsetParent)))) {\n clientSize = elements.floating[clientProp] || rects.floating[length];\n }\n const centerToReference = endDiff / 2 - startDiff / 2;\n\n // If the padding is large enough that it causes the arrow to no longer be\n // centered, modify the padding so that it is centered.\n const largestPossiblePadding = clientSize / 2 - arrowDimensions[length] / 2 - 1;\n const minPadding = min(paddingObject[minProp], largestPossiblePadding);\n const maxPadding = min(paddingObject[maxProp], largestPossiblePadding);\n\n // Make sure the arrow doesn't overflow the floating element if the center\n // point is outside the floating element's bounds.\n const min$1 = minPadding;\n const max = clientSize - arrowDimensions[length] - maxPadding;\n const center = clientSize / 2 - arrowDimensions[length] / 2 + centerToReference;\n const offset = clamp(min$1, center, max);\n\n // If the reference is small enough that the arrow's padding causes it to\n // to point to nothing for an aligned placement, adjust the offset of the\n // floating element itself. To ensure `shift()` continues to take action,\n // a single reset is performed when this is true.\n const shouldAddOffset = !middlewareData.arrow && getAlignment(placement) != null && center !== offset && rects.reference[length] / 2 - (center < min$1 ? minPadding : maxPadding) - arrowDimensions[length] / 2 < 0;\n const alignmentOffset = shouldAddOffset ? center < min$1 ? center - min$1 : center - max : 0;\n return {\n [axis]: coords[axis] + alignmentOffset,\n data: {\n [axis]: offset,\n centerOffset: center - offset - alignmentOffset,\n ...(shouldAddOffset && {\n alignmentOffset\n })\n },\n reset: shouldAddOffset\n };\n }\n});\n\nfunction getPlacementList(alignment, autoAlignment, allowedPlacements) {\n const allowedPlacementsSortedByAlignment = alignment ? [...allowedPlacements.filter(placement => getAlignment(placement) === alignment), ...allowedPlacements.filter(placement => getAlignment(placement) !== alignment)] : allowedPlacements.filter(placement => getSide(placement) === placement);\n return allowedPlacementsSortedByAlignment.filter(placement => {\n if (alignment) {\n return getAlignment(placement) === alignment || (autoAlignment ? getOppositeAlignmentPlacement(placement) !== placement : false);\n }\n return true;\n });\n}\n/**\n * Optimizes the visibility of the floating element by choosing the placement\n * that has the most space available automatically, without needing to specify a\n * preferred placement. Alternative to `flip`.\n * @see https://floating-ui.com/docs/autoPlacement\n */\nconst autoPlacement = function (options) {\n if (options === void 0) {\n options = {};\n }\n return {\n name: 'autoPlacement',\n options,\n async fn(state) {\n var _middlewareData$autoP, _middlewareData$autoP2, _placementsThatFitOnE;\n const {\n rects,\n middlewareData,\n placement,\n platform,\n elements\n } = state;\n const {\n crossAxis = false,\n alignment,\n allowedPlacements = placements,\n autoAlignment = true,\n ...detectOverflowOptions\n } = evaluate(options, state);\n const placements$1 = alignment !== undefined || allowedPlacements === placements ? getPlacementList(alignment || null, autoAlignment, allowedPlacements) : allowedPlacements;\n const overflow = await detectOverflow(state, detectOverflowOptions);\n const currentIndex = ((_middlewareData$autoP = middlewareData.autoPlacement) == null ? void 0 : _middlewareData$autoP.index) || 0;\n const currentPlacement = placements$1[currentIndex];\n if (currentPlacement == null) {\n return {};\n }\n const alignmentSides = getAlignmentSides(currentPlacement, rects, await (platform.isRTL == null ? void 0 : platform.isRTL(elements.floating)));\n\n // Make `computeCoords` start from the right place.\n if (placement !== currentPlacement) {\n return {\n reset: {\n placement: placements$1[0]\n }\n };\n }\n const currentOverflows = [overflow[getSide(currentPlacement)], overflow[alignmentSides[0]], overflow[alignmentSides[1]]];\n const allOverflows = [...(((_middlewareData$autoP2 = middlewareData.autoPlacement) == null ? void 0 : _middlewareData$autoP2.overflows) || []), {\n placement: currentPlacement,\n overflows: currentOverflows\n }];\n const nextPlacement = placements$1[currentIndex + 1];\n\n // There are more placements to check.\n if (nextPlacement) {\n return {\n data: {\n index: currentIndex + 1,\n overflows: allOverflows\n },\n reset: {\n placement: nextPlacement\n }\n };\n }\n const placementsSortedByMostSpace = allOverflows.map(d => {\n const alignment = getAlignment(d.placement);\n return [d.placement, alignment && crossAxis ?\n // Check along the mainAxis and main crossAxis side.\n d.overflows.slice(0, 2).reduce((acc, v) => acc + v, 0) :\n // Check only the mainAxis.\n d.overflows[0], d.overflows];\n }).sort((a, b) => a[1] - b[1]);\n const placementsThatFitOnEachSide = placementsSortedByMostSpace.filter(d => d[2].slice(0,\n // Aligned placements should not check their opposite crossAxis\n // side.\n getAlignment(d[0]) ? 2 : 3).every(v => v <= 0));\n const resetPlacement = ((_placementsThatFitOnE = placementsThatFitOnEachSide[0]) == null ? void 0 : _placementsThatFitOnE[0]) || placementsSortedByMostSpace[0][0];\n if (resetPlacement !== placement) {\n return {\n data: {\n index: currentIndex + 1,\n overflows: allOverflows\n },\n reset: {\n placement: resetPlacement\n }\n };\n }\n return {};\n }\n };\n};\n\n/**\n * Optimizes the visibility of the floating element by flipping the `placement`\n * in order to keep it in view when the preferred placement(s) will overflow the\n * clipping boundary. Alternative to `autoPlacement`.\n * @see https://floating-ui.com/docs/flip\n */\nconst flip = function (options) {\n if (options === void 0) {\n options = {};\n }\n return {\n name: 'flip',\n options,\n async fn(state) {\n var _middlewareData$arrow, _middlewareData$flip;\n const {\n placement,\n middlewareData,\n rects,\n initialPlacement,\n platform,\n elements\n } = state;\n const {\n mainAxis: checkMainAxis = true,\n crossAxis: checkCrossAxis = true,\n fallbackPlacements: specifiedFallbackPlacements,\n fallbackStrategy = 'bestFit',\n fallbackAxisSideDirection = 'none',\n flipAlignment = true,\n ...detectOverflowOptions\n } = evaluate(options, state);\n\n // If a reset by the arrow was caused due to an alignment offset being\n // added, we should skip any logic now since `flip()` has already done its\n // work.\n // https://github.com/floating-ui/floating-ui/issues/2549#issuecomment-1719601643\n if ((_middlewareData$arrow = middlewareData.arrow) != null && _middlewareData$arrow.alignmentOffset) {\n return {};\n }\n const side = getSide(placement);\n const initialSideAxis = getSideAxis(initialPlacement);\n const isBasePlacement = getSide(initialPlacement) === initialPlacement;\n const rtl = await (platform.isRTL == null ? void 0 : platform.isRTL(elements.floating));\n const fallbackPlacements = specifiedFallbackPlacements || (isBasePlacement || !flipAlignment ? [getOppositePlacement(initialPlacement)] : getExpandedPlacements(initialPlacement));\n const hasFallbackAxisSideDirection = fallbackAxisSideDirection !== 'none';\n if (!specifiedFallbackPlacements && hasFallbackAxisSideDirection) {\n fallbackPlacements.push(...getOppositeAxisPlacements(initialPlacement, flipAlignment, fallbackAxisSideDirection, rtl));\n }\n const placements = [initialPlacement, ...fallbackPlacements];\n const overflow = await detectOverflow(state, detectOverflowOptions);\n const overflows = [];\n let overflowsData = ((_middlewareData$flip = middlewareData.flip) == null ? void 0 : _middlewareData$flip.overflows) || [];\n if (checkMainAxis) {\n overflows.push(overflow[side]);\n }\n if (checkCrossAxis) {\n const sides = getAlignmentSides(placement, rects, rtl);\n overflows.push(overflow[sides[0]], overflow[sides[1]]);\n }\n overflowsData = [...overflowsData, {\n placement,\n overflows\n }];\n\n // One or more sides is overflowing.\n if (!overflows.every(side => side <= 0)) {\n var _middlewareData$flip2, _overflowsData$filter;\n const nextIndex = (((_middlewareData$flip2 = middlewareData.flip) == null ? void 0 : _middlewareData$flip2.index) || 0) + 1;\n const nextPlacement = placements[nextIndex];\n if (nextPlacement) {\n const ignoreCrossAxisOverflow = checkCrossAxis === 'alignment' ? initialSideAxis !== getSideAxis(nextPlacement) : false;\n if (!ignoreCrossAxisOverflow ||\n // We leave the current main axis only if every placement on that axis\n // overflows the main axis.\n overflowsData.every(d => getSideAxis(d.placement) === initialSideAxis ? d.overflows[0] > 0 : true)) {\n // Try next placement and re-run the lifecycle.\n return {\n data: {\n index: nextIndex,\n overflows: overflowsData\n },\n reset: {\n placement: nextPlacement\n }\n };\n }\n }\n\n // First, find the candidates that fit on the mainAxis side of overflow,\n // then find the placement that fits the best on the main crossAxis side.\n let resetPlacement = (_overflowsData$filter = overflowsData.filter(d => d.overflows[0] <= 0).sort((a, b) => a.overflows[1] - b.overflows[1])[0]) == null ? void 0 : _overflowsData$filter.placement;\n\n // Otherwise fallback.\n if (!resetPlacement) {\n switch (fallbackStrategy) {\n case 'bestFit':\n {\n var _overflowsData$filter2;\n const placement = (_overflowsData$filter2 = overflowsData.filter(d => {\n if (hasFallbackAxisSideDirection) {\n const currentSideAxis = getSideAxis(d.placement);\n return currentSideAxis === initialSideAxis ||\n // Create a bias to the `y` side axis due to horizontal\n // reading directions favoring greater width.\n currentSideAxis === 'y';\n }\n return true;\n }).map(d => [d.placement, d.overflows.filter(overflow => overflow > 0).reduce((acc, overflow) => acc + overflow, 0)]).sort((a, b) => a[1] - b[1])[0]) == null ? void 0 : _overflowsData$filter2[0];\n if (placement) {\n resetPlacement = placement;\n }\n break;\n }\n case 'initialPlacement':\n resetPlacement = initialPlacement;\n break;\n }\n }\n if (placement !== resetPlacement) {\n return {\n reset: {\n placement: resetPlacement\n }\n };\n }\n }\n return {};\n }\n };\n};\n\nfunction getSideOffsets(overflow, rect) {\n return {\n top: overflow.top - rect.height,\n right: overflow.right - rect.width,\n bottom: overflow.bottom - rect.height,\n left: overflow.left - rect.width\n };\n}\nfunction isAnySideFullyClipped(overflow) {\n return sides.some(side => overflow[side] >= 0);\n}\n/**\n * Provides data to hide the floating element in applicable situations, such as\n * when it is not in the same clipping context as the reference element.\n * @see https://floating-ui.com/docs/hide\n */\nconst hide = function (options) {\n if (options === void 0) {\n options = {};\n }\n return {\n name: 'hide',\n options,\n async fn(state) {\n const {\n rects\n } = state;\n const {\n strategy = 'referenceHidden',\n ...detectOverflowOptions\n } = evaluate(options, state);\n switch (strategy) {\n case 'referenceHidden':\n {\n const overflow = await detectOverflow(state, {\n ...detectOverflowOptions,\n elementContext: 'reference'\n });\n const offsets = getSideOffsets(overflow, rects.reference);\n return {\n data: {\n referenceHiddenOffsets: offsets,\n referenceHidden: isAnySideFullyClipped(offsets)\n }\n };\n }\n case 'escaped':\n {\n const overflow = await detectOverflow(state, {\n ...detectOverflowOptions,\n altBoundary: true\n });\n const offsets = getSideOffsets(overflow, rects.floating);\n return {\n data: {\n escapedOffsets: offsets,\n escaped: isAnySideFullyClipped(offsets)\n }\n };\n }\n default:\n {\n return {};\n }\n }\n }\n };\n};\n\nfunction getBoundingRect(rects) {\n const minX = min(...rects.map(rect => rect.left));\n const minY = min(...rects.map(rect => rect.top));\n const maxX = max(...rects.map(rect => rect.right));\n const maxY = max(...rects.map(rect => rect.bottom));\n return {\n x: minX,\n y: minY,\n width: maxX - minX,\n height: maxY - minY\n };\n}\nfunction getRectsByLine(rects) {\n const sortedRects = rects.slice().sort((a, b) => a.y - b.y);\n const groups = [];\n let prevRect = null;\n for (let i = 0; i < sortedRects.length; i++) {\n const rect = sortedRects[i];\n if (!prevRect || rect.y - prevRect.y > prevRect.height / 2) {\n groups.push([rect]);\n } else {\n groups[groups.length - 1].push(rect);\n }\n prevRect = rect;\n }\n return groups.map(rect => rectToClientRect(getBoundingRect(rect)));\n}\n/**\n * Provides improved positioning for inline reference elements that can span\n * over multiple lines, such as hyperlinks or range selections.\n * @see https://floating-ui.com/docs/inline\n */\nconst inline = function (options) {\n if (options === void 0) {\n options = {};\n }\n return {\n name: 'inline',\n options,\n async fn(state) {\n const {\n placement,\n elements,\n rects,\n platform,\n strategy\n } = state;\n // A MouseEvent's client{X,Y} coords can be up to 2 pixels off a\n // ClientRect's bounds, despite the event listener being triggered. A\n // padding of 2 seems to handle this issue.\n const {\n padding = 2,\n x,\n y\n } = evaluate(options, state);\n const nativeClientRects = Array.from((await (platform.getClientRects == null ? void 0 : platform.getClientRects(elements.reference))) || []);\n const clientRects = getRectsByLine(nativeClientRects);\n const fallback = rectToClientRect(getBoundingRect(nativeClientRects));\n const paddingObject = getPaddingObject(padding);\n function getBoundingClientRect() {\n // There are two rects and they are disjoined.\n if (clientRects.length === 2 && clientRects[0].left > clientRects[1].right && x != null && y != null) {\n // Find the first rect in which the point is fully inside.\n return clientRects.find(rect => x > rect.left - paddingObject.left && x < rect.right + paddingObject.right && y > rect.top - paddingObject.top && y < rect.bottom + paddingObject.bottom) || fallback;\n }\n\n // There are 2 or more connected rects.\n if (clientRects.length >= 2) {\n if (getSideAxis(placement) === 'y') {\n const firstRect = clientRects[0];\n const lastRect = clientRects[clientRects.length - 1];\n const isTop = getSide(placement) === 'top';\n const top = firstRect.top;\n const bottom = lastRect.bottom;\n const left = isTop ? firstRect.left : lastRect.left;\n const right = isTop ? firstRect.right : lastRect.right;\n const width = right - left;\n const height = bottom - top;\n return {\n top,\n bottom,\n left,\n right,\n width,\n height,\n x: left,\n y: top\n };\n }\n const isLeftSide = getSide(placement) === 'left';\n const maxRight = max(...clientRects.map(rect => rect.right));\n const minLeft = min(...clientRects.map(rect => rect.left));\n const measureRects = clientRects.filter(rect => isLeftSide ? rect.left === minLeft : rect.right === maxRight);\n const top = measureRects[0].top;\n const bottom = measureRects[measureRects.length - 1].bottom;\n const left = minLeft;\n const right = maxRight;\n const width = right - left;\n const height = bottom - top;\n return {\n top,\n bottom,\n left,\n right,\n width,\n height,\n x: left,\n y: top\n };\n }\n return fallback;\n }\n const resetRects = await platform.getElementRects({\n reference: {\n getBoundingClientRect\n },\n floating: elements.floating,\n strategy\n });\n if (rects.reference.x !== resetRects.reference.x || rects.reference.y !== resetRects.reference.y || rects.reference.width !== resetRects.reference.width || rects.reference.height !== resetRects.reference.height) {\n return {\n reset: {\n rects: resetRects\n }\n };\n }\n return {};\n }\n };\n};\n\nconst originSides = /*#__PURE__*/new Set(['left', 'top']);\n\n// For type backwards-compatibility, the `OffsetOptions` type was also\n// Derivable.\n\nasync function convertValueToCoords(state, options) {\n const {\n placement,\n platform,\n elements\n } = state;\n const rtl = await (platform.isRTL == null ? void 0 : platform.isRTL(elements.floating));\n const side = getSide(placement);\n const alignment = getAlignment(placement);\n const isVertical = getSideAxis(placement) === 'y';\n const mainAxisMulti = originSides.has(side) ? -1 : 1;\n const crossAxisMulti = rtl && isVertical ? -1 : 1;\n const rawValue = evaluate(options, state);\n\n // eslint-disable-next-line prefer-const\n let {\n mainAxis,\n crossAxis,\n alignmentAxis\n } = typeof rawValue === 'number' ? {\n mainAxis: rawValue,\n crossAxis: 0,\n alignmentAxis: null\n } : {\n mainAxis: rawValue.mainAxis || 0,\n crossAxis: rawValue.crossAxis || 0,\n alignmentAxis: rawValue.alignmentAxis\n };\n if (alignment && typeof alignmentAxis === 'number') {\n crossAxis = alignment === 'end' ? alignmentAxis * -1 : alignmentAxis;\n }\n return isVertical ? {\n x: crossAxis * crossAxisMulti,\n y: mainAxis * mainAxisMulti\n } : {\n x: mainAxis * mainAxisMulti,\n y: crossAxis * crossAxisMulti\n };\n}\n\n/**\n * Modifies the placement by translating the floating element along the\n * specified axes.\n * A number (shorthand for `mainAxis` or distance), or an axes configuration\n * object may be passed.\n * @see https://floating-ui.com/docs/offset\n */\nconst offset = function (options) {\n if (options === void 0) {\n options = 0;\n }\n return {\n name: 'offset',\n options,\n async fn(state) {\n var _middlewareData$offse, _middlewareData$arrow;\n const {\n x,\n y,\n placement,\n middlewareData\n } = state;\n const diffCoords = await convertValueToCoords(state, options);\n\n // If the placement is the same and the arrow caused an alignment offset\n // then we don't need to change the positioning coordinates.\n if (placement === ((_middlewareData$offse = middlewareData.offset) == null ? void 0 : _middlewareData$offse.placement) && (_middlewareData$arrow = middlewareData.arrow) != null && _middlewareData$arrow.alignmentOffset) {\n return {};\n }\n return {\n x: x + diffCoords.x,\n y: y + diffCoords.y,\n data: {\n ...diffCoords,\n placement\n }\n };\n }\n };\n};\n\n/**\n * Optimizes the visibility of the floating element by shifting it in order to\n * keep it in view when it will overflow the clipping boundary.\n * @see https://floating-ui.com/docs/shift\n */\nconst shift = function (options) {\n if (options === void 0) {\n options = {};\n }\n return {\n name: 'shift',\n options,\n async fn(state) {\n const {\n x,\n y,\n placement\n } = state;\n const {\n mainAxis: checkMainAxis = true,\n crossAxis: checkCrossAxis = false,\n limiter = {\n fn: _ref => {\n let {\n x,\n y\n } = _ref;\n return {\n x,\n y\n };\n }\n },\n ...detectOverflowOptions\n } = evaluate(options, state);\n const coords = {\n x,\n y\n };\n const overflow = await detectOverflow(state, detectOverflowOptions);\n const crossAxis = getSideAxis(getSide(placement));\n const mainAxis = getOppositeAxis(crossAxis);\n let mainAxisCoord = coords[mainAxis];\n let crossAxisCoord = coords[crossAxis];\n if (checkMainAxis) {\n const minSide = mainAxis === 'y' ? 'top' : 'left';\n const maxSide = mainAxis === 'y' ? 'bottom' : 'right';\n const min = mainAxisCoord + overflow[minSide];\n const max = mainAxisCoord - overflow[maxSide];\n mainAxisCoord = clamp(min, mainAxisCoord, max);\n }\n if (checkCrossAxis) {\n const minSide = crossAxis === 'y' ? 'top' : 'left';\n const maxSide = crossAxis === 'y' ? 'bottom' : 'right';\n const min = crossAxisCoord + overflow[minSide];\n const max = crossAxisCoord - overflow[maxSide];\n crossAxisCoord = clamp(min, crossAxisCoord, max);\n }\n const limitedCoords = limiter.fn({\n ...state,\n [mainAxis]: mainAxisCoord,\n [crossAxis]: crossAxisCoord\n });\n return {\n ...limitedCoords,\n data: {\n x: limitedCoords.x - x,\n y: limitedCoords.y - y,\n enabled: {\n [mainAxis]: checkMainAxis,\n [crossAxis]: checkCrossAxis\n }\n }\n };\n }\n };\n};\n/**\n * Built-in `limiter` that will stop `shift()` at a certain point.\n */\nconst limitShift = function (options) {\n if (options === void 0) {\n options = {};\n }\n return {\n options,\n fn(state) {\n const {\n x,\n y,\n placement,\n rects,\n middlewareData\n } = state;\n const {\n offset = 0,\n mainAxis: checkMainAxis = true,\n crossAxis: checkCrossAxis = true\n } = evaluate(options, state);\n const coords = {\n x,\n y\n };\n const crossAxis = getSideAxis(placement);\n const mainAxis = getOppositeAxis(crossAxis);\n let mainAxisCoord = coords[mainAxis];\n let crossAxisCoord = coords[crossAxis];\n const rawOffset = evaluate(offset, state);\n const computedOffset = typeof rawOffset === 'number' ? {\n mainAxis: rawOffset,\n crossAxis: 0\n } : {\n mainAxis: 0,\n crossAxis: 0,\n ...rawOffset\n };\n if (checkMainAxis) {\n const len = mainAxis === 'y' ? 'height' : 'width';\n const limitMin = rects.reference[mainAxis] - rects.floating[len] + computedOffset.mainAxis;\n const limitMax = rects.reference[mainAxis] + rects.reference[len] - computedOffset.mainAxis;\n if (mainAxisCoord < limitMin) {\n mainAxisCoord = limitMin;\n } else if (mainAxisCoord > limitMax) {\n mainAxisCoord = limitMax;\n }\n }\n if (checkCrossAxis) {\n var _middlewareData$offse, _middlewareData$offse2;\n const len = mainAxis === 'y' ? 'width' : 'height';\n const isOriginSide = originSides.has(getSide(placement));\n const limitMin = rects.reference[crossAxis] - rects.floating[len] + (isOriginSide ? ((_middlewareData$offse = middlewareData.offset) == null ? void 0 : _middlewareData$offse[crossAxis]) || 0 : 0) + (isOriginSide ? 0 : computedOffset.crossAxis);\n const limitMax = rects.reference[crossAxis] + rects.reference[len] + (isOriginSide ? 0 : ((_middlewareData$offse2 = middlewareData.offset) == null ? void 0 : _middlewareData$offse2[crossAxis]) || 0) - (isOriginSide ? computedOffset.crossAxis : 0);\n if (crossAxisCoord < limitMin) {\n crossAxisCoord = limitMin;\n } else if (crossAxisCoord > limitMax) {\n crossAxisCoord = limitMax;\n }\n }\n return {\n [mainAxis]: mainAxisCoord,\n [crossAxis]: crossAxisCoord\n };\n }\n };\n};\n\n/**\n * Provides data that allows you to change the size of the floating element —\n * for instance, prevent it from overflowing the clipping boundary or match the\n * width of the reference element.\n * @see https://floating-ui.com/docs/size\n */\nconst size = function (options) {\n if (options === void 0) {\n options = {};\n }\n return {\n name: 'size',\n options,\n async fn(state) {\n var _state$middlewareData, _state$middlewareData2;\n const {\n placement,\n rects,\n platform,\n elements\n } = state;\n const {\n apply = () => {},\n ...detectOverflowOptions\n } = evaluate(options, state);\n const overflow = await detectOverflow(state, detectOverflowOptions);\n const side = getSide(placement);\n const alignment = getAlignment(placement);\n const isYAxis = getSideAxis(placement) === 'y';\n const {\n width,\n height\n } = rects.floating;\n let heightSide;\n let widthSide;\n if (side === 'top' || side === 'bottom') {\n heightSide = side;\n widthSide = alignment === ((await (platform.isRTL == null ? void 0 : platform.isRTL(elements.floating))) ? 'start' : 'end') ? 'left' : 'right';\n } else {\n widthSide = side;\n heightSide = alignment === 'end' ? 'top' : 'bottom';\n }\n const maximumClippingHeight = height - overflow.top - overflow.bottom;\n const maximumClippingWidth = width - overflow.left - overflow.right;\n const overflowAvailableHeight = min(height - overflow[heightSide], maximumClippingHeight);\n const overflowAvailableWidth = min(width - overflow[widthSide], maximumClippingWidth);\n const noShift = !state.middlewareData.shift;\n let availableHeight = overflowAvailableHeight;\n let availableWidth = overflowAvailableWidth;\n if ((_state$middlewareData = state.middlewareData.shift) != null && _state$middlewareData.enabled.x) {\n availableWidth = maximumClippingWidth;\n }\n if ((_state$middlewareData2 = state.middlewareData.shift) != null && _state$middlewareData2.enabled.y) {\n availableHeight = maximumClippingHeight;\n }\n if (noShift && !alignment) {\n const xMin = max(overflow.left, 0);\n const xMax = max(overflow.right, 0);\n const yMin = max(overflow.top, 0);\n const yMax = max(overflow.bottom, 0);\n if (isYAxis) {\n availableWidth = width - 2 * (xMin !== 0 || xMax !== 0 ? xMin + xMax : max(overflow.left, overflow.right));\n } else {\n availableHeight = height - 2 * (yMin !== 0 || yMax !== 0 ? yMin + yMax : max(overflow.top, overflow.bottom));\n }\n }\n await apply({\n ...state,\n availableWidth,\n availableHeight\n });\n const nextDimensions = await platform.getDimensions(elements.floating);\n if (width !== nextDimensions.width || height !== nextDimensions.height) {\n return {\n reset: {\n rects: true\n }\n };\n }\n return {};\n }\n };\n};\n\nexport { arrow, autoPlacement, computePosition, detectOverflow, flip, hide, inline, limitShift, offset, shift, size };\n","function hasWindow() {\n return typeof window !== 'undefined';\n}\nfunction getNodeName(node) {\n if (isNode(node)) {\n return (node.nodeName || '').toLowerCase();\n }\n // Mocked nodes in testing environments may not be instances of Node. By\n // returning `#document` an infinite loop won't occur.\n // https://github.com/floating-ui/floating-ui/issues/2317\n return '#document';\n}\nfunction getWindow(node) {\n var _node$ownerDocument;\n return (node == null || (_node$ownerDocument = node.ownerDocument) == null ? void 0 : _node$ownerDocument.defaultView) || window;\n}\nfunction getDocumentElement(node) {\n var _ref;\n return (_ref = (isNode(node) ? node.ownerDocument : node.document) || window.document) == null ? void 0 : _ref.documentElement;\n}\nfunction isNode(value) {\n if (!hasWindow()) {\n return false;\n }\n return value instanceof Node || value instanceof getWindow(value).Node;\n}\nfunction isElement(value) {\n if (!hasWindow()) {\n return false;\n }\n return value instanceof Element || value instanceof getWindow(value).Element;\n}\nfunction isHTMLElement(value) {\n if (!hasWindow()) {\n return false;\n }\n return value instanceof HTMLElement || value instanceof getWindow(value).HTMLElement;\n}\nfunction isShadowRoot(value) {\n if (!hasWindow() || typeof ShadowRoot === 'undefined') {\n return false;\n }\n return value instanceof ShadowRoot || value instanceof getWindow(value).ShadowRoot;\n}\nconst invalidOverflowDisplayValues = /*#__PURE__*/new Set(['inline', 'contents']);\nfunction isOverflowElement(element) {\n const {\n overflow,\n overflowX,\n overflowY,\n display\n } = getComputedStyle(element);\n return /auto|scroll|overlay|hidden|clip/.test(overflow + overflowY + overflowX) && !invalidOverflowDisplayValues.has(display);\n}\nconst tableElements = /*#__PURE__*/new Set(['table', 'td', 'th']);\nfunction isTableElement(element) {\n return tableElements.has(getNodeName(element));\n}\nconst topLayerSelectors = [':popover-open', ':modal'];\nfunction isTopLayer(element) {\n return topLayerSelectors.some(selector => {\n try {\n return element.matches(selector);\n } catch (_e) {\n return false;\n }\n });\n}\nconst transformProperties = ['transform', 'translate', 'scale', 'rotate', 'perspective'];\nconst willChangeValues = ['transform', 'translate', 'scale', 'rotate', 'perspective', 'filter'];\nconst containValues = ['paint', 'layout', 'strict', 'content'];\nfunction isContainingBlock(elementOrCss) {\n const webkit = isWebKit();\n const css = isElement(elementOrCss) ? getComputedStyle(elementOrCss) : elementOrCss;\n\n // https://developer.mozilla.org/en-US/docs/Web/CSS/Containing_block#identifying_the_containing_block\n // https://drafts.csswg.org/css-transforms-2/#individual-transforms\n return transformProperties.some(value => css[value] ? css[value] !== 'none' : false) || (css.containerType ? css.containerType !== 'normal' : false) || !webkit && (css.backdropFilter ? css.backdropFilter !== 'none' : false) || !webkit && (css.filter ? css.filter !== 'none' : false) || willChangeValues.some(value => (css.willChange || '').includes(value)) || containValues.some(value => (css.contain || '').includes(value));\n}\nfunction getContainingBlock(element) {\n let currentNode = getParentNode(element);\n while (isHTMLElement(currentNode) && !isLastTraversableNode(currentNode)) {\n if (isContainingBlock(currentNode)) {\n return currentNode;\n } else if (isTopLayer(currentNode)) {\n return null;\n }\n currentNode = getParentNode(currentNode);\n }\n return null;\n}\nfunction isWebKit() {\n if (typeof CSS === 'undefined' || !CSS.supports) return false;\n return CSS.supports('-webkit-backdrop-filter', 'none');\n}\nconst lastTraversableNodeNames = /*#__PURE__*/new Set(['html', 'body', '#document']);\nfunction isLastTraversableNode(node) {\n return lastTraversableNodeNames.has(getNodeName(node));\n}\nfunction getComputedStyle(element) {\n return getWindow(element).getComputedStyle(element);\n}\nfunction getNodeScroll(element) {\n if (isElement(element)) {\n return {\n scrollLeft: element.scrollLeft,\n scrollTop: element.scrollTop\n };\n }\n return {\n scrollLeft: element.scrollX,\n scrollTop: element.scrollY\n };\n}\nfunction getParentNode(node) {\n if (getNodeName(node) === 'html') {\n return node;\n }\n const result =\n // Step into the shadow DOM of the parent of a slotted node.\n node.assignedSlot ||\n // DOM Element detected.\n node.parentNode ||\n // ShadowRoot detected.\n isShadowRoot(node) && node.host ||\n // Fallback.\n getDocumentElement(node);\n return isShadowRoot(result) ? result.host : result;\n}\nfunction getNearestOverflowAncestor(node) {\n const parentNode = getParentNode(node);\n if (isLastTraversableNode(parentNode)) {\n return node.ownerDocument ? node.ownerDocument.body : node.body;\n }\n if (isHTMLElement(parentNode) && isOverflowElement(parentNode)) {\n return parentNode;\n }\n return getNearestOverflowAncestor(parentNode);\n}\nfunction getOverflowAncestors(node, list, traverseIframes) {\n var _node$ownerDocument2;\n if (list === void 0) {\n list = [];\n }\n if (traverseIframes === void 0) {\n traverseIframes = true;\n }\n const scrollableAncestor = getNearestOverflowAncestor(node);\n const isBody = scrollableAncestor === ((_node$ownerDocument2 = node.ownerDocument) == null ? void 0 : _node$ownerDocument2.body);\n const win = getWindow(scrollableAncestor);\n if (isBody) {\n const frameElement = getFrameElement(win);\n return list.concat(win, win.visualViewport || [], isOverflowElement(scrollableAncestor) ? scrollableAncestor : [], frameElement && traverseIframes ? getOverflowAncestors(frameElement) : []);\n }\n return list.concat(scrollableAncestor, getOverflowAncestors(scrollableAncestor, [], traverseIframes));\n}\nfunction getFrameElement(win) {\n return win.parent && Object.getPrototypeOf(win.parent) ? win.frameElement : null;\n}\n\nexport { getComputedStyle, getContainingBlock, getDocumentElement, getFrameElement, getNearestOverflowAncestor, getNodeName, getNodeScroll, getOverflowAncestors, getParentNode, getWindow, isContainingBlock, isElement, isHTMLElement, isLastTraversableNode, isNode, isOverflowElement, isShadowRoot, isTableElement, isTopLayer, isWebKit };\n","import { rectToClientRect, arrow as arrow$1, autoPlacement as autoPlacement$1, detectOverflow as detectOverflow$1, flip as flip$1, hide as hide$1, inline as inline$1, limitShift as limitShift$1, offset as offset$1, shift as shift$1, size as size$1, computePosition as computePosition$1 } from '@floating-ui/core';\nimport { round, createCoords, max, min, floor } from '@floating-ui/utils';\nimport { getComputedStyle as getComputedStyle$1, isHTMLElement, isElement, getWindow, isWebKit, getFrameElement, getNodeScroll, getDocumentElement, isTopLayer, getNodeName, isOverflowElement, getOverflowAncestors, getParentNode, isLastTraversableNode, isContainingBlock, isTableElement, getContainingBlock } from '@floating-ui/utils/dom';\nexport { getOverflowAncestors } from '@floating-ui/utils/dom';\n\nfunction getCssDimensions(element) {\n const css = getComputedStyle$1(element);\n // In testing environments, the `width` and `height` properties are empty\n // strings for SVG elements, returning NaN. Fallback to `0` in this case.\n let width = parseFloat(css.width) || 0;\n let height = parseFloat(css.height) || 0;\n const hasOffset = isHTMLElement(element);\n const offsetWidth = hasOffset ? element.offsetWidth : width;\n const offsetHeight = hasOffset ? element.offsetHeight : height;\n const shouldFallback = round(width) !== offsetWidth || round(height) !== offsetHeight;\n if (shouldFallback) {\n width = offsetWidth;\n height = offsetHeight;\n }\n return {\n width,\n height,\n $: shouldFallback\n };\n}\n\nfunction unwrapElement(element) {\n return !isElement(element) ? element.contextElement : element;\n}\n\nfunction getScale(element) {\n const domElement = unwrapElement(element);\n if (!isHTMLElement(domElement)) {\n return createCoords(1);\n }\n const rect = domElement.getBoundingClientRect();\n const {\n width,\n height,\n $\n } = getCssDimensions(domElement);\n let x = ($ ? round(rect.width) : rect.width) / width;\n let y = ($ ? round(rect.height) : rect.height) / height;\n\n // 0, NaN, or Infinity should always fallback to 1.\n\n if (!x || !Number.isFinite(x)) {\n x = 1;\n }\n if (!y || !Number.isFinite(y)) {\n y = 1;\n }\n return {\n x,\n y\n };\n}\n\nconst noOffsets = /*#__PURE__*/createCoords(0);\nfunction getVisualOffsets(element) {\n const win = getWindow(element);\n if (!isWebKit() || !win.visualViewport) {\n return noOffsets;\n }\n return {\n x: win.visualViewport.offsetLeft,\n y: win.visualViewport.offsetTop\n };\n}\nfunction shouldAddVisualOffsets(element, isFixed, floatingOffsetParent) {\n if (isFixed === void 0) {\n isFixed = false;\n }\n if (!floatingOffsetParent || isFixed && floatingOffsetParent !== getWindow(element)) {\n return false;\n }\n return isFixed;\n}\n\nfunction getBoundingClientRect(element, includeScale, isFixedStrategy, offsetParent) {\n if (includeScale === void 0) {\n includeScale = false;\n }\n if (isFixedStrategy === void 0) {\n isFixedStrategy = false;\n }\n const clientRect = element.getBoundingClientRect();\n const domElement = unwrapElement(element);\n let scale = createCoords(1);\n if (includeScale) {\n if (offsetParent) {\n if (isElement(offsetParent)) {\n scale = getScale(offsetParent);\n }\n } else {\n scale = getScale(element);\n }\n }\n const visualOffsets = shouldAddVisualOffsets(domElement, isFixedStrategy, offsetParent) ? getVisualOffsets(domElement) : createCoords(0);\n let x = (clientRect.left + visualOffsets.x) / scale.x;\n let y = (clientRect.top + visualOffsets.y) / scale.y;\n let width = clientRect.width / scale.x;\n let height = clientRect.height / scale.y;\n if (domElement) {\n const win = getWindow(domElement);\n const offsetWin = offsetParent && isElement(offsetParent) ? getWindow(offsetParent) : offsetParent;\n let currentWin = win;\n let currentIFrame = getFrameElement(currentWin);\n while (currentIFrame && offsetParent && offsetWin !== currentWin) {\n const iframeScale = getScale(currentIFrame);\n const iframeRect = currentIFrame.getBoundingClientRect();\n const css = getComputedStyle$1(currentIFrame);\n const left = iframeRect.left + (currentIFrame.clientLeft + parseFloat(css.paddingLeft)) * iframeScale.x;\n const top = iframeRect.top + (currentIFrame.clientTop + parseFloat(css.paddingTop)) * iframeScale.y;\n x *= iframeScale.x;\n y *= iframeScale.y;\n width *= iframeScale.x;\n height *= iframeScale.y;\n x += left;\n y += top;\n currentWin = getWindow(currentIFrame);\n currentIFrame = getFrameElement(currentWin);\n }\n }\n return rectToClientRect({\n width,\n height,\n x,\n y\n });\n}\n\n// If has a CSS width greater than the viewport, then this will be\n// incorrect for RTL.\nfunction getWindowScrollBarX(element, rect) {\n const leftScroll = getNodeScroll(element).scrollLeft;\n if (!rect) {\n return getBoundingClientRect(getDocumentElement(element)).left + leftScroll;\n }\n return rect.left + leftScroll;\n}\n\nfunction getHTMLOffset(documentElement, scroll) {\n const htmlRect = documentElement.getBoundingClientRect();\n const x = htmlRect.left + scroll.scrollLeft - getWindowScrollBarX(documentElement, htmlRect);\n const y = htmlRect.top + scroll.scrollTop;\n return {\n x,\n y\n };\n}\n\nfunction convertOffsetParentRelativeRectToViewportRelativeRect(_ref) {\n let {\n elements,\n rect,\n offsetParent,\n strategy\n } = _ref;\n const isFixed = strategy === 'fixed';\n const documentElement = getDocumentElement(offsetParent);\n const topLayer = elements ? isTopLayer(elements.floating) : false;\n if (offsetParent === documentElement || topLayer && isFixed) {\n return rect;\n }\n let scroll = {\n scrollLeft: 0,\n scrollTop: 0\n };\n let scale = createCoords(1);\n const offsets = createCoords(0);\n const isOffsetParentAnElement = isHTMLElement(offsetParent);\n if (isOffsetParentAnElement || !isOffsetParentAnElement && !isFixed) {\n if (getNodeName(offsetParent) !== 'body' || isOverflowElement(documentElement)) {\n scroll = getNodeScroll(offsetParent);\n }\n if (isHTMLElement(offsetParent)) {\n const offsetRect = getBoundingClientRect(offsetParent);\n scale = getScale(offsetParent);\n offsets.x = offsetRect.x + offsetParent.clientLeft;\n offsets.y = offsetRect.y + offsetParent.clientTop;\n }\n }\n const htmlOffset = documentElement && !isOffsetParentAnElement && !isFixed ? getHTMLOffset(documentElement, scroll) : createCoords(0);\n return {\n width: rect.width * scale.x,\n height: rect.height * scale.y,\n x: rect.x * scale.x - scroll.scrollLeft * scale.x + offsets.x + htmlOffset.x,\n y: rect.y * scale.y - scroll.scrollTop * scale.y + offsets.y + htmlOffset.y\n };\n}\n\nfunction getClientRects(element) {\n return Array.from(element.getClientRects());\n}\n\n// Gets the entire size of the scrollable document area, even extending outside\n// of the `` and `` rect bounds if horizontally scrollable.\nfunction getDocumentRect(element) {\n const html = getDocumentElement(element);\n const scroll = getNodeScroll(element);\n const body = element.ownerDocument.body;\n const width = max(html.scrollWidth, html.clientWidth, body.scrollWidth, body.clientWidth);\n const height = max(html.scrollHeight, html.clientHeight, body.scrollHeight, body.clientHeight);\n let x = -scroll.scrollLeft + getWindowScrollBarX(element);\n const y = -scroll.scrollTop;\n if (getComputedStyle$1(body).direction === 'rtl') {\n x += max(html.clientWidth, body.clientWidth) - width;\n }\n return {\n width,\n height,\n x,\n y\n };\n}\n\n// Safety check: ensure the scrollbar space is reasonable in case this\n// calculation is affected by unusual styles.\n// Most scrollbars leave 15-18px of space.\nconst SCROLLBAR_MAX = 25;\nfunction getViewportRect(element, strategy) {\n const win = getWindow(element);\n const html = getDocumentElement(element);\n const visualViewport = win.visualViewport;\n let width = html.clientWidth;\n let height = html.clientHeight;\n let x = 0;\n let y = 0;\n if (visualViewport) {\n width = visualViewport.width;\n height = visualViewport.height;\n const visualViewportBased = isWebKit();\n if (!visualViewportBased || visualViewportBased && strategy === 'fixed') {\n x = visualViewport.offsetLeft;\n y = visualViewport.offsetTop;\n }\n }\n const windowScrollbarX = getWindowScrollBarX(html);\n // `overflow: hidden` + `scrollbar-gutter: stable` reduces the\n // visual width of the but this is not considered in the size\n // of `html.clientWidth`.\n if (windowScrollbarX <= 0) {\n const doc = html.ownerDocument;\n const body = doc.body;\n const bodyStyles = getComputedStyle(body);\n const bodyMarginInline = doc.compatMode === 'CSS1Compat' ? parseFloat(bodyStyles.marginLeft) + parseFloat(bodyStyles.marginRight) || 0 : 0;\n const clippingStableScrollbarWidth = Math.abs(html.clientWidth - body.clientWidth - bodyMarginInline);\n if (clippingStableScrollbarWidth <= SCROLLBAR_MAX) {\n width -= clippingStableScrollbarWidth;\n }\n } else if (windowScrollbarX <= SCROLLBAR_MAX) {\n // If the scrollbar is on the left, the width needs to be extended\n // by the scrollbar amount so there isn't extra space on the right.\n width += windowScrollbarX;\n }\n return {\n width,\n height,\n x,\n y\n };\n}\n\nconst absoluteOrFixed = /*#__PURE__*/new Set(['absolute', 'fixed']);\n// Returns the inner client rect, subtracting scrollbars if present.\nfunction getInnerBoundingClientRect(element, strategy) {\n const clientRect = getBoundingClientRect(element, true, strategy === 'fixed');\n const top = clientRect.top + element.clientTop;\n const left = clientRect.left + element.clientLeft;\n const scale = isHTMLElement(element) ? getScale(element) : createCoords(1);\n const width = element.clientWidth * scale.x;\n const height = element.clientHeight * scale.y;\n const x = left * scale.x;\n const y = top * scale.y;\n return {\n width,\n height,\n x,\n y\n };\n}\nfunction getClientRectFromClippingAncestor(element, clippingAncestor, strategy) {\n let rect;\n if (clippingAncestor === 'viewport') {\n rect = getViewportRect(element, strategy);\n } else if (clippingAncestor === 'document') {\n rect = getDocumentRect(getDocumentElement(element));\n } else if (isElement(clippingAncestor)) {\n rect = getInnerBoundingClientRect(clippingAncestor, strategy);\n } else {\n const visualOffsets = getVisualOffsets(element);\n rect = {\n x: clippingAncestor.x - visualOffsets.x,\n y: clippingAncestor.y - visualOffsets.y,\n width: clippingAncestor.width,\n height: clippingAncestor.height\n };\n }\n return rectToClientRect(rect);\n}\nfunction hasFixedPositionAncestor(element, stopNode) {\n const parentNode = getParentNode(element);\n if (parentNode === stopNode || !isElement(parentNode) || isLastTraversableNode(parentNode)) {\n return false;\n }\n return getComputedStyle$1(parentNode).position === 'fixed' || hasFixedPositionAncestor(parentNode, stopNode);\n}\n\n// A \"clipping ancestor\" is an `overflow` element with the characteristic of\n// clipping (or hiding) child elements. This returns all clipping ancestors\n// of the given element up the tree.\nfunction getClippingElementAncestors(element, cache) {\n const cachedResult = cache.get(element);\n if (cachedResult) {\n return cachedResult;\n }\n let result = getOverflowAncestors(element, [], false).filter(el => isElement(el) && getNodeName(el) !== 'body');\n let currentContainingBlockComputedStyle = null;\n const elementIsFixed = getComputedStyle$1(element).position === 'fixed';\n let currentNode = elementIsFixed ? getParentNode(element) : element;\n\n // https://developer.mozilla.org/en-US/docs/Web/CSS/Containing_block#identifying_the_containing_block\n while (isElement(currentNode) && !isLastTraversableNode(currentNode)) {\n const computedStyle = getComputedStyle$1(currentNode);\n const currentNodeIsContaining = isContainingBlock(currentNode);\n if (!currentNodeIsContaining && computedStyle.position === 'fixed') {\n currentContainingBlockComputedStyle = null;\n }\n const shouldDropCurrentNode = elementIsFixed ? !currentNodeIsContaining && !currentContainingBlockComputedStyle : !currentNodeIsContaining && computedStyle.position === 'static' && !!currentContainingBlockComputedStyle && absoluteOrFixed.has(currentContainingBlockComputedStyle.position) || isOverflowElement(currentNode) && !currentNodeIsContaining && hasFixedPositionAncestor(element, currentNode);\n if (shouldDropCurrentNode) {\n // Drop non-containing blocks.\n result = result.filter(ancestor => ancestor !== currentNode);\n } else {\n // Record last containing block for next iteration.\n currentContainingBlockComputedStyle = computedStyle;\n }\n currentNode = getParentNode(currentNode);\n }\n cache.set(element, result);\n return result;\n}\n\n// Gets the maximum area that the element is visible in due to any number of\n// clipping ancestors.\nfunction getClippingRect(_ref) {\n let {\n element,\n boundary,\n rootBoundary,\n strategy\n } = _ref;\n const elementClippingAncestors = boundary === 'clippingAncestors' ? isTopLayer(element) ? [] : getClippingElementAncestors(element, this._c) : [].concat(boundary);\n const clippingAncestors = [...elementClippingAncestors, rootBoundary];\n const firstClippingAncestor = clippingAncestors[0];\n const clippingRect = clippingAncestors.reduce((accRect, clippingAncestor) => {\n const rect = getClientRectFromClippingAncestor(element, clippingAncestor, strategy);\n accRect.top = max(rect.top, accRect.top);\n accRect.right = min(rect.right, accRect.right);\n accRect.bottom = min(rect.bottom, accRect.bottom);\n accRect.left = max(rect.left, accRect.left);\n return accRect;\n }, getClientRectFromClippingAncestor(element, firstClippingAncestor, strategy));\n return {\n width: clippingRect.right - clippingRect.left,\n height: clippingRect.bottom - clippingRect.top,\n x: clippingRect.left,\n y: clippingRect.top\n };\n}\n\nfunction getDimensions(element) {\n const {\n width,\n height\n } = getCssDimensions(element);\n return {\n width,\n height\n };\n}\n\nfunction getRectRelativeToOffsetParent(element, offsetParent, strategy) {\n const isOffsetParentAnElement = isHTMLElement(offsetParent);\n const documentElement = getDocumentElement(offsetParent);\n const isFixed = strategy === 'fixed';\n const rect = getBoundingClientRect(element, true, isFixed, offsetParent);\n let scroll = {\n scrollLeft: 0,\n scrollTop: 0\n };\n const offsets = createCoords(0);\n\n // If the scrollbar appears on the left (e.g. RTL systems). Use\n // Firefox with layout.scrollbar.side = 3 in about:config to test this.\n function setLeftRTLScrollbarOffset() {\n offsets.x = getWindowScrollBarX(documentElement);\n }\n if (isOffsetParentAnElement || !isOffsetParentAnElement && !isFixed) {\n if (getNodeName(offsetParent) !== 'body' || isOverflowElement(documentElement)) {\n scroll = getNodeScroll(offsetParent);\n }\n if (isOffsetParentAnElement) {\n const offsetRect = getBoundingClientRect(offsetParent, true, isFixed, offsetParent);\n offsets.x = offsetRect.x + offsetParent.clientLeft;\n offsets.y = offsetRect.y + offsetParent.clientTop;\n } else if (documentElement) {\n setLeftRTLScrollbarOffset();\n }\n }\n if (isFixed && !isOffsetParentAnElement && documentElement) {\n setLeftRTLScrollbarOffset();\n }\n const htmlOffset = documentElement && !isOffsetParentAnElement && !isFixed ? getHTMLOffset(documentElement, scroll) : createCoords(0);\n const x = rect.left + scroll.scrollLeft - offsets.x - htmlOffset.x;\n const y = rect.top + scroll.scrollTop - offsets.y - htmlOffset.y;\n return {\n x,\n y,\n width: rect.width,\n height: rect.height\n };\n}\n\nfunction isStaticPositioned(element) {\n return getComputedStyle$1(element).position === 'static';\n}\n\nfunction getTrueOffsetParent(element, polyfill) {\n if (!isHTMLElement(element) || getComputedStyle$1(element).position === 'fixed') {\n return null;\n }\n if (polyfill) {\n return polyfill(element);\n }\n let rawOffsetParent = element.offsetParent;\n\n // Firefox returns the element as the offsetParent if it's non-static,\n // while Chrome and Safari return the element. The element must\n // be used to perform the correct calculations even if the element is\n // non-static.\n if (getDocumentElement(element) === rawOffsetParent) {\n rawOffsetParent = rawOffsetParent.ownerDocument.body;\n }\n return rawOffsetParent;\n}\n\n// Gets the closest ancestor positioned element. Handles some edge cases,\n// such as table ancestors and cross browser bugs.\nfunction getOffsetParent(element, polyfill) {\n const win = getWindow(element);\n if (isTopLayer(element)) {\n return win;\n }\n if (!isHTMLElement(element)) {\n let svgOffsetParent = getParentNode(element);\n while (svgOffsetParent && !isLastTraversableNode(svgOffsetParent)) {\n if (isElement(svgOffsetParent) && !isStaticPositioned(svgOffsetParent)) {\n return svgOffsetParent;\n }\n svgOffsetParent = getParentNode(svgOffsetParent);\n }\n return win;\n }\n let offsetParent = getTrueOffsetParent(element, polyfill);\n while (offsetParent && isTableElement(offsetParent) && isStaticPositioned(offsetParent)) {\n offsetParent = getTrueOffsetParent(offsetParent, polyfill);\n }\n if (offsetParent && isLastTraversableNode(offsetParent) && isStaticPositioned(offsetParent) && !isContainingBlock(offsetParent)) {\n return win;\n }\n return offsetParent || getContainingBlock(element) || win;\n}\n\nconst getElementRects = async function (data) {\n const getOffsetParentFn = this.getOffsetParent || getOffsetParent;\n const getDimensionsFn = this.getDimensions;\n const floatingDimensions = await getDimensionsFn(data.floating);\n return {\n reference: getRectRelativeToOffsetParent(data.reference, await getOffsetParentFn(data.floating), data.strategy),\n floating: {\n x: 0,\n y: 0,\n width: floatingDimensions.width,\n height: floatingDimensions.height\n }\n };\n};\n\nfunction isRTL(element) {\n return getComputedStyle$1(element).direction === 'rtl';\n}\n\nconst platform = {\n convertOffsetParentRelativeRectToViewportRelativeRect,\n getDocumentElement,\n getClippingRect,\n getOffsetParent,\n getElementRects,\n getClientRects,\n getDimensions,\n getScale,\n isElement,\n isRTL\n};\n\nfunction rectsAreEqual(a, b) {\n return a.x === b.x && a.y === b.y && a.width === b.width && a.height === b.height;\n}\n\n// https://samthor.au/2021/observing-dom/\nfunction observeMove(element, onMove) {\n let io = null;\n let timeoutId;\n const root = getDocumentElement(element);\n function cleanup() {\n var _io;\n clearTimeout(timeoutId);\n (_io = io) == null || _io.disconnect();\n io = null;\n }\n function refresh(skip, threshold) {\n if (skip === void 0) {\n skip = false;\n }\n if (threshold === void 0) {\n threshold = 1;\n }\n cleanup();\n const elementRectForRootMargin = element.getBoundingClientRect();\n const {\n left,\n top,\n width,\n height\n } = elementRectForRootMargin;\n if (!skip) {\n onMove();\n }\n if (!width || !height) {\n return;\n }\n const insetTop = floor(top);\n const insetRight = floor(root.clientWidth - (left + width));\n const insetBottom = floor(root.clientHeight - (top + height));\n const insetLeft = floor(left);\n const rootMargin = -insetTop + \"px \" + -insetRight + \"px \" + -insetBottom + \"px \" + -insetLeft + \"px\";\n const options = {\n rootMargin,\n threshold: max(0, min(1, threshold)) || 1\n };\n let isFirstUpdate = true;\n function handleObserve(entries) {\n const ratio = entries[0].intersectionRatio;\n if (ratio !== threshold) {\n if (!isFirstUpdate) {\n return refresh();\n }\n if (!ratio) {\n // If the reference is clipped, the ratio is 0. Throttle the refresh\n // to prevent an infinite loop of updates.\n timeoutId = setTimeout(() => {\n refresh(false, 1e-7);\n }, 1000);\n } else {\n refresh(false, ratio);\n }\n }\n if (ratio === 1 && !rectsAreEqual(elementRectForRootMargin, element.getBoundingClientRect())) {\n // It's possible that even though the ratio is reported as 1, the\n // element is not actually fully within the IntersectionObserver's root\n // area anymore. This can happen under performance constraints. This may\n // be a bug in the browser's IntersectionObserver implementation. To\n // work around this, we compare the element's bounding rect now with\n // what it was at the time we created the IntersectionObserver. If they\n // are not equal then the element moved, so we refresh.\n refresh();\n }\n isFirstUpdate = false;\n }\n\n // Older browsers don't support a `document` as the root and will throw an\n // error.\n try {\n io = new IntersectionObserver(handleObserve, {\n ...options,\n // Handle