fix issue with breakpoints causing re-render

This commit is contained in:
hzrd149
2023-10-13 10:24:55 -05:00
parent 85a9dad33a
commit ed1cb04235
17 changed files with 133 additions and 63 deletions

View File

@@ -16,8 +16,11 @@
"dependencies": { "dependencies": {
"@cashu/cashu-ts": "^0.8.2-rc.7", "@cashu/cashu-ts": "^0.8.2-rc.7",
"@chakra-ui/anatomy": "^2.2.1", "@chakra-ui/anatomy": "^2.2.1",
"@chakra-ui/breakpoint-utils": "^2.0.8",
"@chakra-ui/icons": "^2.1.1", "@chakra-ui/icons": "^2.1.1",
"@chakra-ui/media-query": "^3.3.0",
"@chakra-ui/react": "^2.8.1", "@chakra-ui/react": "^2.8.1",
"@chakra-ui/shared-utils": "^2.0.4",
"@chakra-ui/styled-system": "^2.9.1", "@chakra-ui/styled-system": "^2.9.1",
"@emotion/react": "^11.11.1", "@emotion/react": "^11.11.1",
"@emotion/styled": "^11.11.0", "@emotion/styled": "^11.11.0",

View File

@@ -1,4 +1,4 @@
import { Card, CardBody, CardProps, Flex, Heading, Image, Link, Tag, Text, useBreakpointValue } from "@chakra-ui/react"; import { Card, CardBody, CardProps, Flex, Heading, Image, Link, Tag, Text } from "@chakra-ui/react";
import { Link as RouterLink, useNavigate } from "react-router-dom"; import { Link as RouterLink, useNavigate } from "react-router-dom";
import { parseStreamEvent } from "../../../helpers/nostr/stream"; import { parseStreamEvent } from "../../../helpers/nostr/stream";
@@ -8,6 +8,7 @@ import { UserLink } from "../../user-link";
import { UserAvatar } from "../../user-avatar"; import { UserAvatar } from "../../user-avatar";
import useEventNaddr from "../../../hooks/use-event-naddr"; import useEventNaddr from "../../../hooks/use-event-naddr";
import Timestamp from "../../timestamp"; import Timestamp from "../../timestamp";
import { useBreakpointValue } from "../../../providers/breakpoint-provider";
export default function EmbeddedStream({ event, ...props }: Omit<CardProps, "children"> & { event: NostrEvent }) { export default function EmbeddedStream({ event, ...props }: Omit<CardProps, "children"> & { event: NostrEvent }) {
const stream = parseStreamEvent(event); const stream = parseStreamEvent(event);

View File

@@ -8,7 +8,7 @@ import {
useRef, useRef,
useState, useState,
} from "react"; } from "react";
import { Image, ImageProps, useBreakpointValue } from "@chakra-ui/react"; import { Image, ImageProps } from "@chakra-ui/react";
import appSettings from "../../services/settings/app-settings"; import appSettings from "../../services/settings/app-settings";
import { useTrusted } from "../../providers/trust"; import { useTrusted } from "../../providers/trust";
@@ -19,6 +19,7 @@ import { isImageURL } from "../../helpers/url";
import PhotoGallery, { PhotoWithoutSize } from "../photo-gallery"; import PhotoGallery, { PhotoWithoutSize } from "../photo-gallery";
import { NostrEvent } from "../../types/nostr-event"; import { NostrEvent } from "../../types/nostr-event";
import useAppSettings from "../../hooks/use-app-settings"; import useAppSettings from "../../hooks/use-app-settings";
import { useBreakpointValue } from "../../providers/breakpoint-provider";
function useElementBlur(initBlur = false): { style: CSSProperties; onClick: MouseEventHandler } { function useElementBlur(initBlur = false): { style: CSSProperties; onClick: MouseEventHandler } {
const [blur, setBlur] = useState(initBlur); const [blur, setBlur] = useState(initBlur);

View File

@@ -1,13 +1,14 @@
import React from "react"; import React from "react";
import { Container, Flex, Spacer, useBreakpointValue } from "@chakra-ui/react"; import { Container, Flex, Spacer } from "@chakra-ui/react";
import { ErrorBoundary } from "../error-boundary";
import { ErrorBoundary } from "../error-boundary";
import { ReloadPrompt } from "../reload-prompt"; import { ReloadPrompt } from "../reload-prompt";
import DesktopSideNav from "./desktop-side-nav"; import DesktopSideNav from "./desktop-side-nav";
import MobileBottomNav from "./mobile-bottom-nav"; import MobileBottomNav from "./mobile-bottom-nav";
import useSubject from "../../hooks/use-subject"; import useSubject from "../../hooks/use-subject";
import accountService from "../../services/account"; import accountService from "../../services/account";
import GhostToolbar from "./ghost-toolbar"; import GhostToolbar from "./ghost-toolbar";
import { useBreakpointValue } from "../../providers/breakpoint-provider";
export default function Layout({ children }: { children: React.ReactNode }) { export default function Layout({ children }: { children: React.ReactNode }) {
const isMobile = useBreakpointValue({ base: true, md: false }); const isMobile = useBreakpointValue({ base: true, md: false });

View File

@@ -1,9 +1,10 @@
import { ButtonGroup, ButtonGroupProps, Divider, useBreakpointValue } from "@chakra-ui/react"; import { ButtonGroup, ButtonGroupProps, Divider } from "@chakra-ui/react";
import { NostrEvent } from "../../../types/nostr-event"; import { NostrEvent } from "../../../types/nostr-event";
import ReactionButton from "./reaction-button"; import ReactionButton from "./reaction-button";
import EventReactionButtons from "../../event-reactions"; import EventReactionButtons from "../../event-reactions";
import useEventReactions from "../../../hooks/use-event-reactions"; import useEventReactions from "../../../hooks/use-event-reactions";
import { useBreakpointValue } from "../../../providers/breakpoint-provider";
export default function NoteReactions({ event, ...props }: Omit<ButtonGroupProps, "children"> & { event: NostrEvent }) { export default function NoteReactions({ event, ...props }: Omit<ButtonGroupProps, "children"> & { event: NostrEvent }) {
const reactions = useEventReactions(event.id) ?? []; const reactions = useEventReactions(event.id) ?? [];

View File

@@ -11,7 +11,6 @@ import {
IconButton, IconButton,
Link, Link,
Text, Text,
useBreakpointValue,
useDisclosure, useDisclosure,
} from "@chakra-ui/react"; } from "@chakra-ui/react";
import { NostrEvent, isATag } from "../../types/nostr-event"; import { NostrEvent, isATag } from "../../types/nostr-event";
@@ -44,6 +43,7 @@ import OpenInDrawerButton from "../open-in-drawer-button";
import { getSharableEventAddress } from "../../helpers/nip19"; import { getSharableEventAddress } from "../../helpers/nip19";
import { COMMUNITY_DEFINITION_KIND, getCommunityName } from "../../helpers/nostr/communities"; import { COMMUNITY_DEFINITION_KIND, getCommunityName } from "../../helpers/nostr/communities";
import useReplaceableEvent from "../../hooks/use-replaceable-event"; import useReplaceableEvent from "../../hooks/use-replaceable-event";
import { useBreakpointValue } from "../../providers/breakpoint-provider";
export type NoteProps = Omit<CardProps, "children"> & { export type NoteProps = Omit<CardProps, "children"> & {
event: NostrEvent; event: NostrEvent;

View File

@@ -1,11 +1,11 @@
import { memo } from "react"; import { memo } from "react";
import { useBreakpointValue } from "@chakra-ui/react";
import { getEventRelays } from "../../services/event-relays"; import { getEventRelays } from "../../services/event-relays";
import { NostrEvent } from "../../types/nostr-event"; import { NostrEvent } from "../../types/nostr-event";
import useSubject from "../../hooks/use-subject"; import useSubject from "../../hooks/use-subject";
import { RelayIconStack, RelayIconStackProps } from "../relay-icon-stack"; import { RelayIconStack, RelayIconStackProps } from "../relay-icon-stack";
import { getEventUID } from "../../helpers/nostr/events"; import { getEventUID } from "../../helpers/nostr/events";
import { useBreakpointValue } from "../../providers/breakpoint-provider";
export type NoteRelaysProps = { export type NoteRelaysProps = {
event: NostrEvent; event: NostrEvent;

View File

@@ -10,9 +10,9 @@ import {
LinkBox, LinkBox,
LinkOverlay, LinkOverlay,
Text, Text,
useBreakpointValue,
} from "@chakra-ui/react"; } from "@chakra-ui/react";
import useOpenGraphData from "../hooks/use-open-graph-data"; import useOpenGraphData from "../hooks/use-open-graph-data";
import { useBreakpointValue } from "../providers/breakpoint-provider";
export default function OpenGraphCard({ url, ...props }: { url: URL } & Omit<CardProps, "children">) { export default function OpenGraphCard({ url, ...props }: { url: URL } & Omit<CardProps, "children">) {
const { value: data } = useOpenGraphData(url); const { value: data } = useOpenGraphData(url);

View File

@@ -1,16 +1,7 @@
import { import { Alert, AlertDescription, AlertIcon, AlertProps, AlertTitle, Button, Spacer, useModal } from "@chakra-ui/react";
Alert,
AlertDescription,
AlertIcon,
AlertProps,
AlertTitle,
Button,
Spacer,
useBreakpointValue,
useModal,
} from "@chakra-ui/react";
import { useExpand } from "../providers/expanded"; import { useExpand } from "../providers/expanded";
import { useBreakpointValue } from "../providers/breakpoint-provider";
export default function SensitiveContentWarning({ description }: { description: string } & AlertProps) { export default function SensitiveContentWarning({ description }: { description: string } & AlertProps) {
const expand = useExpand(); const expand = useExpand();

View File

@@ -1,5 +1,4 @@
import { useMemo, useRef } from "react"; import { useMemo, useRef } from "react";
import { useBreakpointValue } from "@chakra-ui/react";
import { Kind } from "nostr-tools"; import { Kind } from "nostr-tools";
import { Photo } from "react-photo-album"; import { Photo } from "react-photo-album";
@@ -14,6 +13,7 @@ import PhotoGallery, { PhotoWithoutSize } from "../../photo-gallery";
import { useRegisterIntersectionEntity } from "../../../providers/intersection-observer"; import { useRegisterIntersectionEntity } from "../../../providers/intersection-observer";
import { NostrEvent } from "../../../types/nostr-event"; import { NostrEvent } from "../../../types/nostr-event";
import { getEventUID } from "../../../helpers/nostr/events"; import { getEventUID } from "../../../helpers/nostr/events";
import { useBreakpointValue } from "../../../providers/breakpoint-provider";
function GalleryImage({ event, ...props }: EmbeddedImageProps & { event: NostrEvent }) { function GalleryImage({ event, ...props }: EmbeddedImageProps & { event: NostrEvent }) {
const ref = useRef<HTMLImageElement | null>(null); const ref = useRef<HTMLImageElement | null>(null);

View File

@@ -1,3 +1,3 @@
export function buildAppSelectUrl(identifier: string, select = true) { export function buildAppSelectUrl(identifier: string, select = true) {
return `https://nostrapp.link/main/apps/social#${identifier}` + (select ? "?select=true" : ""); return `https://nostrapp.link/#${identifier}` + (select ? "?select=true" : "");
} }

View File

@@ -0,0 +1,79 @@
import { PropsWithChildren, createContext, useContext } from "react";
import { UseBreakpointOptions, useBreakpoint as useBaseBreakpoint, useTheme } from "@chakra-ui/react";
import { isObject } from "@chakra-ui/shared-utils";
import { arrayToObjectNotation } from "@chakra-ui/breakpoint-utils";
import { breakpoints as defaultBreakPoints } from "@chakra-ui/breakpoint-utils";
// ChakraUIs useBreakpointValue renders twice, once with the fallback value then with the actual breakpoint value
// This causes a lot of re-renders and wasted processing.
// This provider is designed to solve that by providing the current breakpoint through context
const BreakpointContext = createContext("base");
export function useBreakpoint(arg?: string | UseBreakpointOptions) {
return useContext(BreakpointContext) ?? (typeof arg === "object" ? arg.fallback : arg);
}
// copied from https://github.com/chakra-ui/chakra-ui/blob/main/packages/components/media-query/src/media-query.utils.ts
export function getClosestValue<T = any>(
values: Record<string, T>,
breakpoint: string,
breakpoints = defaultBreakPoints,
) {
let index = Object.keys(values).indexOf(breakpoint);
if (index !== -1) {
return values[breakpoint];
}
let stopIndex = breakpoints.indexOf(breakpoint);
while (stopIndex >= 0) {
const key = breakpoints[stopIndex];
if (values.hasOwnProperty(key)) {
index = stopIndex;
break;
}
stopIndex -= 1;
}
if (index !== -1) {
const key = breakpoints[index];
return values[key];
}
return undefined;
}
// copied from https://github.com/chakra-ui/chakra-ui/blob/main/packages/components/media-query/src/use-breakpoint-value.ts
export function useBreakpointValue<T = any>(
values: Partial<Record<string, T>> | Array<T | null>,
arg?: UseBreakpointOptions | string,
): T | undefined {
const opts = isObject(arg) ? arg : { fallback: arg ?? "base" };
// NOTE: get the breakpoint from context instead of calling ChakraUIs useBreakpoint hook
const breakpoint = useBreakpoint(opts);
const theme = useTheme();
if (!breakpoint) return;
/**
* Get the sorted breakpoint keys from the provided breakpoints
*/
const breakpoints = Array.from(theme.__breakpoints?.keys || []);
const obj = Array.isArray(values)
? Object.fromEntries<any>(
Object.entries(arrayToObjectNotation(values, breakpoints)).map(([key, value]) => [key, value]),
)
: values;
return getClosestValue(obj, breakpoint, breakpoints);
}
export default function BreakpointProvider({ children }: PropsWithChildren) {
const breakpoint = useBaseBreakpoint();
return <BreakpointContext.Provider value={breakpoint}>{children}</BreakpointContext.Provider>;
}

View File

@@ -11,6 +11,7 @@ import PostModalProvider from "./post-modal-provider";
import { DefaultEmojiProvider, UserEmojiProvider } from "./emoji-provider"; import { DefaultEmojiProvider, UserEmojiProvider } from "./emoji-provider";
import { UserContactsUserDirectoryProvider } from "./user-directory-provider"; import { UserContactsUserDirectoryProvider } from "./user-directory-provider";
import MuteModalProvider from "./mute-modal-provider"; import MuteModalProvider from "./mute-modal-provider";
import BreakpointProvider from "./breakpoint-provider";
// Top level providers, should be render as close to the root as possible // Top level providers, should be render as close to the root as possible
export const GlobalProviders = ({ children }: { children: React.ReactNode }) => { export const GlobalProviders = ({ children }: { children: React.ReactNode }) => {
@@ -30,22 +31,24 @@ export const GlobalProviders = ({ children }: { children: React.ReactNode }) =>
/** Providers that provider functionality to pages (needs to be rendered under a router) */ /** Providers that provider functionality to pages (needs to be rendered under a router) */
export function PageProviders({ children }: { children: React.ReactNode }) { export function PageProviders({ children }: { children: React.ReactNode }) {
return ( return (
<SigningProvider> <BreakpointProvider>
<DeleteEventProvider> <SigningProvider>
<MuteModalProvider> <DeleteEventProvider>
<InvoiceModalProvider> <MuteModalProvider>
<NotificationTimelineProvider> <InvoiceModalProvider>
<DefaultEmojiProvider> <NotificationTimelineProvider>
<UserEmojiProvider> <DefaultEmojiProvider>
<UserContactsUserDirectoryProvider> <UserEmojiProvider>
<PostModalProvider>{children}</PostModalProvider> <UserContactsUserDirectoryProvider>
</UserContactsUserDirectoryProvider> <PostModalProvider>{children}</PostModalProvider>
</UserEmojiProvider> </UserContactsUserDirectoryProvider>
</DefaultEmojiProvider> </UserEmojiProvider>
</NotificationTimelineProvider> </DefaultEmojiProvider>
</InvoiceModalProvider> </NotificationTimelineProvider>
</MuteModalProvider> </InvoiceModalProvider>
</DeleteEventProvider> </MuteModalProvider>
</SigningProvider> </DeleteEventProvider>
</SigningProvider>
</BreakpointProvider>
); );
} }

View File

@@ -14,7 +14,6 @@ import {
Heading, Heading,
Spacer, Spacer,
Spinner, Spinner,
useBreakpointValue,
useDisclosure, useDisclosure,
} from "@chakra-ui/react"; } from "@chakra-ui/react";
import { useParams, Navigate, useSearchParams, useNavigate } from "react-router-dom"; import { useParams, Navigate, useSearchParams, useNavigate } from "react-router-dom";
@@ -52,6 +51,7 @@ import StreamZapButton from "../components/stream-zap-button";
import StreamGoal from "../components/stream-goal"; import StreamGoal from "../components/stream-goal";
import StreamShareButton from "../components/stream-share-button"; import StreamShareButton from "../components/stream-share-button";
import VerticalPageLayout from "../../../components/vertical-page-layout"; import VerticalPageLayout from "../../../components/vertical-page-layout";
import { useBreakpointValue } from "../../../providers/breakpoint-provider";
function DesktopStreamPage({ stream }: { stream: ParsedStream }) { function DesktopStreamPage({ stream }: { stream: ParsedStream }) {
useAppTitle(stream.title); useAppTitle(stream.title);

View File

@@ -1,5 +1,6 @@
import { Flex, Heading, IconButton, Spacer, useBreakpointValue } from "@chakra-ui/react"; import { Flex, Heading, IconButton, Spacer } from "@chakra-ui/react";
import { useNavigate } from "react-router-dom"; import { useNavigate } from "react-router-dom";
import { EditIcon, GhostIcon } from "../../../components/icons"; import { EditIcon, GhostIcon } from "../../../components/icons";
import { UserAvatar } from "../../../components/user-avatar"; import { UserAvatar } from "../../../components/user-avatar";
import { UserDnsIdentityIcon } from "../../../components/user-dns-identity-icon"; import { UserDnsIdentityIcon } from "../../../components/user-dns-identity-icon";
@@ -9,6 +10,7 @@ import { useUserMetadata } from "../../../hooks/use-user-metadata";
import { UserProfileMenu } from "./user-profile-menu"; import { UserProfileMenu } from "./user-profile-menu";
import { UserFollowButton } from "../../../components/user-follow-button"; import { UserFollowButton } from "../../../components/user-follow-button";
import accountService from "../../../services/account"; import accountService from "../../../services/account";
import { useBreakpointValue } from "../../../providers/breakpoint-provider";
export default function Header({ export default function Header({
pubkey, pubkey,

View File

@@ -99,27 +99,10 @@ const UserView = () => {
const userTopRelays = useUserTopRelays(pubkey, relayCount); const userTopRelays = useUserTopRelays(pubkey, relayCount);
const relayModal = useDisclosure(); const relayModal = useDisclosure();
const articleCount = useUserEventKindCount(pubkey, Kind.Article);
const streamCount = useUserEventKindCount(pubkey, STREAM_KIND);
const goalCount = useUserEventKindCount(pubkey, GOAL_KIND);
const filteredTabs = useMemo(
() =>
tabs.filter((t) => {
if (t.path === "streams" && streamCount === 0) return false;
if (t.path === "goals" && goalCount === 0) return false;
if (t.path === "articles" && articleCount === 0) return false;
return true;
}),
[streamCount, goalCount, articleCount],
);
const matches = useMatches(); const matches = useMatches();
const lastMatch = matches[matches.length - 1]; const lastMatch = matches[matches.length - 1];
const activeTab = filteredTabs.indexOf( const activeTab = tabs.indexOf(tabs.find((t) => lastMatch.pathname.endsWith(t.path)) ?? tabs[0]);
filteredTabs.find((t) => lastMatch.pathname.endsWith(t.path)) ?? filteredTabs[0],
);
const metadata = useUserMetadata(pubkey, userTopRelays, { alwaysRequest: true }); const metadata = useUserMetadata(pubkey, userTopRelays, { alwaysRequest: true });
@@ -136,12 +119,12 @@ const UserView = () => {
flexGrow="1" flexGrow="1"
isLazy isLazy
index={activeTab} index={activeTab}
onChange={(v) => navigate(filteredTabs[v].path, { replace: true })} onChange={(v) => navigate(tabs[v].path, { replace: true })}
colorScheme="primary" colorScheme="primary"
h="full" h="full"
> >
<TabList overflowX="auto" overflowY="hidden" flexShrink={0}> <TabList overflowX="auto" overflowY="hidden" flexShrink={0}>
{filteredTabs.map(({ label }) => ( {tabs.map(({ label }) => (
<Tab key={label} whiteSpace="pre"> <Tab key={label} whiteSpace="pre">
{label} {label}
</Tab> </Tab>
@@ -149,7 +132,7 @@ const UserView = () => {
</TabList> </TabList>
<TabPanels> <TabPanels>
{filteredTabs.map(({ label }) => ( {tabs.map(({ label }) => (
<TabPanel key={label} p={0}> <TabPanel key={label} p={0}>
<ErrorBoundary> <ErrorBoundary>
<Suspense fallback={<Spinner />}> <Suspense fallback={<Spinner />}>

View File

@@ -1033,7 +1033,7 @@
"@chakra-ui/react-context" "2.1.0" "@chakra-ui/react-context" "2.1.0"
"@chakra-ui/shared-utils" "2.0.5" "@chakra-ui/shared-utils" "2.0.5"
"@chakra-ui/breakpoint-utils@2.0.8": "@chakra-ui/breakpoint-utils@2.0.8", "@chakra-ui/breakpoint-utils@^2.0.8":
version "2.0.8" version "2.0.8"
resolved "https://registry.yarnpkg.com/@chakra-ui/breakpoint-utils/-/breakpoint-utils-2.0.8.tgz#750d3712668b69f6e8917b45915cee0e08688eed" resolved "https://registry.yarnpkg.com/@chakra-ui/breakpoint-utils/-/breakpoint-utils-2.0.8.tgz#750d3712668b69f6e8917b45915cee0e08688eed"
integrity sha512-Pq32MlEX9fwb5j5xx8s18zJMARNHlQZH2VH1RZgfgRDpp7DcEgtRW5AInfN5CfqdHLO1dGxA7I3MqEuL5JnIsA== integrity sha512-Pq32MlEX9fwb5j5xx8s18zJMARNHlQZH2VH1RZgfgRDpp7DcEgtRW5AInfN5CfqdHLO1dGxA7I3MqEuL5JnIsA==
@@ -1232,7 +1232,7 @@
resolved "https://registry.yarnpkg.com/@chakra-ui/live-region/-/live-region-2.1.0.tgz#02b4b1d997075f19a7a9a87187e08c72e82ef0dd" resolved "https://registry.yarnpkg.com/@chakra-ui/live-region/-/live-region-2.1.0.tgz#02b4b1d997075f19a7a9a87187e08c72e82ef0dd"
integrity sha512-ZOxFXwtaLIsXjqnszYYrVuswBhnIHHP+XIgK1vC6DePKtyK590Wg+0J0slDwThUAd4MSSIUa/nNX84x1GMphWw== integrity sha512-ZOxFXwtaLIsXjqnszYYrVuswBhnIHHP+XIgK1vC6DePKtyK590Wg+0J0slDwThUAd4MSSIUa/nNX84x1GMphWw==
"@chakra-ui/media-query@3.3.0": "@chakra-ui/media-query@3.3.0", "@chakra-ui/media-query@^3.3.0":
version "3.3.0" version "3.3.0"
resolved "https://registry.yarnpkg.com/@chakra-ui/media-query/-/media-query-3.3.0.tgz#40f9151dedb6a7af9df3be0474b59a799c92c619" resolved "https://registry.yarnpkg.com/@chakra-ui/media-query/-/media-query-3.3.0.tgz#40f9151dedb6a7af9df3be0474b59a799c92c619"
integrity sha512-IsTGgFLoICVoPRp9ykOgqmdMotJG0CnPsKvGQeSFOB/dZfIujdVb14TYxDU4+MURXry1MhJ7LzZhv+Ml7cr8/g== integrity sha512-IsTGgFLoICVoPRp9ykOgqmdMotJG0CnPsKvGQeSFOB/dZfIujdVb14TYxDU4+MURXry1MhJ7LzZhv+Ml7cr8/g==
@@ -1596,6 +1596,11 @@
resolved "https://registry.yarnpkg.com/@chakra-ui/shared-utils/-/shared-utils-2.0.5.tgz#cb2b49705e113853647f1822142619570feba081" resolved "https://registry.yarnpkg.com/@chakra-ui/shared-utils/-/shared-utils-2.0.5.tgz#cb2b49705e113853647f1822142619570feba081"
integrity sha512-4/Wur0FqDov7Y0nCXl7HbHzCg4aq86h+SXdoUeuCMD3dSj7dpsVnStLYhng1vxvlbUnLpdF4oz5Myt3i/a7N3Q== integrity sha512-4/Wur0FqDov7Y0nCXl7HbHzCg4aq86h+SXdoUeuCMD3dSj7dpsVnStLYhng1vxvlbUnLpdF4oz5Myt3i/a7N3Q==
"@chakra-ui/shared-utils@^2.0.4":
version "2.0.4"
resolved "https://registry.yarnpkg.com/@chakra-ui/shared-utils/-/shared-utils-2.0.4.tgz#8661f2b48dd93d04151b10a894a4290c9d9a080c"
integrity sha512-JGWr+BBj3PXGZQ2gxbKSD1wYjESbYsZjkCeE2nevyVk4rN3amV1wQzCnBAhsuJktMaZD6KC/lteo9ou9QUDzpA==
"@chakra-ui/skeleton@2.1.0": "@chakra-ui/skeleton@2.1.0":
version "2.1.0" version "2.1.0"
resolved "https://registry.yarnpkg.com/@chakra-ui/skeleton/-/skeleton-2.1.0.tgz#e3b25dd3afa330029d6d63be0f7cb8d44ad25531" resolved "https://registry.yarnpkg.com/@chakra-ui/skeleton/-/skeleton-2.1.0.tgz#e3b25dd3afa330029d6d63be0f7cb8d44ad25531"