react-native-tinyui 1.0.0 → 1.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,16 +1,47 @@
1
+ <img src="./assets/banner.png" alt="TinyUI — Native iOS components for React Native" width="100%" />
2
+
1
3
  # react-native-tinyui
2
4
 
3
- Dependency-free, native iOS `Menu`, `Popover`, `TipKit`, `Stepper`, `ConcentricView`, `SFSymbol` and `LiquidGlassText` components for React Native's
4
- New Architecture. The public API follows normal React composition patterns;
5
- the native UI is exposed through Fabric components. `Menu`, `Popover`, `Stepper`, `ConcentricView` and `SFSymbol` are
6
- implemented directly with UIKit; `LiquidGlassText` uses SwiftUI where needed.
5
+ A dependency-free collection of native iOS components for React Native's New
6
+ Architecture. Built on Fabric, TinyUI offers familiar React composition while
7
+ staying close to native APIs. It uses UIKit by default and SwiftUI where needed.
8
+
9
+ ## Components
10
+
11
+ | Component | What it does |
12
+ | ---------------------------------- | -------------------------------------------------------------- |
13
+ | [Menu](#menu) | Present native menus with actions, submenus, and sections |
14
+ | [Popover](#popover) | Show interactive React Native content in a native popover |
15
+ | [TipKit](#tipkit) | Present contextual tips using Apple's TipKit framework |
16
+ | [LiquidGlassText](#liquidglasstext) | Render text with native glass effects inside the glyphs |
17
+ | [Stepper](#stepper) | Adjust numeric values with the native iOS stepper |
18
+ | [ConcentricView](#concentricview) | Follow the containing view's corners with concentric rounding |
19
+ | [SFSymbol](#sfsymbol) | Display SF Symbols with native rendering and animation effects |
20
+
21
+ Screenshots below show the example app on an iPhone 17 Pro simulator running
22
+ iOS 26.5.
23
+
24
+ ## Philosophy and comparison with `@expo/ui`
25
+
26
+ TinyUI prioritizes performance, stability, a small app footprint, and familiar
27
+ React composition. These priorities guide which components we add and how we
28
+ bridge them.
7
29
 
8
- The initial component behavior is inspired by
9
- [`@expo/ui`](https://github.com/expo/expo/tree/main/packages/expo-ui), but this
10
- package does not require Expo Modules or any other runtime package. The
11
- React Native ↔ native view integration follows the approach used by
12
- [`react-native-pager-view`](https://github.com/callstack/react-native-pager-view):
13
- a Fabric component owns the platform view that renders its content.
30
+ | Design choice | `react-native-tinyui` | `@expo/ui` |
31
+ | --- | --- | --- |
32
+ | Runtime dependencies | Zero additional runtime dependencies beyond `react` and `react-native`. No `expo`, Expo Modules, or `react-native-nitro-modules` required. | Uses Expo Modules; existing React Native apps must [install `expo`](https://docs.expo.dev/versions/latest/sdk/ui/swift-ui/#installation). |
33
+ | Native implementation | Performance and stability first. Prefers direct UIKit integration through Fabric; uses SwiftUI when a component needs it. | Uses [SwiftUI on iOS](https://docs.expo.dev/versions/latest/sdk/ui/swift-ui/), with its layout and hosting model. |
34
+ | Selective inclusion and app size | Component-specific JS imports avoid loading unrelated component modules. An explicit native component list excludes unselected UI implementations and their framework requirements from the pod. | Provides platform-specific JS entry points. Its [iOS podspec](https://github.com/expo/expo/blob/main/packages/expo-ui/ios/ExpoUI.podspec) includes native sources together, without a per-component selection list. JS imports alone do not select native sources. |
35
+ | Component scope | Welcomes both system UI and third-party UI, such as [GlassText](#liquidglasstext). Adding components to the catalog does not require apps to include their UI implementations when they remain unselected. | Centers on SwiftUI and Jetpack Compose. Supports [custom SwiftUI components and modifiers, including third-party SwiftUI libraries](https://docs.expo.dev/guides/expo-ui-swift-ui/extending/). |
36
+ | React API | Familiar props, children, and controlled/uncontrolled state, composed with ordinary React Native views. Names and behavior stay close to the underlying native APIs. | Exposes native toolkit concepts through React, including SwiftUI views, modifiers, and a [`Host` container](https://docs.expo.dev/versions/latest/sdk/ui/swift-ui/#usage). |
37
+ | Supported targets and maintenance | iOS 17+ and the New Architecture only. Excluding older iOS versions and the legacy bridge reduces compatibility code and keeps maintenance focused. | Covers a broader platform scope: SwiftUI on iOS, Jetpack Compose on Android, and [universal components for iOS, Android, and web](https://docs.expo.dev/versions/latest/sdk/ui/universal/). Requirements depend on the Expo SDK and component. |
38
+
39
+ For the smallest builds, combine component-specific JS imports with
40
+ [`react-native-tinyui.components`](#optional-component-selection). All native
41
+ components are enabled by default, so configure that list explicitly. Shared
42
+ core code, Fabric Codegen, and lightweight registration stubs remain in the
43
+ native build; the size savings come from excluding unused UI implementations.
44
+ Final bundle size also depends on the app's bundler and linker settings.
14
45
 
15
46
  ## Requirements
16
47
 
@@ -74,6 +105,8 @@ compatibility. JavaScript entry points provide cleaner dependency boundaries;
74
105
 
75
106
  ## Menu
76
107
 
108
+ <img src="docs/screenshots/menu.png" alt="Menu with native document actions expanded" width="320" />
109
+
77
110
  `Menu` uses `children` as its trigger and receives its native menu entries
78
111
  through the `options` prop. A tap opens the native menu; `onActionPress`
79
112
  receives every selected action's stable id and displayed title.
@@ -132,6 +165,36 @@ or `type: 'divider'` for structural entries; nested entries use their own
132
165
  `options` array. SF Symbols are passed with `systemImage`; missing symbols
133
166
  simply render no image.
134
167
 
168
+ The trigger can be nested inside a React Native `Pressable` or `Touchable`.
169
+ Tapping an enabled menu trigger opens the menu without firing the parent's
170
+ touch or press handlers; tapping elsewhere in the parent keeps its normal behavior.
171
+
172
+ To open the menu from another control, call `open()` on its ref:
173
+
174
+ ```tsx
175
+ import { useRef } from 'react';
176
+ import { Button, Text } from 'react-native';
177
+ import { Menu, type MenuRef } from 'react-native-tinyui/menu';
178
+
179
+ function DocumentMenu() {
180
+ const menuRef = useRef<MenuRef>(null);
181
+
182
+ return (
183
+ <>
184
+ <Menu ref={menuRef} options={[{ id: 'rename', title: 'Rename' }]}>
185
+ <Text>Document actions</Text>
186
+ </Menu>
187
+ <Button title="Open menu" onPress={() => menuRef.current?.open()} />
188
+ </>
189
+ );
190
+ }
191
+ ```
192
+
193
+ `open()` requires iOS 17.4 or newer and anchors the menu to its mounted trigger.
194
+ It does nothing on older iOS versions, while `disabled`, or when the trigger is
195
+ detached. Tapping the trigger still works on all supported iOS versions. The ref
196
+ also retains the outer View's methods, such as `measure` and `measureInWindow`.
197
+
135
198
  Action options support `subtitle`, `state`, `destructive`, `disabled`, `hidden`,
136
199
  and `keepOpen`. Set explicit `id` values when handling `onActionPress`; actions
137
200
  without one receive a generated menu-path id. Use `icon` to load an image from
@@ -144,6 +207,8 @@ plus `destructive`, `disabled`, `hidden`, and `displayInline`.
144
207
 
145
208
  ## Popover
146
209
 
210
+ <img src="docs/screenshots/popover.png" alt="Popover displaying resizable content above its trigger" width="320" />
211
+
147
212
  `Popover` supports standard controlled and uncontrolled React state. Its content
148
213
  remains a normal interactive React Native view tree hosted by a real
149
214
  `UIPopoverPresentationController`.
@@ -189,6 +254,8 @@ outer container, not the presented content.
189
254
 
190
255
  ## TipKit
191
256
 
257
+ <img src="docs/screenshots/tip-kit.png" alt="TipKit popover with a save action anchored to the favorite button" width="320" />
258
+
192
259
  `TipKit.Popover` anchors a native TipKit `TipUIPopoverViewController` to ordinary
193
260
  React Native children on iOS 17+. The children retain their own touch handlers;
194
261
  the tip appears automatically when both `enabled` and TipKit's eligibility allow
@@ -288,6 +355,8 @@ ID for trying the behavior again without clearing the app's TipKit datastore.
288
355
 
289
356
  ## LiquidGlassText
290
357
 
358
+ <img src="docs/screenshots/liquid-glass-text.png" alt="LiquidGlassText rendering English, Chinese, and numbers over a photo" width="320" />
359
+
291
360
  `LiquidGlassText` renders native glass inside the glyph outlines, based on
292
361
  [GlassText](https://github.com/ailtonvivaz/GlassText). It exposes the effect and
293
362
  typography through React props.
@@ -354,6 +423,8 @@ The adapted Core Text outline implementation retains the upstream MIT notice in
354
423
 
355
424
  ## Stepper
356
425
 
426
+ <img src="docs/screenshots/stepper.png" alt="Native Stepper with a controlled value and configurable range" width="320" />
427
+
357
428
  `Stepper` bridges UIKit's
358
429
  [`UIStepper`](https://developer.apple.com/documentation/uikit/uistepper) through
359
430
  Fabric. It supports fractional steps, press-and-hold repeat, and wrapping at
@@ -412,6 +483,8 @@ stepper shows the minus and plus buttons; render a separate `Text` for the value
412
483
 
413
484
  ## ConcentricView
414
485
 
486
+ <img src="docs/screenshots/concentric-view.png" alt="Nested ConcentricView containers following the bottom screen corners" width="320" />
487
+
415
488
  `ConcentricView` is a Fabric container that lets UIKit resolve its corner radii
416
489
  relative to its containing view. On iOS 26+, it applies
417
490
  [`UICornerRadius.containerConcentricRadius`](https://developer.apple.com/documentation/uikit/uicornerradius-c.class/containerconcentricradius)
@@ -447,6 +520,8 @@ concentric radii; keep those decorations on a surrounding view when needed.
447
520
 
448
521
  ## SFSymbol
449
522
 
523
+ <img src="docs/screenshots/sf-symbol.png" alt="SFSymbol rendering a bell badge with native symbol colors" width="320" />
524
+
450
525
  `SFSymbol` uses **UIKit `UIImageView` + Apple's Symbols framework**, exposed
451
526
  through Fabric. It does not embed a SwiftUI hosting view. Xcode 26+ is required
452
527
  to build; the deployment target remains iOS 17. Yoga measures the configured
@@ -559,6 +634,46 @@ multicolor and variable/draw support depend on each symbol's native annotations.
559
634
  transitions are suppressed while Reduce Motion is enabled, while scale and
560
635
  visibility state changes apply instantly. Set it to `false` to opt out.
561
636
 
637
+ ## Example App
638
+
639
+ The [example app](example/src/App.tsx) demonstrates Menu, Popover, TipKit,
640
+ LiquidGlassText, Stepper, ConcentricView, and SFSymbol. It includes all native
641
+ components, so building it requires Xcode 26+. Use iOS 26+ to try the glass effects
642
+ and the latest SF Symbol features.
643
+
644
+ From the repository root, install the dependencies:
645
+
646
+ ```sh
647
+ yarn
648
+ ```
649
+
650
+ Install the example's Pods:
651
+
652
+ ```sh
653
+ cd example/ios && pod install
654
+ ```
655
+
656
+ Then run Metro and the iOS app from the repository root in separate terminals:
657
+
658
+ ```sh
659
+ yarn example start
660
+ ```
661
+
662
+ ```sh
663
+ yarn example ios
664
+ ```
665
+
666
+ The example uses Metro port `8082`, which is already configured in these scripts.
667
+ See the [development workflow](CONTRIBUTING.md#development-workflow) for more
668
+ details.
669
+
670
+ ## Apps Using This Library
671
+
672
+ - [Night Vision - LiDAR Camera](https://apps.apple.com/app/id1668629667)
673
+ - [Laser Measure - LiDAR Powered](https://apps.apple.com/app/id6466744678)
674
+ - [PhoneAway - Digital Detox](https://apps.apple.com/app/id6744548607)
675
+ - [Fatigue Alert - Stay Awake](https://apps.apple.com/app/id6479893638)
676
+
562
677
  ## Contributing
563
678
 
564
679
  - [Development workflow](CONTRIBUTING.md#development-workflow)
@@ -1,4 +1,5 @@
1
1
  import UIKit
2
+ import UIKit.UIGestureRecognizerSubclass
2
3
 
3
4
  /**
4
5
  * UIButton-backed UIKit menu trigger used as the Fabric component's content
@@ -6,6 +7,7 @@ import UIKit
6
7
  */
7
8
  @objc public final class TinyuiMenuProvider: UIButton {
8
9
  private weak var delegate: TinyuiMenuViewDelegate?
10
+ private weak var menuTouchGate: TinyuiMenuTouchGate?
9
11
 
10
12
  @objc public var triggerView: UIView? {
11
13
  didSet {
@@ -35,6 +37,32 @@ import UIKit
35
37
  configure()
36
38
  }
37
39
 
40
+ override public func didMoveToWindow() {
41
+ super.didMoveToWindow()
42
+ menuTouchGate?.presentedMenus.remove(self)
43
+ menuTouchGate = window.map { TinyuiMenuTouchGate.install(in: $0) }
44
+ }
45
+
46
+ override public func contextMenuInteraction(
47
+ _ interaction: UIContextMenuInteraction,
48
+ willDisplayMenuFor configuration: UIContextMenuConfiguration,
49
+ animator: UIContextMenuInteractionAnimating?
50
+ ) {
51
+ super.contextMenuInteraction(interaction, willDisplayMenuFor: configuration, animator: animator)
52
+ menuTouchGate?.presentedMenus.add(self)
53
+ }
54
+
55
+ override public func contextMenuInteraction(
56
+ _ interaction: UIContextMenuInteraction,
57
+ willEndFor configuration: UIContextMenuConfiguration,
58
+ animator: UIContextMenuInteractionAnimating?
59
+ ) {
60
+ super.contextMenuInteraction(interaction, willEndFor: configuration, animator: animator)
61
+ // The dismissal touch has already been filtered. New touches during the
62
+ // closing animation belong to the page again.
63
+ menuTouchGate?.presentedMenus.remove(self)
64
+ }
65
+
38
66
  override public func layoutSubviews() {
39
67
  super.layoutSubviews()
40
68
  triggerView?.frame = bounds
@@ -56,6 +84,16 @@ import UIKit
56
84
  showsMenuAsPrimaryAction = true
57
85
  }
58
86
 
87
+ @objc public func openMenu() {
88
+ guard isEnabled, isUserInteractionEnabled, !isHidden, alpha > 0.01,
89
+ window != nil, !bounds.isEmpty, menu != nil else {
90
+ return
91
+ }
92
+ if #available(iOS 17.4, *) {
93
+ performPrimaryAction()
94
+ }
95
+ }
96
+
59
97
  /** Applies one complete Fabric props snapshot before rebuilding the menu. */
60
98
  @objc public func update(
61
99
  menuConfig: [String: Any],
@@ -80,3 +118,65 @@ import UIKit
80
118
  )
81
119
  }
82
120
  }
121
+
122
+ /**
123
+ * Uses the early-event filtering approach from Expo's SystemMenuTouchGate:
124
+ * https://github.com/expo/expo/pull/49775
125
+ * TinyUI tracks its own menus through public UIButton lifecycle callbacks.
126
+ */
127
+ final class TinyuiMenuTouchGate: UIGestureRecognizer, UIGestureRecognizerDelegate {
128
+ let presentedMenus = NSHashTable<TinyuiMenuProvider>.weakObjects()
129
+ private static let surfaceTouchHandlerClass = NSClassFromString("RCTSurfaceTouchHandler")
130
+
131
+ init() {
132
+ super.init(target: nil, action: nil)
133
+ cancelsTouchesInView = false
134
+ delaysTouchesBegan = false
135
+ delaysTouchesEnded = false
136
+ delegate = self
137
+ }
138
+
139
+ static func install(in window: UIWindow) -> TinyuiMenuTouchGate {
140
+ if let gate = window.gestureRecognizers?.first(where: { $0 is TinyuiMenuTouchGate })
141
+ as? TinyuiMenuTouchGate {
142
+ return gate
143
+ }
144
+ let gate = TinyuiMenuTouchGate()
145
+ window.addGestureRecognizer(gate)
146
+ return gate
147
+ }
148
+
149
+ private func ignoreReactTouches(_ touches: Set<UITouch>, event: UIEvent) {
150
+ guard let window = view as? UIWindow,
151
+ presentedMenus.allObjects.contains(where: { $0.window === window }),
152
+ let handlerClass = Self.surfaceTouchHandlerClass else {
153
+ return
154
+ }
155
+
156
+ for touch in touches where touch.phase == .began {
157
+ var ancestor = touch.view
158
+ while let current = ancestor {
159
+ for handler in current.gestureRecognizers ?? [] where handler.isKind(of: handlerClass) {
160
+ handler.ignore(touch, for: event)
161
+ }
162
+ ancestor = current.superview
163
+ }
164
+ }
165
+ }
166
+
167
+ func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldReceive event: UIEvent) -> Bool {
168
+ // Filtering in touchesBegan alone is too late: RN may already have sent
169
+ // touchStart/onPressIn to JS. UIKit asks this delegate before delivery.
170
+ if let touches = event.allTouches {
171
+ ignoreReactTouches(touches, event: event)
172
+ }
173
+ return true
174
+ }
175
+
176
+ override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent) {
177
+ super.touchesBegan(touches, with: event)
178
+ // Fallback for delivery orders where RN sees the touch first.
179
+ ignoreReactTouches(touches, event: event)
180
+ state = .failed
181
+ }
182
+ }
@@ -64,6 +64,33 @@ using namespace facebook::react;
64
64
  }
65
65
  }
66
66
 
67
+ #pragma mark - Touch handling
68
+
69
+ - (SharedTouchEventEmitter)touchEventEmitterAtPoint:(CGPoint)point
70
+ {
71
+ // The provider's hitTest returns its UIButton, so the surface touch handler
72
+ // finds this Fabric view first. Keep the trigger's touch sequence in UIKit:
73
+ // forwarding it to JS lets an ancestor Pressable/Touchable claim the same
74
+ // touch and run its press callbacks while the native menu is opening.
75
+ if (_menuProvider.isEnabled) {
76
+ return nullptr;
77
+ }
78
+
79
+ return [super touchEventEmitterAtPoint:point];
80
+ }
81
+
82
+ #pragma mark - Commands
83
+
84
+ - (void)handleCommand:(const NSString *)commandName args:(const NSArray *)args
85
+ {
86
+ RCTTinyuiMenuViewHandleCommand(self, commandName, args);
87
+ }
88
+
89
+ - (void)open
90
+ {
91
+ [_menuProvider openMenu];
92
+ }
93
+
67
94
  #pragma mark - Props
68
95
 
69
96
  - (void)updateProps:(Props::Shared const &)props
@@ -1,6 +1,9 @@
1
+ import type * as React from 'react';
1
2
  import {
2
3
  codegenNativeComponent,
4
+ codegenNativeCommands,
3
5
  type CodegenTypes,
6
+ type HostComponent,
4
7
  type ViewProps,
5
8
  } from 'react-native';
6
9
  import type { DirectEventHandler } from 'react-native/Libraries/Types/CodegenTypes';
@@ -12,6 +15,14 @@ export interface NativeMenuProps extends ViewProps {
12
15
  onActionPress?: DirectEventHandler<Readonly<{ id: string; title: string }>>;
13
16
  }
14
17
 
18
+ interface NativeCommands {
19
+ open: (viewRef: React.ComponentRef<HostComponent<NativeMenuProps>>) => void;
20
+ }
21
+
22
+ export const Commands = codegenNativeCommands<NativeCommands>({
23
+ supportedCommands: ['open'],
24
+ });
25
+
15
26
  export default codegenNativeComponent<NativeMenuProps>('TinyuiMenuView', {
16
27
  excludedPlatforms: ['android'],
17
28
  });
@@ -1,9 +1,9 @@
1
1
  "use strict";
2
2
 
3
- import { forwardRef } from 'react';
3
+ import { forwardRef, useImperativeHandle, useRef } from 'react';
4
4
  import { View } from 'react-native';
5
5
  import { assertComponentEnabled } from "../utils/index.js";
6
- import NativeMenuView from './MenuNativeComponent';
6
+ import NativeMenuView, { Commands } from './MenuNativeComponent';
7
7
  import { serializeMenuOptions } from "./options.js";
8
8
  import { jsx as _jsx } from "react/jsx-runtime";
9
9
  const MenuRoot = /*#__PURE__*/forwardRef(function Menu({
@@ -17,12 +17,22 @@ const MenuRoot = /*#__PURE__*/forwardRef(function Menu({
17
17
  ...viewProps
18
18
  }, ref) {
19
19
  assertComponentEnabled('Menu');
20
+ const viewRef = useRef(null);
21
+ const nativeRef = useRef(null);
22
+ useImperativeHandle(ref, () => Object.assign(viewRef.current, {
23
+ open() {
24
+ if (!disabled && nativeRef.current) {
25
+ Commands.open(nativeRef.current);
26
+ }
27
+ }
28
+ }), [disabled]);
20
29
  const menuConfig = serializeMenuOptions(options);
21
30
  return /*#__PURE__*/_jsx(View, {
22
31
  ...viewProps,
23
- ref: ref,
32
+ ref: viewRef,
24
33
  collapsable: false,
25
34
  children: /*#__PURE__*/_jsx(NativeMenuView, {
35
+ ref: nativeRef,
26
36
  accessibilityLabel: accessibilityLabel,
27
37
  disabled: disabled,
28
38
  menuConfig: menuConfig,
@@ -1 +1 @@
1
- {"version":3,"names":["forwardRef","View","assertComponentEnabled","NativeMenuView","serializeMenuOptions","jsx","_jsx","MenuRoot","Menu","accessibilityLabel","children","disabled","onActionPress","options","title","testID","viewProps","ref","menuConfig","collapsable"],"sourceRoot":"../../../src","sources":["Menu/index.tsx"],"mappings":";;AAAA,SAASA,UAAU,QAA2B,OAAO;AACrD,SAASC,IAAI,QAAQ,cAAc;AAEnC,SAASC,sBAAsB,QAAQ,mBAAU;AAEjD,OAAOC,cAAc,MAAM,uBAAuB;AAClD,SAASC,oBAAoB,QAAQ,cAAW;AAAC,SAAAC,GAAA,IAAAC,IAAA;AAEjD,MAAMC,QAAQ,gBAAGP,UAAU,CAAuC,SAASQ,IAAIA,CAC7E;EACEC,kBAAkB;EAClBC,QAAQ;EACRC,QAAQ;EACRC,aAAa;EACbC,OAAO;EACPC,KAAK;EACLC,MAAM;EACN,GAAGC;AACL,CAAC,EACDC,GAAG,EACH;EACAf,sBAAsB,CAAC,MAAM,CAAC;EAE9B,MAAMgB,UAAU,GAAGd,oBAAoB,CAACS,OAAO,CAAC;EAEhD,oBACEP,IAAA,CAACL,IAAI;IAAA,GAAKe,SAAS;IAAEC,GAAG,EAAEA,GAAI;IAACE,WAAW,EAAE,KAAM;IAAAT,QAAA,eAChDJ,IAAA,CAACH,cAAc;MACbM,kBAAkB,EAAEA,kBAAmB;MACvCE,QAAQ,EAAEA,QAAS;MACnBO,UAAU,EAAEA,UAAW;MACvBN,aAAa,EAAEA,aAAc;MAC7BG,MAAM,EAAEA,MAAO;MACfD,KAAK,EAAEA,KAAM;MAAAJ,QAAA,eAEbJ,IAAA,CAACL,IAAI;QAACkB,WAAW,EAAE,KAAM;QAAAT,QAAA,EAAEA;MAAQ,CAAO;IAAC,CAC7B;EAAC,CACb,CAAC;AAEX,CAAC,CAAC;AAEF,OAAO,MAAMF,IAAI,GAAGD,QAAyB","ignoreList":[]}
1
+ {"version":3,"names":["forwardRef","useImperativeHandle","useRef","View","assertComponentEnabled","NativeMenuView","Commands","serializeMenuOptions","jsx","_jsx","MenuRoot","Menu","accessibilityLabel","children","disabled","onActionPress","options","title","testID","viewProps","ref","viewRef","nativeRef","Object","assign","current","open","menuConfig","collapsable"],"sourceRoot":"../../../src","sources":["Menu/index.tsx"],"mappings":";;AAAA,SACEA,UAAU,EACVC,mBAAmB,EACnBC,MAAM,QAED,OAAO;AACd,SAASC,IAAI,QAA2B,cAAc;AAEtD,SAASC,sBAAsB,QAAQ,mBAAU;AAEjD,OAAOC,cAAc,IAAIC,QAAQ,QAAQ,uBAAuB;AAChE,SAASC,oBAAoB,QAAQ,cAAW;AAAC,SAAAC,GAAA,IAAAC,IAAA;AAEjD,MAAMC,QAAQ,gBAAGV,UAAU,CAAqB,SAASW,IAAIA,CAC3D;EACEC,kBAAkB;EAClBC,QAAQ;EACRC,QAAQ;EACRC,aAAa;EACbC,OAAO;EACPC,KAAK;EACLC,MAAM;EACN,GAAGC;AACL,CAAC,EACDC,GAAG,EACH;EACAhB,sBAAsB,CAAC,MAAM,CAAC;EAE9B,MAAMiB,OAAO,GAAGnB,MAAM,CAAe,IAAI,CAAC;EAC1C,MAAMoB,SAAS,GAAGpB,MAAM,CAAsC,IAAI,CAAC;EAEnED,mBAAmB,CACjBmB,GAAG,EACH,MACEG,MAAM,CAACC,MAAM,CAACH,OAAO,CAACI,OAAO,EAAG;IAC9BC,IAAIA,CAAA,EAAG;MACL,IAAI,CAACZ,QAAQ,IAAIQ,SAAS,CAACG,OAAO,EAAE;QAClCnB,QAAQ,CAACoB,IAAI,CAACJ,SAAS,CAACG,OAAO,CAAC;MAClC;IACF;EACF,CAAC,CAAC,EACJ,CAACX,QAAQ,CACX,CAAC;EAED,MAAMa,UAAU,GAAGpB,oBAAoB,CAACS,OAAO,CAAC;EAEhD,oBACEP,IAAA,CAACN,IAAI;IAAA,GAAKgB,SAAS;IAAEC,GAAG,EAAEC,OAAQ;IAACO,WAAW,EAAE,KAAM;IAAAf,QAAA,eACpDJ,IAAA,CAACJ,cAAc;MACbe,GAAG,EAAEE,SAAU;MACfV,kBAAkB,EAAEA,kBAAmB;MACvCE,QAAQ,EAAEA,QAAS;MACnBa,UAAU,EAAEA,UAAW;MACvBZ,aAAa,EAAEA,aAAc;MAC7BG,MAAM,EAAEA,MAAO;MACfD,KAAK,EAAEA,KAAM;MAAAJ,QAAA,eAEbJ,IAAA,CAACN,IAAI;QAACyB,WAAW,EAAE,KAAM;QAAAf,QAAA,EAAEA;MAAQ,CAAO;IAAC,CAC7B;EAAC,CACb,CAAC;AAEX,CAAC,CAAC;AAEF,OAAO,MAAMF,IAAI,GAAGD,QAAyB","ignoreList":[]}
@@ -1 +1 @@
1
- {"version":3,"names":["Menu","TipKit","Stepper","ConcentricView","SFSymbol","Popover","PopoverClose","getNativeTinyui","assertComponentEnabled","LiquidGlassText"],"sourceRoot":"../../src","sources":["index.tsx"],"mappings":";;AAAA,SAASA,IAAI,QAAQ,iBAAQ;AAC7B,SAASC,MAAM,QAAQ,mBAAU;AAsBjC,SAASC,OAAO,QAAQ,oBAAW;AAGnC,SAASC,cAAc,QAAQ,2BAAkB;AAGjD,SAASC,QAAQ,QAAQ,qBAAY;AAYrC,SAASC,OAAO,EAAEC,YAAY,QAAQ,oBAAW;AAUjD,SAASC,eAAe,EAAEC,sBAAsB,QAAQ,kBAAS;AAGjE,SAASC,eAAe,QAAQ,4BAAmB","ignoreList":[]}
1
+ {"version":3,"names":["Menu","TipKit","Stepper","ConcentricView","SFSymbol","Popover","PopoverClose","getNativeTinyui","assertComponentEnabled","LiquidGlassText"],"sourceRoot":"../../src","sources":["index.tsx"],"mappings":";;AAAA,SAASA,IAAI,QAAQ,iBAAQ;AAC7B,SAASC,MAAM,QAAQ,mBAAU;AAuBjC,SAASC,OAAO,QAAQ,oBAAW;AAGnC,SAASC,cAAc,QAAQ,2BAAkB;AAGjD,SAASC,QAAQ,QAAQ,qBAAY;AAYrC,SAASC,OAAO,EAAEC,YAAY,QAAQ,oBAAW;AAUjD,SAASC,eAAe,EAAEC,sBAAsB,QAAQ,kBAAS;AAGjE,SAASC,eAAe,QAAQ,4BAAmB","ignoreList":[]}
@@ -1,4 +1,5 @@
1
- import { type CodegenTypes, type ViewProps } from 'react-native';
1
+ import type * as React from 'react';
2
+ import { type CodegenTypes, type HostComponent, type ViewProps } from 'react-native';
2
3
  import type { DirectEventHandler } from 'react-native/Libraries/Types/CodegenTypes';
3
4
  export interface NativeMenuProps extends ViewProps {
4
5
  menuConfig: CodegenTypes.UnsafeMixed;
@@ -9,6 +10,10 @@ export interface NativeMenuProps extends ViewProps {
9
10
  title: string;
10
11
  }>>;
11
12
  }
13
+ interface NativeCommands {
14
+ open: (viewRef: React.ComponentRef<HostComponent<NativeMenuProps>>) => void;
15
+ }
16
+ export declare const Commands: NativeCommands;
12
17
  declare const _default: import("react-native/types_generated/Libraries/Utilities/codegenNativeComponent").NativeComponentType<NativeMenuProps>;
13
18
  export default _default;
14
19
  //# sourceMappingURL=MenuNativeComponent.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"MenuNativeComponent.d.ts","sourceRoot":"","sources":["../../../../src/Menu/MenuNativeComponent.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,KAAK,YAAY,EACjB,KAAK,SAAS,EACf,MAAM,cAAc,CAAC;AACtB,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,2CAA2C,CAAC;AAEpF,MAAM,WAAW,eAAgB,SAAQ,SAAS;IAChD,UAAU,EAAE,YAAY,CAAC,WAAW,CAAC;IACrC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,aAAa,CAAC,EAAE,kBAAkB,CAAC,QAAQ,CAAC;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC,CAAC;CAC7E;;AAED,wBAEG"}
1
+ {"version":3,"file":"MenuNativeComponent.d.ts","sourceRoot":"","sources":["../../../../src/Menu/MenuNativeComponent.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,KAAK,MAAM,OAAO,CAAC;AACpC,OAAO,EAGL,KAAK,YAAY,EACjB,KAAK,aAAa,EAClB,KAAK,SAAS,EACf,MAAM,cAAc,CAAC;AACtB,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,2CAA2C,CAAC;AAEpF,MAAM,WAAW,eAAgB,SAAQ,SAAS;IAChD,UAAU,EAAE,YAAY,CAAC,WAAW,CAAC;IACrC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,aAAa,CAAC,EAAE,kBAAkB,CAAC,QAAQ,CAAC;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC,CAAC;CAC7E;AAED,UAAU,cAAc;IACtB,IAAI,EAAE,CAAC,OAAO,EAAE,KAAK,CAAC,YAAY,CAAC,aAAa,CAAC,eAAe,CAAC,CAAC,KAAK,IAAI,CAAC;CAC7E;AAED,eAAO,MAAM,QAAQ,gBAEnB,CAAC;;AAEH,wBAEG"}
@@ -1,4 +1,4 @@
1
1
  import type { MenuComponent } from './types.js';
2
2
  export declare const Menu: MenuComponent;
3
- export type { MenuActionOption, MenuActionPressEvent, MenuActionPressEventData, MenuDividerOption, MenuItemState, MenuOption, MenuProps, MenuSectionOption, MenuSubmenuOption, } from './types.js';
3
+ export type { MenuActionOption, MenuActionPressEvent, MenuActionPressEventData, MenuDividerOption, MenuItemState, MenuOption, MenuProps, MenuRef, MenuSectionOption, MenuSubmenuOption, } from './types.js';
4
4
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/Menu/index.tsx"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,aAAa,EAAa,MAAM,YAAS,CAAC;AAqCxD,eAAO,MAAM,IAAI,EAAe,aAAa,CAAC;AAE9C,YAAY,EACV,gBAAgB,EAChB,oBAAoB,EACpB,wBAAwB,EACxB,iBAAiB,EACjB,aAAa,EACb,UAAU,EACV,SAAS,EACT,iBAAiB,EACjB,iBAAiB,GAClB,MAAM,YAAS,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/Menu/index.tsx"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAE,aAAa,EAAsB,MAAM,YAAS,CAAC;AAsDjE,eAAO,MAAM,IAAI,EAAe,aAAa,CAAC;AAE9C,YAAY,EACV,gBAAgB,EAChB,oBAAoB,EACpB,wBAAwB,EACxB,iBAAiB,EACjB,aAAa,EACb,UAAU,EACV,SAAS,EACT,OAAO,EACP,iBAAiB,EACjB,iBAAiB,GAClB,MAAM,YAAS,CAAC"}
@@ -1,5 +1,5 @@
1
- import type { ComponentRef, ForwardRefExoticComponent, ReactNode, RefAttributes } from 'react';
2
- import type { ColorValue, View, ViewProps } from 'react-native';
1
+ import type { ForwardRefExoticComponent, ReactNode, RefAttributes } from 'react';
2
+ import type { ColorValue, HostInstance, ViewProps } from 'react-native';
3
3
  export type MenuItemState = 'off' | 'on' | 'mixed';
4
4
  interface MenuOptionLabel {
5
5
  title: string;
@@ -59,6 +59,13 @@ export interface MenuActionPressEventData {
59
59
  export type MenuActionPressEvent = Readonly<{
60
60
  nativeEvent: Readonly<MenuActionPressEventData>;
61
61
  }>;
62
+ export type MenuRef = HostInstance & {
63
+ /**
64
+ * Opens the menu at its mounted trigger on iOS 17.4 and newer.
65
+ * Does nothing on older iOS versions or while disabled or detached.
66
+ */
67
+ open(): void;
68
+ };
62
69
  export interface MenuProps extends Omit<ViewProps, 'children'> {
63
70
  /** The trigger element. */
64
71
  children: ReactNode;
@@ -71,7 +78,7 @@ export interface MenuProps extends Omit<ViewProps, 'children'> {
71
78
  /** Called whenever an enabled action is selected. */
72
79
  onActionPress?: (event: MenuActionPressEvent) => void;
73
80
  }
74
- export interface MenuComponent extends ForwardRefExoticComponent<MenuProps & RefAttributes<ComponentRef<typeof View>>> {
81
+ export interface MenuComponent extends ForwardRefExoticComponent<MenuProps & RefAttributes<MenuRef>> {
75
82
  }
76
83
  export {};
77
84
  //# sourceMappingURL=types.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../../src/Menu/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,YAAY,EACZ,yBAAyB,EACzB,SAAS,EACT,aAAa,EACd,MAAM,OAAO,CAAC;AACf,OAAO,KAAK,EAAE,UAAU,EAAE,IAAI,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAEhE,MAAM,MAAM,aAAa,GAAG,KAAK,GAAG,IAAI,GAAG,OAAO,CAAC;AAEnD,UAAU,eAAe;IACvB,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,sBAAsB;IACtB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,+FAA+F;IAC/F,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,+CAA+C;IAC/C,SAAS,CAAC,EAAE,UAAU,CAAC;IACvB;;;;OAIG;IACH,UAAU,CAAC,EAAE,UAAU,CAAC;CACzB;AAED,MAAM,WAAW,gBAAiB,SAAQ,eAAe;IACvD,mEAAmE;IACnE,IAAI,CAAC,EAAE,QAAQ,CAAC;IAChB,gEAAgE;IAChE,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,KAAK,CAAC,EAAE,aAAa,CAAC;IACtB,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,iEAAiE;IACjE,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAED,MAAM,WAAW,iBAAkB,SAAQ,eAAe;IACxD,IAAI,EAAE,SAAS,CAAC;IAChB,yDAAyD;IACzD,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,8CAA8C;IAC9C,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,kDAAkD;IAClD,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,qEAAqE;IACrE,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,OAAO,EAAE,SAAS,UAAU,EAAE,CAAC;CAChC;AAED,MAAM,WAAW,iBAAiB;IAChC,IAAI,EAAE,SAAS,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,SAAS,UAAU,EAAE,CAAC;CAChC;AAED,MAAM,WAAW,iBAAiB;IAChC,IAAI,EAAE,SAAS,CAAC;CACjB;AAED,MAAM,MAAM,UAAU,GACpB,gBAAgB,GAAG,iBAAiB,GAAG,iBAAiB,GAAG,iBAAiB,CAAC;AAE/E,MAAM,WAAW,wBAAwB;IACvC,wEAAwE;IACxE,EAAE,EAAE,MAAM,CAAC;IACX,6CAA6C;IAC7C,KAAK,EAAE,MAAM,CAAC;CACf;AAED,MAAM,MAAM,oBAAoB,GAAG,QAAQ,CAAC;IAC1C,WAAW,EAAE,QAAQ,CAAC,wBAAwB,CAAC,CAAC;CACjD,CAAC,CAAC;AAEH,MAAM,WAAW,SAAU,SAAQ,IAAI,CAAC,SAAS,EAAE,UAAU,CAAC;IAC5D,2BAA2B;IAC3B,QAAQ,EAAE,SAAS,CAAC;IACpB,8DAA8D;IAC9D,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,6DAA6D;IAC7D,OAAO,EAAE,SAAS,UAAU,EAAE,CAAC;IAC/B,kDAAkD;IAClD,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,qDAAqD;IACrD,aAAa,CAAC,EAAE,CAAC,KAAK,EAAE,oBAAoB,KAAK,IAAI,CAAC;CACvD;AAED,MAAM,WAAW,aAAc,SAAQ,yBAAyB,CAC9D,SAAS,GAAG,aAAa,CAAC,YAAY,CAAC,OAAO,IAAI,CAAC,CAAC,CACrD;CAAG"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../../src/Menu/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,yBAAyB,EACzB,SAAS,EACT,aAAa,EACd,MAAM,OAAO,CAAC;AACf,OAAO,KAAK,EAAE,UAAU,EAAE,YAAY,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAExE,MAAM,MAAM,aAAa,GAAG,KAAK,GAAG,IAAI,GAAG,OAAO,CAAC;AAEnD,UAAU,eAAe;IACvB,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,sBAAsB;IACtB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,+FAA+F;IAC/F,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,+CAA+C;IAC/C,SAAS,CAAC,EAAE,UAAU,CAAC;IACvB;;;;OAIG;IACH,UAAU,CAAC,EAAE,UAAU,CAAC;CACzB;AAED,MAAM,WAAW,gBAAiB,SAAQ,eAAe;IACvD,mEAAmE;IACnE,IAAI,CAAC,EAAE,QAAQ,CAAC;IAChB,gEAAgE;IAChE,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,KAAK,CAAC,EAAE,aAAa,CAAC;IACtB,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,iEAAiE;IACjE,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAED,MAAM,WAAW,iBAAkB,SAAQ,eAAe;IACxD,IAAI,EAAE,SAAS,CAAC;IAChB,yDAAyD;IACzD,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,8CAA8C;IAC9C,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,kDAAkD;IAClD,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,qEAAqE;IACrE,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,OAAO,EAAE,SAAS,UAAU,EAAE,CAAC;CAChC;AAED,MAAM,WAAW,iBAAiB;IAChC,IAAI,EAAE,SAAS,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,SAAS,UAAU,EAAE,CAAC;CAChC;AAED,MAAM,WAAW,iBAAiB;IAChC,IAAI,EAAE,SAAS,CAAC;CACjB;AAED,MAAM,MAAM,UAAU,GACpB,gBAAgB,GAAG,iBAAiB,GAAG,iBAAiB,GAAG,iBAAiB,CAAC;AAE/E,MAAM,WAAW,wBAAwB;IACvC,wEAAwE;IACxE,EAAE,EAAE,MAAM,CAAC;IACX,6CAA6C;IAC7C,KAAK,EAAE,MAAM,CAAC;CACf;AAED,MAAM,MAAM,oBAAoB,GAAG,QAAQ,CAAC;IAC1C,WAAW,EAAE,QAAQ,CAAC,wBAAwB,CAAC,CAAC;CACjD,CAAC,CAAC;AAEH,MAAM,MAAM,OAAO,GAAG,YAAY,GAAG;IACnC;;;OAGG;IACH,IAAI,IAAI,IAAI,CAAC;CACd,CAAC;AAEF,MAAM,WAAW,SAAU,SAAQ,IAAI,CAAC,SAAS,EAAE,UAAU,CAAC;IAC5D,2BAA2B;IAC3B,QAAQ,EAAE,SAAS,CAAC;IACpB,8DAA8D;IAC9D,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,6DAA6D;IAC7D,OAAO,EAAE,SAAS,UAAU,EAAE,CAAC;IAC/B,kDAAkD;IAClD,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,qDAAqD;IACrD,aAAa,CAAC,EAAE,CAAC,KAAK,EAAE,oBAAoB,KAAK,IAAI,CAAC;CACvD;AAED,MAAM,WAAW,aAAc,SAAQ,yBAAyB,CAC9D,SAAS,GAAG,aAAa,CAAC,OAAO,CAAC,CACnC;CAAG"}
@@ -1,7 +1,7 @@
1
1
  export { Menu } from './Menu/index.js';
2
2
  export { TipKit } from './TipKit/index.js';
3
3
  export type { TipAction, TipDisplayFrequency, TipError, TipInvalidationReason, TipPopoverProps, TipKitConfiguration, TipStatus, } from './TipKit/index.js';
4
- export type { MenuActionOption, MenuActionPressEvent, MenuActionPressEventData, MenuDividerOption, MenuItemState, MenuOption, MenuProps, MenuSectionOption, MenuSubmenuOption, } from './Menu/index.js';
4
+ export type { MenuActionOption, MenuActionPressEvent, MenuActionPressEventData, MenuDividerOption, MenuItemState, MenuOption, MenuProps, MenuRef, MenuSectionOption, MenuSubmenuOption, } from './Menu/index.js';
5
5
  export { Stepper } from './Stepper/index.js';
6
6
  export type { StepperProps } from './Stepper/index.js';
7
7
  export { ConcentricView } from './ConcentricView/index.js';
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/index.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,iBAAQ,CAAC;AAC9B,OAAO,EAAE,MAAM,EAAE,MAAM,mBAAU,CAAC;AAClC,YAAY,EACV,SAAS,EACT,mBAAmB,EACnB,QAAQ,EACR,qBAAqB,EACrB,eAAe,EACf,mBAAmB,EACnB,SAAS,GACV,MAAM,mBAAU,CAAC;AAClB,YAAY,EACV,gBAAgB,EAChB,oBAAoB,EACpB,wBAAwB,EACxB,iBAAiB,EACjB,aAAa,EACb,UAAU,EACV,SAAS,EACT,iBAAiB,EACjB,iBAAiB,GAClB,MAAM,iBAAQ,CAAC;AAEhB,OAAO,EAAE,OAAO,EAAE,MAAM,oBAAW,CAAC;AACpC,YAAY,EAAE,YAAY,EAAE,MAAM,oBAAW,CAAC;AAE9C,OAAO,EAAE,cAAc,EAAE,MAAM,2BAAkB,CAAC;AAClD,YAAY,EAAE,mBAAmB,EAAE,MAAM,2BAAkB,CAAC;AAE5D,OAAO,EAAE,QAAQ,EAAE,MAAM,qBAAY,CAAC;AACtC,YAAY,EACV,yBAAyB,EACzB,cAAc,EACd,qBAAqB,EACrB,aAAa,EACb,qBAAqB,EACrB,aAAa,EACb,iBAAiB,EACjB,cAAc,GACf,MAAM,qBAAY,CAAC;AAEpB,OAAO,EAAE,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAW,CAAC;AAClD,YAAY,EACV,gBAAgB,EAChB,uBAAuB,EACvB,iBAAiB,EACjB,cAAc,EACd,wBAAwB,EACxB,YAAY,GACb,MAAM,oBAAW,CAAC;AAEnB,OAAO,EAAE,eAAe,EAAE,sBAAsB,EAAE,MAAM,kBAAS,CAAC;AAClE,YAAY,EAAE,eAAe,EAAE,MAAM,kBAAS,CAAC;AAE/C,OAAO,EAAE,eAAe,EAAE,MAAM,4BAAmB,CAAC;AACpD,YAAY,EACV,yBAAyB,EACzB,qBAAqB,EACrB,oBAAoB,EACpB,oBAAoB,GACrB,MAAM,4BAAmB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/index.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,iBAAQ,CAAC;AAC9B,OAAO,EAAE,MAAM,EAAE,MAAM,mBAAU,CAAC;AAClC,YAAY,EACV,SAAS,EACT,mBAAmB,EACnB,QAAQ,EACR,qBAAqB,EACrB,eAAe,EACf,mBAAmB,EACnB,SAAS,GACV,MAAM,mBAAU,CAAC;AAClB,YAAY,EACV,gBAAgB,EAChB,oBAAoB,EACpB,wBAAwB,EACxB,iBAAiB,EACjB,aAAa,EACb,UAAU,EACV,SAAS,EACT,OAAO,EACP,iBAAiB,EACjB,iBAAiB,GAClB,MAAM,iBAAQ,CAAC;AAEhB,OAAO,EAAE,OAAO,EAAE,MAAM,oBAAW,CAAC;AACpC,YAAY,EAAE,YAAY,EAAE,MAAM,oBAAW,CAAC;AAE9C,OAAO,EAAE,cAAc,EAAE,MAAM,2BAAkB,CAAC;AAClD,YAAY,EAAE,mBAAmB,EAAE,MAAM,2BAAkB,CAAC;AAE5D,OAAO,EAAE,QAAQ,EAAE,MAAM,qBAAY,CAAC;AACtC,YAAY,EACV,yBAAyB,EACzB,cAAc,EACd,qBAAqB,EACrB,aAAa,EACb,qBAAqB,EACrB,aAAa,EACb,iBAAiB,EACjB,cAAc,GACf,MAAM,qBAAY,CAAC;AAEpB,OAAO,EAAE,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAW,CAAC;AAClD,YAAY,EACV,gBAAgB,EAChB,uBAAuB,EACvB,iBAAiB,EACjB,cAAc,EACd,wBAAwB,EACxB,YAAY,GACb,MAAM,oBAAW,CAAC;AAEnB,OAAO,EAAE,eAAe,EAAE,sBAAsB,EAAE,MAAM,kBAAS,CAAC;AAClE,YAAY,EAAE,eAAe,EAAE,MAAM,kBAAS,CAAC;AAE/C,OAAO,EAAE,eAAe,EAAE,MAAM,4BAAmB,CAAC;AACpD,YAAY,EACV,yBAAyB,EACzB,qBAAqB,EACrB,oBAAoB,EACpB,oBAAoB,GACrB,MAAM,4BAAmB,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "react-native-tinyui",
3
- "version": "1.0.0",
3
+ "version": "1.1.1",
4
4
  "description": "Dependency-free native iOS Menu, Popover, TipKit, Stepper, ConcentricView, SFSymbol and LiquidGlassText components for React Native",
5
5
  "main": "./lib/module/index.js",
6
6
  "types": "./lib/typescript/src/index.d.ts",
@@ -1,6 +1,9 @@
1
+ import type * as React from 'react';
1
2
  import {
2
3
  codegenNativeComponent,
4
+ codegenNativeCommands,
3
5
  type CodegenTypes,
6
+ type HostComponent,
4
7
  type ViewProps,
5
8
  } from 'react-native';
6
9
  import type { DirectEventHandler } from 'react-native/Libraries/Types/CodegenTypes';
@@ -12,6 +15,14 @@ export interface NativeMenuProps extends ViewProps {
12
15
  onActionPress?: DirectEventHandler<Readonly<{ id: string; title: string }>>;
13
16
  }
14
17
 
18
+ interface NativeCommands {
19
+ open: (viewRef: React.ComponentRef<HostComponent<NativeMenuProps>>) => void;
20
+ }
21
+
22
+ export const Commands = codegenNativeCommands<NativeCommands>({
23
+ supportedCommands: ['open'],
24
+ });
25
+
15
26
  export default codegenNativeComponent<NativeMenuProps>('TinyuiMenuView', {
16
27
  excludedPlatforms: ['android'],
17
28
  });
@@ -1,12 +1,17 @@
1
- import { forwardRef, type ComponentRef } from 'react';
2
- import { View } from 'react-native';
1
+ import {
2
+ forwardRef,
3
+ useImperativeHandle,
4
+ useRef,
5
+ type ComponentRef,
6
+ } from 'react';
7
+ import { View, type HostInstance } from 'react-native';
3
8
 
4
9
  import { assertComponentEnabled } from '../utils';
5
- import type { MenuComponent, MenuProps } from './types';
6
- import NativeMenuView from './MenuNativeComponent';
10
+ import type { MenuComponent, MenuProps, MenuRef } from './types';
11
+ import NativeMenuView, { Commands } from './MenuNativeComponent';
7
12
  import { serializeMenuOptions } from './options';
8
13
 
9
- const MenuRoot = forwardRef<ComponentRef<typeof View>, MenuProps>(function Menu(
14
+ const MenuRoot = forwardRef<MenuRef, MenuProps>(function Menu(
10
15
  {
11
16
  accessibilityLabel,
12
17
  children,
@@ -21,11 +26,28 @@ const MenuRoot = forwardRef<ComponentRef<typeof View>, MenuProps>(function Menu(
21
26
  ) {
22
27
  assertComponentEnabled('Menu');
23
28
 
29
+ const viewRef = useRef<HostInstance>(null);
30
+ const nativeRef = useRef<ComponentRef<typeof NativeMenuView>>(null);
31
+
32
+ useImperativeHandle(
33
+ ref,
34
+ () =>
35
+ Object.assign(viewRef.current!, {
36
+ open() {
37
+ if (!disabled && nativeRef.current) {
38
+ Commands.open(nativeRef.current);
39
+ }
40
+ },
41
+ }),
42
+ [disabled]
43
+ );
44
+
24
45
  const menuConfig = serializeMenuOptions(options);
25
46
 
26
47
  return (
27
- <View {...viewProps} ref={ref} collapsable={false}>
48
+ <View {...viewProps} ref={viewRef} collapsable={false}>
28
49
  <NativeMenuView
50
+ ref={nativeRef}
29
51
  accessibilityLabel={accessibilityLabel}
30
52
  disabled={disabled}
31
53
  menuConfig={menuConfig}
@@ -49,6 +71,7 @@ export type {
49
71
  MenuItemState,
50
72
  MenuOption,
51
73
  MenuProps,
74
+ MenuRef,
52
75
  MenuSectionOption,
53
76
  MenuSubmenuOption,
54
77
  } from './types';
package/src/Menu/types.ts CHANGED
@@ -1,10 +1,9 @@
1
1
  import type {
2
- ComponentRef,
3
2
  ForwardRefExoticComponent,
4
3
  ReactNode,
5
4
  RefAttributes,
6
5
  } from 'react';
7
- import type { ColorValue, View, ViewProps } from 'react-native';
6
+ import type { ColorValue, HostInstance, ViewProps } from 'react-native';
8
7
 
9
8
  export type MenuItemState = 'off' | 'on' | 'mixed';
10
9
 
@@ -75,6 +74,14 @@ export type MenuActionPressEvent = Readonly<{
75
74
  nativeEvent: Readonly<MenuActionPressEventData>;
76
75
  }>;
77
76
 
77
+ export type MenuRef = HostInstance & {
78
+ /**
79
+ * Opens the menu at its mounted trigger on iOS 17.4 and newer.
80
+ * Does nothing on older iOS versions or while disabled or detached.
81
+ */
82
+ open(): void;
83
+ };
84
+
78
85
  export interface MenuProps extends Omit<ViewProps, 'children'> {
79
86
  /** The trigger element. */
80
87
  children: ReactNode;
@@ -89,5 +96,5 @@ export interface MenuProps extends Omit<ViewProps, 'children'> {
89
96
  }
90
97
 
91
98
  export interface MenuComponent extends ForwardRefExoticComponent<
92
- MenuProps & RefAttributes<ComponentRef<typeof View>>
99
+ MenuProps & RefAttributes<MenuRef>
93
100
  > {}
package/src/index.tsx CHANGED
@@ -17,6 +17,7 @@ export type {
17
17
  MenuItemState,
18
18
  MenuOption,
19
19
  MenuProps,
20
+ MenuRef,
20
21
  MenuSectionOption,
21
22
  MenuSubmenuOption,
22
23
  } from './Menu';