From 34f8c65f532b5798be9a3548ae2534ead3da9f77 Mon Sep 17 00:00:00 2001 From: Seghir Nadir Date: Thu, 23 May 2024 00:09:50 +0200 Subject: [PATCH] only make order summary sticky when it's not longer than view (#47680) * only sticky summary when it's not longer than view * Add changefile(s) from automation for the following project(s): woocommerce-blocks * fix tests * correctly check for height * switch how to get top * remove from editor --------- Co-authored-by: github-actions --- .../components/sidebar-layout/sidebar.tsx | 2 +- .../assets/js/base/hooks/index.js | 1 + .../js/base/hooks/use-observed-viewport.ts | 93 +++++++++++++++++++ .../checkout-totals-block/frontend.tsx | 10 +- .../checkout-totals-block/style.scss | 6 +- .../js/blocks/checkout/styles/editor.scss | 6 ++ .../assets/js/blocks/checkout/test/block.js | 12 +++ ...only-sticky-summary-if-smaller-than-screen | 4 + 8 files changed, 129 insertions(+), 5 deletions(-) create mode 100644 plugins/woocommerce-blocks/assets/js/base/hooks/use-observed-viewport.ts create mode 100644 plugins/woocommerce/changelog/47680-fix-only-sticky-summary-if-smaller-than-screen diff --git a/plugins/woocommerce-blocks/assets/js/base/components/sidebar-layout/sidebar.tsx b/plugins/woocommerce-blocks/assets/js/base/components/sidebar-layout/sidebar.tsx index 891cbe698cd8..1d4bcb5c9bb0 100644 --- a/plugins/woocommerce-blocks/assets/js/base/components/sidebar-layout/sidebar.tsx +++ b/plugins/woocommerce-blocks/assets/js/base/components/sidebar-layout/sidebar.tsx @@ -9,7 +9,7 @@ import classNames from 'classnames'; */ import { ForwardRefProps } from './types'; -const Sidebar = forwardRef< HTMLInputElement, ForwardRefProps >( +const Sidebar = forwardRef< HTMLDivElement, ForwardRefProps >( ( { children, className = '' }, ref ): JSX.Element => { return (
{ + * const [ observedRef, observedElement, viewWindow ] = useObservedViewport(); + * + * return ( + * + * ); + * }; + * ``` + */ +export function useObservedViewport< T extends HTMLElement >(): [ + React.Ref< T >, + { height: number; width: number }, + { height: number; width: number } +] { + const [ observedElement, setObservedElement ] = useState( { + height: 0, + width: 0, + } ); + + const [ viewWindow, setViewWindow ] = useState( { + height: 0, + width: 0, + } ); + + const observedRef = useRef< T >( null ); + + useEffect( () => { + if ( ! observedRef.current ) { + return; + } + const element = observedRef.current; + const resizeObserver = new ResizeObserver( ( entries ) => { + entries.forEach( ( entry ) => { + if ( entry.target === element ) { + const { height, width } = entry.contentRect; + const elementTop = + element.computedStyleMap().get( 'top' )?.toString() || + '0'; + setObservedElement( { + height: height + parseInt( elementTop, 10 ), + width, + } ); + } + } ); + } ); + + const intersectionObserver = new IntersectionObserver( + ( entries ) => { + entries.forEach( ( entry ) => { + const { height, width } = entry.boundingClientRect; + setObservedElement( { height, width } ); + if ( entry.target.ownerDocument.defaultView ) { + setViewWindow( { + height: entry.target.ownerDocument.defaultView + ?.innerHeight, + width: entry.target.ownerDocument.defaultView + ?.innerWidth, + } ); + } + } ); + }, + { + root: null, + rootMargin: '0px', + threshold: 1, + } + ); + + resizeObserver.observe( element ); + intersectionObserver.observe( element ); + + return () => { + if ( ! element ) { + return; + } + + resizeObserver.unobserve( element ); + intersectionObserver.unobserve( element ); + }; + }, [] ); + return [ observedRef, observedElement, viewWindow ]; +} diff --git a/plugins/woocommerce-blocks/assets/js/blocks/checkout/inner-blocks/checkout-totals-block/frontend.tsx b/plugins/woocommerce-blocks/assets/js/blocks/checkout/inner-blocks/checkout-totals-block/frontend.tsx index 726204c6cb75..045b87d429c6 100644 --- a/plugins/woocommerce-blocks/assets/js/blocks/checkout/inner-blocks/checkout-totals-block/frontend.tsx +++ b/plugins/woocommerce-blocks/assets/js/blocks/checkout/inner-blocks/checkout-totals-block/frontend.tsx @@ -4,7 +4,7 @@ import classnames from 'classnames'; import { Sidebar } from '@woocommerce/base-components/sidebar-layout'; import { StoreNoticesContainer } from '@woocommerce/blocks-components'; - +import { useObservedViewport } from '@woocommerce/base-hooks'; const FrontendBlock = ( { children, className, @@ -12,9 +12,15 @@ const FrontendBlock = ( { children: JSX.Element; className?: string; } ): JSX.Element => { + const [ observedRef, observedElement, viewWindow ] = + useObservedViewport< HTMLDivElement >(); + const isSticky = observedElement.height < viewWindow.height; return ( ( { useResizeObserver: jest.fn().mockReturnValue( [ null, { width: 0 } ] ), } ) ); +global.ResizeObserver = jest.fn().mockImplementation( () => ( { + observe: jest.fn(), + unobserve: jest.fn(), + disconnect: jest.fn(), +} ) ); + +global.IntersectionObserver = jest.fn().mockImplementation( () => ( { + observe: jest.fn(), + unobserve: jest.fn(), + disconnect: jest.fn(), +} ) ); + jest.mock( '@wordpress/element', () => { return { ...jest.requireActual( '@wordpress/element' ), diff --git a/plugins/woocommerce/changelog/47680-fix-only-sticky-summary-if-smaller-than-screen b/plugins/woocommerce/changelog/47680-fix-only-sticky-summary-if-smaller-than-screen new file mode 100644 index 000000000000..0d2c9ff5f595 --- /dev/null +++ b/plugins/woocommerce/changelog/47680-fix-only-sticky-summary-if-smaller-than-screen @@ -0,0 +1,4 @@ +Significance: patch +Type: fix +Comment: This is a follow up to another PR not yet shipped. +