From a2d973869205d71aa384e88a79032fe3cee5b66e Mon Sep 17 00:00:00 2001 From: Andrew Serong <14988353+andrewserong@users.noreply.github.com> Date: Thu, 25 Jan 2024 11:26:20 +1100 Subject: [PATCH 01/47] List View: Add keyboard clipboard events for cut, copy, paste (#57838) * List View: Try adding keyboard clipboard events for cut, copy, paste * Make useClipboardHandler that works with the list view * Ensure focus remains within list view after cut and paste * Add e2e tests * Fix linting issue * Update packages/block-editor/src/components/list-view/utils.js Co-authored-by: Robert Anderson * Try consolidating some of the copy and paste behaviour * Add comment references the other useClipboardHandler * Add JSDoc comments for the new utility functions * Tidy up comment --------- Co-authored-by: Robert Anderson --- .../src/components/list-view/block.js | 2 +- .../src/components/list-view/index.js | 31 ++- .../list-view/use-clipboard-handler.js | 199 ++++++++++++++++++ .../src/components/list-view/utils.js | 8 +- .../writing-flow/use-clipboard-handler.js | 84 +------- .../src/components/writing-flow/utils.js | 103 +++++++++ .../specs/editor/various/list-view.spec.js | 96 ++++++++- 7 files changed, 430 insertions(+), 93 deletions(-) create mode 100644 packages/block-editor/src/components/list-view/use-clipboard-handler.js create mode 100644 packages/block-editor/src/components/writing-flow/utils.js diff --git a/packages/block-editor/src/components/list-view/block.js b/packages/block-editor/src/components/list-view/block.js index aab9d444a5948..6dedabb48f8b8 100644 --- a/packages/block-editor/src/components/list-view/block.js +++ b/packages/block-editor/src/components/list-view/block.js @@ -187,7 +187,7 @@ function ListViewBlock( { selectBlock( undefined, focusClientId, null, null ); } - focusListItem( focusClientId, treeGridElementRef ); + focusListItem( focusClientId, treeGridElementRef?.current ); }, [ selectBlock, treeGridElementRef ] ); diff --git a/packages/block-editor/src/components/list-view/index.js b/packages/block-editor/src/components/list-view/index.js index 5270a7af3a296..895571755e4fa 100644 --- a/packages/block-editor/src/components/list-view/index.js +++ b/packages/block-editor/src/components/list-view/index.js @@ -42,6 +42,7 @@ import useListViewExpandSelectedItem from './use-list-view-expand-selected-item' import { store as blockEditorStore } from '../../store'; import { BlockSettingsDropdown } from '../block-settings-menu/block-settings-dropdown'; import { focusListItem } from './utils'; +import useClipboardHandler from './use-clipboard-handler'; const expanded = ( state, action ) => { if ( Array.isArray( action.clientIds ) ) { @@ -137,14 +138,6 @@ function ListViewComponent( const [ expandedState, setExpandedState ] = useReducer( expanded, {} ); - const { ref: dropZoneRef, target: blockDropTarget } = useListViewDropZone( { - dropZoneElement, - expandedState, - setExpandedState, - } ); - const elementRef = useRef(); - const treeGridRef = useMergeRefs( [ elementRef, dropZoneRef, ref ] ); - const [ insertedBlock, setInsertedBlock ] = useState( null ); const { setSelectedTreeId } = useListViewExpandSelectedItem( { @@ -166,11 +159,31 @@ function ListViewComponent( }, [ setSelectedTreeId, updateBlockSelection, onSelect, getBlock ] ); + + const { ref: dropZoneRef, target: blockDropTarget } = useListViewDropZone( { + dropZoneElement, + expandedState, + setExpandedState, + } ); + const elementRef = useRef(); + + // Allow handling of copy, cut, and paste events. + const clipBoardRef = useClipboardHandler( { + selectBlock: selectEditorBlock, + } ); + + const treeGridRef = useMergeRefs( [ + clipBoardRef, + elementRef, + dropZoneRef, + ref, + ] ); + useEffect( () => { // If a blocks are already selected when the list view is initially // mounted, shift focus to the first selected block. if ( selectedClientIds?.length ) { - focusListItem( selectedClientIds[ 0 ], elementRef ); + focusListItem( selectedClientIds[ 0 ], elementRef?.current ); } // Disable reason: Only focus on the selected item when the list view is mounted. // eslint-disable-next-line react-hooks/exhaustive-deps diff --git a/packages/block-editor/src/components/list-view/use-clipboard-handler.js b/packages/block-editor/src/components/list-view/use-clipboard-handler.js new file mode 100644 index 0000000000000..cd25c71e9bf7c --- /dev/null +++ b/packages/block-editor/src/components/list-view/use-clipboard-handler.js @@ -0,0 +1,199 @@ +/** + * WordPress dependencies + */ +import { useDispatch, useSelect } from '@wordpress/data'; +import { useRefEffect } from '@wordpress/compose'; + +/** + * Internal dependencies + */ +import { store as blockEditorStore } from '../../store'; +import { useNotifyCopy } from '../../utils/use-notify-copy'; +import { focusListItem } from './utils'; +import { getPasteBlocks, setClipboardBlocks } from '../writing-flow/utils'; + +// This hook borrows from useClipboardHandler in ../writing-flow/use-clipboard-handler.js +// and adds behaviour for the list view, while skipping partial selection. +export default function useClipboardHandler( { selectBlock } ) { + const { + getBlockOrder, + getBlockRootClientId, + getBlocksByClientId, + getPreviousBlockClientId, + getSelectedBlockClientIds, + getSettings, + canInsertBlockType, + canRemoveBlocks, + } = useSelect( blockEditorStore ); + const { flashBlock, removeBlocks, replaceBlocks, insertBlocks } = + useDispatch( blockEditorStore ); + const notifyCopy = useNotifyCopy(); + + return useRefEffect( ( node ) => { + function updateFocusAndSelection( focusClientId, shouldSelectBlock ) { + if ( shouldSelectBlock ) { + selectBlock( undefined, focusClientId, null, null ); + } + + focusListItem( focusClientId, node ); + } + + // Determine which blocks to update: + // If the current (focused) block is part of the block selection, use the whole selection. + // If the focused block is not part of the block selection, only update the focused block. + function getBlocksToUpdate( clientId ) { + const selectedBlockClientIds = getSelectedBlockClientIds(); + const isUpdatingSelectedBlocks = + selectedBlockClientIds.includes( clientId ); + const firstBlockClientId = isUpdatingSelectedBlocks + ? selectedBlockClientIds[ 0 ] + : clientId; + const firstBlockRootClientId = + getBlockRootClientId( firstBlockClientId ); + + const blocksToUpdate = isUpdatingSelectedBlocks + ? selectedBlockClientIds + : [ clientId ]; + + return { + blocksToUpdate, + firstBlockClientId, + firstBlockRootClientId, + originallySelectedBlockClientIds: selectedBlockClientIds, + }; + } + + function handler( event ) { + if ( event.defaultPrevented ) { + // This was possibly already handled in rich-text/use-paste-handler.js. + return; + } + + // Only handle events that occur within the list view. + if ( ! node.contains( event.target.ownerDocument.activeElement ) ) { + return; + } + + // Retrieve the block clientId associated with the focused list view row. + // This enables applying copy / cut / paste behavior to the focused block, + // rather than just the blocks that are currently selected. + const listViewRow = + event.target.ownerDocument.activeElement?.closest( + '[role=row]' + ); + const clientId = listViewRow?.dataset?.block; + if ( ! clientId ) { + return; + } + + const { + blocksToUpdate: selectedBlockClientIds, + firstBlockClientId, + firstBlockRootClientId, + originallySelectedBlockClientIds, + } = getBlocksToUpdate( clientId ); + + if ( selectedBlockClientIds.length === 0 ) { + return; + } + + event.preventDefault(); + + if ( event.type === 'copy' || event.type === 'cut' ) { + if ( selectedBlockClientIds.length === 1 ) { + flashBlock( selectedBlockClientIds[ 0 ] ); + } + + notifyCopy( event.type, selectedBlockClientIds ); + const blocks = getBlocksByClientId( selectedBlockClientIds ); + setClipboardBlocks( event, blocks ); + } + + if ( event.type === 'cut' ) { + // Don't update the selection if the blocks cannot be deleted. + if ( + ! canRemoveBlocks( + selectedBlockClientIds, + firstBlockRootClientId + ) + ) { + return; + } + + let blockToFocus = + getPreviousBlockClientId( firstBlockClientId ) ?? + // If the previous block is not found (when the first block is deleted), + // fallback to focus the parent block. + firstBlockRootClientId; + + // Remove blocks, but don't update selection, and it will be handled below. + removeBlocks( selectedBlockClientIds, false ); + + // Update the selection if the original selection has been removed. + const shouldUpdateSelection = + originallySelectedBlockClientIds.length > 0 && + getSelectedBlockClientIds().length === 0; + + // If there's no previous block nor parent block, focus the first block. + if ( ! blockToFocus ) { + blockToFocus = getBlockOrder()[ 0 ]; + } + + updateFocusAndSelection( blockToFocus, shouldUpdateSelection ); + } else if ( event.type === 'paste' ) { + const { + __experimentalCanUserUseUnfilteredHTML: + canUserUseUnfilteredHTML, + } = getSettings(); + const blocks = getPasteBlocks( + event, + canUserUseUnfilteredHTML + ); + + if ( selectedBlockClientIds.length === 1 ) { + const [ selectedBlockClientId ] = selectedBlockClientIds; + + // If a single block is focused, and the blocks to be posted can + // be inserted within the block, then append the pasted blocks + // within the focused block. For example, if you have copied a paragraph + // block and paste it within a single Group block, this will append + // the paragraph block within the Group block. + if ( + blocks.every( ( block ) => + canInsertBlockType( + block.name, + selectedBlockClientId + ) + ) + ) { + insertBlocks( + blocks, + undefined, + selectedBlockClientId + ); + updateFocusAndSelection( blocks[ 0 ]?.clientId, false ); + return; + } + } + + replaceBlocks( + selectedBlockClientIds, + blocks, + blocks.length - 1, + -1 + ); + updateFocusAndSelection( blocks[ 0 ]?.clientId, false ); + } + } + + node.ownerDocument.addEventListener( 'copy', handler ); + node.ownerDocument.addEventListener( 'cut', handler ); + node.ownerDocument.addEventListener( 'paste', handler ); + + return () => { + node.ownerDocument.removeEventListener( 'copy', handler ); + node.ownerDocument.removeEventListener( 'cut', handler ); + node.ownerDocument.removeEventListener( 'paste', handler ); + }; + }, [] ); +} diff --git a/packages/block-editor/src/components/list-view/utils.js b/packages/block-editor/src/components/list-view/utils.js index ed7a321dea0c8..c91376b047211 100644 --- a/packages/block-editor/src/components/list-view/utils.js +++ b/packages/block-editor/src/components/list-view/utils.js @@ -63,12 +63,12 @@ export function getCommonDepthClientIds( * * @typedef {import('@wordpress/element').RefObject} RefObject * - * @param {string} focusClientId The client ID of the block to focus. - * @param {RefObject} treeGridElementRef The container element to search within. + * @param {string} focusClientId The client ID of the block to focus. + * @param {?HTMLElement} treeGridElement The container element to search within. */ -export function focusListItem( focusClientId, treeGridElementRef ) { +export function focusListItem( focusClientId, treeGridElement ) { const getFocusElement = () => { - const row = treeGridElementRef.current?.querySelector( + const row = treeGridElement?.querySelector( `[role=row][data-block="${ focusClientId }"]` ); if ( ! row ) return null; diff --git a/packages/block-editor/src/components/writing-flow/use-clipboard-handler.js b/packages/block-editor/src/components/writing-flow/use-clipboard-handler.js index 5b78d2f8656b6..8528655c1dcc9 100644 --- a/packages/block-editor/src/components/writing-flow/use-clipboard-handler.js +++ b/packages/block-editor/src/components/writing-flow/use-clipboard-handler.js @@ -1,17 +1,9 @@ /** * WordPress dependencies */ -import { - serialize, - pasteHandler, - createBlock, - findTransform, - getBlockTransforms, -} from '@wordpress/blocks'; import { documentHasSelection, documentHasUncollapsedSelection, - __unstableStripHTML as stripHTML, } from '@wordpress/dom'; import { useDispatch, useSelect } from '@wordpress/data'; import { useRefEffect } from '@wordpress/compose'; @@ -19,9 +11,9 @@ import { useRefEffect } from '@wordpress/compose'; /** * Internal dependencies */ -import { getPasteEventData } from '../../utils/pasting'; import { store as blockEditorStore } from '../../store'; import { useNotifyCopy } from '../../utils/use-notify-copy'; +import { getPasteBlocks, setClipboardBlocks } from './utils'; export default function useClipboardHandler() { const { @@ -112,29 +104,7 @@ export default function useClipboardHandler() { blocks = [ head, ...inBetweenBlocks, tail ]; } - const wrapperBlockName = event.clipboardData.getData( - '__unstableWrapperBlockName' - ); - - if ( wrapperBlockName ) { - blocks = createBlock( - wrapperBlockName, - JSON.parse( - event.clipboardData.getData( - '__unstableWrapperBlockAttributes' - ) - ), - blocks - ); - } - - const serialized = serialize( blocks ); - - event.clipboardData.setData( - 'text/plain', - toPlainText( serialized ) - ); - event.clipboardData.setData( 'text/html', serialized ); + setClipboardBlocks( event, blocks ); } } @@ -153,35 +123,10 @@ export default function useClipboardHandler() { __experimentalCanUserUseUnfilteredHTML: canUserUseUnfilteredHTML, } = getSettings(); - const { plainText, html, files } = getPasteEventData( event ); - let blocks = []; - - if ( files.length ) { - const fromTransforms = getBlockTransforms( 'from' ); - blocks = files - .reduce( ( accumulator, file ) => { - const transformation = findTransform( - fromTransforms, - ( transform ) => - transform.type === 'files' && - transform.isMatch( [ file ] ) - ); - if ( transformation ) { - accumulator.push( - transformation.transform( [ file ] ) - ); - } - return accumulator; - }, [] ) - .flat(); - } else { - blocks = pasteHandler( { - HTML: html, - plainText, - mode: 'BLOCKS', - canUserUseUnfilteredHTML, - } ); - } + const blocks = getPasteBlocks( + event, + canUserUseUnfilteredHTML + ); if ( selectedBlockClientIds.length === 1 ) { const [ selectedBlockClientId ] = selectedBlockClientIds; @@ -223,20 +168,3 @@ export default function useClipboardHandler() { }; }, [] ); } - -/** - * Given a string of HTML representing serialized blocks, returns the plain - * text extracted after stripping the HTML of any tags and fixing line breaks. - * - * @param {string} html Serialized blocks. - * @return {string} The plain-text content with any html removed. - */ -function toPlainText( html ) { - // Manually handle BR tags as line breaks prior to `stripHTML` call - html = html.replace( /
/g, '\n' ); - - const plainText = stripHTML( html ).trim(); - - // Merge any consecutive line breaks - return plainText.replace( /\n\n+/g, '\n\n' ); -} diff --git a/packages/block-editor/src/components/writing-flow/utils.js b/packages/block-editor/src/components/writing-flow/utils.js new file mode 100644 index 0000000000000..ef1827077ccbf --- /dev/null +++ b/packages/block-editor/src/components/writing-flow/utils.js @@ -0,0 +1,103 @@ +/** + * WordPress dependencies + */ +import { __unstableStripHTML as stripHTML } from '@wordpress/dom'; +import { + serialize, + createBlock, + pasteHandler, + findTransform, + getBlockTransforms, +} from '@wordpress/blocks'; + +/** + * Internal dependencies + */ +import { getPasteEventData } from '../../utils/pasting'; + +/** + * Sets the clipboard data for the provided blocks, with both HTML and plain + * text representations. + * + * @param {ClipboardEvent} event Clipboard event. + * @param {WPBlock[]} blocks Blocks to set as clipboard data. + */ +export function setClipboardBlocks( event, blocks ) { + let _blocks = blocks; + const wrapperBlockName = event.clipboardData.getData( + '__unstableWrapperBlockName' + ); + + if ( wrapperBlockName ) { + _blocks = createBlock( + wrapperBlockName, + JSON.parse( + event.clipboardData.getData( + '__unstableWrapperBlockAttributes' + ) + ), + _blocks + ); + } + + const serialized = serialize( _blocks ); + + event.clipboardData.setData( 'text/plain', toPlainText( serialized ) ); + event.clipboardData.setData( 'text/html', serialized ); +} + +/** + * Returns the blocks to be pasted from the clipboard event. + * + * @param {ClipboardEvent} event The clipboard event. + * @param {boolean} canUserUseUnfilteredHTML Whether the user can or can't post unfiltered HTML. + * @return {Array|string} A list of blocks or a string, depending on `handlerMode`. + */ +export function getPasteBlocks( event, canUserUseUnfilteredHTML ) { + const { plainText, html, files } = getPasteEventData( event ); + let blocks = []; + + if ( files.length ) { + const fromTransforms = getBlockTransforms( 'from' ); + blocks = files + .reduce( ( accumulator, file ) => { + const transformation = findTransform( + fromTransforms, + ( transform ) => + transform.type === 'files' && + transform.isMatch( [ file ] ) + ); + if ( transformation ) { + accumulator.push( transformation.transform( [ file ] ) ); + } + return accumulator; + }, [] ) + .flat(); + } else { + blocks = pasteHandler( { + HTML: html, + plainText, + mode: 'BLOCKS', + canUserUseUnfilteredHTML, + } ); + } + + return blocks; +} + +/** + * Given a string of HTML representing serialized blocks, returns the plain + * text extracted after stripping the HTML of any tags and fixing line breaks. + * + * @param {string} html Serialized blocks. + * @return {string} The plain-text content with any html removed. + */ +function toPlainText( html ) { + // Manually handle BR tags as line breaks prior to `stripHTML` call + html = html.replace( /
/g, '\n' ); + + const plainText = stripHTML( html ).trim(); + + // Merge any consecutive line breaks + return plainText.replace( /\n\n+/g, '\n\n' ); +} diff --git a/test/e2e/specs/editor/various/list-view.spec.js b/test/e2e/specs/editor/various/list-view.spec.js index 00f21b4e51c5e..cb15c12c84b49 100644 --- a/test/e2e/specs/editor/various/list-view.spec.js +++ b/test/e2e/specs/editor/various/list-view.spec.js @@ -450,7 +450,7 @@ test.describe( 'List View', () => { ).toBeFocused(); } ); - test( 'should select, duplicate, delete, and deselect blocks using keyboard', async ( { + test( 'should cut, copy, paste, select, duplicate, delete, and deselect blocks using keyboard', async ( { editor, page, pageUtils, @@ -808,6 +808,100 @@ test.describe( 'List View', () => { { name: 'core/heading', selected: false, focused: false }, { name: 'core/file', selected: false, focused: true }, ] ); + + // Copy and paste blocks. To begin, add another Group block. + await editor.insertBlock( { + name: 'core/group', + innerBlocks: [ + { name: 'core/paragraph' }, + { name: 'core/pullquote' }, + ], + } ); + + // Click the newly inserted Group block List View item to ensure it is focused. + await listView + .getByRole( 'link', { + name: 'Group', + expanded: false, + } ) + .click(); + + // Move down to group block, expand, and then move to the paragraph block. + await page.keyboard.press( 'ArrowDown' ); + await page.keyboard.press( 'ArrowRight' ); + await page.keyboard.press( 'ArrowDown' ); + await page.keyboard.press( 'ArrowDown' ); + await pageUtils.pressKeys( 'primary+c' ); + await page.keyboard.press( 'ArrowUp' ); + await pageUtils.pressKeys( 'primary+v' ); + + await expect + .poll( + listViewUtils.getBlocksWithA11yAttributes, + 'Should be able to copy focused block and paste in the list view via keyboard shortcuts' + ) + .toMatchObject( [ + { name: 'core/heading', selected: false, focused: false }, + { name: 'core/file', selected: false, focused: false }, + { + name: 'core/group', + selected: true, + innerBlocks: [ + { + name: 'core/pullquote', + selected: false, + focused: true, + }, + { + name: 'core/pullquote', + selected: false, + focused: false, + }, + ], + }, + ] ); + + // Cut and paste blocks. + await page.keyboard.press( 'ArrowUp' ); + await pageUtils.pressKeys( 'primary+x' ); + + await expect + .poll( + listViewUtils.getBlocksWithA11yAttributes, + 'Should be able to cut a block in the list view, with the preceding block being selected' + ) + .toMatchObject( [ + { name: 'core/heading', selected: false, focused: false }, + { name: 'core/file', selected: true, focused: true }, + ] ); + + await pageUtils.pressKeys( 'primary+v' ); + + await expect + .poll( + listViewUtils.getBlocksWithA11yAttributes, + 'Should be able to paste previously cut block in the list view via keyboard shortcuts' + ) + .toMatchObject( [ + { name: 'core/heading', selected: false, focused: false }, + { + name: 'core/group', + selected: true, + focused: true, + innerBlocks: [ + { + name: 'core/pullquote', + selected: false, + focused: false, + }, + { + name: 'core/pullquote', + selected: false, + focused: false, + }, + ], + }, + ] ); } ); test( 'block settings dropdown menu', async ( { From 621a3cd0ee1b86e0a213e820a159fac033cb7a7b Mon Sep 17 00:00:00 2001 From: George Mamadashvili Date: Thu, 25 Jan 2024 07:55:59 +0400 Subject: [PATCH 02/47] Try fixing flaky Paragraph block e2e test (#58208) --- test/e2e/specs/editor/blocks/paragraph.spec.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/test/e2e/specs/editor/blocks/paragraph.spec.js b/test/e2e/specs/editor/blocks/paragraph.spec.js index dd3cd9196efb2..4918ac3d619b5 100644 --- a/test/e2e/specs/editor/blocks/paragraph.spec.js +++ b/test/e2e/specs/editor/blocks/paragraph.spec.js @@ -236,8 +236,9 @@ test.describe( 'Paragraph', () => { { // Dragging on the top half of the heading block. + // Make sure to target the top dropzone by dragging > 30px inside the block. await draggingUtils.dragOver( - headingBox.x, + headingBox.x + 32, headingBox.y + 1 ); await expect( draggingUtils.dropZone ).toBeVisible(); From 3da4d4452bab39cc902d280932a46620668d7b3a Mon Sep 17 00:00:00 2001 From: Nick Diego Date: Thu, 25 Jan 2024 02:44:47 -0600 Subject: [PATCH 03/47] Add spaces before list markup and remove extra spaces. (#58226) --- docs/getting-started/fundamentals/block-in-the-editor.md | 8 +++++--- docs/getting-started/fundamentals/block-wrapper.md | 1 + .../fundamentals/file-structure-of-a-block.md | 3 ++- .../fundamentals/markup-representation-block.md | 8 +++++--- .../fundamentals/registration-of-a-block.md | 1 + .../fundamentals/static-dynamic-rendering.md | 7 +++++-- 6 files changed, 19 insertions(+), 9 deletions(-) diff --git a/docs/getting-started/fundamentals/block-in-the-editor.md b/docs/getting-started/fundamentals/block-in-the-editor.md index 56ba72c283bdf..2089d8aba2f0e 100644 --- a/docs/getting-started/fundamentals/block-in-the-editor.md +++ b/docs/getting-started/fundamentals/block-in-the-editor.md @@ -3,6 +3,7 @@ The Block Editor is a React Single Page Application (SPA) and every block in the editor is displayed through a React component defined in the `edit` property of the settings object used to [register the block on the client](https://developer.wordpress.org/block-editor/getting-started/fundamentals/registration-of-a-block/#registration-of-the-block-with-javascript-client-side). The `props` object received by the block's `Edit` React component includes: + - [`attributes`](https://developer.wordpress.org/block-editor/reference-guides/block-api/block-edit-save/#attributes) - attributes object - [`setAttributes`](https://developer.wordpress.org/block-editor/reference-guides/block-api/block-edit-save/#setattributes) - method to update the attributes object - [`isSelected`](https://developer.wordpress.org/block-editor/reference-guides/block-api/block-edit-save/#isselected) - boolean that communicates whether the block is currently selected @@ -14,18 +15,21 @@ The WordPress Gutenberg project uses A good workflow when using a component for the Block Editor is: + - Import the component from a WordPress package - Add the corresponding code for the component to your project in JSX format - Most built-in components will be used to set [block attributes](https://developer.wordpress.org/block-editor/getting-started/fundamentals/block-json/#using-attributes-to-store-block-data), so define any necessary attributes in `block.json` and create event handlers to update those attributes with `setAttributes` in your component - If needed, adapt the code to be serialized and stored in the database - - ## Block Controls: Block Toolbar and Settings Sidebar To simplify block customization and ensure a consistent experience for users, there are a number of built-in UI patterns to help generate the editor preview. @@ -95,7 +98,6 @@ _See the [full block example](https://github.com/WordPress/block-development-exa Note that `BlockControls` is only visible when the block is currently selected and in visual editing mode. `BlockControls` are not shown when editing a block in HTML editing mode. - ### Settings Sidebar The Settings Sidebar is used to display less-often-used settings or settings that require more screen space. The Settings Sidebar should be used for **block-level settings only**. diff --git a/docs/getting-started/fundamentals/block-wrapper.md b/docs/getting-started/fundamentals/block-wrapper.md index cf588cf33cf6f..6582d3af3301f 100644 --- a/docs/getting-started/fundamentals/block-wrapper.md +++ b/docs/getting-started/fundamentals/block-wrapper.md @@ -24,6 +24,7 @@ For the [`edit` React component and the `save` function](https://developer.wordp The [`useBlockProps()`](https://developer.wordpress.org/block-editor/reference-guides/packages/packages-block-editor/#useblockprops) hook available on the [`@wordpress/block-editor`](https://developer.wordpress.org/block-editor/reference-guides/packages/packages-block-editor) allows passing the required attributes for the Block Editor to the `edit` block's outer wrapper. Among other things, the `useBlockProps()` hook takes care of including in this wrapper: + - An `id` for the block's markup - Some accessibility and `data-` attributes - Classes and inline styles reflecting custom settings, which include by default: diff --git a/docs/getting-started/fundamentals/file-structure-of-a-block.md b/docs/getting-started/fundamentals/file-structure-of-a-block.md index 72531ccfb2b27..b52f5c5efd0f7 100644 --- a/docs/getting-started/fundamentals/file-structure-of-a-block.md +++ b/docs/getting-started/fundamentals/file-structure-of-a-block.md @@ -30,7 +30,8 @@ This file contains the [metadata of the block](https://developer.wordpress.org/b Among other data it provides properties to define the paths of the files involved in the block's behaviour, output and style. If there's a build process involved, this `block.json` along with the generated files are placed into a destination folder (usually the `build` folder) so the paths provided target to the bundled versions of these files. -The most relevant properties that can be defined in a `block.json` to set the files involved in the block's behaviour, output or style are: +The most relevant properties that can be defined in a `block.json` to set the files involved in the block's behaviour, output, or style are: + - The [`editorScript`](https://developer.wordpress.org/block-editor/reference-guides/block-api/block-metadata/#editor-script) property, usually set with the path of a bundled `index.js` file (output build from `src/index.js`). - The [`style`](https://developer.wordpress.org/block-editor/reference-guides/block-api/block-metadata/#style) property, usually set with the path of a bundled `style-index.css` file (output build from `src/style.(css|scss|sass)`). - The [`editorStyle`](https://developer.wordpress.org/block-editor/reference-guides/block-api/block-metadata/#editor-style) property, usually set with the path of a bundled `index.css` (output build from `src/editor.(css|scss|sass)`). diff --git a/docs/getting-started/fundamentals/markup-representation-block.md b/docs/getting-started/fundamentals/markup-representation-block.md index 506d0feb8d3d1..b048160907a25 100644 --- a/docs/getting-started/fundamentals/markup-representation-block.md +++ b/docs/getting-started/fundamentals/markup-representation-block.md @@ -1,8 +1,9 @@ # Markup representation of a block -When stored, in the database (DB) or in templates as HTML files, blocks are represented using a [specific HTML grammar](https://developer.wordpress.org/block-editor/explanations/architecture/key-concepts/#data-and-attributes), which is technically valid HTML based on HTML comments that act as explicit block delimiters +When stored in the database or in templates as HTML files, blocks are represented using a [specific HTML grammar](https://developer.wordpress.org/block-editor/explanations/architecture/key-concepts/#data-and-attributes), which is technically valid HTML based on HTML comments that act as explicit block delimiters These are some of the rules for the markup used to represent a block: + - All core block comments start with a prefix and the block name: `wp:blockname` - For custom blocks, `blockname` is `namespace/blockname` - The comment can be a single line, self-closing, or wrapper for HTML content. @@ -17,21 +18,22 @@ _Example: Markup representation of an `image` core block_ ``` The [markup representation of a block is parsed for the Block Editor](https://developer.wordpress.org/block-editor/explanations/architecture/data-flow/) and the block's output for the front end: + - In the editor, WordPress parses this block markup, captures its data and loads its `edit` version - In the front end, WordPress parses this block markup, captures its data and generates its final HTML markup Whenever a block is saved, the `save` function, defined when the [block is registered in the client](https://developer.wordpress.org/block-editor/getting-started/fundamentals/registration-of-a-block/#registration-of-the-block-with-javascript-client-side), is called to return the markup that will be saved into the database within the block delimiter's comment. If `save` is `null` (common case for blocks with dynamic rendering), only a single line block delimiter's comment is stored, along with any attributes The Post Editor checks that the markup created by the `save` function is identical to the block's markup saved to the database: + - If there are any differences, the Post Editor triggers a [block validation error](https://developer.wordpress.org/block-editor/reference-guides/block-api/block-edit-save/#validation). - Block validation errors usually happen when a block’s `save` function is updated to change the markup produced by the block. - A block developer can mitigate these issues by adding a [**block deprecation**](https://developer.wordpress.org/block-editor/reference-guides/block-api/block-deprecation/) to register the change in the block. -The markup of a **block with dynamic rendering** is expected to change so the markup of these blocks is not saved to the database. What is saved in the DB as representation of the block, for blocks with dynamic rendering, is a single line of HTML consisting on just the block delimiter's comment (including block attributes values). That HTML is not subject to the Post Editor’s validation. +The markup of a **block with dynamic rendering** is expected to change so the markup of these blocks is not saved to the database. What is saved in the database as representation of the block, for blocks with dynamic rendering, is a single line of HTML consisting on just the block delimiter's comment (including block attributes values). That HTML is not subject to the Post Editor’s validation. _Example: Markup representation of a block with dynamic rendering (`save` = `null`) and attributes_ - ```html ``` diff --git a/docs/getting-started/fundamentals/registration-of-a-block.md b/docs/getting-started/fundamentals/registration-of-a-block.md index 7d7b0e5ac3163..65cd85b0fa3e5 100644 --- a/docs/getting-started/fundamentals/registration-of-a-block.md +++ b/docs/getting-started/fundamentals/registration-of-a-block.md @@ -69,6 +69,7 @@ The content of block.json (or any other .json file) ca The client-side block settings object passed as a second parameter includes two especially relevant properties: + - `edit`: The React component that gets used in the editor for our block. - `save`: The function that returns the static HTML markup that gets saved to the Database. diff --git a/docs/getting-started/fundamentals/static-dynamic-rendering.md b/docs/getting-started/fundamentals/static-dynamic-rendering.md index 34d5432850c45..214fb9da8b40f 100644 --- a/docs/getting-started/fundamentals/static-dynamic-rendering.md +++ b/docs/getting-started/fundamentals/static-dynamic-rendering.md @@ -63,6 +63,7 @@ The markup stored for a block can be modified before it gets rendered on the fro Some examples of core blocks with static rendering are: + - [`separator`](https://github.com/WordPress/gutenberg/blob/trunk/packages/block-library/src/separator) (see its [`save`](https://github.com/WordPress/gutenberg/blob/trunk/packages/block-library/src/separator/save.js) function) - [`spacer`](https://github.com/WordPress/gutenberg/blob/trunk/packages/block-library/src/spacer) (see its [`save`](https://github.com/WordPress/gutenberg/blob/trunk/packages/block-library/src/spacer/save.js) function). - [`button`](https://github.com/WordPress/gutenberg/tree/trunk/packages/block-library/src/button) (see its [`save`](https://github.com/WordPress/gutenberg/blob/trunk/packages/block-library/src/button/save.js) function). @@ -82,10 +83,12 @@ There are some common use cases for dynamic blocks: ### How to define dynamic rendering for a block A block can define dynamic rendering in two main ways: + 1. Via the `render_callback` argument that can be passed to the [`register_block_type()` function](https://developer.wordpress.org/block-editor/getting-started/fundamentals/registration-of-a-block/#registration-of-the-block-with-php-server-side). -1. Via a separate PHP file (usually named `render.php`) which path can be defined at the [`render` property of the `block.json`](https://developer.wordpress.org/block-editor/getting-started/fundamentals/block-json/#files-for-the-blocks-behavior-output-or-style). +2. Via a separate PHP file (usually named `render.php`) which path can be defined at the [`render` property of the `block.json`](https://developer.wordpress.org/block-editor/getting-started/fundamentals/block-json/#files-for-the-blocks-behavior-output-or-style). Both of these ways to define the block's dynamic rendering receive the following data: + - `$attributes` - The array of attributes for this block. - `$content` - Rendered block output (markup of the block as stored in the database). - `$block` - The instance of the [WP_Block](https://developer.wordpress.org/reference/classes/wp_block/) class that represents the block being rendered ([metadata of the block](https://developer.wordpress.org/block-editor/reference-guides/block-api/block-metadata/)). @@ -95,7 +98,6 @@ Both of these ways to define the block's dynamic rendering receive the following For example, the [`site-title`](https://github.com/WordPress/gutenberg/tree/trunk/packages/block-library/src/site-title) core block with the following function registered as [`render_callback`](https://github.com/WordPress/gutenberg/blob/trunk/packages/block-library/src/site-title/index.php)... - ```php function render_block_core_site_title( $attributes ) { $site_title = get_bloginfo( 'name' ); @@ -159,6 +161,7 @@ For dynamic blocks, the `save` callback function can return just `null`, which t Blocks with dynamic rendering can also save an HTML representation of the block as a backup. If you provide a server-side rendering callback, the HTML representing the block in the database will be replaced with the output of your callback, but will be rendered if your block is deactivated (the plugin that registers the block is uninstalled) or your render callback is removed. In some cases, the block saves an HTML representation of the block and uses a dynamic rendering to fine-tune this markup if some conditions are met. Some examples of core blocks using this approach are: + - The [`cover`](https://github.com/WordPress/gutenberg/blob/trunk/packages/block-library/src/cover) block saves a [full HTML representation of the block in the database](https://github.com/WordPress/gutenberg/blob/trunk/packages/block-library/src/cover/save.js). This markup is processed via a [`render_callback`](https://github.com/WordPress/gutenberg/blob/22741661998834e69db74ad863705ee2ce97b446/packages/block-library/src/cover/index.php#L74) when requested to do some PHP magic that dynamically [injects the featured image if the "use featured image" setting is enabled](https://github.com/WordPress/gutenberg/blob/22741661998834e69db74ad863705ee2ce97b446/packages/block-library/src/cover/index.php#L16). - The [`image`](https://github.com/WordPress/gutenberg/blob/trunk/packages/block-library/src/image) block also saves [its HTML representation in the database](https://github.com/WordPress/gutenberg/blob/trunk/packages/block-library/src/image/save.js) and processes it via a [`render_callback`](https://github.com/WordPress/gutenberg/blob/22741661998834e69db74ad863705ee2ce97b446/packages/block-library/src/image/index.php#L363) when requested to [add some attributes to the markup](https://github.com/WordPress/gutenberg/blob/22741661998834e69db74ad863705ee2ce97b446/packages/block-library/src/image/index.php#L18) if some conditions are met. From fae5b9a270362ae103a44423dc957d14b7969c1b Mon Sep 17 00:00:00 2001 From: James Koster Date: Thu, 25 Jan 2024 08:49:54 +0000 Subject: [PATCH 04/47] Data views: Remove min-width style on table cells (#58204) * Remove min-width style * Reduce title maxwidth --- packages/dataviews/src/style.scss | 4 ---- packages/edit-site/src/components/page-pages/index.js | 2 +- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/packages/dataviews/src/style.scss b/packages/dataviews/src/style.scss index 07797d3624af7..6ce1b9dadcae5 100644 --- a/packages/dataviews/src/style.scss +++ b/packages/dataviews/src/style.scss @@ -87,10 +87,6 @@ padding: $grid-unit-15; white-space: nowrap; - @include break-huge() { - min-width: 200px; - } - &[data-field-id="actions"] { text-align: right; } diff --git a/packages/edit-site/src/components/page-pages/index.js b/packages/edit-site/src/components/page-pages/index.js index ea59eab333c42..603a7b30de2ed 100644 --- a/packages/edit-site/src/components/page-pages/index.js +++ b/packages/edit-site/src/components/page-pages/index.js @@ -298,7 +298,7 @@ export default function PagePages() { __( '(no title)' ) ); }, - maxWidth: 400, + maxWidth: 300, enableHiding: false, }, { From e0005a813686157e2f25f6d4b28cc72ebadbfaae Mon Sep 17 00:00:00 2001 From: Carolina Nymark Date: Thu, 25 Jan 2024 09:57:48 +0100 Subject: [PATCH 05/47] Follow up on the Post navigation link taxonomy filters (#57949) * Remove the taxonomy filter with hard coded slugs. * Remove inSameTerm attribute * Add filter for publicly_queryable taxonomies * simplify the check for the taxonomy attribute in index.php --- docs/reference-guides/core-blocks.md | 2 +- .../block-library/src/post-navigation-link/block.json | 3 --- packages/block-library/src/post-navigation-link/edit.js | 8 +------- packages/block-library/src/post-navigation-link/index.php | 7 ++----- 4 files changed, 4 insertions(+), 16 deletions(-) diff --git a/docs/reference-guides/core-blocks.md b/docs/reference-guides/core-blocks.md index 0cf9bb77f71f8..02c6c397d924c 100644 --- a/docs/reference-guides/core-blocks.md +++ b/docs/reference-guides/core-blocks.md @@ -639,7 +639,7 @@ Displays the next or previous post link that is adjacent to the current post. ([ - **Name:** core/post-navigation-link - **Category:** theme - **Supports:** color (background, link, text), typography (fontSize, lineHeight), ~~html~~, ~~reusable~~ -- **Attributes:** arrow, inSameTerm, label, linkLabel, showTitle, taxonomy, textAlign, type +- **Attributes:** arrow, label, linkLabel, showTitle, taxonomy, textAlign, type ## Post Template diff --git a/packages/block-library/src/post-navigation-link/block.json b/packages/block-library/src/post-navigation-link/block.json index 61d42f0e55f20..cdfecf6c627ca 100644 --- a/packages/block-library/src/post-navigation-link/block.json +++ b/packages/block-library/src/post-navigation-link/block.json @@ -29,9 +29,6 @@ "type": "string", "default": "none" }, - "inSameTerm": { - "type": "boolean" - }, "taxonomy": { "type": "string", "default": "" diff --git a/packages/block-library/src/post-navigation-link/edit.js b/packages/block-library/src/post-navigation-link/edit.js index 464531f9d4546..1c41367575cb6 100644 --- a/packages/block-library/src/post-navigation-link/edit.js +++ b/packages/block-library/src/post-navigation-link/edit.js @@ -66,7 +66,6 @@ export default function PostNavigationLinkEdit( { const filteredTaxonomies = getTaxonomies( { type: postType, per_page: -1, - context: 'view', } ); return filteredTaxonomies; }, @@ -78,11 +77,7 @@ export default function PostNavigationLinkEdit( { value: '', }; const taxonomyOptions = ( taxonomies ?? [] ) - .filter( - ( tax ) => - tax.slug !== 'nav_menu' && - tax.slug !== 'wp_pattern_category' - ) + .filter( ( { visibility } ) => !! visibility?.publicly_queryable ) .map( ( item ) => { return { value: item.slug, @@ -168,7 +163,6 @@ export default function PostNavigationLinkEdit( { onChange={ ( value ) => setAttributes( { taxonomy: value, - inSameTerm: value === '' ? false : true, } ) } help={ __( diff --git a/packages/block-library/src/post-navigation-link/index.php b/packages/block-library/src/post-navigation-link/index.php index 50106bdd7cce5..69c9a3f39f8a7 100644 --- a/packages/block-library/src/post-navigation-link/index.php +++ b/packages/block-library/src/post-navigation-link/index.php @@ -99,9 +99,6 @@ function render_block_core_post_navigation_link( $attributes, $content ) { } } - $in_same_term = isset( $attributes['inSameTerm'] ) ? $attributes['inSameTerm'] : false; - $taxonomy = isset( $attributes['taxonomy'] ) && $in_same_term ? $attributes['taxonomy'] : ''; - /** * The dynamic portion of the function name, `$navigation_type`, * Refers to the type of adjacency, 'next' or 'previous'. @@ -111,8 +108,8 @@ function render_block_core_post_navigation_link( $attributes, $content ) { */ $get_link_function = "get_{$navigation_type}_post_link"; - if ( $in_same_term ) { - $content = $get_link_function( $format, $link, $in_same_term, '', $taxonomy ); + if ( ! empty( $attributes['taxonomy'] ) ) { + $content = $get_link_function( $format, $link, true, '', $attributes['taxonomy'] ); } else { $content = $get_link_function( $format, $link ); } From 246db96b86f6adb19e200fc4a2d71a1a6e0b32bf Mon Sep 17 00:00:00 2001 From: Aki Hamano <54422211+t-hamano@users.noreply.github.com> Date: Thu, 25 Jan 2024 20:02:17 +0900 Subject: [PATCH 06/47] Font Library: Refactor stylesheet using CSS variables (#58237) --- .../font-library-modal/style.scss | 53 +++++++------------ 1 file changed, 20 insertions(+), 33 deletions(-) diff --git a/packages/edit-site/src/components/global-styles/font-library-modal/style.scss b/packages/edit-site/src/components/global-styles/font-library-modal/style.scss index 99599d179f019..4b8e69abcfc2b 100644 --- a/packages/edit-site/src/components/global-styles/font-library-modal/style.scss +++ b/packages/edit-site/src/components/global-styles/font-library-modal/style.scss @@ -27,17 +27,17 @@ .font-library-modal__tabpanel-layout { main { - padding-bottom: 4rem; + padding-bottom: $grid-unit-80; } footer { - border-top: 1px solid #e5e5e5; - margin: 0 -32px -32px; - padding: 16px 32px; + border-top: 1px solid $gray-300; + margin: 0 #{$grid-unit-40 * -1} #{$grid-unit-40 * -1}; + padding: $grid-unit-20 $grid-unit-40; position: absolute; - bottom: 32px; + bottom: $grid-unit-40; width: 100%; - background-color: #fff; + background-color: $white; } } @@ -50,10 +50,10 @@ } .font-library-modal__font-card { - border: 1px solid #e5e5e5; + border: 1px solid $gray-200; width: 100%; height: auto; - padding: 1rem; + padding: $grid-unit-20; margin-top: -1px; /* To collapse the margin with the previous element */ .font-library-modal__font-card__name { @@ -61,30 +61,29 @@ } .font-library-modal__font-card__count { - color: #6e6e6e; + color: $gray-700; } } .font-library-modal__library-font-variant { - border: 1px solid #e5e5e5; - padding: 1rem; + border: 1px solid $gray-200; + padding: $grid-unit-20; margin-top: -1px; /* To collapse the margin with the previous element */ } .font-library-modal__font-variant { - border-bottom: 1px solid #e5e5e5; - padding-bottom: 1rem; + border-bottom: 1px solid $gray-200; + padding-bottom: $grid-unit-20; } .font-library-modal__tabs { [role="tablist"] { position: sticky; top: 0; - width: calc(100% + 64px); - border-bottom: 1px solid #e6e6e6; - background: #fff; - margin: 0 -32px; - padding: 0 16px; + border-bottom: 1px solid $gray-300; + background: $white; + margin: 0 #{$grid-unit-40 * -1}; + padding: 0 $grid-unit-20; z-index: 1; } } @@ -93,12 +92,12 @@ align-items: center; display: flex; justify-content: center; - height: 250px; + height: $grid-unit-80 * 4; // 256px width: 100%; } button.font-library-modal__upload-area { - background-color: #f0f0f0; + background-color: $gray-100; } .font-library-modal__local-fonts { @@ -106,7 +105,7 @@ button.font-library-modal__upload-area { width: 80%; .font-library-modal__upload-area__text { - color: #6e6e6e; + color: $gray-700; } .font-library-modal__upload-area__notice { @@ -114,14 +113,6 @@ button.font-library-modal__upload-area { } } -.font-library-modal__font-name { - font-weight: bold; -} - -.font-library-modal__font-filename { - color: #6e6e6e; -} - .font-library-modal__font-variant_demo-wrapper { white-space: nowrap; overflow: hidden; @@ -154,7 +145,3 @@ button.font-library-modal__upload-area { max-width: 350px; } } - -.font-library-modal__font-collection__notice { - margin: 0; -} From 571209438b0f878fc6ad83a9842e978c0ab714b1 Mon Sep 17 00:00:00 2001 From: Lena Morita Date: Thu, 25 Jan 2024 20:14:19 +0900 Subject: [PATCH 07/47] Storybook: Add badges to private components (#58123) * Storybook: Set up badges for private components * Add badges * Add badge for WIP --- package-lock.json | 32 +++++++++++++++++++ package.json | 1 + .../stories/index.story.tsx | 1 + .../dropdown-menu-v2/stories/index.story.tsx | 1 + .../src/progress-bar/stories/index.story.tsx | 1 + .../src/tabs/stories/index.story.tsx | 1 + .../src/theme/stories/index.story.tsx | 1 + storybook/main.js | 1 + storybook/preview.js | 24 ++++++++++++++ 9 files changed, 63 insertions(+) diff --git a/package-lock.json b/package-lock.json index c6669febe69f8..3a1d40aa412cc 100644 --- a/package-lock.json +++ b/package-lock.json @@ -95,6 +95,7 @@ "@emotion/babel-plugin": "11.3.0", "@emotion/jest": "11.7.1", "@emotion/native": "11.0.0", + "@geometricpanda/storybook-addon-badges": "2.0.1", "@octokit/rest": "16.26.0", "@octokit/types": "6.34.0", "@octokit/webhooks-types": "5.6.0", @@ -5151,6 +5152,31 @@ "resolved": "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.1.2.tgz", "integrity": "sha512-ou3elfqG/hZsbmF4bxeJhPHIf3G2pm0ujc39hYEZrfVqt7Vk/Zji6CXc3W0pmYM8BW1g40U+akTl9DKZhFhInQ==" }, + "node_modules/@geometricpanda/storybook-addon-badges": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@geometricpanda/storybook-addon-badges/-/storybook-addon-badges-2.0.1.tgz", + "integrity": "sha512-dCEK/xJewuFe1d+ndF0hQIAJRnUsV9q5kuDmp7zvO7fTd7cDz0X9Bjz0lNRn6n4Z9bL9/iFHKzJESDHFfs4ihQ==", + "dev": true, + "peerDependencies": { + "@storybook/blocks": "^7.0.0", + "@storybook/components": "^7.0.0", + "@storybook/core-events": "^7.0.0", + "@storybook/manager-api": "^7.0.0", + "@storybook/preview-api": "^7.0.0", + "@storybook/theming": "^7.0.0", + "@storybook/types": "^7.0.0", + "react": "^16.8.0 || ^17.0.0 || ^18.0.0", + "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0" + }, + "peerDependenciesMeta": { + "react": { + "optional": true + }, + "react-dom": { + "optional": true + } + } + }, "node_modules/@hapi/hoek": { "version": "9.2.1", "resolved": "https://registry.npmjs.org/@hapi/hoek/-/hoek-9.2.1.tgz", @@ -59813,6 +59839,12 @@ "resolved": "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.1.2.tgz", "integrity": "sha512-ou3elfqG/hZsbmF4bxeJhPHIf3G2pm0ujc39hYEZrfVqt7Vk/Zji6CXc3W0pmYM8BW1g40U+akTl9DKZhFhInQ==" }, + "@geometricpanda/storybook-addon-badges": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@geometricpanda/storybook-addon-badges/-/storybook-addon-badges-2.0.1.tgz", + "integrity": "sha512-dCEK/xJewuFe1d+ndF0hQIAJRnUsV9q5kuDmp7zvO7fTd7cDz0X9Bjz0lNRn6n4Z9bL9/iFHKzJESDHFfs4ihQ==", + "dev": true + }, "@hapi/hoek": { "version": "9.2.1", "resolved": "https://registry.npmjs.org/@hapi/hoek/-/hoek-9.2.1.tgz", diff --git a/package.json b/package.json index e47b3580c2a41..243e70ccc504c 100644 --- a/package.json +++ b/package.json @@ -107,6 +107,7 @@ "@emotion/babel-plugin": "11.3.0", "@emotion/jest": "11.7.1", "@emotion/native": "11.0.0", + "@geometricpanda/storybook-addon-badges": "2.0.1", "@octokit/rest": "16.26.0", "@octokit/types": "6.34.0", "@octokit/webhooks-types": "5.6.0", diff --git a/packages/components/src/custom-select-control-v2/stories/index.story.tsx b/packages/components/src/custom-select-control-v2/stories/index.story.tsx index 2c7ae3507046b..7714edc86157c 100644 --- a/packages/components/src/custom-select-control-v2/stories/index.story.tsx +++ b/packages/components/src/custom-select-control-v2/stories/index.story.tsx @@ -26,6 +26,7 @@ const meta: Meta< typeof CustomSelect > = { value: { control: { type: null } }, }, parameters: { + badges: [ 'wip' ], actions: { argTypesRegex: '^on.*' }, controls: { expanded: true }, docs: { diff --git a/packages/components/src/dropdown-menu-v2/stories/index.story.tsx b/packages/components/src/dropdown-menu-v2/stories/index.story.tsx index 343da0b7839d3..9e606770caa3a 100644 --- a/packages/components/src/dropdown-menu-v2/stories/index.story.tsx +++ b/packages/components/src/dropdown-menu-v2/stories/index.story.tsx @@ -58,6 +58,7 @@ const meta: Meta< typeof DropdownMenu > = { }, parameters: { actions: { argTypesRegex: '^on.*' }, + badges: [ 'private' ], controls: { expanded: true }, docs: { canvas: { sourceState: 'shown' }, diff --git a/packages/components/src/progress-bar/stories/index.story.tsx b/packages/components/src/progress-bar/stories/index.story.tsx index e3d217ffd3f41..e213ea34db139 100644 --- a/packages/components/src/progress-bar/stories/index.story.tsx +++ b/packages/components/src/progress-bar/stories/index.story.tsx @@ -15,6 +15,7 @@ const meta: Meta< typeof ProgressBar > = { value: { control: { type: 'number', min: 0, max: 100, step: 1 } }, }, parameters: { + badges: [ 'private' ], controls: { expanded: true, }, diff --git a/packages/components/src/tabs/stories/index.story.tsx b/packages/components/src/tabs/stories/index.story.tsx index 0e7ab725e371d..632aaf0ac9242 100644 --- a/packages/components/src/tabs/stories/index.story.tsx +++ b/packages/components/src/tabs/stories/index.story.tsx @@ -30,6 +30,7 @@ const meta: Meta< typeof Tabs > = { }, parameters: { actions: { argTypesRegex: '^on.*' }, + badges: [ 'private' ], controls: { expanded: true }, docs: { canvas: { sourceState: 'shown' } }, }, diff --git a/packages/components/src/theme/stories/index.story.tsx b/packages/components/src/theme/stories/index.story.tsx index 3d52dea7fba57..4e231cf2624cd 100644 --- a/packages/components/src/theme/stories/index.story.tsx +++ b/packages/components/src/theme/stories/index.story.tsx @@ -19,6 +19,7 @@ const meta: Meta< typeof Theme > = { background: { control: { type: 'color' } }, }, parameters: { + badges: [ 'private' ], controls: { expanded: true }, docs: { canvas: { sourceState: 'shown' } }, }, diff --git a/storybook/main.js b/storybook/main.js index 45123a7c1ff23..97f974b40027e 100644 --- a/storybook/main.js +++ b/storybook/main.js @@ -52,6 +52,7 @@ module.exports = { '@storybook/addon-toolbars', '@storybook/addon-actions', 'storybook-source-link', + '@geometricpanda/storybook-addon-badges', ], framework: { name: '@storybook/react-webpack5', diff --git a/storybook/preview.js b/storybook/preview.js index 61bdef8aae5f3..02b3ab22ed355 100644 --- a/storybook/preview.js +++ b/storybook/preview.js @@ -99,6 +99,30 @@ export const decorators = [ ]; export const parameters = { + // For @geometricpanda/storybook-addon-badges + badgesConfig: { + private: { + title: '🔒 Private', + tooltip: { + title: 'Component is locked as a private API', + desc: 'We do not yet recommend using this outside of the Gutenberg codebase.', + links: [ + { + title: 'About @wordpress/private-apis', + href: 'https://developer.wordpress.org/block-editor/reference-guides/packages/packages-private-apis/', + }, + ], + }, + }, + wip: { + title: '🚧 WIP', + styles: { backgroundColor: '#FFF0BD' }, + tooltip: { + title: 'Component is a work in progress', + desc: 'This component is not ready for use in production, including the Gutenberg codebase. DO NOT export outside of @wordpress/components.', + }, + }, + }, controls: { sort: 'requiredFirst', }, From 44eaeac3d08ce225ee4183e899c4fd685ae11ca2 Mon Sep 17 00:00:00 2001 From: Sarah Norris <1645628+mikachan@users.noreply.github.com> Date: Thu, 25 Jan 2024 11:14:34 +0000 Subject: [PATCH 08/47] Font Library: Typo fixes (#58243) * Fix typo in library-font-variant.js * Fix typos in __construct.php * Fix typos in isConfigValid.php --- .../font-library-modal/library-font-variant.js | 4 ++-- .../fonts/font-library/wpFontCollection/__construct.php | 6 +++--- .../fonts/font-library/wpFontCollection/isConfigValid.php | 6 +++--- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/packages/edit-site/src/components/global-styles/font-library-modal/library-font-variant.js b/packages/edit-site/src/components/global-styles/font-library-modal/library-font-variant.js index 94fee2852478e..0d84b9fbcb5ae 100644 --- a/packages/edit-site/src/components/global-styles/font-library-modal/library-font-variant.js +++ b/packages/edit-site/src/components/global-styles/font-library-modal/library-font-variant.js @@ -20,7 +20,7 @@ function LibraryFontVariant( { face, font } ) { const { isFontActivated, toggleActivateFont } = useContext( FontLibraryContext ); - const isIstalled = + const isInstalled = font?.fontFace?.length > 0 ? isFontActivated( font.slug, @@ -52,7 +52,7 @@ function LibraryFontVariant( { face, font } ) { setExpectedIncorrectUsage( 'WP_Font_Collection::is_config_valid' ); new WP_Font_Collection( $config ); } @@ -65,7 +65,7 @@ public function test_should_do_ti_wrong( $config ) { * * @return array */ - public function data_should_do_ti_wrong() { + public function data_should_do_it_wrong() { return array( 'no id' => array( array( diff --git a/phpunit/tests/fonts/font-library/wpFontCollection/isConfigValid.php b/phpunit/tests/fonts/font-library/wpFontCollection/isConfigValid.php index 7cfdfc829ab86..9179db9db10a8 100644 --- a/phpunit/tests/fonts/font-library/wpFontCollection/isConfigValid.php +++ b/phpunit/tests/fonts/font-library/wpFontCollection/isConfigValid.php @@ -44,16 +44,16 @@ public function data_is_config_valid() { } /** - * @dataProvider data_is_config_valid_should_call_doing_ti_wrong + * @dataProvider data_is_config_valid_should_call_doing_it_wrong * * @param mixed $config Config of the font collection. */ - public function test_is_config_valid_should_call_doing_ti_wrong( $config ) { + public function test_is_config_valid_should_call_doing_it_wrong( $config ) { $this->setExpectedIncorrectUsage( 'WP_Font_Collection::is_config_valid', 'Should call _doing_it_wrong if the config is not valid.' ); $this->assertFalse( WP_Font_Collection::is_config_valid( $config ), 'Should return false if the config is not valid.' ); } - public function data_is_config_valid_should_call_doing_ti_wrong() { + public function data_is_config_valid_should_call_doing_it_wrong() { return array( 'with missing slug' => array( 'config' => array( From 1e62218d4df79734720ac928d12119ff872e43a0 Mon Sep 17 00:00:00 2001 From: Jason Crist Date: Thu, 25 Jan 2024 06:39:31 -0500 Subject: [PATCH 09/47] Removed
and