Browse Source

Merge pull request #8532 from weseek/imprv/133158-141063-update-search-typeahead

imprv: Update SearchTypeahead.tsx
Yuki Takei 2 years ago
parent
commit
8f54a87247

+ 17 - 20
apps/app/src/components/SearchTypeahead.tsx

@@ -7,6 +7,7 @@ import React, {
 } from 'react';
 
 import { UserPicture, PageListMeta, PagePathLabel } from '@growi/ui/dist/components';
+import type { TypeaheadRef } from 'react-bootstrap-typeahead';
 import { AsyncTypeahead, Menu, MenuItem } from 'react-bootstrap-typeahead';
 
 import type { IFocusable } from '~/client/interfaces/focusable';
@@ -46,15 +47,6 @@ type Props = TypeaheadProps & {
   helpElement?: React.ReactNode,
 };
 
-// see https://github.com/ericgio/react-bootstrap-typeahead/issues/266#issuecomment-414987723
-type TypeaheadInstance = {
-  setState(input: { text: string | undefined; }): void;
-  clear: () => void,
-  focus: () => void,
-  toggleMenu: () => void,
-  state: { selected: IPageWithSearchMeta[] }
-}
-
 const SearchTypeahead: ForwardRefRenderFunction<IFocusable, Props> = (props: Props, ref) => {
   const {
     onSearchError, onSearch, onInputChange, onChange, onSubmit,
@@ -64,7 +56,7 @@ const SearchTypeahead: ForwardRefRenderFunction<IFocusable, Props> = (props: Pro
 
   const [input, setInput] = useState(keywordOnInit);
   const [searchKeyword, setSearchKeyword] = useState('');
-  const [isForcused, setFocused] = useState(false);
+  const [isFocused, setFocused] = useState(false);
 
   const { data: searchResult, error: searchError, isLoading } = useSWRxSearch(
     disableIncrementalSearch ? null : searchKeyword,
@@ -72,7 +64,7 @@ const SearchTypeahead: ForwardRefRenderFunction<IFocusable, Props> = (props: Pro
     { limit: 10 },
   );
 
-  const typeaheadRef = useRef<TypeaheadInstance>(null);
+  const typeaheadRef = useRef<TypeaheadRef>(null);
 
   const focusToTypeahead = () => {
     const instance = typeaheadRef.current;
@@ -144,14 +136,18 @@ const SearchTypeahead: ForwardRefRenderFunction<IFocusable, Props> = (props: Pro
     if (selectedItems.length > 0) {
       setInput(selectedItems[0].data.path);
 
+      if (onInputChange != null) {
+        onInputChange(selectedItems[0].data.path);
+      }
+
       if (onChange != null) {
         onChange(selectedItems);
       }
     }
-  }, [onChange]);
+  }, [onChange, onInputChange]);
 
   const keyDownHandler = useCallback((event: KeyboardEvent) => {
-    if (event.keyCode === 13) { // Enter key
+    if (event.key === 'Enter') {
       if (onSubmit != null && input != null && input.length > 0) {
         // schedule to submit with 100ms delay
         timeoutIdRef.current = setTimeout(() => onSubmit(input), DELAY_FOR_SUBMISSION);
@@ -171,19 +167,20 @@ const SearchTypeahead: ForwardRefRenderFunction<IFocusable, Props> = (props: Pro
   useEffect(() => {
     // update input with Next Link
     // update input workaround. see: https://github.com/ericgio/react-bootstrap-typeahead/issues/266#issuecomment-414987723
-    if (typeaheadRef.current != null) {
+    if (typeaheadRef.current != null && keywordOnInit != null) {
       typeaheadRef.current.setState({
         text: keywordOnInit,
       });
     }
   }, [keywordOnInit]);
 
-  const labelKey = useCallback((option?: IPageWithSearchMeta) => {
-    return option?.data.path ?? '';
+
+  const labelKey = useCallback((option: IPageWithSearchMeta) => {
+    return option.data.path ?? '';
   }, []);
 
   const renderMenu = useCallback((options: IPageWithSearchMeta[], menuProps) => {
-    if (!isForcused) {
+    if (!isFocused) {
       return <></>;
     }
 
@@ -219,7 +216,7 @@ const SearchTypeahead: ForwardRefRenderFunction<IFocusable, Props> = (props: Pro
         ))}
       </Menu>
     );
-  }, [disableIncrementalSearch, helpElement, input, isForcused]);
+  }, [disableIncrementalSearch, helpElement, input, isFocused]);
 
   const isOpenAlways = helpElement != null;
 
@@ -228,12 +225,12 @@ const SearchTypeahead: ForwardRefRenderFunction<IFocusable, Props> = (props: Pro
       <AsyncTypeahead
         {...props}
         id="search-typeahead-asynctypeahead"
-        // ref={typeaheadRef}
+        ref={typeaheadRef}
         delay={400}
         // eslint-disable-next-line @typescript-eslint/no-explicit-any
         inputProps={{ autoComplete: 'off', ...(inputProps as any ?? {}) }}
         isLoading={isLoading}
-        // labelKey={labelKey}
+        labelKey={labelKey}
         defaultInputValue={keywordOnInit}
         options={searchResult?.data ?? []} // Search result (Some page names)
         align="left"

+ 8 - 8
apps/app/test/cypress/e2e/30-search/30-search--search.cy.ts

@@ -123,7 +123,7 @@ context('Search all pages', () => {
     cy.waitUntil(() => {
       // do
       cy.getByTestid('grw-tag-labels').as('tagLabels').should('be.visible');
-      cy.get('@tagLabels').find('a.btn').as('btn').click();
+      cy.get('@tagLabels').find('button').first().as('btn').click({force: true});
       // wait until
       return cy.get('body').within(() => {
         return Cypress.$('.modal.show').is(':visible');
@@ -225,23 +225,23 @@ context('Sort with dropdown', () => {
     // open sort dropdown
     cy.waitUntil(() => {
       // do
-      cy.get('.grw-search-page-nav').within(() => {
-        cy.get('button.dropdown-toggle').first().click({force: true});
+      cy.get('.search-control').within(() => {
+        cy.get('button').first().click({force: true});
       });
       // wait until
-      return cy.get('.grw-search-page-nav').within(() => {
+      return cy.get('.search-control').within(() => {
         return Cypress.$('.dropdown-menu.show').is(':visible');
       });
     });
   });
 
   it('Open sort dropdown', () => {
-    cy.get('.grw-search-page-nav .dropdown-menu.show').should('be.visible');
+    cy.get('.search-control .dropdown-menu.show').should('be.visible');
       cy.screenshot(`${ssPrefix}2-open-sort-dropdown`);
   });
 
   it('Sort by relevance', () => {
-    cy.get('.grw-search-page-nav .dropdown-menu.show').should('be.visible').within(() => {
+    cy.get('.search-control .dropdown-menu.show').should('be.visible').within(() => {
       cy.get('button:nth-child(1)').click({force: true});
     });
     cy.getByTestid('search-result-base').should('be.visible');
@@ -256,7 +256,7 @@ context('Sort with dropdown', () => {
   });
 
   it('Sort by creation date', () => {
-    cy.get('.grw-search-page-nav .dropdown-menu.show').should('be.visible').within(() => {
+    cy.get('.search-control .dropdown-menu.show').should('be.visible').within(() => {
       cy.get('button:nth-child(2)').click({force: true});
     });
     cy.getByTestid('search-result-base').should('be.visible');
@@ -271,7 +271,7 @@ context('Sort with dropdown', () => {
   });
 
   it('Sort by last update date', () => {
-    cy.get('.grw-search-page-nav .dropdown-menu.show').should('be.visible').within(() => {
+    cy.get('.search-control .dropdown-menu.show').should('be.visible').within(() => {
       cy.get('button:nth-child(3)').click({force: true});
     });
     cy.getByTestid('search-result-base').should('be.visible');