Skip to content

Commit

Permalink
only make order summary sticky when it's not longer than view (#47680)
Browse files Browse the repository at this point in the history
* 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 <github-actions@github.com>
  • Loading branch information
senadir and github-actions committed May 22, 2024
1 parent 501272c commit 34f8c65
Show file tree
Hide file tree
Showing 8 changed files with 129 additions and 5 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -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 (
<div
Expand Down
1 change: 1 addition & 0 deletions plugins/woocommerce-blocks/assets/js/base/hooks/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,4 @@ export * from './use-typography-props';
export * from './use-is-mounted';
export * from './use-spoken-message';
export * from './use-style-props';
export * from './use-observed-viewport';
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
/**
* External dependencies
*/
import { useState, useRef, useEffect } from '@wordpress/element';

/**
* Returns a ref, its dimensions, and its visible viewport dimensions. Useful to know if an element should be sticky or not. This hook only runs when an element changes its intersection or dimensions.
*
* @example
*
* ```js
* const App = () => {
* const [ observedRef, observedElement, viewWindow ] = useObservedViewport();
*
* return (
* <MyElement ref={ observedRef } className={ observedElement.height < viewWindow.height ? 'is-sticky': '' } />
* );
* };
* ```
*/
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 ];
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,23 @@
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,
}: {
children: JSX.Element;
className?: string;
} ): JSX.Element => {
const [ observedRef, observedElement, viewWindow ] =
useObservedViewport< HTMLDivElement >();
const isSticky = observedElement.height < viewWindow.height;
return (
<Sidebar
className={ classnames( 'wc-block-checkout__sidebar', className ) }
ref={ observedRef }
className={ classnames( 'wc-block-checkout__sidebar', className, {
'is-sticky': isSticky,
} ) }
>
<StoreNoticesContainer
context={ 'woocommerce/checkout-totals-block' }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,10 @@

.is-large {
.wc-block-checkout__sidebar {
position: sticky;
top: $gap-largest;
align-self: flex-start;
top: $gap-large;
&.is-sticky {
position: sticky;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,12 @@
position: relative;
}
}

.is-large {
.wc-block-checkout__sidebar {
top: 0;
}
}
}

body.wc-lock-selected-block--move {
Expand Down
12 changes: 12 additions & 0 deletions plugins/woocommerce-blocks/assets/js/blocks/checkout/test/block.js
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,18 @@ jest.mock( '@wordpress/compose', () => ( {
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' ),
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
Significance: patch
Type: fix
Comment: This is a follow up to another PR not yet shipped.

0 comments on commit 34f8c65

Please sign in to comment.