react-native-native-select 1.0.0

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 ADDED
@@ -0,0 +1,109 @@
1
+ # react-native-native-select
2
+
3
+ A strictly native, performant Select component for React Native built exclusively for the **New Architecture**.
4
+
5
+ It leverages actual OS primitives: `UIMenu` (iOS 14+), `UIPickerView` (iOS Wheel), and `AppCompatSpinner` (Android), offering a truly native look and feel that JS-based libraries cannot match.
6
+
7
+ ## Preview
8
+
9
+ | iOS (Dropdown Mode) | iOS (Dialog/Wheel Mode) | Android |
10
+ |:---:|:---:|:---:|
11
+ | *[Insert Screenshot of iOS Select with open Menu]* | *[Insert Screenshot of iOS Bottom Wheel picker]* | *[Insert Screenshot of Android Dropdown]* |
12
+ | *Native UIMenu (iOS 14+)* | *Classic UIPickerView* | *Native AppCompatSpinner* |
13
+
14
+ ## Why this library?
15
+
16
+ Most Select/Picker libraries in the React Native ecosystem fall into two categories:
17
+ 1. **JS-based Simulations:** They render a Modal with a FlatList. They are customizable but feel "off" compared to the OS native UI and often lack accessibility standards like [`react-native-picker-select`](https://www.npmjs.com/package/react-native-picker-select).
18
+ 2. **Legacy Wrappers:** Libraries like [`@react-native-picker/picker`](https://www.npmjs.com/package/@react-native-picker/picker) are excellent but often rely on the old bridge or split functionality across different components.
19
+
20
+ **react-native-native-select** is designed for modern apps:
21
+ * **Zero JS Thread Overhead:** Fully native implementation using Fabric.
22
+ * **Modern iOS UI:** Supports the iOS 14+ `pull-down` menu style out of the box.
23
+ * **Native Performance:** Interactions run on the UI thread.
24
+
25
+ ## Requirements
26
+
27
+ * **React Native:** >= 0.71.0
28
+ * **Architecture:** New Architecture **Enabled**
29
+ * **iOS:** 14.0+ (for Dropdown mode), 11.0+ (for Dialog mode)
30
+
31
+ ## Installation
32
+
33
+ ```bash
34
+ npm install react-native-native-select
35
+ # or
36
+ yarn add react-native-native-select
37
+ ```
38
+
39
+ ### iOS Setup
40
+
41
+ Since this library uses native modules, you must run pod install:
42
+
43
+ ```bash
44
+ cd ios && pod install
45
+ ```
46
+
47
+ ## Usage
48
+
49
+ ```tsx
50
+ import { StyleSheet, View, Text } from 'react-native';
51
+ import { Select } from 'react-native-native-select';
52
+
53
+ export default function App() {
54
+ return (
55
+ <View style={styles.container}>
56
+ <Text style={styles.label}>Choose a fruit:</Text>
57
+
58
+ <Select
59
+ style={styles.select}
60
+ mode="dropdown"
61
+ options={["Apple", "Banana", "Orange", "Mango"]}
62
+ selectedIndex={0}
63
+ onValueChange={(e) => {
64
+ console.log("Selected Item:", e.nativeEvent.value); // Ex: "Apple"
65
+ console.log("Selected Index:", e.nativeEvent.index); // Ex: 0
66
+ }}
67
+ />
68
+ </View>
69
+ );
70
+ }
71
+
72
+ const styles = StyleSheet.create({
73
+ container: {
74
+ flex: 1,
75
+ justifyContent: 'center',
76
+ padding: 20,
77
+ },
78
+ label: {
79
+ marginBottom: 10,
80
+ fontSize: 16,
81
+ },
82
+ select: {
83
+ width: '100%',
84
+ height: 50, // Height is required for layout calculation
85
+ },
86
+ });
87
+ ```
88
+
89
+ ### Android Usage
90
+
91
+ Please take a look at this [Android example usage](./tests/android_demo.tsx) because the native component is not updating the visual state at the moment
92
+
93
+ ## Props
94
+
95
+ | Prop | Type | Required | Description |
96
+ | :--- | :--- | :---: | :--- |
97
+ | **`options`** | `string[]` | **Yes** | An array of strings to display in the list. |
98
+ | **`selectedIndex`** | `number` | No | The index of the currently selected item. Defaults to `0`. |
99
+ | **`mode`** | `'dropdown' \| 'dialog'` | No | **iOS Only.** <br>`dropdown`: Uses `UIMenu` (Modern iOS 14+). <br>`dialog`: Uses `UIPickerView` (Classic Wheel). <br> *On Android, this prop is ignored as it always uses the native Spinner.* |
100
+ | **`onValueChange`** | `function` | No | Callback fired when an item is selected. Returns `{ value: string, index: number }`. |
101
+ | **`style`** | `ViewStyle` | No | Standard style prop. **Note:** You must define `width` and `height` for the view to render correctly. |
102
+
103
+ ## Troubleshooting
104
+
105
+ **The component is visible but empty (Empty space)**
106
+ Ensure you have defined a `width` and `height` in the `style` prop. Native views on iOS require explicit dimensions or Flexbox constraints to render their subviews correctly.
107
+
108
+ **App crashes on launch**
109
+ Ensure `RCT_NEW_ARCH_ENABLED=1` was present when you ran `pod install`. This library does not support the old React Native Bridge.
@@ -0,0 +1,36 @@
1
+ buildscript {
2
+ ext.safeExtGet = {prop, fallback ->
3
+ rootProject.ext.has(prop) ? rootProject.ext.get(prop) : fallback
4
+ }
5
+ repositories {
6
+ google()
7
+ gradlePluginPortal()
8
+ }
9
+ dependencies {
10
+ classpath("com.android.tools.build:gradle:7.2.0")
11
+ }
12
+ }
13
+
14
+ apply plugin: 'com.android.library'
15
+ apply plugin: 'com.facebook.react'
16
+
17
+ android {
18
+ compileSdkVersion safeExtGet('compileSdkVersion', 31)
19
+
20
+ defaultConfig {
21
+ minSdkVersion safeExtGet('minSdkVersion', 21)
22
+ targetSdkVersion safeExtGet('targetSdkVersion', 31)
23
+ }
24
+ }
25
+
26
+ repositories {
27
+ maven {
28
+ url "$projectDir/../node_modules/react-native/android"
29
+ }
30
+ mavenCentral()
31
+ google()
32
+ }
33
+
34
+ dependencies {
35
+ implementation 'com.facebook.react:react-native:+'
36
+ }
@@ -0,0 +1,3 @@
1
+ <manifest xmlns:android="http://schemas.android.com/apk/res/android"
2
+ package="com.rtnselect">
3
+ </manifest>
@@ -0,0 +1,127 @@
1
+ package com.rtnselect;
2
+
3
+ import android.content.Context;
4
+ import android.util.AttributeSet;
5
+ import android.util.Log;
6
+ import android.view.View;
7
+ import android.widget.AdapterView;
8
+ import android.widget.ArrayAdapter;
9
+ import androidx.annotation.Nullable;
10
+ import androidx.appcompat.widget.AppCompatSpinner;
11
+
12
+ import com.facebook.react.bridge.Arguments;
13
+ import com.facebook.react.bridge.ReactContext;
14
+ import com.facebook.react.bridge.WritableMap;
15
+ import com.facebook.react.uimanager.events.RCTEventEmitter;
16
+
17
+ import java.util.List;
18
+
19
+ public class SelectView extends AppCompatSpinner implements AdapterView.OnItemSelectedListener {
20
+
21
+ private final String TAG = "RTNSelect";
22
+
23
+ public SelectView(Context context) {
24
+ super(context);
25
+ init();
26
+ }
27
+
28
+ public SelectView(Context context, @Nullable AttributeSet attrs) {
29
+ super(context, attrs);
30
+ init();
31
+ }
32
+
33
+ public SelectView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
34
+ super(context, attrs, defStyleAttr);
35
+ init();
36
+ }
37
+
38
+ private void init() {
39
+ this.setOnItemSelectedListener(this);
40
+ }
41
+
42
+ @Override
43
+ public boolean performClick() {
44
+ boolean result = super.performClick();
45
+ return result;
46
+ }
47
+
48
+ @Override
49
+ protected void onAttachedToWindow() {
50
+ super.onAttachedToWindow();
51
+ }
52
+
53
+ @Override
54
+ protected void onDetachedFromWindow() {
55
+ super.onDetachedFromWindow();
56
+ }
57
+
58
+ public void setOptions(List<String> options) {
59
+
60
+ ArrayAdapter<String> adapter = new ArrayAdapter<>(getContext(), android.R.layout.simple_spinner_item, options);
61
+ adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
62
+
63
+ this.setAdapter(adapter);
64
+ }
65
+
66
+ @Override
67
+ public void setSelection(int position) {
68
+
69
+ this.post(new Runnable() {
70
+ @Override
71
+ public void run() {
72
+ SelectView.super.setSelection(position);
73
+ }
74
+ });
75
+
76
+ ReactContext reactContext = (ReactContext) getContext();
77
+ if (reactContext != null) {
78
+ String val = "unknown";
79
+ if (getAdapter() != null && getAdapter().getCount() > position) {
80
+ Object item = getAdapter().getItem(position);
81
+ if (item != null) val = item.toString();
82
+ }
83
+
84
+ WritableMap event = Arguments.createMap();
85
+ event.putString("value", val);
86
+ event.putInt("index", position);
87
+
88
+ try {
89
+ reactContext.getJSModule(RCTEventEmitter.class).receiveEvent(
90
+ getId(),
91
+ "topValueChange",
92
+ event
93
+ );
94
+ } catch (Exception e) {
95
+ }
96
+ }
97
+ }
98
+
99
+ @Override
100
+ public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
101
+ String val = "null";
102
+ if (parent != null && parent.getItemAtPosition(position) != null) {
103
+ val = parent.getItemAtPosition(position).toString();
104
+ }
105
+
106
+ ReactContext reactContext = (ReactContext) getContext();
107
+ if (reactContext != null) {
108
+ WritableMap event = Arguments.createMap();
109
+ event.putString("value", val);
110
+ event.putInt("index", position);
111
+
112
+ try {
113
+ reactContext.getJSModule(RCTEventEmitter.class).receiveEvent(
114
+ getId(),
115
+ "topValueChange",
116
+ event
117
+ );
118
+ } catch (Exception e) {
119
+ }
120
+ } else {
121
+ }
122
+ }
123
+
124
+ @Override
125
+ public void onNothingSelected(AdapterView<?> parent) {
126
+ }
127
+ }
@@ -0,0 +1,83 @@
1
+ package com.rtnselect;
2
+
3
+ import androidx.annotation.NonNull;
4
+ import androidx.annotation.Nullable;
5
+
6
+ import com.facebook.react.bridge.ReactApplicationContext;
7
+ import com.facebook.react.bridge.ReactContext;
8
+ import com.facebook.react.bridge.ReadableArray;
9
+ import com.facebook.react.common.MapBuilder;
10
+ import com.facebook.react.module.annotations.ReactModule;
11
+ import com.facebook.react.uimanager.SimpleViewManager;
12
+ import com.facebook.react.uimanager.ThemedReactContext;
13
+ import com.facebook.react.uimanager.ViewManagerDelegate;
14
+ import com.facebook.react.uimanager.annotations.ReactProp;
15
+ import com.facebook.react.viewmanagers.RTNSelectManagerDelegate;
16
+ import com.facebook.react.viewmanagers.RTNSelectManagerInterface;
17
+
18
+ import java.util.ArrayList;
19
+ import java.util.Map;
20
+
21
+ @ReactModule(name = SelectViewManager.REACT_CLASS)
22
+ public class SelectViewManager extends SimpleViewManager<SelectView>
23
+ implements RTNSelectManagerInterface<SelectView> {
24
+
25
+ public static final String REACT_CLASS = "RTNSelect";
26
+ private final ViewManagerDelegate<SelectView> mDelegate;
27
+
28
+ public SelectViewManager(ReactApplicationContext reactContext) {
29
+ mDelegate = new RTNSelectManagerDelegate<>(this);
30
+ }
31
+
32
+ @Nullable
33
+ @Override
34
+ protected ViewManagerDelegate<SelectView> getDelegate() {
35
+ return mDelegate;
36
+ }
37
+
38
+ @NonNull
39
+ @Override
40
+ public String getName() {
41
+ return REACT_CLASS;
42
+ }
43
+
44
+ @Nullable
45
+ @Override
46
+ public Map<String, Object> getExportedCustomDirectEventTypeConstants() {
47
+ // Strict mapping: Native 'topValueChange' -> JS 'onValueChange'
48
+ return MapBuilder.of(
49
+ "topValueChange",
50
+ MapBuilder.of("registrationName", "onValueChange")
51
+ );
52
+ }
53
+
54
+ @NonNull
55
+ @Override
56
+ protected SelectView createViewInstance(@NonNull ThemedReactContext reactContext) {
57
+ return new SelectView(reactContext);
58
+ }
59
+
60
+ @Override
61
+ @ReactProp(name = "options")
62
+ public void setOptions(SelectView view, @Nullable ReadableArray value) {
63
+ ArrayList<String> list = new ArrayList<>();
64
+ if (value != null) {
65
+ for (int i = 0; i < value.size(); i++) {
66
+ list.add(value.getString(i));
67
+ }
68
+ }
69
+ view.setOptions(list);
70
+ }
71
+
72
+ @Override
73
+ @ReactProp(name = "selectedIndex")
74
+ public void setSelectedIndex(SelectView view, int value) {
75
+ view.setSelection(value);
76
+ }
77
+
78
+ @Override
79
+ @ReactProp(name = "mode")
80
+ public void setMode(SelectView view, @Nullable String value) {}
81
+
82
+ public void setOnValueChange(SelectView view, @Nullable Object value) {}
83
+ }
@@ -0,0 +1,21 @@
1
+ package com.rtnselect;
2
+
3
+ import com.facebook.react.ReactPackage;
4
+ import com.facebook.react.bridge.NativeModule;
5
+ import com.facebook.react.bridge.ReactApplicationContext;
6
+ import com.facebook.react.uimanager.ViewManager;
7
+
8
+ import java.util.Collections;
9
+ import java.util.List;
10
+
11
+ public class SelectViewPackage implements ReactPackage {
12
+ @Override
13
+ public List<ViewManager> createViewManagers(ReactApplicationContext reactContext) {
14
+ return Collections.singletonList(new SelectViewManager(reactContext));
15
+ }
16
+
17
+ @Override
18
+ public List<NativeModule> createNativeModules(ReactApplicationContext reactContext) {
19
+ return Collections.emptyList();
20
+ }
21
+ }
@@ -0,0 +1,10 @@
1
+ #import <React/RCTViewComponentView.h>
2
+ #import <UIKit/UIKit.h>
3
+
4
+ NS_ASSUME_NONNULL_BEGIN
5
+
6
+ @interface RTNSelect : RCTViewComponentView <UIPickerViewDataSource, UIPickerViewDelegate>
7
+
8
+ @end
9
+
10
+ NS_ASSUME_NONNULL_END
@@ -0,0 +1,245 @@
1
+ #import "RTNSelect.h"
2
+ #import <React/RCTComponent.h>
3
+
4
+ #import <react/renderer/components/RTNSelectSpec/ComponentDescriptors.h>
5
+ #import <react/renderer/components/RTNSelectSpec/EventEmitters.h>
6
+ #import <react/renderer/components/RTNSelectSpec/Props.h>
7
+ #import <react/renderer/components/RTNSelectSpec/RCTComponentViewHelpers.h>
8
+
9
+ #import "RCTFabricComponentsPlugins.h"
10
+
11
+ using namespace facebook::react;
12
+
13
+ @interface RTNSelect () <RCTRTNSelectViewProtocol>
14
+ @end
15
+
16
+ @implementation RTNSelect {
17
+ UIPickerView *_pickerView;
18
+ UIButton *_button;
19
+
20
+ std::vector<std::string> _options;
21
+ NSInteger _selectedIndex;
22
+ RCTDirectEventBlock _onValueChangeLegacy;
23
+ }
24
+
25
+ + (ComponentDescriptorProvider)componentDescriptorProvider
26
+ {
27
+ return concreteComponentDescriptorProvider<RTNSelectComponentDescriptor>();
28
+ }
29
+
30
+ - (instancetype)initWithFrame:(CGRect)frame
31
+ {
32
+ if (self = [super initWithFrame:frame]) {
33
+ static const auto defaultProps = std::make_shared<const RTNSelectProps>();
34
+ _props = defaultProps;
35
+ _selectedIndex = 0;
36
+
37
+ _pickerView = [[UIPickerView alloc] initWithFrame:self.bounds];
38
+ _pickerView.dataSource = self;
39
+ _pickerView.delegate = self;
40
+ _pickerView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
41
+
42
+ _button = [UIButton buttonWithType:UIButtonTypeSystem];
43
+ _button.frame = self.bounds;
44
+ _button.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
45
+
46
+ // Style du bouton (alignement à gauche, couleur noire pour le texte)
47
+ _button.contentHorizontalAlignment = UIControlContentHorizontalAlignmentLeft;
48
+ [_button setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];
49
+
50
+ if (@available(iOS 14.0, *)) {
51
+ _button.showsMenuAsPrimaryAction = YES;
52
+ }
53
+
54
+ _button.hidden = YES;
55
+
56
+ [self addSubview:_pickerView];
57
+ [self addSubview:_button];
58
+ }
59
+
60
+ return self;
61
+ }
62
+
63
+ - (void)layoutSubviews {
64
+ [super layoutSubviews];
65
+ _pickerView.frame = self.bounds;
66
+ _button.frame = self.bounds;
67
+ }
68
+
69
+ // ============================================================================
70
+ // Gestion du Menu Flottant (Dropdown)
71
+ // ============================================================================
72
+
73
+ - (void)updateButtonMenu {
74
+ if (@available(iOS 14.0, *)) {
75
+ NSMutableArray<UIAction *> *actions = [NSMutableArray array];
76
+
77
+ for (int i = 0; i < _options.size(); i++) {
78
+ std::string optionString = _options[i];
79
+ NSString *title = [NSString stringWithUTF8String:optionString.c_str()];
80
+
81
+ UIAction *action = [UIAction actionWithTitle:title image:nil identifier:nil handler:^(__kindof UIAction * _Nonnull action) {
82
+ [self selectIndex:i fromSource:@"dropdown"];
83
+ }];
84
+
85
+ if (i == _selectedIndex) {
86
+ action.state = UIMenuElementStateOn;
87
+ [_button setTitle:title forState:UIControlStateNormal];
88
+ }
89
+
90
+ [actions addObject:action];
91
+ }
92
+
93
+ UIMenu *menu = [UIMenu menuWithTitle:@"" children:actions];
94
+ _button.menu = menu;
95
+ }
96
+ }
97
+
98
+ // ============================================================================
99
+ // Méthode unifiée de sélection (appelée par Picker ou Dropdown)
100
+ // ============================================================================
101
+
102
+ - (void)selectIndex:(NSInteger)index fromSource:(NSString *)source {
103
+ if (index >= _options.size()) return;
104
+
105
+ _selectedIndex = index;
106
+
107
+ if ([source isEqualToString:@"dropdown"]) {
108
+ [_pickerView selectRow:index inComponent:0 animated:NO];
109
+ [self updateButtonMenu];
110
+ } else {
111
+ [self updateButtonMenu];
112
+ }
113
+
114
+ if (_eventEmitter) {
115
+ auto emitter = std::static_pointer_cast<RTNSelectEventEmitter const>(_eventEmitter);
116
+ emitter->onValueChange({
117
+ .value = _options[index],
118
+ .index = (int)index
119
+ });
120
+ }
121
+
122
+ if (_onValueChangeLegacy) {
123
+ _onValueChangeLegacy(@{
124
+ @"value": [NSString stringWithUTF8String:_options[index].c_str()],
125
+ @"index": @(index)
126
+ });
127
+ }
128
+ }
129
+
130
+ // ============================================================================
131
+ // 1. FABRIC (New Architecture) Implementation
132
+ // ============================================================================
133
+
134
+ - (void)updateProps:(Props::Shared const &)props oldProps:(Props::Shared const &)oldProps
135
+ {
136
+ const auto &oldViewProps = *std::static_pointer_cast<const RTNSelectProps>(_props);
137
+ const auto &newViewProps = *std::static_pointer_cast<const RTNSelectProps>(props);
138
+
139
+ bool optionsChanged = oldViewProps.options != newViewProps.options;
140
+ bool indexChanged = oldViewProps.selectedIndex != newViewProps.selectedIndex;
141
+ bool modeChanged = oldViewProps.mode != newViewProps.mode;
142
+
143
+ if (optionsChanged) {
144
+ _options = newViewProps.options;
145
+ }
146
+
147
+ if (indexChanged) {
148
+ _selectedIndex = newViewProps.selectedIndex;
149
+ }
150
+
151
+ [super updateProps:props oldProps:oldProps];
152
+
153
+ dispatch_async(dispatch_get_main_queue(), ^{
154
+ if (optionsChanged) {
155
+ [self->_pickerView reloadAllComponents];
156
+ [self updateButtonMenu];
157
+ }
158
+
159
+ if (indexChanged && newViewProps.selectedIndex < self->_options.size()) {
160
+ [self->_pickerView selectRow:newViewProps.selectedIndex inComponent:0 animated:YES];
161
+ [self updateButtonMenu];
162
+ }
163
+
164
+ if (modeChanged || optionsChanged) {
165
+ if (newViewProps.mode == RTNSelectMode::Dropdown) {
166
+ self->_pickerView.hidden = YES;
167
+ self->_button.hidden = NO;
168
+ } else {
169
+ self->_pickerView.hidden = NO;
170
+ self->_button.hidden = YES;
171
+ }
172
+ }
173
+ });
174
+ }
175
+
176
+ // ============================================================================
177
+ // 2. LEGACY / INTEROP Implementation
178
+ // ============================================================================
179
+
180
+ - (void)setOptions:(NSArray<NSString *> *)options {
181
+ _options.clear();
182
+ for (NSString *option in options) {
183
+ _options.push_back([option UTF8String]);
184
+ }
185
+ dispatch_async(dispatch_get_main_queue(), ^{
186
+ [self->_pickerView reloadAllComponents];
187
+ [self updateButtonMenu];
188
+ });
189
+ }
190
+
191
+ - (void)setSelectedIndex:(NSInteger)selectedIndex {
192
+ _selectedIndex = selectedIndex;
193
+ dispatch_async(dispatch_get_main_queue(), ^{
194
+ if (selectedIndex < self->_options.size()) {
195
+ [self->_pickerView selectRow:selectedIndex inComponent:0 animated:YES];
196
+ [self updateButtonMenu];
197
+ }
198
+ });
199
+ }
200
+
201
+ - (void)setMode:(NSString *)mode {
202
+ dispatch_async(dispatch_get_main_queue(), ^{
203
+ if ([mode isEqualToString:@"dropdown"]) {
204
+ self->_pickerView.hidden = YES;
205
+ self->_button.hidden = NO;
206
+ } else {
207
+ self->_pickerView.hidden = NO;
208
+ self->_button.hidden = YES;
209
+ }
210
+ });
211
+ }
212
+
213
+ - (void)setOnValueChange:(RCTDirectEventBlock)onValueChange {
214
+ _onValueChangeLegacy = onValueChange;
215
+ }
216
+
217
+ // ============================================================================
218
+ // 3. UIPickerView Delegate Methods
219
+ // ============================================================================
220
+
221
+ - (NSInteger)numberOfComponentsInPickerView:(UIPickerView *)pickerView {
222
+ return 1;
223
+ }
224
+
225
+ - (NSInteger)pickerView:(UIPickerView *)pickerView numberOfRowsInComponent:(NSInteger)component {
226
+ return _options.size();
227
+ }
228
+
229
+ - (NSString *)pickerView:(UIPickerView *)pickerView titleForRow:(NSInteger)row forComponent:(NSInteger)component {
230
+ if (row < _options.size()) {
231
+ return [NSString stringWithUTF8String:_options[row].c_str()];
232
+ }
233
+ return @"";
234
+ }
235
+
236
+ - (void)pickerView:(UIPickerView *)pickerView didSelectRow:(NSInteger)row inComponent:(NSInteger)component {
237
+ [self selectIndex:row fromSource:@"picker"];
238
+ }
239
+
240
+ @end
241
+
242
+ Class<RCTComponentViewProtocol> RTNSelectCls(void)
243
+ {
244
+ return RTNSelect.class;
245
+ }
@@ -0,0 +1,22 @@
1
+ #import <React/RCTLog.h>
2
+ #import <React/RCTUIManager.h>
3
+ #import <React/RCTViewManager.h>
4
+ #import "RTNSelect.h"
5
+
6
+ @interface RTNSelectManager : RCTViewManager
7
+ @end
8
+
9
+ @implementation RTNSelectManager
10
+
11
+ RCT_EXPORT_MODULE(RTNSelect)
12
+
13
+ - (UIView *)view {
14
+ return [[RTNSelect alloc] init];
15
+ }
16
+
17
+ RCT_EXPORT_VIEW_PROPERTY(options, NSArray)
18
+ RCT_EXPORT_VIEW_PROPERTY(selectedIndex, NSInteger)
19
+ RCT_EXPORT_VIEW_PROPERTY(mode, NSString)
20
+ RCT_EXPORT_VIEW_PROPERTY(onValueChange, RCTDirectEventBlock)
21
+
22
+ @end
package/package.json ADDED
@@ -0,0 +1,43 @@
1
+ {
2
+ "name": "react-native-native-select",
3
+ "version": "1.0.0",
4
+ "description": "react-native-native-select is a strictly native, performant Select component for React Native built exclusively for the New Architecture.",
5
+
6
+ "main": "src/index.ts",
7
+ "react-native": "src/index.ts",
8
+ "types": "src/index.ts",
9
+
10
+ "source": "src/index",
11
+ "files": [
12
+ "src",
13
+ "android",
14
+ "ios",
15
+ "react-native-native-select.podspec",
16
+ "!android/build",
17
+ "!ios/build",
18
+ "!tests",
19
+ "!**/__tests__",
20
+ "!**/__fixtures__",
21
+ "!**/__mocks__"
22
+ ],
23
+ "keywords": ["react-native", "ios", "android", "picker", "dropdown", "select", "input select", "new architecture", "typescript", "native-module"],
24
+ "repository": "https://github.com/wneel/react-native-native-select",
25
+ "author": "Wayan NEEL <66263633+wneel@users.noreply.github.com> (https://github.com/wneel)",
26
+ "license": "MIT",
27
+ "bugs": {
28
+ "url": "https://github.com/wneel/react-native-native-select/issues"
29
+ },
30
+ "homepage": "https://github.com/wneel/react-native-native-select#readme",
31
+ "peerDependencies": {
32
+ "react": "*",
33
+ "react-native": ">=0.71.0"
34
+ },
35
+ "codegenConfig": {
36
+ "name": "RTNSelectSpec",
37
+ "type": "components",
38
+ "jsSrcsDir": "src",
39
+ "android": {
40
+ "javaPackageName": "com.rtnselect"
41
+ }
42
+ }
43
+ }
@@ -0,0 +1,19 @@
1
+ require "json"
2
+
3
+ package = JSON.parse(File.read(File.join(__dir__, "package.json")))
4
+
5
+ Pod::Spec.new do |s|
6
+ s.name = "react-native-native-select"
7
+ s.version = package["version"]
8
+ s.summary = "A strictly native, performant Select component for React Native."
9
+ s.description = package["description"]
10
+ s.homepage = "https://github.com/wneel/react-native-native-select"
11
+ s.license = package["license"]
12
+ s.platforms = { :ios => "11.0" }
13
+ s.author = package["author"]
14
+ s.source = { :git => "https://github.com/wneel/react-native-native-select.git", :tag => "#{s.version}" }
15
+
16
+ s.source_files = "ios/**/*.{h,m,mm,swift}"
17
+
18
+ install_modules_dependencies(s)
19
+ end
@@ -0,0 +1,21 @@
1
+ import codegenNativeComponent from 'react-native/Libraries/Utilities/codegenNativeComponent';
2
+
3
+ import type { HostComponent } from 'react-native';
4
+ import type { ViewProps } from 'react-native/Libraries/Components/View/ViewPropTypes';
5
+ import type { Int32, DirectEventHandler, WithDefault } from 'react-native/Libraries/Types/CodegenTypes';
6
+
7
+ type OnChangeEvent = Readonly<{
8
+ value: string;
9
+ index: Int32;
10
+ }>;
11
+
12
+ export interface NativeProps extends ViewProps {
13
+ options: ReadonlyArray<string>;
14
+ selectedIndex?: Int32;
15
+ mode?: WithDefault<'dialog' | 'dropdown', 'dialog'>;
16
+ onValueChange?: DirectEventHandler<OnChangeEvent>;
17
+ }
18
+
19
+ export default codegenNativeComponent<NativeProps>(
20
+ 'RTNSelect'
21
+ ) as HostComponent<NativeProps>;
package/src/index.ts ADDED
@@ -0,0 +1,2 @@
1
+ export { default as Select } from './RTNSelectNativeComponent';
2
+ export * from './RTNSelectNativeComponent';