From 0316055c2c48f9ed870d181ad9f69b668582190e Mon Sep 17 00:00:00 2001 From: Dominic Go Date: Sat, 21 Dec 2024 13:40:52 +0800 Subject: [PATCH] =?UTF-8?q?=F0=9F=93=9D=20Docs:=20README=20-=20Update=20No?= =?UTF-8?q?tice?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 4437 +++++++++++++++++++++++++++++++++++----- docs/README-01-Pre.md | 27 +- docs/README-02-Docs.md | 3525 +++++++++++++++++++++++++++++++ 3 files changed, 7514 insertions(+), 475 deletions(-) diff --git a/README.md b/README.md index ad800812..74f4485c 100644 --- a/README.md +++ b/README.md @@ -6,10 +6,17 @@ A small component for using context menu's on iOS.

-## 🚧⚠️ Documentation WIP ⚠️🚧 +## 🚧⚠️ Notices ⚠️🚧 -πŸ“ Note: See [`TODO.md`](docs/TODO.md) for progress. +πŸ“ **Version `2.x` Notice**: Hello, please note that versions `2.x` and below of this library are no longer supported; please do not submit an issue if the version you are using is below `3.x`. +* If you really need a fix for the particular issue/bug, please create a repro and add a test case in the [examples](example/src/examples) directory via a pull request in the main branch; i will investigate the bug, and backport the fix from `3.x` to `2.x`. +* I apologize but i do not have the resources to maintain multiple versions of this library; all issues must be reproducible from `3.x` first before i can backport the changes to an older version of this library. +* Please understand that PR for the repro is crucial; i cannot work on the fix if i don't have a repro to start on; words describing the issue is not enough due to the language barrier. Once you've created a test case, please tag me on the PR so i get notified. +* **Summary**: I will fix the bugs you encounter, however i cannot work on fixing them until a repro/test case is created in the examples directory. Thank you for understanding. + +
+πŸ“ **Documentation Notice**: See [`TODO.md`](docs/TODO.md) for progress. - The documentation is incomplete (some parts/sections are marked as **TBA** i.e. "to be added"). - Some of the links in the documentation are broken (i.e. the URL points to `PLACE_HOLDER_LINK`). - Some of the gifs/images are old, or broken. @@ -26,6 +33,8 @@ A small component for using context menu's on iOS. ### Versions +
+ | Library Version | Compatibility | | :-------------- | ------------------------------------------------------------ | | `3.x`+ | Depends on `react-native-ios-utilities@5.x`
Depends on `ContextMenuAuxiliaryPreview`
iOS 13+
Xcode 15+ | @@ -206,20 +215,6 @@ cd ios && pod install
-### Installation (Experimental Version) - -```sh -# 1. install library + dependencies -npm install react-native-ios-utilities@next -npm install react-native-ios-context-menu@next - - -# 2. then run pod install (uses auto-linking) -cd ios && pod install -``` - -
- ### Updating This library has cocoapods dependency to [`ContextMenuAuxiliaryPreview`](https://github.com/dominicstop/ContextMenuAuxiliaryPreview) and [`DGSwiftUtilities`](https://github.com/dominicstop/DGSwiftUtilities), so you may need to update them separately (as needed). @@ -369,675 +364,4199 @@ const styles = StyleSheet.create({

-## D. Documentation +# react-native-ios-context-menu -πŸ’‘ **Tip**: Most of the time, when a type or component is mentioned, you can click it to jump to that item in the README (or its declaration in the source code). +A small component for using context menu's on iOS. -
+![context-menu-example-demo](./assets/context-menu-example-demo.gif) -### D.1. Components +

-#### `ContextMenuView` Component +## 🚧⚠️ Documentation WIP ⚠️🚧 -##### `ContextMenuView` Component: Props +πŸ“ Note: See [`TODO.md`](docs/TODO.md) for progress. -| Prop Name and Type | Description | -| :----------------------------------------------------------- | :----------------------------------------------------------- | -| βš›οΈ `ViewProps` | This component supports all the standard props from a `` component. | -| πŸ”€ `menuConfig`

βš›οΈ [`MenuConfig`](PLACE_HOLDER_LINK) | This prop configures the context menu, along with what menu actions to show.

This prop accepts a `MenuConfig` object. This object is used to configure various aspects of the context menu. Here are some relevant properties:

1️⃣ `MenuConfig.menuTitle`: the context menu title (required) β€” if you don't want to show the menu title, pass in an empty string.

2️⃣ `MenuConfig.menuItems`: the actions to show (e.g. the title, icons, subtitle, etc) β€” accepts either an array of `MenuActionConfig` or `MenuConfig` objects.

3️⃣ `MenuConfig.menuOptions`: the attributes of the context menu (e.g. destructive) β€” accepts an array of `UIMenuOptions` string items, and any nested menus or submenus to show (see "**Note A**").

πŸ“ **Note A**: Passing a `MenuConfig` object inside of the `MenuConfig.menuItems` property will result in a nested context menu (i.e. a submenu).

In this scenario, the `MenuConfig.menuOptions` and `MenuConfig.icon` can be used to configure the appearance of the submenu.

For usage examples regarding nested menus, see [Example 06](contextmenuview-example06).

πŸ“ **Note B**: Passing a value of `null` (or `undefined`) to this prop will not disable the context menu. Instead, please use the `isContextMenuEnabled` prop to disable the context menu.

πŸ“ **Note C**: You can put `MenuConfig` in state if you want to dynamically change the menu configuration (this will allow you to add/remove submenu items, or update the current menu options).

If the context menu is currently visible, changing/updating the `MenuConfig` value passed to this prop will cause the context menu to change in real-time. This behavior is only supported on iOS 14+.

πŸ“Œ Some example links to get you started:
β€’ For basic usage examples regarding `MenuConfig`, see: [Example 1](#contextmenuview-example-06),

β€’ For examples on creating + configuring the menu action items (i.e `MenuActionConfig`), see: [Example 2](#contextmenuview-example-02),

β€’ For menu action attributes + menu state, and action subtitles, see: [Example 4](#contextmenuview-example-04), [Example 8](#contextmenuview-example-08), and [Example 13](#contextmenuview-example-13),

β€’ For examples regarding the usage of icons (i.e `ImageItemConfig`), see: [Example 16](#contextmenuview-example-16), [Example 17](#contextmenuview-example-17), and [Example 18](#contextmenuview-example-18). | -| πŸ”€ `previewConfig`

βš›οΈ [`MenuPreviewConfig`](PLACE_HOLDER_LINK) | Configures the context menu's preview.

If no configuration is provided then it will default to using the context menu component itself as the preview.

πŸ“ **Note**: If you do not want to show a preview (i.e. only show the context menu itself), consider using a [`ContextMenuButton`](PLACE_HOLDER_LINK) component instead.

πŸ“Œ Some example links to get you started:
β€’ For examples regarding the configuration of the context menu preview (e.g. custom previews), see: [Example 11](#contextmenuview-example-11), [Example 12](#contextmenuview-example-12), [Example 14](#contextmenuview-example-14), and [Example 15](#contextmenuview-example-15). | -| πŸ”€ `shouldUseDiscoverability`
`TitleAsFallbackValueForSubtitle`

βš›οΈ `boolean`

✳️ **Default**: `true` | On iOS 15+, the value passed to the `MenuActionConfig.discoverabilityTitle` property is no longer displayed as a subtitle under the menu action.

Instead you need to set a different property called `MenuActionConfig.subtitle`.

The `discoverabilityTitle` property is now used for the "discoverability heads-up display" (e.g when an app supports keyboard shortcuts, holding down the command key presents a list of shortcuts; the `discoverabilityTitle` is then used as the title for the shortcut).

If this prop is set to true, it will then use the value passed on to the `discoverabilityTitle` value as the subtitle for the menu action, preserving the old behavior. In other words, this prop exists for backwards-compatibility reasons.

πŸ“ **Note**: This prop is set to `true` by default; set this to `false` if you don't want this automatic behaviour to happen. | -| πŸ”€ `shouldWaitForMenuToHide`
`BeforeFiringOnPressMenuItem`

βš›οΈ `boolean`

✳️ **Default**: `true` | If set to `true` (which it is by default), the `onPressMenuItem` event will be triggered after the context menu has been hidden (i.e. after `onMenuDidHide` event is triggered).

Set this to `false` if you want `onPressMenuItem` to trigger as soon as an item has been pressed in the context menu.

πŸ“ **Note**: Layout updates while the context menu is transitioning from it's open to hidden state might cause layout flickering (e.g. [Issue #43](https://github.com/dominicstop/react-native-ios-context-menu/issues/43)). | -| πŸ”€ `isContextMenuEnabled`

βš›οΈ `boolean`

✳️ **Default**: `true` | Enables or disables the context menu. Useful if you want to temporarily disable the context menu. | -| πŸ”€ `lazyPreview`

βš›οΈ `boolean`

✳️ **Default**: `true` | If set to `true` (which it is by default), the custom context menu preview (i.e. the component returned from the `ContextMenuView.renderPreview` prop) and the auxiliary preview (i.e. the component returned from the `ContextMenuView.renderAuxillaryPreview` prop) are only mounted/rendered when the context menu is visible.

Set this to `false` if you want the preview content to be always mounted. | -| πŸ”€ `renderPreview`

βš›οΈ [`() => React.ReactElement`](PLACE_HOLDER_LINK) | This prop is a "render" prop, i.e it accepts a function that returns a react component.

The returned component will displayed in the context menu preview. | -| πŸ”€ `isAuxiliaryPreviewEnabled`

βš›οΈ `boolean`

✳️ **Default**: `false` | ⚠️ **Experimental**: Please see [Auxiliary Preview](#contextmenuview-component-experimental---auxiliary-preview) section.

TBA | -| πŸ”€ `auxiliaryPreviewConfig`

βš›οΈ `MenuAuxiliaryPreviewConfig` | ⚠️ **Experimental**: Please see [Auxiliary Preview](#contextmenuview-component-experimental---auxiliary-preview) section.

TBA | -| πŸ”€ `renderAuxillaryPreview`

βš›οΈ `() => React.ReactElement` | ⚠️ **Experimental**: Please see [Auxiliary Preview](#contextmenuview-component-experimental---auxiliary-preview) section.

TBA | +- The documentation is incomplete (some parts/sections are marked as **TBA** i.e. "to be added"). +- Some of the links in the documentation are broken (i.e. the URL points to `PLACE_HOLDER_LINK`). +- Some of the gifs/images are old, or broken. +- For now, please see the [Usage And Examples](#e-usage-and-examples) section, and [Showcase, Tests and Demos](#F-Showcase-Tests-and-Demos) section for information on how to use this library.

-##### `ContextMenuView` Component: Event Props - -| Prop Name and Type | Description | -| :----------------------------------------------------------- | :----------------------------------------------------------- | -| πŸ”€ `onMenuWillShow`

βš›οΈ [`OnMenuWillShowEvent`](./src/types/MenuEvents.ts) | Event that gets called **before** the context menu is shown, i.e this event is immediately invoked when the menu is about to become visible. | -| πŸ”€ `onMenuDidShow`

βš›οΈ [`OnMenuDidShowEvent`](./src/types/MenuEvents.ts) | Event that gets called **after** the context menu is shown, i.e this event is invoked after the menu entrance animation is finished. | -| πŸ”€ `onMenuWillHide`

βš›οΈ [`OnMenuWillHideEvent`](./src/types/MenuEvents.ts) | Event that gets called **before** the context menu is hidden, i.e this event is immediately invoked when the menu is about to become hidden. | -| πŸ”€ `onMenuDidHide`

βš›οΈ [`OnMenuDidHideEvent`](./src/types/MenuEvents.ts) | Event that gets called **after** the context menu is hidden, i.e this event is invoked after the menu exit animation is finished. | -| πŸ”€ `onMenuWillCancel`

βš›οΈ [`OnMenuWillCancelEvent`](./src/types/MenuEvents.ts) | Event that gets called when the menu is **cancelled and about to be hidden**, i.e this event is immediately invoked when the context menu interaction is cancelled. | -| πŸ”€ `onMenuDidCancel`

βš›οΈ [`OnMenuDidCancelEvent`](./src/types/MenuEvents.ts) | Event that gets called when the menu is **cancelled and hidden**, i.e. this event is invoked when the context menu is cancelled, and the menu exit transition is finished. | -| πŸ”€ `onPressMenuItem`

βš›οΈ [`OnPressMenuItemEvent`](./src/types/MenuEvents.ts) | Event that gets called when a menu action is pressed.

You can identify which action was pressed via `nativeEvent.actionKey ` property in the `nativeEvent` object.

Check out [Example 1](#contextmenuview-example-01), and [Example 9](#contextmenuview-example-09) for examples regarding the `onPressMenuItem` event prop.

πŸ“ **Note**: If `shouldWaitForMenuToHide`
`BeforeFiringOnPressMenuItem` prop is set to `true` (which it is by default), then this event will fire after `onMenuDidHide` is triggered. | -| πŸ”€ `onPressMenuPreview`

βš›οΈ [`OnPressMenuPreviewEvent`](./src/types/MenuEvents.ts) | Event that gets called when the menu's preview is pressed. | -| πŸ”€ `onMenuAuxiliaryPreviewWillShow`

βš›οΈ [`OnMenuAuxiliaryPreviewWillShowEvent`](./src/types/MenuEvents.ts) | ⚠️ **Experimental**: Please see [Auxiliary Preview](#contextmenuview-component-experimental---auxiliary-preview) section.

TBA | -| πŸ”€ `onMenuAuxiliaryPreviewDidShow`

βš›οΈ [`OnMenuAuxiliaryPreviewDidShowEvent`](./src/types/MenuEvents.ts) | ⚠️ **Experimental**: Please see [Auxiliary Preview](#contextmenuview-component-experimental---auxiliary-preview) section.

TBA | -| πŸ”€ `onMenuAuxiliaryPreviewDidShow`

βš›οΈ [`DeferredElementProvider`](./src/components/ContextMenuView/ContextMenuViewTypes) i.e.
`(deferredID, completion)Β =>Β void` | This event gets called whenever a `UIDeferredMenuElement` needs to be loaded. A deferred menu element can be created via a `DeferredMenuElementConfig` object.

A deferred menu is a context menu is basically a placeholder β€” i.e. it appears as a loading indicator in the context menu.

When you pass in a `DeferredMenuElementConfig` object to `MenuConfig.menuItems`, it means you want to load and add additional menu items once the context menu is opened.

This event will provide a `completion` callback β€” use this to provide the additional context menu items you want to load.

πŸ“ **Note A**: Deferred menu elements only work on iOS 14+.

πŸ“ **Note B**: You can dynamically update the context menu items without using the prop β€” the difference is that deferred menu items will show a placeholder loading indicator when the additional menu items haven't been loaded yet.

πŸ“ **Note C**: It is possible to have multiple deferred menu elements (e.g. deferred elements can also provide deferred elements, and so on).

Just be sure to use a unique `deferredID` so you can tell them apart.

πŸ“Œ **Example Usage**:
β€’ [`ContextMenuViewExample19`](#ContextMenuView-Example-19). | - -
+| Notice | +| ------------------------------------------------------------ | +| πŸ“ **Note** #1: Version `3.x` is a rewrite of this library to support both fabric (the new architecture), and offer backwards compatibility to paper (the old architecture).

Support for the new architecture (fabric), and backwards compatibility for the old architecture (paper) is handled via a peer via a peer dependency to [`react-native-ios-utilites@v5`](https://github.com/dominicstop/react-native-ios-utilities). | +| πŸ“ **Note** #2: The documentation + examples are currently being rewritten.

❀️ [`README-old-v1.md`](./README-old-v1.md) β€” Documentation for `v1.x`
🧑 [`README-old-v2.md`](./README-old-v2.md) β€” Documentation for `v2.x`
πŸ’› [`example/src/examples`](./example/src/examples) β€” The typescript rewrite of the examples (WIP). | -##### `ContextMenuView` Component: Properties/Methods +
-| Prop Name and Type | Description | -| :----------------------------------------------------------- | :----------------------------------------------------------- | -| πŸ”€ `dismissMenu`

βš›οΈ `Promise` | Allows you to programmatically dismiss the context menu. Only available on iOS 14 and above. | -| πŸ”€ `presentMenu`

βš›οΈ `Promise` | Allows you to programmatically show the context menu. | -| πŸ”€ `showAuxiliaryPreviewAsPopover`

βš›οΈ `Promise` | Allows you to programmatically show the auxiliary preview as a popover. | +### Versions -
+| Library Version | Compatibility | +| :-------------- | ------------------------------------------------------------ | +| `3.x`+ | Depends on `react-native-ios-utilities@5.x`
Depends on `ContextMenuAuxiliaryPreview`
iOS 13+
Xcode 15+ | +| `2.1` | Uses `Expo-Modules`
Depends on `react-native-ios-utilities@4.x`
Depends on `ContextMenuAuxiliaryPreview`
iOS 13+
Xcode 15+ | +| `2.0.x` | Uses `Expo-Modules`
Depends on `react-native-ios-utilities@4.x`
iOS 13+
Xcode 15+ | +| `1.6.2` | iOS 10 to iOS 15
Xcode 12+ | +| `1.4` | iOS 10 to iOS 15
Xcode 13+ | +| `1.3` and Below | iOS 10 to 14
Xcode 12+ | -##### `ContextMenuView` Component: Experimental - Auxiliary Preview +

-The context menu auxiliary preview is an experimental feature, and is not officially part of `UIKit`'s "Menu and Shortcuts" API. +## Table of Contents -This is just a feature that I've implemented myself and added to the library β€” as such official support is limited and might break in a future iOS version. Please use at your own risk. +| Sections and Links | +| ------------------------------------------------------------ | +| [A. **Introduction**](#a-introduction)

β€’ [Gifs and Demos](#gifs-and-demos)
β€’ [Features](#features) | +| [B. **Installation**](#b-installation)

β€’ [Expo](#expo)
β€’ [Troubleshooting](#troubleshooting)
--β€’ [Xcode Build Error (Swift)](#troubleshooting-xcode-build-error-(swift))
--β€’ [Xcode Build Error (Undefined symbol)](#troubleshooting-xcode-build-error-(undefined-symbol)) | +| [C. **Basic Usage**](#c-basic-usage) | +| [D. **Documentation**](#d-documentation)

β€’ [D.1. Components](#d1-components)
--β€’ [`ContextMenuView` Component](#contextmenuview-component)
----β€’ [Props](#contextmenuview-component-props)
----β€’ [Event Props](#contextmenuview-component-event-props)
----β€’ [Properties/Methods](#contextmenuview-component-properties/methods)
----β€’ [Experimental - Aux. Preview](#contextmenuview-component-experimental---auxiliary-preview)

--β€’ [`ContextMenuButton` Component](#contextmenubutton-component)
----β€’ [Props](#contextmenubutton-component-props)
----β€’ [Event Props](#contextmenubutton-component-event-props)
----β€’ [Properties/Methods](#contextmenubutton-component-properties/methods)

β€’ [D.2. Context](#d2-context)
--β€’ [`ContextMenuButtonContext`](#ContextMenuButtonContext-context)
--β€’ [`ContextMenuButtonContext`](#ContextMenuButtonContext-context)

β€’ [D.3. Hooks](#d3-hooks)
--β€’ [`useMenuContext`](#useMenuContext-hook)
--β€’ [`useMenuButtonContext`](#useMenuButtonContext-hook)

β€’ [D.4. Objects and Types](#d4-objects-and-types)
--β€’ [`MenuConfig.ts`](#MenuConfigts)
----β€’ [Object Type: `MenuConfig`](#Object-Type-MenuConfig)
----β€’ [Object Type: `MenuActionConfig`](#Object-Type-MenuActionConfig)
----β€’ [Object Type: `DeferredMenuElementConfig`](#Object-Type-DeferredMenuElementConfig)
----β€’ [String Union: `MenuAttributes`](#String-Union-MenuAttributes)
----β€’ [String Union: `MenuState`](#String-Union-MenuState)
----β€’ [String Union: `UIMenuOptions`](#String-Union-UIMenuOptions)

--β€’ [`MenuPreviewConfig.ts`](#MenuPreviewConfigts)
----β€’ [Object Type: `MenuPreviewConfig`](#Object-Type-MenuPreviewConfig)
----β€’ [String Union: `ContextMenuInteractionCommitStyle`](#String-Union-ContextMenuInteractionCommitStyle)
----β€’ [String Union: `MenuPreviewSize`](#String-Union-MenuPreviewSize)
----β€’ [String Union: `MenuPreviewType`](#String-Union-MenuPreviewType)

--β€’ [`MenuAuxiliaryPreviewConfig.ts`](#MenuAuxiliaryPreviewConfigts)
----β€’ [Object Type: `MenuAuxiliaryPreviewConfig`](#Object-Type-MenuAuxiliaryPreviewConfig)
----β€’ [String Union Type: `MenuAuxiliaryPreviewAnchorPosition`](#String-Union-Type-MenuAuxiliaryPreviewAnchorPosition)
----β€’ [String Union Type: `MenuAuxiliaryPreviewHorizontalAlignment`](#String-Union-Type-MenuAuxiliaryPreviewHorizontalAlignment)
----β€’ [String Union Type: `UIViewAnimateOptions`](#String-Union-Type-UIViewAnimateOptions)
----β€’ [Object Type: `UIViewAnimateConfig`](#Object-Type-UIViewAnimateConfig)
----β€’ [Object Type: `MenuAuxiliaryPreviewBaseTransitionConfig`](#Object-Type-MenuAuxiliaryPreviewBaseTransitionConfig)
----β€’ [Object Union Type: `MenuAuxiliaryPreviewTransitionConfig`](#Object-Union-Type-`MenuAuxiliaryPreviewTransitionConfig`)
----β€’ [Mixed Union Type: `MenuAuxiliaryPreviewTransitionEntranceDelay`](#Mixed-Union-Type-MenuAuxiliaryPreviewTransitionEntranceDelay)

--β€’ [`MenuIconConfig.ts`](#MenuIconConfigts)
--β€’ [`ImageItemConfig.ts`](#ImageItemConfigts)
----β€’ [Object Type: `ImageItemConfig`](#Object-Type-ImageItemConfig)
----β€’ [Object Type: `ImageResolvedAssetSource`](#Object-Type-ImageResolvedAssetSource)
----β€’ [Object Type: `ImageRectConfig`](#Object-Type-ImageRectConfig)
----β€’ [Object Type: `ImageGradientConfig`](#Object-Type-ImageGradientConfig)
----β€’ [Object Type: `ImageSystemConfig`](#Object-Type-ImageSystemConfig)

--β€’ [Undocumented Types](#Undocumented-Types)

β€’ [D.5. Constants](#d5-constants) | +| [E. **Usage And Examples**](#E-Usage-And-Examples)
πŸ“ **Note**: See [Example Index](#toc-examples-index) section for a complete list of examples + their descriptions. | +| [F. **Showcase, Tests and Demos**](#F-Showcase-Tests-and-Demos) | +| [G. **Meta**](#G-Meta) | +| [H. **Licence**](#H-Licence) |
-#### `ContextMenuButton` Component - -For basic usage, please see [Example 1](#contextmenubutton-example-01) section. +### TOC: Examples Index -* The `ContextMenuButton` component is almost the same as the `ContextMenuView` component (It supports the same kind of props and events).
+| Examples | +| ------------------------------------------------------------ | +| πŸ“Œ **[`ContextMenuView` Example 01](#ContextMenuView-Example-01)**
πŸ’­ **Summary**: A basic context menu that has 3 menu action items. | +| πŸ“Œ **[`ContextMenuView` Example 02](#ContextMenuView-Example-02)**
πŸ’­ **Summary**: Icon Example β€” A basic context menu that has 3 menu action items, each with a different "SF Symbols" icon. This examples shows how to add a system icon in the context menu action. | +| πŸ“Œ **[`ContextMenuView` Example 03](#ContextMenuView-Example-03)**
πŸ’­ **Summary**: Nested Menu β€” This example shows a context menu that has a submenu item inside its list of menu actions. | +| πŸ“Œ **[`ContextMenuView` Example 04](#ContextMenuView-Example-04)**
πŸ’­ **Summary**: Menu Attributes β€” This example context menu showcases the `MenuActionConfig.menuAttributes` property. | +| πŸ“Œ **[`ContextMenuView` Example 05](#ContextMenuView-Example-05)**
πŸ’­ **Summary**: Nested Menu + Menu Attributes β€” A context menu that has a in-line submenu. | +| πŸ“Œ **[`ContextMenuView` Example 06](#ContextMenuView-Example-06)**
πŸ’­ **Summary**: Menu Options β€” A context menu that has a destructive submenu. | +| πŸ“Œ **[`ContextMenuView` Example 07](#ContextMenuView-Example-07)**
πŸ’­ **Summary**: Menu Options β€” A context menu that set to be both "destructive" and "display in-line". | +| πŸ“Œ **[`ContextMenuView` Example 08](#ContextMenuView-Example-08)**
πŸ’­ **Summary**: Menu State β€” A context menu with 3 actions that has `'on'`, `'off'`, and `'mixed'` `menuState`. | +| πŸ“Œ **[`ContextMenuView` Example 09](#ContextMenuView-Example-09)**
πŸ’­ **Summary**: Events β€” An example for the `onPressMenuItem` event prop. | +| πŸ“Œ **[`ContextMenuView` Example 10](#ContextMenuView-Example-10)**
πŸ’­ **Summary**: Dynamic Menu β€” An example showing how to dynamically update the context menu while it's visible. In this example, the menu action changes every time the counter increments every second. | +| πŸ“Œ **[`ContextMenuView` Example 11](#ContextMenuView-Example-11)**
πŸ’­ **Summary**: Context Menu Previews β€” An example showing how to use a custom preview for the context menu. | +| πŸ“Œ **[`ContextMenuView` Example 12](#ContextMenuView-Example-12)**
πŸ’­ **Summary**: Context Menu Previews β€” An example showing a custom context menu preview that dynamically changes its size due to its contents updating every second. | +| πŸ“Œ **[`ContextMenuView` Example 13](#ContextMenuView-Example-13)**
πŸ’­ **Summary**: Menu Action β€” An example showing how to add a subtitle to menu action. | +| πŸ“Œ **[`ContextMenuView` Example 14](#ContextMenuView-Example-14)**
πŸ’­ **Summary**: Context Menu Previews β€” An example that changes the exit transition of the context menu preview when its tapped using the `preferredCommitStyle ` config. | +| πŸ“Œ **[`ContextMenuView` Example 15](#ContextMenuView-Example-15)**
πŸ’­ **Summary**: Context Menu Previews β€” An example showing how to configure a context menu that uses targeted previews. | +| πŸ“Œ **[`ContextMenuView` Example 15-02](#ContextMenuView-Example-15-02)**
πŸ’­ **Summary**: Context Menu Previews (Cont). β€” An example showing how to configure a context menu that uses targeted previews + `WrapperView`. | +| πŸ“Œ **[`ContextMenuView` Example 16](#ContextMenuView-Example-16)**
πŸ’­ **Summary**: Icon Example β€” An example showing a context menu with an action that uses a `'IMAGE_ASSET'` image for its icon. | +| πŸ“Œ **[`ContextMenuView` Example 17](#ContextMenuView-Example-17)**
πŸ’­ **Summary**: Icon Example β€” An example showing a context menu with action items that have different colored icons. | +| πŸ“Œ **[`ContextMenuView` Example 18](#ContextMenuView-Example-18)**
πŸ’­ **Summary**: Icon Example β€” An example showing a context menu with action items that has icons that uses local image assets imported via `require(...)`. | +| πŸ“Œ **[`ContextMenuView` Example 19](#ContextMenuView-Example-19)**
πŸ’­ **Summary**: Dynamic Menu β€” An example showing a context menu that has a loading indicator using deferred menu elements. | +| πŸ“Œ **[`ContextMenuView` Example 20](#ContextMenuView-Example-20)**
πŸ’­ **Summary**: Dynamic Menu β€” An example showing a state-controlled context menu that shows a loading indicator using deferred menu elements. | +| πŸ“Œ **[`ContextMenuView` Example 21](#ContextMenuView-Example-21)**
πŸ’­ **Summary**: Menu Element Size β€” TBA | +| πŸ“Œ **[`ContextMenuView` Example 22](#ContextMenuView-Example-22)**
πŸ’­ **Summary**: Menu Element Size β€” TBA | +| πŸ“Œ **[`ContextMenuView` Example 23](#ContextMenuView-Example-23)**
πŸ’­ **Summary**: Menu Element Size β€” TBA | +| πŸ“Œ **[`ContextMenuView` Example 24](#ContextMenuView-Example-24)**
πŸ’­ **Summary**: Menu Attributes β€” `keepsMenuPresented` | +| πŸ“Œ **[`ContextMenuView` Example 25](#ContextMenuView-Example-25)**
πŸ’­ **Summary**: Icon Example β€” Advanced customization (E.g. `scale`, `weight`, `paletteColors`, `hierarchicalColor`). | +| πŸ“Œ **[`ContextMenuView` Example 26](#ContextMenuView-Example-26)**
πŸ’­ **Summary**: Icon Example β€” Network/Remote images as icons. | +| πŸ“Œ **[`ContextMenuView` Example 27](#ContextMenuView-Example-27)**
πŸ’­ **Summary**: Icon Example β€” Network/Remote images as icons + fallback image. | +| πŸ“Œ **[`ContextMenuView` Example 28](#ContextMenuView-Example-28)**
πŸ’­ **Summary**: Programmatically shows the context menu. | +| πŸ“Œ **[`ContextMenuView` Auxiliary Preview - Example 01](#ContextMenuView-Auxiliary-Preview---Example-01)**
πŸ’­ **Summary**: TBA | +| πŸ“Œ **[`ContextMenuView` Auxiliary Preview - Example 02](#ContextMenuView-Auxiliary-Preview---Example-02)**
πŸ’­ **Summary**: TBA | +| πŸ“Œ **[`ContextMenuView` Auxiliary Preview - Example 03](#ContextMenuView-Auxiliary-Preview---Example-03)**
πŸ’­ **Summary**: TBA | +| πŸ“Œ **[`ContextMenuView` Auxiliary Preview - Example 04](#ContextMenuView-Auxiliary-Preview---Example-04)**
πŸ’­ **Summary**: TBA | +| πŸ“Œ **[`ContextMenuView` Auxiliary Preview - Example 05](#ContextMenuView-Auxiliary-Preview---Example-05)**
πŸ’­ **Summary**: TBA | +| πŸ“Œ **[`ContextMenuView` Auxiliary Preview - Example 06](#ContextMenuView-Auxiliary-Preview---Example-06)**
πŸ’­ **Summary**: TBA | +| πŸ“Œ **[`ContextMenuView` Auxiliary Preview - Example 07](#ContextMenuView-Auxiliary-Preview---Example-07)**
πŸ’­ **Summary**: TBA | +| πŸ“Œ **[`ContextMenuView` Auxiliary Preview - Example 08](#ContextMenuView-Auxiliary-Preview---Example-08)**
πŸ’­ **Summary**: TBA | +| πŸ“Œ **[`ContextMenuView` Auxiliary Preview - Example 09](#ContextMenuView-Auxiliary-Preview---Example-09)**
πŸ’­ **Summary**: TBA | +| πŸ“Œ **[`ContextMenuView` Auxiliary Preview - Example 10](#ContextMenuView-Auxiliary-Preview---Example-10)**
πŸ’­ **Summary**: TBA | +| πŸ“Œ **[`ContextMenuView` Auxiliary Preview - Example 11](#ContextMenuView-Auxiliary-Preview---Example-11)**
πŸ’­ **Summary**: TBA | +| πŸ“Œ **[`ContextMenuView` Auxiliary Preview - Example 12](#ContextMenuView-Auxiliary-Preview---Example-12)**
πŸ’­ **Summary**: TBA | +| πŸ“Œ **[`ContextMenuView` Auxiliary Preview - Example 13](#ContextMenuView-Auxiliary-Preview---Example-13)**
πŸ’­ **Summary**: TBA | +| πŸ“Œ **[`ContextMenuView` Auxiliary Preview - Example 14](#ContextMenuView-Auxiliary-Preview---Example-14)**
πŸ’­ **Summary**: TBA | +| πŸ“Œ **[`ContextMenuView` Auxiliary Preview - Example 15](#ContextMenuView-Auxiliary-Preview---Example-15)**
πŸ’­ **Summary**: TBA | +| πŸ“Œ **[`ContextMenuView` Auxiliary Preview - Example 16](#ContextMenuView-Auxiliary-Preview---Example-16)**
πŸ’­ **Summary**: Programmatically shows the auxiliary preview as a popover (w/o showing the context menu). | +| πŸ“Œ **[`ContextMenuButton` Example 01](#ContextMenuButton-Example-01)**
πŸ’­ **Summary**: TBA | +| πŸ“Œ **[`ContextMenuButton` Example 02](#ContextMenuButton-Example-02)**
πŸ’­ **Summary**: TBA | -* The only difference between them is that the `ContextMenuButton` component does not have a preview, and it can be immediately shown when its tapped instead of having to do a long press. See [Example 2](#422-contextmenubutton-simple-example-2) for more details.
+

-* Note that `ContextMenuButton` is only available on iOS 14 and above. On iOS 13, it will use a `ContextMenuButton`,
+### Acknowledgements -* If you want to add additional touch events, you can wrap this component inside a button component (e.g. `TouchableOpacity`).
- * When wrapping this component inside a button, please make sure to set the `useActionSheetFallback` prop to `false`. +Development and maintenance of this library was generously sponsored by [beatgig](https://beatgig.com/) from `11/15/2023` to ` 04/30/2024` at `$1,535`/month (totaling β‰ˆ `$9,100` over the course of 6 months) πŸ₯πŸŽΈ
-##### `ContextMenuButton` Component: Props - -| Prop Name and Type | Description | -| :----------------------------------------------------------- | :----------------------------------------------------------- | -| βš›οΈ `ViewProps` | This component supports all the standard props from a `` component. | -| πŸ”€ `menuConfig`

βš›οΈ [`MenuConfig`](PLACE_HOLDER_LINK) | Same as `ContextMenuView.menuConfig` prop. | -| πŸ”€ `isMenuPrimaryAction`

βš›οΈ `boolean` | When set to true, the context menu will be shown when its tapped instead of a long press. | -| πŸ”€ `shouldUseDiscoverability`
`TitleAsFallbackValueForSubtitle`

βš›οΈ `boolean`

✳️ **Default**: `true` | TBA / Not Implented | -| πŸ”€ `enableContextMenu`

βš›οΈ `boolean`

✳️ **Default**: `true` | Same as `ContextMenuView.enableContextMenu` prop. | -| πŸ”€ `useActionSheetFallback`

βš›οΈ `boolean`

✳️ **Default**: `true` | Same as `ContextMenuView.useActionSheetFallback` prop. | +The initial fabric rewrite (i.e. version `3.x`) was made possible through a generous `$3,750` sponsorship by [natew](https://github.com/natew) + [tamagui](https://github.com/tamagui/tamagui) over the course of 4 months (from: `05/27/24` to `09/30/24`) 🐦✨
-##### `ContextMenuButton` Component: Event Props - -| Prop Name and Type | Description | -| :----------------------------------------------------------- | :------------------------------------------------ | -| πŸ”€ `onMenuWillShow`

βš›οΈ [`OnMenuWillShowEvent`](./src/types/MenuEvents.ts) | Same as `ContextMenuView.onMenuWillShow` event. | -| πŸ”€ `onMenuDidShow`

βš›οΈ [`OnMenuDidShowEvent`](./src/types/MenuEvents.ts) | Same as `ContextMenuView.onMenuDidShow` event. | -| πŸ”€ `onMenuWillHide`

βš›οΈ [`OnMenuWillHideEvent`](./src/types/MenuEvents.ts) | Same as `ContextMenuView.onMenuWillHide` event. | -| πŸ”€ `onMenuDidHide`

βš›οΈ [`OnMenuDidHideEvent`](./src/types/MenuEvents.ts) | Same as `ContextMenuView.onMenuDidHide` event. | -| πŸ”€ `onMenuWillCancel`

βš›οΈ [`OnMenuWillCancelEvent`](./src/types/MenuEvents.ts) | Same as `ContextMenuView.onMenuWillCancel` event. | -| πŸ”€ `onMenuDidCancel`

βš›οΈ [`OnMenuDidCancelEvent`](./src/types/MenuEvents.ts) | Same as `ContextMenuView.onMenuDidCancel` event. | -| πŸ”€ `onMenuWillCreate`

βš›οΈ [`OnMenuWillCreateEvent`](./src/types/MenuEvents.ts) | Same as `ContextMenuView.onMenuWillCreate` event. | -| πŸ”€ `onPressMenuItem`

βš›οΈ [`OnPressMenuItemEvent`](./src/types/MenuEvents.ts) | Same as `ContextMenuView.onPressMenuItem` event. | +very special thanks to: [junzhengca](https://github.com/junzhengca), [brentvatne](https://github.com/brentvatne), [expo](https://github.com/expo), [EvanBacon](https://github.com/EvanBacon), [corasan](https://github.com/corasan), [lauridskern](https://github.com/lauridskern), [ronintechnologies](https://github.com/ronintechnologies), and [gerzonc](https://github.com/gerzonc) for becoming a monthly sponsor, and thank you [fobos531](https://github.com/fobos531) for being a one time sponsor πŸ₯Ί (if you have the means to do so, please considering sponsoring [here](https://github.com/sponsors/dominicstop)) -
+

-##### `ContextMenuButton` Component: Properties/Methods +## A. Introduction -| Prop Name and Type | Description | -| :------------------------------------------ | :-------------------------------------------- | -| πŸ”€ `dismissMenu`

βš›οΈ `Promise` | Same as `ContextMenuView.dismissMenu` method. | +A react native component to use [`UIMenu`](https://developer.apple.com/documentation/uikit/uimenu) on iOS 13 and later.
-### D.2. Context +### Gifs and Demos -#### `ContextMenuViewContext` Context +πŸ“ **Note**: These gifs are from an older version of the library running on iOS 13 (see [Usage And Examples](#e-usage-and-examples) section for updated example gifs).
-TBA +`ContextMenuView` Examples, **Left**: [Example 1](#ContextMenuView-Example-01), [Example 2](#ContextMenuView-Example-02), and **Right**: [Example 3](#ContextMenuView-Example-03), [Example 4](#ContextMenuView-Example-04) +![Simple Example 1 to 4 Gifs](./assets/montage-ContextMenuView-Example-old-1-2-3-4.gif) -| Property | Description | -| ------------------------------------------------------------ | ----------- | -| πŸ”€ `isMenuVisible`

βš›οΈ `boolean` | TBA | -| πŸ”€ `getRefToContextMenuView`

βš›οΈ `()Β =>Β ContextMenuView`
πŸ“Œ [`ContextMenuView`](PLACE_HOLDER_LINK) | TBA | +`ContextMenuView` examples, **Left**: [Example 5](#ContextMenuView-Example-05), [Example 6](#ContextMenuView-Example-06), and **Right**: [Example 7](#ContextMenuView-Example-07), [Example 8](#ContextMenuView-Example-08) +![Simple Example 5 to 8 Gifs](./assets/montage-ContextMenuView-Example-old-5-6-7-8.gif) -
+`ContextMenuView` example, **Left**: [Example 9](#ContextMenuView-Example-09), and **Right**: [Example 10](#ContextMenuView-Example-10) +![Simple Example 9 and 8 Gifs](./assets/montage-ContextMenuView-Example-old-9-10.gif) -#### `ContextMenuButtonContext` Context +`ContextMenuView` examples, **Left**: [Example 11](#ContextMenuView-Example-11), [Example 12](#ContextMenuView-Example-12), and **Right**: [Example 13](#ContextMenuView-Example-13), [ Example 14](#ContextMenuView-Example-14) +![Simple Example 11 to 14 Gifs](./assets/montage-ContextMenuView-Example-old-11-12-13-14.gif) -TBA +`ContextMenuView` examples, **Left**: [Example 15](#ContextMenuView-Example-15), [Example 16](#ContextMenuView-Example-16), and **Right**: [Example 17](#ContextMenuView-Example-17), [Example 18](#ContextMenuView-Example-18) +![Simple Example 11 to 14 Gifs](./assets/montage-ContextMenuView-Example-old-15-16-17-18.gif) -| Property | Description | -| ------------------------------------------------------------ | ----------- | -| πŸ”€ `isMenuVisible`

βš›οΈ `boolean` | TBA | -| πŸ”€ `getRefToContextMenuButton`

βš›οΈ `()Β =>Β ContextMenuView`
πŸ“Œ [`ContextMenuButton`](PLACE_HOLDER_LINK) | TBA | +`ContextMenuView` tests, **Left**: [Test 1](PLACE_HOLDER_LINK), and **Right**: [Test 2](PLACE_HOLDER_LINK) +![Context Menu View Test 1 and 2 Gifs](./assets/montage-ContextMenuView-Test-old-01-02.gif) -
+`ContextMenuView` tests, **Left**: [Test 3](PLACE_HOLDER_LINK), and **Right**: [Test 4](PLACE_HOLDER_LINK) +![Context Menu View Test 3 and 4 Gifs](./assets/montage-ContextMenuView-Test-old-03-04.gif) -### D.3. Hooks +`ContextMenuView` tests, **Left**: [Test 5](PLACE_HOLDER_LINK), and **Right**: [Test 6](PLACE_HOLDER_LINK) +![Context Menu View Test 5 and 6 Gifs](./assets/montage-ContextMenuView-Test-old-05-06.gif) -#### `useMenuContext` Hook +`ContextMenuView` tests, **Left/Right:** [Test 7](PLACE_HOLDER_LINK) +![Context Menu View 7 Gifs](./assets/montage-ContextMenuView-Test-old-07.gif) -A hook to use the `ContextMenuViewContext` context. +`ContextMenuView` `ActionSheetIOS` fallback for simple example 1 to 9 +![Action Sheet Fallback for Simple Example 1 to 9 Gifs](./assets/montage-ContextMenuView-ActionSheetFallback-Example-old-1-to-9.gif) -TBA +`ContextMenuView` `ActionSheetIOS` fallback for context menu view test 1 to 6 (removed in `v3.x`+). +![Action Sheet Fallback for Context Menu View Test 1 to 6 Gifs](./assets/montage-ContextMenuView-ActionSheetFallback-Test-old-1-to-6.gif) + +`ContextMenuButton` examples, **Left**: [Example 1](#ContextMenuButton-Example-01), and **Right**: [Example 2](#ContextMenuButton-Example-02) +![Simple Example 1 and 2 Gifs](./assets/montage-ContextMenuButton-Example-old-1-2.gif)
-#### `useMenuButtonContext` Hook +### Features -A hook to use the `ContextMenuButtonContext` context. +* Support for creating menu actions and submenus (i.e. nested and in-line menus). +* Support for customizing the menu icons (i.e. support for SF Symbols, `require(image)`, and `xcasset` icons, icon tint, etc). +* Extensive support for SF Symbols configuration (e.g. `pointSize`, `weight`, `scale`, `hierarchicalColor`, `paletteColors`). +* Support for iOS 14 functionality (like the `UIButton` context menu, dynamically updating the menu while it's visible, etc). +* Support for setting (almost) all of the native [`UIMenu`](https://developer.apple.com/documentation/uikit/uimenu) and οΏΌ[`UIAction`](https://developer.apple.com/documentation/uikit/uiaction) properties (e.g. `UIMenuElementState`, `MenuElementAtrributes`, `discoverabilityTitle`, etc.) +* Basic `ActionSheetIOS` menu fallback for iOS 12 and below (removed in `v3.x`+). +* Support for creating custom context menu previews (with support for dynamic or fixed preview sizes, setting the [`UIPreviewParameters`](https://developer.apple.com/documentation/uikit/uipreviewparameters), specifying a [`UITargetedPreview`](https://developer.apple.com/documentation/uikit/uitargetedpreview), etc). +* Support for custom auxiliary previews (experimental). +* Support for deferred context menu items. -TBA +

-
+## B. Installation -### D.4. Objects and Types +```sh +# 1. install library + dependencies +npm install react-native-ios-utilities@next +npm install react-native-ios-context-menu@next -#### `MenuConfig.ts` +# 2. then run pod install (uses auto-linking) +cd ios && pod install +``` -* πŸ“Œ **Declaration**: [`MenuConfig.ts`](src/types/MenuConfig.ts) +
-##### Object Type: `MenuConfig` +πŸ“ **Note A**: You might encounter some build errors since this library is written in swift, so there's some extra step involved to use this library (see table below for reference). -> A container for grouping related menu elements in an app menu or contextual menu. +
πŸ“ **Note B**: If you want to use an older or different version of this library, please refer to [versions section](#versions)'s compatibility table. -An object that is used to create and configure a context menu. Internally, this object is used to create a `UIMenu` instance (see [apple docs](https://developer.apple.com/documentation/uikit/uimenu/) for more information). +| Additional Steps | +| :----------------------------------------------------------- | +| 1️⃣ [Add an empty swift file to your project](#troubleshooting-xcode-build-error-swift) | +| 2️⃣ [Update the project's "Library Search Paths" build settings](#troubleshooting-xcode-build-error-undefined-symbol) |
-| Name and Type | Description | -| :----------------------------------------------------------- | :----------------------------------------------------------- | -| πŸ”€ `type`

βš›οΈ `string`, i.e`"menu"` | TBA | -| πŸ”€ `menuTitle`

βš›οΈ `string` | TBA

πŸ“ **Note**: If you don't want a menu title to appear for your context menu, just pass in an empty string to this property. | -| πŸ”€ `menuSubtitle`

βš›οΈ `string` | TBA

πŸ“ **Note**: Requires iOS 15+. | -| πŸ”€ `menuOptions`

βš›οΈ `Array`
πŸ“Œ [`UIMenuOptions`](PLACE_HOLDER_LINK) | TBA | -| πŸ”€ `menuPreferredElementSize`

βš›οΈ `MenuElementSize` | TBA | -| πŸ”€ `menuItems`

βš›οΈ `MenuElementConfig[]` i.e.
`MenuConfig Β¦ MenuActionConfig`
`Β¦ DeferredMenuElementConfig`

πŸ“Œ [`MenuConfig`](PLACE_HOLDER_LINK)
πŸ“Œ [`MenuActionConfig`](PLACE_HOLDER_LINK)
πŸ“Œ [`DeferredMenuElementConfig`](PLACE_HOLDER_LINK) | TBA | -| πŸ”€ `icon`

βš›οΈ `IconConfig ¦ ImageItemConfig`
πŸ“Œ [`IconConfig`](PLACE_HOLDER_LINK) (deprecated)
πŸ“Œ [`ImageItemConfig`](PLACE_HOLDER_LINK) | TBA | +### Installation (Experimental Version) -
+```sh +# 1. install library + dependencies +npm install react-native-ios-utilities@next +npm install react-native-ios-context-menu@next -##### Object Type: `MenuActionConfig` -An object that is used to create a menu action item in the context menu. Internally, this object is used to create a `UIAction` instance (see [apple docs](https://developer.apple.com/documentation/uikit/uiaction) for more information), +# 2. then run pod install (uses auto-linking) +cd ios && pod install +```
-| Name and Type | Description | -| :----------------------------------------------------------- | :---------- | -| πŸ”€ `type`

βš›οΈ `string`, i.e `"action"` | TBA | -| πŸ”€ **Required**: `actionKey`

βš›οΈ `string` | TBA | -| πŸ”€ **Required**: `actionTitle`

βš›οΈ `string` | TBA | -| πŸ”€ `actionSubtitle`

βš›οΈ `string` | TBA | -| πŸ”€ `menuState`

βš›οΈ [`MenuState`](PLACE_HOLDER_LINK) | TBA | -| πŸ”€ `menuAttributes`

βš›οΈ `Array`
πŸ“Œ [`MenuAtrributes`](PLACE_HOLDER_LINK) | TBA | -| πŸ”€ `discoverabilityTitle`

βš›οΈ `string` | TBA | -| πŸ”€ `icon`

βš›οΈ `IconConfig Β¦ ImageItemConfig`
πŸ“Œ [`IconConfig`](PLACE_HOLDER_LINK) (deprecated)
πŸ“Œ [`ImageItemConfig`](PLACE_HOLDER_LINK) | TBA | - -
+### Updating -##### Object Type: `DeferredMenuElementConfig` +This library has cocoapods dependency to [`ContextMenuAuxiliaryPreview`](https://github.com/dominicstop/ContextMenuAuxiliaryPreview) and [`DGSwiftUtilities`](https://github.com/dominicstop/DGSwiftUtilities), so you may need to update them separately (as needed). -An object that is used to create a deferred menu element. Internally, this object is used to create a `UIDeferredMenuElement` instance (see [apple docs](https://developer.apple.com/documentation/uikit/uideferredmenuelement) for more information), +```sh +# A. Either update this specific pod... +pod update ContextMenuAuxiliaryPreview DGSwiftUtilities +pod install --repo-update -| Name and Type | Description | -| ----------------------------------------------------------- | ----------- | -| πŸ”€ **Required**: `type`

βš›οΈ `string` i.e. `deferred`. | TBA | -| πŸ”€ **Required**: `deferredID`

βš›οΈ `string` | TBA | -| πŸ”€: `shouldCache`

βš›οΈ `boolean` | TBA | +# B. Or update all the pods +pod update +```
-##### String Union: `MenuAttributes` - -> Attributes that determine the style of the menu element. - -A union string type that maps to `UIMenuElement.Attributes` enum (see [apple docs](https://developer.apple.com/documentation/uikit/uimenuelement/attributes) for more information). - -
+### Expo -| Type | Description | -| :---------------------- | :---------- | -| βš›οΈ `hidden` | TBA | -| βš›οΈ `disabled` | TBA | -| βš›οΈ `destructive` | TBA | -| βš›οΈ `keepsMenuPresented` | TBA | +- βœ… You can use this library with [Development Builds](https://docs.expo.dev/development/introduction/). No config plugin is required. +- ❌ This library can't be used in the "Expo Go" app because it [requires custom native code](https://docs.expo.dev/workflow/customizing/).
-##### String Union: `MenuState` - -> Constants that indicate the state of an action- or command-based menu element. +### Versions and Dependencies -A union string type that maps to `UIMenuElement.State` enum (see [apple docs](https://developer.apple.com/documentation/uikit/uimenuelement/state) for more information). +| Library Version | Dependencies + Versions | +| --------------- | ------------------------------------------------------------ | +| `2.0.x` | `react-native-ios-utilities` - `4.x` | +| `2.1.x` | `react-native-ios-utilities` - `4.x`
`ContextMenuAuxiliaryPreview` - `0.1.x` | +| `2.2.x` | `react-native-ios-utilities` - `4.x`
`ContextMenuAuxiliaryPreview` - `0.2.x` |
-| Type | Description | -| :--------- | :---------- | -| βš›οΈ `on` | TBA | -| βš›οΈ `off` | TBA | -| βš›οΈ `mixed` | TBA | +### Troubleshooting + +If you encounter any errors/bugs while using this library, or want a particular feature implemented, please create an issue (my inbox is a mess, please feel free to tag me). ✨
-##### String Union: `UIMenuOptions` +#### Troubleshooting: Xcode Build Error (Swift) -> Options for configuring a menu's appearance. +πŸ“ **Note**: This library is written in swift. If you are having trouble building your app after installing this library, try adding an empty swift file to your project: -A union string type that maps to `UIMenu.Options` option set (see [apple docs](https://developer.apple.com/documentation/uikit/uimenu/options/) for more information). +1. Open up your `ios/project.xcworkspace` project +2. On the project navigator panel (located on the right side of Xcode), right click on your project group (or another folder/group i.e the blue or yellow icons) and select the "*New File...*" option +3. In the popup sheet, select "Swift" as the template and then click the "*Next*" button +4. A "*Save As*" popup sheet should appear and then click "*Create*" (you can rename the file first if you want to) +5. If Xcode asks you to create a "*Objective-C Bridging Header*" choose *"Create Objective-C Bridging Header"*
-| Type | Description | -| :----------------- | :---------- | -| βš›οΈ `destructive` | TBA | -| βš›οΈ `displayInline` | TBA | +#### Troubleshooting: Xcode Build Error (Undefined symbol) -
+When installing this library on Xcode 12+, you'll get the following error in Xcode: -##### String Union: `MenuElementSize` +![Xcode linking build error](./assets/installation-troubleshooting-00.png) -> Constants that determine the size of an element in a menu. +``` +Undefined symbol: (extension in UIKit): +__C.UIMenu.init(title: Swift.String, image: __C.UIImage?, identifier: __C.UIMenuIdentifier?, options: __C.UIMenuOptions, children: [__C.UIMenuElement]) -> __C.UIMenu -A union string type that maps to `UIMenu.ElementSize` enum (see [apple docs](https://developer.apple.com/documentation/uikit/uimenu/elementsize) for more information). +Undefined symbol: (extension in UIKit): +__C.UIAction.init(title: Swift.String, image: __C.UIImage?, identifier: __C.UIActionIdentifier?, discoverabilityTitle: Swift.String?, attributes: __C.UIMenuElementAttributes, state: __C.UIMenuElementState, handler: (__C.UIAction) -> ()) -> __C.UIAction +```
-| Type | Description | -| :---------- | :---------- | -| βš›οΈ `small` | TBA | -| βš›οΈ `medium` | TBA | -| βš›οΈ `large` | TBA | +To fix this, see screenshot + follow the steps below: -
+![Xcode - Remove library search paths](./assets/installation-troubleshooting-01-A.png) -#### `MenuPreviewConfig.ts` +
-* πŸ“Œ **Declaration**: [`MenuPreviewConfig.ts`](src/types/MenuPreviewConfig.ts) +1. Open your `ios/project.xcworkspace` project. +2. In the project navigator panel (located on the right side of Xcode), select your project group (i.e. the item with the blueprint icon). +3. The Xcode project editor should appear. In the left panel, under the "Project" section, select your project (if it isn't already selected). +4. In the project section's top tab bar, select the "Build Settings" tab (also make sure the "All" and "Combined" tabs are selected). +5. In the project navigator list, under the "Search Path" section, there should be a "Library Search Paths" setting (alternatively, you can search for "Library Search Paths" in the search bar). +6. According to this [issue comment](https://github.com/facebook/react-native/issues/29246#issuecomment-667518920), you can clear all the items listed in the "Library Search Paths" setting by selecting the items in the list, and pressing the "-" button in the popover. + * **TLDR**: Xcode automatically manages this setting, and the RN template hardcodes it to use Swift 5.0. + * Alternatively, you can change the entry `"$(TOOLCHAIN_DIR)/usr/lib/swift-5.0/$(PLATFORM_NAME)"` to `"$(TOOLCHAIN_DIR)/usr/lib/swift-5.3/$(PLATFORM_NAME)"` i.e. change `swift-5.0` to `swift-5.3`, or whatever the newest version of swift that comes with your Xcode installation (to show the popup dialog, double click the value/item). +7. If you haven't already, make sure to create an empty swift file. Then clean the build folder (the option is in the menu bar under: "Product" -> "Clean Build Folder") and try building your project again. +8. If you are still having problems building the app, try the following and build your project again: + * Try clearing out Xcode's `derivedData` directory: `rm -rf ~/Library/Developer/Xcode/DerivedData/*` (check out this [gist](https://gist.github.com/maciekish/66b6deaa7bc979d0a16c50784e16d697) for instructions on how to clean up Xcode) + * Try clearing out the `Cocoapods` cache: `rm -rf "${HOME}/Library/Caches/CocoaPods"` (and then try running `pod install` again). -##### Object Type: `MenuPreviewConfig` +
-| Name and Type | Description | -| :----------------------------------------------------------- | :---------- | -| πŸ”€ `previewType`

βš›οΈ [`MenuPreviewType`](PLACE_HOLDER_LINK)

✳️ **Default**: `DEFAULT` | TBA | -| πŸ”€ `previewSize`

βš›οΈ [`MenuPreviewSize`](PLACE_HOLDER_LINK)

✳️ **Default**: `INHERIT` | TBA | -| πŸ”€ `isResizeAnimated`

βš›οΈ `boolean`

✳️ **Default**: `true` | TBA | -| πŸ”€ `borderRadius`

βš›οΈ `number` | TBA | -| πŸ”€ `backgroundColor`

βš›οΈ `DynamicColor ¦ string`
πŸ“Œ [`DynamicColor`](PLACE_HOLDER_LINK) | TBA | -| πŸ”€ `previewSize`

βš›οΈ [`ContextMenuInteractionCommitStyle`](PLACE_HOLDER_LINK)

✳️ **Default**: `dismiss` | TBA | -| πŸ”€ `targetViewNode`

βš›οΈ `number` | TBA | +![Xcode - Remove library search paths](./assets/installation-troubleshooting-01-B.png)
-##### String Union: `ContextMenuInteractionCommitStyle` +**Explanation**: Some versions of the react-native template hard codes the swift library search paths to use swift `5.0` (which causes the linker to mismatch the swift system libraries bundled with your Xcode + iOS/Simulator installation). -| Name and Type | Description | -| :------------ | :---------- | -| βš›οΈ `dismiss` | TBA | -| βš›οΈ `pop` | TBA | +Here are some related issues in the RN repo: [Issue 30202](https://github.com/facebook/react-native/pull/30202) and [Issue 29178](https://github.com/facebook/react-native/pull/29178). -
+

-##### String Union: `MenuPreviewSize` +## C. Basic Usage -| Name and Type | Description | -| :------------ | :---------- | -| βš›οΈ `INHERIT` | TBA | -| βš›οΈ `STRETCH` | TBA | +For more examples, check out the [Usage And Examples](#e-usage-and-examples) section.
-##### String Union: `MenuPreviewType` +[πŸ”— Full Example](example/src/examples/BasicUsageExample01.tsx) -| Name and Type | Description | -| :------------ | :---------- | -| βš›οΈ `DEFAULT` | TBA | -| βš›οΈ `CUSTOM` | TBA | +```jsx +import * as React from 'react'; +import { StyleSheet, Text } from 'react-native'; -
+import { ContextMenuView } from 'react-native-ios-context-menu'; -#### `MenuAuxiliaryPreviewConfig.ts` +export function BasicUsageExample01() { + return ( + + + Press And Hold To Show Context Menu + + + ); +}; -* πŸ“Œ **Declaration**: [`MenuAuxiliaryPreviewConfig.ts`](src/types/MenuAuxiliaryPreviewConfig.ts) +const styles = StyleSheet.create({ + container: { + margin: 10, + padding: 10, + }, + text: { + fontSize: 16, + }, +}); +``` -
+

-##### Object Type: `MenuAuxiliaryPreviewConfig` +## D. Documentation -| Name and Type | Description | -| :----------------------------------------------------------- | ----------- | -| πŸ”€ `height`

βš›οΈ `number` | TBA | -| πŸ”€ `anchorPosition`

βš›οΈ `MenuAuxiliaryPreviewAnchorPosition`

✳️ **Default**: `automatic` | TBA | -| πŸ”€ `alignmentHorizontal`

βš›οΈ `MenuAuxiliaryPreviewHorizontalAlignment`

✳️ **Default**: `stretchPreview` | TBA | -| πŸ”€ `marginPreview`

βš›οΈ `number` | TBA | -| πŸ”€ `marginAuxiliaryPreview`

βš›οΈ `number` | TBA | -| πŸ”€ `transitionConfigEntrance`

βš›οΈ `MenuAuxiliaryPreviewTransitionConfig` | TBA | -| πŸ”€ `transitionEntranceDelay`

βš›οΈ `MenuAuxiliaryPreviewTransitionEntranceDelay` | TBA | +πŸ’‘ **Tip**: Most of the time, when a type or component is mentioned, you can click it to jump to that item in the README (or its declaration in the source code).
-##### String Union Type: `MenuAuxiliaryPreviewAnchorPosition` - -| Name and Type | Description | -| :------------- | ----------- | -| βš›οΈ `top` | TBA | -| βš›οΈ `bottom` | TBA | -| βš›οΈ `automatic` | TBA | +### D.1. Components -
+#### `ContextMenuView` Component -##### String Union Type: `MenuAuxiliaryPreviewHorizontalAlignment` +##### `ContextMenuView` Component: Props -| Name and Type | Description | -| -------------------- | ----------- | -| βš›οΈ `stretchScreen` | TBA | -| βš›οΈ `stretchPreview` | TBA | -| βš›οΈ `previewLeading` | TBA | -| βš›οΈ `previewTrailing` | TBA | -| βš›οΈ `previewCenter` | TBA | +| Prop Name and Type | Description | +| :----------------------------------------------------------- | :----------------------------------------------------------- | +| βš›οΈ `ViewProps` | This component supports all the standard props from a `` component. | +| πŸ”€ `menuConfig`

βš›οΈ [`MenuConfig`](PLACE_HOLDER_LINK) | This prop configures the context menu, along with what menu actions to show.

This prop accepts a `MenuConfig` object. This object is used to configure various aspects of the context menu. Here are some relevant properties:

1️⃣ `MenuConfig.menuTitle`: the context menu title (required) β€” if you don't want to show the menu title, pass in an empty string.

2️⃣ `MenuConfig.menuItems`: the actions to show (e.g. the title, icons, subtitle, etc) β€” accepts either an array of `MenuActionConfig` or `MenuConfig` objects.

3️⃣ `MenuConfig.menuOptions`: the attributes of the context menu (e.g. destructive) β€” accepts an array of `UIMenuOptions` string items, and any nested menus or submenus to show (see "**Note A**").

πŸ“ **Note A**: Passing a `MenuConfig` object inside of the `MenuConfig.menuItems` property will result in a nested context menu (i.e. a submenu).

In this scenario, the `MenuConfig.menuOptions` and `MenuConfig.icon` can be used to configure the appearance of the submenu.

For usage examples regarding nested menus, see [Example 06](contextmenuview-example06).

πŸ“ **Note B**: Passing a value of `null` (or `undefined`) to this prop will not disable the context menu. Instead, please use the `isContextMenuEnabled` prop to disable the context menu.

πŸ“ **Note C**: You can put `MenuConfig` in state if you want to dynamically change the menu configuration (this will allow you to add/remove submenu items, or update the current menu options).

If the context menu is currently visible, changing/updating the `MenuConfig` value passed to this prop will cause the context menu to change in real-time. This behavior is only supported on iOS 14+.

πŸ“Œ Some example links to get you started:
β€’ For basic usage examples regarding `MenuConfig`, see: [Example 1](#contextmenuview-example-06),

β€’ For examples on creating + configuring the menu action items (i.e `MenuActionConfig`), see: [Example 2](#contextmenuview-example-02),

β€’ For menu action attributes + menu state, and action subtitles, see: [Example 4](#contextmenuview-example-04), [Example 8](#contextmenuview-example-08), and [Example 13](#contextmenuview-example-13),

β€’ For examples regarding the usage of icons (i.e `ImageItemConfig`), see: [Example 16](#contextmenuview-example-16), [Example 17](#contextmenuview-example-17), and [Example 18](#contextmenuview-example-18). | +| πŸ”€ `previewConfig`

βš›οΈ [`MenuPreviewConfig`](PLACE_HOLDER_LINK) | Configures the context menu's preview.

If no configuration is provided then it will default to using the context menu component itself as the preview.

πŸ“ **Note**: If you do not want to show a preview (i.e. only show the context menu itself), consider using a [`ContextMenuButton`](PLACE_HOLDER_LINK) component instead.

πŸ“Œ Some example links to get you started:
β€’ For examples regarding the configuration of the context menu preview (e.g. custom previews), see: [Example 11](#contextmenuview-example-11), [Example 12](#contextmenuview-example-12), [Example 14](#contextmenuview-example-14), and [Example 15](#contextmenuview-example-15). | +| πŸ”€ `shouldUseDiscoverability`
`TitleAsFallbackValueForSubtitle`

βš›οΈ `boolean`

✳️ **Default**: `true` | On iOS 15+, the value passed to the `MenuActionConfig.discoverabilityTitle` property is no longer displayed as a subtitle under the menu action.

Instead you need to set a different property called `MenuActionConfig.subtitle`.

The `discoverabilityTitle` property is now used for the "discoverability heads-up display" (e.g when an app supports keyboard shortcuts, holding down the command key presents a list of shortcuts; the `discoverabilityTitle` is then used as the title for the shortcut).

If this prop is set to true, it will then use the value passed on to the `discoverabilityTitle` value as the subtitle for the menu action, preserving the old behavior. In other words, this prop exists for backwards-compatibility reasons.

πŸ“ **Note**: This prop is set to `true` by default; set this to `false` if you don't want this automatic behaviour to happen. | +| πŸ”€ `shouldWaitForMenuToHide`
`BeforeFiringOnPressMenuItem`

βš›οΈ `boolean`

✳️ **Default**: `true` | If set to `true` (which it is by default), the `onPressMenuItem` event will be triggered after the context menu has been hidden (i.e. after `onMenuDidHide` event is triggered).

Set this to `false` if you want `onPressMenuItem` to trigger as soon as an item has been pressed in the context menu.

πŸ“ **Note**: Layout updates while the context menu is transitioning from it's open to hidden state might cause layout flickering (e.g. [Issue #43](https://github.com/dominicstop/react-native-ios-context-menu/issues/43)). | +| πŸ”€ `isContextMenuEnabled`

βš›οΈ `boolean`

✳️ **Default**: `true` | Enables or disables the context menu. Useful if you want to temporarily disable the context menu. | +| πŸ”€ `lazyPreview`

βš›οΈ `boolean`

✳️ **Default**: `true` | If set to `true` (which it is by default), the custom context menu preview (i.e. the component returned from the `ContextMenuView.renderPreview` prop) and the auxiliary preview (i.e. the component returned from the `ContextMenuView.renderAuxillaryPreview` prop) are only mounted/rendered when the context menu is visible.

Set this to `false` if you want the preview content to be always mounted. | +| πŸ”€ `renderPreview`

βš›οΈ [`() => React.ReactElement`](PLACE_HOLDER_LINK) | This prop is a "render" prop, i.e it accepts a function that returns a react component.

The returned component will displayed in the context menu preview. | +| πŸ”€ `isAuxiliaryPreviewEnabled`

βš›οΈ `boolean`

✳️ **Default**: `false` | ⚠️ **Experimental**: Please see [Auxiliary Preview](#contextmenuview-component-experimental---auxiliary-preview) section.

TBA | +| πŸ”€ `auxiliaryPreviewConfig`

βš›οΈ `MenuAuxiliaryPreviewConfig` | ⚠️ **Experimental**: Please see [Auxiliary Preview](#contextmenuview-component-experimental---auxiliary-preview) section.

TBA | +| πŸ”€ `renderAuxillaryPreview`

βš›οΈ `() => React.ReactElement` | ⚠️ **Experimental**: Please see [Auxiliary Preview](#contextmenuview-component-experimental---auxiliary-preview) section.

TBA | + +

+ +##### `ContextMenuView` Component: Event Props + +| Prop Name and Type | Description | +| :----------------------------------------------------------- | :----------------------------------------------------------- | +| πŸ”€ `onMenuWillShow`

βš›οΈ [`OnMenuWillShowEvent`](./src/types/MenuEvents.ts) | Event that gets called **before** the context menu is shown, i.e this event is immediately invoked when the menu is about to become visible. | +| πŸ”€ `onMenuDidShow`

βš›οΈ [`OnMenuDidShowEvent`](./src/types/MenuEvents.ts) | Event that gets called **after** the context menu is shown, i.e this event is invoked after the menu entrance animation is finished. | +| πŸ”€ `onMenuWillHide`

βš›οΈ [`OnMenuWillHideEvent`](./src/types/MenuEvents.ts) | Event that gets called **before** the context menu is hidden, i.e this event is immediately invoked when the menu is about to become hidden. | +| πŸ”€ `onMenuDidHide`

βš›οΈ [`OnMenuDidHideEvent`](./src/types/MenuEvents.ts) | Event that gets called **after** the context menu is hidden, i.e this event is invoked after the menu exit animation is finished. | +| πŸ”€ `onMenuWillCancel`

βš›οΈ [`OnMenuWillCancelEvent`](./src/types/MenuEvents.ts) | Event that gets called when the menu is **cancelled and about to be hidden**, i.e this event is immediately invoked when the context menu interaction is cancelled. | +| πŸ”€ `onMenuDidCancel`

βš›οΈ [`OnMenuDidCancelEvent`](./src/types/MenuEvents.ts) | Event that gets called when the menu is **cancelled and hidden**, i.e. this event is invoked when the context menu is cancelled, and the menu exit transition is finished. | +| πŸ”€ `onPressMenuItem`

βš›οΈ [`OnPressMenuItemEvent`](./src/types/MenuEvents.ts) | Event that gets called when a menu action is pressed.

You can identify which action was pressed via `nativeEvent.actionKey ` property in the `nativeEvent` object.

Check out [Example 1](#contextmenuview-example-01), and [Example 9](#contextmenuview-example-09) for examples regarding the `onPressMenuItem` event prop.

πŸ“ **Note**: If `shouldWaitForMenuToHide`
`BeforeFiringOnPressMenuItem` prop is set to `true` (which it is by default), then this event will fire after `onMenuDidHide` is triggered. | +| πŸ”€ `onPressMenuPreview`

βš›οΈ [`OnPressMenuPreviewEvent`](./src/types/MenuEvents.ts) | Event that gets called when the menu's preview is pressed. | +| πŸ”€ `onMenuAuxiliaryPreviewWillShow`

βš›οΈ [`OnMenuAuxiliaryPreviewWillShowEvent`](./src/types/MenuEvents.ts) | ⚠️ **Experimental**: Please see [Auxiliary Preview](#contextmenuview-component-experimental---auxiliary-preview) section.

TBA | +| πŸ”€ `onMenuAuxiliaryPreviewDidShow`

βš›οΈ [`OnMenuAuxiliaryPreviewDidShowEvent`](./src/types/MenuEvents.ts) | ⚠️ **Experimental**: Please see [Auxiliary Preview](#contextmenuview-component-experimental---auxiliary-preview) section.

TBA | +| πŸ”€ `onMenuAuxiliaryPreviewDidShow`

βš›οΈ [`DeferredElementProvider`](./src/components/ContextMenuView/ContextMenuViewTypes) i.e.
`(deferredID, completion)Β =>Β void` | This event gets called whenever a `UIDeferredMenuElement` needs to be loaded. A deferred menu element can be created via a `DeferredMenuElementConfig` object.

A deferred menu is a context menu is basically a placeholder β€” i.e. it appears as a loading indicator in the context menu.

When you pass in a `DeferredMenuElementConfig` object to `MenuConfig.menuItems`, it means you want to load and add additional menu items once the context menu is opened.

This event will provide a `completion` callback β€” use this to provide the additional context menu items you want to load.

πŸ“ **Note A**: Deferred menu elements only work on iOS 14+.

πŸ“ **Note B**: You can dynamically update the context menu items without using the prop β€” the difference is that deferred menu items will show a placeholder loading indicator when the additional menu items haven't been loaded yet.

πŸ“ **Note C**: It is possible to have multiple deferred menu elements (e.g. deferred elements can also provide deferred elements, and so on).

Just be sure to use a unique `deferredID` so you can tell them apart.

πŸ“Œ **Example Usage**:
β€’ [`ContextMenuViewExample19`](#ContextMenuView-Example-19). |
-##### String Union Type: `UIViewAnimateOptions` +##### `ContextMenuView` Component: Properties/Methods -| Name and Type | Description | -| :------------------ | ----------- | -| βš›οΈ `curveEaseIn` | TBA | -| βš›οΈ `curveEaseOut` | TBA | -| βš›οΈ `curveEaseInOut` | TBA | -| βš›οΈ `curveLinear` | TBA | +| Prop Name and Type | Description | +| :----------------------------------------------------------- | :----------------------------------------------------------- | +| πŸ”€ `dismissMenu`

βš›οΈ `Promise` | Allows you to programmatically dismiss the context menu. Only available on iOS 14 and above. | +| πŸ”€ `presentMenu`

βš›οΈ `Promise` | Allows you to programmatically show the context menu. | +| πŸ”€ `showAuxiliaryPreviewAsPopover`

βš›οΈ `Promise` | Allows you to programmatically show the auxiliary preview as a popover. |
-##### Object Type: `UIViewAnimateConfig` +##### `ContextMenuView` Component: Experimental - Auxiliary Preview -| Name and Type | Description | -| :----------------------------------------------- | ----------- | -| πŸ”€ `duration`

βš›οΈ `number` | TBA | -| πŸ”€ `delay`

βš›οΈ `number` | TBA | -| πŸ”€ `options`

βš›οΈ `UIViewAnimateOptions[]` | TBA | +The context menu auxiliary preview is an experimental feature, and is not officially part of `UIKit`'s "Menu and Shortcuts" API. + +This is just a feature that I've implemented myself and added to the library β€” as such official support is limited and might break in a future iOS version. Please use at your own risk.
-##### Object Type: `MenuAuxiliaryPreviewBaseTransitionConfig` +#### `ContextMenuButton` Component -This type is an object tagged union type, with the `transition` property being the tag that separates the unions. +For basic usage, please see [Example 1](#contextmenubutton-example-01) section. -The table below defines the possible valid values that can be assigned to the `type` property (the subsequent tables are the different possible unions). +* The `ContextMenuButton` component is almost the same as the `ContextMenuView` component (It supports the same kind of props and events).
+ +* The only difference between them is that the `ContextMenuButton` component does not have a preview, and it can be immediately shown when its tapped instead of having to do a long press. See [Example 2](#422-contextmenubutton-simple-example-2) for more details.
+ +* Note that `ContextMenuButton` is only available on iOS 14 and above. On iOS 13, it will use a `ContextMenuButton`,
+ +* If you want to add additional touch events, you can wrap this component inside a button component (e.g. `TouchableOpacity`).
+ * When wrapping this component inside a button, please make sure to set the `useActionSheetFallback` prop to `false`. + +
+ +##### `ContextMenuButton` Component: Props + +| Prop Name and Type | Description | +| :----------------------------------------------------------- | :----------------------------------------------------------- | +| βš›οΈ `ViewProps` | This component supports all the standard props from a `` component. | +| πŸ”€ `menuConfig`

βš›οΈ [`MenuConfig`](PLACE_HOLDER_LINK) | Same as `ContextMenuView.menuConfig` prop. | +| πŸ”€ `isMenuPrimaryAction`

βš›οΈ `boolean` | When set to true, the context menu will be shown when its tapped instead of a long press. | +| πŸ”€ `shouldUseDiscoverability`
`TitleAsFallbackValueForSubtitle`

βš›οΈ `boolean`

✳️ **Default**: `true` | TBA / Not Implented | +| πŸ”€ `enableContextMenu`

βš›οΈ `boolean`

✳️ **Default**: `true` | Same as `ContextMenuView.enableContextMenu` prop. | +| πŸ”€ `useActionSheetFallback`

βš›οΈ `boolean`

✳️ **Default**: `true` | Same as `ContextMenuView.useActionSheetFallback` prop. | + +
+ +##### `ContextMenuButton` Component: Event Props + +| Prop Name and Type | Description | +| :----------------------------------------------------------- | :------------------------------------------------ | +| πŸ”€ `onMenuWillShow`

βš›οΈ [`OnMenuWillShowEvent`](./src/types/MenuEvents.ts) | Same as `ContextMenuView.onMenuWillShow` event. | +| πŸ”€ `onMenuDidShow`

βš›οΈ [`OnMenuDidShowEvent`](./src/types/MenuEvents.ts) | Same as `ContextMenuView.onMenuDidShow` event. | +| πŸ”€ `onMenuWillHide`

βš›οΈ [`OnMenuWillHideEvent`](./src/types/MenuEvents.ts) | Same as `ContextMenuView.onMenuWillHide` event. | +| πŸ”€ `onMenuDidHide`

βš›οΈ [`OnMenuDidHideEvent`](./src/types/MenuEvents.ts) | Same as `ContextMenuView.onMenuDidHide` event. | +| πŸ”€ `onMenuWillCancel`

βš›οΈ [`OnMenuWillCancelEvent`](./src/types/MenuEvents.ts) | Same as `ContextMenuView.onMenuWillCancel` event. | +| πŸ”€ `onMenuDidCancel`

βš›οΈ [`OnMenuDidCancelEvent`](./src/types/MenuEvents.ts) | Same as `ContextMenuView.onMenuDidCancel` event. | +| πŸ”€ `onMenuWillCreate`

βš›οΈ [`OnMenuWillCreateEvent`](./src/types/MenuEvents.ts) | Same as `ContextMenuView.onMenuWillCreate` event. | +| πŸ”€ `onPressMenuItem`

βš›οΈ [`OnPressMenuItemEvent`](./src/types/MenuEvents.ts) | Same as `ContextMenuView.onPressMenuItem` event. | + +
+ +##### `ContextMenuButton` Component: Properties/Methods + +| Prop Name and Type | Description | +| :------------------------------------------ | :-------------------------------------------- | +| πŸ”€ `dismissMenu`

βš›οΈ `Promise` | Same as `ContextMenuView.dismissMenu` method. | + +
+ +### D.2. Context + +#### `ContextMenuViewContext` Context + +TBA + +| Property | Description | +| ------------------------------------------------------------ | ----------- | +| πŸ”€ `isMenuVisible`

βš›οΈ `boolean` | TBA | +| πŸ”€ `getRefToContextMenuView`

βš›οΈ `()Β =>Β ContextMenuView`
πŸ“Œ [`ContextMenuView`](PLACE_HOLDER_LINK) | TBA | + +
+ +#### `ContextMenuButtonContext` Context + +TBA + +| Property | Description | +| ------------------------------------------------------------ | ----------- | +| πŸ”€ `isMenuVisible`

βš›οΈ `boolean` | TBA | +| πŸ”€ `getRefToContextMenuButton`

βš›οΈ `()Β =>Β ContextMenuView`
πŸ“Œ [`ContextMenuButton`](PLACE_HOLDER_LINK) | TBA | + +
+ +### D.3. Hooks + +#### `useMenuContext` Hook + +A hook to use the `ContextMenuViewContext` context. + +TBA + +
+ +#### `useMenuButtonContext` Hook + +A hook to use the `ContextMenuButtonContext` context. + +TBA + +
+ +### D.4. Objects and Types + +#### `MenuConfig.ts` + +* πŸ“Œ **Declaration**: [`MenuConfig.ts`](src/types/MenuConfig.ts) + +##### Object Type: `MenuConfig` + +> A container for grouping related menu elements in an app menu or contextual menu. + +An object that is used to create and configure a context menu. Internally, this object is used to create a `UIMenu` instance (see [apple docs](https://developer.apple.com/documentation/uikit/uimenu/) for more information). + +
+ +| Name and Type | Description | +| :----------------------------------------------------------- | :----------------------------------------------------------- | +| πŸ”€ `type`

βš›οΈ `string`, i.e`"menu"` | TBA | +| πŸ”€ `menuTitle`

βš›οΈ `string` | TBA

πŸ“ **Note**: If you don't want a menu title to appear for your context menu, just pass in an empty string to this property. | +| πŸ”€ `menuSubtitle`

βš›οΈ `string` | TBA

πŸ“ **Note**: Requires iOS 15+. | +| πŸ”€ `menuOptions`

βš›οΈ `Array`
πŸ“Œ [`UIMenuOptions`](PLACE_HOLDER_LINK) | TBA | +| πŸ”€ `menuPreferredElementSize`

βš›οΈ `MenuElementSize` | TBA | +| πŸ”€ `menuItems`

βš›οΈ `MenuElementConfig[]` i.e.
`MenuConfig Β¦ MenuActionConfig`
`Β¦ DeferredMenuElementConfig`

πŸ“Œ [`MenuConfig`](PLACE_HOLDER_LINK)
πŸ“Œ [`MenuActionConfig`](PLACE_HOLDER_LINK)
πŸ“Œ [`DeferredMenuElementConfig`](PLACE_HOLDER_LINK) | TBA | +| πŸ”€ `icon`

βš›οΈ `IconConfig ¦ ImageItemConfig`
πŸ“Œ [`IconConfig`](PLACE_HOLDER_LINK) (deprecated)
πŸ“Œ [`ImageItemConfig`](PLACE_HOLDER_LINK) | TBA | + +
+ +##### Object Type: `MenuActionConfig` + +An object that is used to create a menu action item in the context menu. Internally, this object is used to create a `UIAction` instance (see [apple docs](https://developer.apple.com/documentation/uikit/uiaction) for more information), + +
| Name and Type | Description | -| :----------------------------------------------------------- | ----------- | -| πŸ”€ `transition `

βš›οΈ `string` i.e. `'none' Β¦ 'fade'`
`'slide' Β¦ 'zoom' Β¦ 'zoomAndSlide'` | TBA | +| :----------------------------------------------------------- | :---------- | +| πŸ”€ `type`

βš›οΈ `string`, i.e `"action"` | TBA | +| πŸ”€ **Required**: `actionKey`

βš›οΈ `string` | TBA | +| πŸ”€ **Required**: `actionTitle`

βš›οΈ `string` | TBA | +| πŸ”€ `actionSubtitle`

βš›οΈ `string` | TBA | +| πŸ”€ `menuState`

βš›οΈ [`MenuState`](PLACE_HOLDER_LINK) | TBA | +| πŸ”€ `menuAttributes`

βš›οΈ `Array`
πŸ“Œ [`MenuAtrributes`](PLACE_HOLDER_LINK) | TBA | +| πŸ”€ `discoverabilityTitle`

βš›οΈ `string` | TBA | +| πŸ”€ `icon`

βš›οΈ `IconConfig Β¦ ImageItemConfig`
πŸ“Œ [`IconConfig`](PLACE_HOLDER_LINK) (deprecated)
πŸ“Œ [`ImageItemConfig`](PLACE_HOLDER_LINK) | TBA | + +
+ +##### Object Type: `DeferredMenuElementConfig` + +An object that is used to create a deferred menu element. Internally, this object is used to create a `UIDeferredMenuElement` instance (see [apple docs](https://developer.apple.com/documentation/uikit/uideferredmenuelement) for more information), + +| Name and Type | Description | +| ----------------------------------------------------------- | ----------- | +| πŸ”€ **Required**: `type`

βš›οΈ `string` i.e. `deferred`. | TBA | +| πŸ”€ **Required**: `deferredID`

βš›οΈ `string` | TBA | +| πŸ”€: `shouldCache`

βš›οΈ `boolean` | TBA | + +
+ +##### String Union: `MenuAttributes` + +> Attributes that determine the style of the menu element. + +A union string type that maps to `UIMenuElement.Attributes` enum (see [apple docs](https://developer.apple.com/documentation/uikit/uimenuelement/attributes) for more information). + +
+ +| Type | Description | +| :---------------------- | :---------- | +| βš›οΈ `hidden` | TBA | +| βš›οΈ `disabled` | TBA | +| βš›οΈ `destructive` | TBA | +| βš›οΈ `keepsMenuPresented` | TBA | + +
+ +##### String Union: `MenuState` + +> Constants that indicate the state of an action- or command-based menu element. + +A union string type that maps to `UIMenuElement.State` enum (see [apple docs](https://developer.apple.com/documentation/uikit/uimenuelement/state) for more information). + +
+ +| Type | Description | +| :--------- | :---------- | +| βš›οΈ `on` | TBA | +| βš›οΈ `off` | TBA | +| βš›οΈ `mixed` | TBA | + +
+ +##### String Union: `UIMenuOptions` + +> Options for configuring a menu's appearance. + +A union string type that maps to `UIMenu.Options` option set (see [apple docs](https://developer.apple.com/documentation/uikit/uimenu/options/) for more information). + +
+ +| Type | Description | +| :----------------- | :---------- | +| βš›οΈ `destructive` | TBA | +| βš›οΈ `displayInline` | TBA | + +
+ +##### String Union: `MenuElementSize` + +> Constants that determine the size of an element in a menu. + +A union string type that maps to `UIMenu.ElementSize` enum (see [apple docs](https://developer.apple.com/documentation/uikit/uimenu/elementsize) for more information). + +
+ +| Type | Description | +| :---------- | :---------- | +| βš›οΈ `small` | TBA | +| βš›οΈ `medium` | TBA | +| βš›οΈ `large` | TBA | + +
+ +#### `MenuPreviewConfig.ts` + +* πŸ“Œ **Declaration**: [`MenuPreviewConfig.ts`](src/types/MenuPreviewConfig.ts) + +##### Object Type: `MenuPreviewConfig` + +| Name and Type | Description | +| :----------------------------------------------------------- | :---------- | +| πŸ”€ `previewType`

βš›οΈ [`MenuPreviewType`](PLACE_HOLDER_LINK)

✳️ **Default**: `DEFAULT` | TBA | +| πŸ”€ `previewSize`

βš›οΈ [`MenuPreviewSize`](PLACE_HOLDER_LINK)

✳️ **Default**: `INHERIT` | TBA | +| πŸ”€ `isResizeAnimated`

βš›οΈ `boolean`

✳️ **Default**: `true` | TBA | +| πŸ”€ `borderRadius`

βš›οΈ `number` | TBA | +| πŸ”€ `backgroundColor`

βš›οΈ `DynamicColor ¦ string`
πŸ“Œ [`DynamicColor`](PLACE_HOLDER_LINK) | TBA | +| πŸ”€ `previewSize`

βš›οΈ [`ContextMenuInteractionCommitStyle`](PLACE_HOLDER_LINK)

✳️ **Default**: `dismiss` | TBA | +| πŸ”€ `targetViewNode`

βš›οΈ `number` | TBA | + +
+ +##### String Union: `ContextMenuInteractionCommitStyle` + +| Name and Type | Description | +| :------------ | :---------- | +| βš›οΈ `dismiss` | TBA | +| βš›οΈ `pop` | TBA | + +
+ +##### String Union: `MenuPreviewSize` + +| Name and Type | Description | +| :------------ | :---------- | +| βš›οΈ `INHERIT` | TBA | +| βš›οΈ `STRETCH` | TBA | + +
+ +##### String Union: `MenuPreviewType` + +| Name and Type | Description | +| :------------ | :---------- | +| βš›οΈ `DEFAULT` | TBA | +| βš›οΈ `CUSTOM` | TBA | + +
+ +#### `MenuAuxiliaryPreviewConfig.ts` + +* πŸ“Œ **Declaration**: [`MenuAuxiliaryPreviewConfig.ts`](src/types/MenuAuxiliaryPreviewConfig.ts) + +
+ +##### Object Type: `MenuAuxiliaryPreviewConfig` + +| Name and Type | Description | +| :----------------------------------------------------------- | ----------- | +| πŸ”€ `height`

βš›οΈ `number` | TBA | +| πŸ”€ `anchorPosition`

βš›οΈ `MenuAuxiliaryPreviewAnchorPosition`

✳️ **Default**: `automatic` | TBA | +| πŸ”€ `alignmentHorizontal`

βš›οΈ `MenuAuxiliaryPreviewHorizontalAlignment`

✳️ **Default**: `stretchPreview` | TBA | +| πŸ”€ `marginPreview`

βš›οΈ `number` | TBA | +| πŸ”€ `marginAuxiliaryPreview`

βš›οΈ `number` | TBA | +| πŸ”€ `transitionConfigEntrance`

βš›οΈ `MenuAuxiliaryPreviewTransitionConfig` | TBA | +| πŸ”€ `transitionEntranceDelay`

βš›οΈ `MenuAuxiliaryPreviewTransitionEntranceDelay` | TBA | + +
+ +##### String Union Type: `MenuAuxiliaryPreviewAnchorPosition` + +| Name and Type | Description | +| :------------- | ----------- | +| βš›οΈ `top` | TBA | +| βš›οΈ `bottom` | TBA | +| βš›οΈ `automatic` | TBA | + +
+ +##### String Union Type: `MenuAuxiliaryPreviewHorizontalAlignment` + +| Name and Type | Description | +| -------------------- | ----------- | +| βš›οΈ `stretchScreen` | TBA | +| βš›οΈ `stretchPreview` | TBA | +| βš›οΈ `previewLeading` | TBA | +| βš›οΈ `previewTrailing` | TBA | +| βš›οΈ `previewCenter` | TBA | + +
+ +##### String Union Type: `UIViewAnimateOptions` + +| Name and Type | Description | +| :------------------ | ----------- | +| βš›οΈ `curveEaseIn` | TBA | +| βš›οΈ `curveEaseOut` | TBA | +| βš›οΈ `curveEaseInOut` | TBA | +| βš›οΈ `curveLinear` | TBA | + +
+ +##### Object Type: `UIViewAnimateConfig` + +| Name and Type | Description | +| :----------------------------------------------- | ----------- | +| πŸ”€ `duration`

βš›οΈ `number` | TBA | +| πŸ”€ `delay`

βš›οΈ `number` | TBA | +| πŸ”€ `options`

βš›οΈ `UIViewAnimateOptions[]` | TBA | + +
+ +##### Object Type: `MenuAuxiliaryPreviewBaseTransitionConfig` + +This type is an object tagged union type, with the `transition` property being the tag that separates the unions. + +The table below defines the possible valid values that can be assigned to the `type` property (the subsequent tables are the different possible unions). + +| Name and Type | Description | +| :----------------------------------------------------------- | ----------- | +| πŸ”€ `transition `

βš›οΈ `string` i.e. `'none' Β¦ 'fade'`
`'slide' Β¦ 'zoom' Β¦ 'zoomAndSlide'` | TBA | + +
+ +| Name and Type | Description | +| :---------------------------------------------- | ----------- | +| πŸ”€ `transition`

βš›οΈ `string` i.e. `none` | TBA | + +
+ +| Name and Type | Description | +| :---------------------------------------------- | ----------- | +| πŸ”€ `transition`

βš›οΈ `string` i.e. `fade` | TBA | + +
+ +| Name and Type | Description | +| :----------------------------------------------- | ----------- | +| πŸ”€ `transition`

βš›οΈ `string` i.e. `slide` | TBA | +| πŸ”€ `slideOffset`

βš›οΈ `number` | TBA | + +
+ +| Name and Type | Description | +| :---------------------------------------------- | ----------- | +| πŸ”€ `transition`

βš›οΈ `string` i.e. `zoom` | TBA | +| πŸ”€ `zoomOffset`

βš›οΈ `number` | TBA | + +
+ +| Name and Type | Description | +| :------------------------------------------------------ | ----------- | +| πŸ”€ `transition`

βš›οΈ `string` i.e. `zoomAndSlide` | TBA | +| πŸ”€ `slideOffset`

βš›οΈ `number` | TBA | +| πŸ”€ `zoomOffset`

βš›οΈ `number` | TBA | + +
+ +##### Object Union Type: `MenuAuxiliaryPreviewTransitionConfig` + +This type is a union between the `UIViewAnimateConfig` object type, and the `MenuAuxiliaryPreviewBaseTransitionConfig` object type. + +```typescript +export type MenuAuxiliaryPreviewTransitionConfig = + | UIViewAnimateConfig + | MenuAuxiliaryPreviewBaseTransitionConfig; +``` + +
+ +##### Mixed Union Type: `MenuAuxiliaryPreviewTransitionEntranceDelay`. + +| Name and Type | Description | +| :---------------- | ----------- | +| βš›οΈ `number` | TBA | +| βš›οΈ `RECOMMENDED` | TBA | +| βš›οΈ `AFTER_PREVIEW` | TBA | + +
+ +#### `MenuIconConfig.ts` + +* πŸ“Œ **Declaration**: [`MenuIconConfig.ts`](src/types/MenuIconConfig.ts) + +
+ +##### Object Type: `IconConfig` + +This has been deprecated and will be removed in a future version. Use [`ImageItemConfig`](PLACE_HOLDER_LINK) instead. For documentation regarding `IconConfig`, please see the documentation in the [old README](./README-old-v1.md). + +
+ +#### `ImageItemConfig.ts` + +* πŸ“Œ **Declaration**: [`ImageItemConfig.ts`](src/types/ImageItemConfig.ts) + +
+ +##### Object Type: `ImageItemConfig` + +This type is an object tagged union type, with the `type` property being the tag that separates the unions. The table below defines the possible valid values that can be assigned to the `type` property. + +| Name and Type | Description | +| :----------------------------------------------------------- | ----------- | +| πŸ”€ **Required**: `type`

βš›οΈ `ImageItemConfigType` string union, i.e. `'IMAGE_ASSET' Β¦ 'IMAGE_SYSTEM' Β¦ 'IMAGE_REQUIRE'`
` Β¦ 'IMAGE_EMPTY' Β¦ 'IMAGE_RECT' Β¦ 'IMAGE_GRADIENT' `
`Β¦ 'IMAGE_REMOTE_URL'` | TBA | + +
+ +###### `ImageItemConfig`: `IMAGE_ASSET` + +| Name and Type | Description | +| :----------------------------------------------------------- | ------------------------------------------------------------ | +| πŸ”€ **Required**: `type`

βš›οΈ `string` i.e `'IMAGE_ASSET' ` | TBA

πŸ“Œ Maps to [`UIImage.init(named:)`](https://developer.apple.com/documentation/uikit/uiimage/1624146-init) constructor in the apple docs. | +| πŸ”€ **Required**: `imageValue`

βš›οΈ `string` | TBA | +| πŸ”€ `imageOptions?`

βš›οΈ [`ImageOptions`](PLACE_HOLDER_LINK) | TBA | + +
+ +###### `ImageItemConfig`: `IMAGE_SYSTEM` + +| Name and Type | Description | +| :----------------------------------------------------------- | ------------------------------------------------------------ | +| πŸ”€ **Required**: `type`

βš›οΈ `string` i.e `'IMAGE_SYSTEM' ` | TBA

πŸ“Œ Maps to [`UIImage.init(systemName:withConfiguration:)`](https://developer.apple.com/documentation/uikit/uiimage/3294234-init) constructor in the apple docs. | +| πŸ”€ **Required**: `imageValue`

βš›οΈ [`ImageSystemConfig`](PLACE_HOLDER_LINK) | TBA

πŸ“Œ Maps to the `withConfiguration` argument label in the [`UIImage.init(systemName:withConfiguration:)`](https://developer.apple.com/documentation/uikit/uiimage/3294234-init) constructor in the apple docs. | +| `imageOptions`

βš›οΈ [`ImageOptions`](PLACE_HOLDER_LINK) | TBA | +| πŸ”€ `imageLoadingConfig`

βš›οΈ [`ImageLoadingConfig`](PLACE_HOLDER_LINK) | TBA | + +
+ +###### `ImageItemConfig`: `IMAGE_EMPTY` + +| Name and Type | Description | +| :----------------------------------------------------------- | ----------- | +| πŸ”€ **Required**: `type`

βš›οΈ `string` i.e `'IMAGE_EMPTY' ` | TBA | + +
+ +###### `ImageItemConfig`: `IMAGE_RECT` + +| Name and Type | Description | +| :----------------------------------------------------------- | ------------------------------------------------------------ | +| πŸ”€ **Required**: `type`

βš›οΈ `string` i.e `'IMAGE_RECT' ` | TBA

πŸ“ **Note**: Programmatically creates an image using [`UIGraphicsImageRenderer`](https://developer.apple.com/documentation/uikit/uigraphicsrenderer). | +| πŸ”€ **Required**: `imageValue`

βš›οΈ [`ImageRectConfig`](PLACE_HOLDER_LINK) | TBA | + +
+ +###### `ImageItemConfig`: `IMAGE_GRADIENT` + +| Name and Type | Description | +| :----------------------------------------------------------- | ------------------------------------------------------------ | +| πŸ”€ **Required**: `type`

βš›οΈ `string` i.e `'IMAGE_GRADIENT' ` | TBA

πŸ“ **Note**: Programmatically creates an image using [`UIGraphicsImageRenderer`](https://developer.apple.com/documentation/uikit/uigraphicsrenderer). | +| πŸ”€ `imageValue`

βš›οΈ [`ImageGradientConfig`](PLACE_HOLDER_LINK) | TBA | +| `imageOptions`

βš›οΈ [`ImageOptions`](PLACE_HOLDER_LINK) | TBA | + +
+ +###### `ImageItemConfig`: `IMAGE_REMOTE_URL` + +| Name and Type | Description | +| :----------------------------------------------------------- | ----------- | +| πŸ”€ **Required**: `type`

βš›οΈ `string` i.e `'IMAGE_REMOTE_URL' ` | TBA | +| πŸ”€ `imageValue`

βš›οΈ [`ImageRemoteUrlConfig`](PLACE_HOLDER_LINK) | TBA | +| πŸ”€ `imageLoadingConfig`

βš›οΈ [`ImageLoadingConfig`](PLACE_HOLDER_LINK) | TBA | +| `imageOptions`

βš›οΈ [`ImageOptions`](PLACE_HOLDER_LINK) | TBA | + +
+ +##### Object Type: `ImageResolvedAssetSource` + +TBA + +| Name and Type | Description | +| :------------------------------- | ----------- | +| πŸ”€ `height`

βš›οΈ `number` | TBA | +| πŸ”€ `width`

βš›οΈ `number` | TBA | +| πŸ”€ `scale`

βš›οΈ `number` | TBA | +| πŸ”€ `uri`

βš›οΈ `string` | TBA | + +
+ +##### Object Type: `ImageRectConfig` + +TBA + +| Name and Type | Description | +| :----------------------------------------------- | ----------- | +| πŸ”€ **Required**: `width`

βš›οΈ `number` | TBA | +| πŸ”€ **Required**: `height`

βš›οΈ `number` | TBA | +| πŸ”€ **Required**: `fillColor`

βš›οΈ `string` | TBA | +| πŸ”€ `borderRadius?`

βš›οΈ `number` | TBA | + +
+ +##### Object Type: `ImageGradientConfig` + +TBA + +| Name and Type | Description | +| :----------------------------------------------------------- | ------------------------------------------------------------ | +| πŸ”€ **Required**: `width`

βš›οΈ `number` | TBA | +| πŸ”€ **Required**: `height`

βš›οΈ `number` | TBA | +| πŸ”€ `borderRadius?`

βš›οΈ `number` | TBA | +| πŸ”€ **Required**: `colors`

βš›οΈ `Array` | TBA

πŸ“Œ Maps to [`CAGradientLayer.colors`](https://developer.apple.com/documentation/quartzcore/cagradientlayer/1462403-colors) property in the apple docs. | +| πŸ”€ `locations?`

βš›οΈ `Array` | TBA

πŸ“Œ Maps to [`CAGradientLayer.locations`](https://developer.apple.com/documentation/quartzcore/cagradientlayer/1462410-locations) property in the apple docs. | +| πŸ”€ `startPoint?`

βš›οΈ `Point Β¦ PointPreset`

πŸ“Œ [`Point`](PLACE_HOLDER_LINK)
πŸ“Œ [`PointPreset`](PLACE_HOLDER_LINK) | TBA

πŸ“Œ Maps to [`CAGradientLayer.startPoint`](https://developer.apple.com/documentation/quartzcore/cagradientlayer/1462408-startpoint) property in the apple docs. | +| πŸ”€ `endPoint?`

βš›οΈ `Point Β¦ PointPreset`
πŸ“Œ [`Point`](PLACE_HOLDER_LINK)
πŸ“Œ [`PointPreset`](PLACE_HOLDER_LINK) | TBA

πŸ“Œ Maps to [`CAGradientLayer.endPoint`](https://developer.apple.com/documentation/quartzcore/cagradientlayer/1462412-endpoint) property in the apple docs. | +| πŸ”€ `type?`

βš›οΈ `string` i.e `'axial' Β¦ 'conic' Β¦ 'radial'` | TBA

πŸ“Œ Maps to [`CAGradientLayer.type`](https://developer.apple.com/documentation/quartzcore/cagradientlayer/1462413-type) property in the apple docs. | + +
+ +##### Object Type: `ImageSystemConfig` + +TBA + +| Name and Type | Description | +| :----------------------------------------------------------- | ------------------------------------------------------------ | +| πŸ”€ **Required**: `systemName`

βš›οΈ `string` | TBA

πŸ“Œ Maps to the `systemName` argument label in the [`UIImage.init(systemName:withConfiguration:)`](https://developer.apple.com/documentation/uikit/uiimage/3294234-init) constructor in the apple docs. | +| πŸ”€ `pointSize?`

βš›οΈ `number` | TBA

πŸ“Œ Maps to [`UIImage.SymbolConfiguration.init(pointSize:)`](https://developer.apple.com/documentation/uikit/uiimage/symbolconfiguration/3294241-init) constructor in the apple docs. | +| πŸ”€ `weight?`

βš›οΈ [`ImageSymbolWeight`](PLACE_HOLDER_LINK) | TBA

πŸ“Œ Maps to [`UIImage.SymbolConfiguration.init(weight:)`](https://developer.apple.com/documentation/uikit/uiimage/symbolconfiguration/3294247-init) constructor in the apple docs. | +| πŸ”€ `scale?`

βš›οΈ [`ImageSymbolScale`](PLACE_HOLDER_LINK) | TBA

πŸ“Œ Maps to [`UIImage.SymbolConfiguration.init(scale:)`](https://developer.apple.com/documentation/uikit/uiimage/symbolconfiguration/3294244-init) constructor in the apple docs. | +| πŸ”€ `hierarchicalColor?`

βš›οΈ `Array` | TBA

πŸ“ **Note A**: Cannot be used at the same time with `paletteColors` (it's either one or the other).

πŸ“ **Note B**: Requires iOS 15+.

πŸ“Œ Maps to [`UIImage.SymbolConfiguration.init(hierarchicalColor:)`](https://developer.apple.com/documentation/uikit/uiimage/symbolconfiguration/3810053-init) constructor in the apple docs. | +| πŸ”€ `paletteColors?`

βš›οΈ `string` | TBA

πŸ“ **Note A**: Cannot be used at the same time with `hierarchicalColor` (it's either one or the other).

πŸ“ **Note B**: Requires iOS 15+.

πŸ“Œ Maps to [`UIImage.SymbolConfiguration.init(paletteColors:)`](https://developer.apple.com/documentation/uikit/uiimage/symbolconfiguration/3810054-init) constructor in the apple docs. | + +
+ +##### Object Type: `UIImageConfig` + +TBA + +| Name and Type | Description | +| :--------------------------------------------------- | ----------- | +| πŸ”€ `tint`

βš›οΈ `string ¦ DynamicColor` | TBA | +| πŸ”€ `renderingMode`

βš›οΈ `ImageRenderingModes` | TBA | + +
+ +##### Object Union Type: `ImageOptions` + +This type is a unioned with `UIImageConfig` object type, so it inherits its properties. + +| Name and Type | Description | +| :------------------------------------- | ----------- | +| πŸ”€ `cornerRadius`

βš›οΈ `number` | TBA | + +
+ +##### Object Type: `ImageRemoteUrlConfig` + +TBA + +| Name and Type | Description | +| :------------------------------------------ | ----------- | +| πŸ”€ **Required**: `url`

βš›οΈ `string` | TBA | + +
+ +##### Object Type: `ImageLoadingConfig` + +TBA + +| Name and Type | Description | +| :---------------------------------------- | ----------- | +| πŸ”€ `shouldCache`

βš›οΈ `boolean` | TBA | +| πŸ”€ `shouldLazyLoad`

βš›οΈ `boolean` | TBA | + +
+ +#### Undocumented Types + +TBA + +| Type | Description | +| :----------------------------------------------------------- | ------------------------------------------------------------ | +| πŸ“Œ **Declaration**: [`MenuEvents`](src/types/MenuEvents.ts) | This file contains all the menu-related events and event objects. | +| πŸ“Œ **Declaration**: [`MiscTypes.ts`](src/types/MiscTypes.ts) | This file contains a bunch of types that haven't been categorized yet.

Contains: `PointPreset`, `Point`, `DynamicColor`, etc. | +| πŸ“Œ **Declaration**: [`RNICleanupMode.ts`](src/types/RNICleanupMode.ts) | TBA | + +
+ +### D.5. Constants + +#### Object: `LIB_ENV` + +TBA + +
+ +| Type | Description | +| :------------------------------------------------------ | :---------- | +| πŸ”€ `isContextMenuButtonSupported`

βš›οΈ `boolean` | TBA | +| πŸ”€ `isContextMenuViewSupported`

βš›οΈ `boolean` | TBA | + +

+ +## E. Usage And Examples + +### `ContextMenuView` Example 01 + +**Summary**: A basic context menu that has 3 menu action items (e.g. "Action #1", "Action #2", and "Action #3"). + +
+ +| Notes | +| :----------------------------------------------------------- | +| 1️⃣ β€” The `ContextMenuView.menuConfig` prop accepts an optional `MenuConfig` object.
This object will be used to create and configure the context menu. | +| 2️⃣ β€” You can set the context menu title via passing a string value to the `MenuConfig.menuTitle` property.

πŸ“ **Note**: You can pass an empty string if you don't want a title to appear on top your context menu. | +| 3️⃣ β€” To populate the context menu with action items, you can pass a `MenuActionConfig` object in the `MenuConfig.menuItems` property.

πŸ“ **Note A**: The `MenuConfig.menuItems` property can accept an array of a `MenuElementConfig` union type.

To be more specific, the `menuItems` property can accept an array containing any of the following object types: `MenuConfig` object, `MenuActionConfig`, and `DeferredMenuElementConfig`.

πŸ“ **Note B**: If you pass in a `MenuConfig` object in the `MenuConfig.menuItems` property, it means that you want to create a submenu. See [`ContextMenuView` Example 03](#ContextMenuView-Example-03) for more details.

πŸ“ **Note C**: If you pass in a `DeferredMenuElementConfig` object in the `MenuConfig.menuItems` property, it means that you want to create a deferred menu item (i.e. a menu item that has a loading indicator). See [`ContextMenuView` Example 19](#ContextMenuView-Example-19) for more details. | +| 4️⃣ β€” A `MenuActionConfig` object represents an action item in the context menu (e.g. copy, paste, delete, etc).

As such, if you pass in a `MenuActionConfig` object to `MenuConfig.menuItems`, it means that you want to create a context menu action.

πŸ“ **Note A**: The `MenuActionConfig.actionKey` property serves as a unique identifier for your menu action. If you have multiple menu actions, the `actionKey` will help you differentiate them.

πŸ“ **Note B**: You will receive the value you passed in `MenuActionConfig.actionKey` in the `ContextMenuView.onPressMenuItem` event (i.e. via the `nativeEvent` object). | +| 5️⃣ β€” You can use the `ContextMenuView.onPressMenuItem` event prop to get notified whenever a menu action item has been selected.

The function you pass to the `onPressMenuItem` prop will receive a `OnPressMenuItemEventObject` object.

πŸ“ **Note A**: Details about the selected menu action item can be accessed via the `OnPressMenuItemEventObject.nativeEvent` object.

E.g. `OnPressMenuItemEventObject``.nativeEvent.actionKey`.

πŸ“ **Note B**: If `ContextMenuView.shouldWaitForMenuToHide`
`BeforeFiringOnPressMenuItem` prop is set to `true` (which it is by default), then this event will fire after the `onMenuDidHide` event is triggered. | + +
+ +[πŸ”— Full Example](./example/srcexamples/ContextMenuViewExample01.tsx) + +```jsx +// πŸ“ Note: for the sake of brevity, some of the code is omitted... +import { ContextMenuView } from 'react-native-ios-context-menu'; + +export function ContextMenuViewExample01(props) { + return ( + { + Alert.alert( + 'onPressMenuItem Event', + `actionKey: ${nativeEvent.actionKey} - actionTitle: ${nativeEvent.actionTitle}` + ); + }} + > + {/** Components */} + + ); +}; +``` + +![screenshot](./assets/example-ContextMenuViewExample01-old.png) + +![Gif](./assets/example-ContextMenuViewExample01.gif) + +
+ +### `ContextMenuView` Example 02 + +**Summary**: Icon Example β€” This examples shows how to add a system icon in the context menu action. + +
+ +| Notes | +| ------------------------------------------------------------ | +| 1️⃣ β€” A menu action (i.e. `MenuActionConfig` object) can be configured to show an icon via its `MenuActionConfig.icon` property.

πŸ“ **Note A**: The `icon` property accepts a `ImageItemConfig` object.

πŸ“ **Note B**: A `ImageItemConfig` object is used to describe images/assets (e.g. SF Symbols icons, images, xcasset images, programmatic images, etc). | +| 2️⃣ β€” In this example, we want to use a "SF Symbols" icon for the menu action.

In order to do this, the `ImageItemConfig.type` property must be set to `"IMAGE_SYSTEM"`.

πŸ“ **Note A**: Passing in a value of `"IMAGE_SYSTEM"` to the `type` property means that we want to create a "SF Symbols" system icon.

πŸ“ **Note B**: Using a "SF Symbols" icon requires iOS 13+.

πŸ“ **Note C**: Via the `ImageItemConfig` object, you can also configure the context menu action to use other icons (e.g. `xcasset` items, images, gradients, solid colors, etc).

πŸ“ **Note D**: You can apply a tint to the icon via the `ImageItemConfig.imageOptions` property using the `UIImageConfig.tint` and `UIImageConfig.renderingMode` property. See [`ContextMenuView` Example 17](#ContextMenuView-Example-17) for more details. | +| 3️⃣ β€” In order to configure what kind of "SF Symbols" icon we want to use for the menu action, we need to pass in a `ImageSystemConfig` object to the `ImageItemConfig.imageValue` property.

We can set what kind of icon to use via passing a string value to the `ImageSystemConfig.systemName` property.

πŸ“ **Note A**: An `ImageSystemConfig` object is used to generate a "SF Symbols" image. Using this configuration object, we can optionally customize the "SF Symbols" icon further via the following properties: `pointSize`, `weight`, `scale`, `hierarchicalColor`, `paletteColors`, etc.

πŸ“ **Note B**: The string value passed to the `ImageSystemConfig.systemName` property must be a valid SF Symbols name.

πŸ“ **Note C**: To view the list of SF Symbols icons (along with their corresponding icon names), you'll need to download the SF Symbols Mac app from [this page](https://developer.apple.com/design/human-interface-guidelines/sf-symbols/overview/). | + +
+ +[πŸ”— Full Example](./example/srcexamples/ContextMenuViewExample02.tsx) + +```jsx +// πŸ“ Note: for the sake of brevity, some of the code is omitted... +import { ContextMenuView } from 'react-native-ios-context-menu'; + +export function ContextMenuViewExample02(props) { + return ( + + {/** Components */} + + ); +}; +``` + +![screenshot](./assets/example-ContextMenuViewExample02-old.png) + +![Gif](./assets/example-ContextMenuViewExample02.gif) + +
+ +### `ContextMenuView` Example 03 + +**Summary**: Nested Menu β€” This example shows a context menu that has a submenu item inside its list of menu actions. + +
+ +| Notes | +| ------------------------------------------------------------ | +| 1️⃣ β€” A context menu supports having nested menu's (i.e. submenu's).

A submenu is basically just another menu with it's own separate list of menu actions. Tapping it will show another context menu (visually this is similar to a dropdown menu). | +| 2️⃣ β€” As mentioned in the earlier examples, the `MenuConfig.menuItems` property can accept a `MenuActionConfig` object, or a `MenuConfig` object.

Passing in a `MenuActionConfig` object to `MenuConfig.menuItems` makes a menu action, conversely passing in a `MenuConfig` object will create a submenu item.

In other words, to make a submenu, you just need to pass a `MenuConfig` item in the `MenuConfig.menuItems` property.

πŸ“ **Note**: You can nest as many submenu's you want (but just remember that having more than 3 nested submenus is considered bad UX). | + +
+ +[πŸ”— Full Example](./example/srcexamples/ContextMenuViewExample03.tsx) + +```jsx + // πŸ“ Note: for the sake of brevity, some of the code is omitted... +import { ContextMenuView } from 'react-native-ios-context-menu'; + +export function ContextMenuViewExample03(props) { + return ( + + {/** Components */} + + ); +}; +``` + +![screenshot](./assets/example-ContextMenuViewExample03-old.png) + +![Gif](./assets/example-ContextMenuViewExample03.gif) + +
+ +### `ContextMenuView` Example 04 + +**Summary**: Menu Attributes β€” This example context menu showcases the `MenuActionConfig.menuAttributes` property. + +
+ +| Notes | +| ------------------------------------------------------------ | +| 1️⃣ β€” The `MenuActionConfig.menuAttributes` property accepts an array of strings (i.e. an array of `MenuAttributes` items).

In this example, the context menu has 3 actions, each with a different menu attribute assigned to it.

The first menu action is a "disabled" action, i.e. it has it's `menuAttributes` set to `['disabled']`, causing the action title text and icon becomes greyed out. | +| 2️⃣ β€” The second menu action is a destructive action.

It has it's `menuAttributes` set to `['destructive']`, causing the action title text and icon becomes red. | +| 3️⃣ β€” The third menu action is a "hidden" action. It has it's `menuAttributes` set to `['hidden']`.

The menu action is not visible in the menu's list of actions. This is useful for temporarily hiding a menu action item. | +| 4️⃣ β€” The fourth menu action is a "disabled" + "destructive" action.
Visually, it looks very similar to an action that has the `['disabled']` attribute. | + +
+ +[πŸ”— Full Example](./example/srcexamples/ContextMenuViewExample04.tsx) + +```jsx + // πŸ“ Note: for the sake of brevity, some of the code is omitted... +import { ContextMenuView } from 'react-native-ios-context-menu'; + +export function ContextMenuViewExample04(props) { + return ( + + {/** Components */} + + ); +}; +``` + +![screenshot](./assets/example-ContextMenuViewExample04-old.png) + +![Gif](./assets/example-ContextMenuViewExample04.gif) + +
+ +### `ContextMenuView` Example 05 + +**Summary**: Nested Menu + Menu Attributes β€” A context menu that has a in-line submenu. + +
+ +| Notes | +| ------------------------------------------------------------ | +| You can set the menu options via the `MenuConfig.menuOptions` property. It accepts an array of `UIMenuOptions` strings (e.g. `'destructive'`, `'displayInline'`).

If you pass in `['displayInline']` to `menuOptions`, the submenu will be added/combined to its parent menu, but with a small separator between them. | + +
+ +[πŸ”— Full Example](./example/srcexamples/ContextMenuViewExample05.tsx) + +```jsx + // πŸ“ Note: for the sake of brevity, some of the code is omitted... +import { ContextMenuView } from 'react-native-ios-context-menu'; + +export function ContextMenuViewExample05(props) { + return ( + + {/** Components */} + + ); +}; +``` + +![screenshot](./assets/example-ContextMenuViewExample05-old.png) + +![Gif](./assets/example-ContextMenuViewExample05.gif) + +
+ +### `ContextMenuView` Example 06 + +**Summary**: Menu Options β€” A context menu that has a destructive submenu. + +
+ +| Notes | +| ------------------------------------------------------------ | +| You can set the menu options via the `MenuConfig.menuOptions` property. It accepts an array of `UIMenuOptions` strings (e.g. `destructive`, `displayInline`).

If you pass in `['destructive']` to `menuOptions`, it will tint the submenu to red (but it's menu items won't be affected). | + +
+ +[πŸ”— Full Example](./example/srcexamples/ContextMenuViewExample06.tsx) + +```jsx + // πŸ“ Note: for the sake of brevity, some of the code is omitted... +import { ContextMenuView } from 'react-native-ios-context-menu'; + +export function ContextMenuViewExample06(props) { + return ( + + {/** Components */} + + ); +}; +``` + +![screenshot](./assets/example-ContextMenuViewExample06-old.png) + +![Gif](./assets/example-ContextMenuViewExample06.gif) + +
+ +### `ContextMenuView` Example 07 + +**Summary**: Menu Options β€” A context menu that set to be both "destructive" and "display in-line". + +
+ +| Notes | +| ------------------------------------------------------------ | +| You can set the menu options via the `MenuConfig.menuOptions` property. It accepts an array of `UIMenuOptions` strings (e.g. `destructive`, `displayInline`).

Passing in `['destructive', 'displayInline']` to `menuOptions`, is functionally the same as passing in `['displayInline']`. | + +
+ +[πŸ”— Full Example](./example/srcexamples/ContextMenuViewExample07.tsx) + +```jsx + // πŸ“ Note: for the sake of brevity, some of the code is omitted... +import { ContextMenuView } from 'react-native-ios-context-menu'; + +export function ContextMenuViewExample07(props) { + return ( + + {/** Components */} + + ); +}; +``` + +![screenshot](./assets/example-ContextMenuViewExample07-old.png) + +![Gif](./assets/example-ContextMenuViewExample07.gif) + +
+ +### `ContextMenuView` Example 08 + +**Summary**: Menu State β€” A context menu with 3 actions that has `'on'`, `'off'`, and `'mixed'` `menuState`. + +
+ +| Notes | +| ------------------------------------------------------------ | +| You can set an menu action item's the menu state via the `MenuActionConfig.menuState` property.

πŸ“ **Note**: On iOS 13, an action item's menu state is indicated via changing it's icon to a checkmark. However on later version of iOS this behavior has been changed to showing a checkmark besides the action title (see gifs/screenshots below). | + +
+ +[πŸ”— Full Example](./example/srcexamples/ContextMenuViewExample08.tsx) + +```jsx + // πŸ“ Note: for the sake of brevity, some of the code is omitted... +import { ContextMenuView } from 'react-native-ios-context-menu'; + +export function ContextMenuViewExample08(props) { + return ( + + {/** Components */} + + ); +}; +``` + +![screenshot](./assets/example-ContextMenuViewExample08-old.png) + +![Gif](./assets/example-ContextMenuViewExample08.gif) + +
+ +### `ContextMenuView` Example 09 + +**Summary**: Events β€” An example for the `onPressMenuItem` event prop. + +| Notes | +| ------------------------------------------------------------ | +| The `onPressMenuItem` event prop allows you to know which menu item was pressed via the `nativeEvent.actionKey` property in the event object.

πŸ“ **Note A**: The entire menu action config (i.e. `MenuActionConfig`) object of the selected item can be accessed via the `nativeEvent` object (e.g. `nativeEvent.actionTitle`, `nativeEvent.menuState`, etc).

πŸ“ **Note B**: For the full type declaration for all the events, see: [`MenuEvents.ts`](./src/types/MenuEvents.ts). | + +
+ +[πŸ”— Full Example](./example/srcexamples/ContextMenuViewExample09.tsx) + +```jsx + // πŸ“ Note: for the sake of brevity, some of the code is omitted... +import { ContextMenuView } from 'react-native-ios-context-menu'; + +export function ContextMenuViewExample09(props) { + return ( + { + switch (nativeEvent.actionKey) { + case 'save': + Alert.alert('saving...'); + break; + + case 'like': + Alert.alert('liking...'); + break; + + case 'play': + Alert.alert('playing...'); + break; + }; + }} + > + {/** Components */} + + ); +}; +``` + +![screenshot](./assets/example-ContextMenuViewExample09-old.png) + +![Gif](./assets/example-ContextMenuViewExample09.gif) + +
+ +### `ContextMenuView` Example 10 + +**Summary**: Dynamic Menu β€” An example showing how to dynamically update the context menu while it's visible. In this example, the menu action changes every time the counter increments every second. + +
+ +| Notes | +| ------------------------------------------------------------ | +| On iOS 14+ you can update the menu while it's visible, e.g. like adding and removing items in the context menu, or changing the action title, etc.

You can control the context menu config using state, and dynamically change it as shown in the example below.

πŸ“ **Note A**: On iOS 13 the context menu will not update while it's visible.

πŸ“ **Note B**: On iOS 15+, all changes to the context menu config are applied using a fade/crossfade transition. | + +
+ +[πŸ”— Full Example](./example/srcexamples/ContextMenuViewExample10.tsx) + +```jsx + // πŸ“ Note: for the sake of brevity, some of the code is omitted... +export function ContextMenuViewExample10(props) { + // `timer` will increment every second... + const [timer, setTimer] = React.useState(0); + + // ... + return ( + + {/** Components */} + + ); +}; +``` + +![screenshot](./assets/example-ContextMenuViewExample10-old.png) + +![Gif](./assets/example-ContextMenuViewExample10.gif) + +
+ +### `ContextMenuView` Example 11 + +**Summary**: Context Menu Previews β€” An example showing how to use a custom preview for the context menu. + +
+ +| Notes | +| ------------------------------------------------------------ | +| 1️⃣ β€” The `ContextMenuView.renderPreview` render prop allows you show a custom preview when the context menu appears.

πŸ“ **Note**: The `renderPreview` prop accepts a function that returns an element. The returned element will be shown inside the context menu preview. | +| 2️⃣ β€” The `ContextMenuView.previewConfig` is used to control the behavior and appearance of the custom context menu preview.

In order to show the custom context menu preview, we must first set `MenuPreviewConfig.previewType` to `'CUSTOM'`. By default, this property is set to `'DEFAULT'`, which means that you do not want to use a custom preview.

πŸ“ **Note A**: The `previewConfig` prop accepts a `MenuPreviewConfig` object.

πŸ“ **Note B**: The `previewType` property accepts a `MenuPreviewType` string. You can set this to `'DEFAULT'` if you want to quickly disable the custom preview. | +| 3️⃣ β€” In this example, we want the custom preview to be as big as possible, so we set the `MenuPreviewConfig.previewSize` property to `'STRETCH'`.

πŸ“ **Note**: The `previewSize` property accepts a `MenuPreviewSize` string. By default, this prop is set to `'INHERIT'`, which means to just match the size of the root view returned from `renderPreview`. | + +
+ +[πŸ”— Full Example](./example/srcexamples/ContextMenuViewExample11.tsx) + +```jsx + // πŸ“ Note: for the sake of brevity, some of the code is omitted... +import { ContextMenuView } from 'react-native-ios-context-menu'; + +export function ContextMenuViewExample11(props) { + return ( + ( + + + Hello World + + + Hello World + + + Hello World + + + )} + onPressMenuPreview={() => { + Alert.alert( + 'onPressMenuPreview Event', + `Menu preview was pressed...` + ); + }} + > + {/** Components */} + + ); +}; +``` + +![screenshot](./assets/example-ContextMenuViewExample11-old.png) + +![Gif](./assets/example-ContextMenuViewExample11.gif) + +
+ +### `ContextMenuView` Example 12 + +**Summary**: Context Menu Previews β€” An example showing a custom context menu preview that dynamically changes its size due to its contents updating every second. + +
+ +| Notes | +| ------------------------------------------------------------ | +| πŸ“ **Note**: By default, custom preview will animate to its new size. If you want to disable this behavior, set `MenuPreviewConfig.isResizeAnimated` property to `false`. | + +
+ +[πŸ”— Full Example](./example/srcexamples/ContextMenuViewExample12.tsx) + +```jsx + // πŸ“ Note: for the sake of brevity, some of the code is omitted... + +export function ContextMenuViewExample12(props) { + // increments every second... + const [timer, setTimer] = React.useState(0); + + // ... + return ( + ( + + + {`Counter: ${timer}`} + + + {(timer % 2 === 0)? 'EVEN' : 'The number is: ODD'} + + + )} + // ... + > + {/** Components */} + + ); +}; +``` + +![screenshot](./assets/example-ContextMenuViewExample12-old.png) + +![Gif](./assets/example-ContextMenuViewExample12.gif) + +
+ +### `ContextMenuView` Example 13 + +**Summary**: Menu Action β€” An example showing how to add a subtitle to menu action. + +
+ +| Notes | +| ------------------------------------------------------------ | +| You can add a subtitle to a menu action via passing a string value to the `MenuActionConfig.actionSubtitle` property.

πŸ“ **Note A**: On iOS 13/14, you add subtitles to the menu action via the `MenuActionConfig.discoverabilityTitle` property, but on iOS 15+ this property is now used for the "discoverability heads-up display" UI.

πŸ“ **Note B**: For backwards compatibility, the string value you passed to `discoverabilityTitle` will also be used to set `actionSubtitle` on iOS 15+.

To disable this automatic behavior, set the `ContextMenuView.shouldUseDiscoverability` `TitleAsFallbackValueForSubtitle` prop to `false`. | + +
+ +[πŸ”— Full Example](./example/srcexamples/ContextMenuViewExample13.tsx) + +```jsx + // πŸ“ Note: for the sake of brevity, some of the code is omitted... +import { ContextMenuView } from 'react-native-ios-context-menu'; + +export function ContextMenuViewExample13(props) { + return ( + + {/** Components */} + + ); +}; +``` + +![screenshot](./assets/example-ContextMenuViewExample13-old.png) + +![Gif](./assets/example-ContextMenuViewExample13.gif) + +
+ +### `ContextMenuView` Example 14 + +**Summary**: Context Menu Previews β€” An example that changes the exit transition of the context menu preview when its tapped using the `preferredCommitStyleΒ ` config. + +
+ +| Notes | +| ------------------------------------------------------------ | +| The `MenuPreviewConfig.preferredCommitStyle` allows you to configure what preset exit transition to use when the context menu preview is pressed.

πŸ“ **Note A**: By default, `MenuPreviewConfig.preferredCommitStyle` is set to `'dismiss'`.

πŸ“ **Note B**: A `preferredCommitStyle` of `'pop'`' is usually used when navigating to another screen (i.e. a view controller is pushed without the normal push transition). | + +
+ +[πŸ”— Full Example](./example/srcexamples/ContextMenuViewExample14.tsx) + +```jsx + // πŸ“ Note: for the sake of brevity, some of the code is omitted... +export function ContextMenuViewExample14(props) { + return ( + ( + {/** ... */} + )} + > + {/** Components */} + + ); +}; +``` + +![screenshot](./assets/example-ContextMenuViewExample14-old.png) + +![Gif](./assets/example-ContextMenuViewExample14.gif) + +
+ +### `ContextMenuView` Example 15 + +**Summary**: Context Menu Previews β€” An example showing how to configure a context menu that uses targeted previews. + +
+ +| Notes | +| ------------------------------------------------------------ | +| By default, the child elements you render inside the `ContextMenuView` component will be used as the preview when the context menu interaction is triggered.

Targeted previews allows you to specify which specific view to use for the context menu preview, so that when the context menu interaction begins, a different view will be used for the preview (including the initial transition, see the gif below the example code).

πŸ“ **Note A**: The context menu interaction will still be triggered by long pressing on the child elements in the `ContextMenuView` component.

As such, if the view that you are using for the targeted preview is not a child of `ContextMenuView`, then holding down on that view will not trigger the context menu interaction.

πŸ“ **Note B**: Targeted previews is different from setting a [custom context menu preview](#ContextMenuView-Example-11) via the `renderPreview` prop.

A custom preview will replace the contents of the context menu preview entirely with your custom view component once the menu is opened.

A targeted preview on the other hand will change which view to use for the context menu entrance/exit transition (as well as what view to show in the preview if you do not have a custom preview). | + +
+ +[πŸ”— Full Example](./example/srcexamples/ContextMenuViewExample15.tsx) + +```jsx + // πŸ“ Note: for the sake of brevity, some of the code is omitted... +import { ContextMenuView } from 'react-native-ios-context-menu'; + +export function ContextMenuViewExample15(props) { + const [targetViewNode, setTargetViewNode] = React.useState(); + + React.useEffect(() => { + // please note that when a view unmounts and remounts (e.g. + // when you have a view inside a list comp)., you need to + // get the new associated `reactTag` for that view + // + // otherwise the `reactTag` value you provide to the + // `previewConfig` will be stale... + // + // this is why we have to set `targetViewNode` back to + // `udefined` when the component unmounts + return () => { + setTargetViewNode(undefined); + } + }, []); + + return ( + + { + setTargetViewNode(nativeEvent.target) + })} + > + + {`Hello! Target Node: ${targetViewNode}`} + + + + ); +}; +``` + +![screenshot](./assets/example-ContextMenuViewExample15-old.png) + +![Gif](./assets/example-ContextMenuViewExample15.gif) + +
+ +### `ContextMenuView` Example 15-02 + +**Summary**: Context Menu Previews (Cont). β€” An example showing how to configure a context menu that uses targeted previews + `WrapperView`. + +
+ +[πŸ”— Full Example](./example/srcexamples/ContextMenuViewExample15_02.tsx) + +```jsx +// πŸ“ Note: for the sake of brevity, some of the code is omitted... +import { ContextMenuView } from 'react-native-ios-context-menu'; +import { WrapperView } from 'react-native-ios-utilities'; + +export function ContextMenuViewExample15_02(props) { + // save a ref. to the `WrapperView` element containing the preview target you + // want to use for the context menu. + // + // you can then call `getNativeReactTag` to get the associated `reactTag` + // for that view. + const wrapperViewRef = React.useRef(); + + return ( + + + + {`Hello inside: WrapperView\nTarget Node: ${wrapperViewRef.current?.getNativeReactTag()}`} + + + + ); +}; +``` + +![screenshot](./assets/example-ContextMenuViewExample15-02.png) + +
+ +### `ContextMenuView` Example 16 + +**Summary**: Icon Example β€” An example showing a context menu with an action that uses a `'IMAGE_ASSET'` image for its icon. + +
+ +| Notes | +| ------------------------------------------------------------ | +| A config of `ImageItemConfig.type` set to `'IMAGE_ASSET'` means that you want to use a `xcasset` image asset.

πŸ“ **Note**: The string value you pass to the `ImageItemConfig.imageValue` must match the corresponding asset that you want to use in your project's `xcasset` catalog. | + +
+ +[πŸ”— Full Example](./example/srcexamples/ContextMenuViewExample16.tsx) + +```jsx + // πŸ“ Note: for the sake of brevity, some of the code is omitted... +import { ContextMenuView } from 'react-native-ios-context-menu'; + +export function ContextMenuViewExample16(props) { + return ( + + {/** Components */} + + ); +}; +``` + +![screenshot](./assets/example-ContextMenuViewExample16-old.png) + +![Gif](./assets/example-ContextMenuViewExample16.gif) + +
+ +### `ContextMenuView` Example 17 + +**Summary**: Icon Example β€” An example showing a context menu with action items that have different colored icons. + +
+ +| Notes | +| ------------------------------------------------------------ | +| A `ImageItemConfig` object has an optional called `imageOptions`. This property accepts a `UIImageConfig` object.

You can tint the image to a specified color using the `UIImageConfig.tint` property. This property accepts a color string in either `rgb`, `rgba`, or `hex` format.

You can also choose to provide a dynamic color config if you want to use a specific color for light/dark mode.

πŸ“ **Note A**: Any image can be tinted to a specific color, not just `'IMAGE_SYSTEM'` images.

πŸ“ **Note B**: In order for the tint to take effect, set `UIImageConfig.renderingMode` to `alwaysOriginal`. | + +
+ +[πŸ”— Full Example](./example/srcexamples/ContextMenuViewExample17.tsx) + +```jsx + // πŸ“ Note: for the sake of brevity, some of the code is omitted... +import { ContextMenuView } from 'react-native-ios-context-menu'; + +export function ContextMenuViewExample17(props) { + return ( + + {/** Components */} + + ); +}; +``` + +![screenshot](./assets/example-ContextMenuViewExample17-old.png) + +![Gif](./assets/example-ContextMenuViewExample17.gif) + +
+ +### `ContextMenuView` Example 18 + +**Summary**: Icon Example β€” An example showing a context menu with action items that has icons that uses local image assets imported via `require(...)`. + +
+ +| Notes | +| ------------------------------------------------------------ | +| 1️⃣ β€” The first step that we need to do is to generate a `ImageResolvedAssetSource` object of the local image asset we want to use. This object contains metadata about the image as well as its URI in the file system.

The `Image.resolveAssetSource` function returns a `ImageResolvedAssetSource` that corresponds to the source argument you pass into it. Give this function the return value of `require(path/to/image.png)`. | +| 2️⃣ β€” A config of `ImageItemConfig.type` set to `'IMAGE_REQUIRE'` means that we want to use a local image asset imported via the `require(...)` function.

The `ImageItemConfig.imageValue` property accepts a `ImageResolvedAssetSource` object that corresponds to the image asset that you want to use. | + +
+ +[πŸ”— Full Example](./example/srcexamples/ContextMenuViewExample18.tsx) + +```jsx + // πŸ“ Note: for the sake of brevity, some of the code is omitted... +import { ContextMenuView } from 'react-native-ios-context-menu'; + +// Generate a `ImageResolvedAssetSource` object based on the +// image assets... + +const iconA = Image.resolveAssetSource( + require('../assets/emoji-pleading-face.png') +); + +const iconB = Image.resolveAssetSource( + require('../assets/emoji-smiling-face-with-hearts.png') +); + +const iconC = Image.resolveAssetSource( + require('../assets/emoji-sparkling-heart.png') +); + +export function ContextMenuViewExample18(props) { + return ( + + {/** Components */} + + ); +}; +``` + +![screenshot](./assets/example-ContextMenuViewExample18-old.png) + +![Gif](./assets/example-ContextMenuViewExample18.gif) + +
+ +### `ContextMenuView` Example 19 + +**Summary**: Dynamic Menu β€” An example showing a context menu that shows a loading indicator using deferred menu elements. + +
+ +| Notes | +| ------------------------------------------------------------ | +| 1️⃣ β€” If you control your `ContextMenuView.menuConfig` via state, then you can already dynamically add menu items while the context menu is visible (See [`ContextMenuView` Example 10](#ContextMenuView-Example-10)). However, there is no indication in the UI that items are currently being loaded.

You can use a "deferred element" in order to add an action item that has a loading indicator. Once you are done loading the content, then you can replace the deferred element with the actual menu items that you want to add.

πŸ“ **Note**: Deferred elements are only available on iOS 14 and above. | +| 2️⃣ β€” As mentioned in the previous examples, the `MenuConfig.menuItems` property can accept an array of `MenuElementConfig` union type. This means that it can accept an array containing any of the following object types: `MenuConfig` object, `MenuActionConfig`, and `DeferredMenuElementConfig`.

If we pass in a `DeferredMenuElementConfig` to `menuItems`, it means that we want to create "deferred element" item. | +| 3️⃣ β€” To create a deferred element, we just need to create a "config" object that has a property containing both `type` and `deferredID`.

The `DeferredMenuElementConfig.type` property must be set to a string value of `'deferred'`. This indicates that we want to create a deferred element.

The `DeferredMenuElementConfig.deferredID` property must be set to a unique string value. Since we can have multiple deferred elements, the value you pass into this property will be used to identify which deferred element will be replaced with the menu items you want to add when the loading is complete. | +| 4️⃣ β€” Once the context menu is open, any deferred menu items in `MenuConfig.menuItems` will trigger the `ContextMenuView.onRequestDeferredElement` event to fire. Via the event, you will receive two arguments: `deferredID` string and `provider` callback function.

The `deferredID` string corresponds to which deferred element that we need to load, while the `provider` callback function is used to provide the menu items that we want to add and replace the deferred element with. | +| 5️⃣ β€” The `provider` callback function accepts an array of `MenuElementConfig` items.

To replace the deferred element with the menu items you want add, simply call the `provider` callback function with the array of `MenuConfig`, `MenuActionConfig`, or `DeferredMenuElementConfig` objects.

πŸ“ **Note A**: Since the deferred elements were loaded/replaced using the `onRequestDeferredElement` event, there are now two sources of truths for the context menu config: One provided via the `ContextMenuView.menuConfig` prop, and the other via the `onRequestDeferredElement` event.

If you are using a state-controlled menu config, see: [`ContextMenuView` Example 20](#ContextMenuView-Example-20).

πŸ“ **Note B**: It is recommended that you cache the items you have loaded, and then combine them with the existing `menuConfig` once the menu has been closed. | + +
+ +[πŸ”— Full Example](./example/srcexamples/ContextMenuViewExample19.tsx) + +```jsx +// πŸ“ Note: for the sake of brevity, some of the code is omitted... +export function ContextMenuViewExample19(props) { + return ( + { + switch(deferredID) { + case 'deferred-01': + // dummy delay, wait for 1 second... + await Helpers.timeout(1000); + + // provide the items to add to the context menu... + provider([{ + type: 'action', + actionKey: 'action-02', + actionTitle: 'Deferred Item 02', + actionSubtitle: 'Deferred item...' + }, { + type: 'action', + actionKey: 'action-03', + actionTitle: 'Deferred Item 03', + actionSubtitle: 'Deferred item...' + }]); + break; + }; + }} + > + {/** ... */} + + ); +}; +``` + +![example-ContextMenuViewExample19](./assets/example-ContextMenuViewExample19.jpg) + +![example-ContextMenuViewExample19](./assets/example-ContextMenuViewExample19.gif) + +
+ +### `ContextMenuView` Example 20 + +**Summary**: Dynamic Menu β€” An example showing a state-controlled context menu that shows a loading indicator using deferred menu elements. + +
+ +| Notes | +| ----- | +| TBA | + +
+ +[πŸ”— Full Example](./example/srcexamples/ContextMenuViewExample20.tsx) + +```jsx +// πŸ“ Note: for the sake of brevity, some of the code is omitted... +export function ContextMenuViewExample20(props) { + const [extraMenuItems, setExtraMenuItems] = React.useState([]); + + const [isLoading, setIsLoading] = React.useState(true); + const [didLoadItems, setDidLoadItems] = React.useState(false); + + return ( + { + if(didLoadItems) return; + + // for the purposes of this example, let's add a delay + // before showing the loading indicator... + // + // this way, we can see the context menu updating and + // showing the loading indicator. + // + // Ideally, `isLoading` should already be set to `true` + // before the context menu is shown... + await Helpers.timeout(750); + setIsLoading(true); + + // loading... + // dummy delay, wait for 2 second... + await Helpers.timeout(2000); + setDidLoadItems(true); + + // add extra menu items + setExtraMenuItems([{ + type: 'action', + actionKey: 'action-02', + actionTitle: 'Deferred Item 02', + actionSubtitle: 'Deferred item...' + }, { + type: 'action', + actionKey: 'action-03', + actionTitle: 'Deferred Item 03', + actionSubtitle: 'Deferred item...' + }]); + + // hide the loading indicator + setIsLoading(false); + }} + > + {/** ... */} + + ); +}; +``` + +![example-ContextMenuViewExample20](./assets/example-ContextMenuViewExample20.jpg) + +![example-ContextMenuViewExample20](./assets/example-ContextMenuViewExample20.gif) + +
+ +### `ContextMenuView` Example 21 + +**Summary**: Menu Element Size β€” TBA + +
+ +| Notes | +| ----- | +| TBA | + +
+ +[πŸ”— Full Example](./example/srcexamples/ContextMenuViewExample21.tsx) + +```jsx +// πŸ“ Note: for the sake of brevity, some of the code is omitted... +export function ContextMenuViewExample21(props) { + + return ( + + {/** ... */} + + ); +}; +``` + +![example-ContextMenuViewExample21](./assets/example-ContextMenuViewExample21.jpg) + +![example-ContextMenuViewExampleXX](./assets/example-ContextMenuViewExampleXX.gif) + +
+ +### `ContextMenuView` Example 22 + +**Summary**: Menu Element Size β€” TBA + +
+ +| Notes | +| ----- | +| TBA | + +
+ +[πŸ”— Full Example](./example/srcexamples/ContextMenuViewExample22.tsx) + +```jsx +// πŸ“ Note: for the sake of brevity, some of the code is omitted... +export function ContextMenuViewExample22(props) { + + return ( + + {/** ... */} + + ); +}; +``` + +![example-ContextMenuViewExample22](./assets/example-ContextMenuViewExample22.jpg) + +![example-ContextMenuViewExampleXX](./assets/example-ContextMenuViewExampleXX.gif) + +
+ +### `ContextMenuView` Example 23 + +**Summary**: Menu Element Size β€” TBA + +
+ +| Notes | +| ----- | +| | + +
+ +[πŸ”— Full Example](./example/srcexamples/ContextMenuViewExample23.tsx) + +```jsx +// πŸ“ Note: for the sake of brevity, some of the code is omitted... +export function ContextMenuViewExample23(props) { + + return ( + + { /** ... */ } + + ); +}; +``` + +![example-ContextMenuViewExample23](./assets/example-ContextMenuViewExample23.jpg) + +![example-ContextMenuViewExampleXX](./assets/example-ContextMenuViewExampleXX.gif) + +
+ +### `ContextMenuView` Example 24 + +**Summary**: Menu Attributes β€” `keepsMenuPresented` + +
+ +| Notes | +| ----- | +| TBA | + +
+ +[πŸ”— Full Example](./example/srcexamples/ContextMenuViewExample24.tsx) + +```jsx +// πŸ“ Note: for the sake of brevity, some of the code is omitted... +export function ContextMenuViewExample24(props) { + const [actionState1, setActionState1] = React.useState(false); + const [actionState2, setActionState2] = React.useState(false); + const [actionState3, setActionState3] = React.useState(false); + + const isResetEnabled = ( + actionState1 || + actionState2 || + actionState3 + ); + + const handleOnPressMenuItem = ({nativeEvent}) => { + // ... + }; + + return ( + + { /** ... */ } + + ); +}; +``` + +![example-ContextMenuViewExample24](./assets/example-ContextMenuViewExample24.jpg) + +![example-ContextMenuViewExampleXX](./assets/example-ContextMenuViewExampleXX.gif) + +
+ +### `ContextMenuView` Example 25 + +**Summary**: Icon Example β€” Advanced customization (e.g. `scale`, `weight`, `paletteColors`, `hierarchicalColor`). + +
+ +| Notes | +| ----- | +| TBA | + +
+ +[πŸ”— Full Example](./example/srcexamples/ContextMenuViewExample25.tsx) + +```jsx +// πŸ“ Note: for the sake of brevity, some of the code is omitted... +export function ContextMenuViewExample25(props) { + return ( + + {/** .... */} + + ); +}; +``` + + + +![example-ContextMenuViewExample25](./assets/example-ContextMenuViewExample25.jpg) + +![example-ContextMenuViewExampleXX](./assets/example-ContextMenuViewExampleXX.gif) + +
+ +### `ContextMenuView` Example 26 + +**Summary**: Icon Example β€” Network/Remote images as icons. + +
+ +| Notes | +| ----- | +| TBA | + +
+ +[πŸ”— Full Example](./example/srcexamples/ContextMenuViewExample26.tsx) + +```jsx + +// πŸ“ Note: for the sake of brevity, some of the code is omitted... +export function ContextMenuViewExample26(props) { + return ( + + {/** ... */} + + ); +}; +``` + +![example-ContextMenuViewExampleXX](./assets/example-ContextMenuViewExampleXX.jpg) + +![example-ContextMenuViewExample26](./assets/example-ContextMenuViewExample26.gif) + +
+ +### `ContextMenuView` Example 27 + +**Summary**: Icon Example β€” Network/Remote images as icons + fallback image. + +
+ +| Notes | +| ----- | +| TBA | + +
+ +[πŸ”— Full Example](./example/srcexamples/ContextMenuViewExample27.tsx) + +```jsx +// πŸ“ Note: for the sake of brevity, some of the code is omitted... +export function ContextMenuViewExample27(props) { + return ( + + {/** ... */} + + ); +}; + +``` + + + +![example-ContextMenuViewExampleXX](./assets/example-ContextMenuViewExampleXX.jpg) + +![example-ContextMenuViewExampleXX](./assets/example-ContextMenuViewExampleXX.gif) + +
+ +### `ContextMenuView` Example 28 + +**Summary**: Programmatically shows the context menu + +
+ +| Notes | +| ----- | +| TBA | + +
+ +[πŸ”— Full Example](./example/srcexamples/ContextMenuViewExample28.tsx) + +```jsx +// πŸ“ Note: for the sake of brevity, some of the code is omitted... +export function ContextMenuViewExample28(props) { + const menuRef = React.useRef(null); + + return ( + + + { + menuRef.current?.presentMenu(); + }} + /> + + + ); +}; + +``` + +![example-ContextMenuViewExample28](./assets/example-ContextMenuViewExample28.gif) + +
+ +### `ContextMenuView` Auxiliary Preview - Example 01 + +**Summary**: TBA + +
+ +| Notes | +| ------------------------ | +| TBA

πŸ“ **Note A**: | + +
+ +[πŸ”— Full Example](./example/srcexamples/ContextMenuAuxPreviewExample01.tsx) + +```jsx +// πŸ“ Note: for the sake of brevity, some of the code is omitted... +export function ContextMenuAuxPreviewExample01() { + return ( + ( + + + { /** ... */ } + + + )} + > + {/** ... */} + + ); +}; +``` + +![ContextMenuAuxPreviewExample01](./assets/example-ContextMenuAuxPreviewExample01.jpg) + +![placeholder](./assets/placeholder.gif) + +
+ +### `ContextMenuView` Auxiliary Preview - Example 02 + +**Summary**: TBA + +
+ +| Notes | +| ------------------------ | +| TBA

πŸ“ **Note A**: | + +
+ +[πŸ”— Full Example](./example/srcexamples/ContextMenuAuxPreviewExample02.tsx) + +```jsx +// πŸ“ Note: for the sake of brevity, some of the code is omitted... +export function ContextMenuAuxPreviewExample02() { + return ( + ( + + + Faster Transition + + + )} + > + {/** ... */} + + ); +}; +``` + +![ContextMenuAuxPreviewExample02](./assets/example-ContextMenuAuxPreviewExample02.jpg) + +![placeholder](./assets/placeholder.gif) + +
+ +### `ContextMenuView` Auxiliary Preview - Example 03 + +**Summary**: TBA + +
+ +| Notes | +| ------------------------ | +| TBA

πŸ“ **Note A**: | + +
+ +[πŸ”— Full Example](./example/srcexamples/ContextMenuAuxPreviewExample03.tsx) + +```jsx +// πŸ“ Note: for the sake of brevity, some of the code is omitted... +export function ContextMenuAuxPreviewExample03() { + return ( + ( + + + To the left (to the left) + + + )} + > + {/** ... */} + + ); +}; +``` + +![ContextMenuAuxPreviewExample03](./assets/example-ContextMenuAuxPreviewExample03.jpg) + +![placeholder](./assets/placeholder.gif) + +
+ +### `ContextMenuView` Auxiliary Preview - Example 04 + +**Summary**: TBA + +
+ +| Notes | +| ------------------------ | +| TBA

πŸ“ **Note A**: | + +
+ +[πŸ”— Full Example](./example/srcexamples/ContextMenuAuxPreviewExample04.tsx) + +```jsx +// πŸ“ Note: for the sake of brevity, some of the code is omitted... +export function ContextMenuAuxPreviewExample04() { + return ( + ( + + + Yeah right, yeah right + + + )} + > + {/** ... */} + + ); +}; +``` + +![ContextMenuAuxPreviewExample04](./assets/example-ContextMenuAuxPreviewExample04.jpg) + +![placeholder](./assets/placeholder.gif) + +
+ +### `ContextMenuView` Auxiliary Preview - Example 05 + +**Summary**: TBA + +
+ +| Notes | +| ------------------------ | +| TBA

πŸ“ **Note A**: | + +
+ +[πŸ”— Full Example](./example/srcexamples/ContextMenuAuxPreviewExample05.tsx) + +```jsx +// πŸ“ Note: for the sake of brevity, some of the code is omitted... +export function ContextMenuAuxPreviewExample05() { + return ( + ( + + + Center + + + )} + > + { /** ... */ } + + ); +}; +``` + +![ContextMenuAuxPreviewExample05](./assets/example-ContextMenuAuxPreviewExample05.jpg) + +![placeholder](./assets/placeholder.gif) + +
+ +### `ContextMenuView` Auxiliary Preview - Example 06 + +**Summary**: TBA + +
+ +| Notes | +| ------------------------ | +| TBA

πŸ“ **Note A**: | + +
+ +[πŸ”— Full Example](./example/srcexamples/ContextMenuAuxPreviewExample06.tsx) + +```jsx +// πŸ“ Note: for the sake of brevity, some of the code is omitted... +export function ContextMenuAuxPreviewExample06(props) { + return ( + ( + + + + Stretch to Edges of Screen + + + + )} + > + {/** ... */} + + ); +}; +``` + +![ContextMenuAuxPreviewExample06](./assets/example-ContextMenuAuxPreviewExample06.jpg) + +![placeholder](./assets/placeholder.gif) + +
+ +### `ContextMenuView` Auxiliary Preview - Example 07 + +**Summary**: TBA + +
+ +| Notes | +| ------------------------ | +| TBA

πŸ“ **Note A**: | + +
+ +[πŸ”— Full Example](./example/srcexamples/ContextMenuAuxPreviewExample07.tsx) + +```jsx +// πŸ“ Note: for the sake of brevity, some of the code is omitted... +export function ContextMenuAuxPreviewExample07(props) { + return ( + ( + + + 100 + + + x + + + 100 + + + )} + > + {/** ... */} + + ); +}; +``` + +![ContextMenuAuxPreviewExample07](./assets/example-ContextMenuAuxPreviewExample07.jpg) + +![placeholder](./assets/placeholder.gif) + +
+ +### `ContextMenuView` Auxiliary Preview - Example 08 + +**Summary**: TBA + +
+ +| Notes | +| ------------------------ | +| TBA

πŸ“ **Note A**: | + +
+ +[πŸ”— Full Example](./example/srcexamples/ContextMenuAuxPreviewExample08.tsx) + +```jsx +// πŸ“ Note: for the sake of brevity, some of the code is omitted... +export function ContextMenuAuxPreviewExample08(props) { + return ( + ( + // ... + )} + > + {/** ... */} + + ); +}; +``` + +![ContextMenuAuxPreviewExample08](./assets/example-ContextMenuAuxPreviewExample08.jpg) + +![placeholder](./assets/placeholder.gif) + +
+ +### `ContextMenuView` Auxiliary Preview - Example 09 + +**Summary**: TBA + +
+ +| Notes | +| ------------------------ | +| TBA

πŸ“ **Note A**: | + +
+ +[πŸ”— Full Example](./example/srcexamples/ContextMenuAuxPreviewExample09.tsx) + +```jsx +export function ContextMenuAuxPreviewExample09(props) { + return ( + ( + + + Always Bottom + + + )} + > + {/** ... */} + + ); +}; +``` + +![ContextMenuAuxPreviewExample09](./assets/example-ContextMenuAuxPreviewExample09.jpg) + +![placeholder](./assets/placeholder.gif) + +
+ +### `ContextMenuView` Auxiliary Preview - Example 10 + +**Summary**: TBA + +
+ +| Notes | +| ------------------------ | +| TBA

πŸ“ **Note A**: | + +
+ +[πŸ”— Full Example](./example/srcexamples/ContextMenuAuxPreviewExample10.tsx) + +```jsx +// πŸ“ Note: for the sake of brevity, some of the code is omitted... +export function ContextMenuAuxPreviewExample10(props) { + return ( + ( + // ... + )} + > + {/** .... */} + + ); +}; +``` + +![ContextMenuAuxPreviewExample10](./assets/example-ContextMenuAuxPreviewExample10.jpg) + +![placeholder](./assets/placeholder.gif) + +
+ +### `ContextMenuView` Auxiliary Preview - Example 11 + +**Summary**: TBA + +
+ +| Notes | +| ------------------------ | +| TBA

πŸ“ **Note A**: | + +
+ +[πŸ”— Full Example](./example/srcexamples/ContextMenuAuxPreviewExample11.tsx) + +```jsx +// πŸ“ Note: for the sake of brevity, some of the code is omitted... +export function ContextMenuAuxPreviewExample11(props) { + return ( + ( + // ... + )} + > + {/** ... */} + + ); +}; +``` + +![ContextMenuAuxPreviewExample11](./assets/example-ContextMenuAuxPreviewExample11.jpg) + +![placeholder](./assets/placeholder.gif) + +
+ +### `ContextMenuView` Auxiliary Preview - Example 12 + +**Summary**: TBA + +
+ +| Notes | +| ------------------------ | +| TBA

πŸ“ **Note A**: | + +
+ +[πŸ”— Full Example](./example/srcexamples/ContextMenuAuxPreviewExample12.tsx) + +```jsx +// πŸ“ Note: for the sake of brevity, some of the code is omitted... +export function ContextMenuAuxPreviewExample12(props) { + return ( + ( + // ... + )} + > + {/** ... */} + + ); +}; +``` + +![ContextMenuAuxPreviewExample12](./assets/example-ContextMenuAuxPreviewExample12.jpg) + +![placeholder](./assets/placeholder.gif) + +
+ +### `ContextMenuView` Auxiliary Preview - Example 13 + +**Summary**: TBA + +
+ +| Notes | +| ------------------------ | +| TBA

πŸ“ **Note A**: | + +
+ +[πŸ”— Full Example](./example/srcexamples/ContextMenuAuxPreviewExample13.tsx) + +```jsx +// πŸ“ Note: for the sake of brevity, some of the code is omitted... +export function ContextMenuAuxPreviewExample13(props) { + return ( + ( + // ... + )} + > + {/** ... */} + + ); +}; +``` + +![ContextMenuAuxPreviewExample13](./assets/example-ContextMenuAuxPreviewExample13.jpg) + +![placeholder](./assets/placeholder.gif) + +
+ +### `ContextMenuView` Auxiliary Preview - Example 14 + +**Summary**: TBA + +
+ +| Notes | +| ------------------------ | +| TBA

πŸ“ **Note A**: | + +
+ +[πŸ”— Full Example](./example/srcexamples/ContextMenuAuxPreviewExample14.tsx) + +```jsx +// πŸ“ Note: for the sake of brevity, some of the code is omitted... +export function ContextMenuAuxPreviewExample14(props) { + return ( + ( + // ... + )} + > + {/** ... */} + + ); +}; +``` + +![ContextMenuAuxPreviewExample14](./assets/example-ContextMenuAuxPreviewExample14.jpg) + +![placeholder](./assets/placeholder.gif) + +
+ + + +### `ContextMenuView` Auxiliary Preview - Example 15 + +**Summary**: TBA + +
+ +| Notes | +| ------------------------ | +| TBA

πŸ“ **Note A**: | + +
+ +[πŸ”— Full Example](./example/srcexamples/ContextMenuAuxPreviewExample15.tsx) + +```jsx +// πŸ“ Note: for the sake of brevity, some of the code is omitted... + +export function ContextMenuAuxPreviewExample15(props) { + return ( + ( + + + Aux. Preview + + + )} + previewConfig={{ + previewType: 'CUSTOM', + previewSize: 'STRETCH', + }} + renderPreview={() => ( + + + Custom Menu Preview + + + )} + > + {/** ... */} + + ); +}; +``` + +![ContextMenuAuxPreviewExample15](./assets/example-ContextMenuAuxPreviewExample15.jpg) + +![placeholder](./assets/placeholder.gif) + +
+ +### `ContextMenuView` Auxiliary Preview - Example 16 + +**Summary**: Programmatically shows the auxiliary preview as a popover, without showing the context menu. + +
+ +| Notes | +| ----- | +| TBA | + +
+ +[πŸ”— Full Example](./example/srcexamples/ContextMenuViewExampleXX.tsx) + +```jsx +// πŸ“ Note: for the sake of brevity, some of the code is omitted... +export function ContextMenuAuxPreviewExample16(props) { + const menuRef = React.useRef(null); + + return ( + ( + + + Center + + + )} + > + + { + menuRef.current?.showAuxiliaryPreviewAsPopover(); + }} + /> + + + ); +}; +``` + +![example-ContextMenuViewExample16](./assets/example-ContextMenuAuxPreviewExample16.gif) + +
+ +### `ContextMenuButton` Example 01 + +**Summary**: TBA + +
+ +| Notes | +| ------------------------ | +| TBA

πŸ“ **Note A**: | + +
+ +[πŸ”— Full Example](./example/srcexamples/ContextMenuButtonExample01.tsx) + +```jsx + // πŸ“ Note: for the sake of brevity, some of the code is omitted... + +import { ContextMenuButton } from 'react-native-ios-context-menu'; + +export function ContextMenuButtonExample01() { + return ( + { + Alert.alert( + 'onPressMenuItem Event', + `actionKey: ${nativeEvent.actionKey} - actionTitle: ${nativeEvent.actionTitle}` + ); + }} + > + {/** Components */} + + ); +}; +``` + +![screenshot](./assets/example-ContextMenuButtonExample01-old.png) + +![Gif](./assets/example-ContextMenuButtonExample01.gif) + +
+ +### `ContextMenuButton` Example 02 + +**Summary**: TBA + +
+ +| Notes | +| ------------------------ | +| TBA

πŸ“ **Note A**: | + +
+ +[πŸ”— Full Example](./example/srcexamples/ContextMenuButtonExample02.tsx) + +```jsx + // πŸ“ Note: for the sake of brevity, some of the code is omitted... +import { ContextMenuButton } from 'react-native-ios-context-menu'; + +export function ContextMenuButtonExample02(props) { + return ( + { + Alert.alert( + 'onPressMenuItem Event', + `actionKey: ${nativeEvent.actionKey} - actionTitle: ${nativeEvent.actionTitle}` + ); + }} + > + {/** Components */} + + ); +}; +``` -
+![screenshot](./assets/example-ContextMenuButtonExample02-old.png) -| Name and Type | Description | -| :---------------------------------------------- | ----------- | -| πŸ”€ `transition`

βš›οΈ `string` i.e. `none` | TBA | +![Gif](./assets/example-ContextMenuButtonExample02.gif) -
+

-| Name and Type | Description | -| :---------------------------------------------- | ----------- | -| πŸ”€ `transition`

βš›οΈ `string` i.e. `fade` | TBA | +## F. Showcase, Tests and Demos -
+### `ContextMenuView` Test 01 -| Name and Type | Description | -| :----------------------------------------------- | ----------- | -| πŸ”€ `transition`

βš›οΈ `string` i.e. `slide` | TBA | -| πŸ”€ `slideOffset`

βš›οΈ `number` | TBA | +**Summary**: Test for multiple nested/deep submenus. -
+[πŸ”— Source Code](example/src/examples/ContextMenuViewTest01.tsx) -| Name and Type | Description | -| :---------------------------------------------- | ----------- | -| πŸ”€ `transition`

βš›οΈ `string` i.e. `zoom` | TBA | -| πŸ”€ `zoomOffset`

βš›οΈ `number` | TBA | +![Gif](./assets/test-ContextMenuViewTest01.gif)
-| Name and Type | Description | -| :------------------------------------------------------ | ----------- | -| πŸ”€ `transition`

βš›οΈ `string` i.e. `zoomAndSlide` | TBA | -| πŸ”€ `slideOffset`

βš›οΈ `number` | TBA | -| πŸ”€ `zoomOffset`

βš›οΈ `number` | TBA | - -
+### `ContextMenuView` Test 02 -##### Object Union Type: `MenuAuxiliaryPreviewTransitionConfig` +**Summary**: Test for multiple inline menus + nested submenus. -This type is a union between the `UIViewAnimateConfig` object type, and the `MenuAuxiliaryPreviewBaseTransitionConfig` object type. +[πŸ”— Source Code](example/src/examples/ContextMenuViewTest02.tsx) -```typescript -export type MenuAuxiliaryPreviewTransitionConfig = - | UIViewAnimateConfig - | MenuAuxiliaryPreviewBaseTransitionConfig; -``` +![Gif](./assets/test-ContextMenuViewTest02.gif)
-##### Mixed Union Type: `MenuAuxiliaryPreviewTransitionEntranceDelay`. - -| Name and Type | Description | -| :---------------- | ----------- | -| βš›οΈ `number` | TBA | -| βš›οΈ `RECOMMENDED` | TBA | -| βš›οΈ `AFTER_PREVIEW` | TBA | +### `ContextMenuView` Test 03 -
+**Summary**: Test for toggling the `menuState` on and off. -#### `MenuIconConfig.ts` +[πŸ”— Source Code](example/src/examples/ContextMenuViewTest03.tsx) -* πŸ“Œ **Declaration**: [`MenuIconConfig.ts`](src/types/MenuIconConfig.ts) +![Gif](./assets/test-ContextMenuViewTest03.gif)
-##### Object Type: `IconConfig` - -This has been deprecated and will be removed in a future version. Use [`ImageItemConfig`](PLACE_HOLDER_LINK) instead. For documentation regarding `IconConfig`, please see the documentation in the [old README](./README-old-v1.md). +### `ContextMenuView` Test 04 -
+**Summary**: Test for changing the menu icons based on the current `menuState`. -#### `ImageItemConfig.ts` +[πŸ”— Source Code](example/src/examples/ContextMenuViewTest04.tsx) -* πŸ“Œ **Declaration**: [`ImageItemConfig.ts`](src/types/ImageItemConfig.ts) +![Gif](./assets/test-ContextMenuViewTest04.gif)
-##### Object Type: `ImageItemConfig` - -This type is an object tagged union type, with the `type` property being the tag that separates the unions. The table below defines the possible valid values that can be assigned to the `type` property. - -| Name and Type | Description | -| :----------------------------------------------------------- | ----------- | -| πŸ”€ **Required**: `type`

βš›οΈ `ImageItemConfigType` string union, i.e. `'IMAGE_ASSET' Β¦ 'IMAGE_SYSTEM' Β¦ 'IMAGE_REQUIRE'`
` Β¦ 'IMAGE_EMPTY' Β¦ 'IMAGE_RECT' Β¦ 'IMAGE_GRADIENT' `
`Β¦ 'IMAGE_REMOTE_URL'` | TBA | +### `ContextMenuView` Test 05 -
+**Summary**: Test for logging all the menu-related events. -###### `ImageItemConfig`: `IMAGE_ASSET` +[πŸ”— Source Code](example/src/examples/ContextMenuViewTest05.tsx) -| Name and Type | Description | -| :----------------------------------------------------------- | ------------------------------------------------------------ | -| πŸ”€ **Required**: `type`

βš›οΈ `string` i.e `'IMAGE_ASSET' ` | TBA

πŸ“Œ Maps to [`UIImage.init(named:)`](https://developer.apple.com/documentation/uikit/uiimage/1624146-init) constructor in the apple docs. | -| πŸ”€ **Required**: `imageValue`

βš›οΈ `string` | TBA | -| πŸ”€ `imageOptions?`

βš›οΈ [`ImageOptions`](PLACE_HOLDER_LINK) | TBA | +![Gif](./assets/test-ContextMenuViewTest05.gif)
-###### `ImageItemConfig`: `IMAGE_SYSTEM` - -| Name and Type | Description | -| :----------------------------------------------------------- | ------------------------------------------------------------ | -| πŸ”€ **Required**: `type`

βš›οΈ `string` i.e `'IMAGE_SYSTEM' ` | TBA

πŸ“Œ Maps to [`UIImage.init(systemName:withConfiguration:)`](https://developer.apple.com/documentation/uikit/uiimage/3294234-init) constructor in the apple docs. | -| πŸ”€ **Required**: `imageValue`

βš›οΈ [`ImageSystemConfig`](PLACE_HOLDER_LINK) | TBA

πŸ“Œ Maps to the `withConfiguration` argument label in the [`UIImage.init(systemName:withConfiguration:)`](https://developer.apple.com/documentation/uikit/uiimage/3294234-init) constructor in the apple docs. | -| `imageOptions`

βš›οΈ [`ImageOptions`](PLACE_HOLDER_LINK) | TBA | -| πŸ”€ `imageLoadingConfig`

βš›οΈ [`ImageLoadingConfig`](PLACE_HOLDER_LINK) | TBA | +### `ContextMenuView` Test 06 -
+**Summary**: Test for programmatically adding a menu action item. -###### `ImageItemConfig`: `IMAGE_EMPTY` +[πŸ”— Source Code](example/src/examples/ContextMenuViewTest06.tsx) -| Name and Type | Description | -| :----------------------------------------------------------- | ----------- | -| πŸ”€ **Required**: `type`

βš›οΈ `string` i.e `'IMAGE_EMPTY' ` | TBA | +![Gif](./assets/test-ContextMenuViewTest06.gif)
-###### `ImageItemConfig`: `IMAGE_RECT` - -| Name and Type | Description | -| :----------------------------------------------------------- | ------------------------------------------------------------ | -| πŸ”€ **Required**: `type`

βš›οΈ `string` i.e `'IMAGE_RECT' ` | TBA

πŸ“ **Note**: Programmatically creates an image using [`UIGraphicsImageRenderer`](https://developer.apple.com/documentation/uikit/uigraphicsrenderer). | -| πŸ”€ **Required**: `imageValue`

βš›οΈ [`ImageRectConfig`](PLACE_HOLDER_LINK) | TBA | +### `ContextMenuView` Test 07 -
+**Summary**: Test for checking the different possible custom menu preview configurations. -###### `ImageItemConfig`: `IMAGE_GRADIENT` +[πŸ”— Source Code](example/src/examples/ContextMenuViewTest07.tsx) -| Name and Type | Description | -| :----------------------------------------------------------- | ------------------------------------------------------------ | -| πŸ”€ **Required**: `type`

βš›οΈ `string` i.e `'IMAGE_GRADIENT' ` | TBA

πŸ“ **Note**: Programmatically creates an image using [`UIGraphicsImageRenderer`](https://developer.apple.com/documentation/uikit/uigraphicsrenderer). | -| πŸ”€ `imageValue`

βš›οΈ [`ImageGradientConfig`](PLACE_HOLDER_LINK) | TBA | -| `imageOptions`

βš›οΈ [`ImageOptions`](PLACE_HOLDER_LINK) | TBA | +![Gif](./assets/test-ContextMenuViewTest07.gif)
-###### `ImageItemConfig`: `IMAGE_REMOTE_URL` - -| Name and Type | Description | -| :----------------------------------------------------------- | ----------- | -| πŸ”€ **Required**: `type`

βš›οΈ `string` i.e `'IMAGE_REMOTE_URL' ` | TBA | -| πŸ”€ `imageValue`

βš›οΈ [`ImageRemoteUrlConfig`](PLACE_HOLDER_LINK) | TBA | -| πŸ”€ `imageLoadingConfig`

βš›οΈ [`ImageLoadingConfig`](PLACE_HOLDER_LINK) | TBA | -| `imageOptions`

βš›οΈ [`ImageOptions`](PLACE_HOLDER_LINK) | TBA | - -
+### `ContextMenuView` Test 08 -##### Object Type: `ImageResolvedAssetSource` +**Summary**: Test for programmatically dismissing the menu. -TBA +[πŸ”— Source Code](example/src/examples/ContextMenuViewTest08.tsx) -| Name and Type | Description | -| :------------------------------- | ----------- | -| πŸ”€ `height`

βš›οΈ `number` | TBA | -| πŸ”€ `width`

βš›οΈ `number` | TBA | -| πŸ”€ `scale`

βš›οΈ `number` | TBA | -| πŸ”€ `uri`

βš›οΈ `string` | TBA | +![Gif](./assets/test-ContextMenuViewTest08.gif)
-##### Object Type: `ImageRectConfig` - -TBA - -| Name and Type | Description | -| :----------------------------------------------- | ----------- | -| πŸ”€ **Required**: `width`

βš›οΈ `number` | TBA | -| πŸ”€ **Required**: `height`

βš›οΈ `number` | TBA | -| πŸ”€ **Required**: `fillColor`

βš›οΈ `string` | TBA | -| πŸ”€ `borderRadius?`

βš›οΈ `number` | TBA | - -
+### `ContextMenuView` Test 09 -##### Object Type: `ImageGradientConfig` +**Summary**: Generate new 'deferredID' everytime the context menu is shown/hide. This is a test for `cleanupOrphanedDeferredElements`. -TBA +[πŸ”— Source Code](example/src/examples/ContextMenuViewTest09.tsx) -| Name and Type | Description | -| :----------------------------------------------------------- | ------------------------------------------------------------ | -| πŸ”€ **Required**: `width`

βš›οΈ `number` | TBA | -| πŸ”€ **Required**: `height`

βš›οΈ `number` | TBA | -| πŸ”€ `borderRadius?`

βš›οΈ `number` | TBA | -| πŸ”€ **Required**: `colors`

βš›οΈ `Array` | TBA

πŸ“Œ Maps to [`CAGradientLayer.colors`](https://developer.apple.com/documentation/quartzcore/cagradientlayer/1462403-colors) property in the apple docs. | -| πŸ”€ `locations?`

βš›οΈ `Array` | TBA

πŸ“Œ Maps to [`CAGradientLayer.locations`](https://developer.apple.com/documentation/quartzcore/cagradientlayer/1462410-locations) property in the apple docs. | -| πŸ”€ `startPoint?`

βš›οΈ `Point Β¦ PointPreset`

πŸ“Œ [`Point`](PLACE_HOLDER_LINK)
πŸ“Œ [`PointPreset`](PLACE_HOLDER_LINK) | TBA

πŸ“Œ Maps to [`CAGradientLayer.startPoint`](https://developer.apple.com/documentation/quartzcore/cagradientlayer/1462408-startpoint) property in the apple docs. | -| πŸ”€ `endPoint?`

βš›οΈ `Point Β¦ PointPreset`
πŸ“Œ [`Point`](PLACE_HOLDER_LINK)
πŸ“Œ [`PointPreset`](PLACE_HOLDER_LINK) | TBA

πŸ“Œ Maps to [`CAGradientLayer.endPoint`](https://developer.apple.com/documentation/quartzcore/cagradientlayer/1462412-endpoint) property in the apple docs. | -| πŸ”€ `type?`

βš›οΈ `string` i.e `'axial' Β¦ 'conic' Β¦ 'radial'` | TBA

πŸ“Œ Maps to [`CAGradientLayer.type`](https://developer.apple.com/documentation/quartzcore/cagradientlayer/1462413-type) property in the apple docs. | +![Gif](./assets/test-ContextMenuViewTest09.gif)
-##### Object Type: `ImageSystemConfig` - -TBA - -| Name and Type | Description | -| :----------------------------------------------------------- | ------------------------------------------------------------ | -| πŸ”€ **Required**: `systemName`

βš›οΈ `string` | TBA

πŸ“Œ Maps to the `systemName` argument label in the [`UIImage.init(systemName:withConfiguration:)`](https://developer.apple.com/documentation/uikit/uiimage/3294234-init) constructor in the apple docs. | -| πŸ”€ `pointSize?`

βš›οΈ `number` | TBA

πŸ“Œ Maps to [`UIImage.SymbolConfiguration.init(pointSize:)`](https://developer.apple.com/documentation/uikit/uiimage/symbolconfiguration/3294241-init) constructor in the apple docs. | -| πŸ”€ `weight?`

βš›οΈ [`ImageSymbolWeight`](PLACE_HOLDER_LINK) | TBA

πŸ“Œ Maps to [`UIImage.SymbolConfiguration.init(weight:)`](https://developer.apple.com/documentation/uikit/uiimage/symbolconfiguration/3294247-init) constructor in the apple docs. | -| πŸ”€ `scale?`

βš›οΈ [`ImageSymbolScale`](PLACE_HOLDER_LINK) | TBA

πŸ“Œ Maps to [`UIImage.SymbolConfiguration.init(scale:)`](https://developer.apple.com/documentation/uikit/uiimage/symbolconfiguration/3294244-init) constructor in the apple docs. | -| πŸ”€ `hierarchicalColor?`

βš›οΈ `Array` | TBA

πŸ“ **Note A**: Cannot be used at the same time with `paletteColors` (it's either one or the other).

πŸ“ **Note B**: Requires iOS 15+.

πŸ“Œ Maps to [`UIImage.SymbolConfiguration.init(hierarchicalColor:)`](https://developer.apple.com/documentation/uikit/uiimage/symbolconfiguration/3810053-init) constructor in the apple docs. | -| πŸ”€ `paletteColors?`

βš›οΈ `string` | TBA

πŸ“ **Note A**: Cannot be used at the same time with `hierarchicalColor` (it's either one or the other).

πŸ“ **Note B**: Requires iOS 15+.

πŸ“Œ Maps to [`UIImage.SymbolConfiguration.init(paletteColors:)`](https://developer.apple.com/documentation/uikit/uiimage/symbolconfiguration/3810054-init) constructor in the apple docs. | - -
+### `ContextMenuView` Test 10 -##### Object Type: `UIImageConfig` +**Summary**: Test for nested menus, deferred elements, large icons, and small menus, -TBA +[πŸ”— Source Code](example/src/examples/ContextMenuViewTest10.tsx) -| Name and Type | Description | -| :--------------------------------------------------- | ----------- | -| πŸ”€ `tint`

βš›οΈ `string ¦ DynamicColor` | TBA | -| πŸ”€ `renderingMode`

βš›οΈ `ImageRenderingModes` | TBA | +![Gif](./assets/test-ContextMenuViewTest10.gif)
-##### Object Union Type: `ImageOptions` - -This type is a unioned with `UIImageConfig` object type, so it inherits its properties. - -| Name and Type | Description | -| :------------------------------------- | ----------- | -| πŸ”€ `cornerRadius`

βš›οΈ `number` | TBA | - -
+### `ContextMenuAuxPreview` Test 01 -##### Object Type: `ImageRemoteUrlConfig` +**Summary**: TBA -TBA +[πŸ”— Source Code](example/src/examples/ContextMenuAuxPreviewTest01.tsx) -| Name and Type | Description | -| :------------------------------------------ | ----------- | -| πŸ”€ **Required**: `url`

βš›οΈ `string` | TBA | +![Gif](./assets/test-ContextMenuAuxPreviewTest01.gif)
-##### Object Type: `ImageLoadingConfig` +### `Test02Screen` -TBA +**Summary**: Repro for [Issue #43](https://github.com/dominicstop/react-native-ios-context-menu/issues/43) -| Name and Type | Description | -| :---------------------------------------- | ----------- | -| πŸ”€ `shouldCache`

βš›οΈ `boolean` | TBA | -| πŸ”€ `shouldLazyLoad`

βš›οΈ `boolean` | TBA | +[πŸ”— Source Code](example/src/screens/Test02Screen.tsx) + +![Gif](./assets/screen-Test02Screen.gif)
-#### Undocumented Types +### `Test03Screen` -TBA +**Summary**: Repro for [Issue #47](https://github.com/dominicstop/react-native-ios-context-menu/issues/47) -| Type | Description | -| :----------------------------------------------------------- | ------------------------------------------------------------ | -| πŸ“Œ **Declaration**: [`MenuEvents`](src/types/MenuEvents.ts) | This file contains all the menu-related events and event objects. | -| πŸ“Œ **Declaration**: [`MiscTypes.ts`](src/types/MiscTypes.ts) | This file contains a bunch of types that haven't been categorized yet.

Contains: `PointPreset`, `Point`, `DynamicColor`, etc. | -| πŸ“Œ **Declaration**: [`RNICleanupMode.ts`](src/types/RNICleanupMode.ts) | TBA | +[πŸ”— Source Code](example/src/screens/Test03Screen.tsx) -
+![Gif](./assets/screen-Test03Screen.gif) -### D.5. Constants +

-#### Object: `LIB_ENV` +## G. Meta -TBA +

-
+## H. Licence -| Type | Description | -| :------------------------------------------------------ | :---------- | -| πŸ”€ `isContextMenuButtonSupported`

βš›οΈ `boolean` | TBA | -| πŸ”€ `isContextMenuViewSupported`

βš›οΈ `boolean` | TBA | +[MIT](./LICENSE)

-## E. Usage And Examples +## Misc and Contact + +* 🐀 **Twitter/X**: `@GoDominic` +* πŸ’Œ **Email**: `dominicgo@dominicgo.dev` +* 🌐 **Website**: [dominicgo.dev](https://dominicgo.dev)## E. Usage And Examples ### `ContextMenuView` Example 01 diff --git a/docs/README-01-Pre.md b/docs/README-01-Pre.md index ef4efc49..19e58f56 100644 --- a/docs/README-01-Pre.md +++ b/docs/README-01-Pre.md @@ -6,10 +6,17 @@ A small component for using context menu's on iOS.

-## 🚧⚠️ Documentation WIP ⚠️🚧 +## 🚧⚠️ Notices ⚠️🚧 -πŸ“ Note: See [`TODO.md`](docs/TODO.md) for progress. +πŸ“ **Version `2.x` Notice**: Hello, please note that versions `2.x` and below of this library are no longer supported; please do not submit an issue if the version you are using is below `3.x`. +* If you really need a fix for the particular issue/bug, please create a repro and add a test case in the [examples](example/src/examples) directory via a pull request in the main branch; i will investigate the bug, and backport the fix from `3.x` to `2.x`. +* I apologize but i do not have the resources to maintain multiple versions of this library; all issues must be reproducible from `3.x` first before i can backport the changes to an older version of this library. +* Please understand that PR for the repro is crucial; i cannot work on the fix if i don't have a repro to start on; words describing the issue is not enough due to the language barrier. Once you've created a test case, please tag me on the PR so i get notified. +* **Summary**: I will fix the bugs you encounter, however i cannot work on fixing them until a repro/test case is created in the examples directory. Thank you for understanding. +
+ +πŸ“ **Documentation Notice**: See [`TODO.md`](docs/TODO.md) for progress. - The documentation is incomplete (some parts/sections are marked as **TBA** i.e. "to be added"). - Some of the links in the documentation are broken (i.e. the URL points to `PLACE_HOLDER_LINK`). - Some of the gifs/images are old, or broken. @@ -26,6 +33,8 @@ A small component for using context menu's on iOS. ### Versions +
+ | Library Version | Compatibility | | :-------------- | ------------------------------------------------------------ | | `3.x`+ | Depends on `react-native-ios-utilities@5.x`
Depends on `ContextMenuAuxiliaryPreview`
iOS 13+
Xcode 15+ | @@ -206,20 +215,6 @@ cd ios && pod install
-### Installation (Experimental Version) - -```sh -# 1. install library + dependencies -npm install react-native-ios-utilities@next -npm install react-native-ios-context-menu@next - - -# 2. then run pod install (uses auto-linking) -cd ios && pod install -``` - -
- ### Updating This library has cocoapods dependency to [`ContextMenuAuxiliaryPreview`](https://github.com/dominicstop/ContextMenuAuxiliaryPreview) and [`DGSwiftUtilities`](https://github.com/dominicstop/DGSwiftUtilities), so you may need to update them separately (as needed). diff --git a/docs/README-02-Docs.md b/docs/README-02-Docs.md index 0bfe271c..ad800812 100644 --- a/docs/README-02-Docs.md +++ b/docs/README-02-Docs.md @@ -1,3 +1,374 @@ +# react-native-ios-context-menu + +A small component for using context menu's on iOS. + +![context-menu-example-demo](./assets/context-menu-example-demo.gif) + +

+ +## 🚧⚠️ Documentation WIP ⚠️🚧 + +πŸ“ Note: See [`TODO.md`](docs/TODO.md) for progress. + +- The documentation is incomplete (some parts/sections are marked as **TBA** i.e. "to be added"). +- Some of the links in the documentation are broken (i.e. the URL points to `PLACE_HOLDER_LINK`). +- Some of the gifs/images are old, or broken. +- For now, please see the [Usage And Examples](#e-usage-and-examples) section, and [Showcase, Tests and Demos](#F-Showcase-Tests-and-Demos) section for information on how to use this library. + +

+ +| Notice | +| ------------------------------------------------------------ | +| πŸ“ **Note** #1: Version `3.x` is a rewrite of this library to support both fabric (the new architecture), and offer backwards compatibility to paper (the old architecture).

Support for the new architecture (fabric), and backwards compatibility for the old architecture (paper) is handled via a peer via a peer dependency to [`react-native-ios-utilites@v5`](https://github.com/dominicstop/react-native-ios-utilities). | +| πŸ“ **Note** #2: The documentation + examples are currently being rewritten.

❀️ [`README-old-v1.md`](./README-old-v1.md) β€” Documentation for `v1.x`
🧑 [`README-old-v2.md`](./README-old-v2.md) β€” Documentation for `v2.x`
πŸ’› [`example/src/examples`](./example/src/examples) β€” The typescript rewrite of the examples (WIP). | + +
+ +### Versions + +| Library Version | Compatibility | +| :-------------- | ------------------------------------------------------------ | +| `3.x`+ | Depends on `react-native-ios-utilities@5.x`
Depends on `ContextMenuAuxiliaryPreview`
iOS 13+
Xcode 15+ | +| `2.1` | Uses `Expo-Modules`
Depends on `react-native-ios-utilities@4.x`
Depends on `ContextMenuAuxiliaryPreview`
iOS 13+
Xcode 15+ | +| `2.0.x` | Uses `Expo-Modules`
Depends on `react-native-ios-utilities@4.x`
iOS 13+
Xcode 15+ | +| `1.6.2` | iOS 10 to iOS 15
Xcode 12+ | +| `1.4` | iOS 10 to iOS 15
Xcode 13+ | +| `1.3` and Below | iOS 10 to 14
Xcode 12+ | + +

+ +## Table of Contents + +| Sections and Links | +| ------------------------------------------------------------ | +| [A. **Introduction**](#a-introduction)

β€’ [Gifs and Demos](#gifs-and-demos)
β€’ [Features](#features) | +| [B. **Installation**](#b-installation)

β€’ [Expo](#expo)
β€’ [Troubleshooting](#troubleshooting)
--β€’ [Xcode Build Error (Swift)](#troubleshooting-xcode-build-error-(swift))
--β€’ [Xcode Build Error (Undefined symbol)](#troubleshooting-xcode-build-error-(undefined-symbol)) | +| [C. **Basic Usage**](#c-basic-usage) | +| [D. **Documentation**](#d-documentation)

β€’ [D.1. Components](#d1-components)
--β€’ [`ContextMenuView` Component](#contextmenuview-component)
----β€’ [Props](#contextmenuview-component-props)
----β€’ [Event Props](#contextmenuview-component-event-props)
----β€’ [Properties/Methods](#contextmenuview-component-properties/methods)
----β€’ [Experimental - Aux. Preview](#contextmenuview-component-experimental---auxiliary-preview)

--β€’ [`ContextMenuButton` Component](#contextmenubutton-component)
----β€’ [Props](#contextmenubutton-component-props)
----β€’ [Event Props](#contextmenubutton-component-event-props)
----β€’ [Properties/Methods](#contextmenubutton-component-properties/methods)

β€’ [D.2. Context](#d2-context)
--β€’ [`ContextMenuButtonContext`](#ContextMenuButtonContext-context)
--β€’ [`ContextMenuButtonContext`](#ContextMenuButtonContext-context)

β€’ [D.3. Hooks](#d3-hooks)
--β€’ [`useMenuContext`](#useMenuContext-hook)
--β€’ [`useMenuButtonContext`](#useMenuButtonContext-hook)

β€’ [D.4. Objects and Types](#d4-objects-and-types)
--β€’ [`MenuConfig.ts`](#MenuConfigts)
----β€’ [Object Type: `MenuConfig`](#Object-Type-MenuConfig)
----β€’ [Object Type: `MenuActionConfig`](#Object-Type-MenuActionConfig)
----β€’ [Object Type: `DeferredMenuElementConfig`](#Object-Type-DeferredMenuElementConfig)
----β€’ [String Union: `MenuAttributes`](#String-Union-MenuAttributes)
----β€’ [String Union: `MenuState`](#String-Union-MenuState)
----β€’ [String Union: `UIMenuOptions`](#String-Union-UIMenuOptions)

--β€’ [`MenuPreviewConfig.ts`](#MenuPreviewConfigts)
----β€’ [Object Type: `MenuPreviewConfig`](#Object-Type-MenuPreviewConfig)
----β€’ [String Union: `ContextMenuInteractionCommitStyle`](#String-Union-ContextMenuInteractionCommitStyle)
----β€’ [String Union: `MenuPreviewSize`](#String-Union-MenuPreviewSize)
----β€’ [String Union: `MenuPreviewType`](#String-Union-MenuPreviewType)

--β€’ [`MenuAuxiliaryPreviewConfig.ts`](#MenuAuxiliaryPreviewConfigts)
----β€’ [Object Type: `MenuAuxiliaryPreviewConfig`](#Object-Type-MenuAuxiliaryPreviewConfig)
----β€’ [String Union Type: `MenuAuxiliaryPreviewAnchorPosition`](#String-Union-Type-MenuAuxiliaryPreviewAnchorPosition)
----β€’ [String Union Type: `MenuAuxiliaryPreviewHorizontalAlignment`](#String-Union-Type-MenuAuxiliaryPreviewHorizontalAlignment)
----β€’ [String Union Type: `UIViewAnimateOptions`](#String-Union-Type-UIViewAnimateOptions)
----β€’ [Object Type: `UIViewAnimateConfig`](#Object-Type-UIViewAnimateConfig)
----β€’ [Object Type: `MenuAuxiliaryPreviewBaseTransitionConfig`](#Object-Type-MenuAuxiliaryPreviewBaseTransitionConfig)
----β€’ [Object Union Type: `MenuAuxiliaryPreviewTransitionConfig`](#Object-Union-Type-`MenuAuxiliaryPreviewTransitionConfig`)
----β€’ [Mixed Union Type: `MenuAuxiliaryPreviewTransitionEntranceDelay`](#Mixed-Union-Type-MenuAuxiliaryPreviewTransitionEntranceDelay)

--β€’ [`MenuIconConfig.ts`](#MenuIconConfigts)
--β€’ [`ImageItemConfig.ts`](#ImageItemConfigts)
----β€’ [Object Type: `ImageItemConfig`](#Object-Type-ImageItemConfig)
----β€’ [Object Type: `ImageResolvedAssetSource`](#Object-Type-ImageResolvedAssetSource)
----β€’ [Object Type: `ImageRectConfig`](#Object-Type-ImageRectConfig)
----β€’ [Object Type: `ImageGradientConfig`](#Object-Type-ImageGradientConfig)
----β€’ [Object Type: `ImageSystemConfig`](#Object-Type-ImageSystemConfig)

--β€’ [Undocumented Types](#Undocumented-Types)

β€’ [D.5. Constants](#d5-constants) | +| [E. **Usage And Examples**](#E-Usage-And-Examples)
πŸ“ **Note**: See [Example Index](#toc-examples-index) section for a complete list of examples + their descriptions. | +| [F. **Showcase, Tests and Demos**](#F-Showcase-Tests-and-Demos) | +| [G. **Meta**](#G-Meta) | +| [H. **Licence**](#H-Licence) | + +
+ +### TOC: Examples Index + +| Examples | +| ------------------------------------------------------------ | +| πŸ“Œ **[`ContextMenuView` Example 01](#ContextMenuView-Example-01)**
πŸ’­ **Summary**: A basic context menu that has 3 menu action items. | +| πŸ“Œ **[`ContextMenuView` Example 02](#ContextMenuView-Example-02)**
πŸ’­ **Summary**: Icon Example β€” A basic context menu that has 3 menu action items, each with a different "SF Symbols" icon. This examples shows how to add a system icon in the context menu action. | +| πŸ“Œ **[`ContextMenuView` Example 03](#ContextMenuView-Example-03)**
πŸ’­ **Summary**: Nested Menu β€” This example shows a context menu that has a submenu item inside its list of menu actions. | +| πŸ“Œ **[`ContextMenuView` Example 04](#ContextMenuView-Example-04)**
πŸ’­ **Summary**: Menu Attributes β€” This example context menu showcases the `MenuActionConfig.menuAttributes` property. | +| πŸ“Œ **[`ContextMenuView` Example 05](#ContextMenuView-Example-05)**
πŸ’­ **Summary**: Nested Menu + Menu Attributes β€” A context menu that has a in-line submenu. | +| πŸ“Œ **[`ContextMenuView` Example 06](#ContextMenuView-Example-06)**
πŸ’­ **Summary**: Menu Options β€” A context menu that has a destructive submenu. | +| πŸ“Œ **[`ContextMenuView` Example 07](#ContextMenuView-Example-07)**
πŸ’­ **Summary**: Menu Options β€” A context menu that set to be both "destructive" and "display in-line". | +| πŸ“Œ **[`ContextMenuView` Example 08](#ContextMenuView-Example-08)**
πŸ’­ **Summary**: Menu State β€” A context menu with 3 actions that has `'on'`, `'off'`, and `'mixed'` `menuState`. | +| πŸ“Œ **[`ContextMenuView` Example 09](#ContextMenuView-Example-09)**
πŸ’­ **Summary**: Events β€” An example for the `onPressMenuItem` event prop. | +| πŸ“Œ **[`ContextMenuView` Example 10](#ContextMenuView-Example-10)**
πŸ’­ **Summary**: Dynamic Menu β€” An example showing how to dynamically update the context menu while it's visible. In this example, the menu action changes every time the counter increments every second. | +| πŸ“Œ **[`ContextMenuView` Example 11](#ContextMenuView-Example-11)**
πŸ’­ **Summary**: Context Menu Previews β€” An example showing how to use a custom preview for the context menu. | +| πŸ“Œ **[`ContextMenuView` Example 12](#ContextMenuView-Example-12)**
πŸ’­ **Summary**: Context Menu Previews β€” An example showing a custom context menu preview that dynamically changes its size due to its contents updating every second. | +| πŸ“Œ **[`ContextMenuView` Example 13](#ContextMenuView-Example-13)**
πŸ’­ **Summary**: Menu Action β€” An example showing how to add a subtitle to menu action. | +| πŸ“Œ **[`ContextMenuView` Example 14](#ContextMenuView-Example-14)**
πŸ’­ **Summary**: Context Menu Previews β€” An example that changes the exit transition of the context menu preview when its tapped using the `preferredCommitStyle ` config. | +| πŸ“Œ **[`ContextMenuView` Example 15](#ContextMenuView-Example-15)**
πŸ’­ **Summary**: Context Menu Previews β€” An example showing how to configure a context menu that uses targeted previews. | +| πŸ“Œ **[`ContextMenuView` Example 15-02](#ContextMenuView-Example-15-02)**
πŸ’­ **Summary**: Context Menu Previews (Cont). β€” An example showing how to configure a context menu that uses targeted previews + `WrapperView`. | +| πŸ“Œ **[`ContextMenuView` Example 16](#ContextMenuView-Example-16)**
πŸ’­ **Summary**: Icon Example β€” An example showing a context menu with an action that uses a `'IMAGE_ASSET'` image for its icon. | +| πŸ“Œ **[`ContextMenuView` Example 17](#ContextMenuView-Example-17)**
πŸ’­ **Summary**: Icon Example β€” An example showing a context menu with action items that have different colored icons. | +| πŸ“Œ **[`ContextMenuView` Example 18](#ContextMenuView-Example-18)**
πŸ’­ **Summary**: Icon Example β€” An example showing a context menu with action items that has icons that uses local image assets imported via `require(...)`. | +| πŸ“Œ **[`ContextMenuView` Example 19](#ContextMenuView-Example-19)**
πŸ’­ **Summary**: Dynamic Menu β€” An example showing a context menu that has a loading indicator using deferred menu elements. | +| πŸ“Œ **[`ContextMenuView` Example 20](#ContextMenuView-Example-20)**
πŸ’­ **Summary**: Dynamic Menu β€” An example showing a state-controlled context menu that shows a loading indicator using deferred menu elements. | +| πŸ“Œ **[`ContextMenuView` Example 21](#ContextMenuView-Example-21)**
πŸ’­ **Summary**: Menu Element Size β€” TBA | +| πŸ“Œ **[`ContextMenuView` Example 22](#ContextMenuView-Example-22)**
πŸ’­ **Summary**: Menu Element Size β€” TBA | +| πŸ“Œ **[`ContextMenuView` Example 23](#ContextMenuView-Example-23)**
πŸ’­ **Summary**: Menu Element Size β€” TBA | +| πŸ“Œ **[`ContextMenuView` Example 24](#ContextMenuView-Example-24)**
πŸ’­ **Summary**: Menu Attributes β€” `keepsMenuPresented` | +| πŸ“Œ **[`ContextMenuView` Example 25](#ContextMenuView-Example-25)**
πŸ’­ **Summary**: Icon Example β€” Advanced customization (E.g. `scale`, `weight`, `paletteColors`, `hierarchicalColor`). | +| πŸ“Œ **[`ContextMenuView` Example 26](#ContextMenuView-Example-26)**
πŸ’­ **Summary**: Icon Example β€” Network/Remote images as icons. | +| πŸ“Œ **[`ContextMenuView` Example 27](#ContextMenuView-Example-27)**
πŸ’­ **Summary**: Icon Example β€” Network/Remote images as icons + fallback image. | +| πŸ“Œ **[`ContextMenuView` Example 28](#ContextMenuView-Example-28)**
πŸ’­ **Summary**: Programmatically shows the context menu. | +| πŸ“Œ **[`ContextMenuView` Auxiliary Preview - Example 01](#ContextMenuView-Auxiliary-Preview---Example-01)**
πŸ’­ **Summary**: TBA | +| πŸ“Œ **[`ContextMenuView` Auxiliary Preview - Example 02](#ContextMenuView-Auxiliary-Preview---Example-02)**
πŸ’­ **Summary**: TBA | +| πŸ“Œ **[`ContextMenuView` Auxiliary Preview - Example 03](#ContextMenuView-Auxiliary-Preview---Example-03)**
πŸ’­ **Summary**: TBA | +| πŸ“Œ **[`ContextMenuView` Auxiliary Preview - Example 04](#ContextMenuView-Auxiliary-Preview---Example-04)**
πŸ’­ **Summary**: TBA | +| πŸ“Œ **[`ContextMenuView` Auxiliary Preview - Example 05](#ContextMenuView-Auxiliary-Preview---Example-05)**
πŸ’­ **Summary**: TBA | +| πŸ“Œ **[`ContextMenuView` Auxiliary Preview - Example 06](#ContextMenuView-Auxiliary-Preview---Example-06)**
πŸ’­ **Summary**: TBA | +| πŸ“Œ **[`ContextMenuView` Auxiliary Preview - Example 07](#ContextMenuView-Auxiliary-Preview---Example-07)**
πŸ’­ **Summary**: TBA | +| πŸ“Œ **[`ContextMenuView` Auxiliary Preview - Example 08](#ContextMenuView-Auxiliary-Preview---Example-08)**
πŸ’­ **Summary**: TBA | +| πŸ“Œ **[`ContextMenuView` Auxiliary Preview - Example 09](#ContextMenuView-Auxiliary-Preview---Example-09)**
πŸ’­ **Summary**: TBA | +| πŸ“Œ **[`ContextMenuView` Auxiliary Preview - Example 10](#ContextMenuView-Auxiliary-Preview---Example-10)**
πŸ’­ **Summary**: TBA | +| πŸ“Œ **[`ContextMenuView` Auxiliary Preview - Example 11](#ContextMenuView-Auxiliary-Preview---Example-11)**
πŸ’­ **Summary**: TBA | +| πŸ“Œ **[`ContextMenuView` Auxiliary Preview - Example 12](#ContextMenuView-Auxiliary-Preview---Example-12)**
πŸ’­ **Summary**: TBA | +| πŸ“Œ **[`ContextMenuView` Auxiliary Preview - Example 13](#ContextMenuView-Auxiliary-Preview---Example-13)**
πŸ’­ **Summary**: TBA | +| πŸ“Œ **[`ContextMenuView` Auxiliary Preview - Example 14](#ContextMenuView-Auxiliary-Preview---Example-14)**
πŸ’­ **Summary**: TBA | +| πŸ“Œ **[`ContextMenuView` Auxiliary Preview - Example 15](#ContextMenuView-Auxiliary-Preview---Example-15)**
πŸ’­ **Summary**: TBA | +| πŸ“Œ **[`ContextMenuView` Auxiliary Preview - Example 16](#ContextMenuView-Auxiliary-Preview---Example-16)**
πŸ’­ **Summary**: Programmatically shows the auxiliary preview as a popover (w/o showing the context menu). | +| πŸ“Œ **[`ContextMenuButton` Example 01](#ContextMenuButton-Example-01)**
πŸ’­ **Summary**: TBA | +| πŸ“Œ **[`ContextMenuButton` Example 02](#ContextMenuButton-Example-02)**
πŸ’­ **Summary**: TBA | + +

+ +### Acknowledgements + +Development and maintenance of this library was generously sponsored by [beatgig](https://beatgig.com/) from `11/15/2023` to ` 04/30/2024` at `$1,535`/month (totaling β‰ˆ `$9,100` over the course of 6 months) πŸ₯πŸŽΈ + +
+ +The initial fabric rewrite (i.e. version `3.x`) was made possible through a generous `$3,750` sponsorship by [natew](https://github.com/natew) + [tamagui](https://github.com/tamagui/tamagui) over the course of 4 months (from: `05/27/24` to `09/30/24`) 🐦✨ + +
+ +very special thanks to: [junzhengca](https://github.com/junzhengca), [brentvatne](https://github.com/brentvatne), [expo](https://github.com/expo), [EvanBacon](https://github.com/EvanBacon), [corasan](https://github.com/corasan), [lauridskern](https://github.com/lauridskern), [ronintechnologies](https://github.com/ronintechnologies), and [gerzonc](https://github.com/gerzonc) for becoming a monthly sponsor, and thank you [fobos531](https://github.com/fobos531) for being a one time sponsor πŸ₯Ί (if you have the means to do so, please considering sponsoring [here](https://github.com/sponsors/dominicstop)) + +

+ +## A. Introduction + +A react native component to use [`UIMenu`](https://developer.apple.com/documentation/uikit/uimenu) on iOS 13 and later. + +
+ +### Gifs and Demos + +πŸ“ **Note**: These gifs are from an older version of the library running on iOS 13 (see [Usage And Examples](#e-usage-and-examples) section for updated example gifs).
+ +`ContextMenuView` Examples, **Left**: [Example 1](#ContextMenuView-Example-01), [Example 2](#ContextMenuView-Example-02), and **Right**: [Example 3](#ContextMenuView-Example-03), [Example 4](#ContextMenuView-Example-04) +![Simple Example 1 to 4 Gifs](./assets/montage-ContextMenuView-Example-old-1-2-3-4.gif) + +`ContextMenuView` examples, **Left**: [Example 5](#ContextMenuView-Example-05), [Example 6](#ContextMenuView-Example-06), and **Right**: [Example 7](#ContextMenuView-Example-07), [Example 8](#ContextMenuView-Example-08) +![Simple Example 5 to 8 Gifs](./assets/montage-ContextMenuView-Example-old-5-6-7-8.gif) + +`ContextMenuView` example, **Left**: [Example 9](#ContextMenuView-Example-09), and **Right**: [Example 10](#ContextMenuView-Example-10) +![Simple Example 9 and 8 Gifs](./assets/montage-ContextMenuView-Example-old-9-10.gif) + +`ContextMenuView` examples, **Left**: [Example 11](#ContextMenuView-Example-11), [Example 12](#ContextMenuView-Example-12), and **Right**: [Example 13](#ContextMenuView-Example-13), [ Example 14](#ContextMenuView-Example-14) +![Simple Example 11 to 14 Gifs](./assets/montage-ContextMenuView-Example-old-11-12-13-14.gif) + +`ContextMenuView` examples, **Left**: [Example 15](#ContextMenuView-Example-15), [Example 16](#ContextMenuView-Example-16), and **Right**: [Example 17](#ContextMenuView-Example-17), [Example 18](#ContextMenuView-Example-18) +![Simple Example 11 to 14 Gifs](./assets/montage-ContextMenuView-Example-old-15-16-17-18.gif) + +`ContextMenuView` tests, **Left**: [Test 1](PLACE_HOLDER_LINK), and **Right**: [Test 2](PLACE_HOLDER_LINK) +![Context Menu View Test 1 and 2 Gifs](./assets/montage-ContextMenuView-Test-old-01-02.gif) + +`ContextMenuView` tests, **Left**: [Test 3](PLACE_HOLDER_LINK), and **Right**: [Test 4](PLACE_HOLDER_LINK) +![Context Menu View Test 3 and 4 Gifs](./assets/montage-ContextMenuView-Test-old-03-04.gif) + +`ContextMenuView` tests, **Left**: [Test 5](PLACE_HOLDER_LINK), and **Right**: [Test 6](PLACE_HOLDER_LINK) +![Context Menu View Test 5 and 6 Gifs](./assets/montage-ContextMenuView-Test-old-05-06.gif) + +`ContextMenuView` tests, **Left/Right:** [Test 7](PLACE_HOLDER_LINK) +![Context Menu View 7 Gifs](./assets/montage-ContextMenuView-Test-old-07.gif) + +`ContextMenuView` `ActionSheetIOS` fallback for simple example 1 to 9 +![Action Sheet Fallback for Simple Example 1 to 9 Gifs](./assets/montage-ContextMenuView-ActionSheetFallback-Example-old-1-to-9.gif) + +`ContextMenuView` `ActionSheetIOS` fallback for context menu view test 1 to 6 (removed in `v3.x`+). +![Action Sheet Fallback for Context Menu View Test 1 to 6 Gifs](./assets/montage-ContextMenuView-ActionSheetFallback-Test-old-1-to-6.gif) + +`ContextMenuButton` examples, **Left**: [Example 1](#ContextMenuButton-Example-01), and **Right**: [Example 2](#ContextMenuButton-Example-02) +![Simple Example 1 and 2 Gifs](./assets/montage-ContextMenuButton-Example-old-1-2.gif) + +
+ +### Features + +* Support for creating menu actions and submenus (i.e. nested and in-line menus). +* Support for customizing the menu icons (i.e. support for SF Symbols, `require(image)`, and `xcasset` icons, icon tint, etc). +* Extensive support for SF Symbols configuration (e.g. `pointSize`, `weight`, `scale`, `hierarchicalColor`, `paletteColors`). +* Support for iOS 14 functionality (like the `UIButton` context menu, dynamically updating the menu while it's visible, etc). +* Support for setting (almost) all of the native [`UIMenu`](https://developer.apple.com/documentation/uikit/uimenu) and οΏΌ[`UIAction`](https://developer.apple.com/documentation/uikit/uiaction) properties (e.g. `UIMenuElementState`, `MenuElementAtrributes`, `discoverabilityTitle`, etc.) +* Basic `ActionSheetIOS` menu fallback for iOS 12 and below (removed in `v3.x`+). +* Support for creating custom context menu previews (with support for dynamic or fixed preview sizes, setting the [`UIPreviewParameters`](https://developer.apple.com/documentation/uikit/uipreviewparameters), specifying a [`UITargetedPreview`](https://developer.apple.com/documentation/uikit/uitargetedpreview), etc). +* Support for custom auxiliary previews (experimental). +* Support for deferred context menu items. + +

+ +## B. Installation + +```sh +# 1. install library + dependencies +npm install react-native-ios-utilities@next +npm install react-native-ios-context-menu@next + +# 2. then run pod install (uses auto-linking) +cd ios && pod install +``` + +
+ +πŸ“ **Note A**: You might encounter some build errors since this library is written in swift, so there's some extra step involved to use this library (see table below for reference). + +
πŸ“ **Note B**: If you want to use an older or different version of this library, please refer to [versions section](#versions)'s compatibility table. + +| Additional Steps | +| :----------------------------------------------------------- | +| 1️⃣ [Add an empty swift file to your project](#troubleshooting-xcode-build-error-swift) | +| 2️⃣ [Update the project's "Library Search Paths" build settings](#troubleshooting-xcode-build-error-undefined-symbol) | + +
+ +### Installation (Experimental Version) + +```sh +# 1. install library + dependencies +npm install react-native-ios-utilities@next +npm install react-native-ios-context-menu@next + + +# 2. then run pod install (uses auto-linking) +cd ios && pod install +``` + +
+ +### Updating + +This library has cocoapods dependency to [`ContextMenuAuxiliaryPreview`](https://github.com/dominicstop/ContextMenuAuxiliaryPreview) and [`DGSwiftUtilities`](https://github.com/dominicstop/DGSwiftUtilities), so you may need to update them separately (as needed). + +```sh +# A. Either update this specific pod... +pod update ContextMenuAuxiliaryPreview DGSwiftUtilities +pod install --repo-update + +# B. Or update all the pods +pod update +``` + +
+ +### Expo + +- βœ… You can use this library with [Development Builds](https://docs.expo.dev/development/introduction/). No config plugin is required. +- ❌ This library can't be used in the "Expo Go" app because it [requires custom native code](https://docs.expo.dev/workflow/customizing/). + +
+ +### Versions and Dependencies + +| Library Version | Dependencies + Versions | +| --------------- | ------------------------------------------------------------ | +| `2.0.x` | `react-native-ios-utilities` - `4.x` | +| `2.1.x` | `react-native-ios-utilities` - `4.x`
`ContextMenuAuxiliaryPreview` - `0.1.x` | +| `2.2.x` | `react-native-ios-utilities` - `4.x`
`ContextMenuAuxiliaryPreview` - `0.2.x` | + +
+ +### Troubleshooting + +If you encounter any errors/bugs while using this library, or want a particular feature implemented, please create an issue (my inbox is a mess, please feel free to tag me). ✨ + +
+ +#### Troubleshooting: Xcode Build Error (Swift) + +πŸ“ **Note**: This library is written in swift. If you are having trouble building your app after installing this library, try adding an empty swift file to your project: + +1. Open up your `ios/project.xcworkspace` project +2. On the project navigator panel (located on the right side of Xcode), right click on your project group (or another folder/group i.e the blue or yellow icons) and select the "*New File...*" option +3. In the popup sheet, select "Swift" as the template and then click the "*Next*" button +4. A "*Save As*" popup sheet should appear and then click "*Create*" (you can rename the file first if you want to) +5. If Xcode asks you to create a "*Objective-C Bridging Header*" choose *"Create Objective-C Bridging Header"* + +
+ +#### Troubleshooting: Xcode Build Error (Undefined symbol) + +When installing this library on Xcode 12+, you'll get the following error in Xcode: + +![Xcode linking build error](./assets/installation-troubleshooting-00.png) + +``` +Undefined symbol: (extension in UIKit): +__C.UIMenu.init(title: Swift.String, image: __C.UIImage?, identifier: __C.UIMenuIdentifier?, options: __C.UIMenuOptions, children: [__C.UIMenuElement]) -> __C.UIMenu + +Undefined symbol: (extension in UIKit): +__C.UIAction.init(title: Swift.String, image: __C.UIImage?, identifier: __C.UIActionIdentifier?, discoverabilityTitle: Swift.String?, attributes: __C.UIMenuElementAttributes, state: __C.UIMenuElementState, handler: (__C.UIAction) -> ()) -> __C.UIAction +``` + +
+ +To fix this, see screenshot + follow the steps below: + +![Xcode - Remove library search paths](./assets/installation-troubleshooting-01-A.png) + +
+ +1. Open your `ios/project.xcworkspace` project. +2. In the project navigator panel (located on the right side of Xcode), select your project group (i.e. the item with the blueprint icon). +3. The Xcode project editor should appear. In the left panel, under the "Project" section, select your project (if it isn't already selected). +4. In the project section's top tab bar, select the "Build Settings" tab (also make sure the "All" and "Combined" tabs are selected). +5. In the project navigator list, under the "Search Path" section, there should be a "Library Search Paths" setting (alternatively, you can search for "Library Search Paths" in the search bar). +6. According to this [issue comment](https://github.com/facebook/react-native/issues/29246#issuecomment-667518920), you can clear all the items listed in the "Library Search Paths" setting by selecting the items in the list, and pressing the "-" button in the popover. + * **TLDR**: Xcode automatically manages this setting, and the RN template hardcodes it to use Swift 5.0. + * Alternatively, you can change the entry `"$(TOOLCHAIN_DIR)/usr/lib/swift-5.0/$(PLATFORM_NAME)"` to `"$(TOOLCHAIN_DIR)/usr/lib/swift-5.3/$(PLATFORM_NAME)"` i.e. change `swift-5.0` to `swift-5.3`, or whatever the newest version of swift that comes with your Xcode installation (to show the popup dialog, double click the value/item). +7. If you haven't already, make sure to create an empty swift file. Then clean the build folder (the option is in the menu bar under: "Product" -> "Clean Build Folder") and try building your project again. +8. If you are still having problems building the app, try the following and build your project again: + * Try clearing out Xcode's `derivedData` directory: `rm -rf ~/Library/Developer/Xcode/DerivedData/*` (check out this [gist](https://gist.github.com/maciekish/66b6deaa7bc979d0a16c50784e16d697) for instructions on how to clean up Xcode) + * Try clearing out the `Cocoapods` cache: `rm -rf "${HOME}/Library/Caches/CocoaPods"` (and then try running `pod install` again). + +
+ +![Xcode - Remove library search paths](./assets/installation-troubleshooting-01-B.png) + +
+ +**Explanation**: Some versions of the react-native template hard codes the swift library search paths to use swift `5.0` (which causes the linker to mismatch the swift system libraries bundled with your Xcode + iOS/Simulator installation). + +Here are some related issues in the RN repo: [Issue 30202](https://github.com/facebook/react-native/pull/30202) and [Issue 29178](https://github.com/facebook/react-native/pull/29178). + +

+ +## C. Basic Usage + +For more examples, check out the [Usage And Examples](#e-usage-and-examples) section. + +
+ +[πŸ”— Full Example](example/src/examples/BasicUsageExample01.tsx) + +```jsx +import * as React from 'react'; +import { StyleSheet, Text } from 'react-native'; + +import { ContextMenuView } from 'react-native-ios-context-menu'; + +export function BasicUsageExample01() { + return ( + + + Press And Hold To Show Context Menu + + + ); +}; + +const styles = StyleSheet.create({ + container: { + margin: 10, + padding: 10, + }, + text: { + fontSize: 16, + }, +}); +``` + +

+ ## D. Documentation πŸ’‘ **Tip**: Most of the time, when a type or component is mentioned, you can click it to jump to that item in the README (or its declaration in the source code). @@ -666,3 +1037,3157 @@ TBA

+## E. Usage And Examples + +### `ContextMenuView` Example 01 + +**Summary**: A basic context menu that has 3 menu action items (e.g. "Action #1", "Action #2", and "Action #3"). + +
+ +| Notes | +| :----------------------------------------------------------- | +| 1️⃣ β€” The `ContextMenuView.menuConfig` prop accepts an optional `MenuConfig` object.
This object will be used to create and configure the context menu. | +| 2️⃣ β€” You can set the context menu title via passing a string value to the `MenuConfig.menuTitle` property.

πŸ“ **Note**: You can pass an empty string if you don't want a title to appear on top your context menu. | +| 3️⃣ β€” To populate the context menu with action items, you can pass a `MenuActionConfig` object in the `MenuConfig.menuItems` property.

πŸ“ **Note A**: The `MenuConfig.menuItems` property can accept an array of a `MenuElementConfig` union type.

To be more specific, the `menuItems` property can accept an array containing any of the following object types: `MenuConfig` object, `MenuActionConfig`, and `DeferredMenuElementConfig`.

πŸ“ **Note B**: If you pass in a `MenuConfig` object in the `MenuConfig.menuItems` property, it means that you want to create a submenu. See [`ContextMenuView` Example 03](#ContextMenuView-Example-03) for more details.

πŸ“ **Note C**: If you pass in a `DeferredMenuElementConfig` object in the `MenuConfig.menuItems` property, it means that you want to create a deferred menu item (i.e. a menu item that has a loading indicator). See [`ContextMenuView` Example 19](#ContextMenuView-Example-19) for more details. | +| 4️⃣ β€” A `MenuActionConfig` object represents an action item in the context menu (e.g. copy, paste, delete, etc).

As such, if you pass in a `MenuActionConfig` object to `MenuConfig.menuItems`, it means that you want to create a context menu action.

πŸ“ **Note A**: The `MenuActionConfig.actionKey` property serves as a unique identifier for your menu action. If you have multiple menu actions, the `actionKey` will help you differentiate them.

πŸ“ **Note B**: You will receive the value you passed in `MenuActionConfig.actionKey` in the `ContextMenuView.onPressMenuItem` event (i.e. via the `nativeEvent` object). | +| 5️⃣ β€” You can use the `ContextMenuView.onPressMenuItem` event prop to get notified whenever a menu action item has been selected.

The function you pass to the `onPressMenuItem` prop will receive a `OnPressMenuItemEventObject` object.

πŸ“ **Note A**: Details about the selected menu action item can be accessed via the `OnPressMenuItemEventObject.nativeEvent` object.

E.g. `OnPressMenuItemEventObject``.nativeEvent.actionKey`.

πŸ“ **Note B**: If `ContextMenuView.shouldWaitForMenuToHide`
`BeforeFiringOnPressMenuItem` prop is set to `true` (which it is by default), then this event will fire after the `onMenuDidHide` event is triggered. | + +
+ +[πŸ”— Full Example](./example/srcexamples/ContextMenuViewExample01.tsx) + +```jsx +// πŸ“ Note: for the sake of brevity, some of the code is omitted... +import { ContextMenuView } from 'react-native-ios-context-menu'; + +export function ContextMenuViewExample01(props) { + return ( + { + Alert.alert( + 'onPressMenuItem Event', + `actionKey: ${nativeEvent.actionKey} - actionTitle: ${nativeEvent.actionTitle}` + ); + }} + > + {/** Components */} + + ); +}; +``` + +![screenshot](./assets/example-ContextMenuViewExample01-old.png) + +![Gif](./assets/example-ContextMenuViewExample01.gif) + +
+ +### `ContextMenuView` Example 02 + +**Summary**: Icon Example β€” This examples shows how to add a system icon in the context menu action. + +
+ +| Notes | +| ------------------------------------------------------------ | +| 1️⃣ β€” A menu action (i.e. `MenuActionConfig` object) can be configured to show an icon via its `MenuActionConfig.icon` property.

πŸ“ **Note A**: The `icon` property accepts a `ImageItemConfig` object.

πŸ“ **Note B**: A `ImageItemConfig` object is used to describe images/assets (e.g. SF Symbols icons, images, xcasset images, programmatic images, etc). | +| 2️⃣ β€” In this example, we want to use a "SF Symbols" icon for the menu action.

In order to do this, the `ImageItemConfig.type` property must be set to `"IMAGE_SYSTEM"`.

πŸ“ **Note A**: Passing in a value of `"IMAGE_SYSTEM"` to the `type` property means that we want to create a "SF Symbols" system icon.

πŸ“ **Note B**: Using a "SF Symbols" icon requires iOS 13+.

πŸ“ **Note C**: Via the `ImageItemConfig` object, you can also configure the context menu action to use other icons (e.g. `xcasset` items, images, gradients, solid colors, etc).

πŸ“ **Note D**: You can apply a tint to the icon via the `ImageItemConfig.imageOptions` property using the `UIImageConfig.tint` and `UIImageConfig.renderingMode` property. See [`ContextMenuView` Example 17](#ContextMenuView-Example-17) for more details. | +| 3️⃣ β€” In order to configure what kind of "SF Symbols" icon we want to use for the menu action, we need to pass in a `ImageSystemConfig` object to the `ImageItemConfig.imageValue` property.

We can set what kind of icon to use via passing a string value to the `ImageSystemConfig.systemName` property.

πŸ“ **Note A**: An `ImageSystemConfig` object is used to generate a "SF Symbols" image. Using this configuration object, we can optionally customize the "SF Symbols" icon further via the following properties: `pointSize`, `weight`, `scale`, `hierarchicalColor`, `paletteColors`, etc.

πŸ“ **Note B**: The string value passed to the `ImageSystemConfig.systemName` property must be a valid SF Symbols name.

πŸ“ **Note C**: To view the list of SF Symbols icons (along with their corresponding icon names), you'll need to download the SF Symbols Mac app from [this page](https://developer.apple.com/design/human-interface-guidelines/sf-symbols/overview/). | + +
+ +[πŸ”— Full Example](./example/srcexamples/ContextMenuViewExample02.tsx) + +```jsx +// πŸ“ Note: for the sake of brevity, some of the code is omitted... +import { ContextMenuView } from 'react-native-ios-context-menu'; + +export function ContextMenuViewExample02(props) { + return ( + + {/** Components */} + + ); +}; +``` + +![screenshot](./assets/example-ContextMenuViewExample02-old.png) + +![Gif](./assets/example-ContextMenuViewExample02.gif) + +
+ +### `ContextMenuView` Example 03 + +**Summary**: Nested Menu β€” This example shows a context menu that has a submenu item inside its list of menu actions. + +
+ +| Notes | +| ------------------------------------------------------------ | +| 1️⃣ β€” A context menu supports having nested menu's (i.e. submenu's).

A submenu is basically just another menu with it's own separate list of menu actions. Tapping it will show another context menu (visually this is similar to a dropdown menu). | +| 2️⃣ β€” As mentioned in the earlier examples, the `MenuConfig.menuItems` property can accept a `MenuActionConfig` object, or a `MenuConfig` object.

Passing in a `MenuActionConfig` object to `MenuConfig.menuItems` makes a menu action, conversely passing in a `MenuConfig` object will create a submenu item.

In other words, to make a submenu, you just need to pass a `MenuConfig` item in the `MenuConfig.menuItems` property.

πŸ“ **Note**: You can nest as many submenu's you want (but just remember that having more than 3 nested submenus is considered bad UX). | + +
+ +[πŸ”— Full Example](./example/srcexamples/ContextMenuViewExample03.tsx) + +```jsx + // πŸ“ Note: for the sake of brevity, some of the code is omitted... +import { ContextMenuView } from 'react-native-ios-context-menu'; + +export function ContextMenuViewExample03(props) { + return ( + + {/** Components */} + + ); +}; +``` + +![screenshot](./assets/example-ContextMenuViewExample03-old.png) + +![Gif](./assets/example-ContextMenuViewExample03.gif) + +
+ +### `ContextMenuView` Example 04 + +**Summary**: Menu Attributes β€” This example context menu showcases the `MenuActionConfig.menuAttributes` property. + +
+ +| Notes | +| ------------------------------------------------------------ | +| 1️⃣ β€” The `MenuActionConfig.menuAttributes` property accepts an array of strings (i.e. an array of `MenuAttributes` items).

In this example, the context menu has 3 actions, each with a different menu attribute assigned to it.

The first menu action is a "disabled" action, i.e. it has it's `menuAttributes` set to `['disabled']`, causing the action title text and icon becomes greyed out. | +| 2️⃣ β€” The second menu action is a destructive action.

It has it's `menuAttributes` set to `['destructive']`, causing the action title text and icon becomes red. | +| 3️⃣ β€” The third menu action is a "hidden" action. It has it's `menuAttributes` set to `['hidden']`.

The menu action is not visible in the menu's list of actions. This is useful for temporarily hiding a menu action item. | +| 4️⃣ β€” The fourth menu action is a "disabled" + "destructive" action.
Visually, it looks very similar to an action that has the `['disabled']` attribute. | + +
+ +[πŸ”— Full Example](./example/srcexamples/ContextMenuViewExample04.tsx) + +```jsx + // πŸ“ Note: for the sake of brevity, some of the code is omitted... +import { ContextMenuView } from 'react-native-ios-context-menu'; + +export function ContextMenuViewExample04(props) { + return ( + + {/** Components */} + + ); +}; +``` + +![screenshot](./assets/example-ContextMenuViewExample04-old.png) + +![Gif](./assets/example-ContextMenuViewExample04.gif) + +
+ +### `ContextMenuView` Example 05 + +**Summary**: Nested Menu + Menu Attributes β€” A context menu that has a in-line submenu. + +
+ +| Notes | +| ------------------------------------------------------------ | +| You can set the menu options via the `MenuConfig.menuOptions` property. It accepts an array of `UIMenuOptions` strings (e.g. `'destructive'`, `'displayInline'`).

If you pass in `['displayInline']` to `menuOptions`, the submenu will be added/combined to its parent menu, but with a small separator between them. | + +
+ +[πŸ”— Full Example](./example/srcexamples/ContextMenuViewExample05.tsx) + +```jsx + // πŸ“ Note: for the sake of brevity, some of the code is omitted... +import { ContextMenuView } from 'react-native-ios-context-menu'; + +export function ContextMenuViewExample05(props) { + return ( + + {/** Components */} + + ); +}; +``` + +![screenshot](./assets/example-ContextMenuViewExample05-old.png) + +![Gif](./assets/example-ContextMenuViewExample05.gif) + +
+ +### `ContextMenuView` Example 06 + +**Summary**: Menu Options β€” A context menu that has a destructive submenu. + +
+ +| Notes | +| ------------------------------------------------------------ | +| You can set the menu options via the `MenuConfig.menuOptions` property. It accepts an array of `UIMenuOptions` strings (e.g. `destructive`, `displayInline`).

If you pass in `['destructive']` to `menuOptions`, it will tint the submenu to red (but it's menu items won't be affected). | + +
+ +[πŸ”— Full Example](./example/srcexamples/ContextMenuViewExample06.tsx) + +```jsx + // πŸ“ Note: for the sake of brevity, some of the code is omitted... +import { ContextMenuView } from 'react-native-ios-context-menu'; + +export function ContextMenuViewExample06(props) { + return ( + + {/** Components */} + + ); +}; +``` + +![screenshot](./assets/example-ContextMenuViewExample06-old.png) + +![Gif](./assets/example-ContextMenuViewExample06.gif) + +
+ +### `ContextMenuView` Example 07 + +**Summary**: Menu Options β€” A context menu that set to be both "destructive" and "display in-line". + +
+ +| Notes | +| ------------------------------------------------------------ | +| You can set the menu options via the `MenuConfig.menuOptions` property. It accepts an array of `UIMenuOptions` strings (e.g. `destructive`, `displayInline`).

Passing in `['destructive', 'displayInline']` to `menuOptions`, is functionally the same as passing in `['displayInline']`. | + +
+ +[πŸ”— Full Example](./example/srcexamples/ContextMenuViewExample07.tsx) + +```jsx + // πŸ“ Note: for the sake of brevity, some of the code is omitted... +import { ContextMenuView } from 'react-native-ios-context-menu'; + +export function ContextMenuViewExample07(props) { + return ( + + {/** Components */} + + ); +}; +``` + +![screenshot](./assets/example-ContextMenuViewExample07-old.png) + +![Gif](./assets/example-ContextMenuViewExample07.gif) + +
+ +### `ContextMenuView` Example 08 + +**Summary**: Menu State β€” A context menu with 3 actions that has `'on'`, `'off'`, and `'mixed'` `menuState`. + +
+ +| Notes | +| ------------------------------------------------------------ | +| You can set an menu action item's the menu state via the `MenuActionConfig.menuState` property.

πŸ“ **Note**: On iOS 13, an action item's menu state is indicated via changing it's icon to a checkmark. However on later version of iOS this behavior has been changed to showing a checkmark besides the action title (see gifs/screenshots below). | + +
+ +[πŸ”— Full Example](./example/srcexamples/ContextMenuViewExample08.tsx) + +```jsx + // πŸ“ Note: for the sake of brevity, some of the code is omitted... +import { ContextMenuView } from 'react-native-ios-context-menu'; + +export function ContextMenuViewExample08(props) { + return ( + + {/** Components */} + + ); +}; +``` + +![screenshot](./assets/example-ContextMenuViewExample08-old.png) + +![Gif](./assets/example-ContextMenuViewExample08.gif) + +
+ +### `ContextMenuView` Example 09 + +**Summary**: Events β€” An example for the `onPressMenuItem` event prop. + +| Notes | +| ------------------------------------------------------------ | +| The `onPressMenuItem` event prop allows you to know which menu item was pressed via the `nativeEvent.actionKey` property in the event object.

πŸ“ **Note A**: The entire menu action config (i.e. `MenuActionConfig`) object of the selected item can be accessed via the `nativeEvent` object (e.g. `nativeEvent.actionTitle`, `nativeEvent.menuState`, etc).

πŸ“ **Note B**: For the full type declaration for all the events, see: [`MenuEvents.ts`](./src/types/MenuEvents.ts). | + +
+ +[πŸ”— Full Example](./example/srcexamples/ContextMenuViewExample09.tsx) + +```jsx + // πŸ“ Note: for the sake of brevity, some of the code is omitted... +import { ContextMenuView } from 'react-native-ios-context-menu'; + +export function ContextMenuViewExample09(props) { + return ( + { + switch (nativeEvent.actionKey) { + case 'save': + Alert.alert('saving...'); + break; + + case 'like': + Alert.alert('liking...'); + break; + + case 'play': + Alert.alert('playing...'); + break; + }; + }} + > + {/** Components */} + + ); +}; +``` + +![screenshot](./assets/example-ContextMenuViewExample09-old.png) + +![Gif](./assets/example-ContextMenuViewExample09.gif) + +
+ +### `ContextMenuView` Example 10 + +**Summary**: Dynamic Menu β€” An example showing how to dynamically update the context menu while it's visible. In this example, the menu action changes every time the counter increments every second. + +
+ +| Notes | +| ------------------------------------------------------------ | +| On iOS 14+ you can update the menu while it's visible, e.g. like adding and removing items in the context menu, or changing the action title, etc.

You can control the context menu config using state, and dynamically change it as shown in the example below.

πŸ“ **Note A**: On iOS 13 the context menu will not update while it's visible.

πŸ“ **Note B**: On iOS 15+, all changes to the context menu config are applied using a fade/crossfade transition. | + +
+ +[πŸ”— Full Example](./example/srcexamples/ContextMenuViewExample10.tsx) + +```jsx + // πŸ“ Note: for the sake of brevity, some of the code is omitted... +export function ContextMenuViewExample10(props) { + // `timer` will increment every second... + const [timer, setTimer] = React.useState(0); + + // ... + return ( + + {/** Components */} + + ); +}; +``` + +![screenshot](./assets/example-ContextMenuViewExample10-old.png) + +![Gif](./assets/example-ContextMenuViewExample10.gif) + +
+ +### `ContextMenuView` Example 11 + +**Summary**: Context Menu Previews β€” An example showing how to use a custom preview for the context menu. + +
+ +| Notes | +| ------------------------------------------------------------ | +| 1️⃣ β€” The `ContextMenuView.renderPreview` render prop allows you show a custom preview when the context menu appears.

πŸ“ **Note**: The `renderPreview` prop accepts a function that returns an element. The returned element will be shown inside the context menu preview. | +| 2️⃣ β€” The `ContextMenuView.previewConfig` is used to control the behavior and appearance of the custom context menu preview.

In order to show the custom context menu preview, we must first set `MenuPreviewConfig.previewType` to `'CUSTOM'`. By default, this property is set to `'DEFAULT'`, which means that you do not want to use a custom preview.

πŸ“ **Note A**: The `previewConfig` prop accepts a `MenuPreviewConfig` object.

πŸ“ **Note B**: The `previewType` property accepts a `MenuPreviewType` string. You can set this to `'DEFAULT'` if you want to quickly disable the custom preview. | +| 3️⃣ β€” In this example, we want the custom preview to be as big as possible, so we set the `MenuPreviewConfig.previewSize` property to `'STRETCH'`.

πŸ“ **Note**: The `previewSize` property accepts a `MenuPreviewSize` string. By default, this prop is set to `'INHERIT'`, which means to just match the size of the root view returned from `renderPreview`. | + +
+ +[πŸ”— Full Example](./example/srcexamples/ContextMenuViewExample11.tsx) + +```jsx + // πŸ“ Note: for the sake of brevity, some of the code is omitted... +import { ContextMenuView } from 'react-native-ios-context-menu'; + +export function ContextMenuViewExample11(props) { + return ( + ( + + + Hello World + + + Hello World + + + Hello World + + + )} + onPressMenuPreview={() => { + Alert.alert( + 'onPressMenuPreview Event', + `Menu preview was pressed...` + ); + }} + > + {/** Components */} + + ); +}; +``` + +![screenshot](./assets/example-ContextMenuViewExample11-old.png) + +![Gif](./assets/example-ContextMenuViewExample11.gif) + +
+ +### `ContextMenuView` Example 12 + +**Summary**: Context Menu Previews β€” An example showing a custom context menu preview that dynamically changes its size due to its contents updating every second. + +
+ +| Notes | +| ------------------------------------------------------------ | +| πŸ“ **Note**: By default, custom preview will animate to its new size. If you want to disable this behavior, set `MenuPreviewConfig.isResizeAnimated` property to `false`. | + +
+ +[πŸ”— Full Example](./example/srcexamples/ContextMenuViewExample12.tsx) + +```jsx + // πŸ“ Note: for the sake of brevity, some of the code is omitted... + +export function ContextMenuViewExample12(props) { + // increments every second... + const [timer, setTimer] = React.useState(0); + + // ... + return ( + ( + + + {`Counter: ${timer}`} + + + {(timer % 2 === 0)? 'EVEN' : 'The number is: ODD'} + + + )} + // ... + > + {/** Components */} + + ); +}; +``` + +![screenshot](./assets/example-ContextMenuViewExample12-old.png) + +![Gif](./assets/example-ContextMenuViewExample12.gif) + +
+ +### `ContextMenuView` Example 13 + +**Summary**: Menu Action β€” An example showing how to add a subtitle to menu action. + +
+ +| Notes | +| ------------------------------------------------------------ | +| You can add a subtitle to a menu action via passing a string value to the `MenuActionConfig.actionSubtitle` property.

πŸ“ **Note A**: On iOS 13/14, you add subtitles to the menu action via the `MenuActionConfig.discoverabilityTitle` property, but on iOS 15+ this property is now used for the "discoverability heads-up display" UI.

πŸ“ **Note B**: For backwards compatibility, the string value you passed to `discoverabilityTitle` will also be used to set `actionSubtitle` on iOS 15+.

To disable this automatic behavior, set the `ContextMenuView.shouldUseDiscoverability` `TitleAsFallbackValueForSubtitle` prop to `false`. | + +
+ +[πŸ”— Full Example](./example/srcexamples/ContextMenuViewExample13.tsx) + +```jsx + // πŸ“ Note: for the sake of brevity, some of the code is omitted... +import { ContextMenuView } from 'react-native-ios-context-menu'; + +export function ContextMenuViewExample13(props) { + return ( + + {/** Components */} + + ); +}; +``` + +![screenshot](./assets/example-ContextMenuViewExample13-old.png) + +![Gif](./assets/example-ContextMenuViewExample13.gif) + +
+ +### `ContextMenuView` Example 14 + +**Summary**: Context Menu Previews β€” An example that changes the exit transition of the context menu preview when its tapped using the `preferredCommitStyleΒ ` config. + +
+ +| Notes | +| ------------------------------------------------------------ | +| The `MenuPreviewConfig.preferredCommitStyle` allows you to configure what preset exit transition to use when the context menu preview is pressed.

πŸ“ **Note A**: By default, `MenuPreviewConfig.preferredCommitStyle` is set to `'dismiss'`.

πŸ“ **Note B**: A `preferredCommitStyle` of `'pop'`' is usually used when navigating to another screen (i.e. a view controller is pushed without the normal push transition). | + +
+ +[πŸ”— Full Example](./example/srcexamples/ContextMenuViewExample14.tsx) + +```jsx + // πŸ“ Note: for the sake of brevity, some of the code is omitted... +export function ContextMenuViewExample14(props) { + return ( + ( + {/** ... */} + )} + > + {/** Components */} + + ); +}; +``` + +![screenshot](./assets/example-ContextMenuViewExample14-old.png) + +![Gif](./assets/example-ContextMenuViewExample14.gif) + +
+ +### `ContextMenuView` Example 15 + +**Summary**: Context Menu Previews β€” An example showing how to configure a context menu that uses targeted previews. + +
+ +| Notes | +| ------------------------------------------------------------ | +| By default, the child elements you render inside the `ContextMenuView` component will be used as the preview when the context menu interaction is triggered.

Targeted previews allows you to specify which specific view to use for the context menu preview, so that when the context menu interaction begins, a different view will be used for the preview (including the initial transition, see the gif below the example code).

πŸ“ **Note A**: The context menu interaction will still be triggered by long pressing on the child elements in the `ContextMenuView` component.

As such, if the view that you are using for the targeted preview is not a child of `ContextMenuView`, then holding down on that view will not trigger the context menu interaction.

πŸ“ **Note B**: Targeted previews is different from setting a [custom context menu preview](#ContextMenuView-Example-11) via the `renderPreview` prop.

A custom preview will replace the contents of the context menu preview entirely with your custom view component once the menu is opened.

A targeted preview on the other hand will change which view to use for the context menu entrance/exit transition (as well as what view to show in the preview if you do not have a custom preview). | + +
+ +[πŸ”— Full Example](./example/srcexamples/ContextMenuViewExample15.tsx) + +```jsx + // πŸ“ Note: for the sake of brevity, some of the code is omitted... +import { ContextMenuView } from 'react-native-ios-context-menu'; + +export function ContextMenuViewExample15(props) { + const [targetViewNode, setTargetViewNode] = React.useState(); + + React.useEffect(() => { + // please note that when a view unmounts and remounts (e.g. + // when you have a view inside a list comp)., you need to + // get the new associated `reactTag` for that view + // + // otherwise the `reactTag` value you provide to the + // `previewConfig` will be stale... + // + // this is why we have to set `targetViewNode` back to + // `udefined` when the component unmounts + return () => { + setTargetViewNode(undefined); + } + }, []); + + return ( + + { + setTargetViewNode(nativeEvent.target) + })} + > + + {`Hello! Target Node: ${targetViewNode}`} + + + + ); +}; +``` + +![screenshot](./assets/example-ContextMenuViewExample15-old.png) + +![Gif](./assets/example-ContextMenuViewExample15.gif) + +
+ +### `ContextMenuView` Example 15-02 + +**Summary**: Context Menu Previews (Cont). β€” An example showing how to configure a context menu that uses targeted previews + `WrapperView`. + +
+ +[πŸ”— Full Example](./example/srcexamples/ContextMenuViewExample15_02.tsx) + +```jsx +// πŸ“ Note: for the sake of brevity, some of the code is omitted... +import { ContextMenuView } from 'react-native-ios-context-menu'; +import { WrapperView } from 'react-native-ios-utilities'; + +export function ContextMenuViewExample15_02(props) { + // save a ref. to the `WrapperView` element containing the preview target you + // want to use for the context menu. + // + // you can then call `getNativeReactTag` to get the associated `reactTag` + // for that view. + const wrapperViewRef = React.useRef(); + + return ( + + + + {`Hello inside: WrapperView\nTarget Node: ${wrapperViewRef.current?.getNativeReactTag()}`} + + + + ); +}; +``` + +![screenshot](./assets/example-ContextMenuViewExample15-02.png) + +
+ +### `ContextMenuView` Example 16 + +**Summary**: Icon Example β€” An example showing a context menu with an action that uses a `'IMAGE_ASSET'` image for its icon. + +
+ +| Notes | +| ------------------------------------------------------------ | +| A config of `ImageItemConfig.type` set to `'IMAGE_ASSET'` means that you want to use a `xcasset` image asset.

πŸ“ **Note**: The string value you pass to the `ImageItemConfig.imageValue` must match the corresponding asset that you want to use in your project's `xcasset` catalog. | + +
+ +[πŸ”— Full Example](./example/srcexamples/ContextMenuViewExample16.tsx) + +```jsx + // πŸ“ Note: for the sake of brevity, some of the code is omitted... +import { ContextMenuView } from 'react-native-ios-context-menu'; + +export function ContextMenuViewExample16(props) { + return ( + + {/** Components */} + + ); +}; +``` + +![screenshot](./assets/example-ContextMenuViewExample16-old.png) + +![Gif](./assets/example-ContextMenuViewExample16.gif) + +
+ +### `ContextMenuView` Example 17 + +**Summary**: Icon Example β€” An example showing a context menu with action items that have different colored icons. + +
+ +| Notes | +| ------------------------------------------------------------ | +| A `ImageItemConfig` object has an optional called `imageOptions`. This property accepts a `UIImageConfig` object.

You can tint the image to a specified color using the `UIImageConfig.tint` property. This property accepts a color string in either `rgb`, `rgba`, or `hex` format.

You can also choose to provide a dynamic color config if you want to use a specific color for light/dark mode.

πŸ“ **Note A**: Any image can be tinted to a specific color, not just `'IMAGE_SYSTEM'` images.

πŸ“ **Note B**: In order for the tint to take effect, set `UIImageConfig.renderingMode` to `alwaysOriginal`. | + +
+ +[πŸ”— Full Example](./example/srcexamples/ContextMenuViewExample17.tsx) + +```jsx + // πŸ“ Note: for the sake of brevity, some of the code is omitted... +import { ContextMenuView } from 'react-native-ios-context-menu'; + +export function ContextMenuViewExample17(props) { + return ( + + {/** Components */} + + ); +}; +``` + +![screenshot](./assets/example-ContextMenuViewExample17-old.png) + +![Gif](./assets/example-ContextMenuViewExample17.gif) + +
+ +### `ContextMenuView` Example 18 + +**Summary**: Icon Example β€” An example showing a context menu with action items that has icons that uses local image assets imported via `require(...)`. + +
+ +| Notes | +| ------------------------------------------------------------ | +| 1️⃣ β€” The first step that we need to do is to generate a `ImageResolvedAssetSource` object of the local image asset we want to use. This object contains metadata about the image as well as its URI in the file system.

The `Image.resolveAssetSource` function returns a `ImageResolvedAssetSource` that corresponds to the source argument you pass into it. Give this function the return value of `require(path/to/image.png)`. | +| 2️⃣ β€” A config of `ImageItemConfig.type` set to `'IMAGE_REQUIRE'` means that we want to use a local image asset imported via the `require(...)` function.

The `ImageItemConfig.imageValue` property accepts a `ImageResolvedAssetSource` object that corresponds to the image asset that you want to use. | + +
+ +[πŸ”— Full Example](./example/srcexamples/ContextMenuViewExample18.tsx) + +```jsx + // πŸ“ Note: for the sake of brevity, some of the code is omitted... +import { ContextMenuView } from 'react-native-ios-context-menu'; + +// Generate a `ImageResolvedAssetSource` object based on the +// image assets... + +const iconA = Image.resolveAssetSource( + require('../assets/emoji-pleading-face.png') +); + +const iconB = Image.resolveAssetSource( + require('../assets/emoji-smiling-face-with-hearts.png') +); + +const iconC = Image.resolveAssetSource( + require('../assets/emoji-sparkling-heart.png') +); + +export function ContextMenuViewExample18(props) { + return ( + + {/** Components */} + + ); +}; +``` + +![screenshot](./assets/example-ContextMenuViewExample18-old.png) + +![Gif](./assets/example-ContextMenuViewExample18.gif) + +
+ +### `ContextMenuView` Example 19 + +**Summary**: Dynamic Menu β€” An example showing a context menu that shows a loading indicator using deferred menu elements. + +
+ +| Notes | +| ------------------------------------------------------------ | +| 1️⃣ β€” If you control your `ContextMenuView.menuConfig` via state, then you can already dynamically add menu items while the context menu is visible (See [`ContextMenuView` Example 10](#ContextMenuView-Example-10)). However, there is no indication in the UI that items are currently being loaded.

You can use a "deferred element" in order to add an action item that has a loading indicator. Once you are done loading the content, then you can replace the deferred element with the actual menu items that you want to add.

πŸ“ **Note**: Deferred elements are only available on iOS 14 and above. | +| 2️⃣ β€” As mentioned in the previous examples, the `MenuConfig.menuItems` property can accept an array of `MenuElementConfig` union type. This means that it can accept an array containing any of the following object types: `MenuConfig` object, `MenuActionConfig`, and `DeferredMenuElementConfig`.

If we pass in a `DeferredMenuElementConfig` to `menuItems`, it means that we want to create "deferred element" item. | +| 3️⃣ β€” To create a deferred element, we just need to create a "config" object that has a property containing both `type` and `deferredID`.

The `DeferredMenuElementConfig.type` property must be set to a string value of `'deferred'`. This indicates that we want to create a deferred element.

The `DeferredMenuElementConfig.deferredID` property must be set to a unique string value. Since we can have multiple deferred elements, the value you pass into this property will be used to identify which deferred element will be replaced with the menu items you want to add when the loading is complete. | +| 4️⃣ β€” Once the context menu is open, any deferred menu items in `MenuConfig.menuItems` will trigger the `ContextMenuView.onRequestDeferredElement` event to fire. Via the event, you will receive two arguments: `deferredID` string and `provider` callback function.

The `deferredID` string corresponds to which deferred element that we need to load, while the `provider` callback function is used to provide the menu items that we want to add and replace the deferred element with. | +| 5️⃣ β€” The `provider` callback function accepts an array of `MenuElementConfig` items.

To replace the deferred element with the menu items you want add, simply call the `provider` callback function with the array of `MenuConfig`, `MenuActionConfig`, or `DeferredMenuElementConfig` objects.

πŸ“ **Note A**: Since the deferred elements were loaded/replaced using the `onRequestDeferredElement` event, there are now two sources of truths for the context menu config: One provided via the `ContextMenuView.menuConfig` prop, and the other via the `onRequestDeferredElement` event.

If you are using a state-controlled menu config, see: [`ContextMenuView` Example 20](#ContextMenuView-Example-20).

πŸ“ **Note B**: It is recommended that you cache the items you have loaded, and then combine them with the existing `menuConfig` once the menu has been closed. | + +
+ +[πŸ”— Full Example](./example/srcexamples/ContextMenuViewExample19.tsx) + +```jsx +// πŸ“ Note: for the sake of brevity, some of the code is omitted... +export function ContextMenuViewExample19(props) { + return ( + { + switch(deferredID) { + case 'deferred-01': + // dummy delay, wait for 1 second... + await Helpers.timeout(1000); + + // provide the items to add to the context menu... + provider([{ + type: 'action', + actionKey: 'action-02', + actionTitle: 'Deferred Item 02', + actionSubtitle: 'Deferred item...' + }, { + type: 'action', + actionKey: 'action-03', + actionTitle: 'Deferred Item 03', + actionSubtitle: 'Deferred item...' + }]); + break; + }; + }} + > + {/** ... */} + + ); +}; +``` + +![example-ContextMenuViewExample19](./assets/example-ContextMenuViewExample19.jpg) + +![example-ContextMenuViewExample19](./assets/example-ContextMenuViewExample19.gif) + +
+ +### `ContextMenuView` Example 20 + +**Summary**: Dynamic Menu β€” An example showing a state-controlled context menu that shows a loading indicator using deferred menu elements. + +
+ +| Notes | +| ----- | +| TBA | + +
+ +[πŸ”— Full Example](./example/srcexamples/ContextMenuViewExample20.tsx) + +```jsx +// πŸ“ Note: for the sake of brevity, some of the code is omitted... +export function ContextMenuViewExample20(props) { + const [extraMenuItems, setExtraMenuItems] = React.useState([]); + + const [isLoading, setIsLoading] = React.useState(true); + const [didLoadItems, setDidLoadItems] = React.useState(false); + + return ( + { + if(didLoadItems) return; + + // for the purposes of this example, let's add a delay + // before showing the loading indicator... + // + // this way, we can see the context menu updating and + // showing the loading indicator. + // + // Ideally, `isLoading` should already be set to `true` + // before the context menu is shown... + await Helpers.timeout(750); + setIsLoading(true); + + // loading... + // dummy delay, wait for 2 second... + await Helpers.timeout(2000); + setDidLoadItems(true); + + // add extra menu items + setExtraMenuItems([{ + type: 'action', + actionKey: 'action-02', + actionTitle: 'Deferred Item 02', + actionSubtitle: 'Deferred item...' + }, { + type: 'action', + actionKey: 'action-03', + actionTitle: 'Deferred Item 03', + actionSubtitle: 'Deferred item...' + }]); + + // hide the loading indicator + setIsLoading(false); + }} + > + {/** ... */} + + ); +}; +``` + +![example-ContextMenuViewExample20](./assets/example-ContextMenuViewExample20.jpg) + +![example-ContextMenuViewExample20](./assets/example-ContextMenuViewExample20.gif) + +
+ +### `ContextMenuView` Example 21 + +**Summary**: Menu Element Size β€” TBA + +
+ +| Notes | +| ----- | +| TBA | + +
+ +[πŸ”— Full Example](./example/srcexamples/ContextMenuViewExample21.tsx) + +```jsx +// πŸ“ Note: for the sake of brevity, some of the code is omitted... +export function ContextMenuViewExample21(props) { + + return ( + + {/** ... */} + + ); +}; +``` + +![example-ContextMenuViewExample21](./assets/example-ContextMenuViewExample21.jpg) + +![example-ContextMenuViewExampleXX](./assets/example-ContextMenuViewExampleXX.gif) + +
+ +### `ContextMenuView` Example 22 + +**Summary**: Menu Element Size β€” TBA + +
+ +| Notes | +| ----- | +| TBA | + +
+ +[πŸ”— Full Example](./example/srcexamples/ContextMenuViewExample22.tsx) + +```jsx +// πŸ“ Note: for the sake of brevity, some of the code is omitted... +export function ContextMenuViewExample22(props) { + + return ( + + {/** ... */} + + ); +}; +``` + +![example-ContextMenuViewExample22](./assets/example-ContextMenuViewExample22.jpg) + +![example-ContextMenuViewExampleXX](./assets/example-ContextMenuViewExampleXX.gif) + +
+ +### `ContextMenuView` Example 23 + +**Summary**: Menu Element Size β€” TBA + +
+ +| Notes | +| ----- | +| | + +
+ +[πŸ”— Full Example](./example/srcexamples/ContextMenuViewExample23.tsx) + +```jsx +// πŸ“ Note: for the sake of brevity, some of the code is omitted... +export function ContextMenuViewExample23(props) { + + return ( + + { /** ... */ } + + ); +}; +``` + +![example-ContextMenuViewExample23](./assets/example-ContextMenuViewExample23.jpg) + +![example-ContextMenuViewExampleXX](./assets/example-ContextMenuViewExampleXX.gif) + +
+ +### `ContextMenuView` Example 24 + +**Summary**: Menu Attributes β€” `keepsMenuPresented` + +
+ +| Notes | +| ----- | +| TBA | + +
+ +[πŸ”— Full Example](./example/srcexamples/ContextMenuViewExample24.tsx) + +```jsx +// πŸ“ Note: for the sake of brevity, some of the code is omitted... +export function ContextMenuViewExample24(props) { + const [actionState1, setActionState1] = React.useState(false); + const [actionState2, setActionState2] = React.useState(false); + const [actionState3, setActionState3] = React.useState(false); + + const isResetEnabled = ( + actionState1 || + actionState2 || + actionState3 + ); + + const handleOnPressMenuItem = ({nativeEvent}) => { + // ... + }; + + return ( + + { /** ... */ } + + ); +}; +``` + +![example-ContextMenuViewExample24](./assets/example-ContextMenuViewExample24.jpg) + +![example-ContextMenuViewExampleXX](./assets/example-ContextMenuViewExampleXX.gif) + +
+ +### `ContextMenuView` Example 25 + +**Summary**: Icon Example β€” Advanced customization (e.g. `scale`, `weight`, `paletteColors`, `hierarchicalColor`). + +
+ +| Notes | +| ----- | +| TBA | + +
+ +[πŸ”— Full Example](./example/srcexamples/ContextMenuViewExample25.tsx) + +```jsx +// πŸ“ Note: for the sake of brevity, some of the code is omitted... +export function ContextMenuViewExample25(props) { + return ( + + {/** .... */} + + ); +}; +``` + + + +![example-ContextMenuViewExample25](./assets/example-ContextMenuViewExample25.jpg) + +![example-ContextMenuViewExampleXX](./assets/example-ContextMenuViewExampleXX.gif) + +
+ +### `ContextMenuView` Example 26 + +**Summary**: Icon Example β€” Network/Remote images as icons. + +
+ +| Notes | +| ----- | +| TBA | + +
+ +[πŸ”— Full Example](./example/srcexamples/ContextMenuViewExample26.tsx) + +```jsx + +// πŸ“ Note: for the sake of brevity, some of the code is omitted... +export function ContextMenuViewExample26(props) { + return ( + + {/** ... */} + + ); +}; +``` + +![example-ContextMenuViewExampleXX](./assets/example-ContextMenuViewExampleXX.jpg) + +![example-ContextMenuViewExample26](./assets/example-ContextMenuViewExample26.gif) + +
+ +### `ContextMenuView` Example 27 + +**Summary**: Icon Example β€” Network/Remote images as icons + fallback image. + +
+ +| Notes | +| ----- | +| TBA | + +
+ +[πŸ”— Full Example](./example/srcexamples/ContextMenuViewExample27.tsx) + +```jsx +// πŸ“ Note: for the sake of brevity, some of the code is omitted... +export function ContextMenuViewExample27(props) { + return ( + + {/** ... */} + + ); +}; + +``` + + + +![example-ContextMenuViewExampleXX](./assets/example-ContextMenuViewExampleXX.jpg) + +![example-ContextMenuViewExampleXX](./assets/example-ContextMenuViewExampleXX.gif) + +
+ +### `ContextMenuView` Example 28 + +**Summary**: Programmatically shows the context menu + +
+ +| Notes | +| ----- | +| TBA | + +
+ +[πŸ”— Full Example](./example/srcexamples/ContextMenuViewExample28.tsx) + +```jsx +// πŸ“ Note: for the sake of brevity, some of the code is omitted... +export function ContextMenuViewExample28(props) { + const menuRef = React.useRef(null); + + return ( + + + { + menuRef.current?.presentMenu(); + }} + /> + + + ); +}; + +``` + +![example-ContextMenuViewExample28](./assets/example-ContextMenuViewExample28.gif) + +
+ +### `ContextMenuView` Auxiliary Preview - Example 01 + +**Summary**: TBA + +
+ +| Notes | +| ------------------------ | +| TBA

πŸ“ **Note A**: | + +
+ +[πŸ”— Full Example](./example/srcexamples/ContextMenuAuxPreviewExample01.tsx) + +```jsx +// πŸ“ Note: for the sake of brevity, some of the code is omitted... +export function ContextMenuAuxPreviewExample01() { + return ( + ( + + + { /** ... */ } + + + )} + > + {/** ... */} + + ); +}; +``` + +![ContextMenuAuxPreviewExample01](./assets/example-ContextMenuAuxPreviewExample01.jpg) + +![placeholder](./assets/placeholder.gif) + +
+ +### `ContextMenuView` Auxiliary Preview - Example 02 + +**Summary**: TBA + +
+ +| Notes | +| ------------------------ | +| TBA

πŸ“ **Note A**: | + +
+ +[πŸ”— Full Example](./example/srcexamples/ContextMenuAuxPreviewExample02.tsx) + +```jsx +// πŸ“ Note: for the sake of brevity, some of the code is omitted... +export function ContextMenuAuxPreviewExample02() { + return ( + ( + + + Faster Transition + + + )} + > + {/** ... */} + + ); +}; +``` + +![ContextMenuAuxPreviewExample02](./assets/example-ContextMenuAuxPreviewExample02.jpg) + +![placeholder](./assets/placeholder.gif) + +
+ +### `ContextMenuView` Auxiliary Preview - Example 03 + +**Summary**: TBA + +
+ +| Notes | +| ------------------------ | +| TBA

πŸ“ **Note A**: | + +
+ +[πŸ”— Full Example](./example/srcexamples/ContextMenuAuxPreviewExample03.tsx) + +```jsx +// πŸ“ Note: for the sake of brevity, some of the code is omitted... +export function ContextMenuAuxPreviewExample03() { + return ( + ( + + + To the left (to the left) + + + )} + > + {/** ... */} + + ); +}; +``` + +![ContextMenuAuxPreviewExample03](./assets/example-ContextMenuAuxPreviewExample03.jpg) + +![placeholder](./assets/placeholder.gif) + +
+ +### `ContextMenuView` Auxiliary Preview - Example 04 + +**Summary**: TBA + +
+ +| Notes | +| ------------------------ | +| TBA

πŸ“ **Note A**: | + +
+ +[πŸ”— Full Example](./example/srcexamples/ContextMenuAuxPreviewExample04.tsx) + +```jsx +// πŸ“ Note: for the sake of brevity, some of the code is omitted... +export function ContextMenuAuxPreviewExample04() { + return ( + ( + + + Yeah right, yeah right + + + )} + > + {/** ... */} + + ); +}; +``` + +![ContextMenuAuxPreviewExample04](./assets/example-ContextMenuAuxPreviewExample04.jpg) + +![placeholder](./assets/placeholder.gif) + +
+ +### `ContextMenuView` Auxiliary Preview - Example 05 + +**Summary**: TBA + +
+ +| Notes | +| ------------------------ | +| TBA

πŸ“ **Note A**: | + +
+ +[πŸ”— Full Example](./example/srcexamples/ContextMenuAuxPreviewExample05.tsx) + +```jsx +// πŸ“ Note: for the sake of brevity, some of the code is omitted... +export function ContextMenuAuxPreviewExample05() { + return ( + ( + + + Center + + + )} + > + { /** ... */ } + + ); +}; +``` + +![ContextMenuAuxPreviewExample05](./assets/example-ContextMenuAuxPreviewExample05.jpg) + +![placeholder](./assets/placeholder.gif) + +
+ +### `ContextMenuView` Auxiliary Preview - Example 06 + +**Summary**: TBA + +
+ +| Notes | +| ------------------------ | +| TBA

πŸ“ **Note A**: | + +
+ +[πŸ”— Full Example](./example/srcexamples/ContextMenuAuxPreviewExample06.tsx) + +```jsx +// πŸ“ Note: for the sake of brevity, some of the code is omitted... +export function ContextMenuAuxPreviewExample06(props) { + return ( + ( + + + + Stretch to Edges of Screen + + + + )} + > + {/** ... */} + + ); +}; +``` + +![ContextMenuAuxPreviewExample06](./assets/example-ContextMenuAuxPreviewExample06.jpg) + +![placeholder](./assets/placeholder.gif) + +
+ +### `ContextMenuView` Auxiliary Preview - Example 07 + +**Summary**: TBA + +
+ +| Notes | +| ------------------------ | +| TBA

πŸ“ **Note A**: | + +
+ +[πŸ”— Full Example](./example/srcexamples/ContextMenuAuxPreviewExample07.tsx) + +```jsx +// πŸ“ Note: for the sake of brevity, some of the code is omitted... +export function ContextMenuAuxPreviewExample07(props) { + return ( + ( + + + 100 + + + x + + + 100 + + + )} + > + {/** ... */} + + ); +}; +``` + +![ContextMenuAuxPreviewExample07](./assets/example-ContextMenuAuxPreviewExample07.jpg) + +![placeholder](./assets/placeholder.gif) + +
+ +### `ContextMenuView` Auxiliary Preview - Example 08 + +**Summary**: TBA + +
+ +| Notes | +| ------------------------ | +| TBA

πŸ“ **Note A**: | + +
+ +[πŸ”— Full Example](./example/srcexamples/ContextMenuAuxPreviewExample08.tsx) + +```jsx +// πŸ“ Note: for the sake of brevity, some of the code is omitted... +export function ContextMenuAuxPreviewExample08(props) { + return ( + ( + // ... + )} + > + {/** ... */} + + ); +}; +``` + +![ContextMenuAuxPreviewExample08](./assets/example-ContextMenuAuxPreviewExample08.jpg) + +![placeholder](./assets/placeholder.gif) + +
+ +### `ContextMenuView` Auxiliary Preview - Example 09 + +**Summary**: TBA + +
+ +| Notes | +| ------------------------ | +| TBA

πŸ“ **Note A**: | + +
+ +[πŸ”— Full Example](./example/srcexamples/ContextMenuAuxPreviewExample09.tsx) + +```jsx +export function ContextMenuAuxPreviewExample09(props) { + return ( + ( + + + Always Bottom + + + )} + > + {/** ... */} + + ); +}; +``` + +![ContextMenuAuxPreviewExample09](./assets/example-ContextMenuAuxPreviewExample09.jpg) + +![placeholder](./assets/placeholder.gif) + +
+ +### `ContextMenuView` Auxiliary Preview - Example 10 + +**Summary**: TBA + +
+ +| Notes | +| ------------------------ | +| TBA

πŸ“ **Note A**: | + +
+ +[πŸ”— Full Example](./example/srcexamples/ContextMenuAuxPreviewExample10.tsx) + +```jsx +// πŸ“ Note: for the sake of brevity, some of the code is omitted... +export function ContextMenuAuxPreviewExample10(props) { + return ( + ( + // ... + )} + > + {/** .... */} + + ); +}; +``` + +![ContextMenuAuxPreviewExample10](./assets/example-ContextMenuAuxPreviewExample10.jpg) + +![placeholder](./assets/placeholder.gif) + +
+ +### `ContextMenuView` Auxiliary Preview - Example 11 + +**Summary**: TBA + +
+ +| Notes | +| ------------------------ | +| TBA

πŸ“ **Note A**: | + +
+ +[πŸ”— Full Example](./example/srcexamples/ContextMenuAuxPreviewExample11.tsx) + +```jsx +// πŸ“ Note: for the sake of brevity, some of the code is omitted... +export function ContextMenuAuxPreviewExample11(props) { + return ( + ( + // ... + )} + > + {/** ... */} + + ); +}; +``` + +![ContextMenuAuxPreviewExample11](./assets/example-ContextMenuAuxPreviewExample11.jpg) + +![placeholder](./assets/placeholder.gif) + +
+ +### `ContextMenuView` Auxiliary Preview - Example 12 + +**Summary**: TBA + +
+ +| Notes | +| ------------------------ | +| TBA

πŸ“ **Note A**: | + +
+ +[πŸ”— Full Example](./example/srcexamples/ContextMenuAuxPreviewExample12.tsx) + +```jsx +// πŸ“ Note: for the sake of brevity, some of the code is omitted... +export function ContextMenuAuxPreviewExample12(props) { + return ( + ( + // ... + )} + > + {/** ... */} + + ); +}; +``` + +![ContextMenuAuxPreviewExample12](./assets/example-ContextMenuAuxPreviewExample12.jpg) + +![placeholder](./assets/placeholder.gif) + +
+ +### `ContextMenuView` Auxiliary Preview - Example 13 + +**Summary**: TBA + +
+ +| Notes | +| ------------------------ | +| TBA

πŸ“ **Note A**: | + +
+ +[πŸ”— Full Example](./example/srcexamples/ContextMenuAuxPreviewExample13.tsx) + +```jsx +// πŸ“ Note: for the sake of brevity, some of the code is omitted... +export function ContextMenuAuxPreviewExample13(props) { + return ( + ( + // ... + )} + > + {/** ... */} + + ); +}; +``` + +![ContextMenuAuxPreviewExample13](./assets/example-ContextMenuAuxPreviewExample13.jpg) + +![placeholder](./assets/placeholder.gif) + +
+ +### `ContextMenuView` Auxiliary Preview - Example 14 + +**Summary**: TBA + +
+ +| Notes | +| ------------------------ | +| TBA

πŸ“ **Note A**: | + +
+ +[πŸ”— Full Example](./example/srcexamples/ContextMenuAuxPreviewExample14.tsx) + +```jsx +// πŸ“ Note: for the sake of brevity, some of the code is omitted... +export function ContextMenuAuxPreviewExample14(props) { + return ( + ( + // ... + )} + > + {/** ... */} + + ); +}; +``` + +![ContextMenuAuxPreviewExample14](./assets/example-ContextMenuAuxPreviewExample14.jpg) + +![placeholder](./assets/placeholder.gif) + +
+ + + +### `ContextMenuView` Auxiliary Preview - Example 15 + +**Summary**: TBA + +
+ +| Notes | +| ------------------------ | +| TBA

πŸ“ **Note A**: | + +
+ +[πŸ”— Full Example](./example/srcexamples/ContextMenuAuxPreviewExample15.tsx) + +```jsx +// πŸ“ Note: for the sake of brevity, some of the code is omitted... + +export function ContextMenuAuxPreviewExample15(props) { + return ( + ( + + + Aux. Preview + + + )} + previewConfig={{ + previewType: 'CUSTOM', + previewSize: 'STRETCH', + }} + renderPreview={() => ( + + + Custom Menu Preview + + + )} + > + {/** ... */} + + ); +}; +``` + +![ContextMenuAuxPreviewExample15](./assets/example-ContextMenuAuxPreviewExample15.jpg) + +![placeholder](./assets/placeholder.gif) + +
+ +### `ContextMenuView` Auxiliary Preview - Example 16 + +**Summary**: Programmatically shows the auxiliary preview as a popover, without showing the context menu. + +
+ +| Notes | +| ----- | +| TBA | + +
+ +[πŸ”— Full Example](./example/srcexamples/ContextMenuViewExampleXX.tsx) + +```jsx +// πŸ“ Note: for the sake of brevity, some of the code is omitted... +export function ContextMenuAuxPreviewExample16(props) { + const menuRef = React.useRef(null); + + return ( + ( + + + Center + + + )} + > + + { + menuRef.current?.showAuxiliaryPreviewAsPopover(); + }} + /> + + + ); +}; +``` + +![example-ContextMenuViewExample16](./assets/example-ContextMenuAuxPreviewExample16.gif) + +
+ +### `ContextMenuButton` Example 01 + +**Summary**: TBA + +
+ +| Notes | +| ------------------------ | +| TBA

πŸ“ **Note A**: | + +
+ +[πŸ”— Full Example](./example/srcexamples/ContextMenuButtonExample01.tsx) + +```jsx + // πŸ“ Note: for the sake of brevity, some of the code is omitted... + +import { ContextMenuButton } from 'react-native-ios-context-menu'; + +export function ContextMenuButtonExample01() { + return ( + { + Alert.alert( + 'onPressMenuItem Event', + `actionKey: ${nativeEvent.actionKey} - actionTitle: ${nativeEvent.actionTitle}` + ); + }} + > + {/** Components */} + + ); +}; +``` + +![screenshot](./assets/example-ContextMenuButtonExample01-old.png) + +![Gif](./assets/example-ContextMenuButtonExample01.gif) + +
+ +### `ContextMenuButton` Example 02 + +**Summary**: TBA + +
+ +| Notes | +| ------------------------ | +| TBA

πŸ“ **Note A**: | + +
+ +[πŸ”— Full Example](./example/srcexamples/ContextMenuButtonExample02.tsx) + +```jsx + // πŸ“ Note: for the sake of brevity, some of the code is omitted... +import { ContextMenuButton } from 'react-native-ios-context-menu'; + +export function ContextMenuButtonExample02(props) { + return ( + { + Alert.alert( + 'onPressMenuItem Event', + `actionKey: ${nativeEvent.actionKey} - actionTitle: ${nativeEvent.actionTitle}` + ); + }} + > + {/** Components */} + + ); +}; +``` + +![screenshot](./assets/example-ContextMenuButtonExample02-old.png) + +![Gif](./assets/example-ContextMenuButtonExample02.gif) + +

+ +## F. Showcase, Tests and Demos + +### `ContextMenuView` Test 01 + +**Summary**: Test for multiple nested/deep submenus. + +[πŸ”— Source Code](example/src/examples/ContextMenuViewTest01.tsx) + +![Gif](./assets/test-ContextMenuViewTest01.gif) + +
+ +### `ContextMenuView` Test 02 + +**Summary**: Test for multiple inline menus + nested submenus. + +[πŸ”— Source Code](example/src/examples/ContextMenuViewTest02.tsx) + +![Gif](./assets/test-ContextMenuViewTest02.gif) + +
+ +### `ContextMenuView` Test 03 + +**Summary**: Test for toggling the `menuState` on and off. + +[πŸ”— Source Code](example/src/examples/ContextMenuViewTest03.tsx) + +![Gif](./assets/test-ContextMenuViewTest03.gif) + +
+ +### `ContextMenuView` Test 04 + +**Summary**: Test for changing the menu icons based on the current `menuState`. + +[πŸ”— Source Code](example/src/examples/ContextMenuViewTest04.tsx) + +![Gif](./assets/test-ContextMenuViewTest04.gif) + +
+ +### `ContextMenuView` Test 05 + +**Summary**: Test for logging all the menu-related events. + +[πŸ”— Source Code](example/src/examples/ContextMenuViewTest05.tsx) + +![Gif](./assets/test-ContextMenuViewTest05.gif) + +
+ +### `ContextMenuView` Test 06 + +**Summary**: Test for programmatically adding a menu action item. + +[πŸ”— Source Code](example/src/examples/ContextMenuViewTest06.tsx) + +![Gif](./assets/test-ContextMenuViewTest06.gif) + +
+ +### `ContextMenuView` Test 07 + +**Summary**: Test for checking the different possible custom menu preview configurations. + +[πŸ”— Source Code](example/src/examples/ContextMenuViewTest07.tsx) + +![Gif](./assets/test-ContextMenuViewTest07.gif) + +
+ +### `ContextMenuView` Test 08 + +**Summary**: Test for programmatically dismissing the menu. + +[πŸ”— Source Code](example/src/examples/ContextMenuViewTest08.tsx) + +![Gif](./assets/test-ContextMenuViewTest08.gif) + +
+ +### `ContextMenuView` Test 09 + +**Summary**: Generate new 'deferredID' everytime the context menu is shown/hide. This is a test for `cleanupOrphanedDeferredElements`. + +[πŸ”— Source Code](example/src/examples/ContextMenuViewTest09.tsx) + +![Gif](./assets/test-ContextMenuViewTest09.gif) + +
+ +### `ContextMenuView` Test 10 + +**Summary**: Test for nested menus, deferred elements, large icons, and small menus, + +[πŸ”— Source Code](example/src/examples/ContextMenuViewTest10.tsx) + +![Gif](./assets/test-ContextMenuViewTest10.gif) + +
+ +### `ContextMenuAuxPreview` Test 01 + +**Summary**: TBA + +[πŸ”— Source Code](example/src/examples/ContextMenuAuxPreviewTest01.tsx) + +![Gif](./assets/test-ContextMenuAuxPreviewTest01.gif) + +
+ +### `Test02Screen` + +**Summary**: Repro for [Issue #43](https://github.com/dominicstop/react-native-ios-context-menu/issues/43) + +[πŸ”— Source Code](example/src/screens/Test02Screen.tsx) + +![Gif](./assets/screen-Test02Screen.gif) + +
+ +### `Test03Screen` + +**Summary**: Repro for [Issue #47](https://github.com/dominicstop/react-native-ios-context-menu/issues/47) + +[πŸ”— Source Code](example/src/screens/Test03Screen.tsx) + +![Gif](./assets/screen-Test03Screen.gif) + +

+ +## G. Meta + +

+ +## H. Licence + +[MIT](./LICENSE) + +

+ +## Misc and Contact + +* 🐀 **Twitter/X**: `@GoDominic` +* πŸ’Œ **Email**: `dominicgo@dominicgo.dev` +* 🌐 **Website**: [dominicgo.dev](https://dominicgo.dev) \ No newline at end of file