Skip to content

Commit 3d9cd20

Browse files
deps: Migrate to @react-native-clipboard/clipboard
`Clipboard` in RN core is deprecated; see warning at https://reactnative.dev/docs/clipboard We've reportedly been getting console warnings that we should use @react-native-community/clipboard instead of the RN-core module. Do basically that, except we use its new name, @react-native-clipboard/clipboard; see react-native-clipboard/clipboard#87 Put the types in a .js.flow file, rather than a libdef in `flow-typed/`, inspired by Greg's commit 007dea3. Supersedes: #4502 Co-authored-by: rajprakash00 <[email protected]>
1 parent dc5ab4c commit 3d9cd20

File tree

10 files changed

+184
-5
lines changed

10 files changed

+184
-5
lines changed

.eslintrc.yaml

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -225,7 +225,11 @@ rules:
225225
- devDependencies: ['**/__tests__/**/*.js', tools/**]
226226
no-restricted-imports:
227227
- error
228-
- patterns:
228+
- paths:
229+
- name: 'react-native'
230+
importNames: ['Clipboard']
231+
message: 'Use Clipboard from @react-native-clipboard/clipboard instead.'
232+
patterns:
229233
- group: ['**/__tests__/**']
230234
- group: ['/react-redux']
231235
message: 'Use our own src/react-redux.js instead.'

.flowconfig

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,7 @@ module.name_mapper='^react-native/\(.*\)$' -> '<PROJECT_ROOT>/node_modules/react
120120
module.name_mapper='^@?[./a-zA-Z0-9$_-]+\.\(bmp\|gif\|jpg\|jpeg\|png\|psd\|svg\|webp\|m4v\|mov\|mp4\|mpeg\|mpg\|webm\|aac\|aiff\|caf\|m4a\|mp3\|wav\|html\|pdf\)$' -> '<PROJECT_ROOT>/node_modules/react-native/Libraries/Image/RelativeImageStub'
121121
# This lets us write .js.flow files instead of libdefs.
122122
# Add more libraries as needed to this pattern with `\|`: `foo\|bar\|…`.
123-
module.name_mapper='^\(sqlite3\|@react-navigation/bottom-tabs\|@react-navigation/drawer\|@react-navigation/material-top-tabs\|@react-navigation/native\|@react-navigation/stack\)$' -> '<PROJECT_ROOT>/types/\0'
123+
module.name_mapper='^\(sqlite3\|@react-navigation/bottom-tabs\|@react-navigation/drawer\|@react-navigation/material-top-tabs\|@react-navigation/native\|@react-navigation/stack\|@react-native-clipboard/clipboard\)$' -> '<PROJECT_ROOT>/types/\0'
124124

125125
suppress_type=$FlowIssue
126126
suppress_type=$FlowFixMe

ios/Podfile.lock

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -360,6 +360,8 @@ PODS:
360360
- React-Core
361361
- RNCAsyncStorage (1.16.1):
362362
- React-Core
363+
- RNCClipboard (1.8.5):
364+
- React-Core
363365
- RNCMaskedView (0.1.11):
364366
- React
365367
- RNCPushNotificationIOS (1.10.1):
@@ -480,6 +482,7 @@ DEPENDENCIES:
480482
- ReactCommon/turbomodule/core (from `../node_modules/react-native/ReactCommon`)
481483
- rn-fetch-blob (from `../node_modules/rn-fetch-blob`)
482484
- "RNCAsyncStorage (from `../node_modules/@react-native-async-storage/async-storage`)"
485+
- "RNCClipboard (from `../node_modules/@react-native-clipboard/clipboard`)"
483486
- "RNCMaskedView (from `../node_modules/@react-native-community/masked-view`)"
484487
- "RNCPushNotificationIOS (from `../node_modules/@react-native-community/push-notification-ios`)"
485488
- RNDeviceInfo (from `../node_modules/react-native-device-info`)
@@ -603,6 +606,8 @@ EXTERNAL SOURCES:
603606
:path: "../node_modules/rn-fetch-blob"
604607
RNCAsyncStorage:
605608
:path: "../node_modules/@react-native-async-storage/async-storage"
609+
RNCClipboard:
610+
:path: "../node_modules/@react-native-clipboard/clipboard"
606611
RNCMaskedView:
607612
:path: "../node_modules/@react-native-community/masked-view"
608613
RNCPushNotificationIOS:
@@ -680,6 +685,7 @@ SPEC CHECKSUMS:
680685
ReactCommon: 8fea6422328e2fc093e25c9fac67adbcf0f04fb4
681686
rn-fetch-blob: f525a73a78df9ed5d35e67ea65e79d53c15255bc
682687
RNCAsyncStorage: b49b4e38a1548d03b74b30e558a1d18465b94be7
688+
RNCClipboard: cc054ad1e8a33d2a74cd13e565588b4ca928d8fd
683689
RNCMaskedView: 0e1bc4bfa8365eba5fbbb71e07fbdc0555249489
684690
RNCPushNotificationIOS: 87b8d16d3ede4532745e05b03c42cff33a36cc45
685691
RNDeviceInfo: 4944cf8787b9c5bffaf301fda68cc1a2ec003341

jest/jestSetup.js

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@ import { polyfillGlobal } from 'react-native/Libraries/Utilities/PolyfillFunctio
55
import { URL, URLSearchParams } from 'react-native-url-polyfill';
66
// $FlowIgnore[untyped-import] - this is not anywhere near critical
77
import mockAsyncStorage from '@react-native-async-storage/async-storage/jest/async-storage-mock';
8+
// $FlowIgnore[untyped-import] - this is not anywhere near critical
9+
import mockClipboard from '@react-native-clipboard/clipboard/jest/clipboard-mock';
810

911
import { assertUsingModernFakeTimers } from '../src/__tests__/lib/fakeTimers';
1012

@@ -102,6 +104,10 @@ jest.mock('react-native-reanimated', () => {
102104

103105
jest.mock('@react-native-async-storage/async-storage', () => mockAsyncStorage);
104106

107+
// As instructed at
108+
// https://github.com/react-native-clipboard/clipboard/tree/v1.9.0#mocking-clipboard
109+
jest.mock('@react-native-clipboard/clipboard', () => mockClipboard);
110+
105111
// Without this, we get lots of these errors on importing the module:
106112
// `Invariant Violation: Native module cannot be null.`
107113
jest.mock('@react-native-community/push-notification-ios', () => ({

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
"dependencies": {
2121
"@expo/react-native-action-sheet": "^3.8.0",
2222
"@react-native-async-storage/async-storage": "^1.13.0",
23+
"@react-native-clipboard/clipboard": "^1.8.5",
2324
"@react-native-community/cameraroll": "chrisbobbe/react-native-cameraroll#17fa5d8d2",
2425
"@react-native-community/masked-view": "^0.1.10",
2526
"@react-native-community/netinfo": "6.0.0",

src/RootErrorBoundary.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
/* @flow strict-local */
22
import React from 'react';
33
import type { Node } from 'react';
4-
import { View, Text, Clipboard, TextInput, ScrollView, Button, Platform } from 'react-native';
4+
import { View, Text, TextInput, ScrollView, Button, Platform } from 'react-native';
5+
import Clipboard from '@react-native-clipboard/clipboard';
56
import Toast from 'react-native-simple-toast';
67
// $FlowFixMe[untyped-import]
78
import isEqual from 'lodash.isequal';

src/action-sheets/index.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
/* @flow strict-local */
2-
import { Clipboard, Share, Alert } from 'react-native';
2+
import { Share, Alert } from 'react-native';
3+
import Clipboard from '@react-native-clipboard/clipboard';
34
import invariant from 'invariant';
45
import * as resolved_topic from '@zulip/shared/js/resolved_topic';
56

src/webview/handleOutboundEvents.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
/* @flow strict-local */
2-
import { Clipboard, Alert } from 'react-native';
2+
import { Alert } from 'react-native';
3+
import Clipboard from '@react-native-clipboard/clipboard';
34

45
import * as NavigationService from '../nav/NavigationService';
56
import * as api from '../api';
Lines changed: 154 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,154 @@
1+
/**
2+
* Flowtype definitions for Clipboard
3+
* Generated by Flowgen from a Typescript Definition
4+
* Flowgen v1.11.0
5+
*
6+
* @flow strict-local
7+
*/
8+
9+
import type EmitterSubscription from 'react-native/Libraries/vendor/emitter/_EmitterSubscription';
10+
11+
/**
12+
* `Clipboard` gives you an interface for setting and getting content from Clipboard on both iOS and Android
13+
*/
14+
declare var Clipboard: {
15+
/**
16+
* Get content of string type, this method returns a `Promise`, so you can use following code to get clipboard content
17+
* ```javascript
18+
* async _getContent() {
19+
* var content = await Clipboard.getString();
20+
* }
21+
* ```
22+
*/
23+
getString(): Promise<string>,
24+
25+
/**
26+
* Get clipboard image as PNG in base64, this method returns a `Promise`, so you can use following code to get clipboard content
27+
* ```javascript
28+
* async _getContent() {
29+
* var content = await Clipboard.getImagePNG();
30+
* }
31+
* ```
32+
*/
33+
getImagePNG(): Promise<string>,
34+
35+
/**
36+
* Get clipboard image as JPG in base64, this method returns a `Promise`, so you can use following code to get clipboard content
37+
* ```javascript
38+
* async _getContent() {
39+
* var content = await Clipboard.getImageJPG();
40+
* }
41+
* ```
42+
*/
43+
getImageJPG(): Promise<string>,
44+
45+
/**
46+
* Set content of base64 image type. You can use following code to set clipboard content
47+
* ```javascript
48+
* _setContent() {
49+
* Clipboard.setImage(...);
50+
* }
51+
*
52+
* iOS only
53+
* ```
54+
* @param the content to be stored in the clipboard.
55+
*/
56+
setImage(content: string): void,
57+
getImage(): Promise<string>,
58+
59+
/**
60+
* Set content of string type. You can use following code to set clipboard content
61+
* ```javascript
62+
* _setContent() {
63+
* Clipboard.setString('hello world');
64+
* }
65+
* ```
66+
* @param the content to be stored in the clipboard.
67+
*/
68+
setString(content: string): void,
69+
70+
/**
71+
* Returns whether the clipboard has content or is empty.
72+
* This method returns a `Promise`, so you can use following code to get clipboard content
73+
* ```javascript
74+
* async _hasContent() {
75+
* var hasContent = await Clipboard.hasString();
76+
* }
77+
* ```
78+
*/
79+
hasString(): $FlowFixMe, // `any` in TypeScript upstream :(
80+
81+
/**
82+
* Returns whether the clipboard has an image or is empty.
83+
* This method returns a `Promise`, so you can use following code to check clipboard content
84+
* ```javascript
85+
* async _hasContent() {
86+
* var hasContent = await Clipboard.hasImage();
87+
* }
88+
* ```
89+
*/
90+
hasImage(): $FlowFixMe, // `any` in TypeScript upstream :(
91+
92+
/**
93+
* (IOS Only)
94+
* Returns whether the clipboard has a URL content. Can check
95+
* if there is a URL content in clipboard without triggering PasteBoard notification for iOS 14+
96+
* This method returns a `Promise`, so you can use following code to check for url content in clipboard.
97+
* ```javascript
98+
* async _hasURL() {
99+
* var hasURL = await Clipboard.hasURL();
100+
* }
101+
* ```
102+
*/
103+
hasURL(): $FlowFixMe, // `any` in TypeScript upstream :(
104+
105+
/**
106+
* (IOS 14+ Only)
107+
* Returns whether the clipboard has a Number(UIPasteboardDetectionPatternNumber) content. Can check
108+
* if there is a Number content in clipboard without triggering PasteBoard notification for iOS 14+
109+
* This method returns a `Promise`, so you can use following code to check for Number content in clipboard.
110+
* ```javascript
111+
* async _hasNumber() {
112+
* var hasNumber = await Clipboard.hasNumber();
113+
* }
114+
* ```
115+
*/
116+
hasNumber(): $FlowFixMe, // `any` in TypeScript upstream :(
117+
118+
/**
119+
* (IOS 14+ Only)
120+
* Returns whether the clipboard has a WebURL(UIPasteboardDetectionPatternProbableWebURL) content. Can check
121+
* if there is a WebURL content in clipboard without triggering PasteBoard notification for iOS 14+
122+
* This method returns a `Promise`, so you can use following code to check for WebURL content in clipboard.
123+
* ```javascript
124+
* async _hasWebURL() {
125+
* var hasWebURL = await Clipboard.hasWebURL();
126+
* }
127+
* ```
128+
*/
129+
hasWebURL(): $FlowFixMe, // `any` in TypeScript upstream :(
130+
131+
/**
132+
* (iOS and Android Only)
133+
* Adds a listener to get notifications when the clipboard has changed.
134+
* If this is the first listener, turns on clipboard notifications on the native side.
135+
* It returns EmitterSubscription where you can call "remove" to remove listener
136+
* ```javascript
137+
* const listener = () => console.log("changed!");
138+
* Clipboard.addListener(listener);
139+
* ```
140+
*/
141+
addListener(callback: () => void): EmitterSubscription,
142+
143+
/**
144+
* (iOS and Android Only)
145+
* Removes all previously registered listeners and turns off notifications on the native side.
146+
* ```javascript
147+
* Clipboard.removeAllListeners();
148+
* ```
149+
*/
150+
removeAllListeners(): void,
151+
...
152+
};
153+
154+
export default Clipboard;

yarn.lock

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1795,6 +1795,11 @@
17951795
dependencies:
17961796
merge-options "^3.0.4"
17971797

1798+
"@react-native-clipboard/clipboard@^1.8.5":
1799+
version "1.8.5"
1800+
resolved "https://registry.yarnpkg.com/@react-native-clipboard/clipboard/-/clipboard-1.8.5.tgz#b11276e38ef288b0fd70c0a38506e2deecc5fa5a"
1801+
integrity sha512-o2RPDwP9JMnLece1Qq6a3Fsz/VxfA9auLckkGOor7WcI82DWaWiJ6Uiyu7H1xpaUyqWc+ypVKRX680GYS36HjA==
1802+
17981803
"@react-native-community/cameraroll@chrisbobbe/react-native-cameraroll#17fa5d8d2":
17991804
version "4.0.4"
18001805
resolved "https://codeload.github.com/chrisbobbe/react-native-cameraroll/tar.gz/17fa5d8d2f4e00ec78304070a0b91292e884b7f5"

0 commit comments

Comments
 (0)