|
1 | 1 | import type { Href } from '@react-types/shared'; |
2 | | -import type { Context, ReactNode, Ref } from 'react'; |
| 2 | +import type { Context, Ref } from 'react'; |
3 | 3 | import type { ContextValue, SlotProps } from 'react-aria-components'; |
4 | 4 |
|
5 | | -import { announce } from '@react-aria/live-announcer'; |
6 | 5 | import { mergeRefs } from '@react-aria/utils'; |
7 | 6 | import { useEffect, useLayoutEffect, useMemo, useState } from 'react'; |
8 | 7 | import { mergeProps } from 'react-aria'; |
9 | 8 | import { useSlottedContext } from 'react-aria-components'; |
10 | 9 | import { useHref as useRouterHref } from 'react-router'; |
11 | 10 |
|
12 | | -import { toastQueue } from './Toast'; |
13 | | - |
14 | 11 | type ImageLoadingStatus = 'idle' | 'loading' | 'loaded' | 'error'; |
15 | 12 |
|
16 | 13 | const useMedia = (media: string) => { |
@@ -94,67 +91,4 @@ const useLPContextProps = <T, U extends SlotProps, E>( |
94 | 91 | return [mergedProps, mergedRef]; |
95 | 92 | }; |
96 | 93 |
|
97 | | -const fallbackCopyToClipboard = (text: string) => |
98 | | - new Promise<boolean>((resolve, reject) => { |
99 | | - // Using setTimeout to ensure we focus the text area after the DOM is updated |
100 | | - // in cases of dropdown menus |
101 | | - setTimeout(() => { |
102 | | - try { |
103 | | - const textArea = document.createElement('textarea'); |
104 | | - textArea.value = text; |
105 | | - |
106 | | - textArea.style.position = 'fixed'; |
107 | | - textArea.style.left = '-999999px'; |
108 | | - textArea.style.top = '-999999px'; |
109 | | - document.body.appendChild(textArea); |
110 | | - |
111 | | - textArea.focus(); |
112 | | - textArea.select(); |
113 | | - |
114 | | - const successful = document.execCommand('copy'); |
115 | | - document.body.removeChild(textArea); |
116 | | - |
117 | | - if (successful) { |
118 | | - resolve(true); |
119 | | - } else { |
120 | | - reject(new Error('execCommand failed')); |
121 | | - } |
122 | | - } catch (error) { |
123 | | - reject(error); |
124 | | - } |
125 | | - }, 10); // Small delay to ensure focus operations complete |
126 | | - }); |
127 | | - |
128 | | -// navigator.clipboard is only available in secure contexts (https) |
129 | | -// We need to use document.execCommand for insecure contexts (http) |
130 | | -// for example when testing the Sandbox locally |
131 | | -const copyToClipboard = async ( |
132 | | - text: string, |
133 | | - toastMessage?: string | ReactNode, |
134 | | - errorMessage?: string | ReactNode, |
135 | | -) => { |
136 | | - const MAX_WIDTH = 80; |
137 | | - |
138 | | - try { |
139 | | - if ('clipboard' in navigator) { |
140 | | - await navigator.clipboard.writeText(text); |
141 | | - } else { |
142 | | - await fallbackCopyToClipboard(text); |
143 | | - } |
144 | | - |
145 | | - toastQueue.add({ |
146 | | - title: |
147 | | - toastMessage ?? |
148 | | - `'${text.length > MAX_WIDTH ? `${text.slice(0, MAX_WIDTH)}...` : text}' copied to clipboard.`, |
149 | | - status: 'success', |
150 | | - }); |
151 | | - announce('Copied!', 'polite', 300); |
152 | | - return true; |
153 | | - } catch { |
154 | | - announce('Failed to copy', 'polite', 300); |
155 | | - toastQueue.add({ title: errorMessage ?? 'Unable to copy', status: 'error' }); |
156 | | - return false; |
157 | | - } |
158 | | -}; |
159 | | - |
160 | | -export { copyToClipboard, useHref, useImageLoadingStatus, useLPContextProps, useMedia }; |
| 94 | +export { useHref, useImageLoadingStatus, useLPContextProps, useMedia }; |
0 commit comments