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

ToolsPanel: Add CSS classes to first and last displayed ToolsPanelItems #37546

Merged
merged 11 commits into from
Jan 21, 2022

Conversation

aaronrobertshaw
Copy link
Contributor

@aaronrobertshaw aaronrobertshaw commented Dec 21, 2021

Related:

Description

The switch of the Color block support panel to the ToolsPanel requires rendering the color controls as the new color dropdowns within an ItemGroup. To maintain the order of controls when some are injected via SlotFill, the ToolsPanel will render placeholder elements that are hidden. These placeholders interfere with the normal ItemGroup styling which relies on CSS pseudo-selectors e.g. :last-child.

To achieve the same result we need to be able to target the first and last displayed ToolsPanelItems. This PR aims to achieve that by applying first and last CSS classes to the appropriate ToolsPanelItem.

How has this been tested?

A simple unit test is included with these changes.

Manually:
  1. Load the block editor, add a group block, and select it.
  2. Inspect the various ToolsPanel panels in the sidebar and ensure the correct items get the new classes
  3. Update the group block's configuration via its block.json file. Test various options like mixing optional and default controls etc.
  4. Bonus points: Inject some test ad hoc controls into the group block and confirm panel item order and classes.
Example ad hoc control for group block

Note this control isn't meant to be fully functional.

diff --git a/packages/block-library/src/group/edit.js b/packages/block-library/src/group/edit.js
index 3209106ff8..aef9e240a9 100644
--- a/packages/block-library/src/group/edit.js
+++ b/packages/block-library/src/group/edit.js
@@ -9,6 +9,7 @@ import {
 	useInnerBlocksProps,
 	useSetting,
 	store as blockEditorStore,
+	__experimentalToolsPanelColorDropdown as ToolsPanelColorDropdown,
 } from '@wordpress/block-editor';
 import { SelectControl } from '@wordpress/components';
 import { __ } from '@wordpress/i18n';
@@ -68,6 +69,22 @@ function GroupEdit( { attributes, setAttributes, clientId } ) {
 
 	return (
 		<>
+			<InspectorControls __experimentalGroup="color">
+				<ToolsPanelColorDropdown
+					settings={ {
+						label: 'Overlay',
+						colorValue: undefined,
+						onColorChange: () => undefined,
+						gradientValue: undefined,
+						onGradientChange: () => undefined,
+						isShownByDefault: false,
+						hasValue: () => undefined,
+						onDeselect: () => undefined,
+						resetAllFilter: undefined,
+					} }
+					panelId={ clientId }
+				/>
+			</InspectorControls>
 			<InspectorControls __experimentalGroup="advanced">
 				<SelectControl
 					label={ __( 'HTML element' ) }

Types of changes

New feature.

Checklist:

  • My code is tested.
  • My code follows the WordPress code style.
  • My code follows the accessibility standards.
  • I've tested my changes with keyboard and screen readers.
  • My code has proper inline documentation.
  • I've included developer documentation if appropriate.
  • I've updated all React Native files affected by any refactorings/renamings in this PR (please manually search all *.native.js files for terms that need renaming or removal).

@aaronrobertshaw aaronrobertshaw added [Type] Enhancement A suggestion for improvement. [Feature] UI Components Impacts or related to the UI component system labels Dec 21, 2021
@aaronrobertshaw aaronrobertshaw self-assigned this Dec 21, 2021
@github-actions
Copy link

github-actions bot commented Dec 21, 2021

Size Change: +138 B (0%)

Total Size: 1.13 MB

Filename Size Change
build/components/index.min.js 214 kB +138 B (0%)
ℹ️ View Unchanged
Filename Size
build/a11y/index.min.js 960 B
build/admin-manifest/index.min.js 1.1 kB
build/annotations/index.min.js 2.75 kB
build/api-fetch/index.min.js 2.21 kB
build/autop/index.min.js 2.12 kB
build/blob/index.min.js 459 B
build/block-directory/index.min.js 6.28 kB
build/block-directory/style-rtl.css 1.01 kB
build/block-directory/style.css 1.01 kB
build/block-editor/default-editor-styles-rtl.css 378 B
build/block-editor/default-editor-styles.css 378 B
build/block-editor/index.min.js 141 kB
build/block-editor/style-rtl.css 14.6 kB
build/block-editor/style.css 14.6 kB
build/block-library/blocks/archives/editor-rtl.css 61 B
build/block-library/blocks/archives/editor.css 60 B
build/block-library/blocks/archives/style-rtl.css 65 B
build/block-library/blocks/archives/style.css 65 B
build/block-library/blocks/audio/editor-rtl.css 150 B
build/block-library/blocks/audio/editor.css 150 B
build/block-library/blocks/audio/style-rtl.css 111 B
build/block-library/blocks/audio/style.css 111 B
build/block-library/blocks/audio/theme-rtl.css 125 B
build/block-library/blocks/audio/theme.css 125 B
build/block-library/blocks/block/editor-rtl.css 161 B
build/block-library/blocks/block/editor.css 161 B
build/block-library/blocks/button/editor-rtl.css 470 B
build/block-library/blocks/button/editor.css 470 B
build/block-library/blocks/button/style-rtl.css 560 B
build/block-library/blocks/button/style.css 560 B
build/block-library/blocks/buttons/editor-rtl.css 292 B
build/block-library/blocks/buttons/editor.css 292 B
build/block-library/blocks/buttons/style-rtl.css 275 B
build/block-library/blocks/buttons/style.css 275 B
build/block-library/blocks/calendar/style-rtl.css 207 B
build/block-library/blocks/calendar/style.css 207 B
build/block-library/blocks/categories/editor-rtl.css 84 B
build/block-library/blocks/categories/editor.css 83 B
build/block-library/blocks/categories/style-rtl.css 79 B
build/block-library/blocks/categories/style.css 79 B
build/block-library/blocks/code/style-rtl.css 90 B
build/block-library/blocks/code/style.css 90 B
build/block-library/blocks/code/theme-rtl.css 131 B
build/block-library/blocks/code/theme.css 131 B
build/block-library/blocks/columns/editor-rtl.css 108 B
build/block-library/blocks/columns/editor.css 108 B
build/block-library/blocks/columns/style-rtl.css 406 B
build/block-library/blocks/columns/style.css 406 B
build/block-library/blocks/comment-template/style-rtl.css 127 B
build/block-library/blocks/comment-template/style.css 127 B
build/block-library/blocks/comments-pagination-numbers/editor-rtl.css 123 B
build/block-library/blocks/comments-pagination-numbers/editor.css 121 B
build/block-library/blocks/comments-pagination/editor-rtl.css 222 B
build/block-library/blocks/comments-pagination/editor.css 209 B
build/block-library/blocks/comments-pagination/style-rtl.css 235 B
build/block-library/blocks/comments-pagination/style.css 231 B
build/block-library/blocks/cover/editor-rtl.css 546 B
build/block-library/blocks/cover/editor.css 547 B
build/block-library/blocks/cover/style-rtl.css 1.22 kB
build/block-library/blocks/cover/style.css 1.22 kB
build/block-library/blocks/embed/editor-rtl.css 293 B
build/block-library/blocks/embed/editor.css 293 B
build/block-library/blocks/embed/style-rtl.css 417 B
build/block-library/blocks/embed/style.css 417 B
build/block-library/blocks/embed/theme-rtl.css 124 B
build/block-library/blocks/embed/theme.css 124 B
build/block-library/blocks/file/editor-rtl.css 300 B
build/block-library/blocks/file/editor.css 300 B
build/block-library/blocks/file/style-rtl.css 255 B
build/block-library/blocks/file/style.css 255 B
build/block-library/blocks/file/view.min.js 322 B
build/block-library/blocks/freeform/editor-rtl.css 2.44 kB
build/block-library/blocks/freeform/editor.css 2.44 kB
build/block-library/blocks/gallery/editor-rtl.css 965 B
build/block-library/blocks/gallery/editor.css 967 B
build/block-library/blocks/gallery/style-rtl.css 1.6 kB
build/block-library/blocks/gallery/style.css 1.6 kB
build/block-library/blocks/gallery/theme-rtl.css 122 B
build/block-library/blocks/gallery/theme.css 122 B
build/block-library/blocks/group/editor-rtl.css 159 B
build/block-library/blocks/group/editor.css 159 B
build/block-library/blocks/group/style-rtl.css 57 B
build/block-library/blocks/group/style.css 57 B
build/block-library/blocks/group/theme-rtl.css 78 B
build/block-library/blocks/group/theme.css 78 B
build/block-library/blocks/heading/style-rtl.css 114 B
build/block-library/blocks/heading/style.css 114 B
build/block-library/blocks/html/editor-rtl.css 332 B
build/block-library/blocks/html/editor.css 333 B
build/block-library/blocks/image/editor-rtl.css 810 B
build/block-library/blocks/image/editor.css 809 B
build/block-library/blocks/image/style-rtl.css 507 B
build/block-library/blocks/image/style.css 511 B
build/block-library/blocks/image/theme-rtl.css 124 B
build/block-library/blocks/image/theme.css 124 B
build/block-library/blocks/latest-comments/style-rtl.css 284 B
build/block-library/blocks/latest-comments/style.css 284 B
build/block-library/blocks/latest-posts/editor-rtl.css 137 B
build/block-library/blocks/latest-posts/editor.css 137 B
build/block-library/blocks/latest-posts/style-rtl.css 528 B
build/block-library/blocks/latest-posts/style.css 527 B
build/block-library/blocks/list/style-rtl.css 94 B
build/block-library/blocks/list/style.css 94 B
build/block-library/blocks/media-text/editor-rtl.css 266 B
build/block-library/blocks/media-text/editor.css 263 B
build/block-library/blocks/media-text/style-rtl.css 493 B
build/block-library/blocks/media-text/style.css 490 B
build/block-library/blocks/more/editor-rtl.css 431 B
build/block-library/blocks/more/editor.css 431 B
build/block-library/blocks/navigation-link/editor-rtl.css 649 B
build/block-library/blocks/navigation-link/editor.css 650 B
build/block-library/blocks/navigation-link/style-rtl.css 94 B
build/block-library/blocks/navigation-link/style.css 94 B
build/block-library/blocks/navigation-submenu/editor-rtl.css 299 B
build/block-library/blocks/navigation-submenu/editor.css 299 B
build/block-library/blocks/navigation-submenu/view.min.js 343 B
build/block-library/blocks/navigation/editor-rtl.css 1.99 kB
build/block-library/blocks/navigation/editor.css 2 kB
build/block-library/blocks/navigation/style-rtl.css 1.85 kB
build/block-library/blocks/navigation/style.css 1.84 kB
build/block-library/blocks/navigation/view.min.js 2.81 kB
build/block-library/blocks/nextpage/editor-rtl.css 395 B
build/block-library/blocks/nextpage/editor.css 395 B
build/block-library/blocks/page-list/editor-rtl.css 401 B
build/block-library/blocks/page-list/editor.css 402 B
build/block-library/blocks/page-list/style-rtl.css 175 B
build/block-library/blocks/page-list/style.css 175 B
build/block-library/blocks/paragraph/editor-rtl.css 157 B
build/block-library/blocks/paragraph/editor.css 157 B
build/block-library/blocks/paragraph/style-rtl.css 273 B
build/block-library/blocks/paragraph/style.css 273 B
build/block-library/blocks/post-author/style-rtl.css 175 B
build/block-library/blocks/post-author/style.css 176 B
build/block-library/blocks/post-comments-form/style-rtl.css 446 B
build/block-library/blocks/post-comments-form/style.css 446 B
build/block-library/blocks/post-comments/style-rtl.css 521 B
build/block-library/blocks/post-comments/style.css 521 B
build/block-library/blocks/post-excerpt/editor-rtl.css 73 B
build/block-library/blocks/post-excerpt/editor.css 73 B
build/block-library/blocks/post-excerpt/style-rtl.css 69 B
build/block-library/blocks/post-excerpt/style.css 69 B
build/block-library/blocks/post-featured-image/editor-rtl.css 721 B
build/block-library/blocks/post-featured-image/editor.css 721 B
build/block-library/blocks/post-featured-image/style-rtl.css 153 B
build/block-library/blocks/post-featured-image/style.css 153 B
build/block-library/blocks/post-template/editor-rtl.css 99 B
build/block-library/blocks/post-template/editor.css 98 B
build/block-library/blocks/post-template/style-rtl.css 305 B
build/block-library/blocks/post-template/style.css 305 B
build/block-library/blocks/post-terms/style-rtl.css 73 B
build/block-library/blocks/post-terms/style.css 73 B
build/block-library/blocks/post-title/style-rtl.css 80 B
build/block-library/blocks/post-title/style.css 80 B
build/block-library/blocks/preformatted/style-rtl.css 103 B
build/block-library/blocks/preformatted/style.css 103 B
build/block-library/blocks/pullquote/editor-rtl.css 198 B
build/block-library/blocks/pullquote/editor.css 198 B
build/block-library/blocks/pullquote/style-rtl.css 389 B
build/block-library/blocks/pullquote/style.css 388 B
build/block-library/blocks/pullquote/theme-rtl.css 167 B
build/block-library/blocks/pullquote/theme.css 167 B
build/block-library/blocks/query-pagination-numbers/editor-rtl.css 122 B
build/block-library/blocks/query-pagination-numbers/editor.css 121 B
build/block-library/blocks/query-pagination/editor-rtl.css 221 B
build/block-library/blocks/query-pagination/editor.css 211 B
build/block-library/blocks/query-pagination/style-rtl.css 234 B
build/block-library/blocks/query-pagination/style.css 231 B
build/block-library/blocks/query/editor-rtl.css 131 B
build/block-library/blocks/query/editor.css 132 B
build/block-library/blocks/quote/style-rtl.css 187 B
build/block-library/blocks/quote/style.css 187 B
build/block-library/blocks/quote/theme-rtl.css 223 B
build/block-library/blocks/quote/theme.css 226 B
build/block-library/blocks/rss/editor-rtl.css 202 B
build/block-library/blocks/rss/editor.css 204 B
build/block-library/blocks/rss/style-rtl.css 289 B
build/block-library/blocks/rss/style.css 288 B
build/block-library/blocks/search/editor-rtl.css 165 B
build/block-library/blocks/search/editor.css 165 B
build/block-library/blocks/search/style-rtl.css 397 B
build/block-library/blocks/search/style.css 398 B
build/block-library/blocks/search/theme-rtl.css 64 B
build/block-library/blocks/search/theme.css 64 B
build/block-library/blocks/separator/editor-rtl.css 99 B
build/block-library/blocks/separator/editor.css 99 B
build/block-library/blocks/separator/style-rtl.css 245 B
build/block-library/blocks/separator/style.css 245 B
build/block-library/blocks/separator/theme-rtl.css 172 B
build/block-library/blocks/separator/theme.css 172 B
build/block-library/blocks/shortcode/editor-rtl.css 474 B
build/block-library/blocks/shortcode/editor.css 474 B
build/block-library/blocks/site-logo/editor-rtl.css 744 B
build/block-library/blocks/site-logo/editor.css 744 B
build/block-library/blocks/site-logo/style-rtl.css 181 B
build/block-library/blocks/site-logo/style.css 181 B
build/block-library/blocks/site-tagline/editor-rtl.css 86 B
build/block-library/blocks/site-tagline/editor.css 86 B
build/block-library/blocks/site-title/editor-rtl.css 84 B
build/block-library/blocks/site-title/editor.css 84 B
build/block-library/blocks/social-link/editor-rtl.css 177 B
build/block-library/blocks/social-link/editor.css 177 B
build/block-library/blocks/social-links/editor-rtl.css 670 B
build/block-library/blocks/social-links/editor.css 669 B
build/block-library/blocks/social-links/style-rtl.css 1.32 kB
build/block-library/blocks/social-links/style.css 1.32 kB
build/block-library/blocks/spacer/editor-rtl.css 332 B
build/block-library/blocks/spacer/editor.css 332 B
build/block-library/blocks/spacer/style-rtl.css 48 B
build/block-library/blocks/spacer/style.css 48 B
build/block-library/blocks/table/editor-rtl.css 471 B
build/block-library/blocks/table/editor.css 472 B
build/block-library/blocks/table/style-rtl.css 481 B
build/block-library/blocks/table/style.css 481 B
build/block-library/blocks/table/theme-rtl.css 188 B
build/block-library/blocks/table/theme.css 188 B
build/block-library/blocks/tag-cloud/style-rtl.css 214 B
build/block-library/blocks/tag-cloud/style.css 215 B
build/block-library/blocks/template-part/editor-rtl.css 560 B
build/block-library/blocks/template-part/editor.css 559 B
build/block-library/blocks/template-part/theme-rtl.css 101 B
build/block-library/blocks/template-part/theme.css 101 B
build/block-library/blocks/text-columns/editor-rtl.css 95 B
build/block-library/blocks/text-columns/editor.css 95 B
build/block-library/blocks/text-columns/style-rtl.css 166 B
build/block-library/blocks/text-columns/style.css 166 B
build/block-library/blocks/verse/style-rtl.css 87 B
build/block-library/blocks/verse/style.css 87 B
build/block-library/blocks/video/editor-rtl.css 571 B
build/block-library/blocks/video/editor.css 572 B
build/block-library/blocks/video/style-rtl.css 173 B
build/block-library/blocks/video/style.css 173 B
build/block-library/blocks/video/theme-rtl.css 124 B
build/block-library/blocks/video/theme.css 124 B
build/block-library/common-rtl.css 908 B
build/block-library/common.css 905 B
build/block-library/editor-rtl.css 10.1 kB
build/block-library/editor.css 10.1 kB
build/block-library/index.min.js 166 kB
build/block-library/reset-rtl.css 474 B
build/block-library/reset.css 474 B
build/block-library/style-rtl.css 10.8 kB
build/block-library/style.css 10.8 kB
build/block-library/theme-rtl.css 672 B
build/block-library/theme.css 676 B
build/block-serialization-default-parser/index.min.js 1.09 kB
build/block-serialization-spec-parser/index.min.js 2.79 kB
build/blocks/index.min.js 46.4 kB
build/components/style-rtl.css 15.5 kB
build/components/style.css 15.5 kB
build/compose/index.min.js 11.2 kB
build/core-data/index.min.js 13.3 kB
build/customize-widgets/index.min.js 11.4 kB
build/customize-widgets/style-rtl.css 1.5 kB
build/customize-widgets/style.css 1.49 kB
build/data-controls/index.min.js 631 B
build/data/index.min.js 7.49 kB
build/date/index.min.js 31.9 kB
build/deprecated/index.min.js 485 B
build/dom-ready/index.min.js 304 B
build/dom/index.min.js 4.5 kB
build/edit-navigation/index.min.js 16 kB
build/edit-navigation/style-rtl.css 3.76 kB
build/edit-navigation/style.css 3.76 kB
build/edit-post/classic-rtl.css 546 B
build/edit-post/classic.css 547 B
build/edit-post/index.min.js 29.6 kB
build/edit-post/style-rtl.css 7.15 kB
build/edit-post/style.css 7.14 kB
build/edit-site/index.min.js 37.7 kB
build/edit-site/style-rtl.css 6.85 kB
build/edit-site/style.css 6.84 kB
build/edit-widgets/index.min.js 16.5 kB
build/edit-widgets/style-rtl.css 4.17 kB
build/edit-widgets/style.css 4.17 kB
build/editor/index.min.js 38.4 kB
build/editor/style-rtl.css 3.71 kB
build/editor/style.css 3.71 kB
build/element/index.min.js 3.29 kB
build/escape-html/index.min.js 517 B
build/format-library/index.min.js 6.58 kB
build/format-library/style-rtl.css 571 B
build/format-library/style.css 571 B
build/hooks/index.min.js 1.63 kB
build/html-entities/index.min.js 424 B
build/i18n/index.min.js 3.75 kB
build/is-shallow-equal/index.min.js 501 B
build/keyboard-shortcuts/index.min.js 1.8 kB
build/keycodes/index.min.js 1.39 kB
build/list-reusable-blocks/index.min.js 1.72 kB
build/list-reusable-blocks/style-rtl.css 838 B
build/list-reusable-blocks/style.css 838 B
build/media-utils/index.min.js 2.92 kB
build/notices/index.min.js 925 B
build/nux/index.min.js 2.08 kB
build/nux/style-rtl.css 747 B
build/nux/style.css 743 B
build/plugins/index.min.js 1.84 kB
build/primitives/index.min.js 924 B
build/priority-queue/index.min.js 582 B
build/react-i18n/index.min.js 671 B
build/react-refresh-entry/index.min.js 8.44 kB
build/react-refresh-runtime/index.min.js 7.31 kB
build/redux-routine/index.min.js 2.65 kB
build/reusable-blocks/index.min.js 2.22 kB
build/reusable-blocks/style-rtl.css 256 B
build/reusable-blocks/style.css 256 B
build/rich-text/index.min.js 11 kB
build/server-side-render/index.min.js 1.58 kB
build/shortcode/index.min.js 1.49 kB
build/token-list/index.min.js 639 B
build/url/index.min.js 1.9 kB
build/viewport/index.min.js 1.05 kB
build/warning/index.min.js 248 B
build/widgets/index.min.js 7.15 kB
build/widgets/style-rtl.css 1.16 kB
build/widgets/style.css 1.16 kB
build/wordcount/index.min.js 1.04 kB

compressed-size-action

@ramonjd
Copy link
Member

ramonjd commented Jan 5, 2022

I was testing this both using this standalone PR, and rebased on #34027, and can confirm that the first and last classes appear on the first and last ToolsPanel control wrappers where there are two or more controls.

I tested using the Typography, Border and Color panels. The last class is removed from existing last control and added to the new "last" control when I add optional controls from the drop down.

Similarly, removing optional controls resets the last class to the last control for me 👍

Where there is one control only both classes first last appear for me:

Screen Shot 2022-01-06 at 9 56 13 am

Is that intentional? I don't see any side effects of this, but just checking in case there could be conflict between first and last styles when applied to the same element.

Even if it required the use of parentNode. Open to suggestions on how better to approach this.

Do you mean because it's not using React Testing Library queries? I'd tend to think it's okay since the classnames are fairly invisible to the user anyway.

Copy link
Member

@ramonjd ramonjd left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This LGTM.

I left a couple of questions, also I had a question about the use of first and last classnames over at https://github.com/WordPress/gutenberg/pull/34027/files#r779209344

They seem pretty generic to me, but I might not have the entire picture.

All things I think could be dealt with later.

@aaronrobertshaw
Copy link
Contributor Author

Is that intentional? I don't see any side effects of this, but just checking in case there could be conflict between first and last styles when applied to the same element.

It was intentional. The use case I was focused on was achieving the same styling of the color dropdowns in the color panel after switching to the ToolsPanel in #34027. The first class applied top rounded corners while the last class applied bottom rounded corners. Having both classes applied in that circumstance should allow CSS to target that case as well if there were conflicts.

Do you mean because it's not using React Testing Library queries? I'd tend to think it's okay since the classnames are fairly invisible to the user anyway.

Yes, it felt a little rough to me that I couldn't retrieve the desired element directly through React Testing Library queries. Other PRs have been warned against using parentNode or querySelector etc if it can be avoided.

@aaronrobertshaw
Copy link
Contributor Author

They seem pretty generic to me, but I might not have the entire picture.

That's a good point. It should be a trivial change so I can make that shortly.

@aaronrobertshaw
Copy link
Contributor Author

They seem pretty generic to me, but I might not have the entire picture.

That's a good point. It should be a trivial change so I can make that shortly.

Thinking a little more on this, I'm not sure what the best approach is.

More specific class names such as .components-tools-panel-item__first would prevent accidental applications of styles. One catch with that though is that if the ToolsPanel is refactored (which has been raised previously) we'd need to continue to support that more specific class name.

@ciampo would you be able to provide some wisdom on the best approach here?

@ramonjd
Copy link
Member

ramonjd commented Jan 6, 2022

Other PRs have been warned against using parentNode or querySelector etc if it can be avoided.

Would using a fragment like this be better/more acceptable?

<ToolsPanelItem { ...controlProps }>
	<>Item 2</>
</ToolsPanelItem>

...

expect( screen.getByText( 'Item 2' ) ).toHaveClass( 'first' );

Copy link
Contributor

@ciampo ciampo left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey @aaronrobertshaw and @ramonjd , thank you for the ping (and happy new year!)

I've left a few inline comments, sorry for the delay in reviewing!

packages/components/src/tools-panel/tools-panel/hook.ts Outdated Show resolved Hide resolved
packages/components/src/tools-panel/test/index.js Outdated Show resolved Hide resolved
@aaronrobertshaw aaronrobertshaw force-pushed the add/tools-panel-items-first-and-last-classes branch from 5b3ae82 to 4a3b43a Compare January 10, 2022 00:13
@ramonjd
Copy link
Member

ramonjd commented Jan 10, 2022

I know there are ongoing discussions, but I just took this for another test spin and, functionally, it's all working as expected, similar to the last round of testing

I also checked every storybook example to make sure the classes are applied 👍

Jan-11-2022 10-16-28

@aaronrobertshaw
Copy link
Contributor Author

The snapshot test appears to be failing on this PR (but passes locally) due to the styled components' class names changing. I've run out of time today but will revisit this tomorrow. Any suggestions on how best to handle this are welcome 🙂

Comment on lines 221 to 243
border-left: 1px solid rgba( 0, 0, 0, 0.1 );
border-right: 1px solid rgba( 0, 0, 0, 0.1 );
border-bottom: 1px solid rgba( 0, 0, 0, 0.1 );

&&.first {
border-top-left-radius: 10px;
border-top-right-radius: 10px;
border-top: 1px solid rgba( 0, 0, 0, 0.1 );
}

&.last {
border-bottom-left-radius: 10px;
border-bottom-right-radius: 10px;
}

&& > div,
&& > div > button {
width: 100%;
border-radius: inherit;
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

By using ItemGroup's isBordered and isSeparated props, we don't need to define custom CSS for borders (apart from a one-line override for the last item)

see diff
diff --git a/packages/components/src/tools-panel/stories/tools-panel-with-item-group-slot.js b/packages/components/src/tools-panel/stories/tools-panel-with-item-group-slot.js
index 950a3c3f5e..ae4eaad17a 100644
--- a/packages/components/src/tools-panel/stories/tools-panel-with-item-group-slot.js
+++ b/packages/components/src/tools-panel/stories/tools-panel-with-item-group-slot.js
@@ -169,6 +169,8 @@ export const ToolsPanelWithItemGroupSlot = () => {
 				<Panel>
 					<ToolsPanelItems.Slot
 						as={ ItemGroup }
+						isBordered
+						isSeparated
 						className={ slotWrapperClassName }
 						resetAll={ resetAll }
 					/>
@@ -218,29 +220,18 @@ const SlotWrapper = css`
 
 const ToolsPanelItemClass = css`
 	padding: 0;
-	border-left: 1px solid rgba( 0, 0, 0, 0.1 );
-	border-right: 1px solid rgba( 0, 0, 0, 0.1 );
-	border-bottom: 1px solid rgba( 0, 0, 0, 0.1 );
-
-	&&.first {
-		border-top-left-radius: 10px;
-		border-top-right-radius: 10px;
-		border-top: 1px solid rgba( 0, 0, 0, 0.1 );
+
+	&.first {
+		border-left: 2px solid blue;
 	}
 
 	&.last {
-		border-bottom-left-radius: 10px;
-		border-bottom-right-radius: 10px;
+		border-right: 2px solid red;
+		border-bottom-color: transparent;
 	}
 
 	&& > div,
 	&& > div > button {
 		width: 100%;
-		border-radius: inherit;
-	}
-
-	/* .components-dropdown class overrides ToolsPanelItemPlaceholder styles */
-	&[class*='ToolsPanelItemPlaceholder'] {
-		display: none;
 	}
 `;

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks. These were leftover from when the Item wasn't a direct child of the slot. I'll clean it up.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Revisiting this, the proposed suggestion won't really work for our needs and jogged my memory on why the original approach was taken.

There are a couple of issues:

  • The border-radius: inherit for the button is needed so the focus outline is consistent with the rounded corners
  • We still need the application of the border-radius on the .first and .last classes because the ItemGroup styling doesn't handle hidden elements. (Part of the whole reason for this PR in the first place)
  • Using isBordered and isSeparated forces everything to visually be represented as an item.

Regarding the last point, it is a problem when in our real-world use case, a contrast checker is also rendered into the panel. This means the contrast checker is not a ToolsPanelItem but appears within the slot which is technically rendered as an ItemGroup. Not forcing isBordered and isSeparated means it can be visually separated.

GIFs demostrating `isBordered` issue
Suggested Changes Current Approach
ToolsPanelFirstLastContrastChecker ToolsPanelFirstLastContrastChecker2

I've updated the story to include a contrast checker.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The border-radius: inherit for the button is needed so the focus outline is consistent with the rounded corners

Makes sense, thank you for the explanation!

We still need the application of the border-radius on the .first and .last classes because the ItemGroup styling doesn't handle hidden elements. (Part of the whole reason for this PR in the first place)

Could you show a scenario in which ItemGroup would fail in this scenario? When I came up with the code path above, I tested the Storybook example and everything seems to work fine when showing/hiding toolspanel items.

Using isBordered and isSeparated forces everything to visually be represented as an item.
Regarding the last point, it is a problem when in our real-world use case, a contrast checker is also rendered into the panel. This means the contrast checker is not a ToolsPanelItem but appears within the slot which is technically rendered as an ItemGroup. Not forcing isBordered and isSeparated means it can be visually separated.

Thank you for the explanation! There's an issue, though: ItemGroup would technically expect ContrastChecker to be rendered inside an Item.
The main reason is that by default ItemGroup renders an element with role="list", which itself expects children with role listitem. We could override the role, but then I would argue that we shouldn't use ItemGroup at all, since we would be making use of its 2 major features (list semantics and visual bordered styles).

A potential solution could be to render ItemGroup as a child of ToolsPanel:

ToolsPanel
├── ItemGroup
│   ├── ToolsPanelItem as Item
│   │   ├── [item contents]
│   ├── ToolsPanelItem as Item
│   │   ├── [item contents]
│   ├── ToolsPanelItem as Item
│   │   ├── [item contents]
├── ContrastChecker

although we may probably need to re-apply the grid container styles to ItemGroup. If that didn't work, maybe ItemGroup is not the right fit for this scenario?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you show a scenario in which ItemGroup would fail in this scenario? When I came up with the code path above, I tested the Storybook example and everything seems to work fine when showing/hiding toolspanel items.

The inheritance of the border-radius doesn't work fine because the ItemGroup styles rely on > *:first-of-type > * and > *:last-of-type > * to apply the rounded style border radii. These styles can't take into account whether the element in the item is actually just a non-visible placeholder.

I've updated the story to explicitly disable isRounded on the slot's ItemGroup. As noted previously, we still need styles to handle the border-radius on the .first and .last items. They can be made to inherit from the wrapping ItemGroup (with an extra rule to target the item wrapper), exactly how this styling happens isn't really the issue. We could apply a custom border-radius to the ItemGroup then inherit on the appropriate items or just style those first/last items directly. Either way these first/last classes were needed.

With all the iterations on this, I didn't remove the border color and styling part of the styles as I was distracted by the contrast checker issue when looking at the implications for #34027.

There's an issue, though: ItemGroup would technically expect ContrastChecker to be rendered inside an Item.

This is a fair point and is relevant to #34027. Either way, we still need the classes this PR provides and I don't think should be a blocker here.

I'll remove the contrast checker from the example here so as to avoid future confusion.

A potential solution could be to render ItemGroup as a child of ToolsPanel:

With a view towards #34027, this is easier said than done. Any block or plugin could add new color options to be included within the Inspector Controls color panel. This means the fills that render in the slot come from different places and may contain a mix of color options, contrast checkers or any other element they wish to add into the panel (help text etc).

Moving the contrast checkers to the bottom of the panel was done via CSS ordering in #34027.

I don't believe we can programmatically control the fills, especially when we don't know exactly what we'll be dealing with, so to make the ItemGroup color options only and an inner element of the ToolsPanel we'd likely need to create one or two new slots and nest those inside an already nested slot in the block editor. It makes the color panel a special case with the Inspector Controls group slots and probably more difficult for consumers.

Given that, I'd be inclined in #34027 to no longer use the ItemGroup at all.

If that didn't work, maybe ItemGroup is not the right fit for this scenario

Agreed. This is more a hangover of the color panel being updated without consideration or knowledge that there was a PR open for review to move it to using the ToolsPanel.

I'll update #34027 to remove the use of ItemGroup for the colors panel.

That is obviously separate to this PR so I think this should be ok to land. Since the decision to adopt the new first/last classname props was accepted we've only been iterating on the storybook example.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry for the delayed response (has a couple of setbacks this week)!

I agree with all of your points — the style rules (and semantics requirements) related to ItemGroup are very strict, and everything is made even more complicated by the fact that tool panel items can be added via slot-fills.

In the light of our findings I think that the best way forward, at least for now, is to avoid using ItemGroup in combination with ToolsPanel — both in #34027 and in this PR (you may even, at this point, re-introduce the contrast checker).

We will also have a look at how to improve the ItemGroup component (of course separately from this PR), in order to make it more flexible/adaptable to different situations (both in terms of styles and in terms of the list semantics).

@ciampo
Copy link
Contributor

ciampo commented Jan 13, 2022

The snapshot test appears to be failing on this PR (but passes locally) due to the styled components' class names changing. I've run out of time today but will revisit this tomorrow. Any suggestions on how best to handle this are welcome 🙂

That is very weird, tests are passing locally for me as well. Maybe this PR needs to be rebased to get the latest version of all deps?

@aaronrobertshaw aaronrobertshaw force-pushed the add/tools-panel-items-first-and-last-classes branch from a373122 to 62c3769 Compare January 14, 2022 03:02
@aaronrobertshaw
Copy link
Contributor Author

That is very weird, tests are passing locally for me as well. Maybe this PR needs to be rebased to get the latest version of all deps?

After rebasing, the emotion styles were different locally as well. The snapshot was updated in 62c3769 and unit tests are passing.

@ciampo
Copy link
Contributor

ciampo commented Jan 14, 2022

That is very weird, tests are passing locally for me as well. Maybe this PR needs to be rebased to get the latest version of all deps?

After rebasing, the emotion styles were different locally as well. The snapshot was updated in 62c3769 and unit tests are passing.

That's great news!

Sorry if this review is taking longer than expected, but this PR is actually of great value to understand any potential limitations that we have with the current set of components and the way each component interacts with each other (e.g. ToolsPanel and ItemGroup)

@aaronrobertshaw
Copy link
Contributor Author

Sorry if this review is taking longer than expected

It will take as long as it needs 🙂

this PR is actually of great value to understand any potential limitations that we have with the current set of components and the way each component interacts with each other (e.g. ToolsPanel and ItemGroup)

The catch, in this case, is twofold. First, we are using the ToolsPanel as an ItemGroup which blurs the lines. Second, we aren't controlling what gets added to the ToolsPanel/ItemGroup.

So you are right we do have a limitation there but I don't think that is the fault of either component.

The likely cleanest approach is to create additional nested slots so we can in fact control (or set expectations for) what is rendered internally to the ToolsPanel. One slot for the color controls, another for anything else. Those fills are then rendered appropriately (within ItemGroup or not) into the color panel slot which itself is within the Inspector Controls slot and so on.

As always thanks for the continued effort and attention to detail 👍

@ciampo
Copy link
Contributor

ciampo commented Jan 20, 2022

The catch, in this case, is twofold. First, we are using the ToolsPanel as an ItemGroup which blurs the lines. Second, we aren't controlling what gets added to the ToolsPanel/ItemGroup.

Very true. In any case, it served as a very good stress test for ItemGroup!

So you are right we do have a limitation there but I don't think that is the fault of either component.

Definitely not a fault, but in my opinion a good indication for which direction we need to look at when developing our components further.

The likely cleanest approach is to create additional nested slots so we can in fact control (or set expectations for) what is rendered internally to the ToolsPanel. One slot for the color controls, another for anything else. Those fills are then rendered appropriately (within ItemGroup or not) into the color panel slot which itself is within the Inspector Controls slot and so on.

That is definitely an idea, but for now I think we can keep it simple (i.e. let's not use ItemGroup in this scenario) and allow this PR to move forward

@aaronrobertshaw aaronrobertshaw force-pushed the add/tools-panel-items-first-and-last-classes branch from 966c29b to 5fe3da5 Compare January 21, 2022 04:44
@aaronrobertshaw
Copy link
Contributor Author

I've rebased this PR to resolve conflicts after the merge of the ToolsPanel memorization updates. The unit tests are passing still and storybook examples are all functioning as expected.

Once the e2es pass, I'll merge this one.

@aaronrobertshaw aaronrobertshaw merged commit 5062a1e into trunk Jan 21, 2022
@aaronrobertshaw aaronrobertshaw deleted the add/tools-panel-items-first-and-last-classes branch January 21, 2022 05:30
@github-actions github-actions bot added this to the Gutenberg 12.5 milestone Jan 21, 2022
@jasmussen
Copy link
Contributor

Just chiming in to say thank you for making structural improvements to the itemgroup. The component is important both for global styles, and for toolspanels going forward, allowing us to much more carefully manage prominence of individual tool controls, while still making them available.

The technical implementation is in good hands here, and from a recent implementation challenge, any flexibility in how these are rendered will be welcome 👌

@ciampo ciampo mentioned this pull request Jan 21, 2022
12 tasks
@ciampo
Copy link
Contributor

ciampo commented Jan 21, 2022

Just chiming in to say thank you for making structural improvements to the itemgroup. The component is important both for global styles, and for toolspanels going forward, allowing us to much more carefully manage prominence of individual tool controls, while still making them available.

The technical implementation is in good hands here, and from a recent implementation challenge, any flexibility in how these are rendered will be welcome 👌

ItemGroup is definitely an important component for us. It's going to be challenging to make it more flexible, but we're definitely going to look into it!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
[Feature] UI Components Impacts or related to the UI component system [Type] Enhancement A suggestion for improvement.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants