Skip to content

Commit

Permalink
prep build 08/07
Browse files Browse the repository at this point in the history
  • Loading branch information
bph committed Aug 7, 2023
2 parents e5bc32e + 51e30ad commit baa2f87
Show file tree
Hide file tree
Showing 19 changed files with 468 additions and 99 deletions.
5 changes: 5 additions & 0 deletions docs/explanations/faq.md
Original file line number Diff line number Diff line change
Expand Up @@ -219,6 +219,11 @@ This is the canonical list of keyboard shortcuts:
<td><kbd>Esc</kbd></td>
<td><kbd>Esc</kbd></td>
</tr>
<tr>
<td>Select text across multiple blocks.</td>
<td></td>
<td><kbd>Shift</kbd>+<kbd>Arrow (⇦, ⇧, ⇨, ⇩)</kbd></td>
</tr>
</tbody>
</table>

Expand Down
10 changes: 10 additions & 0 deletions packages/block-editor/src/components/keyboard-shortcuts/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,16 @@ function KeyboardShortcutsRegister() {
},
} );

registerShortcut( {
name: 'core/block-editor/multi-text-selection',
category: 'selection',
description: __( 'Select text across multiple blocks.' ),
keyCombination: {
modifier: 'shift',
character: 'arrow',
},
} );

registerShortcut( {
name: 'core/block-editor/focus-toolbar',
category: 'global',
Expand Down
1 change: 1 addition & 0 deletions packages/block-library/src/column/edit.js
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,7 @@ function ColumnEdit( {
<BlockVerticalAlignmentToolbar
onChange={ updateAlignment }
value={ verticalAlignment }
controls={ [ 'top', 'center', 'bottom', 'stretch' ] }
/>
</BlockControls>
<InspectorControls>
Expand Down
4 changes: 4 additions & 0 deletions packages/block-library/src/columns/style.scss
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,10 @@
align-self: flex-end;
}

&.is-vertically-aligned-stretch {
align-self: stretch;
}

&.is-vertically-aligned-top,
&.is-vertically-aligned-center,
&.is-vertically-aligned-bottom {
Expand Down
4 changes: 3 additions & 1 deletion packages/block-library/src/details/block.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,9 @@
"default": false
},
"summary": {
"type": "string"
"type": "string",
"source": "html",
"selector": "summary"
}
},
"supports": {
Expand Down
4 changes: 2 additions & 2 deletions packages/core-data/src/entity-provider.js
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,7 @@ export function useEntityProp( kind, name, prop, _id ) {
* The return value has the shape `[ blocks, onInput, onChange ]`.
* `onInput` is for block changes that don't create undo levels
* or dirty the post, non-persistent changes, and `onChange` is for
* peristent changes. They map directly to the props of a
* persistent changes. They map directly to the props of a
* `BlockEditorProvider` and are intended to be used with it,
* or similar components or hooks.
*
Expand Down Expand Up @@ -290,7 +290,7 @@ export function useEntityBlockEditor( kind, name, { id: _id } = {} ) {
} );
}

// We need to go through all block attributs deeply and update the
// We need to go through all block attributes deeply and update the
// footnote anchor numbering (textContent) to match the new order.
const newBlocks = updateBlocksAttributes( _blocks );

Expand Down
272 changes: 272 additions & 0 deletions packages/core-data/src/test/entity-provider.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,272 @@
/**
* External dependencies
*/
import { act, render } from '@testing-library/react';

/**
* WordPress dependencies
*/
import {
createBlock,
registerBlockType,
unregisterBlockType,
getBlockTypes,
} from '@wordpress/blocks';
import { RichText, useBlockProps } from '@wordpress/block-editor';
import { createRegistry, RegistryProvider } from '@wordpress/data';

/**
* Internal dependencies
*/
import { store as coreDataStore } from '../index';
import { useEntityBlockEditor } from '../entity-provider';

const postTypeConfig = {
kind: 'postType',
name: 'post',
baseURL: '/wp/v2/posts',
transientEdits: { blocks: true, selection: true },
mergedEdits: { meta: true },
rawAttributes: [ 'title', 'excerpt', 'content' ],
};

const postTypeEntity = {
slug: 'post',
rest_base: 'posts',
labels: {
item_updated: 'Updated Post',
item_published: 'Post published',
item_reverted_to_draft: 'Post reverted to draft.',
},
};

const aSinglePost = {
id: 1,
type: 'post',
content: {
raw: '<!-- wp:test-block-with-array-of-strings --><div><p>apples</p><p></p><p>oranges</p></div><!-- /wp:test-block-with-array-of-strings --><!-- wp:test-block --><p>A paragraph</p><!-- /wp:test-block -->',
rendered: '<p>A paragraph</p>',
},
meta: {
footnotes: '[]',
},
};

function createRegistryWithStores() {
// Create a registry.
const registry = createRegistry();

// Register store.
registry.register( coreDataStore );

// Register post type entity.
registry.dispatch( coreDataStore ).addEntities( [ postTypeConfig ] );

// Store post type entity.
registry
.dispatch( coreDataStore )
.receiveEntityRecords( 'root', 'postType', [ postTypeEntity ] );

// Store a single post for use by the tests.
registry
.dispatch( coreDataStore )
.receiveEntityRecords( 'postType', 'post', [ aSinglePost ] );

return registry;
}

describe( 'useEntityBlockEditor', () => {
let registry;

beforeEach( () => {
registry = createRegistryWithStores();

const edit = ( { children } ) => <>{ children }</>;

registerBlockType( 'core/test-block', {
supports: {
className: false,
},
save: ( { attributes } ) => {
const { content } = attributes;
return (
<p { ...useBlockProps.save() }>
<RichText.Content value={ content } />
</p>
);
},
category: 'text',
attributes: {
content: {
type: 'string',
source: 'html',
selector: 'p',
default: '',
__experimentalRole: 'content',
},
},
title: 'block title',
edit,
} );

registerBlockType( 'core/test-block-with-array-of-strings', {
supports: {
className: false,
},
save: ( { attributes } ) => {
const { items } = attributes;
return (
<div>
{ items.map( ( item, index ) => (
<p key={ index }>{ item }</p>
) ) }
</div>
);
},
category: 'text',
attributes: {
items: {
type: 'array',
items: {
type: 'string',
},
default: [ 'apples', null, 'oranges' ],
},
},
title: 'block title',
edit,
} );
} );

afterEach( () => {
getBlockTypes().forEach( ( block ) => {
unregisterBlockType( block.name );
} );
} );

it( 'does not mutate block attributes that include an array of strings or null values', async () => {
let blocks, onChange;
const TestComponent = () => {
[ blocks, , onChange ] = useEntityBlockEditor( 'postType', 'post', {
id: 1,
} );

return <div />;
};

render(
<RegistryProvider value={ registry }>
<TestComponent />
</RegistryProvider>
);

expect( blocks[ 0 ].name ).toEqual(
'core/test-block-with-array-of-strings'
);
expect( blocks[ 0 ].attributes.items ).toEqual( [
'apples',
null,
'oranges',
] );

// Add a block with content that will match against footnotes logic, causing
// `updateFootnotes` to iterate over blocks and their attributes.
act( () => {
onChange(
[
...blocks,
createBlock( 'core/test-block', {
content:
'<p><sup data-fn="1234" class="fn"><a href="#1234" id="1234-link">1</a></sup></p>',
} ),
],
{
selection: {
selectionStart: {},
selectionEnd: {},
initialPosition: {},
},
}
);
} );

// Ensure the first block remains the same, with unaltered attributes.
expect( blocks[ 0 ].name ).toEqual(
'core/test-block-with-array-of-strings'
);
expect( blocks[ 0 ].attributes.items ).toEqual( [
'apples',
null,
'oranges',
] );
} );

it( 'updates the order of footnotes when a new footnote is inserted', async () => {
// Start with a post containing a block with a single footnote (set to 1).
registry
.dispatch( coreDataStore )
.receiveEntityRecords( 'postType', 'post', [
{
id: 1,
type: 'post',
content: {
raw: '<!-- wp:test-block --><p>A paragraph<sup data-fn="abcd" class="fn"><a href="#abcd" id="abcd-link">1</a></sup></p><!-- /wp:test-block -->',
rendered: '<p>A paragraph</p>',
},
meta: {
footnotes: '[]',
},
},
] );

let blocks, onChange;

const TestComponent = () => {
[ blocks, , onChange ] = useEntityBlockEditor( 'postType', 'post', {
id: 1,
} );

return <div />;
};

render(
<RegistryProvider value={ registry }>
<TestComponent />
</RegistryProvider>
);

// The first block should have the footnote number 1.
expect( blocks[ 0 ].attributes.content ).toEqual(
'A paragraph<sup data-fn="abcd" class="fn"><a href="#abcd" id="abcd-link">1</a></sup>'
);

// Add a block with a new footnote with an arbitrary footnote number that will be overwritten after insertion.
act( () => {
onChange(
[
createBlock( 'core/test-block', {
content:
'A new paragraph<sup data-fn="xyz" class="xyz"><a href="#xyz" id="xyz-link">999</a></sup>',
} ),
...blocks,
],
{
selection: {
selectionStart: {},
selectionEnd: {},
initialPosition: {},
},
}
);
} );

// The newly inserted block should have the footnote number 1, and the
// existing footnote number 1 should be updated to 2.
expect( blocks[ 0 ].attributes.content ).toEqual(
'A new paragraph<sup data-fn="xyz" class="xyz"><a href="#xyz" id="xyz-link">1</a></sup>'
);
expect( blocks[ 1 ].attributes.content ).toEqual(
'A paragraph<sup data-fn="abcd" class="fn"><a href="#abcd" id="abcd-link">2</a></sup>'
);
} );
} );
Original file line number Diff line number Diff line change
Expand Up @@ -272,6 +272,35 @@ exports[`KeyboardShortcutHelpModal should match snapshot when the modal is activ
</kbd>
</div>
</li>
<li
class="edit-post-keyboard-shortcut-help-modal__shortcut"
>
<div
class="edit-post-keyboard-shortcut-help-modal__shortcut-description"
>
Select text across multiple blocks.
</div>
<div
class="edit-post-keyboard-shortcut-help-modal__shortcut-term"
>
<kbd
aria-label="Shift + Arrow"
class="edit-post-keyboard-shortcut-help-modal__shortcut-key-combination"
>
<kbd
class="edit-post-keyboard-shortcut-help-modal__shortcut-key"
>
Shift
</kbd>
+
<kbd
class="edit-post-keyboard-shortcut-help-modal__shortcut-key"
>
Arrow
</kbd>
</kbd>
</div>
</li>
</ul>
</section>
<section
Expand Down
Loading

0 comments on commit baa2f87

Please sign in to comment.