├── .gitignore ├── README.md ├── TurboClipboard.h ├── TurboClipboard.mm ├── TurboClipboard.podspec ├── lib └── cpp-generated │ ├── TurboClipboardSpec-generated.mm │ └── TurboClipboardSpec.h ├── package-lock.json ├── package.json ├── react-native-tscodegen.json └── src ├── TurboModule.ts └── index.ts /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | yarn-error.log 3 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # React Native Turbo Module example 2 | 3 | This repository is a Turbo Module implementation of Clipboard Core React Native module. 4 | 5 | ## How to make your own Turbo Module 6 | 7 | 1. Create a new npm package 8 | 2. Add `react-native-tscodegen` and `react-native-tscodegen-types` as devDependencies 9 | 3. Copy `TurboClipboard.podspec`, rename it, change library name, author etc 10 | 4. Implement `TurboModule.ts` file: define all the methods in the Spec interface 11 | 5. Copy `react-native-tscodegen.json`, rename library name etc 12 | 6. Add `codegen` script to `package.json` with the following command to run: `react-native-tscodegen ./react-native-tscodegen.json` 13 | 7. Run `npm run codegen` - it will generate Spec files - the JSI bridge which you should include in your sources. Your native module interface should extend `NSObject ` - the generated spec by the codegen of your `TurboModule.ts` 14 | 8. Add your implementation source files following the example of `TurboClipboard` header and `mm` file 15 | 9. Change `source_files` in the PodSpec accordingly 16 | 10. Include in your TurboModule enabled application 17 | 11. Use it 18 | 19 | ## LICENSE 20 | 21 | MIT 22 | -------------------------------------------------------------------------------- /TurboClipboard.h: -------------------------------------------------------------------------------- 1 | #import "TurboClipboardSpec.h" 2 | 3 | @interface TurboClipboard : NSObject 4 | 5 | @end 6 | -------------------------------------------------------------------------------- /TurboClipboard.mm: -------------------------------------------------------------------------------- 1 | #import 2 | 3 | #import 4 | #import 5 | #import 6 | #import 7 | #import "TurboClipboardSpec.h" 8 | 9 | using namespace facebook::react; 10 | 11 | @interface TurboClipboard () 12 | @end 13 | 14 | @implementation TurboClipboard 15 | 16 | RCT_EXPORT_MODULE() 17 | 18 | - (dispatch_queue_t)methodQueue 19 | { 20 | return dispatch_get_main_queue(); 21 | } 22 | 23 | RCT_EXPORT_METHOD(setString : (NSString *)content) 24 | { 25 | UIPasteboard *clipboard = [UIPasteboard generalPasteboard]; 26 | clipboard.string = (content ?: @""); 27 | } 28 | 29 | RCT_EXPORT_METHOD(getString : (RCTPromiseResolveBlock)resolve reject : (__unused RCTPromiseRejectBlock)reject) 30 | { 31 | UIPasteboard *clipboard = [UIPasteboard generalPasteboard]; 32 | resolve((clipboard.string ?: @"")); 33 | } 34 | 35 | - (std::shared_ptr)getTurboModule:(const ObjCTurboModule::InitParams &)params 36 | { 37 | return std::make_shared(params); 38 | } 39 | 40 | @end 41 | 42 | Class TurboClipboardCls(void) 43 | { 44 | return TurboClipboard.class; 45 | } 46 | -------------------------------------------------------------------------------- /TurboClipboard.podspec: -------------------------------------------------------------------------------- 1 | folly_compiler_flags = '-DFOLLY_NO_CONFIG -DFOLLY_MOBILE=1 -DFOLLY_USE_LIBCPP=1 -Wno-comma -Wno-shorten-64-to-32' 2 | 3 | 4 | Pod::Spec.new do |s| 5 | s.name = 'TurboClipboard' 6 | s.version = '0.1.0' 7 | s.license = { :type => 'MIT' } 8 | s.homepage = 'https://github.com/terrysahaidak/TurboClipboard' 9 | s.authors = { 'Terry Sahaidak' => 'terry@sahaidak.com' } 10 | s.summary = 'Test' 11 | s.platforms = { :ios => "11.0" } 12 | s.source = { :git => 'https://github.com/terrysahaidak/TurboClipboard.git', :tag => 'v3.1.0' } 13 | 14 | s.compiler_flags = folly_compiler_flags + ' -Wno-nullability-completeness' 15 | s.pod_target_xcconfig = { 16 | "DEFINES_MODULE" => "YES", 17 | "USE_HEADERMAP" => "YES", 18 | "CLANG_CXX_LANGUAGE_STANDARD" => "c++14", 19 | "HEADER_SEARCH_PATHS" => "\"$(PODS_TARGET_SRCROOT)/ReactCommon\" \"$(PODS_TARGET_SRCROOT)\" \"$(PODS_ROOT)/Headers/Private/React-Core\" " 20 | } 21 | 22 | s.source_files = 'TurboClipboard.{h,mm}', 'lib/cpp-generated/**/*.{h,mm}' 23 | 24 | s.dependency "ReactCommon" 25 | s.dependency "RCTRequired" 26 | s.dependency "RCTTypeSafety" 27 | s.dependency "React-Core" 28 | s.dependency "React-jsi" 29 | end 30 | -------------------------------------------------------------------------------- /lib/cpp-generated/TurboClipboardSpec-generated.mm: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) Facebook, Inc. and its affiliates. 3 | * 4 | * This source code is licensed under the MIT license found in the 5 | * LICENSE file in the root directory of this source tree. 6 | * 7 | * @generated by codegen project: GenerateModuleObjCpp 8 | * 9 | * We create an umbrella header (and corresponding implementation) here since 10 | * Cxx compilation in BUCK has a limitation: source-code producing genrule()s 11 | * must have a single output. More files => more genrule()s => slower builds. 12 | */ 13 | 14 | #import "TurboClipboardSpec.h" 15 | 16 | 17 | namespace facebook { 18 | namespace react { 19 | 20 | static facebook::jsi::Value __hostFunction_TurboClipboardSpecJSI_getString(facebook::jsi::Runtime& rt, TurboModule &turboModule, const facebook::jsi::Value* args, size_t count) { 21 | return static_cast(turboModule).invokeObjCMethod(rt, PromiseKind, "getString", @selector(getString:reject:), args, count); 22 | } 23 | 24 | static facebook::jsi::Value __hostFunction_TurboClipboardSpecJSI_setString(facebook::jsi::Runtime& rt, TurboModule &turboModule, const facebook::jsi::Value* args, size_t count) { 25 | return static_cast(turboModule).invokeObjCMethod(rt, VoidKind, "setString", @selector(setString:), args, count); 26 | } 27 | 28 | TurboClipboardSpecJSI::TurboClipboardSpecJSI(const ObjCTurboModule::InitParams ¶ms) 29 | : ObjCTurboModule(params) { 30 | 31 | methodMap_["getString"] = MethodMetadata {0, __hostFunction_TurboClipboardSpecJSI_getString}; 32 | 33 | 34 | methodMap_["setString"] = MethodMetadata {1, __hostFunction_TurboClipboardSpecJSI_setString}; 35 | 36 | } 37 | } // namespace react 38 | } // namespace facebook 39 | -------------------------------------------------------------------------------- /lib/cpp-generated/TurboClipboardSpec.h: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) Facebook, Inc. and its affiliates. 3 | * 4 | * This source code is licensed under the MIT license found in the 5 | * LICENSE file in the root directory of this source tree. 6 | * 7 | * @generated by codegen project: GenerateModuleObjCpp 8 | * 9 | * We create an umbrella header (and corresponding implementation) here since 10 | * Cxx compilation in BUCK has a limitation: source-code producing genrule()s 11 | * must have a single output. More files => more genrule()s => slower builds. 12 | */ 13 | 14 | #ifndef __cplusplus 15 | #error This file must be compiled as Obj-C++. If you are importing it, you must change your file extension to .mm. 16 | #endif 17 | #import 18 | #import 19 | #import 20 | #import 21 | #import 22 | #import 23 | #import 24 | #import 25 | #import 26 | #import 27 | 28 | 29 | @protocol TurboClipboardSpec 30 | 31 | - (void)getString:(RCTPromiseResolveBlock)resolve 32 | reject:(RCTPromiseRejectBlock)reject; 33 | - (void)setString:(NSString *)content; 34 | 35 | @end 36 | namespace facebook { 37 | namespace react { 38 | /** 39 | * ObjC++ class for module 'TurboClipboard' 40 | */ 41 | class JSI_EXPORT TurboClipboardSpecJSI : public ObjCTurboModule { 42 | public: 43 | TurboClipboardSpecJSI(const ObjCTurboModule::InitParams ¶ms); 44 | }; 45 | } // namespace react 46 | } // namespace facebook 47 | 48 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "TurboClipboard", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "NativeTurboClipboard.js", 6 | "scripts": { 7 | "codegen": "react-native-tscodegen ./react-native-tscodegen.json" 8 | }, 9 | "keywords": [], 10 | "author": "", 11 | "license": "ISC", 12 | "devDependencies": { 13 | "react-native-tscodegen": "^0.68.1", 14 | "react-native-tscodegen-types": "^0.67.2" 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /react-native-tscodegen.json: -------------------------------------------------------------------------------- 1 | { 2 | "libraryName": "TurboClipboard", 3 | "outputDirectory": "./lib/cpp-generated", 4 | "moduleSpecName": "TurboClipboardSpec", 5 | "generators": ["modulesIOS"], 6 | "inputFile": "./src/TurboModule.ts" 7 | } 8 | -------------------------------------------------------------------------------- /src/TurboModule.ts: -------------------------------------------------------------------------------- 1 | import { TurboModule, TurboModuleRegistry } from 'react-native-tscodegen-types'; 2 | 3 | export interface Spec extends TurboModule { 4 | getConstants: () => {}; 5 | getString: () => Promise; 6 | setString: (content: string) => void; 7 | } 8 | 9 | export default (TurboModuleRegistry.getEnforcing('TurboClipboard')) as Spec; 10 | 11 | -------------------------------------------------------------------------------- /src/index.ts: -------------------------------------------------------------------------------- 1 | import NativeModule from './TurboModule'; 2 | 3 | export function getString(): Promise { 4 | return NativeModule.getString(); 5 | } 6 | 7 | export function setString(content: string): void { 8 | NativeModule.setString(content); 9 | } 10 | 11 | --------------------------------------------------------------------------------