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

Private experimental cross-module selectors and actions #44521

Conversation

adamziel
Copy link
Contributor

@adamziel adamziel commented Sep 28, 2022

What?

This PR introduces a private selectors APIs in @wordpress/data via the new @wordpress/experimental package:

// Package wordpress/block-data:
import { unlock } from '../experiments';
import { experiments as dataExperiments } from '@wordpress/data';
const { registerPrivateActionsAndSelectors } = unlock( dataExperiments );

import { store as blockEditorStore } from './store';
import { __unstableSelectionHasUnmergeableBlock } from './store/selectors';
registerPrivateActionsAndSelectors( store, {}, {
     __experimentalHasContentRoleAttribute
} );

// plain usage
unlock( registry.select( blockEditorStore ) ).getContentLockingParent();

// usage in React
useSelect( ( select ) => ( {
  parent: privateOf( select( blockEditorStore ) ).__unstableSelectionHasUnmergeableBlock();
} ) );

This PR demonstrates the usage by making the __unstableSelectionHasUnmergeableBlock selector private. I intend to roll back this change before merging, and then follow-up with a migration PR to ensure new experimental selectors won't be added to the public API.

Why?

Exporting __unstable and __experimental selectors makes them available to extenders and locks them in as a part of the public API. Let's not add new such exports if it can be avoided.

Testing

Confirm the new API makes sense and that all the tests pass.

cc @jorgefilipecosta @ellatrix @talldan @draganescu @peterwilsoncc @jsnajdr

@adamziel adamziel self-assigned this Sep 28, 2022
@adamziel adamziel added [Type] Enhancement A suggestion for improvement. [Package] Blocks /packages/blocks [Package] Block editor /packages/block-editor Developer Experience Ideas about improving block and theme developer experience labels Sep 28, 2022
@adamziel adamziel force-pushed the experiments/private-selectors-and-actions branch from 27fbb8f to a09263f Compare September 28, 2022 05:12
@github-actions
Copy link

github-actions bot commented Sep 28, 2022

Size Change: +717 B (0%)

Total Size: 1.31 MB

Filename Size Change
build/block-editor/index.min.js 179 kB +132 B (0%)
build/blocks/index.min.js 50.1 kB +183 B (0%)
build/data/index.min.js 8.48 kB +402 B (+5%) 🔍
ℹ️ View Unchanged
Filename Size
build/a11y/index.min.js 982 B
build/annotations/index.min.js 2.76 kB
build/api-fetch/index.min.js 2.26 kB
build/autop/index.min.js 2.14 kB
build/blob/index.min.js 475 B
build/block-directory/index.min.js 7.14 kB
build/block-directory/style-rtl.css 1.02 kB
build/block-directory/style.css 1.02 kB
build/block-editor/default-editor-styles-rtl.css 401 B
build/block-editor/default-editor-styles.css 401 B
build/block-editor/style-rtl.css 16.5 kB
build/block-editor/style.css 16.5 kB
build/block-library/blocks/archives/editor-rtl.css 107 B
build/block-library/blocks/archives/editor.css 106 B
build/block-library/blocks/archives/style-rtl.css 129 B
build/block-library/blocks/archives/style.css 129 B
build/block-library/blocks/audio/editor-rtl.css 185 B
build/block-library/blocks/audio/editor.css 185 B
build/block-library/blocks/audio/style-rtl.css 158 B
build/block-library/blocks/audio/style.css 158 B
build/block-library/blocks/audio/theme-rtl.css 160 B
build/block-library/blocks/audio/theme.css 160 B
build/block-library/blocks/avatar/editor-rtl.css 154 B
build/block-library/blocks/avatar/editor.css 154 B
build/block-library/blocks/avatar/style-rtl.css 126 B
build/block-library/blocks/avatar/style.css 126 B
build/block-library/blocks/block/editor-rtl.css 338 B
build/block-library/blocks/block/editor.css 338 B
build/block-library/blocks/button/editor-rtl.css 514 B
build/block-library/blocks/button/editor.css 514 B
build/block-library/blocks/button/style-rtl.css 564 B
build/block-library/blocks/button/style.css 564 B
build/block-library/blocks/buttons/editor-rtl.css 373 B
build/block-library/blocks/buttons/editor.css 373 B
build/block-library/blocks/buttons/style-rtl.css 368 B
build/block-library/blocks/buttons/style.css 368 B
build/block-library/blocks/calendar/style-rtl.css 270 B
build/block-library/blocks/calendar/style.css 270 B
build/block-library/blocks/categories/editor-rtl.css 125 B
build/block-library/blocks/categories/editor.css 124 B
build/block-library/blocks/categories/style-rtl.css 138 B
build/block-library/blocks/categories/style.css 138 B
build/block-library/blocks/code/editor-rtl.css 102 B
build/block-library/blocks/code/editor.css 102 B
build/block-library/blocks/code/style-rtl.css 159 B
build/block-library/blocks/code/style.css 159 B
build/block-library/blocks/code/theme-rtl.css 160 B
build/block-library/blocks/code/theme.css 160 B
build/block-library/blocks/columns/editor-rtl.css 147 B
build/block-library/blocks/columns/editor.css 147 B
build/block-library/blocks/columns/style-rtl.css 442 B
build/block-library/blocks/columns/style.css 442 B
build/block-library/blocks/comment-author-avatar/editor-rtl.css 163 B
build/block-library/blocks/comment-author-avatar/editor.css 163 B
build/block-library/blocks/comment-content/style-rtl.css 134 B
build/block-library/blocks/comment-content/style.css 134 B
build/block-library/blocks/comment-template/style-rtl.css 237 B
build/block-library/blocks/comment-template/style.css 236 B
build/block-library/blocks/comments-pagination-numbers/editor-rtl.css 159 B
build/block-library/blocks/comments-pagination-numbers/editor.css 157 B
build/block-library/blocks/comments-pagination/editor-rtl.css 258 B
build/block-library/blocks/comments-pagination/editor.css 249 B
build/block-library/blocks/comments-pagination/style-rtl.css 272 B
build/block-library/blocks/comments-pagination/style.css 268 B
build/block-library/blocks/comments-title/editor-rtl.css 118 B
build/block-library/blocks/comments-title/editor.css 118 B
build/block-library/blocks/comments/editor-rtl.css 875 B
build/block-library/blocks/comments/editor.css 874 B
build/block-library/blocks/comments/style-rtl.css 672 B
build/block-library/blocks/comments/style.css 671 B
build/block-library/blocks/cover/editor-rtl.css 646 B
build/block-library/blocks/cover/editor.css 647 B
build/block-library/blocks/cover/style-rtl.css 1.6 kB
build/block-library/blocks/cover/style.css 1.59 kB
build/block-library/blocks/embed/editor-rtl.css 327 B
build/block-library/blocks/embed/editor.css 327 B
build/block-library/blocks/embed/style-rtl.css 446 B
build/block-library/blocks/embed/style.css 446 B
build/block-library/blocks/embed/theme-rtl.css 160 B
build/block-library/blocks/embed/theme.css 160 B
build/block-library/blocks/file/editor-rtl.css 335 B
build/block-library/blocks/file/editor.css 335 B
build/block-library/blocks/file/style-rtl.css 288 B
build/block-library/blocks/file/style.css 288 B
build/block-library/blocks/file/view.min.js 346 B
build/block-library/blocks/freeform/editor-rtl.css 2.47 kB
build/block-library/blocks/freeform/editor.css 2.47 kB
build/block-library/blocks/gallery/editor-rtl.css 978 B
build/block-library/blocks/gallery/editor.css 981 B
build/block-library/blocks/gallery/style-rtl.css 1.56 kB
build/block-library/blocks/gallery/style.css 1.56 kB
build/block-library/blocks/gallery/theme-rtl.css 144 B
build/block-library/blocks/gallery/theme.css 144 B
build/block-library/blocks/group/editor-rtl.css 687 B
build/block-library/blocks/group/editor.css 687 B
build/block-library/blocks/group/style-rtl.css 105 B
build/block-library/blocks/group/style.css 105 B
build/block-library/blocks/group/theme-rtl.css 125 B
build/block-library/blocks/group/theme.css 125 B
build/block-library/blocks/heading/style-rtl.css 128 B
build/block-library/blocks/heading/style.css 128 B
build/block-library/blocks/html/editor-rtl.css 360 B
build/block-library/blocks/html/editor.css 362 B
build/block-library/blocks/image/editor-rtl.css 912 B
build/block-library/blocks/image/editor.css 912 B
build/block-library/blocks/image/style-rtl.css 662 B
build/block-library/blocks/image/style.css 666 B
build/block-library/blocks/image/theme-rtl.css 159 B
build/block-library/blocks/image/theme.css 159 B
build/block-library/blocks/latest-comments/style-rtl.css 333 B
build/block-library/blocks/latest-comments/style.css 333 B
build/block-library/blocks/latest-posts/editor-rtl.css 250 B
build/block-library/blocks/latest-posts/editor.css 249 B
build/block-library/blocks/latest-posts/style-rtl.css 514 B
build/block-library/blocks/latest-posts/style.css 514 B
build/block-library/blocks/list/style-rtl.css 135 B
build/block-library/blocks/list/style.css 135 B
build/block-library/blocks/media-text/editor-rtl.css 300 B
build/block-library/blocks/media-text/editor.css 298 B
build/block-library/blocks/media-text/style-rtl.css 540 B
build/block-library/blocks/media-text/style.css 539 B
build/block-library/blocks/more/editor-rtl.css 465 B
build/block-library/blocks/more/editor.css 465 B
build/block-library/blocks/navigation-link/editor-rtl.css 742 B
build/block-library/blocks/navigation-link/editor.css 741 B
build/block-library/blocks/navigation-link/style-rtl.css 153 B
build/block-library/blocks/navigation-link/style.css 153 B
build/block-library/blocks/navigation-submenu/editor-rtl.css 329 B
build/block-library/blocks/navigation-submenu/editor.css 329 B
build/block-library/blocks/navigation/editor-rtl.css 2.18 kB
build/block-library/blocks/navigation/editor.css 2.19 kB
build/block-library/blocks/navigation/style-rtl.css 2.25 kB
build/block-library/blocks/navigation/style.css 2.24 kB
build/block-library/blocks/navigation/view-modal.min.js 2.81 kB
build/block-library/blocks/navigation/view.min.js 443 B
build/block-library/blocks/nextpage/editor-rtl.css 428 B
build/block-library/blocks/nextpage/editor.css 428 B
build/block-library/blocks/page-list/editor-rtl.css 397 B
build/block-library/blocks/page-list/editor.css 398 B
build/block-library/blocks/page-list/style-rtl.css 212 B
build/block-library/blocks/page-list/style.css 212 B
build/block-library/blocks/paragraph/editor-rtl.css 214 B
build/block-library/blocks/paragraph/editor.css 214 B
build/block-library/blocks/paragraph/style-rtl.css 321 B
build/block-library/blocks/paragraph/style.css 321 B
build/block-library/blocks/post-author/style-rtl.css 212 B
build/block-library/blocks/post-author/style.css 212 B
build/block-library/blocks/post-comments-form/editor-rtl.css 137 B
build/block-library/blocks/post-comments-form/editor.css 137 B
build/block-library/blocks/post-comments-form/style-rtl.css 536 B
build/block-library/blocks/post-comments-form/style.css 537 B
build/block-library/blocks/post-date/style-rtl.css 107 B
build/block-library/blocks/post-date/style.css 107 B
build/block-library/blocks/post-excerpt/editor-rtl.css 119 B
build/block-library/blocks/post-excerpt/editor.css 119 B
build/block-library/blocks/post-excerpt/style-rtl.css 116 B
build/block-library/blocks/post-excerpt/style.css 116 B
build/block-library/blocks/post-featured-image/editor-rtl.css 620 B
build/block-library/blocks/post-featured-image/editor.css 618 B
build/block-library/blocks/post-featured-image/style-rtl.css 346 B
build/block-library/blocks/post-featured-image/style.css 346 B
build/block-library/blocks/post-navigation-link/style-rtl.css 190 B
build/block-library/blocks/post-navigation-link/style.css 189 B
build/block-library/blocks/post-template/editor-rtl.css 140 B
build/block-library/blocks/post-template/editor.css 139 B
build/block-library/blocks/post-template/style-rtl.css 317 B
build/block-library/blocks/post-template/style.css 317 B
build/block-library/blocks/post-terms/style-rtl.css 136 B
build/block-library/blocks/post-terms/style.css 136 B
build/block-library/blocks/post-title/style-rtl.css 138 B
build/block-library/blocks/post-title/style.css 138 B
build/block-library/blocks/preformatted/style-rtl.css 139 B
build/block-library/blocks/preformatted/style.css 139 B
build/block-library/blocks/pullquote/editor-rtl.css 170 B
build/block-library/blocks/pullquote/editor.css 170 B
build/block-library/blocks/pullquote/style-rtl.css 357 B
build/block-library/blocks/pullquote/style.css 357 B
build/block-library/blocks/pullquote/theme-rtl.css 201 B
build/block-library/blocks/pullquote/theme.css 201 B
build/block-library/blocks/query-pagination-numbers/editor-rtl.css 158 B
build/block-library/blocks/query-pagination-numbers/editor.css 156 B
build/block-library/blocks/query-pagination/editor-rtl.css 258 B
build/block-library/blocks/query-pagination/editor.css 247 B
build/block-library/blocks/query-pagination/style-rtl.css 326 B
build/block-library/blocks/query-pagination/style.css 322 B
build/block-library/blocks/query-title/style-rtl.css 108 B
build/block-library/blocks/query-title/style.css 108 B
build/block-library/blocks/query/editor-rtl.css 475 B
build/block-library/blocks/query/editor.css 477 B
build/block-library/blocks/quote/style-rtl.css 253 B
build/block-library/blocks/quote/style.css 253 B
build/block-library/blocks/quote/theme-rtl.css 255 B
build/block-library/blocks/quote/theme.css 259 B
build/block-library/blocks/read-more/style-rtl.css 168 B
build/block-library/blocks/read-more/style.css 168 B
build/block-library/blocks/rss/editor-rtl.css 239 B
build/block-library/blocks/rss/editor.css 240 B
build/block-library/blocks/rss/style-rtl.css 323 B
build/block-library/blocks/rss/style.css 323 B
build/block-library/blocks/search/editor-rtl.css 205 B
build/block-library/blocks/search/editor.css 205 B
build/block-library/blocks/search/style-rtl.css 441 B
build/block-library/blocks/search/style.css 439 B
build/block-library/blocks/search/theme-rtl.css 149 B
build/block-library/blocks/search/theme.css 149 B
build/block-library/blocks/separator/editor-rtl.css 184 B
build/block-library/blocks/separator/editor.css 184 B
build/block-library/blocks/separator/style-rtl.css 269 B
build/block-library/blocks/separator/style.css 269 B
build/block-library/blocks/separator/theme-rtl.css 229 B
build/block-library/blocks/separator/theme.css 229 B
build/block-library/blocks/shortcode/editor-rtl.css 498 B
build/block-library/blocks/shortcode/editor.css 498 B
build/block-library/blocks/site-logo/editor-rtl.css 522 B
build/block-library/blocks/site-logo/editor.css 522 B
build/block-library/blocks/site-logo/style-rtl.css 238 B
build/block-library/blocks/site-logo/style.css 238 B
build/block-library/blocks/site-tagline/editor-rtl.css 129 B
build/block-library/blocks/site-tagline/editor.css 129 B
build/block-library/blocks/site-title/editor-rtl.css 155 B
build/block-library/blocks/site-title/editor.css 155 B
build/block-library/blocks/site-title/style-rtl.css 101 B
build/block-library/blocks/site-title/style.css 101 B
build/block-library/blocks/social-link/editor-rtl.css 219 B
build/block-library/blocks/social-link/editor.css 219 B
build/block-library/blocks/social-links/editor-rtl.css 709 B
build/block-library/blocks/social-links/editor.css 708 B
build/block-library/blocks/social-links/style-rtl.css 1.43 kB
build/block-library/blocks/social-links/style.css 1.43 kB
build/block-library/blocks/spacer/editor-rtl.css 360 B
build/block-library/blocks/spacer/editor.css 360 B
build/block-library/blocks/spacer/style-rtl.css 96 B
build/block-library/blocks/spacer/style.css 96 B
build/block-library/blocks/table/editor-rtl.css 537 B
build/block-library/blocks/table/editor.css 537 B
build/block-library/blocks/table/style-rtl.css 664 B
build/block-library/blocks/table/style.css 663 B
build/block-library/blocks/table/theme-rtl.css 207 B
build/block-library/blocks/table/theme.css 207 B
build/block-library/blocks/tag-cloud/style-rtl.css 287 B
build/block-library/blocks/tag-cloud/style.css 288 B
build/block-library/blocks/template-part/editor-rtl.css 436 B
build/block-library/blocks/template-part/editor.css 436 B
build/block-library/blocks/template-part/theme-rtl.css 139 B
build/block-library/blocks/template-part/theme.css 139 B
build/block-library/blocks/text-columns/editor-rtl.css 135 B
build/block-library/blocks/text-columns/editor.css 135 B
build/block-library/blocks/text-columns/style-rtl.css 198 B
build/block-library/blocks/text-columns/style.css 198 B
build/block-library/blocks/verse/style-rtl.css 130 B
build/block-library/blocks/verse/style.css 130 B
build/block-library/blocks/video/editor-rtl.css 720 B
build/block-library/blocks/video/editor.css 723 B
build/block-library/blocks/video/style-rtl.css 212 B
build/block-library/blocks/video/style.css 212 B
build/block-library/blocks/video/theme-rtl.css 160 B
build/block-library/blocks/video/theme.css 160 B
build/block-library/classic-rtl.css 193 B
build/block-library/classic.css 193 B
build/block-library/common-rtl.css 1.05 kB
build/block-library/common.css 1.04 kB
build/block-library/editor-elements-rtl.css 126 B
build/block-library/editor-elements.css 126 B
build/block-library/editor-rtl.css 11.7 kB
build/block-library/editor.css 11.7 kB
build/block-library/elements-rtl.css 105 B
build/block-library/elements.css 105 B
build/block-library/index.min.js 194 kB
build/block-library/reset-rtl.css 514 B
build/block-library/reset.css 514 B
build/block-library/style-rtl.css 12.4 kB
build/block-library/style.css 12.4 kB
build/block-library/theme-rtl.css 735 B
build/block-library/theme.css 740 B
build/block-serialization-default-parser/index.min.js 1.12 kB
build/block-serialization-spec-parser/index.min.js 2.83 kB
build/components/index.min.js 203 kB
build/components/style-rtl.css 11.5 kB
build/components/style.css 11.6 kB
build/compose/index.min.js 12.3 kB
build/core-data/index.min.js 15.5 kB
build/customize-widgets/index.min.js 11.3 kB
build/customize-widgets/style-rtl.css 1.41 kB
build/customize-widgets/style.css 1.41 kB
build/data-controls/index.min.js 653 B
build/date/index.min.js 32.1 kB
build/deprecated/index.min.js 507 B
build/dom-ready/index.min.js 324 B
build/dom/index.min.js 4.7 kB
build/edit-navigation/index.min.js 16.2 kB
build/edit-navigation/style-rtl.css 4.08 kB
build/edit-navigation/style.css 4.09 kB
build/edit-post/classic-rtl.css 569 B
build/edit-post/classic.css 570 B
build/edit-post/index.min.js 34.4 kB
build/edit-post/style-rtl.css 7.42 kB
build/edit-post/style.css 7.41 kB
build/edit-site/index.min.js 61.1 kB
build/edit-site/style-rtl.css 8.48 kB
build/edit-site/style.css 8.46 kB
build/edit-widgets/index.min.js 16.7 kB
build/edit-widgets/style-rtl.css 4.44 kB
build/edit-widgets/style.css 4.44 kB
build/editor/index.min.js 43.7 kB
build/editor/style-rtl.css 3.63 kB
build/editor/style.css 3.62 kB
build/element/index.min.js 4.68 kB
build/escape-html/index.min.js 537 B
build/experiments/index.min.js 1.07 kB
build/format-library/index.min.js 6.95 kB
build/format-library/style-rtl.css 596 B
build/format-library/style.css 596 B
build/hooks/index.min.js 1.64 kB
build/html-entities/index.min.js 448 B
build/i18n/index.min.js 3.77 kB
build/is-shallow-equal/index.min.js 527 B
build/keyboard-shortcuts/index.min.js 1.78 kB
build/keycodes/index.min.js 1.83 kB
build/list-reusable-blocks/index.min.js 2.13 kB
build/list-reusable-blocks/style-rtl.css 858 B
build/list-reusable-blocks/style.css 857 B
build/media-utils/index.min.js 2.93 kB
build/notices/index.min.js 963 B
build/nux/index.min.js 2.06 kB
build/nux/style-rtl.css 759 B
build/nux/style.css 755 B
build/plugins/index.min.js 1.94 kB
build/preferences-persistence/index.min.js 2.22 kB
build/preferences/index.min.js 1.33 kB
build/primitives/index.min.js 944 B
build/priority-queue/index.min.js 1.58 kB
build/react-i18n/index.min.js 696 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.74 kB
build/reusable-blocks/index.min.js 2.21 kB
build/reusable-blocks/style-rtl.css 281 B
build/reusable-blocks/style.css 281 B
build/rich-text/index.min.js 10.7 kB
build/server-side-render/index.min.js 1.77 kB
build/shortcode/index.min.js 1.53 kB
build/style-engine/index.min.js 1.48 kB
build/token-list/index.min.js 644 B
build/url/index.min.js 3.61 kB
build/vendors/inert-polyfill.min.js 2.48 kB
build/vendors/react-dom.min.js 38.5 kB
build/vendors/react.min.js 4.34 kB
build/viewport/index.min.js 1.08 kB
build/warning/index.min.js 268 B
build/widgets/index.min.js 7.21 kB
build/widgets/style-rtl.css 1.21 kB
build/widgets/style.css 1.21 kB
build/wordcount/index.min.js 1.06 kB

compressed-size-action

@adamziel adamziel changed the title [WIP] Make WordPress 6.1 experimental selectors private Make new experimental selectors introduced in WordPress 6.1 private Sep 29, 2022
@adamziel adamziel changed the title Make new experimental selectors introduced in WordPress 6.1 private Private selectors Sep 29, 2022
@adamziel adamziel changed the title Private selectors Exporting selectors privately Sep 29, 2022
@adamziel adamziel changed the title Exporting selectors privately Exportable private selectors Sep 29, 2022
packages/data/src/index.js Outdated Show resolved Hide resolved

function __experimentalPrivateSelector( { name }, selector ) {
return ( ...args ) =>
selector( defaultRegistry.stores[ name ].store.getState(), ...args );
Copy link
Member

Choose a reason for hiding this comment

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

It is a major shortcoming that the selector always selects from the default registry, and not the one that's in React context and is returned by useRegistry. I wonder if we can do anything about it?

Copy link
Member

Choose a reason for hiding this comment

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

// registration
registerPrivateSelectors( blockEditorStore, {
  getContentLockingParent
} );

// plain usage
const { privateOf } = unlock( dataExperiments );
privateOf( registry.select( blockEditorStore ) ).getContentLockingParent();

// usage in React
useSelect( ( select ) => ( {
  parent: privateOf( select( blockEditorStore ) ).getContentLockingParent();
} ) );

I can register private selectors and actions on a store, and then the object returned by select has the good old public methods, but can also be "unlocked" with privateOf to access the private parts.

The same can be done with actions and dispatch.

Ideally, I would not need a custom privateOf function, but could use the general purpose unlock to unlock any object. Could be implemented by having a Symbol.for( 'accessKey' ) property on an object. Very similar to how, to a for of loop, you can pass either an object with a Symbol.iterator field or an actual iterator.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@jsnajdr I really like this idea and I'm exploring an implementation. Would you mind taking a look? I think the new lockObj/unlockObj API could very well replace the old register/unlock API – I just need some better names.

Copy link
Member

Choose a reason for hiding this comment

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

I'm adding this to my todo-list after finishing the React 18 migration. Which currrently utilizes me 100% 🙂

Copy link
Member

@jorgefilipecosta jorgefilipecosta left a comment

Choose a reason for hiding this comment

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

This approach seems like a solution that we could use 👍 I agree with @jsnajdr that using only the default registry is not ideal, so Ideally I think we would apply the solution @jsnajdr referred.

@adamziel adamziel force-pushed the experiments/private-selectors-and-actions branch from 7550dd2 to cf3ae62 Compare November 27, 2022 23:45
@adamziel adamziel changed the title Exportable private selectors Private experimental cross-module selectors and actions Nov 28, 2022
@adamziel adamziel changed the base branch from trunk to experiments/pivot-to-lock-unlock November 28, 2022 19:04
@adamziel adamziel force-pushed the experiments/private-selectors-and-actions branch 2 times, most recently from c3c874f to 3b3eaca Compare November 28, 2022 19:47
@adamziel
Copy link
Contributor Author

adamziel commented Nov 28, 2022

I just updated this PR as @jsnajdr suggested:

// registration
registerPrivateSelectors( blockEditorStore, {
  getContentLockingParent
} );

// plain usage
unlock( registry.select( blockEditorStore ) ).getContentLockingParent();

// usage in React
useSelect( ( select ) => ( {
  parent: unlock( select( blockEditorStore ) ).getContentLockingParent();
} ) );

You can register private selectors and actions on a store, and the object returned by select() has the good old public methods, but can also be "unlocked" to access the private parts. The same can be done with actions and dispatch.

This now works with all the registries, not just the default one.

It's easy to migrate the current code to the new one – we just need to add unlock() where a private selector or action is used.

@adamziel adamziel force-pushed the experiments/private-selectors-and-actions branch from d418a57 to 172e63b Compare November 28, 2022 21:47
@adamziel
Copy link
Contributor Author

The JavaScript unit tests seems to fail due to Browserslist: caniuse-lite is outdated. Please run: npx browserslist@latest --update-db, I don't see any actual failure. Any ideas how to fix it?

@adamziel adamziel force-pushed the experiments/private-selectors-and-actions branch from 172e63b to e444d1d Compare December 22, 2022 09:33
@adamziel
Copy link
Contributor Author

I'm merging this PR into #46131 – the two are closely related, updating them separately takes effort, and keeping the code separate makes the dependency less clear.

@adamziel adamziel merged this pull request into experiments/pivot-to-lock-unlock Dec 22, 2022
@adamziel adamziel deleted the experiments/private-selectors-and-actions branch December 22, 2022 11:43
adamziel added a commit that referenced this pull request Dec 22, 2022
Introduces a private selectors APIs in `@wordpress/data` via [the new `@wordpress/experimental`](#43386 (comment)) package:

```js
// Package wordpress/block-data:
import { unlock } from '../experiments';
import { experiments as dataExperiments } from '@wordpress/data';
const { registerPrivateActionsAndSelectors } = unlock( dataExperiments );

import { store as blockEditorStore } from './store';
import { __unstableSelectionHasUnmergeableBlock } from './store/selectors';
registerPrivateActionsAndSelectors( store, {}, {
     __experimentalHasContentRoleAttribute
} );

// plain usage
unlock( registry.select( blockEditorStore ) ).getContentLockingParent();

// usage in React
useSelect( ( select ) => ( {
  parent: privateOf( select( blockEditorStore ) ).__unstableSelectionHasUnmergeableBlock();
} ) );
```
Comment on lines +525 to +529
import { __unstableSelectionHasUnmergeableBlock } from './store/selectors';
registerPrivateSelectors( store, {
__experimentalHasContentRoleAttribute,
} );
```
Copy link
Contributor

Choose a reason for hiding this comment

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

These selectors don't match, which adds confusion.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

ah snap good spot, I'll fix this in #46131

Copy link
Contributor Author

Choose a reason for hiding this comment

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

adamziel added a commit that referenced this pull request Jan 17, 2023
## Description

This commit introduces a more convenient API for managing the private experiments as the former `register`-based API was quite cumbersome to use.

The idea is to "lock" private data inside public objects:

```js
const { lock, unlock } = __dangerousOptInToUnstableAPIsOnlyForCoreModules(
	'<CONSENT STRING>',
	'@wordpress/blocks'
);

export const publicObject = {};
lock( __experiments, "Shh, private data!" );

publicObject
// {}

unlock( publicObject )
// "Shh, private data!"
```

This new `lock()`/`unlock()` API enables private functions, classes, components, selectors, actions, arguments, and properties. Any package that opted-in to private APIs can call `unlock()` on  publicly available artifacts to retrieve the related private API.

Kudos to @jsnajdr for [identifying an opportunity to simplify the API](#44521 (comment))!

## Examples

### Private selectors:

```js
// In wordpress/block-data:
import { store as blockEditorStore } from './store';
import { unlock } from '../experiments';
import { __unstableSelectionHasUnmergeableBlock } from './store/selectors';

unlock( store ).registerPrivateSelectors( {
  __unstableSelectionHasUnmergeableBlock
} );

// In a React component:
function MyComponent() {
    const hasRole = useSelect( ( select ) => (
        unlock( select( blockEditorStore ) ).__unstableSelectionHasUnmergeableBlock()
    ) );

    // ...
}
```

### Private functions, classes, and variables

```js
// In packages/package1/index.js:
import { lock } from './experiments';

export const experiments = {};
/* Attach private data to the exported object */
lock(experiments, {
	__experimentalCallback: function() {},
	__experimentalReactComponent: function ExperimentalComponent() { return <div/>; },
	__experimentalClass: class Experiment{},
	__experimentalVariable: 5,
});


// In packages/package2/index.js:
import { experiments } from '@wordpress/package1';
import { unlock } from './experiments';

const {
	__experimentalCallback,
	__experimentalReactComponent,
	__experimentalClass,
	__experimentalVariable
} = unlock( experiments );
```

### Private function arguments

To add an experimental argument to a stable function you'll need
to prepare a stable and an experimental version of that function.
Then, export the stable function and `lock()` the unstable function
inside it:

```js
// In @wordpress/package1/index.js:
import { lock } from './experiments';

// The experimental function contains all the logic
function __experimentalValidateBlocks(formula, __experimentalIsStrict) {
	let isValid = false;
	// ...complex logic we don't want to duplicate...
	if ( __experimentalIsStrict ) {
		// ...
	}
	// ...complex logic we don't want to duplicate...

	return isValid;
}

// The stable public function is a thin wrapper that calls the
// experimental function with the experimental features disabled
export function validateBlocks(blocks) {
	__experimentalValidateBlocks(blocks, false);
}
lock( validateBlocks, __experimentalValidateBlocks );

// In @wordpress/package2/index.js:
import { validateBlocks } from '@wordpress/package1';
import { unlock } from './experiments';

// The experimental function may be "unlocked" given the stable function:
const __experimentalValidateBlocks = unlock(validateBlocks);
__experimentalValidateBlocks(blocks, true);
```

### Private React Component properties

To add an experimental argument to a stable component you'll need
to prepare a stable and an experimental version of that component.
Then, export the stable function and `lock()` the unstable function
inside it:

```js
// In @wordpress/package1/index.js:
import { lock } from './experiments';

// The experimental component contains all the logic
const ExperimentalMyButton = ( { title, __experimentalShowIcon = true } ) => {
	// ...complex logic we don't want to duplicate...
  
	return (
		<button>
			{ __experimentalShowIcon  && <Icon src={some icon} /> } { title }  
		</button>
	);
}

// The stable public component is a thin wrapper that calls the
// experimental component with the experimental features disabled
export const MyButton = ( { title } ) => 
    <ExperimentalMyExistingButton title={ title } __experimentalShowIcon={ false } />

lock(MyButton, ExperimentalMyButton);


// In @wordpress/package2/index.js:
import { MyButton } from '@wordpress/package1';
import { unlock } from './experiments';

// The experimental component may be "unlocked" given the stable component:
const ExperimentalMyButton = unlock(MyButton);
export function MyComponent() {
	return (
		<ExperimentalMyButton data={data} __experimentalShowIcon={ true } />
	)
}
```


Co-authored-by: Ramon <[email protected]>
Co-authored-by: Robert Anderson <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Developer Experience Ideas about improving block and theme developer experience [Package] Block editor /packages/block-editor [Package] Blocks /packages/blocks [Type] Enhancement A suggestion for improvement.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants