expo-clipboard 1.0.1 → 2.0.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/CHANGELOG.md +38 -0
- package/android/build.gradle +79 -0
- package/android/src/main/AndroidManifest.xml +2 -0
- package/android/src/main/java/expo/modules/clipboard/ClipboardEventEmitter.kt +49 -0
- package/android/src/main/java/expo/modules/clipboard/ClipboardModule.kt +41 -0
- package/android/src/main/java/expo/modules/clipboard/ClipboardPackage.kt +12 -0
- package/build/Clipboard.d.ts +53 -2
- package/build/Clipboard.js +63 -1
- package/build/Clipboard.js.map +1 -1
- package/build/ExpoClipboard.d.ts +1 -4
- package/build/ExpoClipboard.js +2 -10
- package/build/ExpoClipboard.js.map +1 -1
- package/build/ExpoClipboard.web.d.ts +2 -0
- package/build/ExpoClipboard.web.js +4 -2
- package/build/ExpoClipboard.web.js.map +1 -1
- package/ios/EXClipboard/EXClipboardModule.h +8 -0
- package/ios/EXClipboard/EXClipboardModule.m +88 -0
- package/ios/EXClipboard.podspec +28 -0
- package/package.json +6 -7
- package/src/Clipboard.ts +78 -1
- package/src/ExpoClipboard.ts +2 -10
- package/src/ExpoClipboard.web.ts +4 -2
- package/unimodule.json +4 -0
package/CHANGELOG.md
CHANGED
|
@@ -8,6 +8,44 @@
|
|
|
8
8
|
|
|
9
9
|
### 🐛 Bug fixes
|
|
10
10
|
|
|
11
|
+
### 💡 Others
|
|
12
|
+
|
|
13
|
+
## 2.0.1 — 2021-10-01
|
|
14
|
+
|
|
15
|
+
_This version does not introduce any user-facing changes._
|
|
16
|
+
|
|
17
|
+
## 2.0.0 — 2021-09-28
|
|
18
|
+
|
|
19
|
+
### 🛠 Breaking changes
|
|
20
|
+
|
|
21
|
+
- Dropped support for iOS 11.0 ([#14383](https://github.com/expo/expo/pull/14383) by [@cruzach](https://github.com/cruzach))
|
|
22
|
+
|
|
23
|
+
### 🐛 Bug fixes
|
|
24
|
+
|
|
25
|
+
- Fix building errors from use_frameworks! in Podfile. ([#14523](https://github.com/expo/expo/pull/14523) by [@kudo](https://github.com/kudo))
|
|
26
|
+
|
|
27
|
+
### 💡 Others
|
|
28
|
+
|
|
29
|
+
- Clean up Android code. ([#13517](https://github.com/expo/expo/pull/13517) by [@mstach60161](https://github.com/mstach60161))
|
|
30
|
+
- Migrated from `@unimodules/core` to `expo-modules-core`. ([#13757](https://github.com/expo/expo/pull/13757) by [@tsapeta](https://github.com/tsapeta))
|
|
31
|
+
|
|
32
|
+
## 1.1.0 — 2021-06-16
|
|
33
|
+
|
|
34
|
+
### 🎉 New features
|
|
35
|
+
|
|
36
|
+
- Added Clipboard event listener ([#13050](https://github.com/expo/expo/pull/13050) by [@cruzach](https://github.com/cruzach))
|
|
37
|
+
|
|
38
|
+
### 🐛 Bug fixes
|
|
39
|
+
|
|
40
|
+
- Fixed `getStringAsync` causing crashes on Web when an exception is thrown. ([#12494](https://github.com/expo/expo/pull/12494) by [@robertherber](https://github.com/robertherber))
|
|
41
|
+
- Fixed newlines not being copied on web. ([#12951](https://github.com/expo/expo/pull/12951) by [@cruzach](https://github.com/cruzach))
|
|
42
|
+
|
|
43
|
+
## 1.0.2 — 2021-03-23
|
|
44
|
+
|
|
45
|
+
### 🐛 Bug fixes
|
|
46
|
+
|
|
47
|
+
- Remove peerDependencies and unimodulePeerDependencies from Expo modules. ([#11980](https://github.com/expo/expo/pull/11980) by [@brentvatne](https://github.com/brentvatne))
|
|
48
|
+
|
|
11
49
|
## 1.0.1 — 2020-12-08
|
|
12
50
|
|
|
13
51
|
_This version does not introduce any user-facing changes._
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
apply plugin: 'com.android.library'
|
|
2
|
+
apply plugin: 'kotlin-android'
|
|
3
|
+
apply plugin: 'maven'
|
|
4
|
+
|
|
5
|
+
group = 'host.exp.exponent'
|
|
6
|
+
version = '2.0.1'
|
|
7
|
+
|
|
8
|
+
buildscript {
|
|
9
|
+
// Simple helper that allows the root project to override versions declared by this library.
|
|
10
|
+
ext.safeExtGet = { prop, fallback ->
|
|
11
|
+
rootProject.ext.has(prop) ? rootProject.ext.get(prop) : fallback
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
repositories {
|
|
15
|
+
mavenCentral()
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
dependencies {
|
|
19
|
+
classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:${safeExtGet('kotlinVersion', '1.4.21')}")
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
// Upload android library to maven with javadoc and android sources
|
|
24
|
+
configurations {
|
|
25
|
+
deployerJars
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
// Creating sources with comments
|
|
29
|
+
task androidSourcesJar(type: Jar) {
|
|
30
|
+
classifier = 'sources'
|
|
31
|
+
from android.sourceSets.main.java.srcDirs
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
// Put the androidSources and javadoc to the artifacts
|
|
35
|
+
artifacts {
|
|
36
|
+
archives androidSourcesJar
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
uploadArchives {
|
|
40
|
+
repositories {
|
|
41
|
+
mavenDeployer {
|
|
42
|
+
configuration = configurations.deployerJars
|
|
43
|
+
repository(url: mavenLocal().url)
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
android {
|
|
49
|
+
compileSdkVersion rootProject.ext.compileSdkVersion
|
|
50
|
+
|
|
51
|
+
compileOptions {
|
|
52
|
+
sourceCompatibility JavaVersion.VERSION_1_8
|
|
53
|
+
targetCompatibility JavaVersion.VERSION_1_8
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
defaultConfig {
|
|
57
|
+
minSdkVersion rootProject.ext.minSdkVersion
|
|
58
|
+
targetSdkVersion rootProject.ext.targetSdkVersion
|
|
59
|
+
versionCode 3
|
|
60
|
+
versionName '2.0.1'
|
|
61
|
+
}
|
|
62
|
+
lintOptions {
|
|
63
|
+
abortOnError false
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
repositories {
|
|
68
|
+
mavenCentral()
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
dependencies {
|
|
72
|
+
implementation project(':expo-modules-core')
|
|
73
|
+
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:${safeExtGet('kotlinVersion', '1.4.21')}"
|
|
74
|
+
|
|
75
|
+
if (project.findProject(':unimodules-test-core')) {
|
|
76
|
+
testImplementation project(':unimodules-test-core')
|
|
77
|
+
}
|
|
78
|
+
testImplementation "org.robolectric:robolectric:4.3.1"
|
|
79
|
+
}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
package expo.modules.clipboard
|
|
2
|
+
|
|
3
|
+
import android.content.Context
|
|
4
|
+
import android.content.ClipboardManager
|
|
5
|
+
import android.os.Bundle
|
|
6
|
+
import android.util.Log
|
|
7
|
+
|
|
8
|
+
import expo.modules.core.ModuleRegistry
|
|
9
|
+
import expo.modules.core.interfaces.LifecycleEventListener
|
|
10
|
+
import expo.modules.core.interfaces.services.EventEmitter
|
|
11
|
+
import expo.modules.core.interfaces.services.UIManager
|
|
12
|
+
|
|
13
|
+
class ClipboardEventEmitter(context: Context, moduleRegistry: ModuleRegistry) : LifecycleEventListener {
|
|
14
|
+
private val onClipboardEventName = "onClipboardChanged"
|
|
15
|
+
private var isListening = true
|
|
16
|
+
private var eventEmitter = moduleRegistry.getModule(EventEmitter::class.java)
|
|
17
|
+
|
|
18
|
+
init {
|
|
19
|
+
moduleRegistry.getModule(UIManager::class.java).registerLifecycleEventListener(this)
|
|
20
|
+
val clipboard = context.getSystemService(Context.CLIPBOARD_SERVICE) as? ClipboardManager
|
|
21
|
+
if (clipboard == null) {
|
|
22
|
+
Log.e("Clipboard", "CLIPBOARD_SERVICE unavailable. Events wont be received")
|
|
23
|
+
} else {
|
|
24
|
+
clipboard.addPrimaryClipChangedListener {
|
|
25
|
+
if (isListening) {
|
|
26
|
+
val clip = clipboard.primaryClip
|
|
27
|
+
if (clip != null && clip.itemCount >= 1) {
|
|
28
|
+
eventEmitter.emit(
|
|
29
|
+
onClipboardEventName,
|
|
30
|
+
Bundle().apply {
|
|
31
|
+
putString("content", clip.getItemAt(0).text.toString())
|
|
32
|
+
}
|
|
33
|
+
)
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
override fun onHostResume() {
|
|
41
|
+
isListening = true
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
override fun onHostPause() {
|
|
45
|
+
isListening = false
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
override fun onHostDestroy() = Unit
|
|
49
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
package expo.modules.clipboard
|
|
2
|
+
|
|
3
|
+
import android.content.Context
|
|
4
|
+
import android.content.ClipData
|
|
5
|
+
import android.content.ClipboardManager
|
|
6
|
+
|
|
7
|
+
import expo.modules.core.ExportedModule
|
|
8
|
+
import expo.modules.core.ModuleRegistry
|
|
9
|
+
import expo.modules.core.Promise
|
|
10
|
+
import expo.modules.core.interfaces.ExpoMethod
|
|
11
|
+
|
|
12
|
+
class ClipboardModule(context: Context) : ExportedModule(context) {
|
|
13
|
+
private val NAME = "ExpoClipboard"
|
|
14
|
+
|
|
15
|
+
override fun getName(): String {
|
|
16
|
+
return NAME
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
override fun onCreate(moduleRegistry: ModuleRegistry) {
|
|
20
|
+
ClipboardEventEmitter(context, moduleRegistry)
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
@ExpoMethod
|
|
24
|
+
fun getStringAsync(promise: Promise) {
|
|
25
|
+
val clipboard = context.getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager
|
|
26
|
+
val clip = clipboard.primaryClip
|
|
27
|
+
if (clip != null && clip.itemCount >= 1) {
|
|
28
|
+
promise.resolve(clip.getItemAt(0).text)
|
|
29
|
+
} else {
|
|
30
|
+
promise.resolve("")
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
@ExpoMethod
|
|
35
|
+
fun setString(content: String, promise: Promise) {
|
|
36
|
+
val clipboard = context.getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager
|
|
37
|
+
val clip = ClipData.newPlainText(null, content)
|
|
38
|
+
clipboard.setPrimaryClip(clip)
|
|
39
|
+
promise.resolve(null)
|
|
40
|
+
}
|
|
41
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
package expo.modules.clipboard
|
|
2
|
+
|
|
3
|
+
import android.content.Context
|
|
4
|
+
|
|
5
|
+
import expo.modules.core.BasePackage
|
|
6
|
+
import expo.modules.core.ExportedModule
|
|
7
|
+
|
|
8
|
+
class ClipboardPackage : BasePackage() {
|
|
9
|
+
override fun createExportedModules(context: Context): List<ExportedModule> {
|
|
10
|
+
return listOf(ClipboardModule(context) as ExportedModule)
|
|
11
|
+
}
|
|
12
|
+
}
|
package/build/Clipboard.d.ts
CHANGED
|
@@ -1,2 +1,53 @@
|
|
|
1
|
-
import
|
|
2
|
-
|
|
1
|
+
import { EventEmitter, Subscription } from 'expo-modules-core';
|
|
2
|
+
declare type ClipboardEvent = {
|
|
3
|
+
/**
|
|
4
|
+
* The new content of the user's clipboard.
|
|
5
|
+
*/
|
|
6
|
+
content: string;
|
|
7
|
+
};
|
|
8
|
+
export { Subscription, EventEmitter, ClipboardEvent };
|
|
9
|
+
/**
|
|
10
|
+
* Gets the content of the user's clipboard. Please note that calling this method on web will prompt
|
|
11
|
+
* the user to grant your app permission to "see text and images copied to the clipboard."
|
|
12
|
+
*
|
|
13
|
+
* @returns A promise that resolves to the content of the clipboard.
|
|
14
|
+
*/
|
|
15
|
+
export declare function getStringAsync(): Promise<string>;
|
|
16
|
+
/**
|
|
17
|
+
* Sets the content of the user's clipboard.
|
|
18
|
+
*
|
|
19
|
+
* @param text The string to save to the clipboard.
|
|
20
|
+
*
|
|
21
|
+
* @returns On web, this returns a boolean value indicating whether or not the string was saved to
|
|
22
|
+
* the user's clipboard. On iOS and Android, nothing is returned.
|
|
23
|
+
*/
|
|
24
|
+
export declare function setString(text: string): void;
|
|
25
|
+
/**
|
|
26
|
+
* Adds a listener that will fire whenever the content of the user's clipboard changes. This method
|
|
27
|
+
* is a no-op on Web.
|
|
28
|
+
*
|
|
29
|
+
* @param listener Callback to execute when listener is triggered. The callback is provided a
|
|
30
|
+
* single argument that is an object with a `content` key.
|
|
31
|
+
*
|
|
32
|
+
* @example
|
|
33
|
+
* ```typescript
|
|
34
|
+
* addClipboardListener(({ content }: ClipboardEvent) => {
|
|
35
|
+
* alert('Copy pasta! Here's the string that was copied: ' + content);
|
|
36
|
+
* });
|
|
37
|
+
* ```
|
|
38
|
+
*/
|
|
39
|
+
export declare function addClipboardListener(listener: (event: ClipboardEvent) => void): Subscription;
|
|
40
|
+
/**
|
|
41
|
+
* Removes the listener added by addClipboardListener. This method is a no-op on Web.
|
|
42
|
+
*
|
|
43
|
+
* @param subscription The subscription to remove (created by addClipboardListener).
|
|
44
|
+
*
|
|
45
|
+
* @example
|
|
46
|
+
* ```typescript
|
|
47
|
+
* const subscription = addClipboardListener(() => {
|
|
48
|
+
* alert('Copy pasta!');
|
|
49
|
+
* });
|
|
50
|
+
* removeClipboardListener(subscription);
|
|
51
|
+
* ```
|
|
52
|
+
*/
|
|
53
|
+
export declare function removeClipboardListener(subscription: Subscription): void;
|
package/build/Clipboard.js
CHANGED
|
@@ -1,3 +1,65 @@
|
|
|
1
|
+
import { EventEmitter, UnavailabilityError } from 'expo-modules-core';
|
|
1
2
|
import ExpoClipboard from './ExpoClipboard';
|
|
2
|
-
|
|
3
|
+
const emitter = new EventEmitter(ExpoClipboard);
|
|
4
|
+
const onClipboardEventName = 'onClipboardChanged';
|
|
5
|
+
export { EventEmitter };
|
|
6
|
+
/**
|
|
7
|
+
* Gets the content of the user's clipboard. Please note that calling this method on web will prompt
|
|
8
|
+
* the user to grant your app permission to "see text and images copied to the clipboard."
|
|
9
|
+
*
|
|
10
|
+
* @returns A promise that resolves to the content of the clipboard.
|
|
11
|
+
*/
|
|
12
|
+
export async function getStringAsync() {
|
|
13
|
+
if (!ExpoClipboard.getStringAsync) {
|
|
14
|
+
throw new UnavailabilityError('Clipboard', 'getStringAsync');
|
|
15
|
+
}
|
|
16
|
+
return await ExpoClipboard.getStringAsync();
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Sets the content of the user's clipboard.
|
|
20
|
+
*
|
|
21
|
+
* @param text The string to save to the clipboard.
|
|
22
|
+
*
|
|
23
|
+
* @returns On web, this returns a boolean value indicating whether or not the string was saved to
|
|
24
|
+
* the user's clipboard. On iOS and Android, nothing is returned.
|
|
25
|
+
*/
|
|
26
|
+
export function setString(text) {
|
|
27
|
+
if (!ExpoClipboard.setString) {
|
|
28
|
+
throw new UnavailabilityError('Clipboard', 'setString');
|
|
29
|
+
}
|
|
30
|
+
return ExpoClipboard.setString(text);
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Adds a listener that will fire whenever the content of the user's clipboard changes. This method
|
|
34
|
+
* is a no-op on Web.
|
|
35
|
+
*
|
|
36
|
+
* @param listener Callback to execute when listener is triggered. The callback is provided a
|
|
37
|
+
* single argument that is an object with a `content` key.
|
|
38
|
+
*
|
|
39
|
+
* @example
|
|
40
|
+
* ```typescript
|
|
41
|
+
* addClipboardListener(({ content }: ClipboardEvent) => {
|
|
42
|
+
* alert('Copy pasta! Here's the string that was copied: ' + content);
|
|
43
|
+
* });
|
|
44
|
+
* ```
|
|
45
|
+
*/
|
|
46
|
+
export function addClipboardListener(listener) {
|
|
47
|
+
return emitter.addListener(onClipboardEventName, listener);
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Removes the listener added by addClipboardListener. This method is a no-op on Web.
|
|
51
|
+
*
|
|
52
|
+
* @param subscription The subscription to remove (created by addClipboardListener).
|
|
53
|
+
*
|
|
54
|
+
* @example
|
|
55
|
+
* ```typescript
|
|
56
|
+
* const subscription = addClipboardListener(() => {
|
|
57
|
+
* alert('Copy pasta!');
|
|
58
|
+
* });
|
|
59
|
+
* removeClipboardListener(subscription);
|
|
60
|
+
* ```
|
|
61
|
+
*/
|
|
62
|
+
export function removeClipboardListener(subscription) {
|
|
63
|
+
emitter.removeSubscription(subscription);
|
|
64
|
+
}
|
|
3
65
|
//# sourceMappingURL=Clipboard.js.map
|
package/build/Clipboard.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Clipboard.js","sourceRoot":"","sources":["../src/Clipboard.ts"],"names":[],"mappings":"AAAA,OAAO,aAAa,MAAM,iBAAiB,CAAC;
|
|
1
|
+
{"version":3,"file":"Clipboard.js","sourceRoot":"","sources":["../src/Clipboard.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAgB,mBAAmB,EAAE,MAAM,mBAAmB,CAAC;AAEpF,OAAO,aAAa,MAAM,iBAAiB,CAAC;AAE5C,MAAM,OAAO,GAAG,IAAI,YAAY,CAAC,aAAa,CAAC,CAAC;AAEhD,MAAM,oBAAoB,GAAG,oBAAoB,CAAC;AASlD,OAAO,EAAgB,YAAY,EAAkB,CAAC;AAEtD;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,cAAc;IAClC,IAAI,CAAC,aAAa,CAAC,cAAc,EAAE;QACjC,MAAM,IAAI,mBAAmB,CAAC,WAAW,EAAE,gBAAgB,CAAC,CAAC;KAC9D;IACD,OAAO,MAAM,aAAa,CAAC,cAAc,EAAE,CAAC;AAC9C,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,SAAS,CAAC,IAAY;IACpC,IAAI,CAAC,aAAa,CAAC,SAAS,EAAE;QAC5B,MAAM,IAAI,mBAAmB,CAAC,WAAW,EAAE,WAAW,CAAC,CAAC;KACzD;IACD,OAAO,aAAa,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC;AACvC,CAAC;AAED;;;;;;;;;;;;;GAaG;AACH,MAAM,UAAU,oBAAoB,CAAC,QAAyC;IAC5E,OAAO,OAAO,CAAC,WAAW,CAAiB,oBAAoB,EAAE,QAAQ,CAAC,CAAC;AAC7E,CAAC;AAED;;;;;;;;;;;;GAYG;AACH,MAAM,UAAU,uBAAuB,CAAC,YAA0B;IAChE,OAAO,CAAC,kBAAkB,CAAC,YAAY,CAAC,CAAC;AAC3C,CAAC","sourcesContent":["import { EventEmitter, Subscription, UnavailabilityError } from 'expo-modules-core';\n\nimport ExpoClipboard from './ExpoClipboard';\n\nconst emitter = new EventEmitter(ExpoClipboard);\n\nconst onClipboardEventName = 'onClipboardChanged';\n\ntype ClipboardEvent = {\n /**\n * The new content of the user's clipboard.\n */\n content: string;\n};\n\nexport { Subscription, EventEmitter, ClipboardEvent };\n\n/**\n * Gets the content of the user's clipboard. Please note that calling this method on web will prompt\n * the user to grant your app permission to \"see text and images copied to the clipboard.\"\n *\n * @returns A promise that resolves to the content of the clipboard.\n */\nexport async function getStringAsync(): Promise<string> {\n if (!ExpoClipboard.getStringAsync) {\n throw new UnavailabilityError('Clipboard', 'getStringAsync');\n }\n return await ExpoClipboard.getStringAsync();\n}\n\n/**\n * Sets the content of the user's clipboard.\n *\n * @param text The string to save to the clipboard.\n *\n * @returns On web, this returns a boolean value indicating whether or not the string was saved to\n * the user's clipboard. On iOS and Android, nothing is returned.\n */\nexport function setString(text: string): void {\n if (!ExpoClipboard.setString) {\n throw new UnavailabilityError('Clipboard', 'setString');\n }\n return ExpoClipboard.setString(text);\n}\n\n/**\n * Adds a listener that will fire whenever the content of the user's clipboard changes. This method\n * is a no-op on Web.\n *\n * @param listener Callback to execute when listener is triggered. The callback is provided a\n * single argument that is an object with a `content` key.\n *\n * @example\n * ```typescript\n * addClipboardListener(({ content }: ClipboardEvent) => {\n * alert('Copy pasta! Here's the string that was copied: ' + content);\n * });\n * ```\n */\nexport function addClipboardListener(listener: (event: ClipboardEvent) => void): Subscription {\n return emitter.addListener<ClipboardEvent>(onClipboardEventName, listener);\n}\n\n/**\n * Removes the listener added by addClipboardListener. This method is a no-op on Web.\n *\n * @param subscription The subscription to remove (created by addClipboardListener).\n *\n * @example\n * ```typescript\n * const subscription = addClipboardListener(() => {\n * alert('Copy pasta!');\n * });\n * removeClipboardListener(subscription);\n * ```\n */\nexport function removeClipboardListener(subscription: Subscription) {\n emitter.removeSubscription(subscription);\n}\n"]}
|
package/build/ExpoClipboard.d.ts
CHANGED
package/build/ExpoClipboard.js
CHANGED
|
@@ -1,11 +1,3 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
export default {
|
|
4
|
-
async getStringAsync() {
|
|
5
|
-
return await Clipboard.getString();
|
|
6
|
-
},
|
|
7
|
-
setString(text) {
|
|
8
|
-
Clipboard.setString(text);
|
|
9
|
-
},
|
|
10
|
-
};
|
|
1
|
+
import { NativeModulesProxy } from 'expo-modules-core';
|
|
2
|
+
export default NativeModulesProxy.ExpoClipboard;
|
|
11
3
|
//# sourceMappingURL=ExpoClipboard.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ExpoClipboard.js","sourceRoot":"","sources":["../src/ExpoClipboard.ts"],"names":[],"mappings":"AAAA,
|
|
1
|
+
{"version":3,"file":"ExpoClipboard.js","sourceRoot":"","sources":["../src/ExpoClipboard.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AAEvD,eAAe,kBAAkB,CAAC,aAAa,CAAC","sourcesContent":["import { NativeModulesProxy } from 'expo-modules-core';\n\nexport default NativeModulesProxy.ExpoClipboard;\n"]}
|
|
@@ -14,7 +14,7 @@ export default {
|
|
|
14
14
|
text = window.clipboardData.getData('Text');
|
|
15
15
|
}
|
|
16
16
|
catch (e) {
|
|
17
|
-
Promise.reject(new Error('Unable to retrieve item from clipboard.'));
|
|
17
|
+
return Promise.reject(new Error('Unable to retrieve item from clipboard.'));
|
|
18
18
|
}
|
|
19
19
|
}
|
|
20
20
|
return text;
|
|
@@ -22,7 +22,7 @@ export default {
|
|
|
22
22
|
setString(text) {
|
|
23
23
|
let success = false;
|
|
24
24
|
const textField = document.createElement('textarea');
|
|
25
|
-
textField.
|
|
25
|
+
textField.textContent = text;
|
|
26
26
|
document.body.appendChild(textField);
|
|
27
27
|
textField.select();
|
|
28
28
|
try {
|
|
@@ -33,5 +33,7 @@ export default {
|
|
|
33
33
|
document.body.removeChild(textField);
|
|
34
34
|
return success;
|
|
35
35
|
},
|
|
36
|
+
addClipboardListener() { },
|
|
37
|
+
removeClipboardListener() { },
|
|
36
38
|
};
|
|
37
39
|
//# sourceMappingURL=ExpoClipboard.web.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ExpoClipboard.web.js","sourceRoot":"","sources":["../src/ExpoClipboard.web.ts"],"names":[],"mappings":"AAAA,eAAe;IACb,IAAI,IAAI;QACN,OAAO,eAAe,CAAC;IACzB,CAAC;IACD,KAAK,CAAC,cAAc;QAClB,IAAI,IAAI,GAAG,EAAE,CAAC;QACd,IAAI;YACF,IAAI,GAAG,MAAM,SAAS,CAAC,SAAS,CAAC,QAAQ,EAAE,CAAC;SAC7C;QAAC,OAAO,CAAC,EAAE;YACV,IAAI;gBACF,oBAAoB;gBACpB,aAAa;gBACb,IAAI,GAAG,MAAM,CAAC,aAAa,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;aAC7C;YAAC,OAAO,CAAC,EAAE;gBACV,OAAO,CAAC,MAAM,CAAC,IAAI,KAAK,CAAC,yCAAyC,CAAC,CAAC,CAAC;
|
|
1
|
+
{"version":3,"file":"ExpoClipboard.web.js","sourceRoot":"","sources":["../src/ExpoClipboard.web.ts"],"names":[],"mappings":"AAAA,eAAe;IACb,IAAI,IAAI;QACN,OAAO,eAAe,CAAC;IACzB,CAAC;IACD,KAAK,CAAC,cAAc;QAClB,IAAI,IAAI,GAAG,EAAE,CAAC;QACd,IAAI;YACF,IAAI,GAAG,MAAM,SAAS,CAAC,SAAS,CAAC,QAAQ,EAAE,CAAC;SAC7C;QAAC,OAAO,CAAC,EAAE;YACV,IAAI;gBACF,oBAAoB;gBACpB,aAAa;gBACb,IAAI,GAAG,MAAM,CAAC,aAAa,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;aAC7C;YAAC,OAAO,CAAC,EAAE;gBACV,OAAO,OAAO,CAAC,MAAM,CAAC,IAAI,KAAK,CAAC,yCAAyC,CAAC,CAAC,CAAC;aAC7E;SACF;QACD,OAAO,IAAI,CAAC;IACd,CAAC;IACD,SAAS,CAAC,IAAY;QACpB,IAAI,OAAO,GAAG,KAAK,CAAC;QACpB,MAAM,SAAS,GAAG,QAAQ,CAAC,aAAa,CAAC,UAAU,CAAC,CAAC;QACrD,SAAS,CAAC,WAAW,GAAG,IAAI,CAAC;QAC7B,QAAQ,CAAC,IAAI,CAAC,WAAW,CAAC,SAAS,CAAC,CAAC;QACrC,SAAS,CAAC,MAAM,EAAE,CAAC;QACnB,IAAI;YACF,QAAQ,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC;YAC7B,OAAO,GAAG,IAAI,CAAC;SAChB;QAAC,OAAO,CAAC,EAAE,GAAE;QACd,QAAQ,CAAC,IAAI,CAAC,WAAW,CAAC,SAAS,CAAC,CAAC;QACrC,OAAO,OAAO,CAAC;IACjB,CAAC;IACD,oBAAoB,KAAU,CAAC;IAC/B,uBAAuB,KAAU,CAAC;CACnC,CAAC","sourcesContent":["export default {\n get name(): string {\n return 'ExpoClipboard';\n },\n async getStringAsync(): Promise<string> {\n let text = '';\n try {\n text = await navigator.clipboard.readText();\n } catch (e) {\n try {\n // Internet Explorer\n // @ts-ignore\n text = window.clipboardData.getData('Text');\n } catch (e) {\n return Promise.reject(new Error('Unable to retrieve item from clipboard.'));\n }\n }\n return text;\n },\n setString(text: string): boolean {\n let success = false;\n const textField = document.createElement('textarea');\n textField.textContent = text;\n document.body.appendChild(textField);\n textField.select();\n try {\n document.execCommand('copy');\n success = true;\n } catch (e) {}\n document.body.removeChild(textField);\n return success;\n },\n addClipboardListener(): void {},\n removeClipboardListener(): void {},\n};\n"]}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
// Copyright © 2021 650 Industries. All rights reserved.
|
|
2
|
+
|
|
3
|
+
#import <ExpoModulesCore/EXExportedModule.h>
|
|
4
|
+
#import <ExpoModulesCore/EXModuleRegistryConsumer.h>
|
|
5
|
+
#import <ExpoModulesCore/EXEventEmitter.h>
|
|
6
|
+
|
|
7
|
+
@interface EXClipboardModule : EXExportedModule <EXModuleRegistryConsumer, EXEventEmitter>
|
|
8
|
+
@end
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
// Copyright 2021-present 650 Industries. All rights reserved.
|
|
2
|
+
|
|
3
|
+
#import <EXClipboard/EXClipboardModule.h>
|
|
4
|
+
|
|
5
|
+
#import <ExpoModulesCore/EXEventEmitterService.h>
|
|
6
|
+
|
|
7
|
+
static NSString * const onClipboardEventName = @"onClipboardChanged";
|
|
8
|
+
|
|
9
|
+
@interface EXClipboardModule ()
|
|
10
|
+
|
|
11
|
+
@property (nonatomic, weak) EXModuleRegistry *moduleRegistry;
|
|
12
|
+
@property (nonatomic, assign) BOOL isListening;
|
|
13
|
+
@property (nonatomic, assign) BOOL isBeingObserved;
|
|
14
|
+
@property (nonatomic, weak) id<EXEventEmitterService> eventEmitter;
|
|
15
|
+
|
|
16
|
+
@end
|
|
17
|
+
|
|
18
|
+
@implementation EXClipboardModule
|
|
19
|
+
|
|
20
|
+
EX_EXPORT_MODULE(ExpoClipboard);
|
|
21
|
+
|
|
22
|
+
# pragma mark - EXModuleRegistryConsumer
|
|
23
|
+
|
|
24
|
+
- (void)setModuleRegistry:(EXModuleRegistry *)moduleRegistry
|
|
25
|
+
{
|
|
26
|
+
_moduleRegistry = moduleRegistry;
|
|
27
|
+
_eventEmitter = [moduleRegistry getModuleImplementingProtocol:@protocol(EXEventEmitterService)];
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
# pragma mark - Exported methods
|
|
31
|
+
|
|
32
|
+
EX_EXPORT_METHOD_AS(getStringAsync,
|
|
33
|
+
getStringAsyncWithResolver:(EXPromiseResolveBlock)resolve
|
|
34
|
+
reject:(EXPromiseRejectBlock)reject)
|
|
35
|
+
{
|
|
36
|
+
UIPasteboard *clipboard = [UIPasteboard generalPasteboard];
|
|
37
|
+
resolve((clipboard.string ?: @""));
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
EX_EXPORT_METHOD_AS(setString,
|
|
41
|
+
setStringWithContent:(NSString *)content
|
|
42
|
+
resolver:(EXPromiseResolveBlock)resolve
|
|
43
|
+
rejecter:(EXPromiseRejectBlock)reject)
|
|
44
|
+
{
|
|
45
|
+
UIPasteboard *clipboard = [UIPasteboard generalPasteboard];
|
|
46
|
+
clipboard.string = (content ? : @"");
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
# pragma mark - EXEventEmitter
|
|
50
|
+
|
|
51
|
+
- (NSArray<NSString *> *)supportedEvents
|
|
52
|
+
{
|
|
53
|
+
return @[onClipboardEventName];
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
- (void)startObserving
|
|
57
|
+
{
|
|
58
|
+
[self setIsBeingObserved:YES];
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
- (void)stopObserving
|
|
62
|
+
{
|
|
63
|
+
[self setIsBeingObserved:NO];
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
- (void)setIsBeingObserved:(BOOL)isBeingObserved
|
|
67
|
+
{
|
|
68
|
+
_isBeingObserved = isBeingObserved;
|
|
69
|
+
BOOL shouldListen = _isBeingObserved;
|
|
70
|
+
if (shouldListen && !_isListening) {
|
|
71
|
+
// Avoid setting duplicate observers
|
|
72
|
+
[[NSNotificationCenter defaultCenter] removeObserver:self name:UIPasteboardChangedNotification object:nil];
|
|
73
|
+
[[NSNotificationCenter defaultCenter] addObserver:self
|
|
74
|
+
selector:@selector(listenToClipboard) name:UIPasteboardChangedNotification object:nil];
|
|
75
|
+
_isListening = YES;
|
|
76
|
+
} else if (!shouldListen && _isListening) {
|
|
77
|
+
[[NSNotificationCenter defaultCenter] removeObserver:self name:UIPasteboardChangedNotification object:nil];
|
|
78
|
+
_isListening = NO;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
- (void)listenToClipboard
|
|
83
|
+
{
|
|
84
|
+
UIPasteboard *clipboard = [UIPasteboard generalPasteboard];
|
|
85
|
+
[_eventEmitter sendEventWithName:onClipboardEventName body:@{ @"content" : clipboard.string ?: @"" }];
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
@end
|
|
@@ -0,0 +1,28 @@
|
|
|
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 = 'EXClipboard'
|
|
7
|
+
s.version = package['version']
|
|
8
|
+
s.summary = package['description']
|
|
9
|
+
s.description = package['description']
|
|
10
|
+
s.license = package['license']
|
|
11
|
+
s.author = package['author']
|
|
12
|
+
s.homepage = package['homepage']
|
|
13
|
+
s.platform = :ios, '12.0'
|
|
14
|
+
s.source = { git: 'https://github.com/expo/expo.git' }
|
|
15
|
+
s.static_framework = true
|
|
16
|
+
s.source_files = 'EXClipboard/**/*.{h,m}'
|
|
17
|
+
s.preserve_paths = 'EXClipboard/**/*.{h,m}'
|
|
18
|
+
s.requires_arc = true
|
|
19
|
+
|
|
20
|
+
s.dependency 'ExpoModulesCore'
|
|
21
|
+
|
|
22
|
+
if !$ExpoUseSources&.include?(package['name']) && ENV['EXPO_USE_SOURCE'].to_i == 0 && File.exist?("#{s.name}.xcframework") && Gem::Version.new(Pod::VERSION) >= Gem::Version.new('1.10.0')
|
|
23
|
+
s.source_files = "#{s.name}/**/*.h"
|
|
24
|
+
s.vendored_frameworks = "#{s.name}.xcframework"
|
|
25
|
+
else
|
|
26
|
+
s.source_files = "#{s.name}/**/*.{h,m}"
|
|
27
|
+
end
|
|
28
|
+
end
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "expo-clipboard",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "2.0.1",
|
|
4
4
|
"description": "ExpoClipboard standalone module",
|
|
5
5
|
"main": "build/Clipboard.js",
|
|
6
6
|
"types": "build/Clipboard.d.ts",
|
|
@@ -28,16 +28,15 @@
|
|
|
28
28
|
},
|
|
29
29
|
"author": "650 Industries, Inc.",
|
|
30
30
|
"license": "MIT",
|
|
31
|
-
"homepage": "https://docs.expo.
|
|
32
|
-
"
|
|
33
|
-
"
|
|
34
|
-
"react-native": "*"
|
|
31
|
+
"homepage": "https://docs.expo.dev/versions/latest/sdk/clipboard",
|
|
32
|
+
"dependencies": {
|
|
33
|
+
"expo-modules-core": "~0.4.2"
|
|
35
34
|
},
|
|
36
35
|
"devDependencies": {
|
|
37
|
-
"expo-module-scripts": "^
|
|
36
|
+
"expo-module-scripts": "^2.0.0"
|
|
38
37
|
},
|
|
39
38
|
"jest": {
|
|
40
39
|
"preset": "expo-module-scripts/universal"
|
|
41
40
|
},
|
|
42
|
-
"gitHead": "
|
|
41
|
+
"gitHead": "2718b696f4a6919905b0f47ebb24ff65b42d8ff9"
|
|
43
42
|
}
|
package/src/Clipboard.ts
CHANGED
|
@@ -1,2 +1,79 @@
|
|
|
1
|
+
import { EventEmitter, Subscription, UnavailabilityError } from 'expo-modules-core';
|
|
2
|
+
|
|
1
3
|
import ExpoClipboard from './ExpoClipboard';
|
|
2
|
-
|
|
4
|
+
|
|
5
|
+
const emitter = new EventEmitter(ExpoClipboard);
|
|
6
|
+
|
|
7
|
+
const onClipboardEventName = 'onClipboardChanged';
|
|
8
|
+
|
|
9
|
+
type ClipboardEvent = {
|
|
10
|
+
/**
|
|
11
|
+
* The new content of the user's clipboard.
|
|
12
|
+
*/
|
|
13
|
+
content: string;
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
export { Subscription, EventEmitter, ClipboardEvent };
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Gets the content of the user's clipboard. Please note that calling this method on web will prompt
|
|
20
|
+
* the user to grant your app permission to "see text and images copied to the clipboard."
|
|
21
|
+
*
|
|
22
|
+
* @returns A promise that resolves to the content of the clipboard.
|
|
23
|
+
*/
|
|
24
|
+
export async function getStringAsync(): Promise<string> {
|
|
25
|
+
if (!ExpoClipboard.getStringAsync) {
|
|
26
|
+
throw new UnavailabilityError('Clipboard', 'getStringAsync');
|
|
27
|
+
}
|
|
28
|
+
return await ExpoClipboard.getStringAsync();
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Sets the content of the user's clipboard.
|
|
33
|
+
*
|
|
34
|
+
* @param text The string to save to the clipboard.
|
|
35
|
+
*
|
|
36
|
+
* @returns On web, this returns a boolean value indicating whether or not the string was saved to
|
|
37
|
+
* the user's clipboard. On iOS and Android, nothing is returned.
|
|
38
|
+
*/
|
|
39
|
+
export function setString(text: string): void {
|
|
40
|
+
if (!ExpoClipboard.setString) {
|
|
41
|
+
throw new UnavailabilityError('Clipboard', 'setString');
|
|
42
|
+
}
|
|
43
|
+
return ExpoClipboard.setString(text);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Adds a listener that will fire whenever the content of the user's clipboard changes. This method
|
|
48
|
+
* is a no-op on Web.
|
|
49
|
+
*
|
|
50
|
+
* @param listener Callback to execute when listener is triggered. The callback is provided a
|
|
51
|
+
* single argument that is an object with a `content` key.
|
|
52
|
+
*
|
|
53
|
+
* @example
|
|
54
|
+
* ```typescript
|
|
55
|
+
* addClipboardListener(({ content }: ClipboardEvent) => {
|
|
56
|
+
* alert('Copy pasta! Here's the string that was copied: ' + content);
|
|
57
|
+
* });
|
|
58
|
+
* ```
|
|
59
|
+
*/
|
|
60
|
+
export function addClipboardListener(listener: (event: ClipboardEvent) => void): Subscription {
|
|
61
|
+
return emitter.addListener<ClipboardEvent>(onClipboardEventName, listener);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Removes the listener added by addClipboardListener. This method is a no-op on Web.
|
|
66
|
+
*
|
|
67
|
+
* @param subscription The subscription to remove (created by addClipboardListener).
|
|
68
|
+
*
|
|
69
|
+
* @example
|
|
70
|
+
* ```typescript
|
|
71
|
+
* const subscription = addClipboardListener(() => {
|
|
72
|
+
* alert('Copy pasta!');
|
|
73
|
+
* });
|
|
74
|
+
* removeClipboardListener(subscription);
|
|
75
|
+
* ```
|
|
76
|
+
*/
|
|
77
|
+
export function removeClipboardListener(subscription: Subscription) {
|
|
78
|
+
emitter.removeSubscription(subscription);
|
|
79
|
+
}
|
package/src/ExpoClipboard.ts
CHANGED
|
@@ -1,11 +1,3 @@
|
|
|
1
|
-
|
|
2
|
-
import Clipboard from 'react-native/Libraries/Components/Clipboard/Clipboard';
|
|
1
|
+
import { NativeModulesProxy } from 'expo-modules-core';
|
|
3
2
|
|
|
4
|
-
export default
|
|
5
|
-
async getStringAsync(): Promise<string> {
|
|
6
|
-
return await Clipboard.getString();
|
|
7
|
-
},
|
|
8
|
-
setString(text: string): void {
|
|
9
|
-
Clipboard.setString(text);
|
|
10
|
-
},
|
|
11
|
-
};
|
|
3
|
+
export default NativeModulesProxy.ExpoClipboard;
|
package/src/ExpoClipboard.web.ts
CHANGED
|
@@ -12,7 +12,7 @@ export default {
|
|
|
12
12
|
// @ts-ignore
|
|
13
13
|
text = window.clipboardData.getData('Text');
|
|
14
14
|
} catch (e) {
|
|
15
|
-
Promise.reject(new Error('Unable to retrieve item from clipboard.'));
|
|
15
|
+
return Promise.reject(new Error('Unable to retrieve item from clipboard.'));
|
|
16
16
|
}
|
|
17
17
|
}
|
|
18
18
|
return text;
|
|
@@ -20,7 +20,7 @@ export default {
|
|
|
20
20
|
setString(text: string): boolean {
|
|
21
21
|
let success = false;
|
|
22
22
|
const textField = document.createElement('textarea');
|
|
23
|
-
textField.
|
|
23
|
+
textField.textContent = text;
|
|
24
24
|
document.body.appendChild(textField);
|
|
25
25
|
textField.select();
|
|
26
26
|
try {
|
|
@@ -30,4 +30,6 @@ export default {
|
|
|
30
30
|
document.body.removeChild(textField);
|
|
31
31
|
return success;
|
|
32
32
|
},
|
|
33
|
+
addClipboardListener(): void {},
|
|
34
|
+
removeClipboardListener(): void {},
|
|
33
35
|
};
|
package/unimodule.json
ADDED