Skip to content

Commit

Permalink
fix: use document.execCommand for non-secure context (TabbyML#1137)
Browse files Browse the repository at this point in the history
* fix: use document.execCommand for non-secure context

* fix: use shadn's toast component

* fix: onError option of useCopyToClipboard

* fix: use sonner
  • Loading branch information
liangfung authored Dec 29, 2023
1 parent a18ff03 commit 3ca9049
Show file tree
Hide file tree
Showing 8 changed files with 88 additions and 33 deletions.
5 changes: 3 additions & 2 deletions ee/tabby-ui/app/layout.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { Metadata } from 'next'
import { Toaster } from 'react-hot-toast'

import { Toaster } from '@/components/ui/sonner'

import '@/app/globals.css'

Expand Down Expand Up @@ -35,7 +36,7 @@ export default function RootLayout({ children }: RootLayoutProps) {
fontMono.variable
)}
>
<Toaster />
<Toaster richColors />
<Providers attribute="class" defaultTheme="system" enableSystem>
<div className="flex min-h-screen flex-col">{children}</div>
<TailwindIndicator />
Expand Down
3 changes: 1 addition & 2 deletions ee/tabby-ui/components/chat.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import React from 'react'
import { useChat } from 'ai/react'
import type { Message } from 'ai/react'
import { find, findIndex } from 'lodash-es'
import { toast } from 'react-hot-toast'
import { toast } from 'sonner'

import { usePatchFetch } from '@/lib/hooks/use-patch-fetch'
import { useStore } from '@/lib/hooks/use-store'
Expand All @@ -27,7 +27,6 @@ export interface ChatProps extends React.ComponentProps<'div'> {
export function Chat({ id, initialMessages, loading, className }: ChatProps) {
usePatchFetch()
const chats = useStore(useChatStore, state => state.chats)

const {
messages,
append,
Expand Down
2 changes: 1 addition & 1 deletion ee/tabby-ui/components/clear-history.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

import * as React from 'react'
import { useRouter } from 'next/navigation'
import { toast } from 'react-hot-toast'
import { toast } from 'sonner'

import { ServerActionResult } from '@/lib/types'
import {
Expand Down
3 changes: 0 additions & 3 deletions ee/tabby-ui/components/toaster.tsx

This file was deleted.

31 changes: 31 additions & 0 deletions ee/tabby-ui/components/ui/sonner.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
'use client'

import { useTheme } from 'next-themes'
import { Toaster as Sonner } from 'sonner'

type ToasterProps = React.ComponentProps<typeof Sonner>

const Toaster = ({ ...props }: ToasterProps) => {
const { theme = 'system' } = useTheme()

return (
<Sonner
theme={theme as ToasterProps['theme']}
className="toaster group"
toastOptions={{
classNames: {
toast:
'group toast group-[.toaster]:bg-background group-[.toaster]:text-foreground group-[.toaster]:border-border group-[.toaster]:shadow-lg',
description: 'group-[.toast]:text-muted-foreground',
actionButton:
'group-[.toast]:bg-primary group-[.toast]:text-primary-foreground',
cancelButton:
'group-[.toast]:bg-muted group-[.toast]:text-muted-foreground'
}
}}
{...props}
/>
)
}

export { Toaster }
45 changes: 33 additions & 12 deletions ee/tabby-ui/lib/hooks/use-copy-to-clipboard.tsx
Original file line number Diff line number Diff line change
@@ -1,32 +1,53 @@
'use client'

import * as React from 'react'
import copy from 'copy-to-clipboard'
import { toast } from 'sonner'

export interface useCopyToClipboardProps {
timeout?: number
onError?: (e?: any) => void
}

export function useCopyToClipboard({
timeout = 2000
timeout = 2000,
onError
}: useCopyToClipboardProps) {
const [isCopied, setIsCopied] = React.useState<Boolean>(false)

const copyToClipboard = (value: string) => {
if (typeof window === 'undefined' || !navigator.clipboard?.writeText) {
return
}
const onCopySuccess = () => {
setIsCopied(true)
setTimeout(() => {
setIsCopied(false)
}, timeout)
}

if (!value) {
const onCopyError = (error?: any) => {
if (typeof onError === 'function') {
onError?.(error)
return
}

navigator.clipboard.writeText(value).then(() => {
setIsCopied(true)
toast.error('Failed to copy.')
}

setTimeout(() => {
setIsCopied(false)
}, timeout)
})
const copyToClipboard = (value: string) => {
if (typeof window === 'undefined') return
if (!value) return

if (!!navigator.clipboard?.writeText) {
navigator.clipboard
.writeText(value)
.then(onCopySuccess)
.catch(onCopyError)
} else {
const copyResult = copy(value)
if (copyResult) {
onCopySuccess()
} else {
onCopyError()
}
}
}

return { isCopied, copyToClipboard }
Expand Down
3 changes: 2 additions & 1 deletion ee/tabby-ui/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@
"class-variance-authority": "^0.4.0",
"clsx": "^1.2.1",
"compare-versions": "^6.1.0",
"copy-to-clipboard": "^3.3.3",
"downshift": "^8.2.2",
"focus-trap-react": "^10.1.1",
"graphql": "^16.8.1",
Expand All @@ -52,13 +53,13 @@
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-hook-form": "^7.48.2",
"react-hot-toast": "^2.4.1",
"react-intersection-observer": "^9.4.4",
"react-markdown": "^8.0.7",
"react-syntax-highlighter": "^15.5.0",
"react-textarea-autosize": "^8.4.1",
"remark-gfm": "^3.0.1",
"remark-math": "^5.1.1",
"sonner": "^1.3.1",
"swr": "^2.2.4",
"use-local-storage": "^3.0.0",
"zod": "^3.22.4",
Expand Down
29 changes: 17 additions & 12 deletions ee/tabby-ui/yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -2832,6 +2832,13 @@ convert-source-map@^2.0.0:
resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-2.0.0.tgz#4b560f649fc4e918dd0ab75cf4961e8bc882d82a"
integrity sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==

copy-to-clipboard@^3.3.3:
version "3.3.3"
resolved "https://registry.yarnpkg.com/copy-to-clipboard/-/copy-to-clipboard-3.3.3.tgz#55ac43a1db8ae639a4bd99511c148cdd1b83a1b0"
integrity sha512-2KV8NhB5JqC3ky0r9PMCAZKbUHSwtEo4CwCs0KXgruG43gX5PMqDEBbVU4OUzw2MuAWUfsuFmWvEKG5QRfSnJA==
dependencies:
toggle-selection "^1.0.6"

cosmiconfig@^8.1.0, cosmiconfig@^8.1.3:
version "8.3.6"
resolved "https://registry.yarnpkg.com/cosmiconfig/-/cosmiconfig-8.3.6.tgz#060a2b871d66dba6c8538ea1118ba1ac16f5fae3"
Expand Down Expand Up @@ -3869,11 +3876,6 @@ globby@^11.0.3, globby@^11.1.0:
merge2 "^1.4.1"
slash "^3.0.0"

goober@^2.1.10:
version "2.1.13"
resolved "https://registry.yarnpkg.com/goober/-/goober-2.1.13.tgz#e3c06d5578486212a76c9eba860cbc3232ff6d7c"
integrity sha512-jFj3BQeleOoy7t93E9rZ2de+ScC4lQICLwiAQmKMg9F6roKGaLSHoCDYKkWlSafg138jejvq/mTdvmnwDQgqoQ==

gopd@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/gopd/-/gopd-1.0.1.tgz#29ff76de69dac7489b7c0918a5788e56477c332c"
Expand Down Expand Up @@ -5931,13 +5933,6 @@ react-hook-form@^7.48.2:
resolved "https://registry.yarnpkg.com/react-hook-form/-/react-hook-form-7.48.2.tgz#01150354d2be61412ff56a030b62a119283b9935"
integrity sha512-H0T2InFQb1hX7qKtDIZmvpU1Xfn/bdahWBN1fH19gSe4bBEqTfmlr7H3XWTaVtiK4/tpPaI1F3355GPMZYge+A==

react-hot-toast@^2.4.1:
version "2.4.1"
resolved "https://registry.yarnpkg.com/react-hot-toast/-/react-hot-toast-2.4.1.tgz#df04295eda8a7b12c4f968e54a61c8d36f4c0994"
integrity sha512-j8z+cQbWIM5LY37pR6uZR6D4LfseplqnuAO4co4u8917hBUvXlEqyP1ZzqVLcqoyUesZZv/ImreoCeHVDpE5pQ==
dependencies:
goober "^2.1.10"

react-intersection-observer@^9.4.4:
version "9.5.2"
resolved "https://registry.yarnpkg.com/react-intersection-observer/-/react-intersection-observer-9.5.2.tgz#f68363a1ff292323c0808201b58134307a1626d0"
Expand Down Expand Up @@ -6458,6 +6453,11 @@ [email protected]:
resolved "https://registry.yarnpkg.com/solid-swr-store/-/solid-swr-store-0.10.7.tgz#9511308f01250a1509efbfaad5b481be7517e436"
integrity sha512-A6d68aJmRP471aWqKKPE2tpgOiR5fH4qXQNfKIec+Vap+MGQm3tvXlT8n0I8UgJSlNAsSAUuw2VTviH2h3Vv5g==

sonner@^1.3.1:
version "1.3.1"
resolved "https://registry.yarnpkg.com/sonner/-/sonner-1.3.1.tgz#64aa2971d1110b6fe349f961d148c933f38ee9fa"
integrity sha512-+rOAO56b2eI3q5BtgljERSn2umRk63KFIvgb2ohbZ5X+Eb5u+a/7/0ZgswYqgBMg8dyl7n6OXd9KasA8QF9ToA==

source-map-js@^1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/source-map-js/-/source-map-js-1.0.2.tgz#adbc361d9c62df380125e7f161f71c826f1e490c"
Expand Down Expand Up @@ -6800,6 +6800,11 @@ to-regex-range@^5.0.1:
dependencies:
is-number "^7.0.0"

toggle-selection@^1.0.6:
version "1.0.6"
resolved "https://registry.yarnpkg.com/toggle-selection/-/toggle-selection-1.0.6.tgz#6e45b1263f2017fa0acc7d89d78b15b8bf77da32"
integrity sha512-BiZS+C1OS8g/q2RRbJmy59xpyghNBqrr6k5L/uKBGRsTfxmu3ffiRnd8mlGPUVayg8pvfi5urfnu8TU7DVOkLQ==

tr46@~0.0.3:
version "0.0.3"
resolved "https://registry.yarnpkg.com/tr46/-/tr46-0.0.3.tgz#8184fd347dac9cdc185992f3a6622e14b9d9ab6a"
Expand Down

0 comments on commit 3ca9049

Please sign in to comment.