From e5a15326516b3c614d42edcf9c8c4c23187a5d64 Mon Sep 17 00:00:00 2001 From: arvinxx Date: Sun, 14 Feb 2021 02:21:15 +0800 Subject: [PATCH] =?UTF-8?q?:sparkles:=20feat(search-bar):=20=E6=B7=BB?= =?UTF-8?q?=E5=8A=A0=E5=BF=AB=E6=8D=B7=E9=94=AE=E6=93=8D=E4=BD=9C=E6=94=AF?= =?UTF-8?q?=E6=8C=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../SearchInput/components/Options/index.tsx | 33 +++--- .../SearchInput/components/Options/style.less | 14 ++- .../searchBar/app/SearchInput/index.tsx | 18 +-- .../app/SearchInput/useKeyboardService.ts | 110 ++++++++++++++++++ .../searchBar/app/SearchResult/index.tsx | 10 +- .../searchBar/app/SearchResult/style.less | 1 + src/contentScripts/searchBar/app/index.tsx | 4 +- .../searchBar/app/useSearchBarService.ts | 4 - .../searchBar/app/useSearchService.ts | 50 ++++++-- src/theme/token/base.less | 5 + types/SearchBar.d.ts | 5 + 11 files changed, 208 insertions(+), 46 deletions(-) create mode 100644 src/contentScripts/searchBar/app/SearchInput/useKeyboardService.ts diff --git a/src/contentScripts/searchBar/app/SearchInput/components/Options/index.tsx b/src/contentScripts/searchBar/app/SearchInput/components/Options/index.tsx index f8e9ad2..f2f9768 100644 --- a/src/contentScripts/searchBar/app/SearchInput/components/Options/index.tsx +++ b/src/contentScripts/searchBar/app/SearchInput/components/Options/index.tsx @@ -4,39 +4,36 @@ import { Checkbox, Space } from 'antd'; import cls from 'classnames'; import { SearchService } from '../../../useSearchService'; +import { KeyboardService } from '../../useKeyboardService'; import styles from './style.less'; -interface Option { - key: SearchBar.SearchType; - title: string; -} - -const options: Option[] = [ - { key: 'repo', title: '知识库' }, - { key: 'doc', title: '文档' }, - { key: 'topic', title: '主题' }, - { key: 'artboard', title: '画板' }, - { key: 'group', title: '团队' }, - // { key: 'user', title: '用户' }, - // { key: 'attachment', title: '附件' }, -]; - const Options: FC = () => { - const { type, setType, related, setRelated } = useContext(SearchService); + const { + type, + setType, + related, + setRelated, + options, + optionActiveIndex, + } = useContext(SearchService); + const { focusKey, focusOnOptions } = useContext(KeyboardService); return (
- {options.map((option) => ( + {options.map((option, index) => (
{ setType(option.key); + focusOnOptions(); }} > {option.title} diff --git a/src/contentScripts/searchBar/app/SearchInput/components/Options/style.less b/src/contentScripts/searchBar/app/SearchInput/components/Options/style.less index b23565b..c170464 100644 --- a/src/contentScripts/searchBar/app/SearchInput/components/Options/style.less +++ b/src/contentScripts/searchBar/app/SearchInput/components/Options/style.less @@ -15,17 +15,27 @@ transition: all 150ms ease-in-out; } -.optionActive { +.active { color: @yuque-brand-color-dark; background: @yuque-brand-color-light; } +.selected { + color: white; + background: @yuque-brand-color-light-darken; +} + [theme='dark'] { .option { background: @dark-mode-background-dark; } - .optionActive { + .active { color: @dark-mode-yuque-brand-color-dark; background: @dark-mode-yuque-brand-color-light; } + + .selected { + color: white; + background: @dark-mode-yuque-brand-color-light-lighter; + } } diff --git a/src/contentScripts/searchBar/app/SearchInput/index.tsx b/src/contentScripts/searchBar/app/SearchInput/index.tsx index c37b2ea..5ad91dc 100644 --- a/src/contentScripts/searchBar/app/SearchInput/index.tsx +++ b/src/contentScripts/searchBar/app/SearchInput/index.tsx @@ -1,32 +1,32 @@ import type { FC } from 'react'; import React, { useContext } from 'react'; import { Input } from 'antd'; +import { KeyboardService, useKeyboardService } from './useKeyboardService'; import Options from './components/Options'; import { SearchService } from '../useSearchService'; -import { SearchBarService } from '../useSearchBarService'; + import styles from './style.less'; const SearchInput: FC = () => { const { onSearchEvent } = useContext(SearchService); - const { hide } = useContext(SearchBarService); + const keyboardService = useKeyboardService(); + const { inputRef, focusOnInput } = keyboardService; return ( -
+ { - if (e.key === 'Escape') { - hide(); - } - }} + onFocus={focusOnInput} + // onKeyDown={onKeyDown} /> -
+ ); }; diff --git a/src/contentScripts/searchBar/app/SearchInput/useKeyboardService.ts b/src/contentScripts/searchBar/app/SearchInput/useKeyboardService.ts new file mode 100644 index 0000000..b96a9e8 --- /dev/null +++ b/src/contentScripts/searchBar/app/SearchInput/useKeyboardService.ts @@ -0,0 +1,110 @@ +import { useContext, useEffect, useRef, useState } from 'react'; +import type { Input } from 'antd'; + +import { getServiceToken } from '@/utils'; +import { SearchService } from '../useSearchService'; +import { SearchBarService } from '../useSearchBarService'; + +type FocusType = 'input' | 'options' | 'result'; + +/** + * Keyboard 需要的状态 + */ +export const useKeyboardService = () => { + const { setType, optionKeys, optionActiveIndex } = useContext(SearchService); + const { hide } = useContext(SearchBarService); + + const [focusKey, setFocusKey] = useState('input'); + const inputRef = useRef(null); + + /** + * 按 Tabs 键切换选中 type + * @param back + */ + const switchOptionIndex = (back?: boolean) => { + let newIndex: number; + + if (back) { + newIndex = + optionActiveIndex === 0 ? optionKeys.length - 1 : optionActiveIndex - 1; + } else { + newIndex = + optionActiveIndex === optionKeys.length - 1 ? 0 : optionActiveIndex + 1; + } + + setType(optionKeys[newIndex]); + }; + + const focusOnInput = () => { + inputRef.current?.focus(); + setFocusKey('input'); + }; + + const focusOnOptions = () => { + inputRef.current?.blur(); + setFocusKey('options'); + }; + + // 将焦点切换到 Options + const onKeyDown = (event: KeyboardEvent) => { + // 焦点在 options 的情况 + if (focusKey === 'options') { + console.log(event.key); + switch (event.key) { + case 'Tab': + event.preventDefault(); + switchOptionIndex(event.shiftKey); + break; + + case 'ArrowRight': + switchOptionIndex(); + break; + case 'ArrowLeft': + switchOptionIndex(true); + break; + case 'ArrowUp': + case 'Escape': + focusOnInput(); + break; + default: + } + } + + // 焦点在 input 的情况 + if (focusKey === 'input') { + switch (event.key) { + case 'Tab': + event.preventDefault(); + focusOnOptions(); + switchOptionIndex(event.shiftKey); + break; + case 'Escape': + hide(); + break; + case 'ArrowDown': + event.preventDefault(); + focusOnOptions(); + break; + default: + } + } + }; + + useEffect(() => { + window.onkeydown = onKeyDown; + + return () => { + window.onkeydown = null; + }; + }, [focusKey, optionActiveIndex]); + + return { + onKeyDown, + focusKey, + inputRef, + focusOnInput, + focusOnOptions, + }; +}; + +export const KeyboardService = getServiceToken(useKeyboardService); diff --git a/src/contentScripts/searchBar/app/SearchResult/index.tsx b/src/contentScripts/searchBar/app/SearchResult/index.tsx index b6f5ab6..0e45565 100644 --- a/src/contentScripts/searchBar/app/SearchResult/index.tsx +++ b/src/contentScripts/searchBar/app/SearchResult/index.tsx @@ -11,7 +11,15 @@ const SearchResult: FC = () => { const { result, loading } = useContext(SearchService); return ( - + {result?.map((item) => { const { title, info, id, url, target, type } = item; diff --git a/src/contentScripts/searchBar/app/SearchResult/style.less b/src/contentScripts/searchBar/app/SearchResult/style.less index 49c4c69..7d43409 100644 --- a/src/contentScripts/searchBar/app/SearchResult/style.less +++ b/src/contentScripts/searchBar/app/SearchResult/style.less @@ -1,5 +1,6 @@ @import '~theme/index'; .skeleton { + margin-top: 16px; padding: 8px 12px 24px; } .repo { diff --git a/src/contentScripts/searchBar/app/index.tsx b/src/contentScripts/searchBar/app/index.tsx index d6d5f33..49113d3 100644 --- a/src/contentScripts/searchBar/app/index.tsx +++ b/src/contentScripts/searchBar/app/index.tsx @@ -12,6 +12,7 @@ import SearchResult from './SearchResult'; import AnimatedHeight from './AnimatedHeight'; import styles from './style.less'; +import { isDev } from '@/utils'; const SearchBar: FC = () => { const { visible, searchBarRef } = useContext(SearchBarService); @@ -60,7 +61,6 @@ const SearchBar: FC = () => {