-
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
Rewrite <FormTokenField>
to functional component and Typescript.
#41216
Conversation
Size Change: -695 B (0%) Total Size: 1.24 MB
ℹ️ View Unchanged
|
<TokenInput>
in FormTokenField to functional component and Typescript.<FormTokenField>
to functional component and Typescript.
<FormTokenField>
to functional component and Typescript.<FormTokenField>
to functional component and Typescript.
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.
Wow, thank you for taking on this monster component! 👏
I've looked through all but the main index.tsx
file and suggestions-list.tsx
. Before I go any further, would you be able to move the bug fix that you did to a separate PR? This is a complex component written a long time ago and we're very unfamiliar with it. We'd appreciate any help from your end so we can review it safely with confidence.
That means:
- Extracting any functional changes that aren't part of the essential refactor, and move them to a separate PR so we can concentrate on reviewing the refactor.
- Adding GitHub inline comments to any notable changes that needed to happen. (For example, things like the removal of the TODO comment and
withSafeTimeout
in suggestions-list. I can't tell why these changes were needed, so it'd be very helpful if you could add some explanation.)
Thank you so much! 🙌
onlyScrollIfNeeded?: boolean; | ||
} | ||
|
||
declare module 'dom-scroll-into-view' { |
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 adding the types for this 😅 I see the package is unmaintained and also doesn't have an @types
!
I guess we're waiting on Safari now to implement the "nearest"
options so we can replace it with Element.scrollIntoView()
? Maybe by next year!
@@ -10,7 +10,6 @@ import ReactDOM from 'react-dom'; | |||
*/ |
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'll want to update these tests to use React Testing Library eventually, but I guess it's nice to have these act
wrappers in the meantime 😄
__experimentalValidateInput={ | ||
__experimentalValidateInput | ||
? ( newValue ) => continents.includes( newValue ) | ||
: () => true | ||
} |
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 was going back and forth on whether we should do this in the Storybook (is it too confusing?), but ultimately I think it's probably good. I think it will be clearer once we have the prop descriptions showing up in the props table.
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.
In Storybook, the type shown is token: string) => boolean
but the control says "Set boolean" — wouldn't that be a bit confusing?
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.
Updated storybook and type documents. How is 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.
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.
Works for me 👍
packages/components/src/form-token-field/test/lib/token-field-wrapper.js
Outdated
Show resolved
Hide resolved
const selected = _value.map( ( item ) => { | ||
if ( typeof item === 'string' ) { | ||
return item; | ||
} | ||
return item.value; | ||
} ); |
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.
Fixed a problem where a filter in the query loop block would suggest something that was already selected.
Separating to another PR would result in a type mismatch.
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.
Awesome, thank you! I haven't gotten to suggestions-list
yet, but I've reviewed the main file. I'll probably be able to review the suggestions-list later today or maybe tomorrow.
Before I forget, could you also add a changelog entry please? This probably warrants two entries — one under Bug Fix and another under Internal 🌟
updateSuggestions( suggestionsDidUpdate ); | ||
}, [ suggestions ] ); |
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.
In the original logic, updateSuggestions()
also runs on value
updates, presumably because getMatchingSuggestions()
depends on value
. Was this logic removed on purpose?
gutenberg/packages/components/src/form-token-field/index.js
Lines 86 to 88 in 046ca65
if ( suggestionsDidUpdate || value !== prevProps.value ) { | |
this.updateSuggestions( suggestionsDidUpdate ); | |
} |
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 think this is a mistake. I will fix it.
useEffect( () => { | ||
updateSuggestions(); | ||
}, [ incompleteTokenValue ] ); |
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.
Note for posterity — This useEffect
mimics the setState
callback in the original logic here:
gutenberg/packages/components/src/form-token-field/index.js
Lines 244 to 247 in 046ca65
this.setState( | |
{ incompleteTokenValue: tokenValue }, | |
this.updateSuggestions | |
); |
); | ||
|
||
updateSuggestions( suggestionsDidUpdate ); | ||
}, [ suggestions ] ); |
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 are in the process of reenabling the react-hooks/exhaustive-deps
eslint rule (#41166), and this deps array here is going to trigger a warning:
React Hook useEffect has missing dependencies: 'prevSuggestions' and 'updateSuggestions'. Either include them or remove the dependency array.
And speaking of updateSuggestions
... this and getMatchingSuggestions
are really hard to verify correctness because they rely on so much outer state ☠️ Ideally I'd want to refactor them into pure-ish functions and move them out of the main component function! But, since this PR is already pretty big, we should probably keep changes to a minimum. How about we do something like this for now?
}, [ suggestions ] ); | |
// TODO: updateSuggestions() should first be refactored so its actual deps are clearer | |
// eslint-disable-next-line react-hooks/exhaustive-deps | |
}, [ suggestions, prevSuggestions ] ); |
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.
suggestions-list
looks great 👍
I also did some manually testing in the Storybook, and did not find any regressions. We should be good to merge once the remaining feedback is addressed.
* Remove findRenderedComponentWithType as it does not work with functional components.
Co-authored-by: Lena Morita <[email protected]>
Co-authored-by: Lena Morita <[email protected]>
Co-authored-by: Lena Morita <[email protected]>
Co-authored-by: Lena Morita <[email protected]>
Co-authored-by: Lena Morita <[email protected]>
Co-authored-by: Lena Morita <[email protected]>
af8adec
to
e1bc853
Compare
__experimentalValidateInput={ | ||
__experimentalValidateInput | ||
? ( newValue ) => continents.includes( newValue ) | ||
: () => true | ||
} |
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.
Works for me 👍
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.
Yay! Awesome work here. The Storybook docs look really good, and you even got in some subtle bug fixes. Very cool.
I just found one stray line that needs to be cleaned up (I think it's just an oversight). Feel free to merge after that one is addressed 🙏
* this is needed to remove leading and trailing spaces from tag names, like wp-admin does. | ||
* Otherwise the REST API won't save them.) | ||
* | ||
* @default ( token: string ) => token.trim() |
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.
❤️
Co-authored-by: Lena Morita <[email protected]>
ref: #35744, #22890
What?
Rewrites the component JavaScript in packages/components/form-token-field in TypeScript and refactor to functional component.
Also, fixed an issue where the filter in the query loop block would suggest something that was already selected.
Part of #35744
Testing Instructions