diff --git a/.editorconfig b/.editorconfig new file mode 100755 index 000000000..bfba45975 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,16 @@ +# EditorConfig is awesome: https://EditorConfig.org + +# top-most EditorConfig file +root = true + +# Unix-style newlines with a newline ending every file +[*] +charset = utf-8 +indent_style = space +indent_size = 2 +end_of_line = lf +insert_final_newline = true +trim_trailing_whitespace = true + +[*.{sh,bash}] +end_of_line = lf diff --git a/.env.example b/.env.example new file mode 100644 index 000000000..aa4064161 --- /dev/null +++ b/.env.example @@ -0,0 +1 @@ +PLASMO_PUBLIC_APP_TYPE=extension diff --git a/.gitignore b/.gitignore index d2eb8083f..542768c1a 100644 --- a/.gitignore +++ b/.gitignore @@ -39,4 +39,4 @@ keys.json .tsbuildinfo # temporary remove development icon -assets/icon.development.png \ No newline at end of file +assets/icon.development.png diff --git a/assets/icon512.development.png b/assets/icon512.development.png new file mode 100644 index 000000000..abe82b60b Binary files /dev/null and b/assets/icon512.development.png differ diff --git a/assets/icons/icon.development.png b/assets/icons/icon.development.png new file mode 100644 index 000000000..67e7b9398 Binary files /dev/null and b/assets/icons/icon.development.png differ diff --git a/assets/icons/offline/logo128.development.png b/assets/icons/offline/logo128.development.png new file mode 100644 index 000000000..2e1cf70f9 Binary files /dev/null and b/assets/icons/offline/logo128.development.png differ diff --git a/assets/icons/offline/logo256.development.png b/assets/icons/offline/logo256.development.png new file mode 100644 index 000000000..778adca1b Binary files /dev/null and b/assets/icons/offline/logo256.development.png differ diff --git a/assets/icons/offline/logo64.development.png b/assets/icons/offline/logo64.development.png new file mode 100644 index 000000000..e2904a59c Binary files /dev/null and b/assets/icons/offline/logo64.development.png differ diff --git a/assets/icons/online/logo128.development.png b/assets/icons/online/logo128.development.png new file mode 100644 index 000000000..4d4a80f7f Binary files /dev/null and b/assets/icons/online/logo128.development.png differ diff --git a/assets/icons/online/logo256.development.png b/assets/icons/online/logo256.development.png new file mode 100644 index 000000000..921908055 Binary files /dev/null and b/assets/icons/online/logo256.development.png differ diff --git a/assets/icons/online/logo64.development.png b/assets/icons/online/logo64.development.png new file mode 100644 index 000000000..1d9e5a5e8 Binary files /dev/null and b/assets/icons/online/logo64.development.png differ diff --git a/assets/popup.css b/assets/popup.css new file mode 100644 index 000000000..7ce859145 --- /dev/null +++ b/assets/popup.css @@ -0,0 +1,122 @@ +@font-face { + font-family: "ManropeLocal"; + font-style: normal; + font-weight: 300; + src: url(/assets/fonts/Manrope-Light.woff2) format('woff2'); +} + +@font-face { + font-family: "ManropeLocal"; + font-style: normal; + font-weight: 400; + src: url(/assets/fonts/Manrope-Regular.woff2) format('woff2'); +} + +@font-face { + font-family: "ManropeLocal"; + font-style: normal; + font-weight: 500; + src: url(/assets/fonts/Manrope-Medium.woff2) format('woff2'); +} + +@font-face { + font-family: "ManropeLocal"; + font-style: normal; + font-weight: 600; + src: url(/assets/fonts/Manrope-SemiBold.woff2) format('woff2'); +} + +@font-face { + font-family: "ManropeLocal"; + font-style: normal; + font-weight: 600; + src: url(/assets/fonts/Manrope-Bold.woff2) format('woff2'); +} + +@font-face { + font-family: "ManropeLocal"; + font-style: normal; + font-weight: 700; + src: url(/assets/fonts/Manrope-ExtraBold.woff2) format('woff2'); +} + +* { + scrollbar-width: none; +} + +*::-webkit-scrollbar { + display: none +} + +::selection { + background-color: rgba(171, 154, 255, .6); + color: #fff; +} + +:root { + --defaultBackgroundColor: white; +} + +@media (prefers-color-scheme: dark) { + :root { + --defaultBackgroundColor: black; + } +} + +body { + margin: 0; + padding: 0; +} + +body#popup { + width: 377px; + height: 600px; +} + +body.fullscreen { + width: 377px; + height: 100vh; + margin: 0 auto; +} + +body.fullscreen::before { + content: ""; + position: fixed; + top: 50%; + left: 50%; + width: 377px; + height: 100vh; + transform: translate(-50%, -50%); + pointer-events: none; + box-shadow: 0 0 128px 0 rgba(171, 154, 255, .4); +} + +body, +button, +input, +select, +textarea { + font-family: "ManropeLocal", "Manrope VF", "Manrope", sans-serif !important; +} + +button { + background: transparent; + border: 0; + padding: 0; +} + +#cover { + position: fixed; + top: 0; + right: 0; + bottom: 0; + left: 0; + z-index: 99999999; + background-color: var(--backgroundColor, var(--defaultBackgroundColor, white)); + transition: background-color linear 230ms; +} + +#cover[aria-hidden] { + background: transparent; + pointer-events: none; +} diff --git a/assets/popup.js b/assets/popup.js new file mode 100644 index 000000000..7c36b0bcb --- /dev/null +++ b/assets/popup.js @@ -0,0 +1,3 @@ +const backgroundColor = localStorage.getItem("ARCONNECT_THEME_BACKGROUND_COLOR"); + +if (backgroundColor) document.documentElement.style.setProperty('--backgroundColor', backgroundColor); \ No newline at end of file diff --git a/package.json b/package.json index ea4701a1f..6712ae895 100644 --- a/package.json +++ b/package.json @@ -7,10 +7,11 @@ "packageManager": "yarn@1.22.18", "homepage": "https://arconnect.io", "scripts": { - "dev:chrome": "plasmo dev", + "dev:chrome": "plasmo dev --verbose", "build:chrome": "plasmo build --no-hoist", "dev:firefox": "plasmo dev --target=firefox-mv2", "build:firefox": "plasmo build --target=firefox-mv2 --no-hoist", + "nuke": "rm -rf node_modules build .plasmo", "fmt": "prettier --write .", "fmt:check": "prettier --check .", "prepare": "husky install" @@ -69,7 +70,7 @@ "check-password-strength": "^2.0.7", "copy-to-clipboard": "^3.3.2", "dayjs": "^1.11.6", - "framer-motion": "7.5.3", + "framer-motion": "^11.11.7", "human-crypto-keys": "^0.1.4", "js-confetti": "^0.11.0", "mitt": "^3.0.0", diff --git a/src/components/SliderMenu.tsx b/src/components/SliderMenu.tsx index 8f30b4a59..f1466bd1e 100644 --- a/src/components/SliderMenu.tsx +++ b/src/components/SliderMenu.tsx @@ -7,6 +7,7 @@ import styled, { useTheme } from "styled-components"; interface SliderMenuProps { title: string; + hasNav?: boolean; isOpen: boolean; onClose?: () => void; children?: React.ReactNode; @@ -14,6 +15,7 @@ interface SliderMenuProps { export default function SliderMenu({ title, + hasNav, isOpen, onClose, children @@ -37,6 +39,7 @@ export default function SliderMenu({ ` +const Wrapper = styled(motion.div)<{ + displayTheme: DisplayTheme; + hasNav: boolean; +}>` position: fixed; bottom: 0; left: 0; height: auto; - max-height: 93%; + max-height: calc(100% - 66px); border-top: ${(props) => props.displayTheme === "light" ? `1px solid ${props.theme.primary}` @@ -79,6 +85,8 @@ const Wrapper = styled(motion.div)<{ displayTheme: DisplayTheme }>` background-color: ${(props) => props.displayTheme === "light" ? "#ffffff" : "#191919"}; border-radius: 10px 10px 0 0; + padding-bottom: ${(props) => (props.hasNav ? "66px" : "0")}; + box-sizing: border-box; `; export const animationSlideFromBottom: Variants = { diff --git a/src/components/dashboard/Wallets.tsx b/src/components/dashboard/Wallets.tsx index 53f6c2dc7..e0b6aec30 100644 --- a/src/components/dashboard/Wallets.tsx +++ b/src/components/dashboard/Wallets.tsx @@ -5,7 +5,6 @@ import { useStorage } from "@plasmohq/storage/hook"; import { type AnsUser, getAnsProfile } from "~lib/ans"; import { ExtensionStorage } from "~utils/storage"; import { useLocation, useRoute } from "wouter"; -import { PlusIcon } from "@iconicicons/react"; import type { StoredWallet } from "~wallets"; import { Reorder } from "framer-motion"; import WalletListItem from "./list/WalletListItem"; diff --git a/src/components/hardware/HardwareWalletTheme.tsx b/src/components/hardware/HardwareWalletTheme.tsx index d3521e825..d712610f7 100644 --- a/src/components/hardware/HardwareWalletTheme.tsx +++ b/src/components/hardware/HardwareWalletTheme.tsx @@ -1,38 +1,81 @@ -import { type DefaultTheme, ThemeProvider } from "styled-components"; -import { type PropsWithChildren, useMemo } from "react"; +import { ThemeProvider, type DefaultTheme } from "styled-components"; +import { useEffect, type PropsWithChildren } from "react"; import { useHardwareApi } from "~wallets/hooks"; +import { useTheme } from "~utils/theme"; +import { Provider } from "@arconnect/components"; +import { useTheme as useStyledComponentsTheme } from "styled-components"; +import { MotionGlobalConfig } from "framer-motion"; -export default function HardwareWalletTheme({ - children -}: PropsWithChildren<{}>) { - // hardware api type +const ARCONNECT_THEME_BACKGROUND_COLOR = "ARCONNECT_THEME_BACKGROUND_COLOR"; + +/** + * Modify the theme if the active wallet is a hardware wallet. We transform the + * default accent color to match the hardware wallet's accent. + */ +function hardwareThemeModifier(theme: DefaultTheme): DefaultTheme { + return { + ...theme, + theme: "154, 184, 255", + primary: "#9AB8FF", + primaryBtnHover: "#6F93E1" + }; +} + +function noThemeModifier(theme: DefaultTheme): DefaultTheme { + return theme; +} + +export function ArConnectThemeProvider({ children }: PropsWithChildren<{}>) { const hardwareApi = useHardwareApi(); + const theme = useTheme(); + const themeModifier = hardwareApi ? hardwareThemeModifier : noThemeModifier; + + useEffect(() => { + const reducedMotionPreference = window.matchMedia( + "(prefers-reduced-motion)" + ); - // hardware wallet accent color - const hardwareApiTheme = useMemo(() => { - if (!hardwareApi) return false; + if (reducedMotionPreference.matches) { + // This could also be always set to `true` at the top of the file and then set to `false` after the application + // loads if we still notice some flicker due to any animation/transition playing when the view first loads. + + MotionGlobalConfig.skipAnimations = true; + } + }, []); + + return ( + + + + + {children} + + + ); +} + +export function ThemeBackgroundObserver() { + const styledComponentsTheme = useStyledComponentsTheme(); + const backgroundColor = styledComponentsTheme.background; + + useEffect(() => { + let formattedBackgroundColor = ""; + + if (backgroundColor.length === 3 || backgroundColor.length === 6) { + formattedBackgroundColor = `#${backgroundColor}`; + } else if (/\d{1,3}, ?\d{1,3}, ?\d{1,3}/.test(backgroundColor)) { + formattedBackgroundColor = `rgb(${backgroundColor})`; + } else if (/\d{1,3}, ?\d{1,3}, ?\d{1,3}, ?.+/.test(backgroundColor)) { + formattedBackgroundColor = `rgba(${backgroundColor})`; + } - if (hardwareApi === "keystone") { - return "154, 184, 255"; + if (formattedBackgroundColor) { + localStorage.setItem( + ARCONNECT_THEME_BACKGROUND_COLOR, + formattedBackgroundColor + ); } + }, [backgroundColor]); - return false; - }, [hardwareApi]); - - // modify theme if the active wallet is a - // hardware wallet - // we transform the default accent color - // to match the hardware wallet's accent - function themeModifier(theme: DefaultTheme): DefaultTheme { - if (!hardwareApiTheme) return theme; - - return { - ...theme, - theme: hardwareApiTheme, - primary: "#9AB8FF", - primaryBtnHover: "#6F93E1" - }; - } - - return {children}; + return null; } diff --git a/src/components/popup/HeadV2.tsx b/src/components/popup/HeadV2.tsx index fef804ee0..e7b16aa31 100644 --- a/src/components/popup/HeadV2.tsx +++ b/src/components/popup/HeadV2.tsx @@ -28,7 +28,6 @@ interface HeadV2Props { // allow opening the wallet switcher showBack?: boolean; padding?: string; - allowOpen?: boolean; back?: (...args) => any; } @@ -37,8 +36,7 @@ export default function HeadV2({ showOptions = true, back, padding, - showBack = true, - allowOpen = true + showBack = true }: HeadV2Props) { // scroll position const [scrollDirection, setScrollDirection] = useState<"up" | "down">("up"); @@ -110,37 +108,40 @@ export default function HeadV2({ scrolled={scrolled} padding={padding} > - { - if (back) await back(); - else goBack(); - }} - > - - + {showBack ? ( + { + if (back) await back(); + else goBack(); + }} + > + + + ) : null} {title} - - { - if (!allowOpen) return; - setOpen(true); - }} - > - {!ans?.avatar && !svgieAvatar && } - - {hardwareApi === "keystone" && ( - - )} - - - + {showOptions ? ( + + { + setOpen(true); + }} + > + {!ans?.avatar && !svgieAvatar && } + + {hardwareApi === "keystone" && ( + + )} + + + + ) : null} {isOpen && setOpen(false)} />} diff --git a/src/components/popup/HistoryProvider.tsx b/src/components/popup/HistoryProvider.tsx index 01f8e3b73..69f72680f 100644 --- a/src/components/popup/HistoryProvider.tsx +++ b/src/components/popup/HistoryProvider.tsx @@ -1,5 +1,4 @@ -import { type PropsWithChildren, useEffect, useState } from "react"; -import { getDecryptionKey } from "~wallets/auth"; +import { type PropsWithChildren, useState } from "react"; import { useLocation } from "wouter"; import { type BackAction, @@ -27,18 +26,6 @@ export default function HistoryProvider({ children }: PropsWithChildren<{}>) { history.back(); }; - // redirect to unlock if decryiption - // key is not available - useEffect(() => { - (async () => { - const decryptionKey = await getDecryptionKey(); - - if (!decryptionKey) { - push("/unlock"); - } - })(); - }, []); - return ( {children} diff --git a/src/components/popup/Navigation.tsx b/src/components/popup/Navigation.tsx index 8c0495a11..c7e2193a2 100644 --- a/src/components/popup/Navigation.tsx +++ b/src/components/popup/Navigation.tsx @@ -88,7 +88,7 @@ const NavigationBarWrapper = styled.nav<{ displayTheme: DisplayTheme }>` height: 62px; background-color: ${(props) => props.displayTheme === "light" ? "#F5F5F5" : "#191919"}; - width: 378px; + width: 377px; display: flex; `; diff --git a/src/components/popup/Route.tsx b/src/components/popup/Route.tsx index c7a3c78ae..6aa301a39 100644 --- a/src/components/popup/Route.tsx +++ b/src/components/popup/Route.tsx @@ -14,32 +14,18 @@ const Route: typeof BaseRoute = ({ path, component, children }) => { ? children(params) : children; - return ( - - {matches && {routeContent}} - - ); + return matches ? {routeContent} : null; }; -export const Wrapper = styled(motion.div)<{ - responsive?: boolean; - expanded?: boolean; -}>` +const PageWrapper = styled(motion.main)` position: relative; - width: ${(props) => (props.responsive ? "100%" : "377.5px")}; - min-height: ${(props) => (props.expanded ? "100vh" : "600px")}; - max-height: max-content; - background-color: rgb(${(props) => props.theme.background}); -`; - -const PageWrapper = styled(Wrapper)` - position: absolute; top: 0; width: 100%; - transition: background-color 0.23s ease-in-out; + min-height: 100vh; + max-height: max-content; `; -const Page = ({ children }: PropsWithChildren) => { +export const Page = ({ children }: PropsWithChildren) => { const opacityAnimation: Variants = { initial: { opacity: 0 }, enter: { opacity: 1 }, @@ -48,6 +34,7 @@ const Page = ({ children }: PropsWithChildren) => { return ( window.removeEventListener("scroll", listener); }, []); @@ -242,18 +234,23 @@ export default function WalletHeader() { } } ]; - if (!isExpanded && items.length === 4) { + + if (location.pathname === "/popup.html") { + // This option won't be shown in the fullscreen mode (fullscreen.html) or the embedded wallet: + items.push({ icon: , title: "expand_view", - route: () => { - window.open(window.location.href.split("#")[0] + "?expanded=true"); + route: async () => { + await browser.tabs.create({ + url: browser.runtime.getURL("tabs/fullscreen.html") + }); } }); } return items; - }, [activeAddress, isExpanded]); + }, [activeAddress]); return ( 14}> diff --git a/src/components/popup/home/Balance.tsx b/src/components/popup/home/Balance.tsx index 4b0a62194..e81944278 100644 --- a/src/components/popup/home/Balance.tsx +++ b/src/components/popup/home/Balance.tsx @@ -111,18 +111,9 @@ export default function Balance() { })(); }, [activeAddress]); - // router push - const [push] = useHistory(); - // display theme const theme = useTheme(); - // lock wallet and terminate session - async function lockWallet() { - await removeDecryptionKey(); - push("/unlock"); - } - useEffect(() => { if ( balance.toNumber() !== historicalBalance[historicalBalance.length - 1] @@ -166,7 +157,10 @@ export default function Balance() { content={browser.i18n.getMessage("lock_wallet")} position="top" > - + diff --git a/src/popup.html b/src/popup.html new file mode 100644 index 000000000..6ee23af8b --- /dev/null +++ b/src/popup.html @@ -0,0 +1,12 @@ + + + + __plasmo_static_index_title__ + + + + + +
+ + diff --git a/src/popup.tsx b/src/popup.tsx index 1c20dbe5e..f9b8c6c06 100644 --- a/src/popup.tsx +++ b/src/popup.tsx @@ -1,13 +1,10 @@ -import Route, { Wrapper } from "~components/popup/Route"; -import styled, { createGlobalStyle } from "styled-components"; -import { GlobalStyle, useTheme } from "~utils/theme"; +import Route, { Page, Wrapper } from "~components/popup/Route"; +import styled from "styled-components"; import { useHashLocation } from "~utils/hash_router"; -import { Provider } from "@arconnect/components"; import { syncLabels, useSetUp } from "~wallets"; import { useEffect, useState } from "react"; import { Router } from "wouter"; -import HardwareWalletTheme from "~components/hardware/HardwareWalletTheme"; import HistoryProvider from "~components/popup/HistoryProvider"; import Home from "~routes/popup"; @@ -49,187 +46,158 @@ import ContactSettings from "~routes/popup/settings/contacts/[address]"; import NewContact from "~routes/popup/settings/contacts/new"; import NotificationSettings from "~routes/popup/settings/notifications"; import GenerateQR from "~routes/popup/settings/wallets/[address]/qr"; +import { ArConnectThemeProvider } from "~components/hardware/HardwareWalletTheme"; +import { AnimatePresence } from "framer-motion"; export default function Popup() { - const theme = useTheme(); - const [expanded, setExpanded] = useState(false); - - // init popup - useSetUp(); + const initialScreenType = useSetUp(); useEffect(() => { - // sync ans labels syncLabels(); - - // check expanded view - if (new URLSearchParams(window.location.search).get("expanded")) { - setExpanded(true); - } }, []); - return ( - - - - - - - - - - - - {(params: { quoteId: string }) => ( - - )} - - - {() => } - - {(params: { id?: string }) => } - - - {(params: { tokenID: string }) => ( - - )} - - - - - - - - {(params: { address: string }) => ( - - )} - - - {(params: { address: string }) => ( - - )} - - - {(params: { address: string }) => ( - - )} - - - - {(params: { url: string }) => ( - - )} - - - {(params: { url: string }) => ( - - )} - - - - {(params: { id: string }) => ( - - )} - - - - - {(params: { address: string }) => ( - - )} - - - - - {(params: { id: string }) => ( - - )} - - - {(params: { id: string }) => ( - - )} - - - {(params: { id: string }) => ( - - )} - - - - - {(params: { id: string }) => ( - - )} - - - - {(params: { id: string }) => } - - - - {(params: { id: string }) => } - - - {(params: { id: string; gateway?: string }) => ( - - )} - - - {(params: { token: string; qty: string }) => ( - - )} - - - {(params: { - token: string; - qty: string; - message?: string; - }) => ( - - )} - - - - - - - - - ); -} - -const HideScrollbar = createGlobalStyle<{ expanded?: boolean }>` - * { - scrollbar-width: none; + let content: React.ReactElement = null; - &::-webkit-scrollbar { - display: none - } + if (initialScreenType === "cover") { + content = ; + } else if (initialScreenType === "locked") { + content = ( + + + + ); + } else if (initialScreenType === "generating") { + // This can only happen in the embedded wallet: + content = ( + +

Generating Wallet...

+
+ ); + } else { + content = ( + + + + + + {(params: { quoteId: string }) => ( + + )} + + + {() => } + + {(params: { id?: string }) => } + + + {(params: { tokenID: string }) => ( + + )} + + + + + + + + {(params: { address: string }) => ( + + )} + + + {(params: { address: string }) => ( + + )} + + + {(params: { address: string }) => ( + + )} + + + + {(params: { url: string }) => } + + + {(params: { url: string }) => } + + + + {(params: { id: string }) => } + + + + + {(params: { address: string }) => ( + + )} + + + + + {(params: { id: string }) => ( + + )} + + + {(params: { id: string }) => ( + + )} + + + {(params: { id: string }) => ( + + )} + + + + + {(params: { id: string }) => ( + + )} + + + + {(params: { id: string }) => } + + + + {(params: { id: string }) => } + + + {(params: { id: string; gateway?: string }) => ( + + )} + + + {(params: { token: string; qty: string }) => ( + + )} + + + {(params: { token: string; qty: string; message?: string }) => ( + + )} + + + + + ); } - body { - ${(props) => - props?.expanded - ? `background-image: linear-gradient( to right, transparent, rgba( ${props.theme.theme},.4 ), transparent);` - : ""} - } -`; - -const ExpandedViewWrapper = styled.div` - width: 100%; - display: flex; - justify-content: center; -`; + return ( + + {content} + + ); +} diff --git a/src/routes/popup/send/index.tsx b/src/routes/popup/send/index.tsx index 77401098f..c62ccf5af 100644 --- a/src/routes/popup/send/index.tsx +++ b/src/routes/popup/send/index.tsx @@ -599,6 +599,7 @@ export default function Send({ id }: Props) { { setShownTokenSelector(false); @@ -651,6 +652,7 @@ export default function Send({ id }: Props) { { setShowSlider(false); diff --git a/src/routes/popup/transaction/[id].tsx b/src/routes/popup/transaction/[id].tsx index 2475295e4..647ac69de 100644 --- a/src/routes/popup/transaction/[id].tsx +++ b/src/routes/popup/transaction/[id].tsx @@ -42,11 +42,13 @@ import { generateProfileIcon, ProfilePicture } from "~components/Recipient"; -import { TempTransactionStorage } from "~utils/storage"; +import { ExtensionStorage, TempTransactionStorage } from "~utils/storage"; import { useContact } from "~contacts/hooks"; import { EventType, PageType, trackEvent, trackPage } from "~utils/analytics"; import BigNumber from "bignumber.js"; import { fetchTokenByProcessId } from "~lib/transactions"; +import { useStorage } from "@plasmohq/storage/hook"; +import type { StoredWallet } from "~wallets"; // pull contacts and check if to address is in contacts @@ -71,8 +73,22 @@ export default function Transaction({ id: rawId, gw, message }: Props) { const childRef = useRef(null); useAdjustAmountTitleWidth(parentRef, childRef, quantity); + const [wallets] = useStorage( + { + key: "wallets", + instance: ExtensionStorage + }, + [] + ); + + const fromAddress = transaction?.owner.address; + const toAddress = transaction?.recipient; + const fromMe = wallets.find((wallet) => wallet.address === fromAddress); + const toMe = wallets.find((wallet) => wallet.address === toAddress); + // const [contact, setContact] = useState(undefined); - const contact = useContact(transaction?.recipient); + const fromContact = useContact(fromAddress); + const toContact = useContact(toAddress); const [ao, setAo] = useState({ isAo: false }); @@ -356,7 +372,50 @@ export default function Transaction({ id: rawId, gw, message }: Props) { {browser.i18n.getMessage("transaction_from")} - {formatAddress(transaction.owner.address, 6)} +
+ {!fromContact ? ( + <> + {formatAddress(fromMe || fromAddress, 6)} + + {fromMe ? null : ( + + {browser.i18n.getMessage("user_not_in_contacts")}{" "} + { + trackEvent(EventType.ADD_CONTACT, { + fromSendFlow: true + }); + browser.tabs.create({ + url: browser.runtime.getURL( + `tabs/dashboard.html#/contacts/new?address=${fromAddress}` + ) + }); + }} + > + {browser.i18n.getMessage("create_contact")} + + + )} + + ) : ( +
+ {fromContact.profileIcon ? ( + + ) : ( + + {generateProfileIcon( + fromContact?.name || fromContact.address + )} + + )} + {fromContact?.name || + formatAddress(fromContact.address, 6)} +
+ )} +
@@ -365,44 +424,46 @@ export default function Transaction({ id: rawId, gw, message }: Props) {
- {!contact ? ( + {!toContact ? ( <> - {(transaction.recipient && - formatAddress(transaction.recipient, 6)) || - "-"} - - {browser.i18n.getMessage("user_not_in_contacts")}{" "} - { - trackEvent(EventType.ADD_CONTACT, { - fromSendFlow: true - }); - browser.tabs.create({ - url: browser.runtime.getURL( - `tabs/dashboard.html#/contacts/new?address=${transaction.recipient}` - ) - }); - }} - > - {browser.i18n.getMessage("create_contact")} - - + {formatAddress(toMe || toAddress, 6)} + + {toMe ? null : ( + + {browser.i18n.getMessage("user_not_in_contacts")}{" "} + { + trackEvent(EventType.ADD_CONTACT, { + fromSendFlow: true + }); + browser.tabs.create({ + url: browser.runtime.getURL( + `tabs/dashboard.html#/contacts/new?address=${toAddress}` + ) + }); + }} + > + {browser.i18n.getMessage("create_contact")} + + + )} ) : (
- {contact.profileIcon ? ( + {toContact.profileIcon ? ( ) : ( {generateProfileIcon( - contact?.name || contact.address + toContact?.name || toContact.address )} )} - {contact?.name || formatAddress(contact.address, 6)} + {toContact?.name || + formatAddress(toContact.address, 6)}
)}
diff --git a/src/routes/popup/unlock.tsx b/src/routes/popup/unlock.tsx index 8edee3c12..9accf31ce 100644 --- a/src/routes/popup/unlock.tsx +++ b/src/routes/popup/unlock.tsx @@ -12,7 +12,6 @@ import { useToasts } from "@arconnect/components"; import HeadV2 from "~components/popup/HeadV2"; -import styled from "styled-components"; export default function Unlock() { // password input diff --git a/src/tabs/arlocal.html b/src/tabs/arlocal.html new file mode 100644 index 000000000..7b1215e63 --- /dev/null +++ b/src/tabs/arlocal.html @@ -0,0 +1,12 @@ + + + + __plasmo_static_index_title__ + + + + + +
+ + diff --git a/src/tabs/arlocal.tsx b/src/tabs/arlocal.tsx index bc1ce21a6..f10728c2f 100644 --- a/src/tabs/arlocal.tsx +++ b/src/tabs/arlocal.tsx @@ -1,12 +1,12 @@ import { InputWithBtn, InputWrapper } from "~components/arlocal/InputWrapper"; import { RefreshButton } from "~components/IconButton"; import { useEffect, useMemo, useState } from "react"; -import { GlobalStyle, useTheme } from "~utils/theme"; +import { useTheme } from "~utils/theme"; import { urlToGateway } from "~gateways/utils"; import { useStorage } from "@plasmohq/storage/hook"; import { ExtensionStorage } from "~utils/storage"; import { RefreshIcon } from "@iconicicons/react"; -import { useNoWallets } from "~wallets"; +import { useNoWallets, useRemoveCover } from "~wallets"; import { ButtonV2 as Button, InputV2 as Input, @@ -30,8 +30,11 @@ import Mint from "~components/arlocal/Mint"; import browser from "webextension-polyfill"; import Arweave from "arweave"; import axios from "axios"; +import { ArConnectThemeProvider } from "~components/hardware/HardwareWalletTheme"; + +export default function ArLocal() { + useRemoveCover(); -function ArLocal() { // testnet data const testnetInput = useInput(); const [lastUsedTestnet, setLastUsedTestnet] = useStorage( @@ -156,61 +159,52 @@ function ArLocal() { const noWallets = useNoWallets(); return ( - - {noWallets && } - - - ArLocal {browser.i18n.getMessage("devtools")} - <Spacer x={0.2} /> - <Text noMargin>by ArConnect</Text> - - - {browser.i18n.getMessage(online ? "testnetLive" : "testnetDown")} - - - - - - - - loadTestnet()} - refreshing={loadingTestnet} - > - - - - - {(!online && ) || ( - <> - - - - - - - )} - - - ); -} - -export default function () { - const theme = useTheme(); - - return ( - - - - + + + {noWallets && } + + + ArLocal {browser.i18n.getMessage("devtools")} + <Spacer x={0.2} /> + <Text noMargin>by ArConnect</Text> + + + {browser.i18n.getMessage(online ? "testnetLive" : "testnetDown")} + + + + + + + + loadTestnet()} + refreshing={loadingTestnet} + > + + + + + {(!online && ) || ( + <> + + + + + + + )} + + + ); } diff --git a/src/tabs/auth.html b/src/tabs/auth.html new file mode 100644 index 000000000..7b1215e63 --- /dev/null +++ b/src/tabs/auth.html @@ -0,0 +1,12 @@ + + + + __plasmo_static_index_title__ + + + + + +
+ + diff --git a/src/tabs/auth.tsx b/src/tabs/auth.tsx index 574ea18d5..e6697519d 100644 --- a/src/tabs/auth.tsx +++ b/src/tabs/auth.tsx @@ -1,12 +1,10 @@ import Route, { Wrapper } from "~components/popup/Route"; -import { GlobalStyle, useTheme } from "~utils/theme"; import { useHashLocation } from "~utils/hash_router"; -import { Provider } from "@arconnect/components"; import { syncLabels } from "~wallets"; import { useEffect } from "react"; import { Router } from "wouter"; -import HardwareWalletTheme from "~components/hardware/HardwareWalletTheme"; +import { ArConnectThemeProvider } from "~components/hardware/HardwareWalletTheme"; import Allowance from "~routes/auth/allowance"; import Signature from "~routes/auth/signature"; @@ -20,31 +18,26 @@ import SignKeystone from "~routes/auth/signKeystone"; import BatchSignDataItem from "~routes/auth/batchSignDataItem"; export default function Auth() { - const theme = useTheme(); - useEffect(() => { syncLabels(); }, []); return ( - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + ); } diff --git a/src/tabs/dashboard.html b/src/tabs/dashboard.html new file mode 100644 index 000000000..7b1215e63 --- /dev/null +++ b/src/tabs/dashboard.html @@ -0,0 +1,12 @@ + + + + __plasmo_static_index_title__ + + + + + +
+ + diff --git a/src/tabs/dashboard.tsx b/src/tabs/dashboard.tsx index b4bc4e2d1..b7f4bc792 100644 --- a/src/tabs/dashboard.tsx +++ b/src/tabs/dashboard.tsx @@ -1,15 +1,12 @@ -import { GlobalStyle, useTheme } from "~utils/theme"; import { useHashLocation } from "~utils/hash_router"; -import { Provider } from "@arconnect/components"; import { syncLabels, useSetUp } from "~wallets"; import { Router, Route } from "wouter"; import { useEffect } from "react"; import Settings from "~routes/dashboard"; +import { ArConnectThemeProvider } from "~components/hardware/HardwareWalletTheme"; export default function Dashboard() { - const theme = useTheme(); - useSetUp(); useEffect(() => { @@ -17,11 +14,10 @@ export default function Dashboard() { }, []); return ( - - + - + ); } diff --git a/src/tabs/devtools.html b/src/tabs/devtools.html new file mode 100644 index 000000000..7b1215e63 --- /dev/null +++ b/src/tabs/devtools.html @@ -0,0 +1,12 @@ + + + + __plasmo_static_index_title__ + + + + + +
+ + diff --git a/src/tabs/devtools.tsx b/src/tabs/devtools.tsx index 07a226aa6..e3b7cd420 100644 --- a/src/tabs/devtools.tsx +++ b/src/tabs/devtools.tsx @@ -1,19 +1,21 @@ -import { Card, Provider, Spacer, Text } from "@arconnect/components"; -import { GlobalStyle, useTheme } from "~utils/theme"; +import { Card, Spacer, Text } from "@arconnect/components"; import { useEffect, useMemo, useState } from "react"; import { useStorage } from "@plasmohq/storage/hook"; import { ExtensionStorage } from "~utils/storage"; import { getTab } from "~applications/tab"; import { getAppURL } from "~utils/format"; -import { useNoWallets } from "~wallets"; +import { useNoWallets, useRemoveCover } from "~wallets"; import AppSettings from "~components/dashboard/subsettings/AppSettings"; import Connector from "~components/devtools/Connector"; import NoWallets from "~components/devtools/NoWallets"; import Application from "~applications/application"; import browser from "webextension-polyfill"; import styled from "styled-components"; +import { ArConnectThemeProvider } from "~components/hardware/HardwareWalletTheme"; + +export default function DevTools() { + useRemoveCover(); -export default function Devtools() { // fetch app data const [app, setApp] = useState(); @@ -44,15 +46,11 @@ export default function Devtools() { return connectedApps.includes(app.url); }, [app, connectedApps]); - // ui theme - const theme = useTheme(); - // no wallets const noWallets = useNoWallets(); return ( - - + {noWallets && } @@ -68,7 +66,7 @@ export default function Devtools() { (connected && app && )} - + ); } diff --git a/src/tabs/fullscreen.html b/src/tabs/fullscreen.html new file mode 100644 index 000000000..15e1dc5d3 --- /dev/null +++ b/src/tabs/fullscreen.html @@ -0,0 +1,12 @@ + + + + __plasmo_static_index_title__ + + + + + +
+ + diff --git a/src/tabs/fullscreen.tsx b/src/tabs/fullscreen.tsx new file mode 100644 index 000000000..688a42c86 --- /dev/null +++ b/src/tabs/fullscreen.tsx @@ -0,0 +1,5 @@ +import Popup from "~popup"; + +export default function () { + return ; +} diff --git a/src/tabs/welcome.html b/src/tabs/welcome.html new file mode 100644 index 000000000..7b1215e63 --- /dev/null +++ b/src/tabs/welcome.html @@ -0,0 +1,12 @@ + + + + __plasmo_static_index_title__ + + + + + +
+ + diff --git a/src/tabs/welcome.tsx b/src/tabs/welcome.tsx index 223b4539f..527b572c1 100644 --- a/src/tabs/welcome.tsx +++ b/src/tabs/welcome.tsx @@ -1,7 +1,5 @@ import { type Path, pathToRegexp } from "path-to-regexp"; -import { GlobalStyle, useTheme } from "~utils/theme"; import { useHashLocation } from "~utils/hash_router"; -import { Provider } from "@arconnect/components"; import { Router, Route } from "wouter"; import Home from "~routes/welcome"; @@ -10,13 +8,14 @@ import Setup from "~routes/welcome/setup"; import makeCachedMatcher from "wouter/matcher"; import GettingStarted from "~routes/welcome/gettingStarted"; +import { ArConnectThemeProvider } from "~components/hardware/HardwareWalletTheme"; +import { useRemoveCover } from "~wallets"; export default function Welcome() { - const theme = useTheme(); + useRemoveCover(); return ( - - + @@ -32,7 +31,7 @@ export default function Welcome() { )} - + ); } diff --git a/src/utils/format.ts b/src/utils/format.ts index 8216a1bd9..45514e201 100644 --- a/src/utils/format.ts +++ b/src/utils/format.ts @@ -1,4 +1,5 @@ import BigNumber from "bignumber.js"; +import type { StoredWallet } from "~wallets"; /** * Get app URL from any link @@ -33,12 +34,27 @@ export function getCommunityUrl(link: string) { * * @returns Formatted address */ -export function formatAddress(address: string, count = 13) { - return ( - address.substring(0, count) + - "..." + - address.substring(address.length - count, address.length) - ); +export function formatAddress( + addressOrWallet?: string | StoredWallet, + count = 13 +) { + // TODO: What about ANS? + + if (!addressOrWallet) return "-"; + + if (typeof addressOrWallet === "string") { + return ( + addressOrWallet.substring(0, count) + + "..." + + addressOrWallet.substring( + addressOrWallet.length - count, + addressOrWallet.length + ) + ); + } + + // TODO: Does it make sense to use the nickname or you only see the active one? + return `${formatAddress(addressOrWallet.address, count)} (you)`; } /** diff --git a/src/utils/icon.ts b/src/utils/icon.ts index 7c41f23e5..bfad9b9c4 100644 --- a/src/utils/icon.ts +++ b/src/utils/icon.ts @@ -1,3 +1,5 @@ +// Production: + import offline64 from "url:/assets/icons/offline/logo64.png"; import offline128 from "url:/assets/icons/offline/logo128.png"; import offline256 from "url:/assets/icons/offline/logo256.png"; @@ -6,33 +8,83 @@ import online64 from "url:/assets/icons/online/logo64.png"; import online128 from "url:/assets/icons/online/logo128.png"; import online256 from "url:/assets/icons/online/logo256.png"; +// Development: + +// Same as production ones, then: +// +// 1. Open with GIMP. +// 2. Colors > Hua-Saturation: +// - Hue = -130 +// - Lightness = -75.5 +// - Saturation = 100 + +import devOffline64 from "url:/assets/icons/offline/logo64.development.png"; +import devOffline128 from "url:/assets/icons/offline/logo128.development.png"; +import devOffline256 from "url:/assets/icons/offline/logo256.development.png"; + +import devOnline64 from "url:/assets/icons/online/logo64.development.png"; +import devOnline128 from "url:/assets/icons/online/logo128.development.png"; +import devOnline256 from "url:/assets/icons/online/logo256.development.png"; + import browser from "webextension-polyfill"; -/** - * Update the popup icon - * - * @param hasPerms Does the site have any permissions? - */ -export async function updateIcon(hasPerms: boolean) { - const offlineLogos = { +interface LogosBySize { + 64: string; + 128: string; + 256: string; +} + +interface LogosByEnvironment { + default: LogosBySize; + development: LogosBySize; +} + +const offlineLogos: LogosByEnvironment = { + default: { 64: offline64, 128: offline128, 256: offline256 - }; - const onlineLogos = { + }, + development: { + 64: devOffline64, + 128: devOffline128, + 256: devOffline256 + } +}; + +const onlineLogos: LogosByEnvironment = { + default: { 64: online64, 128: online128, 256: online256 - }; + }, + development: { + 64: devOnline64, + 128: devOnline128, + 256: devOnline256 + } +}; + +/** + * Update the popup icon + * + * @param hasPerms Does the site have any permissions? + */ +export async function updateIcon(hasPerms: boolean) { + // Set logos if connected / if not connected: + const logosByEnvironment = hasPerms ? onlineLogos : offlineLogos; + + // Use the "gold" version for development: + const logosBySize = + logosByEnvironment[process.env.NODE_ENV] || logosByEnvironment.default; - // set logos if connected / if not connected if (browser.runtime.getManifest().manifest_version === 3) { await browser.action.setIcon({ - path: hasPerms ? onlineLogos : offlineLogos + path: logosBySize }); } else { await browser.browserAction.setIcon({ - path: hasPerms ? onlineLogos : offlineLogos + path: logosBySize }); } } diff --git a/src/utils/theme.ts b/src/utils/theme.ts index 7b0599be3..2c3e02f74 100644 --- a/src/utils/theme.ts +++ b/src/utils/theme.ts @@ -1,108 +1,53 @@ -import { createGlobalStyle, css } from "styled-components"; +import { css } from "styled-components"; import type { DisplayTheme } from "@arconnect/components"; import { useEffect, useState } from "react"; import useSetting from "~settings/hook"; -// import fonts -import manropeLight from "url:/assets/fonts/Manrope-Light.woff2"; -import manropeRegular from "url:/assets/fonts/Manrope-Regular.woff2"; -import manropeMedium from "url:/assets/fonts/Manrope-Medium.woff2"; -import manropeSemiBold from "url:/assets/fonts/Manrope-SemiBold.woff2"; -import manropeBold from "url:/assets/fonts/Manrope-Bold.woff2"; -import manropeExtraBold from "url:/assets/fonts/Manrope-ExtraBold.woff2"; - type ThemeSetting = "light" | "dark" | "system"; -/** - * Determinates the theme of the UI - */ -export function useTheme() { - const [theme] = useSetting("display_theme"); - const [displayTheme, setDisplayTheme] = useState("light"); - - useEffect(() => { - if (theme !== "system") { - return setDisplayTheme(theme); - } - - // match theme - const darkModePreference = window.matchMedia( - "(prefers-color-scheme: dark)" - ); +const darkModePreference = window.matchMedia("(prefers-color-scheme: dark)"); - setDisplayTheme(darkModePreference.matches ? "dark" : "light"); - - // listen for system theme changes - const listener = (e: MediaQueryListEvent) => - setDisplayTheme(e.matches ? "dark" : "light"); - - darkModePreference.addEventListener("change", listener); - - return () => darkModePreference.removeEventListener("change", listener); - }, [theme]); +function getInitialDisplayTheme(themeSetting: ThemeSetting): DisplayTheme { + if (themeSetting !== "system") { + // "light" or "dark" + return themeSetting; + } - return displayTheme; + return darkModePreference.matches ? "dark" : "light"; } -export const GlobalStyle = createGlobalStyle` - @font-face { - font-family: "ManropeLocal"; - font-style: normal; - font-weight: 300; - src: url(${manropeLight}) format('woff2'); - } - - @font-face { - font-family: "ManropeLocal"; - font-style: normal; - font-weight: 400; - src: url(${manropeRegular}) format('woff2'); - } +export function useTheme() { + const [themeSetting] = useSetting("display_theme"); - @font-face { - font-family: "ManropeLocal"; - font-style: normal; - font-weight: 500; - src: url(${manropeMedium}) format('woff2'); - } + const [displayTheme, setDisplayTheme] = useState(() => { + return getInitialDisplayTheme(themeSetting); + }); - @font-face { - font-family: "ManropeLocal"; - font-style: normal; - font-weight: 600; - src: url(${manropeSemiBold}) format('woff2'); - } + useEffect(() => { + setDisplayTheme(getInitialDisplayTheme(themeSetting)); + }, [themeSetting]); - @font-face { - font-family: "ManropeLocal"; - font-style: normal; - font-weight: 600; - src: url(${manropeBold}) format('woff2'); - } + useEffect(() => { + if (themeSetting !== "system") return; - @font-face { - font-family: "ManropeLocal"; - font-style: normal; - font-weight: 700; - src: url(${manropeExtraBold}) format('woff2'); - } + function handleDarkModePreferenceChange(e: MediaQueryListEvent) { + setDisplayTheme(e.matches ? "dark" : "light"); + } - body { - margin: 0; - padding: 0; - min-height: 500px; - transition: background-color .23s ease-in-out; - } + darkModePreference.addEventListener( + "change", + handleDarkModePreferenceChange + ); - body, button, input, select, textarea { - font-family: "ManropeLocal", "Manrope VF", "Manrope", sans-serif !important; - } + return () => + darkModePreference.removeEventListener( + "change", + handleDarkModePreferenceChange + ); + }, [themeSetting]); - ::selection { - background-color: rgba(${(props) => props.theme.theme}, .6); - color: #fff; - } -`; + return displayTheme; +} /** * Hover effect css diff --git a/src/wallets/index.ts b/src/wallets/index.ts index 0655bb0c1..e0b4a160d 100644 --- a/src/wallets/index.ts +++ b/src/wallets/index.ts @@ -46,29 +46,99 @@ export async function getWallets() { return wallets || []; } +type InitialScreenType = "cover" | "locked" | "generating" | "default"; + /** * Hook that opens a new tab if ArConnect has not been set up yet */ -export const useSetUp = () => +export function useSetUp() { + const [initialScreenType, setInitialScreenType] = + useState("cover"); + useEffect(() => { - (async () => { - const activeAddress = await getActiveAddress(); - const wallets = await getWallets(); + async function checkWalletState() { + const [activeAddress, wallets, decryptionKey] = await Promise.all([ + getActiveAddress(), + getWallets(), + getDecryptionKey() + ]); + + const hasWallets = activeAddress && wallets.length > 0; + + let nextInitialScreenType: InitialScreenType = "cover"; + + switch (process.env.PLASMO_PUBLIC_APP_TYPE) { + // `undefined` has been added here just in case, so that the default behavior if nothing is specific is + // building the browser extension, just like it was before adding support for the embedded wallet: + case undefined: + case "extension": { + if (!hasWallets) { + await browser.tabs.create({ + url: browser.runtime.getURL("tabs/welcome.html") + }); + + window.top.close(); + } else if (!decryptionKey) { + nextInitialScreenType = "locked"; + } else { + nextInitialScreenType = "default"; + } + + break; + } + + case "embedded": { + nextInitialScreenType = !hasWallets ? "generating" : "default"; + + break; + } + + default: { + throw new Error( + `Unknown APP_TYPE = ${process.env.PLASMO_PUBLIC_APP_TYPE}` + ); + } + } - if ( - !activeAddress || - activeAddress === "" || - wallets.length === 0 || - !wallets - ) { - await browser.tabs.create({ - url: browser.runtime.getURL("tabs/welcome.html") - }); - window.top.close(); + setInitialScreenType(nextInitialScreenType); + + const coverElement = document.getElementById("cover"); + + if (coverElement) { + if (nextInitialScreenType === "cover") { + coverElement.removeAttribute("aria-hidden"); + } else { + coverElement.setAttribute("aria-hidden", "true"); + } } - })(); + } + + ExtensionStorage.watch({ + decryption_key: checkWalletState + }); + + checkWalletState(); + + return () => { + ExtensionStorage.unwatch({ + decryption_key: checkWalletState + }); + }; }, []); + return initialScreenType; +} + +export function useRemoveCover() { + useEffect(() => { + const coverElement = document.getElementById("cover"); + + if (coverElement) { + coverElement.setAttribute("aria-hidden", "true"); + } + }, []); +} + /** * Hook to get if there are no wallets added */ diff --git a/yarn.lock b/yarn.lock index d888d11db..feacc163d 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1151,16 +1151,6 @@ "@lezer/lr" "^1.0.0" json5 "^2.2.1" -"@motionone/animation@^10.13.1": - version "10.18.0" - resolved "https://registry.npmjs.org/@motionone/animation/-/animation-10.18.0.tgz#868d00b447191816d5d5cf24b1cafa144017922b" - integrity sha512-9z2p5GFGCm0gBsZbi8rVMOAJCtw1WqBTIPw3ozk06gDvZInBPIsQcHgYogEJ4yuHJ+akuW8g1SEIOpTOvYs8hw== - dependencies: - "@motionone/easing" "^10.18.0" - "@motionone/types" "^10.17.1" - "@motionone/utils" "^10.18.0" - tslib "^2.3.1" - "@motionone/animation@^10.17.0": version "10.17.0" resolved "https://registry.yarnpkg.com/@motionone/animation/-/animation-10.17.0.tgz#7633c6f684b5fee2b61c405881b8c24662c68fca" @@ -1171,18 +1161,6 @@ "@motionone/utils" "^10.17.0" tslib "^2.3.1" -"@motionone/dom@10.13.1": - version "10.13.1" - resolved "https://registry.npmjs.org/@motionone/dom/-/dom-10.13.1.tgz#fc29ea5d12538f21b211b3168e502cfc07a24882" - integrity sha512-zjfX+AGMIt/fIqd/SL1Lj93S6AiJsEA3oc5M9VkUr+Gz+juRmYN1vfvZd6MvEkSqEjwPQgcjN7rGZHrDB9APfQ== - dependencies: - "@motionone/animation" "^10.13.1" - "@motionone/generators" "^10.13.1" - "@motionone/types" "^10.13.0" - "@motionone/utils" "^10.13.1" - hey-listen "^1.0.8" - tslib "^2.3.1" - "@motionone/dom@^10.15.3": version "10.17.0" resolved "https://registry.yarnpkg.com/@motionone/dom/-/dom-10.17.0.tgz#519dd78aab0750a94614c69a82da5290cd617383" @@ -1203,23 +1181,6 @@ "@motionone/utils" "^10.17.0" tslib "^2.3.1" -"@motionone/easing@^10.18.0": - version "10.18.0" - resolved "https://registry.npmjs.org/@motionone/easing/-/easing-10.18.0.tgz#7b82f6010dfee3a1bb0ee83abfbaff6edae0c708" - integrity sha512-VcjByo7XpdLS4o9T8t99JtgxkdMcNWD3yHU/n6CLEz3bkmKDRZyYQ/wmSf6daum8ZXqfUAgFeCZSpJZIMxaCzg== - dependencies: - "@motionone/utils" "^10.18.0" - tslib "^2.3.1" - -"@motionone/generators@^10.13.1": - version "10.18.0" - resolved "https://registry.npmjs.org/@motionone/generators/-/generators-10.18.0.tgz#fe09ab5cfa0fb9a8884097feb7eb60abeb600762" - integrity sha512-+qfkC2DtkDj4tHPu+AFKVfR/C30O1vYdvsGYaR13W/1cczPrrcjdvYCj0VLFuRMN+lP1xvpNZHCRNM4fBzn1jg== - dependencies: - "@motionone/types" "^10.17.1" - "@motionone/utils" "^10.18.0" - tslib "^2.3.1" - "@motionone/generators@^10.17.0": version "10.17.0" resolved "https://registry.yarnpkg.com/@motionone/generators/-/generators-10.17.0.tgz#878d292539c41434c13310d5f863a87a94e6e689" @@ -1229,25 +1190,11 @@ "@motionone/utils" "^10.17.0" tslib "^2.3.1" -"@motionone/types@^10.13.0", "@motionone/types@^10.17.1": - version "10.17.1" - resolved "https://registry.npmjs.org/@motionone/types/-/types-10.17.1.tgz#cf487badbbdc9da0c2cb86ffc1e5d11147c6e6fb" - integrity sha512-KaC4kgiODDz8hswCrS0btrVrzyU2CSQKO7Ps90ibBVSQmjkrt2teqta6/sOG59v7+dPnKMAg13jyqtMKV2yJ7A== - "@motionone/types@^10.17.0": version "10.17.0" resolved "https://registry.yarnpkg.com/@motionone/types/-/types-10.17.0.tgz#179571ce98851bac78e19a1c3974767227f08ba3" integrity sha512-EgeeqOZVdRUTEHq95Z3t8Rsirc7chN5xFAPMYFobx8TPubkEfRSm5xihmMUkbaR2ErKJTUw3347QDPTHIW12IA== -"@motionone/utils@^10.13.1", "@motionone/utils@^10.18.0": - version "10.18.0" - resolved "https://registry.npmjs.org/@motionone/utils/-/utils-10.18.0.tgz#a59ff8932ed9009624bca07c56b28ef2bb2f885e" - integrity sha512-3XVF7sgyTSI2KWvTf6uLlBJ5iAgRgmvp3bpuOiQJvInd4nZ19ET8lX5unn30SlmRH7hXbBbH+Gxd0m0klJ3Xtw== - dependencies: - "@motionone/types" "^10.17.1" - hey-listen "^1.0.8" - tslib "^2.3.1" - "@motionone/utils@^10.17.0": version "10.17.0" resolved "https://registry.yarnpkg.com/@motionone/utils/-/utils-10.17.0.tgz#cc0ba8acdc6848ff48d8c1f2d0d3e7602f4f942e" @@ -6791,19 +6738,12 @@ form-data@^4.0.0: combined-stream "^1.0.8" mime-types "^2.1.12" -framer-motion@7.5.3: - version "7.5.3" - resolved "https://registry.npmjs.org/framer-motion/-/framer-motion-7.5.3.tgz#a1de7d6c4abbf7333619d4a6c8df74c12240be43" - integrity sha512-VvANga9Z7bYtKMAsM/je81FwJDHfThOYywN04xVQ4OGdMVY09Bowx/q7nZd6XtytLuv6byc6GT1mYwag+SQ/nw== +framer-motion@^11.11.7: + version "11.11.7" + resolved "https://registry.yarnpkg.com/framer-motion/-/framer-motion-11.11.7.tgz#3af277845ff690f6935fbcf781fa3eb4146e2321" + integrity sha512-89CgILOXPeG3L7ymOTGrLmf8IiKubYLUN/QkYgQuLvehAHfqgwJbLfCnhuyRI4WTds1TXkUp67A7IJrgRY/j1w== dependencies: - "@motionone/dom" "10.13.1" - framesync "6.1.2" - hey-listen "^1.0.8" - popmotion "11.0.5" - style-value-types "5.1.2" - tslib "2.4.0" - optionalDependencies: - "@emotion/is-prop-valid" "^0.8.2" + tslib "^2.4.0" framer-motion@^7.5.3: version "7.10.3" @@ -6816,13 +6756,6 @@ framer-motion@^7.5.3: optionalDependencies: "@emotion/is-prop-valid" "^0.8.2" -framesync@6.1.2: - version "6.1.2" - resolved "https://registry.npmjs.org/framesync/-/framesync-6.1.2.tgz#755eff2fb5b8f3b4d2b266dd18121b300aefea27" - integrity sha512-jBTqhX6KaQVDyus8muwZbBeGGP0XgujBRbQ7gM7BRdS3CadCZIHiawyzYLnafYcvZIh5j8WE7cxZKFn7dXhu9g== - dependencies: - tslib "2.4.0" - from2@^2.3.0: version "2.3.0" resolved "https://registry.yarnpkg.com/from2/-/from2-2.3.0.tgz#8bfb5502bde4a4d36cfdeea007fcca21d7e382af" @@ -9856,16 +9789,6 @@ plimit-lit@^3.0.1: dependencies: queue-lit "^3.0.0" -popmotion@11.0.5: - version "11.0.5" - resolved "https://registry.npmjs.org/popmotion/-/popmotion-11.0.5.tgz#8e3e014421a0ffa30ecd722564fd2558954e1f7d" - integrity sha512-la8gPM1WYeFznb/JqF4GiTkRRPZsfaj2+kCxqQgr2MJylMmIKUwBfWW8Wa5fml/8gmtlD5yI01MP1QCZPWmppA== - dependencies: - framesync "6.1.2" - hey-listen "^1.0.8" - style-value-types "5.1.2" - tslib "2.4.0" - possible-typed-array-names@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/possible-typed-array-names/-/possible-typed-array-names-1.0.0.tgz#89bb63c6fada2c3e90adc4a647beeeb39cc7bf8f" @@ -11163,14 +11086,6 @@ strip-json-comments@~2.0.1: resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a" integrity sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ== -style-value-types@5.1.2: - version "5.1.2" - resolved "https://registry.npmjs.org/style-value-types/-/style-value-types-5.1.2.tgz#6be66b237bd546048a764883528072ed95713b62" - integrity sha512-Vs9fNreYF9j6W2VvuDTP7kepALi7sk0xtk2Tu8Yxi9UoajJdEVpNpCov0HsLTqXvNGKX+Uv09pkozVITi1jf3Q== - dependencies: - hey-listen "^1.0.8" - tslib "2.4.0" - styled-components@^5.3.6: version "5.3.11" resolved "https://registry.yarnpkg.com/styled-components/-/styled-components-5.3.11.tgz#9fda7bf1108e39bf3f3e612fcc18170dedcd57a8"