1import * as Schema from "effect/Schema";
2import * as Clipboard from "expo-clipboard";
3import * as Haptics from "expo-haptics";
4
5export class CopyTextClipboardWriteError extends Schema.TaggedError<CopyTextClipboardWriteError>()(
6 "CopyTextClipboardWriteError",
7 {
8 target: Schema.String,
9 cause: Schema.Defect(),
10 },
11) {
12 override get message(): string {
13 return `Failed to copy ${this.target} to the clipboard.`;
14 }
15}
16
17export class CopyTextHapticFeedbackError extends Schema.TaggedError<CopyTextHapticFeedbackError>()(
18 "CopyTextHapticFeedbackError",
19 {
20 target: Schema.String,
21 feedback: Schema.Literals(["light-impact", "selection"]),
22 cause: Schema.Defect(),
23 },
24) {
25 override get message(): string {
26 return `Failed to trigger ${this.feedback} haptic feedback after copying ${this.target}.`;
27 }
28}
29
30interface CopyTextWithHapticOptions {
31 readonly target?: string;
32 readonly feedback?: "light-impact" | "selection";
33}
34
35export async function tryCopyTextWithHaptic(
36 value: string,
37 options: CopyTextWithHapticOptions = {},
38): Promise<boolean> {
39 const target = options.target ?? "text";
40 const feedback = options.feedback ?? "light-impact";
41
42 const clipboardWrite = (async () => {
43 try {
44 await Clipboard.setStringAsync(value);
45 return true;
46 } catch (cause) {
47 const error = new CopyTextClipboardWriteError({ target, cause });
48 console.error(error.message, { _tag: error._tag, target, stack: error.stack });
49 return false;
50 }
51 })();
52
53 void (async () => {
54 try {
55 if (feedback === "selection") {
56 await Haptics.selectionAsync();
57 } else {
58 await Haptics.impactAsync(Haptics.ImpactFeedbackStyle.Light);
59 }
60 } catch (cause) {
61 const error = new CopyTextHapticFeedbackError({ target, feedback, cause });
62 console.error(error.message, { _tag: error._tag, target, feedback, stack: error.stack });
63 }
64 })();
65
66 return await clipboardWrite;
67}
68
69export function copyTextWithHaptic(value: string, options: CopyTextWithHapticOptions = {}): void {
70 void tryCopyTextWithHaptic(value, options);
71}