Skip to content

Commit

Permalink
Merge pull request #2138 from google/enhancement/2021-only-render-wid…
Browse files Browse the repository at this point in the history
…get-area-when-widgets

Enhancement/2021 only render widget area when active widgets exist
  • Loading branch information
felixarntz committed Oct 14, 2020
2 parents 1e5220e + b8738fd commit 099cac9
Show file tree
Hide file tree
Showing 3 changed files with 70 additions and 83 deletions.
106 changes: 55 additions & 51 deletions assets/js/googlesitekit/widgets/components/WidgetAreaRenderer.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,6 @@
import classnames from 'classnames';
import PropTypes from 'prop-types';

/**
* WordPress dependencies
*/
import { useMemo, useState } from '@wordpress/element';

/**
* Internal dependencies
*/
Expand Down Expand Up @@ -102,69 +97,78 @@ const resizeClasses = ( classNames, counter ) => {
return [ classNames, counter ];
};

const WidgetAreaRenderer = ( { slug } ) => {
const widgetArea = useSelect( ( select ) => select( STORE_NAME ).getWidgetArea( slug ) );
const widgets = useSelect( ( select ) => select( STORE_NAME ).getWidgets( slug ) );
const getWidgetClassNames = ( activeWidgets ) => {
let classNames = [].fill( null, 0, activeWidgets.length );
let counter = 0;
activeWidgets.forEach( ( widget, i ) => {
const width = widget.width;

// State handled by WidgetRenderer instances, based on whether the widget
// renders content or `null`.
const [ activeWidgets, setActiveWidgets ] = useState( {} );

const widgetClassNames = useMemo( () => {
let classNames = [].fill( null, 0, widgets.length );
let counter = 0;
widgets.forEach( ( widget, i ) => {
// If this widget is not active (outputs `null`), there's no sense in outputting classes for it.
if ( ! activeWidgets[ widget.slug ] ) {
return;
}
// Increase column counter based on width.
counter += WIDTH_GRID_COUNTER_MAP[ width ];

const width = widget.width;
// If counter is exactly 12, the next widget is going to be in a new row.
if ( counter % 12 === 0 ) {
counter = 0;
}

// Increase column counter based on width.
counter += WIDTH_GRID_COUNTER_MAP[ width ];
// If counter is going above 12, this widget is too wide for the current row.
// So it's going to be the first widget in the next row instead.
if ( counter > 12 ) {
counter -= WIDTH_GRID_COUNTER_MAP[ width ];

// If counter is exactly 12, the next widget is going to be in a new row.
if ( counter % 12 === 0 ) {
counter = 0;
// If the column count without the overflowing widget is exactly 9, expand
// the widths of these widgets slightly to fill the entire 12 columns.
if ( counter === 9 ) {
[ classNames, counter ] = resizeClasses( classNames, counter );
}

// If counter is going above 12, this widget is too wide for the current row.
// So it's going to be the first widget in the next row instead.
if ( counter > 12 ) {
counter -= WIDTH_GRID_COUNTER_MAP[ width ];
// See above, initial counter for the next row of widgets.
counter = WIDTH_GRID_COUNTER_MAP[ width ];
}

// If the column count without the overflowing widget is exactly 9, expand
// the widths of these widgets slightly to fill the entire 12 columns.
if ( counter === 9 ) {
[ classNames, counter ] = resizeClasses( classNames, counter );
}
// Actually set the class for the current widget. This must be set after
// potentially resizing classes, since in that case this will be the overflowing
// widget which should NOT be adjusted because it will be in the next row.
classNames[ i ] = WIDTH_GRID_CLASS_MAP[ width ];
} );

// See above, initial counter for the next row of widgets.
counter = WIDTH_GRID_COUNTER_MAP[ width ];
}
if ( counter === 9 ) {
[ classNames, counter ] = resizeClasses( classNames, counter );
}

// Actually set the class for the current widget. This must be set after
// potentially resizing classes, since in that case this will be the overflowing
// widget which should NOT be adjusted because it will be in the next row.
classNames[ i ] = WIDTH_GRID_CLASS_MAP[ width ];
} );
return classNames;
};

if ( counter === 9 ) {
[ classNames, counter ] = resizeClasses( classNames, counter );
}
const filterActiveWidgets = ( widgets ) => {
return widgets.filter( ( widget ) => {
const widgetExists = widgets.some( ( item ) => item.slug === widget.slug );
const isComponent = typeof widget.component === 'function';
const isActive = widget.component.prototype.render
? new widget.component( {} ).render()
: widget.component( {} );

return widgetExists && isComponent && Boolean( isActive );
} );
};

const WidgetAreaRenderer = ( { slug } ) => {
const widgetArea = useSelect( ( select ) => select( STORE_NAME ).getWidgetArea( slug ) );
const widgets = useSelect( ( select ) => select( STORE_NAME ).getWidgets( slug ) );

const activeWidgets = filterActiveWidgets( widgets );

if ( activeWidgets.length === 0 ) {
return null;
}

return classNames;
}, [ widgets, activeWidgets ] );
const widgetClassNames = getWidgetClassNames( activeWidgets );

const widgetsOutput = widgets.map( ( widget, i ) => {
const widgetsOutput = activeWidgets.map( ( widget, i ) => {
return (
<WidgetRenderer
gridClassName={ widgetClassNames[ i ] !== null ? classnames( widgetClassNames[ i ] ) : 'googlesitekit-widget-area--hidden' }
key={ widget.slug }
slug={ widget.slug }
activeWidgets={ activeWidgets }
setActiveWidgets={ setActiveWidgets }
/>
);
} );
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -274,4 +274,18 @@ describe( 'WidgetAreaRenderer', () => {
expect( container.firstChild.querySelectorAll( '.googlesitekit-widget-area-widgets > .mdc-layout-grid__inner > .mdc-layout-grid__cell.mdc-layout-grid__cell--span-12 > .mdc-layout-grid > .mdc-layout-grid__inner' ) ).toHaveLength( 1 );
} );
} );

it( 'should not render widget area with no active widgets', async () => {
createWidgets( registry, areaName, [
{ component: WidgetComponentEmpty, slug: 'empty', width: WIDGET_WIDTHS.HALF },
] );

const widgets = registry.select( STORE_NAME ).getWidgets( areaName );
const { container } = render( <WidgetAreaRenderer slug={ areaName } />, { registry } );

await waitFor( () => {
expect( widgets ).toHaveLength( 1 );
expect( container.querySelectorAll( '.googlesitekit-widget-area' ) ).toHaveLength( 0 );
} );
} );
} );
33 changes: 1 addition & 32 deletions assets/js/googlesitekit/widgets/components/WidgetRenderer.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,40 +30,16 @@ import Widget from './Widget';

const { useSelect } = Data;

const WidgetRenderer = ( { slug, gridClassName, activeWidgets, setActiveWidgets } ) => {
const WidgetRenderer = ( { slug, gridClassName } ) => {
const widget = useSelect( ( select ) => select( STORE_NAME ).getWidget( slug ) );

if ( ! widget ) {
if ( activeWidgets[ slug ] ) {
setActiveWidgets( {
...activeWidgets,
[ slug ]: false,
} );
}
return null;
}

// Capitalize the "component" variable, as it is required by JSX.
const { component: Component, wrapWidget } = widget;

// Check if widget component will render `null` by calling it directly.
if ( typeof Component === 'function' && ! Component( {} ) ) {
if ( activeWidgets[ slug ] ) {
setActiveWidgets( {
...activeWidgets,
[ slug ]: false,
} );
}
return null;
}

if ( ! activeWidgets[ slug ] ) {
setActiveWidgets( {
...activeWidgets,
[ slug ]: true,
} );
}

let widgetComponent = <Component />;

if ( wrapWidget ) {
Expand All @@ -84,13 +60,6 @@ const WidgetRenderer = ( { slug, gridClassName, activeWidgets, setActiveWidgets
WidgetRenderer.propTypes = {
slug: PropTypes.string.isRequired,
gridClassName: PropTypes.string,
activeWidgets: PropTypes.object,
setActiveWidgets: PropTypes.func,
};

WidgetRenderer.defaultProps = {
activeWidgets: {},
setActiveWidgets: () => {},
};

export default WidgetRenderer;

0 comments on commit 099cac9

Please sign in to comment.