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

CustomSelectControlV2: Use InputBase for styling #60261

Merged
merged 6 commits into from
May 28, 2024

Conversation

mirka
Copy link
Member

@mirka mirka commented Mar 27, 2024

After #60226
Part of #55023

What?

Reuse InputBase and SelectControlChevronDown for styling CustomSelectControlV2.

Why?

For more DRY and consistent styling.

(InputBase is an internal component used to style the standard borders for an input, as well as handle the layout for prefix/suffix elements.)

Testing Instructions

  • Focus styles for CustomSelectControlV2 Legacy should match the styles for v1.
  • The chevron should have the correct padding in all possible sizes.

Note

Long strings will still overlap with the chevron. I'll address this separately.

@mirka mirka added [Type] Enhancement A suggestion for improvement. [Package] Components /packages/components labels Mar 27, 2024
@mirka mirka self-assigned this Mar 27, 2024
Comment on lines -89 to -92
const CustomSelectButton = contextConnectWithoutRef(
UnconnectedCustomSelectButton,
'CustomSelectControlButton'
);
Copy link
Member Author

Choose a reason for hiding this comment

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

We don't need to connect this to the context system anymore.

Copy link
Member

Choose a reason for hiding this comment

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

Would you mind elaborating on why?

Copy link
Member

Choose a reason for hiding this comment

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

Nevermind, already seen #60261 (comment) 👍🏻

Comment on lines -115 to -124
const translatedProps = {
'aria-describedby': props.describedBy,
children,
renderSelectedValue: __experimentalShowSelectedHint
? renderSelectedValueHint
: undefined,
...restProps,
};
Copy link
Member Author

Choose a reason for hiding this comment

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

I replaced this with direct prop assignments on the _CustomSelect component for simplicity.

}, [ __next40pxDefaultSize, size ] );

const translatedProps = {
'aria-describedby': props.describedBy,
Copy link
Member Author

Choose a reason for hiding this comment

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

describedBy wasn't being destructured from the props, and therefore it was still being passed invalidly to _CustomSelect through the rest props. Fixed.

}

return {
CustomSelectControlButton: { _overrides: { size: selectedSize } },
Copy link
Member Author

Choose a reason for hiding this comment

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

No more need to tunnel this via context system, because we can directly set the newly exposed size prop on _CustomSelect.

Copy link
Member

@fullofcaffeine fullofcaffeine May 27, 2024

Choose a reason for hiding this comment

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

@@ -64,7 +64,7 @@ function getUIFlexProps( labelPosition?: LabelPosition ) {
return props;
}

export function InputBase(
Copy link
Member Author

Choose a reason for hiding this comment

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

Removed this unused export, because a consumer can erroneously import this named version instead of the default export which is properly wrapped in a forwardRef().

(This happened to me while working on this PR and it wasted a couple minutes of my life 😇)

Copy link
Member

Choose a reason for hiding this comment

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

Nit, but, what is the current convention for components - should we provide both (named, default) or just one - and if so, it seems default is preferred?

Another approach would be to connect before while assigning to a const and then export as needed.

Copy link
Member Author

Choose a reason for hiding this comment

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

Good question. We do indeed have some conventions that are actually for accommodating our current docgen, more than anything else.

Doesn't matter that much for internal components like InputBase, which aren't fed into the docgen.

Copy link
Member Author

Choose a reason for hiding this comment

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

I refactored some of these types because the rejiggering work I did in this PR surfaced some mistakes in how we were using them.

@mirka mirka force-pushed the custom-select-v2-input-base branch from 17764cd to a45ee08 Compare May 24, 2024 12:42
@@ -14,6 +14,19 @@ export type CustomSelectStore = {

export type CustomSelectContext = CustomSelectStore | undefined;

type CustomSelectSize< Size = 'compact' | 'default' > = {
Copy link
Member Author

Choose a reason for hiding this comment

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

For context, the public interface of CustomSelectControlV2 only has these two size variants, whereas the private (internal) CustomSelectButton has three size variants for back compat.

@mirka mirka marked this pull request as ready for review May 24, 2024 13:28
@mirka mirka requested a review from ajitbohra as a code owner May 24, 2024 13:28
@mirka mirka requested review from fullofcaffeine and a team May 24, 2024 13:29
Copy link

github-actions bot commented May 24, 2024

The following accounts have interacted with this PR and/or linked issues. I will continue to update these lists as activity occurs. You can also manually ask me to refresh this list by adding the props-bot label.

If you're merging code through a pull request on GitHub, copy and paste the following into the bottom of the merge commit message.

Co-authored-by: mirka <0mirka00@git.wordpress.org>
Co-authored-by: fullofcaffeine <fullofcaffeine@git.wordpress.org>
Co-authored-by: tyxla <tyxla@git.wordpress.org>
Co-authored-by: DaniGuardiola <daniguardiola@git.wordpress.org>

To understand the WordPress project's expectations around crediting contributors, please review the Contributor Attribution page in the Core Handbook.

Copy link
Member

@fullofcaffeine fullofcaffeine left a comment

Choose a reason for hiding this comment

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

I didn't know about InputBase; I can see it's part of the input-control component. Would it make more sense to make it a separate component if it's going to be used as the basis for others like this (in a follow-up, ofc)? It feels weird it doesn't have its own doc, too. For now, it'd be nice if you could add a bit more information/background on InputBase in the PR description, if possible.

Other than that, the changes looks good! Storybook stories also look good. However, I can still see the API and styling issues I've found while working on #61272. Since this component is still private, I think it's fine to merge this now and rebase/merge it into #61272 to see how it behaves with the fixes there. Will start looking into it as soon as this is merged.

Copy link
Member

@tyxla tyxla left a comment

Choose a reason for hiding this comment

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

Looks good to me visually and works well 👍 Thanks.

Just left a couple of minor questions, but other than that, good to go 🚀

const contextSystemValue = useMemo( () => {
let selectedSize;

const translatedSize = ( () => {
Copy link
Member

Choose a reason for hiding this comment

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

Is there a good reason for the IIFE here? Can be a simple if without an IIFE IMHO.

Copy link
Member Author

Choose a reason for hiding this comment

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

To me, this takes the least cognitive load to read because it doesn't introduce a mutable variable (let), and it's a bit of overkill to extract out the entire function. I'm probably more mutation-averse than average though 😓

Copy link
Member

Choose a reason for hiding this comment

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

Primitive values cannot be mutated, so we're technically not really mutating anything. Also, the IIFE makes the code a bit more complex to read than if we were using a let. No strong feelings either way, so I'm happy to leave this to your judgment!

Copy link
Member Author

Choose a reason for hiding this comment

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

Touché, I should've said reassignment! I always considered variable reassignment to be a form of mutation (as in mutable state), but I guess those two terms should be differentiated in JS at least.

}
size={ translatedSize }
store={ store }
{ ...restProps }
Copy link
Member

Choose a reason for hiding this comment

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

Do we intentionally allow the restProps to override the above props like store or renderSelectedValue? Should these props be declared below the restProps to prevent that from happening?

Copy link
Contributor

Choose a reason for hiding this comment

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

Everything that can't be merged should be overridable, as per the open/closed pattern.

Copy link
Member Author

Choose a reason for hiding this comment

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

Also store or renderSelectedValue are not documented in the public interface for this, so it would be very at-your-own-risk if anyone tried that.

No strong opinion, but I think the general strategy of "keep everything overridable unless there is a specific, strong reason not to" would be fine.

Copy link
Member

Choose a reason for hiding this comment

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

Would be much better if JS supported if expressions :/

Copy link

Flaky tests detected in 106f28a.
Some tests passed with failed attempts. The failures may not be related to this commit but are still reported for visibility. See the documentation for more information.

🔍 Workflow run URL: https://github.com/WordPress/gutenberg/actions/runs/9271457879
📝 Reported issues:

@mirka
Copy link
Member Author

mirka commented May 28, 2024

I didn't know about InputBase; I can see it's part of the input-control component. Would it make more sense to make it a separate component if it's going to be used as the basis for others like this (in a follow-up, ofc)? It feels weird it doesn't have its own doc, too. For now, it'd be nice if you could add a bit more information/background on InputBase in the PR description, if possible.

Sorry about that. I added a quick note to the PR description, and a JSDoc on the component for good measure. And good point, we might want to consider extracting out the InputBase from the input-control folder, since it's starting to be used in more places.

@mirka mirka merged commit 6fa3471 into trunk May 28, 2024
63 checks passed
@mirka mirka deleted the custom-select-v2-input-base branch May 28, 2024 15:22
@github-actions github-actions bot added this to the Gutenberg 18.5 milestone May 28, 2024
@DaniGuardiola
Copy link
Contributor

DaniGuardiola commented May 28, 2024

@mirka fwiw, I wanna take a closer look at this InputBase thingy. A while back I looked at it and it seems to be doing a whole lot of not really that much :P - I think there's potential for simplifying or splitting this up into something more manageable and way simpler. Note that I'm including a few different layers that I noticed in input code, so maybe I'm getting things mixed up here and this one's as simple as it gets. In any case, this is for another day, just wanted to make a note!

carstingaxion pushed a commit to carstingaxion/gutenberg that referenced this pull request Jun 4, 2024
* Stop exporting unconnected InputBase

* CustomSelectControlV2: Use InputBase for styling

* Adjust styles

* Clean up

* Add changelog

* Add JSDoc description for InputBase

Co-authored-by: mirka <0mirka00@git.wordpress.org>
Co-authored-by: fullofcaffeine <fullofcaffeine@git.wordpress.org>
Co-authored-by: tyxla <tyxla@git.wordpress.org>
Co-authored-by: DaniGuardiola <daniguardiola@git.wordpress.org>
patil-vipul pushed a commit to patil-vipul/gutenberg that referenced this pull request Jun 17, 2024
* Stop exporting unconnected InputBase

* CustomSelectControlV2: Use InputBase for styling

* Adjust styles

* Clean up

* Add changelog

* Add JSDoc description for InputBase

Co-authored-by: mirka <0mirka00@git.wordpress.org>
Co-authored-by: fullofcaffeine <fullofcaffeine@git.wordpress.org>
Co-authored-by: tyxla <tyxla@git.wordpress.org>
Co-authored-by: DaniGuardiola <daniguardiola@git.wordpress.org>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
[Package] Components /packages/components [Type] Enhancement A suggestion for improvement.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants