react-native-anchored-menu 0.0.7 β†’ 0.0.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/README.md +64 -0
  2. package/package.json +2 -2
package/README.md CHANGED
@@ -122,6 +122,70 @@ open({
122
122
 
123
123
  ---
124
124
 
125
+ ## πŸͺŸ Using inside React Native `<Modal>`
126
+
127
+ React Native `<Modal>` is rendered in a separate native layer. To ensure the menu appears **above** the modal content, mount a provider/layer **inside** the modal tree.
128
+
129
+ **Sheets & overlays**:
130
+
131
+ - **Native-layer overlays** (RN `<Modal>`, `react-native-navigation` modals/overlays, etc.): mount `AnchoredMenuLayer` inside that overlay’s content tree.
132
+ - **JS-only sheets** (rendered as normal React views in the same tree): you can keep a single provider at the app root.
133
+
134
+ Recommended:
135
+
136
+ ```tsx
137
+ import React, { useState } from "react";
138
+ import { Modal, Pressable, Text, View } from "react-native";
139
+ import {
140
+ AnchoredMenuLayer,
141
+ MenuAnchor,
142
+ useAnchoredMenuActions,
143
+ } from "react-native-anchored-menu";
144
+
145
+ export function ExampleModalMenu() {
146
+ const [visible, setVisible] = useState(false);
147
+ const { open } = useAnchoredMenuActions();
148
+
149
+ return (
150
+ <>
151
+ <Pressable onPress={() => setVisible(true)}>
152
+ <Text>Open modal</Text>
153
+ </Pressable>
154
+
155
+ <Modal transparent visible={visible} onRequestClose={() => setVisible(false)}>
156
+ <AnchoredMenuLayer>
157
+ <View style={{ flex: 1, justifyContent: "center", alignItems: "center" }}>
158
+ <MenuAnchor id="modal-menu">
159
+ <Pressable
160
+ onPress={() =>
161
+ open({
162
+ id: "modal-menu",
163
+ host: "view",
164
+ render: ({ close }) => (
165
+ <View style={{ backgroundColor: "#111", padding: 12, borderRadius: 8 }}>
166
+ <Pressable onPress={close}>
167
+ <Text style={{ color: "#fff" }}>Action</Text>
168
+ </Pressable>
169
+ </View>
170
+ ),
171
+ })
172
+ }
173
+ >
174
+ <Text>Open menu</Text>
175
+ </Pressable>
176
+ </MenuAnchor>
177
+
178
+ <Pressable onPress={() => setVisible(false)}>
179
+ <Text>Close modal</Text>
180
+ </Pressable>
181
+ </View>
182
+ </AnchoredMenuLayer>
183
+ </Modal>
184
+ </>
185
+ );
186
+ }
187
+ ```
188
+
125
189
  ## 🧠 API
126
190
 
127
191
  ### `useAnchoredMenuActions()`
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "react-native-anchored-menu",
3
- "version": "0.0.7",
3
+ "version": "0.0.9",
4
4
  "description": "Headless anchored menu/popover for React Native with stable measurement (view host by default).",
5
5
  "repository": {
6
6
  "type": "git",
@@ -30,5 +30,5 @@
30
30
  "react": "*",
31
31
  "react-native": "*"
32
32
  },
33
- "readme": "# react-native-anchored-menu\n\nA **headless, anchor-based menu / popover system for React Native** designed to work reliably across:\n\n- iOS & Android\n- FlatList / SectionList\n- Complex layouts\n- New Architecture (Fabric)\n- Modal & non-modal contexts\n\nThis library focuses on **correct measurement and positioning**, not UI. \nYou fully control how the menu looks and behaves.\n\n---\n\n## 🎬 Demo\n\n| View host (normal screens) | View host inside native `<Modal>` |\n| --- | --- |\n| ![View host demo](https://raw.githubusercontent.com/mahmoudelfekygithub/react-native-anchored-menu/main/assets/demo1.gif) | ![Modal demo](https://raw.githubusercontent.com/mahmoudelfekygithub/react-native-anchored-menu/main/assets/demo2.gif) |\n\n---\n\n## ✨ Why this library exists\n\nMost React Native menu / popover libraries break in at least one of these cases:\n\n- Wrong position on Android\n- Unreliable measurement inside FlatList\n- Broken behavior with Fabric\n- Rendering behind or inside unexpected layers\n- Forced UI and styling\n\n**react-native-anchored-menu** solves these by:\n\n- Using **stable anchor measurement**\n- Separating **state (Provider)** from **rendering (Hosts)**\n- Supporting multiple rendering strategies (View / Modal)\n- Staying **100% headless**\n\n---\n\n## βœ… Features\n\n- πŸ“ Anchor menus to any component\n- πŸ“ Accurate positioning (`auto`, `top`, `bottom`)\n- 🧠 FlatList-safe measurement\n- πŸͺŸ Works inside and outside native `<Modal>`\n- 🧩 Fully headless render API\n- 🧹 Tap outside to dismiss\n- πŸ”„ Auto-close on scroll (optional)\n- 🌍 RTL-aware positioning\n- 🧱 Multiple host strategies\n\n---\n\n## πŸ“¦ Installation\n\n```bash\nnpm install react-native-anchored-menu\n# or\nyarn add react-native-anchored-menu\n```\n\nNo native linking required.\n\n---\n\n## πŸš€ Basic Usage\n\n### 1️⃣ Wrap your app\n\n```tsx\nimport { AnchoredMenuProvider } from \"react-native-anchored-menu\";\n\nexport default function Root() {\n return (\n <AnchoredMenuProvider>\n <App />\n </AnchoredMenuProvider>\n );\n}\n```\n\n> ⚠️ You **do NOT need** to manually mount any host by default. \n> Hosts are automatically mounted internally.\n\n---\n\n### 2️⃣ Add an anchor\n\n```tsx\nimport { MenuAnchor } from \"react-native-anchored-menu\";\n\n<MenuAnchor id=\"profile-menu\">\n <Pressable>\n <Text>Open menu</Text>\n </Pressable>\n</MenuAnchor>\n```\n\n---\n\n### 3️⃣ Open the menu\n\n```tsx\nimport { useAnchoredMenuActions } from \"react-native-anchored-menu\";\n\nconst { open, close } = useAnchoredMenuActions();\n\nopen({\n id: \"profile-menu\",\n render: ({ close }) => (\n <View style={{ backgroundColor: \"#111\", padding: 12, borderRadius: 8 }}>\n <Pressable onPress={close}>\n <Text style={{ color: \"#fff\" }}>Logout</Text>\n </Pressable>\n </View>\n ),\n});\n```\n\n---\n\n## 🧠 API\n\n### `useAnchoredMenuActions()`\n\n```ts\nconst { open, close } = useAnchoredMenuActions();\n```\n\n### `useAnchoredMenuState(selector?)`\n\n```ts\nconst isOpen = useAnchoredMenuState((s) => s.isOpen);\n```\n\n**Recommended (performance)**: prefer split hooks in large trees to reduce re-renders:\n\n```ts\nconst isOpen = useAnchoredMenuState((s) => s.isOpen);\nconst { open } = useAnchoredMenuActions();\n```\n\n> `useAnchoredMenu()` is still available for backwards compatibility, but the split hooks are recommended\n> to reduce re-renders in large trees.\n\n---\n\n### `open(options)`\n\n```ts\nopen({\n id: string;\n\n placement?: \"auto\" | \"top\" | \"bottom\";\n align?: \"start\" | \"center\" | \"end\";\n offset?: number;\n margin?: number;\n rtlAware?: boolean;\n\n render?: ({ close, anchor }) => ReactNode;\n content?: ReactNode;\n\n host?: \"view\" | \"modal\";\n\n animationType?: \"fade\" | \"none\";\n statusBarTranslucent?: boolean;\n\n /**\n * Measurement strategy.\n * - \"stable\" (default): waits for interactions and retries for correctness (best for FlatList/Android)\n * - \"fast\": one-frame measure (lowest latency, less reliable on complex layouts)\n */\n measurement?: \"stable\" | \"fast\";\n\n /**\n * Only used when `measurement=\"stable\"` (default: 8).\n */\n measurementTries?: number;\n});\n```\n\n---\n\n## 🧭 Placement Behavior\n\n- `auto` β†’ below if space allows, otherwise above\n- `top` β†’ prefer above, fallback below\n- `bottom` β†’ prefer below, fallback above\n\n---\n\n## 🧱 Host System\n\n- Default host: **view**\n- Hosts are auto-mounted\n- `modal` host is disabled on Fabric and falls back to `view`\n\n---\n\n## πŸ“„ License\n\nMIT Β© Mahmoud Elfeky\n"
33
+ "readme": "# react-native-anchored-menu\n\nA **headless, anchor-based menu / popover system for React Native** designed to work reliably across:\n\n- iOS & Android\n- FlatList / SectionList\n- Complex layouts\n- New Architecture (Fabric)\n- Modal & non-modal contexts\n\nThis library focuses on **correct measurement and positioning**, not UI. \nYou fully control how the menu looks and behaves.\n\n---\n\n## 🎬 Demo\n\n| View host (normal screens) | View host inside native `<Modal>` |\n| --- | --- |\n| ![View host demo](https://raw.githubusercontent.com/mahmoudelfekygithub/react-native-anchored-menu/main/assets/demo1.gif) | ![Modal demo](https://raw.githubusercontent.com/mahmoudelfekygithub/react-native-anchored-menu/main/assets/demo2.gif) |\n\n---\n\n## ✨ Why this library exists\n\nMost React Native menu / popover libraries break in at least one of these cases:\n\n- Wrong position on Android\n- Unreliable measurement inside FlatList\n- Broken behavior with Fabric\n- Rendering behind or inside unexpected layers\n- Forced UI and styling\n\n**react-native-anchored-menu** solves these by:\n\n- Using **stable anchor measurement**\n- Separating **state (Provider)** from **rendering (Hosts)**\n- Supporting multiple rendering strategies (View / Modal)\n- Staying **100% headless**\n\n---\n\n## βœ… Features\n\n- πŸ“ Anchor menus to any component\n- πŸ“ Accurate positioning (`auto`, `top`, `bottom`)\n- 🧠 FlatList-safe measurement\n- πŸͺŸ Works inside and outside native `<Modal>`\n- 🧩 Fully headless render API\n- 🧹 Tap outside to dismiss\n- πŸ”„ Auto-close on scroll (optional)\n- 🌍 RTL-aware positioning\n- 🧱 Multiple host strategies\n\n---\n\n## πŸ“¦ Installation\n\n```bash\nnpm install react-native-anchored-menu\n# or\nyarn add react-native-anchored-menu\n```\n\nNo native linking required.\n\n---\n\n## πŸš€ Basic Usage\n\n### 1️⃣ Wrap your app\n\n```tsx\nimport { AnchoredMenuProvider } from \"react-native-anchored-menu\";\n\nexport default function Root() {\n return (\n <AnchoredMenuProvider>\n <App />\n </AnchoredMenuProvider>\n );\n}\n```\n\n> ⚠️ You **do NOT need** to manually mount any host by default. \n> Hosts are automatically mounted internally.\n\n---\n\n### 2️⃣ Add an anchor\n\n```tsx\nimport { MenuAnchor } from \"react-native-anchored-menu\";\n\n<MenuAnchor id=\"profile-menu\">\n <Pressable>\n <Text>Open menu</Text>\n </Pressable>\n</MenuAnchor>\n```\n\n---\n\n### 3️⃣ Open the menu\n\n```tsx\nimport { useAnchoredMenuActions } from \"react-native-anchored-menu\";\n\nconst { open, close } = useAnchoredMenuActions();\n\nopen({\n id: \"profile-menu\",\n render: ({ close }) => (\n <View style={{ backgroundColor: \"#111\", padding: 12, borderRadius: 8 }}>\n <Pressable onPress={close}>\n <Text style={{ color: \"#fff\" }}>Logout</Text>\n </Pressable>\n </View>\n ),\n});\n```\n\n---\n\n## πŸͺŸ Using inside React Native `<Modal>`\n\nReact Native `<Modal>` is rendered in a separate native layer. To ensure the menu appears **above** the modal content, mount a provider/layer **inside** the modal tree.\n\n**Sheets & overlays**:\n\n- **Native-layer overlays** (RN `<Modal>`, `react-native-navigation` modals/overlays, etc.): mount `AnchoredMenuLayer` inside that overlay’s content tree.\n- **JS-only sheets** (rendered as normal React views in the same tree): you can keep a single provider at the app root.\n\nRecommended:\n\n```tsx\nimport React, { useState } from \"react\";\nimport { Modal, Pressable, Text, View } from \"react-native\";\nimport {\n AnchoredMenuLayer,\n MenuAnchor,\n useAnchoredMenuActions,\n} from \"react-native-anchored-menu\";\n\nexport function ExampleModalMenu() {\n const [visible, setVisible] = useState(false);\n const { open } = useAnchoredMenuActions();\n\n return (\n <>\n <Pressable onPress={() => setVisible(true)}>\n <Text>Open modal</Text>\n </Pressable>\n\n <Modal transparent visible={visible} onRequestClose={() => setVisible(false)}>\n <AnchoredMenuLayer>\n <View style={{ flex: 1, justifyContent: \"center\", alignItems: \"center\" }}>\n <MenuAnchor id=\"modal-menu\">\n <Pressable\n onPress={() =>\n open({\n id: \"modal-menu\",\n host: \"view\",\n render: ({ close }) => (\n <View style={{ backgroundColor: \"#111\", padding: 12, borderRadius: 8 }}>\n <Pressable onPress={close}>\n <Text style={{ color: \"#fff\" }}>Action</Text>\n </Pressable>\n </View>\n ),\n })\n }\n >\n <Text>Open menu</Text>\n </Pressable>\n </MenuAnchor>\n\n <Pressable onPress={() => setVisible(false)}>\n <Text>Close modal</Text>\n </Pressable>\n </View>\n </AnchoredMenuLayer>\n </Modal>\n </>\n );\n}\n```\n\n## 🧠 API\n\n### `useAnchoredMenuActions()`\n\n```ts\nconst { open, close } = useAnchoredMenuActions();\n```\n\n### `useAnchoredMenuState(selector?)`\n\n```ts\nconst isOpen = useAnchoredMenuState((s) => s.isOpen);\n```\n\n**Recommended (performance)**: prefer split hooks in large trees to reduce re-renders:\n\n```ts\nconst isOpen = useAnchoredMenuState((s) => s.isOpen);\nconst { open } = useAnchoredMenuActions();\n```\n\n> `useAnchoredMenu()` is still available for backwards compatibility, but the split hooks are recommended\n> to reduce re-renders in large trees.\n\n---\n\n### `open(options)`\n\n```ts\nopen({\n id: string;\n\n placement?: \"auto\" | \"top\" | \"bottom\";\n align?: \"start\" | \"center\" | \"end\";\n offset?: number;\n margin?: number;\n rtlAware?: boolean;\n\n render?: ({ close, anchor }) => ReactNode;\n content?: ReactNode;\n\n host?: \"view\" | \"modal\";\n\n animationType?: \"fade\" | \"none\";\n statusBarTranslucent?: boolean;\n\n /**\n * Measurement strategy.\n * - \"stable\" (default): waits for interactions and retries for correctness (best for FlatList/Android)\n * - \"fast\": one-frame measure (lowest latency, less reliable on complex layouts)\n */\n measurement?: \"stable\" | \"fast\";\n\n /**\n * Only used when `measurement=\"stable\"` (default: 8).\n */\n measurementTries?: number;\n});\n```\n\n---\n\n## 🧭 Placement Behavior\n\n- `auto` β†’ below if space allows, otherwise above\n- `top` β†’ prefer above, fallback below\n- `bottom` β†’ prefer below, fallback above\n\n---\n\n## 🧱 Host System\n\n- Default host: **view**\n- Hosts are auto-mounted\n- `modal` host is disabled on Fabric and falls back to `view`\n\n---\n\n## πŸ“„ License\n\nMIT Β© Mahmoud Elfeky\n"
34
34
  }