diff --git a/package.json b/package.json index 3ea4d4c07..16477d6a1 100644 --- a/package.json +++ b/package.json @@ -132,7 +132,7 @@ "react-hook-form": "^7.49.2", "react-infinite-scroll-component": "^6.1.0", "react-insta-stories": "^2.6.2", - "react-intl": "^6.5.5", + "react-intl": "^6.8.7", "react-loading-skeleton": "^3.3.1", "react-mentions": "^4.4.10", "react-modal-sheet": "^2.2.0", diff --git a/src/core/components/Button/styles.tsx b/src/core/components/Button/styles.tsx index 0c83aec57..082b08c9a 100644 --- a/src/core/components/Button/styles.tsx +++ b/src/core/components/Button/styles.tsx @@ -19,7 +19,9 @@ const commonButtonStyles = ({ theme }: { theme: DefaultTheme }) => css<{ fullWid } `; -export const DefaultButton = styled.button<{ fullWidth?: boolean }>` +export const DefaultButton = styled.button.withConfig({ + shouldForwardProp: (prop) => prop !== 'fullWidth', +})<{ fullWidth?: boolean }>` ${commonButtonStyles}; background-color: #fff; border: 1px solid #e3e4e8; @@ -32,7 +34,9 @@ export const DefaultButton = styled.button<{ fullWidth?: boolean }>` } `; -export const PrimaryButton = styled.button<{ fullWidth?: boolean }>` +export const PrimaryButton = styled.button.withConfig({ + shouldForwardProp: (prop) => prop !== 'fullWidth', +})<{ fullWidth?: boolean }>` ${commonButtonStyles}; border: none; background-color: ${({ theme }) => theme.palette.primary.main}; @@ -45,7 +49,9 @@ export const PrimaryButton = styled.button<{ fullWidth?: boolean }>` } `; -export const SecondaryButton = styled.button<{ active?: boolean; fullWidth?: boolean }>` +export const SecondaryButton = styled.button.withConfig({ + shouldForwardProp: (prop) => prop !== 'active' && prop !== 'fullWidth', +})<{ active?: boolean; fullWidth?: boolean }>` ${commonButtonStyles}; color: ${({ theme }) => theme.palette.neutral.shade1}; background-color: transparent; diff --git a/src/core/components/HorizontalList/index.tsx b/src/core/components/HorizontalList/index.tsx index 6745b777d..dec4f1a9f 100644 --- a/src/core/components/HorizontalList/index.tsx +++ b/src/core/components/HorizontalList/index.tsx @@ -65,7 +65,9 @@ function findColumnByWidth(width: number, columns: { [width: number]: number }) return founded[1]; } -const StretchedList = styled.div<{ currentWidth: number; columns: { [width: number]: number } }>` +const StretchedList = styled.div.withConfig({ + shouldForwardProp: (prop) => prop !== 'currentWidth' && prop !== 'columns', +})<{ currentWidth: number; columns: { [width: number]: number } }>` margin-bottom: 0.188rem; // give the shadow a little space display: grid; grid-auto-flow: column; diff --git a/src/core/components/OptionMenu/styles.tsx b/src/core/components/OptionMenu/styles.tsx index eb710ae9b..6095e4035 100644 --- a/src/core/components/OptionMenu/styles.tsx +++ b/src/core/components/OptionMenu/styles.tsx @@ -28,6 +28,8 @@ export const Option = styled.div<{ active?: boolean }>` } `; -export const Container = styled.div<{ pullRight?: boolean }>` +export const Container = styled.div.withConfig({ + shouldForwardProp: (prop) => prop !== 'pullRight', +})<{ pullRight?: boolean }>` ${({ pullRight }) => pullRight && `margin-left: auto;`} `; diff --git a/src/core/components/SideBar/styles.tsx b/src/core/components/SideBar/styles.tsx index 4f488c252..11dddb7a6 100644 --- a/src/core/components/SideBar/styles.tsx +++ b/src/core/components/SideBar/styles.tsx @@ -19,7 +19,9 @@ export const MenuName = styled.div` white-space: normal; `; -export const MenuTabContainer = styled.div<{ active?: boolean }>` +export const MenuTabContainer = styled.div.withConfig({ + shouldForwardProp: (prop) => prop !== 'active', +})<{ active?: boolean }>` flex-direction: column; display: flex; align-items: center; diff --git a/src/core/components/SideMenuActionItem/styles.tsx b/src/core/components/SideMenuActionItem/styles.tsx index aa464daaa..db5e98d0f 100644 --- a/src/core/components/SideMenuActionItem/styles.tsx +++ b/src/core/components/SideMenuActionItem/styles.tsx @@ -47,7 +47,9 @@ export const AnchorActionItem = styled.a<{ active?: boolean }>` `}; `; -export const IconWrapper = styled.div<{ active?: boolean }>` +export const IconWrapper = styled.div.withConfig({ + shouldForwardProp: (prop) => prop !== 'active', +})<{ active?: boolean }>` width: 40px; height: 40px; border-radius: 4px; diff --git a/src/core/components/SideMenuItem/styles.tsx b/src/core/components/SideMenuItem/styles.tsx index 5f33f79fc..fe1fe93cc 100644 --- a/src/core/components/SideMenuItem/styles.tsx +++ b/src/core/components/SideMenuItem/styles.tsx @@ -30,7 +30,9 @@ export const SideMenuItemContainer = styled(SecondaryButton)` `} `; -export const IconWrapper = styled.div<{ active?: boolean }>` +export const IconWrapper = styled.div.withConfig({ + shouldForwardProp: (prop) => prop !== 'active', +})<{ active?: boolean }>` width: 40px; height: 40px; border-radius: 4px; @@ -38,6 +40,7 @@ export const IconWrapper = styled.div<{ active?: boolean }>` align-items: center; justify-content: center; margin-right: 8px; + ${({ active, theme }) => active ? css` diff --git a/src/core/components/Time/index.tsx b/src/core/components/Time/index.tsx index df28ec7f6..ff259acf5 100644 --- a/src/core/components/Time/index.tsx +++ b/src/core/components/Time/index.tsx @@ -12,11 +12,17 @@ export interface TimeProps { } const Time = ({ className, date = Date.now() }: TimeProps) => { + const isValidDate = !isNaN(date) && new Date(date).getTime() > 0; const delta = Date.now() - date; return ( - {delta < DAY ? : } + {isValidDate && + (delta < DAY ? ( + + ) : ( + + ))} ); }; diff --git a/src/core/components/Uploaders/Image/styles.tsx b/src/core/components/Uploaders/Image/styles.tsx index da6a7cc54..7d00a17c8 100644 --- a/src/core/components/Uploaders/Image/styles.tsx +++ b/src/core/components/Uploaders/Image/styles.tsx @@ -8,7 +8,9 @@ import Skeleton from '~/core/components/Skeleton'; import RemoveIcon from '~/icons/Remove'; import ExclamationCircle from '~/icons/ExclamationCircle'; -export const ImageContainer = styled.div<{ border?: boolean }>` +export const ImageContainer = styled.div.withConfig({ + shouldForwardProp: (prop) => prop !== 'border', +})<{ border?: boolean }>` position: relative; display: inline-block; min-width: 2em; @@ -38,9 +40,13 @@ const ImgPreviewContainerStyles = css<{ mediaFit?: string; loading?: string }>` object-position: center; `; -export const ImgPreview = styled.img.attrs<{ mediaFit?: string; loading?: string }>({ - loading: 'lazy', -})` +export const ImgPreview = styled.img + .withConfig({ + shouldForwardProp: (prop) => prop !== 'mediaFit', + }) + .attrs<{ mediaFit?: string; loading?: string }>({ + loading: 'lazy', + })` ${ImgPreviewContainerStyles} `; diff --git a/src/core/components/Uploaders/Video/styles.tsx b/src/core/components/Uploaders/Video/styles.tsx index 020702fd5..22f562c9a 100644 --- a/src/core/components/Uploaders/Video/styles.tsx +++ b/src/core/components/Uploaders/Video/styles.tsx @@ -8,7 +8,9 @@ import LiveBadge from '~/social/components/LiveBadge'; import { ExclamationCircle, Play, Remove } from '~/icons'; -export const VideoContainer = styled.div<{ border?: boolean }>` +export const VideoContainer = styled.div.withConfig({ + shouldForwardProp: (prop) => prop !== 'border', +})<{ border?: boolean }>` position: relative; display: inline-block; min-width: 2em; diff --git a/src/social/components/CommunityInfo/styles.tsx b/src/social/components/CommunityInfo/styles.tsx index 5f3ab2dcb..6af0190b9 100644 --- a/src/social/components/CommunityInfo/styles.tsx +++ b/src/social/components/CommunityInfo/styles.tsx @@ -32,7 +32,9 @@ export const Container = styled.div` margin-bottom: 12px; `; -export const Cover = styled.div<{ backgroundImage?: string }>` +export const Cover = styled.div.withConfig({ + shouldForwardProp: (prop) => prop !== 'backgroundImage', +})<{ backgroundImage?: string }>` padding-top: 56.25%; position: relative; diff --git a/src/social/components/SocialSearch/styles.tsx b/src/social/components/SocialSearch/styles.tsx index 78c5c7586..989ffbaac 100644 --- a/src/social/components/SocialSearch/styles.tsx +++ b/src/social/components/SocialSearch/styles.tsx @@ -13,7 +13,9 @@ export const SearchIcon = styled(Search).attrs({ width: 16, height: 16 })` fill: ${({ theme }) => theme.palette.base.shade2}; `; -export const SocialSearchContainer = styled.div<{ sticky?: boolean }>` +export const SocialSearchContainer = styled.div.withConfig({ + shouldForwardProp: (prop) => prop !== 'sticky', +})<{ sticky?: boolean }>` position: relative; ${({ sticky }) => diff --git a/src/social/components/community/Card/styles.tsx b/src/social/components/community/Card/styles.tsx index a81117cf8..95548d090 100644 --- a/src/social/components/community/Card/styles.tsx +++ b/src/social/components/community/Card/styles.tsx @@ -12,7 +12,9 @@ export const Container = styled.div` overflow: hidden; `; -export const Cover = styled.div<{ backgroundImage?: string }>` +export const Cover = styled.div.withConfig({ + shouldForwardProp: (prop) => prop !== 'backgroundImage', +})<{ backgroundImage?: string }>` padding-top: 74.46%; position: relative; diff --git a/src/social/components/community/CategoryCard/styles.tsx b/src/social/components/community/CategoryCard/styles.tsx index 23ccaee4d..4d2c33d8a 100644 --- a/src/social/components/community/CategoryCard/styles.tsx +++ b/src/social/components/community/CategoryCard/styles.tsx @@ -1,6 +1,8 @@ import styled from 'styled-components'; -export const Container = styled.div<{ backgroundImage?: string }>` +export const Container = styled.div.withConfig({ + shouldForwardProp: (prop) => prop !== 'backgroundImage', +})<{ backgroundImage?: string }>` min-width: 160px; min-height: 150px; cursor: pointer; diff --git a/src/social/components/community/Header/styles.tsx b/src/social/components/community/Header/styles.tsx index 462a70f25..5a23a29ce 100644 --- a/src/social/components/community/Header/styles.tsx +++ b/src/social/components/community/Header/styles.tsx @@ -8,9 +8,9 @@ interface CommunityHeaderContainerProps { isActive?: boolean; } -export const CommunityHeaderContainer = styled.a.attrs( - (props) => props, -)` +export const CommunityHeaderContainer = styled.a.withConfig({ + shouldForwardProp: (prop) => !['loading', 'isActive'].includes(prop), +})` display: grid; grid-template-areas: 'avatar title' 'avatar children'; grid-template-columns: min-content auto; diff --git a/src/social/components/community/Name/styles.tsx b/src/social/components/community/Name/styles.tsx index d60264246..f672ad84d 100644 --- a/src/social/components/community/Name/styles.tsx +++ b/src/social/components/community/Name/styles.tsx @@ -19,7 +19,9 @@ export const Name = styled.div` padding-right: 1ch; `; -export const NameContainer = styled.div<{ +export const NameContainer = styled.div.withConfig({ + shouldForwardProp: (prop) => prop !== 'isActive' && prop !== 'isTitle', +})<{ isActive?: boolean; isTitle?: boolean; }>` diff --git a/src/social/components/community/TrendingItem/UITrendingItem.tsx b/src/social/components/community/TrendingItem/UITrendingItem.tsx index 87691a5f5..e0b43cdbd 100644 --- a/src/social/components/community/TrendingItem/UITrendingItem.tsx +++ b/src/social/components/community/TrendingItem/UITrendingItem.tsx @@ -21,7 +21,9 @@ const ItemContainer = styled.div` overflow: hidden; `; -const Cover = styled.div<{ backgroundImage?: string }>` +const Cover = styled.div.withConfig({ + shouldForwardProp: (prop) => prop !== 'backgroundImage', +})<{ backgroundImage?: string }>` padding-left: 100%; ${({ backgroundImage, theme }) => ` diff --git a/src/social/components/post/ChildrenContent/index.tsx b/src/social/components/post/ChildrenContent/index.tsx index e960f794e..11727ef9c 100644 --- a/src/social/components/post/ChildrenContent/index.tsx +++ b/src/social/components/post/ChildrenContent/index.tsx @@ -49,7 +49,7 @@ const ChildrenContent = ({ contents }: { contents: Amity.Post[] }) => { return ( <> {items.map((poll) => ( - + ))} ); diff --git a/src/social/components/post/GalleryContent/ImageItem.tsx b/src/social/components/post/GalleryContent/ImageItem.tsx index beeb462fc..4a3a82135 100644 --- a/src/social/components/post/GalleryContent/ImageItem.tsx +++ b/src/social/components/post/GalleryContent/ImageItem.tsx @@ -8,6 +8,7 @@ interface ThumbnailProps { export const Thumbnail = ({ item }: ThumbnailProps) => { return ( { return ( ` +export const AdditionalInfo = styled.div.withConfig({ + shouldForwardProp: (prop) => prop !== 'showTime', +})<{ showTime?: boolean }>` display: flex; align-items: center; diff --git a/src/social/pages/NewsFeed/styles.tsx b/src/social/pages/NewsFeed/styles.tsx index df00274b3..db23c6b64 100644 --- a/src/social/pages/NewsFeed/styles.tsx +++ b/src/social/pages/NewsFeed/styles.tsx @@ -32,7 +32,9 @@ export const MobileContainer = styled.div` } `; -export const CommunitySideMenuOverlay = styled.div<{ isOpen: boolean }>` +export const CommunitySideMenuOverlay = styled.div.withConfig({ + shouldForwardProp: (prop) => prop !== 'isOpen', +})<{ isOpen?: boolean }>` position: fixed; top: 0; left: 0; @@ -48,7 +50,9 @@ export const CommunitySideMenuOverlay = styled.div<{ isOpen: boolean }>` cursor: pointer; `; -export const StyledCommunitySideMenu = styled(CommunitySideMenu)<{ isOpen: boolean }>` +export const StyledCommunitySideMenu = styled(CommunitySideMenu).withConfig({ + shouldForwardProp: (prop) => prop !== 'isOpen', +})<{ isOpen?: boolean }>` position: fixed; top: 0; left: 0; diff --git a/src/v4/social/hooks/useVisibilitySensor.tsx b/src/v4/social/hooks/useVisibilitySensor.tsx new file mode 100644 index 000000000..14243139c --- /dev/null +++ b/src/v4/social/hooks/useVisibilitySensor.tsx @@ -0,0 +1,34 @@ +import { RefObject, useEffect, useState } from 'react'; + +interface UseVisibilitySensorProps { + threshold: number; + elementRef: RefObject; +} + +export const useVisibilitySensor = ({ threshold, elementRef }: UseVisibilitySensorProps) => { + const [isVisible, setIsVisible] = useState(false); + + useEffect(() => { + if (!elementRef.current) return; + + const observer = new IntersectionObserver( + (entries) => { + entries.forEach((entry) => { + const isIntersecting = entry.isIntersecting; + setIsVisible(isIntersecting); + }); + }, + { + threshold: threshold, + }, + ); + + observer.observe(elementRef.current); + + return () => { + observer.disconnect(); + }; + }, [threshold, elementRef]); + + return { isVisible }; +};