-
Notifications
You must be signed in to change notification settings - Fork 4.3k
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
Block Controls SlotFill: refactor to allow passing multiple contexts, including internal components context #51264
Conversation
…nts context (cherry picked from commit d7d169783b89b0838f2add86852b9cb378fdc890)
@jsnajdr — my only question at this point is: should the components context be passed specifically in every instance of |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we also use the components context system in React Native code? Because I added the provider teleporting only to the web BlockControlsSlot
, not to the mobile one.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also it seems that in React Native we don't support the bubblesVirtually
variant with portals. The bubblesVirtually
prop is simply ignored. The Fill is always rendered in the Slot's React tree. It doesn't see context from the Fill tree, and teleporting the toolbar context is not needed, the component already sees it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Folks from the mobile team may be best suited to answer here.
From a quick look, I don't think that there are native components explicitly using the components context system, although it is my understanding that web versions of components could be used by React Native, meaning that we'll likely neet to pass all the context values that we do in the web counterpart?
Also it seems that in React Native we don't support the bubblesVirtually variant with portals. The bubblesVirtually prop is simply ignored. The Fill is always rendered in the Slot's React tree. It doesn't see context from the Fill tree, and teleporting the toolbar context is not needed, the component already sees it.
If that's the case, though, then forwarding such contexts is not necessary, as you say.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I pushed a commit that removes context forwarding (teleporting) from the slot.native.js
component completely, including the pre-exisiting ToolbarContext
. Mobile uses the non-virtual Slot implementation, and all these contexts (toolbar, component system, Emotion styles) are already present it its parent React tree.
We'll need to reintroduce the forwarding when we migrate mobile slotfills to the portal bubblesVirtually
implementation.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for the call out @ciampo 🙇 ! As you shared in the above comments, the SlotFill
implementation in React Native is limited compared to the web version as we don't support bubblesVirtually
. I checked the usage of ToolbarContext
and seems we are not using it, only in the web version, so I agree on removing it from here.
Web:
<ToolbarContext.Provider value={ toolbarState }> |
Native:
const ToolbarContainer = ( { children } ) => <View>{ children }</View>; |
Regarding these changes, I tested locally and I encountered an error that I shared here. Let me know if I can help anyhow, thanks!
const fillProps = useMemo( | ||
() => [ | ||
[ ToolbarContext.Provider, { value: toolbarState } ], | ||
[ ComponentsContext.Provider, { value: contextState } ], |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Here I did a little change, passing a props object instead of a value for a hard-coded value
prop. That makes the system more flexible.
We'll want to migrate the <StyleProvider document={...}>
usage also to this format, and there's a document
prop instead of value
.
It would be nice to remove the hard-coded StyleProvider
from the Fill
implementation, as added in #38237, and configure the slots and fills that really need this explicitly.
@youknowriad added StyleProvider
wrappers around specific fills in #31073. There should be eventually migrated to the fillProps
format.
The StyleProvider
s from #31073 (specific places) and #38237 (universal for every <Fill bubblesVirtually>
) often overlap each other, rendering the same provider two times next to each other. I believe the universal one should eventually go away.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you for the extra context, Jarda! Your suggestion makes sense in terms of code hygiene and separation of concerns, although there are a few aspects that we should also take into account:
- the
emotion
library (and thereforeStyleProvider
) was always meant to be kept as an internal implementation detail to the package. Adopting your suggested approach would require exportingStyleProvider
from the package. Although maybe we can still keep it as a "generic" style provider (not necessarily Emotion-themed), and if one day we migrate away from Emotion that the provider is not needed anymore, we can leave it around as an empty, no-op context - a good portion of
@wordpress/components
components would needStyleProvider
to render correctly, meaning that most probably every usage ofSlot
would need to passStyleProvider
- related to the point above, removing
StyleProvider
from theFill
implementation has the potential to cause visual breaking changes to third-party consumers
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What is ComponentsContext
? Can ToolbarContext
be part of it?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ComponentsContext
is a kind of a generic key-value store, where a parent component can tell child components things like "inside toolbar dropdown menus should be in this toolbar-specific style" or "inside input control the prefix subcomponent should have a certain padding-left". Originally comes from Q and his G2 system.
ToolbarContext
is a thing coming from Reakit, where a parent component (container) exposes some API for children (items).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, so ToolbarContext
is basically the same thing as ComponentsContext
but specific to Toolbar
components. I wonder if there's a way to unify.
Size Change: -3.07 kB (0%) Total Size: 1.39 MB
ℹ️ View Unchanged
|
Yes, answered it here: #51264 (comment). The
|
Flaky tests detected in 98ad917. 🔍 Workflow run URL: https://github.com/WordPress/gutenberg/actions/runs/5198427281
|
One more item that needs addressing (quoting from #51154 (comment)):
|
… is present anyway
Maybe forwarding the components context from the Slot tree, without merging it with the context from the Fill tree, is actually the right thing to do. Typically the |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I believe this can be merged now, if all tests pass. CI checks complain about a missing changelog entry for @wordpress/components
, but we're adding only a new private API, nothing publicly visible.
… including internal components context (WordPress#51264) * SlotFill: pass array of contexts in fillProps, use it to pass components context (cherry picked from commit d7d169783b89b0838f2add86852b9cb378fdc890) * Use lock/unlock instead of exporting experimental API * Pass props object instead of just value prop * Mobile BlockControlsSlot: remove ToolbarContext teleport, the context is present anyway * Put forwardedContext into a fillProps field --------- Co-authored-by: Jarda Snajdr <jsnajdr@gmail.com>
What?
While working on #51154, with the help of @jsnajdr we realised that components rendering in the block toolbar via the block controls
SlotFill
wouldn't have access to the internal components context.This PR extracts @jsnajdr 's proposed solution, so that it can be reviewed and merged separately from the rest of the changes in that PR.
Why?
In order to function as expected, components from
@wordpress/components
need to access data passed via React Context. The issue is that, when usingSlotFill
, the components rendered in theFill
don't normally have access to the context in which theFill
renders.How?
The solution is to manually forward these contexts in the
SlotFill
component. This PR refactors the code taking care of context forwarding, making it more general and thus allowing for an additional context (the internal components' context) to also be forwarded.The internal components context is a private API, and is made available to other packages via
lock
/unlock
.Testing Instructions
This PR is not expected to cause any differences in how the block editor works — it is just an internal change that will allow more components to work seamlessly.
Play around with the block toolbar in the block editor, everything should keep working as on
trunk
.