[
  {
    "path": ".gitattributes",
    "content": "*.pbxproj -text\n"
  },
  {
    "path": ".github/FUNDING.yml",
    "content": "# These are supported funding model platforms\n\ngithub: gorhom\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/bug_template.yaml",
    "content": "name: Bug Report\ndescription: File a bug report.\ntitle: \"[Bug]: \"\nlabels: [\"bug\", \"triage\"]\nbody:\n  - type: markdown\n    attributes:\n      value: |\n        Thanks for taking the time to fill out this bug report!\n\n        ⚠️ **Please note that issues that do not follow the template will be closed.**\n        ## Environment Info\n  - type: dropdown\n    id: version\n    attributes:\n      label: Version\n      description: What version of the library are you using?\n      options:\n        - v5\n        - v4 (deprecated)\n        - v2 (deprecated)\n      default: 0\n    validations:\n      required: true\n  - type: dropdown\n    id: ra-version\n    attributes:\n      label: Reanimated Version\n      description: What version of React Native Reanimated are you using?\n      options:\n        - v3\n        - v2 (deprecated)\n        - v1 (deprecated)\n      default: 0\n    validations:\n      required: true\n  - type: dropdown\n    id: gh-version\n    attributes:\n      label: Gesture Handler Version\n      description: What version of Gesture Handler are you using?\n      options:\n        - v2\n        - v1 (deprecated)\n      default: 0\n    validations:\n      required: true\n\n  - type: dropdown\n    id: platform\n    attributes:\n      label: Platforms\n      description: What platform\\s this bug is occurring on?\n      multiple: true\n      options:\n        - iOS\n        - Android\n        - Web\n    validations:\n      required: true\n\n  - type: textarea\n    id: what-happened\n    attributes:\n      label: What happened?\n      description: Please provide a clear and concise description of what the bug is? Include screenshots or gifs if needed.\n      placeholder: Tell us what happened?\n    validations:\n      required: true\n\n  - type: textarea\n    id: repo-steps\n    attributes:\n      label: Reproduction steps\n      description: You must provide a clear list of steps and code to reproduce the problem.\n      placeholder: ex. - drag the bottom sheet...\n      value: \"- \"\n    validations:\n      required: true\n\n  - type: input\n    id: snack\n    attributes:\n      label: Reproduction sample\n      description: You must provide a reproduction sample code using **Expo Snack** [issue reproduction template](https://snack.expo.dev/@gorhom/bottom-sheet---issue-reproduction-template)\n      placeholder: ex. https://snack.expo.dev/@gorhom/bottom-sheet---issue-reproduction-template\n    validations:\n      required: true\n\n  - type: textarea\n    id: logs\n    attributes:\n      label: Relevant log output\n      description: Please copy and paste any relevant log output. This will be automatically formatted into code, so no need for backticks.\n      render: shell\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/feature_request.md",
    "content": "---\nname: Feature request\nabout: Suggest an idea for this project\ntitle: ''\nlabels: enhancement\nassignees: ''\n\n---\n\n# Feature Request\n\n<!--\n  This issue should serve for you to present or pitch an idea to the maintainers - but remember that it would be better if you were to submit a PR instead 🤗\n-->\n\n## Why it is needed\n\n<!--\n  Please tell us a bit more of why you want this feature to be added, what's its origin\n-->\n\n## Possible implementation\n\n<!--\n  It really helps if you could describe from a technical POV how this new feature would work, which code it rely on, etc\n-->\n\n### Code sample\n\n<!--\n  Please show how the new code could work, if doable\n-->\n"
  },
  {
    "path": ".github/PULL_REQUEST_TEMPLATE.md",
    "content": "Please provide enough information so that others can review your pull request:\n\n## Motivation\n\nExplain the **motivation** for making this change. What existing problem does the pull request solve?\n\n"
  },
  {
    "path": ".github/workflows/auto-close.yml",
    "content": "name: Auto Close Issue Workflow\n\non:\n  issues:\n    types: \n      - opened\n      - reopened\n      - edited\n\nenv:\n  GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}\n  NUMBER: ${{ github.event.issue.number }}\n  USER: ${{ github.event.issue.user.login }}\n  REPO: \"gorhom/react-native-bottom-sheet\"\n\njobs:\n  autoclose:\n    if: ${{ !contains(github.event.issue.body, 'snack.expo.dev') && !contains(github.event.issue.body, 'gorhom.dev')}}\n    runs-on: ubuntu-latest\n    permissions:\n      issues: write\n    steps:\n      - name: Close Issue\n        run: gh issue close \"$NUMBER\" --comment \"Hello @$USER :wave:, this issue is being automatically closed and locked because it does not follow the issue template.\" --repo \"$REPO\"\n      - name: Label Issue\n        run: gh issue edit \"$NUMBER\" --add-label \"invalid\" --repo \"$REPO\"\n      - name: Lock Issue\n        run: gh issue lock \"$NUMBER\" -r \"spam\" --repo \"$REPO\""
  },
  {
    "path": ".github/workflows/label-sponsors.yml",
    "content": "name: Label sponsors\non:\n  pull_request:\n    types: [opened]\n  issues:\n    types: [opened]\njobs:\n  build:\n    name: is-sponsor-label\n    runs-on: ubuntu-latest\n    steps:\n      - uses: JasonEtco/is-sponsor-label-action@v1.2.0\n        with:\n          label: sponsor\n        env:\n          GITHUB_TOKEN: ${{ secrets.ACTIONS_TOKEN }}\n"
  },
  {
    "path": ".github/workflows/stale.yml",
    "content": "name: Mark stale issues and pull requests\n\non:\n  schedule:\n  - cron: '39 9 * * *'\n\njobs:\n  stale:\n\n    runs-on: ubuntu-latest\n    permissions:\n      issues: write\n      pull-requests: write\n\n    steps:\n    - uses: actions/stale@v5.0.0\n      with:\n        repo-token: ${{ secrets.GITHUB_TOKEN }}\n        stale-issue-message: 'This issue is stale because it has been open 30 days with no activity. Remove stale label or comment or this will be closed in 5 days.'\n        stale-pr-message: 'This PR is stale because it has been open 30 days with no activity. Remove stale label or comment or this will be closed in 10 days.'\n        close-issue-message: 'This issue was closed because it has been stalled for 5 days with no activity.'\n        stale-issue-label: 'no-issue-activity'\n        stale-pr-label: 'no-pr-activity'\n        days-before-stale: 30\n        days-before-pr-stale: 30\n        days-before-close: 5\n        days-before-pr-close: 10\n        exempt-assignees: 'gorhom'\n        exempt-issue-labels: 'sponsor'\n        exempt-pr-labels: 'sponsor'\n"
  },
  {
    "path": ".github/workflows/website.yml",
    "content": "name: Deploy to GitHub Pages\n\non:\n  push:\n    branches:\n      - master\n    paths:\n      - 'website/**'\n\njobs:\n  build:\n    name: Build Docusaurus\n    runs-on: ubuntu-latest\n    steps:\n      - uses: actions/checkout@v4\n        with:\n          fetch-depth: 0\n      - uses: actions/setup-node@v4\n        with:\n          node-version: 18\n          cache: yarn\n\n      - name: Install dependencies\n        working-directory: website\n        run: yarn install --frozen-lockfile\n      - name: Build website\n        working-directory: website\n        run: yarn build\n\n      - name: Upload Build Artifact\n        uses: actions/upload-pages-artifact@v3\n        with:\n          path: website/build\n\n  deploy:\n    name: Deploy to GitHub Pages\n    needs: build\n\n    # Grant GITHUB_TOKEN the permissions required to make a Pages deployment\n    permissions:\n      pages: write # to deploy to Pages\n      id-token: write # to verify the deployment originates from an appropriate source\n\n    # Deploy to the github-pages environment\n    environment:\n      name: github-pages\n      url: ${{ steps.deployment.outputs.page_url }}\n\n    runs-on: ubuntu-latest\n    steps:\n      - name: Deploy to GitHub Pages\n        id: deployment\n        uses: actions/deploy-pages@v4"
  },
  {
    "path": ".gitignore",
    "content": "# OSX\n#\n.DS_Store\n\n# XDE\n.expo/\n\n# VSCode\njsconfig.json\n\n# Xcode\n#\nbuild/\n*.pbxuser\n!default.pbxuser\n*.mode1v3\n!default.mode1v3\n*.mode2v3\n!default.mode2v3\n*.perspectivev3\n!default.perspectivev3\nxcuserdata\n*.xccheckout\n*.moved-aside\nDerivedData\n*.hmap\n*.ipa\n*.xcuserstate\nproject.xcworkspace\n\n# Android/IJ\n#\n.idea\n.gradle\nlocal.properties\nandroid.iml\n\n# Cocoapods\n#\nPods/\n\n# node.js\n#\nnode_modules\nnpm-debug.log\nyarn-debug.log\nyarn-error.log\nyarn.lock\nexample/yarn.lock\n\n# BUCK\nbuck-out/\n\\.buckd/\nandroid/app/libs\nandroid/keystores/debug.keystore\n\n# generated by bob\nlib/\n\n# Dependencies\ndocs/node_modules\n\n# Production\ndocs//build\n\n# Generated files\ndocs/.docusaurus\ndocs/.cache-loader\n\n# Misc\ndocs/.DS_Store\ndocs/.env.local\ndocs/.env.development.local\ndocs/.env.test.local\ndocs/.env.production.local\n\ndocs/npm-debug.log*\ndocs/yarn-debug.log*\ndocs/yarn-error.log*\n"
  },
  {
    "path": ".huskyrc.json",
    "content": "{\n  \"hooks\": {\n    \"commit-msg\": \"commitlint -E HUSKY_GIT_PARAMS\",\n    \"pre-commit\": \"lint-staged\"\n  }\n}\n"
  },
  {
    "path": ".release-it.json",
    "content": "{\n  \"git\": {\n    \"push\": true,\n    \"tagName\": \"v${version}\",\n    \"commitMessage\": \"chore: release v${version}\"\n  },\n  \"github\": {\n    \"release\": true\n  },\n  \"npm\": {\n    \"publish\": false\n  },\n  \"plugins\": {\n    \"@release-it/conventional-changelog\": {\n      \"preset\": {\n        \"name\": \"conventionalcommits\",\n        \"types\": [\n          {\n            \"type\": \"feat\",\n            \"section\": \"🚀 New Features\"\n          },\n          {\n            \"type\": \"fix\",\n            \"section\": \"🐛 Bug Fixes\"\n          },\n          {\n            \"type\": \"chore\",\n            \"section\": \"🧹 Maintenance Chores\"\n          },\n          {\n            \"type\": \"refactor\",\n            \"section\": \"♻️ Code Refactor\"\n          }\n        ]\n      },\n      \"infile\": \"CHANGELOG.md\"\n    }\n  }\n}\n"
  },
  {
    "path": ".vscode/settings.json",
    "content": "{\n  \"editor.defaultFormatter\": \"biomejs.biome\",\n  \"editor.formatOnSave\": true,\n  \"editor.codeActionsOnSave\": {\n    \"source.fixAll.biome\": \"explicit\",\n    \"source.organizeImports.biome\": \"explicit\"\n  },\n  \"[typescriptreact]\": {\n    \"editor.defaultFormatter\": \"biomejs.biome\"\n  },\n  \"[javascript]\": {\n    \"editor.defaultFormatter\": \"biomejs.biome\"\n  },\n  \"[typescript]\": {\n    \"editor.defaultFormatter\": \"biomejs.biome\"\n  },\n  \"[json]\": {\n    \"editor.defaultFormatter\": \"biomejs.biome\"\n  },\n  \"[jsonc]\": {\n    \"editor.defaultFormatter\": \"biomejs.biome\"\n  }\n}\n"
  },
  {
    "path": "CHANGELOG.md",
    "content": "# Changelog\n\n## [5.2.8](https://github.com/gorhom/react-native-bottom-sheet/compare/v5.2.7...v5.2.8) (2025-12-04)\n\n### 🐛 Bug Fixes\n\n* **mock:** replace JSX syntax with `createElement` ([#2302](https://github.com/gorhom/react-native-bottom-sheet/issues/2302))(by [@huextrat](https://github.com/huextrat)) ([fdeff8f](https://github.com/gorhom/react-native-bottom-sheet/commit/fdeff8f289186672a14013e404d143922a9be232))\n* removed deprecated Easing constant ([#2486](https://github.com/gorhom/react-native-bottom-sheet/issues/2486))(by [@joshua-zbni](https://github.com/joshua-zbni)) ([164d982](https://github.com/gorhom/react-native-bottom-sheet/commit/164d9828b40aeb18f52925731e9602db40c699a5))\n\n### 🧹 Maintenance Chores\n\n* updated example deps ([f3aa263](https://github.com/gorhom/react-native-bottom-sheet/commit/f3aa26310ea6ebc353031c17884e0f4b3a6a3f4d))\n\n## [5.2.7](https://github.com/gorhom/react-native-bottom-sheet/compare/v5.2.6...v5.2.7) (2025-11-26)\n\n### 🐛 Bug Fixes\n\n* fixed function undefined error in useBoundingClientRect ([#2561](https://github.com/gorhom/react-native-bottom-sheet/issues/2561))(by [@tylerdgenius](https://github.com/tylerdgenius), [@fab-nikhil](https://github.com/fab-nikhil), [@pinpong](https://github.com/pinpong)) ([3a99ee4](https://github.com/gorhom/react-native-bottom-sheet/commit/3a99ee4a2bc69ed280f045951edf4cfcf6bc6581))\n\n### 🧹 Maintenance Chores\n\n* updated ts tags for getBoundingClientRect ([6b22037](https://github.com/gorhom/react-native-bottom-sheet/commit/6b220371a4b591ac694cf1a8e16173f28ccdbba5))\n\n## [5.2.6](https://github.com/gorhom/react-native-bottom-sheet/compare/v5.2.5...v5.2.6) (2025-09-05)\n\n### 🐛 Bug Fixes\n\n* **#2452:** prevented the bottom sheet from snapping to -1 when resizing the detent while keyboard is open([#2327](https://github.com/gorhom/react-native-bottom-sheet/issues/2327))(by [@pakerwreah](https://github.com/pakerwreah)) ([c68edac](https://github.com/gorhom/react-native-bottom-sheet/commit/c68edacf50b76ca08ac599a8485a533c710c6289)), closes [#2452](https://github.com/gorhom/react-native-bottom-sheet/issues/2452)\n* prevent the bottom sheet from closing when over dragging while keyboard is open ([cce1f7e](https://github.com/gorhom/react-native-bottom-sheet/commit/cce1f7e0cc1b0d3c2a0014ba17624f8671816e15))\n\n## [5.2.5](https://github.com/gorhom/react-native-bottom-sheet/compare/v5.2.4...v5.2.5) (2025-09-04)\n\n### 🐛 Bug Fixes\n\n* **#2449:** adjust next index to current index when animating to a temporary position ([20de151](https://github.com/gorhom/react-native-bottom-sheet/commit/20de1513f571e079d243da9f3bbf3688f10acf7b)), closes [#2449](https://github.com/gorhom/react-native-bottom-sheet/issues/2449)\n* **#2449:** adjust next index to the highest detent index when animating by keyboard ([f8cd4fe](https://github.com/gorhom/react-native-bottom-sheet/commit/f8cd4fe37c1b05abd4153f586d61658a3d7954b8)), closes [#2449](https://github.com/gorhom/react-native-bottom-sheet/issues/2449)\n* conditionally apply web-only cursor style to avoid TypeScript error ([#2420](https://github.com/gorhom/react-native-bottom-sheet/issues/2420))(by [@kirstilynn](https://github.com/kirstilynn)) ([e5c077b](https://github.com/gorhom/react-native-bottom-sheet/commit/e5c077b9cc630d256ca8d9a895a35b1989394d7a))\n\n### 🧹 Maintenance Chores\n\n* updated the example deps ([c9e0473](https://github.com/gorhom/react-native-bottom-sheet/commit/c9e0473f097d61d467449b68af1170e58267136a))\n\n## [5.2.4](https://github.com/gorhom/react-native-bottom-sheet/compare/v5.2.3...v5.2.4) (2025-08-28)\n\n### 🐛 Bug Fixes\n\n* **#2430:** fixed flickering issue with animation by keyboard ([334e94c](https://github.com/gorhom/react-native-bottom-sheet/commit/334e94c5ffd700261201c07bd153711d38b09ef6))\n* **#2430:** fixed the force closing when switching between two text inputs ([086baed](https://github.com/gorhom/react-native-bottom-sheet/commit/086baeda48be71b9b8d020e1b680573a92218b18))\n* **#2431:** added handling for evaluating position for detent change while animating ([090afa6](https://github.com/gorhom/react-native-bottom-sheet/commit/090afa64338e27882ae4c32b090e9ce72a2ba38a)), closes [#2431](https://github.com/gorhom/react-native-bottom-sheet/issues/2431)\n* memoized the scrollable creator hook ([e51e523](https://github.com/gorhom/react-native-bottom-sheet/commit/e51e52382ee561a2db6022af36ab5181e07c8042))\n\n### 🧹 Maintenance Chores\n\n* updated biome dep ([eb03ab0](https://github.com/gorhom/react-native-bottom-sheet/commit/eb03ab074dc17df9c3ff404f645db3bfbc0c6aab))\n\n## [5.2.3](https://github.com/gorhom/react-native-bottom-sheet/compare/v5.2.2...v5.2.3) (2025-08-18)\n\n## [5.2.2](https://github.com/gorhom/react-native-bottom-sheet/compare/v5.2.1...v5.2.2) (2025-08-18)\n\n### 🐛 Bug Fixes\n\n* **#2364:** fixed layouting issue when dynamic sizing enabled and handle is not provided ([d3275b1](https://github.com/gorhom/react-native-bottom-sheet/commit/d3275b1e97ab7ed975cc28ddcfaa2ffb25624c98))\n\n## [5.2.1](https://github.com/gorhom/react-native-bottom-sheet/compare/v5.2.0...v5.2.1) (2025-08-18)\n\n### 🐛 Bug Fixes\n\n* **#2418:** updated nullability check for highestDetentPosition ([b51ea61](https://github.com/gorhom/react-native-bottom-sheet/commit/b51ea619a2c36d5a2514ad00a43928e206db0512)), closes [#2418](https://github.com/gorhom/react-native-bottom-sheet/issues/2418)\n\n## [5.2.0](https://github.com/gorhom/react-native-bottom-sheet/compare/v5.1.8...v5.2.0) (2025-08-17)\n\n### 🚀 New Features\n\n* added a scrollable creator hook to allow integrate with third party list libraries ([d6250e2](https://github.com/gorhom/react-native-bottom-sheet/commit/d6250e20b19801c5ea50af3e369904ebb90eb7b9))\n\n### 🐛 Bug Fixes\n\n* **#2356:** added missing dependencies to callback hooks ([#2382](https://github.com/gorhom/react-native-bottom-sheet/issues/2382)) ([dfaec13](https://github.com/gorhom/react-native-bottom-sheet/commit/dfaec131efde3126f6ff11e2fd409fd94864ef8c)), closes [#2356](https://github.com/gorhom/react-native-bottom-sheet/issues/2356) [#2356](https://github.com/gorhom/react-native-bottom-sheet/issues/2356)\n\n### 🧹 Maintenance Chores\n\n* updated animated layout hook default return ([99efdd7](https://github.com/gorhom/react-native-bottom-sheet/commit/99efdd77c49db49039afabb14a8d34cd68764afc))\n* updated example deps ([248ddd9](https://github.com/gorhom/react-native-bottom-sheet/commit/248ddd97a098627773114d1784c3abb0c5bd028e))\n* updated examples ([eb95f3a](https://github.com/gorhom/react-native-bottom-sheet/commit/eb95f3a65e7a7ecd6b317b9e2a28df79780215c7))\n* updated types ([a123b17](https://github.com/gorhom/react-native-bottom-sheet/commit/a123b179e3fd86c54b601f9caf2f1f936a79b187))\n\n### ♻️ Code Refactor\n\n* added isForcedClosing to animation state ([ab97f77](https://github.com/gorhom/react-native-bottom-sheet/commit/ab97f7755683ff2553e4daaee471fc6db6adf2ee))\n* optimise animation state ([63dc473](https://github.com/gorhom/react-native-bottom-sheet/commit/63dc4733c20e7d9dd4b1f8a5a80894a8395420b8))\n* optimise keyboard state, and remove redundant variables ([bd6c8c6](https://github.com/gorhom/react-native-bottom-sheet/commit/bd6c8c66f5617e0c398047a3c0934ab75105b17a))\n* optimise layout state ([4dfe07a](https://github.com/gorhom/react-native-bottom-sheet/commit/4dfe07a1a49e5e7a2faf339535d2dc7678f71323))\n* optimise next position state ([3d6add6](https://github.com/gorhom/react-native-bottom-sheet/commit/3d6add6d8e9570165241c0c801953c72b47c2921))\n* optimise scrollable state ([bacca9d](https://github.com/gorhom/react-native-bottom-sheet/commit/bacca9d024df6be1157e19a607b85ded84d69b7e))\n* optimise snap points/detents state ([5de7bd3](https://github.com/gorhom/react-native-bottom-sheet/commit/5de7bd343492d7f0ac978502431a1465e2d7299c))\n* removed isContentHeightFixed shared value ([e26426a](https://github.com/gorhom/react-native-bottom-sheet/commit/e26426a17e4793b7749d337fc549d118db0111f2))\n* removed next position animated value ([b81a1fd](https://github.com/gorhom/react-native-bottom-sheet/commit/b81a1fd31641b4440754be70c5007add418621b7))\n\n## [5.1.8](https://github.com/gorhom/react-native-bottom-sheet/compare/v5.1.6...v5.1.8) (2025-07-27)\n\n\n### Bug Fixes\n\n* added support for reanimated v4 ([#2223](https://github.com/gorhom/react-native-bottom-sheet/issues/2223))(by [@skusnierz](https://github.com/skusnierz)) ([d96a18e](https://github.com/gorhom/react-native-bottom-sheet/commit/d96a18eb113739bb7707e2f61e17ece2afb3b174))\n* migrate from `useWorkletCallback` ([#2356](https://github.com/gorhom/react-native-bottom-sheet/issues/2356))(by [@tomekzaw](https://github.com/tomekzaw)) ([3620972](https://github.com/gorhom/react-native-bottom-sheet/commit/3620972160f987b4437c06927a9ab768fbffe843))\n\n## [5.1.7](https://github.com/gorhom/react-native-bottom-sheet/compare/v5.1.6...v5.1.7) (2025-07-27)\n\n## [5.1.6](https://github.com/gorhom/react-native-bottom-sheet/compare/v5.1.5...v5.1.6) (2025-06-03)\n\n\n### Bug Fixes\n\n* **#2267:** early exit when attempting to snap to index while layout is not ready ([0715f03](https://github.com/gorhom/react-native-bottom-sheet/commit/0715f0384a187cdb1df903d693666ac4b12db807)), closes [#2267](https://github.com/gorhom/react-native-bottom-sheet/issues/2267)\n* **#2278:** removed flashlist for web ([e17096f](https://github.com/gorhom/react-native-bottom-sheet/commit/e17096feade145f9e6349815398f8aaae758d554)), closes [#2278](https://github.com/gorhom/react-native-bottom-sheet/issues/2278)\n* added positions to onAnimate, and prevent index to be negative with keyboard animations ([#2271](https://github.com/gorhom/react-native-bottom-sheet/issues/2271))(by [@souyahia](https://github.com/souyahia)) ([898270e](https://github.com/gorhom/react-native-bottom-sheet/commit/898270e62e0f83c8f8df671a60d6aabe749d890e))\n* allow bottom sheet view to resize it self when its content resized ([5397478](https://github.com/gorhom/react-native-bottom-sheet/commit/53974786a18aceab1cc15def1b29c94ef93002e3))\n* updated BottomSheetModal mock, add createBottomSheetScrollableComponent and enum mocks ([#2265](https://github.com/gorhom/react-native-bottom-sheet/issues/2265))(by [@gabimoncha](https://github.com/gabimoncha)) ([a77904a](https://github.com/gorhom/react-native-bottom-sheet/commit/a77904ac935278bec4e086700e1e93baa54282b6))\n\n## [5.1.5](https://github.com/gorhom/react-native-bottom-sheet/compare/v5.1.4...v5.1.5) (2025-05-26)\n\n\n### Bug Fixes\n\n* **#2237:** fixed node handle lookup for virtualized list on web (by [@btoo](https://github.com/btoo)) ([6442b0e](https://github.com/gorhom/react-native-bottom-sheet/commit/6442b0ea54a38d8dcb82f63aade077ead29d382b))\n* **#2288:** added unique id to the root bottom sheet modal portal ([711ea7a](https://github.com/gorhom/react-native-bottom-sheet/commit/711ea7a5290ef485b9ba5c65eb45e28d6e495b43)), closes [#2288](https://github.com/gorhom/react-native-bottom-sheet/issues/2288)\n* fixed initial content height calculation on web ([4db946e](https://github.com/gorhom/react-native-bottom-sheet/commit/4db946e4af331bb2d3a80002ee6051da9f3593eb))\n* prevent canceling touchmove events when not cancelable ([#2244](https://github.com/gorhom/react-native-bottom-sheet/issues/2244))(by [@erickreutz](https://github.com/erickreutz)) ([14d5d1e](https://github.com/gorhom/react-native-bottom-sheet/commit/14d5d1e89f22b5101445799fd0cb836ecb7c4882))\n* provide the portal host name with use portal ([67e9097](https://github.com/gorhom/react-native-bottom-sheet/commit/67e909711164aba900c2764034723c8b0e051704))\n\n## [5.1.4](https://github.com/gorhom/react-native-bottom-sheet/compare/v5.1.3...v5.1.4) (2025-05-04)\n\n\n### Bug Fixes\n\n* **#2237:** fixed recursive loop in findNodeHandle.web (by @TNAJanssen) ([3556ba8](https://github.com/gorhom/react-native-bottom-sheet/commit/3556ba8e1445a78dfc6cfc93997500d52a03368e))\n\n## [5.1.3](https://github.com/gorhom/react-native-bottom-sheet/compare/v5.1.2...v5.1.3) (2025-05-04)\n\n\n### Bug Fixes\n\n* **#2237:** updated findNodeHandle for web to support React 19 ([47a95f5](https://github.com/gorhom/react-native-bottom-sheet/commit/47a95f517ab5b4680d0f5a45b09464911aafd35e)), closes [#2237](https://github.com/gorhom/react-native-bottom-sheet/issues/2237)\n\n## [5.1.2](https://github.com/gorhom/react-native-bottom-sheet/compare/v5.1.1...v5.1.2) (2025-03-09)\n\n\n### Bug Fixes\n\n* **#2163:** restart closing animation when container height get updated ([4ed9f3c](https://github.com/gorhom/react-native-bottom-sheet/commit/4ed9f3cb542316a984893efa2025ca5384ffe89a)), closes [#2163](https://github.com/gorhom/react-native-bottom-sheet/issues/2163)\n* **#2177:** set absolute fill to backdrop default style ([979ba7c](https://github.com/gorhom/react-native-bottom-sheet/commit/979ba7ce0b9d69abfaefd169ee692bf818fa4d0d)), closes [#2177](https://github.com/gorhom/react-native-bottom-sheet/issues/2177)\n\n## [5.1.1](https://github.com/gorhom/react-native-bottom-sheet/compare/v5.1.0...v5.1.1) (2025-02-09)\n\n\n### Bug Fixes\n\n* **#2043:** handle unnecessary invocation of index side effect ([#2073](https://github.com/gorhom/react-native-bottom-sheet/issues/2073))(inspired by @IslamRustamov) ([2164c02](https://github.com/gorhom/react-native-bottom-sheet/commit/2164c02e63177f9ac69acc05722c85e8d55cd931)), closes [#2043](https://github.com/gorhom/react-native-bottom-sheet/issues/2043)\n\n# [5.1.0](https://github.com/gorhom/react-native-bottom-sheet/compare/v5.0.6...v5.1.0) (2025-02-06)\n\n\n### Bug Fixes\n\n* **#2129:** fixed initial isAnimatedOnMount value ([0850cb8](https://github.com/gorhom/react-native-bottom-sheet/commit/0850cb864819f79189592cb66c2b6d179957ba61))\n\n\n### Features\n\n* added enableBlurKeyboardOnGesture prop to handle blurring keyboard on gesture ([1c31aca](https://github.com/gorhom/react-native-bottom-sheet/commit/1c31acad50a7c171548ea7f4594a4d1d563cf40f))\n\n## [5.0.6](https://github.com/gorhom/react-native-bottom-sheet/compare/v5.0.5...v5.0.6) (2024-11-17)\n\n\n### Bug Fixes\n\n* clipped views when keyboard is closing ([2320a81](https://github.com/gorhom/react-native-bottom-sheet/commit/2320a81f95e696e22debe5a823740f51fadae0f6))\n* removed keyboard height setting from hide event ([61473b5](https://github.com/gorhom/react-native-bottom-sheet/commit/61473b56c3389e5ac9edfeb1dc4b93907e3b5d05))\n* updated useStableCallback to set callback in ref without useEffect ([#2010](https://github.com/gorhom/react-native-bottom-sheet/issues/2010))(by [@pavel-krasnov](https://github.com/pavel-krasnov)) ([e898859](https://github.com/gorhom/react-native-bottom-sheet/commit/e89885936391f5ce106983d8aac814bcb422e82c))\n* useStableCallback implementation ([87a73c5](https://github.com/gorhom/react-native-bottom-sheet/commit/87a73c59b83ef0b3868c12403a467ea3aebf0dd5))\n\n## [5.0.5](https://github.com/gorhom/react-native-bottom-sheet/compare/v5.0.4...v5.0.5) (2024-10-26)\n\n\n### Bug Fixes\n\n* **#1983:** updated shared values access as hook dependancies ([#1992](https://github.com/gorhom/react-native-bottom-sheet/issues/1992))(by [@pinpong](https://github.com/pinpong)) ([9757bd2](https://github.com/gorhom/react-native-bottom-sheet/commit/9757bd251cba67cf26489640f20fd1557b1a426e)), closes [#1983](https://github.com/gorhom/react-native-bottom-sheet/issues/1983) [#1983](https://github.com/gorhom/react-native-bottom-sheet/issues/1983)\n* added BottomSheetFlashList mock ([#1988](https://github.com/gorhom/react-native-bottom-sheet/issues/1988))(by @Fadikk367) ([13c7d47](https://github.com/gorhom/react-native-bottom-sheet/commit/13c7d47beae6f2451968d30e862f0ea49b7199b6))\n\n## [5.0.4](https://github.com/gorhom/react-native-bottom-sheet/compare/v5.0.3...v5.0.4) (2024-10-20)\n\n\n### Bug Fixes\n\n* **#1983:** updated shared values access as hook dependancies ([ae41b2d](https://github.com/gorhom/react-native-bottom-sheet/commit/ae41b2da650d2be614d840fbdfe1d29db6d7a575)), closes [#1983](https://github.com/gorhom/react-native-bottom-sheet/issues/1983)\n* **#1987:** updated provided style handling for bottom sheet view ([4c8ae25](https://github.com/gorhom/react-native-bottom-sheet/commit/4c8ae252b8ec0bb420b60f8314cc7f04ed12b519)), closes [#1987](https://github.com/gorhom/react-native-bottom-sheet/issues/1987)\n\n## [5.0.3](https://github.com/gorhom/react-native-bottom-sheet/compare/v5.0.2...v5.0.3) (2024-10-20)\n\n\n### Bug Fixes\n\n* added children type to containerComponent prop type ([#1971](https://github.com/gorhom/react-native-bottom-sheet/issues/1971))(by @Nodonisko) ([203e52f](https://github.com/gorhom/react-native-bottom-sheet/commit/203e52fa5be3e167522776f184d79511bdf35344))\n* dynamic sizing with detached static views ([b72e275](https://github.com/gorhom/react-native-bottom-sheet/commit/b72e27519c36671d84973f8b0b9cd1f8a7a8b8c1))\n* fixed dynamic scrollables content size with footer in place ([ace0da7](https://github.com/gorhom/react-native-bottom-sheet/commit/ace0da7475d68d4f27d386ead9f71c2eb19fbe31))\n* updated reduce motion handling, to respeact user setting and allow overriding ([1ef05c7](https://github.com/gorhom/react-native-bottom-sheet/commit/1ef05c7fee821c356220452ccf61d33d29483c00))\n\n## [5.0.2](https://github.com/gorhom/react-native-bottom-sheet/compare/v5.0.1...v5.0.2) (2024-10-14)\n\n\n### Bug Fixes\n\n* **#1035,#1043:** updated default animatedNextPositionIndex to INITIAL_VALUE ([#1960](https://github.com/gorhom/react-native-bottom-sheet/issues/1960))(by [@dfalling](https://github.com/dfalling)) ([1cf3e41](https://github.com/gorhom/react-native-bottom-sheet/commit/1cf3e4167f2ffacf36c7abebb527f79048754121)), closes [#1035](https://github.com/gorhom/react-native-bottom-sheet/issues/1035) [#1043](https://github.com/gorhom/react-native-bottom-sheet/issues/1043)\n* **#1968:** moved the flashlist optional import into the component body ([ab33e21](https://github.com/gorhom/react-native-bottom-sheet/commit/ab33e2132f8e6fdb4a3c36e34c0f2ff04e09f11f)), closes [#1968](https://github.com/gorhom/react-native-bottom-sheet/issues/1968)\n\n## [5.0.1](https://github.com/gorhom/react-native-bottom-sheet/compare/v5.0.0...v5.0.1) (2024-10-14)\n\n\n### Bug Fixes\n\n* removed redundant dependency ([3ffc7f7](https://github.com/gorhom/react-native-bottom-sheet/commit/3ffc7f70e8769fc1ecc39754111754b53d12bff8))\n\n# [5.0.0](https://github.com/gorhom/react-native-bottom-sheet/compare/v4.6.4...v5.0.0) (2024-10-13)\n\n### Features\n\n* added web support (#1150) ([`a996b4a`](https://github.com/gorhom/react-native-bottom-sheet/commit/a996b4aa68139136ec75e0921025d235471c838d))\n* added flashlist as a scrollable ([9bf39ed](https://github.com/gorhom/react-native-bottom-sheet/commit/9bf39ed08d7377937b0e8b8af65791b178c06492))\n* rewrite gesture apis with gesture handler 2 (#1126) ([`6a4d296`](https://github.com/gorhom/react-native-bottom-sheet/commit/6a4d2967684b01e28f23b1b35afbb4cc4dabaf1d))\n* added accessibility overrides support ([#1288](https://github.com/gorhom/react-native-bottom-sheet/issues/1288))(by @Mahmoud-SK) ([6203c18](https://github.com/gorhom/react-native-bottom-sheet/commit/6203c18acc9f8dc3a31af5bf5ad80e368deceb52))\n* added default dynamic sizing ([#1513](https://github.com/gorhom/react-native-bottom-sheet/issues/1513))(with @Eli-Nathan & [@ororsatti](https://github.com/ororsatti)) ([#1683](https://github.com/gorhom/react-native-bottom-sheet/issues/1683)) ([8017fb6](https://github.com/gorhom/react-native-bottom-sheet/commit/8017fb6b02088d3c66c64a8a23e0f63f22884d36))\n* added a new bottom sheet stack behaviour `replace` ([#1897](https://github.com/gorhom/react-native-bottom-sheet/issues/1897))(with [@janodetzel](https://github.com/janodetzel)) ([997d794](https://github.com/gorhom/react-native-bottom-sheet/commit/997d794ccffe8739268ec50dfecca624e10f8752))\n\n### Bug Fixes\n\n* addressed an edge case with scrollview content sizing on initial rendering on safari ([d1226b7](https://github.com/gorhom/react-native-bottom-sheet/commit/d1226b70ac2405b4a98c8e5be6cee94ae110a35b))\n* replaced deprecated reanimated Extrapolate with Extrapolation ([#1875](https://github.com/gorhom/react-native-bottom-sheet/issues/1875))(by [@cenksari](https://github.com/cenksari)) ([5af3e80](https://github.com/gorhom/react-native-bottom-sheet/commit/5af3e803b0313154f42fbadba7dae6d32719c01c))\n* updated animation sequencing to respect force closing by user ([#1941](https://github.com/gorhom/react-native-bottom-sheet/issues/1941)) ([e4f3fe3](https://github.com/gorhom/react-native-bottom-sheet/commit/e4f3fe339b20a28d8573fa31f0d1b85be3ef2085))\n* updated the enable content panning gesture logic ([2962a2d](https://github.com/gorhom/react-native-bottom-sheet/commit/2962a2d5326e517a48fe11d0e0d762beacca890d))\n* updated the scrollable locking logic while scrolling ([#1939](https://github.com/gorhom/react-native-bottom-sheet/issues/1939)) ([d2b959c](https://github.com/gorhom/react-native-bottom-sheet/commit/d2b959c1f25f1aaeed1b30d21c43809c72490ef3))\n* updated the keyboard handling for Android with keyboard input mode resize ([08db4ab](https://github.com/gorhom/react-native-bottom-sheet/commit/08db4ab4b0058955e9ee2d55f87da8fefb5390ad))\n* replace getRefNativeTag with findNodeHandle ([#1823](https://github.com/gorhom/react-native-bottom-sheet/issues/1823))(by @AndreiCalazans) ([866b4ee](https://github.com/gorhom/react-native-bottom-sheet/commit/866b4ee570fc345d59053561c26af67144e8fd6f))\n* **BottomSheetContainer:** cannot add new property 'value' ([#1808](https://github.com/gorhom/react-native-bottom-sheet/issues/1808))(by @MoritzCooks) ([ccd6bb5](https://github.com/gorhom/react-native-bottom-sheet/commit/ccd6bb540884f35fb9c0dcd5527ed8bac0c1be91))\n* added error message when dynamic sizing enabled with a wrong children type ([8b62dca](https://github.com/gorhom/react-native-bottom-sheet/commit/8b62dca06752a3c047162a693a75173a7c701e3e))\n* bottom sheet not appearing for users that have reduced motion turned on ([#1743](https://github.com/gorhom/react-native-bottom-sheet/issues/1743))(by [@fobos531](https://github.com/fobos531)) ([9b4ef4d](https://github.com/gorhom/react-native-bottom-sheet/commit/9b4ef4dabb7ce1f846ae90e2bab39fa9354ff125))\n* fixed the mount animation with reduce motion enabled ([#1560](https://github.com/gorhom/react-native-bottom-sheet/issues/1560), [#1674](https://github.com/gorhom/react-native-bottom-sheet/issues/1674)) ([6efd8ae](https://github.com/gorhom/react-native-bottom-sheet/commit/6efd8aeb0e312555fa77609869eedbf46a4a04b3))\n* added BottomSheetTextInput to the mock file ([#1698](https://github.com/gorhom/react-native-bottom-sheet/issues/1698))(by [@ghorbani-m](https://github.com/ghorbani-m)) ([dee95e5](https://github.com/gorhom/react-native-bottom-sheet/commit/dee95e5b161d78b0aae34d85abea3d8042417892))\n* added footer height to content height when using dynamic sizing ([#1725](https://github.com/gorhom/react-native-bottom-sheet/issues/1725)) ([5009085](https://github.com/gorhom/react-native-bottom-sheet/commit/50090859f9e50932c641df5b0d6f91cc9f3b5bad))\n* added missing mock of Touchables ([#1700](https://github.com/gorhom/react-native-bottom-sheet/issues/1700))(by [@jaworek](https://github.com/jaworek)) ([a6f44c0](https://github.com/gorhom/react-native-bottom-sheet/commit/a6f44c01ef8f1b9154ce2313614daf075567f641))\n* added support for web without Babel/SWC ([#1741](https://github.com/gorhom/react-native-bottom-sheet/issues/1741))(by [@joshsmith](https://github.com/joshsmith)) ([d620494](https://github.com/gorhom/react-native-bottom-sheet/commit/d620494877e98f4331d8c0a1cb7d375abb06db60))\n* fixed the backdrop tap gesture on web ([#1446](https://github.com/gorhom/react-native-bottom-sheet/issues/1446)) ([b0792de](https://github.com/gorhom/react-native-bottom-sheet/commit/b0792dea5ec605b449d40037cbecfd35bf0ff066))\n* allowed content max height be applied for dynamic sizing ([57c196c](https://github.com/gorhom/react-native-bottom-sheet/commit/57c196cfdf2f63622fb5ea8d6d32cf21b9dd9367))\n* dismiss all action for modals ([#1529](https://github.com/gorhom/react-native-bottom-sheet/issues/1529))(by [@david-gomes5](https://github.com/david-gomes5)) ([17269f1](https://github.com/gorhom/react-native-bottom-sheet/commit/17269f1f55b91f33cec24870ebe00f2510888a4b))\n* fixed position x index sequencing with container resizing ([#1675](https://github.com/gorhom/react-native-bottom-sheet/issues/1675)) ([f0ec705](https://github.com/gorhom/react-native-bottom-sheet/commit/f0ec705cd74ea6e31614ab12c0b4fdc097d3820d))\n* prevent updating backdrop state when unmounting ([#1657](https://github.com/gorhom/react-native-bottom-sheet/issues/1657))(by [@christophby](https://github.com/christophby)) ([d746d85](https://github.com/gorhom/react-native-bottom-sheet/commit/d746d85b92e2bdb4351ea4d3fde140e3199ac671))\n* **web:** use absolute positioning for BottomSheetContainer in web ([#1597](https://github.com/gorhom/react-native-bottom-sheet/issues/1597)) ([d6e3dc9](https://github.com/gorhom/react-native-bottom-sheet/commit/d6e3dc9b327b840895c875dcf016fb5c80a62915))\n* (BottomSheetTextInput): reset shouldHandleKeyboardEvents on unmount (#1495)(by @koplyarov) ([`81cd66f`](https://github.com/gorhom/react-native-bottom-sheet/commit/81cd66f9c49843e43231d1d81ec4aa518a9f1b95))\n* updated containerOffset top value to default to 0 (#1420)(by @beqramo) ([`b81cb93`](https://github.com/gorhom/react-native-bottom-sheet/commit/b81cb9368b55c24703a9c000a76e89a2d253e141))\n* resume close animation when container gets resized (#1374) (#1392) ([`1f69625`](https://github.com/gorhom/react-native-bottom-sheet/commit/1f69625e180fcec4d8d3dec436f8d5bb4eba476b))\n* (bottom-sheet-modal): added container component prop to modal (#1309)(by @magrinj) ([`67e1e09`](https://github.com/gorhom/react-native-bottom-sheet/commit/67e1e09acbc0e96e435a0c2247fa1e0bc19f91aa))\n* updated scrollables mocks with ReactNative list equivalent (#1394)(by @gkueny) ([`630f87f`](https://github.com/gorhom/react-native-bottom-sheet/commit/630f87ff6bd19c4dfc071783139c938eda3baf6c))\n* crash on swipe down (#1367)(by @beqramo) ([`3ccbefc`](https://github.com/gorhom/react-native-bottom-sheet/commit/3ccbefc4d16558867d518f7e0306fbb4d1dbdbeb))\n* (BottomSheetScrollView): updated scroll responders props type (#1335)(by @eps1lon) ([`e42fafc`](https://github.com/gorhom/react-native-bottom-sheet/commit/e42fafcc492d01665c296bf551a6a264eb866fc5))\n* fixed keyboard dismissing issue with Reanimated v3 (#1346)(by @janicduplessis) ([`1d1a464`](https://github.com/gorhom/react-native-bottom-sheet/commit/1d1a46489bede1d3f119df2fb6f467e778461c39))\n- (#1119): fixed race condition between onmount and keyboard animations ([`a1ec74d`](https://github.com/gorhom/react-native-bottom-sheet/commit/a1ec74dbbc85476bb39f3637e9a97214e0cad9a0))\n\n#### Chores And Housekeeping\n\n* updated expo and react native deps (#1445) ([`f6f2304`](https://github.com/gorhom/react-native-bottom-sheet/commit/f6f2304235c05f92d86ce8083caf910b9297a10a))\n* updated react native and other deps (#1412) ([`549e461`](https://github.com/gorhom/react-native-bottom-sheet/commit/549e461530a91e1d7c95a5178bd2238ebf84df86))\n* fixed types (#1123)(by @stropho) ([`b440964`](https://github.com/gorhom/react-native-bottom-sheet/commit/b44096451d4fed81be7f08b0edf638e4a1c42ccd))\n* updated reanimated to v3 (#1324) ([`4829316`](https://github.com/gorhom/react-native-bottom-sheet/commit/4829316beeff95c9e2efa5fbfdfcf7ef37b4af60))\n"
  },
  {
    "path": "CODE_OF_CONDUCT.md",
    "content": "# Contributor Covenant Code of Conduct\n\n## Our Pledge\n\nWe as members, contributors, and leaders pledge to make participation in our\ncommunity a harassment-free experience for everyone, regardless of age, body\nsize, visible or invisible disability, ethnicity, sex characteristics, gender\nidentity and expression, level of experience, education, socio-economic status,\nnationality, personal appearance, race, religion, or sexual identity\nand orientation.\n\nWe pledge to act and interact in ways that contribute to an open, welcoming,\ndiverse, inclusive, and healthy community.\n\n## Our Standards\n\nExamples of behavior that contributes to a positive environment for our\ncommunity include:\n\n* Demonstrating empathy and kindness toward other people\n* Being respectful of differing opinions, viewpoints, and experiences\n* Giving and gracefully accepting constructive feedback\n* Accepting responsibility and apologizing to those affected by our mistakes,\n  and learning from the experience\n* Focusing on what is best not just for us as individuals, but for the\n  overall community\n\nExamples of unacceptable behavior include:\n\n* The use of sexualized language or imagery, and sexual attention or\n  advances of any kind\n* Trolling, insulting or derogatory comments, and personal or political attacks\n* Public or private harassment\n* Publishing others' private information, such as a physical or email\n  address, without their explicit permission\n* Other conduct which could reasonably be considered inappropriate in a\n  professional setting\n\n## Enforcement Responsibilities\n\nCommunity leaders are responsible for clarifying and enforcing our standards of\nacceptable behavior and will take appropriate and fair corrective action in\nresponse to any behavior that they deem inappropriate, threatening, offensive,\nor harmful.\n\nCommunity leaders have the right and responsibility to remove, edit, or reject\ncomments, commits, code, wiki edits, issues, and other contributions that are\nnot aligned to this Code of Conduct, and will communicate reasons for moderation\ndecisions when appropriate.\n\n## Scope\n\nThis Code of Conduct applies within all community spaces, and also applies when\nan individual is officially representing the community in public spaces.\nExamples of representing our community include using an official e-mail address,\nposting via an official social media account, or acting as an appointed\nrepresentative at an online or offline event.\n\n## Enforcement\n\nInstances of abusive, harassing, or otherwise unacceptable behavior may be\nreported to the community leaders responsible for enforcement at\n[@gorhom](https://twitter.com/gorhom) on twitter.\nAll complaints will be reviewed and investigated promptly and fairly.\n\nAll community leaders are obligated to respect the privacy and security of the\nreporter of any incident.\n\n## Enforcement Guidelines\n\nCommunity leaders will follow these Community Impact Guidelines in determining\nthe consequences for any action they deem in violation of this Code of Conduct:\n\n### 1. Correction\n\n**Community Impact**: Use of inappropriate language or other behavior deemed\nunprofessional or unwelcome in the community.\n\n**Consequence**: A private, written warning from community leaders, providing\nclarity around the nature of the violation and an explanation of why the\nbehavior was inappropriate. A public apology may be requested.\n\n### 2. Warning\n\n**Community Impact**: A violation through a single incident or series\nof actions.\n\n**Consequence**: A warning with consequences for continued behavior. No\ninteraction with the people involved, including unsolicited interaction with\nthose enforcing the Code of Conduct, for a specified period of time. This\nincludes avoiding interactions in community spaces as well as external channels\nlike social media. Violating these terms may lead to a temporary or\npermanent ban.\n\n### 3. Temporary Ban\n\n**Community Impact**: A serious violation of community standards, including\nsustained inappropriate behavior.\n\n**Consequence**: A temporary ban from any sort of interaction or public\ncommunication with the community for a specified period of time. No public or\nprivate interaction with the people involved, including unsolicited interaction\nwith those enforcing the Code of Conduct, is allowed during this period.\nViolating these terms may lead to a permanent ban.\n\n### 4. Permanent Ban\n\n**Community Impact**: Demonstrating a pattern of violation of community\nstandards, including sustained inappropriate behavior,  harassment of an\nindividual, or aggression toward or disparagement of classes of individuals.\n\n**Consequence**: A permanent ban from any sort of public interaction within\nthe community.\n\n## Attribution\n\nThis Code of Conduct is adapted from the [Contributor Covenant][homepage],\nversion 2.0, available at\nhttps://www.contributor-covenant.org/version/2/0/code_of_conduct.html.\n\nCommunity Impact Guidelines were inspired by [Mozilla's code of conduct\nenforcement ladder](https://github.com/mozilla/diversity).\n\n[homepage]: https://www.contributor-covenant.org\n\nFor answers to common questions about this code of conduct, see the FAQ at\nhttps://www.contributor-covenant.org/faq. Translations are available at\nhttps://www.contributor-covenant.org/translations.\n"
  },
  {
    "path": "CONTRIBUTING.md",
    "content": "# Contributing\n\nWe want this community to be friendly and respectful to each other. Please follow it in all your interactions with the project.\n\n## Development workflow\n\nTo get started with the project, run `yarn bootstrap` in the root directory to install the required dependencies for each package:\n\n```sh\nyarn bootstrap\n```\n\nWhile developing, you can run the [example app](/example/) to test your changes.\n\nTo start the packager:\n\n```sh\nyarn example start\n```\n\nTo run the example app on Android:\n\n```sh\nyarn example android\n```\n\nTo run the example app on iOS:\n\n```sh\nyarn example android\n```\n\nMake sure your code passes TypeScript and ESLint. Run the following to verify:\n\n```sh\nyarn typescript\nyarn lint\n```\n\nTo fix formatting errors, run the following:\n\n```sh\nyarn lint --fix\n```\n\nRemember to add tests for your change if possible. Run the unit tests by:\n\n```sh\nyarn test\n```\n\n### Commit message convention\n\nWe follow the [conventional commits specification](https://www.conventionalcommits.org/en) for our commit messages:\n\n- `fix`: bug fixes, e.g. fix crash due to deprecated method.\n- `feat`: new features, e.g. add new method to the module.\n- `refactor`: code refactor, e.g. migrate from class components to hooks.\n- `docs`: changes into documentation, e.g. add usage example for the module..\n- `test`: adding or updating tests, eg add integration tests using detox.\n- `chore`: tooling changes, e.g. change CI config.\n\nOur pre-commit hooks verify that your commit message matches this format when committing.\n\n### Linting and tests\n\n[ESLint](https://eslint.org/), [Prettier](https://prettier.io/), [TypeScript](https://www.typescriptlang.org/)\n\nWe use [TypeScript](https://www.typescriptlang.org/) for type checking, [ESLint](https://eslint.org/) with [Prettier](https://prettier.io/) for linting and formatting the code, and [Jest](https://jestjs.io/) for testing.\n\nOur pre-commit hooks verify that the linter and tests pass when committing.\n\n### Scripts\n\nThe `package.json` file contains various scripts for common tasks:\n\n- `yarn bootstrap`: setup project by installing all dependencies and pods.\n- `yarn typescript`: type-check files with TypeScript.\n- `yarn lint`: lint files with ESLint.\n- `yarn test`: run unit tests with Jest.\n- `yarn example start`: start the Metro server for the example app.\n- `yarn example android`: run the example app on Android.\n- `yarn example ios`: run the example app on iOS.\n\n### Sending a pull request\n\n> **Working on your first pull request?** You can learn how from this _free_ series: [How to Contribute to an Open Source Project on GitHub](https://egghead.io/series/how-to-contribute-to-an-open-source-project-on-github).\n\nWhen you're sending a pull request:\n\n- Prefer small pull requests focused on one change.\n- Verify that linters and tests are passing.\n- Review the documentation to make sure it looks good.\n- Follow the pull request template when opening a pull request.\n- For pull requests that change the API or implementation, discuss with maintainers first by opening an issue.\n"
  },
  {
    "path": "LICENSE",
    "content": "MIT License\n\nCopyright (c) 2020 Mo Gorhom\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n"
  },
  {
    "path": "README.md",
    "content": "# React Native Bottom Sheet\n\n[![Reanimated v3 version](https://img.shields.io/github/package-json/v/gorhom/react-native-bottom-sheet/master?label=Reanimated%20v3&style=flat-square)](https://www.npmjs.com/package/@gorhom/bottom-sheet) [![Reanimated v2 version](https://img.shields.io/github/package-json/v/gorhom/react-native-bottom-sheet/v4?label=Reanimated%20v2&style=flat-square)](https://www.npmjs.com/package/@gorhom/bottom-sheet)  [![Reanimated v1 version](https://img.shields.io/github/package-json/v/gorhom/react-native-bottom-sheet/v2?label=Reanimated%20v1&style=flat-square)](https://www.npmjs.com/package/@gorhom/bottom-sheet)<br>\n[![license](https://img.shields.io/npm/l/@gorhom/bottom-sheet?style=flat-square)](https://www.npmjs.com/package/@gorhom/bottom-sheet) [![npm](https://img.shields.io/badge/types-included-blue?style=flat-square)](https://www.npmjs.com/package/@gorhom/bottom-sheet) [![runs with expo](https://img.shields.io/badge/Runs%20with%20Expo-4630EB.svg?style=flat-square&logo=EXPO&labelColor=f3f3f3&logoColor=000)](https://expo.io/) <br> ![NPM Downloads](https://img.shields.io/npm/dw/%40gorhom%2Fbottom-sheet?style=flat-square)\n\n\nA performant interactive bottom sheet with fully configurable options 🚀\n\n![React Native Bottom Sheet](./preview.gif)\n\n---\n\n## Features\n- ⭐️ Support React Native Web, [read more](https://gorhom.dev/react-native-bottom-sheet/web-support).\n- ⭐️ Dynamic Sizing, [read more](https://gorhom.dev/react-native-bottom-sheet/dynamic-sizing).\n- ⭐️ Support FlashList, [read more](https://gorhom.dev/react-native-bottom-sheet/components/bottomsheetflashlist).\n- Modal presentation view, [Bottom Sheet Modal](https://gorhom.dev/react-native-bottom-sheet/modal).\n- Smooth gesture interactions & snapping animations.\n- Seamless [keyboard handling](https://gorhom.dev/react-native-bottom-sheet/keyboard-handling) for iOS & Android.\n- Support [pull to refresh](https://gorhom.dev/react-native-bottom-sheet/pull-to-refresh) for scrollables.\n- Support `FlatList`, `SectionList`, `ScrollView` & `View` scrolling interactions, [read more](https://gorhom.dev/react-native-bottom-sheet/scrollables).\n- Support `React Navigation` Integration, [read more](https://gorhom.dev/react-native-bottom-sheet/react-navigation-integration).\n- Compatible with `Reanimated` v1-3.\n- Compatible with `Expo`.\n- Accessibility support.\n- Written in `TypeScript`.\n- [Read more](https://gorhom.dev/react-native-bottom-sheet).\n\n## Getting Started\n\nCheck out [the documentation website](https://gorhom.dev/react-native-bottom-sheet).\n\n## Versioning\n\nThis library been written in 3 versions of `Reanimated`, and kept all implementation in separate branches:\n\n- **`v5`** | [branch](https://github.com/gorhom/react-native-bottom-sheet/tree/master) | [changelog](https://github.com/gorhom/react-native-bottom-sheet/blob/master/CHANGELOG.md) : written with `Reanimated v3` & `Gesture Handler v2`.\n\n- `v4` (not maintained) | [branch](https://github.com/gorhom/react-native-bottom-sheet/tree/v4) | [changelog](https://github.com/gorhom/react-native-bottom-sheet/blob/v4/CHANGELOG.md) : written with `Reanimated v2`.\n\n- `v2` (not maintained) | [branch](https://github.com/gorhom/react-native-bottom-sheet/tree/v2) | [changelog](https://github.com/gorhom/react-native-bottom-sheet/blob/v2/CHANGELOG.md) : written with `Reanimated v1` & compatible with `Reanimated v2`.\n\n> I highly recommend to use `v5` which provides more stability with all latest features.\n\n## Author\n\n- [Mo Gorhom](https://gorhom.dev/)\n\n## Sponsor & Support\n\nTo keep this library maintained and up-to-date please consider [sponsoring it on GitHub](https://github.com/sponsors/gorhom). Or if you are looking for a private support or help in customizing the experience, then reach out to me on Twitter [@gorhom](https://twitter.com/gorhom).\n\n## License\n\n[MIT](./LICENSE)\n\n---\n\n<p align=\"center\">\n  <a href=\"https://gorhom.dev/#gh-light-mode-only\" target=\"_blank\">\n    <img height=\"18\" alt=\"Mo Gorhom\" src=\"./mogorhom-light.png\">\n  </a>\n  <a href=\"https://gorhom.dev/#gh-dark-mode-only\" target=\"_blank\">\n    <img height=\"18\" alt=\"Mo Gorhom\" src=\"./mogorhom-dark.png\">\n  </a>\n</p>\n"
  },
  {
    "path": "babel.config.js",
    "content": "module.exports = {\n  presets: ['module:metro-react-native-babel-preset'],\n  plugins: ['react-native-reanimated/plugin'],\n};\n"
  },
  {
    "path": "biome.json",
    "content": "{\n  \"$schema\": \"https://biomejs.dev/schemas/2.2.2/schema.json\",\n  \"vcs\": { \"enabled\": true, \"clientKind\": \"git\", \"useIgnoreFile\": false },\n  \"formatter\": {\n    \"enabled\": true,\n    \"useEditorconfig\": true,\n    \"formatWithErrors\": false,\n    \"indentStyle\": \"space\",\n    \"lineEnding\": \"lf\",\n    \"lineWidth\": 80,\n    \"includes\": [\"**\", \"!**/.github\", \"!**/lib\", \"!**/.expo\", \"!**/website\"]\n  },\n  \"assist\": { \"actions\": { \"source\": { \"organizeImports\": \"on\" } } },\n  \"linter\": {\n    \"enabled\": true,\n    \"rules\": {\n      \"recommended\": true,\n      \"complexity\": {\n        \"noUselessLoneBlockStatements\": \"warn\",\n        \"noUselessUndefinedInitialization\": \"warn\",\n        \"noVoid\": \"warn\",\n        \"useLiteralKeys\": \"warn\",\n        \"noAdjacentSpacesInRegex\": \"warn\",\n        \"noCommaOperator\": \"warn\"\n      },\n      \"correctness\": {\n        \"noConstAssign\": \"error\",\n        \"noConstantCondition\": \"off\",\n        \"noEmptyCharacterClassInRegex\": \"warn\",\n        \"noGlobalObjectCalls\": \"warn\",\n        \"noInnerDeclarations\": \"off\",\n        \"noInvalidUseBeforeDeclaration\": \"off\",\n        \"noUndeclaredVariables\": \"error\",\n        \"noUnreachable\": \"error\",\n        \"noUnusedVariables\": \"warn\",\n        \"useExhaustiveDependencies\": \"error\",\n        \"useHookAtTopLevel\": \"error\",\n        \"useIsNan\": \"warn\",\n        \"useValidTypeof\": \"warn\"\n      },\n      \"security\": { \"noGlobalEval\": \"error\" },\n      \"style\": {\n        \"noYodaExpression\": \"warn\",\n        \"useBlockStatements\": \"warn\",\n        \"useCollapsedElseIf\": \"off\",\n        \"useConsistentBuiltinInstantiation\": \"warn\",\n        \"useDefaultSwitchClause\": \"off\",\n        \"useSingleVarDeclarator\": \"off\",\n        \"useExponentiationOperator\": \"off\",\n        \"useArrayLiterals\": \"warn\"\n      },\n      \"suspicious\": {\n        \"noCatchAssign\": \"warn\",\n        \"noCommentText\": \"error\",\n        \"noConsole\": {\n          \"level\": \"error\",\n          \"options\": { \"allow\": [\"warn\", \"error\"] }\n        },\n        \"noControlCharactersInRegex\": \"warn\",\n        \"noDebugger\": \"warn\",\n        \"noDoubleEquals\": \"warn\",\n        \"noDuplicateClassMembers\": \"error\",\n        \"noDuplicateJsxProps\": \"error\",\n        \"noDuplicateObjectKeys\": \"error\",\n        \"noEmptyBlockStatements\": \"off\",\n        \"noFallthroughSwitchClause\": \"warn\",\n        \"noFunctionAssign\": \"warn\",\n        \"noLabelVar\": \"warn\",\n        \"noRedeclare\": \"off\",\n        \"noSelfCompare\": \"warn\",\n        \"noShadowRestrictedNames\": \"warn\",\n        \"noSparseArray\": \"warn\",\n        \"noWith\": \"warn\"\n      }\n    },\n    \"includes\": [\n      \"**\",\n      \"!**/node_modules/\",\n      \"!**/lib\",\n      \"!**/.expo\",\n      \"!**/website\"\n    ]\n  },\n  \"javascript\": {\n    \"jsxRuntime\": \"reactClassic\",\n    \"formatter\": {\n      \"trailingCommas\": \"es5\",\n      \"semicolons\": \"always\",\n      \"arrowParentheses\": \"asNeeded\",\n      \"quoteStyle\": \"single\",\n      \"bracketSpacing\": true\n    },\n    \"globals\": [\n      \"clearImmediate\",\n      \"queueMicrotask\",\n      \"Blob\",\n      \"Set\",\n      \"Promise\",\n      \"requestIdleCallback\",\n      \"setImmediate\",\n      \"requestAnimationFrame\",\n      \"File\",\n      \"Map\",\n      \"__DEV__\",\n      \"WebSocket\"\n    ]\n  },\n  \"files\": {\n    \"includes\": [\n      \"**\",\n      \"!**/node_modules/\",\n      \"!**/lib\",\n      \"!**/.expo\",\n      \"!**/example\",\n      \"!**/website\"\n    ]\n  }\n}\n"
  },
  {
    "path": "commitlint.config.js",
    "content": "module.exports = {\n  extends: ['@commitlint/config-conventional'],\n};\n"
  },
  {
    "path": "example/.gitignore",
    "content": "# Learn more https://docs.github.com/en/get-started/getting-started-with-git/ignoring-files\n\n# dependencies\nnode_modules/\n\n# Expo\n.expo/\ndist/\nweb-build/\n\n# Native\n*.orig.*\n*.jks\n*.p8\n*.p12\n*.key\n*.mobileprovision\n\n# Metro\n.metro-health-check*\n\n# debug\nnpm-debug.*\nyarn-debug.*\nyarn-error.*\n\n# macOS\n.DS_Store\n*.pem\n\n# local env files\n.env*.local\n\n# typescript\n*.tsbuildinfo\n"
  },
  {
    "path": "example/App.tsx",
    "content": "import React from 'react';\nimport { StyleSheet } from 'react-native';\nimport { GestureHandlerRootView } from 'react-native-gesture-handler';\nimport Main from './src/Main';\n\nimport { enableScreens } from 'react-native-screens';\nenableScreens(true);\n\n// @ts-ignore\nimport { enableLogging } from '@gorhom/bottom-sheet';\nenableLogging();\n\nexport default function App() {\n  return (\n    <GestureHandlerRootView style={styles.container}>\n      <Main />\n    </GestureHandlerRootView>\n  );\n}\n\nconst styles = StyleSheet.create({\n  container: {\n    flex: 1,\n  },\n});\n"
  },
  {
    "path": "example/app.json",
    "content": "{\n  \"expo\": {\n    \"name\": \"BottomSheet\",\n    \"slug\": \"BottomSheet\",\n    \"githubUrl\": \"https://github.com/gorhom/react-native-bottom-sheet\",\n    \"version\": \"5.0.0\",\n    \"orientation\": \"portrait\",\n    \"icon\": \"./assets/icon.png\",\n    \"userInterfaceStyle\": \"automatic\",\n    \"backgroundColor\": \"#000000\",\n    \"newArchEnabled\": true,\n    \"splash\": {\n      \"image\": \"./assets/splash.png\",\n      \"resizeMode\": \"contain\",\n      \"backgroundColor\": \"#000000\"\n    },\n    \"assetBundlePatterns\": [\"**/*\"],\n    \"ios\": {\n      \"supportsTablet\": true,\n      \"bundleIdentifier\": \"dev.gorhom.bottomsheet\"\n    },\n    \"android\": {\n      \"adaptiveIcon\": {\n        \"foregroundImage\": \"./assets/adaptive-icon.png\",\n        \"backgroundColor\": \"#000000\"\n      },\n      \"package\": \"dev.gorhom.bottomsheet\",\n      \"softwareKeyboardLayoutMode\": \"pan\"\n    },\n    \"web\": {\n      \"favicon\": \"./assets/favicon.png\"\n    },\n    \"plugins\": [\n      [\n        \"expo-asset\",\n        {\n          \"assets\": [\"./assets\"]\n        }\n      ]\n    ]\n  }\n}\n"
  },
  {
    "path": "example/babel.config.js",
    "content": "const path = require('node:path');\nconst pak = require('../package.json');\n\nmodule.exports = api => {\n  api.cache(true);\n  return {\n    presets: ['babel-preset-expo'],\n    plugins: [\n      [\n        'module-resolver',\n        {\n          extensions: ['.tsx', '.ts', '.js', '.json'],\n          alias: {\n            [pak.name]: path.join(__dirname, '..', pak.source),\n          },\n        },\n      ],\n      '@babel/plugin-proposal-export-namespace-from',\n      'react-native-worklets/plugin',\n    ],\n  };\n};\n"
  },
  {
    "path": "example/metro.config.js",
    "content": "// Learn more https://docs.expo.io/guides/customizing-metro\nconst { getDefaultConfig } = require('expo/metro-config');\nconst path = require('node:path');\nconst {\n  wrapWithReanimatedMetroConfig,\n} = require('react-native-reanimated/metro-config');\n\n// Find the project and workspace directories\nconst projectRoot = __dirname;\n// This can be replaced with `find-yarn-workspace-root`\nconst workspaceRoot = path.resolve(projectRoot, '..');\n\n/** @type {import('expo/metro-config').MetroConfig} */\nconst config = getDefaultConfig(__dirname);\n\nconfig.watchFolders = [workspaceRoot];\nconfig.resolver.nodeModulesPaths = [path.resolve(projectRoot, 'node_modules')];\n\nconfig.resolver.disableHierarchicalLookup = true;\n\nmodule.exports = wrapWithReanimatedMetroConfig(config);\n"
  },
  {
    "path": "example/package.json",
    "content": "{\n  \"name\": \"@gorhom/bottomsheet-example\",\n  \"version\": \"5.0.0\",\n  \"main\": \"node_modules/expo/AppEntry.js\",\n  \"scripts\": {\n    \"start\": \"expo start\",\n    \"android\": \"expo start --android\",\n    \"ios\": \"expo start --ios\",\n    \"web\": \"expo start --web\"\n  },\n  \"dependencies\": {\n    \"@expo/webpack-config\": \"~19.0.1\",\n    \"@gorhom/portal\": \"^1.0.14\",\n    \"@gorhom/showcase-template\": \"^4.0.1\",\n    \"@legendapp/list\": \"^2.0.0\",\n    \"@react-navigation/material-top-tabs\": \"^7.2.13\",\n    \"@react-navigation/native\": \"^7.1.9\",\n    \"@react-navigation/native-stack\": \"^7.3.13\",\n    \"@react-navigation/stack\": \"^7.3.2\",\n    \"@shopify/flash-list\": \"2.0.2\",\n    \"expo\": \"~54.0.26\",\n    \"expo-asset\": \"~12.0.7\",\n    \"expo-blur\": \"~15.0.6\",\n    \"expo-image\": \"~3.0.7\",\n    \"expo-status-bar\": \"~3.0.7\",\n    \"react\": \"19.1.0\",\n    \"react-dom\": \"19.1.0\",\n    \"react-native\": \"0.81.5\",\n    \"react-native-gesture-handler\": \"~2.28.0\",\n    \"react-native-maps\": \"1.20.1\",\n    \"react-native-pager-view\": \"6.9.1\",\n    \"react-native-reanimated\": \"~4.1.0\",\n    \"react-native-redash\": \"^18.1.0\",\n    \"react-native-safe-area-context\": \"~5.6.0\",\n    \"react-native-screens\": \"~4.16.0\",\n    \"react-native-tab-view\": \"^3.5.2\",\n    \"react-native-web\": \"^0.21.0\",\n    \"react-native-webview\": \"13.15.0\",\n    \"react-native-worklets\": \"0.5.1\"\n  },\n  \"devDependencies\": {\n    \"@babel/core\": \"^7.25.2\",\n    \"@babel/plugin-proposal-export-namespace-from\": \"^7.18.9\",\n    \"@types/faker\": \"^4.1.12\",\n    \"@types/react\": \"~19.1.10\",\n    \"@types/react-native\": \"^0.73.0\",\n    \"babel-loader\": \"^10.0.0\",\n    \"babel-plugin-module-resolver\": \"^5.0.0\",\n    \"faker\": \"^4.1.0\",\n    \"typescript\": \"~5.9.2\"\n  },\n  \"overrides\": {\n    \"use-latest-callback\": \"^0.2.3\"\n  },\n  \"resolutions\": {\n    \"use-latest-callback\": \"^0.2.3\"\n  },\n  \"private\": true\n}\n"
  },
  {
    "path": "example/src/Dev.tsx",
    "content": "import BottomSheet, {\n  BottomSheetFlatList,\n  BottomSheetView,\n} from '@gorhom/bottom-sheet';\nimport React, { useCallback, useMemo, useRef } from 'react';\nimport {\n  Button,\n  type FlatList,\n  type LayoutChangeEvent,\n  StyleSheet,\n  Text,\n  View,\n} from 'react-native';\nimport {\n  SafeAreaProvider,\n  useSafeAreaFrame,\n  useSafeAreaInsets,\n} from 'react-native-safe-area-context';\n\nconst DATA = new Array(50).fill(0).map((_, index) => ({\n  id: `item-${index}`,\n}));\n\nconst SNAP_POINTS = [300, 600];\n\nconst renderItem = ({ item }) => (\n  <View style={styles.itemContainer}>\n    <Text>{item.id}</Text>\n  </View>\n);\n\nconst App = () => {\n  //#region ref\n  const bottomSheetRef = useRef<BottomSheet>(null);\n  const [mount, setMount] = React.useState(false);\n  //#endregion\n\n  //#region hooks\n  const { bottom: bottomSafeArea, top: topSafeArea } = useSafeAreaInsets();\n  const { height } = useSafeAreaFrame();\n  //#endregion\n\n  //#region callbacks\n  const handleOnLayout = useCallback(\n    ({ nativeEvent: layout }: LayoutChangeEvent) => {\n      // eslint-disable-next-line no-console\n      console.log('BottomSheetFlatList::handleOnLayout', layout);\n    },\n    []\n  );\n  //#endregion\n\n  //#region styles\n  const contentContainerStyle = useMemo(\n    () => ({\n      paddingBottom: bottomSafeArea,\n    }),\n    [bottomSafeArea]\n  );\n  //#endregion\n\n  // renders\n  const ref = useRef<FlatList>(null);\n  // ref.current?.getNativeScrollRef()\n  return (\n    <View style={styles.container}>\n      <Button\n        title=\"Mount\"\n        onPress={() => {\n          setMount(prev => !prev);\n        }}\n      />\n      {/* {<BottomSheetFlatList\n            data={DATA}\n            style={styles.itemList}\n            contentContainerStyle={contentContainerStyle}\n            renderItem={renderItem}\n            onLayout={handleOnLayout}\n          />} */}\n      {mount ? (\n        <BottomSheet\n          ref={bottomSheetRef}\n          topInset={topSafeArea}\n          snapPoints={SNAP_POINTS}\n          enableDynamicSizing={false}\n        >\n          <BottomSheetView>\n            <Text>Hello World!</Text>\n          </BottomSheetView>\n        </BottomSheet>\n      ) : null}\n    </View>\n  );\n};\n\nconst styles = StyleSheet.create({\n  container: {\n    flex: 1,\n    padding: 24,\n    justifyContent: 'center',\n    alignItems: 'center',\n    backgroundColor: 'grey',\n  },\n  contentContainer: {\n    flex: 1,\n    alignItems: 'center',\n    justifyContent: 'center',\n    minHeight: 200,\n  },\n  itemList: {\n    flex: 1,\n  },\n  itemContainer: {\n    padding: 6,\n  },\n});\n\nexport default () => (\n  <SafeAreaProvider>\n    <App />\n  </SafeAreaProvider>\n);\n"
  },
  {
    "path": "example/src/Main.tsx",
    "content": "import { ShowcaseApp } from '@gorhom/showcase-template';\nimport React from 'react';\nimport { description, version } from '../../package.json';\nimport { screens } from './screens';\n\nconst author = {\n  username: 'Mo Gorhom',\n  url: 'https://gorhom.dev',\n};\n\nexport default () => (\n  <ShowcaseApp\n    name=\"Bottom Sheet\"\n    description={description}\n    version={version}\n    author={author}\n    data={screens}\n  />\n);\n"
  },
  {
    "path": "example/src/components/button/Button.tsx",
    "content": "import React, { memo } from 'react';\nimport { ViewStyle, TextStyle } from 'react-native';\nimport { ShowcaseButton, ShowcaseLabel } from '@gorhom/showcase-template';\n\ninterface ButtonProps {\n  label: string;\n  labelStyle?: TextStyle;\n  style?: ViewStyle;\n  onPress: () => void;\n}\n\nconst ButtonComponent = ({\n  label,\n  labelStyle,\n  style,\n  onPress,\n}: ButtonProps) => (\n  <ShowcaseButton containerStyle={style} onPress={onPress}>\n    <ShowcaseLabel style={labelStyle}>{label}</ShowcaseLabel>\n  </ShowcaseButton>\n);\n\nexport const Button = memo(ButtonComponent);\n"
  },
  {
    "path": "example/src/components/button/index.ts",
    "content": "export { Button } from './Button';\n"
  },
  {
    "path": "example/src/components/contactItem/ContactItem.tsx",
    "content": "import React, { memo, useMemo } from 'react';\nimport { Text, StyleSheet, View, TextStyle, ViewStyle } from 'react-native';\nimport { TouchableOpacity } from '@gorhom/bottom-sheet';\n\ninterface ContactItemProps {\n  title: string;\n  subTitle?: string;\n  titleStyle?: TextStyle;\n  subTitleStyle?: TextStyle;\n  thumbnailStyle?: ViewStyle;\n  iconStyle?: ViewStyle;\n  onPress?: () => void;\n}\n\nconst ContactItemComponent = ({\n  title,\n  subTitle,\n  titleStyle,\n  subTitleStyle,\n  thumbnailStyle,\n  iconStyle,\n  onPress,\n}: ContactItemProps) => {\n  const ContentWrapper = useMemo<any>(\n    () => (onPress ? TouchableOpacity : View),\n    [onPress]\n  );\n  // render\n  return (\n    <ContentWrapper onPress={onPress} style={styles.container}>\n      <View style={[styles.thumbnail, thumbnailStyle]} />\n      <View style={styles.contentContainer}>\n        <Text style={[styles.title, titleStyle]}>{title}</Text>\n        {subTitle && (\n          <Text style={[styles.subtitle, subTitleStyle]}>{subTitle}</Text>\n        )}\n      </View>\n      <View style={[styles.icon, iconStyle]} />\n    </ContentWrapper>\n  );\n};\n\nconst styles = StyleSheet.create({\n  container: {\n    flexDirection: 'row',\n    alignContent: 'center',\n    marginVertical: 12,\n  },\n  contentContainer: {\n    flex: 1,\n    alignSelf: 'center',\n    marginLeft: 12,\n  },\n  thumbnail: {\n    width: 46,\n    height: 46,\n    borderRadius: 46,\n    backgroundColor: 'rgba(0, 0, 0, 0.25)',\n  },\n  icon: {\n    alignSelf: 'center',\n    width: 24,\n    height: 24,\n    borderRadius: 24,\n    backgroundColor: 'rgba(0, 0, 0, 0.125)',\n  },\n  title: {\n    color: '#111',\n    fontSize: 16,\n    marginBottom: 4,\n    textTransform: 'capitalize',\n  },\n\n  subtitle: {\n    color: '#666',\n    fontSize: 14,\n    textTransform: 'capitalize',\n  },\n});\n\nexport const ContactItem = memo(ContactItemComponent);\n"
  },
  {
    "path": "example/src/components/contactItem/index.ts",
    "content": "export { ContactItem } from './ContactItem';\n"
  },
  {
    "path": "example/src/components/contactList/ContactList.tsx",
    "content": "import {\n  BottomSheetFlatList,\n  BottomSheetScrollView,\n  BottomSheetSectionList,\n  BottomSheetView,\n  BottomSheetVirtualizedList,\n} from '@gorhom/bottom-sheet';\nimport { useFocusEffect } from '@react-navigation/native';\nimport React, { useMemo, useCallback, type ComponentProps, memo } from 'react';\nimport { Platform, Text, View, type ViewStyle } from 'react-native';\nimport {\n  useSafeAreaFrame,\n  useSafeAreaInsets,\n} from 'react-native-safe-area-context';\nimport {\n  createContactListMockData,\n  createContactSectionsMockData,\n} from '../../utilities/createMockData';\nimport { ContactItem } from '../contactItem';\nimport { styles } from './styles';\n\nexport interface ContactListProps\n  extends Pick<\n    ComponentProps<typeof BottomSheetFlatList>,\n    'enableFooterMarginAdjustment'\n  > {\n  type: 'FlatList' | 'SectionList' | 'ScrollView' | 'View' | 'VirtualizedList';\n  count?: number;\n  style?: ViewStyle;\n  onItemPress?: () => void;\n  onRefresh?: () => void;\n}\n\nconst keyExtractor = (item: any, index: number) => `${item.name}.${index}`;\nconst handleGetItem = (data: any[], index: number) => data[index];\nconst handleGetCount = (data: any[]) => data.length;\n\nconst ContactListComponent = ({\n  type,\n  count = 25,\n  style,\n  onRefresh,\n  onItemPress,\n  ...rest\n}: ContactListProps) => {\n  // hooks\n  const { bottom: bottomSafeArea } = useSafeAreaInsets();\n\n  //#region variables\n  const sections = useMemo(() => createContactSectionsMockData(count), [count]);\n  const data = useMemo(() => createContactListMockData(count), [count]);\n  //#endregion\n\n  // styles\n  const contentContainerStyle = useMemo(\n    () => ({\n      ...styles.contentContainer,\n      ...style,\n      paddingBottom: bottomSafeArea,\n    }),\n    [style, bottomSafeArea]\n  );\n\n  // renders\n  const renderFlatListItem = useCallback(\n    ({ item, index }) => (\n      <ContactItem\n        key={`${type}.${item.name}.${index}`}\n        title={`${index}: ${item.name}`}\n        subTitle={item.jobTitle}\n        onPress={onItemPress}\n      />\n    ),\n    [type, onItemPress]\n  );\n  const renderSectionItem = useCallback(\n    ({ item, index }) => (\n      <ContactItem\n        key={`${type}.${item.name}.${index}`}\n        title={`${index}: ${item.name}`}\n        subTitle={item.jobTitle}\n        onPress={onItemPress}\n      />\n    ),\n    [type, onItemPress]\n  );\n  const renderScrollViewItem = useCallback(\n    (item, index) => (\n      <ContactItem\n        key={`${type}.${item.name}.${index}`}\n        title={`${index}: ${item.name}`}\n        subTitle={item.jobTitle}\n        onPress={onItemPress}\n      />\n    ),\n    [type, onItemPress]\n  );\n  const renderSectionHeader = useCallback(\n    ({ section }: any) => (\n      <View style={styles.sectionHeaderContainer}>\n        <Text style={styles.sectionHeaderTitle}>{section.title}</Text>\n      </View>\n    ),\n    []\n  );\n\n  if (type === 'FlatList') {\n    return (\n      <BottomSheetFlatList\n        {...rest}\n        data={data}\n        refreshing={false}\n        onRefresh={onRefresh}\n        keyExtractor={keyExtractor}\n        initialNumToRender={5}\n        bounces={true}\n        windowSize={10}\n        maxToRenderPerBatch={5}\n        renderItem={renderFlatListItem}\n        style={styles.container}\n        keyboardDismissMode=\"interactive\"\n        indicatorStyle=\"black\"\n        contentContainerStyle={contentContainerStyle}\n        focusHook={useFocusEffect}\n      />\n    );\n  } else if (type === 'VirtualizedList') {\n    return (\n      <BottomSheetVirtualizedList\n        {...rest}\n        data={data}\n        keyExtractor={keyExtractor}\n        initialNumToRender={5}\n        getItem={handleGetItem}\n        getItemCount={handleGetCount}\n        bounces={true}\n        windowSize={10}\n        maxToRenderPerBatch={5}\n        renderItem={renderFlatListItem}\n        style={styles.container}\n        keyboardDismissMode=\"interactive\"\n        indicatorStyle=\"black\"\n        contentContainerStyle={contentContainerStyle}\n        focusHook={useFocusEffect}\n      />\n    );\n  } else if (type === 'ScrollView') {\n    return (\n      <BottomSheetScrollView\n        {...rest}\n        style={styles.container}\n        contentContainerStyle={contentContainerStyle}\n        bounces={true}\n        focusHook={useFocusEffect}\n        indicatorStyle=\"black\"\n      >\n        {data.map(renderScrollViewItem)}\n      </BottomSheetScrollView>\n    );\n  } else if (type === 'SectionList') {\n    return (\n      <BottomSheetSectionList\n        {...rest}\n        style={styles.container}\n        contentContainerStyle={contentContainerStyle}\n        stickySectionHeadersEnabled\n        initialNumToRender={5}\n        windowSize={10}\n        maxToRenderPerBatch={5}\n        bounces={true}\n        sections={sections}\n        keyExtractor={keyExtractor}\n        renderSectionHeader={renderSectionHeader}\n        renderItem={renderSectionItem}\n        focusHook={useFocusEffect}\n        indicatorStyle=\"black\"\n        removeClippedSubviews={Platform.OS === 'android' && sections.length > 0}\n      />\n    );\n  } else if (type === 'View') {\n    return (\n      <BottomSheetView style={styles.contentContainer} {...rest}>\n        {data.map(renderScrollViewItem)}\n      </BottomSheetView>\n    );\n  }\n\n  return null;\n};\n\nexport const ContactList = memo(ContactListComponent);\n"
  },
  {
    "path": "example/src/components/contactList/index.ts",
    "content": "export { ContactList } from './ContactList';\nexport type { ContactListProps } from './ContactList';\n"
  },
  {
    "path": "example/src/components/contactList/styles.ts",
    "content": "import { StyleSheet } from 'react-native';\n\nexport const styles = StyleSheet.create({\n  sectionHeaderContainer: {\n    paddingTop: 24,\n    paddingBottom: 6,\n    backgroundColor: 'white',\n  },\n  sectionHeaderTitle: {\n    fontSize: 16,\n    textTransform: 'uppercase',\n    color: 'black',\n  },\n  container: {\n    overflow: 'visible',\n    flex: 1,\n  },\n  contentContainer: {\n    paddingHorizontal: 16,\n    overflow: 'visible',\n  },\n});\n"
  },
  {
    "path": "example/src/components/contactList/styles.web.ts",
    "content": "import { StyleSheet } from 'react-native';\n\nexport const styles = StyleSheet.create({\n  sectionHeaderContainer: {\n    paddingTop: 24,\n    paddingBottom: 6,\n    backgroundColor: 'white',\n  },\n  sectionHeaderTitle: {\n    fontSize: 16,\n    textTransform: 'uppercase',\n    color: 'black',\n  },\n  container: {\n    flex: 1,\n  },\n  contentContainer: {\n    paddingHorizontal: 16,\n  },\n});\n"
  },
  {
    "path": "example/src/components/customBackground/CustomBackground.tsx",
    "content": "import React, { memo, useMemo } from 'react';\nimport { StyleSheet } from 'react-native';\nimport { BottomSheetBackgroundProps } from '@gorhom/bottom-sheet';\nimport Animated, {\n  useAnimatedStyle,\n  interpolateColor,\n} from 'react-native-reanimated';\n\ninterface CustomBackgroundProps extends BottomSheetBackgroundProps {}\n\nconst CustomBackgroundComponent: React.FC<CustomBackgroundProps> = ({\n  style,\n  animatedIndex,\n}) => {\n  //#region styles\n  const containerAnimatedStyle = useAnimatedStyle(\n    () => ({\n      // @ts-ignore\n      backgroundColor: interpolateColor(\n        animatedIndex.value,\n        [0, 1],\n        ['#ffffff', '#a8b5eb']\n      ),\n    }),\n    [animatedIndex.value]\n  );\n  const containerStyle = useMemo(\n    () => [styles.container, style, containerAnimatedStyle],\n    [style, containerAnimatedStyle]\n  );\n  //#endregion\n\n  // render\n  return <Animated.View pointerEvents=\"none\" style={containerStyle} />;\n};\n\nexport const CustomBackground = memo(CustomBackgroundComponent);\n\nconst styles = StyleSheet.create({\n  container: {\n    borderTopLeftRadius: 20,\n    borderTopRightRadius: 20,\n    backgroundColor: '#fff',\n  },\n});\n"
  },
  {
    "path": "example/src/components/customBackground/index.ts",
    "content": "export { CustomBackground } from './CustomBackground';\n"
  },
  {
    "path": "example/src/components/customFooter/CustomFooter.tsx",
    "content": "import React, { memo, useCallback, useMemo } from 'react';\nimport { Pressable, StyleSheet } from 'react-native';\nimport {\n  BottomSheetFooter,\n  BottomSheetFooterProps,\n  useBottomSheet,\n} from '@gorhom/bottom-sheet';\nimport { useSafeAreaInsets } from 'react-native-safe-area-context';\nimport Animated, {\n  Extrapolation,\n  interpolate,\n  useAnimatedStyle,\n} from 'react-native-reanimated';\nimport { toRad } from 'react-native-redash';\n\nconst AnimatedRectButton = Animated.createAnimatedComponent(Pressable);\n\ninterface CustomFooterProps extends BottomSheetFooterProps {}\n\nconst CustomFooterComponent = ({\n  animatedFooterPosition,\n}: CustomFooterProps) => {\n  //#region hooks\n  const { bottom: bottomSafeArea } = useSafeAreaInsets();\n  const { expand, collapse, animatedIndex } = useBottomSheet();\n  //#endregion\n\n  //#region styles\n  const arrowAnimatedStyle = useAnimatedStyle(() => {\n    const arrowRotate = interpolate(\n      animatedIndex.value,\n      [0, 1],\n      [toRad(0), toRad(-180)],\n      Extrapolation.CLAMP\n    );\n    return {\n      transform: [{ rotate: `${arrowRotate}rad` }],\n    };\n  }, [animatedIndex.value]);\n  const arrowStyle = useMemo(\n    () => [arrowAnimatedStyle, styles.arrow],\n    [arrowAnimatedStyle]\n  );\n  const containerAnimatedStyle = useAnimatedStyle(\n    () => ({\n      opacity: interpolate(\n        animatedIndex.value,\n        [-0.85, 0],\n        [0, 1],\n        Extrapolation.CLAMP\n      ),\n    }),\n    [animatedIndex]\n  );\n  const containerStyle = useMemo(\n    () => [containerAnimatedStyle, styles.container],\n    [containerAnimatedStyle]\n  );\n  //#endregion\n\n  const handleArrowPress = useCallback(() => {\n    if (animatedIndex.value === 0) {\n      expand();\n    } else {\n      collapse();\n    }\n  }, [expand, collapse, animatedIndex]);\n\n  return (\n    <BottomSheetFooter\n      bottomInset={bottomSafeArea}\n      animatedFooterPosition={animatedFooterPosition}\n    >\n      <AnimatedRectButton style={containerStyle} onPress={handleArrowPress}>\n        <Animated.Text style={arrowStyle}>⌃</Animated.Text>\n      </AnimatedRectButton>\n    </BottomSheetFooter>\n  );\n};\n\nconst styles = StyleSheet.create({\n  container: {\n    alignSelf: 'flex-end',\n    justifyContent: 'center',\n    alignItems: 'center',\n    marginHorizontal: 24,\n    marginBottom: 12,\n    width: 50,\n    height: 50,\n    borderRadius: 25,\n    backgroundColor: '#80f',\n    shadowOffset: {\n      width: 0,\n      height: 12,\n    },\n    shadowOpacity: 0.25,\n    shadowRadius: 8.0,\n\n    elevation: 8,\n  },\n  arrow: {\n    fontSize: 20,\n    height: 20,\n    textAlignVertical: 'center',\n    fontWeight: '900',\n    color: '#fff',\n  },\n});\n\nexport const CustomFooter = memo(CustomFooterComponent);\n"
  },
  {
    "path": "example/src/components/customFooter/index.ts",
    "content": "export { CustomFooter } from './CustomFooter';\n"
  },
  {
    "path": "example/src/components/customHandle/CustomHandle.tsx",
    "content": "import type { BottomSheetHandleProps } from '@gorhom/bottom-sheet';\nimport React, { memo, useMemo } from 'react';\nimport { type StyleProp, StyleSheet, Text, type ViewStyle } from 'react-native';\nimport Animated, {\n  Extrapolation,\n  interpolate,\n  useAnimatedStyle,\n  useDerivedValue,\n} from 'react-native-reanimated';\nimport { toRad } from 'react-native-redash';\nimport { transformOrigin } from '../../utilities/transformOrigin';\n\ninterface CustomHandleProps extends BottomSheetHandleProps {\n  title: string;\n}\n\nconst CustomHandleComponent: React.FC<CustomHandleProps> = ({\n  ref,\n  title,\n  style,\n  onLayout,\n  animatedIndex,\n}) => {\n  //#region animations\n\n  const indicatorTransformOriginY = useDerivedValue(\n    () =>\n      interpolate(\n        animatedIndex.value,\n        [0, 1, 2],\n        [-1, 0, 1],\n        Extrapolation.CLAMP\n      ),\n    [animatedIndex.value]\n  );\n  //#endregion\n\n  //#region styles\n  const containerStyle = useMemo(() => [styles.container, style], [style]);\n  const containerAnimatedStyle = useAnimatedStyle(() => {\n    const borderTopRadius = interpolate(\n      animatedIndex.value,\n      [1, 2],\n      [20, 0],\n      Extrapolation.CLAMP\n    );\n    return {\n      borderTopLeftRadius: borderTopRadius,\n      borderTopRightRadius: borderTopRadius,\n    };\n  }, [animatedIndex.value]);\n  const leftIndicatorStyle = useMemo(\n    () => ({\n      ...styles.indicator,\n      ...styles.leftIndicator,\n    }),\n    []\n  );\n  const leftIndicatorAnimatedStyle = useAnimatedStyle(() => {\n    const leftIndicatorRotate = interpolate(\n      animatedIndex.value,\n      [0, 1, 2],\n      [toRad(-30), 0, toRad(30)],\n      Extrapolation.CLAMP\n    );\n    return {\n      transform: transformOrigin(\n        { x: 0, y: indicatorTransformOriginY.value },\n        {\n          rotate: `${leftIndicatorRotate}rad`,\n        },\n        {\n          translateX: -5,\n        }\n      ),\n    };\n  }, [animatedIndex.value, indicatorTransformOriginY.value]);\n  const rightIndicatorStyle = useMemo(\n    () => ({\n      ...styles.indicator,\n      ...styles.rightIndicator,\n    }),\n    []\n  );\n  const rightIndicatorAnimatedStyle = useAnimatedStyle(() => {\n    const rightIndicatorRotate = interpolate(\n      animatedIndex.value,\n      [0, 1, 2],\n      [toRad(30), 0, toRad(-30)],\n      Extrapolation.CLAMP\n    );\n    return {\n      transform: transformOrigin(\n        { x: 0, y: indicatorTransformOriginY.value },\n        {\n          rotate: `${rightIndicatorRotate}rad`,\n        },\n        {\n          translateX: 5,\n        }\n      ),\n    };\n  }, [animatedIndex.value, indicatorTransformOriginY.value]);\n  //#endregion\n\n  // render\n  return (\n    <Animated.View\n      ref={ref}\n      style={[containerStyle, containerAnimatedStyle]}\n      onLayout={onLayout}\n      renderToHardwareTextureAndroid={true}\n    >\n      <Animated.View style={[leftIndicatorStyle, leftIndicatorAnimatedStyle]} />\n      <Animated.View\n        style={[rightIndicatorStyle, rightIndicatorAnimatedStyle]}\n      />\n      <Text style={styles.title}>{title}</Text>\n    </Animated.View>\n  );\n};\n\nexport const CustomHandle = memo(CustomHandleComponent);\n\nconst styles = StyleSheet.create({\n  container: {\n    alignContent: 'center',\n    alignItems: 'center',\n    paddingBottom: 12,\n    paddingHorizontal: 16,\n    borderBottomWidth: 1,\n    borderBottomColor: 'rgba(0,0,0,0.125)',\n    zIndex: 99999,\n  },\n  indicator: {\n    marginTop: 10,\n    position: 'absolute',\n    width: 10,\n    height: 4,\n    backgroundColor: '#999',\n  },\n  leftIndicator: {\n    borderTopStartRadius: 2,\n    borderBottomStartRadius: 2,\n  },\n  rightIndicator: {\n    borderTopEndRadius: 2,\n    borderBottomEndRadius: 2,\n  },\n  title: {\n    marginTop: 26,\n    fontSize: 20,\n    lineHeight: 20,\n    textAlign: 'center',\n    fontWeight: 'bold',\n  },\n});\n"
  },
  {
    "path": "example/src/components/customHandle/index.ts",
    "content": "export { CustomHandle } from './CustomHandle';\n"
  },
  {
    "path": "example/src/components/headerHandle/HeaderHandle.tsx",
    "content": "import {\n  BottomSheetHandle,\n  type BottomSheetHandleProps,\n} from '@gorhom/bottom-sheet';\nimport React, { memo } from 'react';\nimport { StyleSheet, Text } from 'react-native';\n\ninterface HeaderHandleProps extends BottomSheetHandleProps {}\n\nconst HeaderHandleComponent = ({ children, ...rest }: HeaderHandleProps) => {\n  return (\n    <BottomSheetHandle\n      style={styles.container}\n      indicatorStyle={styles.indicator}\n      {...rest}\n    >\n      {typeof children === 'string' ? (\n        <Text style={styles.title}>{children}</Text>\n      ) : (\n        children\n      )}\n    </BottomSheetHandle>\n  );\n};\n\nconst styles = StyleSheet.create({\n  container: {\n    paddingBottom: 12,\n    paddingHorizontal: 16,\n    borderBottomWidth: 1,\n    borderBottomColor: 'rgba(0,0,0,0.075)',\n    zIndex: 99999,\n  },\n  title: {\n    marginTop: 16,\n    fontSize: 20,\n    lineHeight: 20,\n    textAlign: 'center',\n    fontWeight: 'bold',\n    color: 'black',\n  },\n  indicator: {\n    height: 4,\n    opacity: 0.5,\n  },\n});\n\nexport const HeaderHandle = memo(HeaderHandleComponent);\n"
  },
  {
    "path": "example/src/components/headerHandle/index.ts",
    "content": "export { HeaderHandle } from './HeaderHandle';\n"
  },
  {
    "path": "example/src/components/searchHandle/SearchHandle.tsx",
    "content": "import {\n  type BottomSheetHandleProps,\n  BottomSheetTextInput,\n} from '@gorhom/bottom-sheet';\nimport { useShowcaseTheme } from '@gorhom/showcase-template';\nimport React, { memo, useState, useCallback } from 'react';\nimport {\n  Dimensions,\n  type NativeSyntheticEvent,\n  StyleSheet,\n  type TextInputChangeEventData,\n  View,\n} from 'react-native';\n\nconst { width: SCREEN_WIDTH } = Dimensions.get('screen');\nexport const SEARCH_HANDLE_HEIGHT = 69;\n\ninterface SearchHandleProps extends BottomSheetHandleProps {\n  initialValue?: string;\n  onChange?: (text: string) => void;\n}\n\nconst SearchHandleComponent = ({\n  initialValue = '',\n  onChange,\n}: SearchHandleProps) => {\n  // state\n  const [value, setValue] = useState(initialValue);\n\n  // hooks\n  const { colors } = useShowcaseTheme();\n\n  // callbacks\n  const handleInputChange = useCallback(\n    ({\n      nativeEvent: { text },\n    }: NativeSyntheticEvent<TextInputChangeEventData>) => {\n      setValue(text);\n\n      if (onChange) {\n        onChange(text);\n      }\n    },\n    [onChange]\n  );\n\n  // render\n  return (\n    <View style={styles.container}>\n      <View style={styles.indicator} />\n      <BottomSheetTextInput\n        style={styles.input}\n        value={value}\n        textContentType=\"location\"\n        placeholderTextColor={colors.secondaryText}\n        placeholder=\"Search for a place or address\"\n        onChange={handleInputChange}\n      />\n    </View>\n  );\n};\n\nexport const styles = StyleSheet.create({\n  container: {\n    paddingHorizontal: 16,\n    paddingVertical: 5,\n  },\n  indicator: {\n    alignSelf: 'center',\n    width: (8 * SCREEN_WIDTH) / 100,\n    height: 5,\n    borderRadius: 4,\n    backgroundColor: 'rgba(0, 0, 0, 0.5)',\n  },\n  input: {\n    marginTop: 8,\n    marginBottom: 10,\n    borderRadius: 10,\n    fontSize: 16,\n    lineHeight: 20,\n    padding: 8,\n    backgroundColor: 'rgba(151, 151, 151, 0.25)',\n  },\n});\n\nexport const SearchHandle = memo(SearchHandleComponent);\n"
  },
  {
    "path": "example/src/components/searchHandle/index.ts",
    "content": "export { SearchHandle, SEARCH_HANDLE_HEIGHT } from './SearchHandle';\n"
  },
  {
    "path": "example/src/screens/advanced/BackdropExample.tsx",
    "content": "import BottomSheet, { BottomSheetBackdrop } from '@gorhom/bottom-sheet';\nimport React, { useCallback, useMemo, useRef, useState } from 'react';\nimport { StyleSheet, View } from 'react-native';\nimport { Button } from '../../components/button';\nimport { ContactList } from '../../components/contactList';\nimport { HeaderHandle } from '../../components/headerHandle';\n\nconst BackdropExample = () => {\n  // state\n  const [backdropPressBehavior, setBackdropPressBehavior] = useState<\n    'none' | 'close' | 'collapse'\n  >('collapse');\n\n  // hooks\n  const bottomSheetRef = useRef<BottomSheet>(null);\n\n  // variables\n  const snapPoints = useMemo(() => ['25%', '50%'], []);\n\n  // callbacks\n  const handleTogglePressBehavior = useCallback(() => {\n    setBackdropPressBehavior(state => {\n      switch (state) {\n        case 'none':\n          return 'close';\n        case 'close':\n          return 'collapse';\n        case 'collapse':\n          return 'none';\n      }\n    });\n  }, []);\n  const handleExpandPress = useCallback(() => {\n    bottomSheetRef.current?.expand();\n  }, []);\n  const handleCollapsePress = useCallback(() => {\n    bottomSheetRef.current?.collapse();\n  }, []);\n  const handleClosePress = useCallback(() => {\n    bottomSheetRef.current?.close();\n  }, []);\n\n  // renders\n  const renderBackdrop = useCallback(\n    props => (\n      <BottomSheetBackdrop {...props} pressBehavior={backdropPressBehavior} />\n    ),\n    [backdropPressBehavior]\n  );\n  const renderHeaderHandle = useCallback(\n    props => <HeaderHandle {...props} children=\"Backdrop Example\" />,\n    []\n  );\n  return (\n    <View style={styles.container}>\n      <Button\n        label={`Toggle Press Behavior: ${backdropPressBehavior}`}\n        onPress={handleTogglePressBehavior}\n      />\n      <Button label=\"Expand\" onPress={handleExpandPress} />\n      <Button label=\"Collapse\" onPress={handleCollapsePress} />\n      <Button label=\"Close\" onPress={handleClosePress} />\n      <BottomSheet\n        ref={bottomSheetRef}\n        snapPoints={snapPoints}\n        backdropComponent={renderBackdrop}\n        handleComponent={renderHeaderHandle}\n        enableDynamicSizing={false}\n      >\n        <ContactList type=\"FlatList\" count={10} />\n      </BottomSheet>\n    </View>\n  );\n};\n\nconst styles = StyleSheet.create({\n  container: {\n    flex: 1,\n    padding: 24,\n  },\n});\n\nexport default BackdropExample;\n"
  },
  {
    "path": "example/src/screens/advanced/CustomBackgroundExample.tsx",
    "content": "import React, { useCallback, useMemo, useRef } from 'react';\nimport { View, StyleSheet } from 'react-native';\nimport BottomSheet from '@gorhom/bottom-sheet';\nimport { CustomBackground } from '../../components/customBackground';\nimport { Button } from '../../components/button';\nimport { ContactList } from '../../components/contactList';\nimport { HeaderHandle } from '../../components/headerHandle';\n\nconst CustomBackgroundExample = () => {\n  // hooks\n  const bottomSheetRef = useRef<BottomSheet>(null);\n\n  // variables\n  const snapPoints = useMemo(() => [150, 450], []);\n\n  // callbacks\n  const handleSnapPress = useCallback(index => {\n    bottomSheetRef.current?.snapToIndex(index);\n  }, []);\n  const handleExpandPress = useCallback(() => {\n    bottomSheetRef.current?.expand();\n  }, []);\n  const handleCollapsePress = useCallback(() => {\n    bottomSheetRef.current?.collapse();\n  }, []);\n  const handleClosePress = useCallback(() => {\n    bottomSheetRef.current?.close();\n  }, []);\n\n  // render\n  const renderHeaderHandle = useCallback(\n    props => <HeaderHandle {...props} children=\"Custom Background Example\" />,\n    []\n  );\n  return (\n    <View style={styles.container}>\n      <Button label=\"Snap To 450\" onPress={() => handleSnapPress(1)} />\n      <Button label=\"Snap To 150\" onPress={() => handleSnapPress(0)} />\n      <Button label=\"Expand\" onPress={handleExpandPress} />\n      <Button label=\"Collapse\" onPress={handleCollapsePress} />\n      <Button label=\"Close\" onPress={handleClosePress} />\n      <BottomSheet\n        ref={bottomSheetRef}\n        snapPoints={snapPoints}\n        animateOnMount={true}\n        handleComponent={renderHeaderHandle}\n        backgroundComponent={CustomBackground}\n      >\n        <ContactList type=\"View\" count={5} />\n      </BottomSheet>\n    </View>\n  );\n};\n\nconst styles = StyleSheet.create({\n  container: {\n    flex: 1,\n    padding: 24,\n  },\n  contentContainerStyle: {\n    paddingTop: 12,\n    paddingHorizontal: 24,\n    backgroundColor: 'white',\n  },\n  headerContainer: {\n    backgroundColor: 'transparent',\n  },\n});\n\nexport default CustomBackgroundExample;\n"
  },
  {
    "path": "example/src/screens/advanced/CustomHandleExample.tsx",
    "content": "import BottomSheet from '@gorhom/bottom-sheet';\nimport React, { useCallback, useMemo, useRef } from 'react';\nimport { StyleSheet, View } from 'react-native';\nimport { Button } from '../../components/button';\nimport { ContactList } from '../../components/contactList';\nimport { CustomHandle } from '../../components/customHandle';\n\nconst CustomHandleExample = () => {\n  // hooks\n  const bottomSheetRef = useRef<BottomSheet>(null);\n\n  // variables\n  const snapPoints = useMemo(() => [150, 300, 450], []);\n\n  // callbacks\n  const handleSnapPress = useCallback(index => {\n    bottomSheetRef.current?.snapToIndex(index);\n  }, []);\n  const handleExpandPress = useCallback(() => {\n    bottomSheetRef.current?.expand();\n  }, []);\n  const handleCollapsePress = useCallback(() => {\n    bottomSheetRef.current?.collapse();\n  }, []);\n  const handleClosePress = useCallback(() => {\n    bottomSheetRef.current?.close();\n  }, []);\n\n  // renders\n  const renderCustomHandle = useCallback(\n    props => <CustomHandle title=\"Custom Handle Example\" {...props} />,\n    []\n  );\n  return (\n    <View style={styles.container}>\n      <Button label=\"Snap To 450\" onPress={() => handleSnapPress(2)} />\n      <Button label=\"Snap To 300\" onPress={() => handleSnapPress(1)} />\n      <Button label=\"Snap To 150\" onPress={() => handleSnapPress(0)} />\n      <Button label=\"Expand\" onPress={handleExpandPress} />\n      <Button label=\"Collapse\" onPress={handleCollapsePress} />\n      <Button label=\"Close\" onPress={handleClosePress} />\n      <BottomSheet\n        ref={bottomSheetRef}\n        snapPoints={snapPoints}\n        enableDynamicSizing={false}\n        handleComponent={renderCustomHandle}\n      >\n        <ContactList count={10} type=\"FlatList\" />\n      </BottomSheet>\n    </View>\n  );\n};\n\nconst styles = StyleSheet.create({\n  container: {\n    flex: 1,\n    padding: 24,\n  },\n});\n\nexport default CustomHandleExample;\n"
  },
  {
    "path": "example/src/screens/advanced/CustomThemeExample.tsx",
    "content": "import React, { useCallback, useMemo, useRef } from 'react';\nimport { View, StyleSheet } from 'react-native';\nimport BottomSheet, { BottomSheetView } from '@gorhom/bottom-sheet';\nimport { Button } from '../../components/button';\nimport { ContactItem } from '../../components/contactItem';\nimport { createContactListMockData } from '../../utilities/createMockData';\n\nconst CustomThemeExample = () => {\n  // hooks\n  const bottomSheetRef = useRef<BottomSheet>(null);\n\n  // variables\n  const snapPoints = useMemo(() => ['25%', '50%'], []);\n  const data = useMemo(() => createContactListMockData(5), []);\n\n  // callbacks\n  const handleExpandPress = useCallback(() => {\n    bottomSheetRef.current?.expand();\n  }, []);\n  const handleCollapsePress = useCallback(() => {\n    bottomSheetRef.current?.collapse();\n  }, []);\n  const handleClosePress = useCallback(() => {\n    bottomSheetRef.current?.close();\n  }, []);\n\n  // renders\n  const renderItem = useCallback(\n    (item, index) => (\n      <ContactItem\n        key={`${item.name}.${index}`}\n        title={item.name}\n        subTitle={item.jobTitle}\n        titleStyle={styles.titleStyle}\n        subTitleStyle={styles.subTitleStyle}\n        thumbnailStyle={styles.thumbnailStyle}\n        iconStyle={styles.iconStyle}\n      />\n    ),\n    []\n  );\n  return (\n    <View style={styles.container}>\n      <Button label=\"Expand\" onPress={handleExpandPress} />\n      <Button label=\"Collapse\" onPress={handleCollapsePress} />\n      <Button label=\"Close\" onPress={handleClosePress} />\n\n      <BottomSheet\n        ref={bottomSheetRef}\n        snapPoints={snapPoints}\n        animateOnMount={true}\n        backgroundStyle={styles.backgroundContainer}\n        handleIndicatorStyle={styles.handleIndicator}\n      >\n        <BottomSheetView style={styles.contentContainer}>\n          {data.map(renderItem)}\n        </BottomSheetView>\n      </BottomSheet>\n    </View>\n  );\n};\n\nconst styles = StyleSheet.create({\n  container: {\n    flex: 1,\n    padding: 24,\n  },\n  contentContainer: {\n    paddingHorizontal: 16,\n    overflow: 'visible',\n  },\n  backgroundContainer: {\n    backgroundColor: '#222',\n  },\n  handleIndicator: {\n    backgroundColor: '#eee',\n  },\n  titleStyle: {\n    color: '#dfdfdf',\n  },\n  subTitleStyle: {},\n  thumbnailStyle: {\n    backgroundColor: '#444',\n  },\n  iconStyle: {\n    backgroundColor: '#292929',\n  },\n});\n\nexport default CustomThemeExample;\n"
  },
  {
    "path": "example/src/screens/advanced/DynamicSizingExample.tsx",
    "content": "import BottomSheet, {\n  BottomSheetFooter,\n  type BottomSheetFooterProps,\n  BottomSheetScrollView,\n  BottomSheetView,\n  type SNAP_POINT_TYPE,\n} from '@gorhom/bottom-sheet';\nimport React, { useCallback, useMemo, useRef, useState } from 'react';\nimport { StyleSheet, View } from 'react-native';\nimport { useSafeAreaInsets } from 'react-native-safe-area-context';\nimport { Button } from '../../components/button';\nimport { ContactItem } from '../../components/contactItem';\nimport { createContactListMockData } from '../../utilities/createMockData';\n\nconst DATA = createContactListMockData(20);\n\nconst DynamicSizingExample = () => {\n  //#region state\n  const [count, setCount] = useState(1);\n  const [maxHeight, setMaxHeight] = useState<undefined | number>();\n  //#endregion\n\n  //#region variable\n  const data = useMemo(() => DATA.slice(0, count), [count]);\n  //#endregion\n\n  //#region hooks\n  const { bottom: safeBottomArea } = useSafeAreaInsets();\n  const bottomSheetRef = useRef<BottomSheet>(null);\n  //#endregion\n\n  //#region callbacks\n  const handleIncreaseContentPress = useCallback(() => {\n    setCount(state => state + 1);\n  }, []);\n  const handleDecreaseContentPress = useCallback(() => {\n    setCount(state => Math.max(state - 1, 1));\n  }, []);\n  const handleSetMaxHeight = useCallback(() => {\n    setMaxHeight(state => (state ? undefined : 500));\n  }, []);\n  const handleExpandPress = useCallback(() => {\n    bottomSheetRef.current?.expand();\n  }, []);\n  const handleClosePress = useCallback(() => {\n    bottomSheetRef.current?.close();\n  }, []);\n  const handleSheetChange = useCallback(\n    (index: number, position: number, type: SNAP_POINT_TYPE) => {\n      // biome-ignore lint/suspicious/noConsole: <explanation>\n      console.log('handleSheetChange', { index, position, type });\n    },\n    []\n  );\n  //#endregion\n\n  //#region styles\n  const footerContainerStyle = useMemo(\n    () => ({\n      ...styles.footerContainer,\n      paddingBottom: safeBottomArea || 6,\n    }),\n    [safeBottomArea]\n  );\n  //#endregion\n\n  //#region renders\n  const footerComponent = useMemo(\n    () => (props: BottomSheetFooterProps) => (\n      <BottomSheetFooter style={footerContainerStyle} {...props}>\n        <View style={{ flex: 1 }}>\n          <Button\n            label=\"Add Item\"\n            style={styles.footerButton}\n            onPress={handleIncreaseContentPress}\n          />\n        </View>\n        <View style={{ flex: 1 }}>\n          <Button\n            label=\"Remove Item\"\n            style={styles.footerButton}\n            onPress={handleDecreaseContentPress}\n          />\n        </View>\n      </BottomSheetFooter>\n    ),\n    [\n      footerContainerStyle,\n      handleIncreaseContentPress,\n      handleDecreaseContentPress,\n    ]\n  );\n  return (\n    <View style={styles.container}>\n      <Button label=\"Expand\" onPress={handleExpandPress} />\n      <Button label=\"Close\" onPress={handleClosePress} />\n      <Button\n        label={`Max Dynamic Size: ${maxHeight}`}\n        onPress={handleSetMaxHeight}\n      />\n      <BottomSheet\n        ref={bottomSheetRef}\n        enablePanDownToClose={true}\n        maxDynamicContentSize={maxHeight}\n        footerComponent={footerComponent}\n        onChange={handleSheetChange}\n      >\n        <BottomSheetScrollView\n          contentContainerStyle={styles.contentContainerStyle}\n          enableFooterMarginAdjustment={true}\n        >\n          {data.map(item => (\n            <ContactItem\n              key={item.name}\n              title={item.name}\n              subTitle={item.jobTitle}\n            />\n          ))}\n        </BottomSheetScrollView>\n      </BottomSheet>\n    </View>\n  );\n};\n\nconst styles = StyleSheet.create({\n  container: {\n    flex: 1,\n    padding: 24,\n  },\n  contentContainerStyle: {\n    paddingTop: 12,\n    paddingHorizontal: 24,\n    backgroundColor: 'white',\n  },\n  message: {\n    fontSize: 24,\n    fontWeight: '600',\n    marginBottom: 12,\n    color: 'black',\n  },\n  footerContainer: {\n    flexDirection: 'row',\n    justifyContent: 'space-between',\n    gap: 12,\n    paddingHorizontal: 24,\n  },\n  footerButton: {\n    flex: 1,\n  },\n});\n\nexport default DynamicSizingExample;\n"
  },
  {
    "path": "example/src/screens/advanced/FooterExample.tsx",
    "content": "import BottomSheet from '@gorhom/bottom-sheet';\nimport React, { useCallback, useMemo, useRef } from 'react';\nimport { StyleSheet, View } from 'react-native';\nimport { Button } from '../../components/button';\nimport { ContactList } from '../../components/contactList';\nimport { CustomFooter } from '../../components/customFooter';\nimport { SearchHandle } from '../../components/searchHandle';\n\nconst FooterExample = () => {\n  // hooks\n  const bottomSheetRef = useRef<BottomSheet>(null);\n\n  // variables\n  const snapPoints = useMemo(() => ['25%', '50%'], []);\n\n  // callbacks\n  const handleExpandPress = useCallback(() => {\n    bottomSheetRef.current?.expand();\n  }, []);\n  const handleCollapsePress = useCallback(() => {\n    bottomSheetRef.current?.collapse();\n  }, []);\n  const handleClosePress = useCallback(() => {\n    bottomSheetRef.current?.close();\n  }, []);\n\n  // renders\n  return (\n    <View style={styles.container}>\n      <Button label=\"Expand\" onPress={handleExpandPress} />\n      <Button label=\"Collapse\" onPress={handleCollapsePress} />\n      <Button label=\"Close\" onPress={handleClosePress} />\n      <BottomSheet\n        ref={bottomSheetRef}\n        snapPoints={snapPoints}\n        keyboardBehavior=\"interactive\"\n        keyboardBlurBehavior=\"restore\"\n        enablePanDownToClose={true}\n        enableDynamicSizing={false}\n        handleComponent={SearchHandle}\n        footerComponent={CustomFooter}\n      >\n        <ContactList\n          count={10}\n          type=\"FlatList\"\n          enableFooterMarginAdjustment={false}\n        />\n      </BottomSheet>\n    </View>\n  );\n};\n\nconst styles = StyleSheet.create({\n  container: {\n    flex: 1,\n    padding: 24,\n  },\n  footer: {\n    alignSelf: 'flex-end',\n    justifyContent: 'center',\n    alignItems: 'center',\n    marginHorizontal: 24,\n    width: 50,\n    height: 50,\n    borderRadius: 25,\n    backgroundColor: '#80f',\n    shadowOffset: {\n      width: 0,\n      height: 12,\n    },\n    shadowOpacity: 0.25,\n    shadowRadius: 8.0,\n\n    elevation: 24,\n  },\n  footerText: {\n    fontSize: 16,\n    fontWeight: '600',\n    color: '#fff',\n  },\n});\n\nexport default FooterExample;\n"
  },
  {
    "path": "example/src/screens/advanced/KeyboardHandlingExample.tsx",
    "content": "import BottomSheet from '@gorhom/bottom-sheet';\nimport React, { useCallback, useMemo, useRef, useState } from 'react';\nimport { StyleSheet, View } from 'react-native';\nimport { Button } from '../../components/button';\nimport { ContactList } from '../../components/contactList';\nimport {\n  SEARCH_HANDLE_HEIGHT,\n  SearchHandle,\n} from '../../components/searchHandle';\n\nconst KeyboardHandlingExample = () => {\n  // state\n  const [keyboardBehavior, setKeyboardBehavior] = useState<\n    'extend' | 'fillParent' | 'interactive'\n  >('interactive');\n  const [keyboardBlurBehavior, setKeyboardBlurBehavior] = useState<\n    'none' | 'restore'\n  >('none');\n  const [blurKeyboardOnGesture, setBlurKeyboardOnGesture] = useState(false);\n\n  // hooks\n  const bottomSheetRef = useRef<BottomSheet>(null);\n\n  // variables\n  const snapPoints = useMemo(() => [SEARCH_HANDLE_HEIGHT + 34, 480], []);\n\n  // callbacks\n  const handleToggleKeyboardBehavior = useCallback(() => {\n    setKeyboardBehavior(state => {\n      switch (state) {\n        case 'interactive':\n          return 'extend';\n        case 'extend':\n          return 'fillParent';\n        case 'fillParent':\n          return 'interactive';\n      }\n    });\n  }, []);\n  const handleToggleKeyboardBlurBehavior = useCallback(() => {\n    setKeyboardBlurBehavior(state => {\n      switch (state) {\n        case 'none':\n          return 'restore';\n        case 'restore':\n          return 'none';\n      }\n    });\n  }, []);\n  const handleToggleBlurKeyboardOnGesture = useCallback(() => {\n    setBlurKeyboardOnGesture(state => !state);\n  }, []);\n  const handleExpandPress = useCallback(() => {\n    bottomSheetRef.current?.expand();\n  }, []);\n  const handleCollapsePress = useCallback(() => {\n    bottomSheetRef.current?.collapse();\n  }, []);\n  const handleClosePress = useCallback(() => {\n    bottomSheetRef.current?.close();\n  }, []);\n\n  // renders\n  return (\n    <View style={styles.container}>\n      <Button\n        label={`Toggle Keyboard Behavior: ${keyboardBehavior}`}\n        onPress={handleToggleKeyboardBehavior}\n      />\n      <Button\n        label={`Toggle Keyboard Blur Behavior: ${keyboardBlurBehavior}`}\n        onPress={handleToggleKeyboardBlurBehavior}\n      />\n      <Button\n        label={`Toggle Blur Keyboard On Gesture: ${blurKeyboardOnGesture}`}\n        onPress={handleToggleBlurKeyboardOnGesture}\n      />\n      <Button label=\"Expand\" onPress={handleExpandPress} />\n      <Button label=\"Collapse\" onPress={handleCollapsePress} />\n      <Button label=\"Close\" onPress={handleClosePress} />\n      <BottomSheet\n        ref={bottomSheetRef}\n        snapPoints={snapPoints}\n        enableDynamicSizing={false}\n        keyboardBehavior={keyboardBehavior}\n        keyboardBlurBehavior={keyboardBlurBehavior}\n        enableBlurKeyboardOnGesture={blurKeyboardOnGesture}\n        handleComponent={SearchHandle}\n      >\n        <ContactList count={15} type=\"FlatList\" />\n      </BottomSheet>\n    </View>\n  );\n};\n\nconst styles = StyleSheet.create({\n  container: {\n    flex: 1,\n    padding: 24,\n  },\n});\n\nexport default KeyboardHandlingExample;\n"
  },
  {
    "path": "example/src/screens/advanced/PullToRefreshExample.tsx",
    "content": "import BottomSheet from '@gorhom/bottom-sheet';\nimport React, { useCallback, useMemo, useRef } from 'react';\nimport { StyleSheet, View } from 'react-native';\nimport { Button } from '../../components/button';\nimport { ContactList } from '../../components/contactList';\nimport { HeaderHandle } from '../../components/headerHandle/HeaderHandle';\n\nconst PullToRefreshExample = () => {\n  // hooks\n  const bottomSheetRef = useRef<BottomSheet>(null);\n\n  // variables\n  const snapPoints = useMemo(() => ['25%', '50%'], []);\n\n  // callbacks\n  const handleRefresh = useCallback(() => {\n    // biome-ignore lint/suspicious/noConsole: it is need for the example\n    console.log('handleRefresh');\n  }, []);\n  const handleExpandPress = useCallback(() => {\n    bottomSheetRef.current?.expand();\n  }, []);\n  const handleCollapsePress = useCallback(() => {\n    bottomSheetRef.current?.collapse();\n  }, []);\n  const handleClosePress = useCallback(() => {\n    bottomSheetRef.current?.close();\n  }, []);\n\n  // renders\n  const renderHeaderHandle = useCallback(\n    props => <HeaderHandle {...props} children=\"Pull To Refresh Example\" />,\n    []\n  );\n  return (\n    <View style={styles.container}>\n      <Button label=\"Expand\" onPress={handleExpandPress} />\n      <Button label=\"Collapse\" onPress={handleCollapsePress} />\n      <Button label=\"Close\" onPress={handleClosePress} />\n      <BottomSheet\n        ref={bottomSheetRef}\n        snapPoints={snapPoints}\n        enableDynamicSizing={false}\n        handleComponent={renderHeaderHandle}\n      >\n        <ContactList type=\"FlatList\" count={15} onRefresh={handleRefresh} />\n      </BottomSheet>\n    </View>\n  );\n};\n\nconst styles = StyleSheet.create({\n  container: {\n    flex: 1,\n    padding: 24,\n  },\n});\n\nexport default PullToRefreshExample;\n"
  },
  {
    "path": "example/src/screens/advanced/ShadowExample.tsx",
    "content": "import React, { useCallback, useMemo, useRef } from 'react';\nimport { View, StyleSheet, Platform } from 'react-native';\nimport BottomSheet from '@gorhom/bottom-sheet';\nimport { useShowcaseTheme } from '@gorhom/showcase-template';\nimport { Button } from '../../components/button';\nimport { ContactList } from '../../components/contactList';\nimport { HeaderHandle } from '../../components/headerHandle';\n\nconst ShadowExample = () => {\n  // hooks\n  const bottomSheetRef = useRef<BottomSheet>(null);\n  const { colors } = useShowcaseTheme();\n\n  // variables\n  const snapPoints = useMemo(() => ['25%', '50%'], []);\n\n  // styles\n  const sheetStyle = useMemo(\n    () => ({\n      ...styles.sheetContainer,\n      ...styles.sheetContainerShadow,\n      shadowColor: colors.secondaryText,\n    }),\n    [colors.secondaryText]\n  );\n\n  // callbacks\n  const handleExpandPress = useCallback(() => {\n    bottomSheetRef.current?.expand();\n  }, []);\n  const handleCollapsePress = useCallback(() => {\n    bottomSheetRef.current?.collapse();\n  }, []);\n  const handleClosePress = useCallback(() => {\n    bottomSheetRef.current?.close();\n  }, []);\n\n  // renders\n  const renderHeaderHandle = useCallback(\n    props => <HeaderHandle {...props} children=\"Shadow Example\" />,\n    []\n  );\n  return (\n    <View style={styles.container}>\n      <Button label=\"Expand\" onPress={handleExpandPress} />\n      <Button label=\"Collapse\" onPress={handleCollapsePress} />\n      <Button label=\"Close\" onPress={handleClosePress} />\n\n      <BottomSheet\n        ref={bottomSheetRef}\n        snapPoints={snapPoints}\n        animateOnMount={true}\n        handleComponent={renderHeaderHandle}\n        style={sheetStyle}\n      >\n        <ContactList type=\"View\" count={3} />\n      </BottomSheet>\n    </View>\n  );\n};\n\nconst styles = StyleSheet.create({\n  container: {\n    backgroundColor: 'white',\n    flex: 1,\n    padding: 24,\n  },\n  sheetContainer: {\n    backgroundColor: 'white',\n    borderTopStartRadius: 24,\n    borderTopEndRadius: 24,\n  },\n  sheetContainerShadow: Platform.select({\n    ios: {\n      shadowOffset: {\n        width: 0,\n        height: 12,\n      },\n      shadowOpacity: 0.75,\n      shadowRadius: 16.0,\n      shadowColor: '#000',\n    },\n    android: {\n      elevation: 24,\n    },\n    web: {\n      boxShadow: '0px -4px 16px rgba(0,0,0, 0.25)',\n    },\n  }) as any,\n});\n\nexport default ShadowExample;\n"
  },
  {
    "path": "example/src/screens/basic/BasicExamples.tsx",
    "content": "import React, { useCallback, memo, useRef, useMemo, useState } from 'react';\nimport { StyleSheet, View } from 'react-native';\nimport BottomSheet, { useBottomSheetSpringConfigs } from '@gorhom/bottom-sheet';\nimport { ContactList } from '../../components/contactList';\nimport { Button } from '../../components/button';\n\ninterface ExampleScreenProps {\n  title: string;\n  type: 'FlatList' | 'SectionList' | 'ScrollView' | 'View' | 'VirtualizedList';\n  count?: number;\n}\n\nconst createExampleScreen = ({ type, count = 25 }: ExampleScreenProps) =>\n  memo(() => {\n    //#region state\n    const [enableContentPanningGesture, setEnableContentPanningGesture] =\n      useState(true);\n    const [enableHandlePanningGesture, setEnableHandlePanningGesture] =\n      useState(true);\n    //#endregion\n\n    //#region refs\n    const bottomSheetRef = useRef<BottomSheet>(null);\n    //#endregion\n\n    //#region variables\n    const snapPoints = useMemo(() => ['25%', '50%', '90%'], []);\n    const enableContentPanningGestureButtonText = useMemo(\n      () =>\n        enableContentPanningGesture\n          ? 'Disable Content Panning Gesture'\n          : 'Enable Content Panning Gesture',\n      [enableContentPanningGesture]\n    );\n    const enableHandlePanningGestureButtonText = useMemo(\n      () =>\n        enableHandlePanningGesture\n          ? 'Disable Handle Panning Gesture'\n          : 'Enable Handle Panning Gesture',\n      [enableHandlePanningGesture]\n    );\n    const animationConfigs = useBottomSheetSpringConfigs({\n      damping: 80,\n      overshootClamping: true,\n      restDisplacementThreshold: 0.1,\n      restSpeedThreshold: 0.1,\n      stiffness: 500,\n    });\n    //#endregion\n\n    //#region callbacks\n    const handleSheetChange = useCallback((index: number) => {\n      // eslint-disable-next-line no-console\n      console.log('handleSheetChange', index);\n    }, []);\n    const handleSheetAnimate = useCallback(\n      (fromIndex: number, toIndex: number) => {\n        // eslint-disable-next-line no-console\n        console.log('handleSheetAnimate', `from ${fromIndex} to ${toIndex}`);\n      },\n      []\n    );\n    const handleSnapPress = useCallback((index: number) => {\n      bottomSheetRef.current?.snapToIndex(index);\n    }, []);\n    const handleExpandPress = useCallback(() => {\n      bottomSheetRef.current?.expand();\n    }, []);\n    const handleCollapsePress = useCallback(() => {\n      bottomSheetRef.current?.collapse();\n    }, []);\n    const handleClosePress = useCallback(() => {\n      bottomSheetRef.current?.close();\n    }, []);\n    const handleEnableContentPanningGesturePress = useCallback(() => {\n      setEnableContentPanningGesture(state => !state);\n    }, []);\n    const handleEnableHandlePanningGesturePress = useCallback(() => {\n      setEnableHandlePanningGesture(state => !state);\n    }, []);\n    //#endregion\n\n    return (\n      <View style={styles.container}>\n        <Button label=\"Snap To 90%\" onPress={() => handleSnapPress(2)} />\n        <Button label=\"Snap To 50%\" onPress={() => handleSnapPress(1)} />\n        <Button label=\"Snap To 25%\" onPress={() => handleSnapPress(0)} />\n        <Button label=\"Expand\" onPress={handleExpandPress} />\n        <Button label=\"Collapse\" onPress={handleCollapsePress} />\n        <Button label=\"Close\" onPress={handleClosePress} />\n        <Button\n          label={enableContentPanningGestureButtonText}\n          onPress={handleEnableContentPanningGesturePress}\n        />\n        <Button\n          label={enableHandlePanningGestureButtonText}\n          onPress={handleEnableHandlePanningGesturePress}\n        />\n        <BottomSheet\n          ref={bottomSheetRef}\n          index={1}\n          snapPoints={snapPoints}\n          animationConfigs={animationConfigs}\n          animateOnMount={true}\n          enableContentPanningGesture={enableContentPanningGesture}\n          enableHandlePanningGesture={enableHandlePanningGesture}\n          enableDynamicSizing={false}\n          onChange={handleSheetChange}\n          onAnimate={handleSheetAnimate}\n        >\n          <ContactList key={`${type}.list`} type={type} count={count} />\n        </BottomSheet>\n      </View>\n    );\n  });\n\nconst styles = StyleSheet.create({\n  container: {\n    flex: 1,\n    padding: 24,\n  },\n});\n\nexport const FlatListExampleScreen = createExampleScreen({\n  title: 'FlatList Example',\n  type: 'FlatList',\n});\n\nexport const VirtualizedListExampleScreen = createExampleScreen({\n  title: 'VirtualizedList Example',\n  type: 'VirtualizedList',\n});\n\nexport const ScrollViewExampleScreen = createExampleScreen({\n  title: 'Title',\n  type: 'ScrollView',\n});\n\nexport const SectionListExampleScreen = createExampleScreen({\n  title: 'Title',\n  type: 'SectionList',\n});\n\nexport const ViewExampleScreen = createExampleScreen({\n  title: 'Title',\n  type: 'View',\n  count: 8,\n});\n"
  },
  {
    "path": "example/src/screens/index.ts",
    "content": "import type { ShowcaseExampleScreenSectionType } from '@gorhom/showcase-template';\nimport { Platform } from 'react-native';\n\nconst screens: Array<object> = [\n  {\n    name: '🔥 LegendList',\n    slug: 'Integrations/LegendList-featured',\n    title: '🔥 LegendList',\n    getScreen: () => require('./integrations/legendlist').default,\n  },\n];\n\n//#region Basic Section\nconst basicSection = {\n  title: 'Basic',\n  collapsible: false,\n  data: [\n    {\n      name: 'View',\n      slug: 'Basic/ViewExample',\n      getScreen: () => require('./basic/BasicExamples').ViewExampleScreen,\n    },\n    {\n      name: 'ScrollView',\n      slug: 'Basic/ScrollViewExample',\n      getScreen: () => require('./basic/BasicExamples').ScrollViewExampleScreen,\n    },\n    {\n      name: 'FlatList',\n      slug: 'Basic/FlatListExample',\n      getScreen: () => require('./basic/BasicExamples').FlatListExampleScreen,\n    },\n    {\n      name: 'SectionList',\n      slug: 'Basic/SectionListExample',\n      getScreen: () =>\n        require('./basic/BasicExamples').SectionListExampleScreen,\n    },\n    {\n      name: 'VirtualizedList',\n      slug: 'Basic/VirtualizedListExample',\n      getScreen: () =>\n        require('./basic/BasicExamples').VirtualizedListExampleScreen,\n    },\n  ],\n};\nscreens.push(basicSection);\n//#endregion\n\n//#region Modal Section\nconst modalSection = {\n  title: 'Modal',\n  data: [\n    {\n      name: 'Simple',\n      slug: 'Modal/SimpleExample',\n      getScreen: () => require('./modal/SimpleExample').default,\n    },\n    {\n      name: 'Backdrop',\n      slug: 'Modal/BackdropExample',\n      getScreen: () => require('./modal/BackdropExample').default,\n    },\n    {\n      name: 'Stack Modals',\n      slug: 'Modal/StackExample',\n      getScreen: () => require('./modal/StackExample').default,\n    },\n    {\n      name: 'Dynamic Sizing',\n      slug: 'Modal/DynamicSizingExample',\n      getScreen: () => require('./modal/DynamicSizingExample').default,\n    },\n    {\n      name: 'Detached',\n      slug: 'Modal/DetachedExample',\n      getScreen: () => require('./modal/DetachedExample').default,\n    },\n  ],\n};\nscreens.push(modalSection);\n//#endregion\n\n//#region Advanced Section\nconst advancedSection = {\n  title: 'Advanced',\n  collapsed: true,\n  data: [\n    {\n      name: 'Custom Handle',\n      slug: 'Advanced/CustomHandleExample',\n      getScreen: () => require('./advanced/CustomHandleExample').default,\n    },\n    {\n      name: 'Custom Background',\n      slug: 'Advanced/CustomBackgroundExample',\n      getScreen: () => require('./advanced/CustomBackgroundExample').default,\n    },\n    {\n      name: 'Custom Theme',\n      slug: 'Advanced/CustomThemeExample',\n      getScreen: () => require('./advanced/CustomThemeExample').default,\n    },\n    {\n      name: 'Backdrop',\n      slug: 'Advanced/BackdropExample',\n      getScreen: () => require('./advanced/BackdropExample').default,\n    },\n    {\n      name: 'Dynamic Sizing',\n      slug: 'Advanced/DynamicSizingExample',\n      getScreen: () => require('./advanced/DynamicSizingExample').default,\n    },\n    {\n      name: 'Shadow',\n      slug: 'Advanced/ShadowExample',\n      getScreen: () => require('./advanced/ShadowExample').default,\n    },\n    {\n      name: 'Footer',\n      slug: 'Advanced/FooterExample',\n      getScreen: () => require('./advanced/FooterExample').default,\n    },\n  ],\n};\nif (Platform.OS !== 'web') {\n  advancedSection.data.push(\n    {\n      name: 'Keyboard Handling',\n      slug: 'Advanced/KeyboardHandlingExample',\n      getScreen: () => require('./advanced/KeyboardHandlingExample').default,\n    },\n    {\n      name: 'Pull To Refresh',\n      slug: 'Advanced/PullToRefreshExample',\n      getScreen: () => require('./advanced/PullToRefreshExample').default,\n    }\n  );\n}\nscreens.push(advancedSection);\n//#endregion\n\n//#region Third Party Integration Section\nif (Platform.OS !== 'web') {\n  const integrationSection = {\n    title: 'Third Party Integration',\n    data: [\n      {\n        name: 'React Navigation',\n        slug: 'Integrations/NavigatorExample',\n        getScreen: () =>\n          require('./integrations/navigation/NavigatorExample').default,\n      },\n      {\n        name: 'React Native Screens',\n        slug: 'Integrations/NativeScreensExample',\n        getScreen: () => require('./integrations/NativeScreensExample').default,\n      },\n      {\n        name: 'View Pager',\n        slug: 'Integrations/ViewPagerExample',\n        getScreen: () => require('./integrations/ViewPagerExample').default,\n      },\n      {\n        name: 'Map',\n        slug: 'Integrations/MapExample',\n        getScreen: () => require('./integrations/map/MapExample').default,\n        screenOptions: {\n          headerTintColor: 'black',\n          headerTransparent: true,\n        },\n      },\n      {\n        name: 'FlashList',\n        slug: 'Integrations/FlashList',\n        getScreen: () => require('./integrations/flashlist').default,\n      },\n      {\n        name: 'LegendList',\n        slug: 'Integrations/LegendList',\n        getScreen: () => require('./integrations/legendlist').default,\n      },\n    ],\n    collapsed: true,\n  };\n  screens.push(integrationSection);\n}\n\n//#endregion\n\nexport { screens };\n"
  },
  {
    "path": "example/src/screens/integrations/NativeScreensExample.tsx",
    "content": "import React from 'react';\nimport { View, StyleSheet, Platform } from 'react-native';\nimport { useNavigation } from '@react-navigation/native';\nimport { createNativeStackNavigator } from '@react-navigation/native-stack';\nimport { Button } from '../../components/button';\nimport ModalBackdropExample from '../modal/BackdropExample';\nimport { withModalProvider } from '../modal/withModalProvider';\n\nconst RootScreen = () => {\n  const { navigate } = useNavigation();\n  return (\n    <View style={styles.container}>\n      <Button\n        label=\"Navigate to Native Modal\"\n        // @ts-ignore\n        onPress={() => navigate('NativeModal')}\n      />\n    </View>\n  );\n};\n\nconst styles = StyleSheet.create({\n  container: {\n    flex: 1,\n    padding: 24,\n  },\n});\n\nconst NativeStack = createNativeStackNavigator();\n\nexport default withModalProvider(() => (\n  <NativeStack.Navigator>\n    <NativeStack.Screen\n      name=\"Root\"\n      component={RootScreen}\n      options={{ headerShown: false }}\n    />\n    <NativeStack.Screen\n      name=\"NativeModal\"\n      component={ModalBackdropExample}\n      options={{\n        presentation: 'modal',\n        headerShown: Platform.OS === 'ios',\n      }}\n    />\n  </NativeStack.Navigator>\n));\n"
  },
  {
    "path": "example/src/screens/integrations/ViewPagerExample.tsx",
    "content": "import React, { useMemo } from 'react';\nimport { View, Text, StyleSheet } from 'react-native';\nimport { createMaterialTopTabNavigator } from '@react-navigation/material-top-tabs';\nimport BottomSheet from '@gorhom/bottom-sheet';\nimport { ContactList } from '../../components/contactList';\n\nconst FirstRoute = () => {\n  const snapPoints = useMemo(() => ['25%', '50%', '90%'], []);\n\n  return (\n    <View style={[styles.scene, styles.firstScene]}>\n      <BottomSheet\n        snapPoints={snapPoints}\n        enableDynamicSizing={false}\n        activeOffsetY={[-1, 1]}\n        failOffsetX={[-5, 5]}\n        animateOnMount={true}\n      >\n        <ContactList type=\"FlatList\" count={15} />\n      </BottomSheet>\n    </View>\n  );\n};\n\nconst SecondRoute = () => (\n  <View style={[styles.scene, styles.secondScene]}>\n    <Text style={styles.emoji}>🙈</Text>\n  </View>\n);\n\nconst Tab = createMaterialTopTabNavigator();\n\nconst ViewPagerScreen = () => {\n  return (\n    <Tab.Navigator>\n      <Tab.Screen name=\"Home\" component={FirstRoute} />\n      <Tab.Screen name=\"Settings\" component={SecondRoute} />\n    </Tab.Navigator>\n  );\n};\n\nconst styles = StyleSheet.create({\n  scene: {\n    flex: 1,\n  },\n  firstScene: {\n    backgroundColor: '#ff4081',\n  },\n  secondScene: {\n    alignContent: 'center',\n    alignItems: 'center',\n    justifyContent: 'center',\n    backgroundColor: '#673ab7',\n  },\n  emoji: {\n    fontSize: 46,\n  },\n});\n\nexport default ViewPagerScreen;\n"
  },
  {
    "path": "example/src/screens/integrations/flashlist/FlashListExample.tsx",
    "content": "import BottomSheet, {\n  useBottomSheetScrollableCreator,\n} from '@gorhom/bottom-sheet';\nimport { FlashList, type ListRenderItemInfo } from '@shopify/flash-list';\nimport React, { useCallback, useMemo, useRef, useState } from 'react';\nimport {\n  ActivityIndicator,\n  StyleSheet,\n  Text,\n  View,\n  type ViewabilityConfig,\n} from 'react-native';\nimport { Button } from '../../../components/button';\nimport TweetContent from './TweetContent';\nimport { tweets as tweetsData } from './data/tweets';\nimport type Tweet from './models/Tweet';\n\nconst keyExtractor = (item: Tweet) => {\n  return item.id;\n};\n\nconst snapPoints = ['25%', '50%', '90%'];\n\nconst FlashListExample = () => {\n  //#region state\n  const [tweets, setTweets] = useState(tweetsData);\n  //#endregion\n\n  //#region refs\n  const bottomSheetRef = useRef<BottomSheet>(null);\n  const remainingTweets = useRef([...tweetsData].splice(10, tweetsData.length));\n  const viewabilityConfig = useRef<ViewabilityConfig>({\n    waitForInteraction: true,\n    itemVisiblePercentThreshold: 50,\n    minimumViewTime: 1000,\n  }).current;\n  //#endregion\n\n  const handleOnEndReached = useCallback(() => {\n    setTimeout(() => {\n      setTweets([...tweets, ...remainingTweets.current.splice(0, 10)]);\n    }, 1000);\n  }, [tweets]);\n  const handleSnapPress = useCallback((index: number) => {\n    bottomSheetRef.current?.snapToIndex(index);\n  }, []);\n  const handleExpandPress = useCallback(() => {\n    bottomSheetRef.current?.expand();\n  }, []);\n  const handleCollapsePress = useCallback(() => {\n    bottomSheetRef.current?.collapse();\n  }, []);\n  const handleClosePress = useCallback(() => {\n    bottomSheetRef.current?.close();\n  }, []);\n\n  //#region render\n  const renderItem = useCallback(\n    ({ item }: ListRenderItemInfo<Tweet>) => <TweetContent tweet={item} />,\n    []\n  );\n  const renderFooter = useMemo(\n    () => <Footer isLoading={tweets.length !== tweetsData.length} />,\n    [tweets]\n  );\n  const BottomSheetFlashListScrollable = useBottomSheetScrollableCreator();\n  return (\n    <View style={styles.container}>\n      <Button label=\"Snap To 90%\" onPress={() => handleSnapPress(2)} />\n      <Button label=\"Snap To 50%\" onPress={() => handleSnapPress(1)} />\n      <Button label=\"Snap To 25%\" onPress={() => handleSnapPress(0)} />\n      <Button label=\"Expand\" onPress={handleExpandPress} />\n      <Button label=\"Collapse\" onPress={handleCollapsePress} />\n      <Button label=\"Close\" onPress={handleClosePress} />\n      <BottomSheet\n        ref={bottomSheetRef}\n        snapPoints={snapPoints}\n        enableDynamicSizing={false}\n      >\n        <FlashList\n          keyExtractor={keyExtractor}\n          renderItem={renderItem}\n          onEndReached={handleOnEndReached}\n          ListFooterComponent={renderFooter}\n          ListEmptyComponent={Empty}\n          estimatedItemSize={150}\n          ItemSeparatorComponent={Divider}\n          data={tweets}\n          viewabilityConfig={viewabilityConfig}\n          renderScrollComponent={BottomSheetFlashListScrollable}\n        />\n      </BottomSheet>\n    </View>\n  );\n  //#endregion\n};\n\nconst Divider = () => {\n  return <View style={styles.divider} />;\n};\n\nconst Footer = ({ isLoading }: { isLoading: boolean }) => {\n  return (\n    <View style={styles.footer}>\n      {isLoading ? (\n        <ActivityIndicator />\n      ) : (\n        <Text style={styles.footerTitle}>No more tweets</Text>\n      )}\n    </View>\n  );\n};\n\nconst Empty = () => {\n  const title = 'Welcome to your timeline';\n  const subTitle =\n    \"It's empty now but it won't be for long. Start following peopled you'll see Tweets show up here\";\n  return (\n    <View style={styles.emptyComponent} testID=\"EmptyComponent\">\n      <Text style={styles.emptyComponentTitle}>{title}</Text>\n      <Text style={styles.emptyComponentSubtitle}>{subTitle}</Text>\n    </View>\n  );\n};\n\nconst styles = StyleSheet.create({\n  container: {\n    flex: 1,\n    padding: 24,\n  },\n\n  divider: {\n    width: '100%',\n    height: StyleSheet.hairlineWidth,\n    backgroundColor: '#DDD',\n  },\n  header: {\n    height: 40,\n    justifyContent: 'center',\n    alignItems: 'center',\n    backgroundColor: '#1DA1F2',\n  },\n  footer: {\n    height: 40,\n    justifyContent: 'center',\n    alignItems: 'center',\n  },\n  headerTitle: {\n    color: '#FFFFFF',\n    padding: 8,\n    borderRadius: 12,\n    fontSize: 12,\n  },\n  footerTitle: {\n    padding: 8,\n    borderRadius: 12,\n    fontSize: 12,\n  },\n  emptyComponentTitle: {\n    color: 'black',\n    fontSize: 20,\n    fontWeight: 'bold',\n  },\n  emptyComponentSubtitle: {\n    color: '#808080',\n    padding: 8,\n    fontSize: 14,\n    textAlign: 'center',\n  },\n  emptyComponent: {\n    justifyContent: 'center',\n    alignItems: 'center',\n    flex: 1,\n  },\n});\n\nexport default FlashListExample;\n"
  },
  {
    "path": "example/src/screens/integrations/flashlist/TweetContent.tsx",
    "content": "import { Image } from 'expo-image';\nimport React from 'react';\n\nimport { StyleSheet, Text, View, type ViewStyle } from 'react-native';\n\nimport type Author from './models/Author';\nimport type Tweet from './models/Tweet';\n\nexport interface TweetContentProps {\n  tweet: Tweet;\n}\n\nconst tweetActions = (\n  retweets: React.ReactNode,\n  comments: React.ReactNode,\n  likes: React.ReactNode\n) => {\n  return (\n    <View style={[styles.rowActions, styles.actionBar]}>\n      <View style={styles.elemAction}>\n        <Image\n          style={styles.actionButton}\n          source={require('../../../../assets/comment.png')}\n        />\n        <Text style={styles.actionText}>{comments}</Text>\n      </View>\n      <View style={styles.elemAction}>\n        <Image\n          style={styles.actionButton}\n          source={require('../../../../assets/retweet.png')}\n        />\n        <Text style={styles.actionText}>{retweets}</Text>\n      </View>\n      <View style={styles.elemAction}>\n        <Image\n          style={styles.actionButton}\n          source={require('../../../../assets/like.png')}\n        />\n        <Text style={styles.actionText}>{likes}</Text>\n      </View>\n      <Image\n        style={styles.actionButton}\n        source={require('../../../../assets/share.png')}\n      />\n    </View>\n  );\n};\n\nconst avatar = (author: Author) => {\n  return (\n    <View style={styles.avatar}>\n      <Text style={styles.avatarTextStyle}>\n        {author.name.toUpperCase().charAt(0)}\n      </Text>\n    </View>\n  );\n};\ninterface GrayTextProps {\n  children: React.ReactNode;\n  numberOfLines?: number;\n  style?: ViewStyle;\n}\n\nconst GrayText = ({ children, numberOfLines, style }: GrayTextProps) => {\n  return (\n    <Text style={[style, styles.gray]} numberOfLines={numberOfLines}>\n      {children}\n    </Text>\n  );\n};\n\nconst TweetContent = ({ tweet }: TweetContentProps) => {\n  return (\n    <View style={styles.singleItem}>\n      <View style={styles.row}>\n        {avatar(tweet.author)}\n        <View style={styles.tweetContentContainer}>\n          <View style={styles.rowTop}>\n            <Text numberOfLines={1} style={styles.header}>\n              {tweet.author.name}\n            </Text>\n            <GrayText style={styles.author} numberOfLines={1}>\n              @{tweet.author.screenName}\n            </GrayText>\n            <GrayText>·</GrayText>\n            <GrayText>2h</GrayText>\n          </View>\n          <Text style={styles.description}>{tweet.fullText}</Text>\n          <View style={styles.rowActions}>\n            {tweetActions(\n              tweet.retweetCount,\n              tweet.replyCount,\n              tweet.favoriteCount\n            )}\n          </View>\n        </View>\n      </View>\n    </View>\n  );\n};\n\nconst styles = StyleSheet.create({\n  author: {\n    flexShrink: 1,\n  },\n  actionBar: {\n    marginTop: 8,\n    justifyContent: 'space-between',\n    marginRight: 16,\n  },\n  actionButton: {\n    width: 18,\n    height: 18,\n    marginRight: 8,\n  },\n  gray: {\n    color: '#777',\n    fontSize: 13,\n    paddingRight: 2,\n  },\n  avatar: {\n    height: 44,\n    width: 44,\n    backgroundColor: '#00A4EF',\n    marginRight: 16,\n    flexShrink: 0,\n    marginTop: 4,\n    justifyContent: 'center',\n    alignItems: 'center',\n  },\n  avatarTextStyle: {\n    color: '#FFF',\n    fontSize: 18,\n    fontWeight: 'bold',\n  },\n  header: {\n    fontSize: 14,\n    fontWeight: 'bold',\n    paddingBottom: 4,\n    paddingRight: 4,\n    color: '#000',\n  },\n  description: {\n    fontSize: 14,\n    color: '#000',\n  },\n  singleItem: {\n    paddingHorizontal: 16,\n    minHeight: 44,\n    flex: 1,\n    padding: 16,\n    backgroundColor: '#FFF',\n  },\n  rowTop: {\n    flexDirection: 'row',\n  },\n  rowActions: {\n    flexGrow: 1,\n    justifyContent: 'space-between',\n    flexDirection: 'row',\n  },\n  row: {\n    flexDirection: 'row',\n  },\n  elemAction: {\n    flexDirection: 'row',\n    alignItems: 'center',\n    justifyContent: 'flex-start',\n  },\n  actionText: {\n    fontSize: 12,\n    color: '#444',\n  },\n  tweetContentContainer: {\n    flexShrink: 1,\n    flexGrow: 1,\n  },\n});\n\nexport default TweetContent;\n"
  },
  {
    "path": "example/src/screens/integrations/flashlist/data/tweets.ts",
    "content": "/* eslint-disable max-len */\n\nimport type Tweet from '../models/Tweet';\n\nexport const tweets: Tweet[] = [\n  {\n    author: {\n      name: 'Aram Miquel',\n      screenName: 'aram_miquel',\n      avatar:\n        'https://images.unsplash.com/photo-1649011463206-cb765493f8bf?crop=entropy&cs=tinysrgb&fit=crop&fm=jpg&h=48&ixid=MnwxfDB8MXxyYW5kb218MHx8fHx8fHx8MTY1MTY1Njk3NA&ixlib=rb-1.2.1&q=80&w=48',\n    },\n    id: '1480837336535646209',\n    fullText:\n      'Apple should pay more attention. It’s unfair to users, but even more to the small developers that play by the rules!',\n    retweetCount: 2,\n    replyCount: 1,\n    favoriteCount: 5,\n  },\n  {\n    author: {\n      name: 'Gergely Orosz',\n      screenName: 'GergelyOrosz',\n      avatar:\n        'https://images.unsplash.com/photo-1649827159600-237a092f95b5?crop=entropy&cs=tinysrgb&fit=crop&fm=jpg&h=48&ixid=MnwxfDB8MXxyYW5kb218MHx8fHx8fHx8MTY1MTY1Njk5OQ&ixlib=rb-1.2.1&q=80&w=48',\n    },\n    id: '1480833114096214018',\n    fullText:\n      'I write about real-world hiring insights for paid subscribers of https://t.co/SLe64y6YsX - many of whom are hiring managers themselves.\\n\\nIt might be a hard pill to swallow, but retaining existing folks, not overloading them with too many in-person interviews comes before hiring.',\n    retweetCount: 0,\n    replyCount: 0,\n    favoriteCount: 3,\n  },\n  {\n    author: {\n      name: 'ryancarson.eth',\n      screenName: 'ryancarson',\n      avatar:\n        'https://images.unsplash.com/photo-1650355255329-66a873ebab57?crop=entropy&cs=tinysrgb&fit=crop&fm=jpg&h=48&ixid=MnwxfDB8MXxyYW5kb218MHx8fHx8fHx8MTY1MTY1Njk3NQ&ixlib=rb-1.2.1&q=80&w=48',\n    },\n    id: '1480806838140649472',\n    fullText:\n      'Not bullish on @LooksRareNFT and $LOOKS yet? (Disclosure: I staked my airdropped tokens. DYOR as always.)',\n    retweetCount: 2,\n    replyCount: 2,\n    favoriteCount: 13,\n  },\n  {\n    author: {\n      name: 'Cris Miquel',\n      screenName: 'crismiquelg',\n      avatar:\n        'https://images.unsplash.com/photo-1650192905858-e0bc957bf390?crop=entropy&cs=tinysrgb&fit=crop&fm=jpg&h=48&ixid=MnwxfDB8MXxyYW5kb218MHx8fHx8fHx8MTY1MTY1NzEwNw&ixlib=rb-1.2.1&q=80&w=48',\n    },\n    id: '1480543522465976324',\n    fullText:\n      'mi único propósito para 2022 es dejar de despedirme con la mano en las videollamadas como si fuera idiota',\n    retweetCount: 2,\n    replyCount: 14,\n    favoriteCount: 64,\n  },\n  {\n    author: {\n      name: 'Lorenzo',\n      screenName: 'Kelset',\n      avatar:\n        'https://images.unsplash.com/photo-1650346910129-e73df7b26eb0?crop=entropy&cs=tinysrgb&fit=crop&fm=jpg&h=48&ixid=MnwxfDB8MXxyYW5kb218MHx8fHx8fHx8MTY1MTY1Njk3Nw&ixlib=rb-1.2.1&q=80&w=48',\n    },\n    id: '1480879826781286413',\n    fullText: '🔥this is fine🔥',\n    retweetCount: 0,\n    replyCount: 0,\n    favoriteCount: 0,\n  },\n  {\n    author: {\n      name: 'Vitto Rivabella 🥑',\n      screenName: 'VittoStack',\n      avatar:\n        'https://images.unsplash.com/photo-1649623053337-03a9aca84fc1?crop=entropy&cs=tinysrgb&fit=crop&fm=jpg&h=48&ixid=MnwxfDB8MXxyYW5kb218MHx8fHx8fHx8MTY1MTY1NzEwNg&ixlib=rb-1.2.1&q=80&w=48',\n    },\n    id: '1480576201878028289',\n    fullText:\n      'DAOs are the best place to become a Web3 developer.\\n\\nUnfortunately, only a bunch are really valuable.\\n\\n4 best DAOs to learn Web3  ↓',\n    retweetCount: 158,\n    replyCount: 20,\n    favoriteCount: 551,\n  },\n  {\n    author: {\n      name: 'Justin Moore | Sponsorship Coach',\n      screenName: 'justinmooretfam',\n      avatar:\n        'https://images.unsplash.com/photo-1650213986462-1804543441c2?crop=entropy&cs=tinysrgb&fit=crop&fm=jpg&h=48&ixid=MnwxfDB8MXxyYW5kb218MHx8fHx8fHx8MTY1MTY1Njk3OA&ixlib=rb-1.2.1&q=80&w=48',\n    },\n    id: '1480875135355666432',\n    fullText: 'Stop waiting for brands to contact you.',\n    retweetCount: 2,\n    replyCount: 0,\n    favoriteCount: 11,\n  },\n  {\n    author: {\n      name: 'March',\n      screenName: 'fdesbml',\n      avatar:\n        'https://images.unsplash.com/photo-1650975109944-2772703c72f7?crop=entropy&cs=tinysrgb&fit=crop&fm=jpg&h=48&ixid=MnwxfDB8MXxyYW5kb218MHx8fHx8fHx8MTY1MTY1NzEwNA&ixlib=rb-1.2.1&q=80&w=48',\n    },\n    id: '1480362830805311495',\n    fullText:\n      'Hand-knit jewelry by Nora Folk | She uses a mixed technique of weaving, knitting, braiding and knotting fine nylon microfilaments to create organic shapes. https://t.co/BZFBQwuHeO',\n    retweetCount: 901,\n    replyCount: 10,\n    favoriteCount: 5889,\n  },\n  {\n    author: {\n      name: 'Samuel Molina',\n      screenName: 'FuKuy',\n      avatar:\n        'https://images.unsplash.com/photo-1651264042772-23891c614270?crop=entropy&cs=tinysrgb&fit=crop&fm=jpg&h=48&ixid=MnwxfDB8MXxyYW5kb218MHx8fHx8fHx8MTY1MTY1Njk4MA&ixlib=rb-1.2.1&q=80&w=48',\n    },\n    id: '1480818112614260739',\n    fullText:\n      'RT @Sadface_RL: A beginners guide to health bars.\\n\\n#pixelart #art #animation #gamedev #indiedev #indiegamedev #indiegame https://t.co/Fhb4m…',\n    retweetCount: 177,\n    replyCount: 0,\n    favoriteCount: 0,\n  },\n  {\n    author: {\n      name: 'Fumio 💡',\n      screenName: 'IK1T',\n      avatar:\n        'https://images.unsplash.com/photo-1650548211932-f6ebd1c73867?crop=entropy&cs=tinysrgb&fit=crop&fm=jpg&h=48&ixid=MnwxfDB8MXxyYW5kb218MHx8fHx8fHx8MTY1MTY1NzEwMw&ixlib=rb-1.2.1&q=80&w=48',\n    },\n    id: '1480811969242357760',\n    fullText:\n      \"Happy #PortfolioDay !\\nDear friends ❤️ I'm Fumio, a Lighting Artist 💡 currently working on Star Citizen.\\nLooking forward to meeting awesome artists on twitter 😊🎨✨\\n\\n🖼️ https://t.co/HOEB3v9c6E\\n\\n#PortfolioDay #LightingArtist #gamedev #Lighting https://t.co/ROIZ4iqRkE\",\n    retweetCount: 19,\n    replyCount: 1,\n    favoriteCount: 70,\n  },\n  {\n    author: {\n      name: 'ryancarson.eth',\n      screenName: 'ryancarson',\n      avatar:\n        'https://images.unsplash.com/photo-1650355255329-66a873ebab57?crop=entropy&cs=tinysrgb&fit=crop&fm=jpg&h=48&ixid=MnwxfDB8MXxyYW5kb218MHx8fHx8fHx8MTY1MTY1Njk3NQ&ixlib=rb-1.2.1&q=80&w=48',\n    },\n    id: '1480809821754511361',\n    fullText: 'gm y’all!',\n    retweetCount: 0,\n    replyCount: 11,\n    favoriteCount: 19,\n  },\n  {\n    author: {\n      name: 'SonyAlphaRumors',\n      screenName: 'SonyAlphaRumors',\n      avatar:\n        'https://images.unsplash.com/photo-1650170495855-add188d60239?crop=entropy&cs=tinysrgb&fit=crop&fm=jpg&h=48&ixid=MnwxfDB8MXxyYW5kb218MHx8fHx8fHx8MTY1MTY1Njk4MQ&ixlib=rb-1.2.1&q=80&w=48',\n    },\n    id: '1480859756940218370',\n    fullText:\n      'ZY Productions: This $429 Viltrox FE 24mm F1.8 Lens Is Surprisingly Good https://t.co/pAPvDYI5t4',\n    retweetCount: 0,\n    replyCount: 0,\n    favoriteCount: 2,\n  },\n  {\n    author: {\n      name: 'Sommer Panage',\n      screenName: 'Sommer',\n      avatar:\n        'https://images.unsplash.com/photo-1651236243448-ff4ea397cdf5?crop=entropy&cs=tinysrgb&fit=crop&fm=jpg&h=48&ixid=MnwxfDB8MXxyYW5kb218MHx8fHx8fHx8MTY1MTY1NzEwMQ&ixlib=rb-1.2.1&q=80&w=48',\n    },\n    id: '1480713374350651394',\n    fullText:\n      'I love working with people who are friendly. Who say “thank you” or cheer you on or say “good job.” These things may seem small, but they add up in the same way (but opposite direction) that all the negs and “paper cuts” do. They create a culture. They matter. Kindness matters.',\n    retweetCount: 94,\n    replyCount: 11,\n    favoriteCount: 744,\n  },\n  {\n    author: {\n      name: '@levelsio',\n      screenName: 'levelsio',\n      avatar:\n        'https://images.unsplash.com/photo-1650964858223-f4e7f5279f48?crop=entropy&cs=tinysrgb&fit=crop&fm=jpg&h=48&ixid=MnwxfDB8MXxyYW5kb218MHx8fHx8fHx8MTY1MTY1Njk4Mg&ixlib=rb-1.2.1&q=80&w=48',\n    },\n    id: '1480883313787084801',\n    fullText:\n      '✨ Added a mailto: link so people can invite their friends too https://t.co/fR3ufZJeuP',\n    retweetCount: 0,\n    replyCount: 3,\n    favoriteCount: 18,\n  },\n  {\n    author: {\n      name: 'The muy ameisin Bonilista',\n      screenName: 'bonilista',\n      avatar:\n        'https://images.unsplash.com/photo-1650296231490-2deba34258bf?crop=entropy&cs=tinysrgb&fit=crop&fm=jpg&h=48&ixid=MnwxfDB8MXxyYW5kb218MHx8fHx8fHx8MTY1MTY1NzEwMA&ixlib=rb-1.2.1&q=80&w=48',\n    },\n    id: '1480843314349981698',\n    fullText:\n      'El patrocinio de la #Bonilista cuesta 0,036 centimos por cada persona que lee el correo. Eso, sin contar la republicación en @lavozdegalicia.\\nSi te interesa reservar un patrocinio, tienes fechas disponibles a partir del 1 de mayo y más info en \\nhttps://t.co/umLWuCrVnY',\n    retweetCount: 0,\n    replyCount: 0,\n    favoriteCount: 0,\n  },\n  {\n    author: {\n      name: 'John Arthorne',\n      screenName: 'jarthorne',\n      avatar:\n        'https://images.unsplash.com/photo-1651417060303-716ae896ef88?crop=entropy&cs=tinysrgb&fit=crop&fm=jpg&h=48&ixid=MnwxfDB8MXxyYW5kb218MHx8fHx8fHx8MTY1MTY1Njk4NA&ixlib=rb-1.2.1&q=80&w=48',\n    },\n    id: '1480546473590857729',\n    fullText:\n      'The number of people joining Shopify RnD *today* alone is greater than the size of the RnD team when I joined 6 years ago 🤯. To my ~300 new colleagues: Welcome! 🚀',\n    retweetCount: 14,\n    replyCount: 6,\n    favoriteCount: 234,\n  },\n  {\n    author: {\n      name: 'Paul Graham',\n      screenName: 'paulg',\n      avatar:\n        'https://images.unsplash.com/photo-1649089475942-b523f9d00219?crop=entropy&cs=tinysrgb&fit=crop&fm=jpg&h=48&ixid=MnwxfDB8MXxyYW5kb218MHx8fHx8fHx8MTY1MTY1NzA5OQ&ixlib=rb-1.2.1&q=80&w=48',\n    },\n    id: '1480875433013002243',\n    fullText:\n      '\"In truth, Theodoric was something of a parvenu, as every other Goth must have been aware.\"\\n\\n— J. M. Wallace-Hadrill',\n    retweetCount: 1,\n    replyCount: 2,\n    favoriteCount: 22,\n  },\n  {\n    author: {\n      name: 'Gergely Orosz',\n      screenName: 'GergelyOrosz',\n      avatar:\n        'https://images.unsplash.com/photo-1650122597661-ceccf6d50692?crop=entropy&cs=tinysrgb&fit=crop&fm=jpg&h=48&ixid=MnwxfDB8MXxyYW5kb218MHx8fHx8fHx8MTY1MTY1Njk4NQ&ixlib=rb-1.2.1&q=80&w=48',\n    },\n    id: '1480813715880615936',\n    fullText:\n      'Ok I got hooked on Wordle as well.\\n\\nWordle 206 3/6\\n\\n⬜🟨🟩⬜⬜\\n🟩⬜🟩🟩⬜\\n🟩🟩🟩🟩🟩',\n    retweetCount: 0,\n    replyCount: 6,\n    favoriteCount: 31,\n  },\n  {\n    author: {\n      name: 'Toni Colom',\n      screenName: 'tonicolom',\n      avatar:\n        'https://images.unsplash.com/photo-1649861972512-faadc16a4571?crop=entropy&cs=tinysrgb&fit=crop&fm=jpg&h=48&ixid=MnwxfDB8MXxyYW5kb218MHx8fHx8fHx8MTY1MTY1NzA5Nw&ixlib=rb-1.2.1&q=80&w=48',\n    },\n    id: '1480824991486824448',\n    fullText:\n      'Para cumplir todas las tradiciones de estas fechas sólo me faltaba una cosa: la revisión de 2021 y los objetivos de 2022.\\n\\nEn este episodio con @chusnarrolo, que viene de un año movidito, hablamos del presente y del futuro de nuestras #marcas.\\n\\n#Podcast\\nhttps://t.co/7YA6KrPrwX',\n    retweetCount: 0,\n    replyCount: 0,\n    favoriteCount: 1,\n  },\n  {\n    author: {\n      name: 'Amanda Emmanuel',\n      screenName: 'amandaemmanuel',\n      avatar:\n        'https://images.unsplash.com/photo-1649894158708-bd47ad9ef4e3?crop=entropy&cs=tinysrgb&fit=crop&fm=jpg&h=48&ixid=MnwxfDB8MXxyYW5kb218MHx8fHx8fHx8MTY1MTY1NzA5Ng&ixlib=rb-1.2.1&q=80&w=48',\n    },\n    id: '1480611397503492100',\n    fullText:\n      \"Last year I had an idea but I couldn't find a technical co-founder to build it, so I became one\\n\\nIn 12-weeks:\\n\\nI taught myself Rails \\nbuilt the MVP\\non-boarded 10 customers\\nadded customer requested features\\nhit 165K MAUs\\n\\nNever underestimate yourself 🚀\",\n    retweetCount: 240,\n    replyCount: 175,\n    favoriteCount: 4385,\n  },\n  {\n    author: {\n      name: 'Majid Jabrayilov',\n      screenName: 'mecid',\n      avatar:\n        'https://images.unsplash.com/photo-1649080480680-221b69e21ce1?crop=entropy&cs=tinysrgb&fit=crop&fm=jpg&h=48&ixid=MnwxfDB8MXxyYW5kb218MHx8fHx8fHx8MTY1MTY1Njk4Nw&ixlib=rb-1.2.1&q=80&w=48',\n    },\n    id: '1480876283382935552',\n    fullText:\n      'Pull-to-refresh is a widespread User Interface pattern that we use to request a data update in our apps. The SwiftUI Release 3 provides a brand new way to set up a pull-to-refresh action using the new refreshable view modifier.\\nhttps://t.co/bqU9Qaak1K https://t.co/wwNHOAhYtY',\n    retweetCount: 2,\n    replyCount: 0,\n    favoriteCount: 19,\n  },\n  {\n    author: {\n      name: 'Icon Galleries',\n      screenName: 'icongalleries',\n      avatar:\n        'https://images.unsplash.com/photo-1649733484875-2e837f5b640b?crop=entropy&cs=tinysrgb&fit=crop&fm=jpg&h=48&ixid=MnwxfDB8MXxyYW5kb218MHx8fHx8fHx8MTY1MTY1NzA5NA&ixlib=rb-1.2.1&q=80&w=48',\n    },\n    id: '1480669856647233543',\n    fullText:\n      'Lots of new #macOS icons today, including work from @raphaellopesph \\n\\nCheck out the icons at https://t.co/puMlrIlC6N',\n    retweetCount: 2,\n    replyCount: 0,\n    favoriteCount: 4,\n  },\n  {\n    author: {\n      name: 'Capture One Pro',\n      screenName: 'captureonepro',\n      avatar:\n        'https://images.unsplash.com/photo-1649393153970-fd7ec111a577?crop=entropy&cs=tinysrgb&fit=crop&fm=jpg&h=48&ixid=MnwxfDB8MXxyYW5kb218MHx8fHx8fHx8MTY1MTY1Njk4OA&ixlib=rb-1.2.1&q=80&w=48',\n    },\n    id: '1480841955613581313',\n    fullText:\n      'Want to know what @dunnadidit thinks about Capture One 22?\\n\\nWatch the video in the link below, where he tries out our new HDR and Panorama features.\\n\\n#hdr #panorama #captureone #editingsoftware\\n\\nhttps://t.co/7FxEC2LBwo https://t.co/sxvi6UQC8o',\n    retweetCount: 3,\n    replyCount: 0,\n    favoriteCount: 7,\n  },\n  {\n    author: {\n      name: 'Colin Cornaby',\n      screenName: 'colincornaby',\n      avatar:\n        'https://images.unsplash.com/photo-1651170022383-6eaa642ee2fa?crop=entropy&cs=tinysrgb&fit=crop&fm=jpg&h=48&ixid=MnwxfDB8MXxyYW5kb218MHx8fHx8fHx8MTY1MTY1NzA0NQ&ixlib=rb-1.2.1&q=80&w=48',\n    },\n    id: '1480321521126019073',\n    fullText:\n      'Anyone seen inconsistent Metal performance numbers on Apple Silicon Macs? Xcode FPS counter shows a GPU time of about 9 ms. But the built in shader profiler shows a time less than 3 ms. My best guess is maybe there is a significant of time being spent not in shaders?',\n    retweetCount: 0,\n    replyCount: 2,\n    favoriteCount: 0,\n  },\n  {\n    author: {\n      name: 'Smashing Magazine',\n      screenName: 'smashingmag',\n      avatar:\n        'https://images.unsplash.com/photo-1649562231804-f1bfadc450d2?crop=entropy&cs=tinysrgb&fit=crop&fm=jpg&h=48&ixid=MnwxfDB8MXxyYW5kb218MHx8fHx8fHx8MTY1MTY1NzA5Mw&ixlib=rb-1.2.1&q=80&w=48',\n    },\n    id: '1480816866360766465',\n    fullText:\n      'RT @smashingmag: 📣 New Smashing Workshops in 2022:\\n \\n😎 Accessible Front-End Patterns — @cariefisher\\n👾 Front-End Testing — @bahmutov\\n👻 HTML…',\n    retweetCount: 15,\n    replyCount: 0,\n    favoriteCount: 0,\n  },\n  {\n    author: {\n      name: 'Young IT Girls',\n      screenName: 'youngitgirls',\n      avatar:\n        'https://images.unsplash.com/photo-1649562231804-f1bfadc450d2?crop=entropy&cs=tinysrgb&fit=crop&fm=jpg&h=48&ixid=MnwxfDB8MXxyYW5kb218MHx8fHx8fHx8MTY1MTY1NzA5Mw&ixlib=rb-1.2.1&q=80&w=48',\n    },\n    id: '1480856688060256258',\n    fullText:\n      \"🚀 Arranquem l'any amb noves aventures i moltes ganes de continuar treballant \\n\\n@CanodromBCN\",\n    retweetCount: 3,\n    replyCount: 0,\n    favoriteCount: 5,\n  },\n  {\n    author: {\n      name: 'Gergely Orosz',\n      screenName: 'GergelyOrosz',\n      avatar:\n        'https://images.unsplash.com/photo-1650122597661-ceccf6d50692?crop=entropy&cs=tinysrgb&fit=crop&fm=jpg&h=48&ixid=MnwxfDB8MXxyYW5kb218MHx8fHx8fHx8MTY1MTY1Njk4NQ&ixlib=rb-1.2.1&q=80&w=48',\n    },\n    id: '1480832043093221379',\n    fullText:\n      'I refrain from talking much about the \"real world\" of hiring on Twitter, because the majority of people have not been on the other side.\\n\\nIt\\'s easy to gather likes by tweeting \"hire more juniors\" when it\\'s not you who will be responsible for the success - or failure - of them.',\n    retweetCount: 0,\n    replyCount: 3,\n    favoriteCount: 37,\n  },\n  {\n    author: {\n      name: 'I Am Devloper',\n      screenName: 'iamdevloper',\n      avatar:\n        'https://images.unsplash.com/photo-1651354239553-0998040fa5ca?crop=entropy&cs=tinysrgb&fit=crop&fm=jpg&h=48&ixid=MnwxfDB8MXxyYW5kb218MHx8fHx8fHx8MTY1MTY1Njk5MQ&ixlib=rb-1.2.1&q=80&w=48',\n    },\n    id: '1480861741185650691',\n    fullText:\n      \"you don't need to spend 3hrs automating a solution to save you 10 minutes of manual input\",\n    retweetCount: 20,\n    replyCount: 40,\n    favoriteCount: 339,\n  },\n  {\n    author: {\n      name: 'Connor Shorten',\n      screenName: 'CShorten30',\n      avatar:\n        'https://images.unsplash.com/photo-1649711992982-092a8e53e39c?crop=entropy&cs=tinysrgb&fit=crop&fm=jpg&h=48&ixid=MnwxfDB8MXxyYW5kb218MHx8fHx8fHx8MTY1MTY1NzA1OQ&ixlib=rb-1.2.1&q=80&w=48',\n    },\n    id: '1466746804704354309',\n    fullText:\n      \"This video explains Weaviate's Wikidata Vector Search Web Demo! 🔥💻🔥\\n\\nThis covers a range of topics from:\\n• Wikidata versus Wikipedia\\n• PyTorch-BigGraph\\n• The Weaviate Demo and Vector Search Visualization\\n• My thoughts on Graph Data in Deep Learning\\n\\nhttps://t.co/SaTC0Ltvpi\",\n    retweetCount: 21,\n    replyCount: 1,\n    favoriteCount: 79,\n  },\n  {\n    author: {\n      name: 'Digital Photography School (dPS)',\n      screenName: 'digitalps',\n      avatar:\n        'https://images.unsplash.com/photo-1649920762277-3dcd6db40334?crop=entropy&cs=tinysrgb&fit=crop&fm=jpg&h=48&ixid=MnwxfDB8MXxyYW5kb218MHx8fHx8fHx8MTY1MTY1Njk5Mg&ixlib=rb-1.2.1&q=80&w=48',\n    },\n    id: '1480863337219080196',\n    fullText:\n      'The Essential Guide to Depth of Field for Beginners https://t.co/GySMCoXRWr',\n    retweetCount: 0,\n    replyCount: 0,\n    favoriteCount: 6,\n  },\n  {\n    author: {\n      name: 'Manuel Maly',\n      screenName: 'manuelmaly',\n      avatar:\n        'https://images.unsplash.com/photo-1650821314547-ea4e6f5c31ab?crop=entropy&cs=tinysrgb&fit=crop&fm=jpg&h=48&ixid=MnwxfDB8MXxyYW5kb218MHx8fHx8fHx8MTY1MTY1NzA5Mg&ixlib=rb-1.2.1&q=80&w=48',\n    },\n    id: '1480815825133129736',\n    fullText:\n      'You know you’re coding SwiftUI when the tabbar hide/show animation is the hardest part in your AR app',\n    retweetCount: 0,\n    replyCount: 0,\n    favoriteCount: 12,\n  },\n  {\n    author: {\n      name: 'Dickie Bush 🚢',\n      screenName: 'dickiebush',\n      avatar:\n        'https://images.unsplash.com/photo-1649470241643-e601950cc489?crop=entropy&cs=tinysrgb&fit=crop&fm=jpg&h=48&ixid=MnwxfDB8MXxyYW5kb218MHx8fHx8fHx8MTY1MTY1Njk5NA&ixlib=rb-1.2.1&q=80&w=48',\n    },\n    id: '1480886826638487560',\n    fullText:\n      'RT @Nicolascole77: Digital Writing 101: \\n\\nStart small. Test ideas. Double-down and invest in the winners. Repeat.',\n    retweetCount: 2,\n    replyCount: 0,\n    favoriteCount: 0,\n  },\n  {\n    author: {\n      name: 'Kuba Jaroszewski',\n      screenName: 'pierd86',\n      avatar:\n        'https://images.unsplash.com/photo-1650315985351-d56d1a00f227?crop=entropy&cs=tinysrgb&fit=crop&fm=jpg&h=48&ixid=MnwxfDB8MXxyYW5kb218MHx8fHx8fHx8MTY1MTY1NzA5MA&ixlib=rb-1.2.1&q=80&w=48',\n    },\n    id: '1480884617838141443',\n    fullText:\n      'RT @Kjell_Kod: The worst thing about Rust is that it raises the bar for every other programming language.',\n    retweetCount: 3,\n    replyCount: 0,\n    favoriteCount: 0,\n  },\n  {\n    author: {\n      name: 'Applesfera',\n      screenName: 'applesfera',\n      avatar:\n        'https://images.unsplash.com/photo-1593114970899-95c26e8d8841?crop=entropy&cs=tinysrgb&fit=crop&fm=jpg&h=48&ixid=MnwxfDB8MXxyYW5kb218MHx8fHx8fHx8MTY1MTY1Njk5NQ&ixlib=rb-1.2.1&q=80&w=48',\n    },\n    id: '1480802469361950720',\n    fullText:\n      'Así de potentes serán las Apple Glass: usarán el cargador de 96W de los nuevos MacBook Pro, según Kuo https://t.co/j2dVay33il https://t.co/5ooOIuks9n',\n    retweetCount: 3,\n    replyCount: 1,\n    favoriteCount: 23,\n  },\n  {\n    author: {\n      name: 'mossegalapoma',\n      screenName: 'mossegalapoma',\n      avatar:\n        'https://images.unsplash.com/photo-1649898914298-244e49d9a8ac?crop=entropy&cs=tinysrgb&fit=crop&fm=jpg&h=48&ixid=MnwxfDB8MXxyYW5kb218MHx8fHx8fHx8MTY1MTY1NzA4OQ&ixlib=rb-1.2.1&q=80&w=48',\n    },\n    id: '1480885162665721862',\n    fullText:\n      'En breu enregistrem el programa 503 amb convidats parlant de Catalan DAO @catalandaoETH -  seguiment en directe al nostre canal de Twitch i en format podcast https://t.co/eHj6alp2yp}',\n    retweetCount: 0,\n    replyCount: 0,\n    favoriteCount: 1,\n  },\n  {\n    author: {\n      name: 'Javier Rosano',\n      screenName: 'Javi_Rosano',\n      avatar:\n        'https://images.unsplash.com/photo-1650971831044-ccf2ac979a92?crop=entropy&cs=tinysrgb&fit=crop&fm=jpg&h=48&ixid=MnwxfDB8MXxyYW5kb218MHx8fHx8fHx8MTY1MTY1Njk5Ng&ixlib=rb-1.2.1&q=80&w=48',\n    },\n    id: '1480884199288721408',\n    fullText:\n      '@Imanolzuaznabar Había olvidado por qué quería bloquearte... 😂😂😂',\n    retweetCount: 0,\n    replyCount: 0,\n    favoriteCount: 0,\n  },\n  {\n    author: {\n      name: 'Antoni Bassas',\n      screenName: 'antonibassas',\n      avatar:\n        'https://images.unsplash.com/photo-1650139504331-9bc867a86b3b?crop=entropy&cs=tinysrgb&fit=crop&fm=jpg&h=48&ixid=MnwxfDB8MXxyYW5kb218MHx8fHx8fHx8MTY1MTY1NzA4Nw&ixlib=rb-1.2.1&q=80&w=48',\n    },\n    id: '1480844486158786560',\n    fullText:\n      \"RT @AraBassas: 📹 L'anàlisi d'@antonibassas: \\\"La independència no és el projecte d'un home sol'' 👇\\nhttps://t.co/QYBdrLOOLQ https://t.co/Ggmv…\",\n    retweetCount: 5,\n    replyCount: 0,\n    favoriteCount: 0,\n  },\n  {\n    author: {\n      name: 'Rapha 🎄',\n      screenName: 'raphaellopesph',\n      avatar:\n        'https://images.unsplash.com/photo-1649051048669-1e86a8170ab9?crop=entropy&cs=tinysrgb&fit=crop&fm=jpg&h=48&ixid=MnwxfDB8MXxyYW5kb218MHx8fHx8fHx8MTY1MTY1Njk5OA&ixlib=rb-1.2.1&q=80&w=48',\n    },\n    id: '1480877054484692993',\n    fullText:\n      'RT @icongalleries: Lots of new #macOS icons today, including work from @raphaellopesph \\n\\nCheck out the icons at https://t.co/puMlrIlC6N',\n    retweetCount: 2,\n    replyCount: 0,\n    favoriteCount: 0,\n  },\n  {\n    author: {\n      name: 'Sidney Diongzon',\n      screenName: 'SidneyDiongzon',\n      avatar:\n        'https://images.unsplash.com/photo-1649731284194-d2ba81f16ba3?crop=entropy&cs=tinysrgb&fit=crop&fm=jpg&h=48&ixid=MnwxfDB8MXxyYW5kb218MHx8fHx8fHx8MTY1MTY1NzA4Ng&ixlib=rb-1.2.1&q=80&w=48',\n    },\n    id: '1480886466725167105',\n    fullText: 'Video coming out tomorrow instead. In the mean, gimme a 🖐',\n    retweetCount: 0,\n    replyCount: 1,\n    favoriteCount: 3,\n  },\n  {\n    author: {\n      name: 'Cris Busquets 🦊',\n      screenName: 'cbusquets',\n      avatar:\n        'https://images.unsplash.com/photo-1649827159600-237a092f95b5?crop=entropy&cs=tinysrgb&fit=crop&fm=jpg&h=48&ixid=MnwxfDB8MXxyYW5kb218MHx8fHx8fHx8MTY1MTY1Njk5OQ&ixlib=rb-1.2.1&q=80&w=48',\n    },\n    id: '1480827445775323138',\n    fullText:\n      'Hace unos 10 años que diseño profesionalmente.\\n\\nEn ocasiones me sigo encallando al definir el sistema tipográfico de un proyecto.\\n\\nY esto no me hace peor diseñadora 💁🏻‍♀️\\n\\n¿Qué se te atraganta a ti?',\n    retweetCount: 0,\n    replyCount: 2,\n    favoriteCount: 10,\n  },\n  {\n    author: {\n      name: 'Colin Cornaby',\n      screenName: 'colincornaby',\n      avatar:\n        'https://images.unsplash.com/photo-1651170022383-6eaa642ee2fa?crop=entropy&cs=tinysrgb&fit=crop&fm=jpg&h=48&ixid=MnwxfDB8MXxyYW5kb218MHx8fHx8fHx8MTY1MTY1NzA0NQ&ixlib=rb-1.2.1&q=80&w=48',\n    },\n    id: '1480795430405349377',\n    fullText:\n      'Update: I think this is due to \"legacy\" sort of game engine issues like main thread rendering and no double or triple buffering. Mostly the double or triple buffering. When aiming for 120 fps any little delay seems to cause a cascade of frame misses, which can happen often.',\n    retweetCount: 0,\n    replyCount: 1,\n    favoriteCount: 1,\n  },\n  {\n    author: {\n      name: 'Easlo',\n      screenName: 'heyeaslo',\n      avatar:\n        'https://images.unsplash.com/photo-1650035417643-250fa6ee5895?crop=entropy&cs=tinysrgb&fit=crop&fm=jpg&h=48&ixid=MnwxfDB8MXxyYW5kb218MHx8fHx8fHx8MTY1MTY1NzAwMQ&ixlib=rb-1.2.1&q=80&w=48',\n    },\n    id: '1480856110261157894',\n    fullText:\n      'Get access to 140+ Notion resources below!\\nhttps://t.co/r3wkfOdu4S',\n    retweetCount: 2,\n    replyCount: 0,\n    favoriteCount: 35,\n  },\n  {\n    author: {\n      name: 'Cris Busquets 🦊',\n      screenName: 'cbusquets',\n      avatar:\n        'https://images.unsplash.com/photo-1649827159600-237a092f95b5?crop=entropy&cs=tinysrgb&fit=crop&fm=jpg&h=48&ixid=MnwxfDB8MXxyYW5kb218MHx8fHx8fHx8MTY1MTY1Njk5OQ&ixlib=rb-1.2.1&q=80&w=48',\n    },\n    id: '1480856144960761858',\n    fullText:\n      'RT @cbusquets: Sinceramente, cada vez me preocupa más la brecha tecnológica que estamos creando.\\n\\nUsar aplicaciones y webs es fácil para mí…',\n    retweetCount: 6,\n    replyCount: 0,\n    favoriteCount: 0,\n  },\n  {\n    author: {\n      name: 'Colin Cornaby',\n      screenName: 'colincornaby',\n      avatar:\n        'https://images.unsplash.com/photo-1651170022383-6eaa642ee2fa?crop=entropy&cs=tinysrgb&fit=crop&fm=jpg&h=48&ixid=MnwxfDB8MXxyYW5kb218MHx8fHx8fHx8MTY1MTY1NzA0NQ&ixlib=rb-1.2.1&q=80&w=48',\n    },\n    id: '1480800801794658304',\n    fullText:\n      'It puts a bit of a shadow over middleware like MoltenVk too. Tuning for M1 really has to be done through Metal. A lot of companies are sustaining their Mac development through tooling like MoltenVk. But results on Apple hardware may just be ok.',\n    retweetCount: 0,\n    replyCount: 1,\n    favoriteCount: 0,\n  },\n  {\n    author: {\n      name: 'Tyler Hedrick',\n      screenName: 'tyler_hedrick',\n      avatar:\n        'https://images.unsplash.com/photo-1650871604168-2e8b22829db8?crop=entropy&cs=tinysrgb&fit=crop&fm=jpg&h=48&ixid=MnwxfDB8MXxyYW5kb218MHx8fHx8fHx8MTY1MTY1NzAwMg&ixlib=rb-1.2.1&q=80&w=48',\n    },\n    id: '1480581024241258500',\n    fullText:\n      'Wordle 205 5/6\\n\\n🟨🟨⬛⬛🟩\\n⬛🟨⬛🟩🟩\\n⬛⬛🟩🟩🟩\\n⬛⬛⬛⬛⬛\\n🟩🟩🟩🟩🟩',\n    retweetCount: 0,\n    replyCount: 1,\n    favoriteCount: 2,\n  },\n  {\n    author: {\n      name: '@levelsio',\n      screenName: 'levelsio',\n      avatar:\n        'https://images.unsplash.com/photo-1650964858223-f4e7f5279f48?crop=entropy&cs=tinysrgb&fit=crop&fm=jpg&h=48&ixid=MnwxfDB8MXxyYW5kb218MHx8fHx8fHx8MTY1MTY1Njk4Mg&ixlib=rb-1.2.1&q=80&w=48',\n    },\n    id: '1480807787336650752',\n    fullText:\n      '🏎 Less than 3 hours from feature request to implemented by @derrickreimer, indie founder of @savvycal\\n\\n📆 I needed single-use calendar links but based on already existing links I made b4, because ppl were sharing the link to others w/out paying for https://t.co/PL9rryfQ7X https://t.co/29JqkB9nDQ',\n    retweetCount: 1,\n    replyCount: 3,\n    favoriteCount: 84,\n  },\n  {\n    author: {\n      name: 'Itnig',\n      screenName: 'itnig',\n      avatar:\n        'https://images.unsplash.com/photo-1650035418821-77ee35531a6b?crop=entropy&cs=tinysrgb&fit=crop&fm=jpg&h=48&ixid=MnwxfDB8MXxyYW5kb218MHx8fHx8fHx8MTY1MTY1NzA4NQ&ixlib=rb-1.2.1&q=80&w=48',\n    },\n    id: '1480834735383273474',\n    fullText:\n      'Internxt, competing against Google Drive and Dropbox\\n\\nCheck our weekly newsletter:\\nhttps://t.co/Jd9yYf2d8L https://t.co/QZzXnOwgWu',\n    retweetCount: 0,\n    replyCount: 1,\n    favoriteCount: 7,\n  },\n  {\n    author: {\n      name: 'Gergely Orosz',\n      screenName: 'GergelyOrosz',\n      avatar:\n        'https://images.unsplash.com/photo-1650122597661-ceccf6d50692?crop=entropy&cs=tinysrgb&fit=crop&fm=jpg&h=48&ixid=MnwxfDB8MXxyYW5kb218MHx8fHx8fHx8MTY1MTY1Njk4NQ&ixlib=rb-1.2.1&q=80&w=48',\n    },\n    id: '1480818823448207363',\n    fullText:\n      \"When you're looking at companies with great engineering cultures, look for those that have parallel career tracks between eng management and engineering. And examples of actual moves.\\n\\nLike at @Shopify. Two moves to opposite tracks at the same time. 👏 @MikkoH &amp; @stephanleroux https://t.co/nJgpiZvCwu\",\n    retweetCount: 8,\n    replyCount: 4,\n    favoriteCount: 101,\n  },\n  {\n    author: {\n      name: 'Jordi Sellas Ferrés',\n      screenName: 'jordisellas',\n      avatar:\n        'https://images.unsplash.com/photo-1649320099555-9e436f69db29?crop=entropy&cs=tinysrgb&fit=crop&fm=jpg&h=48&ixid=MnwxfDB8MXxyYW5kb218MHx8fHx8fHx8MTY1MTY1NzAwNA&ixlib=rb-1.2.1&q=80&w=48',\n    },\n    id: '1480804792230453255',\n    fullText:\n      'RT @artsinhealthfdn: #ArtsAgainstCovid TALKS 🎥\\n\\n\"Després de 200 anys parlant d\\'objectes, potser toca parlar de subjectes, i això obliga als…',\n    retweetCount: 3,\n    replyCount: 0,\n    favoriteCount: 0,\n  },\n  {\n    author: {\n      name: 'Nicolas Cole',\n      screenName: 'Nicolascole77',\n      avatar:\n        'https://images.unsplash.com/photo-1649452814987-ece76376762a?crop=entropy&cs=tinysrgb&fit=crop&fm=jpg&h=48&ixid=MnwxfDB8MXxyYW5kb218MHx8fHx8fHx8MTY1MTY1NzA4Mw&ixlib=rb-1.2.1&q=80&w=48',\n    },\n    id: '1480714108253048834',\n    fullText:\n      'Digital Writing 101: \\n\\nStart small. Test ideas. Double-down and invest in the winners. Repeat.',\n    retweetCount: 2,\n    replyCount: 2,\n    favoriteCount: 34,\n  },\n  {\n    author: {\n      name: 'Jordi Sellas Ferrés',\n      screenName: 'jordisellas',\n      avatar:\n        'https://images.unsplash.com/photo-1649320099555-9e436f69db29?crop=entropy&cs=tinysrgb&fit=crop&fm=jpg&h=48&ixid=MnwxfDB8MXxyYW5kb218MHx8fHx8fHx8MTY1MTY1NzAwNA&ixlib=rb-1.2.1&q=80&w=48',\n    },\n    id: '1480879213729222663',\n    fullText:\n      \"RT @elmondahir: 👶🏻 Ja és aquí el número 21!\\n\\nDedicat a la INFÀNCIA, hi trobareu articles d'@emparmoliner @MiquiOtero @AlexGutierrezM @atril…\",\n    retweetCount: 8,\n    replyCount: 0,\n    favoriteCount: 0,\n  },\n  {\n    author: {\n      name: 'puntCAT',\n      screenName: 'puntCAT',\n      avatar:\n        'https://images.unsplash.com/photo-1649510998230-fda6188271fe?crop=entropy&cs=tinysrgb&fit=crop&fm=jpg&h=48&ixid=MnwxfDB8MXxyYW5kb218MHx8fHx8fHx8MTY1MTY1NzAwNQ&ixlib=rb-1.2.1&q=80&w=48',\n    },\n    id: '1480854330374868993',\n    fullText:\n      \"Les @youngitgirls formaran part de l'ecosistema creatiu del #Canòdrom de Barcelona.\\nA més d'aquesta associació, que impulsa el talent digital jove entre les noies, hi ha 12 projectes més que l'Ateneu d'Innovació Digital incorpora pel curs vinent.\\n\\n👇\\nhttps://t.co/1qFbk4oR1m\",\n    retweetCount: 0,\n    replyCount: 0,\n    favoriteCount: 5,\n  },\n  {\n    author: {\n      name: 'Un Sr de Barcelona',\n      screenName: 'UnSrdeBarcelona',\n      avatar:\n        'https://images.unsplash.com/photo-1650357519740-c888919621f8?crop=entropy&cs=tinysrgb&fit=crop&fm=jpg&h=48&ixid=MnwxfDB8MXxyYW5kb218MHx8fHx8fHx8MTY1MTY1NzA4Mg&ixlib=rb-1.2.1&q=80&w=48',\n    },\n    id: '1478406590730547203',\n    fullText:\n      'Hola.\\n\\nMe llamo Elizabeth Holmes.\\n\\nProbablemente me quedan pocos días antes de entrar en la cárcel. Por mucho tiempo.\\n\\n¿Mi crimen?\\nHaber demostrado que Silicon Valley, Wall Street y toda la prensa económica no se enteran. Vamos, que no tienen ni puta idea.\\n\\n¿Te lo explico? https://t.co/Dk0ZUnL5pP',\n    retweetCount: 3800,\n    replyCount: 138,\n    favoriteCount: 9052,\n  },\n  {\n    author: {\n      name: 'Samuel Molina',\n      screenName: 'FuKuy',\n      avatar:\n        'https://images.unsplash.com/photo-1651264042772-23891c614270?crop=entropy&cs=tinysrgb&fit=crop&fm=jpg&h=48&ixid=MnwxfDB8MXxyYW5kb218MHx8fHx8fHx8MTY1MTY1Njk4MA&ixlib=rb-1.2.1&q=80&w=48',\n    },\n    id: '1480840983914946560',\n    fullText:\n      \"RT @IK1T: Happy #PortfolioDay !\\nDear friends ❤️ I'm Fumio, a Lighting Artist 💡 currently working on Star Citizen.\\nLooking forward to meetin…\",\n    retweetCount: 19,\n    replyCount: 0,\n    favoriteCount: 0,\n  },\n  {\n    author: {\n      name: 'I Am Devloper',\n      screenName: 'iamdevloper',\n      avatar:\n        'https://images.unsplash.com/photo-1651354239553-0998040fa5ca?crop=entropy&cs=tinysrgb&fit=crop&fm=jpg&h=48&ixid=MnwxfDB8MXxyYW5kb218MHx8fHx8fHx8MTY1MTY1Njk5MQ&ixlib=rb-1.2.1&q=80&w=48',\n    },\n    id: '1480861250678575104',\n    fullText:\n      \"that thing you've been putting off will take around 15 minutes to complete\",\n    retweetCount: 46,\n    replyCount: 14,\n    favoriteCount: 358,\n  },\n  {\n    author: {\n      name: 'Gergely Orosz',\n      screenName: 'GergelyOrosz',\n      avatar:\n        'https://images.unsplash.com/photo-1650122597661-ceccf6d50692?crop=entropy&cs=tinysrgb&fit=crop&fm=jpg&h=48&ixid=MnwxfDB8MXxyYW5kb218MHx8fHx8fHx8MTY1MTY1Njk4NQ&ixlib=rb-1.2.1&q=80&w=48',\n    },\n    id: '1480855281655586817',\n    fullText:\n      \"Want to get better at writing? Here's what I do:\\n\\nI start writing those drafts when the ideas come.\\n\\nTweak them as I go.\\n\\nI looked back at all the posts I never ended publishing on my blog. Here's some from the last 12 months, many of these a few thousand words in: https://t.co/CFxLlZWxjp\",\n    retweetCount: 1,\n    replyCount: 7,\n    favoriteCount: 49,\n  },\n  {\n    author: {\n      name: 'Aeon+Psyche',\n      screenName: 'aeonmag',\n      avatar:\n        'https://images.unsplash.com/photo-1650099667209-d0e0cc6bd27f?crop=entropy&cs=tinysrgb&fit=crop&fm=jpg&h=48&ixid=MnwxfDB8MXxyYW5kb218MHx8fHx8fHx8MTY1MTY1NzAwNg&ixlib=rb-1.2.1&q=80&w=48',\n    },\n    id: '1480872218360004610',\n    fullText:\n      'Paraconsistent logics find structure in our inconsistent world https://t.co/aAmusRlUzt',\n    retweetCount: 1,\n    replyCount: 0,\n    favoriteCount: 1,\n  },\n  {\n    author: {\n      name: 'Ara Bassas',\n      screenName: 'AraBassas',\n      avatar:\n        'https://images.unsplash.com/photo-1650448211778-da533fd39266?crop=entropy&cs=tinysrgb&fit=crop&fm=jpg&h=48&ixid=MnwxfDB8MXxyYW5kb218MHx8fHx8fHx8MTY1MTY1NzA4MA&ixlib=rb-1.2.1&q=80&w=48',\n    },\n    id: '1480841869001113600',\n    fullText:\n      \"📹 L'anàlisi d'@antonibassas: \\\"La independència no és el projecte d'un home sol'' 👇\\nhttps://t.co/QYBdrLOOLQ https://t.co/GgmvzQ3zhy\",\n    retweetCount: 5,\n    replyCount: 4,\n    favoriteCount: 12,\n  },\n  {\n    author: {\n      name: 'Aeon+Psyche',\n      screenName: 'aeonmag',\n      avatar:\n        'https://images.unsplash.com/photo-1650099667209-d0e0cc6bd27f?crop=entropy&cs=tinysrgb&fit=crop&fm=jpg&h=48&ixid=MnwxfDB8MXxyYW5kb218MHx8fHx8fHx8MTY1MTY1NzAwNg&ixlib=rb-1.2.1&q=80&w=48',\n    },\n    id: '1480887302893322242',\n    fullText:\n      'Paraconsistent logics help us find structure in the noise of a world messy with inconsistencies https://t.co/aAmusRlUzt',\n    retweetCount: 1,\n    replyCount: 0,\n    favoriteCount: 3,\n  },\n  {\n    author: {\n      name: 'Pedro',\n      screenName: 'pepicrft',\n      avatar:\n        'https://images.unsplash.com/photo-1649542053026-6b59f8723c1a?crop=entropy&cs=tinysrgb&fit=crop&fm=jpg&h=48&ixid=MnwxfDB8MXxyYW5kb218MHx8fHx8fHx8MTY1MTY1NzAwOA&ixlib=rb-1.2.1&q=80&w=48',\n    },\n    id: '1480857038804586497',\n    fullText:\n      'I find very annoying the power Spanish media has to discredit topics some politicians bring up for debate like “why the reduction of meat consumption is good for the environment”. If we can’t talk about fighting climate change, do we prefer to move on and ignore the issue?',\n    retweetCount: 0,\n    replyCount: 1,\n    favoriteCount: 4,\n  },\n  {\n    author: {\n      name: 'ganyet.eth',\n      screenName: 'ganyet',\n      avatar:\n        'https://images.unsplash.com/photo-1650476217339-6b7e08b844a7?crop=entropy&cs=tinysrgb&fit=crop&fm=jpg&h=48&ixid=MnwxfDB8MXxyYW5kb218MHx8fHx8fHx8MTY1MTY1NzA3OQ&ixlib=rb-1.2.1&q=80&w=48',\n    },\n    id: '1480816503138177024',\n    fullText:\n      'Ens hem trobat amb el @jordisellas al #CatVers fa una estona. https://t.co/pMo97qa2xm https://t.co/1bHfEdoeDQ',\n    retweetCount: 0,\n    replyCount: 2,\n    favoriteCount: 7,\n  },\n  {\n    author: {\n      name: 'Imanol Zuaznabar',\n      screenName: 'Imanolzuaznabar',\n      avatar:\n        'https://images.unsplash.com/photo-1650502446427-0307c61635be?crop=entropy&cs=tinysrgb&fit=crop&fm=jpg&h=48&ixid=MnwxfDB8MXxyYW5kb218MHx8fHx8fHx8MTY1MTY1NzAwOQ&ixlib=rb-1.2.1&q=80&w=48',\n    },\n    id: '1480574196396744708',\n    fullText:\n      'El antes y el después de una fotografía de la Vía Láctea en media hora de edición. https://t.co/RWDRdPVfNg',\n    retweetCount: 182,\n    replyCount: 29,\n    favoriteCount: 1478,\n  },\n  {\n    author: {\n      name: 'Victor Blackwell CNN',\n      screenName: 'VictorBlackwell',\n      avatar:\n        'https://images.unsplash.com/photo-1649019612111-2f919bb7fd61?crop=entropy&cs=tinysrgb&fit=crop&fm=jpg&h=48&ixid=MnwxfDB8MXxyYW5kb218MHx8fHx8fHx8MTY1MTY1NzA3OA&ixlib=rb-1.2.1&q=80&w=48',\n    },\n    id: '1480653173224321030',\n    fullText:\n      'Poet Maya Angelou becomes the first Black woman to appear on a US quarter https://t.co/6MI768E6kV',\n    retweetCount: 10321,\n    replyCount: 732,\n    favoriteCount: 73010,\n  },\n  {\n    author: {\n      name: 'Paul Orlando',\n      screenName: 'porlando',\n      avatar:\n        'https://images.unsplash.com/photo-1649741622889-f46774607f66?crop=entropy&cs=tinysrgb&fit=crop&fm=jpg&h=48&ixid=MnwxfDB8MXxyYW5kb218MHx8fHx8fHx8MTY1MTY1NzAxMQ&ixlib=rb-1.2.1&q=80&w=48',\n    },\n    id: '1480698332510969860',\n    fullText:\n      \"I was on the @changelog podcast talking about complex systems, Goodhart's Law, autonomous vehicles, A Pattern Language, and more. Have a listen: https://t.co/y5uORofMWt\",\n    retweetCount: 0,\n    replyCount: 1,\n    favoriteCount: 0,\n  },\n  {\n    author: {\n      name: 'Directo al paladar',\n      screenName: 'directopaladar',\n      avatar:\n        'https://images.unsplash.com/photo-1651006450895-2b8509422212?crop=entropy&cs=tinysrgb&fit=crop&fm=jpg&h=48&ixid=MnwxfDB8MXxyYW5kb218MHx8fHx8fHx8MTY1MTY1NzAyMg&ixlib=rb-1.2.1&q=80&w=48',\n    },\n    id: '1480859549330554884',\n    fullText:\n      'Lubina con calabacín, ají dulce y tomates cherry al horno, receta ligera para disfrutar https://t.co/0wcU8jmaXM https://t.co/W14VI5C3h7',\n    retweetCount: 1,\n    replyCount: 0,\n    favoriteCount: 1,\n  },\n  {\n    author: {\n      name: 'Niall McCormack',\n      screenName: 'ndmccormack',\n      avatar:\n        'https://images.unsplash.com/photo-1649624964799-609681c92d1b?crop=entropy&cs=tinysrgb&fit=crop&fm=jpg&h=48&ixid=MnwxfDB8MXxyYW5kb218MHx8fHx8fHx8MTY1MTY1NzAxMw&ixlib=rb-1.2.1&q=80&w=48',\n    },\n    id: '1480825783086206981',\n    fullText:\n      'RT @fdesbml: Hand-knit jewelry by Nora Folk | She uses a mixed technique of weaving, knitting, braiding and knotting fine nylon microfilame…',\n    retweetCount: 901,\n    replyCount: 0,\n    favoriteCount: 0,\n  },\n  {\n    author: {\n      name: 'James Meickle',\n      screenName: 'jmeickle',\n      avatar:\n        'https://images.unsplash.com/photo-1649960234288-7049f6020779?crop=entropy&cs=tinysrgb&fit=crop&fm=jpg&h=48&ixid=MnwxfDB8MXxyYW5kb218MHx8fHx8fHx8MTY1MTY1NzA3Ng&ixlib=rb-1.2.1&q=80&w=48',\n    },\n    id: '1480540773036793862',\n    fullText:\n      \"Me in 2005: computers aren't magic, they're just machines that do exactly what you tell them\\n\\nMe in 2022 exhaling an enormous vape hit: SO, the first thing to know about computers is, you never give one your true name\",\n    retweetCount: 2431,\n    replyCount: 43,\n    favoriteCount: 17504,\n  },\n  {\n    author: {\n      name: 'Makers.cat',\n      screenName: 'makers_cat',\n      avatar:\n        'https://images.unsplash.com/photo-1649682716735-b1ba94eda742?crop=entropy&cs=tinysrgb&fit=crop&fm=jpg&h=48&ixid=MnwxfDB8MXxyYW5kb218MHx8fHx8fHx8MTY1MTY1NzAxNQ&ixlib=rb-1.2.1&q=80&w=48',\n    },\n    id: '1480826431362019328',\n    fullText:\n      'RT @palmerabollo: Las impresoras térmicas básicas solo pintan puntos negros. Pensé que tendría que hacer el \"dithering\" de la imagen, pero…',\n    retweetCount: 7,\n    replyCount: 0,\n    favoriteCount: 0,\n  },\n  {\n    author: {\n      name: 'Guido',\n      screenName: 'palmerabollo',\n      avatar:\n        'https://images.unsplash.com/photo-1649877845039-2f1f5e524b91?crop=entropy&cs=tinysrgb&fit=crop&fm=jpg&h=48&ixid=MnwxfDB8MXxyYW5kb218MHx8fHx8fHx8MTY1MTY1NzA3NQ&ixlib=rb-1.2.1&q=80&w=48',\n    },\n    id: '1480599758641287169',\n    fullText:\n      'Las impresoras térmicas básicas solo pintan puntos negros. Pensé que tendría que hacer el \"dithering\" de la imagen, pero lo hace la librería python \"thermalprinter\" https://t.co/TI5OzzF787. Floyd y Steinberg eran unos genios. Cabalgamos a hombros de gigantes. https://t.co/rPubwSzrYs',\n    retweetCount: 7,\n    replyCount: 1,\n    favoriteCount: 165,\n  },\n  {\n    author: {\n      name: 'Chus Naharro',\n      screenName: 'chusnarrolo',\n      avatar:\n        'https://images.unsplash.com/photo-1649217707439-eb9ca4e9c62f?crop=entropy&cs=tinysrgb&fit=crop&fm=jpg&h=48&ixid=MnwxfDB8MXxyYW5kb218MHx8fHx8fHx8MTY1MTY1NzAxNg&ixlib=rb-1.2.1&q=80&w=48',\n    },\n    id: '1480872099141103616',\n    fullText:\n      'RT @sunne: Necesito una lista de podcast grabados por mujeres , de la zona de Barcelona. Me da igual el idioma.\\n\\nMe ayudáis? Yo conozco alg…',\n    retweetCount: 8,\n    replyCount: 0,\n    favoriteCount: 0,\n  },\n  {\n    author: {\n      name: 'Justin Moore | Sponsorship Coach',\n      screenName: 'justinmooretfam',\n      avatar:\n        'https://images.unsplash.com/photo-1650213986462-1804543441c2?crop=entropy&cs=tinysrgb&fit=crop&fm=jpg&h=48&ixid=MnwxfDB8MXxyYW5kb218MHx8fHx8fHx8MTY1MTY1Njk3OA&ixlib=rb-1.2.1&q=80&w=48',\n    },\n    id: '1480800006412009472',\n    fullText: 'Opp!',\n    retweetCount: 0,\n    replyCount: 0,\n    favoriteCount: 1,\n  },\n  {\n    author: {\n      name: 'Directo al paladar',\n      screenName: 'directopaladar',\n      avatar:\n        'https://images.unsplash.com/photo-1651006450895-2b8509422212?crop=entropy&cs=tinysrgb&fit=crop&fm=jpg&h=48&ixid=MnwxfDB8MXxyYW5kb218MHx8fHx8fHx8MTY1MTY1NzAyMg&ixlib=rb-1.2.1&q=80&w=48',\n    },\n    id: '1480829354150092801',\n    fullText:\n      'Rebajas en El Corte Inglés: robots de cocina, batidoras, cafeteras y más ofertas en pequeño electrodoméstico de cocina https://t.co/ZT4gBTcnzs https://t.co/oH0oiIt5kz',\n    retweetCount: 0,\n    replyCount: 0,\n    favoriteCount: 2,\n  },\n  {\n    author: {\n      name: 'Farhan is hiring engineers',\n      screenName: 'fnthawar',\n      avatar:\n        'https://images.unsplash.com/photo-1651522003733-647782d87365?crop=entropy&cs=tinysrgb&fit=crop&fm=jpg&h=48&ixid=MnwxfDB8MXxyYW5kb218MHx8fHx8fHx8MTY1MTY1NzAxNw&ixlib=rb-1.2.1&q=80&w=48',\n    },\n    id: '1480867384751763457',\n    fullText: '🔥',\n    retweetCount: 0,\n    replyCount: 0,\n    favoriteCount: 4,\n  },\n  {\n    author: {\n      name: 'Pranshu Bahadur',\n      screenName: 'PranshuBahadur',\n      avatar:\n        'https://images.unsplash.com/photo-1649896867298-3f991eeb6ca2?crop=entropy&cs=tinysrgb&fit=crop&fm=jpg&h=48&ixid=MnwxfDB8MXxyYW5kb218MHx8fHx8fHx8MTY1MTY1NzA3Mw&ixlib=rb-1.2.1&q=80&w=48',\n    },\n    id: '1480807117325889536',\n    fullText:\n      'Hey everyone! Ever wanted to \"find the needle in the haystack\"?\\n\\nCheck out @CShorten30\\'s new video about the haystack vector search engine by @SeMI_tech!\\n\\nFor real though, this is really cool stuff 🤓',\n    retweetCount: 2,\n    replyCount: 2,\n    favoriteCount: 2,\n  },\n  {\n    author: {\n      name: 'Antonio Ortiz',\n      screenName: 'antonello',\n      avatar:\n        'https://images.unsplash.com/photo-1649437637540-2b9f980399db?crop=entropy&cs=tinysrgb&fit=crop&fm=jpg&h=48&ixid=MnwxfDB8MXxyYW5kb218MHx8fHx8fHx8MTY1MTY1NzAxOQ&ixlib=rb-1.2.1&q=80&w=48',\n    },\n    id: '1480849157287989249',\n    fullText:\n      'Me reafirmo en cómo creo que podemos afrontar esta variante: asumir que casi todos la vamos a pillar, protegiendo sólo a los muy vulnerables; asumir que atención primeria no puede asumir esto ni con refuerzos, descargar procesos a la población. Y confiar en vacunas y anticuerpos',\n    retweetCount: 15,\n    replyCount: 3,\n    favoriteCount: 26,\n  },\n  {\n    author: {\n      name: 'EL PAÍS',\n      screenName: 'el_pais',\n      avatar:\n        'https://images.unsplash.com/photo-1649600748105-871cb9b4631e?crop=entropy&cs=tinysrgb&fit=crop&fm=jpg&h=48&ixid=MnwxfDB8MXxyYW5kb218MHx8fHx8fHx8MTY1MTY1NzA3Mg&ixlib=rb-1.2.1&q=80&w=48',\n    },\n    id: '1480846818481221632',\n    fullText:\n      '🔴ÚLTIMA HORA | La OMS calcula que más del 50% de la población europea se contagiará de ómicron en las próximas 6 a 8 semanas https://t.co/x9xC3IWPMy https://t.co/WAn95IhYx3',\n    retweetCount: 636,\n    replyCount: 117,\n    favoriteCount: 949,\n  },\n  {\n    author: {\n      name: 'Glenn McComb',\n      screenName: 'lenymo',\n      avatar:\n        'https://images.unsplash.com/photo-1649482409426-f0813f293610?crop=entropy&cs=tinysrgb&fit=crop&fm=jpg&h=48&ixid=MnwxfDB8MXxyYW5kb218MHx8fHx8fHx8MTY1MTY1NzAyMA&ixlib=rb-1.2.1&q=80&w=48',\n    },\n    id: '1480812010774294529',\n    fullText:\n      'Retrogram is now accepting “yeet”. Great game, thanks @twolivesleft and @alittlecj.',\n    retweetCount: 1,\n    replyCount: 2,\n    favoriteCount: 3,\n  },\n  {\n    author: {\n      name: 'Cris Busquets 🦊',\n      screenName: 'cbusquets',\n      avatar:\n        'https://images.unsplash.com/photo-1649827159600-237a092f95b5?crop=entropy&cs=tinysrgb&fit=crop&fm=jpg&h=48&ixid=MnwxfDB8MXxyYW5kb218MHx8fHx8fHx8MTY1MTY1Njk5OQ&ixlib=rb-1.2.1&q=80&w=48',\n    },\n    id: '1480857415721660419',\n    fullText:\n      'RT @cbusquets: Creo que cada día se genera más contenido sobre diseño en español y esto me hace feliz.\\n\\nConfío en que algo habrá contribuid…',\n    retweetCount: 1,\n    replyCount: 0,\n    favoriteCount: 0,\n  },\n  {\n    author: {\n      name: 'Oriol Capdevila',\n      screenName: 'urikpd',\n      avatar:\n        'https://images.unsplash.com/photo-1649001241772-a0dfc60aa1d4?crop=entropy&cs=tinysrgb&fit=crop&fm=jpg&h=48&ixid=MnwxfDB8MXxyYW5kb218MHx8fHx8fHx8MTY1MTY1NzA3MQ&ixlib=rb-1.2.1&q=80&w=48',\n    },\n    id: '1480843919659257857',\n    fullText:\n      'RT @crismiquelg: mi único propósito para 2022 es dejar de despedirme con la mano en las videollamadas como si fuera idiota',\n    retweetCount: 2,\n    replyCount: 0,\n    favoriteCount: 0,\n  },\n  {\n    author: {\n      name: 'Tyler Hedrick',\n      screenName: 'tyler_hedrick',\n      avatar:\n        'https://images.unsplash.com/photo-1650871604168-2e8b22829db8?crop=entropy&cs=tinysrgb&fit=crop&fm=jpg&h=48&ixid=MnwxfDB8MXxyYW5kb218MHx8fHx8fHx8MTY1MTY1NzAwMg&ixlib=rb-1.2.1&q=80&w=48',\n    },\n    id: '1479133518189924352',\n    fullText:\n      'Alright I’m gonna be one of those people now that shares his Wordle each day \\n\\nWordle 201 4/6\\n\\n⬛⬛⬛🟨⬛\\n⬛🟨⬛🟩⬛\\n🟩🟨⬛🟨⬛\\n🟩🟩🟩🟩🟩',\n    retweetCount: 0,\n    replyCount: 3,\n    favoriteCount: 9,\n  },\n  {\n    author: {\n      name: 'Jordi Sellas Ferrés',\n      screenName: 'jordisellas',\n      avatar:\n        'https://images.unsplash.com/photo-1649320099555-9e436f69db29?crop=entropy&cs=tinysrgb&fit=crop&fm=jpg&h=48&ixid=MnwxfDB8MXxyYW5kb218MHx8fHx8fHx8MTY1MTY1NzAwNA&ixlib=rb-1.2.1&q=80&w=48',\n    },\n    id: '1480820257937936390',\n    fullText:\n      'Passejada digital matinal amb en Ganyet. Coses que fem i que explicarem demà a la ràdio.',\n    retweetCount: 0,\n    replyCount: 2,\n    favoriteCount: 5,\n  },\n  {\n    author: {\n      name: 'Aeon+Psyche',\n      screenName: 'aeonmag',\n      avatar:\n        'https://images.unsplash.com/photo-1650099667209-d0e0cc6bd27f?crop=entropy&cs=tinysrgb&fit=crop&fm=jpg&h=48&ixid=MnwxfDB8MXxyYW5kb218MHx8fHx8fHx8MTY1MTY1NzAwNg&ixlib=rb-1.2.1&q=80&w=48',\n    },\n    id: '1480879690801987585',\n    fullText:\n      'Tension, bureaucracy and deep humanity define life aboard a refugee rescue ship. @guardian on Aeon Video: https://t.co/qrtEf27Omh',\n    retweetCount: 0,\n    replyCount: 0,\n    favoriteCount: 0,\n  },\n  {\n    author: {\n      name: 'puntCAT',\n      screenName: 'puntCAT',\n      avatar:\n        'https://images.unsplash.com/photo-1649510998230-fda6188271fe?crop=entropy&cs=tinysrgb&fit=crop&fm=jpg&h=48&ixid=MnwxfDB8MXxyYW5kb218MHx8fHx8fHx8MTY1MTY1NzAwNQ&ixlib=rb-1.2.1&q=80&w=48',\n    },\n    id: '1480857176117809159',\n    fullText:\n      \"RT @youngitgirls: 🚀 Arranquem l'any amb noves aventures i moltes ganes de continuar treballant \\n\\n@CanodromBCN\",\n    retweetCount: 3,\n    replyCount: 0,\n    favoriteCount: 0,\n  },\n  {\n    author: {\n      name: 'Smashing Magazine',\n      screenName: 'smashingmag',\n      avatar:\n        'https://images.unsplash.com/photo-1649562231804-f1bfadc450d2?crop=entropy&cs=tinysrgb&fit=crop&fm=jpg&h=48&ixid=MnwxfDB8MXxyYW5kb218MHx8fHx8fHx8MTY1MTY1NzA5Mw&ixlib=rb-1.2.1&q=80&w=48',\n    },\n    id: '1480824523247296514',\n    fullText:\n      \"RT @jmeickle: Me in 2005: computers aren't magic, they're just machines that do exactly what you tell them\\n\\nMe in 2022 exhaling an enormous…\",\n    retweetCount: 2431,\n    replyCount: 0,\n    favoriteCount: 0,\n  },\n  {\n    author: {\n      name: 'Applesfera',\n      screenName: 'applesfera',\n      avatar:\n        'https://images.unsplash.com/photo-1593114970899-95c26e8d8841?crop=entropy&cs=tinysrgb&fit=crop&fm=jpg&h=48&ixid=MnwxfDB8MXxyYW5kb218MHx8fHx8fHx8MTY1MTY1Njk5NQ&ixlib=rb-1.2.1&q=80&w=48',\n    },\n    id: '1480810888932306948',\n    fullText:\n      'Private Relay qué es y cómo podemos utilizarlo para navegar de forma más segura y privada https://t.co/NEpltAYwyA https://t.co/r193iBDOar',\n    retweetCount: 5,\n    replyCount: 0,\n    favoriteCount: 5,\n  },\n  {\n    author: {\n      name: 'Directo al paladar',\n      screenName: 'directopaladar',\n      avatar:\n        'https://images.unsplash.com/photo-1651006450895-2b8509422212?crop=entropy&cs=tinysrgb&fit=crop&fm=jpg&h=48&ixid=MnwxfDB8MXxyYW5kb218MHx8fHx8fHx8MTY1MTY1NzAyMg&ixlib=rb-1.2.1&q=80&w=48',\n    },\n    id: '1480799151659044866',\n    fullText:\n      'Así es el banco italiano donde el queso parmesano sirve como aval bancario desde la II Guerra Mundial https://t.co/6niGp8CfiM https://t.co/lqWyYN0ugb',\n    retweetCount: 2,\n    replyCount: 0,\n    favoriteCount: 14,\n  },\n  {\n    author: {\n      name: 'Aitor Goyenechea 💭',\n      screenName: 'AitorGoy',\n      avatar:\n        'https://images.unsplash.com/photo-1650269717251-d3e5249a8bc8?crop=entropy&cs=tinysrgb&fit=crop&fm=jpg&h=48&ixid=MnwxfDB8MXxyYW5kb218MHx8fHx8fHx8MTY1MTY1NzA2OQ&ixlib=rb-1.2.1&q=80&w=48',\n    },\n    id: '1480834634091008007',\n    fullText: 'Esto',\n    retweetCount: 1,\n    replyCount: 1,\n    favoriteCount: 2,\n  },\n  {\n    author: {\n      name: 'Dean Jackson 🦕',\n      screenName: 'grorg',\n      avatar:\n        'https://images.unsplash.com/photo-1589049216803-a40738dfef85?crop=entropy&cs=tinysrgb&fit=crop&fm=jpg&h=48&ixid=MnwxfDB8MXxyYW5kb218MHx8fHx8fHx8MTY1MTY1NzA2OA&ixlib=rb-1.2.1&q=80&w=48',\n    },\n    id: '1478178339747602432',\n    fullText:\n      '@twolivesleft retrogram is telling me that “yeet” is not a word! the youth will be disappointed.',\n    retweetCount: 0,\n    replyCount: 3,\n    favoriteCount: 1,\n  },\n  {\n    author: {\n      name: 'Simon Nickel',\n      screenName: 'simonnickel',\n      avatar:\n        'https://images.unsplash.com/photo-1649869140207-53a4722ce7d8?crop=entropy&cs=tinysrgb&fit=crop&fm=jpg&h=48&ixid=MnwxfDB8MXxyYW5kb218MHx8fHx8fHx8MTY1MTY1NzA2Ng&ixlib=rb-1.2.1&q=80&w=48',\n    },\n    id: '1480823771200110592',\n    fullText:\n      'Anyone ever had the App Store Connect app actually open the review when you get a notification? Never worked for me.\\n\\nAlso: Layout is hard 🙄 https://t.co/m1PBl71iOH',\n    retweetCount: 0,\n    replyCount: 5,\n    favoriteCount: 5,\n  },\n  {\n    author: {\n      name: 'Santiago Alonso 💬',\n      screenName: 'salonsoweb',\n      avatar:\n        'https://images.unsplash.com/photo-1649423515812-5d7f4adb170c?crop=entropy&cs=tinysrgb&fit=crop&fm=jpg&h=48&ixid=MnwxfDB8MXxyYW5kb218MHx8fHx8fHx8MTY1MTY1NzAyMw&ixlib=rb-1.2.1&q=80&w=48',\n    },\n    id: '1480793786225676289',\n    fullText: 'Primera charleta del año! 🥳🤸‍♂️🥳🤸‍♂️🥳🤸‍♂️🥳🤸‍♂️ 👇🏻👇🏻',\n    retweetCount: 3,\n    replyCount: 0,\n    favoriteCount: 6,\n  },\n  {\n    author: {\n      name: 'Arts in Health International Foundation',\n      screenName: 'artsinhealthfdn',\n      avatar:\n        'https://images.unsplash.com/photo-1650633904515-af9f8caa8582?crop=entropy&cs=tinysrgb&fit=crop&fm=jpg&h=48&ixid=MnwxfDB8MXxyYW5kb218MHx8fHx8fHx8MTY1MTY1NzA2NQ&ixlib=rb-1.2.1&q=80&w=48',\n    },\n    id: '1480497586595414019',\n    fullText:\n      '#ArtsAgainstCovid TALKS 🎥\\n\\n\"Després de 200 anys parlant d\\'objectes, potser toca parlar de subjectes, i això obliga als museus a fer un canvi copernicà\"\\n\\nPepe Serra, director de @MuseuNac_Cat, reflexiona sobre el paper actual dels museus. \\nMira-ho aquí 👉 https://t.co/3prlEnWExp',\n    retweetCount: 3,\n    replyCount: 0,\n    favoriteCount: 8,\n  },\n  {\n    author: {\n      name: 'Cris Busquets 🦊',\n      screenName: 'cbusquets',\n      avatar:\n        'https://images.unsplash.com/photo-1649827159600-237a092f95b5?crop=entropy&cs=tinysrgb&fit=crop&fm=jpg&h=48&ixid=MnwxfDB8MXxyYW5kb218MHx8fHx8fHx8MTY1MTY1Njk5OQ&ixlib=rb-1.2.1&q=80&w=48',\n    },\n    id: '1480493695560568834',\n    fullText:\n      'Sinceramente, cada vez me preocupa más la brecha tecnológica que estamos creando.\\n\\nUsar aplicaciones y webs es fácil para mí, pero constantemente veo personas a quienes les cuesta entender el flujo / iconos / botones.\\n\\nMe da la impresión de que es porque hacemos user tests...',\n    retweetCount: 6,\n    replyCount: 8,\n    favoriteCount: 57,\n  },\n  {\n    author: {\n      name: '📸 𝙼𝚊𝚞𝚛𝚘 𝙵𝚞𝚎𝚗𝚝𝚎𝚜 🤳 fotomaf ⭐️',\n      screenName: 'Fotomaf',\n      avatar:\n        'https://images.unsplash.com/photo-1649003175381-2df7e82ef6f6?crop=entropy&cs=tinysrgb&fit=crop&fm=jpg&h=48&ixid=MnwxfDB8MXxyYW5kb218MHx8fHx8fHx8MTY1MTY1NzAyNA&ixlib=rb-1.2.1&q=80&w=48',\n    },\n    id: '1480850406892838917',\n    fullText:\n      'RT @antonello: Me reafirmo en cómo creo que podemos afrontar esta variante: asumir que casi todos la vamos a pillar, protegiendo sólo a los…',\n    retweetCount: 15,\n    replyCount: 0,\n    favoriteCount: 0,\n  },\n  {\n    author: {\n      name: 'Ben Scheirman',\n      screenName: 'subdigital',\n      avatar:\n        'https://images.unsplash.com/photo-1651419935061-c7f954d37446?crop=entropy&cs=tinysrgb&fit=crop&fm=jpg&h=48&ixid=MnwxfDB8MXxyYW5kb218MHx8fHx8fHx8MTY1MTY1NzA2NA&ixlib=rb-1.2.1&q=80&w=48',\n    },\n    id: '1480882339005747204',\n    fullText:\n      'RT @VictorBlackwell: Poet Maya Angelou becomes the first Black woman to appear on a US quarter https://t.co/6MI768E6kV',\n    retweetCount: 10321,\n    replyCount: 0,\n    favoriteCount: 0,\n  },\n  {\n    author: {\n      name: \"El Món d'Ahir\",\n      screenName: 'elmondahir',\n      avatar:\n        'https://images.unsplash.com/photo-1649005200470-3ac8cc79a7bc?crop=entropy&cs=tinysrgb&fit=crop&fm=jpg&h=48&ixid=MnwxfDB8MXxyYW5kb218MHx8fHx8fHx8MTY1MTY1NzAyNg&ixlib=rb-1.2.1&q=80&w=48',\n    },\n    id: '1480869573796798464',\n    fullText:\n      \"👶🏻 Ja és aquí el número 21!\\n\\nDedicat a la INFÀNCIA, hi trobareu articles d'@emparmoliner @MiquiOtero @AlexGutierrezM @atrillas @Guillemmartnez @_mrspremise @RaquelRicart1 i @XavierAntich, entre d'altres. \\n\\nJA A LA VENDA a https://t.co/uRF4jx4mpa i molt aviat a llibreries! https://t.co/vxdylJJGaq\",\n    retweetCount: 8,\n    replyCount: 1,\n    favoriteCount: 7,\n  },\n  {\n    author: {\n      name: 'Elvira',\n      screenName: 'ElviraBurchik',\n      avatar:\n        'https://images.unsplash.com/photo-1649171170932-c2dfd27321b4?crop=entropy&cs=tinysrgb&fit=crop&fm=jpg&h=48&ixid=MnwxfDB8MXxyYW5kb218MHx8fHx8fHx8MTY1MTY1NzA2Mg&ixlib=rb-1.2.1&q=80&w=48',\n    },\n    id: '1480822722838077441',\n    fullText:\n      'RT @Sommer: I love working with people who are friendly. Who say “thank you” or cheer you on or say “good job.” These things may seem small…',\n    retweetCount: 94,\n    replyCount: 0,\n    favoriteCount: 0,\n  },\n  {\n    author: {\n      name: 'Webificando Podcast',\n      screenName: 'Webificandop',\n      avatar:\n        'https://images.unsplash.com/photo-1650790362837-a450407ceb1c?crop=entropy&cs=tinysrgb&fit=crop&fm=jpg&h=48&ixid=MnwxfDB8MXxyYW5kb218MHx8fHx8fHx8MTY1MTY1NzAyNw&ixlib=rb-1.2.1&q=80&w=48',\n    },\n    id: '1480792377065365511',\n    fullText:\n      'Holis! 👋\\n\\nHoy tendremos al gran @salonsoweb para hablar de sus proyectos, automatizaciones y más cosas 🍿🍿\\n\\n¿Integromat o Zapier? ¿Hay alguna alternativa a la altura? 🤔\\n\\n🕕 18:00 CET\\n\\nEn Twitch 👇\\nhttps://t.co/tVO9irSqpj',\n    retweetCount: 1,\n    replyCount: 0,\n    favoriteCount: 3,\n  },\n  {\n    author: {\n      name: 'Applesfera',\n      screenName: 'applesfera',\n      avatar:\n        'https://images.unsplash.com/photo-1593114970899-95c26e8d8841?crop=entropy&cs=tinysrgb&fit=crop&fm=jpg&h=48&ixid=MnwxfDB8MXxyYW5kb218MHx8fHx8fHx8MTY1MTY1Njk5NQ&ixlib=rb-1.2.1&q=80&w=48',\n    },\n    id: '1480804355263631360',\n    fullText:\n      'Por qué Apple no adopta RCS en iMessage a pesar de las polémicas declaraciones de un responsable de Android https://t.co/OWVa6gle5k https://t.co/Wrvmi0S3wh',\n    retweetCount: 5,\n    replyCount: 1,\n    favoriteCount: 8,\n  },\n  {\n    author: {\n      name: 'DAZN España',\n      screenName: 'DAZN_ES',\n      avatar:\n        'https://images.unsplash.com/photo-1650400759211-2d8ae616b006?crop=entropy&cs=tinysrgb&fit=crop&fm=jpg&h=48&ixid=MnwxfDB8MXxyYW5kb218MHx8fHx8fHx8MTY1MTY1NzA2MQ&ixlib=rb-1.2.1&q=80&w=48',\n    },\n    id: '1480872115276496904',\n    fullText:\n      'El recital de adelantamientos que Hamilton nos regaló en Brasil 🔥\\n\\n📽️: @F1\\nhttps://t.co/d2lSNmz1Qq',\n    retweetCount: 17,\n    replyCount: 3,\n    favoriteCount: 151,\n  },\n  {\n    author: {\n      name: 'Envato Tuts+',\n      screenName: 'tutsplus',\n      avatar:\n        'https://images.unsplash.com/photo-1650542914594-033761afbd86?crop=entropy&cs=tinysrgb&fit=crop&fm=jpg&h=48&ixid=MnwxfDB8MXxyYW5kb218MHx8fHx8fHx8MTY1MTY1NzAyOQ&ixlib=rb-1.2.1&q=80&w=48',\n    },\n    id: '1480885466668974083',\n    fullText:\n      'Losing data from an external hard drive can send you into a panic. But before losing hope, READ THIS: ➡️  \\n\\nThose lost files can be recovered. Head to @tutsplus to learn four ways to restore data from an external hard drive for #Mac. Let’s begin: https://t.co/xIeOtrGwXL https://t.co/F3R1fA2u85',\n    retweetCount: 0,\n    replyCount: 0,\n    favoriteCount: 2,\n  },\n  {\n    author: {\n      name: 'Connor Shorten',\n      screenName: 'CShorten30',\n      avatar:\n        'https://images.unsplash.com/photo-1649711992982-092a8e53e39c?crop=entropy&cs=tinysrgb&fit=crop&fm=jpg&h=48&ixid=MnwxfDB8MXxyYW5kb218MHx8fHx8fHx8MTY1MTY1NzA1OQ&ixlib=rb-1.2.1&q=80&w=48',\n    },\n    id: '1480880267816546307',\n    fullText:\n      'RT @PranshuBahadur: Hey everyone! Ever wanted to \"find the needle in the haystack\"?\\n\\nCheck out @CShorten30\\'s new video about the haystack v…',\n    retweetCount: 2,\n    replyCount: 0,\n    favoriteCount: 0,\n  },\n  {\n    author: {\n      name: 'Changelog',\n      screenName: 'changelog',\n      avatar:\n        'https://images.unsplash.com/photo-1649219026888-aca032914261?crop=entropy&cs=tinysrgb&fit=crop&fm=jpg&h=48&ixid=MnwxfDB8MXxyYW5kb218MHx8fHx8fHx8MTY1MTY1NzAzMA&ixlib=rb-1.2.1&q=80&w=48',\n    },\n    id: '1480858641959956483',\n    fullText:\n      \"RT @porlando: I was on the @changelog podcast talking about complex systems, Goodhart's Law, autonomous vehicles, A Pattern Language, and m…\",\n    retweetCount: 0,\n    replyCount: 0,\n    favoriteCount: 0,\n  },\n  {\n    author: {\n      name: 'Applesfera',\n      screenName: 'applesfera',\n      avatar:\n        'https://images.unsplash.com/photo-1593114970899-95c26e8d8841?crop=entropy&cs=tinysrgb&fit=crop&fm=jpg&h=48&ixid=MnwxfDB8MXxyYW5kb218MHx8fHx8fHx8MTY1MTY1Njk5NQ&ixlib=rb-1.2.1&q=80&w=48',\n    },\n    id: '1480881128617791488',\n    fullText:\n      'El adiós a Lightning y la teoría del Smart Connector en el iPhone del futuro https://t.co/1sQWRVR9z6 https://t.co/3qEcGvi5ha',\n    retweetCount: 1,\n    replyCount: 0,\n    favoriteCount: 11,\n  },\n  {\n    author: {\n      name: 'Aeon+Psyche',\n      screenName: 'aeonmag',\n      avatar:\n        'https://images.unsplash.com/photo-1650099667209-d0e0cc6bd27f?crop=entropy&cs=tinysrgb&fit=crop&fm=jpg&h=48&ixid=MnwxfDB8MXxyYW5kb218MHx8fHx8fHx8MTY1MTY1NzAwNg&ixlib=rb-1.2.1&q=80&w=48',\n    },\n    id: '1480857084883345408',\n    fullText:\n      'When logic fails to make sense of a world noisy with inconsistency, paraconsistent logics hold out (im)possible solutions https://t.co/aAmusRlUzt',\n    retweetCount: 2,\n    replyCount: 0,\n    favoriteCount: 5,\n  },\n  {\n    author: {\n      name: '˗ˏˋrogieˎˊ',\n      screenName: 'rogie',\n      avatar:\n        'https://images.unsplash.com/photo-1648198835787-9f1b46dd261b?crop=entropy&cs=tinysrgb&fit=crop&fm=jpg&h=48&ixid=MnwxfDB8MXxyYW5kb218MHx8fHx8fHx8MTY1MTY1NzA1OA&ixlib=rb-1.2.1&q=80&w=48',\n    },\n    id: '1480802209474351105',\n    fullText:\n      'I just applied for a FREE Citizenship NFT for Satoshi Island 🏝️ @satoshiisland \\n\\nA real private island being turned into the crypto capital of the world!\\n\\nTo apply for yours, go to https://t.co/IASuZO959O and click on the Citizenship tab in the menu.\\n#satoshiisland #NFT #Airdrop',\n    retweetCount: 0,\n    replyCount: 3,\n    favoriteCount: 2,\n  },\n  {\n    author: {\n      name: 'Álvaro Bernal 🥑',\n      screenName: 'abn',\n      avatar:\n        'https://images.unsplash.com/photo-1650754294117-f648f300545f?crop=entropy&cs=tinysrgb&fit=crop&fm=jpg&h=48&ixid=MnwxfDB8MXxyYW5kb218MHx8fHx8fHx8MTY1MTY1NzAzMQ&ixlib=rb-1.2.1&q=80&w=48',\n    },\n    id: '1480872313792962568',\n    fullText:\n      'RT @DAZN_ES: El recital de adelantamientos que Hamilton nos regaló en Brasil 🔥\\n\\n📽️: @F1\\nhttps://t.co/d2lSNmz1Qq',\n    retweetCount: 17,\n    replyCount: 0,\n    favoriteCount: 0,\n  },\n  {\n    author: {\n      name: 'Michael Andersson',\n      screenName: 'Kjell_Kod',\n      avatar:\n        'https://images.unsplash.com/photo-1650719782577-d16dddc61ca7?crop=entropy&cs=tinysrgb&fit=crop&fm=jpg&h=48&ixid=MnwxfDB8MXxyYW5kb218MHx8fHx8fHx8MTY1MTY1NzA1Nw&ixlib=rb-1.2.1&q=80&w=48',\n    },\n    id: '1480631817472466946',\n    fullText:\n      'The worst thing about Rust is that it raises the bar for every other programming language.',\n    retweetCount: 3,\n    replyCount: 4,\n    favoriteCount: 18,\n  },\n  {\n    author: {\n      name: 'I Am Devloper',\n      screenName: 'iamdevloper',\n      avatar:\n        'https://images.unsplash.com/photo-1651354239553-0998040fa5ca?crop=entropy&cs=tinysrgb&fit=crop&fm=jpg&h=48&ixid=MnwxfDB8MXxyYW5kb218MHx8fHx8fHx8MTY1MTY1Njk5MQ&ixlib=rb-1.2.1&q=80&w=48',\n    },\n    id: '1480861999953289216',\n    fullText:\n      \"although arguably, the 19th time you ran the automated solution, you'll have recouped your initial investment\\n\\nso, by all means, shave that yak\",\n    retweetCount: 7,\n    replyCount: 5,\n    favoriteCount: 164,\n  },\n  {\n    author: {\n      name: 'Tyler Hedrick',\n      screenName: 'tyler_hedrick',\n      avatar:\n        'https://images.unsplash.com/photo-1650871604168-2e8b22829db8?crop=entropy&cs=tinysrgb&fit=crop&fm=jpg&h=48&ixid=MnwxfDB8MXxyYW5kb218MHx8fHx8fHx8MTY1MTY1NzAwMg&ixlib=rb-1.2.1&q=80&w=48',\n    },\n    id: '1480887659379654657',\n    fullText:\n      'My first time in 3!\\n\\nWordle 206 3/6*\\n\\n🟨⬛⬛🟨⬛\\n🟩🟩🟩⬛⬛\\n🟩🟩🟩🟩🟩',\n    retweetCount: 0,\n    replyCount: 0,\n    favoriteCount: 1,\n  },\n  {\n    author: {\n      name: 'The Spectator Index',\n      screenName: 'spectatorindex',\n      avatar:\n        'https://images.unsplash.com/photo-1651245571998-b3a505f2fa96?crop=entropy&cs=tinysrgb&fit=crop&fm=jpg&h=48&ixid=MnwxfDB8MXxyYW5kb218MHx8fHx8fHx8MTY1MTY1NzAzMw&ixlib=rb-1.2.1&q=80&w=48',\n    },\n    id: '1480876650514448385',\n    fullText:\n      \"JUST IN: World Health Organization regional director says over half Europe's population could be infected with omicron variant within a few weeks\",\n    retweetCount: 416,\n    replyCount: 57,\n    favoriteCount: 1147,\n  },\n  {\n    author: {\n      name: 'sadface',\n      screenName: 'Sadface_RL',\n      avatar:\n        'https://images.unsplash.com/photo-1650304003871-2bdb8aa62dfc?crop=entropy&cs=tinysrgb&fit=crop&fm=jpg&h=48&ixid=MnwxfDB8MXxyYW5kb218MHx8fHx8fHx8MTY1MTY1NzA1NQ&ixlib=rb-1.2.1&q=80&w=48',\n    },\n    id: '1480602754435407876',\n    fullText:\n      'A beginners guide to health bars.\\n\\n#pixelart #art #animation #gamedev #indiedev #indiegamedev #indiegame https://t.co/Fhb4mQITRc',\n    retweetCount: 177,\n    replyCount: 2,\n    favoriteCount: 1056,\n  },\n  {\n    author: {\n      name: 'SunnePod 🎙️',\n      screenName: 'sunne',\n      avatar:\n        'https://images.unsplash.com/photo-1650743768349-94043ebae1e3?crop=entropy&cs=tinysrgb&fit=crop&fm=jpg&h=48&ixid=MnwxfDB8MXxyYW5kb218MHx8fHx8fHx8MTY1MTY1NzAzNA&ixlib=rb-1.2.1&q=80&w=48',\n    },\n    id: '1480676869720657920',\n    fullText:\n      \"Necesito una lista de podcast grabados por mujeres , de la zona de Barcelona. Me da igual el idioma.\\n\\nMe ayudáis? Yo conozco algunos pero necesito conocer más ' pa una cosa'\",\n    retweetCount: 8,\n    replyCount: 8,\n    favoriteCount: 9,\n  },\n  {\n    author: {\n      name: 'MoonCat2878',\n      screenName: 'mooncat2878',\n      avatar:\n        'https://images.unsplash.com/photo-1650797073595-0a415bb3764a?crop=entropy&cs=tinysrgb&fit=crop&fm=jpg&h=48&ixid=MnwxfDB8MXxyYW5kb218MHx8fHx8fHx8MTY1MTY1NzA1NA&ixlib=rb-1.2.1&q=80&w=48',\n    },\n    id: '1480601483141959688',\n    fullText:\n      \"1/20\\n\\nI invested 55 $ETH into @LooksRareNFT for 85,636 $LOOKS tokens + I got 12,000 tokens from Airdrops.\\n\\nI paid an average of $ 1,90 per $LOOKS.\\n\\nI own a total of 97,935 $LOOKS and am staking all of them.\\n\\nSo why did I invest in @LooksRareNFT let's dig in! https://t.co/MFTMJc0gpp\",\n    retweetCount: 583,\n    replyCount: 131,\n    favoriteCount: 1896,\n  },\n  {\n    author: {\n      name: 'Pedro',\n      screenName: 'pepicrft',\n      avatar:\n        'https://images.unsplash.com/photo-1649542053026-6b59f8723c1a?crop=entropy&cs=tinysrgb&fit=crop&fm=jpg&h=48&ixid=MnwxfDB8MXxyYW5kb218MHx8fHx8fHx8MTY1MTY1NzAwOA&ixlib=rb-1.2.1&q=80&w=48',\n    },\n    id: '1480879632840859648',\n    fullText: 'https://t.co/J0KnQjvwfA',\n    retweetCount: 0,\n    replyCount: 0,\n    favoriteCount: 0,\n  },\n  {\n    author: {\n      name: 'Chus Naharro',\n      screenName: 'chusnarrolo',\n      avatar:\n        'https://images.unsplash.com/photo-1649217707439-eb9ca4e9c62f?crop=entropy&cs=tinysrgb&fit=crop&fm=jpg&h=48&ixid=MnwxfDB8MXxyYW5kb218MHx8fHx8fHx8MTY1MTY1NzAxNg&ixlib=rb-1.2.1&q=80&w=48',\n    },\n    id: '1480859223038865408',\n    fullText:\n      'Revisar y proyectar. @tonicolom me invitó a su podcast para hablar de cómo nos fue en 2021 y qué esperamos del 2022 (y damos detalles de lo que nos hemos marcado 🤓)',\n    retweetCount: 1,\n    replyCount: 0,\n    favoriteCount: 1,\n  },\n  {\n    author: {\n      name: 'Directo al paladar',\n      screenName: 'directopaladar',\n      avatar:\n        'https://images.unsplash.com/photo-1651006450895-2b8509422212?crop=entropy&cs=tinysrgb&fit=crop&fm=jpg&h=48&ixid=MnwxfDB8MXxyYW5kb218MHx8fHx8fHx8MTY1MTY1NzAyMg&ixlib=rb-1.2.1&q=80&w=48',\n    },\n    id: '1480843457946128388',\n    fullText:\n      'Qué es la dieta keto, quién puede seguirla y 43 recetas que se adaptan a ella https://t.co/ElB0N2HTG9 https://t.co/Q8xwC9EDyY',\n    retweetCount: 0,\n    replyCount: 0,\n    favoriteCount: 4,\n  },\n  {\n    author: {\n      name: 'Chus Naharro',\n      screenName: 'chusnarrolo',\n      avatar:\n        'https://images.unsplash.com/photo-1649217707439-eb9ca4e9c62f?crop=entropy&cs=tinysrgb&fit=crop&fm=jpg&h=48&ixid=MnwxfDB8MXxyYW5kb218MHx8fHx8fHx8MTY1MTY1NzAxNg&ixlib=rb-1.2.1&q=80&w=48',\n    },\n    id: '1480811903400255489',\n    fullText:\n      'RT @salonsoweb: Primera charleta del año! 🥳🤸‍♂️🥳🤸‍♂️🥳🤸‍♂️🥳🤸‍♂️ 👇🏻👇🏻',\n    retweetCount: 3,\n    replyCount: 0,\n    favoriteCount: 0,\n  },\n  {\n    author: {\n      name: 'Dru Riley 📈',\n      screenName: 'DruRly',\n      avatar:\n        'https://images.unsplash.com/photo-1650502445841-162208d37a79?crop=entropy&cs=tinysrgb&fit=crop&fm=jpg&h=48&ixid=MnwxfDB8MXxyYW5kb218MHx8fHx8fHx8MTY1MTY1NzAzNg&ixlib=rb-1.2.1&q=80&w=48',\n    },\n    id: '1480570135878451205',\n    fullText: 'Who should I talk to about DAOs?',\n    retweetCount: 11,\n    replyCount: 100,\n    favoriteCount: 144,\n  },\n  {\n    author: {\n      name: 'Philip Young',\n      screenName: 'philipyoungg',\n      avatar:\n        'https://images.unsplash.com/photo-1651437074099-fa632f2e708f?crop=entropy&cs=tinysrgb&fit=crop&fm=jpg&h=48&ixid=MnwxfDB8MXxyYW5kb218MHx8fHx8fHx8MTY1MTY1NzA0OQ&ixlib=rb-1.2.1&q=80&w=48',\n    },\n    id: '1480835233796657152',\n    fullText:\n      \"Re reading it today and it still blew my mind. You really have to read this. \\n\\nIt's all meat.\",\n    retweetCount: 0,\n    replyCount: 0,\n    favoriteCount: 3,\n  },\n  {\n    author: {\n      name: 'Buffer',\n      screenName: 'buffer',\n      avatar:\n        'https://images.unsplash.com/photo-1651067046747-39410fa2d173?crop=entropy&cs=tinysrgb&fit=crop&fm=jpg&h=48&ixid=MnwxfDB8MXxyYW5kb218MHx8fHx8fHx8MTY1MTY1NzAzNw&ixlib=rb-1.2.1&q=80&w=48',\n    },\n    id: '1480842677738516481',\n    fullText:\n      \"“The amount of transparency that we have with our customers definitely generates a lot of trust, because they understand that we are doing things that are new and that we're trying things to improve the impact of our products.”\\n\\n✨ Phantila Phataraprasit, founder of @Sabai_Design\",\n    retweetCount: 0,\n    replyCount: 0,\n    favoriteCount: 4,\n  },\n  {\n    author: {\n      name: 'James Saeed 🤼‍♂️',\n      screenName: 'j_t_saeed',\n      avatar:\n        'https://images.unsplash.com/photo-1650022935614-e215270b77de?crop=entropy&cs=tinysrgb&fit=crop&fm=jpg&h=48&ixid=MnwxfDB8MXxyYW5kb218MHx8fHx8fHx8MTY1MTY1NzA1Mg&ixlib=rb-1.2.1&q=80&w=48',\n    },\n    id: '1480839929664098307',\n    fullText:\n      'RT @aram_miquel: Apple should pay more attention. It’s unfair to users, but even more to the small developers that play by the rules!',\n    retweetCount: 2,\n    replyCount: 0,\n    favoriteCount: 0,\n  },\n  {\n    author: {\n      name: 'DUNNA',\n      screenName: 'dunnadidit',\n      avatar:\n        'https://images.unsplash.com/photo-1650471506791-adff557fd92b?crop=entropy&cs=tinysrgb&fit=crop&fm=jpg&h=48&ixid=MnwxfDB8MXxyYW5kb218MHx8fHx8fHx8MTY1MTY1NzAzOA&ixlib=rb-1.2.1&q=80&w=48',\n    },\n    id: '1480883792260775938',\n    fullText:\n      'RT @captureonepro: Want to know what @dunnadidit thinks about Capture One 22?\\n\\nWatch the video in the link below, where he tries out our ne…',\n    retweetCount: 3,\n    replyCount: 0,\n    favoriteCount: 0,\n  },\n  {\n    author: {\n      name: 'Cris Busquets 🦊',\n      screenName: 'cbusquets',\n      avatar:\n        'https://images.unsplash.com/photo-1649827159600-237a092f95b5?crop=entropy&cs=tinysrgb&fit=crop&fm=jpg&h=48&ixid=MnwxfDB8MXxyYW5kb218MHx8fHx8fHx8MTY1MTY1Njk5OQ&ixlib=rb-1.2.1&q=80&w=48',\n    },\n    id: '1374083317935570947',\n    fullText:\n      'Creo que cada día se genera más contenido sobre diseño en español y esto me hace feliz.\\n\\nConfío en que algo habrá contribuido mi aventura marciana 😁',\n    retweetCount: 1,\n    replyCount: 2,\n    favoriteCount: 76,\n  },\n  {\n    author: {\n      name: 'Pedro',\n      screenName: 'pepicrft',\n      avatar:\n        'https://images.unsplash.com/photo-1649542053026-6b59f8723c1a?crop=entropy&cs=tinysrgb&fit=crop&fm=jpg&h=48&ixid=MnwxfDB8MXxyYW5kb218MHx8fHx8fHx8MTY1MTY1NzAwOA&ixlib=rb-1.2.1&q=80&w=48',\n    },\n    id: '1480880317737152517',\n    fullText: '🤯 Around 300 people',\n    retweetCount: 0,\n    replyCount: 0,\n    favoriteCount: 2,\n  },\n  {\n    author: {\n      name: 'Imanol Zuaznabar',\n      screenName: 'Imanolzuaznabar',\n      avatar:\n        'https://images.unsplash.com/photo-1650502446427-0307c61635be?crop=entropy&cs=tinysrgb&fit=crop&fm=jpg&h=48&ixid=MnwxfDB8MXxyYW5kb218MHx8fHx8fHx8MTY1MTY1NzAwOQ&ixlib=rb-1.2.1&q=80&w=48',\n    },\n    id: '1480837773800181765',\n    fullText:\n      '@Javi_Rosano La primera vez que disparé desde ahí me quedé alucinado viendo el JPEG de cámara, aquello es otra liga 😄',\n    retweetCount: 0,\n    replyCount: 0,\n    favoriteCount: 1,\n  },\n  {\n    author: {\n      name: 'Cris Busquets 🦊',\n      screenName: 'cbusquets',\n      avatar:\n        'https://images.unsplash.com/photo-1649827159600-237a092f95b5?crop=entropy&cs=tinysrgb&fit=crop&fm=jpg&h=48&ixid=MnwxfDB8MXxyYW5kb218MHx8fHx8fHx8MTY1MTY1Njk5OQ&ixlib=rb-1.2.1&q=80&w=48',\n    },\n    id: '1480861803496280065',\n    fullText:\n      'Si estás construyendo tu #portfolio y no puedes publicar algunos de los proyectos porque están bajo un NDA, quizás esto te interesa 🤘\\n\\nhttps://t.co/6kvzwCQs1H',\n    retweetCount: 0,\n    replyCount: 0,\n    favoriteCount: 6,\n  },\n  {\n    author: {\n      name: 'Gergely Orosz',\n      screenName: 'GergelyOrosz',\n      avatar:\n        'https://images.unsplash.com/photo-1650122597661-ceccf6d50692?crop=entropy&cs=tinysrgb&fit=crop&fm=jpg&h=48&ixid=MnwxfDB8MXxyYW5kb218MHx8fHx8fHx8MTY1MTY1Njk4NQ&ixlib=rb-1.2.1&q=80&w=48',\n    },\n    id: '1480830543382122499',\n    fullText:\n      \"If you work in tech, you probably have strong opinions on how hiring is broken.\\n\\nWrite this down. The pain points you see and what you'd solve if you were the hiring manager.\\n\\nThere's a good chance you'll be a hiring manager in a few years. Get this list out and make the changes.\",\n    retweetCount: 11,\n    replyCount: 8,\n    favoriteCount: 85,\n  },\n  {\n    author: {\n      name: 'Ludo the great',\n      screenName: 'granludo',\n      avatar:\n        'https://images.unsplash.com/photo-1651226550740-b30efba028f6?crop=entropy&cs=tinysrgb&fit=crop&fm=jpg&h=48&ixid=MnwxfDB8MXxyYW5kb218MHx8fHx8fHx8MTY1MTY1NzA1MQ&ixlib=rb-1.2.1&q=80&w=48',\n    },\n    id: '1480823014409355266',\n    fullText:\n      'He decidit no comprar-me aquesta samarreta. #butIshould https://t.co/zkao8s06Tx',\n    retweetCount: 1,\n    replyCount: 2,\n    favoriteCount: 5,\n  },\n  {\n    author: {\n      name: '@levelsio',\n      screenName: 'levelsio',\n      avatar:\n        'https://images.unsplash.com/photo-1650964858223-f4e7f5279f48?crop=entropy&cs=tinysrgb&fit=crop&fm=jpg&h=48&ixid=MnwxfDB8MXxyYW5kb218MHx8fHx8fHx8MTY1MTY1Njk4Mg&ixlib=rb-1.2.1&q=80&w=48',\n    },\n    id: '1480808657780543493',\n    fullText:\n      '1) User clicks on https://t.co/PL9rryfQ7X client dashboard to schedule meeting\\n2) Robot checks where user is from, EU, non-EU or US\\n3) Robot picks right calendar link\\n4) Robot duplicates the link, makes it single-use and personalizes the title with their name in it',\n    retweetCount: 0,\n    replyCount: 1,\n    favoriteCount: 19,\n  },\n  {\n    author: {\n      name: 'Kosta Eleftheriou',\n      screenName: 'keleftheriou',\n      avatar:\n        'https://images.unsplash.com/photo-1651017810072-3043e05ddbcc?crop=entropy&cs=tinysrgb&fit=crop&fm=jpg&h=48&ixid=MnwxfDB8MXxyYW5kb218MHx8fHx8fHx8MTY1MTY1NzA0MA&ixlib=rb-1.2.1&q=80&w=48',\n    },\n    id: '1480626605370142724',\n    fullText: '💰 How to make $13,000,000 on the App Store:\\n\\n(thread)',\n    retweetCount: 606,\n    replyCount: 25,\n    favoriteCount: 2201,\n  },\n  {\n    author: {\n      name: 'Philip Young',\n      screenName: 'philipyoungg',\n      avatar:\n        'https://images.unsplash.com/photo-1651437074099-fa632f2e708f?crop=entropy&cs=tinysrgb&fit=crop&fm=jpg&h=48&ixid=MnwxfDB8MXxyYW5kb218MHx8fHx8fHx8MTY1MTY1NzA0OQ&ixlib=rb-1.2.1&q=80&w=48',\n    },\n    id: '1480876712275496960',\n    fullText:\n      \"Session milestone:\\n\\nToday's revenue is at $500 😱\\n\\nAn outlier but worth to celebrate! 🥳\\n\\nSpend my day cleaning the house, learning AWS + SNS (painful), and reading book to make Session better ⚡️ https://t.co/2Zf7UJStt6\",\n    retweetCount: 0,\n    replyCount: 4,\n    favoriteCount: 36,\n  },\n  {\n    author: {\n      name: 'Easlo',\n      screenName: 'heyeaslo',\n      avatar:\n        'https://images.unsplash.com/photo-1650035417643-250fa6ee5895?crop=entropy&cs=tinysrgb&fit=crop&fm=jpg&h=48&ixid=MnwxfDB8MXxyYW5kb218MHx8fHx8fHx8MTY1MTY1NzAwMQ&ixlib=rb-1.2.1&q=80&w=48',\n    },\n    id: '1480766432275144706',\n    fullText:\n      'Notion can literally do everything.\\n\\nNotion + Super → Website\\nNotion + Queue → Schedule Twitter\\nNotion + Instapost → Schedule Instagram\\nNotion + Zorbi → Flashcards\\nNotion + NotionForms → Forms\\nNotion + HelpKit → Knowledge Base \\nNotion + Float → Course',\n    retweetCount: 55,\n    replyCount: 15,\n    favoriteCount: 532,\n  },\n  {\n    author: {\n      name: 'SonyAlphaRumors',\n      screenName: 'SonyAlphaRumors',\n      avatar:\n        'https://images.unsplash.com/photo-1650170495855-add188d60239?crop=entropy&cs=tinysrgb&fit=crop&fm=jpg&h=48&ixid=MnwxfDB8MXxyYW5kb218MHx8fHx8fHx8MTY1MTY1Njk4MQ&ixlib=rb-1.2.1&q=80&w=48',\n    },\n    id: '1480809744881303554',\n    fullText: 'Sony Tidbits… https://t.co/xOStQJcjO9',\n    retweetCount: 0,\n    replyCount: 0,\n    favoriteCount: 1,\n  },\n  {\n    author: {\n      name: 'Aeon+Psyche',\n      screenName: 'aeonmag',\n      avatar:\n        'https://images.unsplash.com/photo-1650099667209-d0e0cc6bd27f?crop=entropy&cs=tinysrgb&fit=crop&fm=jpg&h=48&ixid=MnwxfDB8MXxyYW5kb218MHx8fHx8fHx8MTY1MTY1NzAwNg&ixlib=rb-1.2.1&q=80&w=48',\n    },\n    id: '1480841997997035524',\n    fullText:\n      'Recognising that waste is central, not peripheral, to everything we design, make and do is key to transforming the future https://t.co/2iIvy0430c',\n    retweetCount: 4,\n    replyCount: 0,\n    favoriteCount: 12,\n  },\n  {\n    author: {\n      name: 'Dickie Bush 🚢',\n      screenName: 'dickiebush',\n      avatar:\n        'https://images.unsplash.com/photo-1649470241643-e601950cc489?crop=entropy&cs=tinysrgb&fit=crop&fm=jpg&h=48&ixid=MnwxfDB8MXxyYW5kb218MHx8fHx8fHx8MTY1MTY1Njk5NA&ixlib=rb-1.2.1&q=80&w=48',\n    },\n    id: '1480713019772518407',\n    fullText:\n      'The single biggest mistake beginner writers make:\\n\\nPublishing weekly blog posts into the void.\\n\\nInstead, you should write daily Atomic Essays.\\n\\nAnd here are 4 reasons why: https://t.co/FoYUUkA3RV',\n    retweetCount: 58,\n    replyCount: 16,\n    favoriteCount: 439,\n  },\n  {\n    author: {\n      name: 'B&H Photo Video',\n      screenName: 'bhphoto',\n      avatar:\n        'https://images.unsplash.com/photo-1651275001129-e8e4fbba075d?crop=entropy&cs=tinysrgb&fit=crop&fm=jpg&h=48&ixid=MnwxfDB8MXxyYW5kb218MHx8fHx8fHx8MTY1MTY1NzA0MQ&ixlib=rb-1.2.1&q=80&w=48',\n    },\n    id: '1480876449284472838',\n    fullText:\n      'The latest Canon Cinema EOS System release is coming and it will be \"Ready for Anything.\" \\nClick here for more information on January 19, 2022 at 7 AM EST - https://t.co/1BS8S8uAhm\\n\\nWhat are you hoping this release will bring? https://t.co/UIFyV8hyqv',\n    retweetCount: 1,\n    replyCount: 0,\n    favoriteCount: 7,\n  },\n  {\n    author: {\n      name: 'Simeon',\n      screenName: 'twolivesleft',\n      avatar:\n        'https://images.unsplash.com/photo-1649633720119-ae64fda5fac9?crop=entropy&cs=tinysrgb&fit=crop&fm=jpg&h=48&ixid=MnwxfDB8MXxyYW5kb218MHx8fHx8fHx8MTY1MTY1NzA0OA&ixlib=rb-1.2.1&q=80&w=48',\n    },\n    id: '1480831252060016640',\n    fullText:\n      'RT @lenymo: Retrogram is now accepting “yeet”. Great game, thanks @twolivesleft and @alittlecj. https://t.co/5Y7oiqIQua',\n    retweetCount: 1,\n    replyCount: 0,\n    favoriteCount: 0,\n  },\n  {\n    author: {\n      name: 'Aeon+Psyche',\n      screenName: 'aeonmag',\n      avatar:\n        'https://images.unsplash.com/photo-1650099667209-d0e0cc6bd27f?crop=entropy&cs=tinysrgb&fit=crop&fm=jpg&h=48&ixid=MnwxfDB8MXxyYW5kb218MHx8fHx8fHx8MTY1MTY1NzAwNg&ixlib=rb-1.2.1&q=80&w=48',\n    },\n    id: '1480864584710103046',\n    fullText:\n      'Artworks have the capacity to transport us into other worlds. But where exactly do we go when we are immersed in art? https://t.co/F1QXdpujFh',\n    retweetCount: 4,\n    replyCount: 0,\n    favoriteCount: 14,\n  },\n  {\n    author: {\n      name: 'Zachary Diaz',\n      screenName: 'ZacharyDiaz',\n      avatar:\n        'https://images.unsplash.com/photo-1651045433852-1a4dc09fc859?crop=entropy&cs=tinysrgb&fit=crop&fm=jpg&h=48&ixid=MnwxfDB8MXxyYW5kb218MHx8fHx8fHx8MTY1MTY1NzA0Mw&ixlib=rb-1.2.1&q=80&w=48',\n    },\n    id: '1480713396806832132',\n    fullText:\n      'A week of onboarding later and I can share my new role: I’ve joined @tiktok_us Live and will be leading the Creator Management team. \\n\\nThere is a massive opportunity to bring more live creators and content categories to the existing ecosystem.\\n\\nPSA: I’m hiring Creator Managers! https://t.co/VGeTOtVvSq',\n    retweetCount: 20,\n    replyCount: 242,\n    favoriteCount: 721,\n  },\n  {\n    author: {\n      name: 'David Cortés',\n      screenName: 'davebcn87',\n      avatar:\n        'https://images.unsplash.com/photo-1650509354833-d3eeb1d161e1?crop=entropy&cs=tinysrgb&fit=crop&fm=jpg&h=48&ixid=MnwxfDB8MXxyYW5kb218MHx8fHx8fHx8MTY1MTY1NzA0Nw&ixlib=rb-1.2.1&q=80&w=48',\n    },\n    id: '1480887856184897538',\n    fullText:\n      'Want to keep track of your achievements? \\n\\nStart a brag document.\\n\\n https://t.co/5BivvuxWzO',\n    retweetCount: 0,\n    replyCount: 0,\n    favoriteCount: 0,\n  },\n  {\n    author: {\n      name: 'Smashing Magazine',\n      screenName: 'smashingmag',\n      avatar:\n        'https://images.unsplash.com/photo-1649562231804-f1bfadc450d2?crop=entropy&cs=tinysrgb&fit=crop&fm=jpg&h=48&ixid=MnwxfDB8MXxyYW5kb218MHx8fHx8fHx8MTY1MTY1NzA5Mw&ixlib=rb-1.2.1&q=80&w=48',\n    },\n    id: '1479108107154255875',\n    fullText:\n      '📣 New Smashing Workshops in 2022:\\n \\n😎 Accessible Front-End Patterns — @cariefisher\\n👾 Front-End Testing — @bahmutov\\n👻 HTML Email — \\n@HTeuMeuLeu\\n🚚 DevOps — \\n@mishunov\\n🚂 Designing For Complex UI — @smashingmag\\n🚚 Data Visualization — \\n@wattenberger\\n \\n👉 https://t.co/aFVbyZMada https://t.co/1MORKvqwYZ',\n    retweetCount: 15,\n    replyCount: 1,\n    favoriteCount: 52,\n  },\n  {\n    author: {\n      name: 'Applesfera',\n      screenName: 'applesfera',\n      avatar:\n        'https://images.unsplash.com/photo-1593114970899-95c26e8d8841?crop=entropy&cs=tinysrgb&fit=crop&fm=jpg&h=48&ixid=MnwxfDB8MXxyYW5kb218MHx8fHx8fHx8MTY1MTY1Njk5NQ&ixlib=rb-1.2.1&q=80&w=48',\n    },\n    id: '1480870016425902081',\n    fullText:\n      'La App Store deberá permitir pagos de terceros, pero Apple seguirá cobrando una comisión reducida al desarrollador https://t.co/TZboDnFhoc https://t.co/Ci1RRMjMzq',\n    retweetCount: 5,\n    replyCount: 0,\n    favoriteCount: 5,\n  },\n  {\n    author: {\n      name: 'Franz Jeitz',\n      screenName: 'fudgegraphics',\n      avatar:\n        'https://images.unsplash.com/photo-1650039673254-08927baf72ac?crop=entropy&cs=tinysrgb&fit=crop&fm=jpg&h=48&ixid=MnwxfDB8MXxyYW5kb218MHx8fHx8fHx8MTY1MTY1NzA0NA&ixlib=rb-1.2.1&q=80&w=48',\n    },\n    id: '1480842566685925377',\n    fullText: 'Wordle 206 3/6\\n\\n⬜🟩⬜🟨⬜\\n⬜🟩🟩⬜🟩\\n🟩🟩🟩🟩🟩',\n    retweetCount: 0,\n    replyCount: 0,\n    favoriteCount: 1,\n  },\n  {\n    author: {\n      name: '📸 𝙼𝚊𝚞𝚛𝚘 𝙵𝚞𝚎𝚗𝚝𝚎𝚜 🤳 fotomaf ⭐️',\n      screenName: 'Fotomaf',\n      avatar:\n        'https://images.unsplash.com/photo-1649003175381-2df7e82ef6f6?crop=entropy&cs=tinysrgb&fit=crop&fm=jpg&h=48&ixid=MnwxfDB8MXxyYW5kb218MHx8fHx8fHx8MTY1MTY1NzAyNA&ixlib=rb-1.2.1&q=80&w=48',\n    },\n    id: '1480837515909246977',\n    fullText: 'RT @AitorGoy: Esto https://t.co/NEIdMjQtzF',\n    retweetCount: 1,\n    replyCount: 0,\n    favoriteCount: 0,\n  },\n  {\n    author: {\n      name: 'Colin Cornaby',\n      screenName: 'colincornaby',\n      avatar:\n        'https://images.unsplash.com/photo-1651170022383-6eaa642ee2fa?crop=entropy&cs=tinysrgb&fit=crop&fm=jpg&h=48&ixid=MnwxfDB8MXxyYW5kb218MHx8fHx8fHx8MTY1MTY1NzA0NQ&ixlib=rb-1.2.1&q=80&w=48',\n    },\n    id: '1480800802599956480',\n    fullText:\n      'If you know what to look for you might be able to write more M1 friendly Vulkan code and shaders.',\n    retweetCount: 0,\n    replyCount: 1,\n    favoriteCount: 0,\n  },\n];\n"
  },
  {
    "path": "example/src/screens/integrations/flashlist/index.ts",
    "content": "export { default } from './FlashListExample';\n"
  },
  {
    "path": "example/src/screens/integrations/flashlist/models/Author.ts",
    "content": "export default interface Author {\n  name: string;\n  avatar: string;\n  screenName: string;\n}\n"
  },
  {
    "path": "example/src/screens/integrations/flashlist/models/Tweet.ts",
    "content": "import type Author from './Author';\n\nexport default interface Tweet {\n  id: string;\n  author: Author;\n  fullText: string;\n  retweetCount: number;\n  replyCount: number;\n  favoriteCount: number;\n}\n"
  },
  {
    "path": "example/src/screens/integrations/legendlist/LegendListExample.tsx",
    "content": "import BottomSheet, {\n  useBottomSheetScrollableCreator,\n} from '@gorhom/bottom-sheet';\nimport { LegendList, type LegendListRef } from '@legendapp/list';\nimport React, { useCallback, useRef } from 'react';\nimport { StyleSheet, View } from 'react-native';\nimport { Button } from '../../../components/button';\nimport renderItem from './renderItem';\n\nexport const DRAW_DISTANCE = 200;\nexport const ESTIMATED_ITEM_LENGTH = 200;\n\nconst snapPoints = ['50%', '85%'];\nconst data = new Array(500).fill(0).map((_, i) => ({\n  id: i.toString(),\n  type: 'item',\n}));\n\nconst keyExtractor = (item: (typeof data)[0]) => `id${item.id}`;\n\nconst LegendListExample = () => {\n  //#region refs\n  const bottomSheetRef = useRef<BottomSheet>(null);\n  //#endregion\n\n  //#region callbacks\n  const handleExpandPress = useCallback(() => {\n    bottomSheetRef.current?.expand();\n  }, []);\n  const handleCollapsePress = useCallback(() => {\n    bottomSheetRef.current?.collapse();\n  }, []);\n  const handleClosePress = useCallback(() => {\n    bottomSheetRef.current?.close();\n  }, []);\n  //#endregion\n\n  //#region renders\n  const BottomSheetLegendListScrollable = useBottomSheetScrollableCreator();\n  //#endregion\n\n  return (\n    <View style={styles.container}>\n      <Button label=\"Expand\" onPress={handleExpandPress} />\n      <Button label=\"Collapse\" onPress={handleCollapsePress} />\n      <Button label=\"Close\" onPress={handleClosePress} />\n      <BottomSheet\n        ref={bottomSheetRef}\n        enableDynamicSizing={false}\n        snapPoints={snapPoints}\n      >\n        <LegendList\n          style={styles.scrollContainer}\n          contentContainerStyle={styles.listContainer}\n          data={data}\n          renderItem={renderItem}\n          keyExtractor={keyExtractor}\n          indicatorStyle=\"black\"\n          estimatedItemSize={ESTIMATED_ITEM_LENGTH}\n          drawDistance={DRAW_DISTANCE}\n          maintainVisibleContentPosition\n          renderScrollComponent={BottomSheetLegendListScrollable}\n          recycleItems\n        />\n      </BottomSheet>\n    </View>\n  );\n};\n\nconst styles = StyleSheet.create({\n  container: {\n    flex: 1,\n    padding: 24,\n  },\n  scrollContainer: {\n    flex: 1,\n    height: 0.1,\n  },\n  listContainer: {},\n});\n\nexport default LegendListExample;\n"
  },
  {
    "path": "example/src/screens/integrations/legendlist/index.ts",
    "content": "export { default } from './LegendListExample';\n"
  },
  {
    "path": "example/src/screens/integrations/legendlist/renderItem.tsx",
    "content": "import type { LegendListRenderItemProps } from '@legendapp/list';\nimport Faker from 'faker';\nimport { memo, useRef, useState } from 'react';\nimport {\n  Animated,\n  Image,\n  Platform,\n  Pressable,\n  StyleSheet,\n  Text,\n  UIManager,\n  View,\n} from 'react-native';\nimport { RectButton } from 'react-native-gesture-handler';\n\nexport interface Item {\n  id: string;\n}\n\n// Generate random metadata\nconst randomAvatars = Array.from(\n  { length: 20 },\n  (_, i) => `https://i.pravatar.cc/150?img=${i + 1}`\n);\n\nif (Platform.OS === 'android') {\n  if (UIManager.setLayoutAnimationEnabledExperimental) {\n    UIManager.setLayoutAnimationEnabledExperimental(true);\n  }\n}\n\nexport const ItemCard = memo(({ item }: LegendListRenderItemProps<Item>) => {\n  const indexForData = item.id.includes('new')\n    ? 100 + +item.id.replace('new', '')\n    : +item.id;\n\n  const randomText = Faker.lorem.sentences(10);\n  const avatarUrl = randomAvatars[indexForData % randomAvatars.length];\n  const authorName = Faker.name.firstName();\n  const timestamp = `${Math.max(1, indexForData % 24)}h ago`;\n\n  return (\n    <View style={styles.itemOuterContainer}>\n      <View style={styles.itemContainer}>\n        <View style={styles.headerContainer}>\n          <Image source={{ uri: avatarUrl }} style={styles.avatar} />\n          <View style={styles.headerText}>\n            <Text style={styles.authorName}>\n              {authorName} {item.id}\n            </Text>\n            <Text style={styles.timestamp}>{timestamp}</Text>\n          </View>\n        </View>\n\n        <Text style={styles.itemTitle}>Item #{item.id}</Text>\n        <Text style={styles.itemBody}>{randomText}</Text>\n        <View style={styles.itemFooter}>\n          <Text style={styles.footerText}>❤️ 42</Text>\n          <Text style={styles.footerText}>💬 12</Text>\n          <Text style={styles.footerText}>🔄 8</Text>\n        </View>\n      </View>\n    </View>\n  );\n});\n\nexport const renderItem = (props: LegendListRenderItemProps<Item>) => (\n  <ItemCard {...props} />\n);\n\nconst styles = StyleSheet.create({\n  itemOuterContainer: {\n    padding: 12,\n  },\n  itemContainer: {\n    overflow: 'hidden',\n  },\n  titleContainer: {\n    flexDirection: 'row',\n    alignItems: 'center',\n    gap: 8,\n  },\n  stepContainer: {\n    gap: 8,\n    marginBottom: 8,\n  },\n  listContainer: {\n    paddingHorizontal: 16,\n  },\n  itemTitle: {\n    fontSize: 18,\n    fontWeight: 'bold',\n    marginBottom: 8,\n    color: '#1a1a1a',\n  },\n  itemBody: {\n    fontSize: 14,\n    color: '#666666',\n    lineHeight: 20,\n    // flex: 1,\n  },\n  itemFooter: {\n    flexDirection: 'row',\n    justifyContent: 'flex-start',\n    gap: 16,\n    marginTop: 12,\n    paddingTop: 12,\n    borderTopWidth: 1,\n    borderTopColor: '#f0f0f0',\n  },\n  footerText: {\n    fontSize: 14,\n    color: '#888888',\n  },\n  headerContainer: {\n    flexDirection: 'row',\n    alignItems: 'center',\n    marginBottom: 12,\n  },\n  avatar: {\n    width: 40,\n    height: 40,\n    borderRadius: 20,\n    marginRight: 12,\n  },\n  headerText: {\n    flex: 1,\n  },\n  authorName: {\n    fontSize: 16,\n    fontWeight: '600',\n    color: '#1a1a1a',\n  },\n  timestamp: {\n    fontSize: 12,\n    color: '#888888',\n    marginTop: 2,\n  },\n});\n\nexport default renderItem;\n"
  },
  {
    "path": "example/src/screens/integrations/map/BlurredBackground.tsx",
    "content": "import React from 'react';\nimport { StyleSheet, View } from 'react-native';\nimport { BlurView } from 'expo-blur';\n\nconst BlurredBackground = () => {\n  return (\n    <View style={styles.container}>\n      <BlurView\n        tint=\"systemThickMaterialDark\"\n        blurReductionFactor={1}\n        experimentalBlurMethod=\"dimezisBlurView\"\n        intensity={100}\n        style={styles.blurView}\n      />\n    </View>\n  );\n};\n\nconst styles = StyleSheet.create({\n  blurView: {\n    ...StyleSheet.absoluteFillObject,\n  },\n  container: {\n    ...StyleSheet.absoluteFillObject,\n    borderTopLeftRadius: 10,\n    borderTopRightRadius: 10,\n    overflow: 'hidden',\n  },\n});\n\nexport default BlurredBackground;\n"
  },
  {
    "path": "example/src/screens/integrations/map/BlurredHandle.tsx",
    "content": "import React, { useMemo } from 'react';\nimport { View, StyleSheet, Dimensions } from 'react-native';\nimport { useShowcaseTheme } from '@gorhom/showcase-template';\n\nconst { width: SCREEN_WIDTH } = Dimensions.get('screen');\n\nconst BlurredHandle = () => {\n  // hooks\n  const { colors } = useShowcaseTheme();\n\n  // styles\n  const indicatorStyle = useMemo(\n    () => [\n      styles.indicator,\n      {\n        backgroundColor: colors.secondaryText,\n      },\n    ],\n    [colors.secondaryText]\n  );\n\n  // render\n  return (\n    <View style={styles.container}>\n      <View style={indicatorStyle} />\n    </View>\n  );\n};\n\nexport const styles = StyleSheet.create({\n  container: {\n    paddingHorizontal: 16,\n    paddingVertical: 5,\n  },\n  indicator: {\n    alignSelf: 'center',\n    width: (8 * SCREEN_WIDTH) / 100,\n    height: 5,\n    borderRadius: 4,\n    backgroundColor: 'rgba(0, 0, 0, 0.2)',\n  },\n});\n\nexport default BlurredHandle;\n"
  },
  {
    "path": "example/src/screens/integrations/map/LocationDetails.tsx",
    "content": "import React, { memo, useCallback, useMemo } from 'react';\nimport { View, StyleSheet, Image, ViewProps } from 'react-native';\nimport { FlatList, TouchableOpacity } from 'react-native-gesture-handler';\nimport { useSafeAreaInsets } from 'react-native-safe-area-context';\nimport { ShowcaseLabel, useShowcaseTheme } from '@gorhom/showcase-template';\nimport { BottomSheetView } from '@gorhom/bottom-sheet';\nimport { Button } from '../../../components/button';\nimport { Location } from '../../../types';\n\nconst keyExtractor = (item: string, index: number) => `${index}${item}`;\nconst photoSize = 180;\n\nexport const LOCATION_DETAILS_HEIGHT = 298;\n\ninterface LocationDetailsProps extends Location, Pick<ViewProps, 'onLayout'> {\n  onClose: () => void;\n}\n\nconst LocationDetailsComponent = ({\n  name,\n  address,\n  photos,\n  onLayout,\n  onClose,\n}: LocationDetailsProps) => {\n  //#region hooks\n  const { colors } = useShowcaseTheme();\n  const { bottom } = useSafeAreaInsets();\n  //#endregion\n\n  //#region styles\n  const containerStyle = useMemo(\n    () => ({\n      ...styles.container,\n      paddingBottom: bottom,\n    }),\n    [bottom]\n  );\n  const closeButtonStyle = useMemo(\n    () => [\n      styles.closeButton,\n      {\n        backgroundColor: colors.secondaryCard,\n      },\n    ],\n    [colors.secondaryCard]\n  );\n  //#endregion\n\n  //#region renders\n  const renderPhoto = useCallback(({ item }: any) => {\n    return (\n      <Image\n        style={styles.photo}\n        width={photoSize}\n        height={photoSize / 1.5}\n        resizeMode=\"cover\"\n        source={{ uri: item }}\n      />\n    );\n  }, []);\n  const renderSeparator = useCallback(\n    () => <View style={styles.separator} />,\n    []\n  );\n  return (\n    <BottomSheetView style={containerStyle} onLayout={onLayout}>\n      <View style={styles.headerContainer}>\n        <View style={styles.headerContentContainer}>\n          <ShowcaseLabel style={styles.name}>{name}</ShowcaseLabel>\n          <ShowcaseLabel style={styles.address}>{address}</ShowcaseLabel>\n        </View>\n\n        <TouchableOpacity style={closeButtonStyle} onPress={onClose}>\n          <ShowcaseLabel style={styles.closeText}>X</ShowcaseLabel>\n        </TouchableOpacity>\n      </View>\n\n      <FlatList\n        data={photos}\n        horizontal={true}\n        renderItem={renderPhoto}\n        ItemSeparatorComponent={renderSeparator}\n        keyExtractor={keyExtractor}\n        showsHorizontalScrollIndicator={false}\n        style={styles.flatListContainer}\n        contentContainerStyle={styles.flatListContentContainer}\n      />\n\n      <View style={styles.actionsContainer}>\n        <Button\n          label=\"Call\"\n          labelStyle={styles.actionButtonLabel}\n          style={styles.actionButton}\n          onPress={() => {}}\n        />\n        <Button\n          label=\"Save\"\n          labelStyle={styles.actionButtonLabel}\n          style={styles.actionButton}\n          onPress={() => {}}\n        />\n        <Button\n          label=\"Share\"\n          labelStyle={styles.actionButtonLabel}\n          style={styles.actionButton}\n          onPress={() => {}}\n        />\n      </View>\n    </BottomSheetView>\n  );\n  //#endregion\n};\n\nconst styles = StyleSheet.create({\n  container: {},\n  // header\n  headerContainer: {\n    flexDirection: 'row',\n    paddingBottom: 8,\n    paddingHorizontal: 16,\n  },\n  headerContentContainer: {\n    flexGrow: 1,\n  },\n  name: {\n    fontSize: 22,\n    lineHeight: 22,\n    fontWeight: '700',\n  },\n  address: {\n    marginTop: 4,\n    fontSize: 14,\n    lineHeight: 14,\n    fontWeight: '400',\n  },\n  closeButton: {\n    alignContent: 'center',\n    alignItems: 'center',\n    width: 30,\n    height: 30,\n    borderRadius: 30,\n    padding: 0,\n    margin: 0,\n  },\n  closeText: {\n    fontSize: 15,\n    fontWeight: '600',\n    lineHeight: 30,\n  },\n  directionsButton: {\n    alignItems: 'center',\n    justifyContent: 'center',\n    minHeight: 40,\n    marginVertical: 8,\n    marginHorizontal: 16,\n    borderRadius: 10,\n    backgroundColor: '#027AFF',\n  },\n  // photos\n  flatListContainer: {\n    paddingVertical: 8,\n  },\n  flatListContentContainer: {\n    paddingHorizontal: 16,\n  },\n  separator: {\n    width: 4,\n  },\n  photo: {\n    width: photoSize,\n    height: photoSize / 1.5,\n    backgroundColor: 'rgba(0, 0, 0, 0.25)',\n  },\n  // actions\n  actionsContainer: {\n    paddingVertical: 8,\n    paddingLeft: 16,\n    paddingRight: 8,\n    flexDirection: 'row',\n    alignContent: 'space-between',\n  },\n  actionButton: {\n    flex: 1,\n    marginRight: 8,\n    alignItems: 'center',\n    borderRadius: 10,\n    minHeight: 40,\n  },\n  actionButtonLabel: {\n    color: '#027AFF',\n  },\n});\n\nexport const LocationDetails = memo(LocationDetailsComponent);\n"
  },
  {
    "path": "example/src/screens/integrations/map/LocationDetailsBottomSheet.tsx",
    "content": "import React, { useEffect } from 'react';\nimport { BottomSheetModal } from '@gorhom/bottom-sheet';\nimport {\n  forwardRef,\n  useCallback,\n  useImperativeHandle,\n  useRef,\n  useState,\n} from 'react';\nimport { useHeaderHeight } from '@react-navigation/elements';\nimport { SharedValue } from 'react-native-reanimated';\nimport { LocationDetails } from './LocationDetails';\nimport BlurredBackground from './BlurredBackground';\nimport BlurredHandle from './BlurredHandle';\nimport { Location } from '../../../types';\n\ninterface LocationDetailsBottomSheetProps {\n  index: SharedValue<number>;\n  position: SharedValue<number>;\n}\n\nexport interface LocationDetailsBottomSheetMethods {\n  present: (location: Location) => void;\n}\n\nconst SNAP_POINTS = ['100%'];\n\nexport const LocationDetailsBottomSheet = forwardRef<\n  LocationDetailsBottomSheetMethods,\n  LocationDetailsBottomSheetProps\n>(({ index, position }, ref) => {\n  //#region refs\n  const bottomSheetRef = useRef<BottomSheetModal>(null);\n  //#endregion\n\n  //#region state\n  const [selectedLocation, setSelectedLocation] = useState<Location>();\n  //#endregion\n\n  //#region hooks\n  const headerHeight = useHeaderHeight();\n  //#endregion\n\n  //#region callbacks\n  const handleCloseLocationDetails = useCallback(() => {\n    bottomSheetRef.current?.dismiss();\n  }, []);\n  const handleOnDismiss = useCallback(() => {\n    setSelectedLocation(undefined);\n  }, []);\n  //#endregion\n\n  //#region effects\n  useImperativeHandle(ref, () => ({\n    present: location => {\n      setSelectedLocation(location);\n    },\n  }));\n\n  useEffect(() => {\n    if (selectedLocation) {\n      bottomSheetRef.current?.present();\n    }\n  }, [selectedLocation]);\n  //#endregion\n\n  return (\n    <BottomSheetModal\n      ref={bottomSheetRef}\n      key=\"PoiDetailsSheet\"\n      name=\"PoiDetailsSheet\"\n      snapPoints={SNAP_POINTS}\n      topInset={headerHeight}\n      animatedIndex={index}\n      animatedPosition={position}\n      handleComponent={BlurredHandle}\n      backgroundComponent={BlurredBackground}\n      onDismiss={handleOnDismiss}\n    >\n      <LocationDetails\n        onClose={handleCloseLocationDetails}\n        {...(selectedLocation as Location)}\n      />\n    </BottomSheetModal>\n  );\n});\n"
  },
  {
    "path": "example/src/screens/integrations/map/LocationItem.tsx",
    "content": "import React, { memo } from 'react';\nimport { StyleSheet, View } from 'react-native';\nimport { ShowcaseLabel } from '@gorhom/showcase-template';\n\ninterface LocationItemProps {\n  title: string;\n  subTitle?: string;\n}\n\nconst LocationItemComponent = ({ title, subTitle }: LocationItemProps) => {\n  // render\n  return (\n    <>\n      <View style={styles.container}>\n        <View style={styles.thumbnail} />\n        <View style={styles.contentContainer}>\n          <ShowcaseLabel style={styles.title}>{title}</ShowcaseLabel>\n          {subTitle && (\n            <ShowcaseLabel style={styles.subtitle}>{subTitle}</ShowcaseLabel>\n          )}\n        </View>\n      </View>\n      <View style={styles.separator} />\n    </>\n  );\n};\n\nconst styles = StyleSheet.create({\n  container: {\n    flexDirection: 'row',\n    alignContent: 'center',\n    alignItems: 'center',\n    marginVertical: 12,\n  },\n  contentContainer: {\n    flex: 1,\n    alignSelf: 'center',\n    marginLeft: 12,\n  },\n  thumbnail: {\n    width: 32,\n    height: 32,\n    borderRadius: 32,\n    backgroundColor: 'rgba(0, 0, 0, 0.25)',\n  },\n  title: {\n    fontSize: 16,\n    fontWeight: '700',\n    marginBottom: 4,\n    textTransform: 'capitalize',\n  },\n  subtitle: {\n    color: '#999',\n    fontSize: 14,\n    textTransform: 'capitalize',\n  },\n  separator: {\n    flex: 1,\n    height: 0.5,\n    backgroundColor: '#666',\n  },\n});\n\nexport const LocationItem = memo(LocationItemComponent);\n"
  },
  {
    "path": "example/src/screens/integrations/map/LocationListBottomSheet.tsx",
    "content": "import React, { forwardRef, useCallback, useMemo } from 'react';\nimport {\n  BottomSheetBackdrop,\n  BottomSheetBackdropProps,\n  BottomSheetModal,\n  BottomSheetScrollView,\n  TouchableOpacity,\n} from '@gorhom/bottom-sheet';\nimport { useHeaderHeight } from '@react-navigation/elements';\nimport { StyleSheet } from 'react-native';\nimport { useSafeAreaInsets } from 'react-native-safe-area-context';\nimport { SharedValue, useAnimatedStyle } from 'react-native-reanimated';\nimport BlurredBackground from './BlurredBackground';\nimport BlurredHandle from './BlurredHandle';\nimport { LocationItem } from './LocationItem';\nimport { createLocationListMockData } from '../../../utilities/createMockData';\nimport { Location } from '../../../types';\n\ninterface LocationListBottomSheetProps {\n  index: SharedValue<number>;\n  position: SharedValue<number>;\n  onItemPress: (location: Location) => void;\n}\n\nexport const MIDDLE_SNAP_POINT = 300;\n\nconst SNAP_POINTS = [64, MIDDLE_SNAP_POINT, '100%'];\nconst DATA = createLocationListMockData(15);\n\nexport const LocationListBottomSheet = forwardRef<\n  BottomSheetModal,\n  LocationListBottomSheetProps\n>(({ index, position, onItemPress }, ref) => {\n  //#region hooks\n  const headerHeight = useHeaderHeight();\n  const { bottom: bottomSafeArea } = useSafeAreaInsets();\n  //#endregion\n\n  //#region styles\n  const scrollViewAnimatedStyle = useAnimatedStyle(\n    () => ({\n      opacity: index.value,\n    }),\n    [index.value]\n  );\n  const scrollViewStyle = useMemo(\n    () => [styles.scrollView, scrollViewAnimatedStyle],\n    [scrollViewAnimatedStyle]\n  );\n  const scrollViewContentContainer = useMemo(\n    () => [\n      styles.scrollViewContentContainer,\n      { paddingBottom: bottomSafeArea },\n    ],\n    [bottomSafeArea]\n  );\n  //#endregion\n\n  //#region render\n  const renderBackdrop = useCallback(\n    (props: BottomSheetBackdropProps) => (\n      <BottomSheetBackdrop\n        {...props}\n        enableTouchThrough={true}\n        pressBehavior=\"none\"\n        appearsOnIndex={2}\n        disappearsOnIndex={1}\n      />\n    ),\n    []\n  );\n\n  const renderItem = useCallback(\n    (item: Location, index: number) => (\n      <TouchableOpacity\n        key={`${item.name}.${index}`}\n        onPress={() => onItemPress(item)}\n      >\n        <LocationItem title={item.name} subTitle={item.address} />\n      </TouchableOpacity>\n    ),\n    [onItemPress]\n  );\n\n  return (\n    <BottomSheetModal\n      ref={ref}\n      key=\"PoiListSheet\"\n      name=\"PoiListSheet\"\n      index={1}\n      snapPoints={SNAP_POINTS}\n      topInset={headerHeight}\n      enableDismissOnClose={false}\n      enablePanDownToClose={false}\n      enableDynamicSizing={false}\n      animatedPosition={position}\n      animatedIndex={index}\n      backdropComponent={renderBackdrop}\n      handleComponent={BlurredHandle}\n      backgroundComponent={BlurredBackground}\n    >\n      <BottomSheetScrollView\n        keyboardDismissMode=\"on-drag\"\n        keyboardShouldPersistTaps=\"never\"\n        style={scrollViewStyle}\n        contentContainerStyle={scrollViewContentContainer}\n      >\n        {DATA.map(renderItem)}\n      </BottomSheetScrollView>\n    </BottomSheetModal>\n  );\n});\n\nconst styles = StyleSheet.create({\n  scrollView: {\n    flex: 1,\n  },\n  scrollViewContentContainer: {\n    paddingHorizontal: 16,\n  },\n});\n"
  },
  {
    "path": "example/src/screens/integrations/map/MapExample.tsx",
    "content": "import React, { useCallback, useLayoutEffect, useMemo, useRef } from 'react';\nimport { View, StyleSheet, Dimensions } from 'react-native';\nimport MapView from 'react-native-maps';\nimport { useSharedValue, useDerivedValue } from 'react-native-reanimated';\nimport { BottomSheetModal } from '@gorhom/bottom-sheet';\nimport type { Location } from '../../../types';\nimport Weather from './Weather';\nimport { withModalProvider } from '../../modal/withModalProvider';\nimport {\n  LocationDetailsBottomSheet,\n  LocationDetailsBottomSheetMethods,\n} from './LocationDetailsBottomSheet';\nimport { LocationListBottomSheet } from './LocationListBottomSheet';\n\nconst { height: SCREEN_HEIGHT } = Dimensions.get('window');\n\nconst MapExample = () => {\n  //#region refs\n  const mapRef = useRef<MapView>(null);\n  const poiListModalRef = useRef<BottomSheetModal>(null);\n  const poiDetailsModalRef = useRef<LocationDetailsBottomSheetMethods>(null);\n  //#endregion\n\n  //#region variables\n  const mapInitialCamera = useMemo(\n    () => ({\n      center: {\n        latitude: 52.3791,\n        longitude: 4.9003,\n      },\n      heading: 0,\n      pitch: 0,\n      zoom: 10,\n      altitude: 40000,\n    }),\n    []\n  );\n  //#endregion\n\n  //#region animated variables\n  const animatedPOIListIndex = useSharedValue<number>(0);\n  const animatedPOIListPosition = useSharedValue<number>(SCREEN_HEIGHT);\n  const animatedPOIDetailsIndex = useSharedValue<number>(0);\n  const animatedPOIDetailsPosition = useSharedValue<number>(SCREEN_HEIGHT);\n\n  const weatherAnimatedIndex = useDerivedValue(() =>\n    animatedPOIListIndex.value > animatedPOIDetailsIndex.value\n      ? animatedPOIListIndex.value\n      : animatedPOIDetailsIndex.value\n  );\n  const weatherAnimatedPosition = useDerivedValue(() =>\n    animatedPOIListPosition.value < animatedPOIDetailsPosition.value\n      ? animatedPOIListPosition.value\n      : animatedPOIDetailsPosition.value\n  );\n  //#endregion\n\n  //#region callbacks\n  const handleTouchStart = useCallback(() => {\n    poiListModalRef.current?.collapse();\n  }, []);\n  const handleOnLocationPress = useCallback((item: Location) => {\n    poiDetailsModalRef.current?.present(item);\n  }, []);\n  //#endregion\n\n  //#region effects\n  useLayoutEffect(() => {\n    requestAnimationFrame(() => poiListModalRef.current?.present());\n  }, []);\n  //#endregion\n\n  // renders\n  return (\n    <View style={styles.container}>\n      <MapView\n        ref={mapRef}\n        initialCamera={mapInitialCamera}\n        zoomEnabled={false}\n        style={styles.mapContainer}\n        onTouchStart={handleTouchStart}\n      />\n\n      <Weather\n        animatedIndex={weatherAnimatedIndex}\n        animatedPosition={weatherAnimatedPosition}\n      />\n\n      <LocationListBottomSheet\n        ref={poiListModalRef}\n        index={animatedPOIListIndex}\n        position={animatedPOIListPosition}\n        onItemPress={handleOnLocationPress}\n      />\n      <LocationDetailsBottomSheet\n        ref={poiDetailsModalRef}\n        index={animatedPOIDetailsIndex}\n        position={animatedPOIDetailsPosition}\n      />\n    </View>\n  );\n};\n\nconst styles = StyleSheet.create({\n  container: {\n    flex: 1,\n    padding: 24,\n  },\n  mapContainer: {\n    ...StyleSheet.absoluteFillObject,\n  },\n  scrollView: {\n    flex: 1,\n  },\n  scrollViewContentContainer: {\n    paddingHorizontal: 16,\n  },\n});\n\nexport default withModalProvider(MapExample);\n"
  },
  {
    "path": "example/src/screens/integrations/map/Weather.tsx",
    "content": "import React, { useCallback, useMemo, useState } from 'react';\nimport { LayoutChangeEvent, StyleSheet } from 'react-native';\nimport Animated, {\n  Extrapolation,\n  interpolate,\n  useAnimatedStyle,\n} from 'react-native-reanimated';\nimport { useSafeAreaFrame } from 'react-native-safe-area-context';\nimport { ShowcaseLabel, useShowcaseTheme } from '@gorhom/showcase-template';\nimport { MIDDLE_SNAP_POINT } from './LocationListBottomSheet';\n\ninterface WeatherProps {\n  animatedPosition: Animated.SharedValue<number>;\n  animatedIndex: Animated.SharedValue<number>;\n}\n\nconst SPACE = 8;\n\nconst Weather = ({ animatedIndex, animatedPosition }: WeatherProps) => {\n  //#region state\n  const [height, setHeight] = useState(0);\n  //#endregion\n\n  //#region hooks\n  const { height: screenHeight } = useSafeAreaFrame();\n  const { colors } = useShowcaseTheme();\n  //#endregion\n\n  //#region callbacks\n  const handleOnLayout = useCallback(\n    ({ nativeEvent: { layout } }: LayoutChangeEvent) => {\n      setHeight(layout.height);\n    },\n    []\n  );\n  //#endregion\n\n  //#region styles\n  const containerAnimatedStyle = useAnimatedStyle(() => {\n    const belowMiddlePosition =\n      screenHeight - animatedPosition.value < MIDDLE_SNAP_POINT;\n    return {\n      opacity: interpolate(\n        animatedIndex.value,\n        [1, 1.125],\n        [1, 0],\n        Extrapolation.CLAMP\n      ),\n      transform: [\n        {\n          translateY: belowMiddlePosition\n            ? animatedPosition.value - height - SPACE\n            : screenHeight - MIDDLE_SNAP_POINT - height - SPACE,\n        },\n      ],\n    };\n  }, [animatedIndex.value, animatedPosition.value, height, screenHeight]);\n  const containerStyle = useMemo(\n    () => [\n      styles.container,\n      { backgroundColor: colors.secondaryCard },\n      containerAnimatedStyle,\n    ],\n    [colors.secondaryCard, containerAnimatedStyle]\n  );\n  //#endregion\n\n  return (\n    <Animated.View onLayout={handleOnLayout} style={containerStyle}>\n      <ShowcaseLabel style={styles.label}>☁️ 12°</ShowcaseLabel>\n    </Animated.View>\n  );\n};\n\nconst styles = StyleSheet.create({\n  container: {\n    position: 'absolute',\n    right: 12,\n    top: 0,\n    padding: 6,\n    marginTop: 0,\n    borderRadius: 4,\n  },\n  label: {\n    fontSize: 12,\n    lineHeight: 12,\n    fontWeight: '800',\n  },\n});\n\nexport default Weather;\n"
  },
  {
    "path": "example/src/screens/integrations/navigation/DummyScreen.tsx",
    "content": "import React, { useCallback, memo } from 'react';\nimport { useNavigation } from '@react-navigation/native';\nimport { ContactList } from '../../../components/contactList';\n\ninterface DummyScreenProps {\n  title: string;\n  nextScreen: string;\n  type: 'FlatList' | 'SectionList' | 'ScrollView' | 'View';\n  count?: number;\n}\n\nconst createDummyScreen = ({\n  nextScreen,\n  type,\n  count = 50,\n}: DummyScreenProps) =>\n  memo(() => {\n    const { navigate } = useNavigation();\n\n    const handleNavigatePress = useCallback(() => {\n      requestAnimationFrame(() => navigate(nextScreen as any));\n      // eslint-disable-next-line react-hooks/exhaustive-deps\n    }, []);\n\n    return (\n      <ContactList\n        key={`${type}.list`}\n        count={count}\n        type={type}\n        onItemPress={handleNavigatePress}\n      />\n    );\n  });\n\nexport default createDummyScreen;\n"
  },
  {
    "path": "example/src/screens/integrations/navigation/NavigatorExample.tsx",
    "content": "import BottomSheet from '@gorhom/bottom-sheet';\nimport {\n  NavigationContainer,\n  NavigationIndependentTree,\n} from '@react-navigation/native';\nimport {\n  type StackNavigationOptions,\n  TransitionPresets,\n  createStackNavigator,\n} from '@react-navigation/stack';\nimport React, {\n  type ComponentProps,\n  useCallback,\n  useMemo,\n  useRef,\n} from 'react';\nimport { StyleSheet, View } from 'react-native';\nimport { Button } from '../../../components/button';\nimport createDummyScreen from './DummyScreen';\n\nconst Stack = createStackNavigator();\nconst ScreenA = createDummyScreen({\n  title: 'FlatList Screen',\n  nextScreen: 'ScrollView Screen',\n  type: 'FlatList',\n});\n\nconst ScreenB = createDummyScreen({\n  title: 'ScrollView Screen',\n  nextScreen: 'SectionList Screen',\n  type: 'ScrollView',\n  count: 25,\n});\n\nconst ScreenC = createDummyScreen({\n  title: 'SectionList Screen',\n  nextScreen: 'View Screen',\n  type: 'SectionList',\n  count: 20,\n});\n\nconst ScreenD = createDummyScreen({\n  title: 'View Screen',\n  nextScreen: 'FlatList Screen',\n  type: 'View',\n  count: 5,\n});\n\nconst Navigator = () => {\n  const screenOptions = useMemo<StackNavigationOptions>(\n    () => ({\n      ...TransitionPresets.SlideFromRightIOS,\n      headerMode: 'float',\n      headerShown: true,\n      safeAreaInsets: { top: 0 },\n      headerShadowVisible: false,\n      cardStyle: {\n        backgroundColor: 'white',\n        overflow: 'visible',\n      },\n    }),\n    []\n  );\n\n  const options = useMemo<ComponentProps<typeof Stack.Screen>['options']>(\n    () => ({\n      headerBackTitle: 'Back',\n    }),\n    []\n  );\n  return (\n    <NavigationIndependentTree>\n      <NavigationContainer>\n        <Stack.Navigator screenOptions={screenOptions}>\n          <Stack.Screen\n            name=\"FlatList Screen\"\n            options={{ headerLeft: () => null }}\n            component={ScreenA}\n          />\n          <Stack.Screen\n            name=\"ScrollView Screen\"\n            options={options}\n            component={ScreenB}\n          />\n          <Stack.Screen\n            name=\"SectionList Screen\"\n            options={options}\n            component={ScreenC}\n          />\n          <Stack.Screen\n            name=\"View Screen\"\n            options={options}\n            component={ScreenD}\n          />\n        </Stack.Navigator>\n      </NavigationContainer>\n    </NavigationIndependentTree>\n  );\n};\n\nconst NavigatorExample = () => {\n  // hooks\n  const bottomSheetRef = useRef<BottomSheet>(null);\n\n  // variables\n  const snapPoints = useMemo(() => ['25%', '50%', '90%'], []);\n\n  // callbacks\n  const handleSnapPress = useCallback((index: number) => {\n    bottomSheetRef.current?.snapToIndex(index);\n  }, []);\n  const handleExpandPress = useCallback(() => {\n    bottomSheetRef.current?.expand();\n  }, []);\n  const handleCollapsePress = useCallback(() => {\n    bottomSheetRef.current?.collapse();\n  }, []);\n  const handleClosePress = useCallback(() => {\n    bottomSheetRef.current?.close();\n  }, []);\n\n  // renders\n  return (\n    <View style={styles.container}>\n      <Button label=\"Snap To 90%\" onPress={() => handleSnapPress(2)} />\n      <Button label=\"Snap To 50%\" onPress={() => handleSnapPress(1)} />\n      <Button label=\"Snap To 25%\" onPress={() => handleSnapPress(0)} />\n      <Button label=\"Expand\" onPress={() => handleExpandPress()} />\n      <Button label=\"Collapse\" onPress={() => handleCollapsePress()} />\n      <Button label=\"Close\" onPress={() => handleClosePress()} />\n      <BottomSheet\n        ref={bottomSheetRef}\n        index={1}\n        enableDynamicSizing={false}\n        snapPoints={snapPoints}\n        animateOnMount={true}\n      >\n        <Navigator />\n      </BottomSheet>\n    </View>\n  );\n};\n\nconst styles = StyleSheet.create({\n  container: {\n    flex: 1,\n    padding: 24,\n  },\n});\n\nexport default NavigatorExample;\n"
  },
  {
    "path": "example/src/screens/modal/BackdropExample.tsx",
    "content": "import React, { useCallback, useMemo, useRef, useState } from 'react';\nimport { View, StyleSheet, Alert } from 'react-native';\nimport {\n  BottomSheetModal,\n  BottomSheetBackdrop,\n  BottomSheetBackdropProps,\n  BottomSheetHandleProps,\n} from '@gorhom/bottom-sheet';\nimport { Button } from '../../components/button';\nimport { ContactList } from '../../components/contactList';\nimport { HeaderHandle } from '../../components/headerHandle';\nimport { withModalProvider } from './withModalProvider';\n\nexport const BackdropExample = () => {\n  // state\n  const [backdropPressBehavior, setBackdropPressBehavior] = useState<\n    'none' | 'close' | 'collapse'\n  >('collapse');\n  // refs\n  const bottomSheetRef = useRef<BottomSheetModal>(null);\n\n  // variables\n  const snapPoints = useMemo(() => ['25%', '50%'], []);\n\n  //#region callbacks\n  const handleDismiss = useCallback(() => {\n    Alert.alert('Modal Been Dismissed');\n  }, []);\n  const handlePresentPress = useCallback(() => {\n    bottomSheetRef.current?.present();\n  }, []);\n  const handleTogglePressBehavior = useCallback(() => {\n    setBackdropPressBehavior(state => {\n      switch (state) {\n        case 'none':\n          return 'close';\n        case 'close':\n          return 'collapse';\n        case 'collapse':\n          return 'none';\n      }\n    });\n  }, []);\n  const handleExpandPress = useCallback(() => {\n    bottomSheetRef.current?.expand();\n  }, []);\n  const handleCollapsePress = useCallback(() => {\n    bottomSheetRef.current?.collapse();\n  }, []);\n  const handleClosePress = useCallback(() => {\n    bottomSheetRef.current?.close();\n  }, []);\n  //#endregion\n\n  // renders\n  const renderBackdrop = useCallback(\n    (props: BottomSheetBackdropProps) => (\n      <BottomSheetBackdrop {...props} pressBehavior={backdropPressBehavior} />\n    ),\n    [backdropPressBehavior]\n  );\n\n  const renderHeaderHandle = useCallback(\n    (props: BottomSheetHandleProps) => (\n      <HeaderHandle {...props} children=\"Modal With Backdrop Example\" />\n    ),\n    []\n  );\n  return (\n    <View style={styles.container}>\n      <Button label=\"Present Modal\" onPress={handlePresentPress} />\n      <Button\n        label={`Toggle Press Behavior: ${backdropPressBehavior}`}\n        onPress={handleTogglePressBehavior}\n      />\n      <Button label=\"Expand\" onPress={handleExpandPress} />\n      <Button label=\"Collapse\" onPress={handleCollapsePress} />\n      <Button label=\"Close\" onPress={handleClosePress} />\n      <BottomSheetModal\n        ref={bottomSheetRef}\n        snapPoints={snapPoints}\n        enableDynamicSizing={false}\n        handleComponent={renderHeaderHandle}\n        backdropComponent={renderBackdrop}\n        onDismiss={handleDismiss}\n      >\n        <ContactList type=\"View\" count={5} />\n      </BottomSheetModal>\n    </View>\n  );\n};\n\nconst styles = StyleSheet.create({\n  container: {\n    flex: 1,\n    padding: 24,\n  },\n});\n\nexport default withModalProvider(BackdropExample);\n"
  },
  {
    "path": "example/src/screens/modal/DetachedExample.tsx",
    "content": "import {\n  BottomSheetFooter,\n  type BottomSheetFooterProps,\n  type BottomSheetHandleProps,\n  BottomSheetModal,\n  BottomSheetView,\n} from '@gorhom/bottom-sheet';\nimport React, { useCallback, useMemo, useRef, useState } from 'react';\nimport { StyleSheet, Text, View } from 'react-native';\nimport { useSafeAreaInsets } from 'react-native-safe-area-context';\nimport { Button } from '../../components/button';\nimport { ContactItem } from '../../components/contactItem';\nimport { HeaderHandle } from '../../components/headerHandle';\nimport type { Contact } from '../../types';\nimport { createContactListMockData } from '../../utilities/createMockData';\nimport { withModalProvider } from './withModalProvider';\n\nconst DATA = createContactListMockData(4);\n\nconst DetachedExample = () => {\n  // refs\n  const bottomSheetRef = useRef<BottomSheetModal>(null);\n\n  // state\n  const [count, setCount] = useState(2);\n\n  // variables\n  const data = useMemo(() => DATA.slice(0, count), [count]);\n\n  // hooks\n  const { bottom: safeBottomArea } = useSafeAreaInsets();\n\n  // callbacks\n  const handlePresentPress = useCallback(() => {\n    bottomSheetRef.current?.present();\n  }, []);\n  const handleDismissPress = useCallback(() => {\n    bottomSheetRef.current?.dismiss();\n  }, []);\n  const handleClosePress = useCallback(() => {\n    bottomSheetRef.current?.close();\n  }, []);\n  const handleResizePress = useCallback(() => {\n    setCount(state => (state === 2 ? 4 : 2));\n  }, []);\n\n  // renders\n  const renderHeaderHandle = useCallback(\n    (props: BottomSheetHandleProps) => (\n      <HeaderHandle {...props}>Detached Example</HeaderHandle>\n    ),\n    []\n  );\n  const renderItem = useCallback(\n    (item: Contact, index: number) => (\n      <ContactItem\n        key={`${item.name}.${index}`}\n        title={`${index}: ${item.name}`}\n        subTitle={item.jobTitle}\n      />\n    ),\n    []\n  );\n  const renderFooter = useCallback(\n    (props: BottomSheetFooterProps) => (\n      <BottomSheetFooter {...props}>\n        <Button\n          label=\"Resize\"\n          style={styles.footer}\n          labelStyle={styles.footerText}\n          onPress={handleResizePress}\n        />\n      </BottomSheetFooter>\n    ),\n    [handleResizePress]\n  );\n  return (\n    <View style={styles.container}>\n      <Button label=\"Present\" onPress={handlePresentPress} />\n      <Button label=\"Dismiss\" onPress={handleDismissPress} />\n      <Button label=\"Close\" onPress={handleClosePress} />\n      <BottomSheetModal\n        ref={bottomSheetRef}\n        bottomInset={safeBottomArea + 16}\n        enablePanDownToClose={true}\n        style={styles.sheetContainer}\n        backgroundComponent={null}\n        footerComponent={renderFooter}\n        handleComponent={renderHeaderHandle}\n        detached={true}\n      >\n        <BottomSheetView\n          style={styles.contentContainerStyle}\n          enableFooterMarginAdjustment={true}\n        >\n          {data.map(renderItem)}\n        </BottomSheetView>\n      </BottomSheetModal>\n    </View>\n  );\n};\n\nconst styles = StyleSheet.create({\n  container: {\n    flex: 1,\n    padding: 24,\n  },\n  sheetContainer: {\n    marginHorizontal: 16,\n    backgroundColor: 'white',\n    borderRadius: 16,\n    shadowColor: 'rgba(0,0,0,0.25)',\n    shadowOffset: {\n      width: 0,\n      height: 5,\n    },\n    shadowOpacity: 0.25,\n    shadowRadius: 16.0,\n\n    elevation: 24,\n  },\n  contentContainerStyle: {\n    paddingTop: 12,\n    paddingHorizontal: 12,\n  },\n  footer: {\n    justifyContent: 'center',\n    alignItems: 'center',\n    marginHorizontal: 12,\n    padding: 6,\n    marginBottom: 12,\n    borderRadius: 24,\n    backgroundColor: '#80f',\n  },\n  footerText: {\n    fontSize: 16,\n    fontWeight: '600',\n    color: '#fff',\n  },\n});\n\nexport default withModalProvider(DetachedExample);\n"
  },
  {
    "path": "example/src/screens/modal/DynamicSizingExample.tsx",
    "content": "import {\n  BottomSheetFooter,\n  type BottomSheetFooterProps,\n  BottomSheetModal,\n  BottomSheetScrollView,\n  type SNAP_POINT_TYPE,\n} from '@gorhom/bottom-sheet';\nimport React, { useCallback, useMemo, useRef, useState } from 'react';\nimport { StyleSheet, Text, View } from 'react-native';\nimport { useSafeAreaInsets } from 'react-native-safe-area-context';\nimport { Button } from '../../components/button';\nimport { ContactItem } from '../../components/contactItem';\nimport { createContactListMockData } from '../../utilities/createMockData';\nimport { withModalProvider } from './withModalProvider';\n\nconst DATA = createContactListMockData(20);\n\nconst DynamicSizingExample = () => {\n  //#region state\n  const [count, setCount] = useState(1);\n  const [maxHeight, setMaxHeight] = useState<undefined | number>();\n  //#endregion\n\n  //#region variable\n  const data = useMemo(() => DATA.slice(0, count), [count]);\n  //#endregion\n\n  //#region hooks\n  const { bottom: safeBottomArea } = useSafeAreaInsets();\n  const bottomSheetRef = useRef<BottomSheetModal>(null);\n  //#endregion\n\n  //#region callbacks\n  const handleIncreaseContentPress = useCallback(() => {\n    setCount(state => state + 1);\n  }, []);\n  const handleDecreaseContentPress = useCallback(() => {\n    setCount(state => Math.max(state - 1, 1));\n  }, []);\n  const handleSetMaxHeight = useCallback(() => {\n    setMaxHeight(state => (state ? undefined : 500));\n  }, []);\n  const handlePresentPress = useCallback(() => {\n    bottomSheetRef.current?.present();\n  }, []);\n  const handleDismissPress = useCallback(() => {\n    bottomSheetRef.current?.dismiss();\n  }, []);\n  const handleSheetChange = useCallback(\n    (index: number, position: number, type: SNAP_POINT_TYPE) => {\n      // biome-ignore lint/suspicious/noConsole: <explanation>\n      console.log('handleSheetChange', { index, position, type });\n    },\n    []\n  );\n  //#endregion\n\n  //#region styles\n  const footerContainerStyle = useMemo(\n    () => ({\n      ...styles.footerContainer,\n      paddingBottom: safeBottomArea || 6,\n    }),\n    [safeBottomArea]\n  );\n  //#endregion\n\n  //#region renders\n  const footerComponent = useMemo(\n    () => (props: BottomSheetFooterProps) => (\n      <BottomSheetFooter style={footerContainerStyle} {...props}>\n        <View style={{ flex: 1 }}>\n          <Button\n            label=\"Add Item\"\n            style={styles.footerButton}\n            onPress={handleIncreaseContentPress}\n          />\n        </View>\n        <View style={{ flex: 1 }}>\n          <Button\n            label=\"Remove Item\"\n            style={styles.footerButton}\n            onPress={handleDecreaseContentPress}\n          />\n        </View>\n      </BottomSheetFooter>\n    ),\n    [\n      footerContainerStyle,\n      handleIncreaseContentPress,\n      handleDecreaseContentPress,\n    ]\n  );\n  return (\n    <View style={styles.container}>\n      <Button label=\"Present\" onPress={handlePresentPress} />\n      <Button label=\"Dismiss\" onPress={handleDismissPress} />\n      <Button\n        label={`Max Dynamic Size: ${maxHeight}`}\n        onPress={handleSetMaxHeight}\n      />\n      <BottomSheetModal\n        ref={bottomSheetRef}\n        enablePanDownToClose={true}\n        maxDynamicContentSize={maxHeight}\n        footerComponent={footerComponent}\n        onChange={handleSheetChange}\n      >\n        <BottomSheetScrollView\n          contentContainerStyle={styles.contentContainerStyle}\n          enableFooterMarginAdjustment={true}\n        >\n          {data.map(item => (\n            <ContactItem\n              key={item.name}\n              title={item.name}\n              subTitle={item.jobTitle}\n            />\n          ))}\n        </BottomSheetScrollView>\n      </BottomSheetModal>\n    </View>\n  );\n};\n\nconst styles = StyleSheet.create({\n  container: {\n    flex: 1,\n    padding: 24,\n  },\n  contentContainerStyle: {\n    paddingTop: 12,\n    paddingHorizontal: 24,\n    backgroundColor: 'white',\n  },\n  message: {\n    fontSize: 24,\n    fontWeight: '600',\n    marginBottom: 12,\n    color: 'black',\n  },\n  footerContainer: {\n    flexDirection: 'row',\n    justifyContent: 'space-between',\n    gap: 12,\n    paddingHorizontal: 24,\n  },\n  footerButton: {\n    flex: 1,\n  },\n});\n\nexport default withModalProvider(DynamicSizingExample);\n"
  },
  {
    "path": "example/src/screens/modal/SimpleExample.tsx",
    "content": "import {\n  type BottomSheetHandleProps,\n  BottomSheetModal,\n} from '@gorhom/bottom-sheet';\nimport React, { useCallback, useMemo, useRef, useState } from 'react';\nimport { StyleSheet, View } from 'react-native';\nimport { Button } from '../../components/button';\nimport { ContactList } from '../../components/contactList';\nimport { HeaderHandle } from '../../components/headerHandle';\nimport { withModalProvider } from './withModalProvider';\n\nexport const SimpleExample = () => {\n  //#region state\n  const [enablePanDownToClose, setEnablePanDownToClose] = useState(true);\n  const [enableDismissOnClose, setEnableDismissOnClose] = useState(true);\n  //#endregion\n\n  // refs\n  const bottomSheetRef = useRef<BottomSheetModal>(null);\n\n  // variables\n  const snapPoints = useMemo(() => ['25%', '50%'], []);\n\n  //#region callbacks\n  const handleChange = useCallback((index: number) => {\n    console.log('handleChange', index);\n  }, []);\n  const handleAnimate = useCallback((fromIndex: number, toIndex: number) => {\n    console.log('handleAnimate', fromIndex, '>', toIndex);\n  }, []);\n  const handleDismiss = useCallback(() => {\n    console.log('on dismiss');\n  }, []);\n  const handleDismissPress = useCallback(() => {\n    bottomSheetRef.current?.dismiss();\n  }, []);\n  const handleClosePress = useCallback(() => {\n    bottomSheetRef.current?.close();\n  }, []);\n  const handleExpandPress = useCallback(() => {\n    bottomSheetRef.current?.expand();\n  }, []);\n  const handleCollapsePress = useCallback(() => {\n    bottomSheetRef.current?.collapse();\n  }, []);\n  const handlePresentPress = useCallback(() => {\n    bottomSheetRef.current?.present();\n  }, []);\n  const handleEnablePanDownToClosePress = useCallback(() => {\n    setEnablePanDownToClose(state => !state);\n  }, []);\n  const handleEnableDismissOnClosePress = useCallback(() => {\n    setEnableDismissOnClose(state => !state);\n  }, []);\n  //#endregion\n\n  // renders\n  const renderHeaderHandle = useCallback(\n    (props: BottomSheetHandleProps) => (\n      <HeaderHandle {...props} children=\"Modal Example\" />\n    ),\n    []\n  );\n  return (\n    <View style={styles.container}>\n      <Button label=\"Present Modal\" onPress={handlePresentPress} />\n      <Button label=\"Dismiss Modal\" onPress={handleDismissPress} />\n      <Button label=\"Expand\" onPress={handleExpandPress} />\n      <Button label=\"Collapse\" onPress={handleCollapsePress} />\n      <Button label=\"Close\" onPress={handleClosePress} />\n      <Button\n        label={`${\n          enablePanDownToClose ? 'Disable' : 'Enable'\n        } Pan Down To Close`}\n        onPress={handleEnablePanDownToClosePress}\n      />\n      <Button\n        label={`${\n          enableDismissOnClose ? 'Disable' : 'Enable'\n        } Dismiss On Close`}\n        onPress={handleEnableDismissOnClosePress}\n      />\n      <BottomSheetModal\n        ref={bottomSheetRef}\n        snapPoints={snapPoints}\n        enablePanDownToClose={enablePanDownToClose}\n        enableDismissOnClose={enableDismissOnClose}\n        enableDynamicSizing={false}\n        onDismiss={handleDismiss}\n        onChange={handleChange}\n        onAnimate={handleAnimate}\n        handleComponent={renderHeaderHandle}\n      >\n        <ContactList count={5} type=\"ScrollView\" />\n      </BottomSheetModal>\n    </View>\n  );\n};\n\nconst styles = StyleSheet.create({\n  container: {\n    flex: 1,\n    padding: 24,\n  },\n});\n\nexport default withModalProvider(SimpleExample);\n"
  },
  {
    "path": "example/src/screens/modal/StackExample.tsx",
    "content": "import {\n  type BottomSheetHandleProps,\n  BottomSheetModal,\n  useBottomSheetModal,\n} from '@gorhom/bottom-sheet';\nimport React, { useCallback, useMemo, useRef } from 'react';\nimport { StyleSheet, View } from 'react-native';\nimport { Button } from '../../components/button';\nimport { ContactList } from '../../components/contactList';\nimport { HeaderHandle } from '../../components/headerHandle';\nimport { withModalProvider } from './withModalProvider';\n\nconst StackExample = () => {\n  // hooks\n  const { dismiss, dismissAll } = useBottomSheetModal();\n\n  // refs\n  const bottomSheetModalARef = useRef<BottomSheetModal>(null);\n  const bottomSheetModalBRef = useRef<BottomSheetModal>(null);\n  const bottomSheetModalCRef = useRef<BottomSheetModal>(null);\n\n  // variables\n  const snapPoints = useMemo(() => ['25%', '50%'], []);\n\n  // callbacks\n  const handlePresentAPress = useCallback(() => {\n    if (bottomSheetModalARef.current) {\n      bottomSheetModalARef.current.present();\n    }\n  }, []);\n  const handleDismissAPress = useCallback(() => {\n    if (bottomSheetModalARef.current) {\n      bottomSheetModalARef.current.dismiss();\n    }\n  }, []);\n  const handlePresentBPress = useCallback(() => {\n    if (bottomSheetModalBRef.current) {\n      bottomSheetModalBRef.current.present();\n    }\n  }, []);\n  const handleDismissBPress = useCallback(() => {\n    if (bottomSheetModalBRef.current) {\n      bottomSheetModalBRef.current.dismiss();\n    }\n  }, []);\n  const handlePresentCPress = useCallback(() => {\n    if (bottomSheetModalCRef.current) {\n      bottomSheetModalCRef.current.present();\n    }\n  }, []);\n  const handleDismissCPress = useCallback(() => {\n    if (bottomSheetModalCRef.current) {\n      bottomSheetModalCRef.current.dismiss();\n    }\n  }, []);\n  const handleDismissAllPress = useCallback(() => {\n    dismissAll();\n  }, [dismissAll]);\n  const handleDismissByHookPress = useCallback(() => {\n    dismiss('A');\n  }, [dismiss]);\n\n  // renders\n  const renderHeaderHandle = useCallback(\n    (title: string) => (props: BottomSheetHandleProps) => (\n      <HeaderHandle {...props} children={title} />\n    ),\n    []\n  );\n  const renderBottomSheetContent = useCallback(\n    (onPress: () => void) => (\n      <ContactList type=\"FlatList\" onItemPress={onPress} count={6} />\n    ),\n    []\n  );\n  return (\n    <View style={styles.container}>\n      <View style={styles.row}>\n        <View style={styles.rowItem}>\n          <Button label=\"Present Modal A\" onPress={handlePresentAPress} />\n        </View>\n        <View style={styles.rowItem}>\n          <Button label=\"Dismiss Modal A\" onPress={handleDismissAPress} />\n        </View>\n      </View>\n\n      <View style={styles.row}>\n        <View style={styles.rowItem}>\n          <Button label=\"Present Modal B\" onPress={handlePresentBPress} />\n        </View>\n        <View style={styles.rowItem}>\n          <Button label=\"Dismiss Modal B\" onPress={handleDismissBPress} />\n        </View>\n      </View>\n\n      <View style={styles.row}>\n        <View style={styles.rowItem}>\n          <Button label=\"Present Modal C\" onPress={handlePresentCPress} />\n        </View>\n        <View style={styles.rowItem}>\n          <Button label=\"Dismiss Modal C\" onPress={handleDismissCPress} />\n        </View>\n      </View>\n      <Button label=\"Dismiss All Modals\" onPress={handleDismissAllPress} />\n      <Button label=\"Dismiss All By Hook\" onPress={handleDismissByHookPress} />\n\n      <BottomSheetModal\n        name=\"A\"\n        ref={bottomSheetModalARef}\n        snapPoints={snapPoints}\n        enableDynamicSizing={false}\n        handleComponent={renderHeaderHandle('Modal A')}\n        children={renderBottomSheetContent(handlePresentBPress)}\n      />\n\n      <BottomSheetModal\n        name=\"B\"\n        ref={bottomSheetModalBRef}\n        snapPoints={snapPoints}\n        enableDynamicSizing={false}\n        handleComponent={renderHeaderHandle('Modal B')}\n        children={renderBottomSheetContent(handlePresentCPress)}\n      />\n\n      <BottomSheetModal\n        name=\"C\"\n        ref={bottomSheetModalCRef}\n        index={1}\n        snapPoints={snapPoints}\n        enableDynamicSizing={false}\n        enablePanDownToClose={false}\n        handleComponent={renderHeaderHandle('Modal C')}\n        children={renderBottomSheetContent(handleDismissCPress)}\n      />\n    </View>\n  );\n};\n\nconst styles = StyleSheet.create({\n  container: {\n    flex: 1,\n    padding: 24,\n  },\n  row: {\n    flexDirection: 'row',\n    justifyContent: 'space-between',\n    gap: 12,\n  },\n  rowItem: {\n    flex: 1,\n  },\n});\n\nexport default withModalProvider(StackExample);\n"
  },
  {
    "path": "example/src/screens/modal/withModalProvider.tsx",
    "content": "import { BottomSheetModalProvider } from '@gorhom/bottom-sheet';\nimport React, { type FC } from 'react';\n\nexport const withModalProvider = (Component: FC) => () => (\n  <BottomSheetModalProvider>\n    <Component />\n  </BottomSheetModalProvider>\n);\n"
  },
  {
    "path": "example/src/screens/withGestureHandlerRoot.tsx",
    "content": "import React, { FC } from 'react';\nimport { StyleSheet } from 'react-native';\nimport { GestureHandlerRootView } from 'react-native-gesture-handler';\n\nexport const withGestureHandlerRoot = (Component: FC) => () =>\n  (\n    <GestureHandlerRootView style={styles.container}>\n      <Component />\n    </GestureHandlerRootView>\n  );\n\nconst styles = StyleSheet.create({\n  container: {\n    flex: 1,\n  },\n});\n"
  },
  {
    "path": "example/src/types.d.ts",
    "content": "export type Contact = {\n  name: string;\n  jobTitle: string;\n  address: string;\n};\n\nexport type Location = {\n  id: string;\n  name: string;\n  address: string;\n  photos: string[];\n};\n"
  },
  {
    "path": "example/src/utilities/createMockData.ts",
    "content": "import Faker from 'faker';\nimport { Dimensions } from 'react-native';\nimport type { Contact, Location } from '../types';\n\nconst { width: SCREEN_WIDTH } = Dimensions.get('screen');\n\nexport const createContactListMockData = (count: number = 20): Contact[] => {\n  return new Array(count).fill(0).map(() => ({\n    name: `${Faker.name.firstName()} ${Faker.name.lastName()}`,\n    address: `${Faker.address.city()}, ${Faker.address.country()}`,\n    jobTitle: Faker.name.jobTitle(),\n  }));\n};\n\nexport const createContactSectionsMockData = (count: number = 20) => {\n  return new Array(Math.round(count / 4)).fill(0).map(() => ({\n    title: Faker.address.country(),\n    data: new Array(Math.round(count / 4)).fill(0).map(() => ({\n      name: `${Faker.name.firstName()} ${Faker.name.lastName()}`,\n      address: `${Faker.address.city()}, ${Faker.address.country()}`,\n      jobTitle: Faker.name.jobTitle(),\n    })),\n  }));\n};\n\nexport const createLocationListMockData = (count: number = 50): Location[] => {\n  return [\n    {\n      id: 'ams',\n      name: 'Amsterdam',\n      address: 'North Holland, Netherlands',\n      photos: [\n        'https://www.infocusclinical.com/wp-content/uploads/2020/02/summer-amsterdam-FP.jpg',\n        'https://images.theconversation.com/files/162459/original/image-20170325-12162-1tfrmbb.jpg?ixlib=rb-1.1.0&q=45&auto=format&w=200&fit=clip',\n        'https://www.kevinandamanda.com/wp-content/uploads/2014/09/amsterdam-2014-03.jpg',\n        'https://specials-images.forbesimg.com/imageserve/5de4a1db755ebf0006fbea42/960x0.jpg?cropX1=0&cropX2=2121&cropY1=0&cropY2=1414',\n      ],\n    },\n    ...new Array(count).fill(0).map((_, index) => ({\n      id: Faker.random.alphaNumeric(6),\n      name: `${Faker.address.city()}`,\n      address: `${Faker.address.state()}, ${Faker.address.country()}`,\n      photos: Array(5)\n        .fill(0)\n        .map((__, _index) => Faker.image.city(SCREEN_WIDTH + index + _index)),\n    })),\n  ];\n};\n"
  },
  {
    "path": "example/src/utilities/transformOrigin.ts",
    "content": "// @ts-ignore\nexport const transformOrigin = ({ x, y }, ...transformations) => {\n  'worklet';\n  return [\n    { translateX: x },\n    { translateY: y },\n    ...transformations,\n    { translateX: x * -1 },\n    { translateY: y * -1 },\n  ];\n};\n"
  },
  {
    "path": "example/tsconfig.json",
    "content": "{\n  \"extends\": \"expo/tsconfig.base\",\n  \"compilerOptions\": {\n    \"strict\": true,\n    \"paths\": {\n      \"@gorhom/bottom-sheet\": [\"../src/index\"]\n    },\n  }\n}\n"
  },
  {
    "path": "example/web/index.html",
    "content": "<!DOCTYPE html>\n<html lang=\"%LANG_ISO_CODE%\">\n  <head>\n    <meta charset=\"utf-8\" />\n    <meta httpEquiv=\"X-UA-Compatible\" content=\"IE=edge\" />\n    <!-- \n      This viewport works for phones with notches.\n      It's optimized for gestures by disabling global zoom.\n     -->\n    <meta\n      name=\"viewport\"\n      content=\"width=device-width, initial-scale=1, minimum-scale=1, maximum-scale=1.00001, viewport-fit=cover\"\n    />\n    <meta name=\"theme-color\" content=\"#fff\" media=\"(prefers-color-scheme: light)\">\n    <meta name=\"theme-color\" content=\"#000\" media=\"(prefers-color-scheme: dark)\">\n    <title>%WEB_TITLE%</title>\n    <style>\n      /**\n       * Extend the react-native-web reset:\n       * https://github.com/necolas/react-native-web/blob/master/packages/react-native-web/src/exports/StyleSheet/initialRules.js\n       */\n      html,\n      body,\n      #root {\n        width: 100%;\n        /* To smooth any scrolling behavior */\n        -webkit-overflow-scrolling: touch;\n        margin: 0px;\n        padding: 0px;\n        /* Allows content to fill the viewport and go beyond the bottom */\n        min-height: 100%;\n        background-color: #000;\n      }\n      #root {\n        flex-shrink: 0;\n        flex-basis: auto;\n        flex-grow: 1;\n        display: flex;\n        flex: 1;\n        background-color: #000;\n      }\n\n      html {\n        scroll-behavior: smooth;\n        /* Prevent text size change on orientation change https://gist.github.com/tfausak/2222823#file-ios-8-web-app-html-L138 */\n        -webkit-text-size-adjust: 100%;\n        height: calc(100% + env(safe-area-inset-top));\n      }\n\n      body {\n        display: flex;\n        /* Allows you to scroll below the viewport; default value is visible */\n        overflow-y: auto;\n        overscroll-behavior-y: none;\n        text-rendering: optimizeLegibility;\n        -webkit-font-smoothing: antialiased;\n        -moz-osx-font-smoothing: grayscale;\n        -ms-overflow-style: scrollbar;\n      }\n      /* Enable for apps that support dark-theme */\n      /*@media (prefers-color-scheme: dark) {\n        body {\n          background-color: black;\n        }\n      }*/\n    </style>\n  </head>\n\n  <body>\n    <!-- \n      A generic no script element with a reload button and a message.\n      Feel free to customize this however you'd like.\n    -->\n    <noscript>\n      <form\n        action=\"\"\n        style=\"\n          background-color: #fff;\n          position: fixed;\n          top: 0;\n          left: 0;\n          right: 0;\n          bottom: 0;\n          z-index: 9999;\n        \"\n      >\n        <div\n          style=\"\n            font-size: 18px;\n            font-family: Helvetica, sans-serif;\n            line-height: 24px;\n            margin: 10%;\n            width: 80%;\n          \"\n        >\n          <p>Oh no! It looks like JavaScript is not enabled in your browser.</p>\n          <p style=\"margin: 20px 0\">\n            <button\n              type=\"submit\"\n              style=\"\n                background-color: #4630eb;\n                border-radius: 100px;\n                border: none;\n                box-shadow: none;\n                color: #fff;\n                cursor: pointer;\n                font-weight: bold;\n                line-height: 20px;\n                padding: 6px 16px;\n              \"\n            >\n              Reload\n            </button>\n          </p>\n        </div>\n      </form>\n    </noscript>\n    <!-- The root element for your Expo app. -->\n    <div id=\"root\"></div>\n  </body>\n</html>\n"
  },
  {
    "path": "example/webpack.config.js",
    "content": "const createExpoWebpackConfigAsync = require('@expo/webpack-config');\nconst path = require('path');\n\nconst root = path.resolve(__dirname, '..');\nconst node_modules = path.join(__dirname, 'node_modules');\n\nmodule.exports = async function (env, argv) {\n  const config = await createExpoWebpackConfigAsync(\n    {\n      ...env,\n      babel: {\n        dangerouslyAddModulePathsToTranspile: ['react-native-reanimated'],\n      },\n    },\n    argv\n  );\n\n  config.module.rules.push({\n    test: /\\.(js|jsx|ts|tsx)$/,\n    include: path.resolve(root, 'src'),\n    use: 'babel-loader',\n  });\n\n  Object.assign(config.resolve.alias, {\n    react: path.join(node_modules, 'react'),\n    'react-native': path.join(node_modules, 'react-native'),\n    'react-native-web': path.join(node_modules, 'react-native-web'),\n    'react-native-reanimated': path.join(\n      node_modules,\n      'react-native-reanimated'\n    ),\n    'react-native-gesture-handler': path.join(\n      node_modules,\n      'react-native-gesture-handler'\n    ),\n  });\n\n  // Customize the config before returning it.\n  return config;\n};\n"
  },
  {
    "path": "lint-staged.config.js",
    "content": "module.exports = {\n  '*.{js,ts,cjs,mjs,d.cts,d.mts,jsx,tsx,json,jsonc}': [\n    'biome check --files-ignore-unknown=true', // Check formatting and lint\n    'biome check --write --no-errors-on-unmatched', // Format, sort imports, lint, and apply safe fixes\n    'biome check --write --unsafe --no-errors-on-unmatched', // Format, sort imports, lints, apply safe/unsafe fixes\n    'biome format --write --no-errors-on-unmatched', // Format\n    'biome lint --write --no-errors-on-unmatched', // Lint and apply safe fixes\n  ],\n  '*': [\n    'biome check --no-errors-on-unmatched --files-ignore-unknown=true', // Check formatting and lint\n  ],\n};\n"
  },
  {
    "path": "mock.js",
    "content": "/**\n * Mock implementation for test runners.\n *\n * Example:\n *\n * ```js\n * jest.mock('@gorhom/bottom-sheet', () => require('@gorhom/bottom-sheet/mock'));\n * ```\n */\n\nconst React = require('react');\nconst ReactNative = require('react-native');\n\nconst NOOP = () => {};\nconst NOOP_VALUE = { value: 0, set: NOOP, get: () => 0 };\n\nconst BottomSheetModalProvider = ({ children }) => {\n  return children;\n};\n\nconst BottomSheetBackdrop = NOOP;\n\nconst BottomSheetComponent = props => {\n  return props.children;\n};\n\nclass BottomSheetModal extends React.Component {\n  // Store mock data passed via present\n  data = null;\n\n  snapToIndex() {}\n  snapToPosition() {}\n  expand() {}\n  collapse() {}\n  close() {\n    this.data = null;\n  }\n  forceClose() {\n    this.data = null;\n  }\n  present(data) {\n    // Store data passed to present\n    this.data = data;\n    // Need to trigger a re-render somehow if component depends on this state,\n    // but for basic mock, just storing is often enough.\n  }\n  dismiss() {\n    this.data = null;\n  }\n\n  render() {\n    const { children: Content } = this.props;\n    return typeof Content === 'function'\n      ? React.createElement(Content, { data: this.data })\n      : Content;\n  }\n}\n\nclass BottomSheet extends React.Component {\n  snapToIndex() {}\n  snapToPosition() {}\n  expand() {}\n  collapse() {}\n  close() {}\n  forceClose() {}\n\n  render() {\n    return this.props.children;\n  }\n}\n\nconst useBottomSheet = () => ({\n  snapToIndex: NOOP,\n  snapToPosition: NOOP,\n  expand: NOOP,\n  collapse: NOOP,\n  close: NOOP,\n  forceClose: NOOP,\n\n  animatedIndex: NOOP_VALUE,\n  animatedPosition: NOOP_VALUE,\n});\n\nconst useBottomSheetModal = () => ({\n  dismiss: NOOP,\n  dismissAll: NOOP,\n});\n\nconst useBottomSheetAnimationConfigs = configs => configs;\n\nconst bottomSheetInternal = {\n  stopAnimation: NOOP,\n  animateToPosition: NOOP,\n  setScrollableRef: NOOP,\n  removeScrollableRef: NOOP,\n};\n\nconst bottomSheetModalInternal = {\n  mountSheet: NOOP,\n  unmountSheet: NOOP,\n  willUnmountSheet: NOOP,\n};\n\nconst internalProxy = {\n  get(target, prop) {\n    return prop in target ? target[prop] : NOOP_VALUE;\n  },\n};\n\nconst useBottomSheetInternal = () =>\n  new Proxy(bottomSheetInternal, internalProxy);\n\nconst useBottomSheetModalInternal = () =>\n  new Proxy(bottomSheetModalInternal, internalProxy);\n\nconst useBottomSheetDynamicSnapPoints = () => ({\n  animatedSnapPoints: NOOP_VALUE,\n  animatedHandleHeight: NOOP_VALUE,\n  animatedContentHeight: NOOP_VALUE,\n  handleContentLayout: NOOP,\n});\n\nconst GESTURE_SOURCE = {\n  UNDETERMINED: 0,\n  SCROLLABLE: 1,\n  HANDLE: 2,\n  CONTENT: 3,\n};\n\nconst SHEET_STATE = {\n  CLOSED: 0,\n  OPENED: 1,\n  EXTENDED: 2,\n  OVER_EXTENDED: 3,\n  FILL_PARENT: 4,\n};\n\nconst SCROLLABLE_STATE = {\n  LOCKED: 0,\n  UNLOCKED: 1,\n  UNDETERMINED: 2,\n};\n\nconst SCROLLABLE_TYPE = {\n  UNDETERMINED: 0,\n  VIEW: 1,\n  FLATLIST: 2,\n  SCROLLVIEW: 3,\n  SECTIONLIST: 4,\n  VIRTUALIZEDLIST: 5,\n};\n\nconst ANIMATION_STATE = {\n  UNDETERMINED: 0,\n  RUNNING: 1,\n  STOPPED: 2,\n  INTERRUPTED: 3,\n};\n\nconst ANIMATION_SOURCE = {\n  NONE: 0,\n  MOUNT: 1,\n  GESTURE: 2,\n  USER: 3,\n  CONTAINER_RESIZE: 4,\n  SNAP_POINT_CHANGE: 5,\n  KEYBOARD: 6,\n};\n\nconst ANIMATION_METHOD = {\n  TIMING: 0,\n  SPRING: 1,\n};\n\nconst KEYBOARD_STATE = {\n  UNDETERMINED: 0,\n  SHOWN: 1,\n  HIDDEN: 2,\n};\n\nconst SNAP_POINT_TYPE = {\n  PROVIDED: 0,\n  DYNAMIC: 1,\n};\n\nconst ENUMS = {\n  GESTURE_SOURCE,\n  SHEET_STATE,\n  SCROLLABLE_STATE,\n  SCROLLABLE_TYPE,\n  ANIMATION_STATE,\n  ANIMATION_SOURCE,\n  ANIMATION_METHOD,\n  KEYBOARD_STATE,\n  SNAP_POINT_TYPE,\n};\n\nconst createBottomSheetScrollableComponent = (_type, ScrollableComponent) => {\n  return ScrollableComponent;\n};\n\nmodule.exports = {\n  BottomSheetView: BottomSheetComponent,\n  BottomSheetTextInput: ReactNative.TextInput,\n  BottomSheetScrollView: ReactNative.ScrollView,\n  BottomSheetSectionList: ReactNative.SectionList,\n  BottomSheetFlatList: ReactNative.FlatList,\n  BottomSheetFlashList: ReactNative.FlatList,\n  BottomSheetVirtualizedList: ReactNative.VirtualizedList,\n\n  TouchableOpacity: ReactNative.TouchableOpacity,\n  TouchableHighlight: ReactNative.TouchableHighlight,\n  TouchableWithoutFeedback: ReactNative.TouchableWithoutFeedback,\n\n  BottomSheetModalProvider,\n  BottomSheetModal,\n  BottomSheetBackdrop,\n\n  default: BottomSheet,\n\n  useBottomSheet,\n  useBottomSheetModal,\n  useBottomSheetSpringConfigs: useBottomSheetAnimationConfigs,\n  useBottomSheetTimingConfigs: useBottomSheetAnimationConfigs,\n  useBottomSheetInternal,\n  useBottomSheetModalInternal,\n  useBottomSheetDynamicSnapPoints,\n\n  ...ENUMS,\n  createBottomSheetScrollableComponent,\n};\n"
  },
  {
    "path": "package.json",
    "content": "{\n  \"name\": \"@gorhom/bottom-sheet\",\n  \"version\": \"5.2.8\",\n  \"description\": \"A performant interactive bottom sheet with fully configurable options 🚀\",\n  \"main\": \"lib/commonjs/index\",\n  \"module\": \"lib/module/index\",\n  \"types\": \"lib/typescript/index.d.ts\",\n  \"react-native\": \"src/index.ts\",\n  \"source\": \"src/index.ts\",\n  \"files\": [\n    \"src\",\n    \"lib\",\n    \"mock.js\"\n  ],\n  \"keywords\": [\n    \"react-native\",\n    \"ios\",\n    \"android\",\n    \"web\",\n    \"bottom-sheet\",\n    \"bottomsheet\",\n    \"reanimated\",\n    \"sheet\"\n  ],\n  \"repository\": \"https://github.com/gorhom/react-native-bottom-sheet\",\n  \"author\": \"Mo Gorhom (https://gorhom.dev)\",\n  \"license\": \"MIT\",\n  \"bugs\": {\n    \"url\": \"https://github.com/gorhom/react-native-bottom-sheet/issues\"\n  },\n  \"homepage\": \"https://gorhom.dev/react-native-bottom-sheet/\",\n  \"scripts\": {\n    \"typescript\": \"tsc --skipLibCheck --noEmit\",\n    \"lint\": \"biome lint --error-on-warnings ./src\",\n    \"build\": \"bob build && yarn copy-dts && yarn delete-dts.js && yarn delete-debug-view\",\n    \"copy-dts\": \"copyfiles -u 1 \\\"src/**/*.d.ts\\\" lib/typescript\",\n    \"delete-debug-view\": \"rm -r ./lib/commonjs/components/bottomSheetDebugView && rm -r ./lib/module/components/bottomSheetDebugView && rm -r ./lib/typescript/components/bottomSheetDebugView\",\n    \"delete-dts.js\": \"find ./lib/commonjs -name '*.d.js*' -delete && find ./lib/module -name '*.d.js*' -delete\",\n    \"release\": \"rm -rf lib && yarn build && release-it\",\n    \"example\": \"yarn --cwd example\",\n    \"bootstrap\": \"yarn install && yarn example\"\n  },\n  \"dependencies\": {\n    \"@gorhom/portal\": \"1.0.14\",\n    \"invariant\": \"^2.2.4\"\n  },\n  \"devDependencies\": {\n    \"@biomejs/biome\": \"2.2.2\",\n    \"@commitlint/cli\": \"^19.8.1\",\n    \"@commitlint/config-conventional\": \"^19.8.1\",\n    \"@release-it/conventional-changelog\": \"^10.0.1\",\n    \"@types/invariant\": \"^2.2.34\",\n    \"@types/react\": \"~18.3.12\",\n    \"@types/react-native\": \"~0.73.0\",\n    \"copyfiles\": \"^2.4.1\",\n    \"husky\": \"^4.3.8\",\n    \"lint-staged\": \"^13.2.2\",\n    \"metro-react-native-babel-preset\": \"^0.77.0\",\n    \"react\": \"18.3.1\",\n    \"react-native\": \"0.76.0\",\n    \"react-native-builder-bob\": \"^0.30.3\",\n    \"react-native-gesture-handler\": \"~2.20.2\",\n    \"react-native-reanimated\": \"~3.19.1\",\n    \"release-it\": \"^19.0.4\",\n    \"typescript\": \"^5.8.3\"\n  },\n  \"peerDependencies\": {\n    \"@types/react\": \"*\",\n    \"@types/react-native\": \"*\",\n    \"react\": \"*\",\n    \"react-native\": \"*\",\n    \"react-native-gesture-handler\": \">=2.16.1\",\n    \"react-native-reanimated\": \">=3.16.0 || >=4.0.0-\"\n  },\n  \"peerDependenciesMeta\": {\n    \"@types/react-native\": {\n      \"optional\": true\n    },\n    \"@types/react\": {\n      \"optional\": true\n    }\n  },\n  \"react-native-builder-bob\": {\n    \"source\": \"src\",\n    \"output\": \"lib\",\n    \"targets\": [\n      \"commonjs\",\n      \"module\",\n      \"typescript\"\n    ]\n  },\n  \"resolutions\": {\n    \"conventional-changelog-conventionalcommits\": \"8.0.0\"\n  },\n  \"overrides\": {\n    \"conventional-changelog-conventionalcommits\": \"8.0.0\"\n  }\n}\n"
  },
  {
    "path": "src/components/bottomSheet/BottomSheet.tsx",
    "content": "import invariant from 'invariant';\nimport React, {\n  forwardRef,\n  memo,\n  useCallback,\n  useEffect,\n  useImperativeHandle,\n  useMemo,\n} from 'react';\nimport { Platform, StyleSheet } from 'react-native';\nimport { State } from 'react-native-gesture-handler';\nimport Animated, {\n  cancelAnimation,\n  Extrapolation,\n  interpolate,\n  ReduceMotion,\n  runOnJS,\n  runOnUI,\n  useAnimatedReaction,\n  useDerivedValue,\n  useReducedMotion,\n  useSharedValue,\n  type WithSpringConfig,\n  type WithTimingConfig,\n} from 'react-native-reanimated';\nimport {\n  ANIMATION_SOURCE,\n  ANIMATION_STATUS,\n  INITIAL_LAYOUT_VALUE,\n  KEYBOARD_BEHAVIOR,\n  KEYBOARD_BLUR_BEHAVIOR,\n  KEYBOARD_INPUT_MODE,\n  KEYBOARD_STATUS,\n  SHEET_STATE,\n  SNAP_POINT_TYPE,\n} from '../../constants';\nimport {\n  BottomSheetInternalProvider,\n  BottomSheetProvider,\n} from '../../contexts';\nimport {\n  useAnimatedDetents,\n  useAnimatedKeyboard,\n  useAnimatedLayout,\n  usePropsValidator,\n  useReactiveSharedValue,\n  useScrollable,\n  useStableCallback,\n} from '../../hooks';\nimport type { AnimationState, BottomSheetMethods } from '../../types';\nimport {\n  animate,\n  getKeyboardAnimationConfigs,\n  normalizeSnapPoint,\n  print,\n} from '../../utilities';\nimport { BottomSheetBackgroundContainer } from '../bottomSheetBackground';\n// import BottomSheetDebugView from '../bottomSheetDebugView';\nimport { BottomSheetFooterContainer } from '../bottomSheetFooter';\nimport BottomSheetGestureHandlersProvider from '../bottomSheetGestureHandlersProvider';\nimport {\n  BottomSheetHandle,\n  BottomSheetHandleContainer,\n} from '../bottomSheetHandle';\nimport { BottomSheetHostingContainer } from '../bottomSheetHostingContainer';\nimport { BottomSheetBody } from './BottomSheetBody';\nimport { BottomSheetContent } from './BottomSheetContent';\nimport {\n  DEFAULT_ACCESSIBILITY_LABEL,\n  DEFAULT_ACCESSIBILITY_ROLE,\n  DEFAULT_ACCESSIBLE,\n  DEFAULT_ANIMATE_ON_MOUNT,\n  DEFAULT_DYNAMIC_SIZING,\n  DEFAULT_ENABLE_BLUR_KEYBOARD_ON_GESTURE,\n  DEFAULT_ENABLE_CONTENT_PANNING_GESTURE,\n  DEFAULT_ENABLE_OVER_DRAG,\n  DEFAULT_ENABLE_PAN_DOWN_TO_CLOSE,\n  DEFAULT_KEYBOARD_BEHAVIOR,\n  DEFAULT_KEYBOARD_BLUR_BEHAVIOR,\n  DEFAULT_KEYBOARD_INDEX,\n  DEFAULT_KEYBOARD_INPUT_MODE,\n  DEFAULT_OVER_DRAG_RESISTANCE_FACTOR,\n  INITIAL_POSITION,\n  INITIAL_VALUE,\n} from './constants';\nimport type { AnimateToPositionType, BottomSheetProps } from './types';\n\nAnimated.addWhitelistedUIProps({\n  decelerationRate: true,\n});\n\ntype BottomSheet = BottomSheetMethods;\n\nconst BottomSheetComponent = forwardRef<BottomSheet, BottomSheetProps>(\n  function BottomSheet(props, ref) {\n    //#region extract props\n    const {\n      // animations configurations\n      animationConfigs: _providedAnimationConfigs,\n\n      // configurations\n      index: _providedIndex = 0,\n      snapPoints: _providedSnapPoints,\n      animateOnMount = DEFAULT_ANIMATE_ON_MOUNT,\n      enableContentPanningGesture = DEFAULT_ENABLE_CONTENT_PANNING_GESTURE,\n      enableHandlePanningGesture,\n      enableOverDrag = DEFAULT_ENABLE_OVER_DRAG,\n      enablePanDownToClose = DEFAULT_ENABLE_PAN_DOWN_TO_CLOSE,\n      enableDynamicSizing = DEFAULT_DYNAMIC_SIZING,\n      overDragResistanceFactor = DEFAULT_OVER_DRAG_RESISTANCE_FACTOR,\n      overrideReduceMotion: _providedOverrideReduceMotion,\n\n      // styles\n      style,\n      containerStyle: _providedContainerStyle,\n      backgroundStyle: _providedBackgroundStyle,\n      handleStyle: _providedHandleStyle,\n      handleIndicatorStyle: _providedHandleIndicatorStyle,\n\n      // hooks\n      gestureEventsHandlersHook,\n\n      // keyboard\n      keyboardBehavior = DEFAULT_KEYBOARD_BEHAVIOR,\n      keyboardBlurBehavior = DEFAULT_KEYBOARD_BLUR_BEHAVIOR,\n      android_keyboardInputMode = DEFAULT_KEYBOARD_INPUT_MODE,\n      enableBlurKeyboardOnGesture = DEFAULT_ENABLE_BLUR_KEYBOARD_ON_GESTURE,\n\n      // layout\n      containerLayoutState,\n      topInset = 0,\n      bottomInset = 0,\n      maxDynamicContentSize,\n      containerHeight,\n      containerOffset,\n\n      // animated callback shared values\n      animatedPosition: _providedAnimatedPosition,\n      animatedIndex: _providedAnimatedIndex,\n\n      // gestures\n      simultaneousHandlers: _providedSimultaneousHandlers,\n      waitFor: _providedWaitFor,\n      activeOffsetX: _providedActiveOffsetX,\n      activeOffsetY: _providedActiveOffsetY,\n      failOffsetX: _providedFailOffsetX,\n      failOffsetY: _providedFailOffsetY,\n\n      // callbacks\n      onChange: _providedOnChange,\n      onClose: _providedOnClose,\n      onAnimate: _providedOnAnimate,\n\n      // private\n      $modal = false,\n      detached = false,\n\n      // components\n      handleComponent = BottomSheetHandle,\n      backdropComponent: BackdropComponent,\n      backgroundComponent,\n      footerComponent,\n      children,\n\n      // accessibility\n      accessible: _providedAccessible = DEFAULT_ACCESSIBLE,\n      accessibilityLabel:\n        _providedAccessibilityLabel = DEFAULT_ACCESSIBILITY_LABEL,\n      accessibilityRole:\n        _providedAccessibilityRole = DEFAULT_ACCESSIBILITY_ROLE,\n    } = props;\n    //#endregion\n\n    //#region validate props\n    if (__DEV__) {\n      // biome-ignore lint/correctness/useHookAtTopLevel: used in development only.\n      usePropsValidator({\n        index: _providedIndex,\n        snapPoints: _providedSnapPoints,\n        enableDynamicSizing,\n        topInset,\n        bottomInset,\n        containerHeight,\n        containerOffset,\n      });\n    }\n    //#endregion\n\n    //#region layout variables\n    const animatedLayoutState = useAnimatedLayout(\n      containerLayoutState,\n      topInset,\n      bottomInset,\n      $modal,\n      handleComponent === null\n    );\n    const animatedDetentsState = useAnimatedDetents(\n      _providedSnapPoints,\n      animatedLayoutState,\n      enableDynamicSizing,\n      maxDynamicContentSize,\n      detached,\n      $modal,\n      bottomInset\n    );\n    const animatedSheetHeight = useDerivedValue(() => {\n      const { containerHeight } = animatedLayoutState.get();\n      const { highestDetentPosition } = animatedDetentsState.get();\n\n      if (highestDetentPosition === undefined) {\n        return INITIAL_LAYOUT_VALUE;\n      }\n\n      return containerHeight - highestDetentPosition;\n    }, [animatedLayoutState, animatedDetentsState]);\n    const animatedCurrentIndex = useReactiveSharedValue(\n      animateOnMount ? -1 : _providedIndex\n    );\n    const animatedPosition = useSharedValue(INITIAL_POSITION);\n\n    // conditional\n    const isAnimatedOnMount = useSharedValue(\n      !animateOnMount || _providedIndex === -1\n    );\n    const isLayoutCalculated = useDerivedValue(() => {\n      let isContainerHeightCalculated = false;\n      const { containerHeight, handleHeight } = animatedLayoutState.get();\n      //container height was provided.\n      if (containerHeight !== null || containerHeight !== undefined) {\n        isContainerHeightCalculated = true;\n      }\n      // container height did set.\n      if (containerHeight !== INITIAL_LAYOUT_VALUE) {\n        isContainerHeightCalculated = true;\n      }\n\n      let isHandleHeightCalculated = false;\n      // handle component is null.\n      if (handleComponent === null) {\n        isHandleHeightCalculated = true;\n      }\n      // handle height did set.\n      if (handleHeight !== INITIAL_LAYOUT_VALUE) {\n        isHandleHeightCalculated = true;\n      }\n\n      let isSnapPointsNormalized = false;\n      const { detents } = animatedDetentsState.get();\n      // the first snap point did normalized\n      if (detents) {\n        isSnapPointsNormalized = true;\n      }\n\n      return (\n        isContainerHeightCalculated &&\n        isHandleHeightCalculated &&\n        isSnapPointsNormalized\n      );\n    }, [animatedLayoutState, animatedDetentsState, handleComponent]);\n    const isInTemporaryPosition = useSharedValue(false);\n    const animatedContainerHeightDidChange = useSharedValue(false);\n\n    // gesture\n    const animatedContentGestureState = useSharedValue<State>(\n      State.UNDETERMINED\n    );\n    const animatedHandleGestureState = useSharedValue<State>(\n      State.UNDETERMINED\n    );\n    //#endregion\n\n    //#region hooks variables\n    // keyboard\n    const { state: animatedKeyboardState, textInputNodesRef } =\n      useAnimatedKeyboard();\n    const userReduceMotionSetting = useReducedMotion();\n    const reduceMotion = useMemo(() => {\n      return !_providedOverrideReduceMotion ||\n        _providedOverrideReduceMotion === ReduceMotion.System\n        ? userReduceMotionSetting\n        : _providedOverrideReduceMotion === ReduceMotion.Always;\n    }, [userReduceMotionSetting, _providedOverrideReduceMotion]);\n    //#endregion\n\n    //#region state/dynamic variables\n    // states\n    const animatedAnimationState = useSharedValue<AnimationState>({\n      status: ANIMATION_STATUS.UNDETERMINED,\n      source: ANIMATION_SOURCE.MOUNT,\n    });\n    const animatedSheetState = useDerivedValue(() => {\n      const { detents, closedDetentPosition } = animatedDetentsState.get();\n\n      if (\n        !detents ||\n        detents.length === 0 ||\n        closedDetentPosition === undefined\n      ) {\n        return SHEET_STATE.CLOSED;\n      }\n\n      // closed position = position >= container height\n      if (animatedPosition.value >= closedDetentPosition) {\n        return SHEET_STATE.CLOSED;\n      }\n\n      const { containerHeight } = animatedLayoutState.get();\n      // extended position = container height - sheet height\n      const extendedPosition = containerHeight - animatedSheetHeight.value;\n      if (animatedPosition.value === extendedPosition) {\n        return SHEET_STATE.EXTENDED;\n      }\n\n      // extended position with keyboard =\n      // container height - (sheet height + keyboard height in root container)\n      const keyboardHeightInContainer =\n        animatedKeyboardState.get().heightWithinContainer;\n      const extendedPositionWithKeyboard = Math.max(\n        0,\n        containerHeight -\n          (animatedSheetHeight.value + keyboardHeightInContainer)\n      );\n\n      // detect if keyboard is open and the sheet is in temporary position\n      if (\n        keyboardBehavior === KEYBOARD_BEHAVIOR.interactive &&\n        isInTemporaryPosition.value &&\n        animatedPosition.value === extendedPositionWithKeyboard\n      ) {\n        return SHEET_STATE.EXTENDED;\n      }\n\n      // fill parent = 0\n      if (animatedPosition.value === 0) {\n        return SHEET_STATE.FILL_PARENT;\n      }\n\n      // detect if position is below extended point\n      if (animatedPosition.value < extendedPosition) {\n        return SHEET_STATE.OVER_EXTENDED;\n      }\n\n      return SHEET_STATE.OPENED;\n    }, [\n      animatedLayoutState,\n      animatedDetentsState,\n      animatedKeyboardState,\n      animatedPosition,\n      animatedSheetHeight,\n      isInTemporaryPosition,\n      keyboardBehavior,\n    ]);\n    const {\n      state: animatedScrollableState,\n      status: animatedScrollableStatus,\n      setScrollableRef,\n      removeScrollableRef,\n    } = useScrollable(\n      enableContentPanningGesture,\n      animatedSheetState,\n      animatedKeyboardState,\n      animatedAnimationState\n    );\n    // dynamic\n    const animatedIndex = useDerivedValue(() => {\n      const { detents } = animatedDetentsState.get();\n      if (!detents || detents.length === 0) {\n        return -1;\n      }\n\n      const adjustedSnapPoints = detents.slice().reverse();\n      const adjustedSnapPointsIndexes = detents\n        .slice()\n        .map((_, index: number) => index)\n        .reverse();\n\n      const { containerHeight } = animatedLayoutState.get();\n      /**\n       * we add the close state index `-1`\n       */\n      adjustedSnapPoints.push(containerHeight);\n      adjustedSnapPointsIndexes.push(-1);\n\n      const currentIndex = isLayoutCalculated.value\n        ? interpolate(\n            animatedPosition.value,\n            adjustedSnapPoints,\n            adjustedSnapPointsIndexes,\n            Extrapolation.CLAMP\n          )\n        : -1;\n\n      const {\n        status: animationStatus,\n        source: animationSource,\n        nextIndex,\n        nextPosition,\n      } = animatedAnimationState.get();\n      /**\n       * if the sheet is currently running an animation by the keyboard opening,\n       * then we clamp the index on android with resize keyboard mode.\n       */\n      if (\n        android_keyboardInputMode === KEYBOARD_INPUT_MODE.adjustResize &&\n        animationStatus === ANIMATION_STATUS.RUNNING &&\n        animationSource === ANIMATION_SOURCE.KEYBOARD &&\n        isInTemporaryPosition.value\n      ) {\n        return Math.max(animatedCurrentIndex.value, currentIndex);\n      }\n\n      /**\n       * if the sheet is currently running an animation by snap point change - usually caused\n       * by dynamic content height -, then we return the next position index.\n       */\n      if (\n        animationStatus === ANIMATION_STATUS.RUNNING &&\n        animationSource === ANIMATION_SOURCE.SNAP_POINT_CHANGE &&\n        nextIndex !== undefined &&\n        nextPosition !== undefined\n      ) {\n        return nextIndex;\n      }\n\n      return currentIndex;\n    }, [\n      android_keyboardInputMode,\n      animatedAnimationState,\n      animatedLayoutState,\n      animatedCurrentIndex,\n      animatedPosition,\n      animatedDetentsState,\n      isInTemporaryPosition,\n      isLayoutCalculated,\n    ]);\n    //#endregion\n\n    //#region private methods\n    const handleOnChange = useCallback(\n      function handleOnChange(index: number, position: number) {\n        if (__DEV__) {\n          print({\n            component: 'BottomSheet',\n            method: 'handleOnChange',\n            category: 'callback',\n            params: {\n              index,\n              position,\n            },\n          });\n        }\n\n        if (!_providedOnChange) {\n          return;\n        }\n\n        const { dynamicDetentIndex } = animatedDetentsState.get();\n\n        _providedOnChange(\n          index,\n          position,\n          index === dynamicDetentIndex\n            ? SNAP_POINT_TYPE.DYNAMIC\n            : SNAP_POINT_TYPE.PROVIDED\n        );\n      },\n      [_providedOnChange, animatedDetentsState]\n    );\n    const handleOnAnimate = useCallback(\n      function handleOnAnimate(targetIndex: number, targetPosition: number) {\n        if (__DEV__) {\n          print({\n            component: 'BottomSheet',\n            method: 'handleOnAnimate',\n            category: 'callback',\n            params: {\n              toIndex: targetIndex,\n              toPosition: targetPosition,\n              fromIndex: animatedCurrentIndex.value,\n              fromPosition: animatedPosition.value,\n            },\n          });\n        }\n\n        if (targetIndex === animatedCurrentIndex.get()) {\n          return;\n        }\n\n        if (!_providedOnAnimate) {\n          return;\n        }\n\n        _providedOnAnimate(\n          animatedCurrentIndex.value,\n          targetIndex,\n          animatedPosition.value,\n          targetPosition\n        );\n      },\n      [_providedOnAnimate, animatedCurrentIndex, animatedPosition]\n    );\n    const handleOnClose = useCallback(\n      function handleOnClose() {\n        if (__DEV__) {\n          print({\n            component: 'BottomSheet',\n            method: 'handleOnClose',\n            category: 'callback',\n          });\n        }\n\n        if (!_providedOnClose) {\n          return;\n        }\n\n        _providedOnClose();\n      },\n      [_providedOnClose]\n    );\n    //#endregion\n\n    //#region animation\n    const stopAnimation = useCallback(() => {\n      'worklet';\n      cancelAnimation(animatedPosition);\n      animatedAnimationState.set({\n        status: ANIMATION_STATUS.STOPPED,\n        source: ANIMATION_SOURCE.NONE,\n      });\n    }, [animatedPosition, animatedAnimationState]);\n    const animateToPositionCompleted = useCallback(\n      function animateToPositionCompleted(isFinished?: boolean) {\n        'worklet';\n        if (!isFinished) {\n          return;\n        }\n\n        const { nextIndex, nextPosition } = animatedAnimationState.get();\n\n        if (__DEV__) {\n          runOnJS(print)({\n            component: 'BottomSheet',\n            method: 'animateToPositionCompleted',\n            params: {\n              currentIndex: animatedCurrentIndex.value,\n              nextIndex,\n              nextPosition,\n            },\n          });\n        }\n\n        if (nextIndex === undefined || nextPosition === undefined) {\n          return;\n        }\n\n        // callbacks\n        if (nextIndex !== animatedCurrentIndex.get()) {\n          runOnJS(handleOnChange)(nextIndex, nextPosition);\n        }\n\n        if (nextIndex === -1) {\n          runOnJS(handleOnClose)();\n        }\n\n        animatedCurrentIndex.set(nextIndex);\n\n        // reset values\n        animatedContainerHeightDidChange.set(false);\n        isAnimatedOnMount.set(true);\n        animatedAnimationState.set({\n          status: ANIMATION_STATUS.STOPPED,\n          source: ANIMATION_SOURCE.NONE,\n          nextIndex: undefined,\n          nextPosition: undefined,\n          isForcedClosing: undefined,\n        });\n      },\n      [\n        handleOnChange,\n        handleOnClose,\n        animatedCurrentIndex,\n        animatedAnimationState,\n        animatedContainerHeightDidChange,\n        isAnimatedOnMount,\n      ]\n    );\n    const animateToPosition: AnimateToPositionType = useCallback(\n      function animateToPosition(\n        position: number,\n        source: ANIMATION_SOURCE,\n        velocity = 0,\n        configs?: WithTimingConfig | WithSpringConfig\n      ) {\n        'worklet';\n        if (__DEV__) {\n          runOnJS(print)({\n            component: 'BottomSheet',\n            method: 'animateToPosition',\n            params: {\n              currentPosition: animatedPosition.value,\n              nextPosition: position,\n              source,\n            },\n          });\n        }\n\n        if (position === undefined) {\n          return;\n        }\n\n        if (position === animatedPosition.get()) {\n          return;\n        }\n\n        // early exit if there is a running animation to\n        // the same position\n        const { status: animationStatus, nextPosition } =\n          animatedAnimationState.get();\n        if (\n          animationStatus === ANIMATION_STATUS.RUNNING &&\n          position === nextPosition\n        ) {\n          return;\n        }\n\n        // stop animation if it is running\n        if (animationStatus === ANIMATION_STATUS.RUNNING) {\n          stopAnimation();\n        }\n\n        /**\n         * offset the position if keyboard is shown and behavior not extend.\n         */\n        let offset = 0;\n\n        const { status, heightWithinContainer } = animatedKeyboardState.get();\n        const sheetState = animatedSheetState.get();\n        if (\n          status === KEYBOARD_STATUS.SHOWN &&\n          keyboardBehavior !== KEYBOARD_BEHAVIOR.extend &&\n          ([\n            ANIMATION_SOURCE.KEYBOARD,\n            ANIMATION_SOURCE.SNAP_POINT_CHANGE,\n          ].includes(source) ||\n            sheetState === SHEET_STATE.OVER_EXTENDED)\n        ) {\n          offset = heightWithinContainer;\n        }\n        const { detents, closedDetentPosition, highestDetentPosition } =\n          animatedDetentsState.get();\n        let index = detents?.indexOf(position + offset) ?? -1;\n\n        /**\n         * because keyboard position is not part of the detents array,\n         * we will need to manually set the index to the highest detent index.\n         */\n        if (\n          index === -1 &&\n          status === KEYBOARD_STATUS.SHOWN &&\n          position !== closedDetentPosition\n        ) {\n          index = highestDetentPosition ?? DEFAULT_KEYBOARD_INDEX;\n        }\n\n        /**\n         * set the animation state\n         */\n        animatedAnimationState.set(state => {\n          'worklet';\n          return {\n            ...state,\n            status: ANIMATION_STATUS.RUNNING,\n            source,\n            nextIndex: index,\n            nextPosition: position,\n          };\n        });\n\n        /**\n         * fire `onAnimate` callback\n         */\n        runOnJS(handleOnAnimate)(index, position);\n\n        /**\n         * start animation\n         */\n        animatedPosition.value = animate({\n          point: position,\n          configs: configs || _providedAnimationConfigs,\n          velocity,\n          overrideReduceMotion: _providedOverrideReduceMotion,\n          onComplete: animateToPositionCompleted,\n        });\n      },\n      [\n        handleOnAnimate,\n        stopAnimation,\n        animateToPositionCompleted,\n        keyboardBehavior,\n        _providedAnimationConfigs,\n        _providedOverrideReduceMotion,\n        animatedDetentsState,\n        animatedAnimationState,\n        animatedKeyboardState,\n        animatedPosition,\n        animatedSheetState,\n      ]\n    );\n    /**\n     * Set to position without animation.\n     *\n     * @param targetPosition position to be set.\n     */\n    const setToPosition = useCallback(\n      function setToPosition(targetPosition: number) {\n        'worklet';\n        if (!targetPosition) {\n          return;\n        }\n\n        if (targetPosition === animatedPosition.get()) {\n          return;\n        }\n\n        const { status: animationStatus, nextPosition } =\n          animatedAnimationState.get();\n\n        // early exit if there is a running animation to\n        // the same position\n        if (\n          animationStatus === ANIMATION_STATUS.RUNNING &&\n          targetPosition === nextPosition\n        ) {\n          return;\n        }\n\n        if (__DEV__) {\n          runOnJS(print)({\n            component: 'BottomSheet',\n            method: 'setToPosition',\n            params: {\n              currentPosition: animatedPosition.value,\n              targetPosition,\n            },\n          });\n        }\n\n        /**\n         * store next position\n         */\n        const { detents } = animatedDetentsState.get();\n        const index = detents?.indexOf(targetPosition) ?? -1;\n        animatedAnimationState.set(state => {\n          'worklet';\n          return {\n            ...state,\n            nextPosition: targetPosition,\n            nextIndex: index,\n          };\n        });\n\n        stopAnimation();\n\n        // set values\n        animatedPosition.value = targetPosition;\n        animatedContainerHeightDidChange.value = false;\n      },\n      [\n        stopAnimation,\n        animatedPosition,\n        animatedContainerHeightDidChange,\n        animatedAnimationState,\n        animatedDetentsState,\n      ]\n    );\n    //#endregion\n\n    //#region private methods\n    /**\n     * Calculate and evaluate the current position based on multiple\n     * local states.\n     */\n    const getEvaluatedPosition = useCallback(\n      function getEvaluatedPosition(source: ANIMATION_SOURCE) {\n        'worklet';\n        const currentIndex = animatedCurrentIndex.value;\n        const { detents, highestDetentPosition, closedDetentPosition } =\n          animatedDetentsState.get();\n        const keyboardStatus = animatedKeyboardState.get().status;\n\n        if (\n          detents === undefined ||\n          highestDetentPosition === undefined ||\n          closedDetentPosition === undefined\n        ) {\n          return;\n        }\n\n        /**\n         * if the keyboard blur behavior is restore and keyboard is hidden,\n         * then we return the previous snap point.\n         */\n        if (\n          source === ANIMATION_SOURCE.KEYBOARD &&\n          keyboardBlurBehavior === KEYBOARD_BLUR_BEHAVIOR.restore &&\n          keyboardStatus === KEYBOARD_STATUS.HIDDEN &&\n          animatedContentGestureState.value !== State.ACTIVE &&\n          animatedHandleGestureState.value !== State.ACTIVE\n        ) {\n          isInTemporaryPosition.value = false;\n          const nextPosition = detents[currentIndex];\n          return nextPosition;\n        }\n\n        /**\n         * if the keyboard appearance behavior is extend and keyboard is shown,\n         * then we return the heights snap point.\n         */\n        if (\n          keyboardBehavior === KEYBOARD_BEHAVIOR.extend &&\n          keyboardStatus === KEYBOARD_STATUS.SHOWN\n        ) {\n          return highestDetentPosition;\n        }\n\n        /**\n         * if the keyboard appearance behavior is fill parent and keyboard is shown,\n         * then we return 0 ( full screen ).\n         */\n        if (\n          keyboardBehavior === KEYBOARD_BEHAVIOR.fillParent &&\n          keyboardStatus === KEYBOARD_STATUS.SHOWN\n        ) {\n          isInTemporaryPosition.value = true;\n          return 0;\n        }\n\n        /**\n         * if the keyboard appearance behavior is interactive and keyboard is shown,\n         * then we return the heights points minus the keyboard in container height.\n         */\n        if (\n          keyboardBehavior === KEYBOARD_BEHAVIOR.interactive &&\n          keyboardStatus === KEYBOARD_STATUS.SHOWN &&\n          // ensure that this logic does not run on android\n          // with resize input mode\n          !(\n            Platform.OS === 'android' &&\n            android_keyboardInputMode === 'adjustResize'\n          )\n        ) {\n          isInTemporaryPosition.value = true;\n          const keyboardHeightInContainer =\n            animatedKeyboardState.get().heightWithinContainer;\n          return Math.max(0, highestDetentPosition - keyboardHeightInContainer);\n        }\n\n        /**\n         * if the bottom sheet is in temporary position, then we return\n         * the current position.\n         */\n        if (isInTemporaryPosition.value) {\n          return animatedPosition.value;\n        }\n\n        /**\n         * if the bottom sheet did not animate on mount,\n         * then we return the provided index or the closed position.\n         */\n        if (!isAnimatedOnMount.value) {\n          return _providedIndex === -1\n            ? closedDetentPosition\n            : detents[_providedIndex];\n        }\n\n        const { status, nextIndex, nextPosition } =\n          animatedAnimationState.get();\n\n        /**\n         * if the evaluated position is for a snap change source while the sheet is currently running\n         * an animation and the next position is different than the detent at next index,\n         * then we return the detent at next index.\n         *\n         * https://github.com/gorhom/react-native-bottom-sheet/issues/2431\n         */\n        if (\n          source === ANIMATION_SOURCE.SNAP_POINT_CHANGE &&\n          status === ANIMATION_STATUS.RUNNING &&\n          nextIndex !== undefined &&\n          nextPosition !== undefined &&\n          detents[nextIndex] !== nextPosition\n        ) {\n          return detents[nextIndex];\n        }\n\n        /**\n         * return the current index position.\n         */\n        return detents[currentIndex];\n      },\n      [\n        animatedContentGestureState,\n        animatedCurrentIndex,\n        animatedHandleGestureState,\n        animatedAnimationState,\n        animatedKeyboardState,\n        animatedPosition,\n        animatedDetentsState,\n        isInTemporaryPosition,\n        isAnimatedOnMount,\n        keyboardBehavior,\n        keyboardBlurBehavior,\n        _providedIndex,\n        android_keyboardInputMode,\n      ]\n    );\n\n    /**\n     * Evaluate the bottom sheet position based based on a event source and other local states.\n     */\n    const evaluatePosition = useCallback(\n      function evaluatePosition(\n        source: ANIMATION_SOURCE,\n        animationConfigs?: WithSpringConfig | WithTimingConfig\n      ) {\n        'worklet';\n        const {\n          status: animationStatus,\n          nextIndex,\n          isForcedClosing,\n        } = animatedAnimationState.get();\n\n        const { detents, closedDetentPosition } = animatedDetentsState.get();\n        if (\n          detents === undefined ||\n          detents.length === 0 ||\n          closedDetentPosition === undefined\n        ) {\n          return;\n        }\n\n        /**\n         * if a force closing is running and source not from user, then we early exit\n         */\n        if (isForcedClosing && source !== ANIMATION_SOURCE.USER) {\n          return;\n        }\n        /**\n         * when evaluating the position while layout is not calculated, then we early exit till it is.\n         */\n        if (!isLayoutCalculated.value) {\n          return;\n        }\n\n        const proposedPosition = getEvaluatedPosition(source);\n        if (proposedPosition === undefined) {\n          return;\n        }\n\n        /**\n         * when evaluating the position while the mount animation not been handled,\n         * then we evaluate on mount use cases.\n         */\n        if (!isAnimatedOnMount.value) {\n          /**\n           * if animate on mount is set to true, then we animate to the propose position,\n           * else, we set the position with out animation.\n           */\n          if (animateOnMount) {\n            animateToPosition(\n              proposedPosition,\n              ANIMATION_SOURCE.MOUNT,\n              undefined,\n              animationConfigs\n            );\n          } else {\n            setToPosition(proposedPosition);\n            isAnimatedOnMount.value = true;\n          }\n          return;\n        }\n\n        /**\n         * when evaluating the position while the bottom sheet is animating.\n         */\n        if (animationStatus === ANIMATION_STATUS.RUNNING) {\n          const nextPositionIndex = nextIndex ?? INITIAL_VALUE;\n          /**\n           * when evaluating the position while the bottom sheet is\n           * closing, then we force closing the bottom sheet with no animation.\n           */\n          if (nextPositionIndex === -1 && !isInTemporaryPosition.value) {\n            setToPosition(closedDetentPosition);\n            return;\n          }\n\n          /**\n           * when evaluating the position while it's animating to\n           * a position other than the current position, then we\n           * restart the animation.\n           */\n          if (nextPositionIndex !== animatedCurrentIndex.value) {\n            animateToPosition(\n              detents[nextPositionIndex],\n              source,\n              undefined,\n              animationConfigs\n            );\n            return;\n          }\n        }\n\n        /**\n         * when evaluating the position while the bottom sheet is in closed\n         * position and not animating, we re-set the position to closed position.\n         */\n        if (\n          animationStatus !== ANIMATION_STATUS.RUNNING &&\n          animatedCurrentIndex.value === -1\n        ) {\n          /**\n           * early exit if reduce motion is enabled and index is out of sync with position.\n           */\n          if (\n            reduceMotion &&\n            detents[animatedIndex.value] !== animatedPosition.value\n          ) {\n            return;\n          }\n          setToPosition(closedDetentPosition);\n          return;\n        }\n\n        /**\n         * when evaluating the position after the container resize, then we\n         * force the bottom sheet to the proposed position with no\n         * animation.\n         */\n        if (animatedContainerHeightDidChange.value) {\n          setToPosition(proposedPosition);\n          return;\n        }\n\n        /**\n         * we fall back to the proposed position.\n         */\n        animateToPosition(\n          proposedPosition,\n          source,\n          undefined,\n          animationConfigs\n        );\n      },\n      [\n        getEvaluatedPosition,\n        animateToPosition,\n        setToPosition,\n        reduceMotion,\n        animateOnMount,\n        animatedAnimationState,\n        animatedContainerHeightDidChange,\n        animatedCurrentIndex,\n        animatedIndex,\n        animatedPosition,\n        animatedDetentsState,\n        isAnimatedOnMount,\n        isInTemporaryPosition,\n        isLayoutCalculated,\n      ]\n    );\n    //#endregion\n\n    //#region public methods\n    const handleSnapToIndex = useStableCallback(function handleSnapToIndex(\n      index: number,\n      animationConfigs?: WithSpringConfig | WithTimingConfig\n    ) {\n      const { detents } = animatedDetentsState.get();\n      const isLayoutReady = isLayoutCalculated.get();\n\n      if (detents === undefined || detents.length === 0) {\n        return;\n      }\n\n      // early exit if layout is not ready yet.\n      if (!isLayoutReady) {\n        return;\n      }\n\n      invariant(\n        index >= -1 && index <= detents.length - 1,\n        `'index' was provided but out of the provided snap points range! expected value to be between -1, ${\n          detents.length - 1\n        }`\n      );\n\n      if (__DEV__) {\n        print({\n          component: 'BottomSheet',\n          method: 'handleSnapToIndex',\n          params: {\n            index,\n          },\n        });\n      }\n\n      const targetPosition = detents[index];\n\n      /**\n       * exit method if :\n       * - layout is not calculated.\n       * - already animating to next position.\n       * - sheet is forced closing.\n       */\n      const { nextPosition, nextIndex, isForcedClosing } =\n        animatedAnimationState.get();\n      if (\n        !isLayoutCalculated.value ||\n        index === nextIndex ||\n        targetPosition === nextPosition ||\n        isForcedClosing\n      ) {\n        return;\n      }\n\n      /**\n       * reset temporary position boolean.\n       */\n      isInTemporaryPosition.value = false;\n\n      runOnUI(animateToPosition)(\n        targetPosition,\n        ANIMATION_SOURCE.USER,\n        0,\n        animationConfigs\n      );\n    });\n    const handleSnapToPosition = useCallback(\n      function handleSnapToPosition(\n        position: number | string,\n        animationConfigs?: WithSpringConfig | WithTimingConfig\n      ) {\n        'worklet';\n        if (__DEV__) {\n          print({\n            component: 'BottomSheet',\n            method: 'handleSnapToPosition',\n            params: {\n              position,\n            },\n          });\n        }\n\n        const { containerHeight } = animatedLayoutState.get();\n        /**\n         * normalized provided position.\n         */\n        const targetPosition = normalizeSnapPoint(position, containerHeight);\n\n        /**\n         * exit method if :\n         * - layout is not calculated.\n         * - already animating to next position.\n         * - sheet is forced closing.\n         */\n        const { nextPosition, isForcedClosing } = animatedAnimationState.get();\n        if (\n          !isLayoutCalculated ||\n          targetPosition === nextPosition ||\n          isForcedClosing\n        ) {\n          return;\n        }\n\n        /**\n         * mark the new position as temporary.\n         */\n        isInTemporaryPosition.value = true;\n\n        runOnUI(animateToPosition)(\n          targetPosition,\n          ANIMATION_SOURCE.USER,\n          0,\n          animationConfigs\n        );\n      },\n      [\n        animateToPosition,\n        isInTemporaryPosition,\n        isLayoutCalculated,\n        animatedLayoutState,\n        animatedAnimationState,\n      ]\n    );\n    const handleClose = useCallback(\n      function handleClose(\n        animationConfigs?: WithSpringConfig | WithTimingConfig\n      ) {\n        if (__DEV__) {\n          print({\n            component: 'BottomSheet',\n            method: 'handleClose',\n          });\n        }\n\n        const closedDetentPosition =\n          animatedDetentsState.get().closedDetentPosition;\n        if (closedDetentPosition === undefined) {\n          return;\n        }\n\n        const targetPosition = closedDetentPosition;\n\n        /**\n         * exit method if :\n         * - layout is not calculated.\n         * - already animating to next position.\n         * - sheet is forced closing.\n         */\n        const { nextPosition, isForcedClosing } = animatedAnimationState.get();\n        if (\n          !isLayoutCalculated.value ||\n          targetPosition === nextPosition ||\n          isForcedClosing\n        ) {\n          return;\n        }\n\n        /**\n         * reset temporary position variable.\n         */\n        isInTemporaryPosition.value = false;\n\n        runOnUI(animateToPosition)(\n          targetPosition,\n          ANIMATION_SOURCE.USER,\n          0,\n          animationConfigs\n        );\n      },\n      [\n        animateToPosition,\n        isLayoutCalculated,\n        isInTemporaryPosition,\n        animatedDetentsState,\n        animatedAnimationState,\n      ]\n    );\n    const handleForceClose = useCallback(\n      function handleForceClose(\n        animationConfigs?: WithSpringConfig | WithTimingConfig\n      ) {\n        if (__DEV__) {\n          print({\n            component: 'BottomSheet',\n            method: 'handleForceClose',\n          });\n        }\n\n        const closedDetentPosition =\n          animatedDetentsState.get().closedDetentPosition;\n        if (closedDetentPosition === undefined) {\n          return;\n        }\n\n        const targetPosition = closedDetentPosition;\n\n        /**\n         * exit method if :\n         * - already animating to next position.\n         * - sheet is forced closing.\n         */\n        const { nextPosition, isForcedClosing } = animatedAnimationState.get();\n        if (targetPosition === nextPosition || isForcedClosing) {\n          return;\n        }\n\n        /**\n         * reset temporary position variable.\n         */\n        isInTemporaryPosition.value = false;\n\n        /**\n         * set force closing variable.\n         */\n        animatedAnimationState.set(state => {\n          'worklet';\n          return {\n            ...state,\n            isForcedClosing: true,\n          };\n        });\n\n        runOnUI(animateToPosition)(\n          targetPosition,\n          ANIMATION_SOURCE.USER,\n          0,\n          animationConfigs\n        );\n      },\n      [\n        animateToPosition,\n        isInTemporaryPosition,\n        animatedDetentsState,\n        animatedAnimationState,\n      ]\n    );\n    const handleExpand = useCallback(\n      function handleExpand(\n        animationConfigs?: WithSpringConfig | WithTimingConfig\n      ) {\n        if (__DEV__) {\n          print({\n            component: 'BottomSheet',\n            method: 'handleExpand',\n          });\n        }\n\n        const { detents } = animatedDetentsState.get();\n        if (detents === undefined || detents.length === 0) {\n          return;\n        }\n\n        const targetIndex = detents.length - 1;\n        const targetPosition = detents[targetIndex];\n\n        /**\n         * exit method if :\n         * - layout is not calculated.\n         * - already animating to next position.\n         * - sheet is forced closing.\n         */\n        const { nextPosition, nextIndex, isForcedClosing } =\n          animatedAnimationState.get();\n        if (\n          !isLayoutCalculated.value ||\n          targetIndex === nextIndex ||\n          targetPosition === nextPosition ||\n          isForcedClosing\n        ) {\n          return;\n        }\n\n        /**\n         * reset temporary position boolean.\n         */\n        isInTemporaryPosition.value = false;\n\n        runOnUI(animateToPosition)(\n          targetPosition,\n          ANIMATION_SOURCE.USER,\n          0,\n          animationConfigs\n        );\n      },\n      [\n        animateToPosition,\n        isInTemporaryPosition,\n        isLayoutCalculated,\n        animatedDetentsState,\n        animatedAnimationState,\n      ]\n    );\n    const handleCollapse = useCallback(\n      function handleCollapse(\n        animationConfigs?: WithSpringConfig | WithTimingConfig\n      ) {\n        if (__DEV__) {\n          print({\n            component: 'BottomSheet',\n            method: 'handleCollapse',\n          });\n        }\n\n        const { detents } = animatedDetentsState.get();\n        if (detents === undefined || detents.length === 0) {\n          return;\n        }\n\n        const targetPosition = detents[0];\n\n        /**\n         * exit method if :\n         * - layout is not calculated.\n         * - already animating to next position.\n         * - sheet is forced closing.\n         */\n        const { nextPosition, nextIndex, isForcedClosing } =\n          animatedAnimationState.get();\n        if (\n          !isLayoutCalculated ||\n          nextIndex === 0 ||\n          targetPosition === nextPosition ||\n          isForcedClosing\n        ) {\n          return;\n        }\n\n        /**\n         * reset temporary position boolean.\n         */\n        isInTemporaryPosition.value = false;\n\n        runOnUI(animateToPosition)(\n          targetPosition,\n          ANIMATION_SOURCE.USER,\n          0,\n          animationConfigs\n        );\n      },\n      [\n        animateToPosition,\n        isLayoutCalculated,\n        isInTemporaryPosition,\n        animatedDetentsState,\n        animatedAnimationState,\n      ]\n    );\n\n    useImperativeHandle(ref, () => ({\n      snapToIndex: handleSnapToIndex,\n      snapToPosition: handleSnapToPosition,\n      expand: handleExpand,\n      collapse: handleCollapse,\n      close: handleClose,\n      forceClose: handleForceClose,\n    }));\n    //#endregion\n\n    //#region contexts variables\n    const internalContextVariables = useMemo(\n      () => ({\n        textInputNodesRef,\n        enableContentPanningGesture,\n        enableDynamicSizing,\n        overDragResistanceFactor,\n        enableOverDrag,\n        enablePanDownToClose,\n        animatedAnimationState,\n        animatedSheetState,\n        animatedScrollableState,\n        animatedScrollableStatus,\n        animatedContentGestureState,\n        animatedHandleGestureState,\n        animatedKeyboardState,\n        animatedLayoutState,\n        animatedIndex,\n        animatedPosition,\n        animatedSheetHeight,\n        animatedDetentsState,\n        isInTemporaryPosition,\n        simultaneousHandlers: _providedSimultaneousHandlers,\n        waitFor: _providedWaitFor,\n        activeOffsetX: _providedActiveOffsetX,\n        activeOffsetY: _providedActiveOffsetY,\n        failOffsetX: _providedFailOffsetX,\n        failOffsetY: _providedFailOffsetY,\n        enableBlurKeyboardOnGesture,\n        animateToPosition,\n        stopAnimation,\n        setScrollableRef,\n        removeScrollableRef,\n      }),\n      [\n        textInputNodesRef,\n        animatedIndex,\n        animatedPosition,\n        animatedSheetHeight,\n        animatedLayoutState,\n        animatedContentGestureState,\n        animatedHandleGestureState,\n        animatedAnimationState,\n        animatedKeyboardState,\n        animatedSheetState,\n        animatedScrollableState,\n        animatedScrollableStatus,\n        animatedDetentsState,\n        isInTemporaryPosition,\n        enableContentPanningGesture,\n        overDragResistanceFactor,\n        enableOverDrag,\n        enablePanDownToClose,\n        enableDynamicSizing,\n        enableBlurKeyboardOnGesture,\n        _providedSimultaneousHandlers,\n        _providedWaitFor,\n        _providedActiveOffsetX,\n        _providedActiveOffsetY,\n        _providedFailOffsetX,\n        _providedFailOffsetY,\n        setScrollableRef,\n        removeScrollableRef,\n        animateToPosition,\n        stopAnimation,\n      ]\n    );\n    const externalContextVariables = useMemo(\n      () => ({\n        animatedIndex,\n        animatedPosition,\n        snapToIndex: handleSnapToIndex,\n        snapToPosition: handleSnapToPosition,\n        expand: handleExpand,\n        collapse: handleCollapse,\n        close: handleClose,\n        forceClose: handleForceClose,\n      }),\n      [\n        animatedIndex,\n        animatedPosition,\n        handleSnapToIndex,\n        handleSnapToPosition,\n        handleExpand,\n        handleCollapse,\n        handleClose,\n        handleForceClose,\n      ]\n    );\n    //#endregion\n\n    //#region effects\n    useAnimatedReaction(\n      () => animatedLayoutState.get().containerHeight,\n      (result, previous) => {\n        if (result === INITIAL_LAYOUT_VALUE) {\n          return;\n        }\n\n        animatedContainerHeightDidChange.value = result !== previous;\n\n        const { closedDetentPosition } = animatedDetentsState.get();\n        if (closedDetentPosition === undefined) {\n          return;\n        }\n\n        /**\n         * When user close the bottom sheet while the keyboard open on Android with\n         * software keyboard layout mode set to resize, the close position would be\n         * set to the container height - the keyboard height, and when the keyboard\n         * closes, the container height and here we restart the animation again.\n         *\n         * [read more](https://github.com/gorhom/react-native-bottom-sheet/issues/2163)\n         */\n        const {\n          status: animationStatus,\n          source: animationSource,\n          nextIndex,\n        } = animatedAnimationState.get();\n        if (\n          animationStatus === ANIMATION_STATUS.RUNNING &&\n          animationSource === ANIMATION_SOURCE.GESTURE &&\n          nextIndex === -1\n        ) {\n          animateToPosition(closedDetentPosition, ANIMATION_SOURCE.GESTURE);\n        }\n      },\n      [\n        animatedContainerHeightDidChange,\n        animatedAnimationState,\n        animatedDetentsState,\n      ]\n    );\n\n    /**\n     * Reaction to the `snapPoints` change, to insure that the sheet position reflect\n     * to the current point correctly.\n     *\n     * @alias OnSnapPointsChange\n     */\n    useAnimatedReaction(\n      () => animatedDetentsState.get().detents,\n      (result, previous) => {\n        /**\n         * if values did not change, and did handle on mount animation\n         * then we early exit the method.\n         */\n        if (\n          JSON.stringify(result) === JSON.stringify(previous) &&\n          isAnimatedOnMount.value\n        ) {\n          return;\n        }\n\n        /**\n         * if layout is not calculated yet, then we exit the method.\n         */\n        if (!isLayoutCalculated.value) {\n          return;\n        }\n\n        if (__DEV__) {\n          runOnJS(print)({\n            component: 'BottomSheet',\n            method: 'useAnimatedReaction::OnSnapPointChange',\n            category: 'effect',\n            params: {\n              result,\n            },\n          });\n        }\n\n        evaluatePosition(ANIMATION_SOURCE.SNAP_POINT_CHANGE);\n      },\n      [isLayoutCalculated, isAnimatedOnMount, animatedDetentsState]\n    );\n\n    /**\n     * Reaction to the keyboard state change.\n     *\n     * @alias OnKeyboardStateChange\n     */\n    useAnimatedReaction(\n      () =>\n        animatedKeyboardState.get().status + animatedKeyboardState.get().height,\n      (result, _previousResult) => {\n        /**\n         * if keyboard state is equal to the previous state, then exit the method\n         */\n        if (result === _previousResult) {\n          return;\n        }\n\n        const { status, height, easing, duration, target } =\n          animatedKeyboardState.get();\n\n        /**\n         * if state is undetermined, then we early exit.\n         */\n        if (status === KEYBOARD_STATUS.UNDETERMINED) {\n          return;\n        }\n\n        const { status: animationStatus, source: animationSource } =\n          animatedAnimationState.get();\n        /**\n         * if keyboard is hidden by customer gesture, then we early exit.\n         */\n        if (\n          status === KEYBOARD_STATUS.HIDDEN &&\n          animationStatus === ANIMATION_STATUS.RUNNING &&\n          animationSource === ANIMATION_SOURCE.GESTURE\n        ) {\n          return;\n        }\n\n        /**\n         * Calculate the keyboard height in the container.\n         */\n        const containerOffset = animatedLayoutState.get().containerOffset;\n        let heightWithinContainer =\n          height === 0\n            ? 0\n            : $modal\n              ? Math.abs(\n                  height - Math.abs(bottomInset - containerOffset.bottom)\n                )\n              : Math.abs(height - containerOffset.bottom);\n\n        if (__DEV__) {\n          runOnJS(print)({\n            component: 'BottomSheet',\n            method: 'useAnimatedReaction::OnKeyboardStateChange',\n            category: 'effect',\n            params: {\n              status,\n              height,\n              heightWithinContainer,\n              containerOffset,\n            },\n          });\n        }\n\n        /**\n         * if platform is android and the input mode is resize, then exit the method\n         */\n        if (\n          Platform.OS === 'android' &&\n          android_keyboardInputMode === KEYBOARD_INPUT_MODE.adjustResize\n        ) {\n          heightWithinContainer = 0;\n\n          if (keyboardBehavior === KEYBOARD_BEHAVIOR.interactive) {\n            animatedKeyboardState.set({\n              target,\n              status,\n              height,\n              easing,\n              duration,\n              heightWithinContainer,\n            });\n            return;\n          }\n        }\n        animatedKeyboardState.set(state => ({\n          ...state,\n          heightWithinContainer,\n        }));\n\n        /**\n         * if user is interacting with sheet, then exit the method\n         */\n        const hasActiveGesture =\n          animatedContentGestureState.value === State.ACTIVE ||\n          animatedContentGestureState.value === State.BEGAN ||\n          animatedHandleGestureState.value === State.ACTIVE ||\n          animatedHandleGestureState.value === State.BEGAN;\n        if (hasActiveGesture) {\n          return;\n        }\n\n        /**\n         * if new keyboard state is hidden and blur behavior is none, then exit the method\n         */\n        if (\n          status === KEYBOARD_STATUS.HIDDEN &&\n          keyboardBlurBehavior === KEYBOARD_BLUR_BEHAVIOR.none\n        ) {\n          return;\n        }\n\n        const animationConfigs = getKeyboardAnimationConfigs(easing, duration);\n        evaluatePosition(ANIMATION_SOURCE.KEYBOARD, animationConfigs);\n      },\n      [\n        $modal,\n        bottomInset,\n        keyboardBehavior,\n        keyboardBlurBehavior,\n        android_keyboardInputMode,\n        animatedKeyboardState,\n        animatedLayoutState,\n        getEvaluatedPosition,\n      ]\n    );\n\n    /**\n     * sets provided animated position\n     */\n    useAnimatedReaction(\n      () => animatedPosition.value,\n      _animatedPosition => {\n        if (_providedAnimatedPosition) {\n          _providedAnimatedPosition.value = _animatedPosition + topInset;\n        }\n      },\n      [_providedAnimatedPosition, topInset]\n    );\n\n    /**\n     * sets provided animated index\n     */\n    useAnimatedReaction(\n      () => animatedIndex.value,\n      _animatedIndex => {\n        if (_providedAnimatedIndex) {\n          _providedAnimatedIndex.value = _animatedIndex;\n        }\n      },\n      [_providedAnimatedIndex]\n    );\n\n    /**\n     * React to `index` prop to snap the sheet to the new position.\n     *\n     * @alias onIndexChange\n     */\n    useEffect(() => {\n      // early exit, if animate on mount is set and it did not animate yet.\n      if (animateOnMount && !isAnimatedOnMount.value) {\n        return;\n      }\n\n      handleSnapToIndex(_providedIndex);\n    }, [animateOnMount, _providedIndex, isAnimatedOnMount, handleSnapToIndex]);\n    //#endregion\n\n    // render\n    return (\n      <BottomSheetProvider value={externalContextVariables}>\n        <BottomSheetInternalProvider value={internalContextVariables}>\n          <BottomSheetGestureHandlersProvider\n            gestureEventsHandlersHook={gestureEventsHandlersHook}\n          >\n            {BackdropComponent ? (\n              <BackdropComponent\n                animatedIndex={animatedIndex}\n                animatedPosition={animatedPosition}\n                style={StyleSheet.absoluteFillObject}\n              />\n            ) : null}\n            <BottomSheetHostingContainer\n              key=\"BottomSheetContainer\"\n              shouldCalculateHeight={!$modal}\n              layoutState={animatedLayoutState}\n              containerLayoutState={containerLayoutState}\n              topInset={topInset}\n              bottomInset={bottomInset}\n              detached={detached}\n              style={_providedContainerStyle}\n            >\n              <BottomSheetBody style={style}>\n                {backgroundComponent === null ? null : (\n                  <BottomSheetBackgroundContainer\n                    key=\"BottomSheetBackgroundContainer\"\n                    animatedIndex={animatedIndex}\n                    animatedPosition={animatedPosition}\n                    backgroundComponent={backgroundComponent}\n                    backgroundStyle={_providedBackgroundStyle}\n                  />\n                )}\n                <BottomSheetContent\n                  pointerEvents=\"box-none\"\n                  accessible={_providedAccessible ?? undefined}\n                  accessibilityRole={_providedAccessibilityRole ?? undefined}\n                  accessibilityLabel={_providedAccessibilityLabel ?? undefined}\n                  keyboardBehavior={keyboardBehavior}\n                  detached={detached}\n                >\n                  {children}\n                  {footerComponent ? (\n                    <BottomSheetFooterContainer\n                      footerComponent={footerComponent}\n                    />\n                  ) : null}\n                </BottomSheetContent>\n                {handleComponent !== null ? (\n                  <BottomSheetHandleContainer\n                    key=\"BottomSheetHandleContainer\"\n                    animatedIndex={animatedIndex}\n                    animatedPosition={animatedPosition}\n                    enableHandlePanningGesture={enableHandlePanningGesture}\n                    enableOverDrag={enableOverDrag}\n                    enablePanDownToClose={enablePanDownToClose}\n                    overDragResistanceFactor={overDragResistanceFactor}\n                    keyboardBehavior={keyboardBehavior}\n                    handleComponent={handleComponent}\n                    handleStyle={_providedHandleStyle}\n                    handleIndicatorStyle={_providedHandleIndicatorStyle}\n                  />\n                ) : null}\n              </BottomSheetBody>\n              {/* <BottomSheetDebugView\n                values={{\n                  index: animatedIndex,\n                  position: animatedPosition,\n                  sheetStatus: animatedSheetState,\n                  scrollableStatus: animatedScrollableStatus,\n                  layoutState: animatedLayoutState,\n                  detentsState: animatedDetentsState,\n                  sheetHeight: animatedSheetHeight,\n                  isLayoutCalculated,\n                }}\n              /> */}\n            </BottomSheetHostingContainer>\n          </BottomSheetGestureHandlersProvider>\n        </BottomSheetInternalProvider>\n      </BottomSheetProvider>\n    );\n  }\n);\n\nconst BottomSheet = memo(BottomSheetComponent);\nBottomSheet.displayName = 'BottomSheet';\n\nexport default BottomSheet;\n"
  },
  {
    "path": "src/components/bottomSheet/BottomSheetBody.tsx",
    "content": "import React, { memo, useMemo } from 'react';\nimport { Platform } from 'react-native';\nimport Animated, { useAnimatedStyle } from 'react-native-reanimated';\nimport { useBottomSheetInternal } from '../../hooks';\nimport type { BottomSheetProps } from '../bottomSheet/types';\nimport { styles } from './styles';\n\ntype BottomSheetBodyProps = {\n  style?: BottomSheetProps['style'];\n  children?: React.ReactNode;\n};\n\nfunction BottomSheetBodyComponent({ style, children }: BottomSheetBodyProps) {\n  //#region hooks\n  const { animatedIndex, animatedPosition } = useBottomSheetInternal();\n  //#endregion\n\n  //#region styles\n  const containerAnimatedStyle = useAnimatedStyle(\n    () => ({\n      opacity: Platform.OS === 'android' && animatedIndex.get() === -1 ? 0 : 1,\n      transform: [\n        {\n          translateY: animatedPosition.get(),\n        },\n      ],\n    }),\n    [animatedPosition, animatedIndex]\n  );\n  const containerStyle = useMemo(\n    () => [style, styles.container, containerAnimatedStyle],\n    [style, containerAnimatedStyle]\n  );\n  //#endregion\n\n  return (\n    <Animated.View style={containerStyle} collapsable={true}>\n      {children}\n    </Animated.View>\n  );\n}\n\nexport const BottomSheetBody = memo(BottomSheetBodyComponent);\nBottomSheetBody.displayName = 'BottomSheetBody';\n"
  },
  {
    "path": "src/components/bottomSheet/BottomSheetContent.tsx",
    "content": "import React, { memo, useMemo } from 'react';\nimport type { ViewProps, ViewStyle } from 'react-native';\nimport Animated, {\n  type AnimatedStyle,\n  useAnimatedStyle,\n  useDerivedValue,\n} from 'react-native-reanimated';\nimport {\n  INITIAL_LAYOUT_VALUE,\n  KEYBOARD_BEHAVIOR,\n  KEYBOARD_STATUS,\n} from '../../constants';\nimport { useBottomSheetInternal } from '../../hooks';\nimport type { NullableAccessibilityProps } from '../../types';\nimport { animate } from '../../utilities';\nimport BottomSheetDraggableView from '../bottomSheetDraggableView';\nimport {} from './constants';\nimport type { BottomSheetProps } from './types';\n\ntype BottomSheetContent = {\n  style?: AnimatedStyle<ViewStyle>;\n} & Pick<\n  BottomSheetProps,\n  | 'children'\n  | 'detached'\n  | 'animationConfigs'\n  | 'overrideReduceMotion'\n  | 'keyboardBehavior'\n> &\n  NullableAccessibilityProps &\n  ViewProps;\n\nfunction BottomSheetContentComponent({\n  detached,\n  animationConfigs,\n  overrideReduceMotion,\n  keyboardBehavior,\n  accessible,\n  accessibilityLabel,\n  accessibilityHint,\n  accessibilityRole,\n  children,\n}: BottomSheetContent) {\n  //#region hooks\n  const {\n    enableDynamicSizing,\n    overDragResistanceFactor,\n    enableContentPanningGesture,\n    animatedPosition,\n    animatedLayoutState,\n    animatedDetentsState,\n    animatedSheetHeight,\n    animatedKeyboardState,\n    isInTemporaryPosition,\n  } = useBottomSheetInternal();\n  //#endregion\n\n  //#region variables\n  const animatedContentHeightMax = useDerivedValue(() => {\n    const { containerHeight, handleHeight } = animatedLayoutState.get();\n\n    /**\n     * if container height is not yet calculated, then we exit the method\n     */\n    if (containerHeight === INITIAL_LAYOUT_VALUE) {\n      return 0;\n    }\n\n    const {\n      status: keyboardStatus,\n      heightWithinContainer: keyboardHeightWithinContainer,\n    } = animatedKeyboardState.get();\n\n    let contentHeight = animatedSheetHeight.get() - Math.max(0, handleHeight);\n\n    switch (keyboardBehavior) {\n      case KEYBOARD_BEHAVIOR.extend:\n        if (keyboardStatus === KEYBOARD_STATUS.SHOWN) {\n          contentHeight = contentHeight - keyboardHeightWithinContainer;\n        }\n        break;\n\n      case KEYBOARD_BEHAVIOR.fillParent:\n        if (!isInTemporaryPosition.get()) {\n          break;\n        }\n\n        if (keyboardStatus === KEYBOARD_STATUS.SHOWN) {\n          contentHeight =\n            containerHeight - handleHeight - keyboardHeightWithinContainer;\n        } else {\n          contentHeight = containerHeight - handleHeight;\n        }\n        break;\n\n      case KEYBOARD_BEHAVIOR.interactive: {\n        if (!isInTemporaryPosition.get()) {\n          break;\n        }\n        const contentWithKeyboardHeight =\n          contentHeight + keyboardHeightWithinContainer;\n\n        if (keyboardStatus === KEYBOARD_STATUS.SHOWN) {\n          if (\n            keyboardHeightWithinContainer + animatedSheetHeight.get() >\n            containerHeight\n          ) {\n            contentHeight =\n              containerHeight - keyboardHeightWithinContainer - handleHeight;\n          }\n        } else if (contentWithKeyboardHeight + handleHeight > containerHeight) {\n          contentHeight = containerHeight - handleHeight;\n        } else {\n          contentHeight = contentWithKeyboardHeight;\n        }\n        break;\n      }\n    }\n\n    /**\n     * before the container is measured, `contentHeight` value will be below zero,\n     * which will lead to freeze the scrollable.\n     *\n     * @link (https://github.com/gorhom/react-native-bottom-sheet/issues/470)\n     */\n    return Math.max(contentHeight, 0);\n  }, [\n    animatedLayoutState,\n    animatedKeyboardState,\n    animatedSheetHeight,\n    isInTemporaryPosition,\n    keyboardBehavior,\n  ]);\n  const animatedPaddingBottom = useDerivedValue(() => {\n    const containerHeight = animatedLayoutState.get().containerHeight;\n    /**\n     * if container height is not yet calculated, then we exit the method\n     */\n    if (containerHeight === INITIAL_LAYOUT_VALUE) {\n      return 0;\n    }\n\n    const { highestDetentPosition } = animatedDetentsState.get();\n\n    const highestSnapPoint = Math.max(\n      highestDetentPosition ?? 0,\n      animatedPosition.get()\n    );\n    /**\n     * added safe area to prevent the sheet from floating above\n     * the bottom of the screen, when sheet being over dragged or\n     * when the sheet is resized.\n     */\n    const overDragSafePaddingBottom =\n      Math.sqrt(highestSnapPoint - containerHeight * -1) *\n      overDragResistanceFactor;\n\n    let paddingBottom = overDragSafePaddingBottom;\n\n    /**\n     * if keyboard is open, then we try to add padding to prevent content\n     * from being covered by the keyboard.\n     */\n    const {\n      status: keyboardStatus,\n      heightWithinContainer: keyboardHeightWithinContainer,\n    } = animatedKeyboardState.get();\n    if (keyboardStatus === KEYBOARD_STATUS.SHOWN) {\n      paddingBottom = overDragSafePaddingBottom + keyboardHeightWithinContainer;\n    }\n\n    return paddingBottom;\n  }, [\n    overDragResistanceFactor,\n    animatedPosition,\n    animatedLayoutState,\n    animatedDetentsState,\n    animatedKeyboardState,\n  ]);\n  //#endregion\n\n  //#region styles\n  const contentMaskContainerAnimatedStyle = useAnimatedStyle(() => {\n    const { containerHeight, contentHeight } = animatedLayoutState.get();\n    /**\n     * if container height is not yet calculated, then we exit the method\n     */\n    if (containerHeight === INITIAL_LAYOUT_VALUE) {\n      return {};\n    }\n\n    /**\n     * if dynamic sizing is enabled, and content height\n     * is still not set, then we exit method.\n     */\n    if (enableDynamicSizing && contentHeight === INITIAL_LAYOUT_VALUE) {\n      return {};\n    }\n\n    const paddingBottom = detached ? 0 : animatedPaddingBottom.get();\n    const height = animatedContentHeightMax.get() + paddingBottom;\n\n    return {\n      paddingBottom: animate({\n        point: paddingBottom,\n        configs: animationConfigs,\n        overrideReduceMotion,\n      }),\n      height: animate({\n        point: height,\n        configs: animationConfigs,\n        overrideReduceMotion,\n      }),\n    };\n  }, [\n    overDragResistanceFactor,\n    enableDynamicSizing,\n    detached,\n    animationConfigs,\n    overrideReduceMotion,\n    animatedLayoutState,\n    animatedContentHeightMax,\n    animatedLayoutState,\n  ]);\n  const contentContainerStyle = useMemo(\n    () => [\n      detached\n        ? { overflow: 'visible' as const }\n        : { overflow: 'hidden' as const },\n      contentMaskContainerAnimatedStyle,\n    ],\n    [contentMaskContainerAnimatedStyle, detached]\n  );\n  //#endregion\n\n  //#region render\n  const DraggableView = enableContentPanningGesture\n    ? BottomSheetDraggableView\n    : Animated.View;\n  return (\n    <DraggableView\n      accessible={accessible}\n      accessibilityLabel={accessibilityLabel}\n      accessibilityHint={accessibilityHint}\n      accessibilityRole={accessibilityRole}\n      style={contentContainerStyle}\n    >\n      {children}\n    </DraggableView>\n  );\n  //#endregion\n}\n\nexport const BottomSheetContent = memo(BottomSheetContentComponent);\nBottomSheetContent.displayName = 'BottomSheetContent';\n"
  },
  {
    "path": "src/components/bottomSheet/constants.ts",
    "content": "import {\n  KEYBOARD_BEHAVIOR,\n  KEYBOARD_BLUR_BEHAVIOR,\n  KEYBOARD_INPUT_MODE,\n  SCREEN_HEIGHT,\n} from '../../constants';\n\n// default values\nconst DEFAULT_HANDLE_HEIGHT = 24;\nconst DEFAULT_OVER_DRAG_RESISTANCE_FACTOR = 2.5;\nconst DEFAULT_ENABLE_CONTENT_PANNING_GESTURE = true;\nconst DEFAULT_ENABLE_HANDLE_PANNING_GESTURE = true;\nconst DEFAULT_ENABLE_OVER_DRAG = true;\nconst DEFAULT_ENABLE_PAN_DOWN_TO_CLOSE = false;\nconst DEFAULT_ANIMATE_ON_MOUNT = true;\nconst DEFAULT_DYNAMIC_SIZING = true;\n\n// keyboard\nconst DEFAULT_KEYBOARD_BEHAVIOR = KEYBOARD_BEHAVIOR.interactive;\nconst DEFAULT_KEYBOARD_BLUR_BEHAVIOR = KEYBOARD_BLUR_BEHAVIOR.none;\nconst DEFAULT_KEYBOARD_INPUT_MODE = KEYBOARD_INPUT_MODE.adjustPan;\nconst DEFAULT_ENABLE_BLUR_KEYBOARD_ON_GESTURE = false;\nconst DEFAULT_KEYBOARD_INDEX = -998;\n\n// initial values\nconst INITIAL_VALUE = Number.NEGATIVE_INFINITY;\nconst INITIAL_SNAP_POINT = -999;\nconst INITIAL_POSITION = SCREEN_HEIGHT;\n\n// accessibility\nconst DEFAULT_ACCESSIBLE = true;\nconst DEFAULT_ACCESSIBILITY_LABEL = 'Bottom Sheet';\nconst DEFAULT_ACCESSIBILITY_ROLE = 'adjustable';\n\nexport {\n  DEFAULT_HANDLE_HEIGHT,\n  DEFAULT_OVER_DRAG_RESISTANCE_FACTOR,\n  DEFAULT_ENABLE_CONTENT_PANNING_GESTURE,\n  DEFAULT_ENABLE_HANDLE_PANNING_GESTURE,\n  DEFAULT_ENABLE_OVER_DRAG,\n  DEFAULT_ENABLE_PAN_DOWN_TO_CLOSE,\n  DEFAULT_DYNAMIC_SIZING,\n  DEFAULT_ANIMATE_ON_MOUNT,\n  // keyboard\n  DEFAULT_KEYBOARD_BEHAVIOR,\n  DEFAULT_KEYBOARD_BLUR_BEHAVIOR,\n  DEFAULT_KEYBOARD_INPUT_MODE,\n  DEFAULT_ENABLE_BLUR_KEYBOARD_ON_GESTURE,\n  DEFAULT_KEYBOARD_INDEX,\n  // layout\n  INITIAL_POSITION,\n  INITIAL_SNAP_POINT,\n  INITIAL_VALUE,\n  // accessibility\n  DEFAULT_ACCESSIBLE,\n  DEFAULT_ACCESSIBILITY_LABEL,\n  DEFAULT_ACCESSIBILITY_ROLE,\n};\n"
  },
  {
    "path": "src/components/bottomSheet/index.ts",
    "content": "export { default } from './BottomSheet';\nexport type { BottomSheetProps } from './types';\n"
  },
  {
    "path": "src/components/bottomSheet/styles.ts",
    "content": "import { StyleSheet } from 'react-native';\n\nexport const styles = StyleSheet.create({\n  container: {\n    flexDirection: 'column-reverse',\n    position: 'absolute',\n    top: 0,\n    left: 0,\n    right: 0,\n  },\n});\n"
  },
  {
    "path": "src/components/bottomSheet/types.d.ts",
    "content": "import type React from 'react';\nimport type { Insets, StyleProp, View, ViewStyle } from 'react-native';\nimport type { PanGesture } from 'react-native-gesture-handler';\nimport type {\n  AnimateStyle,\n  ReduceMotion,\n  SharedValue,\n  WithSpringConfig,\n  WithTimingConfig,\n} from 'react-native-reanimated';\nimport type {\n  ANIMATION_SOURCE,\n  KEYBOARD_BEHAVIOR,\n  KEYBOARD_BLUR_BEHAVIOR,\n  KEYBOARD_INPUT_MODE,\n  SNAP_POINT_TYPE,\n} from '../../constants';\nimport type {\n  ContainerLayoutState,\n  GestureEventsHandlersHookType,\n  NullableAccessibilityProps,\n} from '../../types';\nimport type { BottomSheetBackdropProps } from '../bottomSheetBackdrop';\nimport type { BottomSheetBackgroundProps } from '../bottomSheetBackground';\nimport type { BottomSheetFooterProps } from '../bottomSheetFooter';\nimport type { BottomSheetHandleProps } from '../bottomSheetHandle';\n\nexport interface BottomSheetProps\n  extends BottomSheetAnimationConfigs,\n    Partial<BottomSheetGestureProps>,\n    Omit<NullableAccessibilityProps, 'accessibilityHint'> {\n  //#region configuration\n  /**\n   * Initial snap point index, provide `-1` to initiate bottom sheet in closed state.\n   * @type number\n   * @default 0\n   */\n  index?: number;\n  /**\n   * Points for the bottom sheet to snap to. It accepts array of number, string or mix.\n   * String values should be a percentage.\n   *\n   * ⚠️ This prop is required unless you set `enableDynamicSizing` to `true`.\n   * @example\n   * snapPoints={[200, 500]}\n   * snapPoints={[200, '%50']}\n   * snapPoints={['%100']}\n   * @type Array<string | number>\n   */\n  snapPoints?: Array<string | number> | SharedValue<Array<string | number>>;\n  /**\n   * Defines how violently sheet has to be stopped while over dragging.\n   * @type number\n   * @default 2.5\n   */\n  overDragResistanceFactor?: number;\n  /**\n   * Defines whether the bottom sheet is attached to the bottom or no.\n   * @type boolean\n   * @default false\n   */\n  detached?: boolean;\n  /**\n   * Enable content panning gesture interaction.\n   * @type boolean\n   * @default true\n   */\n  enableContentPanningGesture?: boolean;\n  /**\n   * Enable handle panning gesture interaction.\n   * @type boolean\n   * @default true\n   */\n  enableHandlePanningGesture?: boolean;\n  /**\n   * Enable over drag for the sheet.\n   * @type boolean\n   * @default true\n   */\n  enableOverDrag?: boolean;\n  /**\n   * Enable pan down gesture to close the sheet.\n   * @type boolean\n   * @default false\n   */\n  enablePanDownToClose?: boolean;\n  /**\n   * Enable dynamic sizing for content view and scrollable content size.\n   * @type boolean\n   * @default true\n   */\n  enableDynamicSizing?: boolean;\n  /**\n   * To start the sheet closed and snap to initial index when it's mounted.\n   * @type boolean\n   * @default true\n   */\n  animateOnMount?: boolean;\n  /**\n   * To override the user reduce motion setting.\n   * - `ReduceMotion.System`: if the `Reduce motion` accessibility setting is enabled on the device, disable the animation.\n   * - `ReduceMotion.Always`: disable the animation, even if `Reduce motion` accessibility setting is not enabled.\n   * - `ReduceMotion.Never`: enable the animation, even if `Reduce motion` accessibility setting is enabled.\n   * @type ReduceMotion\n   * @see https://docs.swmansion.com/react-native-reanimated/docs/guides/accessibility\n   * @default ReduceMotion.System\n   */\n  overrideReduceMotion?: ReduceMotion;\n  //#endregion\n\n  //#region layout\n  /**\n   * Container height helps to calculate the internal sheet layouts,\n   * if `containerHeight` not provided, the library internally will calculate it,\n   * however this will cause an extra re-rendering.\n   * @type number | SharedValue<number>;\n   * @deprecated please use `containerLayoutState` instead.\n   */\n  containerHeight?: number | SharedValue<number>;\n  /**\n   * Container offset helps to accurately detect container offsets.\n   * @type SharedValue<number>;\n   * @deprecated please use `containerLayoutState` instead.\n   */\n  containerOffset?: SharedValue<Required<Insets>>;\n  /**\n   * Container layout state, this is used to calculate the container height and offsets.\n   * If not provided, the library will use the default container layout state.\n   * @type SharedValue<ContainerLayoutState>\n   * @default undefined\n   */\n  containerLayoutState?: SharedValue<ContainerLayoutState>;\n  /**\n   * Top inset value helps to calculate percentage snap points values,\n   * usually comes from `@react-navigation/stack` hook `useHeaderHeight` or\n   * from `react-native-safe-area-context` hook `useSafeArea`.\n   * @type number\n   * @default 0\n   */\n  topInset?: number;\n  /**\n   * Bottom inset value helps to calculate percentage snap points values,\n   * usually comes from `react-native-safe-area-context` hook `useSafeArea`.\n   * @type number\n   * @default 0\n   */\n  bottomInset?: number;\n  /**\n   * Max dynamic content size height to limit the bottom sheet height\n   * from exceeding a provided size.\n   * @type number\n   * @default container height\n   */\n  maxDynamicContentSize?: number;\n  //#endregion\n\n  //#region keyboard\n  /**\n   * Defines the keyboard appearance behavior.\n   * @enum\n   * - `interactive`: offset the sheet by the size of the keyboard.\n   * - `extend`: extend the sheet to its maximum snap point.\n   * - `fillParent`: extend the sheet to fill parent.\n   * @type `interactive` | `extend` | `fillParent`\n   * @default interactive\n   */\n  keyboardBehavior?: keyof typeof KEYBOARD_BEHAVIOR;\n  /**\n   * Defines the keyboard blur behavior.\n   * - `none`: do nothing.\n   * - `restore`: restore sheet position.\n   */\n  keyboardBlurBehavior?: keyof typeof KEYBOARD_BLUR_BEHAVIOR;\n  /**\n   * Enable blurring the keyboard when user start to drag the bottom sheet.\n   * @default false\n   */\n  enableBlurKeyboardOnGesture?: boolean;\n  /**\n   * Defines keyboard input mode for Android only.\n   * @link {https://developer.android.com/guide/topics/manifest/activity-element#wsoft}\n   * @type `adjustPan` | `adjustResize`\n   * @default `adjustPan`\n   */\n  android_keyboardInputMode?: keyof typeof KEYBOARD_INPUT_MODE;\n\n  //#endregion\n\n  //#region styles\n  /**\n   * View style to be applied to the container.\n   * @type ViewStyle\n   * @default undefined\n   */\n  containerStyle?: StyleProp<ViewStyle>;\n  /**\n   * View style to be applied to the sheet container component,\n   * it also could be an Animated Style.\n   * @type AnimateStyle<ViewStyle>\n   * @default undefined\n   */\n  style?: StyleProp<\n    AnimateStyle<\n      Omit<\n        ViewStyle,\n        | 'flexDirection'\n        | 'position'\n        | 'top'\n        | 'left'\n        | 'bottom'\n        | 'right'\n        | 'opacity'\n        | 'transform'\n      >\n    >\n  >;\n  /**\n   * View style to be applied to the background component.\n   * @type ViewStyle\n   * @default undefined\n   */\n  backgroundStyle?: StyleProp<\n    Omit<ViewStyle, 'position' | 'top' | 'left' | 'bottom' | 'right'>\n  >;\n  /**\n   * View style to be applied to the handle component.\n   * @type ViewStyle\n   * @default undefined\n   */\n  handleStyle?: StyleProp<ViewStyle>;\n  /**\n   * View style to be applied to the handle indicator component.\n   * @type ViewStyle\n   * @default undefined\n   */\n  handleIndicatorStyle?: StyleProp<ViewStyle>;\n  //#endregion\n\n  /**\n   * Custom hook to provide pan gesture events handler, which will allow advance and\n   * customize handling for pan gesture.\n   * @warning this is an experimental feature and the hook signature can change without a major version bump.\n   * @type GestureEventsHandlersHookType\n   * @default useGestureEventsHandlersDefault\n   */\n  gestureEventsHandlersHook?: GestureEventsHandlersHookType;\n\n  //#region animated nodes\n  /**\n   * Animated value to be used as a callback of the position node internally.\n   * @type SharedValue<number>\n   */\n  animatedPosition?: SharedValue<number>;\n  /**\n   * Animated value to be used as a callback for the position index node internally.\n   * @type SharedValue<number>\n   */\n  animatedIndex?: SharedValue<number>;\n  //#endregion\n\n  //#region callbacks\n  /**\n   * Callback when the sheet position changed to a provided point.\n   *\n   * @type (index: number) => void;\n   */\n  onChange?: (index: number, position: number, type: SNAP_POINT_TYPE) => void;\n  /**\n   * Callback when the sheet close.\n   *\n   * @type () => void;\n   */\n  onClose?: () => void;\n  /**\n   * Callback when the sheet about to animate to a new position.\n   *\n   * @type (fromIndex: number, toIndex: number, fromPosition: number, toPosition: number) => void;\n   */\n  onAnimate?: (\n    fromIndex: number,\n    toIndex: number,\n    fromPosition: number,\n    toPosition: number\n  ) => void;\n  //#endregion\n\n  //#region components\n  /**\n   * Component to be placed as a sheet handle.\n   * @see {BottomSheetHandleProps}\n   * @type React.FC\\<BottomSheetHandleProps\\>\n   */\n  handleComponent?: React.FC<BottomSheetHandleProps> | null;\n\n  /**\n   * Component to be placed as a sheet backdrop.\n   * @see {BottomSheetBackdropProps}\n   * @type React.FC\\<BottomSheetBackdropProps\\>\n   * @default undefined\n   */\n  backdropComponent?: React.FC<BottomSheetBackdropProps>;\n  /**\n   * Component to be placed as a background.\n   * @see {BottomSheetBackgroundProps}\n   * @type React.FC\\<BottomSheetBackgroundProps\\>\n   */\n  backgroundComponent?: React.FC<BottomSheetBackgroundProps> | null;\n  /**\n   * Component to be placed as a footer.\n   * @see {BottomSheetFooterProps}\n   * @type React.FC\\<BottomSheetFooterProps\\>\n   */\n  footerComponent?: React.FC<BottomSheetFooterProps>;\n  /**\n   * A scrollable node or normal view.\n   * @type React.ReactNode\n   */\n  children: React.ReactNode;\n  //#endregion\n\n  //#region private\n  /**\n   * An indicator whether if the sheet running in a modal.\n   * @type boolean\n   */\n  $modal?: boolean;\n  //#endregion\n}\n\nexport interface BottomSheetAnimationConfigs {\n  /**\n   * Animation configs, this could be created by:\n   * - `useBottomSheetSpringConfigs`\n   * - `useBottomSheetTimingConfigs`\n   * @type WithSpringConfig | WithTimingConfig\n   */\n  animationConfigs?: WithSpringConfig | WithTimingConfig;\n}\n\nexport type AnimateToPositionType = (\n  position: number,\n  source: ANIMATION_SOURCE,\n  velocity?: number,\n  configs?: WithTimingConfig | WithSpringConfig\n) => void;\n\nexport type BottomSheetGestureProps = {\n  activeOffsetX: Parameters<PanGesture['activeOffsetX']>[0];\n  activeOffsetY: Parameters<PanGesture['activeOffsetY']>[0];\n\n  failOffsetY: Parameters<PanGesture['failOffsetY']>[0];\n  failOffsetX: Parameters<PanGesture['failOffsetX']>[0];\n\n  simultaneousHandlers: Parameters<\n    PanGesture['simultaneousWithExternalGesture']\n  >[0];\n  waitFor: Parameters<PanGesture['requireExternalGestureToFail']>[0];\n};\n"
  },
  {
    "path": "src/components/bottomSheetBackdrop/BottomSheetBackdrop.tsx",
    "content": "import React, {\n  memo,\n  useCallback,\n  useEffect,\n  useMemo,\n  useRef,\n  useState,\n} from 'react';\nimport type { ViewProps } from 'react-native';\nimport { Gesture, GestureDetector } from 'react-native-gesture-handler';\nimport Animated, {\n  interpolate,\n  useAnimatedStyle,\n  useAnimatedReaction,\n  runOnJS,\n  Extrapolation,\n} from 'react-native-reanimated';\nimport { useBottomSheet } from '../../hooks';\nimport {\n  DEFAULT_ACCESSIBILITY_HINT,\n  DEFAULT_ACCESSIBILITY_LABEL,\n  DEFAULT_ACCESSIBILITY_ROLE,\n  DEFAULT_ACCESSIBLE,\n  DEFAULT_APPEARS_ON_INDEX,\n  DEFAULT_DISAPPEARS_ON_INDEX,\n  DEFAULT_ENABLE_TOUCH_THROUGH,\n  DEFAULT_OPACITY,\n  DEFAULT_PRESS_BEHAVIOR,\n} from './constants';\nimport { styles } from './styles';\nimport type { BottomSheetDefaultBackdropProps } from './types';\n\nconst BottomSheetBackdropComponent = ({\n  animatedIndex,\n  opacity: _providedOpacity,\n  appearsOnIndex: _providedAppearsOnIndex,\n  disappearsOnIndex: _providedDisappearsOnIndex,\n  enableTouchThrough: _providedEnableTouchThrough,\n  pressBehavior = DEFAULT_PRESS_BEHAVIOR,\n  onPress,\n  style,\n  children,\n  accessible: _providedAccessible = DEFAULT_ACCESSIBLE,\n  accessibilityRole: _providedAccessibilityRole = DEFAULT_ACCESSIBILITY_ROLE,\n  accessibilityLabel: _providedAccessibilityLabel = DEFAULT_ACCESSIBILITY_LABEL,\n  accessibilityHint: _providedAccessibilityHint = DEFAULT_ACCESSIBILITY_HINT,\n}: BottomSheetDefaultBackdropProps) => {\n  //#region hooks\n  const { snapToIndex, close } = useBottomSheet();\n  const isMounted = useRef(false);\n  //#endregion\n\n  //#region defaults\n  const opacity = _providedOpacity ?? DEFAULT_OPACITY;\n  const appearsOnIndex = _providedAppearsOnIndex ?? DEFAULT_APPEARS_ON_INDEX;\n  const disappearsOnIndex =\n    _providedDisappearsOnIndex ?? DEFAULT_DISAPPEARS_ON_INDEX;\n  const enableTouchThrough =\n    _providedEnableTouchThrough ?? DEFAULT_ENABLE_TOUCH_THROUGH;\n  //#endregion\n\n  //#region variables\n  const [pointerEvents, setPointerEvents] = useState<\n    ViewProps['pointerEvents']\n  >(enableTouchThrough ? 'none' : 'auto');\n  //#endregion\n\n  //#region callbacks\n  const handleOnPress = useCallback(() => {\n    onPress?.();\n\n    if (pressBehavior === 'close') {\n      close();\n    } else if (pressBehavior === 'collapse') {\n      snapToIndex(disappearsOnIndex as number);\n    } else if (typeof pressBehavior === 'number') {\n      snapToIndex(pressBehavior);\n    }\n  }, [snapToIndex, close, disappearsOnIndex, pressBehavior, onPress]);\n  const handleContainerTouchability = useCallback(\n    (shouldDisableTouchability: boolean) => {\n      isMounted.current &&\n        setPointerEvents(shouldDisableTouchability ? 'none' : 'auto');\n    },\n    []\n  );\n  //#endregion\n\n  //#region tap gesture\n  const tapHandler = useMemo(() => {\n    const gesture = Gesture.Tap().onEnd(() => {\n      runOnJS(handleOnPress)();\n    });\n    return gesture;\n  }, [handleOnPress]);\n  //#endregion\n\n  //#region styles\n  const containerAnimatedStyle = useAnimatedStyle(\n    () => ({\n      opacity: interpolate(\n        animatedIndex.value,\n        [-1, disappearsOnIndex, appearsOnIndex],\n        [0, 0, opacity],\n        Extrapolation.CLAMP\n      ),\n    }),\n    [animatedIndex, appearsOnIndex, disappearsOnIndex, opacity]\n  );\n  const containerStyle = useMemo(\n    () => [styles.backdrop, style, containerAnimatedStyle],\n    [style, containerAnimatedStyle]\n  );\n  //#endregion\n\n  //#region effects\n  useAnimatedReaction(\n    () => animatedIndex.value <= disappearsOnIndex,\n    (shouldDisableTouchability, previous) => {\n      if (shouldDisableTouchability === previous) {\n        return;\n      }\n      runOnJS(handleContainerTouchability)(shouldDisableTouchability);\n    },\n    [disappearsOnIndex]\n  );\n\n  // addressing updating the state after unmounting.\n  // [link](https://github.com/gorhom/react-native-bottom-sheet/issues/1376)\n  useEffect(() => {\n    isMounted.current = true;\n    return () => {\n      isMounted.current = false;\n    };\n  }, []);\n  //#endregion\n\n  const AnimatedView = (\n    <Animated.View\n      style={containerStyle}\n      pointerEvents={pointerEvents}\n      accessible={_providedAccessible ?? undefined}\n      accessibilityRole={_providedAccessibilityRole ?? undefined}\n      accessibilityLabel={_providedAccessibilityLabel ?? undefined}\n      accessibilityHint={\n        _providedAccessibilityHint\n          ? _providedAccessibilityHint\n          : `Tap to ${\n              typeof pressBehavior === 'string' ? pressBehavior : 'move'\n            } the Bottom Sheet`\n      }\n    >\n      {children}\n    </Animated.View>\n  );\n\n  return pressBehavior !== 'none' ? (\n    <GestureDetector gesture={tapHandler}>{AnimatedView}</GestureDetector>\n  ) : (\n    AnimatedView\n  );\n};\n\nexport const BottomSheetBackdrop = memo(BottomSheetBackdropComponent);\nBottomSheetBackdrop.displayName = 'BottomSheetBackdrop';\n"
  },
  {
    "path": "src/components/bottomSheetBackdrop/constants.ts",
    "content": "const DEFAULT_OPACITY = 0.5;\nconst DEFAULT_APPEARS_ON_INDEX = 1;\nconst DEFAULT_DISAPPEARS_ON_INDEX = 0;\nconst DEFAULT_ENABLE_TOUCH_THROUGH = false;\nconst DEFAULT_PRESS_BEHAVIOR = 'close' as const;\n\nconst DEFAULT_ACCESSIBLE = true;\nconst DEFAULT_ACCESSIBILITY_ROLE = 'button';\nconst DEFAULT_ACCESSIBILITY_LABEL = 'Bottom sheet backdrop';\nconst DEFAULT_ACCESSIBILITY_HINT = 'Tap to close the bottom sheet';\n\nexport {\n  DEFAULT_OPACITY,\n  DEFAULT_APPEARS_ON_INDEX,\n  DEFAULT_DISAPPEARS_ON_INDEX,\n  DEFAULT_ENABLE_TOUCH_THROUGH,\n  DEFAULT_PRESS_BEHAVIOR,\n  DEFAULT_ACCESSIBLE,\n  DEFAULT_ACCESSIBILITY_ROLE,\n  DEFAULT_ACCESSIBILITY_LABEL,\n  DEFAULT_ACCESSIBILITY_HINT,\n};\n"
  },
  {
    "path": "src/components/bottomSheetBackdrop/index.ts",
    "content": "export { BottomSheetBackdrop } from './BottomSheetBackdrop';\nexport type { BottomSheetBackdropProps } from './types';\n"
  },
  {
    "path": "src/components/bottomSheetBackdrop/styles.ts",
    "content": "import { StyleSheet } from 'react-native';\n\nexport const styles = StyleSheet.create({\n  backdrop: {\n    ...StyleSheet.absoluteFillObject,\n    backgroundColor: 'black',\n  },\n});\n"
  },
  {
    "path": "src/components/bottomSheetBackdrop/types.d.ts",
    "content": "import type { ReactNode } from 'react';\nimport type { ViewProps } from 'react-native';\nimport type {\n  BottomSheetVariables,\n  NullableAccessibilityProps,\n} from '../../types';\nimport type { BottomSheetProps } from '../bottomSheet/types';\n\nexport interface BottomSheetBackdropProps\n  extends Pick<ViewProps, 'style'>,\n    BottomSheetVariables {}\n\nexport type BackdropPressBehavior = 'none' | 'close' | 'collapse' | number;\n\nexport interface BottomSheetDefaultBackdropProps\n  extends BottomSheetBackdropProps,\n    NullableAccessibilityProps {\n  /**\n   * Backdrop opacity.\n   * @type number\n   * @default 0.5\n   */\n  opacity?: number;\n  /**\n   * Snap point index when backdrop will appears on.\n   * @type number\n   * @default 1\n   */\n  appearsOnIndex?: number;\n  /**\n   * Snap point index when backdrop will disappears on.\n   * @type number\n   * @default 0\n   */\n  disappearsOnIndex?: number;\n  /**\n   * Enable touch through backdrop component.\n   * @type boolean\n   * @default false\n   */\n  enableTouchThrough?: boolean;\n  /**\n   * What should happen when user press backdrop?\n   * @type BackdropPressBehavior\n   * @default 'close'\n   */\n  pressBehavior?: BackdropPressBehavior;\n\n  /**\n   * Function which will be executed on pressing backdrop component\n   * @type {Function}\n   */\n  onPress?: () => void;\n  /**\n   * Child component that will be rendered on backdrop.\n   */\n  children?: ReactNode | ReactNode[];\n}\n"
  },
  {
    "path": "src/components/bottomSheetBackground/BottomSheetBackground.tsx",
    "content": "import React, { memo } from 'react';\nimport { View } from 'react-native';\nimport { styles } from './styles';\nimport type { BottomSheetBackgroundProps } from './types';\n\nconst BottomSheetBackgroundComponent = ({\n  pointerEvents,\n  style,\n}: BottomSheetBackgroundProps) => (\n  <View\n    pointerEvents={pointerEvents}\n    accessible={true}\n    accessibilityRole=\"adjustable\"\n    accessibilityLabel=\"Bottom Sheet\"\n    style={[styles.background, style]}\n  />\n);\n\nexport const BottomSheetBackground = memo(BottomSheetBackgroundComponent);\nBottomSheetBackground.displayName = 'BottomSheetBackground';\n"
  },
  {
    "path": "src/components/bottomSheetBackground/BottomSheetBackgroundContainer.tsx",
    "content": "import React, { memo, useMemo } from 'react';\nimport { StyleSheet } from 'react-native';\nimport { BottomSheetBackground } from './BottomSheetBackground';\nimport { styles } from './styles';\nimport type { BottomSheetBackgroundContainerProps } from './types';\n\nconst BottomSheetBackgroundContainerComponent = ({\n  animatedIndex,\n  animatedPosition,\n  backgroundComponent: _providedBackgroundComponent,\n  backgroundStyle: _providedBackgroundStyle,\n}: BottomSheetBackgroundContainerProps) => {\n  //#region style\n  const backgroundStyle = useMemo(\n    () => StyleSheet.flatten([styles.container, _providedBackgroundStyle]),\n    [_providedBackgroundStyle]\n  );\n  //#endregion\n\n  const BackgroundComponent =\n    _providedBackgroundComponent ?? BottomSheetBackground;\n  return (\n    <BackgroundComponent\n      pointerEvents=\"none\"\n      animatedIndex={animatedIndex}\n      animatedPosition={animatedPosition}\n      style={backgroundStyle}\n    />\n  );\n};\n\nexport const BottomSheetBackgroundContainer = memo(\n  BottomSheetBackgroundContainerComponent\n);\nBottomSheetBackgroundContainer.displayName = 'BottomSheetBackgroundContainer';\n"
  },
  {
    "path": "src/components/bottomSheetBackground/index.ts",
    "content": "export { BottomSheetBackgroundContainer } from './BottomSheetBackgroundContainer';\nexport type { BottomSheetBackgroundProps } from './types';\n"
  },
  {
    "path": "src/components/bottomSheetBackground/styles.ts",
    "content": "import { StyleSheet } from 'react-native';\n\nexport const styles = StyleSheet.create({\n  container: StyleSheet.absoluteFillObject,\n  background: {\n    backgroundColor: 'white',\n    borderRadius: 15,\n  },\n});\n"
  },
  {
    "path": "src/components/bottomSheetBackground/types.d.ts",
    "content": "import type { ViewProps } from 'react-native';\nimport type { BottomSheetVariables } from '../../types';\nimport type { BottomSheetProps } from '../bottomSheet';\nexport interface BottomSheetBackgroundProps\n  extends Pick<ViewProps, 'pointerEvents' | 'style'>,\n    BottomSheetVariables {}\n\nexport type BottomSheetBackgroundContainerProps = Pick<\n  BottomSheetProps,\n  'backgroundComponent' | 'backgroundStyle'\n> &\n  BottomSheetBackgroundProps;\n"
  },
  {
    "path": "src/components/bottomSheetDebugView/BottomSheetDebugView.tsx",
    "content": "import React from 'react';\nimport { View } from 'react-native';\nimport type { SharedValue } from 'react-native-reanimated';\nimport ReText from './ReText';\nimport { styles } from './styles';\n\ninterface BottomSheetDebugViewProps {\n  values: Record<string, SharedValue<number | boolean | object> | number>;\n}\n\nconst BottomSheetDebugView = ({ values }: BottomSheetDebugViewProps) => {\n  return (\n    <View pointerEvents=\"none\" style={styles.container}>\n      {Object.keys(values).map(key => (\n        <ReText\n          key={`item-${key}`}\n          value={values[key]}\n          style={styles.text}\n          text={key}\n        />\n      ))}\n    </View>\n  );\n};\n\nexport default BottomSheetDebugView;\n"
  },
  {
    "path": "src/components/bottomSheetDebugView/ReText.tsx",
    "content": "import React from 'react';\nimport { type TextProps as RNTextProps, TextInput } from 'react-native';\nimport Animated, {\n  type SharedValue,\n  type AnimatedProps,\n  useAnimatedProps,\n  useDerivedValue,\n} from 'react-native-reanimated';\n\ninterface TextProps {\n  text: string;\n  value: SharedValue<number | boolean | object> | number;\n  style?: AnimatedProps<RNTextProps>['style'];\n}\n\nconst AnimatedTextInput = Animated.createAnimatedComponent(TextInput);\n\nAnimated.addWhitelistedNativeProps({ text: true });\n\nconst ReText = ({ text, value: _providedValue, style }: TextProps) => {\n  const providedValue = useDerivedValue(() => {\n    if (!_providedValue) {\n      return '';\n    }\n\n    let rawValue: number | string | object | boolean = '';\n    if (typeof _providedValue === 'number') {\n      rawValue = _providedValue as number;\n    } else if (typeof _providedValue.get === 'function') {\n      rawValue = _providedValue.get();\n    }\n\n    if (typeof rawValue === 'object') {\n      const rawValueObject = Object.entries(rawValue)\n        .map(item => `${item[0]}: ${item[1]}`)\n        .reduce((result, current, index) => {\n          if (index !== 0) {\n            result = `${result} \\n`;\n          }\n\n          result = `${result}- ${current}`;\n          return result;\n        }, '');\n\n      return `${text}\\n${rawValueObject}`;\n    }\n\n    if (typeof rawValue === 'number') {\n      rawValue = rawValue.toFixed(2);\n    }\n\n    return `${text}: ${rawValue}`;\n  }, [text, _providedValue]);\n  const animatedProps = useAnimatedProps(() => {\n    return {\n      text: providedValue.get(),\n    };\n  }, [providedValue]);\n  return (\n    <AnimatedTextInput\n      underlineColorAndroid=\"transparent\"\n      editable={false}\n      value={providedValue?.get() ?? ''}\n      style={style}\n      // @ts-ignore\n      animatedProps={animatedProps}\n      multiline={true}\n    />\n  );\n};\n\nexport default ReText;\n"
  },
  {
    "path": "src/components/bottomSheetDebugView/ReText.webx.tsx",
    "content": "import React, { useRef } from 'react';\nimport { type TextProps as RNTextProps, TextInput } from 'react-native';\nimport Animated, {\n  type SharedValue,\n  useAnimatedReaction,\n  useDerivedValue,\n} from 'react-native-reanimated';\n\ninterface TextProps {\n  text: string;\n  value: SharedValue<number | boolean> | number;\n  style?: Animated.AnimateProps<RNTextProps>['style'];\n}\n\nconst AnimatedTextInput = Animated.createAnimatedComponent(TextInput);\n\nconst ReText = (props: TextProps) => {\n  const { text, value: _providedValue, style } = { style: {}, ...props };\n  const textRef = useRef<TextInput>(null);\n\n  const providedValue = useDerivedValue(() => {\n    const value =\n      typeof _providedValue === 'number'\n        ? _providedValue\n        : typeof _providedValue.value === 'number'\n          ? _providedValue.value.toFixed(2)\n          : _providedValue.value;\n\n    return `${text}: ${value}`;\n  }, [_providedValue, text]);\n\n  //region effects\n  useAnimatedReaction(\n    () => providedValue.value,\n    result => {\n      textRef.current?.setNativeProps({\n        text: result,\n      });\n    },\n    []\n  );\n  //endregion\n\n  return (\n    <AnimatedTextInput\n      ref={textRef}\n      underlineColorAndroid=\"transparent\"\n      editable={false}\n      value={providedValue.value}\n      style={style}\n    />\n  );\n};\n\nexport default ReText;\n"
  },
  {
    "path": "src/components/bottomSheetDebugView/index.ts",
    "content": "export { default } from './BottomSheetDebugView';\n"
  },
  {
    "path": "src/components/bottomSheetDebugView/styles.ts",
    "content": "import { StyleSheet } from 'react-native';\n\nexport const styles = StyleSheet.create({\n  container: {\n    position: 'absolute',\n    right: 4,\n    top: 0,\n    paddingHorizontal: 4,\n    backgroundColor: 'rgba(0, 0,0,0.5)',\n  },\n  text: {\n    fontSize: 14,\n    lineHeight: 16,\n    textAlignVertical: 'center',\n    padding: 0,\n    marginVertical: 4,\n    color: 'white',\n  },\n});\n"
  },
  {
    "path": "src/components/bottomSheetDebugView/styles.web.ts",
    "content": "import { StyleSheet } from 'react-native';\n\nexport const styles = StyleSheet.create({\n  container: {\n    position: 'absolute',\n    left: 4,\n    top: 80,\n    padding: 2,\n    width: 400,\n    backgroundColor: 'rgba(0, 0,0,0.5)',\n  },\n  text: {\n    fontSize: 14,\n    lineHeight: 16,\n    textAlignVertical: 'center',\n    height: 20,\n    padding: 0,\n    color: 'white',\n  },\n});\n"
  },
  {
    "path": "src/components/bottomSheetDraggableView/BottomSheetDraggableView.tsx",
    "content": "import React, { useMemo, memo } from 'react';\nimport { Gesture, GestureDetector } from 'react-native-gesture-handler';\nimport Animated from 'react-native-reanimated';\nimport { BottomSheetDraggableContext } from '../../contexts/gesture';\nimport {\n  useBottomSheetGestureHandlers,\n  useBottomSheetInternal,\n} from '../../hooks';\nimport type { BottomSheetDraggableViewProps } from './types';\n\nconst BottomSheetDraggableViewComponent = ({\n  nativeGestureRef,\n  refreshControlGestureRef,\n  style,\n  children,\n  ...rest\n}: BottomSheetDraggableViewProps) => {\n  //#region hooks\n  const {\n    enableContentPanningGesture,\n    simultaneousHandlers: _providedSimultaneousHandlers,\n    waitFor,\n    activeOffsetX,\n    activeOffsetY,\n    failOffsetX,\n    failOffsetY,\n  } = useBottomSheetInternal();\n  const { contentPanGestureHandler } = useBottomSheetGestureHandlers();\n  //#endregion\n\n  //#region variables\n  const simultaneousHandlers = useMemo(() => {\n    const refs = [];\n\n    if (nativeGestureRef) {\n      refs.push(nativeGestureRef);\n    }\n\n    if (refreshControlGestureRef) {\n      refs.push(refreshControlGestureRef);\n    }\n\n    if (_providedSimultaneousHandlers) {\n      if (Array.isArray(_providedSimultaneousHandlers)) {\n        refs.push(..._providedSimultaneousHandlers);\n      } else {\n        refs.push(_providedSimultaneousHandlers);\n      }\n    }\n\n    return refs;\n  }, [\n    _providedSimultaneousHandlers,\n    nativeGestureRef,\n    refreshControlGestureRef,\n  ]);\n  const draggableGesture = useMemo(() => {\n    let gesture = Gesture.Pan()\n      .enabled(enableContentPanningGesture)\n      .shouldCancelWhenOutside(false)\n      .runOnJS(false)\n      .onStart(contentPanGestureHandler.handleOnStart)\n      .onChange(contentPanGestureHandler.handleOnChange)\n      .onEnd(contentPanGestureHandler.handleOnEnd)\n      .onFinalize(contentPanGestureHandler.handleOnFinalize);\n\n    if (waitFor) {\n      gesture = gesture.requireExternalGestureToFail(waitFor);\n    }\n\n    if (simultaneousHandlers) {\n      gesture = gesture.simultaneousWithExternalGesture(\n        simultaneousHandlers as never\n      );\n    }\n\n    if (activeOffsetX) {\n      gesture = gesture.activeOffsetX(activeOffsetX);\n    }\n\n    if (activeOffsetY) {\n      gesture = gesture.activeOffsetY(activeOffsetY);\n    }\n\n    if (failOffsetX) {\n      gesture = gesture.failOffsetX(failOffsetX);\n    }\n\n    if (failOffsetY) {\n      gesture = gesture.failOffsetY(failOffsetY);\n    }\n\n    return gesture;\n  }, [\n    activeOffsetX,\n    activeOffsetY,\n    enableContentPanningGesture,\n    failOffsetX,\n    failOffsetY,\n    simultaneousHandlers,\n    waitFor,\n    contentPanGestureHandler.handleOnChange,\n    contentPanGestureHandler.handleOnEnd,\n    contentPanGestureHandler.handleOnFinalize,\n    contentPanGestureHandler.handleOnStart,\n  ]);\n  //#endregion\n\n  return (\n    <GestureDetector gesture={draggableGesture}>\n      <BottomSheetDraggableContext.Provider value={draggableGesture}>\n        <Animated.View style={style} {...rest}>\n          {children}\n        </Animated.View>\n      </BottomSheetDraggableContext.Provider>\n    </GestureDetector>\n  );\n};\n\nconst BottomSheetDraggableView = memo(BottomSheetDraggableViewComponent);\nBottomSheetDraggableView.displayName = 'BottomSheetDraggableView';\n\nexport default BottomSheetDraggableView;\n"
  },
  {
    "path": "src/components/bottomSheetDraggableView/index.ts",
    "content": "export { default } from './BottomSheetDraggableView';\n"
  },
  {
    "path": "src/components/bottomSheetDraggableView/types.d.ts",
    "content": "import type { ReactNode } from 'react';\nimport type { ViewProps as RNViewProps } from 'react-native';\nimport type { GestureRef } from 'react-native-gesture-handler/lib/typescript/handlers/gestures/gesture';\n\nexport type BottomSheetDraggableViewProps = RNViewProps & {\n  nativeGestureRef?: Exclude<GestureRef, number>;\n  refreshControlGestureRef?: Exclude<GestureRef, number>;\n  children: ReactNode[] | ReactNode;\n};\n"
  },
  {
    "path": "src/components/bottomSheetFooter/BottomSheetFooter.tsx",
    "content": "import React, { memo, useCallback, useMemo, useRef } from 'react';\nimport type { LayoutChangeEvent } from 'react-native';\nimport Animated, { useAnimatedStyle } from 'react-native-reanimated';\nimport { KEYBOARD_STATUS } from '../../constants';\nimport {\n  type BoundingClientRect,\n  useBottomSheetInternal,\n  useBoundingClientRect,\n} from '../../hooks';\nimport { print } from '../../utilities';\nimport { styles } from './styles';\nimport type { BottomSheetDefaultFooterProps } from './types';\n\nfunction BottomSheetFooterComponent({\n  animatedFooterPosition,\n  bottomInset = 0,\n  style,\n  children,\n}: BottomSheetDefaultFooterProps) {\n  //#region refs\n  const ref = useRef<Animated.View>(null);\n  //#endregion\n\n  //#region hooks\n  const { animatedLayoutState, animatedKeyboardState } =\n    useBottomSheetInternal();\n  //#endregion\n\n  //#region styles\n  const containerAnimatedStyle = useAnimatedStyle(() => {\n    let footerTranslateY = animatedFooterPosition.get();\n\n    /**\n     * Offset the bottom inset only when keyboard is not shown\n     */\n    if (animatedKeyboardState.get().status !== KEYBOARD_STATUS.SHOWN) {\n      footerTranslateY = footerTranslateY - bottomInset;\n    }\n\n    return {\n      transform: [\n        {\n          translateY: Math.max(0, footerTranslateY),\n        },\n      ],\n    };\n  }, [bottomInset, animatedKeyboardState, animatedFooterPosition]);\n  const containerStyle = useMemo(\n    () => [styles.container, style, containerAnimatedStyle],\n    [style, containerAnimatedStyle]\n  );\n  //#endregion\n\n  //#region callbacks\n  const handleContainerLayout = useCallback(\n    ({\n      nativeEvent: {\n        layout: { height },\n      },\n    }: LayoutChangeEvent) => {\n      animatedLayoutState.modify(state => {\n        'worklet';\n        state.footerHeight = height;\n        return state;\n      });\n\n      if (__DEV__) {\n        print({\n          component: 'BottomSheetFooter',\n          method: 'handleContainerLayout',\n          category: 'layout',\n          params: {\n            height,\n          },\n        });\n      }\n    },\n    [animatedLayoutState]\n  );\n  const handleBoundingClientRect = useCallback(\n    ({ height }: BoundingClientRect) => {\n      animatedLayoutState.modify(state => {\n        'worklet';\n        state.footerHeight = height;\n        return state;\n      });\n\n      if (__DEV__) {\n        print({\n          component: 'BottomSheetFooter',\n          method: 'handleBoundingClientRect',\n          category: 'layout',\n          params: {\n            height,\n          },\n        });\n      }\n    },\n    [animatedLayoutState]\n  );\n  //#endregion\n\n  //#region effects\n  useBoundingClientRect(ref, handleBoundingClientRect);\n  //#endregion\n\n  return children !== null ? (\n    <Animated.View\n      ref={ref}\n      onLayout={handleContainerLayout}\n      style={containerStyle}\n    >\n      {children}\n    </Animated.View>\n  ) : null;\n}\n\nexport const BottomSheetFooter = memo(BottomSheetFooterComponent);\nBottomSheetFooter.displayName = 'BottomSheetFooter';\n"
  },
  {
    "path": "src/components/bottomSheetFooter/BottomSheetFooterContainer.tsx",
    "content": "import React, { memo } from 'react';\nimport { useDerivedValue } from 'react-native-reanimated';\nimport { INITIAL_LAYOUT_VALUE, KEYBOARD_STATUS } from '../../constants';\nimport { useBottomSheetInternal } from '../../hooks';\nimport type { BottomSheetFooterContainerProps } from './types';\n\nconst BottomSheetFooterContainerComponent = ({\n  footerComponent: FooterComponent,\n}: BottomSheetFooterContainerProps) => {\n  //#region hooks\n  const { animatedLayoutState, animatedPosition, animatedKeyboardState } =\n    useBottomSheetInternal();\n  //#endregion\n\n  //#region variables\n  const animatedFooterPosition = useDerivedValue(() => {\n    const { handleHeight, footerHeight, containerHeight } =\n      animatedLayoutState.get();\n    if (handleHeight === INITIAL_LAYOUT_VALUE) {\n      return 0;\n    }\n\n    const { status: keyboardStatus, heightWithinContainer: keyboardHeight } =\n      animatedKeyboardState.get();\n    const position = animatedPosition.get();\n\n    let footerTranslateY = Math.max(0, containerHeight - position);\n    if (keyboardStatus === KEYBOARD_STATUS.SHOWN) {\n      footerTranslateY = footerTranslateY - keyboardHeight;\n    }\n\n    footerTranslateY = footerTranslateY - footerHeight - handleHeight;\n    return footerTranslateY;\n  }, [animatedKeyboardState, animatedPosition, animatedLayoutState]);\n  //#endregion\n\n  return <FooterComponent animatedFooterPosition={animatedFooterPosition} />;\n};\n\nexport const BottomSheetFooterContainer = memo(\n  BottomSheetFooterContainerComponent\n);\nBottomSheetFooterContainer.displayName = 'BottomSheetFooterContainer';\n"
  },
  {
    "path": "src/components/bottomSheetFooter/index.ts",
    "content": "export { BottomSheetFooter } from './BottomSheetFooter';\nexport { BottomSheetFooterContainer } from './BottomSheetFooterContainer';\nexport type { BottomSheetFooterProps } from './types';\n"
  },
  {
    "path": "src/components/bottomSheetFooter/styles.ts",
    "content": "import { StyleSheet } from 'react-native';\n\nexport const styles = StyleSheet.create({\n  container: {\n    position: 'absolute',\n    top: 0,\n    left: 0,\n    right: 0,\n    zIndex: 9999,\n    pointerEvents: 'box-none',\n  },\n});\n"
  },
  {
    "path": "src/components/bottomSheetFooter/types.d.ts",
    "content": "import type { ReactNode } from 'react';\nimport type { ViewStyle } from 'react-native';\nimport type { SharedValue } from 'react-native-reanimated';\nimport type { BottomSheetProps } from '../bottomSheet/types';\n\nexport interface BottomSheetFooterProps {\n  /**\n   * Calculated footer animated position.\n   *\n   * @type SharedValue<number>\n   */\n  animatedFooterPosition: SharedValue<number>;\n}\n\nexport interface BottomSheetDefaultFooterProps extends BottomSheetFooterProps {\n  /**\n   * Bottom inset to be added below the footer, usually comes\n   * from `react-native-safe-area-context` hook `useSafeArea`.\n   *\n   * @type number\n   * @default 0\n   */\n  bottomInset?: number;\n\n  /**\n   * Container style.\n   *\n   * @type ViewStyle\n   */\n  style?: ViewStyle;\n\n  /**\n   * Component to be placed in the footer.\n   *\n   * @type {ReactNode|ReactNode[]}\n   */\n  children?: ReactNode | ReactNode[];\n}\n\nexport interface BottomSheetFooterContainerProps\n  extends Required<Pick<BottomSheetProps, 'footerComponent'>> {}\n"
  },
  {
    "path": "src/components/bottomSheetGestureHandlersProvider/BottomSheetGestureHandlersProvider.tsx",
    "content": "import React, { useMemo } from 'react';\nimport { useSharedValue } from 'react-native-reanimated';\nimport { GESTURE_SOURCE } from '../../constants';\nimport { BottomSheetGestureHandlersContext } from '../../contexts';\nimport {\n  useBottomSheetInternal,\n  useGestureEventsHandlersDefault,\n  useGestureHandler,\n} from '../../hooks';\nimport type { BottomSheetGestureHandlersProviderProps } from './types';\n\nconst BottomSheetGestureHandlersProvider = ({\n  gestureEventsHandlersHook:\n    useGestureEventsHandlers = useGestureEventsHandlersDefault,\n  children,\n}: BottomSheetGestureHandlersProviderProps) => {\n  //#region variables\n  const animatedGestureSource = useSharedValue<GESTURE_SOURCE>(\n    GESTURE_SOURCE.UNDETERMINED\n  );\n  //#endregion\n\n  //#region hooks\n  const { animatedContentGestureState, animatedHandleGestureState } =\n    useBottomSheetInternal();\n  const { handleOnStart, handleOnChange, handleOnEnd, handleOnFinalize } =\n    useGestureEventsHandlers();\n  //#endregion\n\n  //#region gestures\n  const contentPanGestureHandler = useGestureHandler(\n    GESTURE_SOURCE.CONTENT,\n    animatedContentGestureState,\n    animatedGestureSource,\n    handleOnStart,\n    handleOnChange,\n    handleOnEnd,\n    handleOnFinalize\n  );\n\n  const handlePanGestureHandler = useGestureHandler(\n    GESTURE_SOURCE.HANDLE,\n    animatedHandleGestureState,\n    animatedGestureSource,\n    handleOnStart,\n    handleOnChange,\n    handleOnEnd,\n    handleOnFinalize\n  );\n  //#endregion\n\n  //#region context\n  const contextValue = useMemo(\n    () => ({\n      contentPanGestureHandler,\n      handlePanGestureHandler,\n      animatedGestureSource,\n    }),\n    [contentPanGestureHandler, handlePanGestureHandler, animatedGestureSource]\n  );\n  //#endregion\n  return (\n    <BottomSheetGestureHandlersContext.Provider value={contextValue}>\n      {children}\n    </BottomSheetGestureHandlersContext.Provider>\n  );\n};\n\nexport default BottomSheetGestureHandlersProvider;\n"
  },
  {
    "path": "src/components/bottomSheetGestureHandlersProvider/index.ts",
    "content": "export { default } from './BottomSheetGestureHandlersProvider';\n"
  },
  {
    "path": "src/components/bottomSheetGestureHandlersProvider/types.d.ts",
    "content": "import type { ReactChild } from 'react';\nimport React from 'react';\nimport type { BottomSheetProps } from '../bottomSheet/types';\n\nexport interface BottomSheetGestureHandlersProviderProps\n  extends Pick<BottomSheetProps, 'gestureEventsHandlersHook'> {\n  children?: React.ReactNode;\n}\n"
  },
  {
    "path": "src/components/bottomSheetHandle/BottomSheetHandle.tsx",
    "content": "import React, { memo, useMemo } from 'react';\nimport { StyleSheet, View } from 'react-native';\nimport {\n  DEFAULT_ACCESSIBILITY_HINT,\n  DEFAULT_ACCESSIBILITY_LABEL,\n  DEFAULT_ACCESSIBILITY_ROLE,\n  DEFAULT_ACCESSIBLE,\n} from './constants';\nimport { styles } from './styles';\nimport type { BottomSheetDefaultHandleProps } from './types';\n\nfunction BottomSheetHandleComponent({\n  style,\n  indicatorStyle: _indicatorStyle,\n  accessible = DEFAULT_ACCESSIBLE,\n  accessibilityRole = DEFAULT_ACCESSIBILITY_ROLE,\n  accessibilityLabel = DEFAULT_ACCESSIBILITY_LABEL,\n  accessibilityHint = DEFAULT_ACCESSIBILITY_HINT,\n  children,\n}: BottomSheetDefaultHandleProps) {\n  //#region styles\n  const containerStyle = useMemo(\n    () => [styles.container, StyleSheet.flatten(style)],\n    [style]\n  );\n  const indicatorStyle = useMemo(\n    () => [styles.indicator, StyleSheet.flatten(_indicatorStyle)],\n    [_indicatorStyle]\n  );\n  //#endregion\n\n  // render\n  return (\n    <View\n      style={containerStyle}\n      accessible={accessible ?? undefined}\n      accessibilityRole={accessibilityRole ?? undefined}\n      accessibilityLabel={accessibilityLabel ?? undefined}\n      accessibilityHint={accessibilityHint ?? undefined}\n      collapsable={true}\n    >\n      <View style={indicatorStyle} />\n      {children}\n    </View>\n  );\n}\n\nconst BottomSheetHandle = memo(BottomSheetHandleComponent);\nBottomSheetHandle.displayName = 'BottomSheetHandle';\n\nexport default BottomSheetHandle;\n"
  },
  {
    "path": "src/components/bottomSheetHandle/BottomSheetHandleContainer.tsx",
    "content": "import React, { memo, useCallback, useMemo, useRef } from 'react';\nimport type { LayoutChangeEvent, View } from 'react-native';\nimport { Gesture, GestureDetector } from 'react-native-gesture-handler';\nimport Animated from 'react-native-reanimated';\nimport {\n  type BoundingClientRect,\n  useBottomSheetGestureHandlers,\n  useBottomSheetInternal,\n  useBoundingClientRect,\n} from '../../hooks';\nimport { print } from '../../utilities';\nimport { DEFAULT_ENABLE_HANDLE_PANNING_GESTURE } from '../bottomSheet/constants';\nimport type { BottomSheetHandleContainerProps } from './types';\n\nfunction BottomSheetHandleContainerComponent({\n  animatedIndex,\n  animatedPosition,\n  simultaneousHandlers: _internalSimultaneousHandlers,\n  enableHandlePanningGesture = DEFAULT_ENABLE_HANDLE_PANNING_GESTURE,\n  handleComponent: HandleComponent,\n  handleStyle: _providedHandleStyle,\n  handleIndicatorStyle: _providedIndicatorStyle,\n}: BottomSheetHandleContainerProps) {\n  //#region refs\n  const ref = useRef<View>(null);\n  //#endregion\n\n  //#region hooks\n  const {\n    animatedLayoutState,\n    activeOffsetX,\n    activeOffsetY,\n    failOffsetX,\n    failOffsetY,\n    waitFor,\n    simultaneousHandlers: _providedSimultaneousHandlers,\n  } = useBottomSheetInternal();\n  const { handlePanGestureHandler } = useBottomSheetGestureHandlers();\n  //#endregion\n\n  //#region variables\n  const simultaneousHandlers = useMemo<unknown[]>(() => {\n    const refs = [];\n\n    if (_internalSimultaneousHandlers) {\n      refs.push(_internalSimultaneousHandlers);\n    }\n\n    if (_providedSimultaneousHandlers) {\n      if (Array.isArray(_providedSimultaneousHandlers)) {\n        refs.push(..._providedSimultaneousHandlers);\n      } else {\n        refs.push(_providedSimultaneousHandlers);\n      }\n    }\n\n    return refs;\n  }, [_providedSimultaneousHandlers, _internalSimultaneousHandlers]);\n  const panGesture = useMemo(() => {\n    let gesture = Gesture.Pan()\n      .enabled(enableHandlePanningGesture)\n      .shouldCancelWhenOutside(false)\n      .runOnJS(false)\n      .onStart(handlePanGestureHandler.handleOnStart)\n      .onChange(handlePanGestureHandler.handleOnChange)\n      .onEnd(handlePanGestureHandler.handleOnEnd)\n      .onFinalize(handlePanGestureHandler.handleOnFinalize);\n\n    if (waitFor) {\n      gesture = gesture.requireExternalGestureToFail(waitFor);\n    }\n\n    if (simultaneousHandlers) {\n      gesture = gesture.simultaneousWithExternalGesture(\n        simultaneousHandlers as never\n      );\n    }\n\n    if (activeOffsetX) {\n      gesture = gesture.activeOffsetX(activeOffsetX);\n    }\n\n    if (activeOffsetY) {\n      gesture = gesture.activeOffsetY(activeOffsetY);\n    }\n\n    if (failOffsetX) {\n      gesture = gesture.failOffsetX(failOffsetX);\n    }\n\n    if (failOffsetY) {\n      gesture = gesture.failOffsetY(failOffsetY);\n    }\n\n    return gesture;\n  }, [\n    activeOffsetX,\n    activeOffsetY,\n    enableHandlePanningGesture,\n    failOffsetX,\n    failOffsetY,\n    simultaneousHandlers,\n    waitFor,\n    handlePanGestureHandler.handleOnChange,\n    handlePanGestureHandler.handleOnEnd,\n    handlePanGestureHandler.handleOnFinalize,\n    handlePanGestureHandler.handleOnStart,\n  ]);\n  //#endregion\n\n  //#region callbacks\n  const handleContainerLayout = useCallback(\n    function handleContainerLayout({\n      nativeEvent: {\n        layout: { height },\n      },\n    }: LayoutChangeEvent) {\n      animatedLayoutState.modify(state => {\n        'worklet';\n        state.handleHeight = height;\n        return state;\n      });\n\n      if (__DEV__) {\n        print({\n          component: 'BottomSheetHandleContainer',\n          method: 'handleContainerLayout',\n          category: 'layout',\n          params: {\n            height,\n          },\n        });\n      }\n    },\n    [animatedLayoutState]\n  );\n  const handleBoundingClientRect = useCallback(\n    ({ height }: BoundingClientRect) => {\n      animatedLayoutState.modify(state => {\n        'worklet';\n        state.handleHeight = height;\n        return state;\n      });\n\n      if (__DEV__) {\n        print({\n          component: 'BottomSheetHandleContainer',\n          method: 'handleBoundingClientRect',\n          category: 'layout',\n          params: {\n            height,\n          },\n        });\n      }\n    },\n    [animatedLayoutState]\n  );\n  //#endregion\n\n  //#region effects\n  useBoundingClientRect(ref, handleBoundingClientRect);\n  //#endregion\n\n  //#region renders\n  return (\n    <GestureDetector gesture={panGesture}>\n      <Animated.View\n        ref={ref}\n        onLayout={handleContainerLayout}\n        key=\"BottomSheetHandleContainer\"\n      >\n        <HandleComponent\n          animatedIndex={animatedIndex}\n          animatedPosition={animatedPosition}\n          style={_providedHandleStyle}\n          indicatorStyle={_providedIndicatorStyle}\n        />\n      </Animated.View>\n    </GestureDetector>\n  );\n  //#endregion\n}\n\nconst BottomSheetHandleContainer = memo(BottomSheetHandleContainerComponent);\nBottomSheetHandleContainer.displayName = 'BottomSheetHandleContainer';\n\nexport default BottomSheetHandleContainer;\n"
  },
  {
    "path": "src/components/bottomSheetHandle/constants.ts",
    "content": "const DEFAULT_ACCESSIBLE = true;\nconst DEFAULT_ACCESSIBILITY_ROLE = 'adjustable';\nconst DEFAULT_ACCESSIBILITY_LABEL = 'Bottom sheet handle';\nconst DEFAULT_ACCESSIBILITY_HINT =\n  'Drag up or down to extend or minimize the bottom sheet';\n\nexport {\n  DEFAULT_ACCESSIBLE,\n  DEFAULT_ACCESSIBILITY_ROLE,\n  DEFAULT_ACCESSIBILITY_LABEL,\n  DEFAULT_ACCESSIBILITY_HINT,\n};\n"
  },
  {
    "path": "src/components/bottomSheetHandle/index.ts",
    "content": "export { default as BottomSheetHandle } from './BottomSheetHandle';\nexport { default as BottomSheetHandleContainer } from './BottomSheetHandleContainer';\nexport type {\n  BottomSheetHandleProps,\n  BottomSheetHandleContainerProps,\n} from './types';\n"
  },
  {
    "path": "src/components/bottomSheetHandle/styles.ts",
    "content": "import { Platform, StyleSheet } from 'react-native';\nimport { WINDOW_WIDTH } from '../../constants';\n\n\nexport const styles = StyleSheet.create({\n  container: {\n    padding: 10,\n    ...Platform.select({\n      web: {\n        cursor: 'pointer' as const\n      },\n      default: {}\n    }),\n  },\n\n  indicator: {\n    alignSelf: 'center',\n    width: (7.5 * WINDOW_WIDTH) / 100,\n    height: 4,\n    borderRadius: 4,\n    backgroundColor: 'rgba(0, 0, 0, 0.75)',\n  },\n});\n"
  },
  {
    "path": "src/components/bottomSheetHandle/types.d.ts",
    "content": "import type React from 'react';\nimport type { View, ViewProps } from 'react-native';\nimport type { PanGestureHandlerProperties } from 'react-native-gesture-handler';\nimport type { AnimateProps, SharedValue } from 'react-native-reanimated';\nimport type { useInteractivePanGestureHandlerConfigs } from '../../hooks/useGestureHandler';\nimport type {\n  BottomSheetVariables,\n  NullableAccessibilityProps,\n} from '../../types';\nimport type { BottomSheetProps } from '../bottomSheet';\n\nexport type BottomSheetHandleProps = BottomSheetVariables;\nexport interface BottomSheetDefaultHandleProps\n  extends BottomSheetHandleProps,\n    NullableAccessibilityProps {\n  /**\n   * View style to be applied to the handle container.\n   * @type ViewStyle\n   * @default undefined\n   */\n  style?: ViewProps['style'];\n  /**\n   * View style to be applied to the handle indicator.\n   * @type ViewStyle\n   * @default undefined\n   */\n  indicatorStyle?: ViewProps['style'];\n  /**\n   * Content to be added below the indicator.\n   * @type React.ReactNode | React.ReactNode[];\n   * @default undefined\n   */\n  children?: React.ReactNode | React.ReactNode[];\n}\n\nexport type BottomSheetHandleContainerProps = Pick<\n  PanGestureHandlerProperties,\n  'simultaneousHandlers'\n> & {\n  handleComponent: React.FC<BottomSheetDefaultHandleProps>;\n} & Pick<\n    BottomSheetProps,\n    'enableHandlePanningGesture' | 'handleIndicatorStyle' | 'handleStyle'\n  > &\n  Pick<\n    useInteractivePanGestureHandlerConfigs,\n    | 'enableOverDrag'\n    | 'enablePanDownToClose'\n    | 'overDragResistanceFactor'\n    | 'keyboardBehavior'\n  > &\n  BottomSheetHandleProps;\n"
  },
  {
    "path": "src/components/bottomSheetHostingContainer/BottomSheetHostingContainer.tsx",
    "content": "import React, { memo, useCallback, useMemo, useRef } from 'react';\nimport {\n  type LayoutChangeEvent,\n  StatusBar,\n  type StyleProp,\n  View,\n  type ViewStyle,\n} from 'react-native';\nimport { WINDOW_HEIGHT } from '../../constants';\nimport { print } from '../../utilities';\nimport { styles } from './styles';\nimport type { BottomSheetHostingContainerProps } from './types';\n\nfunction BottomSheetHostingContainerComponent({\n  containerLayoutState,\n  layoutState,\n  topInset = 0,\n  bottomInset = 0,\n  shouldCalculateHeight = true,\n  detached,\n  style,\n  children,\n}: BottomSheetHostingContainerProps) {\n  //#region refs\n  const containerRef = useRef<View>(null);\n  //#endregion\n\n  //#region styles\n  const containerStyle = useMemo<StyleProp<ViewStyle>>(\n    () => [\n      style,\n      styles.container,\n      {\n        top: topInset,\n        bottom: bottomInset,\n        overflow: detached ? 'visible' : 'hidden',\n      },\n    ],\n    [style, detached, topInset, bottomInset]\n  );\n  //#endregion\n\n  //#region callbacks\n  const handleLayoutEvent = useCallback(\n    function handleLayoutEvent({\n      nativeEvent: {\n        layout: { height },\n      },\n    }: LayoutChangeEvent) {\n      if (containerLayoutState) {\n        containerLayoutState.modify(state => {\n          'worklet';\n          state.height = height;\n          return state;\n        });\n      }\n\n      if (layoutState) {\n        layoutState.modify(state => {\n          'worklet';\n          state.rawContainerHeight = height;\n          return state;\n        });\n      }\n\n      containerRef.current?.measure(\n        (_x, _y, _width, _height, _pageX, pageY) => {\n          const offset = {\n            bottom: Math.max(\n              0,\n              WINDOW_HEIGHT -\n                ((pageY ?? 0) + height + (StatusBar.currentHeight ?? 0))\n            ),\n            top: pageY ?? 0,\n            left: 0,\n            right: 0,\n          };\n\n          if (containerLayoutState) {\n            containerLayoutState.modify(state => {\n              'worklet';\n              state.offset = offset;\n              return state;\n            });\n          }\n\n          if (layoutState) {\n            layoutState.modify(state => {\n              'worklet';\n              state.containerOffset = offset;\n              return state;\n            });\n          }\n        }\n      );\n\n      if (__DEV__) {\n        print({\n          component: 'BottomSheetHostingContainer',\n          method: 'handleLayoutEvent',\n          category: 'layout',\n          params: {\n            height,\n          },\n        });\n      }\n    },\n    [layoutState, containerLayoutState]\n  );\n  //#endregion\n\n  //#region render\n  return (\n    <View\n      ref={containerRef}\n      pointerEvents=\"box-none\"\n      onLayout={shouldCalculateHeight ? handleLayoutEvent : undefined}\n      style={containerStyle}\n      collapsable={true}\n    >\n      {children}\n    </View>\n  );\n  //#endregion\n}\n\nexport const BottomSheetHostingContainer = memo(\n  BottomSheetHostingContainerComponent\n);\nBottomSheetHostingContainer.displayName = 'BottomSheetHostingContainer';\n"
  },
  {
    "path": "src/components/bottomSheetHostingContainer/index.ts",
    "content": "export { BottomSheetHostingContainer } from './BottomSheetHostingContainer';\nexport type { BottomSheetHostingContainerProps } from './types';\n"
  },
  {
    "path": "src/components/bottomSheetHostingContainer/styles.ts",
    "content": "import { StyleSheet } from 'react-native';\n\nexport const styles = StyleSheet.create({\n  container: { ...StyleSheet.absoluteFillObject, pointerEvents: 'box-none' },\n});\n"
  },
  {
    "path": "src/components/bottomSheetHostingContainer/styles.web.ts",
    "content": "import { StyleSheet } from 'react-native';\n\nexport const styles = StyleSheet.create({\n  container: {\n    position: 'absolute',\n    left: 0,\n    right: 0,\n    bottom: 0,\n    top: 0,\n  },\n});\n"
  },
  {
    "path": "src/components/bottomSheetHostingContainer/types.d.ts",
    "content": "import type { ReactNode } from 'react';\nimport type { Insets, StyleProp, ViewStyle } from 'react-native';\nimport type { SharedValue } from 'react-native-reanimated';\nimport type { ContainerLayoutState, LayoutState } from '../../types';\nimport type { BottomSheetProps } from '../bottomSheet/types';\n\nexport interface BottomSheetHostingContainerProps\n  extends Partial<\n    Pick<BottomSheetProps, 'topInset' | 'bottomInset' | 'detached'>\n  > {\n  containerLayoutState?: SharedValue<ContainerLayoutState>;\n  layoutState?: SharedValue<LayoutState>;\n\n  shouldCalculateHeight?: boolean;\n  style?: StyleProp<ViewStyle>;\n  children?: ReactNode;\n}\n"
  },
  {
    "path": "src/components/bottomSheetModal/BottomSheetModal.tsx",
    "content": "import { Portal, usePortal } from '@gorhom/portal';\nimport React, {\n  forwardRef,\n  memo,\n  type RefObject,\n  useCallback,\n  useImperativeHandle,\n  useMemo,\n  useRef,\n  useState,\n} from 'react';\nimport type { SNAP_POINT_TYPE } from '../../constants';\nimport { useBottomSheetModalInternal } from '../../hooks';\nimport type { BottomSheetMethods, BottomSheetModalMethods } from '../../types';\nimport { print } from '../../utilities';\nimport { id } from '../../utilities/id';\nimport BottomSheet from '../bottomSheet';\nimport {\n  DEFAULT_ENABLE_DISMISS_ON_CLOSE,\n  DEFAULT_STACK_BEHAVIOR,\n} from './constants';\nimport type {\n  BottomSheetModalPrivateMethods,\n  BottomSheetModalProps,\n  BottomSheetModalState,\n} from './types';\n\nconst INITIAL_STATE: BottomSheetModalState = {\n  mount: false,\n  data: undefined,\n};\n\n// biome-ignore lint/suspicious/noExplicitAny: Using 'any' allows users to define their own strict types for 'data' property.\ntype BottomSheetModal<T = any> = BottomSheetModalMethods<T>;\n\n// biome-ignore lint/suspicious/noExplicitAny: Using 'any' allows users to define their own strict types for 'data' property.\nfunction BottomSheetModalComponent<T = any>(\n  props: BottomSheetModalProps<T>,\n  ref: React.ForwardedRef<BottomSheetModal<T>>\n) {\n  const {\n    // modal props\n    name,\n    stackBehavior = DEFAULT_STACK_BEHAVIOR,\n    enableDismissOnClose = DEFAULT_ENABLE_DISMISS_ON_CLOSE,\n    onDismiss: _providedOnDismiss,\n    onAnimate: _providedOnAnimate,\n\n    // bottom sheet props\n    index = 0,\n    snapPoints,\n    enablePanDownToClose = true,\n    animateOnMount = true,\n    containerComponent: ContainerComponent = React.Fragment,\n\n    // callbacks\n    onChange: _providedOnChange,\n\n    // components\n    children: Content,\n    ...bottomSheetProps\n  } = props;\n\n  //#region state\n  const [{ mount, data }, setState] =\n    useState<BottomSheetModalState<T>>(INITIAL_STATE);\n  //#endregion\n\n  //#region hooks\n  const {\n    hostName,\n    containerLayoutState,\n    mountSheet,\n    unmountSheet,\n    willUnmountSheet,\n  } = useBottomSheetModalInternal();\n  const { removePortal: unmountPortal } = usePortal(hostName);\n  //#endregion\n\n  //#region refs\n  const bottomSheetRef = useRef<BottomSheet>(null);\n  const currentIndexRef = useRef(!animateOnMount ? index : -1);\n  const nextIndexRef = useRef<number | null>(null);\n  const restoreIndexRef = useRef(-1);\n  const minimized = useRef(false);\n  const forcedDismissed = useRef(false);\n  const mounted = useRef(false);\n  mounted.current = mount;\n  //#endregion\n\n  //#region variables\n  const key = useMemo(() => name || `bottom-sheet-modal-${id()}`, [name]);\n  //#endregion\n\n  //#region private methods\n  const resetVariables = useCallback(function resetVariables() {\n    print({\n      component: BottomSheetModal.name,\n      method: resetVariables.name,\n    });\n    currentIndexRef.current = -1;\n    restoreIndexRef.current = -1;\n    minimized.current = false;\n    mounted.current = false;\n    forcedDismissed.current = false;\n  }, []);\n  const unmount = useCallback(\n    function unmount() {\n      if (__DEV__) {\n        print({\n          component: BottomSheetModal.name,\n          method: unmount.name,\n        });\n      }\n      const _mounted = mounted.current;\n\n      // reset variables\n      resetVariables();\n\n      // unmount sheet and portal\n      unmountSheet(key);\n      unmountPortal(key);\n\n      // unmount the node, if sheet is still mounted\n      if (_mounted) {\n        setState(INITIAL_STATE);\n      }\n\n      // fire `onDismiss` callback\n      if (_providedOnDismiss) {\n        _providedOnDismiss();\n      }\n    },\n    [key, resetVariables, unmountSheet, unmountPortal, _providedOnDismiss]\n  );\n  //#endregion\n\n  //#region bottom sheet methods\n  const handleSnapToIndex = useCallback<BottomSheetMethods['snapToIndex']>(\n    (...args) => {\n      if (minimized.current) {\n        return;\n      }\n      bottomSheetRef.current?.snapToIndex(...args);\n    },\n    []\n  );\n  const handleSnapToPosition = useCallback<\n    BottomSheetMethods['snapToPosition']\n  >((...args) => {\n    if (minimized.current) {\n      return;\n    }\n    bottomSheetRef.current?.snapToPosition(...args);\n  }, []);\n  const handleExpand: BottomSheetMethods['expand'] = useCallback((...args) => {\n    if (minimized.current) {\n      return;\n    }\n    bottomSheetRef.current?.expand(...args);\n  }, []);\n  const handleCollapse: BottomSheetMethods['collapse'] = useCallback(\n    (...args) => {\n      if (minimized.current) {\n        return;\n      }\n      bottomSheetRef.current?.collapse(...args);\n    },\n    []\n  );\n  const handleClose: BottomSheetMethods['close'] = useCallback((...args) => {\n    if (minimized.current) {\n      return;\n    }\n    bottomSheetRef.current?.close(...args);\n  }, []);\n  const handleForceClose: BottomSheetMethods['forceClose'] = useCallback(\n    (...args) => {\n      if (minimized.current) {\n        return;\n      }\n      bottomSheetRef.current?.forceClose(...args);\n    },\n    []\n  );\n  //#endregion\n\n  //#region bottom sheet modal methods\n  // biome-ignore lint/correctness/useExhaustiveDependencies(BottomSheetModal.name): used for debug only\n  // biome-ignore lint/correctness/useExhaustiveDependencies(ref): ref is a stable object\n  const handlePresent = useCallback(\n    function handlePresent(_data?: T) {\n      requestAnimationFrame(() => {\n        setState({\n          mount: true,\n          data: _data,\n        });\n        mountSheet(\n          key,\n          ref as unknown as RefObject<BottomSheetModalPrivateMethods>,\n          stackBehavior\n        );\n        ref;\n\n        if (__DEV__) {\n          print({\n            component: BottomSheetModal.name,\n            method: handlePresent.name,\n          });\n        }\n      });\n    },\n    // eslint-disable-next-line react-hooks/exhaustive-deps\n    [key, stackBehavior, mountSheet]\n  );\n  // biome-ignore lint/correctness/useExhaustiveDependencies(BottomSheetModal.name): used for debug only\n  const handleDismiss = useCallback<BottomSheetModalMethods['dismiss']>(\n    function handleDismiss(animationConfigs) {\n      if (__DEV__) {\n        print({\n          component: BottomSheetModal.name,\n          method: handleDismiss.name,\n          params: {\n            currentIndexRef: currentIndexRef.current,\n            minimized: minimized.current,\n          },\n        });\n      }\n\n      const animating = nextIndexRef.current != null;\n\n      /**\n       * early exit, if not minimized, it is in closed position and not animating\n       */\n      if (\n        currentIndexRef.current === -1 &&\n        minimized.current === false &&\n        !animating\n      ) {\n        return;\n      }\n\n      /**\n       * unmount and early exit, if minimized or it is in closed position and not animating\n       */\n      if (\n        !animating &&\n        (minimized.current ||\n          (currentIndexRef.current === -1 && enablePanDownToClose))\n      ) {\n        unmount();\n        return;\n      }\n      willUnmountSheet(key);\n      forcedDismissed.current = true;\n      bottomSheetRef.current?.forceClose(animationConfigs);\n    },\n    [willUnmountSheet, unmount, key, enablePanDownToClose]\n  );\n  const handleMinimize = useCallback(\n    function handleMinimize() {\n      if (__DEV__) {\n        print({\n          component: BottomSheetModal.name,\n          method: handleMinimize.name,\n          params: {\n            minimized: minimized.current,\n          },\n        });\n      }\n      if (minimized.current) {\n        return;\n      }\n      minimized.current = true;\n\n      /**\n       * if modal got minimized before it finish its mounting\n       * animation, we set the `restoreIndexRef` to the\n       * provided index.\n       */\n      if (currentIndexRef.current === -1) {\n        restoreIndexRef.current = index;\n      } else {\n        restoreIndexRef.current = currentIndexRef.current;\n      }\n      bottomSheetRef.current?.close();\n    },\n    [index]\n  );\n  // biome-ignore lint/correctness/useExhaustiveDependencies(BottomSheetModal.name): used for debug only\n  const handleRestore = useCallback(function handleRestore() {\n    if (__DEV__) {\n      print({\n        component: BottomSheetModal.name,\n        method: handleRestore.name,\n        params: {\n          minimized: minimized.current,\n          forcedDismissed: forcedDismissed.current,\n        },\n      });\n    }\n    if (!minimized.current || forcedDismissed.current) {\n      return;\n    }\n    minimized.current = false;\n    bottomSheetRef.current?.snapToIndex(restoreIndexRef.current);\n  }, []);\n  //#endregion\n\n  //#region callbacks\n  const handlePortalOnUnmount = useCallback(\n    function handlePortalOnUnmount() {\n      if (__DEV__) {\n        print({\n          component: BottomSheetModal.name,\n          method: handlePortalOnUnmount.name,\n          params: {\n            minimized: minimized.current,\n            forcedDismissed: forcedDismissed.current,\n          },\n        });\n      }\n      /**\n       * if modal is already been dismiss, we exit the method.\n       */\n      if (currentIndexRef.current === -1 && minimized.current === false) {\n        return;\n      }\n\n      mounted.current = false;\n      forcedDismissed.current = true;\n\n      if (minimized.current) {\n        unmount();\n        return;\n      }\n      willUnmountSheet(key);\n      bottomSheetRef.current?.close();\n    },\n    [key, unmount, willUnmountSheet]\n  );\n  const handlePortalRender = useCallback(function handlePortalRender(\n    render: () => void\n  ) {\n    if (mounted.current) {\n      render();\n    }\n  }, []);\n  // biome-ignore lint/correctness/useExhaustiveDependencies(BottomSheetModal.name): used for debug only\n  const handleBottomSheetOnChange = useCallback(\n    function handleBottomSheetOnChange(\n      _index: number,\n      _position: number,\n      _type: SNAP_POINT_TYPE\n    ) {\n      if (__DEV__) {\n        print({\n          component: BottomSheetModal.name,\n          method: handleBottomSheetOnChange.name,\n          category: 'callback',\n          params: {\n            minimized: minimized.current,\n            forcedDismissed: forcedDismissed.current,\n          },\n        });\n      }\n      currentIndexRef.current = _index;\n      nextIndexRef.current = null;\n\n      if (_providedOnChange) {\n        _providedOnChange(_index, _position, _type);\n      }\n    },\n    [_providedOnChange]\n  );\n  const handleBottomSheetOnAnimate = useCallback(\n    (\n      fromIndex: number,\n      toIndex: number,\n      fromPosition: number,\n      toPosition: number\n    ) => {\n      nextIndexRef.current = toIndex;\n\n      if (_providedOnAnimate) {\n        _providedOnAnimate(fromIndex, toIndex, fromPosition, toPosition);\n      }\n    },\n    [_providedOnAnimate]\n  );\n  // biome-ignore lint/correctness/useExhaustiveDependencies(BottomSheetModal.name): used for debug only\n  const handleBottomSheetOnClose = useCallback(\n    function handleBottomSheetOnClose() {\n      if (__DEV__) {\n        print({\n          component: BottomSheetModal.name,\n          method: handleBottomSheetOnClose.name,\n          category: 'callback',\n          params: {\n            minimized: minimized.current,\n            forcedDismissed: forcedDismissed.current,\n          },\n        });\n      }\n\n      if (minimized.current) {\n        return;\n      }\n\n      if (enableDismissOnClose) {\n        unmount();\n      }\n    },\n    [enableDismissOnClose, unmount]\n  );\n  //#endregion\n\n  //#region expose methods\n  useImperativeHandle(ref, () => ({\n    // sheet\n    snapToIndex: handleSnapToIndex,\n    snapToPosition: handleSnapToPosition,\n    expand: handleExpand,\n    collapse: handleCollapse,\n    close: handleClose,\n    forceClose: handleForceClose,\n    // modal methods\n    dismiss: handleDismiss,\n    present: handlePresent,\n    // internal\n    minimize: handleMinimize,\n    restore: handleRestore,\n  }));\n  //#endregion\n\n  // render\n  return mount ? (\n    <Portal\n      key={key}\n      name={key}\n      hostName={hostName}\n      handleOnMount={handlePortalRender}\n      handleOnUpdate={handlePortalRender}\n      handleOnUnmount={handlePortalOnUnmount}\n    >\n      <ContainerComponent key={key}>\n        <BottomSheet\n          {...bottomSheetProps}\n          ref={bottomSheetRef}\n          key={key}\n          index={index}\n          snapPoints={snapPoints}\n          enablePanDownToClose={enablePanDownToClose}\n          animateOnMount={animateOnMount}\n          containerLayoutState={containerLayoutState}\n          onChange={handleBottomSheetOnChange}\n          onClose={handleBottomSheetOnClose}\n          onAnimate={handleBottomSheetOnAnimate}\n          $modal={true}\n        >\n          {typeof Content === 'function' ? <Content data={data} /> : Content}\n        </BottomSheet>\n      </ContainerComponent>\n    </Portal>\n  ) : null;\n}\n\nconst BottomSheetModal = memo(forwardRef(BottomSheetModalComponent)) as <\n  // biome-ignore lint/suspicious/noExplicitAny: Using 'any' allows users to define their own strict types for 'data' property.\n  T = any,\n>(\n  props: BottomSheetModalProps<T> & {\n    ref?: React.ForwardedRef<BottomSheetModal<T>>;\n  }\n) => ReturnType<typeof BottomSheetModalComponent>;\n(\n  BottomSheetModal as React.MemoExoticComponent<\n    typeof BottomSheetModalComponent\n  >\n).displayName = 'BottomSheetModal';\n\nexport default BottomSheetModal;\n"
  },
  {
    "path": "src/components/bottomSheetModal/constants.ts",
    "content": "const DEFAULT_STACK_BEHAVIOR = 'switch';\nconst DEFAULT_ENABLE_DISMISS_ON_CLOSE = true;\n\nexport { DEFAULT_STACK_BEHAVIOR, DEFAULT_ENABLE_DISMISS_ON_CLOSE };\n"
  },
  {
    "path": "src/components/bottomSheetModal/index.ts",
    "content": "export { default } from './BottomSheetModal';\nexport type {\n  BottomSheetModalProps,\n  BottomSheetModalPrivateMethods,\n  BottomSheetModalStackBehavior,\n} from './types';\n"
  },
  {
    "path": "src/components/bottomSheetModal/types.d.ts",
    "content": "import type React from 'react';\nimport type { View } from 'react-native';\nimport type { MODAL_STACK_BEHAVIOR } from '../../constants';\nimport type { BottomSheetProps } from '../bottomSheet';\n\nexport interface BottomSheetModalPrivateMethods {\n  dismiss: (force?: boolean) => void;\n  minimize: () => void;\n  restore: () => void;\n}\n\nexport type BottomSheetModalStackBehavior = keyof typeof MODAL_STACK_BEHAVIOR;\n\n// biome-ignore lint/suspicious/noExplicitAny: Using 'any' allows users to define their own strict types for 'data' property.\nexport interface BottomSheetModalProps<T = any>\n  extends Omit<BottomSheetProps, 'containerHeight' | 'onClose'> {\n  /**\n   * Modal name to help identify the modal for later on.\n   * @type string\n   * @default generated unique key.\n   */\n  name?: string;\n\n  /**\n   * Defines the stack behavior when modal mount.\n   * - `push` it will mount the modal on top of the current one.\n   * - `switch` it will minimize the current modal then mount the new one.\n   * - `replace` it will dismiss the current modal then mount the new one.\n   * @type `push` | `switch` | `replace`\n   * @default switch\n   */\n  stackBehavior?: BottomSheetModalStackBehavior;\n\n  /**\n   * Enable dismiss the modal when it is closed.\n   * @type boolean\n   * @default true\n   */\n  enableDismissOnClose?: boolean;\n\n  /**\n   * Add a custom container like FullWindowOverlay\n   * allow to fix issue like https://github.com/gorhom/react-native-bottom-sheet/issues/832\n   * @type React.ComponentType\n   * @default undefined\n   */\n  containerComponent?: React.ComponentType<React.PropsWithChildren>;\n\n  // callbacks\n  /**\n   * Callback when the modal dismissed.\n   * @type () => void;\n   */\n  onDismiss?: () => void;\n\n  /**\n   * A scrollable node or normal view.\n   * @type React.ReactNode[] | React.ReactNode | (({ data: any }?) => React.ReactElement)\n   */\n  children: React.FC<{ data?: T }> | React.ReactNode[] | React.ReactNode;\n}\n\n// biome-ignore lint/suspicious/noExplicitAny: Using 'any' allows users to define their own strict types for 'data' property.\nexport interface BottomSheetModalState<T = any> {\n  mount: boolean;\n  data: T | undefined;\n}\n"
  },
  {
    "path": "src/components/bottomSheetModalProvider/BottomSheetModalProvider.tsx",
    "content": "import { PortalProvider } from '@gorhom/portal';\nimport React, { useCallback, useMemo, useRef } from 'react';\nimport { useSharedValue } from 'react-native-reanimated';\nimport {\n  INITIAL_CONTAINER_LAYOUT,\n  MODAL_STACK_BEHAVIOR,\n} from '../../constants';\nimport {\n  BottomSheetModalInternalProvider,\n  BottomSheetModalProvider,\n} from '../../contexts';\nimport type { ContainerLayoutState } from '../../types';\nimport { id } from '../../utilities/id';\nimport { BottomSheetHostingContainer } from '../bottomSheetHostingContainer';\nimport type {\n  BottomSheetModalPrivateMethods,\n  BottomSheetModalStackBehavior,\n} from '../bottomSheetModal';\nimport type {\n  BottomSheetModalProviderProps,\n  BottomSheetModalRef,\n} from './types';\n\nconst BottomSheetModalProviderWrapper = ({\n  children,\n}: BottomSheetModalProviderProps) => {\n  //#region layout variables\n  const animatedContainerLayoutState = useSharedValue<ContainerLayoutState>(\n    INITIAL_CONTAINER_LAYOUT\n  );\n  //#endregion\n\n  //#region variables\n  const hostName = useMemo(() => `bottom-sheet-portal-${id()}`, []);\n  const sheetsQueueRef = useRef<BottomSheetModalRef[]>([]);\n  //#endregion\n\n  //#region private methods\n  const handleMountSheet = useCallback(\n    (\n      key: string,\n      ref: React.RefObject<BottomSheetModalPrivateMethods>,\n      stackBehavior: BottomSheetModalStackBehavior\n    ) => {\n      const _sheetsQueue = sheetsQueueRef.current.slice();\n      const sheetIndex = _sheetsQueue.findIndex(item => item.key === key);\n      const sheetOnTop = sheetIndex === _sheetsQueue.length - 1;\n\n      /**\n       * Exit the method, if sheet is already presented\n       * and at the top.\n       */\n      if (sheetIndex !== -1 && sheetOnTop) {\n        return;\n      }\n\n      /**\n       * Minimize the current sheet if:\n       * - it exists.\n       * - it is not unmounting.\n       * - stack behavior is 'replace'.\n       */\n\n      /**\n       * Handle switch or replace stack behaviors, if:\n       * - a modal is currently presented.\n       * - it is not unmounting\n       */\n      const currentMountedSheet = _sheetsQueue[_sheetsQueue.length - 1];\n      if (currentMountedSheet && !currentMountedSheet.willUnmount) {\n        if (stackBehavior === MODAL_STACK_BEHAVIOR.replace) {\n          currentMountedSheet.ref?.current?.dismiss();\n        } else if (stackBehavior === MODAL_STACK_BEHAVIOR.switch) {\n          currentMountedSheet.ref?.current?.minimize();\n        }\n      }\n\n      /**\n       * Restore and remove incoming sheet from the queue,\n       * if it was registered.\n       */\n      if (sheetIndex !== -1) {\n        _sheetsQueue.splice(sheetIndex, 1);\n        ref?.current?.restore();\n      }\n\n      _sheetsQueue.push({\n        key,\n        ref,\n        willUnmount: false,\n      });\n      sheetsQueueRef.current = _sheetsQueue;\n    },\n    []\n  );\n  const handleUnmountSheet = useCallback((key: string) => {\n    const _sheetsQueue = sheetsQueueRef.current.slice();\n    const sheetIndex = _sheetsQueue.findIndex(item => item.key === key);\n    const sheetOnTop = sheetIndex === _sheetsQueue.length - 1;\n\n    /**\n     * Here we remove the unmounted sheet and update\n     * the sheets queue.\n     */\n    _sheetsQueue.splice(sheetIndex, 1);\n    sheetsQueueRef.current = _sheetsQueue;\n\n    /**\n     * Here we try to restore previous sheet position if unmounted\n     * sheet was on top. This is needed when user dismiss\n     * the modal by panning down.\n     */\n    const hasMinimizedSheet = sheetsQueueRef.current.length > 0;\n    const minimizedSheet =\n      sheetsQueueRef.current[sheetsQueueRef.current.length - 1];\n    if (\n      sheetOnTop &&\n      hasMinimizedSheet &&\n      minimizedSheet &&\n      !minimizedSheet.willUnmount\n    ) {\n      sheetsQueueRef.current[\n        sheetsQueueRef.current.length - 1\n      ].ref?.current?.restore();\n    }\n  }, []);\n  const handleWillUnmountSheet = useCallback((key: string) => {\n    const _sheetsQueue = sheetsQueueRef.current.slice();\n    const sheetIndex = _sheetsQueue.findIndex(item => item.key === key);\n    const sheetOnTop = sheetIndex === _sheetsQueue.length - 1;\n\n    /**\n     * Here we mark the sheet that will unmount,\n     * so it won't be restored.\n     */\n    if (sheetIndex !== -1) {\n      _sheetsQueue[sheetIndex].willUnmount = true;\n    }\n\n    /**\n     * Here we try to restore previous sheet position,\n     * This is needed when user dismiss the modal by fire the dismiss action.\n     */\n    const hasMinimizedSheet = _sheetsQueue.length > 1;\n    if (sheetOnTop && hasMinimizedSheet) {\n      _sheetsQueue[_sheetsQueue.length - 2].ref?.current?.restore();\n    }\n\n    sheetsQueueRef.current = _sheetsQueue;\n  }, []);\n  //#endregion\n\n  //#region public methods\n  const handleDismiss = useCallback((key?: string) => {\n    const sheetToBeDismissed = key\n      ? sheetsQueueRef.current.find(item => item.key === key)\n      : sheetsQueueRef.current[sheetsQueueRef.current.length - 1];\n    if (sheetToBeDismissed) {\n      sheetToBeDismissed.ref?.current?.dismiss();\n      return true;\n    }\n    return false;\n  }, []);\n  const handleDismissAll = useCallback(() => {\n    sheetsQueueRef.current.map(item => {\n      item.ref?.current?.dismiss();\n    });\n  }, []);\n  //#endregion\n\n  //#region context variables\n  const externalContextVariables = useMemo(\n    () => ({\n      dismiss: handleDismiss,\n      dismissAll: handleDismissAll,\n    }),\n    [handleDismiss, handleDismissAll]\n  );\n  const internalContextVariables = useMemo(\n    () => ({\n      hostName,\n      containerLayoutState: animatedContainerLayoutState,\n      mountSheet: handleMountSheet,\n      unmountSheet: handleUnmountSheet,\n      willUnmountSheet: handleWillUnmountSheet,\n    }),\n    [\n      hostName,\n      animatedContainerLayoutState,\n      handleMountSheet,\n      handleUnmountSheet,\n      handleWillUnmountSheet,\n    ]\n  );\n  //#endregion\n\n  //#region renders\n  return (\n    <BottomSheetModalProvider value={externalContextVariables}>\n      <BottomSheetModalInternalProvider value={internalContextVariables}>\n        <BottomSheetHostingContainer\n          containerLayoutState={animatedContainerLayoutState}\n        />\n        <PortalProvider rootHostName={hostName}>{children}</PortalProvider>\n      </BottomSheetModalInternalProvider>\n    </BottomSheetModalProvider>\n  );\n  //#endregion\n};\n\nexport default BottomSheetModalProviderWrapper;\n"
  },
  {
    "path": "src/components/bottomSheetModalProvider/index.ts",
    "content": "export { default } from './BottomSheetModalProvider';\n"
  },
  {
    "path": "src/components/bottomSheetModalProvider/types.d.ts",
    "content": "import type { ReactNode, RefObject } from 'react';\nimport type { BottomSheetModalPrivateMethods } from '../bottomSheetModal';\n\nexport interface BottomSheetModalRef {\n  key: string;\n  ref: RefObject<BottomSheetModalPrivateMethods>;\n  willUnmount: boolean;\n}\n\nexport interface BottomSheetModalProviderProps {\n  children?: ReactNode;\n}\n"
  },
  {
    "path": "src/components/bottomSheetRefreshControl/BottomSheetRefreshControl.android.tsx",
    "content": "import React, { memo, useContext, useMemo } from 'react';\nimport { RefreshControl, type RefreshControlProps } from 'react-native';\nimport {\n  Gesture,\n  GestureDetector,\n  type SimultaneousGesture,\n} from 'react-native-gesture-handler';\nimport Animated, { useAnimatedProps } from 'react-native-reanimated';\nimport { SCROLLABLE_STATUS } from '../../constants';\nimport { BottomSheetDraggableContext } from '../../contexts/gesture';\nimport { useBottomSheetInternal } from '../../hooks';\n\nconst AnimatedRefreshControl = Animated.createAnimatedComponent(RefreshControl);\n\ninterface BottomSheetRefreshControlProps extends RefreshControlProps {\n  scrollableGesture: SimultaneousGesture;\n}\n\nfunction BottomSheetRefreshControlComponent({\n  onRefresh,\n  scrollableGesture,\n  ...rest\n}: BottomSheetRefreshControlProps) {\n  //#region hooks\n  const draggableGesture = useContext(BottomSheetDraggableContext);\n  const {\n    animatedScrollableStatus: animatedScrollableState,\n    enableContentPanningGesture,\n  } = useBottomSheetInternal();\n  //#endregion\n\n  if (!draggableGesture && enableContentPanningGesture) {\n    throw \"'BottomSheetRefreshControl' cannot be used out of the BottomSheet!\";\n  }\n\n  //#region variables\n  const animatedProps = useAnimatedProps(\n    () => ({\n      enabled: animatedScrollableState.value === SCROLLABLE_STATUS.UNLOCKED,\n    }),\n    [animatedScrollableState.value]\n  );\n\n  const gesture = useMemo(\n    () =>\n      draggableGesture\n        ? Gesture.Native()\n            // @ts-ignore\n            .simultaneousWithExternalGesture(\n              ...draggableGesture.toGestureArray(),\n              ...scrollableGesture.toGestureArray()\n            )\n            .shouldCancelWhenOutside(true)\n        : undefined,\n    [draggableGesture, scrollableGesture]\n  );\n\n  //#endregion\n\n  // render\n  if (gesture) {\n    return (\n      <GestureDetector gesture={gesture}>\n        <AnimatedRefreshControl\n          {...rest}\n          onRefresh={onRefresh}\n          animatedProps={animatedProps}\n        />\n      </GestureDetector>\n    );\n  }\n  return (\n    <AnimatedRefreshControl\n      {...rest}\n      onRefresh={onRefresh}\n      animatedProps={animatedProps}\n    />\n  );\n}\n\nconst BottomSheetRefreshControl = memo(BottomSheetRefreshControlComponent);\nBottomSheetRefreshControl.displayName = 'BottomSheetRefreshControl';\n\nexport default BottomSheetRefreshControl;\n"
  },
  {
    "path": "src/components/bottomSheetRefreshControl/BottomSheetRefreshControl.tsx",
    "content": "export default () => null;\n"
  },
  {
    "path": "src/components/bottomSheetRefreshControl/index.ts",
    "content": "import type React from 'react';\nimport type { RefreshControlProps } from 'react-native';\nimport type {\n  NativeViewGestureHandlerProps,\n  SimultaneousGesture,\n} from 'react-native-gesture-handler';\nimport BottomSheetRefreshControl from './BottomSheetRefreshControl';\n\nexport default BottomSheetRefreshControl as never as React.MemoExoticComponent<\n  React.ForwardRefExoticComponent<\n    RefreshControlProps & {\n      scrollableGesture: SimultaneousGesture;\n      children: React.ReactNode | React.ReactNode[];\n    } & React.RefAttributes<\n        React.ComponentType<\n          NativeViewGestureHandlerProps & React.RefAttributes<never>\n        >\n      >\n  >\n>;\n"
  },
  {
    "path": "src/components/bottomSheetScrollable/BottomSheetDraggableScrollable.tsx",
    "content": "import React from 'react';\nimport {\n  GestureDetector,\n  type SimultaneousGesture,\n} from 'react-native-gesture-handler';\n\ninterface BottomSheetDraggableScrollableProps {\n  scrollableGesture?: SimultaneousGesture;\n  children: React.ReactNode;\n}\n\nexport function BottomSheetDraggableScrollable({\n  scrollableGesture,\n  children,\n}: BottomSheetDraggableScrollableProps) {\n  if (scrollableGesture) {\n    return (\n      <GestureDetector gesture={scrollableGesture}>{children}</GestureDetector>\n    );\n  }\n\n  return children;\n}\n"
  },
  {
    "path": "src/components/bottomSheetScrollable/BottomSheetFlashList.tsx",
    "content": "// @ts-ignore\nimport type { FlashListProps } from '@shopify/flash-list';\nimport React, { forwardRef, memo, type Ref, useMemo } from 'react';\nimport type { ScrollViewProps } from 'react-native';\nimport type Animated from 'react-native-reanimated';\nimport BottomSheetScrollView from './BottomSheetScrollView';\nimport type {\n  BottomSheetScrollViewMethods,\n  BottomSheetScrollableProps,\n} from './types';\n\nlet FlashList: {\n  FlashList: React.FC;\n};\n// since FlashList is not a dependency for the library\n// we try to import it using metro optional import\ntry {\n  FlashList = require('@shopify/flash-list') as never;\n} catch (_) {}\n\nexport type BottomSheetFlashListProps<T> = Omit<\n  Animated.AnimateProps<FlashListProps<T>>,\n  'decelerationRate' | 'onScroll' | 'scrollEventThrottle'\n> &\n  BottomSheetScrollableProps & {\n    ref?: Ref<React.FC>;\n  };\n\nconst BottomSheetFlashListComponent = forwardRef<\n  React.FC,\n  // biome-ignore lint/suspicious/noExplicitAny: to be addressed\n  BottomSheetFlashListProps<any>\n>((props, ref) => {\n  //#region props\n  const {\n    focusHook,\n    scrollEventsHandlersHook,\n    enableFooterMarginAdjustment,\n    ...rest\n    // biome-ignore lint: to be addressed!\n  }: any = props;\n  //#endregion\n\n  useMemo(() => {\n    if (!FlashList) {\n      throw 'You need to install FlashList first, `yarn install @shopify/flash-list`';\n    }\n\n    console.warn(\n      'BottomSheetFlashList is deprecated, please use useBottomSheetScrollableCreator instead.'\n    );\n  }, []);\n\n  //#region render\n  const renderScrollComponent = useMemo(\n    () =>\n      forwardRef<BottomSheetScrollViewMethods, ScrollViewProps>(\n        // @ts-ignore\n        ({ data, ...props }, ref) => {\n          return (\n            // @ts-ignore\n            <BottomSheetScrollView\n              ref={ref}\n              {...props}\n              focusHook={focusHook}\n              scrollEventsHandlersHook={scrollEventsHandlersHook}\n              enableFooterMarginAdjustment={enableFooterMarginAdjustment}\n            />\n          );\n        }\n      ),\n    [focusHook, scrollEventsHandlersHook, enableFooterMarginAdjustment]\n  );\n  return (\n    <FlashList.FlashList\n      ref={ref}\n      renderScrollComponent={renderScrollComponent}\n      {...rest}\n    />\n  );\n  //#endregion\n});\n\nexport const BottomSheetFlashList = memo(BottomSheetFlashListComponent);\n\nexport default BottomSheetFlashList as <T>(\n  props: BottomSheetFlashListProps<T>\n) => ReturnType<typeof BottomSheetFlashList>;\n"
  },
  {
    "path": "src/components/bottomSheetScrollable/BottomSheetFlashList.web.tsx",
    "content": "export default () => null;\n"
  },
  {
    "path": "src/components/bottomSheetScrollable/BottomSheetFlatList.tsx",
    "content": "import { type ComponentProps, memo } from 'react';\nimport { FlatList as RNFlatList } from 'react-native';\nimport Animated from 'react-native-reanimated';\nimport { SCROLLABLE_TYPE } from '../../constants';\nimport { createBottomSheetScrollableComponent } from './createBottomSheetScrollableComponent';\nimport type {\n  BottomSheetFlatListMethods,\n  BottomSheetFlatListProps,\n} from './types';\n\nconst AnimatedFlatList =\n  Animated.createAnimatedComponent<ComponentProps<typeof RNFlatList>>(\n    RNFlatList\n  );\n\nconst BottomSheetFlatListComponent = createBottomSheetScrollableComponent<\n  BottomSheetFlatListMethods,\n  BottomSheetFlatListProps<never>\n>(SCROLLABLE_TYPE.FLATLIST, AnimatedFlatList);\n\nconst BottomSheetFlatList = memo(BottomSheetFlatListComponent);\nBottomSheetFlatList.displayName = 'BottomSheetFlatList';\n\nexport default BottomSheetFlatList as <T>(\n  props: BottomSheetFlatListProps<T>\n) => ReturnType<typeof BottomSheetFlatList>;\n"
  },
  {
    "path": "src/components/bottomSheetScrollable/BottomSheetScrollView.tsx",
    "content": "import { memo } from 'react';\nimport {\n  ScrollView as RNScrollView,\n  type ScrollViewProps as RNScrollViewProps,\n} from 'react-native';\nimport Animated from 'react-native-reanimated';\nimport { SCROLLABLE_TYPE } from '../../constants';\nimport { createBottomSheetScrollableComponent } from './createBottomSheetScrollableComponent';\nimport type {\n  BottomSheetScrollViewMethods,\n  BottomSheetScrollViewProps,\n} from './types';\n\nconst AnimatedScrollView =\n  Animated.createAnimatedComponent<RNScrollViewProps>(RNScrollView);\n\nconst BottomSheetScrollViewComponent = createBottomSheetScrollableComponent<\n  BottomSheetScrollViewMethods,\n  BottomSheetScrollViewProps\n>(SCROLLABLE_TYPE.SCROLLVIEW, AnimatedScrollView);\n\nconst BottomSheetScrollView = memo(BottomSheetScrollViewComponent);\nBottomSheetScrollView.displayName = 'BottomSheetScrollView';\n\nexport default BottomSheetScrollView as (\n  props: BottomSheetScrollViewProps\n) => ReturnType<typeof BottomSheetScrollView>;\n"
  },
  {
    "path": "src/components/bottomSheetScrollable/BottomSheetSectionList.tsx",
    "content": "import { type ComponentProps, memo } from 'react';\nimport {\n  type DefaultSectionT,\n  SectionList as RNSectionList,\n} from 'react-native';\nimport Animated from 'react-native-reanimated';\nimport { SCROLLABLE_TYPE } from '../../constants';\nimport { createBottomSheetScrollableComponent } from './createBottomSheetScrollableComponent';\nimport type {\n  BottomSheetSectionListMethods,\n  BottomSheetSectionListProps,\n} from './types';\n\nconst AnimatedSectionList =\n  Animated.createAnimatedComponent<ComponentProps<typeof RNSectionList>>(\n    RNSectionList\n  );\n\nconst BottomSheetSectionListComponent = createBottomSheetScrollableComponent<\n  BottomSheetSectionListMethods,\n  BottomSheetSectionListProps<never, DefaultSectionT>\n>(SCROLLABLE_TYPE.SECTIONLIST, AnimatedSectionList);\n\nconst BottomSheetSectionList = memo(BottomSheetSectionListComponent);\nBottomSheetSectionList.displayName = 'BottomSheetSectionList';\n\nexport default BottomSheetSectionList as <ItemT, SectionT = DefaultSectionT>(\n  props: BottomSheetSectionListProps<ItemT, SectionT>\n) => ReturnType<typeof BottomSheetSectionList>;\n"
  },
  {
    "path": "src/components/bottomSheetScrollable/BottomSheetVirtualizedList.tsx",
    "content": "import { type ComponentProps, memo } from 'react';\nimport { VirtualizedList as RNVirtualizedList } from 'react-native';\nimport Animated from 'react-native-reanimated';\nimport { SCROLLABLE_TYPE } from '../../constants';\nimport { createBottomSheetScrollableComponent } from './createBottomSheetScrollableComponent';\nimport type {\n  BottomSheetVirtualizedListMethods,\n  BottomSheetVirtualizedListProps,\n} from './types';\n\nconst AnimatedVirtualizedList =\n  Animated.createAnimatedComponent<ComponentProps<typeof RNVirtualizedList>>(\n    RNVirtualizedList\n  );\n\nconst BottomSheetVirtualizedListComponent =\n  createBottomSheetScrollableComponent<\n    BottomSheetVirtualizedListMethods,\n    BottomSheetVirtualizedListProps<never>\n  >(SCROLLABLE_TYPE.VIRTUALIZEDLIST, AnimatedVirtualizedList);\n\nconst BottomSheetVirtualizedList = memo(BottomSheetVirtualizedListComponent);\nBottomSheetVirtualizedList.displayName = 'BottomSheetVirtualizedList';\n\nexport default BottomSheetVirtualizedList as <T>(\n  props: BottomSheetVirtualizedListProps<T>\n) => ReturnType<typeof BottomSheetVirtualizedList>;\n"
  },
  {
    "path": "src/components/bottomSheetScrollable/ScrollableContainer.android.tsx",
    "content": "import React, { forwardRef } from 'react';\nimport type { SimultaneousGesture } from 'react-native-gesture-handler';\nimport BottomSheetRefreshControl from '../bottomSheetRefreshControl';\nimport { BottomSheetDraggableScrollable } from './BottomSheetDraggableScrollable';\nimport { styles } from './styles';\n\ninterface ScrollableContainerProps {\n  nativeGesture: SimultaneousGesture;\n  // biome-ignore lint: to be addressed\n  refreshControl: any;\n  // biome-ignore lint: to be addressed\n  progressViewOffset: any;\n  // biome-ignore lint: to be addressed\n  refreshing: any;\n  // biome-ignore lint: to be addressed\n  onRefresh: any;\n  // biome-ignore lint: to be addressed\n  ScrollableComponent: any;\n}\n\n// biome-ignore lint: to be addressed\nexport const ScrollableContainer = forwardRef<any, ScrollableContainerProps>(\n  function ScrollableContainer(\n    {\n      nativeGesture,\n      refreshControl: _refreshControl,\n      refreshing,\n      progressViewOffset,\n      onRefresh,\n      ScrollableComponent,\n      ...rest\n    },\n    ref\n  ) {\n    const Scrollable = (\n      <BottomSheetDraggableScrollable scrollableGesture={nativeGesture}>\n        <ScrollableComponent ref={ref} {...rest} />\n      </BottomSheetDraggableScrollable>\n    );\n\n    return onRefresh ? (\n      <BottomSheetRefreshControl\n        scrollableGesture={nativeGesture}\n        refreshing={refreshing}\n        progressViewOffset={progressViewOffset}\n        onRefresh={onRefresh}\n        style={styles.container}\n      >\n        {Scrollable}\n      </BottomSheetRefreshControl>\n    ) : (\n      Scrollable\n    );\n  }\n);\n"
  },
  {
    "path": "src/components/bottomSheetScrollable/ScrollableContainer.tsx",
    "content": "import React, { type FC, forwardRef } from 'react';\nimport type { SimultaneousGesture } from 'react-native-gesture-handler';\nimport { BottomSheetDraggableScrollable } from './BottomSheetDraggableScrollable';\n\ninterface ScrollableContainerProps {\n  nativeGesture?: SimultaneousGesture;\n  // biome-ignore lint/suspicious/noExplicitAny: 🤷‍♂️\n  ScrollableComponent: FC<any>;\n}\n\nexport const ScrollableContainer = forwardRef<never, ScrollableContainerProps>(\n  function ScrollableContainer(\n    { nativeGesture, ScrollableComponent, ...rest },\n    ref\n  ) {\n    return (\n      <BottomSheetDraggableScrollable scrollableGesture={nativeGesture}>\n        <ScrollableComponent ref={ref} {...rest} />\n      </BottomSheetDraggableScrollable>\n    );\n  }\n);\n"
  },
  {
    "path": "src/components/bottomSheetScrollable/ScrollableContainer.web.tsx",
    "content": "import React, {\n  type ComponentProps,\n  forwardRef,\n  useCallback,\n  useRef,\n} from 'react';\nimport type { LayoutChangeEvent, ViewProps } from 'react-native';\nimport type { SimultaneousGesture } from 'react-native-gesture-handler';\nimport Animated from 'react-native-reanimated';\nimport { INITIAL_LAYOUT_VALUE } from '../../constants';\nimport { useBottomSheetInternal } from '../../hooks';\nimport { BottomSheetDraggableScrollable } from './BottomSheetDraggableScrollable';\n\ninterface ScrollableContainerProps {\n  nativeGesture: SimultaneousGesture;\n  setContentSize: (contentHeight: number) => void;\n  // biome-ignore lint/suspicious/noExplicitAny: 🤷‍♂️\n  ScrollableComponent: any;\n  onLayout: ViewProps['onLayout'];\n}\n\n/**\n * Detect if the current browser is Safari or not.\n */\nconst isWebkit = () => {\n  // @ts-ignore\n  return navigator.userAgent.indexOf('Safari') > -1;\n};\n\nexport const ScrollableContainer = forwardRef<\n  never,\n  ScrollableContainerProps & { animatedProps: never }\n>(function ScrollableContainer(\n  {\n    nativeGesture,\n    ScrollableComponent,\n    animatedProps,\n    setContentSize,\n    onLayout,\n    ...rest\n  },\n  ref\n) {\n  //#region refs\n  const isInitialContentHeightCaptured = useRef(false);\n  //#endregion\n\n  //#region hooks\n  const { animatedLayoutState } = useBottomSheetInternal();\n  //#endregion\n\n  //#region callbacks\n  const renderScrollComponent = useCallback(\n    (props: ComponentProps<typeof Animated.ScrollView>) => (\n      <Animated.ScrollView {...props} animatedProps={animatedProps} />\n    ),\n    [animatedProps]\n  );\n\n  /**\n   * A workaround a bug in React Native Web [#1502](https://github.com/necolas/react-native-web/issues/1502),\n   * where the `onContentSizeChange` won't be call on initial render.\n   */\n  const handleOnLayout = useCallback(\n    (event: LayoutChangeEvent) => {\n      if (onLayout) {\n        onLayout(event);\n      }\n\n      if (!isInitialContentHeightCaptured.current) {\n        isInitialContentHeightCaptured.current = true;\n        if (!isWebkit()) {\n          return;\n        }\n\n        /**\n         * early exit if the content height been calculated.\n         */\n        if (animatedLayoutState.get().contentHeight !== INITIAL_LAYOUT_VALUE) {\n          return;\n        }\n        // @ts-ignore\n        window.requestAnimationFrame(() => {\n          // @ts-ignore\n          setContentSize(event.nativeEvent.target.clientHeight);\n        });\n      }\n    },\n    [onLayout, setContentSize, animatedLayoutState]\n  );\n  //#endregion\n  return (\n    <BottomSheetDraggableScrollable scrollableGesture={nativeGesture}>\n      <ScrollableComponent\n        ref={ref}\n        {...rest}\n        onLayout={handleOnLayout}\n        renderScrollComponent={renderScrollComponent}\n      />\n    </BottomSheetDraggableScrollable>\n  );\n});\n"
  },
  {
    "path": "src/components/bottomSheetScrollable/createBottomSheetScrollableComponent.tsx",
    "content": "import React, {\n  forwardRef,\n  useContext,\n  useImperativeHandle,\n  useMemo,\n} from 'react';\nimport { Gesture } from 'react-native-gesture-handler';\nimport { useAnimatedProps } from 'react-native-reanimated';\nimport {\n  SCROLLABLE_DECELERATION_RATE_MAPPER,\n  SCROLLABLE_STATUS,\n  type SCROLLABLE_TYPE,\n} from '../../constants';\nimport { BottomSheetDraggableContext } from '../../contexts/gesture';\nimport {\n  useBottomSheetContentContainerStyle,\n  useBottomSheetInternal,\n  useScrollHandler,\n  useScrollableSetter,\n  useStableCallback,\n} from '../../hooks';\nimport { ScrollableContainer } from './ScrollableContainer';\nimport { useBottomSheetContentSizeSetter } from './useBottomSheetContentSizeSetter';\n\nexport function createBottomSheetScrollableComponent<T, P>(\n  type: SCROLLABLE_TYPE,\n  // biome-ignore lint: to be addressed!\n  ScrollableComponent: any\n) {\n  return forwardRef<T, P>((props, ref) => {\n    //#region props\n    const {\n      // hooks\n      focusHook,\n      scrollEventsHandlersHook,\n      // props\n      enableFooterMarginAdjustment = false,\n      overScrollMode = 'never',\n      keyboardDismissMode = 'interactive',\n      showsVerticalScrollIndicator = true,\n      contentContainerStyle: _providedContentContainerStyle,\n      refreshing,\n      onRefresh,\n      progressViewOffset,\n      refreshControl,\n      // events\n      onScroll,\n      onScrollBeginDrag,\n      onScrollEndDrag,\n      onContentSizeChange,\n      ...rest\n      // biome-ignore lint: to be addressed!\n    }: any = props;\n    //#endregion\n\n    //#region hooks\n    const draggableGesture = useContext(BottomSheetDraggableContext);\n    const { scrollableRef, scrollableContentOffsetY, scrollHandler } =\n      useScrollHandler(\n        scrollEventsHandlersHook,\n        onScroll,\n        onScrollBeginDrag,\n        onScrollEndDrag\n      );\n    const {\n      animatedScrollableStatus: animatedScrollableState,\n      enableContentPanningGesture,\n    } = useBottomSheetInternal();\n    const { setContentSize } = useBottomSheetContentSizeSetter();\n    //#endregion\n\n    if (!draggableGesture && enableContentPanningGesture) {\n      throw \"'Scrollable' cannot be used out of the BottomSheet!\";\n    }\n\n    //#region variables\n    const scrollableAnimatedProps = useAnimatedProps(\n      () => ({\n        decelerationRate:\n          SCROLLABLE_DECELERATION_RATE_MAPPER[animatedScrollableState.value],\n        showsVerticalScrollIndicator: showsVerticalScrollIndicator\n          ? animatedScrollableState.value === SCROLLABLE_STATUS.UNLOCKED\n          : showsVerticalScrollIndicator,\n      }),\n      [animatedScrollableState, showsVerticalScrollIndicator]\n    );\n\n    const scrollableGesture = useMemo(\n      () =>\n        draggableGesture\n          ? Gesture.Native()\n              // @ts-ignore\n              .simultaneousWithExternalGesture(draggableGesture)\n              .shouldCancelWhenOutside(false)\n          : undefined,\n      [draggableGesture]\n    );\n    //#endregion\n\n    //#region callbacks\n    const handleContentSizeChange = useStableCallback(\n      (contentWidth: number, contentHeight: number) => {\n        setContentSize(contentHeight);\n        if (onContentSizeChange) {\n          onContentSizeChange(contentWidth, contentHeight);\n        }\n      }\n    );\n    //#endregion\n\n    //#region styles\n    const contentContainerStyle = useBottomSheetContentContainerStyle(\n      enableFooterMarginAdjustment,\n      _providedContentContainerStyle\n    );\n    //#endregion\n\n    //#region effects\n    // @ts-ignore\n    useImperativeHandle(ref, () => scrollableRef.current);\n    useScrollableSetter(\n      scrollableRef,\n      type,\n      scrollableContentOffsetY,\n      onRefresh !== undefined,\n      focusHook\n    );\n    //#endregion\n\n    //#region render\n    return (\n      <ScrollableContainer\n        ref={scrollableRef}\n        nativeGesture={scrollableGesture}\n        animatedProps={scrollableAnimatedProps}\n        overScrollMode={overScrollMode}\n        keyboardDismissMode={keyboardDismissMode}\n        refreshing={refreshing}\n        scrollEventThrottle={16}\n        progressViewOffset={progressViewOffset}\n        contentContainerStyle={contentContainerStyle}\n        onRefresh={onRefresh}\n        onScroll={scrollHandler}\n        onContentSizeChange={handleContentSizeChange}\n        setContentSize={setContentSize}\n        ScrollableComponent={ScrollableComponent}\n        refreshControl={refreshControl}\n        {...rest}\n      />\n    );\n    //#endregion\n  });\n}\n"
  },
  {
    "path": "src/components/bottomSheetScrollable/index.ts",
    "content": "export { createBottomSheetScrollableComponent } from './createBottomSheetScrollableComponent';\nexport { default as BottomSheetSectionList } from './BottomSheetSectionList';\nexport { default as BottomSheetFlatList } from './BottomSheetFlatList';\nexport { default as BottomSheetScrollView } from './BottomSheetScrollView';\nexport { default as BottomSheetVirtualizedList } from './BottomSheetVirtualizedList';\n\nexport { default as BottomSheetFlashList } from './BottomSheetFlashList';\n\nexport type {\n  BottomSheetFlatListMethods,\n  BottomSheetScrollViewMethods,\n  BottomSheetSectionListMethods,\n  BottomSheetVirtualizedListMethods,\n  BottomSheetScrollableProps,\n} from './types';\n"
  },
  {
    "path": "src/components/bottomSheetScrollable/styles.ts",
    "content": "import { StyleSheet } from 'react-native';\n\nexport const styles = StyleSheet.create({\n  container: {\n    flex: 1,\n    overflow: 'visible',\n  },\n});\n"
  },
  {
    "path": "src/components/bottomSheetScrollable/types.d.ts",
    "content": "import type {\n  DependencyList,\n  EffectCallback,\n  ReactNode,\n  Ref,\n  RefObject,\n} from 'react';\nimport type {\n  FlatListProps,\n  NodeHandle,\n  ScrollResponderMixin,\n  ScrollViewComponent,\n  ScrollViewProps,\n  SectionListProps,\n  SectionListScrollParams,\n  View,\n  VirtualizedListProps,\n} from 'react-native';\nimport type Animated from 'react-native-reanimated';\nimport type { ScrollEventsHandlersHookType } from '../../types';\n\nexport interface BottomSheetScrollableProps {\n  /**\n   * Adjust the scrollable bottom margin to avoid the animated footer.\n   *\n   * @type boolean\n   * @default false\n   */\n  enableFooterMarginAdjustment?: boolean;\n\n  /**\n   * This needed when bottom sheet used with multiple scrollables to allow bottom sheet\n   * detect the current scrollable ref, especially when used with `React Navigation`.\n   * You will need to provide `useFocusEffect` from `@react-navigation/native`.\n   *\n   * @type (effect: EffectCallback, deps?: DependencyList) => void\n   * @default useEffect\n   */\n  focusHook?: (effect: EffectCallback, deps?: DependencyList) => void;\n\n  /**\n   * Custom hook to provide scroll events handler, which will allow advance and\n   * customize handling for scrollables.\n   *\n   * @warning this is an experimental feature and the hook signature can change without a major version bump.\n   * @type ScrollEventsHandlersHookType\n   * @default useScrollEventsHandlersDefault\n   */\n  scrollEventsHandlersHook?: ScrollEventsHandlersHookType;\n}\n\nexport type ScrollableProps<T> =\n  | ScrollViewProps\n  | FlatListProps<T>\n  | SectionListProps<T>;\n\n//#region FlatList\nexport type BottomSheetFlatListProps<T> = Omit<\n  Animated.AnimateProps<FlatListProps<T>>,\n  'decelerationRate' | 'onScroll' | 'scrollEventThrottle'\n> &\n  BottomSheetScrollableProps & {\n    ref?: Ref<BottomSheetFlatListMethods>;\n  };\n\nexport interface BottomSheetFlatListMethods {\n  /**\n   * Scrolls to the end of the content. May be janky without `getItemLayout` prop.\n   */\n  scrollToEnd: (params?: { animated?: boolean | null }) => void;\n\n  /**\n   * Scrolls to the item at the specified index such that it is positioned in the viewable area\n   * such that viewPosition 0 places it at the top, 1 at the bottom, and 0.5 centered in the middle.\n   * Cannot scroll to locations outside the render window without specifying the getItemLayout prop.\n   */\n  scrollToIndex: (params: {\n    animated?: boolean | null;\n    index: number;\n    viewOffset?: number;\n    viewPosition?: number;\n  }) => void;\n\n  /**\n   * Requires linear scan through data - use `scrollToIndex` instead if possible.\n   * May be janky without `getItemLayout` prop.\n   */\n  scrollToItem: (params: {\n    animated?: boolean | null;\n    // biome-ignore lint: to be addressed!\n    item: any;\n    viewPosition?: number;\n  }) => void;\n\n  /**\n   * Scroll to a specific content pixel offset, like a normal `ScrollView`.\n   */\n  scrollToOffset: (params: {\n    animated?: boolean | null;\n    offset: number;\n  }) => void;\n\n  /**\n   * Tells the list an interaction has occured, which should trigger viewability calculations,\n   * e.g. if waitForInteractions is true and the user has not scrolled. This is typically called\n   * by taps on items or by navigation actions.\n   */\n  recordInteraction: () => void;\n\n  /**\n   * Displays the scroll indicators momentarily.\n   */\n  flashScrollIndicators: () => void;\n\n  /**\n   * Provides a handle to the underlying scroll responder.\n   */\n  getScrollResponder: () => ScrollResponderMixin | null | undefined;\n\n  /**\n   * Provides a reference to the underlying host component\n   */\n  getNativeScrollRef: () =>\n    | RefObject<View>\n    | RefObject<ScrollViewComponent>\n    | null\n    | undefined;\n\n  // biome-ignore lint: to be addressed!\n  getScrollableNode: () => any;\n\n  // biome-ignore lint: to be addressed!\n  setNativeProps: (props: { [key: string]: any }) => void;\n}\n//#endregion\n\n//#region ScrollView\nexport type BottomSheetScrollViewProps = Omit<\n  Animated.AnimateProps<ScrollViewProps>,\n  'decelerationRate' | 'scrollEventThrottle'\n> &\n  BottomSheetScrollableProps & {\n    ref?: Ref<BottomSheetScrollViewMethods>;\n    children: ReactNode | ReactNode[];\n  };\n\nexport interface BottomSheetScrollViewMethods {\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 an alternative to the options object.\n   * This is deprecated due to ambiguity (y before x), and SHOULD NOT BE USED.\n   */\n  scrollTo(\n    y?: number | { x?: number; y?: number; animated?: boolean },\n    x?: number,\n    animated?: boolean\n  ): void;\n\n  /**\n   * A helper function that scrolls to the end of the scrollview;\n   * If this is a vertical ScrollView, it scrolls to the bottom.\n   * If this is a horizontal ScrollView scrolls to the right.\n   *\n   * The options object has an animated prop, that enables the scrolling animation or not.\n   * The animated prop defaults to true\n   */\n  scrollToEnd(options?: { animated: boolean }): void;\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  getScrollResponder(): ScrollResponderMixin;\n\n  // biome-ignore lint: to be addressed!\n  getScrollableNode(): any;\n\n  // biome-ignore lint: to be addressed!\n  getInnerViewNode(): any;\n\n  /**\n   * @deprecated Use scrollTo instead\n   */\n  scrollWithoutAnimationTo?: (y: number, x: number) => void;\n\n  /**\n   * This function sends props straight to native. They will not participate in\n   * future diff process - this means that if you do not include them in the\n   * next render, they will remain active (see [Direct\n   * Manipulation](https://reactnative.dev/docs/direct-manipulation)).\n   */\n  setNativeProps(nativeProps: object): void;\n}\n//#endregion\n\n//#region SectionList\nexport type BottomSheetSectionListProps<ItemT, SectionT> = Omit<\n  Animated.AnimateProps<SectionListProps<ItemT, SectionT>>,\n  'decelerationRate' | 'scrollEventThrottle'\n> &\n  BottomSheetScrollableProps & {\n    ref?: Ref<BottomSheetSectionListMethods>;\n  };\n\nexport interface BottomSheetSectionListMethods {\n  /**\n   * Scrolls to the item at the specified sectionIndex and itemIndex (within the section)\n   * positioned in the viewable area such that viewPosition 0 places it at the top\n   * (and may be covered by a sticky header), 1 at the bottom, and 0.5 centered in the middle.\n   */\n  scrollToLocation(params: SectionListScrollParams): void;\n\n  /**\n   * Tells the list an interaction has occurred, which should trigger viewability calculations, e.g.\n   * if `waitForInteractions` is true and the user has not scrolled. This is typically called by\n   * taps on items or by navigation actions.\n   */\n  recordInteraction(): void;\n\n  /**\n   * Displays the scroll indicators momentarily.\n   *\n   * @platform ios\n   */\n  flashScrollIndicators(): void;\n\n  /**\n   * Provides a handle to the underlying scroll responder.\n   */\n  getScrollResponder(): ScrollResponderMixin | undefined;\n\n  /**\n   * Provides a handle to the underlying scroll node.\n   */\n  getScrollableNode(): NodeHandle | undefined;\n}\n//#endregion\n\n//#region\nexport type BottomSheetVirtualizedListProps<T> = Omit<\n  Animated.AnimateProps<VirtualizedListProps<T>>,\n  'decelerationRate' | 'scrollEventThrottle'\n> &\n  BottomSheetScrollableProps & {\n    ref?: Ref<BottomSheetVirtualizedListMethods>;\n  };\n\nexport interface BottomSheetVirtualizedListMethods {\n  scrollToEnd: (params?: { animated?: boolean }) => void;\n  scrollToIndex: (params: {\n    animated?: boolean;\n    index: number;\n    viewOffset?: number;\n    viewPosition?: number;\n  }) => void;\n  scrollToItem: (params: {\n    animated?: boolean;\n    // biome-ignore lint: to be addressed!\n    item: any;\n    viewPosition?: number;\n  }) => void;\n\n  /**\n   * Scroll to a specific content pixel offset in the list.\n   * Param `offset` expects the offset to scroll to. In case of horizontal is true, the\n   * offset is the x-value, in any other case the offset is the y-value.\n   * Param `animated` (true by default) defines whether the list should do an animation while scrolling.\n   */\n  scrollToOffset: (params: { animated?: boolean; offset: number }) => void;\n\n  recordInteraction: () => void;\n}\n//#endregion\n"
  },
  {
    "path": "src/components/bottomSheetScrollable/useBottomSheetContentSizeSetter.ts",
    "content": "import { useCallback } from 'react';\nimport { useBottomSheetInternal } from '../../hooks';\n\n/**\n * A hook to set the content size properly into the bottom sheet,\n * internals.\n */\nexport function useBottomSheetContentSizeSetter() {\n  //#region hooks\n  const { enableDynamicSizing, animatedLayoutState } = useBottomSheetInternal();\n  //#endregion\n\n  //#region methods\n  const setContentSize = useCallback(\n    (contentHeight: number) => {\n      if (!enableDynamicSizing) {\n        return;\n      }\n      animatedLayoutState.modify(state => {\n        'worklet';\n        state.contentHeight = contentHeight;\n        return state;\n      });\n    },\n    [enableDynamicSizing, animatedLayoutState]\n  );\n  //#endregion\n\n  return {\n    setContentSize,\n  };\n}\n"
  },
  {
    "path": "src/components/bottomSheetTextInput/BottomSheetTextInput.tsx",
    "content": "import React, {\n  forwardRef,\n  memo,\n  useCallback,\n  useEffect,\n  useImperativeHandle,\n  useRef,\n} from 'react';\nimport type {\n  NativeSyntheticEvent,\n  TextInputFocusEventData,\n} from 'react-native';\nimport { TextInput as RNTextInput } from 'react-native';\nimport { TextInput } from 'react-native-gesture-handler';\nimport { useBottomSheetInternal } from '../../hooks';\nimport { findNodeHandle } from '../../utilities';\nimport type { BottomSheetTextInputProps } from './types';\n\nconst BottomSheetTextInputComponent = forwardRef<\n  TextInput | undefined,\n  BottomSheetTextInputProps\n>(({ onFocus, onBlur, ...rest }, providedRef) => {\n  //#region refs\n  const ref = useRef<TextInput>(null);\n  //#endregion\n\n  //#region hooks\n  const { animatedKeyboardState, textInputNodesRef } = useBottomSheetInternal();\n  //#endregion\n\n  //#region callbacks\n  const handleOnFocus = useCallback(\n    (args: NativeSyntheticEvent<TextInputFocusEventData>) => {\n      animatedKeyboardState.set(state => ({\n        ...state,\n        target: args.nativeEvent.target,\n      }));\n      if (onFocus) {\n        onFocus(args);\n      }\n    },\n    [onFocus, animatedKeyboardState]\n  );\n  const handleOnBlur = useCallback(\n    (args: NativeSyntheticEvent<TextInputFocusEventData>) => {\n      const keyboardState = animatedKeyboardState.get();\n      const currentFocusedInput = findNodeHandle(\n        RNTextInput.State.currentlyFocusedInput()\n      );\n\n      /**\n       * we need to make sure that we only remove the target\n       * if the target belong to the current component and\n       * if the currently focused input is not in the targets set.\n       */\n      const shouldRemoveCurrentTarget =\n        keyboardState.target === args.nativeEvent.target;\n      const shouldIgnoreBlurEvent =\n        currentFocusedInput &&\n        textInputNodesRef.current.has(currentFocusedInput);\n\n      if (shouldRemoveCurrentTarget && !shouldIgnoreBlurEvent) {\n        animatedKeyboardState.set(state => ({\n          ...state,\n          target: undefined,\n        }));\n      }\n\n      if (onBlur) {\n        onBlur(args);\n      }\n    },\n    [onBlur, animatedKeyboardState, textInputNodesRef]\n  );\n  //#endregion\n\n  //#region effects\n  useEffect(() => {\n    const componentNode = findNodeHandle(ref.current);\n    if (!componentNode) {\n      return;\n    }\n\n    if (!textInputNodesRef.current.has(componentNode)) {\n      textInputNodesRef.current.add(componentNode);\n    }\n\n    return () => {\n      const componentNode = findNodeHandle(ref.current);\n      if (!componentNode) {\n        return;\n      }\n\n      const keyboardState = animatedKeyboardState.get();\n      /**\n       * remove the keyboard state target if it belong\n       * to the current component.\n       */\n      if (keyboardState.target === componentNode) {\n        animatedKeyboardState.set(state => ({\n          ...state,\n          target: undefined,\n        }));\n      }\n\n      if (textInputNodesRef.current.has(componentNode)) {\n        textInputNodesRef.current.delete(componentNode);\n      }\n    };\n  }, [textInputNodesRef, animatedKeyboardState]);\n  useImperativeHandle(providedRef, () => ref.current ?? undefined, []);\n  //#endregion\n\n  return (\n    <TextInput\n      ref={ref}\n      onFocus={handleOnFocus}\n      onBlur={handleOnBlur}\n      {...rest}\n    />\n  );\n});\n\nconst BottomSheetTextInput = memo(BottomSheetTextInputComponent);\nBottomSheetTextInput.displayName = 'BottomSheetTextInput';\n\nexport default BottomSheetTextInput;\n"
  },
  {
    "path": "src/components/bottomSheetTextInput/index.ts",
    "content": "export { default } from './BottomSheetTextInput';\nexport type { BottomSheetTextInputProps } from './types';\n"
  },
  {
    "path": "src/components/bottomSheetTextInput/types.ts",
    "content": "import type { TextInputProps } from 'react-native';\n\nexport interface BottomSheetTextInputProps extends TextInputProps {}\n"
  },
  {
    "path": "src/components/bottomSheetView/BottomSheetView.tsx",
    "content": "import React, { memo, useEffect, useCallback, useMemo } from 'react';\nimport { type LayoutChangeEvent, View } from 'react-native';\nimport { SCROLLABLE_TYPE } from '../../constants';\nimport {\n  useBottomSheetContentContainerStyle,\n  useBottomSheetInternal,\n} from '../../hooks';\nimport { print } from '../../utilities';\nimport { styles } from './styles';\nimport type { BottomSheetViewProps } from './types';\n\nfunction BottomSheetViewComponent({\n  focusHook: useFocusHook = useEffect,\n  enableFooterMarginAdjustment = false,\n  onLayout,\n  style: _providedStyle,\n  children,\n  ...rest\n}: BottomSheetViewProps) {\n  //#region hooks\n  const { animatedScrollableState, enableDynamicSizing, animatedLayoutState } =\n    useBottomSheetInternal();\n  //#endregion\n\n  //#region styles\n  const containerStyle = useBottomSheetContentContainerStyle(\n    enableFooterMarginAdjustment,\n    _providedStyle\n  );\n  const style = useMemo(\n    () => [containerStyle, styles.container],\n    [containerStyle]\n  );\n  //#endregion\n\n  //#region callbacks\n  const handleSettingScrollable = useCallback(() => {\n    animatedScrollableState.set(state => ({\n      ...state,\n      contentOffsetY: 0,\n      type: SCROLLABLE_TYPE.VIEW,\n    }));\n  }, [animatedScrollableState]);\n  const handleLayout = useCallback(\n    (event: LayoutChangeEvent) => {\n      if (enableDynamicSizing) {\n        const {\n          nativeEvent: {\n            layout: { height },\n          },\n        } = event;\n        animatedLayoutState.modify(state => {\n          'worklet';\n          state.contentHeight = height;\n          return state;\n        });\n      }\n\n      if (onLayout) {\n        onLayout(event);\n      }\n\n      if (__DEV__) {\n        print({\n          component: 'BottomSheetView',\n          method: 'handleLayout',\n          category: 'layout',\n          params: {\n            height: event.nativeEvent.layout.height,\n          },\n        });\n      }\n    },\n    [onLayout, animatedLayoutState, enableDynamicSizing]\n  );\n  //#endregion\n\n  //#region effects\n  useFocusHook(handleSettingScrollable);\n  //#endregion\n\n  //render\n  return (\n    <View {...rest} onLayout={handleLayout} style={style}>\n      {children}\n    </View>\n  );\n}\n\nconst BottomSheetView = memo(BottomSheetViewComponent);\nBottomSheetView.displayName = 'BottomSheetView';\n\nexport default BottomSheetView;\n"
  },
  {
    "path": "src/components/bottomSheetView/index.ts",
    "content": "export { default } from './BottomSheetView';\n"
  },
  {
    "path": "src/components/bottomSheetView/styles.ts",
    "content": "import { StyleSheet } from 'react-native';\n\nexport const styles = StyleSheet.create({\n  container: {\n    position: 'absolute',\n    left: 0,\n    top: 0,\n    right: 0,\n  },\n});\n"
  },
  {
    "path": "src/components/bottomSheetView/types.d.ts",
    "content": "import type { DependencyList, EffectCallback, ReactNode } from 'react';\nimport type { ViewProps as RNViewProps } from 'react-native';\n\nexport interface BottomSheetViewProps extends RNViewProps {\n  /**\n   * Adjust the scrollable bottom margin to avoid the animated footer.\n   *\n   * @type boolean\n   * @default false\n   */\n  enableFooterMarginAdjustment?: boolean;\n\n  /**\n   * This needed when bottom sheet used with multiple scrollables to allow bottom sheet\n   * detect the current scrollable ref, especially when used with `React Navigation`.\n   * You will need to provide `useFocusEffect` from `@react-navigation/native`.\n   *\n   * @type (effect: EffectCallback, deps?: DependencyList) => void\n   * @default useEffect\n   */\n  focusHook?: (effect: EffectCallback, deps?: DependencyList) => void;\n\n  children: ReactNode[] | ReactNode;\n}\n"
  },
  {
    "path": "src/components/touchables/Touchables.ios.tsx",
    "content": "export {\n  TouchableOpacity,\n  TouchableHighlight,\n  TouchableWithoutFeedback,\n} from 'react-native';\n"
  },
  {
    "path": "src/components/touchables/Touchables.tsx",
    "content": "export {\n  TouchableOpacity,\n  TouchableHighlight,\n  TouchableWithoutFeedback,\n} from 'react-native-gesture-handler';\n"
  },
  {
    "path": "src/components/touchables/index.ts",
    "content": "import type {\n  TouchableHighlight as RNTouchableHighlight,\n  TouchableOpacity as RNTouchableOpacity,\n  TouchableWithoutFeedback as RNTouchableWithoutFeedback,\n} from 'react-native';\n\nimport {\n  TouchableHighlight,\n  TouchableOpacity,\n  TouchableWithoutFeedback,\n  // @ts-ignore\n} from './Touchables';\n\nexport default {\n  TouchableOpacity: TouchableOpacity as never as typeof RNTouchableOpacity,\n  TouchableHighlight:\n    TouchableHighlight as never as typeof RNTouchableHighlight,\n  TouchableWithoutFeedback:\n    TouchableWithoutFeedback as never as typeof RNTouchableWithoutFeedback,\n};\n"
  },
  {
    "path": "src/constants.ts",
    "content": "import { Dimensions, Platform } from 'react-native';\nimport { Easing } from 'react-native-reanimated';\nimport type { SpringConfig, TimingConfig } from './types';\n\nconst { height: WINDOW_HEIGHT, width: WINDOW_WIDTH } = Dimensions.get('window');\nconst { height: SCREEN_HEIGHT, width: SCREEN_WIDTH } = Dimensions.get('screen');\n\nenum GESTURE_SOURCE {\n  UNDETERMINED = 0,\n  SCROLLABLE = 1,\n  HANDLE = 2,\n  CONTENT = 3,\n}\n\nenum SHEET_STATE {\n  CLOSED = 0,\n  OPENED = 1,\n  EXTENDED = 2,\n  OVER_EXTENDED = 3,\n  FILL_PARENT = 4,\n}\n\nenum SCROLLABLE_STATUS {\n  LOCKED = 0,\n  UNLOCKED = 1,\n  UNDETERMINED = 2,\n}\n\nenum SCROLLABLE_TYPE {\n  UNDETERMINED = 0,\n  VIEW = 1,\n  FLATLIST = 2,\n  SCROLLVIEW = 3,\n  SECTIONLIST = 4,\n  VIRTUALIZEDLIST = 5,\n}\n\nenum ANIMATION_STATUS {\n  UNDETERMINED = 0,\n  RUNNING = 1,\n  STOPPED = 2,\n  INTERRUPTED = 3,\n}\n\nenum ANIMATION_SOURCE {\n  NONE = 0,\n  MOUNT = 1,\n  GESTURE = 2,\n  USER = 3,\n  CONTAINER_RESIZE = 4,\n  SNAP_POINT_CHANGE = 5,\n  KEYBOARD = 6,\n}\n\nenum ANIMATION_METHOD {\n  TIMING = 0,\n  SPRING = 1,\n}\n\nenum KEYBOARD_STATUS {\n  UNDETERMINED = 0,\n  SHOWN = 1,\n  HIDDEN = 2,\n}\n\nenum SNAP_POINT_TYPE {\n  PROVIDED = 0,\n  DYNAMIC = 1,\n}\n\nconst ANIMATION_EASING = Easing.out(Easing.exp);\nconst ANIMATION_DURATION = 250;\n\nconst ANIMATION_CONFIGS = Platform.select<TimingConfig | SpringConfig>({\n  android: {\n    duration: ANIMATION_DURATION,\n    easing: ANIMATION_EASING,\n  },\n  default: {\n    damping: 500,\n    stiffness: 1000,\n    mass: 3,\n    overshootClamping: true,\n    restDisplacementThreshold: 10,\n    restSpeedThreshold: 10,\n  },\n});\n\nconst SCROLLABLE_DECELERATION_RATE_MAPPER = {\n  [SCROLLABLE_STATUS.UNDETERMINED]: 0,\n  [SCROLLABLE_STATUS.LOCKED]: 0,\n  [SCROLLABLE_STATUS.UNLOCKED]: Platform.select({\n    ios: 0.998,\n    android: 0.985,\n    default: 1,\n  }),\n};\n\nconst MODAL_STACK_BEHAVIOR = {\n  replace: 'replace',\n  push: 'push',\n  switch: 'switch',\n};\n\nconst KEYBOARD_BEHAVIOR = {\n  interactive: 'interactive',\n  extend: 'extend',\n  fillParent: 'fillParent',\n} as const;\n\nconst KEYBOARD_BLUR_BEHAVIOR = {\n  none: 'none',\n  restore: 'restore',\n} as const;\n\nconst KEYBOARD_INPUT_MODE = {\n  adjustPan: 'adjustPan',\n  adjustResize: 'adjustResize',\n} as const;\n\nconst KEYBOARD_DISMISS_THRESHOLD = 12.5;\n\nconst INITIAL_LAYOUT_VALUE = -999;\nconst INITIAL_CONTAINER_LAYOUT = {\n  height: INITIAL_LAYOUT_VALUE,\n  offset: {\n    top: 0,\n    bottom: 0,\n    right: 0,\n    left: 0,\n  },\n};\n\nexport {\n  GESTURE_SOURCE,\n  SHEET_STATE,\n  ANIMATION_STATUS,\n  ANIMATION_METHOD,\n  ANIMATION_SOURCE,\n  SCROLLABLE_TYPE,\n  SCROLLABLE_STATUS,\n  KEYBOARD_STATUS,\n  SNAP_POINT_TYPE,\n  WINDOW_HEIGHT,\n  WINDOW_WIDTH,\n  SCREEN_HEIGHT,\n  SCREEN_WIDTH,\n  SCROLLABLE_DECELERATION_RATE_MAPPER,\n  MODAL_STACK_BEHAVIOR,\n  KEYBOARD_BEHAVIOR,\n  KEYBOARD_BLUR_BEHAVIOR,\n  KEYBOARD_INPUT_MODE,\n  KEYBOARD_DISMISS_THRESHOLD,\n  ANIMATION_CONFIGS,\n  ANIMATION_EASING,\n  ANIMATION_DURATION,\n  INITIAL_LAYOUT_VALUE,\n  INITIAL_CONTAINER_LAYOUT,\n};\n"
  },
  {
    "path": "src/contexts/external.ts",
    "content": "import { createContext } from 'react';\nimport type { BottomSheetMethods, BottomSheetVariables } from '../types';\n\nexport const BottomSheetContext = createContext<\n  (BottomSheetMethods & BottomSheetVariables) | null\n>(null);\n\nexport const BottomSheetProvider = BottomSheetContext.Provider;\n"
  },
  {
    "path": "src/contexts/gesture.ts",
    "content": "import { createContext } from 'react';\nimport type { Gesture } from 'react-native-gesture-handler/lib/typescript/handlers/gestures/gesture';\nimport type { GestureHandlersHookType } from '../types';\n\nexport interface BottomSheetGestureHandlersContextType {\n  contentPanGestureHandler: ReturnType<GestureHandlersHookType>;\n  handlePanGestureHandler: ReturnType<GestureHandlersHookType>;\n}\n\nexport const BottomSheetGestureHandlersContext =\n  createContext<BottomSheetGestureHandlersContextType | null>(null);\n\nexport const BottomSheetDraggableContext = createContext<Gesture | null>(null);\n"
  },
  {
    "path": "src/contexts/index.ts",
    "content": "export { BottomSheetContext, BottomSheetProvider } from './external';\nexport {\n  BottomSheetInternalContext,\n  BottomSheetInternalProvider,\n} from './internal';\nexport { BottomSheetGestureHandlersContext } from './gesture';\nexport {\n  BottomSheetModalContext,\n  BottomSheetModalProvider,\n} from './modal/external';\nexport {\n  BottomSheetModalInternalContext,\n  BottomSheetModalInternalProvider,\n} from './modal/internal';\nexport type { BottomSheetModalInternalContextType } from './modal/internal';\n"
  },
  {
    "path": "src/contexts/internal.ts",
    "content": "import { createContext, type RefObject } from 'react';\nimport type { State } from 'react-native-gesture-handler';\nimport type { SharedValue } from 'react-native-reanimated';\nimport type {\n  AnimateToPositionType,\n  BottomSheetGestureProps,\n  BottomSheetProps,\n} from '../components/bottomSheet/types';\nimport type { SCROLLABLE_STATUS, SHEET_STATE } from '../constants';\nimport type {\n  AnimationState,\n  DetentsState,\n  KeyboardState,\n  LayoutState,\n  Scrollable,\n  ScrollableRef,\n  ScrollableState,\n} from '../types';\n\nexport interface BottomSheetInternalContextType\n  extends Partial<BottomSheetGestureProps>,\n    Required<\n      Pick<\n        BottomSheetProps,\n        | 'enableContentPanningGesture'\n        | 'enableOverDrag'\n        | 'enablePanDownToClose'\n        | 'enableDynamicSizing'\n        | 'enableBlurKeyboardOnGesture'\n        | 'overDragResistanceFactor'\n      >\n    > {\n  // animated states\n  animatedDetentsState: SharedValue<DetentsState>;\n  animatedAnimationState: SharedValue<AnimationState>;\n  animatedSheetState: SharedValue<SHEET_STATE>;\n  animatedKeyboardState: SharedValue<KeyboardState>;\n  animatedContentGestureState: SharedValue<State>;\n  animatedHandleGestureState: SharedValue<State>;\n  animatedLayoutState: SharedValue<LayoutState>;\n\n  // scrollable\n  animatedScrollableState: SharedValue<ScrollableState>;\n  animatedScrollableStatus: SharedValue<SCROLLABLE_STATUS>;\n\n  // animated values\n  animatedPosition: SharedValue<number>;\n  animatedIndex: SharedValue<number>;\n  animatedSheetHeight: SharedValue<number>;\n  isInTemporaryPosition: SharedValue<boolean>;\n\n  // methods\n  stopAnimation: () => void;\n  animateToPosition: AnimateToPositionType;\n  setScrollableRef: (ref: ScrollableRef) => void;\n  removeScrollableRef: (ref: RefObject<Scrollable>) => void;\n\n  // refs\n  textInputNodesRef: React.MutableRefObject<Set<number>>;\n}\n\nexport const BottomSheetInternalContext =\n  createContext<BottomSheetInternalContextType | null>(null);\n\nexport const BottomSheetInternalProvider = BottomSheetInternalContext.Provider;\n"
  },
  {
    "path": "src/contexts/modal/external.ts",
    "content": "import { createContext } from 'react';\n\nexport interface BottomSheetModalContextType {\n  dismiss: (key?: string) => boolean;\n  dismissAll: () => void;\n}\n\nexport const BottomSheetModalContext =\n  createContext<BottomSheetModalContextType | null>(null);\n\nexport const BottomSheetModalProvider = BottomSheetModalContext.Provider;\n"
  },
  {
    "path": "src/contexts/modal/internal.ts",
    "content": "import { type RefObject, createContext } from 'react';\nimport type { SharedValue } from 'react-native-reanimated';\nimport type {\n  BottomSheetModalPrivateMethods,\n  BottomSheetModalStackBehavior,\n} from '../../components/bottomSheetModal';\nimport type { ContainerLayoutState } from '../../types';\n\nexport interface BottomSheetModalInternalContextType {\n  hostName: string;\n  containerLayoutState: SharedValue<ContainerLayoutState>;\n  mountSheet: (\n    key: string,\n    ref: RefObject<BottomSheetModalPrivateMethods>,\n    stackBehavior: BottomSheetModalStackBehavior\n  ) => void;\n  unmountSheet: (key: string) => void;\n  willUnmountSheet: (key: string) => void;\n}\n\nexport const BottomSheetModalInternalContext =\n  createContext<BottomSheetModalInternalContextType | null>(null);\n\nexport const BottomSheetModalInternalProvider =\n  BottomSheetModalInternalContext.Provider;\n"
  },
  {
    "path": "src/hooks/index.ts",
    "content": "export { useBottomSheet } from './useBottomSheet';\nexport { useBottomSheetInternal } from './useBottomSheetInternal';\n\n// modal\nexport { useBottomSheetModal } from './useBottomSheetModal';\nexport { useBottomSheetModalInternal } from './useBottomSheetModalInternal';\n\n// scrollable\nexport { useScrollable } from './useScrollable';\nexport { useScrollableSetter } from './useScrollableSetter';\nexport { useScrollHandler } from './useScrollHandler';\n\n// gestures\nexport { useGestureHandler } from './useGestureHandler';\nexport { useGestureEventsHandlersDefault } from './useGestureEventsHandlersDefault';\nexport { useBottomSheetGestureHandlers } from './useBottomSheetGestureHandlers';\n\n// utilities\nexport { useAnimatedLayout } from './useAnimatedLayout';\nexport { useAnimatedKeyboard } from './useAnimatedKeyboard';\nexport { useStableCallback } from './useStableCallback';\nexport { usePropsValidator } from './usePropsValidator';\nexport { useAnimatedDetents } from './useAnimatedDetents';\nexport { useReactiveSharedValue } from './useReactiveSharedValue';\nexport {\n  useBoundingClientRect,\n  type BoundingClientRect,\n} from './useBoundingClientRect';\nexport { useBottomSheetContentContainerStyle } from './useBottomSheetContentContainerStyle';\n"
  },
  {
    "path": "src/hooks/useAnimatedDetents.ts",
    "content": "import { type SharedValue, useDerivedValue } from 'react-native-reanimated';\nimport type { BottomSheetProps } from '../components/bottomSheet';\nimport { INITIAL_LAYOUT_VALUE } from '../constants';\nimport type { DetentsState, LayoutState } from '../types';\nimport { normalizeSnapPoint } from '../utilities';\n\n/**\n * A custom hook that computes and returns the animated detent positions for a bottom sheet component.\n *\n * This hook normalizes the provided snap points (detents), optionally adds a dynamic detent based on content size,\n * and calculates key positions such as the highest detent and the closed position. It supports both static and dynamic\n * sizing, and adapts to modal and detached sheet modes.\n *\n * @param detents - The snap points for the bottom sheet, which can be an array or an object with a `value` property.\n * @param layoutState - A shared animated value containing the current layout state (container, handle, and content heights).\n * @param enableDynamicSizing - Whether dynamic sizing based on content height is enabled.\n * @param maxDynamicContentSize - The maximum allowed content size for dynamic sizing.\n * @param detached - Whether the bottom sheet is in detached mode.\n * @param $modal - Whether the bottom sheet is presented as a modal.\n * @param bottomInset - The bottom inset to apply when the sheet is modal or detached (default is 0).\n */\nexport const useAnimatedDetents = (\n  detents: BottomSheetProps['snapPoints'],\n  layoutState: SharedValue<LayoutState>,\n  enableDynamicSizing: BottomSheetProps['enableDynamicSizing'],\n  maxDynamicContentSize: BottomSheetProps['maxDynamicContentSize'],\n  detached: BottomSheetProps['detached'],\n  $modal: BottomSheetProps['$modal'],\n  bottomInset: BottomSheetProps['bottomInset'] = 0\n) => {\n  const state = useDerivedValue<DetentsState>(() => {\n    const { containerHeight, handleHeight, contentHeight } = layoutState.get();\n\n    // early exit, if container layout is not ready\n    if (containerHeight === INITIAL_LAYOUT_VALUE) {\n      return {};\n    }\n\n    // extract detents from provided props\n    const _detents = detents\n      ? 'value' in detents\n        ? detents.value\n        : detents\n      : [];\n\n    // normalized all provided detents, converting percentage\n    // values into absolute values.\n    let _normalizedDetents = _detents.map(snapPoint =>\n      normalizeSnapPoint(snapPoint, containerHeight)\n    ) as number[];\n\n    let highestDetentPosition =\n      _normalizedDetents[_normalizedDetents.length - 1];\n    let closedDetentPosition = containerHeight;\n    if ($modal || detached) {\n      closedDetentPosition = containerHeight + bottomInset;\n    }\n\n    if (!enableDynamicSizing) {\n      return {\n        detents: _normalizedDetents,\n        highestDetentPosition,\n        closedDetentPosition,\n      };\n    }\n\n    // early exit, if dynamic sizing is enabled and\n    // content height is not calculated yet.\n    if (contentHeight === INITIAL_LAYOUT_VALUE) {\n      return {};\n    }\n\n    // early exit, if handle height is not calculated yet.\n    if (handleHeight === INITIAL_LAYOUT_VALUE) {\n      return {};\n    }\n\n    // calculate a new detents based on content height.\n    const dynamicSnapPoint =\n      containerHeight -\n      Math.min(\n        contentHeight + handleHeight,\n        maxDynamicContentSize !== undefined\n          ? maxDynamicContentSize\n          : containerHeight\n      );\n\n    // push dynamic detent into the normalized detents,\n    // only if it does not exists in the provided list already.\n    if (!_normalizedDetents.includes(dynamicSnapPoint)) {\n      _normalizedDetents.push(dynamicSnapPoint);\n    }\n\n    // sort all detents.\n    _normalizedDetents = _normalizedDetents.sort((a, b) => b - a);\n\n    // update the highest detent position.\n    highestDetentPosition = _normalizedDetents[_normalizedDetents.length - 1];\n\n    // locate the dynamic detent index.\n    const dynamicDetentIndex = _normalizedDetents.indexOf(dynamicSnapPoint);\n\n    return {\n      detents: _normalizedDetents,\n      dynamicDetentIndex,\n      highestDetentPosition,\n      closedDetentPosition,\n    };\n  }, [\n    detents,\n    layoutState,\n    enableDynamicSizing,\n    maxDynamicContentSize,\n    detached,\n    $modal,\n    bottomInset,\n  ]);\n  return state;\n};\n"
  },
  {
    "path": "src/hooks/useAnimatedKeyboard.ts",
    "content": "import { useCallback, useEffect, useRef } from 'react';\nimport {\n  Keyboard,\n  type KeyboardEvent,\n  type KeyboardEventEasing,\n  type KeyboardEventName,\n  Platform,\n} from 'react-native';\nimport {\n  runOnUI,\n  useAnimatedReaction,\n  useSharedValue,\n} from 'react-native-reanimated';\nimport { KEYBOARD_STATUS, SCREEN_HEIGHT } from '../constants';\nimport type { KeyboardState } from '../types';\n\nconst KEYBOARD_EVENT_MAPPER = {\n  KEYBOARD_SHOW: Platform.select({\n    ios: 'keyboardWillShow',\n    android: 'keyboardDidShow',\n    default: '',\n  }) as KeyboardEventName,\n  KEYBOARD_HIDE: Platform.select({\n    ios: 'keyboardWillHide',\n    android: 'keyboardDidHide',\n    default: '',\n  }) as KeyboardEventName,\n};\n\nconst INITIAL_STATE: KeyboardState = {\n  status: KEYBOARD_STATUS.UNDETERMINED,\n  height: 0,\n  heightWithinContainer: 0,\n  easing: 'keyboard',\n  duration: 500,\n};\n\nexport const useAnimatedKeyboard = () => {\n  //#region variables\n  const textInputNodesRef = useRef(new Set<number>());\n  const state = useSharedValue(INITIAL_STATE);\n  const temporaryCachedState = useSharedValue<Omit<\n    KeyboardState,\n    'heightWithinContainer' | 'target'\n  > | null>(null);\n  //#endregion\n\n  //#region worklets\n  const handleKeyboardEvent = useCallback(\n    (\n      status: KEYBOARD_STATUS,\n      height: number,\n      duration: number,\n      easing: KeyboardEventEasing,\n      bottomOffset?: number\n    ) => {\n      'worklet';\n      const currentState = state.get();\n\n      /**\n       * if the keyboard event was fired before the `onFocus` on TextInput,\n       * then we cache the event, and wait till the `target` is been set\n       * to be updated then fire this function again.\n       */\n      if (status === KEYBOARD_STATUS.SHOWN && !currentState.target) {\n        temporaryCachedState.set({\n          status,\n          height,\n          duration,\n          easing,\n        });\n        return;\n      }\n\n      /**\n       * clear temporary cached state.\n       */\n      temporaryCachedState.set(null);\n\n      /**\n       * if keyboard status is hidden, then we keep old height.\n       */\n      let adjustedHeight =\n        status === KEYBOARD_STATUS.SHOWN ? height : currentState.height;\n\n      /**\n       * if keyboard had an bottom offset -android bottom bar-, then\n       * we add that offset to the keyboard height.\n       */\n      if (bottomOffset) {\n        adjustedHeight = adjustedHeight + bottomOffset;\n      }\n\n      state.set(state => ({\n        status,\n        easing,\n        duration,\n        height: adjustedHeight,\n        target: state.target,\n        heightWithinContainer: state.heightWithinContainer,\n      }));\n    },\n    [state, temporaryCachedState]\n  );\n  //#endregion\n\n  //#region effects\n  useEffect(() => {\n    const handleOnKeyboardShow = (event: KeyboardEvent) => {\n      runOnUI(handleKeyboardEvent)(\n        KEYBOARD_STATUS.SHOWN,\n        event.endCoordinates.height,\n        event.duration,\n        event.easing,\n        SCREEN_HEIGHT -\n          event.endCoordinates.height -\n          event.endCoordinates.screenY\n      );\n    };\n    const handleOnKeyboardHide = (event: KeyboardEvent) => {\n      runOnUI(handleKeyboardEvent)(\n        KEYBOARD_STATUS.HIDDEN,\n        event.endCoordinates.height,\n        event.duration,\n        event.easing\n      );\n    };\n\n    const showSubscription = Keyboard.addListener(\n      KEYBOARD_EVENT_MAPPER.KEYBOARD_SHOW,\n      handleOnKeyboardShow\n    );\n\n    const hideSubscription = Keyboard.addListener(\n      KEYBOARD_EVENT_MAPPER.KEYBOARD_HIDE,\n      handleOnKeyboardHide\n    );\n\n    return () => {\n      showSubscription.remove();\n      hideSubscription.remove();\n    };\n  }, [handleKeyboardEvent]);\n\n  /**\n   * This reaction is needed to handle the issue with multiline text input.\n   *\n   * @link https://github.com/gorhom/react-native-bottom-sheet/issues/411\n   */\n  useAnimatedReaction(\n    () => state.value.target,\n    (result, previous) => {\n      if (!result || result === previous) {\n        return;\n      }\n\n      const cachedState = temporaryCachedState.get();\n      if (!cachedState) {\n        return;\n      }\n\n      handleKeyboardEvent(\n        cachedState.status,\n        cachedState.height,\n        cachedState.duration,\n        cachedState.easing\n      );\n    },\n    [temporaryCachedState, handleKeyboardEvent]\n  );\n  //#endregion\n\n  return { state, textInputNodesRef };\n};\n"
  },
  {
    "path": "src/hooks/useAnimatedLayout.ts",
    "content": "import { useMemo, useState } from 'react';\nimport {\n  type SharedValue,\n  makeMutable,\n  useAnimatedReaction,\n} from 'react-native-reanimated';\nimport { INITIAL_CONTAINER_LAYOUT, INITIAL_LAYOUT_VALUE } from '../constants';\nimport type { ContainerLayoutState, LayoutState } from '../types';\n\nconst INITIAL_STATE: LayoutState = {\n  rawContainerHeight: INITIAL_LAYOUT_VALUE,\n  containerHeight: INITIAL_LAYOUT_VALUE,\n  containerOffset: INITIAL_CONTAINER_LAYOUT.offset,\n  handleHeight: INITIAL_LAYOUT_VALUE,\n  footerHeight: INITIAL_LAYOUT_VALUE,\n  contentHeight: INITIAL_LAYOUT_VALUE,\n};\n\n/**\n * A custom hook that manages and animates the layout state of a container,\n * typically used in bottom sheet components. It calculates the effective\n * container height by considering top and bottom insets, and updates the\n * animated state in response to layout changes. The hook supports both modal\n * and non-modal modes, and ensures the container's animated layout state\n * remains in sync with the actual layout measurements.\n *\n * @param containerLayoutState - A shared value representing the current container layout state.\n * @param topInset - The top inset value to be subtracted from the container height.\n * @param bottomInset - The bottom inset value to be subtracted from the container height.\n * @param modal - Optional flag indicating if the layout is in modal mode.\n * @param shouldOverrideHandleHeight - Optional flag to override the handle height in the layout state, only when handle is set to null.\n * @returns An object containing the animated layout state.\n */\nexport function useAnimatedLayout(\n  containerLayoutState: SharedValue<ContainerLayoutState> | undefined,\n  topInset: number,\n  bottomInset: number,\n  modal?: boolean,\n  shouldOverrideHandleHeight?: boolean\n) {\n  //#region  variables\n  const verticalInset = useMemo(\n    () => topInset + bottomInset,\n    [topInset, bottomInset]\n  );\n  const initialState = useMemo(() => {\n    const _state = { ...INITIAL_STATE };\n\n    if (containerLayoutState) {\n      const containerLayout = containerLayoutState.get();\n      _state.containerHeight = modal\n        ? containerLayout.height - verticalInset\n        : containerLayout.height;\n      _state.containerOffset = containerLayout.offset;\n    }\n\n    if (shouldOverrideHandleHeight) {\n      _state.handleHeight = 0;\n    }\n\n    return _state;\n  }, [containerLayoutState, modal, shouldOverrideHandleHeight, verticalInset]);\n  //#endregion\n\n  //#region state\n  const [state] = useState(() => makeMutable(initialState));\n  //#endregion\n\n  //#region effects\n  useAnimatedReaction(\n    () => state.value.rawContainerHeight,\n    (result, previous) => {\n      if (result === previous) {\n        return;\n      }\n      if (result === INITIAL_LAYOUT_VALUE) {\n        return;\n      }\n\n      state.modify(_state => {\n        'worklet';\n        _state.containerHeight = modal ? result - verticalInset : result;\n        return _state;\n      });\n    },\n    [state, verticalInset, modal]\n  );\n  useAnimatedReaction(\n    () => containerLayoutState?.get().height,\n    (result, previous) => {\n      if (!result || result === previous) {\n        return;\n      }\n      if (result === INITIAL_LAYOUT_VALUE) {\n        return;\n      }\n\n      state.modify(_state => {\n        'worklet';\n        _state.containerHeight = modal ? result - verticalInset : result;\n        return _state;\n      });\n    },\n    [state, verticalInset, modal]\n  );\n  //#endregion\n\n  return state;\n}\n"
  },
  {
    "path": "src/hooks/useBottomSheet.ts",
    "content": "import { useContext } from 'react';\nimport { BottomSheetContext } from '../contexts/external';\n\nexport const useBottomSheet = () => {\n  const context = useContext(BottomSheetContext);\n\n  if (context === null) {\n    throw \"'useBottomSheet' cannot be used out of the BottomSheet!\";\n  }\n\n  return context;\n};\n"
  },
  {
    "path": "src/hooks/useBottomSheetContentContainerStyle.ts",
    "content": "import { useMemo, useState } from 'react';\nimport {\n  Platform,\n  StyleSheet,\n  type ViewProps,\n  type ViewStyle,\n} from 'react-native';\nimport { runOnJS, useAnimatedReaction } from 'react-native-reanimated';\nimport { useBottomSheetInternal } from './useBottomSheetInternal';\n\nexport function useBottomSheetContentContainerStyle(\n  enableFooterMarginAdjustment: boolean,\n  _style?: ViewProps['style']\n) {\n  const [footerHeight, setFooterHeight] = useState(0);\n  //#region hooks\n  const { animatedLayoutState } = useBottomSheetInternal();\n  //#endregion\n\n  //#region styles\n  const flattenStyle = useMemo<ViewStyle>(() => {\n    return !_style\n      ? {}\n      : Array.isArray(_style)\n        ? // @ts-ignore\n          (StyleSheet.compose(..._style) as ViewStyle)\n        : (_style as ViewStyle);\n  }, [_style]);\n  const style = useMemo<ViewProps['style']>(() => {\n    if (!enableFooterMarginAdjustment) {\n      return flattenStyle;\n    }\n\n    let currentBottomPadding = 0;\n    if (flattenStyle && typeof flattenStyle === 'object') {\n      const { paddingBottom, padding, paddingVertical } = flattenStyle;\n      if (paddingBottom !== undefined && typeof paddingBottom === 'number') {\n        currentBottomPadding = paddingBottom;\n      } else if (\n        paddingVertical !== undefined &&\n        typeof paddingVertical === 'number'\n      ) {\n        currentBottomPadding = paddingVertical;\n      } else if (padding !== undefined && typeof padding === 'number') {\n        currentBottomPadding = padding;\n      }\n    }\n\n    return [\n      flattenStyle,\n      {\n        paddingBottom: currentBottomPadding + footerHeight,\n        overflow: 'visible',\n      },\n    ];\n  }, [footerHeight, enableFooterMarginAdjustment, flattenStyle]);\n  //#endregion\n\n  //#region effects\n  useAnimatedReaction(\n    () => animatedLayoutState.get().footerHeight,\n    (result, previousFooterHeight) => {\n      if (!enableFooterMarginAdjustment) {\n        return;\n      }\n      runOnJS(setFooterHeight)(result);\n\n      if (Platform.OS === 'web') {\n        /**\n         * a reaction that will append the footer height to the content\n         * height if margin adjustment is true.\n         *\n         * This is needed due to the web layout the footer after the content.\n         */\n        if (result && !previousFooterHeight) {\n          animatedLayoutState.modify(state => {\n            'worklet';\n            state.contentHeight = state.contentHeight + result;\n            return state;\n          });\n        }\n      }\n    },\n    [animatedLayoutState, enableFooterMarginAdjustment]\n  );\n  //#endregion\n  return style;\n}\n"
  },
  {
    "path": "src/hooks/useBottomSheetGestureHandlers.ts",
    "content": "import { useContext } from 'react';\nimport { BottomSheetGestureHandlersContext } from '../contexts/gesture';\n\nexport const useBottomSheetGestureHandlers = () => {\n  const context = useContext(BottomSheetGestureHandlersContext);\n\n  if (context === null) {\n    throw \"'useBottomSheetGestureHandlers' cannot be used out of the BottomSheet!\";\n  }\n\n  return context;\n};\n"
  },
  {
    "path": "src/hooks/useBottomSheetInternal.ts",
    "content": "import { useContext } from 'react';\nimport {\n  BottomSheetInternalContext,\n  type BottomSheetInternalContextType,\n} from '../contexts/internal';\n\nexport function useBottomSheetInternal(\n  unsafe?: false\n): BottomSheetInternalContextType;\n\nexport function useBottomSheetInternal(\n  unsafe: true\n): BottomSheetInternalContextType | null;\n\nexport function useBottomSheetInternal(\n  unsafe?: boolean\n): BottomSheetInternalContextType | null {\n  const context = useContext(BottomSheetInternalContext);\n\n  if (unsafe !== true && context === null) {\n    throw \"'useBottomSheetInternal' cannot be used out of the BottomSheet!\";\n  }\n\n  return context;\n}\n"
  },
  {
    "path": "src/hooks/useBottomSheetModal.ts",
    "content": "import { useContext } from 'react';\nimport { BottomSheetModalContext } from '../contexts';\n\nexport const useBottomSheetModal = () => {\n  const context = useContext(BottomSheetModalContext);\n\n  if (context === null) {\n    throw \"'BottomSheetModalContext' cannot be null!\";\n  }\n\n  return context;\n};\n"
  },
  {
    "path": "src/hooks/useBottomSheetModalInternal.ts",
    "content": "import { useContext } from 'react';\nimport {\n  BottomSheetModalInternalContext,\n  type BottomSheetModalInternalContextType,\n} from '../contexts';\n\nexport function useBottomSheetModalInternal(\n  unsafe?: false\n): BottomSheetModalInternalContextType;\n\nexport function useBottomSheetModalInternal(\n  unsafe: true\n): BottomSheetModalInternalContextType | null;\n\nexport function useBottomSheetModalInternal(\n  unsafe?: boolean\n): BottomSheetModalInternalContextType | null {\n  const context = useContext(BottomSheetModalInternalContext);\n\n  if (unsafe !== true && context === null) {\n    throw \"'BottomSheetModalInternalContext' cannot be null!\";\n  }\n\n  return context;\n}\n"
  },
  {
    "path": "src/hooks/useBottomSheetScrollableCreator.tsx",
    "content": "import { type ReactElement, useCallback } from 'react';\nimport {\n  type BottomSheetScrollableProps,\n  BottomSheetScrollView,\n} from '../components/bottomSheetScrollable';\n\ntype BottomSheetScrollableCreatorConfigs = {} & BottomSheetScrollableProps;\n\n/**\n * A custom hook that creates a scrollable component for third-party libraries\n * like `LegendList` or `FlashList` to integrate the interaction and scrolling\n * behaviors with th BottomSheet component.\n *\n * @param configs - Configuration options for the scrollable creator.\n * @param configs.focusHook - This needed when bottom sheet used with multiple scrollables to allow bottom sheet\n * detect the current scrollable ref, especially when used with `React Navigation`.\n * You will need to provide `useFocusEffect` from `@react-navigation/native`.\n * @param configs.scrollEventsHandlersHook - Custom hook to provide scroll events handler, which will allow advance and\n * customize handling for scrollables.\n * @param configs.enableFooterMarginAdjustment - Adjust the scrollable bottom margin to avoid the animated footer.\n *\n * @example\n * ```tsx\n * const BottomSheetLegendListScrollable = useBottomSheetScrollableCreator();\n *\n * // Usage in JSX\n * <LegendList\n *  renderScrollComponent={BottomSheetLegendListScrollable}\n * />\n * ```\n */\n// biome-ignore lint/suspicious/noExplicitAny: out of my control\nexport function useBottomSheetScrollableCreator<T = any>({\n  focusHook,\n  scrollEventsHandlersHook,\n  enableFooterMarginAdjustment,\n}: BottomSheetScrollableCreatorConfigs = {}): (\n  props: T,\n  ref?: never\n) => ReactElement<T> {\n  return useCallback(\n    function useBottomSheetScrollableCreator(\n      // @ts-expect-error\n      { data: _, ...props }: T,\n      ref?: never\n    ): ReactElement<T> {\n      return (\n        // @ts-expect-error\n        <BottomSheetScrollView\n          ref={ref}\n          {...props}\n          focusHook={focusHook}\n          scrollEventsHandlersHook={scrollEventsHandlersHook}\n          enableFooterMarginAdjustment={enableFooterMarginAdjustment}\n        />\n      );\n    },\n    [focusHook, scrollEventsHandlersHook, enableFooterMarginAdjustment]\n  );\n}\n"
  },
  {
    "path": "src/hooks/useBottomSheetSpringConfigs.ts",
    "content": "import type { WithSpringConfig } from 'react-native-reanimated';\n\n/**\n * Generate spring animation configs.\n * @param configs overridable configs.\n */\nexport const useBottomSheetSpringConfigs = (\n  configs: Omit<WithSpringConfig, 'velocity'>\n) => {\n  return configs;\n};\n"
  },
  {
    "path": "src/hooks/useBottomSheetTimingConfigs.ts",
    "content": "import { useMemo } from 'react';\nimport type { EasingFunction } from 'react-native';\nimport type {\n  EasingFunctionFactory,\n  ReduceMotion,\n} from 'react-native-reanimated';\nimport { ANIMATION_DURATION, ANIMATION_EASING } from '../constants';\n\n/**\n * this is needed to avoid TS4023\n * https://github.com/microsoft/TypeScript/issues/5711\n */\ninterface TimingConfig {\n  duration?: number;\n  easing?: EasingFunction | EasingFunctionFactory;\n  reduceMotion?: ReduceMotion;\n}\n\n/**\n * Generate timing animation configs.\n * @default\n * - easing: Easing.out(Easing.exp)\n * - duration: 250\n * @param configs overridable configs.\n */\nexport const useBottomSheetTimingConfigs = (configs: TimingConfig) => {\n  return useMemo(() => {\n    const _configs: TimingConfig = {\n      easing: configs.easing || ANIMATION_EASING,\n      duration: configs.duration || ANIMATION_DURATION,\n      reduceMotion: configs.reduceMotion,\n    };\n\n    return _configs;\n  }, [configs.duration, configs.easing, configs.reduceMotion]);\n};\n"
  },
  {
    "path": "src/hooks/useBoundingClientRect.ts",
    "content": "import { type RefObject, useLayoutEffect } from 'react';\nimport type { View } from 'react-native';\nimport { isFabricInstalled } from '../utilities/isFabricInstalled';\n\nexport type BoundingClientRect = {\n  x: number;\n  y: number;\n  width: number;\n  height: number;\n  left: number;\n  right: number;\n  top: number;\n  bottom: number;\n};\n\n/**\n * A custom hook that retrieves the bounding client rectangle of a given `ref` element\n * and invokes a handler function with the layout information.\n *\n * This hook is designed to work with React Native's Fabric architecture and provides\n * support for both `unstable_getBoundingClientRect` and `getBoundingClientRect` methods.\n *\n * @param ref - A `RefObject` pointing to a `View` or `null`. The bounding client rectangle\n *              will be retrieved from this reference.\n * @param handler - A callback function that will be invoked with the layout information\n *                  of the referenced element.\n *\n * @remarks\n * - The hook uses `useLayoutEffect` to ensure the layout information is retrieved\n *   after the DOM updates.\n * - The `isFabricInstalled` function is used to determine if the Fabric architecture\n *   is available.\n * - The `unstable_getBoundingClientRect` method is used if available, falling back\n *   to `getBoundingClientRect` otherwise.\n *\n * @example\n * ```tsx\n * const ref = useRef<View | null>(null);\n * useBoundingClientRect(ref, (layout) => {\n *   console.log('Bounding client rect:', layout);\n * });\n * ```\n */\nexport function useBoundingClientRect(\n  ref: RefObject<View | null>,\n  handler: (layout: BoundingClientRect) => void\n) {\n  if (!isFabricInstalled()) {\n    return;\n  }\n\n  // biome-ignore lint/correctness/useHookAtTopLevel: `isFabricInstalled` is a constant that will not change during the runtime\n  useLayoutEffect(() => {\n    if (!ref || !ref.current) {\n      return;\n    }\n\n    if (\n      // @ts-expect-error 👉 https://github.com/facebook/react/commit/53b1f69ba\n      ref.current.unstable_getBoundingClientRect !== null &&\n      // @ts-expect-error 👉 https://github.com/facebook/react/commit/53b1f69ba\n      typeof ref.current.unstable_getBoundingClientRect === 'function'\n    ) {\n      // @ts-expect-error https://github.com/facebook/react/commit/53b1f69ba\n      const layout = ref.current.unstable_getBoundingClientRect();\n      handler(layout);\n      return;\n    }\n\n    // @ts-expect-error once it `unstable_getBoundingClientRect` gets stable 🤞.\n    if (ref.current.getBoundingClientRect !== null) {\n      // @ts-expect-error once it `unstable_getBoundingClientRect` gets stable.\n      const layout = ref.current.getBoundingClientRect();\n      handler(layout);\n    }\n  });\n}\n"
  },
  {
    "path": "src/hooks/useGestureEventsHandlersDefault.tsx",
    "content": "import { useCallback } from 'react';\nimport { Keyboard, Platform } from 'react-native';\nimport { runOnJS, useSharedValue } from 'react-native-reanimated';\nimport {\n  ANIMATION_SOURCE,\n  GESTURE_SOURCE,\n  KEYBOARD_STATUS,\n  SCROLLABLE_TYPE,\n  WINDOW_HEIGHT,\n} from '../constants';\nimport type {\n  GestureEventHandlerCallbackType,\n  GestureEventsHandlersHookType,\n} from '../types';\nimport { clamp } from '../utilities/clamp';\nimport { snapPoint } from '../utilities/snapPoint';\nimport { useBottomSheetInternal } from './useBottomSheetInternal';\n\ntype GestureEventContextType = {\n  initialPosition: number;\n  initialKeyboardStatus: KEYBOARD_STATUS;\n  isScrollablePositionLocked: boolean;\n};\n\nconst INITIAL_CONTEXT: GestureEventContextType = {\n  initialPosition: 0,\n  initialKeyboardStatus: KEYBOARD_STATUS.UNDETERMINED,\n  isScrollablePositionLocked: false,\n};\n\nconst dismissKeyboard = Keyboard.dismiss;\n\n// biome-ignore lint: to be addressed!\nconst resetContext = (context: any) => {\n  'worklet';\n  Object.keys(context).map(key => {\n    context[key] = undefined;\n  });\n};\n\nexport const useGestureEventsHandlersDefault: GestureEventsHandlersHookType =\n  () => {\n    //#region variables\n    const {\n      animatedPosition,\n      animatedDetentsState,\n      animatedKeyboardState,\n      animatedScrollableState,\n      animatedLayoutState,\n      enableOverDrag,\n      enablePanDownToClose,\n      overDragResistanceFactor,\n      isInTemporaryPosition,\n      enableBlurKeyboardOnGesture,\n      animateToPosition,\n      stopAnimation,\n    } = useBottomSheetInternal();\n\n    const context = useSharedValue<GestureEventContextType>({\n      ...INITIAL_CONTEXT,\n    });\n    //#endregion\n\n    //#region gesture methods\n    const handleOnStart: GestureEventHandlerCallbackType = useCallback(\n      function handleOnStart(__, _) {\n        'worklet';\n        // cancel current animation\n        stopAnimation();\n\n        let initialKeyboardStatus = animatedKeyboardState.get().status;\n        // blur the keyboard when user start dragging the bottom sheet\n        if (\n          enableBlurKeyboardOnGesture &&\n          initialKeyboardStatus === KEYBOARD_STATUS.SHOWN\n        ) {\n          initialKeyboardStatus = KEYBOARD_STATUS.HIDDEN;\n          runOnJS(dismissKeyboard)();\n        }\n\n        // store current animated position\n        context.value = {\n          ...context.value,\n          initialPosition: animatedPosition.value,\n          initialKeyboardStatus,\n        };\n\n        /**\n         * if the scrollable content is scrolled, then\n         * we lock the position.\n         */\n        if (animatedScrollableState.get().contentOffsetY > 0) {\n          context.value = {\n            ...context.value,\n            isScrollablePositionLocked: true,\n          };\n        }\n      },\n      [\n        stopAnimation,\n        context,\n        enableBlurKeyboardOnGesture,\n        animatedPosition,\n        animatedKeyboardState,\n        animatedScrollableState,\n      ]\n    );\n    const handleOnChange: GestureEventHandlerCallbackType = useCallback(\n      function handleOnChange(source, { translationY }) {\n        'worklet';\n        const { highestDetentPosition, detents } = animatedDetentsState.get();\n        if (\n          highestDetentPosition === undefined ||\n          detents === undefined ||\n          detents.length === 0\n        ) {\n          return;\n        }\n\n        let highestSnapPoint = highestDetentPosition;\n\n        /**\n         * if keyboard is shown, then we set the highest point to the current\n         * position which includes the keyboard height.\n         */\n        if (\n          isInTemporaryPosition.value &&\n          context.value.initialKeyboardStatus === KEYBOARD_STATUS.SHOWN\n        ) {\n          highestSnapPoint = context.value.initialPosition;\n        }\n\n        /**\n         * if current position is out of provided `snapPoints` and smaller then\n         * highest snap pont, then we set the highest point to the current position.\n         */\n        if (\n          isInTemporaryPosition.value &&\n          context.value.initialPosition < highestSnapPoint\n        ) {\n          highestSnapPoint = context.value.initialPosition;\n        }\n\n        const { containerHeight } = animatedLayoutState.get();\n        const lowestSnapPoint = enablePanDownToClose\n          ? containerHeight\n          : detents[0];\n\n        /**\n         * if scrollable is refreshable and sheet position at the highest\n         * point, then do not interact with current gesture.\n         */\n        if (\n          source === GESTURE_SOURCE.CONTENT &&\n          animatedScrollableState.get().refreshable &&\n          animatedPosition.value === highestSnapPoint\n        ) {\n          return;\n        }\n\n        /**\n         * a negative scrollable content offset to be subtracted from accumulated\n         * current position and gesture translation Y to allow user to drag the sheet,\n         * when scrollable position at the top.\n         * a negative scrollable content offset when the scrollable is not locked.\n         */\n        const negativeScrollableContentOffset =\n          (context.value.initialPosition === highestSnapPoint &&\n            source === GESTURE_SOURCE.CONTENT) ||\n          !context.value.isScrollablePositionLocked\n            ? animatedScrollableState.get().contentOffsetY * -1\n            : 0;\n\n        /**\n         * an accumulated value of starting position with gesture translation y.\n         */\n        const draggedPosition = context.value.initialPosition + translationY;\n\n        /**\n         * an accumulated value of dragged position and negative scrollable content offset,\n         * this will insure locking sheet position when user is scrolling the scrollable until,\n         * they reach to the top of the scrollable.\n         */\n        const accumulatedDraggedPosition =\n          draggedPosition + negativeScrollableContentOffset;\n\n        /**\n         * a clamped value of the accumulated dragged position, to insure keeping the dragged\n         * position between the highest and lowest snap points.\n         */\n        const clampedPosition = clamp(\n          accumulatedDraggedPosition,\n          highestSnapPoint,\n          lowestSnapPoint\n        );\n\n        /**\n         * if scrollable position is locked and the animated position\n         * reaches the highest point, then we unlock the scrollable position.\n         */\n        if (\n          context.value.isScrollablePositionLocked &&\n          source === GESTURE_SOURCE.CONTENT &&\n          animatedPosition.value === highestSnapPoint\n        ) {\n          context.value = {\n            ...context.value,\n            isScrollablePositionLocked: false,\n          };\n        }\n\n        /**\n         * over-drag implementation.\n         */\n        if (enableOverDrag) {\n          if (\n            (source === GESTURE_SOURCE.HANDLE ||\n              animatedScrollableState.get().type === SCROLLABLE_TYPE.VIEW) &&\n            draggedPosition < highestSnapPoint\n          ) {\n            const resistedPosition =\n              highestSnapPoint -\n              Math.sqrt(1 + (highestSnapPoint - draggedPosition)) *\n                overDragResistanceFactor;\n            animatedPosition.value = resistedPosition;\n            return;\n          }\n\n          if (\n            source === GESTURE_SOURCE.HANDLE &&\n            draggedPosition > lowestSnapPoint\n          ) {\n            const resistedPosition =\n              lowestSnapPoint +\n              Math.sqrt(1 + (draggedPosition - lowestSnapPoint)) *\n                overDragResistanceFactor;\n            animatedPosition.value = resistedPosition;\n            return;\n          }\n\n          if (\n            source === GESTURE_SOURCE.CONTENT &&\n            draggedPosition + negativeScrollableContentOffset > lowestSnapPoint\n          ) {\n            const resistedPosition =\n              lowestSnapPoint +\n              Math.sqrt(\n                1 +\n                  (draggedPosition +\n                    negativeScrollableContentOffset -\n                    lowestSnapPoint)\n              ) *\n                overDragResistanceFactor;\n            animatedPosition.value = resistedPosition;\n            return;\n          }\n        }\n\n        animatedPosition.value = clampedPosition;\n      },\n      [\n        enableOverDrag,\n        enablePanDownToClose,\n        overDragResistanceFactor,\n        isInTemporaryPosition,\n        animatedScrollableState,\n        animatedDetentsState,\n        animatedLayoutState,\n        animatedPosition,\n        context,\n      ]\n    );\n    const handleOnEnd: GestureEventHandlerCallbackType = useCallback(\n      function handleOnEnd(source, { translationY, absoluteY, velocityY }) {\n        'worklet';\n        const { highestDetentPosition, detents, closedDetentPosition } =\n          animatedDetentsState.get();\n        if (\n          highestDetentPosition === undefined ||\n          detents === undefined ||\n          detents.length === 0 ||\n          closedDetentPosition === undefined\n        ) {\n          return;\n        }\n\n        const highestSnapPoint = highestDetentPosition;\n        const isSheetAtHighestSnapPoint =\n          animatedPosition.value === highestSnapPoint;\n        const {\n          refreshable: scrollableIsRefreshable,\n          contentOffsetY: scrollableContentOffsetY,\n          type: scrollableType,\n        } = animatedScrollableState.get();\n\n        /**\n         * if scrollable is refreshable and sheet position at the highest\n         * point, then do not interact with current gesture.\n         */\n        if (\n          source === GESTURE_SOURCE.CONTENT &&\n          scrollableIsRefreshable &&\n          isSheetAtHighestSnapPoint\n        ) {\n          return;\n        }\n\n        /**\n         * if the sheet is in a temporary position and the gesture ended above\n         * the current position, then we snap back to the temporary position.\n         */\n        if (\n          isInTemporaryPosition.value &&\n          context.value.initialPosition >= animatedPosition.value\n        ) {\n          if (context.value.initialPosition > animatedPosition.value) {\n            animateToPosition(\n              context.value.initialPosition,\n              ANIMATION_SOURCE.GESTURE,\n              velocityY / 2\n            );\n          }\n          return;\n        }\n\n        /**\n         * close keyboard if current position is below the recorded\n         * start position and keyboard still shown.\n         */\n        const isScrollable =\n          scrollableType !== SCROLLABLE_TYPE.UNDETERMINED &&\n          scrollableType !== SCROLLABLE_TYPE.VIEW;\n\n        /**\n         * if keyboard is shown and the sheet is dragged down,\n         * then we dismiss the keyboard.\n         */\n        if (\n          context.value.initialKeyboardStatus === KEYBOARD_STATUS.SHOWN &&\n          animatedPosition.value > context.value.initialPosition\n        ) {\n          /**\n           * if the platform is ios, current content is scrollable and\n           * the end touch point is below the keyboard position then\n           * we exit the method.\n           *\n           * because the the keyboard dismiss is interactive in iOS.\n           */\n          if (\n            !(\n              Platform.OS === 'ios' &&\n              isScrollable &&\n              absoluteY >\n                WINDOW_HEIGHT -\n                  animatedKeyboardState.get().heightWithinContainer\n            )\n          ) {\n            runOnJS(dismissKeyboard)();\n          }\n        }\n\n        /**\n         * reset isInTemporaryPosition value\n         */\n        if (isInTemporaryPosition.value) {\n          isInTemporaryPosition.value = false;\n        }\n\n        /**\n         * clone snap points array, and insert the container height\n         * if pan down to close is enabled.\n         */\n        const snapPoints = detents.slice();\n        if (enablePanDownToClose) {\n          snapPoints.unshift(closedDetentPosition);\n        }\n\n        /**\n         * calculate the destination point, using redash.\n         */\n        const destinationPoint = snapPoint(\n          translationY + context.value.initialPosition,\n          velocityY,\n          snapPoints\n        );\n\n        /**\n         * if destination point is the same as the current position,\n         * then no need to perform animation.\n         */\n        if (destinationPoint === animatedPosition.value) {\n          return;\n        }\n\n        const wasGestureHandledByScrollView =\n          source === GESTURE_SOURCE.CONTENT && scrollableContentOffsetY > 0;\n        /**\n         * prevents snapping from top to middle / bottom with repeated interrupted scrolls\n         */\n        if (wasGestureHandledByScrollView && isSheetAtHighestSnapPoint) {\n          return;\n        }\n\n        animateToPosition(\n          destinationPoint,\n          ANIMATION_SOURCE.GESTURE,\n          velocityY / 2\n        );\n      },\n      [\n        enablePanDownToClose,\n        isInTemporaryPosition,\n        animatedScrollableState,\n        animatedDetentsState,\n        animatedKeyboardState,\n        animatedPosition,\n        animateToPosition,\n        context,\n      ]\n    );\n    const handleOnFinalize: GestureEventHandlerCallbackType = useCallback(\n      function handleOnFinalize() {\n        'worklet';\n        resetContext(context);\n      },\n      [context]\n    );\n    //#endregion\n\n    return {\n      handleOnStart,\n      handleOnChange,\n      handleOnEnd,\n      handleOnFinalize,\n    };\n  };\n"
  },
  {
    "path": "src/hooks/useGestureEventsHandlersDefault.web.tsx",
    "content": "import { useCallback } from 'react';\nimport { Keyboard, Platform } from 'react-native';\nimport { runOnJS, useSharedValue } from 'react-native-reanimated';\nimport {\n  ANIMATION_SOURCE,\n  GESTURE_SOURCE,\n  KEYBOARD_STATUS,\n  SCROLLABLE_TYPE,\n  WINDOW_HEIGHT,\n} from '../constants';\nimport type { GestureEventHandlerCallbackType } from '../types';\nimport { clamp } from '../utilities/clamp';\nimport { snapPoint } from '../utilities/snapPoint';\nimport { useBottomSheetInternal } from './useBottomSheetInternal';\n\ntype GestureEventContextType = {\n  initialPosition: number;\n  initialKeyboardStatus: KEYBOARD_STATUS;\n  initialTranslationY: number;\n  isScrollablePositionLocked: boolean;\n};\n\nconst INITIAL_CONTEXT: GestureEventContextType = {\n  initialPosition: 0,\n  initialTranslationY: 0,\n  initialKeyboardStatus: KEYBOARD_STATUS.UNDETERMINED,\n  isScrollablePositionLocked: false,\n};\n\nconst dismissKeyboardOnJs = runOnJS(Keyboard.dismiss);\n\n// biome-ignore lint: to be addressed!\nconst resetContext = (context: any) => {\n  'worklet';\n  Object.keys(context).map(key => {\n    context[key] = undefined;\n  });\n};\n\nexport const useGestureEventsHandlersDefault = () => {\n  //#region variables\n  const {\n    animatedPosition,\n    animatedDetentsState,\n    animatedKeyboardState,\n    animatedLayoutState,\n    animatedScrollableState,\n    enableOverDrag,\n    enablePanDownToClose,\n    overDragResistanceFactor,\n    isInTemporaryPosition,\n    animateToPosition,\n    stopAnimation,\n  } = useBottomSheetInternal();\n\n  const context = useSharedValue<GestureEventContextType>({\n    ...INITIAL_CONTEXT,\n  });\n  //#endregion\n\n  //#region gesture methods\n  const handleOnStart: GestureEventHandlerCallbackType = useCallback(\n    function handleOnStart(__, { translationY }) {\n      'worklet';\n      // cancel current animation\n      stopAnimation();\n\n      // store current animated position\n      context.value = {\n        ...context.value,\n        initialPosition: animatedPosition.value,\n        initialKeyboardStatus: animatedKeyboardState.get().status,\n        initialTranslationY: translationY,\n      };\n\n      /**\n       * if the scrollable content is scrolled, then\n       * we lock the position.\n       */\n      if (animatedScrollableState.get().contentOffsetY > 0) {\n        context.value.isScrollablePositionLocked = true;\n      }\n    },\n    [\n      stopAnimation,\n      context,\n      animatedPosition,\n      animatedKeyboardState,\n      animatedScrollableState,\n    ]\n  );\n  const handleOnChange: GestureEventHandlerCallbackType = useCallback(\n    function handleOnChange(source, { translationY }) {\n      'worklet';\n      const { highestDetentPosition, detents } = animatedDetentsState.get();\n      if (highestDetentPosition === undefined || detents === undefined) {\n        return;\n      }\n\n      let highestSnapPoint = highestDetentPosition;\n      translationY = translationY - context.value.initialTranslationY;\n      /**\n       * if keyboard is shown, then we set the highest point to the current\n       * position which includes the keyboard height.\n       */\n      if (\n        isInTemporaryPosition.value &&\n        context.value.initialKeyboardStatus === KEYBOARD_STATUS.SHOWN\n      ) {\n        highestSnapPoint = context.value.initialPosition;\n      }\n\n      /**\n       * if current position is out of provided `snapPoints` and smaller then\n       * highest snap pont, then we set the highest point to the current position.\n       */\n      if (\n        isInTemporaryPosition.value &&\n        context.value.initialPosition < highestSnapPoint\n      ) {\n        highestSnapPoint = context.value.initialPosition;\n      }\n\n      const { containerHeight } = animatedLayoutState.get();\n      const lowestSnapPoint = enablePanDownToClose\n        ? containerHeight\n        : detents[0];\n\n      const {\n        refreshable: scrollableIsRefreshable,\n        contentOffsetY: scrollableContentOffsetY,\n        type: scrollableType,\n      } = animatedScrollableState.get();\n\n      /**\n       * if scrollable is refreshable and sheet position at the highest\n       * point, then do not interact with current gesture.\n       */\n      if (\n        source === GESTURE_SOURCE.CONTENT &&\n        scrollableIsRefreshable &&\n        animatedPosition.value === highestSnapPoint\n      ) {\n        return;\n      }\n\n      /**\n       * a negative scrollable content offset to be subtracted from accumulated\n       * current position and gesture translation Y to allow user to drag the sheet,\n       * when scrollable position at the top.\n       * a negative scrollable content offset when the scrollable is not locked.\n       */\n      const negativeScrollableContentOffset =\n        (context.value.initialPosition === highestSnapPoint &&\n          source === GESTURE_SOURCE.CONTENT) ||\n        !context.value.isScrollablePositionLocked\n          ? scrollableContentOffsetY * -1\n          : 0;\n\n      /**\n       * an accumulated value of starting position with gesture translation y.\n       */\n      const draggedPosition = context.value.initialPosition + translationY;\n\n      /**\n       * an accumulated value of dragged position and negative scrollable content offset,\n       * this will insure locking sheet position when user is scrolling the scrollable until,\n       * they reach to the top of the scrollable.\n       */\n      const accumulatedDraggedPosition =\n        draggedPosition + negativeScrollableContentOffset;\n\n      /**\n       * a clamped value of the accumulated dragged position, to insure keeping the dragged\n       * position between the highest and lowest snap points.\n       */\n      const clampedPosition = clamp(\n        accumulatedDraggedPosition,\n        highestSnapPoint,\n        lowestSnapPoint\n      );\n\n      /**\n       * if scrollable position is locked and the animated position\n       * reaches the highest point, then we unlock the scrollable position.\n       */\n      if (\n        context.value.isScrollablePositionLocked &&\n        source === GESTURE_SOURCE.CONTENT &&\n        animatedPosition.value === highestSnapPoint\n      ) {\n        context.value.isScrollablePositionLocked = false;\n      }\n\n      /**\n       * over-drag implementation.\n       */\n      if (enableOverDrag) {\n        if (\n          (source === GESTURE_SOURCE.HANDLE ||\n            scrollableType === SCROLLABLE_TYPE.VIEW) &&\n          draggedPosition < highestSnapPoint\n        ) {\n          const resistedPosition =\n            highestSnapPoint -\n            Math.sqrt(1 + (highestSnapPoint - draggedPosition)) *\n              overDragResistanceFactor;\n          animatedPosition.value = resistedPosition;\n          return;\n        }\n\n        if (\n          source === GESTURE_SOURCE.HANDLE &&\n          draggedPosition > lowestSnapPoint\n        ) {\n          const resistedPosition =\n            lowestSnapPoint +\n            Math.sqrt(1 + (draggedPosition - lowestSnapPoint)) *\n              overDragResistanceFactor;\n          animatedPosition.value = resistedPosition;\n          return;\n        }\n\n        if (\n          source === GESTURE_SOURCE.CONTENT &&\n          draggedPosition + negativeScrollableContentOffset > lowestSnapPoint\n        ) {\n          const resistedPosition =\n            lowestSnapPoint +\n            Math.sqrt(\n              1 +\n                (draggedPosition +\n                  negativeScrollableContentOffset -\n                  lowestSnapPoint)\n            ) *\n              overDragResistanceFactor;\n          animatedPosition.value = resistedPosition;\n          return;\n        }\n      }\n\n      animatedPosition.value = clampedPosition;\n    },\n    [\n      context,\n      enableOverDrag,\n      enablePanDownToClose,\n      overDragResistanceFactor,\n      isInTemporaryPosition,\n      animatedDetentsState,\n      animatedLayoutState,\n      animatedPosition,\n      animatedScrollableState,\n    ]\n  );\n  const handleOnEnd: GestureEventHandlerCallbackType = useCallback(\n    function handleOnEnd(source, { translationY, absoluteY, velocityY }) {\n      'worklet';\n      const { highestDetentPosition, detents, closedDetentPosition } =\n        animatedDetentsState.get();\n      if (\n        highestDetentPosition === undefined ||\n        detents === undefined ||\n        closedDetentPosition === undefined\n      ) {\n        return;\n      }\n\n      const highestSnapPoint = highestDetentPosition;\n      const isSheetAtHighestSnapPoint =\n        animatedPosition.value === highestSnapPoint;\n\n      const {\n        refreshable: scrollableIsRefreshable,\n        contentOffsetY: scrollableContentOffsetY,\n        type: scrollableType,\n      } = animatedScrollableState.get();\n\n      /**\n       * if scrollable is refreshable and sheet position at the highest\n       * point, then do not interact with current gesture.\n       */\n      if (\n        source === GESTURE_SOURCE.CONTENT &&\n        scrollableIsRefreshable &&\n        isSheetAtHighestSnapPoint\n      ) {\n        return;\n      }\n\n      /**\n       * if the sheet is in a temporary position and the gesture ended above\n       * the current position, then we snap back to the temporary position.\n       */\n      if (\n        isInTemporaryPosition.value &&\n        context.value.initialPosition >= animatedPosition.value\n      ) {\n        if (context.value.initialPosition > animatedPosition.value) {\n          animateToPosition(\n            context.value.initialPosition,\n            ANIMATION_SOURCE.GESTURE,\n            velocityY / 2\n          );\n        }\n        return;\n      }\n\n      /**\n       * close keyboard if current position is below the recorded\n       * start position and keyboard still shown.\n       */\n      const isScrollable =\n        scrollableType !== SCROLLABLE_TYPE.UNDETERMINED &&\n        scrollableType !== SCROLLABLE_TYPE.VIEW;\n\n      /**\n       * if keyboard is shown and the sheet is dragged down,\n       * then we dismiss the keyboard.\n       */\n      if (\n        context.value.initialKeyboardStatus === KEYBOARD_STATUS.SHOWN &&\n        animatedPosition.value > context.value.initialPosition\n      ) {\n        /**\n         * if the platform is ios, current content is scrollable and\n         * the end touch point is below the keyboard position then\n         * we exit the method.\n         *\n         * because the the keyboard dismiss is interactive in iOS.\n         */\n        if (\n          !(\n            Platform.OS === 'ios' &&\n            isScrollable &&\n            absoluteY >\n              WINDOW_HEIGHT - animatedKeyboardState.get().heightWithinContainer\n          )\n        ) {\n          dismissKeyboardOnJs();\n        }\n      }\n\n      /**\n       * reset isInTemporaryPosition value\n       */\n      if (isInTemporaryPosition.value) {\n        isInTemporaryPosition.value = false;\n      }\n\n      /**\n       * clone snap points array, and insert the container height\n       * if pan down to close is enabled.\n       */\n      const snapPoints = detents.slice();\n      if (enablePanDownToClose) {\n        snapPoints.unshift(closedDetentPosition);\n      }\n\n      /**\n       * calculate the destination point, using redash.\n       */\n      const destinationPoint = snapPoint(\n        translationY + context.value.initialPosition,\n        velocityY,\n        snapPoints\n      );\n\n      /**\n       * if destination point is the same as the current position,\n       * then no need to perform animation.\n       */\n      if (destinationPoint === animatedPosition.value) {\n        return;\n      }\n\n      const wasGestureHandledByScrollView =\n        source === GESTURE_SOURCE.CONTENT && scrollableContentOffsetY > 0;\n      /**\n       * prevents snapping from top to middle / bottom with repeated interrupted scrolls\n       */\n      if (wasGestureHandledByScrollView && isSheetAtHighestSnapPoint) {\n        return;\n      }\n\n      animateToPosition(\n        destinationPoint,\n        ANIMATION_SOURCE.GESTURE,\n        velocityY / 2\n      );\n    },\n    [\n      enablePanDownToClose,\n      isInTemporaryPosition,\n      animatedScrollableState,\n      animatedDetentsState,\n      animatedKeyboardState,\n      animatedPosition,\n      animateToPosition,\n      context,\n    ]\n  );\n  const handleOnFinalize: GestureEventHandlerCallbackType = useCallback(\n    function handleOnFinalize() {\n      'worklet';\n      resetContext(context);\n    },\n    [context]\n  );\n  //#endregion\n\n  return {\n    handleOnStart,\n    handleOnChange,\n    handleOnEnd,\n    handleOnFinalize,\n  };\n};\n"
  },
  {
    "path": "src/hooks/useGestureHandler.ts",
    "content": "import { useCallback } from 'react';\nimport {\n  type GestureStateChangeEvent,\n  type GestureUpdateEvent,\n  type PanGestureChangeEventPayload,\n  type PanGestureHandlerEventPayload,\n  State,\n} from 'react-native-gesture-handler';\nimport type { SharedValue } from 'react-native-reanimated';\nimport { GESTURE_SOURCE } from '../constants';\nimport type {\n  GestureEventHandlerCallbackType,\n  GestureHandlersHookType,\n} from '../types';\n\nexport const useGestureHandler: GestureHandlersHookType = (\n  source: GESTURE_SOURCE,\n  state: SharedValue<State>,\n  gestureSource: SharedValue<GESTURE_SOURCE>,\n  onStart: GestureEventHandlerCallbackType,\n  onChange: GestureEventHandlerCallbackType,\n  onEnd: GestureEventHandlerCallbackType,\n  onFinalize: GestureEventHandlerCallbackType\n) => {\n  const handleOnStart = useCallback(\n    (event: GestureStateChangeEvent<PanGestureHandlerEventPayload>) => {\n      'worklet';\n      state.value = State.BEGAN;\n      gestureSource.value = source;\n\n      onStart(source, event);\n      return;\n    },\n    [state, gestureSource, source, onStart]\n  );\n\n  const handleOnChange = useCallback(\n    (\n      event: GestureUpdateEvent<\n        PanGestureHandlerEventPayload & PanGestureChangeEventPayload\n      >\n    ) => {\n      'worklet';\n      if (gestureSource.value !== source) {\n        return;\n      }\n\n      state.value = event.state;\n      onChange(source, event);\n    },\n    [state, gestureSource, source, onChange]\n  );\n\n  const handleOnEnd = useCallback(\n    (event: GestureStateChangeEvent<PanGestureHandlerEventPayload>) => {\n      'worklet';\n      if (gestureSource.value !== source) {\n        return;\n      }\n\n      state.value = event.state;\n      gestureSource.value = GESTURE_SOURCE.UNDETERMINED;\n\n      onEnd(source, event);\n    },\n    [state, gestureSource, source, onEnd]\n  );\n\n  const handleOnFinalize = useCallback(\n    (event: GestureStateChangeEvent<PanGestureHandlerEventPayload>) => {\n      'worklet';\n      if (gestureSource.value !== source) {\n        return;\n      }\n\n      state.value = event.state;\n      gestureSource.value = GESTURE_SOURCE.UNDETERMINED;\n\n      onFinalize(source, event);\n    },\n    [state, gestureSource, source, onFinalize]\n  );\n\n  return {\n    handleOnStart,\n    handleOnChange,\n    handleOnEnd,\n    handleOnFinalize,\n  };\n};\n"
  },
  {
    "path": "src/hooks/usePropsValidator.ts",
    "content": "import invariant from 'invariant';\nimport { useMemo } from 'react';\nimport type { BottomSheetProps } from '../components/bottomSheet';\nimport { INITIAL_SNAP_POINT } from '../components/bottomSheet/constants';\n\n/**\n * @todo\n * replace this with `prop-types`.\n */\n\nexport const usePropsValidator = ({\n  index,\n  snapPoints,\n  enableDynamicSizing,\n  topInset,\n  bottomInset,\n  containerHeight,\n  containerOffset,\n}: Pick<\n  BottomSheetProps,\n  | 'index'\n  | 'snapPoints'\n  | 'enableDynamicSizing'\n  | 'topInset'\n  | 'bottomInset'\n  | 'containerHeight'\n  | 'containerOffset'\n>) => {\n  useMemo(() => {\n    //#region snap points\n    const _snapPoints = snapPoints\n      ? 'get' in snapPoints\n        ? snapPoints.get()\n        : snapPoints\n      : [];\n    invariant(\n      _snapPoints || enableDynamicSizing,\n      `'snapPoints' was not provided! please provide at least one snap point.`\n    );\n\n    _snapPoints.map(snapPoint => {\n      const _snapPoint =\n        typeof snapPoint === 'number'\n          ? snapPoint\n          : Number.parseInt(snapPoint.replace('%', ''), 10);\n\n      invariant(\n        _snapPoint > 0 || _snapPoint === INITIAL_SNAP_POINT,\n        `Snap point '${snapPoint}' is invalid. if you want to allow user to close the sheet, Please use 'enablePanDownToClose' prop.`\n      );\n    });\n\n    invariant(\n      'value' in _snapPoints || _snapPoints.length > 0 || enableDynamicSizing,\n      `'snapPoints' was provided with no points! please provide at least one snap point.`\n    );\n    //#endregion\n\n    //#region index\n    invariant(\n      typeof index === 'number' || typeof index === 'undefined',\n      `'index' was provided but with wrong type ! expected type is a number.`\n    );\n\n    invariant(\n      enableDynamicSizing ||\n        (typeof index === 'number'\n          ? index >= -1 && index <= _snapPoints.length - 1\n          : true),\n      `'index' was provided but out of the provided snap points range! expected value to be between -1, ${\n        _snapPoints.length - 1\n      }`\n    );\n    //#endregion\n\n    //#region insets\n    invariant(\n      typeof topInset === 'number' || typeof topInset === 'undefined',\n      `'topInset' was provided but with wrong type ! expected type is a number.`\n    );\n    invariant(\n      typeof bottomInset === 'number' || typeof bottomInset === 'undefined',\n      `'bottomInset' was provided but with wrong type ! expected type is a number.`\n    );\n    //#endregion\n\n    //#region container height and offset\n    invariant(\n      containerHeight === undefined,\n      `'containerHeight' is deprecated, please use 'containerLayoutState'.`\n    );\n\n    invariant(\n      containerOffset === undefined,\n      `'containerHeight' is deprecated, please use 'containerLayoutState'.`\n    );\n\n    // animations\n  }, [\n    index,\n    snapPoints,\n    topInset,\n    bottomInset,\n    enableDynamicSizing,\n    containerHeight,\n    containerOffset,\n  ]);\n};\n"
  },
  {
    "path": "src/hooks/useReactiveSharedValue.ts",
    "content": "import { useEffect, useRef } from 'react';\nimport type { SharedValue } from 'react-native-reanimated';\nimport { cancelAnimation, makeMutable } from 'react-native-reanimated';\nimport type { Primitive } from '../types';\n\nexport const useReactiveSharedValue = <T>(\n  value: T\n): T extends Primitive ? SharedValue<T> : T => {\n  const initialValueRef = useRef<T>(null);\n  const valueRef = useRef<SharedValue<T>>(null);\n\n  if (value && typeof value === 'object' && 'value' in value) {\n    /**\n     * if provided value is a shared value,\n     * then we do not initialize another one.\n     */\n  } else if (valueRef.current === null) {\n    // @ts-ignore\n    initialValueRef.current = value;\n    /**\n     * if value is an object, then we need to\n     * pass a clone.\n     */\n    if (typeof value === 'object') {\n      // @ts-ignore\n      valueRef.current = makeMutable({ ...value });\n    } else {\n      // @ts-ignore\n      valueRef.current = makeMutable(value);\n    }\n  } else if (initialValueRef.current !== value) {\n    valueRef.current.value = value as T;\n  }\n\n  useEffect(() => {\n    return () => {\n      if (valueRef.current) {\n        cancelAnimation(valueRef.current);\n      }\n    };\n  }, []);\n\n  // @ts-ignore\n  return valueRef.current ?? value;\n};\n"
  },
  {
    "path": "src/hooks/useScrollEventsHandlersDefault.ts",
    "content": "import { useCallback } from 'react';\nimport { State } from 'react-native-gesture-handler';\nimport { scrollTo } from 'react-native-reanimated';\nimport { ANIMATION_STATUS, SCROLLABLE_STATUS, SHEET_STATE } from '../constants';\nimport type {\n  ScrollEventHandlerCallbackType,\n  ScrollEventsHandlersHookType,\n} from '../types';\nimport { useBottomSheetInternal } from './useBottomSheetInternal';\n\nexport type ScrollEventContextType = {\n  initialContentOffsetY: number;\n  shouldLockInitialPosition: boolean;\n};\n\nexport const useScrollEventsHandlersDefault: ScrollEventsHandlersHookType = (\n  scrollableRef,\n  scrollableContentOffsetY\n) => {\n  // hooks\n  const {\n    animatedSheetState,\n    animatedScrollableState,\n    animatedScrollableStatus,\n    animatedAnimationState,\n    animatedHandleGestureState,\n  } = useBottomSheetInternal();\n\n  //#region callbacks\n  const handleOnScroll: ScrollEventHandlerCallbackType<ScrollEventContextType> =\n    useCallback(\n      ({ contentOffset: { y } }, context) => {\n        'worklet';\n        /**\n         * if sheet position is extended or fill parent, then we reset\n         * `shouldLockInitialPosition` value to false.\n         */\n        if (\n          animatedSheetState.value === SHEET_STATE.EXTENDED ||\n          animatedSheetState.value === SHEET_STATE.FILL_PARENT\n        ) {\n          context.shouldLockInitialPosition = false;\n        }\n\n        /**\n         * if handle gesture state is active, then we capture the offset y position\n         * and lock the scrollable with it.\n         */\n        if (animatedHandleGestureState.value === State.ACTIVE) {\n          context.shouldLockInitialPosition = true;\n          context.initialContentOffsetY = y;\n        }\n\n        if (animatedScrollableStatus.value === SCROLLABLE_STATUS.LOCKED) {\n          const lockPosition = context.shouldLockInitialPosition\n            ? (context.initialContentOffsetY ?? 0)\n            : 0;\n          // @ts-ignore\n          scrollTo(scrollableRef, 0, lockPosition, false);\n          scrollableContentOffsetY.value = lockPosition;\n          return;\n        }\n      },\n      [\n        scrollableRef,\n        scrollableContentOffsetY,\n        animatedScrollableStatus,\n        animatedSheetState,\n        animatedHandleGestureState,\n      ]\n    );\n  const handleOnBeginDrag: ScrollEventHandlerCallbackType<ScrollEventContextType> =\n    useCallback(\n      ({ contentOffset: { y } }, context) => {\n        'worklet';\n        scrollableContentOffsetY.value = y;\n        context.initialContentOffsetY = y;\n        animatedScrollableState.set(state => ({\n          ...state,\n          contentOffsetY: y,\n        }));\n\n        /**\n         * if sheet position not extended or fill parent and the scrollable position\n         * not at the top, then we should lock the initial scrollable position.\n         */\n        if (\n          animatedSheetState.value !== SHEET_STATE.EXTENDED &&\n          animatedSheetState.value !== SHEET_STATE.FILL_PARENT &&\n          y > 0\n        ) {\n          context.shouldLockInitialPosition = true;\n        } else {\n          context.shouldLockInitialPosition = false;\n        }\n      },\n      [scrollableContentOffsetY, animatedSheetState, animatedScrollableState]\n    );\n  const handleOnEndDrag: ScrollEventHandlerCallbackType<ScrollEventContextType> =\n    useCallback(\n      ({ contentOffset: { y } }, context) => {\n        'worklet';\n        if (animatedScrollableStatus.value === SCROLLABLE_STATUS.LOCKED) {\n          const lockPosition = context.shouldLockInitialPosition\n            ? (context.initialContentOffsetY ?? 0)\n            : 0;\n          // @ts-ignore\n          scrollTo(scrollableRef, 0, lockPosition, false);\n          scrollableContentOffsetY.value = lockPosition;\n          return;\n        }\n\n        if (animatedAnimationState.get().status !== ANIMATION_STATUS.RUNNING) {\n          scrollableContentOffsetY.value = y;\n          animatedScrollableState.set(state => ({\n            ...state,\n            contentOffsetY: y,\n          }));\n        }\n      },\n      [\n        scrollableRef,\n        scrollableContentOffsetY,\n        animatedAnimationState,\n        animatedScrollableStatus,\n        animatedScrollableState,\n      ]\n    );\n  const handleOnMomentumEnd: ScrollEventHandlerCallbackType<ScrollEventContextType> =\n    useCallback(\n      ({ contentOffset: { y } }, context) => {\n        'worklet';\n        if (animatedScrollableStatus.value === SCROLLABLE_STATUS.LOCKED) {\n          const lockPosition = context.shouldLockInitialPosition\n            ? (context.initialContentOffsetY ?? 0)\n            : 0;\n          // @ts-ignore\n          scrollTo(scrollableRef, 0, lockPosition, false);\n          scrollableContentOffsetY.value = 0;\n          return;\n        }\n\n        if (animatedAnimationState.get().status !== ANIMATION_STATUS.RUNNING) {\n          scrollableContentOffsetY.value = y;\n          animatedScrollableState.set(state => ({\n            ...state,\n            contentOffsetY: y,\n          }));\n        }\n      },\n      [\n        scrollableContentOffsetY,\n        scrollableRef,\n        animatedAnimationState,\n        animatedScrollableStatus,\n        animatedScrollableState,\n      ]\n    );\n  //#endregion\n\n  return {\n    handleOnScroll,\n    handleOnBeginDrag,\n    handleOnEndDrag,\n    handleOnMomentumEnd,\n  };\n};\n"
  },
  {
    "path": "src/hooks/useScrollHandler.ts",
    "content": "import {\n  runOnJS,\n  useAnimatedRef,\n  useAnimatedScrollHandler,\n  useSharedValue,\n} from 'react-native-reanimated';\nimport type { Scrollable, ScrollableEvent } from '../types';\nimport { workletNoop as noop } from '../utilities';\nimport { useScrollEventsHandlersDefault } from './useScrollEventsHandlersDefault';\n\nexport const useScrollHandler = (\n  useScrollEventsHandlers = useScrollEventsHandlersDefault,\n  onScroll?: ScrollableEvent,\n  onScrollBeginDrag?: ScrollableEvent,\n  onScrollEndDrag?: ScrollableEvent\n) => {\n  // refs\n  const scrollableRef = useAnimatedRef<Scrollable>();\n\n  // variables\n  const scrollableContentOffsetY = useSharedValue<number>(0);\n\n  // hooks\n  const {\n    handleOnScroll = noop,\n    handleOnBeginDrag = noop,\n    handleOnEndDrag = noop,\n    handleOnMomentumEnd = noop,\n    handleOnMomentumBegin = noop,\n  } = useScrollEventsHandlers(scrollableRef, scrollableContentOffsetY);\n\n  // callbacks\n  const scrollHandler = useAnimatedScrollHandler(\n    {\n      onScroll: (event, context) => {\n        handleOnScroll(event, context);\n\n        if (onScroll) {\n          runOnJS(onScroll)({ nativeEvent: event });\n        }\n      },\n      onBeginDrag: (event, context) => {\n        handleOnBeginDrag(event, context);\n\n        if (onScrollBeginDrag) {\n          runOnJS(onScrollBeginDrag)({ nativeEvent: event });\n        }\n      },\n      onEndDrag: (event, context) => {\n        handleOnEndDrag(event, context);\n\n        if (onScrollEndDrag) {\n          runOnJS(onScrollEndDrag)({ nativeEvent: event });\n        }\n      },\n      onMomentumBegin: handleOnMomentumBegin,\n      onMomentumEnd: handleOnMomentumEnd,\n    },\n    [\n      handleOnScroll,\n      handleOnBeginDrag,\n      handleOnEndDrag,\n      handleOnMomentumBegin,\n      handleOnMomentumEnd,\n      onScroll,\n      onScrollBeginDrag,\n      onScrollEndDrag,\n    ]\n  );\n\n  return { scrollHandler, scrollableRef, scrollableContentOffsetY };\n};\n"
  },
  {
    "path": "src/hooks/useScrollHandler.web.ts",
    "content": "import { type TouchEvent, useEffect, useRef } from 'react';\nimport { useSharedValue } from 'react-native-reanimated';\nimport { ANIMATION_STATUS, SCROLLABLE_STATUS } from '../constants';\nimport type { Scrollable, ScrollableEvent } from '../types';\nimport { findNodeHandle } from '../utilities/findNodeHandle.web';\nimport { useBottomSheetInternal } from './useBottomSheetInternal';\n\nexport type ScrollEventContextType = {\n  initialContentOffsetY: number;\n  shouldLockInitialPosition: boolean;\n};\n\nexport const useScrollHandler = (_: never, onScroll?: ScrollableEvent) => {\n  //#region refs\n  const scrollableRef = useRef<Scrollable>(null);\n  //#endregion\n\n  //#region variables\n  const scrollableContentOffsetY = useSharedValue<number>(0);\n  //#endregion\n\n  //#region hooks\n  const {\n    animatedScrollableState,\n    animatedScrollableStatus,\n    animatedAnimationState,\n  } = useBottomSheetInternal();\n  //#endregion\n\n  //#region effects\n  useEffect(() => {\n    // biome-ignore lint: to be addressed!\n    const element = findNodeHandle(scrollableRef.current) as any;\n    let scrollOffset = 0;\n    let supportsPassive = false;\n    let maybePrevent = false;\n    let lastTouchY = 0;\n\n    let initialContentOffsetY = 0;\n    const shouldLockInitialPosition = false;\n\n    function handleOnTouchStart(event: TouchEvent) {\n      if (event.touches.length !== 1) {\n        return;\n      }\n\n      initialContentOffsetY = element.scrollTop;\n      lastTouchY = event.touches[0].clientY;\n      maybePrevent = scrollOffset <= 0;\n    }\n\n    function handleOnTouchMove(event: TouchEvent) {\n      if (\n        animatedScrollableStatus.value === SCROLLABLE_STATUS.LOCKED &&\n        event.cancelable\n      ) {\n        return event.preventDefault();\n      }\n\n      if (maybePrevent) {\n        maybePrevent = false;\n\n        const touchY = event.touches[0].clientY;\n        const touchYDelta = touchY - lastTouchY;\n\n        if (touchYDelta > 0 && event.cancelable) {\n          return event.preventDefault();\n        }\n      }\n\n      return true;\n    }\n\n    function handleOnTouchEnd() {\n      if (animatedScrollableStatus.value === SCROLLABLE_STATUS.LOCKED) {\n        const lockPosition = shouldLockInitialPosition\n          ? (initialContentOffsetY ?? 0)\n          : 0;\n        element.scroll({\n          top: 0,\n          left: 0,\n          behavior: 'instant',\n        });\n        scrollableContentOffsetY.value = lockPosition;\n        return;\n      }\n    }\n\n    function handleOnScroll(event: TouchEvent) {\n      scrollOffset = element.scrollTop;\n\n      if (animatedAnimationState.get().status !== ANIMATION_STATUS.RUNNING) {\n        const contentOffsetY = Math.max(0, scrollOffset);\n        scrollableContentOffsetY.value = contentOffsetY;\n        animatedScrollableState.set(state => ({\n          ...state,\n          contentOffsetY,\n        }));\n      }\n\n      if (scrollOffset <= 0 && event.cancelable) {\n        event.preventDefault();\n        event.stopPropagation();\n        return false;\n      }\n      return true;\n    }\n\n    try {\n      // @ts-ignore\n      window.addEventListener('test', null, {\n        // @ts-ignore\n        // biome-ignore lint: to be addressed\n        get passive() {\n          supportsPassive = true;\n        },\n      });\n    } catch (_e) {}\n\n    element.addEventListener(\n      'touchstart',\n      handleOnTouchStart,\n      supportsPassive\n        ? {\n            passive: true,\n          }\n        : false\n    );\n\n    element.addEventListener(\n      'touchmove',\n      handleOnTouchMove,\n      supportsPassive\n        ? {\n            passive: false,\n          }\n        : false\n    );\n\n    element.addEventListener(\n      'touchend',\n      handleOnTouchEnd,\n      supportsPassive\n        ? {\n            passive: false,\n          }\n        : false\n    );\n\n    element.addEventListener(\n      'scroll',\n      handleOnScroll,\n      supportsPassive\n        ? {\n            passive: false,\n          }\n        : false\n    );\n\n    return () => {\n      // @ts-ignore\n      window.removeEventListener('test', null);\n      element.removeEventListener('touchstart', handleOnTouchStart);\n      element.removeEventListener('touchmove', handleOnTouchMove);\n      element.removeEventListener('touchend', handleOnTouchEnd);\n      element.removeEventListener('scroll', handleOnScroll);\n    };\n  }, [\n    animatedAnimationState,\n    animatedScrollableState,\n    animatedScrollableStatus,\n    scrollableContentOffsetY,\n  ]);\n  //#endregion\n\n  return {\n    scrollHandler: onScroll,\n    scrollableRef,\n    scrollableContentOffsetY,\n  };\n};\n"
  },
  {
    "path": "src/hooks/useScrollable.ts",
    "content": "import { type RefObject, useCallback, useRef } from 'react';\nimport type { NodeHandle } from 'react-native';\nimport {\n  type SharedValue,\n  useDerivedValue,\n  useSharedValue,\n} from 'react-native-reanimated';\nimport {\n  ANIMATION_STATUS,\n  KEYBOARD_STATUS,\n  SCROLLABLE_STATUS,\n  SCROLLABLE_TYPE,\n  SHEET_STATE,\n} from '../constants';\nimport type {\n  AnimationState,\n  KeyboardState,\n  Scrollable,\n  ScrollableRef,\n  ScrollableState,\n} from '../types';\nimport { findNodeHandle } from '../utilities';\n\nexport const useScrollable = (\n  enableContentPanningGesture: boolean,\n  animatedSheetState: SharedValue<SHEET_STATE>,\n  animatedKeyboardState: SharedValue<KeyboardState>,\n  animatedAnimationState: SharedValue<AnimationState>\n) => {\n  //#region refs\n  const scrollableRef = useRef<ScrollableRef>(null);\n  const previousScrollableRef = useRef<ScrollableRef>(null);\n  //#endregion\n\n  //#region variables\n  const state = useSharedValue<ScrollableState>({\n    type: SCROLLABLE_TYPE.UNDETERMINED,\n    contentOffsetY: 0,\n    refreshable: false,\n  });\n  const status = useDerivedValue<SCROLLABLE_STATUS>(() => {\n    /**\n     * if user had disabled content panning gesture, then we unlock\n     * the scrollable state.\n     */\n    if (!enableContentPanningGesture) {\n      return SCROLLABLE_STATUS.UNLOCKED;\n    }\n\n    /**\n     * if sheet state is fill parent, then unlock scrolling\n     */\n    if (animatedSheetState.value === SHEET_STATE.FILL_PARENT) {\n      return SCROLLABLE_STATUS.UNLOCKED;\n    }\n\n    /**\n     * if sheet state is extended, then unlock scrolling\n     */\n    if (animatedSheetState.value === SHEET_STATE.EXTENDED) {\n      return SCROLLABLE_STATUS.UNLOCKED;\n    }\n\n    /**\n     * if keyboard is shown and sheet is animating\n     * then we do not lock the scrolling to not lose\n     * current scrollable scroll position.\n     */\n    if (\n      animatedKeyboardState.get().status === KEYBOARD_STATUS.SHOWN &&\n      animatedAnimationState.get().status === ANIMATION_STATUS.RUNNING\n    ) {\n      return SCROLLABLE_STATUS.UNLOCKED;\n    }\n\n    return SCROLLABLE_STATUS.LOCKED;\n  }, [\n    enableContentPanningGesture,\n    animatedSheetState,\n    animatedKeyboardState,\n    animatedAnimationState,\n    state,\n  ]);\n  //#endregion\n\n  //#region callbacks\n  const setScrollableRef = useCallback((ref: ScrollableRef) => {\n    // get current node handle id\n    const currentRefId = scrollableRef.current?.id ?? null;\n\n    if (currentRefId !== ref.id) {\n      if (scrollableRef.current) {\n        // @ts-ignore\n        previousScrollableRef.current = scrollableRef.current;\n      }\n      // @ts-ignore\n      scrollableRef.current = ref;\n    }\n  }, []);\n\n  const removeScrollableRef = useCallback((ref: RefObject<Scrollable>) => {\n    // find node handle id\n    let id: NodeHandle | null;\n    try {\n      id = findNodeHandle(ref.current);\n    } catch {\n      return;\n    }\n\n    // get current node handle id\n    const currentRefId = scrollableRef.current?.id ?? null;\n\n    /**\n     * @DEV\n     * when the incoming node is actually the current node, we reset\n     * the current scrollable ref to the previous one.\n     */\n    if (id === currentRefId) {\n      // @ts-ignore\n      scrollableRef.current = previousScrollableRef.current;\n    }\n  }, []);\n  //#endregion\n\n  return {\n    state,\n    status,\n    setScrollableRef,\n    removeScrollableRef,\n  };\n};\n"
  },
  {
    "path": "src/hooks/useScrollableSetter.ts",
    "content": "import type React from 'react';\nimport { useCallback, useEffect } from 'react';\nimport type { SharedValue } from 'react-native-reanimated';\nimport type { SCROLLABLE_TYPE } from '../constants';\nimport type { Scrollable } from '../types';\nimport { findNodeHandle } from '../utilities';\nimport { useBottomSheetInternal } from './useBottomSheetInternal';\n\nexport const useScrollableSetter = (\n  ref: React.RefObject<Scrollable>,\n  type: SCROLLABLE_TYPE,\n  contentOffsetY: SharedValue<number>,\n  refreshable: boolean,\n  useFocusHook = useEffect\n) => {\n  // hooks\n  const { animatedScrollableState, setScrollableRef, removeScrollableRef } =\n    useBottomSheetInternal();\n\n  // callbacks\n  const handleSettingScrollable = useCallback(() => {\n    // set current content offset\n    animatedScrollableState.set(state => ({\n      ...state,\n      contentOffsetY: contentOffsetY.value,\n      type,\n      refreshable,\n    }));\n\n    // set current scrollable ref\n    const id = findNodeHandle(ref.current);\n    if (id) {\n      setScrollableRef({\n        id: id,\n        node: ref,\n      });\n    } else {\n      console.warn(`Couldn't find the scrollable node handle id!`);\n    }\n\n    return () => {\n      removeScrollableRef(ref);\n    };\n  }, [\n    ref,\n    type,\n    refreshable,\n    contentOffsetY,\n    animatedScrollableState,\n    setScrollableRef,\n    removeScrollableRef,\n  ]);\n\n  // effects\n  useFocusHook(handleSettingScrollable);\n};\n"
  },
  {
    "path": "src/hooks/useStableCallback.ts",
    "content": "import { useCallback, useEffect, useLayoutEffect, useRef } from 'react';\n\ntype Callback<T extends unknown[], R> = (...args: T) => R;\n\n/**\n * Provide a stable version of useCallback.\n */\nexport function useStableCallback<T extends unknown[], R>(\n  callback: Callback<T, R>\n) {\n  const callbackRef = useRef<Callback<T, R>>();\n\n  useLayoutEffect(() => {\n    callbackRef.current = callback;\n  });\n\n  useEffect(() => {\n    return () => {\n      callbackRef.current = undefined;\n    };\n  }, []);\n\n  return useCallback<Callback<T, R | undefined>>((...args) => {\n    return callbackRef.current?.(...args);\n  }, []);\n}\n"
  },
  {
    "path": "src/index.ts",
    "content": "// bottom sheet\nexport { default } from './components/bottomSheet';\n\n// bottom sheet modal\nexport { default as BottomSheetModal } from './components/bottomSheetModal';\nexport { default as BottomSheetModalProvider } from './components/bottomSheetModalProvider';\n\n//#region hooks\nexport { useBottomSheet } from './hooks/useBottomSheet';\nexport { useBottomSheetModal } from './hooks/useBottomSheetModal';\nexport { useBottomSheetSpringConfigs } from './hooks/useBottomSheetSpringConfigs';\nexport { useBottomSheetTimingConfigs } from './hooks/useBottomSheetTimingConfigs';\nexport { useBottomSheetInternal } from './hooks/useBottomSheetInternal';\nexport { useBottomSheetModalInternal } from './hooks/useBottomSheetModalInternal';\nexport { useScrollEventsHandlersDefault } from './hooks/useScrollEventsHandlersDefault';\nexport { useGestureEventsHandlersDefault } from './hooks/useGestureEventsHandlersDefault';\nexport { useBottomSheetGestureHandlers } from './hooks/useBottomSheetGestureHandlers';\nexport { useScrollHandler } from './hooks/useScrollHandler';\nexport { useScrollableSetter } from './hooks/useScrollableSetter';\nexport { useBottomSheetScrollableCreator } from './hooks/useBottomSheetScrollableCreator';\n//#endregion\n\n//#region components\nexport {\n  BottomSheetScrollView,\n  BottomSheetSectionList,\n  BottomSheetFlatList,\n  BottomSheetVirtualizedList,\n  BottomSheetFlashList,\n} from './components/bottomSheetScrollable';\nexport { BottomSheetHandle } from './components/bottomSheetHandle';\nexport { default as BottomSheetDraggableView } from './components/bottomSheetDraggableView';\nexport { default as BottomSheetView } from './components/bottomSheetView';\nexport { default as BottomSheetTextInput } from './components/bottomSheetTextInput';\nexport { BottomSheetBackdrop } from './components/bottomSheetBackdrop';\nexport {\n  BottomSheetFooter,\n  BottomSheetFooterContainer,\n} from './components/bottomSheetFooter';\n\n// touchables\nimport BottomSheetTouchable from './components/touchables';\nexport const {\n  TouchableHighlight,\n  TouchableOpacity,\n  TouchableWithoutFeedback,\n} = BottomSheetTouchable;\n// utils\nexport { createBottomSheetScrollableComponent } from './components/bottomSheetScrollable';\n//#endregion\n\n//#region types\nexport type { BottomSheetProps } from './components/bottomSheet';\nexport type { BottomSheetModalProps } from './components/bottomSheetModal';\nexport type { BottomSheetHandleProps } from './components/bottomSheetHandle';\nexport type { BottomSheetBackgroundProps } from './components/bottomSheetBackground';\nexport type { BottomSheetBackdropProps } from './components/bottomSheetBackdrop';\nexport type { BottomSheetFooterProps } from './components/bottomSheetFooter';\n\nexport type {\n  BottomSheetFlatListMethods,\n  BottomSheetScrollViewMethods,\n  BottomSheetSectionListMethods,\n  BottomSheetVirtualizedListMethods,\n  BottomSheetScrollableProps,\n} from './components/bottomSheetScrollable';\n\nexport type {\n  ScrollEventsHandlersHookType,\n  GestureEventsHandlersHookType,\n  ScrollEventHandlerCallbackType,\n  GestureEventHandlerCallbackType,\n} from './types';\n//#endregion\n\n//#region utilities\nexport * from './constants';\nexport { enableLogging } from './utilities/logger';\n//#endregion\n"
  },
  {
    "path": "src/types.d.ts",
    "content": "import type React from 'react';\nimport type {\n  AccessibilityProps,\n  FlatList,\n  Insets,\n  KeyboardEventEasing,\n  NativeScrollEvent,\n  NativeSyntheticEvent,\n  ScrollView,\n  SectionList,\n} from 'react-native';\nimport type {\n  GestureEventPayload,\n  GestureStateChangeEvent,\n  GestureUpdateEvent,\n  PanGestureChangeEventPayload,\n  PanGestureHandlerEventPayload,\n  State,\n} from 'react-native-gesture-handler';\nimport type {\n  EasingFunction,\n  EasingFunctionFactory,\n  ReduceMotion,\n  SharedValue,\n  WithSpringConfig,\n  WithTimingConfig,\n} from 'react-native-reanimated';\nimport type {\n  ANIMATION_SOURCE,\n  ANIMATION_STATUS,\n  GESTURE_SOURCE,\n  KEYBOARD_STATUS,\n  SCROLLABLE_STATUS,\n  SCROLLABLE_TYPE,\n} from './constants';\n\n//#region Methods\nexport interface BottomSheetMethods {\n  /**\n   * Snap to one of the provided points from `snapPoints`.\n   * @param index snap point index.\n   * @param animationConfigs snap animation configs.\n   *\n   * @see {WithSpringConfig}\n   * @see {WithTimingConfig}\n   */\n  snapToIndex: (\n    index: number,\n    animationConfigs?: WithSpringConfig | WithTimingConfig\n  ) => void;\n  /**\n   * Snap to a position out of provided  `snapPoints`.\n   * @param position position in pixel or percentage.\n   * @param animationConfigs snap animation configs.\n   *\n   * @see {WithSpringConfig}\n   * @see {WithTimingConfig}\n   */\n  snapToPosition: (\n    position: number | string,\n    animationConfigs?: WithSpringConfig | WithTimingConfig\n  ) => void;\n  /**\n   * Snap to the maximum provided point from `snapPoints`.\n   * @param animationConfigs snap animation configs.\n   *\n   * @see {WithSpringConfig}\n   * @see {WithTimingConfig}\n   */\n  expand: (animationConfigs?: WithSpringConfig | WithTimingConfig) => void;\n  /**\n   * Snap to the minimum provided point from `snapPoints`.\n   * @param animationConfigs snap animation configs.\n   *\n   * @see {WithSpringConfig}\n   * @see {WithTimingConfig}\n   */\n  collapse: (animationConfigs?: WithSpringConfig | WithTimingConfig) => void;\n  /**\n   * Close the bottom sheet.\n   * @param animationConfigs snap animation configs.\n   *\n   * @see {WithSpringConfig}\n   * @see {WithTimingConfig}\n   */\n  close: (animationConfigs?: WithSpringConfig | WithTimingConfig) => void;\n  /**\n   * Force close the bottom sheet, this prevent any interruptions till the sheet is closed.\n   * @param animationConfigs snap animation configs.\n   *\n   * @see {WithSpringConfig}\n   * @see {WithTimingConfig}\n   */\n  forceClose: (animationConfigs?: WithSpringConfig | WithTimingConfig) => void;\n}\n\n// biome-ignore lint/suspicious/noExplicitAny: Using 'any' allows users to define their own strict types for 'data' property.\nexport interface BottomSheetModalMethods<T = any> extends BottomSheetMethods {\n  /**\n   * Mount and present the bottom sheet modal to the initial snap point.\n   * @param data to be passed to the modal.\n   */\n  present: (data?: T) => void;\n  /**\n   * Close and unmount the bottom sheet modal.\n   * @param animationConfigs snap animation configs.\n   *\n   * @see {WithSpringConfig}\n   * @see {WithTimingConfig}\n   */\n  dismiss: (animationConfigs?: WithSpringConfig | WithTimingConfig) => void;\n}\n//#endregion\n\nexport interface BottomSheetVariables {\n  /**\n   * Current sheet position index.\n   * @type SharedValue<number>\n   */\n  animatedIndex: SharedValue<number>;\n  /**\n   * Current sheet position.\n   * @type SharedValue<number>\n   */\n  animatedPosition: SharedValue<number>;\n}\n\n//#region scrollable\nexport type ScrollableState = {\n  type: SCROLLABLE_TYPE;\n  contentOffsetY: number;\n  refreshable: boolean;\n};\nexport type Scrollable = FlatList | ScrollView | SectionList;\nexport type ScrollableRef = {\n  id: number;\n  node: React.RefObject<Scrollable>;\n};\nexport type ScrollableEvent = (\n  event: Pick<NativeSyntheticEvent<NativeScrollEvent>, 'nativeEvent'>\n) => void;\n//#endregion\n\n//#region utils\nexport interface TimingConfig {\n  duration?: number;\n  reduceMotion?: ReduceMotion;\n  easing?: EasingFunction | EasingFunctionFactory;\n}\n\nexport type SpringConfig = {\n  stiffness?: number;\n  overshootClamping?: boolean;\n  restDisplacementThreshold?: number;\n  restSpeedThreshold?: number;\n  velocity?: number;\n  reduceMotion?: ReduceMotion;\n} & (\n  | {\n      mass?: number;\n      damping?: number;\n      duration?: never;\n      dampingRatio?: never;\n      clamp?: never;\n    }\n  | {\n      mass?: never;\n      damping?: never;\n      duration?: number;\n      dampingRatio?: number;\n      clamp?: { min?: number; max?: number };\n    }\n);\n\nexport type Primitive = string | number | boolean;\n//#endregion\n\n//#region hooks\nexport type GestureEventPayloadType = GestureEventPayload &\n  PanGestureHandlerEventPayload;\n\nexport type GestureEventContextType = {\n  didStart?: boolean;\n};\n\nexport type GestureEventHandlerCallbackType = (\n  source: GESTURE_SOURCE,\n  payload: GestureEventPayloadType\n) => void;\n\nexport type GestureEventsHandlersHookType = () => {\n  handleOnStart: GestureEventHandlerCallbackType;\n  handleOnChange: GestureEventHandlerCallbackType;\n  handleOnEnd: GestureEventHandlerCallbackType;\n  handleOnFinalize: GestureEventHandlerCallbackType;\n};\n\nexport type GestureHandlersHookType = (\n  source: GESTURE_SOURCE,\n  state: SharedValue<State>,\n  gestureSource: SharedValue<GESTURE_SOURCE>,\n  onStart: GestureEventHandlerCallbackType,\n  onChange: GestureEventHandlerCallbackType,\n  onEnd: GestureEventHandlerCallbackType,\n  onFinalize: GestureEventHandlerCallbackType\n) => {\n  handleOnStart: (\n    event: GestureStateChangeEvent<PanGestureHandlerEventPayload>\n  ) => void;\n  handleOnChange: (\n    event: GestureUpdateEvent<\n      PanGestureHandlerEventPayload & PanGestureChangeEventPayload\n    >\n  ) => void;\n  handleOnEnd: (\n    event: GestureStateChangeEvent<PanGestureHandlerEventPayload>\n  ) => void;\n  handleOnFinalize: (\n    event: GestureStateChangeEvent<PanGestureHandlerEventPayload>\n  ) => void;\n};\n\ntype ScrollEventHandlerCallbackType<C = never> = (\n  payload: NativeScrollEvent,\n  context: C\n) => void;\n\nexport type ScrollEventsHandlersHookType = (\n  ref: React.RefObject<Scrollable>,\n  contentOffsetY: SharedValue<number>\n) => {\n  handleOnScroll?: ScrollEventHandlerCallbackType;\n  handleOnBeginDrag?: ScrollEventHandlerCallbackType;\n  handleOnEndDrag?: ScrollEventHandlerCallbackType;\n  handleOnMomentumBegin?: ScrollEventHandlerCallbackType;\n  handleOnMomentumEnd?: ScrollEventHandlerCallbackType;\n};\n//#endregion\n\n//#region accessibility\nexport interface NullableAccessibilityProps extends AccessibilityProps {\n  accessible?: AccessibilityProps['accessible'] | null;\n  accessibilityLabel?: AccessibilityProps['accessibilityLabel'] | null;\n  accessibilityHint?: AccessibilityProps['accessibilityHint'] | null;\n  accessibilityRole?: AccessibilityProps['accessibilityRole'] | null;\n}\n//#endregion\n\n//#region states\nexport type KeyboardState = {\n  target?: number;\n  status: KEYBOARD_STATUS;\n  height: number;\n  heightWithinContainer: number;\n  easing: KeyboardEventEasing;\n  duration: number;\n};\n\n/**\n * Represents the state of an animation, including its current status and the source that triggered it.\n */\nexport type AnimationState = {\n  /**\n   * The current status of the animation, this can be one of the values defined in the `ANIMATION_STATUS` enum, such as 'idle', 'running', 'completed', etc.\n   */\n  status: ANIMATION_STATUS;\n  /**\n   * The source of the animation which indicates where the animation was initiated from, such as user interaction, system event, or programmatic trigger.\n   * It is represented by the `ANIMATION_SOURCE` enum, which includes values like 'user', 'system', etc.\n   */\n  source: ANIMATION_SOURCE;\n  /**\n   * The index of the next snap point that the animation is targeting.\n   */\n  nextIndex?: number;\n  /**\n   * The next position in pixels that the animation is targeting.\n   */\n  nextPosition?: number;\n  /**\n   * Indicates whether the animation is forced closing to prevent any interruptions.\n   */\n  isForcedClosing?: boolean;\n};\n\n/**\n * Represents the layout state of the bottom sheet container.\n */\nexport type ContainerLayoutState = {\n  /**\n   * The height of the container in pixels.\n   */\n  height: number;\n  /**\n   * The required insets applied to the container, such as padding or safe area.\n   */\n  offset: Required<Insets>;\n};\n\n/**\n * Represents the layout state of the bottom sheet components.\n */\nexport type LayoutState = {\n  /**\n   * The original height of the container before any adjustments.\n   */\n  rawContainerHeight: number;\n  /**\n   * The adjusted height of the container after applying insets or other modifications.\n   */\n  containerHeight: number;\n  /**\n   * The required insets applied to the container, such as padding or safe area.\n   */\n  containerOffset: Required<Insets>;\n  /**\n   * The height of the handle element used to drag the bottom sheet.\n   */\n  handleHeight: number;\n  /**\n   * The height of the footer section within the bottom sheet.\n   */\n  footerHeight: number;\n  /**\n   * The total height of the content inside the bottom sheet.\n   */\n  contentHeight: number;\n};\n\nexport type DetentsState = {\n  detents?: number[];\n  dynamicDetentIndex?: number;\n  highestDetentPosition?: number;\n  closedDetentPosition?: number;\n};\n//#endregion\n"
  },
  {
    "path": "src/utilities/animate.ts",
    "content": "import {\n  type AnimationCallback,\n  type ReduceMotion,\n  type WithSpringConfig,\n  type WithTimingConfig,\n  withSpring,\n  withTiming,\n} from 'react-native-reanimated';\nimport { ANIMATION_CONFIGS, ANIMATION_METHOD } from '../constants';\n\ninterface AnimateParams {\n  point: number;\n  velocity?: number;\n  configs?: WithSpringConfig | WithTimingConfig;\n  overrideReduceMotion?: ReduceMotion;\n  onComplete?: AnimationCallback;\n}\n\nexport const animate = ({\n  point,\n  configs,\n  velocity = 0,\n  overrideReduceMotion,\n  onComplete,\n}: AnimateParams) => {\n  'worklet';\n\n  if (!configs) {\n    configs = ANIMATION_CONFIGS;\n  }\n\n  // Users might have an accessibility setting to reduce motion turned on.\n  // This prevents the animation from running when presenting the sheet, which results in\n  // the bottom sheet not even appearing so we need to override it to ensure the animation runs.\n  // configs.reduceMotion = ReduceMotion.Never;\n\n  if (overrideReduceMotion) {\n    configs.reduceMotion = overrideReduceMotion;\n  }\n\n  // detect animation type\n  const type =\n    'duration' in configs || 'easing' in configs\n      ? ANIMATION_METHOD.TIMING\n      : ANIMATION_METHOD.SPRING;\n\n  if (type === ANIMATION_METHOD.TIMING) {\n    return withTiming(point, configs as WithTimingConfig, onComplete);\n  }\n\n  return withSpring(\n    point,\n    Object.assign({ velocity }, configs) as WithSpringConfig,\n    onComplete\n  );\n};\n"
  },
  {
    "path": "src/utilities/clamp.ts",
    "content": "export const clamp = (\n  value: number,\n  lowerBound: number,\n  upperBound: number\n) => {\n  'worklet';\n  return Math.min(Math.max(lowerBound, value), upperBound);\n};\n"
  },
  {
    "path": "src/utilities/easingExp.ts",
    "content": "/**\n * A modified version of the default AnimatedEasing.exp,\n * to insure its value never goes below `0`.\n * @see https://github.com/software-mansion/react-native-reanimated/issues/1610\n * @param t number\n */\nexport const exp = (t: number) => {\n  'worklet';\n  return Math.min(Math.max(0, Math.pow(2, 10 * (t - 1))), 1);\n};\n"
  },
  {
    "path": "src/utilities/findNodeHandle.ts",
    "content": "export { findNodeHandle } from 'react-native';\n"
  },
  {
    "path": "src/utilities/findNodeHandle.web.ts",
    "content": "import {\n  type NodeHandle,\n  findNodeHandle as _findNodeHandle,\n} from 'react-native';\n\nexport function findNodeHandle(\n  componentOrHandle: Parameters<typeof _findNodeHandle>['0']\n) {\n  let nodeHandle: NodeHandle | null;\n  try {\n    nodeHandle = _findNodeHandle(componentOrHandle);\n    if (nodeHandle) {\n      return nodeHandle;\n    }\n  } catch {}\n\n  try {\n    // @ts-ignore\n    nodeHandle = componentOrHandle.getNativeScrollRef();\n    if (nodeHandle) {\n      return nodeHandle;\n    }\n  } catch {}\n\n  // @ts-ignore https://github.com/facebook/react-native/blob/a314e34d6ee875830d36e4df1789a897c7262056/packages/virtualized-lists/Lists/VirtualizedList.js#L1252\n  nodeHandle = componentOrHandle._scrollRef;\n  if (nodeHandle) {\n    return nodeHandle;\n  }\n\n  console.warn('could not find scrollable ref!');\n  return componentOrHandle;\n}\n"
  },
  {
    "path": "src/utilities/getKeyboardAnimationConfigs.ts",
    "content": "import type { KeyboardEventEasing } from 'react-native';\nimport { Easing } from 'react-native-reanimated';\n\nexport const getKeyboardAnimationConfigs = (\n  easing: KeyboardEventEasing,\n  duration: number\n) => {\n  'worklet';\n  switch (easing) {\n    case 'easeIn':\n      return {\n        easing: Easing.in(Easing.ease),\n        duration,\n      };\n\n    case 'easeOut':\n      return {\n        easing: Easing.out(Easing.ease),\n        duration,\n      };\n\n    case 'easeInEaseOut':\n      return {\n        easing: Easing.inOut(Easing.ease),\n        duration,\n      };\n\n    case 'linear':\n      return {\n        easing: Easing.linear,\n        duration,\n      };\n\n    case 'keyboard':\n      return {\n        damping: 500,\n        stiffness: 1000,\n        mass: 3,\n        overshootClamping: true,\n        restDisplacementThreshold: 10,\n        restSpeedThreshold: 10,\n      };\n  }\n};\n"
  },
  {
    "path": "src/utilities/getRefNativeTag.web.ts",
    "content": "import type { RefObject } from 'react';\nimport { findNodeHandle } from 'react-native';\n\nexport function getRefNativeTag(ref: RefObject<never>) {\n  return findNodeHandle(ref?.current) || null;\n}\n"
  },
  {
    "path": "src/utilities/id.ts",
    "content": "let current = 0;\n\nexport const id = () => {\n  current = (current + 1) % Number.MAX_SAFE_INTEGER;\n  return current;\n};\n"
  },
  {
    "path": "src/utilities/index.ts",
    "content": "export { normalizeSnapPoint } from './normalizeSnapPoint';\nexport { animate } from './animate';\nexport { getKeyboardAnimationConfigs } from './getKeyboardAnimationConfigs';\nexport { print } from './logger';\nexport { noop, workletNoop } from './noop';\nexport { isFabricInstalled } from './isFabricInstalled';\nexport { findNodeHandle } from './findNodeHandle';\n"
  },
  {
    "path": "src/utilities/isFabricInstalled.ts",
    "content": "/**\n * Checks if the Fabric renderer is installed in the current environment.\n *\n * @returns {boolean} `true` if Fabric is installed, otherwise `false`.\n */\nexport function isFabricInstalled() {\n  // @ts-ignore\n  return global?.nativeFabricUIManager != null;\n}\n"
  },
  {
    "path": "src/utilities/logger.ts",
    "content": "interface PrintOptions {\n  component?: string;\n  category?: 'layout' | 'effect' | 'callback';\n  method?: string;\n  params?: Record<string, unknown> | string | number | boolean;\n}\n\ntype Print = (options: PrintOptions) => void;\n\nlet _isLoggingEnabled = false;\nlet _excludeCategories: PrintOptions['category'][] | undefined;\n\nconst enableLogging = (excludeCategories?: PrintOptions['category'][]) => {\n  if (!__DEV__) {\n    console.warn('[BottomSheet] could not enable logging on production!');\n    return;\n  }\n\n  _isLoggingEnabled = true;\n  _excludeCategories = excludeCategories;\n};\n\nlet print: Print = () => {};\n\nif (__DEV__) {\n  print = ({ component, method, params, category }) => {\n    if (!_isLoggingEnabled) {\n      return;\n    }\n\n    if (\n      category &&\n      _excludeCategories &&\n      _excludeCategories.includes(category)\n    ) {\n      return;\n    }\n\n    let message = '';\n\n    if (typeof params === 'object') {\n      message = Object.keys(params)\n        .map(key => `${key}:${params[key]}`)\n        .join(' ');\n    } else {\n      message = `${params ?? ''}`;\n    }\n    // biome-ignore lint/suspicious/noConsole: used for debugging\n    console.log(`[${[component, method].filter(Boolean).join('::')}]`, message);\n  };\n}\n\nObject.freeze(print);\n\nexport { print, enableLogging };\n"
  },
  {
    "path": "src/utilities/noop.ts",
    "content": "const workletNoop = () => {\n  'worklet';\n};\n\nconst noop = () => {};\n\nexport { noop, workletNoop };\n"
  },
  {
    "path": "src/utilities/normalizeSnapPoint.ts",
    "content": "/**\n * Converts a snap point to fixed numbers.\n */\nexport const normalizeSnapPoint = (\n  snapPoint: number | string,\n  containerHeight: number\n) => {\n  'worklet';\n  let normalizedSnapPoint = snapPoint;\n\n  // percentage snap point\n  if (typeof normalizedSnapPoint === 'string') {\n    normalizedSnapPoint =\n      (Number(normalizedSnapPoint.split('%')[0]) * containerHeight) / 100;\n  }\n  return Math.max(0, containerHeight - normalizedSnapPoint);\n};\n"
  },
  {
    "path": "src/utilities/snapPoint.ts",
    "content": "export const snapPoint = (\n  value: number,\n  velocity: number,\n  points: ReadonlyArray<number>\n): number => {\n  'worklet';\n  const point = value + 0.2 * velocity;\n  const deltas = points.map(p => Math.abs(point - p));\n  const minDelta = Math.min.apply(null, deltas);\n  return points.filter(p => Math.abs(point - p) === minDelta)[0];\n};\n"
  },
  {
    "path": "src/utilities/validateSnapPoint.ts",
    "content": "import invariant from 'invariant';\n\nexport const validateSnapPoint = (snapPoint: number | string) => {\n  invariant(\n    typeof snapPoint === 'number' || typeof snapPoint === 'string',\n    `'${snapPoint}' is not a valid snap point! expected types are string or number.`\n  );\n\n  invariant(\n    typeof snapPoint === 'number' ||\n      (typeof snapPoint === 'string' && snapPoint.includes('%')),\n    `'${snapPoint}' is not a valid percentage snap point! expected percentage snap point must include '%'. e.g. '50%'`\n  );\n\n  invariant(\n    typeof snapPoint === 'number' ||\n      (typeof snapPoint === 'string' && Number(snapPoint.split('%')[0])),\n    `'${snapPoint}' is not a valid percentage snap point! expected percentage snap point must be only numbers and '%'. e.g. '50%'`\n  );\n};\n"
  },
  {
    "path": "tsconfig.json",
    "content": "{\n  \"compilerOptions\": {\n    \"baseUrl\": \".\",\n    \"paths\": {\n      \"@gorhom/bottom-sheet\": [\"./src/index\"]\n    },\n    \"allowUnreachableCode\": false,\n    \"allowUnusedLabels\": false,\n    \"esModuleInterop\": true,\n    \"forceConsistentCasingInFileNames\": true,\n    \"jsx\": \"react\",\n    \"lib\": [\"esnext\"],\n    \"module\": \"esnext\",\n    \"moduleResolution\": \"node\",\n    \"noFallthroughCasesInSwitch\": true,\n    \"noImplicitReturns\": true,\n    \"noImplicitUseStrict\": false,\n    \"noStrictGenericChecks\": false,\n    \"noUnusedLocals\": true,\n    \"noUnusedParameters\": true,\n    \"resolveJsonModule\": true,\n    \"skipLibCheck\": true,\n    \"strict\": true,\n    \"target\": \"esnext\"\n  },\n  \"exclude\": [\"example\"],\n  \"include\": [\"src\"]\n}\n"
  },
  {
    "path": "website/.gitignore",
    "content": "# Dependencies\n/node_modules\n\n# Production\n/build\n\n# Generated files\n.docusaurus\n.cache-loader\n\n# Misc\n.DS_Store\n.env.local\n.env.development.local\n.env.test.local\n.env.production.local\n\nnpm-debug.log*\nyarn-debug.log*\nyarn-error.log*\n"
  },
  {
    "path": "website/README.md",
    "content": "# Website\n\nThis website is built using [Docusaurus](https://docusaurus.io/), a modern static website generator.\n\n### Installation\n\n```\n$ yarn\n```\n\n### Local Development\n\n```\n$ yarn start\n```\n\nThis command starts a local development server and opens up a browser window. Most changes are reflected live without having to restart the server.\n\n### Build\n\n```\n$ yarn build\n```\n\nThis command generates static content into the `build` directory and can be served using any static contents hosting service.\n\n### Deployment\n\nUsing SSH:\n\n```\n$ USE_SSH=true yarn deploy\n```\n\nNot using SSH:\n\n```\n$ GIT_USER=<Your GitHub username> yarn deploy\n```\n\nIf you are using GitHub pages for hosting, this command is a convenient way to build the website and push to the `gh-pages` branch.\n"
  },
  {
    "path": "website/babel.config.js",
    "content": "module.exports = {\n  presets: [require.resolve('@docusaurus/core/lib/babel/preset')],\n};\n"
  },
  {
    "path": "website/blog/2021-08-30-bottom-sheet-v4.mdx",
    "content": "---\ntitle: BottomSheet v4 is here!\ndescription: BottomSheet v4 comes with rewritten implementation to provide more stability, performance, and more features.\nslug: bottom-sheet-v4\nauthors:\n  - gorhom\nkeywords:\n  - bottomsheet\n  - bottom-sheet\n  - bottom sheet\n  - react-native\n  - react native\n  - ios\n  - android\n  - sheet\n  - modal\n  - presentation modal\n  - reanimated\ntags: [release]\nimage: /img/bottom-sheet-preview.gif\nhide_table_of_contents: false\n---\n\nimport useBaseUrl from \"@docusaurus/useBaseUrl\";\nimport Video from \"@theme/Video\";\n\nToday I am releasing the `BottomSheet v4`, with a rewritten implementation to provide more stability, performance, and more features.\n\n{/* truncate */}\n\n## Features\n\nIn this release, I have rewritten the implementation to 100% utilize `Reanimated v2` hooks and variables instead of using the JS once. This allows for more customization and provides more stability overall.\n\n### Keyboard Handling\n\n<Video\n  title=\"React Native Bottom Sheet Keyboard Handling\"\n  url={useBaseUrl(\"video/bottom-sheet-keyboard-handling-preview.mp4\")}\n/>\n\nKeyboard handling was released with `v3`, however, there were some issues that pushed this release. Now the keyboard handling is enabled by default and provides more options to customize the behavior, a new prop `android_keyboardInputMode` is introduced to handle the `Android` keyboard appearance config `windowSoftInputMode`.\n\nRead more about [Keyboard Handling](/keyboard-handling).\n\n### Pull to Refresh\n\n<Video\n  title=\"React Native Bottom Sheet Pull to Refresh\"\n  url={useBaseUrl(\"video/bottom-sheet-pull-to-refresh-preview.mp4\")}\n/>\n\nOne of the earliest feature request that was submitted to repo [Pull to refresh](https://github.com/gorhom/react-native-bottom-sheet/issues/66) by [gudberg](https://github.com/gudberg). There was an attempt to implement it on `v3` & `v2` but I was hit with their limitations, until now.\n\nThis feature is enabled by default, users need to provide `refreshing` & `onRefresh` to any of the [Scrollables](/scrollables) and voila!\n\nRead more about [Pull to Refresh](/pull-to-refresh).\n\n### Detach Sheet / Modal\n\n<Video\n  title=\"React Native Bottom Sheet Detach Modal\"\n  url={useBaseUrl(\"video/bottom-sheet-detach-preview.mp4\")}\n/>\n\nAnother powerful addition to `BottomSheet` & `BottomSheetModal` is the ability to detach the sheet from the bottom - so no more bottom sheet 😅 -, which allows users to come up with lots of creative choices and customization to the sheet position.\n\nRead more about [Detach Sheet / Modal](/detach-modal).\n\n### Footer Component\n\n<Video\n  title=\"React Native Bottom Sheet Custom Footer\"\n  url={useBaseUrl(\"video/bottom-sheet-footer-preview.mp4\")}\n/>\n\nLastly, I have added a new prop `footerComponent` to `BottomSheet` & `BottomSheetModal` to allow users to stick their custom component to the bottom of the sheet even when the keyboard is shown.\n\nRead more about [Footer Component](/custom-footer).\n\n## Breaking changes\n\n#### Removed\n\n- Removed `animationEasing` from `BottomSheet` props.\n- Removed `animationDuration` from `BottomSheet` props.\n- Removed `closeOnPress` from `BottomSheetBackdrop` props.\n- Removed `dismissOnClose` from `BottomSheetModal` props.\n- Removed `enableFlashScrollableIndicatorOnExpand` from `BottomSheet` props.\n\n#### Changes\n\n- `snapPoints` prop is no longer accepting `0` as a value.\n- `animateOnMount` props default value is `true`\n\n## Changelog\n\nHere are the highlight change log of `v4`\n\n#### Refactored\n\n- create one generic scrollable component ([`#442`](https://github.com/gorhom/react-native-bottom-sheet/pull/442)).\n- converted all internal state/memoized variables to reanimated shared values. ([`#430`](https://github.com/gorhom/react-native-bottom-sheet/pull/430)).\n- updated handling animated heights ([`#451`](https://github.com/gorhom/react-native-bottom-sheet/pull/451)).\n\n#### Added\n\n- added pull to refresh implementation ([016a01f](https://github.com/gorhom/react-native-bottom-sheet/commit/016a01f3705c83c9903a3e28c875e7b90424a128)).\n- added enable pan down to close ([`#437`](https://github.com/gorhom/react-native-bottom-sheet/pull/437)).\n- added snap to position ([`#443`](https://github.com/gorhom/react-native-bottom-sheet/pull/443)).\n- added footer component ([`#457`](https://github.com/gorhom/react-native-bottom-sheet/pull/457)).\n- added pre-integrated VirtualizedList component ([2d4d69d](https://github.com/gorhom/react-native-bottom-sheet/commit/2d4d69d8881a3cbe452f5e46157e2b9702528206)).\n- added keyboard input mode for android ([069c4b6](https://github.com/gorhom/react-native-bottom-sheet/commit/069c4b6742630dc5fa7d4763a5c4dc6bfec439cc)).\n- added detached bottom sheet ([`#487`](https://github.com/gorhom/react-native-bottom-sheet/pull/487)).\n- added onClose callback to BottomSheet ([ee64545](https://github.com/gorhom/react-native-bottom-sheet/commit/ee64545ce0e7609fb383f1473773c8481a0bc7aa)).\n- added backgroundStyle, handleStyle & handleIndicatorStyle to bottom sheet ([2211765](https://github.com/gorhom/react-native-bottom-sheet/commit/221176546fd59ed0c9d79fe7f0350eda24dd8550)).\n- added forceClose to BottomSheet methods ([3dd5796](https://github.com/gorhom/react-native-bottom-sheet/commit/3dd5796eb722e4e579de7b2439d224a5e0238b55)).\n\n#### Fixed\n\n- fixed sheet positioning on modals ([ee573e9](https://github.com/gorhom/react-native-bottom-sheet/commit/ee573e9463836301d9736c3e5d86b2b363f9fb14)).\n- fixed prevent animatedPosition from becoming undefined ([400d7b9](https://github.com/gorhom/react-native-bottom-sheet/commit/400d7b93caa0a46f678db2978e7e5f95cc87ee99)).\n- fixed on mount flicker on fixed sheet ([48c4988](https://github.com/gorhom/react-native-bottom-sheet/commit/48c49888b95dc88abf320d4d7590f43806e0bd59)).\n- fixed updated keyboard height in container calculation ([2599f6c](https://github.com/gorhom/react-native-bottom-sheet/commit/2599f6cf46af0f95812e34670de5a7cae5d44fd9)).\n- fixed re-snap to current position when snap points get updated ([bb8e202](https://github.com/gorhom/react-native-bottom-sheet/commit/bb8e202af05dc6beeb108cfa1680401374ac58ad)).\n- fixed handle initial closed sheet ([4bc40d9](https://github.com/gorhom/react-native-bottom-sheet/commit/4bc40d93da05dcff664ce939a9944416b9e91359)).\n\nRead the full [change log](https://github.com/gorhom/react-native-bottom-sheet/blob/master/CHANGELOG.md).\n\n## Special thanks\n\nThanks to all users for testing and reporting issues. Without your help, this library wouldn't progress this much ❤️\n\nSpecial thanks to [@kickbk](https://github.com/kickbk), [@vonovak](https://github.com/vonovak), [@likern](https://github.com/likern), [@nandorojo](https://github.com/nandorojo), [@axeldelafosse](https://github.com/axeldelafosse) & [@skdev24](https://github.com/skdev24) for testing & contributing to this release.\n\nFinally, thanks to [Software Mansion](http://swmansion.com/) for powering this library with `Reanimated` & `Gesture Handler`.\n"
  },
  {
    "path": "website/blog/2024-10-05-bottom-sheet-v5.mdx",
    "content": "---\ntitle: BottomSheet v5 is finally out!\ndescription: BottomSheet v5 a fully rewritten implementation to provide more stability, performance, and more features.\nauthors:\n  - gorhom\nslug: bottom-sheet-v5\nkeywords:\n  - bottomsheet\n  - bottom-sheet\n  - bottom sheet\n  - react-native\n  - react native\n  - ios\n  - android\n  - sheet\n  - modal\n  - presentation modal\n  - reanimated\ntags: [release]\ndate: 2024-10-05\nimage: /img/bottom-sheet-preview.gif\nhide_table_of_contents: false\n---\n\nimport useBaseUrl from \"@docusaurus/useBaseUrl\";\nimport Video from \"@theme/Video\";\n\nI am happy to announce the long-awaited release of the **React Native Bottom Sheet v5**. In this release I have completely rewritten the entire gesture solution with the new **[React Native Gesture Handler v2](https://blog.swmansion.com/introducing-gesture-handler-2-0-50515f1c4afc)**, and I have added support for **React Native Web** to provide a performant simplified API across all React Native supported platforms.\n\n{/* truncate */}\n\nThis release has been delayed for a while now due to an increase in responsibilities and commitments in my daily job, moving forward I will try to find someone to help maintaining the project.\n\n## Features\n\n### Web Support\n\nSupporting Web has been on my list since day 0 ([issue #11](https://github.com/gorhom/react-native-bottom-sheet/issues/11)), but unfortunately was not a priority until the community start adopting solutions such as [Expo Web](https://docs.expo.dev/workflow/web/), which also provided an easier development setup for me to kick off the development.\n\nWith this release, users will be able to use the library in web mobile without changing the API 🪄.\n\n<Video\n  title=\"React Native Bottom Sheet Web Support\"\n  url={useBaseUrl(\"video/bottom-sheet-web-support-preview.mp4\")}\n/>\n\n\n:::info\n\n🚧 Keyboard handling support for web will be followed shortly, PRs are always welcome.\n\n:::\n\nThis feature is enabled by default, Read more about [Web Support](/web-support).\n\n### Dynamic Sizing\n\nRe-introduced the dynamic sizing with **0 configuration** from the user, where the library internally managed to calculate static views and list content size height and set it as the bottom sheet content height.\n\n<Video\n  title=\"React Native Bottom Sheet Dynamic Sizing\"\n  url={useBaseUrl(\"video/bottom-sheet-dynamic-sizing-preview.mp4\")}\n/>\n\nThis feature is enabled by default, Read more about [Dynamic Sizing](/dynamic-sizing).\n\n### FlashList Integration\n\nPreviously, I have published the [FlashList](https://shopify.github.io/flash-list/) by [Shopify](https://shopify.engineering/) integration for my sponsors only. However, with this release I decided to publish it for everyone ❤️. Users could easily use the pre-integrated component by importing **`BottomSheetFlashList`** from the library.\n\n```tsx\nimport { BottomSheetFlashList } from '@gorhom/bottom-sheet'\n```\n\n<Video\n  title=\"React Native Bottom Sheet FlashList\"\n  url={useBaseUrl(\"video/bottom-sheet-flashlist-preview.mp4\")}\n/>\n\nThis feature is enabled by default, Read more about [FlashList](/components/bottomsheetflashlist) integration.\n\n## Improvements\n\n### Refactored Snapping Mechanism\n\nThe bottom sheet has multiple events that trigger its snapping to positions, whether a change in a snap point value, container height or the keyboard appearance. Since the introduction of keyboard handling in `v4` there has been multiple issues reported regarding the bottom sheet snapping to a wrong position or sometimes not even reacting to resizing events. With this release, I have refactored the whole snapping mechanism from the scratch and built it working backward from the edge cases such as: content resizing, container resizing and keyboard appearance.\n\n## Migration\n\nAs the introduction of the [Dynamic Sizing](/dynamic-sizing), many might find their bottom sheets heights changes as it is enabled by default. To avoid such issues while migrating to **v5**, I recommend disabling it by setting the prop `enableDynamicSizing` to `false`, then try to figure out whether to use it or limit the dynamic content height by setting the prop `maxDynamicContentSize`.\n\n## Breaking Changes\n\n- Updated Gesture Handler to **v2**\n- Updated Reanimated to **v3**\n- Updated `enableDynamicSizing` default value to **`true`**\n- Updated `stackBehavior` default value to `switch`\n\nread all other changes in [changelog](https://github.com/gorhom/react-native-bottom-sheet/blob/master/CHANGELOG.md).\n\n## Special thanks\n\nThanks to all users for testing and reporting issues. Without your help, this library wouldn't progress this much ❤️\n\nSpecial thanks to [@Mahmoud-SK](https://github.com/Mahmoud-SK), [@Eli-Nathan](https://github.com/Eli-Nathan), [@ororsatti](https://github.com/ororsatti), [@janodetzel](https://github.com/janodetzel), [@cenksari](https://github.com/cenksari), [@AndreiCalazans](https://github.com/AndreiCalazans), [@MoritzCooks](https://github.com/MoritzCooks), [@fobos531](https://github.com/fobos531), [@ghorbani-m](https://github.com/ghorbani-m), [@jaworek](https://github.com/jaworek), [@joshsmith](https://github.com/joshsmith), [@david-gomes5](https://github.com/david-gomes5), [@christophby](https://github.com/christophby), [@koplyarov](https://github.com/koplyarov), [@beqramo](https://github.com/beqramo), [@magrinj](https://github.com/magrinj), [@gkueny](https://github.com/gkueny), [@eps1lon](https://github.com/eps1lon), [@janicduplessis](https://github.com/janicduplessis) and others for testing & contributing to this release.\n\nFinally, thanks to [Software Mansion](http://swmansion.com/) for powering this library with `Reanimated` & `Gesture Handler`.\n"
  },
  {
    "path": "website/blog/authors.yml",
    "content": "gorhom:\n    name: Mo Gorhom\n    title: Author\n    url: https://gorhom.dev/\n    image_url: https://github.com/gorhom.png\n    socials:\n      x: gorhom\n      github: gorhom\n      linkedin: gorhom\n      website: https://gorhom.dev/"
  },
  {
    "path": "website/blog/tags.yml",
    "content": "release:\n  description: \"Blog posts about Bottom Sheet' new releases\""
  },
  {
    "path": "website/docs/components/bottomsheetbackdrop.md",
    "content": "---\nid: bottomsheetbackdrop\ntitle: BottomSheetBackdrop\nsidebar_label: Backdrop\ndescription: a pre-built BottomSheet backdrop implementation with configurable props.\nimage: /img/bottom-sheet-preview.gif\nslug: /components/bottomsheetbackdrop\n---\n\nA pre-built BottomSheet backdrop implementation with configurable props.\n\n## Props\n\nInherits `ViewProps` from `react-native`.\n\n### animatedIndex\n\nCurrent sheet position index.\n\n| type                          | default | required |\n| ----------------------------- | ------- | -------- |\n| Animated.SharedValue\\<number> | 0       | YES      |\n\n### animatedPosition\n\nCurrent sheet position.\n\n| type                          | default | required |\n| ----------------------------- | ------- | -------- |\n| Animated.SharedValue<number/> | 0       | YES      |\n\n### opacity\n\nBackdrop opacity.\n\n| type   | default | required |\n| ------ | ------- | -------- |\n| number | 0.5     | NO       |\n\n### appearsOnIndex\n\nSnap point index when backdrop will appears on.\n\n| type   | default | required |\n| ------ | ------- | -------- |\n| number | 1       | NO       |\n\n### disappearsOnIndex\n\nSnap point index when backdrop will disappears on.\n\n| type   | default | required |\n| ------ | ------- | -------- |\n| number | 0       | NO       |\n\n### enableTouchThrough\n\nEnable touch through backdrop component.\n\n| type    | default | required |\n| ------- | ------- | -------- |\n| boolean | false   | NO       |\n\n### pressBehavior\n\nWhat should happen when user press backdrop?\n\n- `none`: do nothing, and `onPress` prop will be ignored.\n- `close`: close the sheet.\n- `collapse`: collapse the sheet.\n- `N`: snap point index.\n\n| type                              | default | required |\n| --------------------------------- | ------- | -------- |\n| `BackdropPressBehavior` \\| number | 'close' | NO       |\n\n### onPress\n\nPressing the backdrop will call the `onPress` function, it will be called before the action defined by `pressBehavior` is executed\n\n| type     | default   | required |\n| -------- | --------- | -------- |\n| function | undefined | NO       |\n\n## Example\n\n```tsx\nimport React, { useCallback, useMemo, useRef } from \"react\";\nimport { View, Text, StyleSheet } from \"react-native\";\nimport { GestureHandlerRootView } from 'react-native-gesture-handler';\nimport BottomSheet, { BottomSheetView, BottomSheetBackdrop } from \"@gorhom/bottom-sheet\";\n\nconst App = () => {\n\t// ref\n\tconst bottomSheetRef = useRef<BottomSheet>(null);\n\n\t// variables\n\tconst snapPoints = useMemo(() => [\"25%\", \"50%\", \"75%\"], []);\n\n\t// callbacks\n\tconst handleSheetChanges = useCallback((index: number) => {\n\t\tconsole.log(\"handleSheetChanges\", index);\n\t}, []);\n\n\t// renders\n\tconst renderBackdrop = useCallback(\n\t\t(props) => (\n\t\t\t<BottomSheetBackdrop\n\t\t\t\t{...props}\n\t\t\t\tdisappearsOnIndex={1}\n\t\t\t\tappearsOnIndex={2}\n\t\t\t/>\n\t\t),\n\t\t[]\n\t);\n\treturn (\n\t\t<GestureHandlerRootView style={styles.container}>\n\t\t\t<BottomSheet\n\t\t\t\tref={bottomSheetRef}\n\t\t\t\tindex={1}\n\t\t\t\tsnapPoints={snapPoints}\n\t\t\t\tbackdropComponent={renderBackdrop}\n        enableDynamicSizing={false}\n\t\t\t\tonChange={handleSheetChanges}\n\t\t\t>\n\t\t\t\t<BottomSheetView style={styles.contentContainer}>\n\t\t\t\t\t<Text>Awesome 🎉</Text>\n\t\t\t\t</BottomSheetView>\n\t\t\t</BottomSheet>\n\t\t</GestureHandlerRootView>\n\t);\n};\n\nconst styles = StyleSheet.create({\n\tcontainer: {\n\t\tflex: 1,\n\t\tpadding: 24,\n\t\tbackgroundColor: \"grey\",\n\t},\n\tcontentContainer: {\n\t\tflex: 1,\n\t\talignItems: \"center\",\n\t},\n});\n\nexport default App;\n```\n"
  },
  {
    "path": "website/docs/components/bottomsheetflashlist.md",
    "content": "---\nid: bottomsheetflashlist\ntitle: BottomSheetFlashList\nsidebar_label: ⭐️ FlashList\ndescription: a pre-integrated React Native FlashList with BottomSheet gestures.\nimage: /img/bottom-sheet-preview.gif\nslug: /components/bottomsheetflashlist\n---\n\n:::warning\n\nThe `BottomSheetFlashList` has been deprecated in favor of a simpler approach using [`useBottomSheetScrollableCreator`](/hooks#usebottomsheetscrollablecreator).\n\n:::\n\n---\n\nA pre-integrated [**FlashList**](https://shopify.github.io/flash-list/) component with `BottomSheet` gestures.\n\n## Props\n\nInherits `FlashListProps` from [FlashList](https://shopify.github.io/flash-list/docs/usage).\n\n### focusHook\n\nThis needed when bottom sheet used with multiple scrollables to allow bottom sheet detect the current scrollable ref, especially when used with React Navigation. You will need to provide `useFocusEffect` from `@react-navigation/native`.\n\n| type     | default           | required |\n| -------- | ----------------- | -------- |\n| function | `React.useEffect` | NO       |\n\n## Example\n\n```tsx\nimport React, { useCallback, useRef, useMemo } from \"react\";\nimport { StyleSheet, View, Text, Button } from \"react-native\";\nimport { GestureHandlerRootView } from \"react-native-gesture-handler\";\nimport BottomSheet, { BottomSheetFlashList } from \"@gorhom/bottom-sheet\";\n\nconst keyExtractor = (item) => item;\n\nconst App = () => {\n\t// hooks\n\tconst sheetRef = useRef<BottomSheet>(null);\n\n\t// variables\n\tconst data = useMemo(\n\t\t() =>\n\t\t\tArray(50)\n\t\t\t\t.fill(0)\n\t\t\t\t.map((_, index) => `index-${index}`),\n\t\t[]\n\t);\n\tconst snapPoints = useMemo(() => [\"25%\", \"50%\"], []);\n\n\t// callbacks\n\tconst handleSnapPress = useCallback((index) => {\n\t\tsheetRef.current?.snapToIndex(index);\n\t}, []);\n\tconst handleClosePress = useCallback(() => {\n\t\tsheetRef.current?.close();\n\t}, []);\n\n\t// render\n\tconst renderItem = useCallback(({ item }) => {\n\t\treturn (\n\t\t\t<View key={item} style={styles.itemContainer}>\n\t\t\t\t<Text>{item}</Text>\n\t\t\t</View>\n\t\t);\n\t}, []);\n\treturn (\n\t\t<GestureHandlerRootView style={styles.container}>\n\t\t\t<Button title=\"Snap To 50%\" onPress={() => handleSnapPress(1)} />\n\t\t\t<Button title=\"Snap To 25%\" onPress={() => handleSnapPress(0)} />\n\t\t\t<Button title=\"Close\" onPress={() => handleClosePress()} />\n\t\t\t<BottomSheet\n\t\t\t\tref={sheetRef}\n\t\t\t\tsnapPoints={snapPoints}\n\t\t\t\tenableDynamicSizing={false}\n\t\t\t>\n\t\t\t\t<BottomSheetFlashList\n\t\t\t\t\tdata={data}\n\t\t\t\t\tkeyExtractor={keyExtractor}\n\t\t\t\t\trenderItem={renderItem}\n\t\t\t\t\testimatedItemSize={43.3}\n\t\t\t\t/>\n\t\t\t</BottomSheet>\n\t\t</GestureHandlerRootView>\n\t);\n};\n\nconst styles = StyleSheet.create({\n\tcontainer: {\n\t\tflex: 1,\n\t\tpaddingTop: 200,\n\t},\n\tcontentContainer: {\n\t\tbackgroundColor: \"white\",\n\t},\n\titemContainer: {\n\t\tpadding: 6,\n\t\tmargin: 6,\n\t\tbackgroundColor: \"#eee\",\n\t},\n});\n\nexport default App;\n```\n"
  },
  {
    "path": "website/docs/components/bottomsheetflatlist.md",
    "content": "---\nid: bottomsheetflatlist\ntitle: BottomSheetFlatList\nsidebar_label: FlatList\ndescription: a pre-integrated React Native FlatList with BottomSheet gestures.\nimage: /img/bottom-sheet-preview.gif\nslug: /components/bottomsheetflatlist\n---\n\nA pre-integrated `React Native` FlatList with `BottomSheet` gestures.\n\n## Props\n\nInherits `FlatListProps` from `react-native`.\n\n### focusHook\n\nThis needed when bottom sheet used with multiple scrollables to allow bottom sheet detect the current scrollable ref, especially when used with React Navigation. You will need to provide `useFocusEffect` from `@react-navigation/native`.\n\n| type     | default           | required |\n| -------- | ----------------- | -------- |\n| function | `React.useEffect` | NO       |\n\n## Ignored Props\n\nThese props will be ignored if they were passed, because of the internal integration that uses them.\n\n- `scrollEventThrottle`\n- `decelerationRate`\n- `onScrollBeginDrag`\n\n## Example\n\n```tsx\nimport React, { useCallback, useRef, useMemo } from \"react\";\nimport { StyleSheet, View, Text, Button } from \"react-native\";\nimport { GestureHandlerRootView } from 'react-native-gesture-handler';\nimport BottomSheet, { BottomSheetFlatList } from \"@gorhom/bottom-sheet\";\n\nconst App = () => {\n  // hooks\n  const sheetRef = useRef<BottomSheet>(null);\n\n  // variables\n  const data = useMemo(\n    () =>\n      Array(50)\n        .fill(0)\n        .map((_, index) => `index-${index}`),\n    []\n  );\n  const snapPoints = useMemo(() => [\"25%\", \"50%\", \"90%\"], []);\n\n  // callbacks\n  const handleSheetChange = useCallback((index) => {\n    console.log(\"handleSheetChange\", index);\n  }, []);\n  const handleSnapPress = useCallback((index) => {\n    sheetRef.current?.snapToIndex(index);\n  }, []);\n  const handleClosePress = useCallback(() => {\n    sheetRef.current?.close();\n  }, []);\n\n  // render\n  const renderItem = useCallback(\n    ({ item }) => (\n      <View style={styles.itemContainer}>\n        <Text>{item}</Text>\n      </View>\n    ),\n    []\n  );\n  return (\n    <GestureHandlerRootView style={styles.container}>\n      <Button title=\"Snap To 90%\" onPress={() => handleSnapPress(2)} />\n      <Button title=\"Snap To 50%\" onPress={() => handleSnapPress(1)} />\n      <Button title=\"Snap To 25%\" onPress={() => handleSnapPress(0)} />\n      <Button title=\"Close\" onPress={() => handleClosePress()} />\n      <BottomSheet\n        ref={sheetRef}\n        snapPoints={snapPoints}\n        enableDynamicSizing={false}\n        onChange={handleSheetChange}\n      >\n        <BottomSheetFlatList\n          data={data}\n          keyExtractor={(i) => i}\n          renderItem={renderItem}\n          contentContainerStyle={styles.contentContainer}\n        />\n      </BottomSheet>\n    </GestureHandlerRootView>\n  );\n};\n\nconst styles = StyleSheet.create({\n  container: {\n    flex: 1,\n    paddingTop: 200,\n  },\n  contentContainer: {\n    backgroundColor: \"white\",\n  },\n  itemContainer: {\n    padding: 6,\n    margin: 6,\n    backgroundColor: \"#eee\",\n  },\n});\n\nexport default App;\n```\n"
  },
  {
    "path": "website/docs/components/bottomsheetfooter.md",
    "content": "---\nid: bottomsheetfooter\ntitle: BottomSheetFooter\nsidebar_label: Footer\ndescription: an interactive footer component for the BottomSheet.\nimage: /img/bottom-sheet-preview.gif\nslug: /components/bottomsheetfooter\n---\n\nA pre-built component that sticks to the bottom of the BottomSheet and can be modify to fit your own custom interaction.\n\n## Props\n\n### animatedFooterPosition\n\nCalculated footer animated position.\n\n| type                          | default | required |\n| ----------------------------- | ------- | -------- |\n| Animated.SharedValue\\<number> | 0       | NO       |\n\n### bottomInset\n\nBottom inset to be added below the footer.\n\n| type   | default | required |\n| ------ | ------- | -------- |\n| number | 0       | NO       |\n\n### children\n\nComponent to be placed in the footer.\n\n| type                     | default   | required |\n| ------------------------ | --------- | -------- |\n| ReactNode \\| ReactNode[] | undefined | NO       |\n\n## Example\n\n```tsx\nimport React, { useCallback, useMemo, useRef } from 'react';\nimport { View, Text, StyleSheet } from 'react-native';\nimport { GestureHandlerRootView } from 'react-native-gesture-handler';\nimport BottomSheet, { BottomSheetFooter } from '@gorhom/bottom-sheet';\n\nconst App = () => {\n  // ref\n  const bottomSheetRef = useRef<BottomSheet>(null);\n\n  // variables\n  const snapPoints = useMemo(() => ['25%', '50%'], []);\n\n  // renders\n  const renderFooter = useCallback(\n    props => (\n      <BottomSheetFooter {...props} bottomInset={24}>\n        <View style={styles.footerContainer}>\n          <Text style={styles.footerText}>Footer</Text>\n        </View>\n      </BottomSheetFooter>\n    ),\n    []\n  );\n  return (\n    <GestureHandlerRootView style={styles.container}>\n      <BottomSheet\n        ref={bottomSheetRef}\n        index={1}\n        snapPoints={snapPoints}\n        footerComponent={renderFooter}\n      >\n        <View style={styles.contentContainer}>\n          <Text>Awesome 🎉</Text>\n        </View>\n      </BottomSheet>\n    </GestureHandlerRootView>\n  );\n};\n\nconst styles = StyleSheet.create({\n  container: {\n    flex: 1,\n    padding: 24,\n    backgroundColor: 'grey',\n  },\n  contentContainer: {\n    flex: 1,\n    alignItems: 'center',\n  },\n  footerContainer: {\n    padding: 12,\n    margin: 12,\n    borderRadius: 12,\n    backgroundColor: '#80f',\n  },\n  footerText: {\n    textAlign: 'center',\n    color: 'white',\n    fontWeight: '800',\n  },\n});\n\nexport default App;\n```\n"
  },
  {
    "path": "website/docs/components/bottomsheetscrollview.md",
    "content": "---\nid: bottomsheetscrollview\ntitle: BottomSheetScrollView\nsidebar_label: ScrollView\ndescription: a pre-integrated React Native ScrollView with BottomSheet gestures.\nimage: /img/bottom-sheet-preview.gif\nslug: /components/bottomsheetscrollview\n---\n\nA pre-integrated `React Native` ScrollView with `BottomSheet` gestures.\n\n## Props\n\nInherits `ScrollViewProps` from `react-native`.\n\n### focusHook\n\nThis needed when bottom sheet used with multiple scrollables to allow bottom sheet detect the current scrollable ref, especially when used with React Navigation. You will need to provide `useFocusEffect` from `@react-navigation/native`.\n\n| type     | default           | required |\n| -------- | ----------------- | -------- |\n| function | `React.useEffect` | NO       |\n\n## Ignored Props\n\nThese props will be ignored if they were passed, because of the internal integration that uses them.\n\n- `scrollEventThrottle`\n- `decelerationRate`\n- `onScrollBeginDrag`\n\n## Example\n\n```tsx\nimport React, { useCallback, useRef, useMemo } from \"react\";\nimport { StyleSheet, View, Text, Button } from \"react-native\";\nimport { GestureHandlerRootView } from 'react-native-gesture-handler';\nimport BottomSheet, { BottomSheetScrollView } from \"@gorhom/bottom-sheet\";\n\nconst App = () => {\n  // hooks\n  const sheetRef = useRef<BottomSheet>(null);\n\n  // variables\n  const data = useMemo(\n    () =>\n      Array(50)\n        .fill(0)\n        .map((_, index) => `index-${index}`),\n    []\n  );\n  const snapPoints = useMemo(() => [\"25%\", \"50%\", \"90%\"], []);\n\n  // callbacks\n  const handleSheetChange = useCallback((index) => {\n    console.log(\"handleSheetChange\", index);\n  }, []);\n  const handleSnapPress = useCallback((index) => {\n    sheetRef.current?.snapToIndex(index);\n  }, []);\n  const handleClosePress = useCallback(() => {\n    sheetRef.current?.close();\n  }, []);\n\n  // render\n  const renderItem = useCallback(\n    (item) => (\n      <View key={item} style={styles.itemContainer}>\n        <Text>{item}</Text>\n      </View>\n    ),\n    []\n  );\n  return (\n    <GestureHandlerRootView style={styles.container}>\n      <Button title=\"Snap To 90%\" onPress={() => handleSnapPress(2)} />\n      <Button title=\"Snap To 50%\" onPress={() => handleSnapPress(1)} />\n      <Button title=\"Snap To 25%\" onPress={() => handleSnapPress(0)} />\n      <Button title=\"Close\" onPress={() => handleClosePress()} />\n      <BottomSheet\n        ref={sheetRef}\n        index={1}\n        snapPoints={snapPoints}\n        enableDynamicSizing={false}\n        onChange={handleSheetChange}\n      >\n        <BottomSheetScrollView contentContainerStyle={styles.contentContainer}>\n          {data.map(renderItem)}\n        </BottomSheetScrollView>\n      </BottomSheet>\n    </GestureHandlerRootView>\n  );\n};\n\nconst styles = StyleSheet.create({\n  container: {\n    flex: 1,\n    paddingTop: 200,\n  },\n  contentContainer: {\n    backgroundColor: \"white\",\n  },\n  itemContainer: {\n    padding: 6,\n    margin: 6,\n    backgroundColor: \"#eee\",\n  },\n});\n\nexport default App;\n```\n"
  },
  {
    "path": "website/docs/components/bottomsheetsectionlist.md",
    "content": "---\nid: bottomsheetsectionlist\ntitle: BottomSheetSectionList\nsidebar_label: SectionList\ndescription: a pre-integrated React Native SectionList with BottomSheet gestures.\nimage: /img/bottom-sheet-preview.gif\nslug: /components/bottomsheetsectionlist\n---\n\nA pre-integrated `React Native` SectionList with `BottomSheet` gestures.\n\n## Props\n\nInherits `SectionListProps` from `react-native`.\n\n### focusHook\n\nThis needed when bottom sheet used with multiple scrollables to allow bottom sheet detect the current scrollable ref, especially when used with React Navigation. You will need to provide `useFocusEffect` from `@react-navigation/native`.\n\n| type     | default           | required |\n| -------- | ----------------- | -------- |\n| function | `React.useEffect` | NO       |\n\n## Ignored Props\n\nThese props will be ignored if they were passed, because of the internal integration that uses them.\n\n- `scrollEventThrottle`\n- `decelerationRate`\n- `onScrollBeginDrag`\n\n## Example\n\n```tsx\nimport React, { useCallback, useRef, useMemo } from \"react\";\nimport { StyleSheet, View, Text, Button } from \"react-native\";\nimport { GestureHandlerRootView } from 'react-native-gesture-handler';\nimport BottomSheet, { BottomSheetSectionList } from \"@gorhom/bottom-sheet\";\n\nconst App = () => {\n  // hooks\n  const sheetRef = useRef<BottomSheet>(null);\n\n  // variables\n  const sections = useMemo(\n    () =>\n      Array(10)\n        .fill(0)\n        .map((_, index) => ({\n          title: `Section ${index}`,\n          data: Array(10)\n            .fill(0)\n            .map((_, index) => `Item ${index}`),\n        })),\n    []\n  );\n  const snapPoints = useMemo(() => [\"25%\", \"50%\", \"90%\"], []);\n\n  // callbacks\n  const handleSheetChange = useCallback((index) => {\n    console.log(\"handleSheetChange\", index);\n  }, []);\n  const handleSnapPress = useCallback((index) => {\n    sheetRef.current?.snapToIndex(index);\n  }, []);\n  const handleClosePress = useCallback(() => {\n    sheetRef.current?.close();\n  }, []);\n\n  // render\n  const renderSectionHeader = useCallback(\n    ({ section }) => (\n      <View style={styles.sectionHeaderContainer}>\n        <Text>{section.title}</Text>\n      </View>\n    ),\n    []\n  );\n  const renderItem = useCallback(\n    ({ item }) => (\n      <View style={styles.itemContainer}>\n        <Text>{item}</Text>\n      </View>\n    ),\n    []\n  );\n  return (\n    <GestureHandlerRootView style={styles.container}>\n      <Button title=\"Snap To 90%\" onPress={() => handleSnapPress(2)} />\n      <Button title=\"Snap To 50%\" onPress={() => handleSnapPress(1)} />\n      <Button title=\"Snap To 25%\" onPress={() => handleSnapPress(0)} />\n      <Button title=\"Close\" onPress={() => handleClosePress()} />\n      <BottomSheet\n        ref={sheetRef}\n        index={1}\n        snapPoints={snapPoints}\n        enableDynamicSizing={false}\n        onChange={handleSheetChange}\n      >\n        <BottomSheetSectionList\n          sections={sections}\n          keyExtractor={(i) => i}\n          renderSectionHeader={renderSectionHeader}\n          renderItem={renderItem}\n          contentContainerStyle={styles.contentContainer}\n        />\n      </BottomSheet>\n    </GestureHandlerRootView>\n  );\n};\n\nconst styles = StyleSheet.create({\n  container: {\n    flex: 1,\n    paddingTop: 200,\n  },\n  contentContainer: {\n    backgroundColor: \"white\",\n  },\n  sectionHeaderContainer: {\n    backgroundColor: \"white\",\n    padding: 6,\n  },\n  itemContainer: {\n    padding: 6,\n    margin: 6,\n    backgroundColor: \"#eee\",\n  },\n});\n\nexport default App;\n```\n"
  },
  {
    "path": "website/docs/components/bottomsheettextinput.md",
    "content": "---\nid: bottomsheettextinput\ntitle: BottomSheetTextInput\nsidebar_label: TextInput\ndescription: an pre-integrated TextInput component for better keyboard handling.\nimage: /img/bottom-sheet-preview.gif\nslug: /components/bottomsheettextinput\n---\n\nA pre-integrated `TextInput` that communicate with internal functionalities to allow Keyboard handling to work.\n\n## Props\n\nInherits `TextInputProps` from `react-native`.\n\n## Example\n\n```tsx\nimport React, { useCallback, useMemo, useRef } from 'react';\nimport { View, Text, StyleSheet } from 'react-native';\nimport { GestureHandlerRootView } from 'react-native-gesture-handler';\nimport BottomSheet, { BottomSheetView, BottomSheetTextInput } from '@gorhom/bottom-sheet';\n\nconst App = () => {\n  // ref\n  const bottomSheetRef = useRef<BottomSheet>(null);\n\n  // variables\n  const snapPoints = useMemo(() => ['25%', '50%'], []);\n\n  // callbacks\n  const handleSheetChanges = useCallback((index: number) => {\n    console.log('handleSheetChanges', index);\n  }, []);\n\n  // renders\n  return (\n    <GestureHandlerRootView style={styles.container}>\n      <BottomSheet\n        ref={bottomSheetRef}\n        index={1}\n        snapPoints={snapPoints}\n        keyboardBehavior=\"fillParent\"\n        enableDynamicSizing={false}\n        onChange={handleSheetChanges}\n      >\n        <BottomSheetTextInput style={styles.input} />\n        <BottomSheetView style={styles.contentContainer}>\n          <Text>Awesome 🎉</Text>\n        </BottomSheetView>\n      </BottomSheet>\n    </GestureHandlerRootView>\n  );\n};\n\nconst styles = StyleSheet.create({\n  container: {\n    flex: 1,\n    padding: 24,\n    backgroundColor: 'grey',\n  },\n  contentContainer: {\n    flex: 1,\n    alignItems: 'center',\n  },\n  input: {\n    marginTop: 8,\n    marginBottom: 10,\n    borderRadius: 10,\n    fontSize: 16,\n    lineHeight: 20,\n    padding: 8,\n    backgroundColor: 'rgba(151, 151, 151, 0.25)',\n  },\n});\n\nexport default App;\n```\n"
  },
  {
    "path": "website/docs/components/bottomsheetview.md",
    "content": "---\nid: bottomsheetview\ntitle: BottomSheetView\nsidebar_label: View\ndescription: a pre-integrated React Native View with BottomSheet gestures.\nimage: /img/bottom-sheet-preview.gif\nslug: /components/bottomsheetview\n---\n\nA pre-integrated `React Native` View with `BottomSheet` gestures.\n\n## Props\n\nInherits `ViewProps` from `react-native`.\n\n### focusHook\n\nThis needed when bottom sheet used with multiple scrollables to allow bottom sheet detect the current scrollable ref, especially when used with React Navigation. You will need to provide `useFocusEffect` from `@react-navigation/native`.\n\n| type     | default           | required |\n| -------- | ----------------- | -------- |\n| function | `React.useEffect` | NO       |\n\n## Example\n\n```tsx\nimport React, { useCallback, useRef, useMemo } from \"react\";\nimport { StyleSheet, View, Text, Button } from \"react-native\";\nimport { GestureHandlerRootView } from 'react-native-gesture-handler';\nimport BottomSheet, { BottomSheetView } from \"@gorhom/bottom-sheet\";\n\nconst App = () => {\n  // hooks\n  const sheetRef = useRef<BottomSheet>(null);\n\n  // variables\n  const snapPoints = useMemo(() => [\"25%\", \"50%\", \"90%\"], []);\n\n  // callbacks\n  const handleSheetChange = useCallback((index) => {\n    console.log(\"handleSheetChange\", index);\n  }, []);\n  const handleSnapPress = useCallback((index) => {\n    sheetRef.current?.snapToIndex(index);\n  }, []);\n  const handleClosePress = useCallback(() => {\n    sheetRef.current?.close();\n  }, []);\n\n  // render\n  return (\n    <GestureHandlerRootView style={styles.container}>\n      <Button title=\"Snap To 90%\" onPress={() => handleSnapPress(2)} />\n      <Button title=\"Snap To 50%\" onPress={() => handleSnapPress(1)} />\n      <Button title=\"Snap To 25%\" onPress={() => handleSnapPress(0)} />\n      <Button title=\"Close\" onPress={() => handleClosePress()} />\n      <BottomSheet\n        ref={sheetRef}\n        snapPoints={snapPoints}\n        enableDynamicSizing={false}\n        onChange={handleSheetChange}\n      >\n        <BottomSheetView style={styles.contentContainer}>\n          <Text>Awesome 🔥</Text>\n        </BottomSheetView>\n      </BottomSheet>\n    </GestureHandlerRootView>\n  );\n};\n\nconst styles = StyleSheet.create({\n  container: {\n    flex: 1,\n    paddingTop: 200,\n  },\n  contentContainer: {\n    flex: 1,\n    padding: 36,\n    alignItems: 'center',\n  },\n});\n\nexport default App;\n```\n"
  },
  {
    "path": "website/docs/components/bottomsheetvirtualizedlist.md",
    "content": "---\nid: bottomsheetvirtualizedlist\ntitle: BottomSheetVirtualizedList\nsidebar_label: VirtualizedList\ndescription: a pre-integrated React Native VirtualizedList with BottomSheet gestures.\nimage: /img/bottom-sheet-preview.gif\nslug: /components/bottomsheetvirtualizedlist\n---\n\nA pre-integrated `React Native` VirtualizedList with `BottomSheet` gestures.\n\n## Props\n\nInherits `VirtualizedListProps` from `react-native`.\n\n### focusHook\n\nThis needed when bottom sheet used with multiple scrollables to allow bottom sheet detect the current scrollable ref, especially when used with React Navigation. You will need to provide `useFocusEffect` from `@react-navigation/native`.\n\n| type     | default           | required |\n| -------- | ----------------- | -------- |\n| function | `React.useEffect` | NO       |\n\n## Ignored Props\n\nThese props will be ignored if they were passed, because of the internal integration that uses them.\n\n- `scrollEventThrottle`\n- `decelerationRate`\n- `onScrollBeginDrag`\n\n## Example\n\n```tsx\nimport React, { useCallback, useRef, useMemo } from \"react\";\nimport { StyleSheet, View, Text, Button } from \"react-native\";\nimport { GestureHandlerRootView } from 'react-native-gesture-handler';\nimport BottomSheet, { BottomSheetVirtualizedList } from \"@gorhom/bottom-sheet\";\n\nconst App = () => {\n  // hooks\n  const sheetRef = useRef<BottomSheet>(null);\n\n  // variables\n  const data = useMemo(\n    () =>\n      Array(50)\n        .fill(0)\n        .map((_, index) => `index-${index}`),\n    []\n  );\n  const snapPoints = useMemo(() => [\"25%\", \"50%\", \"90%\"], []);\n\n  // callbacks\n  const handleSheetChange = useCallback((index) => {\n    console.log(\"handleSheetChange\", index);\n  }, []);\n  const handleSnapPress = useCallback((index) => {\n    sheetRef.current?.snapToIndex(index);\n  }, []);\n  const handleClosePress = useCallback(() => {\n    sheetRef.current?.close();\n  }, []);\n\n  // render\n  const renderItem = useCallback(\n    ({ item }) => (\n      <View style={styles.itemContainer}>\n        <Text>{item}</Text>\n      </View>\n    ),\n    []\n  );\n  return (\n    <GestureHandlerRootView style={styles.container}>\n      <Button title=\"Snap To 90%\" onPress={() => handleSnapPress(2)} />\n      <Button title=\"Snap To 50%\" onPress={() => handleSnapPress(1)} />\n      <Button title=\"Snap To 25%\" onPress={() => handleSnapPress(0)} />\n      <Button title=\"Close\" onPress={() => handleClosePress()} />\n      <BottomSheet\n        ref={sheetRef}\n        snapPoints={snapPoints}\n        enableDynamicSizing={false}\n        onChange={handleSheetChange}\n      >\n        <BottomSheetVirtualizedList\n          data={data}\n          keyExtractor={(i) => i}\n          getItemCount={(data) => data.length}\n          getItem={(data, index) => data[index]}\n          renderItem={renderItem}\n          contentContainerStyle={styles.contentContainer}\n        />\n      </BottomSheet>\n    </GestureHandlerRootView>\n  );\n};\n\nconst styles = StyleSheet.create({\n  container: {\n    flex: 1,\n    paddingTop: 200,\n  },\n  contentContainer: {\n    backgroundColor: \"white\",\n  },\n  itemContainer: {\n    padding: 6,\n    margin: 6,\n    backgroundColor: \"#eee\",\n  },\n});\n\nexport default App;\n```\n"
  },
  {
    "path": "website/docs/faq.md",
    "content": "---\nid: faq\ntitle: FAQ\ndescription: Bottom Sheet FAQ.\nimage: /img/bottom-sheet-preview.gif\nslug: /faq\nhide_table_of_contents: true\n---\n\n### How this library differ from `reanimated-bottom-sheet` or `react-native-scroll-bottom-sheet`?\n\nThis library was built to provide the most native-like experience and could fit any use-case that developers wants it to be. While both libraries providing similar experience, but they still missing the following:\n\n- `reanimated-bottom-sheet`: Seamless gesture interaction between the sheet and the content.\n- `react-native-scroll-bottom-sheet`: Extracting scrollable content to allow developers customize the sheet content, like integrate React Navigation as the sheet content.\n\nBoth libraries are great! and I have used both of them at my work ❤️\n"
  },
  {
    "path": "website/docs/guides/adding-shadow.mdx",
    "content": "---\nid: adding-shadow\ntitle: Adding Shadow\ndescription: Adding shadow to the Bottom Sheet.\nimage: /img/bottom-sheet-preview.gif\nslug: /adding-shadow\nhide_table_of_contents: true\n---\n\n![React Native Bottom Sheet Shadow](/img/bottom-sheet-shadow.jpg)\n\nTo add shadow to the bottom sheet, you will need to pass the `style` prop with shadow styling config, I recommend checking out [React Native Shadow Generator](https://ethercreative.github.io/react-native-shadow-generator/) by [@ethercreative](https://github.com/ethercreative).\n\n:::note NOTICE\n\nYou may notice that shadow looks different between **iOS** and **Android**, that's because each platform handle drawing shadows differently, read more about [Android Shadows](https://developer.android.com/training/material/shadows-clipping).\n\n:::\n"
  },
  {
    "path": "website/docs/guides/custom-backdrop.mdx",
    "content": "---\nid: custom-backdrop\ntitle: Custom Backdrop\ndescription: Bottom Sheet custom backdrop.\nimage: /img/bottom-sheet-preview.gif\nslug: /custom-backdrop\nhide_table_of_contents: true\n---\n\nTo add a backdrop to your sheet you will need to pass the prop `backdropComponent` to the `BottomSheet` component.\n\nWhen you provide your own backdrop component, it will receive these animated props `animatedIndex` & `animatedPosition` that indicates the position and the index of the sheet.\n\nYou can extend your custom backdrop props interface with the provided `BottomSheetBackdropProps` interface to expose `animatedIndex` & `animatedPosition` into your own interface.\n\n### Example\n\nimport useBaseUrl from \"@docusaurus/useBaseUrl\";\nimport Video from \"@theme/Video\";\n\n<Video\n  title=\"React Native Bottom Sheet Custom Backdrop\"\n  url={useBaseUrl(\"video/bottom-sheet-custom-backdrop-preview.mp4\")}\n/>\n\nHere is an example of a custom backdrop component:\n\n```tsx\nimport React, { useMemo } from \"react\";\nimport { BottomSheetBackdropProps } from \"@gorhom/bottom-sheet\";\nimport Animated, {\n  Extrapolate,\n  interpolate,\n  useAnimatedStyle,\n} from \"react-native-reanimated\";\n\nconst CustomBackdrop = ({ animatedIndex, style }: BottomSheetBackdropProps) => {\n  // animated variables\n  const containerAnimatedStyle = useAnimatedStyle(() => ({\n    opacity: interpolate(\n      animatedIndex.value,\n      [0, 1],\n      [0, 1],\n      Extrapolate.CLAMP\n    ),\n  }));\n\n  // styles\n  const containerStyle = useMemo(\n    () => [\n      style,\n      {\n        backgroundColor: \"#a8b5eb\",\n      },\n      containerAnimatedStyle,\n    ],\n    [style, containerAnimatedStyle]\n  );\n\n  return <Animated.View style={containerStyle} />;\n};\n\nexport default CustomBackdrop;\n```\n"
  },
  {
    "path": "website/docs/guides/custom-background.mdx",
    "content": "---\nid: custom-background\ntitle: Custom Background\ndescription: Bottom Sheet custom background.\nimage: /img/bottom-sheet-preview.gif\nslug: /custom-background\nhide_table_of_contents: true\n---\n\nTo override the default background, you will need to pass the prop `backgroundComponent` to the `BottomSheet` component.\n\nWhen you provide your own background component, it will receive these animated props `animatedIndex` & `animatedPosition` that indicates the position and the index of the sheet.\n\nYou can extend your custom background props interface with the provided `BottomSheetBackgroundProps` interface to expose `animatedIndex` & `animatedPosition` into your own interface.\n\n### Example\n\nimport useBaseUrl from \"@docusaurus/useBaseUrl\";\nimport Video from \"@theme/Video\";\n\n<Video\n  title=\"React Native Bottom Sheet Custom Background\"\n  url={useBaseUrl(\"video/bottom-sheet-custom-background-preview.mp4\")}\n/>\n\nHere is an example of a custom background component:\n\n```tsx\nimport React, { useMemo } from \"react\";\nimport { BottomSheetBackgroundProps } from \"@gorhom/bottom-sheet\";\nimport Animated, {\n  useAnimatedStyle,\n  interpolateColor,\n} from \"react-native-reanimated\";\n\nconst CustomBackground: React.FC<BottomSheetBackgroundProps> = ({\n  style,\n  animatedIndex,\n}) => {\n  //#region styles\n  const containerAnimatedStyle = useAnimatedStyle(() => ({\n    // @ts-ignore\n    backgroundColor: interpolateColor(\n      animatedIndex.value,\n      [0, 1],\n      [\"#ffffff\", \"#a8b5eb\"]\n    ),\n  }));\n  const containerStyle = useMemo(\n    () => [style, containerAnimatedStyle],\n    [style, containerAnimatedStyle]\n  );\n  //#endregion\n\n  // render\n  return <Animated.View pointerEvents=\"none\" style={containerStyle} />;\n};\n\nexport default CustomBackground;\n```\n"
  },
  {
    "path": "website/docs/guides/custom-footer.mdx",
    "content": "---\nid: custom-footer\ntitle: Custom Footer\ndescription: Bottom Sheet custom footer.\nimage: /img/bottom-sheet-preview.gif\nslug: /custom-footer\nhide_table_of_contents: true\n---\n\nTo create a custom footer, you will need to use the pre-built component [BottomSheetFooter](./components/bottomsheetfooter) to wrap your footer component, the `BottomSheetFooter` will help in positioning your component at the bottom of the `BottomSheet` and will react to `Keyboard` appearance too.\n\nWhen you provide your own footer component, it will receive this animated prop `animatedFooterPosition`, which is a calculated animated position for the footer.\n\nYou can extend your custom footer props interface with the provided `BottomSheetFooterProps` interface to expose `animatedFooterPosition` into your own interface.\n\n### Example\n\nimport useBaseUrl from '@docusaurus/useBaseUrl';\nimport Video from '@theme/Video';\n\n<Video\n  title=\"React Native Bottom Sheet Custom Footer\"\n  url={useBaseUrl('video/bottom-sheet-footer-preview.mp4')}\n/>\n\nHere is an example of a custom footer component but first you will need to install `Redash`:\n\n> [Redash](https://github.com/wcandillon/react-native-redash): The React Native Reanimated and Gesture Handler Toolbelt.\n\n```tsx title=\"CustomFooter.tsx\"\nimport React, { useCallback, useMemo } from 'react';\nimport { StyleSheet } from 'react-native';\nimport {\n  BottomSheetFooter,\n  BottomSheetFooterProps,\n  useBottomSheet,\n} from '@gorhom/bottom-sheet';\nimport { RectButton } from 'react-native-gesture-handler';\nimport { useSafeAreaInsets } from 'react-native-safe-area-context';\nimport Animated, {\n  Extrapolate,\n  interpolate,\n  useAnimatedStyle,\n} from 'react-native-reanimated';\nimport { toRad } from 'react-native-redash';\n\nconst AnimatedRectButton = Animated.createAnimatedComponent(RectButton);\n\n// inherent the `BottomSheetFooterProps` to be able receive\n// `animatedFooterPosition`.\ninterface CustomFooterProps extends BottomSheetFooterProps {}\n\nconst CustomFooter = ({ animatedFooterPosition }: CustomFooterProps) => {\n  //#region hooks\n  // we need the bottom safe insets to avoid bottom notches.\n  const { bottom: bottomSafeArea } = useSafeAreaInsets();\n  // extract animated index and other functionalities\n  const { expand, collapse, animatedIndex } = useBottomSheet();\n  //#endregion\n\n  //#region styles\n  // create the arrow animated style reacting to the\n  // sheet index.\n  const arrowAnimatedStyle = useAnimatedStyle(() => {\n    const arrowRotate = interpolate(\n      animatedIndex.value,\n      [0, 1],\n      [toRad(0), toRad(-180)],\n      Extrapolate.CLAMP\n    );\n    return {\n      transform: [{ rotate: `${arrowRotate}rad` }],\n    };\n  }, []);\n  const arrowStyle = useMemo(\n    () => [arrowAnimatedStyle, styles.arrow],\n    [arrowAnimatedStyle]\n  );\n  // create the content animated style reacting to the\n  // sheet index.\n  const containerAnimatedStyle = useAnimatedStyle(\n    () => ({\n      opacity: interpolate(\n        animatedIndex.value,\n        [-0.85, 0],\n        [0, 1],\n        Extrapolate.CLAMP\n      ),\n    }),\n    [animatedIndex]\n  );\n  const containerStyle = useMemo(\n    () => [containerAnimatedStyle, styles.container],\n    [containerAnimatedStyle]\n  );\n  //#endregion\n\n  //#region callbacks\n  const handleArrowPress = useCallback(() => {\n    // if sheet is collapsed, then we extend it,\n    // or the opposite.\n    if (animatedIndex.value === 0) {\n      expand();\n    } else {\n      collapse();\n    }\n  }, [expand, collapse, animatedIndex]);\n  //#endregion\n\n  return (\n    <BottomSheetFooter\n      // we pass the bottom safe inset\n      bottomInset={bottomSafeArea}\n      // we pass the provided `animatedFooterPosition`\n      animatedFooterPosition={animatedFooterPosition}\n    >\n      <AnimatedRectButton style={containerStyle} onPress={handleArrowPress}>\n        <Animated.Text style={arrowStyle}>⌃</Animated.Text>\n      </AnimatedRectButton>\n    </BottomSheetFooter>\n  );\n};\n\n// footer style\nconst styles = StyleSheet.create({\n  container: {\n    alignSelf: 'flex-end',\n    justifyContent: 'center',\n    alignItems: 'center',\n    marginHorizontal: 24,\n    marginBottom: 12,\n    width: 50,\n    height: 50,\n    borderRadius: 25,\n    backgroundColor: '#80f',\n    shadowOffset: {\n      width: 0,\n      height: 12,\n    },\n    shadowOpacity: 0.25,\n    shadowRadius: 8.0,\n\n    elevation: 8,\n  },\n  arrow: {\n    fontSize: 20,\n    height: 20,\n    textAlignVertical: 'center',\n    fontWeight: '900',\n    color: '#fff',\n  },\n});\n\nexport default CustomFooter;\n```\n\n```tsx title=\"App.tsx\"\nimport React, { useCallback, useMemo, useRef } from 'react';\nimport { View, Text, StyleSheet } from 'react-native';\nimport BottomSheet from '@gorhom/bottom-sheet';\nimport CustomFooter from './CustomFooter';\n\nconst App = () => {\n  // variables\n  const snapPoints = useMemo(() => ['25%', '50%'], []);\n\n  // renders\n  return (\n    <View style={styles.container}>\n      <BottomSheet\n        index={1}\n        snapPoints={snapPoints}\n        footerComponent={CustomFooter}\n      >\n        <View style={styles.contentContainer}>\n          <Text>Awesome 🎉</Text>\n        </View>\n      </BottomSheet>\n    </View>\n  );\n};\n\nconst styles = StyleSheet.create({\n  container: {\n    flex: 1,\n    padding: 24,\n    backgroundColor: 'grey',\n  },\n  contentContainer: {\n    flex: 1,\n    alignItems: 'center',\n  },\n});\n\nexport default App;\n```\n"
  },
  {
    "path": "website/docs/guides/custom-handle.mdx",
    "content": "---\nid: custom-handle\ntitle: Custom Handle\ndescription: Bottom Sheet custom handle.\nimage: /img/bottom-sheet-preview.gif\nslug: /custom-handle\nhide_table_of_contents: true\n---\n\nTo override the default handle, you will need to pass the prop `handleComponent` to the `BottomSheet` component.\n\nWhen you provide your own handle component, it will receive these animated props `animatedIndex` & `animatedPosition` that indicates the position and the index of the sheet.\n\nYou can extend your custom handle props interface with the provided `BottomSheetHandleProps` interface to expose `animatedIndex` & `animatedPosition` into your own interface.\n\n### Example\n\nimport useBaseUrl from \"@docusaurus/useBaseUrl\";\nimport Video from \"@theme/Video\";\n\n<Video\n  title=\"React Native Bottom Sheet Custom Handle\"\n  url={useBaseUrl(\"video/bottom-sheet-custom-handle-preview.mp4\")}\n/>\n\nHere is an example of a custom handle component, but first you will need to install `Redash`:\n\n> [Redash](https://github.com/wcandillon/react-native-redash): The React Native Reanimated and Gesture Handler Toolbelt.\n\n```bash\nyarn add react-native-redash\n```\n\n```tsx\nimport React, { useMemo } from \"react\";\nimport { StyleProp, StyleSheet, ViewStyle } from \"react-native\";\nimport { BottomSheetHandleProps } from \"@gorhom/bottom-sheet\";\nimport Animated, {\n  Extrapolate,\n  interpolate,\n  useAnimatedStyle,\n  useDerivedValue,\n} from \"react-native-reanimated\";\nimport { toRad } from \"react-native-redash\";\n\n// @ts-ignore\nexport const transformOrigin = ({ x, y }, ...transformations) => {\n  \"worklet\";\n  return [\n    { translateX: x },\n    { translateY: y },\n    ...transformations,\n    { translateX: x * -1 },\n    { translateY: y * -1 },\n  ];\n};\n\ninterface HandleProps extends BottomSheetHandleProps {\n  style?: StyleProp<ViewStyle>;\n}\n\nconst Handle: React.FC<HandleProps> = ({ style, animatedIndex }) => {\n  //#region animations\n  const indicatorTransformOriginY = useDerivedValue(() =>\n    interpolate(animatedIndex.value, [0, 1, 2], [-1, 0, 1], Extrapolate.CLAMP)\n  );\n  //#endregion\n\n  //#region styles\n  const containerStyle = useMemo(() => [styles.header, style], [style]);\n  const containerAnimatedStyle = useAnimatedStyle(() => {\n    const borderTopRadius = interpolate(\n      animatedIndex.value,\n      [1, 2],\n      [20, 0],\n      Extrapolate.CLAMP\n    );\n    return {\n      borderTopLeftRadius: borderTopRadius,\n      borderTopRightRadius: borderTopRadius,\n    };\n  });\n  const leftIndicatorStyle = useMemo(\n    () => ({\n      ...styles.indicator,\n      ...styles.leftIndicator,\n    }),\n    []\n  );\n  const leftIndicatorAnimatedStyle = useAnimatedStyle(() => {\n    const leftIndicatorRotate = interpolate(\n      animatedIndex.value,\n      [0, 1, 2],\n      [toRad(-30), 0, toRad(30)],\n      Extrapolate.CLAMP\n    );\n    return {\n      transform: transformOrigin(\n        { x: 0, y: indicatorTransformOriginY.value },\n        {\n          rotate: `${leftIndicatorRotate}rad`,\n        },\n        {\n          translateX: -5,\n        }\n      ),\n    };\n  });\n  const rightIndicatorStyle = useMemo(\n    () => ({\n      ...styles.indicator,\n      ...styles.rightIndicator,\n    }),\n    []\n  );\n  const rightIndicatorAnimatedStyle = useAnimatedStyle(() => {\n    const rightIndicatorRotate = interpolate(\n      animatedIndex.value,\n      [0, 1, 2],\n      [toRad(30), 0, toRad(-30)],\n      Extrapolate.CLAMP\n    );\n    return {\n      transform: transformOrigin(\n        { x: 0, y: indicatorTransformOriginY.value },\n        {\n          rotate: `${rightIndicatorRotate}rad`,\n        },\n        {\n          translateX: 5,\n        }\n      ),\n    };\n  });\n  //#endregion\n\n  // render\n  return (\n    <Animated.View\n      style={[containerStyle, containerAnimatedStyle]}\n      renderToHardwareTextureAndroid={true}\n    >\n      <Animated.View style={[leftIndicatorStyle, leftIndicatorAnimatedStyle]} />\n      <Animated.View\n        style={[rightIndicatorStyle, rightIndicatorAnimatedStyle]}\n      />\n    </Animated.View>\n  );\n};\n\nexport default Handle;\n\nconst styles = StyleSheet.create({\n  header: {\n    alignContent: \"center\",\n    alignItems: \"center\",\n    justifyContent: \"center\",\n    backgroundColor: \"white\",\n    paddingVertical: 14,\n    borderBottomWidth: 1,\n    borderBottomColor: \"#fff\",\n  },\n  indicator: {\n    position: \"absolute\",\n    width: 10,\n    height: 4,\n    backgroundColor: \"#999\",\n  },\n  leftIndicator: {\n    borderTopStartRadius: 2,\n    borderBottomStartRadius: 2,\n  },\n  rightIndicator: {\n    borderTopEndRadius: 2,\n    borderBottomEndRadius: 2,\n  },\n});\n```\n"
  },
  {
    "path": "website/docs/guides/detach-modal.mdx",
    "content": "---\nid: detach-modal\ntitle: Detach Modal\ndescription: Bottom Sheet custom footer.\nimage: /img/bottom-sheet-preview.gif\nslug: /detach-modal\nhide_table_of_contents: true\n---\n\nTo create a detach modal, you will need to pass the prop `detached={true}` to the `BottomSheet` or `BottomSheetModal`, along side with `bottomInset` to push the sheet from the bottom.\n\n### Example\n\nimport useBaseUrl from \"@docusaurus/useBaseUrl\";\nimport Video from \"@theme/Video\";\n\n<Video\n  title=\"React Native Bottom Sheet Detach Modal\"\n  url={useBaseUrl(\"video/bottom-sheet-detach-preview.mp4\")}\n/>\n\nHere is an example of a simple detach modal:\n\n```tsx\nimport React, { useMemo, useRef } from \"react\";\nimport { View, Text, StyleSheet } from \"react-native\";\nimport BottomSheet from \"@gorhom/bottom-sheet\";\n\nconst App = () => {\n  // ref\n  const bottomSheetRef = useRef<BottomSheet>(null);\n\n  // variables\n  const snapPoints = useMemo(() => [\"25%\"], []);\n\n  // renders\n  return (\n    <View style={styles.container}>\n      <BottomSheet\n        ref={bottomSheetRef}\n        snapPoints={snapPoints}\n        // add bottom inset to elevate the sheet\n        bottomInset={46}\n        // set `detached` to true\n        detached={true}\n        style={styles.sheetContainer}\n      >\n        <View style={styles.contentContainer}>\n          <Text>Awesome 🎉</Text>\n        </View>\n      </BottomSheet>\n    </View>\n  );\n};\n\nconst styles = StyleSheet.create({\n  container: {\n    flex: 1,\n    padding: 24,\n    backgroundColor: \"grey\",\n  },\n  sheetContainer: {\n    // add horizontal space\n    marginHorizontal: 24,\n  },\n  contentContainer: {\n    flex: 1,\n    alignItems: \"center\",\n  },\n});\n\nexport default App;\n```\n"
  },
  {
    "path": "website/docs/guides/dynamic-sizing.mdx",
    "content": "---\nid: dynamic-sizing\ntitle: Dynamic Sizing\nsidebar_label: ⭐️ Dynamic Sizing\ndescription: Bottom Sheet dynamic sizing.\nimage: /img/bottom-sheet-preview.gif\nslug: /dynamic-sizing\nhide_table_of_contents: true\n---\n\nDynamic Sizing is one of the powerful feature that `v5` introduces, where the library internally managed to calculate static views and list content size height and set it as the bottom sheet content height.\n\n:::info\n\nThe mechanism was introduce previously with [useBottomSheetDynamicSnapPoints](https://gorhom.dev/react-native-bottom-sheet/v4/hooks#usebottomsheetdynamicsnappoints) hook which been deprecated with the new release.\n\n:::\n\nimport useBaseUrl from \"@docusaurus/useBaseUrl\";\nimport Video from \"@theme/Video\";\n\n<Video\n  title=\"React Native Bottom Sheet Dynamic Sizing\"\n  url={useBaseUrl(\"video/bottom-sheet-dynamic-sizing-preview.mp4\")}\n/>\n\n### Usage \n\nIn order to enable the dynamic sizing to work properly, you would need to follow these rules:\n\n1. Use the pre-configured [Scrollables](./scrollables) views, including the static view [BottomSheetView](./components/bottomsheetview).\n2. In order to prevent the bottom sheet a exceeding certain height, you will need to set [`maxDynamicContentSize`](./props#maxdynamiccontentsize) prop.\n\nAnd remember, you can always disable the feature if its not needed by overriding the prop [`enableDynamicSizing`](./props#enabledynamicsizing) with `false`.\n\n"
  },
  {
    "path": "website/docs/guides/keyboard-handling.mdx",
    "content": "---\nid: keyboard-handling\ntitle: Keyboard Handling\ndescription: Keyboard handling with Bottom Sheet.\nimage: /img/bottom-sheet-preview.gif\nslug: /keyboard-handling\nhide_table_of_contents: true\n---\n\nKeyboard handling is one of the main feature of `BottomSheet v4`, thanks to the effort of the community to spot issues, test and help to debug the implementation on both platform `iOS` & `Android`.\n\nTo handle the keyboard appearance, I have simplified the approach by creating a pre-integrated `TextInput` called [BottomSheetTextInput](./components/bottomsheettextinput), which communicate internally to react to the keyboard appearance.\n\nAlso I have introduce two props to allow users to customize the handling, [keyboardBehavior](./props#keyboardbehavior), [keyboardBlurBehavior](./props#keyboardblurbehavior), [enableBlurKeyboardOnGesture](./props#enableblurkeyboardongesture) and [android_keyboardInputMode](./props#android_keyboardinputmode) that is only for `Android`.\n\n:::tip\nTo use custom `TextInput`, you will need to copy the `handleOnFocus` and `handleOnBlur` from [BottomSheetTextInput](https://github.com/gorhom/react-native-bottom-sheet/blob/master/src/components/bottomSheetTextInput/BottomSheetTextInput.tsx) into your own component.\n:::\n\n### Example\n\nimport useBaseUrl from \"@docusaurus/useBaseUrl\";\nimport Video from \"@theme/Video\";\n\n<Video\n  title=\"React Native Bottom Sheet Keyboard Handling\"\n  url={useBaseUrl(\"video/bottom-sheet-keyboard-handling-preview.mp4\")}\n/>\n\nHere is an example of a simple keyboard handling:\n\n```tsx\nimport React, { useMemo } from \"react\";\nimport { View, StyleSheet } from \"react-native\";\nimport BottomSheet, { BottomSheetTextInput } from \"@gorhom/bottom-sheet\";\n\nconst App = () => {\n  // variables\n  const snapPoints = useMemo(() => [\"25%\"], []);\n\n  // renders\n  return (\n    <View style={styles.container}>\n      <BottomSheet snapPoints={snapPoints}>\n        <View style={styles.contentContainer}>\n          <BottomSheetTextInput value=\"Awesome 🎉\" style={styles.textInput} />\n        </View>\n      </BottomSheet>\n    </View>\n  );\n};\n\nconst styles = StyleSheet.create({\n  container: {\n    flex: 1,\n    padding: 24,\n    backgroundColor: \"grey\",\n  },\n  textInput: {\n    alignSelf: \"stretch\",\n    marginHorizontal: 12,\n    marginBottom: 12,\n    padding: 12,\n    borderRadius: 12,\n    backgroundColor: \"grey\",\n    color: \"white\",\n    textAlign: \"center\",\n  },\n  contentContainer: {\n    flex: 1,\n    alignItems: \"center\",\n  },\n});\n\nexport default App;\n```\n"
  },
  {
    "path": "website/docs/guides/pull-to-refresh.mdx",
    "content": "---\nid: pull-to-refresh\ntitle: Pull To Refresh\ndescription: Pull To Refresh with Bottom Sheet.\nimage: /img/bottom-sheet-preview.gif\nslug: /pull-to-refresh\nhide_table_of_contents: true\n---\n\nPull to refresh feature is enabled by default, and it will be activated on the top snap point provided. All you need to do is to provide `refreshing` & `onRefresh` to any of the [Scrollables](./scrollables).\n\n:::note\n\nCurrently `refreshControl` is not supported, feel free to contribute to enable it ❤️\n\n:::\n\n### Example\n\nimport useBaseUrl from \"@docusaurus/useBaseUrl\";\nimport Video from \"@theme/Video\";\n\n<Video\n  title=\"React Native Bottom Sheet Pull to Refresh\"\n  url={useBaseUrl(\"video/bottom-sheet-pull-to-refresh-preview.mp4\")}\n/>\n\nHere is an example of a simple pull to refresh:\n\n```tsx\nimport React, { useCallback, useMemo } from \"react\";\nimport { StyleSheet, View, Text } from \"react-native\";\nimport BottomSheet, { BottomSheetFlatList } from \"@gorhom/bottom-sheet\";\n\nconst App = () => {\n  // variables\n  const data = useMemo(\n    () =>\n      Array(50)\n        .fill(0)\n        .map((_, index) => `index-${index}`),\n    []\n  );\n  const snapPoints = useMemo(() => [\"25%\", \"50%\"], []);\n\n  // callbacks\n  const handleRefresh = useCallback(() => {\n    console.log(\"handleRefresh\");\n  }, []);\n\n  // render\n  const renderItem = useCallback(\n    ({ item }) => (\n      <View style={styles.itemContainer}>\n        <Text>{item}</Text>\n      </View>\n    ),\n    []\n  );\n  return (\n    <View style={styles.container}>\n      <BottomSheet snapPoints={snapPoints}>\n        <BottomSheetFlatList\n          data={data}\n          keyExtractor={(i) => i}\n          renderItem={renderItem}\n          contentContainerStyle={styles.contentContainer}\n          refreshing={false}\n          onRefresh={handleRefresh}\n        />\n      </BottomSheet>\n    </View>\n  );\n};\n\nconst styles = StyleSheet.create({\n  container: {\n    flex: 1,\n  },\n  contentContainer: {\n    backgroundColor: \"white\",\n  },\n  itemContainer: {\n    padding: 6,\n    margin: 6,\n    backgroundColor: \"#eee\",\n  },\n});\n\nexport default App;\n```\n"
  },
  {
    "path": "website/docs/guides/react-navigation.md",
    "content": "---\nid: react-navigation-integration\ntitle: React Navigation Integration\ndescription: Bottom Sheet React Navigation integration.\nimage: /img/bottom-sheet-preview.gif\nslug: /react-navigation-integration\nhide_table_of_contents: true\n---\n\nOne of the main goal of this library, is to allow user to fully integrate a stack navigator in the bottom sheet. This integration allows lots of opportunities for a native-like experience in your app 😇\n\nHowever, there are some tricks has to be follow to enable both libraries to work together seamlessly.\n\n- You need to override `safeAreaInsets`, by default `React Navigation` add the safe area insets to all its navigators, but since your navigator will properly won't cover full screen, you will need to override it and set it to `0`.\n\nFor more details regarding the implementation, please have a look at the [Navigator Example](https://github.com/gorhom/react-native-bottom-sheet/blob/master/example/src/screens/integrations/navigation/NavigatorExample.tsx)\n).\n"
  },
  {
    "path": "website/docs/guides/web-support.mdx",
    "content": "---\nid: web-support\ntitle: Web Support\nsidebar_label: ⭐️ Web Support\ndescription: Bottom Sheet web support.\nimage: /img/bottom-sheet-preview.gif\nslug: /web-support\nhide_table_of_contents: true\n---\n\nSupporting Web has been on my list since day 0 ([issue #11](https://github.com/gorhom/react-native-bottom-sheet/issues/11)), but unfortunately was not a priority until the community start adopting solutions such as [Expo Web](https://docs.expo.dev/workflow/web/), which also provided an easier development setup for me to kick off the development.\n\nWith **v5** release, users will be able to use the library in web mobile without changing the API 🪄.\n\n\nimport useBaseUrl from \"@docusaurus/useBaseUrl\";\nimport Video from \"@theme/Video\";\n\n<Video\n  title=\"React Native Bottom Sheet Web Support\"\n  url={useBaseUrl(\"video/bottom-sheet-web-support-preview.mp4\")}\n/>\n\n### Setup \n\nIn order to use the bottom sheet on web, you would need to follow the instructions from [Reanimated documentation](https://docs.swmansion.com/react-native-reanimated/docs/guides/web-support/)."
  },
  {
    "path": "website/docs/hooks.md",
    "content": "---\nid: hooks\ntitle: Hooks\ndescription: Bottom Sheet hooks.\nimage: /img/bottom-sheet-preview.gif\nslug: /hooks\n---\n\n## useBottomSheet\n\nThis hook provides all the bottom sheet public [methods](methods) and `animatedIndex` & `animatedPosition`, to the internal sheet content or handle.\n\n:::info\n\nThis hook works at any component inside the `BottomSheet`.\n\n:::\n\n```tsx\nimport React from 'react';\nimport { View, Button } from 'react-native';\nimport { useBottomSheet } from '@gorhom/bottom-sheet';\n\nconst SheetContent = () => {\n  const { expand } = useBottomSheet();\n\n  return (\n    <View>\n      <Button onPress={expand}>\n    </View>\n  )\n}\n```\n\n## useBottomSheetSpringConfigs\n\nGenerate animation spring configs.\n\n```tsx\nimport React from 'react';\nimport BottomSheet, { useBottomSheetSpringConfigs } from '@gorhom/bottom-sheet';\n\nconst SheetContent = () => {\n\n  const animationConfigs = useBottomSheetSpringConfigs({\n    damping: 80,\n    overshootClamping: true,\n    restDisplacementThreshold: 0.1,\n    restSpeedThreshold: 0.1,\n    stiffness: 500,\n  });\n\n  return (\n    <BottomSheet\n      // ... other props\n      animationConfigs={animationConfigs}\n    >\n      {CONTENT HERE}\n    </BottomSheet>\n  )\n}\n```\n\n## useBottomSheetTimingConfigs\n\nGenerate animation timing configs.\n\n```tsx\nimport React from 'react';\nimport BottomSheet, { useBottomSheetTimingConfigs } from '@gorhom/bottom-sheet';\nimport { Easing } from 'react-native-reanimated';\n\nconst SheetContent = () => {\n\n  const animationConfigs = useBottomSheetTimingConfigs({\n    duration: 250,\n    easing: Easing.exp,\n  });\n\n  return (\n    <BottomSheet\n      // ... other props\n      animationConfigs={animationConfigs}\n    >\n      {CONTENT HERE}\n    </BottomSheet>\n  )\n}\n```\n\n## useBottomSheetScrollableCreator\n\nA custom hook that creates a scrollable component for third-party libraries like `LegendList` or `FlashList` to integrate the interaction and scrolling behaviors with th BottomSheet component.\n\n```tsx\nimport React from 'react';\nimport BottomSheet, { useBottomSheetScrollableCreator } from '@gorhom/bottom-sheet';\nimport { LegendList } from '@legendapp/list';\n\nconst SheetContent = () => {\n  const BottomSheetScrollable = useBottomSheetScrollableCreator();\n  return (\n    <BottomSheet>\n      <LegendList\n        {...}\n        renderScrollComponent={BottomSheetLegendListScrollable}\n      />\n    </BottomSheet>\n  )\n}\n```\n"
  },
  {
    "path": "website/docs/index.md",
    "content": "---\nid: index\ntitle: Bottom Sheet\nhide_title: true\nsidebar_label: Bottom Sheet\ndescription: A performant interactive bottom sheet with fully configurable options 🚀\nimage: /img/bottom-sheet-preview.gif\nslug: /\n---\n\n<head>\n  <title>React Native Bottom Sheet</title>\n</head>\n\n# React Native Bottom Sheet\n\n[![Reanimated v3 version](https://img.shields.io/github/package-json/v/gorhom/react-native-bottom-sheet/master?label=Reanimated%20v3&style=flat-square)](https://www.npmjs.com/package/@gorhom/bottom-sheet) [![Reanimated v2 version](https://img.shields.io/github/package-json/v/gorhom/react-native-bottom-sheet/v4?label=Reanimated%20v2&style=flat-square)](https://www.npmjs.com/package/@gorhom/bottom-sheet)  [![Reanimated v1 version](https://img.shields.io/github/package-json/v/gorhom/react-native-bottom-sheet/v2?label=Reanimated%20v1&style=flat-square)](https://www.npmjs.com/package/@gorhom/bottom-sheet)<br />\n[![license](https://img.shields.io/npm/l/@gorhom/bottom-sheet?style=flat-square)](https://www.npmjs.com/package/@gorhom/bottom-sheet) [![npm](https://img.shields.io/badge/types-included-blue?style=flat-square)](https://www.npmjs.com/package/@gorhom/bottom-sheet) [![runs with expo](https://img.shields.io/badge/Runs%20with%20Expo-4630EB.svg?style=flat-square&logo=EXPO&labelColor=f3f3f3&logoColor=000)](https://expo.io/) <br /> ![NPM Downloads](https://img.shields.io/npm/dw/%40gorhom%2Fbottom-sheet?style=flat-square)\n\nA performant interactive bottom sheet with fully configurable options 🚀\n\nimport useBaseUrl from \"@docusaurus/useBaseUrl\";\nimport Video from \"@theme/Video\";\n\n<Video\n\ttitle=\"React Native Bottom Sheet\"\n\turl={useBaseUrl(\"video/bottom-sheet-preview.mp4\")}\n\timg={useBaseUrl(\"img/bottom-sheet-preview.gif\")}\n/>\n\n## Features\n\n- ⭐️ Support React Native Web, [read more](./web-support).\n- ⭐️ Dynamic Sizing, [read more](./dynamic-sizing).\n- ⭐️ Support FlashList, [read more](./components/bottomsheetflashlist).\n- Modal presentation view, [Bottom Sheet Modal](./modal).\n- Smooth gesture interactions & snapping animations.\n- Seamless [keyboard handling](./keyboard-handling) for iOS & Android.\n- Support [pull to refresh](./pull-to-refresh) for scrollables.\n- Support `FlatList`, `SectionList`, `ScrollView` & `View` scrolling interactions, [read more](./scrollables).\n- Support `React Navigation` Integration, [read more](./react-navigation-integration).\n- Compatible with `Reanimated` v1-3.\n- Accessibility support.\n- Written in `TypeScript`.\n\n## Installation\n\n```bash\nyarn add @gorhom/bottom-sheet@^5\n```\n\n#### Dependencies\n\nThis library needs these dependencies to be installed in your project before you can use it:\n\n```bash\nyarn add react-native-reanimated react-native-gesture-handler\n```\n\nUsing Expo?\n\n```bash\nnpx expo install react-native-reanimated react-native-gesture-handler\n```\n\n:::info\n**React Native Gesture Handler v2** needs extra steps to finalize its installation, please follow their [installation instructions](https://docs.swmansion.com/react-native-gesture-handler/docs/fundamentals/installation). Please **make sure** to wrap your App with `GestureHandlerRootView` when you've upgraded to React Native Gesture Handler ^2.\n\n**React Native Reanimated v3** needs extra steps to finalize its installation, please follow their [installation instructions](https://docs.swmansion.com/react-native-reanimated/docs/fundamentals/getting-started).\n:::\n\n## Sponsor & Support\n\nTo keep this library maintained and up-to-date please consider [sponsoring it on GitHub](https://github.com/sponsors/gorhom). Or if you are looking for a private support or help in customizing the experience, then reach out to me on Twitter [@gorhom](https://twitter.com/gorhom).\n\n## Built With ❤️\n\n- [react-native-reanimated](https://github.com/software-mansion/react-native-reanimated)\n- [react-native-gesture-handler](https://github.com/software-mansion/react-native-gesture-handler)\n- [react-native-builder-bob](https://github.com/callstack/react-native-builder-bob)\n"
  },
  {
    "path": "website/docs/methods.md",
    "content": "---\nid: methods\ntitle: Methods\ndescription: Bottom Sheet methods.\nimage: /img/bottom-sheet-preview.gif\nslug: /methods\n---\n\nThese methods are accessible using the bottom sheet reference or the hook `useBottomSheet` or `useBottomSheetModal`.\n\n```tsx\nimport React, { useRef } from 'react';\nimport { Button } from 'react-native';\nimport BottomSheet from '@gorhom/bottom-sheet';\n\nconst App = () => {\n  const bottomSheetRef = useRef<BottomSheet>(null);\n\n  const handleClosePress = () => bottomSheetRef.current.close()\n\n  return (\n    <>\n      <Button title=\"Close Sheet\" onPress={handleClosePress} />\n      <BottomSheet ref={bottomSheetRef}>\n    </>\n  )\n}\n\n```\n\n### snapToIndex\n\nSnap to one of the provided points from `snapPoints`.\n\n```ts\ntype snapToIndex = (\n  // snap point index.\n  index: number,\n  // snap animation configs\n  animationConfigs?: Animated.WithSpringConfig | Animated.WithTimingConfig\n) => void;\n```\n\n### snapToPosition\n\nSnap to a position out of provided `snapPoints`.\n\n```ts\ntype snapToPosition = (\n  // position in pixel or percentage.\n  position: number,\n  // snap animation configs\n  animationConfigs?: Animated.WithSpringConfig | Animated.WithTimingConfig\n) => void;\n```\n\n### expand\n\nSnap to the maximum provided point from `snapPoints`.\n\n```ts\ntype expand = (\n  // snap animation configs\n  animationConfigs?: Animated.WithSpringConfig | Animated.WithTimingConfig\n) => void;\n```\n\n### collapse\n\nSnap to the minimum provided point from `snapPoints`.\n\n```ts\ntype collapse = (\n  // snap animation configs\n  animationConfigs?: Animated.WithSpringConfig | Animated.WithTimingConfig\n) => void;\n```\n\n### close\n\nClose the bottom sheet.\n\n```ts\ntype close = (\n  // snap animation configs\n  animationConfigs?: Animated.WithSpringConfig | Animated.WithTimingConfig\n) => void;\n```\n\n### forceClose\n\nForce close the bottom sheet, this prevent any interruptions till the sheet is closed.\n\n```ts\ntype forceClose = (\n  // snap animation configs\n  animationConfigs?: Animated.WithSpringConfig | Animated.WithTimingConfig\n) => void;\n```\n"
  },
  {
    "path": "website/docs/modal/hooks.md",
    "content": "---\nid: hooks\ntitle: Hooks\ndescription: Bottom Sheet modal hooks.\nimage: /img/bottom-sheet-preview.gif\nslug: /modal/hooks\n---\n\n## useBottomSheetModal\n\nThis hook provides modal functionalities only, for sheet functionalities please look at [Bottom Sheet Hooks](../hooks).\n\n> This hook works at any component in `BottomSheetModalProvider`.\n\n```tsx\nimport React from 'react';\nimport { View, Button } from 'react-native';\nimport { useBottomSheetModal } from '@gorhom/bottom-sheet';\n\nconst SheetContent = () => {\n  const { dismiss, dismissAll } = useBottomSheetModal();\n\n  return (\n    <View>\n      <Button onPress={dismiss}>\n    </View>\n  )\n}\n```\n\n## dismiss\n\n```ts\ntype dismiss = (key?: string) => void;\n```\n\nDismiss a modal by its name/key, if key is not provided, then it will dismiss the last presented modal.\n\n## dismissAll\n\n```ts\ntype dismissAll = () => void;\n```\n\nDismiss all mounted/presented modals.\n"
  },
  {
    "path": "website/docs/modal/index.mdx",
    "content": "---\nid: index\ntitle: Modal\nsidebar_label: Modal\ndescription: A performant interactive bottom sheet modal with fully configurable options 🚀\nimage: /img/bottom-sheet-modal-preview.gif\nslug: /modal\n---\n\n# React Native Bottom Sheet Modal\n\nimport useBaseUrl from '@docusaurus/useBaseUrl';\nimport Video from '@theme/Video';\n\n<Video\n  title=\"React Native Bottom Sheet Modal\"\n  url={useBaseUrl('video/bottom-sheet-modal-preview.mp4')}\n/>\n\n**Bottom Sheet Modal** is wrapper/decorator on top of the **Bottom Sheet**, it provides all of its functionalities with extra modal presentation functionalities.\n\nWith the release of the library, support for stack sheet modals were something planned ahead to provide the a native feel & and experience to users.\n\nThe implementation of this feature was inspired by Apple Maps sheet modals ❤️, [check out the Apple Map sheet modals clone](https://github.com/gorhom/react-native-bottom-sheet/blob/master/example/src/screens/integrations/map/MapExample.tsx).\n\n## Features\n\n- ...[Bottom Sheet Features](./#features)\n- Smooth interaction and mounting animation.\n- Support stack sheet modals.\n\n## Installation\n\nThis feature is already shipped with `@gorhom/bottom-sheet` package and it requires no extra dependency.\n"
  },
  {
    "path": "website/docs/modal/methods.md",
    "content": "---\nid: methods\ntitle: Methods\ndescription: Bottom Sheet modal methods.\nimage: /img/bottom-sheet-preview.gif\nslug: /modal/methods\n---\n\n**Bottom Sheet Modal** inherits all [**Bottom Sheet** methods](../methods) and also it introduces its own methods.\n\nThese methods are accessible using the bottom sheet modal reference:\n\n```tsx\nimport React, { useRef } from 'react';\nimport {BottomSheetModal} from '@gorhom/bottom-sheet';\n\nconst App = () => {\n  const bottomSheetModalRef = useRef<BottomSheetModal>(null);\n  const handlePresentPress = () => bottomSheetModalRef.current.present()\n  return (\n    <>\n      <Button title=\"Present Sheet\" onPress={handlePresentPress} />\n      <BottomSheetModal ref={bottomSheetModalRef}>\n    </>\n  )\n}\n\n```\n\n### present\n\nMount and present the bottom sheet modal to the initial snap point.\n\n```ts\ntype present = (\n  // Data to be passed to the modal.\n  data?: any\n) => void;\n```\n\n### dismiss\n\nClose and unmount the bottom sheet modal.\n\n```ts\ntype dismiss = (\n  // AnimationConfigs snap animation configs.\n  animationConfigs?: WithSpringConfig | WithTimingConfig\n) => void;\n```\n"
  },
  {
    "path": "website/docs/modal/props.md",
    "content": "---\nid: props\ntitle: Props\ndescription: Bottom Sheet modal configurable props.\nimage: /img/bottom-sheet-preview.gif\nslug: /modal/props\n---\n\n**Bottom Sheet Modal** inherits all [**Bottom Sheet** props](../props) except for `animateOnMount` & `containerHeight` and also it introduces its own props:\n\n## Configuration\n\n### name\n\nModal name to help identify the modal for later on.\n\n| type   | default                | required |\n| ------ | ---------------------- | -------- |\n| string | `generated unique key` | NO       |\n\n### stackBehavior\n\n**`Available only on v3, for now.`**\n\nDefines the stack behavior when modal mounts.\n\n- `push` it will mount the modal on top of the current one.\n- `switch` it will minimize the current modal then mount the new one.\n- `replace` it will dismiss the current modal then mount the new one.\n\n| type                | default   | required |\n| ------------------- | --------- | -------- |\n| 'push' \\| 'switch' \\| 'replace' | 'switch' | NO       |\n\n### enableDismissOnClose\n\nDismiss the modal when it is closed, this will unmount the modal.\n\n| type    | default | required |\n| ------- | ------- | -------- |\n| boolean | true    | NO       |\n\n## Callbacks\n\n### onDismiss\n\nCallback when the modal dismissed (unmounted).\n\n```ts\ntype onDismiss = () => void;\n```\n\n| type     | default | required |\n| -------- | ------- | -------- |\n| function | null    | NO       |\n\n## Components\n\n### containerComponent\n\nComponent to be placed as a bottom sheet container, this is to place\nthe bottom sheet at the very top layer of your application when using `FullWindowOverlay`\nfrom `React Native Screens`. [read more](https://github.com/gorhom/react-native-bottom-sheet/issues/832)\n\n| type            | default   | required |\n| --------------- | --------- | -------- |\n| React.ReactNode | undefined | NO       |\n"
  },
  {
    "path": "website/docs/modal/usage.md",
    "content": "---\nid: usage\ntitle: Usage\ndescription: Bottom Sheet modal usage.\nimage: /img/bottom-sheet-preview.gif\nslug: /modal/usage\n---\n\nHere is a simple usage of the **Bottom Sheet Modal**, with non-scrollable content. For more scrollable usage please read [Scrollables](../scrollables).\n\n```tsx\nimport React, { useCallback, useMemo, useRef } from 'react';\nimport { View, Text, StyleSheet, Button } from 'react-native';\nimport { GestureHandlerRootView } from 'react-native-gesture-handler';\nimport {\n  BottomSheetModal,\n  BottomSheetView,\n  BottomSheetModalProvider,\n} from '@gorhom/bottom-sheet';\n\nconst App = () => {\n  // ref\n  const bottomSheetModalRef = useRef<BottomSheetModal>(null);\n\n  // callbacks\n  const handlePresentModalPress = useCallback(() => {\n    bottomSheetModalRef.current?.present();\n  }, []);\n  const handleSheetChanges = useCallback((index: number) => {\n    console.log('handleSheetChanges', index);\n  }, []);\n\n  // renders\n  return (\n      <GestureHandlerRootView style={styles.container}>\n        <BottomSheetModalProvider>\n          <Button\n            onPress={handlePresentModalPress}\n            title=\"Present Modal\"\n            color=\"black\"\n          />\n          <BottomSheetModal\n            ref={bottomSheetModalRef}\n            onChange={handleSheetChanges}\n          >\n            <BottomSheetView style={styles.contentContainer}>\n              <Text>Awesome 🎉</Text>\n            </BottomSheetView>\n        </BottomSheetModal>\n        </BottomSheetModalProvider>\n    </GestureHandlerRootView>\n  );\n};\n\nconst styles = StyleSheet.create({\n  container: {\n    flex: 1,\n    padding: 24,\n    justifyContent: 'center',\n    backgroundColor: 'grey',\n  },\n  contentContainer: {\n    flex: 1,\n    alignItems: 'center',\n  },\n});\n\nexport default App;\n```\n"
  },
  {
    "path": "website/docs/props.md",
    "content": "---\nid: props\ntitle: Props\ndescription: Bottom Sheet configurable props.\nimage: /img/bottom-sheet-preview.gif\nslug: /props\n---\n\n## Configuration\n\n### index\n\nInitial snap index. You also could provide `-1` to initiate bottom sheet in closed state.\n\n| type   | default | required |\n| ------ | ------- | -------- |\n| number | 0       | NO       |\n\n### snapPoints\n\nPoints for the bottom sheet to snap to, **points should be sorted from bottom to top**. It accepts array of number, string or mix.\n\n| type                                                          | required |\n| ------------------------------------------------------------- | -------- |\n| Array\\<number\\|string> \\| SharedValue\\<Array\\<string \\| number>> | YES\\*    |\n\n:::caution\nThis prop is required if you set `enableDynamicSizing` to `false` (it's `true` by default). \n:::\n:::caution\nString values should be a percentage.\n:::\n\n#### examples\n\n```ts\nsnapPoints={[200, 500]}\nsnapPoints={[200, '50%']}\nsnapPoints={['100%']}\n```\n\n### overDragResistanceFactor\n\nDefines how violently sheet has to be stopped while over dragging.\n\n| type   | default | required |\n| ------ | ------- | -------- |\n| number | 2.5     | NO       |\n\n### detached\n\nDefines whether the bottom sheet is attached to the bottom or no.\n\n| type    | default | required |\n| ------- | ------- | -------- |\n| boolean | false   | NO       |\n\n### enableContentPanningGesture\n\nEnable content panning gesture interaction.\n\n| type    | default | required |\n| ------- | ------- | -------- |\n| boolean | true    | NO       |\n\n### enableHandlePanningGesture\n\nEnable handle panning gesture interaction.\n\n| type    | default | required |\n| ------- | ------- | -------- |\n| boolean | true    | NO       |\n\n### enableOverDrag\n\nEnable over drag for the sheet.\n\n| type    | default | required |\n| ------- | ------- | -------- |\n| boolean | true    | NO       |\n\n### enablePanDownToClose\n\nEnable pan down gesture to close the sheet.\n\n| type    | default | required |\n| ------- | ------- | -------- |\n| boolean | false   | NO       |\n\n### enableDynamicSizing\n\nEnable dynamic sizing for content view and scrollable content size.\n\n| type    | default | required |\n| ------- | ------- | -------- |\n| boolean | true    | NO       |\n\n:::caution\n\nSetting this prop to `true`, will result in adding a new snap point to the provided snap points and will be sorted accordingly, and this might effect the indexing, for example, if provided snap points are `[100, 1000]`, and the content size is `500` then the final snap points will be `[100, 500, 1000]`.\n\n:::\n\n### animateOnMount\n\nThis will initially mount the sheet closed and when it's mounted and calculated the layout, it will snap to initial snap point index.\n\n| type    | default | required |\n| ------- | ------- | -------- |\n| boolean | true    | NO       |\n\n### overrideReduceMotion\n\nTo override the user reduce motion accessibility setting, [read more](https://docs.swmansion.com/react-native-reanimated/docs/guides/accessibility).\n\n- `ReduceMotion.System`: if the `Reduce motion` accessibility setting is enabled on the device, disable the animation.\n- `ReduceMotion.Always`: disable the animation, even if `Reduce motion` accessibility setting is not enabled.\n- `ReduceMotion.Never`: enable the animation, even if `Reduce motion` accessibility setting is enabled.\n\n| type    | default | required |\n| ------- | ------- | -------- |\n| ReduceMotion | ReduceMotion.System    | NO       |\n\n## Styles\n\n### style\n\nView style to be applied at the sheet container, it also could be an `AnimatedStyle`. This is helpful to add shadow to the sheet.\n\n| type                       | default   | required |\n| -------------------------- | --------- | -------- |\n| ViewStyle \\| AnimatedStyle | undefined | NO       |\n\n### backgroundStyle\n\nView style to be applied to the background component.\n\n| type      | default   | required |\n| --------- | --------- | -------- |\n| ViewStyle | undefined | NO       |\n\n### handleStyle\n\nView style to be applied to the handle component.\n\n| type      | default   | required |\n| --------- | --------- | -------- |\n| ViewStyle | undefined | NO       |\n\n### handleIndicatorStyle\n\nView style to be applied to the handle indicator component.\n\n| type      | default   | required |\n| --------- | --------- | -------- |\n| ViewStyle | undefined | NO       |\n\n## Layout Configuration\n\n### handleHeight\n\nHandle height helps to calculate the internal container and sheet layouts. If `handleComponent` is provided, the library internally will calculate its layout, unless `handleHeight` is provided too.\n\n| type   | default | required |\n| ------ | ------- | -------- |\n| number | 24      | NO       |\n\n### containerHeight\n\nContainer height helps to calculate the internal sheet layouts. If `containerHeight` not provided, the library internally will calculate it, however this will cause an extra re-rendering.\n\n| type   | default | required |\n| ------ | ------- | -------- |\n| number | 0       | NO       |\n\n### contentHeight\n\nContent height helps dynamic snap points calculation.\n\n| type                                    | default   | required |\n| --------------------------------------- | --------- | -------- |\n| number \\| Animated.SharedValue\\<number\\> | undefined | NO       |\n\n### containerOffset\n\nContainer offset helps to accurately detect container offsets.\n\n| type                          | default   | required |\n| ----------------------------- | --------- | -------- |\n| Animated.SharedValue\\<Insets\\> | undefined | NO       |\n\n### topInset\n\nTop inset to be added to the bottom sheet container, usually it comes from `@react-navigation/stack` hook `useHeaderHeight` or from `react-native-safe-area-context` hook `useSafeArea`.\n\n| type   | default | required |\n| ------ | ------- | -------- |\n| number | 0       | NO       |\n\n### bottomInset\n\nBottom inset to be added to the bottom sheet container.\n\n| type   | default | required |\n| ------ | ------- | -------- |\n| number | 0       | NO       |\n\n### maxDynamicContentSize\n\nMax dynamic content size height to limit the bottom sheet height from exceeding a provided size.\n\n| type   | default          | required |\n| ------ | ---------------- | -------- |\n| number | container height | NO       |\n\n## Keyboard Configuration\n\n### keyboardBehavior\n\nDefines the keyboard appearance behavior.\n\n- `extend`: extend the sheet to its maximum snap point.\n- `fillParent`: extend the sheet to fill the parent view.\n- `interactive`: offset the sheet by the size of the keyboard.\n\n| type                                      | default       | required |\n| ----------------------------------------- | ------------- | -------- |\n| 'extend' \\| 'fillParent' \\| 'interactive' | 'interactive' | NO       |\n\n### keyboardBlurBehavior\n\nDefines the keyboard blur behavior.\n\n- `none`: do nothing.\n- `restore`: restore sheet position.\n\n| type                | default | required |\n| ------------------- | ------- | -------- |\n| 'none' \\| 'restore' | 'none'  | NO       |\n\n### enableBlurKeyboardOnGesture\n\nEnable blurring the keyboard when user start to drag the bottom sheet.\n\n| type    | default | required |\n| ------- | ------- | -------- |\n| boolean | false    | NO       |\n\n### android_keyboardInputMode\n\nDefines keyboard input mode for `Android` only, [learn more](https://developer.android.com/guide/topics/manifest/activity-element#wsoft).\n\n| type                          | default     | required |\n| ----------------------------- | ----------- | -------- |\n| 'adjustPan' \\| 'adjustResize' | 'adjustPan' | NO       |\n\n## Animation Configuration\n\n### animationConfigs\n\nAnimation configs, this could be created by:\n\n- [`useBottomSheetSpringConfigs`](./hooks#usebottomsheetspringconfigs)\n- [`useBottomSheetTimingConfigs`](./hooks#usebottomsheettimingconfigs)\n\n```ts\ntype animationConfigs = (\n\tpoint: number,\n\tvelocity: number,\n\tcallback: () => void\n) => number;\n```\n\n| type     | default   | required |\n| -------- | --------- | -------- |\n| function | undefined | NO       |\n\n## Gesture Configuration\n\n### waitFor\n\n[Read about `waitFor`](https://docs.swmansion.com/react-native-gesture-handler/docs/handler-common#waitfor).\n\n| type                     | default | required |\n| ------------------------ | ------- | -------- |\n| React.Ref \\| React.Ref[] | []      | NO       |\n\n### simultaneousHandlers\n\n[Read about `simultaneousHandlers`](https://docs.swmansion.com/react-native-gesture-handler/docs/handler-common#simultaneoushandlers).\n\n| type                     | default | required |\n| ------------------------ | ------- | -------- |\n| React.Ref \\| React.Ref[] | []      | NO       |\n\n### activeOffsetX\n\n[Read about `activeOffsetX`](https://docs.swmansion.com/react-native-gesture-handler/docs/handler-pan#activeoffsetx).\n\n| type     | default   | required |\n| -------- | --------- | -------- |\n| number[] | undefined | NO       |\n\n### activeOffsetY\n\n[Read about `activeOffsetY`](https://docs.swmansion.com/react-native-gesture-handler/docs/handler-pan#activeoffsety).\n\n| type     | default   | required |\n| -------- | --------- | -------- |\n| number[] | undefined | NO       |\n\n### failOffsetX\n\n[Read about `failOffsetX`](https://docs.swmansion.com/react-native-gesture-handler/docs/handler-pan/#failoffsetx).\n\n| type     | default   | required |\n| -------- | --------- | -------- |\n| number[] | undefined | NO       |\n\n### failOffsetY\n\n[Read about `failOffsetY`](https://docs.swmansion.com/react-native-gesture-handler/docs/handler-pan/#failoffsety).\n\n| type     | default   | required |\n| -------- | --------- | -------- |\n| number[] | undefined | NO       |\n\n### gestureEventsHandlersHook\n\nCustom hook to provide pan gesture events handler, which will allow advance and customize handling for pan gesture.\n\n| type                          | default                         | required |\n| ----------------------------- | ------------------------------- | -------- |\n| GestureEventsHandlersHookType | useGestureEventsHandlersDefault | NO       |\n\n> warning: this is an experimental feature and the hook signature can change without a major version bump.\n\n## Animated Nodes\n\n### animatedIndex\n\nAnimated value to be used as a callback for the index node internally.\n\n| type                          | default | required |\n| ----------------------------- | ------- | -------- |\n| Animated.SharedValue\\<number\\> | null    | NO       |\n\n### animatedPosition\n\nAnimated value to be used as a callback for the position node internally.\n\n| type                          | default | required |\n| ----------------------------- | ------- | -------- |\n| Animated.SharedValue\\<number\\> | null    | NO       |\n\n## Callbacks\n\n### onChange\n\nCallback when the sheet position changed.\n\n```ts\ntype onChange = (index: number) => void;\n```\n\n| type     | default | required |\n| -------- | ------- | -------- |\n| function | null    | NO       |\n\n### onAnimate\n\nCallback when the sheet about to animate to a new position.\n\n```ts\ntype onAnimate = (fromIndex: number, toIndex: number, fromPosition: number, toPosition: number) => void;\n```\n\n| type     | default | required |\n| -------- | ------- | -------- |\n| function | null    | NO       |\n\n## Components\n\n### handleComponent\n\nComponent to be placed as a sheet handle.\n\n| type                               | default             | required |\n| ---------------------------------- | ------------------- | -------- |\n| `React.FC\\<BottomSheetHandleProps>` | `BottomSheetHandle` | NO       |\n\n### backdropComponent\n\nComponent to be placed as a sheet backdrop, by default is set to `null`, however the library also provide a default implementation `BottomSheetBackdrop` of a backdrop but you will need to provide it manually.\n\n| type                                   | default | required |\n| -------------------------------------- | ------- | -------- |\n| `React.FC\\<BottomSheetBackgroundProps>` | null    | NO       |\n\n### backgroundComponent\n\nComponent to be placed as a sheet background.\n\n| type                                   | default                 | required |\n| -------------------------------------- | ----------------------- | -------- |\n| `React.FC\\<BottomSheetBackgroundProps>` | `BottomSheetBackground` | NO       |\n\n### footerComponent\n\nComponent to be placed as a sheet footer.\n\n| type                               | default   | required |\n| ---------------------------------- | --------- | -------- |\n| `React.FC\\<BottomSheetFooterProps>` | undefined | NO       |\n\n### children\n\n`Scrollable` node or react node to be places as a sheet content.\n\n| type                                                          | default | required |\n| ------------------------------------------------------------- | ------- | -------- |\n| () => React.ReactNode \\| React.ReactNode[] \\| React.ReactNode | null    | YES      |\n"
  },
  {
    "path": "website/docs/scrollables.md",
    "content": "---\nid: scrollables\ntitle: Scrollables\ndescription: Bottom Sheet scrollables.\nimage: /img/bottom-sheet-preview.gif\nslug: /scrollables\n---\n\nThis library provides a pre-integrated virtualized lists that utilize an internal functionalities with the bottom sheet container to allow smooth panning interactions. These lists I called them Scrollables and they are:\n\n- [BottomSheetFlatList](./components/bottomsheetflatlist)\n- [BottomSheetSectionList](./components/bottomsheetsectionlist)\n- [BottomSheetScrollView](./components/bottomsheetscrollview)\n- [BottomSheetVirtualizedList](./components/bottomsheetvirtualizedlist)\n- [BottomSheetView](./components/bottomsheetview)\n"
  },
  {
    "path": "website/docs/troubleshooting.md",
    "content": "---\nid: troubleshooting\ntitle: Troubleshooting\ndescription: Bottom Sheet troubleshooting.\nimage: /img/bottom-sheet-preview.gif\nslug: /troubleshooting\nhide_table_of_contents: true\n---\n\nThis section attempts to outline issues that users frequently encounter when first getting accustomed to using React Native Bottom Sheet. These issues may or may not be related to React Native Bottom Sheet itself.\n\n## Pressables / Touchables are not working on Android\n\nDue to wrapping the content and handle with `TapGestureHandler` & `PanGestureHandler`, any gesture interaction would not function as expected.\n\nTo resolve this issue, please use touchables that this library provide.\n\n```tsx\nimport {\n  TouchableOpacity,\n  TouchableHighlight,\n  TouchableWithoutFeedback,\n} from '@gorhom/bottom-sheet';\n```\n\n## Adding horizontal FlatList or ScrollView is not working properly on Android\n\nDue to wrapping the content and handle with `TapGestureHandler` & `PanGestureHandler`, any gesture interaction would not function as expected.\n\nTo resolve this issue, please use `ScrollView` & `FlatList` from `react-native-gesture-handler` provide instead `react-native`.\n\n```tsx\nimport {\n  ScrollView,\n  FlatList\n} from 'react-native-gesture-handler';\n```\n\n## My component gesture interaction gets conflicted with Bottom Sheet interactions ?\n\nTo avoid the gesture interaction conflict between the Bottom Sheet and its content, you will need to wrap your component with `NativeViewGestureHandler` from `react-native-gesture-handler`\n\n```tsx\nimport { NativeViewGestureHandler } from 'react-native-gesture-handler';\n\n<NativeViewGestureHandler disallowInterruption={true}>\n   <AwesomeComponent />\n</NativeViewGestureHandler>\n```\n"
  },
  {
    "path": "website/docs/usage.md",
    "content": "---\nid: usage\ntitle: Usage\ndescription: Bottom Sheet usage.\nimage: /img/bottom-sheet-preview.gif\nslug: /usage\n---\n\nHere is a simple usage of the **Bottom Sheet**, with non-scrollable content. For more scrollable usage please read [Scrollables](./scrollables).\n\n```tsx\nimport React, { useCallback, useMemo, useRef } from 'react';\nimport { View, Text, StyleSheet } from 'react-native';\nimport { GestureHandlerRootView } from 'react-native-gesture-handler';\nimport BottomSheet, { BottomSheetView } from '@gorhom/bottom-sheet';\n\nconst App = () => {\n  // ref\n  const bottomSheetRef = useRef<BottomSheet>(null);\n\n  // callbacks\n  const handleSheetChanges = useCallback((index: number) => {\n    console.log('handleSheetChanges', index);\n  }, []);\n\n  // renders\n  return (\n    <GestureHandlerRootView style={styles.container}>\n      <BottomSheet\n        ref={bottomSheetRef}\n        onChange={handleSheetChanges}\n      >\n        <BottomSheetView style={styles.contentContainer}>\n          <Text>Awesome 🎉</Text>\n        </BottomSheetView>\n      </BottomSheet>\n    </GestureHandlerRootView>\n  );\n};\n\nconst styles = StyleSheet.create({\n  container: {\n    flex: 1,\n    backgroundColor: 'grey',\n  },\n  contentContainer: {\n    flex: 1,\n    padding: 36,\n    alignItems: 'center',\n  },\n});\n\nexport default App;\n```"
  },
  {
    "path": "website/docusaurus.config.ts",
    "content": "import type * as Preset from '@docusaurus/preset-classic';\nimport type { Config } from '@docusaurus/types';\nimport { themes as prismThemes } from 'prism-react-renderer';\n\nconst config: Config = {\n  title: 'React Native Bottom Sheet',\n  tagline:\n    'A performant interactive bottom sheet with fully configurable options 🚀',\n  favicon: 'img/favicon.ico',\n\n  // Set the production url of your site here\n  url: 'https://gorhom.github.io',\n  // Set the /<baseUrl>/ pathname under which your site is served\n  // For GitHub pages deployment, it is often '/<projectName>/'\n  baseUrl: '/react-native-bottom-sheet/',\n\n  organizationName: 'gorhom',\n  projectName: 'react-native-bottom-sheet',\n  trailingSlash: false,\n\n  onBrokenLinks: 'throw',\n  onBrokenMarkdownLinks: 'warn',\n\n  presets: [\n    [\n      '@gorhom/docusaurus-preset',\n      {\n        docs: {\n          sidebarPath: './sidebars.ts',\n          routeBasePath: '/',\n          editUrl:\n            'https://github.com/gorhom/react-native-bottom-sheet/tree/master/website/docs',\n          lastVersion: 'current',\n          versions: {\n            current: {\n              label: 'v5',\n            },\n            '4': {\n              label: 'v4 (Reanimated v2)',\n              path: 'v4',\n              noIndex: true,\n              badge: true,\n            },\n            '2': {\n              label: 'v2 (Reanimated v1)',\n              path: 'v2',\n              noIndex: true,\n              badge: true,\n            },\n          },\n        },\n        blog: {\n          showReadingTime: false,\n          feedOptions: {\n            type: ['rss', 'atom'],\n            xslt: true,\n          },\n          // Please change this to your repo.\n          // Remove this to remove the \"edit this page\" links.\n          editUrl:\n            'https://github.com/gorhom/react-native-bottom-sheet/tree/master/website/blog',\n          // Useful options to enforce blogging best practices\n          onInlineTags: 'warn',\n          onInlineAuthors: 'warn',\n          onUntruncatedBlogPosts: 'warn',\n        },\n        theme: {\n          customCss: './src/css/custom.css',\n        },\n        gtag: {\n          trackingID: 'G-VW3MQN4043',\n          anonymizeIP: true,\n        },\n      } satisfies Preset.Options,\n    ],\n  ],\n\n  themeConfig: {\n    // Replace with your project's social card\n    image: 'img/preview.gif',\n\n    colorMode: {\n      defaultMode: 'dark',\n      disableSwitch: false,\n      respectPrefersColorScheme: true,\n    },\n\n    navbar: {\n      title: 'React Native Bottom Sheet',\n      logo: {\n        alt: 'React Native Bottom Sheet',\n        src: 'img/logo.svg',\n      },\n      items: [\n        { to: '/blog', label: 'Blog', position: 'left' },\n\n        {\n          type: 'docsVersionDropdown',\n          position: 'right',\n          dropdownActiveClassDisabled: true,\n          docsPluginId: 'default',\n        },\n        {\n          href: 'https://github.com/gorhom/react-native-bottom-sheet',\n          label: 'GitHub',\n          position: 'right',\n        },\n      ],\n    },\n\n    footer: {\n      style: 'dark',\n    },\n\n    prism: {\n      theme: prismThemes.github,\n      darkTheme: prismThemes.dracula,\n    },\n\n    algolia: {\n      appId: 'V136OEODKA',\n      apiKey: '625bfb5db1f098c89ac0bc2387b83a72',\n      indexName: 'react-native-bottom-sheet',\n      contextualSearch: true,\n    },\n  } satisfies Preset.ThemeConfig,\n\n  future: {\n    experimental_faster: true,\n  },\n};\n\nexport default config;\n"
  },
  {
    "path": "website/package.json",
    "content": "{\n  \"name\": \"@gorhom/bottom-sheet-docs\",\n  \"version\": \"0.0.0\",\n  \"private\": true,\n  \"scripts\": {\n    \"docusaurus\": \"docusaurus\",\n    \"start\": \"docusaurus start\",\n    \"build\": \"docusaurus build\",\n    \"swizzle\": \"docusaurus swizzle\",\n    \"deploy\": \"docusaurus deploy\",\n    \"clear\": \"docusaurus clear\",\n    \"serve\": \"docusaurus serve\",\n    \"write-translations\": \"docusaurus write-translations\",\n    \"write-heading-ids\": \"docusaurus write-heading-ids\",\n    \"typecheck\": \"tsc\"\n  },\n  \"dependencies\": {\n    \"@docusaurus/core\": \"3.7.0\",\n    \"@docusaurus/faster\": \"3.7.0\",\n    \"@docusaurus/plugin-google-gtag\": \"3.7.0\",\n    \"@docusaurus/preset-classic\": \"3.7.0\",\n    \"@gorhom/docusaurus-preset\": \"1.1.0\",\n    \"@gorhom/docusaurus-theme\": \"1.1.0\",\n    \"@mdx-js/react\": \"^3.0.0\",\n    \"clsx\": \"^2.0.0\",\n    \"prism-react-renderer\": \"^2.3.0\",\n    \"react\": \"^19.0.0\",\n    \"react-dom\": \"^19.0.0\"\n  },\n  \"devDependencies\": {\n    \"@docusaurus/module-type-aliases\": \"3.7.0\",\n    \"@docusaurus/tsconfig\": \"3.7.0\",\n    \"@docusaurus/types\": \"3.7.0\",\n    \"typescript\": \"~5.5.2\"\n  },\n  \"browserslist\": {\n    \"production\": [\">0.5%\", \"not dead\", \"not op_mini all\"],\n    \"development\": [\n      \"last 3 chrome version\",\n      \"last 3 firefox version\",\n      \"last 5 safari version\"\n    ]\n  },\n  \"engines\": {\n    \"node\": \">=18.0\"\n  }\n}\n"
  },
  {
    "path": "website/sidebars.ts",
    "content": "import type { SidebarsConfig } from '@docusaurus/plugin-content-docs';\n\n/**\n * Creating a sidebar enables you to:\n - create an ordered group of docs\n - render a sidebar for each doc of that group\n - provide next/previous navigation\n\n The sidebars can be generated from the filesystem, or explicitly defined here.\n\n Create as many sidebars as you want.\n */\nconst sidebars: SidebarsConfig = {\n  // By default, Docusaurus generates a sidebar from the docs folder structure\n  // \"bottom-sheet\": [{ type: \"autogenerated\", dirName: \".\" }],\n\n  // But you can create a sidebar manually\n  'bottom-sheet': [\n    {\n      type: 'category',\n      label: 'Bottom Sheet',\n      link: {\n        type: 'doc',\n        id: 'index',\n      },\n      items: [\n        'usage',\n        'props',\n        'methods',\n        'hooks',\n        'scrollables',\n        {\n          type: 'category',\n          label: 'Components',\n          items: [\n            'components/bottomsheetview',\n            'components/bottomsheetscrollview',\n            'components/bottomsheetflatlist',\n            'components/bottomsheetflashlist',\n            'components/bottomsheetsectionlist',\n            'components/bottomsheetvirtualizedlist',\n            'components/bottomsheetbackdrop',\n            'components/bottomsheetfooter',\n            'components/bottomsheettextinput',\n          ],\n        },\n      ],\n    },\n    {\n      type: 'html',\n      value: \"<hr class='margin-vert--md margin-horiz--md' />\",\n      defaultStyle: false,\n    },\n    {\n      type: 'category',\n      label: 'Bottom Sheet Modal',\n      link: {\n        type: 'doc',\n        id: 'modal/index',\n      },\n      items: ['modal/usage', 'modal/props', 'modal/methods', 'modal/hooks'],\n    },\n    {\n      type: 'html',\n      value: \"<hr class='margin-vert--md margin-horiz--md' />\",\n      defaultStyle: false,\n    },\n    {\n      type: 'category',\n      label: 'Guides',\n      items: [\n        'guides/web-support',\n        'guides/dynamic-sizing',\n        'guides/custom-handle',\n        'guides/custom-backdrop',\n        'guides/custom-background',\n        'guides/custom-footer',\n        'guides/detach-modal',\n        'guides/keyboard-handling',\n        'guides/pull-to-refresh',\n        'guides/adding-shadow',\n        'guides/react-navigation-integration',\n      ],\n    },\n    'troubleshooting',\n    'faq',\n  ],\n};\n\nexport default sidebars;\n"
  },
  {
    "path": "website/src/css/custom.css",
    "content": ""
  },
  {
    "path": "website/src/pages/sponsors.mdx",
    "content": "---\ntitle: Sponsors\ndescription: List of React Native Bottom Sheet sponsors.\nhide_table_of_contents: true\n---\n\n# Sponsors\n\nThanks for sponsoring this library!\n\n---\n\nTo keep this library maintained and up-to-date please consider [sponsoring it on GitHub](https://github.com/sponsors/gorhom). Or if you are looking for a private support or help in customizing the experience, then reach out to me on Twitter [@gorhom](https://twitter.com/gorhom).\n"
  },
  {
    "path": "website/static/.nojekyll",
    "content": ""
  },
  {
    "path": "website/static/CNAME",
    "content": "gorhom.dev"
  },
  {
    "path": "website/static/googled4a9e66f4b4d23d7.html",
    "content": "google-site-verification: googled4a9e66f4b4d23d7.html"
  },
  {
    "path": "website/tsconfig.json",
    "content": "{\n  // This file is not used in compilation. It is here just for a nice editor experience.\n  \"extends\": \"@docusaurus/tsconfig\",\n  \"compilerOptions\": {\n    \"baseUrl\": \".\"\n  }\n}\n"
  },
  {
    "path": "website/versioned_docs/version-2/faq.md",
    "content": "---\nid: faq\ntitle: FAQ\ndescription: Bottom Sheet FAQ.\nimage: /img/bottom-sheet-preview.gif\nslug: /faq\nhide_table_of_contents: true\n---\n\n### How this library differ from `reanimated-bottom-sheet` or `react-native-scroll-bottom-sheet`?\n\nThis library was built to provide the most native-like experience and could fit any use-case that developers wants it to be. While both libraries providing similar experience, but they still missing the following:\n\n- `reanimated-bottom-sheet`: Seamless gesture interaction between the sheet and the content.\n- `react-native-scroll-bottom-sheet`: Extracting scrollable content to allow developers customize the sheet content, like integrate React Navigation as the sheet content.\n\nBoth libraries are great! and I have used both of them at my work ❤️\n"
  },
  {
    "path": "website/versioned_docs/version-2/guides/adding-shadow.mdx",
    "content": "---\nid: adding-shadow\ntitle: Adding Shadow\ndescription: Adding shadow to the Bottom Sheet.\nimage: /img/bottom-sheet-preview.gif\nslug: /adding-shadow\nhide_table_of_contents: true\n---\n\n![React Native Bottom Sheet Shadow](/img/bottom-sheet-shadow.jpg)\n\nTo add shadow to the bottom sheet, you will need to pass the `style` prop with shadow styling config, I recommend checking out [React Native Shadow Generator](https://ethercreative.github.io/react-native-shadow-generator/) by [@ethercreative](https://github.com/ethercreative).\n\n:::note NOTICE\n\nYou may notice that shadow looks different between **iOS** and **Android**, that's because each platform handle drawing shadows differently, read more about [Android Shadows](https://developer.android.com/training/material/shadows-clipping).\n\n:::\n"
  },
  {
    "path": "website/versioned_docs/version-2/guides/custom-backdrop.mdx",
    "content": "---\nid: custom-backdrop\ntitle: Custom Backdrop\ndescription: Bottom Sheet custom backdrop.\nimage: /img/bottom-sheet-preview.gif\nslug: /custom-backdrop\nhide_table_of_contents: true\n---\n\nimport Tabs from '@theme/Tabs';\nimport TabItem from '@theme/TabItem';\n\nTo add a backdrop to your sheet you will need to pass the prop `backdropComponent` to the `BottomSheet` component.\n\nWhen you provide your own backdrop component, it will receive these animated props `animatedIndex` & `animatedPosition` that indicates the position and the index of the sheet.\n\nYou can extend your custom backdrop props interface with the provided `BottomSheetBackdropProps` interface to expose `animatedIndex` & `animatedPosition` into your own interface.\n\n### Example\n\nimport useBaseUrl from '@docusaurus/useBaseUrl';\nimport Video from '@theme/Video';\n\n<Video\n  title=\"React Native Bottom Sheet Custom Backdrop\"\n  url={useBaseUrl('video/bottom-sheet-custom-backdrop-preview.mp4')}\n/>\n\nHere is an example of a custom backdrop component:\n\n```tsx\nimport React, { useMemo } from 'react';\nimport { BottomSheetBackdropProps } from '@gorhom/bottom-sheet';\nimport Animated, { Extrapolate, interpolate } from 'react-native-reanimated';\n\nconst CustomBackdrop = ({ animatedIndex, style }: BottomSheetBackdropProps) => {\n  // animated variables\n  const animatedOpacity = useMemo(\n    () =>\n      interpolate(animatedIndex, {\n        inputRange: [0, 1],\n        outputRange: [0, 1],\n        extrapolate: Extrapolate.CLAMP,\n      }),\n    [animatedIndex]\n  );\n\n  // styles\n  const containerStyle = useMemo(\n    () => [\n      style,\n      {\n        backgroundColor: '#a8b5eb',\n        opacity: animatedOpacity,\n      },\n    ],\n    [style, animatedOpacity]\n  );\n\n  return <Animated.View style={containerStyle} />;\n};\n\nexport default CustomBackdrop;\n```\n"
  },
  {
    "path": "website/versioned_docs/version-2/guides/custom-background.mdx",
    "content": "---\nid: custom-background\ntitle: Custom Background\ndescription: Bottom Sheet custom background.\nimage: /img/bottom-sheet-preview.gif\nslug: /custom-background\nhide_table_of_contents: true\n---\n\nimport Tabs from '@theme/Tabs';\nimport TabItem from '@theme/TabItem';\n\nTo override the default background, you will need to pass the prop `backgroundComponent` to the `BottomSheet` component.\n\nWhen you provide your own background component, it will receive these animated props `animatedIndex` & `animatedPosition` that indicates the position and the index of the sheet.\n\nYou can extend your custom background props interface with the provided `BottomSheetBackgroundProps` interface to expose `animatedIndex` & `animatedPosition` into your own interface.\n\n### Example\n\nimport useBaseUrl from '@docusaurus/useBaseUrl';\nimport Video from '@theme/Video';\n\n<Video\n  title=\"React Native Bottom Sheet Custom Background\"\n  url={useBaseUrl('video/bottom-sheet-custom-background-preview.mp4')}\n/>\n\nHere is an example of a custom background component:\n\n```tsx\nimport React, { useMemo } from 'react';\nimport { BottomSheetBackgroundProps } from '@gorhom/bottom-sheet';\nimport Animated, {\n  Extrapolate,\n  interpolate,\n  interpolateColors,\n} from 'react-native-reanimated';\n\nconst CustomBackground = ({\n  animatedIndex,\n  style,\n}: BottomSheetBackgroundProps) => {\n  // animated variables\n  const animatedBackground = useMemo(\n    () =>\n      interpolateColors(animatedIndex, {\n        inputRange: [0, 1],\n        outputColorRange: ['#fff', '#a8b5eb'],\n      }),\n    [animatedIndex]\n  );\n\n  // styles\n  const containerStyle = useMemo(\n    () => [\n      style,\n      {\n        backgroundColor: animatedBackground,\n      },\n    ],\n    [style, animatedBackground]\n  );\n\n  return <Animated.View style={containerStyle} />;\n};\n\nexport default CustomBackground;\n```\n"
  },
  {
    "path": "website/versioned_docs/version-2/guides/custom-handle.mdx",
    "content": "---\nid: custom-handle\ntitle: Custom Handle\ndescription: Bottom Sheet custom handle.\nimage: /img/bottom-sheet-preview.gif\nslug: /custom-handle\nhide_table_of_contents: true\n---\n\nimport Tabs from '@theme/Tabs';\nimport TabItem from '@theme/TabItem';\n\nTo override the default handle, you will need to pass the prop `handleComponent` to the `BottomSheet` component.\n\nWhen you provide your own handle component, it will receive these animated props `animatedIndex` & `animatedPosition` that indicates the position and the index of the sheet.\n\nYou can extend your custom handle props interface with the provided `BottomSheetHandleProps` interface to expose `animatedIndex` & `animatedPosition` into your own interface.\n\n### Example\n\nimport useBaseUrl from '@docusaurus/useBaseUrl';\nimport Video from '@theme/Video';\n\n<Video\n  title=\"React Native Bottom Sheet Custom Handle\"\n  url={useBaseUrl('video/bottom-sheet-custom-handle-preview.mp4')}\n/>\n\nHere is an example of a custom handle component, but first you will need to install `Redash`:\n\n> [Redash](https://github.com/wcandillon/react-native-redash): The React Native Reanimated and Gesture Handler Toolbelt.\n\n```bash\nyarn add react-native-redash\n```\n\n```tsx\nimport React, { useMemo } from 'react';\nimport { StyleProp, StyleSheet, ViewStyle } from 'react-native';\nimport { BottomSheetHandleProps } from '@gorhom/bottom-sheet';\nimport Animated, { interpolate, Extrapolate } from 'react-native-reanimated';\nimport { transformOrigin, toRad } from 'react-native-redash';\n\ninterface HandleProps extends BottomSheetHandleProps {}\n\nconst Handle: React.FC<HandleProps> = ({ animatedIndex }) => {\n  //#region animations\n  const borderTopRadius = useMemo(\n    () =>\n      interpolate(animatedIndex, {\n        inputRange: [1, 2],\n        outputRange: [20, 0],\n        extrapolate: Extrapolate.CLAMP,\n      }),\n    [animatedIndex]\n  );\n  const indicatorTransformOriginY = useMemo(\n    () =>\n      interpolate(animatedIndex, {\n        inputRange: [0, 1, 2],\n        outputRange: [-1, 0, 1],\n        extrapolate: Extrapolate.CLAMP,\n      }),\n    [animatedIndex]\n  );\n  const leftIndicatorRotate = useMemo(\n    () =>\n      interpolate(animatedIndex, {\n        inputRange: [0, 1, 2],\n        outputRange: [toRad(-30), 0, toRad(30)],\n        extrapolate: Extrapolate.CLAMP,\n      }),\n    [animatedIndex]\n  );\n  const rightIndicatorRotate = interpolate(animatedIndex, {\n    inputRange: [0, 1, 2],\n    outputRange: [toRad(30), 0, toRad(-30)],\n    extrapolate: Extrapolate.CLAMP,\n  });\n  //#endregion\n\n  //#region styles\n  const containerStyle = useMemo(\n    () => [\n      styles.header,\n      {\n        borderTopLeftRadius: borderTopRadius,\n        borderTopRightRadius: borderTopRadius,\n      },\n    ],\n    [borderTopRadius]\n  );\n  const leftIndicatorStyle = useMemo(\n    () => ({\n      ...styles.indicator,\n      ...styles.leftIndicator,\n      transform: transformOrigin(\n        { x: 0, y: indicatorTransformOriginY },\n        {\n          rotate: leftIndicatorRotate,\n          translateX: -5,\n        }\n      ),\n    }),\n    [indicatorTransformOriginY, leftIndicatorRotate]\n  );\n  const rightIndicatorStyle = useMemo(\n    () => ({\n      ...styles.indicator,\n      ...styles.rightIndicator,\n      transform: transformOrigin(\n        { x: 0, y: indicatorTransformOriginY },\n        {\n          rotate: rightIndicatorRotate,\n          translateX: 5,\n        }\n      ),\n    }),\n    [indicatorTransformOriginY, rightIndicatorRotate]\n  );\n  //#endregion\n\n  // render\n  return (\n    <Animated.View style={containerStyle}>\n      <Animated.View style={leftIndicatorStyle} />\n      <Animated.View style={rightIndicatorStyle} />\n    </Animated.View>\n  );\n};\n\nexport default Handle;\n\nconst styles = StyleSheet.create({\n  header: {\n    alignContent: 'center',\n    alignItems: 'center',\n    justifyContent: 'center',\n    backgroundColor: 'white',\n    paddingVertical: 14,\n    shadowColor: 'black',\n    shadowOffset: {\n      width: 0,\n      height: -20,\n    },\n    shadowOpacity: 0.1,\n    shadowRadius: 10,\n    elevation: 16,\n    borderBottomWidth: 1,\n    borderBottomColor: '#fff',\n  },\n  indicator: {\n    position: 'absolute',\n    width: 10,\n    height: 4,\n    backgroundColor: '#999',\n  },\n  leftIndicator: {\n    borderTopStartRadius: 2,\n    borderBottomStartRadius: 2,\n  },\n  rightIndicator: {\n    borderTopEndRadius: 2,\n    borderBottomEndRadius: 2,\n  },\n});\n```\n"
  },
  {
    "path": "website/versioned_docs/version-2/guides/react-naigation.md",
    "content": "---\nid: react-navigation-integration\ntitle: React Navigation Integration\ndescription: Bottom Sheet React Navigation integration.\nimage: /img/bottom-sheet-preview.gif\nslug: /react-navigation-integration\nhide_table_of_contents: true\n---\n\nOne of the main goal of this library, is to allow user to fully integrate a stack navigator in the bottom sheet. This integration allow lots of opportunities for a native-like experience in your app 😇\n\nHowever, there are some tricks has to be follow to enable both libraries to work together seamlessly.\n\n- You need to override `safeAreaInsets`, by default `React Navigation` add the safe area insets to all its navigators, but since your navigator will properly won't cover full screen, you will need to override it and set it to `0`.\n\nFor more details regarding the implementation, please have a look at the [Navigator Example](https://github.com/gorhom/react-native-bottom-sheet/blob/v2/example/src/screens/integrations/NavigatorExample.tsx).\n"
  },
  {
    "path": "website/versioned_docs/version-2/hooks.md",
    "content": "---\nid: hooks\ntitle: Hooks\ndescription: Bottom Sheet hooks.\nimage: /img/bottom-sheet-preview.gif\nslug: /hooks\n---\n\n## `useBottomSheet`\n\nThis hook provides all the bottom sheet public [methods](methods), to the internal sheet content or handle.\n\n> This hook works at any component inside the `BottomSheet`.\n\n```tsx\nimport React from 'react';\nimport { View, Button } from 'react-native';\nimport { useBottomSheet } from '@gorhom/bottom-sheet';\n\nconst SheetContent = () => {\n  const { expand } = useBottomSheet();\n\n  return (\n    <View>\n      <Button onPress={expand}>\n    </View>\n  )\n}\n```\n"
  },
  {
    "path": "website/versioned_docs/version-2/index.mdx",
    "content": "---\nid: index\ntitle: Bottom Sheet\nhide_title: true\nsidebar_label: Bottom Sheet\ndescription: A performant interactive bottom sheet with fully configurable options 🚀\nimage: /img/bottom-sheet-preview.gif\nslug: /\n---\n\n# React Native Bottom Sheet\n\n[![version](https://img.shields.io/github/package-json/v/gorhom/react-native-bottom-sheet/v2?label=version&style=flat-square)](https://www.npmjs.com/package/@gorhom/bottom-sheet) [![npm](https://img.shields.io/npm/l/@gorhom/bottom-sheet?style=flat-square)](https://www.npmjs.com/package/@gorhom/bottom-sheet) [![npm](https://img.shields.io/badge/types-included-blue?style=flat-square)](https://www.npmjs.com/package/@gorhom/bottom-sheet) [![runs with expo](https://img.shields.io/badge/Runs%20with%20Expo-4630EB.svg?style=flat-square&logo=EXPO&labelColor=f3f3f3&logoColor=000)](https://expo.io/)\n\nA performant interactive bottom sheet with fully configurable options 🚀\n\nimport useBaseUrl from \"@docusaurus/useBaseUrl\";\nimport Video from \"@theme/Video\";\n\n<Video\n  title=\"React Native Bottom Sheet\"\n  url={useBaseUrl(\"video/bottom-sheet-preview.mp4\")}\n  img={useBaseUrl(\"img/bottom-sheet-preview.gif\")}\n/>\n\n## Features\n\n- Modal presentation view, [Bottom Sheet Modal](./modal).\n- Smooth gesture interactions & snapping animations.\n- Support `FlatList`, `SectionList`, `ScrollView` & `View` scrolling interactions, [read more](./scrollables).\n- Support `React Navigation` Integration, [read more](./react-navigation-integration).\n- Compatible with Reanimated v1.\n- Compatible with `Expo`.\n- Accessibility support.\n- Written in `TypeScript`.\n\n## Installation\n\nThis version is written with `Reanimated v1` & compatible with `Reanimated v2`:\n\n```bash\nyarn add @gorhom/bottom-sheet@^2\n```\n\n#### Dependencies\n\nThis library needs these dependencies to be installed in your project before you can use it:\n\n```bash\nyarn add react-native-reanimated@^1 react-native-gesture-handler\n```\n\n:::info\n**React Native Gesture Handler** needs extra steps to finalize its installation, please follow their [installation instructions](https://github.com/software-mansion/react-native-gesture-handler).\n\n**React Native Reanimated v1** needs extra steps to finalize its installation, please follow their [installation instructions](https://docs.swmansion.com/react-native-reanimated/docs/1.x.x/getting_started).\n:::\n\n## Built With ❤️\n\n- [react-native-reanimated](https://github.com/software-mansion/react-native-reanimated)\n- [react-native-gesture-handler](https://github.com/software-mansion/react-native-gesture-handler)\n- [react-native-redash](https://github.com/wcandillon/react-native-redash)\n- [react-native-builder-bob](https://github.com/callstack/react-native-builder-bob)\n\n## Sponsor & Support\n\nTo keep this library maintained and up-to-date please consider [sponsoring it on GitHub](https://github.com/sponsors/gorhom). Or if you are looking for a private support or help in customizing the experience, then reach out to me on Twitter [@gorhom](https://twitter.com/gorhom)."
  },
  {
    "path": "website/versioned_docs/version-2/methods.md",
    "content": "---\nid: methods\ntitle: Methods\ndescription: Bottom Sheet methods.\nimage: /img/bottom-sheet-preview.gif\nslug: /methods\n---\n\nThese methods are accessible using the bottom sheet reference.\n\n```tsx\nimport React, { useRef } from 'react';\nimport { Button } from 'react-native';\nimport BottomSheet from '@gorhom/bottom-sheet';\n\nconst App = () => {\n  const bottomSheetRef = useRef<BottomSheet>(null);\n\n  const handleClosePress = () => bottomSheetRef.current.close()\n\n  return (\n    <>\n      <Button title=\"Close Sheet\" onPress={handleClosePress} />\n      <BottomSheet ref={bottomSheetRef}>\n    </>\n  )\n}\n\n```\n\n### `snapTo`\n\nAnimate the sheet to one of the provided point from `snapPoints`.\n\n```ts\ntype snapTo = (index: number) => void;\n```\n\n### `expand`\n\nAnimate the sheet to the highest provided point from `snapPoints`.\n\n```ts\ntype expand = () => void;\n```\n\n### `collapse`\n\nAnimate the sheet to the lowest provided point from `snapPoints`.\n\n```ts\ntype collapse = () => void;\n```\n\n### `close`\n\nClose the sheet.\n\n```ts\ntype close = () => void;\n```\n"
  },
  {
    "path": "website/versioned_docs/version-2/modal/hooks.md",
    "content": "---\nid: hooks\ntitle: Hooks\ndescription: Bottom Sheet modal hooks.\nimage: /img/bottom-sheet-preview.gif\nslug: /modal/hooks\n---\n\n## `useBottomSheetModal`\n\nThis hook provides modal functionalities only, for sheet functionalities please look at [Bottom Sheet Hooks](../hooks).\n\n> This hook works at any component in `BottomSheetModalProvider`.\n\n```tsx\nimport React from 'react';\nimport { View, Button } from 'react-native';\nimport { useBottomSheetModal } from '@gorhom/bottom-sheet';\n\nconst SheetContent = () => {\n  const { dismiss, dismissAll } = useBottomSheetModal();\n\n  return (\n    <View>\n      <Button onPress={dismiss}>\n    </View>\n  )\n}\n```\n\n## `dismiss`\n\n```ts\ntype dismiss = (key: string) => void;\n```\n\nDismiss a modal by its name/key.\n\n## `dismissAll`\n\n```ts\ntype dismissAll = () => void;\n```\n\nDismiss all mounted/presented modals.\n"
  },
  {
    "path": "website/versioned_docs/version-2/modal/index.mdx",
    "content": "---\nid: index\ntitle: Modal\nsidebar_label: Modal\ndescription: A performant interactive bottom sheet modal with fully configurable options 🚀\nimage: /img/bottom-sheet-modal-preview.gif\nslug: /modal\n---\n\n# React Native Bottom Sheet Modal\n\nimport useBaseUrl from '@docusaurus/useBaseUrl';\nimport Video from '@theme/Video';\n\n<Video\n  title=\"React Native Bottom Sheet Modal\"\n  url={useBaseUrl('video/bottom-sheet-modal-preview.mp4')}\n/>\n\n**Bottom Sheet Modal** is wrapper/decorator on top of the **Bottom Sheet**, it provides all of its functionalities with extra modal presentation functionalities.\n\nWith the release of the library, support for stack sheet modals were something planned ahead to provide the a native feel & and experience to users.\n\nThe implementation of this feature was inspired by Apple Maps sheet modals ❤️, [check out the Apple Map sheet modals clone](https://github.com/gorhom/react-native-bottom-sheet/blob/master/example/src/screens/advanced/MapExample.tsx).\n\n## Features\n\n- ...[Bottom Sheet Features](./#features)\n- Smooth interaction and mounting animation.\n- Support stack sheet modals.\n\n## Installation\n\nThis feature is already shipped with `@gorhom/bottom-sheet` package and it requires no extra dependency.\n"
  },
  {
    "path": "website/versioned_docs/version-2/modal/methods.md",
    "content": "---\nid: methods\ntitle: Methods\ndescription: Bottom Sheet modal methods.\nimage: /img/bottom-sheet-preview.gif\nslug: /modal/methods\n---\n\n\n**Bottom Sheet Modal** inherits all [**Bottom Sheet** methods](../methods) and also it introduces its own methods.\n\nThese methods are accessible using the bottom sheet modal reference:\n\n```tsx\nimport React, { useRef } from 'react';\nimport {BottomSheetModal} from '@gorhom/bottom-sheet';\n\nconst App = () => {\n  const bottomSheetModalRef = useRef<BottomSheetModal>(null);\n\n  const handlePresentPress = () => bottomSheetModalRef.current.present()\n\n  return (\n    <>\n      <Button title=\"Present Sheet\" onPress={handlePresentPress} />\n      <BottomSheetModal ref={bottomSheetModalRef}>\n    </>\n  )\n}\n\n```\n\n### `present`\n\n```ts\ntype present = () => void;\n```\n\nMount and present the modal.\n\n### `dismiss`\n\n```ts\ntype dismiss = () => void;\n```\n\nClose and unmount the modal.\n"
  },
  {
    "path": "website/versioned_docs/version-2/modal/props.md",
    "content": "---\nid: props\ntitle: Props\ndescription: Bottom Sheet modal configurable props.\nimage: /img/bottom-sheet-preview.gif\nslug: /modal/props\n---\n\n**Bottom Sheet Modal** inherits all [**Bottom Sheet** props](../props) except for `animateOnMount` & `containerHeight` and also it introduces its own props:\n\n## Configuration\n\n### `name`\n\nModal name to help identify the modal for later on.\n\n| type   | default                | required |\n| ------ | ---------------------- | -------- |\n| string | `generated unique key` | NO       |\n\n### `dismissOnPanDown`\n\nDismiss modal when panning down.\n\n| type    | default | required |\n| ------- | ------- | -------- |\n| boolean | true    | NO       |\n\n## Callbacks\n\n### `onDismiss`\n\nCallback when the modal dismissed.\n\n```ts\ntype onDismiss = () => void;\n```\n\n| type     | default | required |\n| -------- | ------- | -------- |\n| function | null    | NO       |\n"
  },
  {
    "path": "website/versioned_docs/version-2/modal/usage.md",
    "content": "---\nid: usage\ntitle: Usage\ndescription: Bottom Sheet modal usage.\nimage: /img/bottom-sheet-preview.gif\nslug: /modal/usage\n---\n\nHere is a simple usage of the **Bottom Sheet Modal**, with non-scrollable content. For more scrollable usage please read [Scrollables](../scrollables).\n\n```tsx\nimport React, { useCallback, useMemo, useRef } from 'react';\nimport { View, Text, StyleSheet, Button } from 'react-native';\nimport {\n  BottomSheetModal,\n  BottomSheetModalProvider,\n} from '@gorhom/bottom-sheet';\n\nconst App = () => {\n  // ref\n  const bottomSheetModalRef = useRef<BottomSheetModal>(null);\n\n  // variables\n  const snapPoints = useMemo(() => ['25%', '50%'], []);\n\n  // callbacks\n  const handlePresentModalPress = useCallback(() => {\n    bottomSheetModalRef.current?.present();\n  }, []);\n  const handleSheetChanges = useCallback((index: number) => {\n    console.log('handleSheetChanges', index);\n  }, []);\n\n  // renders\n  return (\n    <BottomSheetModalProvider>\n      <View style={styles.container}>\n        <Button\n          onPress={handlePresentModalPress}\n          title=\"Present Modal\"\n          color=\"black\"\n        />\n        <BottomSheetModal\n          ref={bottomSheetModalRef}\n          index={1}\n          snapPoints={snapPoints}\n          onChange={handleSheetChanges}\n        >\n          <View style={styles.contentContainer}>\n            <Text>Awesome 🎉</Text>\n          </View>\n        </BottomSheetModal>\n      </View>\n    </BottomSheetModalProvider>\n  );\n};\n\nconst styles = StyleSheet.create({\n  container: {\n    flex: 1,\n    padding: 24,\n    justifyContent: 'center',\n    backgroundColor: 'grey',\n  },\n  contentContainer: {\n    flex: 1,\n    alignItems: 'center',\n  },\n});\n\nexport default App;\n```\n"
  },
  {
    "path": "website/versioned_docs/version-2/props.md",
    "content": "---\nid: props\ntitle: Props\ndescription: Bottom Sheet configurable props.\nimage: /img/bottom-sheet-preview.gif\nslug: /props\n---\n\n## Configuration\n\n### `index`\n\nInitial snap index. You also could provide `-1` to initiate bottom sheet in closed state.\n\n| type   | default | required |\n| ------ | ------- | -------- |\n| number | 0       | NO       |\n\n### `snapPoints`\n\nPoints for the bottom sheet to snap to, **points should be sorted from bottom to top**. It accepts array of number, string or mix.\n\n| type                  | required |\n| --------------------- | -------- |\n| Array\\<number\\|string> | YES      |\n\n:::caution\nString values should be a percentage.\n:::\n\n#### examples\n\n```ts\nsnapPoints={[200, 500]}\nsnapPoints={[200, '50%']}\nsnapPoints={[-1, '100%']}\n```\n\n### `enableContentPanningGesture`\n\nEnable content panning gesture interaction.\n\n| type    | default | required |\n| ------- | ------- | -------- |\n| boolean | true    | NO       |\n\n### `enableHandlePanningGesture`\n\nEnable handle panning gesture interaction.\n\n| type    | default | required |\n| ------- | ------- | -------- |\n| boolean | true    | NO       |\n\n### `animateOnMount`\n\nThis will initially mount the sheet closed and when it's mounted and calculated the layout, it will snap to initial snap point index.\n\n| type    | default | required |\n| ------- | ------- | -------- |\n| boolean | false   | NO       |\n\n### `style`\n\nView style to be applied at the sheet container, it also could be an `AnimatedStyle`. This is helpful to add shadow to the sheet.\n\n| type                       | default   | required |\n| -------------------------- | --------- | -------- |\n| ViewStyle \\| AnimatedStyle | undefined | NO       |\n\n## Layout Configuration\n\n### `handleHeight`\n\nHandle height helps to calculate the internal container and sheet layouts. If `handleComponent` is provided, the library internally will calculate its layout, unless `handleHeight` is provided too.\n\n| type   | default | required |\n| ------ | ------- | -------- |\n| number | 24      | NO       |\n\n### `containerHeight`\n\nContainer height helps to calculate the internal sheet layouts. If `containerHeight` not provided, the library internally will calculate it, however this will cause an extra re-rendering.\n\n| type   | default | required |\n| ------ | ------- | -------- |\n| number | 0       | NO       |\n\n### `topInset`\n\nTop inset to be added to the bottom sheet container, usually it comes from `@react-navigation/stack` hook `useHeaderHeight` or from `react-native-safe-area-context` hook `useSafeArea`.\n\n| type   | default | required |\n| ------ | ------- | -------- |\n| number | 0       | NO       |\n\n### `bottomInset`\n\nBottom inset to be added to the bottom sheet container.\n\n| type   | default | required |\n| ------ | ------- | -------- |\n| number | 0       | NO       |\n\n## Animation Configuration\n\n### `animationDuration`\n\nSnapping animation duration.\n\n| type   | default | required |\n| ------ | ------- | -------- |\n| number | 500     | NO       |\n\n### `animationEasing`\n\nSnapping animation easing function.\n\n| type             | default | required |\n| ---------------- | ------- | -------- |\n| `EasingFunction` | @TODO   | NO       |\n\n## Animated Nodes\n\n### `animatedIndex`\n\nAnimated value to be used as a callback for the index node internally.\n\n| type                   | default | required |\n| ---------------------- | ------- | -------- |\n| AnimatedValue\\<number\\> | null    | NO       |\n\n### `animatedPosition`\n\nAnimated value to be used as a callback for the position node internally.\n\n| type                   | default | required |\n| ---------------------- | ------- | -------- |\n| AnimatedValue\\<number\\> | null    | NO       |\n\n## Callbacks\n\n### `onChange`\n\nCallback when the sheet position changed.\n\n```ts\ntype onChange = (index: number) => void;\n```\n\n| type     | default | required |\n| -------- | ------- | -------- |\n| function | null    | NO       |\n\n### `onAnimate`\n\nCallback when the sheet about to animate to a new position.\n\n```ts\ntype onAnimate = (fromIndex: number, toIndex: number) => void;\n```\n\n| type     | default | required |\n| -------- | ------- | -------- |\n| function | null    | NO       |\n\n## Components\n\n### `handleComponent`\n\nComponent to be placed as a sheet handle.\n\n| type                               | default             | required |\n| ---------------------------------- | ------------------- | -------- |\n| `React.FC<BottomSheetHandleProps>` | `BottomSheetHandle` | NO       |\n\n### `backdropComponent`\n\nComponent to be placed as a sheet backdrop, by default is set to `null`, however the library also provide a default implementation `BottomSheetBackdrop` of a backdrop but you will need to provide it manually.\n\n| type                                   | default | required |\n| -------------------------------------- | ------- | -------- |\n| `React.FC<BottomSheetBackgroundProps>` | null    | NO       |\n\n### `backgroundComponent`\n\nComponent to be placed as a sheet background.\n\n| type                                   | default                 | required |\n| -------------------------------------- | ----------------------- | -------- |\n| `React.FC<BottomSheetBackgroundProps>` | `BottomSheetBackground` | NO       |\n\n### `children`\n\n`Scrollable` node or react node to be places as a sheet content.\n\n| type                                                          | default | required |\n| ------------------------------------------------------------- | ------- | -------- |\n| () => React.ReactNode \\| React.ReactNode[] \\| React.ReactNode | null    | YES      |\n"
  },
  {
    "path": "website/versioned_docs/version-2/scrollables.md",
    "content": "---\nid: scrollables\ntitle: Scrollables\ndescription: Bottom Sheet scrollables.\nimage: /img/bottom-sheet-preview.gif\nslug: /scrollables\n---\n\nThis library provides a pre-integrated virtualized lists that utilize an internal functionalities with the bottom sheet container to allow smooth panning interactions. These lists I called them Scrollables and they are:\n\n- [BottomSheetFlatList](#bottomsheetflatlist)\n- [BottomSheetSectionList](#bottomsheetsectionlist)\n- [BottomSheetScrollView](#bottomsheetscrollview)\n- [BottomSheetView](#bottomsheetview)\n\n## BottomSheetFlatList\n\nAn extended component of `FlatList` from `react-native`, with bottom sheet integrations.\n\n#### Props\n\n##### `focusHook`\n\nThis needed when bottom sheet used with multiple scrollables to allow bottom sheet detect the current scrollable ref, especially when used with React Navigation. You will need to provide `useFocusEffect` from `@react-navigation/native`.\n\n| type     | default           | required |\n| -------- | ----------------- | -------- |\n| function | `React.useEffect` | NO       |\n\n#### Example\n\n```tsx\nimport React, { useCallback, useRef, useMemo } from 'react';\nimport { StyleSheet, View, Text, Button } from 'react-native';\nimport BottomSheet, { BottomSheetFlatList } from '@gorhom/bottom-sheet';\n\nconst App = () => {\n  // hooks\n  const sheetRef = useRef<BottomSheet>(null);\n\n  // variables\n  const data = useMemo(\n    () =>\n      Array(50)\n        .fill(0)\n        .map((_, index) => `index-${index}`),\n    []\n  );\n  const snapPoints = useMemo(() => ['25%', '50%', '90%'], []);\n\n  // callbacks\n  const handleSheetChange = useCallback(index => {\n    console.log('handleSheetChange', index);\n  }, []);\n  const handleSnapPress = useCallback(index => {\n    sheetRef.current?.snapTo(index);\n  }, []);\n  const handleClosePress = useCallback(() => {\n    sheetRef.current?.close();\n  }, []);\n\n  // render\n  const renderItem = useCallback(\n    ({ item }) => (\n      <View style={styles.itemContainer}>\n        <Text>{item}</Text>\n      </View>\n    ),\n    []\n  );\n  return (\n    <View style={styles.container}>\n      <Button title=\"Snap To 90%\" onPress={() => handleSnapPress(2)} />\n      <Button title=\"Snap To 50%\" onPress={() => handleSnapPress(1)} />\n      <Button title=\"Snap To 25%\" onPress={() => handleSnapPress(0)} />\n      <Button title=\"Close\" onPress={() => handleClosePress()} />\n      <BottomSheet\n        ref={sheetRef}\n        snapPoints={snapPoints}\n        onChange={handleSheetChange}\n      >\n        <BottomSheetFlatList\n          data={data}\n          keyExtractor={i => i}\n          renderItem={renderItem}\n          contentContainerStyle={styles.contentContainer}\n        />\n      </BottomSheet>\n    </View>\n  );\n};\n\nconst styles = StyleSheet.create({\n  container: {\n    flex: 1,\n    paddingTop: 200,\n  },\n  contentContainer: {\n    backgroundColor: 'white',\n  },\n  itemContainer: {\n    padding: 6,\n    margin: 6,\n    backgroundColor: '#eee',\n  },\n});\n\nexport default App;\n```\n\n## BottomSheetSectionList\n\nIs an extended component of `SectionList` from `react-native`, with bottom sheet integrations.\n\n#### Props\n\n##### `focusHook`\n\nThis needed when bottom sheet used with multiple scrollables to allow bottom sheet detect the current scrollable ref, especially when used with React Navigation. You will need to provide `useFocusEffect` from `@react-navigation/native`.\n\n| type     | default           | required |\n| -------- | ----------------- | -------- |\n| function | `React.useEffect` | NO       |\n\n#### Example\n\n```tsx\nimport React, { useCallback, useRef, useMemo } from 'react';\nimport { StyleSheet, View, Text, Button } from 'react-native';\nimport BottomSheet, { BottomSheetSectionList } from '@gorhom/bottom-sheet';\n\nconst App = () => {\n  // hooks\n  const sheetRef = useRef<BottomSheet>(null);\n\n  // variables\n  const sections = useMemo(\n    () =>\n      Array(10)\n        .fill(0)\n        .map((_, index) => ({\n          title: `Section ${index}`,\n          data: Array(10)\n            .fill(0)\n            .map((_, index) => `Item ${index}`),\n        })),\n    []\n  );\n  const snapPoints = useMemo(() => ['25%', '50%', '90%'], []);\n\n  // callbacks\n  const handleSheetChange = useCallback(index => {\n    console.log('handleSheetChange', index);\n  }, []);\n  const handleSnapPress = useCallback(index => {\n    sheetRef.current?.snapTo(index);\n  }, []);\n  const handleClosePress = useCallback(() => {\n    sheetRef.current?.close();\n  }, []);\n\n  // render\n  const renderSectionHeader = useCallback(\n    ({ section }) => (\n      <View style={styles.sectionHeaderContainer}>\n        <Text>{section.title}</Text>\n      </View>\n    ),\n    []\n  );\n  const renderItem = useCallback(\n    ({ item }) => (\n      <View style={styles.itemContainer}>\n        <Text>{item}</Text>\n      </View>\n    ),\n    []\n  );\n  return (\n    <View style={styles.container}>\n      <Button title=\"Snap To 90%\" onPress={() => handleSnapPress(2)} />\n      <Button title=\"Snap To 50%\" onPress={() => handleSnapPress(1)} />\n      <Button title=\"Snap To 25%\" onPress={() => handleSnapPress(0)} />\n      <Button title=\"Close\" onPress={() => handleClosePress()} />\n      <BottomSheet\n        ref={sheetRef}\n        index={1}\n        snapPoints={snapPoints}\n        onChange={handleSheetChange}\n      >\n        <BottomSheetSectionList\n          sections={sections}\n          keyExtractor={i => i}\n          renderSectionHeader={renderSectionHeader}\n          renderItem={renderItem}\n          contentContainerStyle={styles.contentContainer}\n        />\n      </BottomSheet>\n    </View>\n  );\n};\n\nconst styles = StyleSheet.create({\n  container: {\n    flex: 1,\n    paddingTop: 200,\n  },\n  contentContainer: {\n    backgroundColor: 'white',\n  },\n  sectionHeaderContainer: {\n    backgroundColor: 'white',\n    padding: 6,\n  },\n  itemContainer: {\n    padding: 6,\n    margin: 6,\n    backgroundColor: '#eee',\n  },\n});\n\nexport default App;\n```\n\n## BottomSheetScrollView\n\nIs an extended component of `ScrollView` from `react-native`, with bottom sheet integrations.\n\n#### Props\n\n##### `focusHook`\n\nThis needed when bottom sheet used with multiple scrollables to allow bottom sheet detect the current scrollable ref, especially when used with React Navigation. You will need to provide `useFocusEffect` from `@react-navigation/native`.\n\n| type     | default           | required |\n| -------- | ----------------- | -------- |\n| function | `React.useEffect` | NO       |\n\n#### Example\n\n```tsx\nimport React, { useCallback, useRef, useMemo } from 'react';\nimport { StyleSheet, View, Text, Button } from 'react-native';\nimport BottomSheet, { BottomSheetScrollView } from '@gorhom/bottom-sheet';\n\nconst App = () => {\n  // hooks\n  const sheetRef = useRef<BottomSheet>(null);\n\n  // variables\n  const data = useMemo(\n    () =>\n      Array(50)\n        .fill(0)\n        .map((_, index) => `index-${index}`),\n    []\n  );\n  const snapPoints = useMemo(() => ['25%', '50%', '90%'], []);\n\n  // callbacks\n  const handleSheetChange = useCallback(index => {\n    console.log('handleSheetChange', index);\n  }, []);\n  const handleSnapPress = useCallback(index => {\n    sheetRef.current?.snapTo(index);\n  }, []);\n  const handleClosePress = useCallback(() => {\n    sheetRef.current?.close();\n  }, []);\n\n  // render\n  const renderItem = useCallback(\n    item => (\n      <View key={item} style={styles.itemContainer}>\n        <Text>{item}</Text>\n      </View>\n    ),\n    []\n  );\n  return (\n    <View style={styles.container}>\n      <Button title=\"Snap To 90%\" onPress={() => handleSnapPress(2)} />\n      <Button title=\"Snap To 50%\" onPress={() => handleSnapPress(1)} />\n      <Button title=\"Snap To 25%\" onPress={() => handleSnapPress(0)} />\n      <Button title=\"Close\" onPress={() => handleClosePress()} />\n      <BottomSheet\n        ref={sheetRef}\n        index={1}\n        snapPoints={snapPoints}\n        onChange={handleSheetChange}\n      >\n        <BottomSheetScrollView\n          contentContainerStyle={styles.contentContainer}\n        >\n          {data.map(renderItem)}\n        </BottomSheetScrollView>\n      </BottomSheet>\n    </View>\n  );\n};\n\nconst styles = StyleSheet.create({\n  container: {\n    flex: 1,\n    paddingTop: 200,\n  },\n  contentContainer: {\n    backgroundColor: 'white',\n  },\n  itemContainer: {\n    padding: 6,\n    margin: 6,\n    backgroundColor: '#eee',\n  },\n});\n\nexport default App;\n```\n\n## BottomSheetView\n\nIs an extended component of `View` from `react-native`, with bottom sheet integrations.\n\n> This only needed when the bottom sheet used with `React Navigation`.\n\n#### Props\n\n##### `focusHook`\n\nThis needed when bottom sheet used with multiple scrollables to allow bottom sheet detect the current scrollable ref, especially when used with React Navigation. You will need to provide `useFocusEffect` from `@react-navigation/native`.\n\n| type     | default           | required |\n| -------- | ----------------- | -------- |\n| function | `React.useEffect` | NO       |\n\n#### Example\n\n```tsx\nimport React, { useCallback, useRef, useMemo } from 'react';\nimport { StyleSheet, View, Text, Button } from 'react-native';\nimport BottomSheet, { BottomSheetView } from '@gorhom/bottom-sheet';\n\nconst App = () => {\n  // hooks\n  const sheetRef = useRef<BottomSheet>(null);\n\n  // variables\n  const data = useMemo(\n    () =>\n      Array(50)\n        .fill(0)\n        .map((_, index) => `index-${index}`),\n    []\n  );\n  const snapPoints = useMemo(() => ['25%', '50%', '90%'], []);\n\n  // callbacks\n  const handleSheetChange = useCallback(index => {\n    console.log('handleSheetChange', index);\n  }, []);\n  const handleSnapPress = useCallback(index => {\n    sheetRef.current?.snapTo(index);\n  }, []);\n  const handleClosePress = useCallback(() => {\n    sheetRef.current?.close();\n  }, []);\n\n  // render\n  const renderItem = useCallback(\n    item => (\n      <View style={styles.itemContainer}>\n        <Text>{item}</Text>\n      </View>\n    ),\n    []\n  );\n  return (\n    <View style={styles.container}>\n      <Button title=\"Snap To 90%\" onPress={() => handleSnapPress(2)} />\n      <Button title=\"Snap To 50%\" onPress={() => handleSnapPress(1)} />\n      <Button title=\"Snap To 25%\" onPress={() => handleSnapPress(0)} />\n      <Button title=\"Close\" onPress={() => handleClosePress()} />\n      <BottomSheet\n        ref={sheetRef}\n        index={1}\n        snapPoints={snapPoints}\n        onChange={handleSheetChange}\n      >\n        <BottomSheetView style={styles.contentContainer}>\n          {data.map(renderItem)}\n        </BottomSheetView>\n      </BottomSheet>\n    </View>\n  );\n};\n\nconst styles = StyleSheet.create({\n  container: {\n    flex: 1,\n    paddingTop: 200,\n  },\n  contentContainer: {\n    backgroundColor: 'white',\n  },\n  itemContainer: {\n    padding: 6,\n    margin: 6,\n    backgroundColor: '#eee',\n  },\n});\n\nexport default App;\n```\n"
  },
  {
    "path": "website/versioned_docs/version-2/sidebars.ts",
    "content": "import type { SidebarsConfig } from \"@docusaurus/plugin-content-docs\";\n\n/**\n * Creating a sidebar enables you to:\n - create an ordered group of docs\n - render a sidebar for each doc of that group\n - provide next/previous navigation\n\n The sidebars can be generated from the filesystem, or explicitly defined here.\n\n Create as many sidebars as you want.\n */\nconst sidebars: SidebarsConfig = {\n\t// By default, Docusaurus generates a sidebar from the docs folder structure\n\t// \"bottom-sheet\": [{ type: \"autogenerated\", dirName: \".\" }],\n\n\t// But you can create a sidebar manually\n\t\"bottom-sheet\": [\n\t\t{\n\t\t\ttype: \"category\",\n\t\t\tlabel: \"Bottom Sheet\",\n\t\t\tlink: {\n\t\t\t\ttype: \"doc\",\n\t\t\t\tid: \"index\",\n\t\t\t},\n\t\t\titems: [\n\t\t\t\t\"usage\",\n\t\t\t\t\"props\",\n\t\t\t\t\"methods\",\n\t\t\t\t\"hooks\",\n\t\t\t\t\"scrollables\",\n\t\t\t],\n\t\t},\n\t\t{\n\t\t\ttype: \"html\",\n\t\t\tvalue: \"<hr class='margin-vert--md margin-horiz--md' />\",\n\t\t\tdefaultStyle: false\n\t\t},\n\t\t{\n\t\t\ttype: \"category\",\n\t\t\tlabel: \"Bottom Sheet Modal\",\n\t\t\tlink: {\n\t\t\t\ttype: \"doc\",\n\t\t\t\tid: \"modal/index\",\n\t\t\t},\n\t\t\titems: [\"modal/usage\", \"modal/props\", \"modal/methods\", \"modal/hooks\"],\n\t\t},\n\t\t{\n\t\t\ttype: \"html\",\n\t\t\tvalue: \"<hr class='margin-vert--md margin-horiz--md' />\",\n\t\t\tdefaultStyle: false\n\t\t},\n\t\t{\n\t\t\ttype: \"category\",\n\t\t\tlabel: \"Guides\",\n\t\t\titems: [\n\t\t\t\t\"guides/custom-handle\",\n\t\t\t\t\"guides/custom-backdrop\",\n\t\t\t\t\"guides/custom-background\",\n\t\t\t\t\"guides/adding-shadow\",\n\t\t\t\t\"guides/react-navigation-integration\",\n\t\t\t],\n\t\t},\n\t\t\"troubleshooting\",\n\t\t\"faq\",\n\t\t{\n\t\t\ttype: \"html\",\n\t\t\tvalue: \"<hr class='margin-vert--md margin-horiz--md' />\",\n\t\t\tdefaultStyle: false\n\t\t},\n\t\t{\n\t\t\ttype: \"link\",\n\t\t\tlabel: \"Github\",\n\t\t\thref: \"https://github.com/gorhom/react-native-bottom-sheet\"\n\t\t}\n\t],\n};\n\nexport default sidebars;\n"
  },
  {
    "path": "website/versioned_docs/version-2/troubleshooting.md",
    "content": "---\nid: troubleshooting\ntitle: Troubleshooting\ndescription: Bottom Sheet troubleshooting.\nimage: /img/bottom-sheet-preview.gif\nslug: /troubleshooting\nhide_table_of_contents: true\n---\n\nThis section attempts to outline issues that users frequently encounter when first getting accustomed to using React Native Bottom Sheet. These issues may or may not be related to React Native Bottom Sheet itself.\n\n## Pressables / Touchables are not working on Android\n\nDue to wrapping the content and handle with `TapGestureHandler` & `PanGestureHandler`, any gesture interaction would not function as expected.\n\nTo resolve this issue, please use touchables that this library provide.\n\n```tsx\nimport {\n  TouchableOpacity,\n  TouchableHighlight,\n  TouchableWithoutFeedback,\n} from '@gorhom/bottom-sheet';\n```\n\n## Adding horizontal FlatList or ScrollView is not working properly on Android\n\nDue to wrapping the content and handle with `TapGestureHandler` & `PanGestureHandler`, any gesture interaction would not function as expected.\n\nTo resolve this issue, please use `ScrollView` & `FlatList` from `react-native-gesture-handler` provide instead `react-native`.\n\n```tsx\nimport {\n  ScrollView,\n  FlatList\n} from 'react-native-gesture-handler';\n```\n\n## My component gesture interaction gets conflicted with Bottom Sheet interactions ?\n\nTo avoid the gesture interaction conflict between the Bottom Sheet and its content, you will need to wrap your component with `NativeViewGestureHandler` from `react-native-gesture-handler`\n\n```tsx\nimport { NativeViewGestureHandler } from 'react-native-gesture-handler';\n\n<NativeViewGestureHandler disallowInterruption={true}>\n   <AwesomeComponent />\n</NativeViewGestureHandler>\n```\n"
  },
  {
    "path": "website/versioned_docs/version-2/usage.md",
    "content": "---\nid: usage\ntitle: Usage\ndescription: Bottom Sheet usage.\nimage: /img/bottom-sheet-preview.gif\nslug: /usage\n---\n\nHere is a simple usage of the **Bottom Sheet**, with non-scrollable content. For more scrollable usage please read [Scrollables](./scrollables).\n\n```tsx\nimport React, { useCallback, useMemo, useRef } from 'react';\nimport { View, Text, StyleSheet } from 'react-native';\nimport BottomSheet from '@gorhom/bottom-sheet';\n\nconst App = () => {\n  // ref\n  const bottomSheetRef = useRef<BottomSheet>(null);\n\n  // variables\n  const snapPoints = useMemo(() => ['25%', '50%'], []);\n\n  // callbacks\n  const handleSheetChanges = useCallback((index: number) => {\n    console.log('handleSheetChanges', index);\n  }, []);\n\n  // renders\n  return (\n    <View style={styles.container}>\n      <BottomSheet\n        ref={bottomSheetRef}\n        index={1}\n        snapPoints={snapPoints}\n        onChange={handleSheetChanges}\n      >\n        <View style={styles.contentContainer}>\n          <Text>Awesome 🎉</Text>\n        </View>\n      </BottomSheet>\n    </View>\n  );\n};\n\nconst styles = StyleSheet.create({\n  container: {\n    flex: 1,\n    padding: 24,\n    backgroundColor: 'grey',\n  },\n  contentContainer: {\n    flex: 1,\n    alignItems: 'center',\n  },\n});\n\nexport default App;\n```"
  },
  {
    "path": "website/versioned_docs/version-4/components/bottomsheetbackdrop.md",
    "content": "---\nid: bottomsheetbackdrop\ntitle: BottomSheetBackdrop\nsidebar_label: Backdrop\ndescription: a pre-built BottomSheet backdrop implementation with configurable props.\nimage: /img/bottom-sheet-preview.gif\nslug: /components/bottomsheetbackdrop\n---\n\nA pre-built BottomSheet backdrop implementation with configurable props.\n\n## Props\n\nInherits `ViewProps` from `react-native`.\n\n### animatedIndex\n\nCurrent sheet position index.\n\n| type                          | default | required |\n| ----------------------------- | ------- | -------- |\n| Animated.SharedValue\\<number> | 0       | YES      |\n\n### animatedPosition\n\nCurrent sheet position.\n\n| type                          | default | required |\n| ----------------------------- | ------- | -------- |\n| Animated.SharedValue<number/> | 0       | YES      |\n\n### opacity\n\nBackdrop opacity.\n\n| type   | default | required |\n| ------ | ------- | -------- |\n| number | 0.5     | NO       |\n\n### appearsOnIndex\n\nSnap point index when backdrop will appears on.\n\n| type   | default | required |\n| ------ | ------- | -------- |\n| number | 1       | NO       |\n\n### disappearsOnIndex\n\nSnap point index when backdrop will disappears on.\n\n| type   | default | required |\n| ------ | ------- | -------- |\n| number | 0       | NO       |\n\n### enableTouchThrough\n\nEnable touch through backdrop component.\n\n| type    | default | required |\n| ------- | ------- | -------- |\n| boolean | false   | NO       |\n\n### pressBehavior\n\nWhat should happen when user press backdrop?\n\n- `none`: do nothing, and `onPress` prop will be ignored.\n- `close`: close the sheet.\n- `collapse`: collapse the sheet.\n- `N`: snap point index.\n\n| type                              | default | required |\n| --------------------------------- | ------- | -------- |\n| `BackdropPressBehavior` \\| number | 'close' | NO       |\n\n### onPress\n\nPressing the backdrop will call the `onPress` function, it will be called before the action defined by `pressBehavior` is executed\n\n| type     | default   | required |\n| -------- | --------- | -------- |\n| function | undefined | NO       |\n\n## Example\n\n```tsx\nimport React, { useCallback, useMemo, useRef } from \"react\";\nimport { View, Text, StyleSheet } from \"react-native\";\nimport BottomSheet, { BottomSheetBackdrop } from \"@gorhom/bottom-sheet\";\n\nconst App = () => {\n\t// ref\n\tconst bottomSheetRef = useRef<BottomSheet>(null);\n\n\t// variables\n\tconst snapPoints = useMemo(() => [\"25%\", \"50%\", \"75%\"], []);\n\n\t// callbacks\n\tconst handleSheetChanges = useCallback((index: number) => {\n\t\tconsole.log(\"handleSheetChanges\", index);\n\t}, []);\n\n\t// renders\n\tconst renderBackdrop = useCallback(\n\t\t(props) => (\n\t\t\t<BottomSheetBackdrop\n\t\t\t\t{...props}\n\t\t\t\tdisappearsOnIndex={1}\n\t\t\t\tappearsOnIndex={2}\n\t\t\t/>\n\t\t),\n\t\t[]\n\t);\n\treturn (\n\t\t<View style={styles.container}>\n\t\t\t<BottomSheet\n\t\t\t\tref={bottomSheetRef}\n\t\t\t\tindex={1}\n\t\t\t\tsnapPoints={snapPoints}\n\t\t\t\tbackdropComponent={renderBackdrop}\n\t\t\t\tonChange={handleSheetChanges}\n\t\t\t>\n\t\t\t\t<View style={styles.contentContainer}>\n\t\t\t\t\t<Text>Awesome 🎉</Text>\n\t\t\t\t</View>\n\t\t\t</BottomSheet>\n\t\t</View>\n\t);\n};\n\nconst styles = StyleSheet.create({\n\tcontainer: {\n\t\tflex: 1,\n\t\tpadding: 24,\n\t\tbackgroundColor: \"grey\",\n\t},\n\tcontentContainer: {\n\t\tflex: 1,\n\t\talignItems: \"center\",\n\t},\n});\n\nexport default App;\n```\n"
  },
  {
    "path": "website/versioned_docs/version-4/components/bottomsheetflatlist.md",
    "content": "---\nid: bottomsheetflatlist\ntitle: BottomSheetFlatList\nsidebar_label: FlatList\ndescription: a pre-integrated React Native FlatList with BottomSheet gestures.\nimage: /img/bottom-sheet-preview.gif\nslug: /components/bottomsheetflatlist\n---\n\nA pre-integrated `React Native` FlatList with `BottomSheet` gestures.\n\n## Props\n\nInherits `FlatListProps` from `react-native`.\n\n### focusHook\n\nThis needed when bottom sheet used with multiple scrollables to allow bottom sheet detect the current scrollable ref, especially when used with React Navigation. You will need to provide `useFocusEffect` from `@react-navigation/native`.\n\n| type     | default           | required |\n| -------- | ----------------- | -------- |\n| function | `React.useEffect` | NO       |\n\n## Ignored Props\n\nThese props will be ignored if they were passed, because of the internal integration that uses them.\n\n- `scrollEventThrottle`\n- `decelerationRate`\n- `onScrollBeginDrag`\n\n## Example\n\n```tsx\nimport React, { useCallback, useRef, useMemo } from \"react\";\nimport { StyleSheet, View, Text, Button } from \"react-native\";\nimport BottomSheet, { BottomSheetFlatList } from \"@gorhom/bottom-sheet\";\n\nconst App = () => {\n  // hooks\n  const sheetRef = useRef<BottomSheet>(null);\n\n  // variables\n  const data = useMemo(\n    () =>\n      Array(50)\n        .fill(0)\n        .map((_, index) => `index-${index}`),\n    []\n  );\n  const snapPoints = useMemo(() => [\"25%\", \"50%\", \"90%\"], []);\n\n  // callbacks\n  const handleSheetChange = useCallback((index) => {\n    console.log(\"handleSheetChange\", index);\n  }, []);\n  const handleSnapPress = useCallback((index) => {\n    sheetRef.current?.snapToIndex(index);\n  }, []);\n  const handleClosePress = useCallback(() => {\n    sheetRef.current?.close();\n  }, []);\n\n  // render\n  const renderItem = useCallback(\n    ({ item }) => (\n      <View style={styles.itemContainer}>\n        <Text>{item}</Text>\n      </View>\n    ),\n    []\n  );\n  return (\n    <View style={styles.container}>\n      <Button title=\"Snap To 90%\" onPress={() => handleSnapPress(2)} />\n      <Button title=\"Snap To 50%\" onPress={() => handleSnapPress(1)} />\n      <Button title=\"Snap To 25%\" onPress={() => handleSnapPress(0)} />\n      <Button title=\"Close\" onPress={() => handleClosePress()} />\n      <BottomSheet\n        ref={sheetRef}\n        snapPoints={snapPoints}\n        onChange={handleSheetChange}\n      >\n        <BottomSheetFlatList\n          data={data}\n          keyExtractor={(i) => i}\n          renderItem={renderItem}\n          contentContainerStyle={styles.contentContainer}\n        />\n      </BottomSheet>\n    </View>\n  );\n};\n\nconst styles = StyleSheet.create({\n  container: {\n    flex: 1,\n    paddingTop: 200,\n  },\n  contentContainer: {\n    backgroundColor: \"white\",\n  },\n  itemContainer: {\n    padding: 6,\n    margin: 6,\n    backgroundColor: \"#eee\",\n  },\n});\n\nexport default App;\n```\n"
  },
  {
    "path": "website/versioned_docs/version-4/components/bottomsheetfooter.md",
    "content": "---\nid: bottomsheetfooter\ntitle: BottomSheetFooter\nsidebar_label: Footer\ndescription: an interactive footer component for the BottomSheet.\nimage: /img/bottom-sheet-preview.gif\nslug: /components/bottomsheetfooter\n---\n\nA pre-built component that sticks to the bottom of the BottomSheet and can be modify to fit your own custom interaction.\n\n## Props\n\n### animatedFooterPosition\n\nCalculated footer animated position.\n\n| type                          | default | required |\n| ----------------------------- | ------- | -------- |\n| Animated.SharedValue\\<number> | 0       | NO       |\n\n### bottomInset\n\nBottom inset to be added below the footer.\n\n| type   | default | required |\n| ------ | ------- | -------- |\n| number | 0       | NO       |\n\n### children\n\nComponent to be placed in the footer.\n\n| type                     | default   | required |\n| ------------------------ | --------- | -------- |\n| ReactNode \\| ReactNode[] | undefined | NO       |\n\n## Example\n\n```tsx\nimport React, { useCallback, useMemo, useRef } from 'react';\nimport { View, Text, StyleSheet } from 'react-native';\nimport BottomSheet, { BottomSheetFooter } from '@gorhom/bottom-sheet';\n\nconst App = () => {\n  // ref\n  const bottomSheetRef = useRef<BottomSheet>(null);\n\n  // variables\n  const snapPoints = useMemo(() => ['25%', '50%'], []);\n\n  // renders\n  const renderFooter = useCallback(\n    props => (\n      <BottomSheetFooter {...props} bottomInset={24}>\n        <View style={styles.footerContainer}>\n          <Text style={styles.footerText}>Footer</Text>\n        </View>\n      </BottomSheetFooter>\n    ),\n    []\n  );\n  return (\n    <View style={styles.container}>\n      <BottomSheet\n        ref={bottomSheetRef}\n        index={1}\n        snapPoints={snapPoints}\n        footerComponent={renderFooter}\n      >\n        <View style={styles.contentContainer}>\n          <Text>Awesome 🎉</Text>\n        </View>\n      </BottomSheet>\n    </View>\n  );\n};\n\nconst styles = StyleSheet.create({\n  container: {\n    flex: 1,\n    padding: 24,\n    backgroundColor: 'grey',\n  },\n  contentContainer: {\n    flex: 1,\n    alignItems: 'center',\n  },\n  footerContainer: {\n    padding: 12,\n    margin: 12,\n    borderRadius: 12,\n    backgroundColor: '#80f',\n  },\n  footerText: {\n    textAlign: 'center',\n    color: 'white',\n    fontWeight: '800',\n  },\n});\n\nexport default App;\n```\n"
  },
  {
    "path": "website/versioned_docs/version-4/components/bottomsheetscrollview.md",
    "content": "---\nid: bottomsheetscrollview\ntitle: BottomSheetScrollView\nsidebar_label: ScrollView\ndescription: a pre-integrated React Native ScrollView with BottomSheet gestures.\nimage: /img/bottom-sheet-preview.gif\nslug: /components/bottomsheetscrollview\n---\n\nA pre-integrated `React Native` ScrollView with `BottomSheet` gestures.\n\n## Props\n\nInherits `ScrollViewProps` from `react-native`.\n\n### focusHook\n\nThis needed when bottom sheet used with multiple scrollables to allow bottom sheet detect the current scrollable ref, especially when used with React Navigation. You will need to provide `useFocusEffect` from `@react-navigation/native`.\n\n| type     | default           | required |\n| -------- | ----------------- | -------- |\n| function | `React.useEffect` | NO       |\n\n## Ignored Props\n\nThese props will be ignored if they were passed, because of the internal integration that uses them.\n\n- `scrollEventThrottle`\n- `decelerationRate`\n- `onScrollBeginDrag`\n\n## Example\n\n```tsx\nimport React, { useCallback, useRef, useMemo } from \"react\";\nimport { StyleSheet, View, Text, Button } from \"react-native\";\nimport BottomSheet, { BottomSheetScrollView } from \"@gorhom/bottom-sheet\";\n\nconst App = () => {\n  // hooks\n  const sheetRef = useRef<BottomSheet>(null);\n\n  // variables\n  const data = useMemo(\n    () =>\n      Array(50)\n        .fill(0)\n        .map((_, index) => `index-${index}`),\n    []\n  );\n  const snapPoints = useMemo(() => [\"25%\", \"50%\", \"90%\"], []);\n\n  // callbacks\n  const handleSheetChange = useCallback((index) => {\n    console.log(\"handleSheetChange\", index);\n  }, []);\n  const handleSnapPress = useCallback((index) => {\n    sheetRef.current?.snapToIndex(index);\n  }, []);\n  const handleClosePress = useCallback(() => {\n    sheetRef.current?.close();\n  }, []);\n\n  // render\n  const renderItem = useCallback(\n    (item) => (\n      <View key={item} style={styles.itemContainer}>\n        <Text>{item}</Text>\n      </View>\n    ),\n    []\n  );\n  return (\n    <View style={styles.container}>\n      <Button title=\"Snap To 90%\" onPress={() => handleSnapPress(2)} />\n      <Button title=\"Snap To 50%\" onPress={() => handleSnapPress(1)} />\n      <Button title=\"Snap To 25%\" onPress={() => handleSnapPress(0)} />\n      <Button title=\"Close\" onPress={() => handleClosePress()} />\n      <BottomSheet\n        ref={sheetRef}\n        index={1}\n        snapPoints={snapPoints}\n        onChange={handleSheetChange}\n      >\n        <BottomSheetScrollView contentContainerStyle={styles.contentContainer}>\n          {data.map(renderItem)}\n        </BottomSheetScrollView>\n      </BottomSheet>\n    </View>\n  );\n};\n\nconst styles = StyleSheet.create({\n  container: {\n    flex: 1,\n    paddingTop: 200,\n  },\n  contentContainer: {\n    backgroundColor: \"white\",\n  },\n  itemContainer: {\n    padding: 6,\n    margin: 6,\n    backgroundColor: \"#eee\",\n  },\n});\n\nexport default App;\n```\n"
  },
  {
    "path": "website/versioned_docs/version-4/components/bottomsheetsectionlist.md",
    "content": "---\nid: bottomsheetsectionlist\ntitle: BottomSheetSectionList\nsidebar_label: SectionList\ndescription: a pre-integrated React Native SectionList with BottomSheet gestures.\nimage: /img/bottom-sheet-preview.gif\nslug: /components/bottomsheetsectionlist\n---\n\nA pre-integrated `React Native` SectionList with `BottomSheet` gestures.\n\n## Props\n\nInherits `SectionListProps` from `react-native`.\n\n### focusHook\n\nThis needed when bottom sheet used with multiple scrollables to allow bottom sheet detect the current scrollable ref, especially when used with React Navigation. You will need to provide `useFocusEffect` from `@react-navigation/native`.\n\n| type     | default           | required |\n| -------- | ----------------- | -------- |\n| function | `React.useEffect` | NO       |\n\n## Ignored Props\n\nThese props will be ignored if they were passed, because of the internal integration that uses them.\n\n- `scrollEventThrottle`\n- `decelerationRate`\n- `onScrollBeginDrag`\n\n## Example\n\n```tsx\nimport React, { useCallback, useRef, useMemo } from \"react\";\nimport { StyleSheet, View, Text, Button } from \"react-native\";\nimport BottomSheet, { BottomSheetSectionList } from \"@gorhom/bottom-sheet\";\n\nconst App = () => {\n  // hooks\n  const sheetRef = useRef<BottomSheet>(null);\n\n  // variables\n  const sections = useMemo(\n    () =>\n      Array(10)\n        .fill(0)\n        .map((_, index) => ({\n          title: `Section ${index}`,\n          data: Array(10)\n            .fill(0)\n            .map((_, index) => `Item ${index}`),\n        })),\n    []\n  );\n  const snapPoints = useMemo(() => [\"25%\", \"50%\", \"90%\"], []);\n\n  // callbacks\n  const handleSheetChange = useCallback((index) => {\n    console.log(\"handleSheetChange\", index);\n  }, []);\n  const handleSnapPress = useCallback((index) => {\n    sheetRef.current?.snapToIndex(index);\n  }, []);\n  const handleClosePress = useCallback(() => {\n    sheetRef.current?.close();\n  }, []);\n\n  // render\n  const renderSectionHeader = useCallback(\n    ({ section }) => (\n      <View style={styles.sectionHeaderContainer}>\n        <Text>{section.title}</Text>\n      </View>\n    ),\n    []\n  );\n  const renderItem = useCallback(\n    ({ item }) => (\n      <View style={styles.itemContainer}>\n        <Text>{item}</Text>\n      </View>\n    ),\n    []\n  );\n  return (\n    <View style={styles.container}>\n      <Button title=\"Snap To 90%\" onPress={() => handleSnapPress(2)} />\n      <Button title=\"Snap To 50%\" onPress={() => handleSnapPress(1)} />\n      <Button title=\"Snap To 25%\" onPress={() => handleSnapPress(0)} />\n      <Button title=\"Close\" onPress={() => handleClosePress()} />\n      <BottomSheet\n        ref={sheetRef}\n        index={1}\n        snapPoints={snapPoints}\n        onChange={handleSheetChange}\n      >\n        <BottomSheetSectionList\n          sections={sections}\n          keyExtractor={(i) => i}\n          renderSectionHeader={renderSectionHeader}\n          renderItem={renderItem}\n          contentContainerStyle={styles.contentContainer}\n        />\n      </BottomSheet>\n    </View>\n  );\n};\n\nconst styles = StyleSheet.create({\n  container: {\n    flex: 1,\n    paddingTop: 200,\n  },\n  contentContainer: {\n    backgroundColor: \"white\",\n  },\n  sectionHeaderContainer: {\n    backgroundColor: \"white\",\n    padding: 6,\n  },\n  itemContainer: {\n    padding: 6,\n    margin: 6,\n    backgroundColor: \"#eee\",\n  },\n});\n\nexport default App;\n```\n"
  },
  {
    "path": "website/versioned_docs/version-4/components/bottomsheettextinput.md",
    "content": "---\nid: bottomsheettextinput\ntitle: BottomSheetTextInput\nsidebar_label: TextInput\ndescription: an pre-integrated TextInput component for better keyboard handling.\nimage: /img/bottom-sheet-preview.gif\nslug: /components/bottomsheettextinput\n---\n\nA pre-integrated `TextInput` that communicate with internal functionalities to allow Keyboard handling to work.\n\n## Props\n\nInherits `TextInputProps` from `react-native`.\n\n## Example\n\n```tsx\nimport React, { useCallback, useMemo, useRef } from 'react';\nimport { View, Text, StyleSheet } from 'react-native';\nimport BottomSheet, { BottomSheetTextInput } from '@gorhom/bottom-sheet';\n\nconst App = () => {\n  // ref\n  const bottomSheetRef = useRef<BottomSheet>(null);\n\n  // variables\n  const snapPoints = useMemo(() => ['25%', '50%'], []);\n\n  // callbacks\n  const handleSheetChanges = useCallback((index: number) => {\n    console.log('handleSheetChanges', index);\n  }, []);\n\n  // renders\n  return (\n    <View style={styles.container}>\n      <BottomSheet\n        ref={bottomSheetRef}\n        index={1}\n        snapPoints={snapPoints}\n        keyboardBehavior=\"fillParent\"\n        onChange={handleSheetChanges}\n      >\n        <BottomSheetTextInput style={styles.input} />\n        <View style={styles.contentContainer}>\n          <Text>Awesome 🎉</Text>\n        </View>\n      </BottomSheet>\n    </View>\n  );\n};\n\nconst styles = StyleSheet.create({\n  container: {\n    flex: 1,\n    padding: 24,\n    backgroundColor: 'grey',\n  },\n  contentContainer: {\n    flex: 1,\n    alignItems: 'center',\n  },\n  input: {\n    marginTop: 8,\n    marginBottom: 10,\n    borderRadius: 10,\n    fontSize: 16,\n    lineHeight: 20,\n    padding: 8,\n    backgroundColor: 'rgba(151, 151, 151, 0.25)',\n  },\n});\n\nexport default App;\n```\n"
  },
  {
    "path": "website/versioned_docs/version-4/components/bottomsheetview.md",
    "content": "---\nid: bottomsheetview\ntitle: BottomSheetView\nsidebar_label: View\ndescription: a pre-integrated React Native View with BottomSheet gestures.\nimage: /img/bottom-sheet-preview.gif\nslug: /components/bottomsheetview\n---\n\nA pre-integrated `React Native` View with `BottomSheet` gestures.\n\n## Props\n\nInherits `ViewProps` from `react-native`.\n\n### focusHook\n\nThis needed when bottom sheet used with multiple scrollables to allow bottom sheet detect the current scrollable ref, especially when used with React Navigation. You will need to provide `useFocusEffect` from `@react-navigation/native`.\n\n| type     | default           | required |\n| -------- | ----------------- | -------- |\n| function | `React.useEffect` | NO       |\n\n## Example\n\n```tsx\nimport React, { useCallback, useRef, useMemo } from \"react\";\nimport { StyleSheet, View, Text, Button } from \"react-native\";\nimport BottomSheet, { BottomSheetView } from \"@gorhom/bottom-sheet\";\n\nconst App = () => {\n  // hooks\n  const sheetRef = useRef<BottomSheet>(null);\n\n  // variables\n  const snapPoints = useMemo(() => [\"25%\", \"50%\", \"90%\"], []);\n\n  // callbacks\n  const handleSheetChange = useCallback((index) => {\n    console.log(\"handleSheetChange\", index);\n  }, []);\n  const handleSnapPress = useCallback((index) => {\n    sheetRef.current?.snapToIndex(index);\n  }, []);\n  const handleClosePress = useCallback(() => {\n    sheetRef.current?.close();\n  }, []);\n\n  // render\n  return (\n    <View style={styles.container}>\n      <Button title=\"Snap To 90%\" onPress={() => handleSnapPress(2)} />\n      <Button title=\"Snap To 50%\" onPress={() => handleSnapPress(1)} />\n      <Button title=\"Snap To 25%\" onPress={() => handleSnapPress(0)} />\n      <Button title=\"Close\" onPress={() => handleClosePress()} />\n      <BottomSheet\n        ref={sheetRef}\n        snapPoints={snapPoints}\n        onChange={handleSheetChange}\n      >\n        <BottomSheetView>\n          <Text>Awesome 🔥</Text>\n        </BottomSheetView>\n      </BottomSheet>\n    </View>\n  );\n};\n\nconst styles = StyleSheet.create({\n  container: {\n    flex: 1,\n    paddingTop: 200,\n  },\n});\n\nexport default App;\n```\n"
  },
  {
    "path": "website/versioned_docs/version-4/components/bottomsheetvirtualizedlist.md",
    "content": "---\nid: bottomsheetvirtualizedlist\ntitle: BottomSheetVirtualizedList\nsidebar_label: VirtualizedList\ndescription: a pre-integrated React Native VirtualizedList with BottomSheet gestures.\nimage: /img/bottom-sheet-preview.gif\nslug: /components/bottomsheetvirtualizedlist\n---\n\nA pre-integrated `React Native` VirtualizedList with `BottomSheet` gestures.\n\n## Props\n\nInherits `VirtualizedListProps` from `react-native`.\n\n### focusHook\n\nThis needed when bottom sheet used with multiple scrollables to allow bottom sheet detect the current scrollable ref, especially when used with React Navigation. You will need to provide `useFocusEffect` from `@react-navigation/native`.\n\n| type     | default           | required |\n| -------- | ----------------- | -------- |\n| function | `React.useEffect` | NO       |\n\n## Ignored Props\n\nThese props will be ignored if they were passed, because of the internal integration that uses them.\n\n- `scrollEventThrottle`\n- `decelerationRate`\n- `onScrollBeginDrag`\n\n## Example\n\n```tsx\nimport React, { useCallback, useRef, useMemo } from \"react\";\nimport { StyleSheet, View, Text, Button } from \"react-native\";\nimport BottomSheet, { BottomSheetVirtualizedList } from \"@gorhom/bottom-sheet\";\n\nconst App = () => {\n  // hooks\n  const sheetRef = useRef<BottomSheet>(null);\n\n  // variables\n  const data = useMemo(\n    () =>\n      Array(50)\n        .fill(0)\n        .map((_, index) => `index-${index}`),\n    []\n  );\n  const snapPoints = useMemo(() => [\"25%\", \"50%\", \"90%\"], []);\n\n  // callbacks\n  const handleSheetChange = useCallback((index) => {\n    console.log(\"handleSheetChange\", index);\n  }, []);\n  const handleSnapPress = useCallback((index) => {\n    sheetRef.current?.snapToIndex(index);\n  }, []);\n  const handleClosePress = useCallback(() => {\n    sheetRef.current?.close();\n  }, []);\n\n  // render\n  const renderItem = useCallback(\n    ({ item }) => (\n      <View style={styles.itemContainer}>\n        <Text>{item}</Text>\n      </View>\n    ),\n    []\n  );\n  return (\n    <View style={styles.container}>\n      <Button title=\"Snap To 90%\" onPress={() => handleSnapPress(2)} />\n      <Button title=\"Snap To 50%\" onPress={() => handleSnapPress(1)} />\n      <Button title=\"Snap To 25%\" onPress={() => handleSnapPress(0)} />\n      <Button title=\"Close\" onPress={() => handleClosePress()} />\n      <BottomSheet\n        ref={sheetRef}\n        snapPoints={snapPoints}\n        onChange={handleSheetChange}\n      >\n        <BottomSheetVirtualizedList\n          data={data}\n          keyExtractor={(i) => i}\n          getItemCount={(data) => data.length}\n          getItem={(data, index) => data[index]}\n          renderItem={renderItem}\n          contentContainerStyle={styles.contentContainer}\n        />\n      </BottomSheet>\n    </View>\n  );\n};\n\nconst styles = StyleSheet.create({\n  container: {\n    flex: 1,\n    paddingTop: 200,\n  },\n  contentContainer: {\n    backgroundColor: \"white\",\n  },\n  itemContainer: {\n    padding: 6,\n    margin: 6,\n    backgroundColor: \"#eee\",\n  },\n});\n\nexport default App;\n```\n"
  },
  {
    "path": "website/versioned_docs/version-4/faq.md",
    "content": "---\nid: faq\ntitle: FAQ\ndescription: Bottom Sheet FAQ.\nimage: /img/bottom-sheet-preview.gif\nslug: /faq\nhide_table_of_contents: true\n---\n\n### How this library differ from `reanimated-bottom-sheet` or `react-native-scroll-bottom-sheet`?\n\nThis library was built to provide the most native-like experience and could fit any use-case that developers wants it to be. While both libraries providing similar experience, but they still missing the following:\n\n- `reanimated-bottom-sheet`: Seamless gesture interaction between the sheet and the content.\n- `react-native-scroll-bottom-sheet`: Extracting scrollable content to allow developers customize the sheet content, like integrate React Navigation as the sheet content.\n\nBoth libraries are great! and I have used both of them at my work ❤️\n"
  },
  {
    "path": "website/versioned_docs/version-4/guides/adding-shadow.mdx",
    "content": "---\nid: adding-shadow\ntitle: Adding Shadow\ndescription: Adding shadow to the Bottom Sheet.\nimage: /img/bottom-sheet-preview.gif\nslug: /adding-shadow\nhide_table_of_contents: true\n---\n\n![React Native Bottom Sheet Shadow](/img/bottom-sheet-shadow.jpg)\n\nTo add shadow to the bottom sheet, you will need to pass the `style` prop with shadow styling config, I recommend checking out [React Native Shadow Generator](https://ethercreative.github.io/react-native-shadow-generator/) by [@ethercreative](https://github.com/ethercreative).\n\n:::note NOTICE\n\nYou may notice that shadow looks different between **iOS** and **Android**, that's because each platform handle drawing shadows differently, read more about [Android Shadows](https://developer.android.com/training/material/shadows-clipping).\n\n:::\n"
  },
  {
    "path": "website/versioned_docs/version-4/guides/custom-backdrop.mdx",
    "content": "---\nid: custom-backdrop\ntitle: Custom Backdrop\ndescription: Bottom Sheet custom backdrop.\nimage: /img/bottom-sheet-preview.gif\nslug: /custom-backdrop\nhide_table_of_contents: true\n---\n\nTo add a backdrop to your sheet you will need to pass the prop `backdropComponent` to the `BottomSheet` component.\n\nWhen you provide your own backdrop component, it will receive these animated props `animatedIndex` & `animatedPosition` that indicates the position and the index of the sheet.\n\nYou can extend your custom backdrop props interface with the provided `BottomSheetBackdropProps` interface to expose `animatedIndex` & `animatedPosition` into your own interface.\n\n### Example\n\nimport useBaseUrl from \"@docusaurus/useBaseUrl\";\nimport Video from \"@theme/Video\";\n\n<Video\n  title=\"React Native Bottom Sheet Custom Backdrop\"\n  url={useBaseUrl(\"video/bottom-sheet-custom-backdrop-preview.mp4\")}\n/>\n\nHere is an example of a custom backdrop component:\n\n```tsx\nimport React, { useMemo } from \"react\";\nimport { BottomSheetBackdropProps } from \"@gorhom/bottom-sheet\";\nimport Animated, {\n  Extrapolate,\n  interpolate,\n  useAnimatedStyle,\n} from \"react-native-reanimated\";\n\nconst CustomBackdrop = ({ animatedIndex, style }: BottomSheetBackdropProps) => {\n  // animated variables\n  const containerAnimatedStyle = useAnimatedStyle(() => ({\n    opacity: interpolate(\n      animatedIndex.value,\n      [0, 1],\n      [0, 1],\n      Extrapolate.CLAMP\n    ),\n  }));\n\n  // styles\n  const containerStyle = useMemo(\n    () => [\n      style,\n      {\n        backgroundColor: \"#a8b5eb\",\n      },\n      containerAnimatedStyle,\n    ],\n    [style, containerAnimatedStyle]\n  );\n\n  return <Animated.View style={containerStyle} />;\n};\n\nexport default CustomBackdrop;\n```\n"
  },
  {
    "path": "website/versioned_docs/version-4/guides/custom-background.mdx",
    "content": "---\nid: custom-background\ntitle: Custom Background\ndescription: Bottom Sheet custom background.\nimage: /img/bottom-sheet-preview.gif\nslug: /custom-background\nhide_table_of_contents: true\n---\n\nTo override the default background, you will need to pass the prop `backgroundComponent` to the `BottomSheet` component.\n\nWhen you provide your own background component, it will receive these animated props `animatedIndex` & `animatedPosition` that indicates the position and the index of the sheet.\n\nYou can extend your custom background props interface with the provided `BottomSheetBackgroundProps` interface to expose `animatedIndex` & `animatedPosition` into your own interface.\n\n### Example\n\nimport useBaseUrl from \"@docusaurus/useBaseUrl\";\nimport Video from \"@theme/Video\";\n\n<Video\n  title=\"React Native Bottom Sheet Custom Background\"\n  url={useBaseUrl(\"video/bottom-sheet-custom-background-preview.mp4\")}\n/>\n\nHere is an example of a custom background component:\n\n```tsx\nimport React, { useMemo } from \"react\";\nimport { BottomSheetBackgroundProps } from \"@gorhom/bottom-sheet\";\nimport Animated, {\n  useAnimatedStyle,\n  interpolateColor,\n} from \"react-native-reanimated\";\n\nconst CustomBackground: React.FC<BottomSheetBackgroundProps> = ({\n  style,\n  animatedIndex,\n}) => {\n  //#region styles\n  const containerAnimatedStyle = useAnimatedStyle(() => ({\n    // @ts-ignore\n    backgroundColor: interpolateColor(\n      animatedIndex.value,\n      [0, 1],\n      [\"#ffffff\", \"#a8b5eb\"]\n    ),\n  }));\n  const containerStyle = useMemo(\n    () => [style, containerAnimatedStyle],\n    [style, containerAnimatedStyle]\n  );\n  //#endregion\n\n  // render\n  return <Animated.View pointerEvents=\"none\" style={containerStyle} />;\n};\n\nexport default CustomBackground;\n```\n"
  },
  {
    "path": "website/versioned_docs/version-4/guides/custom-footer.mdx",
    "content": "---\nid: custom-footer\ntitle: Custom Footer\ndescription: Bottom Sheet custom footer.\nimage: /img/bottom-sheet-preview.gif\nslug: /custom-footer\nhide_table_of_contents: true\n---\n\nTo create a custom footer, you will need to use the pre-built component [BottomSheetFooter](./components/bottomsheetfooter) to wrap your footer component, the `BottomSheetFooter` will help in positioning your component at the bottom of the `BottomSheet` and will react to `Keyboard` appearance too.\n\nWhen you provide your own footer component, it will receive this animated prop `animatedFooterPosition`, which is a calculated animated position for the footer.\n\nYou can extend your custom footer props interface with the provided `BottomSheetFooterProps` interface to expose `animatedFooterPosition` into your own interface.\n\n### Example\n\nimport useBaseUrl from '@docusaurus/useBaseUrl';\nimport Video from '@theme/Video';\n\n<Video\n  title=\"React Native Bottom Sheet Custom Footer\"\n  url={useBaseUrl('video/bottom-sheet-footer-preview.mp4')}\n/>\n\nHere is an example of a custom footer component but first you will need to install `Redash`:\n\n> [Redash](https://github.com/wcandillon/react-native-redash): The React Native Reanimated and Gesture Handler Toolbelt.\n\n```tsx title=\"CustomFooter.tsx\"\nimport React, { useCallback, useMemo } from 'react';\nimport { StyleSheet } from 'react-native';\nimport {\n  BottomSheetFooter,\n  BottomSheetFooterProps,\n  useBottomSheet,\n} from '@gorhom/bottom-sheet';\nimport { RectButton } from 'react-native-gesture-handler';\nimport { useSafeAreaInsets } from 'react-native-safe-area-context';\nimport Animated, {\n  Extrapolate,\n  interpolate,\n  useAnimatedStyle,\n} from 'react-native-reanimated';\nimport { toRad } from 'react-native-redash';\n\nconst AnimatedRectButton = Animated.createAnimatedComponent(RectButton);\n\n// inherent the `BottomSheetFooterProps` to be able receive\n// `animatedFooterPosition`.\ninterface CustomFooterProps extends BottomSheetFooterProps {}\n\nconst CustomFooter = ({ animatedFooterPosition }: CustomFooterProps) => {\n  //#region hooks\n  // we need the bottom safe insets to avoid bottom notches.\n  const { bottom: bottomSafeArea } = useSafeAreaInsets();\n  // extract animated index and other functionalities\n  const { expand, collapse, animatedIndex } = useBottomSheet();\n  //#endregion\n\n  //#region styles\n  // create the arrow animated style reacting to the\n  // sheet index.\n  const arrowAnimatedStyle = useAnimatedStyle(() => {\n    const arrowRotate = interpolate(\n      animatedIndex.value,\n      [0, 1],\n      [toRad(0), toRad(-180)],\n      Extrapolate.CLAMP\n    );\n    return {\n      transform: [{ rotate: `${arrowRotate}rad` }],\n    };\n  }, []);\n  const arrowStyle = useMemo(\n    () => [arrowAnimatedStyle, styles.arrow],\n    [arrowAnimatedStyle]\n  );\n  // create the content animated style reacting to the\n  // sheet index.\n  const containerAnimatedStyle = useAnimatedStyle(\n    () => ({\n      opacity: interpolate(\n        animatedIndex.value,\n        [-0.85, 0],\n        [0, 1],\n        Extrapolate.CLAMP\n      ),\n    }),\n    [animatedIndex]\n  );\n  const containerStyle = useMemo(\n    () => [containerAnimatedStyle, styles.container],\n    [containerAnimatedStyle]\n  );\n  //#endregion\n\n  //#region callbacks\n  const handleArrowPress = useCallback(() => {\n    // if sheet is collapsed, then we extend it,\n    // or the opposite.\n    if (animatedIndex.value === 0) {\n      expand();\n    } else {\n      collapse();\n    }\n  }, [expand, collapse, animatedIndex]);\n  //#endregion\n\n  return (\n    <BottomSheetFooter\n      // we pass the bottom safe inset\n      bottomInset={bottomSafeArea}\n      // we pass the provided `animatedFooterPosition`\n      animatedFooterPosition={animatedFooterPosition}\n    >\n      <AnimatedRectButton style={containerStyle} onPress={handleArrowPress}>\n        <Animated.Text style={arrowStyle}>⌃</Animated.Text>\n      </AnimatedRectButton>\n    </BottomSheetFooter>\n  );\n};\n\n// footer style\nconst styles = StyleSheet.create({\n  container: {\n    alignSelf: 'flex-end',\n    justifyContent: 'center',\n    alignItems: 'center',\n    marginHorizontal: 24,\n    marginBottom: 12,\n    width: 50,\n    height: 50,\n    borderRadius: 25,\n    backgroundColor: '#80f',\n    shadowOffset: {\n      width: 0,\n      height: 12,\n    },\n    shadowOpacity: 0.25,\n    shadowRadius: 8.0,\n\n    elevation: 8,\n  },\n  arrow: {\n    fontSize: 20,\n    height: 20,\n    textAlignVertical: 'center',\n    fontWeight: '900',\n    color: '#fff',\n  },\n});\n\nexport default CustomFooter;\n```\n\n```tsx title=\"App.tsx\"\nimport React, { useCallback, useMemo, useRef } from 'react';\nimport { View, Text, StyleSheet } from 'react-native';\nimport BottomSheet from '@gorhom/bottom-sheet';\nimport CustomFooter from './CustomFooter';\n\nconst App = () => {\n  // variables\n  const snapPoints = useMemo(() => ['25%', '50%'], []);\n\n  // renders\n  return (\n    <View style={styles.container}>\n      <BottomSheet\n        index={1}\n        snapPoints={snapPoints}\n        footerComponent={CustomFooter}\n      >\n        <View style={styles.contentContainer}>\n          <Text>Awesome 🎉</Text>\n        </View>\n      </BottomSheet>\n    </View>\n  );\n};\n\nconst styles = StyleSheet.create({\n  container: {\n    flex: 1,\n    padding: 24,\n    backgroundColor: 'grey',\n  },\n  contentContainer: {\n    flex: 1,\n    alignItems: 'center',\n  },\n});\n\nexport default App;\n```\n"
  },
  {
    "path": "website/versioned_docs/version-4/guides/custom-handle.mdx",
    "content": "---\nid: custom-handle\ntitle: Custom Handle\ndescription: Bottom Sheet custom handle.\nimage: /img/bottom-sheet-preview.gif\nslug: /custom-handle\nhide_table_of_contents: true\n---\n\nTo override the default handle, you will need to pass the prop `handleComponent` to the `BottomSheet` component.\n\nWhen you provide your own handle component, it will receive these animated props `animatedIndex` & `animatedPosition` that indicates the position and the index of the sheet.\n\nYou can extend your custom handle props interface with the provided `BottomSheetHandleProps` interface to expose `animatedIndex` & `animatedPosition` into your own interface.\n\n### Example\n\nimport useBaseUrl from \"@docusaurus/useBaseUrl\";\nimport Video from \"@theme/Video\";\n\n<Video\n  title=\"React Native Bottom Sheet Custom Handle\"\n  url={useBaseUrl(\"video/bottom-sheet-custom-handle-preview.mp4\")}\n/>\n\nHere is an example of a custom handle component, but first you will need to install `Redash`:\n\n> [Redash](https://github.com/wcandillon/react-native-redash): The React Native Reanimated and Gesture Handler Toolbelt.\n\n```bash\nyarn add react-native-redash\n```\n\n```tsx\nimport React, { useMemo } from \"react\";\nimport { StyleProp, StyleSheet, ViewStyle } from \"react-native\";\nimport { BottomSheetHandleProps } from \"@gorhom/bottom-sheet\";\nimport Animated, {\n  Extrapolate,\n  interpolate,\n  useAnimatedStyle,\n  useDerivedValue,\n} from \"react-native-reanimated\";\nimport { toRad } from \"react-native-redash\";\n\n// @ts-ignore\nexport const transformOrigin = ({ x, y }, ...transformations) => {\n  \"worklet\";\n  return [\n    { translateX: x },\n    { translateY: y },\n    ...transformations,\n    { translateX: x * -1 },\n    { translateY: y * -1 },\n  ];\n};\n\ninterface HandleProps extends BottomSheetHandleProps {\n  style?: StyleProp<ViewStyle>;\n}\n\nconst Handle: React.FC<HandleProps> = ({ style, animatedIndex }) => {\n  //#region animations\n  const indicatorTransformOriginY = useDerivedValue(() =>\n    interpolate(animatedIndex.value, [0, 1, 2], [-1, 0, 1], Extrapolate.CLAMP)\n  );\n  //#endregion\n\n  //#region styles\n  const containerStyle = useMemo(() => [styles.header, style], [style]);\n  const containerAnimatedStyle = useAnimatedStyle(() => {\n    const borderTopRadius = interpolate(\n      animatedIndex.value,\n      [1, 2],\n      [20, 0],\n      Extrapolate.CLAMP\n    );\n    return {\n      borderTopLeftRadius: borderTopRadius,\n      borderTopRightRadius: borderTopRadius,\n    };\n  });\n  const leftIndicatorStyle = useMemo(\n    () => ({\n      ...styles.indicator,\n      ...styles.leftIndicator,\n    }),\n    []\n  );\n  const leftIndicatorAnimatedStyle = useAnimatedStyle(() => {\n    const leftIndicatorRotate = interpolate(\n      animatedIndex.value,\n      [0, 1, 2],\n      [toRad(-30), 0, toRad(30)],\n      Extrapolate.CLAMP\n    );\n    return {\n      transform: transformOrigin(\n        { x: 0, y: indicatorTransformOriginY.value },\n        {\n          rotate: `${leftIndicatorRotate}rad`,\n        },\n        {\n          translateX: -5,\n        }\n      ),\n    };\n  });\n  const rightIndicatorStyle = useMemo(\n    () => ({\n      ...styles.indicator,\n      ...styles.rightIndicator,\n    }),\n    []\n  );\n  const rightIndicatorAnimatedStyle = useAnimatedStyle(() => {\n    const rightIndicatorRotate = interpolate(\n      animatedIndex.value,\n      [0, 1, 2],\n      [toRad(30), 0, toRad(-30)],\n      Extrapolate.CLAMP\n    );\n    return {\n      transform: transformOrigin(\n        { x: 0, y: indicatorTransformOriginY.value },\n        {\n          rotate: `${rightIndicatorRotate}rad`,\n        },\n        {\n          translateX: 5,\n        }\n      ),\n    };\n  });\n  //#endregion\n\n  // render\n  return (\n    <Animated.View\n      style={[containerStyle, containerAnimatedStyle]}\n      renderToHardwareTextureAndroid={true}\n    >\n      <Animated.View style={[leftIndicatorStyle, leftIndicatorAnimatedStyle]} />\n      <Animated.View\n        style={[rightIndicatorStyle, rightIndicatorAnimatedStyle]}\n      />\n    </Animated.View>\n  );\n};\n\nexport default Handle;\n\nconst styles = StyleSheet.create({\n  header: {\n    alignContent: \"center\",\n    alignItems: \"center\",\n    justifyContent: \"center\",\n    backgroundColor: \"white\",\n    paddingVertical: 14,\n    borderBottomWidth: 1,\n    borderBottomColor: \"#fff\",\n  },\n  indicator: {\n    position: \"absolute\",\n    width: 10,\n    height: 4,\n    backgroundColor: \"#999\",\n  },\n  leftIndicator: {\n    borderTopStartRadius: 2,\n    borderBottomStartRadius: 2,\n  },\n  rightIndicator: {\n    borderTopEndRadius: 2,\n    borderBottomEndRadius: 2,\n  },\n});\n```\n"
  },
  {
    "path": "website/versioned_docs/version-4/guides/detach-modal.mdx",
    "content": "---\nid: detach-modal\ntitle: Detach Modal\ndescription: Bottom Sheet custom footer.\nimage: /img/bottom-sheet-preview.gif\nslug: /detach-modal\nhide_table_of_contents: true\n---\n\nTo create a detach modal, you will need to pass the prop `detach={true}` to the `BottomSheet` or `BottomSheetModal`, along side with `bottomInset` to push the sheet from the bottom.\n\n### Example\n\nimport useBaseUrl from \"@docusaurus/useBaseUrl\";\nimport Video from \"@theme/Video\";\n\n<Video\n  title=\"React Native Bottom Sheet Detach Modal\"\n  url={useBaseUrl(\"video/bottom-sheet-detach-preview.mp4\")}\n/>\n\nHere is an example of a simple detach modal:\n\n```tsx\nimport React, { useMemo, useRef } from \"react\";\nimport { View, Text, StyleSheet } from \"react-native\";\nimport BottomSheet from \"@gorhom/bottom-sheet\";\n\nconst App = () => {\n  // ref\n  const bottomSheetRef = useRef<BottomSheet>(null);\n\n  // variables\n  const snapPoints = useMemo(() => [\"25%\"], []);\n\n  // renders\n  return (\n    <View style={styles.container}>\n      <BottomSheet\n        ref={bottomSheetRef}\n        snapPoints={snapPoints}\n        // add bottom inset to elevate the sheet\n        bottomInset={46}\n        // set `detached` to true\n        detached={true}\n        style={styles.sheetContainer}\n      >\n        <View style={styles.contentContainer}>\n          <Text>Awesome 🎉</Text>\n        </View>\n      </BottomSheet>\n    </View>\n  );\n};\n\nconst styles = StyleSheet.create({\n  container: {\n    flex: 1,\n    padding: 24,\n    backgroundColor: \"grey\",\n  },\n  sheetContainer: {\n    // add horizontal space\n    marginHorizontal: 24,\n  },\n  contentContainer: {\n    flex: 1,\n    alignItems: \"center\",\n  },\n});\n\nexport default App;\n```\n"
  },
  {
    "path": "website/versioned_docs/version-4/guides/keyboard-handling.mdx",
    "content": "---\nid: keyboard-handling\ntitle: Keyboard Handling\ndescription: Keyboard handling with Bottom Sheet.\nimage: /img/bottom-sheet-preview.gif\nslug: /keyboard-handling\nhide_table_of_contents: true\n---\n\nKeyboard handling is one of the main feature of `BottomSheet v4`, thanks to the effort of the community to spot issues, test and help to debug the implementation on both platform `iOS` & `Android`.\n\nTo handle the keyboard appearance, I have simplified the approach by creating a pre-integrated `TextInput` called [BottomSheetTextInput](./components/bottomsheettextinput), which communicate internally to react to the keyboard appearance.\n\nAlso I have introduce two props to allow users to customize the handling, [keyboardBehavior](./props#keyboardbehavior), [keyboardBlurBehavior](./props#keyboardblurbehavior) and [android_keyboardInputMode](./props#android_keyboardinputmode) that is only for `Android`.\n\n:::tip\nTo use custom `TextInput`, you will need to copy the `handleOnFocus` and `handleOnBlur` from [BottomSheetTextInput](https://github.com/gorhom/react-native-bottom-sheet/blob/master/src/components/bottomSheetTextInput/BottomSheetTextInput.tsx) into your own component.\n:::\n\n### Example\n\nimport useBaseUrl from \"@docusaurus/useBaseUrl\";\nimport Video from \"@theme/Video\";\n\n<Video\n  title=\"React Native Bottom Sheet Keyboard Handling\"\n  url={useBaseUrl(\"video/bottom-sheet-keyboard-handling-preview.mp4\")}\n/>\n\nHere is an example of a simple keyboard handling:\n\n```tsx\nimport React, { useMemo } from \"react\";\nimport { View, StyleSheet } from \"react-native\";\nimport BottomSheet, { BottomSheetTextInput } from \"@gorhom/bottom-sheet\";\n\nconst App = () => {\n  // variables\n  const snapPoints = useMemo(() => [\"25%\"], []);\n\n  // renders\n  return (\n    <View style={styles.container}>\n      <BottomSheet snapPoints={snapPoints}>\n        <View style={styles.contentContainer}>\n          <BottomSheetTextInput value=\"Awesome 🎉\" style={styles.textInput} />\n        </View>\n      </BottomSheet>\n    </View>\n  );\n};\n\nconst styles = StyleSheet.create({\n  container: {\n    flex: 1,\n    padding: 24,\n    backgroundColor: \"grey\",\n  },\n  textInput: {\n    alignSelf: \"stretch\",\n    marginHorizontal: 12,\n    marginBottom: 12,\n    padding: 12,\n    borderRadius: 12,\n    backgroundColor: \"grey\",\n    color: \"white\",\n    textAlign: \"center\",\n  },\n  contentContainer: {\n    flex: 1,\n    alignItems: \"center\",\n  },\n});\n\nexport default App;\n```\n"
  },
  {
    "path": "website/versioned_docs/version-4/guides/pull-to-refresh.mdx",
    "content": "---\nid: pull-to-refresh\ntitle: Pull To Refresh\ndescription: Pull To Refresh with Bottom Sheet.\nimage: /img/bottom-sheet-preview.gif\nslug: /pull-to-refresh\nhide_table_of_contents: true\n---\n\nPull to refresh feature is enabled by default, and it will be activated on the top snap point provided. All you need to do is to provide `refreshing` & `onRefresh` to any of the [Scrollables](./scrollables).\n\n:::note\n\nCurrently `refreshControl` is not supported, feel free to contribute to enable it ❤️\n\n:::\n\n### Example\n\nimport useBaseUrl from \"@docusaurus/useBaseUrl\";\nimport Video from \"@theme/Video\";\n\n<Video\n  title=\"React Native Bottom Sheet Pull to Refresh\"\n  url={useBaseUrl(\"video/bottom-sheet-pull-to-refresh-preview.mp4\")}\n/>\n\nHere is an example of a simple pull to refresh:\n\n```tsx\nimport React, { useCallback, useMemo } from \"react\";\nimport { StyleSheet, View, Text } from \"react-native\";\nimport BottomSheet, { BottomSheetFlatList } from \"@gorhom/bottom-sheet\";\n\nconst App = () => {\n  // variables\n  const data = useMemo(\n    () =>\n      Array(50)\n        .fill(0)\n        .map((_, index) => `index-${index}`),\n    []\n  );\n  const snapPoints = useMemo(() => [\"25%\", \"50%\"], []);\n\n  // callbacks\n  const handleRefresh = useCallback(() => {\n    console.log(\"handleRefresh\");\n  }, []);\n\n  // render\n  const renderItem = useCallback(\n    ({ item }) => (\n      <View style={styles.itemContainer}>\n        <Text>{item}</Text>\n      </View>\n    ),\n    []\n  );\n  return (\n    <View style={styles.container}>\n      <BottomSheet snapPoints={snapPoints}>\n        <BottomSheetFlatList\n          data={data}\n          keyExtractor={(i) => i}\n          renderItem={renderItem}\n          contentContainerStyle={styles.contentContainer}\n          refreshing={false}\n          onRefresh={handleRefresh}\n        />\n      </BottomSheet>\n    </View>\n  );\n};\n\nconst styles = StyleSheet.create({\n  container: {\n    flex: 1,\n  },\n  contentContainer: {\n    backgroundColor: \"white\",\n  },\n  itemContainer: {\n    padding: 6,\n    margin: 6,\n    backgroundColor: \"#eee\",\n  },\n});\n\nexport default App;\n```\n"
  },
  {
    "path": "website/versioned_docs/version-4/guides/react-navigation.md",
    "content": "---\nid: react-navigation-integration\ntitle: React Navigation Integration\ndescription: Bottom Sheet React Navigation integration.\nimage: /img/bottom-sheet-preview.gif\nslug: /react-navigation-integration\nhide_table_of_contents: true\n---\n\nOne of the main goal of this library, is to allow user to fully integrate a stack navigator in the bottom sheet. This integration allow lots of opportunities for a native-like experience in your app 😇\n\nHowever, there are some tricks has to be follow to enable both libraries to work together seamlessly.\n\n- You need to override `safeAreaInsets`, by default `React Navigation` add the safe area insets to all its navigators, but since your navigator will properly won't cover full screen, you will need to override it and set it to `0`.\n\nFor more details regarding the implementation, please have a look at the [Navigator Example](https://github.com/gorhom/react-native-bottom-sheet/blob/master/example/bare/src/screens/integrations/NavigatorExample.tsx).\n"
  },
  {
    "path": "website/versioned_docs/version-4/hooks.md",
    "content": "---\nid: hooks\ntitle: Hooks\ndescription: Bottom Sheet hooks.\nimage: /img/bottom-sheet-preview.gif\nslug: /hooks\n---\n\n## useBottomSheet\n\nThis hook provides all the bottom sheet public [methods](methods) and `animatedIndex` & `animatedPosition`, to the internal sheet content or handle.\n\n:::info\n\nThis hook works at any component inside the `BottomSheet`.\n\n:::\n\n```tsx\nimport React from 'react';\nimport { View, Button } from 'react-native';\nimport { useBottomSheet } from '@gorhom/bottom-sheet';\n\nconst SheetContent = () => {\n  const { expand } = useBottomSheet();\n\n  return (\n    <View>\n      <Button onPress={expand}>\n    </View>\n  )\n}\n```\n\n## useBottomSheetDynamicSnapPoints\n\nA hook to simplify handling dynamic snap points, it will take an initial snap points with a placeholder for content height `CONTENT_HEIGHT` that will be replaced once the content is measured and will return:\n\n- `animatedSnapPoints`: to provided to BottomSheet or BottomSheetModal.\n- `animatedHandleHeight`: an animated handle height callback node.\n- `animatedContentHeight`: an animated content height.\n- `handleContentLayout`: onLayout callback to be set on BottomSheetView component.\n\n```tsx\nimport React from 'react';\nimport BottomSheet, {\n  useBottomSheetDynamicSnapPoints,\n} from '@gorhom/bottom-sheet';\n\nconst App = () => {\n  const initialSnapPoints = useMemo(() => ['25%', 'CONTENT_HEIGHT'], []);\n\n  const {\n    animatedHandleHeight,\n    animatedSnapPoints,\n    animatedContentHeight,\n    handleContentLayout,\n  } = useBottomSheetDynamicSnapPoints(initialSnapPoints);\n\n  return (\n    //... other views\n    <BottomSheet\n      ref={bottomSheetRef}\n      snapPoints={animatedSnapPoints}\n      handleHeight={animatedHandleHeight}\n      contentHeight={animatedContentHeight}\n    >\n      <BottomSheetView\n        style={contentContainerStyle}\n        onLayout={handleContentLayout}\n      >\n        //... views to be measured\n      </BottomSheetView>\n    </BottomSheet>\n    //... other views\n  );\n};\n```\n\n## useBottomSheetSpringConfigs\n\nGenerate animation spring configs.\n\n```tsx\nimport React from 'react';\nimport BottomSheet, { useBottomSheetSpringConfigs } from '@gorhom/bottom-sheet';\n\nconst SheetContent = () => {\n\n  const animationConfigs = useBottomSheetSpringConfigs({\n    damping: 80,\n    overshootClamping: true,\n    restDisplacementThreshold: 0.1,\n    restSpeedThreshold: 0.1,\n    stiffness: 500,\n  });\n\n  return (\n    <BottomSheet\n      // ... other props\n      animationConfigs={animationConfigs}\n    >\n      {CONTENT HERE}\n    </BottomSheet>\n  )\n}\n```\n\n## useBottomSheetTimingConfigs\n\nGenerate animation timing configs.\n\n```tsx\nimport React from 'react';\nimport BottomSheet, { useBottomSheetTimingConfigs } from '@gorhom/bottom-sheet';\nimport { Easing } from 'react-native-reanimated';\n\nconst SheetContent = () => {\n\n  const animationConfigs = useBottomSheetTimingConfigs({\n    duration: 250,\n    easing: Easing.exp,\n  });\n\n  return (\n    <BottomSheet\n      // ... other props\n      animationConfigs={animationConfigs}\n    >\n      {CONTENT HERE}\n    </BottomSheet>\n  )\n}\n```\n"
  },
  {
    "path": "website/versioned_docs/version-4/index.md",
    "content": "---\nid: index\ntitle: Bottom Sheet\nhide_title: true\nsidebar_label: Bottom Sheet\ndescription: A performant interactive bottom sheet with fully configurable options 🚀\nimage: /img/bottom-sheet-preview.gif\nslug: /\n---\n\n# React Native Bottom Sheet\n\n[![version](https://img.shields.io/github/package-json/v/gorhom/react-native-bottom-sheet/master?label=version&style=flat-square)](https://www.npmjs.com/package/@gorhom/bottom-sheet) [![npm](https://img.shields.io/npm/l/@gorhom/bottom-sheet?style=flat-square)](https://www.npmjs.com/package/@gorhom/bottom-sheet) [![npm](https://img.shields.io/badge/types-included-blue?style=flat-square)](https://www.npmjs.com/package/@gorhom/bottom-sheet) [![runs with expo](https://img.shields.io/badge/Runs%20with%20Expo-4630EB.svg?style=flat-square&logo=EXPO&labelColor=f3f3f3&logoColor=000)](https://expo.io/)\n\nA performant interactive bottom sheet with fully configurable options 🚀\n\nimport useBaseUrl from \"@docusaurus/useBaseUrl\";\nimport Video from \"@theme/Video\";\n\n<Video\n\ttitle=\"React Native Bottom Sheet\"\n\turl={useBaseUrl(\"video/bottom-sheet-preview.mp4\")}\n\timg={useBaseUrl(\"img/bottom-sheet-preview.gif\")}\n/>\n\n## Features\n\n- Modal presentation view, [Bottom Sheet Modal](./modal).\n- Smooth gesture interactions & snapping animations.\n- Seamless [keyboard handling](./keyboard-handling) for iOS & Android.\n- Support [pull to refresh](./pull-to-refresh) for scrollables.\n- Support `FlatList`, `SectionList`, `ScrollView` & `View` scrolling interactions. [read more](./scrollables).\n- Support `React Navigation` Integration, [read more](./react-navigation-integration).\n- Compatible with Reanimated v2 & v3.\n- Compatible with `Expo`.\n- Accessibility support.\n- Written in `TypeScript`.\n\n## Installation\n\n```bash\nyarn add @gorhom/bottom-sheet@^4\n```\n\n#### Dependencies\n\nThis library needs these dependencies to be installed in your project before you can use it:\n\n```bash\nyarn add react-native-reanimated react-native-gesture-handler\n```\n\nUsing Expo?\n\n```bash\nnpx expo install react-native-reanimated react-native-gesture-handler\n```\n\n:::info\n**React Native Gesture Handler** needs extra steps to finalize its installation, please follow their [installation instructions](https://docs.swmansion.com/react-native-gesture-handler/docs/installation). Please **make sure** to wrap your App with `GestureHandlerRootView` when you've upgraded to React Native Gesture Handler ^2.\n\n**React Native Reanimated v2** needs extra steps to finalize its installation, please follow their [installation instructions](https://docs.swmansion.com/react-native-reanimated/docs/fundamentals/getting-started).\n:::\n\n## Sponsor & Support\n\nTo keep this library maintained and up-to-date please consider [sponsoring it on GitHub](https://github.com/sponsors/gorhom). Or if you are looking for a private support or help in customizing the experience, then reach out to me on Twitter [@gorhom](https://twitter.com/gorhom).\n\n## Built With ❤️\n\n- [react-native-reanimated](https://github.com/software-mansion/react-native-reanimated)\n- [react-native-gesture-handler](https://github.com/software-mansion/react-native-gesture-handler)\n- [react-native-redash](https://github.com/wcandillon/react-native-redash)\n- [react-native-builder-bob](https://github.com/callstack/react-native-builder-bob)\n"
  },
  {
    "path": "website/versioned_docs/version-4/methods.md",
    "content": "---\nid: methods\ntitle: Methods\ndescription: Bottom Sheet methods.\nimage: /img/bottom-sheet-preview.gif\nslug: /methods\n---\n\nThese methods are accessible using the bottom sheet reference or the hook `useBottomSheet` or `useBottomSheetModal`.\n\n```tsx\nimport React, { useRef } from 'react';\nimport { Button } from 'react-native';\nimport BottomSheet from '@gorhom/bottom-sheet';\n\nconst App = () => {\n  const bottomSheetRef = useRef<BottomSheet>(null);\n\n  const handleClosePress = () => bottomSheetRef.current.close()\n\n  return (\n    <>\n      <Button title=\"Close Sheet\" onPress={handleClosePress} />\n      <BottomSheet ref={bottomSheetRef}>\n    </>\n  )\n}\n\n```\n\n### snapToIndex\n\nSnap to one of the provided points from `snapPoints`.\n\n```ts\ntype snapToIndex = (\n  // snap point index.\n  index: number,\n  // snap animation configs\n  animationConfigs?: Animated.WithSpringConfig | Animated.WithTimingConfig\n) => void;\n```\n\n### snapToPosition\n\nSnap to a position out of provided `snapPoints`.\n\n```ts\ntype snapToPosition = (\n  // position in pixel or percentage.\n  position: number,\n  // snap animation configs\n  animationConfigs?: Animated.WithSpringConfig | Animated.WithTimingConfig\n) => void;\n```\n\n### expand\n\nSnap to the maximum provided point from `snapPoints`.\n\n```ts\ntype expand = (\n  // snap animation configs\n  animationConfigs?: Animated.WithSpringConfig | Animated.WithTimingConfig\n) => void;\n```\n\n### collapse\n\nSnap to the minimum provided point from `snapPoints`.\n\n```ts\ntype collapse = (\n  // snap animation configs\n  animationConfigs?: Animated.WithSpringConfig | Animated.WithTimingConfig\n) => void;\n```\n\n### close\n\nClose the bottom sheet.\n\n```ts\ntype close = (\n  // snap animation configs\n  animationConfigs?: Animated.WithSpringConfig | Animated.WithTimingConfig\n) => void;\n```\n\n### forceClose\n\nForce close the bottom sheet, this prevent any interruptions till the sheet is closed.\n\n```ts\ntype forceClose = (\n  // snap animation configs\n  animationConfigs?: Animated.WithSpringConfig | Animated.WithTimingConfig\n) => void;\n```\n"
  },
  {
    "path": "website/versioned_docs/version-4/modal/hooks.md",
    "content": "---\nid: hooks\ntitle: Hooks\ndescription: Bottom Sheet modal hooks.\nimage: /img/bottom-sheet-preview.gif\nslug: /modal/hooks\n---\n\n## useBottomSheetModal\n\nThis hook provides modal functionalities only, for sheet functionalities please look at [Bottom Sheet Hooks](../hooks).\n\n> This hook works at any component in `BottomSheetModalProvider`.\n\n```tsx\nimport React from 'react';\nimport { View, Button } from 'react-native';\nimport { useBottomSheetModal } from '@gorhom/bottom-sheet';\n\nconst SheetContent = () => {\n  const { dismiss, dismissAll } = useBottomSheetModal();\n\n  return (\n    <View>\n      <Button onPress={dismiss}>\n    </View>\n  )\n}\n```\n\n## dismiss\n\n```ts\ntype dismiss = (key?: string) => void;\n```\n\nDismiss a modal by its name/key, if key is not provided, then it will dismiss the last presented modal.\n\n## dismissAll\n\n```ts\ntype dismissAll = () => void;\n```\n\nDismiss all mounted/presented modals.\n"
  },
  {
    "path": "website/versioned_docs/version-4/modal/index.mdx",
    "content": "---\nid: index\ntitle: Modal\nsidebar_label: Modal\ndescription: A performant interactive bottom sheet modal with fully configurable options 🚀\nimage: /img/bottom-sheet-modal-preview.gif\nslug: /modal\n---\n\n# React Native Bottom Sheet Modal\n\nimport useBaseUrl from '@docusaurus/useBaseUrl';\nimport Video from '@theme/Video';\n\n<Video\n  title=\"React Native Bottom Sheet Modal\"\n  url={useBaseUrl('video/bottom-sheet-modal-preview.mp4')}\n/>\n\n**Bottom Sheet Modal** is wrapper/decorator on top of the **Bottom Sheet**, it provides all of its functionalities with extra modal presentation functionalities.\n\nWith the release of the library, support for stack sheet modals were something planned ahead to provide the a native feel & and experience to users.\n\nThe implementation of this feature was inspired by Apple Maps sheet modals ❤️, [check out the Apple Map sheet modals clone](https://github.com/gorhom/react-native-bottom-sheet/blob/master/example/bare/src/screens/integrations/MapExample.tsx).\n\n## Features\n\n- ...[Bottom Sheet Features](./#features)\n- Smooth interaction and mounting animation.\n- Support stack sheet modals.\n\n## Installation\n\nThis feature is already shipped with `@gorhom/bottom-sheet` package and it requires no extra dependency.\n"
  },
  {
    "path": "website/versioned_docs/version-4/modal/methods.md",
    "content": "---\nid: methods\ntitle: Methods\ndescription: Bottom Sheet modal methods.\nimage: /img/bottom-sheet-preview.gif\nslug: /modal/methods\n---\n\n**Bottom Sheet Modal** inherits all [**Bottom Sheet** methods](../methods) and also it introduces its own methods.\n\nThese methods are accessible using the bottom sheet modal reference:\n\n```tsx\nimport React, { useRef } from 'react';\nimport {BottomSheetModal} from '@gorhom/bottom-sheet';\n\nconst App = () => {\n  const bottomSheetModalRef = useRef<BottomSheetModal>(null);\n  const handlePresentPress = () => bottomSheetModalRef.current.present()\n  return (\n    <>\n      <Button title=\"Present Sheet\" onPress={handlePresentPress} />\n      <BottomSheetModal ref={bottomSheetModalRef}>\n    </>\n  )\n}\n\n```\n\n### present\n\nMount and present the bottom sheet modal to the initial snap point.\n\n```ts\ntype present = (\n  // Data to be passed to the modal.\n  data?: any\n) => void;\n```\n\n### dismiss\n\nClose and unmount the bottom sheet modal.\n\n```ts\ntype dismiss = (\n  // AnimationConfigs snap animation configs.\n  animationConfigs?: WithSpringConfig | WithTimingConfig\n) => void;\n```\n"
  },
  {
    "path": "website/versioned_docs/version-4/modal/props.md",
    "content": "---\nid: props\ntitle: Props\ndescription: Bottom Sheet modal configurable props.\nimage: /img/bottom-sheet-preview.gif\nslug: /modal/props\n---\n\n**Bottom Sheet Modal** inherits all [**Bottom Sheet** props](../props) except for `animateOnMount` & `containerHeight` and also it introduces its own props:\n\n## Configuration\n\n### name\n\nModal name to help identify the modal for later on.\n\n| type   | default                | required |\n| ------ | ---------------------- | -------- |\n| string | `generated unique key` | NO       |\n\n### stackBehavior\n\n**`Available only on v3, for now.`**\n\nDefines the stack behavior when modal mounts.\n\n- `push` it will mount the modal on top of current modal.\n- `replace` it will minimize the current modal then mount the modal.\n\n| type                | default   | required |\n| ------------------- | --------- | -------- |\n| 'push' \\| 'replace' | 'replace' | NO       |\n\n### enableDismissOnClose\n\nDismiss the modal when it is closed, this will unmount the modal.\n\n| type    | default | required |\n| ------- | ------- | -------- |\n| boolean | true    | NO       |\n\n## Callbacks\n\n### onDismiss\n\nCallback when the modal dismissed (unmounted).\n\n```ts\ntype onDismiss = () => void;\n```\n\n| type     | default | required |\n| -------- | ------- | -------- |\n| function | null    | NO       |\n\n## Components\n\n### containerComponent\n\nComponent to be placed as a bottom sheet container, this is to place\nthe bottom sheet at the very top layer of your application when using `FullWindowOverlay`\nfrom `React Native Screens`. [read more](https://github.com/gorhom/react-native-bottom-sheet/issues/832)\n\n| type            | default   | required |\n| --------------- | --------- | -------- |\n| React.ReactNode | undefined | NO       |\n"
  },
  {
    "path": "website/versioned_docs/version-4/modal/usage.md",
    "content": "---\nid: usage\ntitle: Usage\ndescription: Bottom Sheet modal usage.\nimage: /img/bottom-sheet-preview.gif\nslug: /modal/usage\n---\n\nHere is a simple usage of the **Bottom Sheet Modal**, with non-scrollable content. For more scrollable usage please read [Scrollables](../scrollables).\n\n```tsx\nimport React, { useCallback, useMemo, useRef } from 'react';\nimport { View, Text, StyleSheet, Button } from 'react-native';\nimport {\n  BottomSheetModal,\n  BottomSheetModalProvider,\n} from '@gorhom/bottom-sheet';\n\nconst App = () => {\n  // ref\n  const bottomSheetModalRef = useRef<BottomSheetModal>(null);\n\n  // variables\n  const snapPoints = useMemo(() => ['25%', '50%'], []);\n\n  // callbacks\n  const handlePresentModalPress = useCallback(() => {\n    bottomSheetModalRef.current?.present();\n  }, []);\n  const handleSheetChanges = useCallback((index: number) => {\n    console.log('handleSheetChanges', index);\n  }, []);\n\n  // renders\n  return (\n    <BottomSheetModalProvider>\n      <View style={styles.container}>\n        <Button\n          onPress={handlePresentModalPress}\n          title=\"Present Modal\"\n          color=\"black\"\n        />\n        <BottomSheetModal\n          ref={bottomSheetModalRef}\n          index={1}\n          snapPoints={snapPoints}\n          onChange={handleSheetChanges}\n        >\n          <View style={styles.contentContainer}>\n            <Text>Awesome 🎉</Text>\n          </View>\n        </BottomSheetModal>\n      </View>\n    </BottomSheetModalProvider>\n  );\n};\n\nconst styles = StyleSheet.create({\n  container: {\n    flex: 1,\n    padding: 24,\n    justifyContent: 'center',\n    backgroundColor: 'grey',\n  },\n  contentContainer: {\n    flex: 1,\n    alignItems: 'center',\n  },\n});\n\nexport default App;\n```\n"
  },
  {
    "path": "website/versioned_docs/version-4/props.md",
    "content": "---\nid: props\ntitle: Props\ndescription: Bottom Sheet configurable props.\nimage: /img/bottom-sheet-preview.gif\nslug: /props\n---\n\n## Configuration\n\n### index\n\nInitial snap index. You also could provide `-1` to initiate bottom sheet in closed state.\n\n| type   | default | required |\n| ------ | ------- | -------- |\n| number | 0       | NO       |\n\n### snapPoints\n\nPoints for the bottom sheet to snap to, **points should be sorted from bottom to top**. It accepts array of number, string or mix.\n\n| type                                                          | required |\n| ------------------------------------------------------------- | -------- |\n| Array\\<number\\|string> \\| SharedValue\\<Array\\<string \\| number>> | YES\\*    |\n\n:::caution\nThis prop is required unless you set `enableDynamicSizing` to `true`.\n:::\n:::caution\nString values should be a percentage.\n:::\n\n#### examples\n\n```ts\nsnapPoints={[200, 500]}\nsnapPoints={[200, '50%']}\nsnapPoints={['100%']}\n```\n\n### overDragResistanceFactor\n\nDefines how violently sheet has to be stopped while over dragging.\n\n| type   | default | required |\n| ------ | ------- | -------- |\n| number | 2.5     | NO       |\n\n### detached\n\nDefines whether the bottom sheet is attached to the bottom or no.\n\n| type    | default | required |\n| ------- | ------- | -------- |\n| boolean | false   | NO       |\n\n### enableContentPanningGesture\n\nEnable content panning gesture interaction.\n\n| type    | default | required |\n| ------- | ------- | -------- |\n| boolean | true    | NO       |\n\n### enableHandlePanningGesture\n\nEnable handle panning gesture interaction.\n\n| type    | default | required |\n| ------- | ------- | -------- |\n| boolean | true    | NO       |\n\n### enableOverDrag\n\nEnable over drag for the sheet.\n\n| type    | default | required |\n| ------- | ------- | -------- |\n| boolean | true    | NO       |\n\n### enablePanDownToClose\n\nEnable pan down gesture to close the sheet.\n\n| type    | default | required |\n| ------- | ------- | -------- |\n| boolean | false   | NO       |\n\n### enableDynamicSizing\n\nEnable dynamic sizing for content view and scrollable content size.\n\n| type    | default | required |\n| ------- | ------- | -------- |\n| boolean | false   | NO       |\n\n:::caution\n\nSetting this prop to `true`, will result in adding a new snap point to the provided snap points and will be sorted accordingly, and this might effect the indexing, for example, if provided snap points are `[100, 1000]`, and the content size is `500` then the final snap points will be `[100, 500, 1000]`.\n\n:::\n\n### animateOnMount\n\nThis will initially mount the sheet closed and when it's mounted and calculated the layout, it will snap to initial snap point index.\n\n| type    | default | required |\n| ------- | ------- | -------- |\n| boolean | true    | NO       |\n\n## Styles\n\n### style\n\nView style to be applied at the sheet container, it also could be an `AnimatedStyle`. This is helpful to add shadow to the sheet.\n\n| type                       | default   | required |\n| -------------------------- | --------- | -------- |\n| ViewStyle \\| AnimatedStyle | undefined | NO       |\n\n### backgroundStyle\n\nView style to be applied to the background component.\n\n| type      | default   | required |\n| --------- | --------- | -------- |\n| ViewStyle | undefined | NO       |\n\n### handleStyle\n\nView style to be applied to the handle component.\n\n| type      | default   | required |\n| --------- | --------- | -------- |\n| ViewStyle | undefined | NO       |\n\n### handleIndicatorStyle\n\nView style to be applied to the handle indicator component.\n\n| type      | default   | required |\n| --------- | --------- | -------- |\n| ViewStyle | undefined | NO       |\n\n## Layout Configuration\n\n### handleHeight\n\nHandle height helps to calculate the internal container and sheet layouts. If `handleComponent` is provided, the library internally will calculate its layout, unless `handleHeight` is provided too.\n\n| type   | default | required |\n| ------ | ------- | -------- |\n| number | 24      | NO       |\n\n### containerHeight\n\nContainer height helps to calculate the internal sheet layouts. If `containerHeight` not provided, the library internally will calculate it, however this will cause an extra re-rendering.\n\n| type   | default | required |\n| ------ | ------- | -------- |\n| number | 0       | NO       |\n\n### contentHeight\n\nContent height helps dynamic snap points calculation.\n\n| type                                    | default   | required |\n| --------------------------------------- | --------- | -------- |\n| number \\| Animated.SharedValue\\<number\\> | undefined | NO       |\n\n### containerOffset\n\nContainer offset helps to accurately detect container offsets.\n\n| type                          | default   | required |\n| ----------------------------- | --------- | -------- |\n| Animated.SharedValue\\<Insets\\> | undefined | NO       |\n\n### topInset\n\nTop inset to be added to the bottom sheet container, usually it comes from `@react-navigation/stack` hook `useHeaderHeight` or from `react-native-safe-area-context` hook `useSafeArea`.\n\n| type   | default | required |\n| ------ | ------- | -------- |\n| number | 0       | NO       |\n\n### bottomInset\n\nBottom inset to be added to the bottom sheet container.\n\n| type   | default | required |\n| ------ | ------- | -------- |\n| number | 0       | NO       |\n\n### maxDynamicContentSize\n\nMax dynamic content size height to limit the bottom sheet height from exceeding a provided size.\n\n| type   | default          | required |\n| ------ | ---------------- | -------- |\n| number | container height | NO       |\n\n## Keyboard Configuration\n\n### keyboardBehavior\n\nDefines the keyboard appearance behavior.\n\n- `extend`: extend the sheet to its maximum snap point.\n- `fillParent`: extend the sheet to fill the parent view.\n- `interactive`: offset the sheet by the size of the keyboard.\n\n| type                                      | default       | required |\n| ----------------------------------------- | ------------- | -------- |\n| 'extend' \\| 'fillParent' \\| 'interactive' | 'interactive' | NO       |\n\n### keyboardBlurBehavior\n\nDefines the keyboard blur behavior.\n\n- `none`: do nothing.\n- `restore`: restore sheet position.\n\n| type                | default | required |\n| ------------------- | ------- | -------- |\n| 'none' \\| 'restore' | 'none'  | NO       |\n\n### android_keyboardInputMode\n\nDefines keyboard input mode for `Android` only, [learn more](https://developer.android.com/guide/topics/manifest/activity-element#wsoft).\n\n| type                          | default     | required |\n| ----------------------------- | ----------- | -------- |\n| 'adjustPan' \\| 'adjustResize' | 'adjustPan' | NO       |\n\n## Animation Configuration\n\n### animationConfigs\n\nAnimation configs, this could be created by:\n\n- [`useBottomSheetSpringConfigs`](./hooks#usebottomsheetspringconfigs)\n- [`useBottomSheetTimingConfigs`](./hooks#usebottomsheettimingconfigs)\n\n```ts\ntype animationConfigs = (\n\tpoint: number,\n\tvelocity: number,\n\tcallback: () => void\n) => number;\n```\n\n| type     | default   | required |\n| -------- | --------- | -------- |\n| function | undefined | NO       |\n\n## Gesture Configuration\n\n### waitFor\n\n[Read about `waitFor`](https://docs.swmansion.com/react-native-gesture-handler/docs/handler-common#waitfor).\n\n| type                     | default | required |\n| ------------------------ | ------- | -------- |\n| React.Ref \\| React.Ref[] | []      | NO       |\n\n### simultaneousHandlers\n\n[Read about `simultaneousHandlers`](https://docs.swmansion.com/react-native-gesture-handler/docs/handler-common#simultaneoushandlers).\n\n| type                     | default | required |\n| ------------------------ | ------- | -------- |\n| React.Ref \\| React.Ref[] | []      | NO       |\n\n### activeOffsetX\n\n[Read about `activeOffsetX`](https://docs.swmansion.com/react-native-gesture-handler/docs/handler-pan#activeoffsetx).\n\n| type     | default   | required |\n| -------- | --------- | -------- |\n| number[] | undefined | NO       |\n\n### activeOffsetY\n\n[Read about `activeOffsetY`](https://docs.swmansion.com/react-native-gesture-handler/docs/handler-pan#activeoffsety).\n\n| type     | default   | required |\n| -------- | --------- | -------- |\n| number[] | undefined | NO       |\n\n### failOffsetX\n\n[Read about `failOffsetX`](https://docs.swmansion.com/react-native-gesture-handler/docs/handler-pan/#failoffsetx).\n\n| type     | default   | required |\n| -------- | --------- | -------- |\n| number[] | undefined | NO       |\n\n### failOffsetY\n\n[Read about `failOffsetY`](https://docs.swmansion.com/react-native-gesture-handler/docs/handler-pan/#failoffsety).\n\n| type     | default   | required |\n| -------- | --------- | -------- |\n| number[] | undefined | NO       |\n\n### gestureEventsHandlersHook\n\nCustom hook to provide pan gesture events handler, which will allow advance and customize handling for pan gesture.\n\n| type                          | default                         | required |\n| ----------------------------- | ------------------------------- | -------- |\n| GestureEventsHandlersHookType | useGestureEventsHandlersDefault | NO       |\n\n> warning: this is an experimental feature and the hook signature can change without a major version bump.\n\n## Animated Nodes\n\n### animatedIndex\n\nAnimated value to be used as a callback for the index node internally.\n\n| type                          | default | required |\n| ----------------------------- | ------- | -------- |\n| Animated.SharedValue\\<number\\> | null    | NO       |\n\n### animatedPosition\n\nAnimated value to be used as a callback for the position node internally.\n\n| type                          | default | required |\n| ----------------------------- | ------- | -------- |\n| Animated.SharedValue\\<number\\> | null    | NO       |\n\n## Callbacks\n\n### onChange\n\nCallback when the sheet position changed.\n\n```ts\ntype onChange = (index: number) => void;\n```\n\n| type     | default | required |\n| -------- | ------- | -------- |\n| function | null    | NO       |\n\n### onAnimate\n\nCallback when the sheet about to animate to a new position.\n\n```ts\ntype onAnimate = (fromIndex: number, toIndex: number) => void;\n```\n\n| type     | default | required |\n| -------- | ------- | -------- |\n| function | null    | NO       |\n\n## Components\n\n### handleComponent\n\nComponent to be placed as a sheet handle.\n\n| type                               | default             | required |\n| ---------------------------------- | ------------------- | -------- |\n| `React.FC\\<BottomSheetHandleProps>` | `BottomSheetHandle` | NO       |\n\n### backdropComponent\n\nComponent to be placed as a sheet backdrop, by default is set to `null`, however the library also provide a default implementation `BottomSheetBackdrop` of a backdrop but you will need to provide it manually.\n\n| type                                   | default | required |\n| -------------------------------------- | ------- | -------- |\n| `React.FC\\<BottomSheetBackgroundProps>` | null    | NO       |\n\n### backgroundComponent\n\nComponent to be placed as a sheet background.\n\n| type                                   | default                 | required |\n| -------------------------------------- | ----------------------- | -------- |\n| `React.FC\\<BottomSheetBackgroundProps>` | `BottomSheetBackground` | NO       |\n\n### footerComponent\n\nComponent to be placed as a sheet footer.\n\n| type                               | default   | required |\n| ---------------------------------- | --------- | -------- |\n| `React.FC\\<BottomSheetFooterProps>` | undefined | NO       |\n\n### children\n\n`Scrollable` node or react node to be places as a sheet content.\n\n| type                                                          | default | required |\n| ------------------------------------------------------------- | ------- | -------- |\n| () => React.ReactNode \\| React.ReactNode[] \\| React.ReactNode | null    | YES      |\n"
  },
  {
    "path": "website/versioned_docs/version-4/scrollables.md",
    "content": "---\nid: scrollables\ntitle: Scrollables\ndescription: Bottom Sheet scrollables.\nimage: /img/bottom-sheet-preview.gif\nslug: /scrollables\n---\n\nThis library provides a pre-integrated virtualized lists that utilize an internal functionalities with the bottom sheet container to allow smooth panning interactions. These lists I called them Scrollables and they are:\n\n- [BottomSheetFlatList](./components/bottomsheetflatlist)\n- [BottomSheetSectionList](./components/bottomsheetsectionlist)\n- [BottomSheetScrollView](./components/bottomsheetscrollview)\n- [BottomSheetVirtualizedList](./components/bottomsheetvirtualizedlist)\n- [BottomSheetView](./components/bottomsheetview)\n"
  },
  {
    "path": "website/versioned_docs/version-4/sidebars.ts",
    "content": "import type { SidebarsConfig } from \"@docusaurus/plugin-content-docs\";\n\n/**\n * Creating a sidebar enables you to:\n - create an ordered group of docs\n - render a sidebar for each doc of that group\n - provide next/previous navigation\n\n The sidebars can be generated from the filesystem, or explicitly defined here.\n\n Create as many sidebars as you want.\n */\nconst sidebars: SidebarsConfig = {\n\t// By default, Docusaurus generates a sidebar from the docs folder structure\n\t// \"bottom-sheet\": [{ type: \"autogenerated\", dirName: \".\" }],\n\n\t// But you can create a sidebar manually\n\t\"bottom-sheet\": [\n\t\t{\n\t\t\ttype: \"category\",\n\t\t\tlabel: \"Bottom Sheet\",\n\t\t\tlink: {\n\t\t\t\ttype: \"doc\",\n\t\t\t\tid: \"index\",\n\t\t\t},\n\t\t\titems: [\n\t\t\t\t\"usage\",\n\t\t\t\t\"props\",\n\t\t\t\t\"methods\",\n\t\t\t\t\"hooks\",\n\t\t\t\t\"scrollables\",\n\t\t\t\t{\n\t\t\t\t\ttype: \"category\",\n\t\t\t\t\tlabel: \"Components\",\n\t\t\t\t\titems: [\n\t\t\t\t\t\t\"components/bottomsheetview\",\n\t\t\t\t\t\t\"components/bottomsheetscrollview\",\n\t\t\t\t\t\t\"components/bottomsheetflatlist\",\n\t\t\t\t\t\t\"components/bottomsheetsectionlist\",\n\t\t\t\t\t\t\"components/bottomsheetvirtualizedlist\",\n\t\t\t\t\t\t\"components/bottomsheetbackdrop\",\n\t\t\t\t\t\t\"components/bottomsheetfooter\",\n\t\t\t\t\t\t\"components/bottomsheettextinput\",\n\t\t\t\t\t],\n\t\t\t\t},\n\t\t\t],\n\t\t},\n\t\t{\n\t\t\ttype: \"html\",\n\t\t\tvalue: \"<hr class='margin-vert--md margin-horiz--md' />\",\n\t\t\tdefaultStyle: false\n\t\t},\n\t\t{\n\t\t\ttype: \"category\",\n\t\t\tlabel: \"Bottom Sheet Modal\",\n\t\t\tlink: {\n\t\t\t\ttype: \"doc\",\n\t\t\t\tid: \"modal/index\",\n\t\t\t},\n\t\t\titems: [\"modal/usage\", \"modal/props\", \"modal/methods\", \"modal/hooks\"],\n\t\t},\n\t\t{\n\t\t\ttype: \"html\",\n\t\t\tvalue: \"<hr class='margin-vert--md margin-horiz--md' />\",\n\t\t\tdefaultStyle: false\n\t\t},\n\t\t{\n\t\t\ttype: \"category\",\n\t\t\tlabel: \"Guides\",\n\t\t\titems: [\n\t\t\t\t\"guides/custom-handle\",\n\t\t\t\t\"guides/custom-backdrop\",\n\t\t\t\t\"guides/custom-background\",\n\t\t\t\t\"guides/custom-footer\",\n\t\t\t\t\"guides/detach-modal\",\n\t\t\t\t\"guides/keyboard-handling\",\n\t\t\t\t\"guides/pull-to-refresh\",\n\t\t\t\t\"guides/adding-shadow\",\n\t\t\t\t\"guides/react-navigation-integration\",\n\t\t\t],\n\t\t},\n\t\t\"troubleshooting\",\n\t\t\"faq\",\n\t\t{\n\t\t\ttype: \"html\",\n\t\t\tvalue: \"<hr class='margin-vert--md margin-horiz--md' />\",\n\t\t\tdefaultStyle: false\n\t\t},\n\t\t{\n\t\t\ttype: \"link\",\n\t\t\tlabel: \"Github\",\n\t\t\thref: \"https://github.com/gorhom/react-native-bottom-sheet\"\n\t\t}\n\t],\n};\n\nexport default sidebars;\n"
  },
  {
    "path": "website/versioned_docs/version-4/troubleshooting.md",
    "content": "---\nid: troubleshooting\ntitle: Troubleshooting\ndescription: Bottom Sheet troubleshooting.\nimage: /img/bottom-sheet-preview.gif\nslug: /troubleshooting\nhide_table_of_contents: true\n---\n\nThis section attempts to outline issues that users frequently encounter when first getting accustomed to using React Native Bottom Sheet. These issues may or may not be related to React Native Bottom Sheet itself.\n\n## Pressables / Touchables are not working on Android\n\nDue to wrapping the content and handle with `TapGestureHandler` & `PanGestureHandler`, any gesture interaction would not function as expected.\n\nTo resolve this issue, please use touchables that this library provide.\n\n```tsx\nimport {\n  TouchableOpacity,\n  TouchableHighlight,\n  TouchableWithoutFeedback,\n} from '@gorhom/bottom-sheet';\n```\n\n## Adding horizontal FlatList or ScrollView is not working properly on Android\n\nDue to wrapping the content and handle with `TapGestureHandler` & `PanGestureHandler`, any gesture interaction would not function as expected.\n\nTo resolve this issue, please use `ScrollView` & `FlatList` from `react-native-gesture-handler` provide instead `react-native`.\n\n```tsx\nimport {\n  ScrollView,\n  FlatList\n} from 'react-native-gesture-handler';\n```\n\n## My component gesture interaction gets conflicted with Bottom Sheet interactions ?\n\nTo avoid the gesture interaction conflict between the Bottom Sheet and its content, you will need to wrap your component with `NativeViewGestureHandler` from `react-native-gesture-handler`\n\n```tsx\nimport { NativeViewGestureHandler } from 'react-native-gesture-handler';\n\n<NativeViewGestureHandler disallowInterruption={true}>\n   <AwesomeComponent />\n</NativeViewGestureHandler>\n```\n"
  },
  {
    "path": "website/versioned_docs/version-4/usage.md",
    "content": "---\nid: usage\ntitle: Usage\ndescription: Bottom Sheet usage.\nimage: /img/bottom-sheet-preview.gif\nslug: /usage\n---\n\nHere is a simple usage of the **Bottom Sheet**, with non-scrollable content. For more scrollable usage please read [Scrollables](./scrollables).\n\n```tsx\nimport React, { useCallback, useMemo, useRef } from 'react';\nimport { View, Text, StyleSheet } from 'react-native';\nimport BottomSheet from '@gorhom/bottom-sheet';\n\nconst App = () => {\n  // ref\n  const bottomSheetRef = useRef<BottomSheet>(null);\n\n  // variables\n  const snapPoints = useMemo(() => ['25%', '50%'], []);\n\n  // callbacks\n  const handleSheetChanges = useCallback((index: number) => {\n    console.log('handleSheetChanges', index);\n  }, []);\n\n  // renders\n  return (\n    <View style={styles.container}>\n      <BottomSheet\n        ref={bottomSheetRef}\n        index={1}\n        snapPoints={snapPoints}\n        onChange={handleSheetChanges}\n      >\n        <View style={styles.contentContainer}>\n          <Text>Awesome 🎉</Text>\n        </View>\n      </BottomSheet>\n    </View>\n  );\n};\n\nconst styles = StyleSheet.create({\n  container: {\n    flex: 1,\n    padding: 24,\n    backgroundColor: 'grey',\n  },\n  contentContainer: {\n    flex: 1,\n    alignItems: 'center',\n  },\n});\n\nexport default App;\n```"
  },
  {
    "path": "website/versioned_sidebars/version-2-sidebars.json",
    "content": "{\n  \"bottom-sheet\": [\n    {\n      \"type\": \"category\",\n      \"label\": \"Bottom Sheet\",\n      \"link\": {\n        \"type\": \"doc\",\n        \"id\": \"index\"\n      },\n      \"items\": [\"usage\", \"props\", \"methods\", \"hooks\", \"scrollables\"]\n    },\n    {\n      \"type\": \"html\",\n      \"value\": \"<hr class='margin-vert--md margin-horiz--md' />\",\n      \"defaultStyle\": false\n    },\n    {\n      \"type\": \"category\",\n      \"label\": \"Bottom Sheet Modal\",\n      \"link\": {\n        \"type\": \"doc\",\n        \"id\": \"modal/index\"\n      },\n      \"items\": [\"modal/usage\", \"modal/props\", \"modal/methods\", \"modal/hooks\"]\n    },\n    {\n      \"type\": \"html\",\n      \"value\": \"<hr class='margin-vert--md margin-horiz--md' />\",\n      \"defaultStyle\": false\n    },\n    {\n      \"type\": \"category\",\n      \"label\": \"Guides\",\n      \"items\": [\n        \"guides/custom-handle\",\n        \"guides/custom-backdrop\",\n        \"guides/custom-background\",\n        \"guides/adding-shadow\",\n        \"guides/react-navigation-integration\"\n      ]\n    },\n    \"troubleshooting\",\n    \"faq\"\n  ]\n}\n"
  },
  {
    "path": "website/versioned_sidebars/version-4-sidebars.json",
    "content": "{\n  \"bottom-sheet\": [\n    {\n      \"type\": \"category\",\n      \"label\": \"Bottom Sheet\",\n      \"link\": {\n        \"type\": \"doc\",\n        \"id\": \"index\"\n      },\n      \"items\": [\n        \"usage\",\n        \"props\",\n        \"methods\",\n        \"hooks\",\n        \"scrollables\",\n        {\n          \"type\": \"category\",\n          \"label\": \"Components\",\n          \"items\": [\n            \"components/bottomsheetview\",\n            \"components/bottomsheetscrollview\",\n            \"components/bottomsheetflatlist\",\n            \"components/bottomsheetsectionlist\",\n            \"components/bottomsheetvirtualizedlist\",\n            \"components/bottomsheetbackdrop\",\n            \"components/bottomsheetfooter\",\n            \"components/bottomsheettextinput\"\n          ]\n        }\n      ]\n    },\n    {\n      \"type\": \"html\",\n      \"value\": \"<hr class='margin-vert--md margin-horiz--md' />\",\n      \"defaultStyle\": false\n    },\n    {\n      \"type\": \"category\",\n      \"label\": \"Bottom Sheet Modal\",\n      \"link\": {\n        \"type\": \"doc\",\n        \"id\": \"modal/index\"\n      },\n      \"items\": [\"modal/usage\", \"modal/props\", \"modal/methods\", \"modal/hooks\"]\n    },\n    {\n      \"type\": \"html\",\n      \"value\": \"<hr class='margin-vert--md margin-horiz--md' />\",\n      \"defaultStyle\": false\n    },\n    {\n      \"type\": \"category\",\n      \"label\": \"Guides\",\n      \"items\": [\n        \"guides/custom-handle\",\n        \"guides/custom-backdrop\",\n        \"guides/custom-background\",\n        \"guides/custom-footer\",\n        \"guides/detach-modal\",\n        \"guides/keyboard-handling\",\n        \"guides/pull-to-refresh\",\n        \"guides/adding-shadow\",\n        \"guides/react-navigation-integration\"\n      ]\n    },\n    \"troubleshooting\",\n    \"faq\"\n  ]\n}\n"
  },
  {
    "path": "website/versions.json",
    "content": "[\"4\", \"2\"]\n"
  }
]