From 48b7b9839b966073feed265d6bd442a5febc49d8 Mon Sep 17 00:00:00 2001 From: shivshankar-pindoriya_groww Date: Thu, 26 Dec 2024 15:36:47 +0530 Subject: [PATCH 1/3] fix clear all buttoon background color issue in dark mode --- .../src/components/atoms/Toaster/Toast.tsx | 44 ++++----- .../src/components/atoms/Toaster/Toaster.tsx | 95 +++++++++---------- .../src/components/atoms/Toaster/styles.css | 2 +- 3 files changed, 65 insertions(+), 76 deletions(-) diff --git a/packages/ui-toolkit/src/components/atoms/Toaster/Toast.tsx b/packages/ui-toolkit/src/components/atoms/Toaster/Toast.tsx index f85d18c6..114d150b 100644 --- a/packages/ui-toolkit/src/components/atoms/Toaster/Toast.tsx +++ b/packages/ui-toolkit/src/components/atoms/Toaster/Toast.tsx @@ -5,7 +5,6 @@ import React, { useEffect, useLayoutEffect, useCallback, - isValidElement, CSSProperties } from 'react'; @@ -17,14 +16,10 @@ import { HeightT, ToastProps } from './types'; import './styles.css'; -// Default lifetime of a toasts (in ms) -const TOAST_LIFETIME = 5000; -// Equal to exit animation duration -const TIME_BEFORE_UNMOUNT = 50; - -// Default gap between toasts -const GAP = 14; +const TOAST_LIFETIME = 5000; // Default lifetime of a toasts (in ms) +const TIME_BEFORE_UNMOUNT = 50; // Equal to exit animation duration +const GAP = 14; // Default gap between toasts const Toast = (props: ToastProps) => { @@ -47,22 +42,27 @@ const Toast = (props: ToastProps) => { const [ removed, setRemoved ] = useState(false); const [ offsetBeforeRemove, setOffsetBeforeRemove ] = useState(0); const [ initialHeight, setInitialHeight ] = useState(0); + const toastRef = useRef(null); + const closeTimerStartTimeRef = useRef(0); + const lastCloseTimerStartTimeRef = useRef(0); + const offset = useRef(0); + const isFront = index === 0; const isVisible = index + 1 <= visibleToasts; const toastType = toast.type || 'default'; const dismissible = toast.dismissible !== false; + const showCloseButton = toast.closeButton ?? true; // Default to true + const duration = toast.duration || TOAST_LIFETIME; + const [ y, x ] = position.split('-'); + const isDocumentHidden = useIsDocumentHidden(); + // Height index is used to calculate the offset as it gets updated before the toast array, which means we can calculate the new layout faster. const heightIndex = useMemo( () => heights.findIndex((height) => height.toastId === toast.id) || 0, [ heights, toast.id ] ); - const showCloseButton = toast.closeButton ?? true; // Default to true - const duration = toast.duration || TOAST_LIFETIME; - const closeTimerStartTimeRef = useRef(0); - const offset = useRef(0); - const lastCloseTimerStartTimeRef = useRef(0); - const [ y, x ] = position.split('-'); + const toastsHeightBefore = useMemo(() => { return heights.reduce((prev, curr, reducerIndex) => { // Calculate offset up until current toast @@ -73,14 +73,12 @@ const Toast = (props: ToastProps) => { return prev + curr.height; }, 0); }, [ heights, heightIndex ]); - const isDocumentHidden = useIsDocumentHidden(); offset.current = useMemo(() => heightIndex * gap + toastsHeightBefore, [ heightIndex, toastsHeightBefore ]); useEffect(() => { - // Trigger enter animation without using CSS animation - setMounted(true); + setMounted(true); // Trigger enter animation without using CSS animation }, []); @@ -207,7 +205,7 @@ const Toast = (props: ToastProps) => { tabIndex={0} ref={toastRef} className='borderPrimary backgroundPrimary' - data-sonner-toast="" + data-sonner-toast data-styled={!Boolean(toast.jsx)} data-mounted={mounted} data-removed={removed} @@ -249,9 +247,7 @@ const Toast = (props: ToastProps) => { ) : null } { - toast.jsx || isValidElement(toast.title) ? ( - toast.jsx || toast.title - ) : ( + toast.jsx || ( <> { toastType ? ( @@ -264,11 +260,9 @@ const Toast = (props: ToastProps) => { ) : null } -
+
{toast.title ?
{toast.title}
: null} - { - toast.description ?
{toast.description}
: null - } + {toast.description ?
{toast.description}
: null}
) diff --git a/packages/ui-toolkit/src/components/atoms/Toaster/Toaster.tsx b/packages/ui-toolkit/src/components/atoms/Toaster/Toaster.tsx index e33700e7..bd8120c3 100644 --- a/packages/ui-toolkit/src/components/atoms/Toaster/Toaster.tsx +++ b/packages/ui-toolkit/src/components/atoms/Toaster/Toaster.tsx @@ -4,7 +4,8 @@ import React, { useRef, useCallback, useEffect, - CSSProperties + CSSProperties, + Fragment } from 'react'; import ReactDOM from 'react-dom'; @@ -20,17 +21,10 @@ import { import './styles.css'; -// Visible no of toasts at a time in the viewport -const VISIBLE_TOASTS_AMOUNT = 251; - -// Viewport padding -const VIEWPORT_OFFSET = '28px'; - -// Default toast width -const TOAST_WIDTH = 356; - -// Default gap between toasts -const GAP = 14; +const VISIBLE_TOASTS_AMOUNT = 251; // Visible no of toasts at a time in the viewport +const VIEWPORT_OFFSET = '28px'; // Viewport padding +const TOAST_WIDTH = 356; // Default toast width +const GAP = 14; // Default gap between toasts const Toaster = (props: ToasterProps) => { @@ -44,14 +38,8 @@ const Toaster = (props: ToasterProps) => { containerAriaLabel = 'Notifications', pauseWhenPageIsHidden = true } = props; - const [ toasts, setToasts ] = useState([]); - - const possiblePositions: Position[] = useMemo(() => { - const allToastPositions = toasts.filter(toast => toast.position !== undefined).map(toast => toast.position as Position); - - return Array.from(new Set([ ...allToastPositions ])); - }, [ toasts, position ]); + const [ toasts, setToasts ] = useState([]); const [ heights, setHeights ] = useState([]); const [ expanded, setExpanded ] = useState(false); const [ interacting, setInteracting ] = useState(false); @@ -59,6 +47,12 @@ const Toaster = (props: ToasterProps) => { const listRef = useRef(null); const hotkeyLabel = hotkey.join('+').replace(/Key/g, '').replace(/Digit/g, ''); + const possiblePositions: Position[] = useMemo(() => { + const allToastPositions = toasts.filter(toast => toast.position !== undefined).map(toast => toast.position as Position); + + return Array.from(new Set([ ...allToastPositions ])); + }, [ toasts, position ]); + const removeToast = useCallback((toastToRemove: ToastT) => { setToasts((toasts: ToastT[]) => { @@ -103,14 +97,13 @@ const Toaster = (props: ToasterProps) => { useEffect(() => { // Ensure expanded is always false when no toasts are present / only one left - if (toasts.length <= 1) { - setExpanded(false); - } + if (toasts.length <= 1) setExpanded(false); }, [ toasts ]); + useEffect(() => { const handleKeyDown = (event: KeyboardEvent) => { - const isHotkeyPressed = hotkey.every((key) => (event as any)[key] || event.code === key); + const isHotkeyPressed = hotkey.every((key) => event[key as keyof KeyboardEvent] || event.code === key); if (isHotkeyPressed) { setExpanded(true); @@ -130,17 +123,25 @@ const Toaster = (props: ToasterProps) => { return () => document.removeEventListener('keydown', handleKeyDown); }, [ hotkey ]); - if (!toasts.length) return null; + const calculateTopRightToastsHeight = useCallback(() => { + const topRightToastsHeightArray = heights.filter(toast => toast.position === 'top-right'); + //sum of all toast height with position top right + let topRightToastsHeight = topRightToastsHeightArray.reduce((sum, t) => sum + t.height, 0); - const topRightToastsHeightArray = Array.isArray(heights) ? heights.filter(toast => toast.position === 'top-right') : []; + topRightToastsHeight = topRightToastsHeight + (topRightToastsHeightArray.length - 1) * gap; + topRightToastsHeight = typeof topRightToastsHeight === 'number' ? Math.ceil(topRightToastsHeight) : topRightToastsHeight; - //sum of all toast height with position top right + gap - let sumOfTopRightToastsHeight = topRightToastsHeightArray.reduce((a, b) => { return a + b.height; }, 0); + return topRightToastsHeight; + }, [ heights, gap ]); - sumOfTopRightToastsHeight = sumOfTopRightToastsHeight + (topRightToastsHeightArray.length - 1) * gap; - sumOfTopRightToastsHeight = typeof sumOfTopRightToastsHeight === 'number' ? Math.ceil(sumOfTopRightToastsHeight) : sumOfTopRightToastsHeight; - const expandedViewStyle: CSSProperties = expanded ? { height: `${sumOfTopRightToastsHeight}px`, overflow: 'scroll', backdropFilter: 'blur(4px)' } : {}; + const expandedViewStyle: CSSProperties = expanded + ? { + height: `${calculateTopRightToastsHeight()}px`, + overflow: 'scroll', + backdropFilter: 'blur(4px)' + } + : {}; const removeAllToasts = () => { @@ -148,21 +149,21 @@ const Toaster = (props: ToasterProps) => { }; - const clearAllButtonUI = (yPosition: string, xPosition: string) => { - //close button handle only for top-right position + const clearAllButtonUI = (position: string) => { + //close all toast button is handled only for top-right position const topRightToastsArray = toasts.filter(toast => toast.position === 'top-right'); - if (yPosition !== 'top' || xPosition !== 'right' || topRightToastsArray.length <= 1) return null; + if (position !== 'top-right' || topRightToastsArray.length <= 1) return null; + const [ y, x ] = position.split('-'); return (
setExpanded(true)} - onMouseMove={() => setExpanded(true)} onMouseLeave={() => setExpanded(false)} style={ { @@ -171,11 +172,14 @@ const Toaster = (props: ToasterProps) => { zIndex: 99999999 } as CSSProperties } - >Clear all + > + Clear all
); }; + if (!toasts.length) return null; + return ( // Remove item from normal navigation flow, only available via hotkey
{ const [ y, x ] = position.split('-'); return ( - <> - {clearAllButtonUI(y, x)} + + {clearAllButtonUI(position)}
    { } as CSSProperties } onMouseEnter={() => setExpanded(true)} - onMouseMove={() => setExpanded(true)} - onMouseLeave={ - () => { - // Avoid setting expanded to false when interacting with a toast, e.g. swiping - if (!interacting) { - setExpanded(false); - } - } - } + onMouseLeave={() => !interacting && setExpanded(false)} onPointerDown={ (event) => { const isNotDismissible = @@ -251,7 +246,7 @@ const Toaster = (props: ToasterProps) => { )) }
- +
); }) } diff --git a/packages/ui-toolkit/src/components/atoms/Toaster/styles.css b/packages/ui-toolkit/src/components/atoms/Toaster/styles.css index a256a1b4..43290b36 100644 --- a/packages/ui-toolkit/src/components/atoms/Toaster/styles.css +++ b/packages/ui-toolkit/src/components/atoms/Toaster/styles.css @@ -113,7 +113,7 @@ :where([data-toaster-clear-all]):hover { color: var(--content-primary); - background: var(--background-always-light); + background: var(--background-primary); } :where([data-sonner-toast]) :where([data-close-button]) { From 19ffe5849f8c69f5d720d5b08841f3049941c69c Mon Sep 17 00:00:00 2001 From: shivshankar-pindoriya_groww Date: Fri, 27 Dec 2024 11:21:12 +0530 Subject: [PATCH 2/3] update package version --- packages/ui-toolkit/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/ui-toolkit/package.json b/packages/ui-toolkit/package.json index 407ba01c..ffbd9845 100644 --- a/packages/ui-toolkit/package.json +++ b/packages/ui-toolkit/package.json @@ -1,6 +1,6 @@ { "name": "@groww-tech/ui-toolkit", - "version": "0.7.9-alpha.3", + "version": "0.7.9-alpha.4", "description": "A lightning nature UI", "main": "dist/cjs/index.js", "module": "dist/esm/index.js", From 1c7db4c3816898e52b205b6807ef487e1e5b444f Mon Sep 17 00:00:00 2001 From: Akshay Naik <113993180+AkshayNaikGroww@users.noreply.github.com> Date: Fri, 27 Dec 2024 11:28:32 +0530 Subject: [PATCH 3/3] Update package.json --- packages/ui-toolkit/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/ui-toolkit/package.json b/packages/ui-toolkit/package.json index ffbd9845..2f2c23c7 100644 --- a/packages/ui-toolkit/package.json +++ b/packages/ui-toolkit/package.json @@ -1,6 +1,6 @@ { "name": "@groww-tech/ui-toolkit", - "version": "0.7.9-alpha.4", + "version": "0.7.9-beta", "description": "A lightning nature UI", "main": "dist/cjs/index.js", "module": "dist/esm/index.js",