Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Autoscaling/sizing Block previews #16113

Closed
wants to merge 27 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
a4c2f85
First stab at a proof of concept.
Jun 12, 2019
a379c0f
Attempt to programmatically determine dest dimensions
getdave Jun 24, 2019
20d479e
Add README stub.
jasmussen Jun 27, 2019
5186e2c
Updates to use default args for width and height
getdave Jul 23, 2019
d4b7d95
Update class namespaces to match package
getdave Jul 23, 2019
480e1d8
Add width and height as Effect Hook deps
getdave Jul 23, 2019
4e45237
Use correct `createRef` from @wordpress/element
getdave Jul 23, 2019
96aa785
Revert "Update class namespaces to match package"
getdave Jul 23, 2019
fa2573e
Migrate to useRef hook
getdave Jul 23, 2019
84ad7b0
Adds basic unit test
getdave Jul 23, 2019
5511495
Updates and fleshes out the README
getdave Jul 23, 2019
f9bdb50
Refactor to avoid unecessary state and simplify implementation of sca…
getdave Jul 31, 2019
7cb2283
Add some padding to the preview
getdave Jul 31, 2019
de50bfe
Refactor to utilise JS template strings
getdave Jul 31, 2019
0ffb3e7
WIP: Adds zoom for small individual blocks
getdave Jul 31, 2019
69b6a68
Updates to target block contents more reliably and to calc entire box…
getdave Jul 31, 2019
f789d27
block-preview: render scaled preview in a shadow dom
retrofox Jul 31, 2019
944d023
try: setting styles to shadow dom elements
retrofox Jul 31, 2019
7fde7da
Revert "try: setting styles to shadow dom elements"
getdave Aug 1, 2019
5bceef3
Removes attempt at auto zoom on Block contents
getdave Aug 1, 2019
1f79935
Updates to remove scale by default in favour of opt in via prop
getdave Aug 1, 2019
1bec746
Adds scaleFactor prop to provide control for non dynamically scaled p…
getdave Aug 1, 2019
bdf16ad
Adjust scaleFactor for Block Styles preview
getdave Aug 1, 2019
c5ba882
Fix to ensure hooks are called unconditionally to obey rules of Hooks
getdave Aug 1, 2019
a73b145
Removes padding and border from preview on designer advice
getdave Aug 1, 2019
320002d
Only apply dimensions to preview content when dynamically scaling
getdave Aug 1, 2019
0dedae9
update doc
retrofox Aug 1, 2019
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
55 changes: 55 additions & 0 deletions packages/block-editor/src/components/block-preview/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
BlockPreview
============

BlockPreview allows you to preview any arbitrary HTML and CSS content, with a perfectly scaled thumbnail.

## Usage

Render the component passing in the required props:

```jsx
<BlockPreviewContent
blocks={ blocks }
srcWidth={ 400 }
srcHeight={ 300 }

/>
```

## A note on source dimensions

Please note that `srcWidth` and `srcHeight` refer to the _unscaled dimensions_ of what you mean to preview.

Think of the preview as a big source image, say 800x600 that's scaled down. So if the HTML you mean to preview looks good at 800x600, those are your source dimensionss.

A calculated `transform: scale( ... )` value will be assigned to the thumbnail, so that it fits your _destination_ dimensions, which you set in CSS.


## Props

### `blocks`
* **Type:** `array|object`
* **Default:** `undefined`

A block instance (object) or a blocks array you would like to render a preview.

### `srcWidth`
* **Type:** `Integer`
* **Default:** `400`

The unscaled dimension of the Block you are looking to preview. For example, if the Block looks good at `700x450` then you should set this value to `750`. See also `A note on source dimensions` above.

### `srcHeight`
* **Type:** `Integer`
* **Default:** `300`

The unscaled dimension of the Block you are looking to preview. For example, if the Block looks good at `700x450` then you should set this value to `450`. See also `A note on source dimensions` above.

### `scaleFactor`
* **Type**: `number`
* **Default**: `0.9`

### `scaleToFit`
* **Type**: `bool`
* **Default**: `false`

72 changes: 62 additions & 10 deletions packages/block-editor/src/components/block-preview/index.js
Original file line number Diff line number Diff line change
@@ -1,14 +1,17 @@
/**
* External dependencies
*/

import { castArray } from 'lodash';
import classnames from 'classnames';

/**
* WordPress dependencies
*/
import { __ } from '@wordpress/i18n';
import { Disabled } from '@wordpress/components';
import { withSelect } from '@wordpress/data';
import { useLayoutEffect, useState, useRef } from '@wordpress/element';

/**
* Internal dependencies
Expand All @@ -27,25 +30,74 @@ function BlockPreview( props ) {
return (
<div className="editor-block-preview block-editor-block-preview">
<div className="editor-block-preview__title block-editor-block-preview__title">{ __( 'Preview' ) }</div>
<BlockPreviewContent { ...props } />
<BlockPreviewContent { ...props } srcWidth={ 560 } srcHeight={ 700 } scaleToFit={ true } />
</div>
);
}

export function BlockPreviewContent( { blocks, settings } ) {
export function BlockPreviewContent( { blocks, settings, srcWidth = 400, srcHeight = 300, scaleFactor = 0.9, scaleToFit = false } ) {
// Used to dynamically retrieve the width of the element
// which wraps the preview
const previewRef = useRef( null );

const [ previewScale, setPreviewScale ] = useState( scaleFactor );

// Dynamically calculate the scale factor
useLayoutEffect( () => {
if ( ! scaleToFit ) {
return;
}
// Retrieve the actual width of the element which wraps the preview
// note: this is not the preview itself, but the wrapper element
const destWidth = previewRef.current.offsetWidth;

// Calculate the scale factor necessary to size down the preview thumbnail
// so that it fits within the preview wrapper element
const scale = Math.min( destWidth / srcWidth ) || 1;

setPreviewScale( scale );
}, [ srcWidth, srcHeight ] );

if ( ! blocks ) {
return null;
}

// We use a top-padding to create a responsively sized element with the same aspect ratio as the preview.
// The preview is then absolutely positioned on top of this, creating a visual unit.
const aspectPadding = {
paddingTop: Math.round( srcHeight / srcWidth * 100 ) + '%',
};

let previewStyles = {
transform: `scale(${ previewScale })`,
};

if ( scaleToFit ) {
// Set the predefined optimal width/height for displaying the preview
// and scale down to fit within the preview wrapper
previewStyles = {
...previewStyles,
width: `${ srcWidth }px`,
height: `${ srcHeight }px`,
};
}

const contentClassNames = classnames( 'editor-block-preview__content block-editor-block-preview__content editor-styles-wrapper', {
'is-scaled': previewScale !== 1,
'is-dynamically-scaled': scaleToFit && previewScale !== scaleFactor,
} );

return (
<Disabled className="editor-block-preview__content block-editor-block-preview__content editor-styles-wrapper" aria-hidden>
<BlockEditorProvider
value={ castArray( blocks ) }
settings={ settings }
>
<BlockList />
</BlockEditorProvider>
</Disabled>
<div ref={ previewRef } style={ aspectPadding } className="editor-block-preview__container" aria-hidden>
<Disabled style={ previewStyles } className={ contentClassNames }>
<BlockEditorProvider
value={ castArray( blocks ) }
settings={ settings }
>
<BlockList />
</BlockEditorProvider>
</Disabled>
</div>
);
}

Expand Down
59 changes: 43 additions & 16 deletions packages/block-editor/src/components/block-preview/style.scss
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
// This is the preview that shows up to the right of the thumbnail when hovering.
.block-editor-block-preview {
pointer-events: none;
padding: 10px;
Expand All @@ -9,38 +10,64 @@
}

.block-editor-block-preview__content {
padding: $block-padding;
border: $border-width solid $light-gray-500;
font-family: $editor-font;

> div {
transform: scale(0.9);
transform-origin: center top;
font-family: $editor-font;
}
}

> div section {
height: auto;
}

> .reusable-block-indicator {
display: none;
}
.block-editor-block-preview__title {
margin-bottom: 10px;
color: $dark-gray-300;
}
}

// These rules ensure the preview scales smoothly regardless of the container size.
.editor-block-preview__container {
// In the component, a top padding is provided as an inline style to provid an aspect-ratio.
// This positioning enables the content to sit on top of that padding to fit.
position: relative;

// The preview component measures the pixel width of this item, so as to calculate the scale factor.
// But without this baseline width, it collapses to 0.
width: 100%;

// This ensures that content evne if it overlaps the preview container is properly clipped.
// This is mostly for previews that include arbitrary content.
overflow: hidden;
}

.block-editor-block-preview__content {
// Resetting the block editor paddings and margins
// This element receives inline styles for width, height, and transform-scale.
// Those inline styles are calculated to fit a perfect thumbnail.

// Position above the padding.
position: absolute;
top: 0;
left: 0;

// Important to set the origin.
transform-origin: top left;

// Resetting paddings, margins, and other.
text-align: initial;
margin: 0;
padding: $block-padding;
overflow: visible;
min-height: auto;

.block-editor-block-list__layout,
.block-editor-block-list__block {
padding: 0;
}

.editor-block-list__block-edit [data-block] {
margin-top: 0;
}
}

.block-editor-block-preview__title {
margin-bottom: 10px;
color: $dark-gray-300;
.reusable-block-indicator,
.block-list-appender {
display: none;
}
}
38 changes: 38 additions & 0 deletions packages/block-editor/src/components/block-preview/test/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
/**
* External dependencies
*/
import { shallow } from 'enzyme';

/**
* WordPress dependencies
*/
import { registerCoreBlocks } from '@wordpress/block-library';

/**
* Internal dependencies
*/
import { BlockPreviewContent } from '../index';

describe( 'BlockPreviewContent', () => {
beforeAll( () => {
registerCoreBlocks();
} );

it( 'renders a preview with suitable default dimensions', () => {
const wrapper = shallow( <BlockPreviewContent
name="core/paragraph"
/> );

wrapper.update();

const previewAspectRatioStyle = wrapper.find( '.editor-block-preview__container' ).first().prop( 'style' );
const previewTransform = wrapper.find( '.editor-block-preview__content' ).first().prop( 'style' ).transform;
const previewScale = parseInt( previewTransform.match( /\d/ )[ 0 ], 10 );

expect( previewScale ).toEqual( 1 );

expect( previewAspectRatioStyle ).toEqual( {
paddingTop: '75%',
} );
} );
} );
4 changes: 4 additions & 0 deletions packages/block-editor/src/components/block-styles/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,10 @@ function BlockStyles( {
blocks={ cloneBlock( block, {
className: styleClassName,
} ) }
srcWidth={ 400 }
srcHeight={ 300 }
scaleFactor={ 0.6 }

/>
</div>
<div className="editor-block-styles__item-label block-editor-block-styles__item-label">
Expand Down
20 changes: 3 additions & 17 deletions packages/block-editor/src/components/block-styles/style.scss
Original file line number Diff line number Diff line change
Expand Up @@ -30,29 +30,15 @@
}
}

// Show a little preview thumbnail for style variations.
.block-editor-block-styles__item-preview {
outline: $border-width solid transparent; // Shown in Windows High Contrast mode.
border: 1px solid rgba($dark-gray-900, 0.2);
overflow: hidden;
padding: 0;
text-align: initial;
border: $border-width solid rgba($dark-gray-900, 0.2);
border-radius: $radius-round-rectangle;
display: flex;
height: 60px;
overflow: hidden;
background: $white;

// Actual preview contents.
.block-editor-block-preview__content {
transform: scale(0.7);
transform-origin: center center;
width: 100%;

// Unset some of the styles that might be inherited from the editor style.
margin: 0;
padding: 0;
overflow: visible;
min-height: auto;
}
}

.block-editor-block-styles__item-label {
Expand Down