From 8417fc851a72a79500cab89dcc05a2950aa74e4f Mon Sep 17 00:00:00 2001 From: Xiao Yijun Date: Sun, 9 Oct 2022 22:12:52 +0800 Subject: [PATCH] refactor(console): support searching in add language selector (#2069) --- .../AddLanguageSelector.module.scss | 70 +++++++++--- .../AddLanguageSelector.tsx | 103 +++++++++++++----- .../en/translation/admin-console/general.ts | 1 + .../fr/translation/admin-console/general.ts | 1 + .../translation/admin-console/general.ts | 1 + .../translation/admin-console/general.ts | 1 + .../translation/admin-console/general.ts | 1 + .../translation/admin-console/general.ts | 1 + 8 files changed, 131 insertions(+), 48 deletions(-) diff --git a/packages/console/src/pages/SignInExperience/components/ManageLanguageModal/AddLanguageSelector.module.scss b/packages/console/src/pages/SignInExperience/components/ManageLanguageModal/AddLanguageSelector.module.scss index 34d9dbdee..05c0f9a7f 100644 --- a/packages/console/src/pages/SignInExperience/components/ManageLanguageModal/AddLanguageSelector.module.scss +++ b/packages/console/src/pages/SignInExperience/components/ManageLanguageModal/AddLanguageSelector.module.scss @@ -1,24 +1,58 @@ @use '@/scss/underscore' as _; -.addLanguageButton { - width: 100%; - border-color: var(--color-outline); - color: var(--color-text); - background: unset; +.languageSelector { + .input { + position: relative; - .iconPlus { - color: var(--color-outline); + .addLanguageButton { + height: 38px; + width: 100%; + border-color: var(--color-outline); + color: var(--color-text); + background: unset; + } + + .buttonIcon { + color: var(--color-outline); + } + } + + .dropDown { + position: absolute; + width: 168px; + margin: _.unit(1) 0; + padding: _.unit(1); + background: var(--color-float); + border: 1px solid var(--color-divider); + border-radius: 8px; + max-height: 288px; + overflow-y: auto; + + .dropDownItem { + width: 100%; + border-radius: _.unit(2); + padding: _.unit(2); + list-style: none; + cursor: pointer; + + &:hover { + background: var(--color-hover); + } + + .languageName { + font: var(--font-label-large); + color: var(--color-text); + } + + .languageTag { + font: var(--font-body-medium); + color: var(--color-caption); + } + } + } + + .hidden { + display: none; } } -.dropDownItem { - .languageName { - font: var(--font-label-large); - color: var(--color-text); - } - - .languageTag { - font: var(--font-body-medium); - color: var(--color-caption); - } -} diff --git a/packages/console/src/pages/SignInExperience/components/ManageLanguageModal/AddLanguageSelector.tsx b/packages/console/src/pages/SignInExperience/components/ManageLanguageModal/AddLanguageSelector.tsx index d6a8339bb..a3c88a771 100644 --- a/packages/console/src/pages/SignInExperience/components/ManageLanguageModal/AddLanguageSelector.tsx +++ b/packages/console/src/pages/SignInExperience/components/ManageLanguageModal/AddLanguageSelector.tsx @@ -1,9 +1,12 @@ -import { languages, LanguageTag } from '@logto/language-kit'; -import { useRef, useState } from 'react'; +import { LanguageTag, languages as uiLanguageNameMapping } from '@logto/language-kit'; +import classNames from 'classnames'; +import { ChangeEvent, useEffect, useRef, useState } from 'react'; +import { useTranslation } from 'react-i18next'; import Button from '@/components/Button'; -import Dropdown, { DropdownItem } from '@/components/Dropdown'; +import TextInput from '@/components/TextInput'; import Plus from '@/icons/Plus'; +import SearchIcon from '@/icons/Search'; import * as style from './AddLanguageSelector.module.scss'; @@ -12,17 +15,51 @@ type Props = { onSelect: (languageTag: LanguageTag) => void; }; -// TODO:(LOG-4147) Support Instant Search In Manage Language Editor Dropdown const AddLanguageSelector = ({ options, onSelect }: Props) => { - const anchorRef = useRef(null); + const { t } = useTranslation(undefined, { keyPrefix: 'admin_console' }); + const selectorRef = useRef(null); + const searchInputRef = useRef(null); const [isDropDownOpen, setIsDropDownOpen] = useState(false); + const [searchInputValue, setSearchInputValue] = useState(''); + + const filteredOptions = searchInputValue + ? options.filter( + (languageTag) => + languageTag.toLocaleLowerCase().includes(searchInputValue.toLocaleLowerCase()) || + uiLanguageNameMapping[languageTag] + .toLocaleLowerCase() + .includes(searchInputValue.toLocaleLowerCase()) + ) + : options; + + const clickOutsideHandler = ({ target }: MouseEvent) => { + if (target instanceof HTMLElement && !selectorRef.current?.contains(target)) { + setIsDropDownOpen(false); + setSearchInputValue(''); + } + }; + + useEffect(() => { + if (isDropDownOpen) { + searchInputRef.current?.focus(); + document.addEventListener('mousedown', clickOutsideHandler); + } else { + document.removeEventListener('mousedown', clickOutsideHandler); + } + + return () => { + if (isDropDownOpen) { + document.removeEventListener('mousedown', clickOutsideHandler); + } + }; + }, [isDropDownOpen, searchInputRef]); return ( -
-
+
+
- { - setIsDropDownOpen(false); - }} - > - {options.map((languageTag) => ( - { - onSelect(languageTag); - }} - > -
-
{languages[languageTag]}
+ {isDropDownOpen && filteredOptions.length > 0 && ( +
    + {filteredOptions.map((languageTag) => ( +
  • { + onSelect(languageTag); + setIsDropDownOpen(false); + setSearchInputValue(''); + }} + > +
    {uiLanguageNameMapping[languageTag]}
    {languageTag}
    -
-
- ))} -
+ + ))} + + )}
); }; diff --git a/packages/phrases/src/locales/en/translation/admin-console/general.ts b/packages/phrases/src/locales/en/translation/admin-console/general.ts index 2b58baea7..4abb76f90 100644 --- a/packages/phrases/src/locales/en/translation/admin-console/general.ts +++ b/packages/phrases/src/locales/en/translation/admin-console/general.ts @@ -35,6 +35,7 @@ const general = { unsaved_changes_warning: 'You have made some changes. Are you sure you want to leave this page?', leave_page: 'Leave Page', stay_on_page: 'Stay on Page', + type_to_search: 'Type to search', }; export default general; diff --git a/packages/phrases/src/locales/fr/translation/admin-console/general.ts b/packages/phrases/src/locales/fr/translation/admin-console/general.ts index f7f3a53fe..39cc45b8f 100644 --- a/packages/phrases/src/locales/fr/translation/admin-console/general.ts +++ b/packages/phrases/src/locales/fr/translation/admin-console/general.ts @@ -36,6 +36,7 @@ const general = { 'Vous avez effectué des changements. Êtes-vous sûr de vouloir quitter cette page ?', leave_page: 'Quittez la page', stay_on_page: 'Rester sur la page', + type_to_search: 'Type to search', // UNTRANSLATED }; export default general; diff --git a/packages/phrases/src/locales/ko-kr/translation/admin-console/general.ts b/packages/phrases/src/locales/ko-kr/translation/admin-console/general.ts index 7315b0030..49f4a91c9 100644 --- a/packages/phrases/src/locales/ko-kr/translation/admin-console/general.ts +++ b/packages/phrases/src/locales/ko-kr/translation/admin-console/general.ts @@ -35,6 +35,7 @@ const general = { unsaved_changes_warning: '수정된 내용이 있어요. 정말로 현재 페이지를 벗어날까요?', leave_page: '페이지 나가기', stay_on_page: '페이지 유지하기', + type_to_search: 'Type to search', // UNTRANSLATED }; export default general; diff --git a/packages/phrases/src/locales/pt-pt/translation/admin-console/general.ts b/packages/phrases/src/locales/pt-pt/translation/admin-console/general.ts index a4108c12d..1a916e550 100644 --- a/packages/phrases/src/locales/pt-pt/translation/admin-console/general.ts +++ b/packages/phrases/src/locales/pt-pt/translation/admin-console/general.ts @@ -35,6 +35,7 @@ const general = { unsaved_changes_warning: 'Fez algumas alterações. Tem a certeza que deseja sair desta página?', leave_page: 'Sair da página', stay_on_page: 'Ficar na página', + type_to_search: 'Type to search', // UNTRANSLATED }; export default general; diff --git a/packages/phrases/src/locales/tr-tr/translation/admin-console/general.ts b/packages/phrases/src/locales/tr-tr/translation/admin-console/general.ts index 6479072cd..9f490afc3 100644 --- a/packages/phrases/src/locales/tr-tr/translation/admin-console/general.ts +++ b/packages/phrases/src/locales/tr-tr/translation/admin-console/general.ts @@ -36,6 +36,7 @@ const general = { 'Bazı değişiklikler yaptınız. Bu sayfadan ayrılmak istediğine emin misin?', leave_page: 'Sayfayı terk et', stay_on_page: 'Bu sayfada kal', + type_to_search: 'Type to search', // UNTRANSLATED }; export default general; diff --git a/packages/phrases/src/locales/zh-cn/translation/admin-console/general.ts b/packages/phrases/src/locales/zh-cn/translation/admin-console/general.ts index 95bf0a498..21f70887d 100644 --- a/packages/phrases/src/locales/zh-cn/translation/admin-console/general.ts +++ b/packages/phrases/src/locales/zh-cn/translation/admin-console/general.ts @@ -35,6 +35,7 @@ const general = { unsaved_changes_warning: '还有未保存的变更, 确定要离开吗?', leave_page: '离开此页', stay_on_page: '留在此页', + type_to_search: 'Type to search', // UNTRANSLATED }; export default general;