-
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
FormTokenField: add ability to auto select first matching suggestion for incomplete token #42527
FormTokenField: add ability to auto select first matching suggestion for incomplete token #42527
Conversation
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.
Hey @dinhtungdu , thank you for opening this PR!
My main worry is about the UX — the user has no (visual) indication that the first matching suggestion is going to be automatically selected even if the user hasn't selected it explicitly.
Is there a particular reason for adding this functionality?
if ( | ||
matchingSuggestions.length > 0 && | ||
incompleteTokenValue.length > 0 && | ||
typeof __experimentalValidateInput !== 'undefined' && |
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.
The __experimentalValidateInput
prop is assigned a default value of () => true
, and therefore this check will always be true
.
I also don't understand the rationale for tying this new functionality to the __experimentalValidateInput
— why is that prop necessary?
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 review! I fixed the condition in a796d58.
I also don't understand the rationale for tying this new functionality to the
__experimentalValidateInput
— why is that prop necessary?
This is needed because if no validation is passed to __experimentalValidateInput
, any string can be tokenized by pressing Enter key (or space if tokenizeOnSpace
is true
). But you're right, we don't need that check because addNewToken()
won't be executed if a matched suggestion is found. I deleted the unnecessary condition in 25052bd.
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've posted a few more comments, but my main question about the utility of this new feature is still unaddressed:
My main worry is about the UX — the user has no (visual) indication that the first matching suggestion is going to be automatically selected even if the user hasn't selected it explicitly.
Is there a particular reason for adding this functionality?
Could you elaborate a bit more, please? Thank you!
@ciampo I'm sorry for the late reply. I updated the PR to remove The reason for this functionality is when
You're right. I will add a visual indicator to the first matching suggestion to make the behavior predictable to users. |
Yeah I think it's fairly important for there to be a visual indication that pressing Enter will select the item. The current behaviour seems fairly intuitive to me: keyboard.mp4Saving a keypress doesn't really seem worth the potential confusing behaviour. |
Thanks @dinhtungdu for creating the PR and @ciampo and @jameskoster for taking a look and providing feedback. I would like to add some more context on why we would like to introduce this new behavior to the FormTokenField component: In WC Blocks, we are working on using FormTokenField in the frontend as part of the Filter Products by Attribute block (woocommerce/woocommerce-blocks#6647). We don't allow the shopper to introduce values that don't match one of the available options (we are using As an example, imagine a filter that allows selecting the memory of USB sticks. Ideally, the user should be able to type Kooha-07-22-2022-17-41-58.mp4However, that behavior is not currently possible with FormTokenField. That's specially important when the options are long or use special characters. I understand this behavior might not be necessary in some use-cases for the FormTokenField, but I do think it's a common pattern in many other apps. A couple of examples that come to my mind are URL bars in browsers and Slack apps tooltip:
I agree, however, that having a visual indication that the first option is selected would be advisable. Maybe that could be achieved adding the same styles as |
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.
Hey @Aljullu , I understand your case much better now!
We don't allow the shopper to introduce values that don't match one of the available options (we are using
__experimentalValidateInput
to achieve that).
Together with highlighting the first option, I actually think that this is another key aspect of the UX around this feature — I now understand a bit more why @dinhtungdu initially mentioned __experimentalValidateInput
in relationship to this feature.
I almost wonder if, when __experimentalAutoSelectFirstMatch
is enabled, we should always check for the token to be in the list of suggestions?
diff --git a/packages/components/src/form-token-field/index.tsx b/packages/components/src/form-token-field/index.tsx
index 01b05d7916..ac9b3bab92 100644
--- a/packages/components/src/form-token-field/index.tsx
+++ b/packages/components/src/form-token-field/index.tsx
@@ -423,7 +423,11 @@ export function FormTokenField( props: FormTokenFieldProps ) {
}
function addNewToken( token: string ) {
- if ( ! __experimentalValidateInput( token ) ) {
+ if (
+ ! __experimentalValidateInput( token ) ||
+ ( __experimentalAutoSelectFirstMatch &&
+ ! suggestions.includes( token ) )
+ ) {
speak( messages.__experimentalInvalid, 'assertive' );
return;
}
Or, at least, suggest to implement __experimentalValidateInput
accordingly
@Aljullu @jameskoster I addressed it in #42527 (comment). I'm sorry I didn't record a new screencast. I updated the PR description with the new screencast, (crossposting here for your convenience). Screen.Recording.2022-07-25.at.09.47.14.mov
@ciampo I did this initially. But now I think we shouldn't do this for the most flexibility. When
|
This looks much better to the eye – If the first result has focus then pressing Enter to select it seems fine to me. I do wonder about the a11y implications though. |
Looking at the code changes, I don't think that this PR introduced any regressions, as it uses existing internal functions like |
@jameskoster @ciampo is there anything we can do to move this PR forward? |
I'll be having another look at this PR soon. Unfortunately I've been very busy lately and my response time on PR reviews have become considerably longer. |
No problem! Thanks @ciampo! |
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.
Code changes are looking good.
Before the final approval, let's rebase on top of latest trunk
, since this PR has been open for some time and there are merge conflicts.
It would also be good to add a unit test for the expected behavior when __experimentalAutoSelectFirstMatch
is used
Something like this (looks like this test is still written using `react-dom`, even though we're in the process of migrating our tests to RTL
diff --git a/packages/components/src/form-token-field/test/index.js b/packages/components/src/form-token-field/test/index.js
index 3be06711fc..10f6e3270c 100644
--- a/packages/components/src/form-token-field/test/index.js
+++ b/packages/components/src/form-token-field/test/index.js
@@ -396,6 +396,35 @@ describe( 'FormTokenField', () => {
sendKeyDown( keyCodes.enter );
expect( wrapper.state.tokens ).toEqual( [ 'foo', 'bar' ] );
} );
+
+ it( 'should automatically select the first matching suggestions when __experimentalAutoSelectFirstMatch is set to true', () => {
+ setUp( { __experimentalAutoSelectFirstMatch: true } );
+ wrapper.setState( {
+ isExpanded: true,
+ } );
+ expect( getSuggestionsText() ).toEqual( [] );
+
+ const searchText = 'so';
+
+ act( () => {
+ setText( searchText );
+ } );
+
+ const expectedFirstMatchTokens =
+ fixtures.matchingSuggestions[ searchText ][ 0 ];
+
+ expect( getSelectedSuggestion() ).toEqual(
+ expectedFirstMatchTokens
+ );
+
+ sendKeyDown( keyCodes.enter );
+
+ expect( wrapper.state.tokens ).toEqual( [
+ 'foo',
+ 'bar',
+ expectedFirstMatchTokens.join( '' ),
+ ] );
+ } );
} );
describe( 'removing tokens', () => {
@ciampo I added the unit test per your suggestion. Thank you so much! Can you take another look at this? The failed React Native E2E test is unrelated, I don't have permission to rerun 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.
LGTM, thank you for your patience on this one!
Can you just:
- rebase on top of latest
trunk
- add a CHANGELOG entry under the
### Experimental
section ?
I'll merge when that's done
@ciampo I update my branch with latest
I don't see the |
Apologies if my suggestion wasn't clear enough — I meant the diff --git a/packages/components/CHANGELOG.md b/packages/components/CHANGELOG.md
index d2da776b33..854c823db4 100644
--- a/packages/components/CHANGELOG.md
+++ b/packages/components/CHANGELOG.md
@@ -34,6 +34,10 @@
- `ColorPalette`: Refactor away from `_.uniq()` ([#43330](https://github.com/WordPress/gutenberg/pull/43330/)).
- `Guide`: Refactor away from `_.times()` ([#43374](https://github.com/WordPress/gutenberg/pull/43374/)).
+### Experimental
+
+- `FormTokenField`: add `__experimentalAutoSelectFirstMatch` prop to auto select the first matching suggestion on typing ([#42527](https://github.com/WordPress/gutenberg/pull/42527/)).
+
## 19.17.0 (2022-08-10)
### Bug Fix |
@ciampo Thanks for your clarification! I added the changelog entry and update the PR with the latest |
Awesome! I'll merge when CI is ✅ Thank you again! |
What?
This PR adds a new experimental prop to
<FormTokenField>
allows users to select the first matching suggestion for an incomplete token by pressing the Enter key. This is meant to use in tandem with__experimentalValidateInput
.Why?
This is useful when
<FormTokenField>
is used as a dropdown selector. Users don't need to type the full value of the suggestion to select it with the Enter key.For example, given a component with
['blue', 'red', 'green']
as the suggestion array, users can selectblue
by typingb
orbl
only and then press Enter.How?
Testing Instructions
an
then press Enter key.Antarctica
should be selected.Screenshots or screencast
https://user-images.githubusercontent.com/5423135/179729142-c424170b-4eaf-4904-931c-2687633f1413.movUpdated screencast
Screen.Recording.2022-07-25.at.09.47.14.mov
Changelog
FormTokenField: add
__experimentalAutoSelectFirstMatch
prop to auto select the first matching suggestion on typing.