(false)
const [selectionText, setSelectionText] = useState('')
+ const { toast } = useToast()
useEffect(() => {
Ipc.addListener(TabCommand.connect, () => false)
@@ -37,6 +42,21 @@ export function App() {
}
}, [isHover])
+ useEffect(() => {
+ const handleShowReviewRequest = (_param: any, _sender: any, response: any) => {
+ showReviewRequestToast(toast, () => {
+ Settings.update('hasShownReviewRequest', () => true)
+ })
+ response(true)
+ return true
+ }
+
+ Ipc.addListener(TabCommand.showReviewRequest, handleShowReviewRequest)
+ return () => {
+ Ipc.removeListener(TabCommand.showReviewRequest)
+ }
+ }, [])
+
return (
@@ -50,6 +70,7 @@ export function App() {
+
)
diff --git a/src/components/ReviewRequestToast.tsx b/src/components/ReviewRequestToast.tsx
new file mode 100644
index 00000000..b2cd6de3
--- /dev/null
+++ b/src/components/ReviewRequestToast.tsx
@@ -0,0 +1,39 @@
+import { t } from '@/services/i18n'
+import { ToastAction } from "@/components/ui/toast"
+
+const REVIEW_URL = 'https://chromewebstore.google.com/detail/nlnhbibaommoelemmdfnkjkgoppkohje/reviews'
+const ICON_URL = chrome.runtime.getURL('icon128.png')
+
+export function showReviewRequestToast(toast: any, onAccept: () => void): void {
+ const tst = toast({
+ title: (
+
+
+
+ {t("review_request_title")}
+
+
+ ),
+ description:
+ {t("review_request_message")}
+ ,
+ className: 'flex flex-col text-gray-800',
+ action:
+ {
+ // Close the toast
+ tst.dismiss()
+ }}
+ >{t("review_request_later")}
+ {
+ window.open(REVIEW_URL, '_blank')
+ onAccept()
+ }}
+ >🎉 {t("review_request_button")}
+
,
+ duration: 60 * 1000,
+ })
+}
\ No newline at end of file
diff --git a/src/components/option/ImportExport.tsx b/src/components/option/ImportExport.tsx
index e37c15ce..086d3ca6 100644
--- a/src/components/option/ImportExport.tsx
+++ b/src/components/option/ImportExport.tsx
@@ -1,6 +1,6 @@
import { useState, useRef } from 'react'
import { Dialog } from './Dialog'
-import type { SettingsType } from '@/types'
+import type { UserSettings } from '@/types'
import { Storage, STORAGE_KEY } from '@/services/storage'
import { Settings, migrate } from '@/services/settings'
@@ -24,7 +24,7 @@ function getTimestamp() {
export function ImportExport() {
const [resetDialog, setResetDialog] = useState(false)
const [importDialog, setImportDialog] = useState(false)
- const [importJson, setImportJson] = useState()
+ const [importJson, setImportJson] = useState()
const inputFile = useRef(null)
const handleReset = () => {
@@ -39,7 +39,7 @@ export function ImportExport() {
}
const handleExport = async () => {
- const data = await Storage.get(STORAGE_KEY.USER)
+ const data = await Storage.get(STORAGE_KEY.USER)
data.commands = await Storage.getCommands()
// for back compatibility
@@ -84,7 +84,13 @@ export function ImportExport() {
const handleImportClose = (ret: boolean) => {
if (ret && importJson != null) {
; (async () => {
- const data = await migrate(importJson)
+ const { commandExecutionCount = 0, hasShownReviewRequest = false } = await Settings.get()
+ const data = await migrate({
+ ...importJson,
+ commandExecutionCount,
+ hasShownReviewRequest,
+ stars: []
+ })
await Settings.set(data)
location.reload()
})()
diff --git a/src/components/ui/toast.tsx b/src/components/ui/toast.tsx
new file mode 100644
index 00000000..5ea0563b
--- /dev/null
+++ b/src/components/ui/toast.tsx
@@ -0,0 +1,129 @@
+"use client"
+
+import * as React from "react"
+import * as ToastPrimitives from "@radix-ui/react-toast"
+import { cva, type VariantProps } from "class-variance-authority"
+import { X } from "lucide-react"
+
+import { cn } from "@/lib/utils"
+
+const ToastProvider = ToastPrimitives.Provider
+
+const ToastViewport = React.forwardRef<
+ React.ElementRef,
+ React.ComponentPropsWithoutRef
+>(({ className, ...props }, ref) => (
+
+))
+ToastViewport.displayName = ToastPrimitives.Viewport.displayName
+
+const toastVariants = cva(
+ "group pointer-events-auto relative flex w-full items-center justify-between space-x-2 overflow-hidden rounded-md border p-4 pr-6 shadow-lg transition-all data-[swipe=cancel]:translate-x-0 data-[swipe=end]:translate-x-[var(--radix-toast-swipe-end-x)] data-[swipe=move]:translate-x-[var(--radix-toast-swipe-move-x)] data-[swipe=move]:transition-none data-[state=open]:animate-in data-[state=closed]:animate-out data-[swipe=end]:animate-out data-[state=closed]:fade-out-80 data-[state=closed]:slide-out-to-right-full data-[state=open]:slide-in-from-top-full data-[state=open]:sm:slide-in-from-bottom-full",
+ {
+ variants: {
+ variant: {
+ default: "border bg-background text-foreground",
+ destructive:
+ "destructive group border-destructive bg-destructive text-destructive-foreground",
+ },
+ },
+ defaultVariants: {
+ variant: "default",
+ },
+ }
+)
+
+const Toast = React.forwardRef<
+ React.ElementRef,
+ React.ComponentPropsWithoutRef &
+ VariantProps
+>(({ className, variant, ...props }, ref) => {
+ return (
+
+ )
+})
+Toast.displayName = ToastPrimitives.Root.displayName
+
+const ToastAction = React.forwardRef<
+ React.ElementRef,
+ React.ComponentPropsWithoutRef
+>(({ className, ...props }, ref) => (
+
+))
+ToastAction.displayName = ToastPrimitives.Action.displayName
+
+const ToastClose = React.forwardRef<
+ React.ElementRef,
+ React.ComponentPropsWithoutRef
+>(({ className, ...props }, ref) => (
+
+
+
+))
+ToastClose.displayName = ToastPrimitives.Close.displayName
+
+const ToastTitle = React.forwardRef<
+ React.ElementRef,
+ React.ComponentPropsWithoutRef
+>(({ className, ...props }, ref) => (
+
+))
+ToastTitle.displayName = ToastPrimitives.Title.displayName
+
+const ToastDescription = React.forwardRef<
+ React.ElementRef,
+ React.ComponentPropsWithoutRef
+>(({ className, ...props }, ref) => (
+
+))
+ToastDescription.displayName = ToastPrimitives.Description.displayName
+
+type ToastProps = React.ComponentPropsWithoutRef
+
+type ToastActionElement = React.ReactElement
+
+export {
+ type ToastProps,
+ type ToastActionElement,
+ ToastProvider,
+ ToastViewport,
+ Toast,
+ ToastTitle,
+ ToastDescription,
+ ToastClose,
+ ToastAction,
+}
\ No newline at end of file
diff --git a/src/components/ui/toaster.tsx b/src/components/ui/toaster.tsx
new file mode 100644
index 00000000..b7ffff36
--- /dev/null
+++ b/src/components/ui/toaster.tsx
@@ -0,0 +1,35 @@
+"use client"
+
+import { useToast } from "@/hooks/useToast"
+import {
+ Toast,
+ ToastClose,
+ ToastDescription,
+ ToastProvider,
+ ToastTitle,
+ ToastViewport,
+} from "@/components/ui/toast"
+
+export function Toaster() {
+ const { toasts } = useToast()
+
+ return (
+
+ {toasts.map(function ({ id, title, description, action, ...props }) {
+ return (
+
+
+ {title && {title}}
+ {description && (
+ {description}
+ )}
+
+ {action}
+
+
+ )
+ })}
+
+
+ )
+}
diff --git a/src/hooks/useSetting.ts b/src/hooks/useSetting.ts
index a3874545..7ecf35a8 100644
--- a/src/hooks/useSetting.ts
+++ b/src/hooks/useSetting.ts
@@ -29,6 +29,8 @@ const emptySettings: SettingsType = {
userStyles: [],
startupMethod: { method: STARTUP_METHOD.TEXT_SELECTION },
stars: [],
+ commandExecutionCount: 0,
+ hasShownReviewRequest: false,
}
export function useSetting(): useSettingReturn {
diff --git a/src/hooks/useToast.tsx b/src/hooks/useToast.tsx
new file mode 100644
index 00000000..4e4408a7
--- /dev/null
+++ b/src/hooks/useToast.tsx
@@ -0,0 +1,194 @@
+"use client"
+
+// Inspired by react-hot-toast library
+import * as React from "react"
+
+import type {
+ ToastActionElement,
+ ToastProps,
+} from "@/components/ui/toast"
+
+const TOAST_LIMIT = 1
+const TOAST_REMOVE_DELAY = 1000000
+
+type ToasterToast = ToastProps & {
+ id: string
+ title?: React.ReactNode
+ description?: React.ReactNode
+ action?: ToastActionElement
+}
+
+const actionTypes = {
+ ADD_TOAST: "ADD_TOAST",
+ UPDATE_TOAST: "UPDATE_TOAST",
+ DISMISS_TOAST: "DISMISS_TOAST",
+ REMOVE_TOAST: "REMOVE_TOAST",
+} as const
+
+let count = 0
+
+function genId() {
+ count = (count + 1) % Number.MAX_SAFE_INTEGER
+ return count.toString()
+}
+
+type ActionType = typeof actionTypes
+
+type Action =
+ | {
+ type: ActionType["ADD_TOAST"]
+ toast: ToasterToast
+ }
+ | {
+ type: ActionType["UPDATE_TOAST"]
+ toast: Partial
+ }
+ | {
+ type: ActionType["DISMISS_TOAST"]
+ toastId?: ToasterToast["id"]
+ }
+ | {
+ type: ActionType["REMOVE_TOAST"]
+ toastId?: ToasterToast["id"]
+ }
+
+interface State {
+ toasts: ToasterToast[]
+}
+
+const toastTimeouts = new Map>()
+
+const addToRemoveQueue = (toastId: string) => {
+ if (toastTimeouts.has(toastId)) {
+ return
+ }
+
+ const timeout = setTimeout(() => {
+ toastTimeouts.delete(toastId)
+ dispatch({
+ type: "REMOVE_TOAST",
+ toastId: toastId,
+ })
+ }, TOAST_REMOVE_DELAY)
+
+ toastTimeouts.set(toastId, timeout)
+}
+
+export const reducer = (state: State, action: Action): State => {
+ switch (action.type) {
+ case "ADD_TOAST":
+ return {
+ ...state,
+ toasts: [action.toast, ...state.toasts].slice(0, TOAST_LIMIT),
+ }
+
+ case "UPDATE_TOAST":
+ return {
+ ...state,
+ toasts: state.toasts.map((t) =>
+ t.id === action.toast.id ? { ...t, ...action.toast } : t
+ ),
+ }
+
+ case "DISMISS_TOAST": {
+ const { toastId } = action
+
+ // ! Side effects ! - This could be extracted into a dismissToast() action,
+ // but I'll keep it here for simplicity
+ if (toastId) {
+ addToRemoveQueue(toastId)
+ } else {
+ state.toasts.forEach((toast) => {
+ addToRemoveQueue(toast.id)
+ })
+ }
+
+ return {
+ ...state,
+ toasts: state.toasts.map((t) =>
+ t.id === toastId || toastId === undefined
+ ? {
+ ...t,
+ open: false,
+ }
+ : t
+ ),
+ }
+ }
+ case "REMOVE_TOAST":
+ if (action.toastId === undefined) {
+ return {
+ ...state,
+ toasts: [],
+ }
+ }
+ return {
+ ...state,
+ toasts: state.toasts.filter((t) => t.id !== action.toastId),
+ }
+ }
+}
+
+const listeners: Array<(state: State) => void> = []
+
+let memoryState: State = { toasts: [] }
+
+function dispatch(action: Action) {
+ memoryState = reducer(memoryState, action)
+ listeners.forEach((listener) => {
+ listener(memoryState)
+ })
+}
+
+type Toast = Omit
+
+function toast({ ...props }: Toast) {
+ const id = genId()
+
+ const update = (props: ToasterToast) =>
+ dispatch({
+ type: "UPDATE_TOAST",
+ toast: { ...props, id },
+ })
+ const dismiss = () => dispatch({ type: "DISMISS_TOAST", toastId: id })
+
+ dispatch({
+ type: "ADD_TOAST",
+ toast: {
+ ...props,
+ id,
+ open: true,
+ onOpenChange: (open) => {
+ if (!open) dismiss()
+ },
+ },
+ })
+
+ return {
+ id: id,
+ dismiss,
+ update,
+ }
+}
+
+function useToast() {
+ const [state, setState] = React.useState(memoryState)
+
+ React.useEffect(() => {
+ listeners.push(setState)
+ return () => {
+ const index = listeners.indexOf(setState)
+ if (index > -1) {
+ listeners.splice(index, 1)
+ }
+ }
+ }, [state])
+
+ return {
+ ...state,
+ toast,
+ dismiss: (toastId?: string) => dispatch({ type: "DISMISS_TOAST", toastId }),
+ }
+}
+
+export { useToast, toast }
diff --git a/src/services/defaultSettings.ts b/src/services/defaultSettings.ts
index 92533b1e..a84429e1 100644
--- a/src/services/defaultSettings.ts
+++ b/src/services/defaultSettings.ts
@@ -1,4 +1,4 @@
-import { SettingsType, Command } from '@/types'
+import { UserSettings, Command } from '@/types'
import {
VERSION,
OPEN_MODE,
@@ -87,7 +87,7 @@ export default {
},
],
stars: [],
-} as SettingsType
+} as UserSettings
export const PopupOption = {
width: 600,
diff --git a/src/services/ipc.ts b/src/services/ipc.ts
index ee42ef51..ea724e6e 100644
--- a/src/services/ipc.ts
+++ b/src/services/ipc.ts
@@ -35,6 +35,7 @@ export enum TabCommand {
clickElement = 'clickElement',
closeMenu = 'closeMenu',
getTabId = 'getTabId',
+ showReviewRequest = 'showReviewRequest',
// PageAction
sendWindowSize = 'sendWindowSize',
execPageAction = 'execPageAction',
diff --git a/src/services/settings.ts b/src/services/settings.ts
index c86d2b64..870e018d 100644
--- a/src/services/settings.ts
+++ b/src/services/settings.ts
@@ -11,7 +11,7 @@ import {
SIDE,
ALIGN,
} from '@/const'
-import type { SettingsType, Version, Command, Star } from '@/types'
+import type { SettingsType, UserSettings, Version, Command, Star, UserStats } from '@/types'
import {
isBase64,
isEmpty,
@@ -57,6 +57,10 @@ export const Settings = {
// Stars
data.stars = await Storage.get(LOCAL_STORAGE_KEY.STARS)
+ // UserStats
+ const userStats = await Storage.get(STORAGE_KEY.USER_STATS)
+ data = { ...data, ...userStats }
+
data = await migrate(data)
data.folders = data.folders.filter((folder) => !!folder.title)
@@ -121,14 +125,35 @@ export const Settings = {
data.commands = []
// Stars
- await Storage.set(LOCAL_STORAGE_KEY.STARS, data.stars)
- data.stars = []
+ await Storage.set(LOCAL_STORAGE_KEY.STARS, data.stars)
+
+ // UserStats
+ const userStats: UserStats = {
+ commandExecutionCount: data.commandExecutionCount,
+ hasShownReviewRequest: data.hasShownReviewRequest,
+ }
+ await Storage.set(STORAGE_KEY.USER_STATS, userStats)
- await Storage.set(STORAGE_KEY.USER, data)
+ // Remove UserStats and stars from data
+ const { commandExecutionCount, hasShownReviewRequest, stars, ...restData } = data
+ await Storage.set(STORAGE_KEY.USER, restData)
await Storage.set(LOCAL_STORAGE_KEY.CACHES, caches)
return true
},
+ update: async (
+ key: T,
+ updater: (value: SettingsType[T]) => SettingsType[T],
+ serviceWorker = false,
+ ): Promise => {
+ const settings = await Settings.get()
+ const updatedSettings = {
+ ...settings,
+ [key]: updater(settings[key]),
+ }
+ return Settings.set(updatedSettings, serviceWorker)
+ },
+
addCommands: async (commands: Command[]): Promise => {
const current = await Storage.getCommands()
const newCommands = [...current, ...commands]
diff --git a/src/services/storage.ts b/src/services/storage.ts
index 3b490061..ff501ed6 100644
--- a/src/services/storage.ts
+++ b/src/services/storage.ts
@@ -4,6 +4,7 @@ import { Command, CaptureDataStorage } from '@/types'
export enum STORAGE_KEY {
USER = 0,
COMMAND_COUNT = 2,
+ USER_STATS = 3,
}
export enum LOCAL_STORAGE_KEY {
@@ -33,6 +34,10 @@ const DEFAULT_COUNT = -1
const DEFAULTS = {
[STORAGE_KEY.USER]: DefaultSettings,
[STORAGE_KEY.COMMAND_COUNT]: DEFAULT_COUNT,
+ [STORAGE_KEY.USER_STATS]: {
+ commandExecutionCount: 0,
+ hasShownReviewRequest: false,
+ },
[LOCAL_STORAGE_KEY.CACHES]: {
images: {},
},
diff --git a/src/types.ts b/src/types.ts
index 9936e951..8df76df9 100644
--- a/src/types.ts
+++ b/src/types.ts
@@ -118,10 +118,6 @@ export type StartupMethod = {
leftClickHoldParam?: number
}
-export type Star = {
- id: string
-}
-
export type PopupPlacement = {
side: SIDE
align: ALIGN
@@ -129,7 +125,20 @@ export type PopupPlacement = {
alignOffset: number
}
-export type SettingsType = {
+export type Star = {
+ id: string
+}
+
+type UserStars = {
+ stars: Array
+}
+
+export type UserStats = {
+ commandExecutionCount: number
+ hasShownReviewRequest: boolean
+}
+
+export type UserSettings = {
settingVersion: Version
startupMethod: StartupMethod
popupPlacement: PopupPlacement
@@ -139,9 +148,10 @@ export type SettingsType = {
pageRules: Array
style: STYLE
userStyles: Array
- stars: Array
}
+export type SettingsType = UserSettings & UserStats & UserStars
+
export type SessionData = {
session_id: string
timestamp: number
diff --git a/yarn.lock b/yarn.lock
index 8cbb4d25..e62e6fa1 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -780,6 +780,16 @@
"@radix-ui/react-primitive" "2.1.0"
"@radix-ui/react-slot" "1.2.0"
+"@radix-ui/react-collection@1.1.6":
+ version "1.1.6"
+ resolved "https://registry.yarnpkg.com/@radix-ui/react-collection/-/react-collection-1.1.6.tgz#fecf74475e4660ee99c7eb1ebfa5ccfb1a219fe4"
+ integrity sha512-PbhRFK4lIEw9ADonj48tiYWzkllz81TM7KVYyyMMw2cwHO7D5h4XKEblL8NlaRisTK3QTe6tBEhDccFUryxHBQ==
+ dependencies:
+ "@radix-ui/react-compose-refs" "1.1.2"
+ "@radix-ui/react-context" "1.1.2"
+ "@radix-ui/react-primitive" "2.1.2"
+ "@radix-ui/react-slot" "1.2.2"
+
"@radix-ui/react-compose-refs@1.1.1":
version "1.1.1"
resolved "https://registry.yarnpkg.com/@radix-ui/react-compose-refs/-/react-compose-refs-1.1.1.tgz#6f766faa975f8738269ebb8a23bad4f5a8d2faec"
@@ -852,6 +862,17 @@
"@radix-ui/react-use-callback-ref" "1.1.0"
"@radix-ui/react-use-escape-keydown" "1.1.0"
+"@radix-ui/react-dismissable-layer@1.1.9":
+ version "1.1.9"
+ resolved "https://registry.yarnpkg.com/@radix-ui/react-dismissable-layer/-/react-dismissable-layer-1.1.9.tgz#46e025ba6e6f403677e22fbb7d99b63cf7b32bca"
+ integrity sha512-way197PiTvNp+WBP7svMJasHl+vibhWGQDb6Mgf5mhEWJkgb85z7Lfl9TUdkqpWsf8GRNmoopx9ZxCyDzmgRMQ==
+ dependencies:
+ "@radix-ui/primitive" "1.1.2"
+ "@radix-ui/react-compose-refs" "1.1.2"
+ "@radix-ui/react-primitive" "2.1.2"
+ "@radix-ui/react-use-callback-ref" "1.1.1"
+ "@radix-ui/react-use-escape-keydown" "1.1.1"
+
"@radix-ui/react-focus-guards@1.1.1":
version "1.1.1"
resolved "https://registry.yarnpkg.com/@radix-ui/react-focus-guards/-/react-focus-guards-1.1.1.tgz#8635edd346304f8b42cae86b05912b61aef27afe"
@@ -1005,6 +1026,14 @@
"@radix-ui/react-primitive" "2.0.2"
"@radix-ui/react-use-layout-effect" "1.1.0"
+"@radix-ui/react-portal@1.1.8":
+ version "1.1.8"
+ resolved "https://registry.yarnpkg.com/@radix-ui/react-portal/-/react-portal-1.1.8.tgz#0181e85bc0d8c67229dd8cf198204f5f4cc7c09c"
+ integrity sha512-hQsTUIn7p7fxCPvao/q6wpbxmCwgLrlz+nOrJgC+RwfZqWY/WN+UMqkXzrtKbPrF82P43eCTl3ekeKuyAQbFeg==
+ dependencies:
+ "@radix-ui/react-primitive" "2.1.2"
+ "@radix-ui/react-use-layout-effect" "1.1.1"
+
"@radix-ui/react-presence@1.1.2":
version "1.1.2"
resolved "https://registry.yarnpkg.com/@radix-ui/react-presence/-/react-presence-1.1.2.tgz#bb764ed8a9118b7ec4512da5ece306ded8703cdc"
@@ -1013,6 +1042,14 @@
"@radix-ui/react-compose-refs" "1.1.1"
"@radix-ui/react-use-layout-effect" "1.1.0"
+"@radix-ui/react-presence@1.1.4":
+ version "1.1.4"
+ resolved "https://registry.yarnpkg.com/@radix-ui/react-presence/-/react-presence-1.1.4.tgz#253ac0ad4946c5b4a9c66878335f5cf07c967ced"
+ integrity sha512-ueDqRbdc4/bkaQT3GIpLQssRlFgWaL/U2z/S31qRwwLWoxHLgry3SIfCwhxeQNbirEUXFa+lq3RL3oBYXtcmIA==
+ dependencies:
+ "@radix-ui/react-compose-refs" "1.1.2"
+ "@radix-ui/react-use-layout-effect" "1.1.1"
+
"@radix-ui/react-primitive@2.0.1":
version "2.0.1"
resolved "https://registry.yarnpkg.com/@radix-ui/react-primitive/-/react-primitive-2.0.1.tgz#6d9efc550f7520135366f333d1e820cf225fad9e"
@@ -1034,6 +1071,13 @@
dependencies:
"@radix-ui/react-slot" "1.2.0"
+"@radix-ui/react-primitive@2.1.2":
+ version "2.1.2"
+ resolved "https://registry.yarnpkg.com/@radix-ui/react-primitive/-/react-primitive-2.1.2.tgz#03f64f957719c761d22c2f92cc43ffb64bd42cc8"
+ integrity sha512-uHa+l/lKfxuDD2zjN/0peM/RhhSmRjr5YWdk/37EnSv1nJ88uvG85DPexSm8HdFQROd2VdERJ6ynXbkCFi+APw==
+ dependencies:
+ "@radix-ui/react-slot" "1.2.2"
+
"@radix-ui/react-progress@^1.1.2":
version "1.1.2"
resolved "https://registry.yarnpkg.com/@radix-ui/react-progress/-/react-progress-1.1.2.tgz#3584c346d47f2a6f86076ce5af56ab00c66ded2b"
@@ -1120,6 +1164,13 @@
dependencies:
"@radix-ui/react-compose-refs" "1.1.2"
+"@radix-ui/react-slot@1.2.2":
+ version "1.2.2"
+ resolved "https://registry.yarnpkg.com/@radix-ui/react-slot/-/react-slot-1.2.2.tgz#18e6533e778a2051edc2ad0773da8e22f03f626a"
+ integrity sha512-y7TBO4xN4Y94FvcWIOIh18fM4R1A8S4q1jhoz4PNzOoHsFcN8pogcFmZrTYAm4F9VRUrWP/Mw7xSKybIeRI+CQ==
+ dependencies:
+ "@radix-ui/react-compose-refs" "1.1.2"
+
"@radix-ui/react-switch@^1.1.3":
version "1.1.3"
resolved "https://registry.yarnpkg.com/@radix-ui/react-switch/-/react-switch-1.1.3.tgz#cb6386909d1d3f65a2b81a3b15da8c91d18f49b0"
@@ -1133,6 +1184,24 @@
"@radix-ui/react-use-previous" "1.1.0"
"@radix-ui/react-use-size" "1.1.0"
+"@radix-ui/react-toast@^1.2.13":
+ version "1.2.13"
+ resolved "https://registry.yarnpkg.com/@radix-ui/react-toast/-/react-toast-1.2.13.tgz#e2b27456b52d1b1629becb0299912fd842dc5afe"
+ integrity sha512-e/e43mQAwgYs8BY4y9l99xTK6ig1bK2uXsFLOMn9IZ16lAgulSTsotcPHVT2ZlSb/ye6Sllq7IgyDB8dGhpeXQ==
+ dependencies:
+ "@radix-ui/primitive" "1.1.2"
+ "@radix-ui/react-collection" "1.1.6"
+ "@radix-ui/react-compose-refs" "1.1.2"
+ "@radix-ui/react-context" "1.1.2"
+ "@radix-ui/react-dismissable-layer" "1.1.9"
+ "@radix-ui/react-portal" "1.1.8"
+ "@radix-ui/react-presence" "1.1.4"
+ "@radix-ui/react-primitive" "2.1.2"
+ "@radix-ui/react-use-callback-ref" "1.1.1"
+ "@radix-ui/react-use-controllable-state" "1.2.2"
+ "@radix-ui/react-use-layout-effect" "1.1.1"
+ "@radix-ui/react-visually-hidden" "1.2.2"
+
"@radix-ui/react-toggle-group@^1.1.7":
version "1.1.7"
resolved "https://registry.yarnpkg.com/@radix-ui/react-toggle-group/-/react-toggle-group-1.1.7.tgz#0eaca9e4f8fbf2536f01e33a6211eac4d6cfb83e"
@@ -1194,6 +1263,13 @@
dependencies:
"@radix-ui/react-use-callback-ref" "1.1.0"
+"@radix-ui/react-use-escape-keydown@1.1.1":
+ version "1.1.1"
+ resolved "https://registry.yarnpkg.com/@radix-ui/react-use-escape-keydown/-/react-use-escape-keydown-1.1.1.tgz#b3fed9bbea366a118f40427ac40500aa1423cc29"
+ integrity sha512-Il0+boE7w/XebUHyBjroE+DbByORGR9KKmITzbR7MyQ4akpORYP/ZmbhAr0DG7RmmBqoOnZdy2QlvajJ2QA59g==
+ dependencies:
+ "@radix-ui/react-use-callback-ref" "1.1.1"
+
"@radix-ui/react-use-layout-effect@1.1.0":
version "1.1.0"
resolved "https://registry.yarnpkg.com/@radix-ui/react-use-layout-effect/-/react-use-layout-effect-1.1.0.tgz#3c2c8ce04827b26a39e442ff4888d9212268bd27"
@@ -1230,6 +1306,13 @@
dependencies:
"@radix-ui/react-primitive" "2.0.2"
+"@radix-ui/react-visually-hidden@1.2.2":
+ version "1.2.2"
+ resolved "https://registry.yarnpkg.com/@radix-ui/react-visually-hidden/-/react-visually-hidden-1.2.2.tgz#aa6d0f95b0cd50f08b02393d25132f52ca7861dc"
+ integrity sha512-ORCmRUbNiZIv6uV5mhFrhsIKw4UX/N3syZtyqvry61tbGm4JlgQuSn0hk5TwCARsCjkcnuRkSdCE3xfb+ADHew==
+ dependencies:
+ "@radix-ui/react-primitive" "2.1.2"
+
"@radix-ui/rect@1.1.0":
version "1.1.0"
resolved "https://registry.yarnpkg.com/@radix-ui/rect/-/rect-1.1.0.tgz#f817d1d3265ac5415dadc67edab30ae196696438"