Просмотр исходного кода

Add AiAssistantKeywordSearch component with styling and keyboard handling

Shun Miyazawa 8 месяцев назад
Родитель
Сommit
d069289f6d

+ 23 - 0
apps/app/src/features/openai/client/components/AiAssistant/AiAssistantManagementModal/AiAssistantManagementKeywordSearch.module.scss

@@ -0,0 +1,23 @@
+@use '@growi/core-styles/scss/variables/growi-official-colors';
+@use '@growi/core-styles/scss/bootstrap/init' as bs;
+@use '~/styles/variables' as var;
+
+
+.grw-ai-assistant-keyword-search :global {
+  .rbt {
+    .rbt-input-multi {
+      border: none;
+      border-bottom: 3px solid bs.$gray-200;
+      border-radius: 0;
+
+      &.focus {
+        border-color: var(--grw-primary-500);
+        box-shadow: none;
+      }
+    }
+
+    .rbt-menu {
+       display: none !important;
+    }
+  }
+}

+ 42 - 2
apps/app/src/features/openai/client/components/AiAssistant/AiAssistantManagementModal/AiAssistantManagementKeywordSearch.tsx

@@ -1,4 +1,8 @@
+import type { KeyboardEvent } from 'react';
+import React, { useRef, useCallback } from 'react';
 
+import type { TypeaheadRef } from 'react-bootstrap-typeahead';
+import { Typeahead } from 'react-bootstrap-typeahead';
 import { useTranslation } from 'react-i18next';
 import {
   ModalBody,
@@ -10,14 +14,39 @@ import {
 
 import { AiAssistantManagementHeader } from './AiAssistantManagementHeader';
 
+import styles from './AiAssistantManagementKeywordSearch.module.scss';
+
+const moduleClass = styles['grw-ai-assistant-keyword-search'] ?? '';
 
 export const AiAssistantKeywordSearch = (): JSX.Element => {
   const { t } = useTranslation();
   const { data: aiAssistantManagementModalData } = useAiAssistantManagementModal();
   const isNewAiAssistant = aiAssistantManagementModalData?.aiAssistantData == null;
 
+  const typeaheadRef = useRef<TypeaheadRef>(null);
+
+  const keyDownHandler = useCallback((event: KeyboardEvent<HTMLElement>) => {
+    if (event.code === 'Space') {
+      event.preventDefault();
+
+      // fix: https://redmine.weseek.co.jp/issues/140689
+      // "event.isComposing" is not supported
+      const isComposing = event.nativeEvent.isComposing;
+      if (isComposing) {
+        return;
+      }
+
+      const initialItem = typeaheadRef?.current?.state?.initialItem;
+      const handleMenuItemSelect = typeaheadRef?.current?._handleMenuItemSelect;
+
+      if (initialItem != null && handleMenuItemSelect != null) {
+        handleMenuItemSelect(initialItem, event);
+      }
+    }
+  }, []);
+
   return (
-    <>
+    <div className={moduleClass}>
       <AiAssistantManagementHeader
         backButtonColor="secondary"
         backToPageMode={AiAssistantManagementModalPageMode.PAGE_SELECTION_METHOD}
@@ -28,7 +57,18 @@ export const AiAssistantKeywordSearch = (): JSX.Element => {
         <h4 className="text-center mb-4 fw-bold">
           {t('modal_ai_assistant.search_reference_pages_by_keyword')}
         </h4>
+
+        <Typeahead
+          allowNew
+          multiple
+          options={[]}
+          placeholder="キーワードを入力"
+          id="ai-assistant-keyword-search"
+          ref={typeaheadRef}
+          onKeyDown={keyDownHandler}
+          isLoading={false}
+        />
       </ModalBody>
-    </>
+    </div>
   );
 };