-
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
CustomSelectControlV2: Use InputBase
for styling
#60261
Conversation
const CustomSelectButton = contextConnectWithoutRef( | ||
UnconnectedCustomSelectButton, | ||
'CustomSelectControlButton' | ||
); |
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.
We don't need to connect this to the context system anymore.
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.
Would you mind elaborating on why?
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.
Nevermind, already seen #60261 (comment) 👍🏻
const translatedProps = { | ||
'aria-describedby': props.describedBy, | ||
children, | ||
renderSelectedValue: __experimentalShowSelectedHint | ||
? renderSelectedValueHint | ||
: undefined, | ||
...restProps, | ||
}; |
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 replaced this with direct prop assignments on the _CustomSelect
component for simplicity.
}, [ __next40pxDefaultSize, size ] ); | ||
|
||
const translatedProps = { | ||
'aria-describedby': props.describedBy, |
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.
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 } }, |
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.
No more need to tunnel this via context system, because we can directly set the newly exposed size
prop on _CustomSelect
.
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.
Ah I see 👍🏻 (regarding https://github.com/WordPress/gutenberg/pull/60261/files#r1616307373).
@@ -64,7 +64,7 @@ function getUIFlexProps( labelPosition?: LabelPosition ) { | |||
return props; | |||
} | |||
|
|||
export function InputBase( |
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.
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 😇)
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.
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.
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.
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.
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 refactored some of these types because the rejiggering work I did in this PR surfaced some mistakes in how we were using them.
17764cd
to
a45ee08
Compare
@@ -14,6 +14,19 @@ export type CustomSelectStore = { | |||
|
|||
export type CustomSelectContext = CustomSelectStore | undefined; | |||
|
|||
type CustomSelectSize< Size = 'compact' | 'default' > = { |
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.
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.
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 If you're merging code through a pull request on GitHub, copy and paste the following into the bottom of the merge commit message.
To understand the WordPress project's expectations around crediting contributors, please review the Contributor Attribution page in the Core Handbook. |
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 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.
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.
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 = ( () => { |
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.
Is there a good reason for the IIFE here? Can be a simple if
without an IIFE IMHO.
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.
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 😓
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.
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!
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.
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 } |
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 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?
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.
Everything that can't be merged should be overridable, as per the open/closed pattern.
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 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.
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.
Would be much better if JS supported if
expressions :/
Flaky tests detected in 106f28a. 🔍 Workflow run URL: https://github.com/WordPress/gutenberg/actions/runs/9271457879
|
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 |
@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! |
* 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>
* 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>
After #60226
Part of #55023
What?
Reuse
InputBase
andSelectControlChevronDown
for stylingCustomSelectControlV2
.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
Note
Long strings will still overlap with the chevron. I'll address this separately.