-
Notifications
You must be signed in to change notification settings - Fork 4.2k
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
How we can approach the introduction of a new link component within Gutenberg #18061
Comments
I left a comment at #19523 (comment) which might have been more appropriate to discuss here. In that comment, I included an annotated screenshot of what I considered to be proposed as the layers of abstraction in some final implementation of the new link creation UI: I do kinda wonder / worry, especially in considering a separation between Especially the UI for "viewing" a link, like in the screenshot of #17557 (comment), where it's heavily optimized to be assumed to be shown in a popover. I doubt it would work quite as well if it were detached from Popover. It's fair to say that popovers would be the most common usage, but then it raises the question whether there's a ton of value in separating it from Popover (like in @youknowriad's #19638). Personally, I do like the idea of considering these as small composable units, so the refactor feels good to me, but it does leave |
I could see cases where |
There already is in #19504 the need to use |
In the above model, I think My understanding of
I think this is more-or-less satisfied in its current implementation, but the specifics of the display are heavily optimized to assume that it would be shown in a Consider the screenshot from #17557 (comment):
|
Since images can probably speak better than words in this instance, I'll try to illustrate with screenshots. Consider that I have a modal which renders a form. I might expect something like the following code: function ExampleForm() {
return (
<Modal title="Example Form">
<TextControl label="First name" />
<TextControl label="Last name" />
<LinkControl label="Website" />
<SelectControl label="Country" options={ [ { label: 'United States', value: 'us' } ] } />
</Modal>
);
} As far as the usage of the components, they are quite aligned. But for the rendered output, you can see that one of these is not like the rest: The same example, with a value assigned: function ExampleForm() {
return (
<Modal title="Example Form">
<TextControl label="First name" />
<TextControl label="Last name" />
<LinkControl label="Website" value={ { url: 'https://example.com' } } />
<SelectControl label="Country" options={ [ { label: 'United States', value: 'us' } ] } />
</Modal>
);
} |
This is very nice to see. I guess we should have a page in Storybook showing all controls together (in order to reason about them together). It makes me think we'd want:
|
I've been thinking about some specific tasks to get closer to a desirable separation between
Let me know if any of these don't make sense, or if there are others I am missing. |
This is a great list.
Sounds like it should, the name is not great though
LinkControl as well right?
😍 |
Possibly, yeah. I think it's generic enough. I also think there might be value in having something in |
Another observation from implementing this for the paragraph link format in #19462: The presentation of a link preview including its title is nice: ...but the way this is implemented in the Navigation Link block, it relies on the Furthermore, I have proposed for the I sense that the efforts described in #18042 could play a part here, though I'm not sure if that was specifically modeled for retrieving details associated with the current value of the link vs. details associated with a URL input value. |
Another part of this that I've been thinking about is with regards to the extensibility we're exploring through the
|
What's remaining on this? Can it be closed? |
There's still quite a few action items remaining here, though ideally should be broken down to disparate issues. I've listed some at #18061 (comment) . I can try to revisit this and create those issues to close in favor of. |
Closing in favor of:
|
An effort is underway to create a new unified interface for adding / editing links within the editor. It may look something like this:
Work is already underway to implement this.
What follows below is an analysis and recommendation for how we can go about introducing this new standardised link interface into Gutenberg.
This has been prompted by several discussions as to the best technical route to take in order to allow us to introduce this new UI across the editor with a minimum of disruption.
I will begin with an overview of the existing interface components that provide link-related UI.
I will then analyse how/whether it is possible to modify the existing components to realise the new link UI design.
Following on from this, I will then discuss how the current link interfaces within Gutenberg are created.
Finally, I will propose a route forward centred around creating a single unified component for link interfaces within Gutenberg.
Overview of existing "link" Components
The following components are already available within Gutenberg and are used for creating "link" interfaces.
URLInput
Posts
andPages
as you type. URLs are not handled as search suggestions.packages/block-editor/src/components/url-input
listbox
ARIA attrsURLPopover.LinkEditor
and is only ever used in isolation withinpackages/block-library/src/button/edit.js
. This component is low level. It does not provide a popover or a settings drawer. Therefore when used in isolation it will not provide the design for the new Link UI. Therefore it is ill suited as a wrapper component.URLPopover
URLInput
andExternalLink
internally.packages/block-editor/src/components/url-popover
URLInput
, withURLInput
provinding the input and search suggestions andURLPopover
providing the settings drawer, "selected" states and a popover in which to contain the UI.URLPopover
also exposes the following sub components:URLPopover.LinkEditor
packages/block-editor/src/components/url-popover/link-editor.js
This provides a simple wrapper around
URLInput
to provide a<form>
tag and aApply
button.URLPopover.LinkViewer
packages/block-editor/src/components/url-popover/link-viewer.js
This provides a simple style for "selected" links. It is a wrapper around
ExternalLink
and also provides an "Edit" button.How are link interfaces currently creating within Gutenberg?
As it stands the two existing components
URLInput
andURLPopover
are largely low level components. Therefore, it is important to appreciate that in almost every case where a link interface is required within Gutenberg, these components are consumed and controlled by the parent component (viaprops
) to create a bespoke interface.This happens each time a link UI is created.
Some good examples of this are:
URLPopoverAtLink
component which wires togetherURLPopover
and (indirectly viaURLPopover.LinkEditor
)URLInput
to create a unified link interface.core/image
Block'sedit
implementation. You will note that the implementation is wiring together the low level components in such a way as to produce a unified link interface.MediaPlaceholder
component which has a bespoke link interface which does not even utiliseURLInput
.core/social-link
Block. Again this does not utiliseURLInput
.What we can observe here is that each time an interface for adding links is required, the developer is currently required to wire together a bespoke implementation.
In short, there is currently no unified interface component for creating link UIs in Gutenberg.
Conclusion and Recommendation
Based on the evidence above, it appears that what is required is not extensive modification or refactoring of the existing
URL*
components, but rather the creation of a single component which wires together the lower-level components to provide a unified link interface.Given that
URLInput
is a low level component which is already in use, attempting to refactor this to be a wrapper around a more complex, fully unified Link UI would be complex, time-consuming and provide little or no benefit.Similarly,
URLPopover
is largely a visual component and should not be a candidate for managing state or a fully unified UI.Therefore, the most effective and expedient solution is to create a new component which unifies the existing components under a single interface.
By doing this we will provide the following benefits:
URLInput
andURLPopover
components can be preserved and reused - no need for deprecations.URLInput
andURLPopover
will make these more flexible for future if/when required to create bespoke/highly customised link UIs that cannot be serviced by the unified component.The new component can be relased as "experimental" and then once accepted, it can gradually used to replace the existing bespoke usages of
URLPopover
andURLInput
thereby standardising link intefaces across Gutenberg.This approach has already been trialled in this PR.
Appendix A: do we need to modify the existing components to deliver the new design?
The following changes are required to both components in order to realise the new design:
Changes to URLInput
Update rendering of suggestion items to add in more information about the suggestion (see Design) - this can be achieved by either:
URLInput
directly (note: this means all existing implementations will inherit this change).URLInput
to allow parent/consuming components to modify the rendered output of suggestion items (as per currentLinkControl
PR).Update the
placeholder
on the input - this is most easily achieved by exposing aplaceholder
prop onURLInput
.Fix to ensure that suggestions are hidden when the input is empty.
Design requires that when a URL is entered this is displayed as a search suggestion. Currently
URLInput
will ignore URLs when calling the function prop which fetches search suggestion data. This can be fixed by:updateSuggestions
method to detect URLs and immediately set thestate.suggestions
to be a single object representing the current input value (see the implementation inLinkControl
)URLInput
which conditionally enables URL handling in theupdateSuggestions
method. The parent component must then pass an appropriate handler based on the type of input (see the implementation in LinkControl)Changes to URLPopover
Given that it is mainly a wrapper component, it is unlikely that it would be useful to make changes to
URLPopover
. Almost every example of a Link UI within Gutenberg consumesURLPopover
as a controlled component. All state management and customisation is handled outside ofURLPopover
.The only major changes required to realise the new design would be:
Appendix B: Related Links
The text was updated successfully, but these errors were encountered: