From ccc29e5346c023e8f590a2bbd9f9f585fc25d83f Mon Sep 17 00:00:00 2001 From: Ye-Chan Kang Date: Wed, 24 Apr 2024 19:41:15 +0900 Subject: [PATCH 1/5] feat(common): search (#23) --- src/components/Portal/Portal.tsx | 5 +- src/components/Search/Search.tsx | 19 ++ src/components/Search/SearchContent.tsx | 20 ++ src/components/Search/SearchInput.tsx | 27 +++ src/components/Search/SearchInputToggle.tsx | 43 ++++ src/components/Search/SearchItem.tsx | 55 +++++ src/components/Search/SearchToggle.tsx | 43 ++++ src/components/Search/index.tsx | 40 ++++ src/components/index.ts | 1 + src/stories/common/Search.stories.tsx | 224 ++++++++++++++++++++ 10 files changed, 475 insertions(+), 2 deletions(-) create mode 100644 src/components/Search/Search.tsx create mode 100644 src/components/Search/SearchContent.tsx create mode 100644 src/components/Search/SearchInput.tsx create mode 100644 src/components/Search/SearchInputToggle.tsx create mode 100644 src/components/Search/SearchItem.tsx create mode 100644 src/components/Search/SearchToggle.tsx create mode 100644 src/components/Search/index.tsx create mode 100644 src/stories/common/Search.stories.tsx diff --git a/src/components/Portal/Portal.tsx b/src/components/Portal/Portal.tsx index d702686..e6da309 100644 --- a/src/components/Portal/Portal.tsx +++ b/src/components/Portal/Portal.tsx @@ -21,7 +21,7 @@ const Portal = ({ children, ref, width, onKeyDown, ...props }: ModalContentProps const ACTIONS: Record) => void> = { ArrowDown: () => focus('next'), ArrowUp: () => focus('prev'), - Tab: e => e.preventDefault(), + Tab: () => focus('next'), Enter: () => select(), }; @@ -65,7 +65,7 @@ const Portal = ({ children, ref, width, onKeyDown, ...props }: ModalContentProps const handleOpen = React.useCallback(() => { if (portalRef.current) { - portalRef.current.focus(); + // portalRef.current.focus(); setItems( Array.from(portalRef.current.querySelectorAll('[data-focus-enabled="true"]')).filter(e => { return e.getAttribute('disabled') == null; @@ -102,6 +102,7 @@ const PortalStyled = styled.div<{ width?: React.CSSProperties['width']; position display: grid; min-width: max-content; ${({ width }) => width && `width: ${typeof width === 'string' ? width : `${width}px`};`} + max-width: 100%; padding: 0.25rem; border-radius: 0.25rem; position: fixed; diff --git a/src/components/Search/Search.tsx b/src/components/Search/Search.tsx new file mode 100644 index 0000000..860f28b --- /dev/null +++ b/src/components/Search/Search.tsx @@ -0,0 +1,19 @@ +import { PortalProvider } from '@/components/Portal/PortalProvider'; +import { AlignType } from '@/types/align'; + +interface SearchProps extends React.PropsWithChildren { + align?: AlignType; + space?: number; +} + +/** + * Displays a list of menus. + * @returns + */ +export const Search = ({ align = 'center', space = 0, children }: SearchProps) => { + return ( + + {children} + + ); +}; diff --git a/src/components/Search/SearchContent.tsx b/src/components/Search/SearchContent.tsx new file mode 100644 index 0000000..38a5e28 --- /dev/null +++ b/src/components/Search/SearchContent.tsx @@ -0,0 +1,20 @@ +import * as React from 'react'; + +import { PortalContent } from '@/components/Portal/PortalContent'; + +interface ModalProps extends React.ComponentPropsWithoutRef<'div'> { + width?: React.CSSProperties['width']; +} + +/** + * SearchContent + * @returns + */ +export const SearchContent = React.forwardRef(({ width, children, ...props }, ref) => { + return ( + + {children} + + ); +}); +SearchContent.displayName = 'SearchContent'; diff --git a/src/components/Search/SearchInput.tsx b/src/components/Search/SearchInput.tsx new file mode 100644 index 0000000..993d011 --- /dev/null +++ b/src/components/Search/SearchInput.tsx @@ -0,0 +1,27 @@ +import styled from '@emotion/styled'; +import * as React from 'react'; + +import { Input } from '../Input'; + +interface InputProps extends React.ComponentPropsWithoutRef<'input'> {} + +export const SearchInput = ({ ...props }: InputProps) => { + const inputRef = React.useRef(null); + + React.useEffect(() => { + if (inputRef.current) inputRef.current.focus(); + }, []); + + return ; +}; + +const StyledInput = styled(Input)` + margin: 0.375rem 0.375rem; + padding: 0.375rem 0.375rem; + width: auto; + border-radius: 0.25rem; + font-size: 0.875rem; + line-height: 1.25rem; + outline: 2px solid transparent; + outline-offset: 2px; +`; diff --git a/src/components/Search/SearchInputToggle.tsx b/src/components/Search/SearchInputToggle.tsx new file mode 100644 index 0000000..f209a7c --- /dev/null +++ b/src/components/Search/SearchInputToggle.tsx @@ -0,0 +1,43 @@ +import * as React from 'react'; + +import { PortalContext } from '@/components/Portal/PortalContext'; +import useContext from '@/hooks/useContext'; +import { composeEventHandlers } from '@/libs/event'; +import { composeRefs } from '@/libs/ref'; + +import { Input } from '../..'; + +type ComponentPropsWithoutRef = React.ComponentPropsWithoutRef; + +/** + * SearchInputToggle + * @returns + */ +export const SearchInputToggle = React.forwardRef>( + ({ onClick, onChange, ...props }, ref) => { + const { showModal, setShowModal, setToggleElment } = useContext(PortalContext); + const compRef = React.useRef(null); + + const openModal = () => { + if (showModal) return; + + if (compRef.current) { + const rect = compRef.current; + setToggleElment(rect); + } + + setShowModal(true); + }; + + return ( + + ); + }, +); +SearchInputToggle.displayName = 'SearchInputToggle'; diff --git a/src/components/Search/SearchItem.tsx b/src/components/Search/SearchItem.tsx new file mode 100644 index 0000000..d13636a --- /dev/null +++ b/src/components/Search/SearchItem.tsx @@ -0,0 +1,55 @@ +import { css } from '@emotion/react'; +import styled from '@emotion/styled'; +import * as React from 'react'; + +import { PortalContext } from '@/components/Portal/PortalContext'; +import useContext from '@/hooks/useContext'; +import { composeEventHandlers } from '@/libs/event'; + +interface SearchItemProps extends React.ComponentPropsWithoutRef<'li'> { + disabled?: boolean; +} +export const SearchItem = React.forwardRef(({ disabled = false, ...props }, ref) => { + const { setShowModal } = useContext(PortalContext); + + const onClickHandler = () => { + if (!disabled) setShowModal(false); + }; + + return ( + + ); +}); +SearchItem.displayName = 'SearchItem'; + +const SearchItemStyled = styled.li<{ disabled: boolean }>` + display: flex; + position: relative; + align-items: center; + padding: 0.375rem 0.5rem; + border-radius: 0.25rem; + font-size: 0.875rem; + line-height: 1.25rem; + outline: 2px solid transparent; + outline-offset: 2px; + cursor: default; + ${({ disabled }) => + disabled + ? css` + opacity: 0.5; + ` + : css` + &:hover, + &:focus { + background-color: var(--gray-100); + } + `} +`; diff --git a/src/components/Search/SearchToggle.tsx b/src/components/Search/SearchToggle.tsx new file mode 100644 index 0000000..eeb02d6 --- /dev/null +++ b/src/components/Search/SearchToggle.tsx @@ -0,0 +1,43 @@ +import * as React from 'react'; + +import { PortalContext } from '@/components/Portal/PortalContext'; +import Slot from '@/components/Slot'; +import useContext from '@/hooks/useContext'; +import { composeEventHandlers } from '@/libs/event'; +import { composeRefs } from '@/libs/ref'; + +import { Button } from '../..'; + +type ComponentPropsWithoutRef = React.ComponentPropsWithoutRef & { + asChild?: boolean; +}; + +/** + * SearchToggle + * @returns + */ +export const SearchToggle = React.forwardRef>( + ({ asChild, onClick, ...props }, ref) => { + const { setShowModal, setToggleElment } = useContext(PortalContext); + const compRef = React.useRef(null); + + const Comp = asChild ? Slot : Button; + + return ( + { + if (compRef.current) { + const rect = compRef.current; + setToggleElment(rect); + } + + setShowModal(true); + })} + {...props} + /> + ); + }, +); +SearchToggle.displayName = 'SearchToggle'; diff --git a/src/components/Search/index.tsx b/src/components/Search/index.tsx new file mode 100644 index 0000000..e15448c --- /dev/null +++ b/src/components/Search/index.tsx @@ -0,0 +1,40 @@ +import styled from '@emotion/styled'; + +/* eslint-disable react-refresh/only-export-components */ +export * from './Search'; +export * from './SearchContent'; +export * from './SearchToggle'; +export * from './SearchItem'; +export * from './SearchInput'; +export * from './SearchInputToggle'; + +export const SearchLabel = styled.h3` + font-weight: 600; + font-size: 0.75rem; + line-height: 1rem; + padding: 0.375rem 0.5rem; + margin: 0px; +`; + +export const SearchDivider = styled.div` + height: 1px; + margin: 0.25rem -0.25rem; + background: var(--gray-300); +`; +export const SearchDescription = styled.p` + margin: 0.375rem 0px; + font-weight: 300; +`; + +export const SearchShortcut = styled.span` + font-size: 0.75rem; + letter-spacing: 0.1em; + line-height: 1rem; + margin-left: auto; + opacity: 0.5; +`; + +export const SearchItemList = styled.ul` + margin: 0px; + padding: 0px; +`; diff --git a/src/components/index.ts b/src/components/index.ts index ecbae11..321d94c 100644 --- a/src/components/index.ts +++ b/src/components/index.ts @@ -8,6 +8,7 @@ export * from './HoverCard'; export * from './Input'; export * from './Label'; export * from './Pagination'; +export * from './Search'; export * from './Select'; export * from './Switch'; export * from './Textarea'; diff --git a/src/stories/common/Search.stories.tsx b/src/stories/common/Search.stories.tsx new file mode 100644 index 0000000..57a5bfd --- /dev/null +++ b/src/stories/common/Search.stories.tsx @@ -0,0 +1,224 @@ +import type { Meta, StoryObj } from '@storybook/react'; +import * as React from 'react'; + +import { + Search, + SearchContent, + SearchDivider, + SearchInput, + SearchInputToggle, + SearchItem, + SearchItemList, + SearchLabel, + SearchShortcut, + SearchToggle, +} from '../..'; + +const meta = { + title: 'common/Search', + component: Search, + tags: ['autodocs'], + args: { + align: 'center', + }, + parameters: { + layout: 'centered', + componentSubtitle: 'Base Search', + }, +} satisfies Meta; + +export default meta; + +type Story = StoryObj; + +export const Default: Story = { + args: {}, + decorators: [ + () => { + return ( + + + + + Social + GitHub + Facebook + + User + @bandmators + @bmates + + + + ); + }, + ], +}; + +export const Toggle: Story = { + args: {}, + decorators: [ + () => { + return ( + + + Search Input / + + + + + Social + GitHub + Facebook + + User + @bandmators + @bmates + + + + ); + }, + ], +}; + +export const Space: Story = { + parameters: { + docs: { + description: { + story: 'space is `number` type. ``', + }, + }, + }, + args: { + align: 'start', + space: 16, + children: ( + <> + + Search Input / + + + + + Social + + GitHub + ⌘+T + + Facebook + + User + @bandmators + @bmates + + + + ), + }, +}; + +export const AlignStart: Story = { + parameters: { + docs: { + description: { + story: '``', + }, + }, + }, + args: { + align: 'start', + children: ( + <> + + Search Input / + + + + + Social + + GitHub + ⌘+T + + Facebook + + User + @bandmators + @bmates + + + + ), + }, +}; + +export const AlignCenter: Story = { + parameters: { + docs: { + description: { + story: '``', + }, + }, + }, + args: { + align: 'center', + children: ( + <> + + Search Input / + + + + + Social + + GitHub + ⌘+T + + Facebook + + User + @bandmators + @bmates + + + + ), + }, +}; + +export const AlignEnd: Story = { + parameters: { + docs: { + description: { + story: '``', + }, + }, + }, + args: { + align: 'end', + children: ( + <> + + Search Input / + + + + + Social + + GitHub + ⌘+T + + Facebook + + User + @bandmators + @bmates + + + + ), + }, +}; From 1874c0a8c45d9150fa456ca3bf39f75d4baa0185 Mon Sep 17 00:00:00 2001 From: Ye-Chan Kang Date: Thu, 25 Apr 2024 16:29:18 +0900 Subject: [PATCH 2/5] fix: add to control selecting --- src/components/Select/SelectItem.tsx | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/components/Select/SelectItem.tsx b/src/components/Select/SelectItem.tsx index be5b83a..eca7833 100644 --- a/src/components/Select/SelectItem.tsx +++ b/src/components/Select/SelectItem.tsx @@ -51,6 +51,7 @@ export const SelectItem = React.forwardRef( aria-selected={selected} selected={selected} onClick={composeEventHandlers(props.onClick, onClickHandler)} + data-focus-enabled="true" {...props} > {children} @@ -83,7 +84,8 @@ const SelectItemStyled = styled.li<{ selected: boolean; disabled: boolean }>` opacity: 0.5; ` : css` - &[aria-selected='false']:hover { + &[aria-selected='false']:hover, + &[aria-selected='false']:focus { background-color: var(--gray-100); } `} From a88dcac5c0e89685766af9de936fbc7a45c32a8b Mon Sep 17 00:00:00 2001 From: Ye-Chan Kang Date: Thu, 25 Apr 2024 16:31:04 +0900 Subject: [PATCH 3/5] fix: flexible selection depending on Items --- src/components/Portal/Portal.tsx | 24 ++-- src/components/Portal/PortalContent.tsx | 21 +-- src/components/Search/SearchContent.tsx | 2 +- src/stories/common/Search.stories.tsx | 163 +++++++++--------------- 4 files changed, 86 insertions(+), 124 deletions(-) diff --git a/src/components/Portal/Portal.tsx b/src/components/Portal/Portal.tsx index e6da309..329f72d 100644 --- a/src/components/Portal/Portal.tsx +++ b/src/components/Portal/Portal.tsx @@ -7,13 +7,14 @@ import { composeEventHandlers } from '@/libs/event'; import { composeRefs } from '@/libs/ref'; import { PositionType } from '@/types/position'; -interface ModalContentProps extends React.ComponentProps<'div'> { +export interface PortalProps extends React.ComponentProps<'div'> { ref: React.ForwardedRef; width?: React.CSSProperties['width']; disabledBG?: boolean; + disabledAutoFocus?: boolean; } -const Portal = ({ children, ref, width, onKeyDown, ...props }: ModalContentProps) => { +const Portal = ({ children, ref, width, onKeyDown, disabledAutoFocus, ...props }: PortalProps) => { const portalRef = React.useRef(null); const { showModal, toggleElement, reorgPos } = usePortal({ portalRef }); const [items, setItems] = useState([]); @@ -65,18 +66,21 @@ const Portal = ({ children, ref, width, onKeyDown, ...props }: ModalContentProps const handleOpen = React.useCallback(() => { if (portalRef.current) { - // portalRef.current.focus(); - setItems( - Array.from(portalRef.current.querySelectorAll('[data-focus-enabled="true"]')).filter(e => { - return e.getAttribute('disabled') == null; - }), - ); + if (!disabledAutoFocus) portalRef.current.focus(); + + const newItems = Array.from( + portalRef.current.querySelectorAll('[data-focus-enabled="true"]'), + ).filter(e => { + return e.getAttribute('disabled') == null; + }); + console.log(newItems); + setItems(newItems); } - }, []); + }, [disabledAutoFocus]); React.useEffect(() => { if (showModal && portalRef.current) handleOpen(); - }, [handleOpen, showModal]); + }, [handleOpen, showModal, children]); return ( { - ref: React.ForwardedRef; - width?: React.CSSProperties['width']; - disabledBG?: boolean; -} - -export const PortalContent = ({ children, ref, width, disabledBG = false, onKeyDown, ...props }: ModalContentProps) => { +export const PortalContent = ({ + children, + ref, + width, + disabledBG = false, + disabledAutoFocus = false, + onKeyDown, + ...props +}: PortalProps) => { const { showModal, setShowModal } = useContext(PortalContext)!; const close = () => { @@ -26,7 +27,7 @@ export const PortalContent = ({ children, ref, width, disabledBG = false, onKeyD createPortal( <> {!disabledBG && } - + {children} , diff --git a/src/components/Search/SearchContent.tsx b/src/components/Search/SearchContent.tsx index 38a5e28..4abb889 100644 --- a/src/components/Search/SearchContent.tsx +++ b/src/components/Search/SearchContent.tsx @@ -12,7 +12,7 @@ interface ModalProps extends React.ComponentPropsWithoutRef<'div'> { */ export const SearchContent = React.forwardRef(({ width, children, ...props }, ref) => { return ( - + {children} ); diff --git a/src/stories/common/Search.stories.tsx b/src/stories/common/Search.stories.tsx index 57a5bfd..f86f464 100644 --- a/src/stories/common/Search.stories.tsx +++ b/src/stories/common/Search.stories.tsx @@ -31,6 +31,24 @@ export default meta; type Story = StoryObj; +const animals = [ + 'dog', + 'cat', + 'elephant', + 'lion', + 'tiger', + 'bear', + 'giraffe', + 'zebra', + 'monkey', + 'snake', + 'rabbit', + 'horse', + 'deer', + 'fox', + 'wolf', +]; + export const Default: Story = { args: {}, decorators: [ @@ -55,27 +73,50 @@ export const Default: Story = { ], }; +const TempSearch = () => { + const [text, setText] = React.useState(''); + + return ( + <> + + Search Input / + + + { + setText(e.target.value); + }} + /> + + Social + + GitHub + ⌘+T + + Facebook + + User + @bandmators + @bmates + {animals + .filter(animal => animal.includes(text)) + .slice(0, 5) + .map(item => ( + {item} + ))} + + + + ); +}; + export const Toggle: Story = { args: {}, decorators: [ () => { return ( - - Search Input / - - - - - Social - GitHub - Facebook - - User - @bandmators - @bmates - - + ); }, @@ -93,28 +134,7 @@ export const Space: Story = { args: { align: 'start', space: 16, - children: ( - <> - - Search Input / - - - - - Social - - GitHub - ⌘+T - - Facebook - - User - @bandmators - @bmates - - - - ), + children: , }, }; @@ -128,28 +148,7 @@ export const AlignStart: Story = { }, args: { align: 'start', - children: ( - <> - - Search Input / - - - - - Social - - GitHub - ⌘+T - - Facebook - - User - @bandmators - @bmates - - - - ), + children: , }, }; @@ -163,28 +162,7 @@ export const AlignCenter: Story = { }, args: { align: 'center', - children: ( - <> - - Search Input / - - - - - Social - - GitHub - ⌘+T - - Facebook - - User - @bandmators - @bmates - - - - ), + children: , }, }; @@ -198,27 +176,6 @@ export const AlignEnd: Story = { }, args: { align: 'end', - children: ( - <> - - Search Input / - - - - - Social - - GitHub - ⌘+T - - Facebook - - User - @bandmators - @bmates - - - - ), + children: , }, }; From cf9911b18d5a905b87d8cd40a32675b7b16a34a2 Mon Sep 17 00:00:00 2001 From: Ye-Chan Kang Date: Fri, 26 Apr 2024 23:54:55 +0900 Subject: [PATCH 4/5] feat: handling keydown with SearchInputToggle (#23) --- src/components/Portal/Portal.tsx | 11 +++----- src/components/Portal/PortalContent.tsx | 9 ++++++- src/components/Search/SearchInputToggle.tsx | 29 ++++++++++++++++++++- src/stories/common/Search.stories.tsx | 16 +++++++++--- 4 files changed, 53 insertions(+), 12 deletions(-) diff --git a/src/components/Portal/Portal.tsx b/src/components/Portal/Portal.tsx index 329f72d..805dce2 100644 --- a/src/components/Portal/Portal.tsx +++ b/src/components/Portal/Portal.tsx @@ -27,13 +27,11 @@ const Portal = ({ children, ref, width, onKeyDown, disabledAutoFocus, ...props } }; const handleOnKeyDown = (e: React.KeyboardEvent) => { - if (Object.keys(ACTIONS).includes(e.key)) { - const handler = ACTIONS[e.key]; + const handler = ACTIONS[e.key]; - if (handler) { - e.preventDefault(); - handler(e); - } + if (handler) { + e.preventDefault(); + handler(e); } }; @@ -73,7 +71,6 @@ const Portal = ({ children, ref, width, onKeyDown, disabledAutoFocus, ...props } ).filter(e => { return e.getAttribute('disabled') == null; }); - console.log(newItems); setItems(newItems); } }, [disabledAutoFocus]); diff --git a/src/components/Portal/PortalContent.tsx b/src/components/Portal/PortalContent.tsx index 206985c..99421b7 100644 --- a/src/components/Portal/PortalContent.tsx +++ b/src/components/Portal/PortalContent.tsx @@ -27,7 +27,14 @@ export const PortalContent = ({ createPortal( <> {!disabledBG && } - + {children} , diff --git a/src/components/Search/SearchInputToggle.tsx b/src/components/Search/SearchInputToggle.tsx index f209a7c..f7c161b 100644 --- a/src/components/Search/SearchInputToggle.tsx +++ b/src/components/Search/SearchInputToggle.tsx @@ -14,7 +14,7 @@ type ComponentPropsWithoutRef = React.ComponentProp * @returns */ export const SearchInputToggle = React.forwardRef>( - ({ onClick, onChange, ...props }, ref) => { + ({ onClick, onChange, onKeyDown, ...props }, ref) => { const { showModal, setShowModal, setToggleElment } = useContext(PortalContext); const compRef = React.useRef(null); @@ -29,12 +29,39 @@ export const SearchInputToggle = React.forwardRef { + setShowModal(false); + }; + + const ACTIONS: Record) => void> = { + ArrowDown: () => focus('next'), + ArrowUp: () => focus('prev'), + Tab: () => closeModal(), + Enter: () => focus('next'), + Escape: () => closeModal(), + }; + + const handleOnKeyDown = (e: React.KeyboardEvent) => { + const handler = ACTIONS[e.key]; + + if (handler) { + // e.preventDefault(); + handler(e); + } + }; + + const focus = (key: 'next' | 'prev'): void => { + const el = document.querySelector('#bmates-portal [data-focus-enabled="true"]') as HTMLElement; + if (key === 'next' && el) el.focus(); + }; + return ( ); diff --git a/src/stories/common/Search.stories.tsx b/src/stories/common/Search.stories.tsx index f86f464..06a5199 100644 --- a/src/stories/common/Search.stories.tsx +++ b/src/stories/common/Search.stories.tsx @@ -53,9 +53,15 @@ export const Default: Story = { args: {}, decorators: [ () => { + const [text, setText] = React.useState(''); return ( - + { + setText(e.target.value); + }} + /> Social @@ -63,8 +69,12 @@ export const Default: Story = { Facebook User - @bandmators - @bmates + {animals + .filter(animal => animal.includes(text)) + .slice(0, 5) + .map(item => ( + {item} + ))} From 1944924a59830bc60e06f6beb507127df42ce30c Mon Sep 17 00:00:00 2001 From: Ye-Chan Kang Date: Wed, 15 May 2024 22:36:36 +0900 Subject: [PATCH 5/5] feat(common): search input toggle key event (#24) --- src/components/Portal/Portal.tsx | 3 ++- src/components/Search/SearchInputToggle.tsx | 8 ++++---- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/src/components/Portal/Portal.tsx b/src/components/Portal/Portal.tsx index 805dce2..99b8b2e 100644 --- a/src/components/Portal/Portal.tsx +++ b/src/components/Portal/Portal.tsx @@ -16,7 +16,7 @@ export interface PortalProps extends React.ComponentProps<'div'> { const Portal = ({ children, ref, width, onKeyDown, disabledAutoFocus, ...props }: PortalProps) => { const portalRef = React.useRef(null); - const { showModal, toggleElement, reorgPos } = usePortal({ portalRef }); + const { showModal, setShowModal, toggleElement, reorgPos } = usePortal({ portalRef }); const [items, setItems] = useState([]); const ACTIONS: Record) => void> = { @@ -24,6 +24,7 @@ const Portal = ({ children, ref, width, onKeyDown, disabledAutoFocus, ...props } ArrowUp: () => focus('prev'), Tab: () => focus('next'), Enter: () => select(), + Escape: () => setShowModal(false), }; const handleOnKeyDown = (e: React.KeyboardEvent) => { diff --git a/src/components/Search/SearchInputToggle.tsx b/src/components/Search/SearchInputToggle.tsx index f7c161b..19d1af8 100644 --- a/src/components/Search/SearchInputToggle.tsx +++ b/src/components/Search/SearchInputToggle.tsx @@ -1,12 +1,11 @@ import * as React from 'react'; +import { Input } from '@/components/Input'; import { PortalContext } from '@/components/Portal/PortalContext'; import useContext from '@/hooks/useContext'; import { composeEventHandlers } from '@/libs/event'; import { composeRefs } from '@/libs/ref'; -import { Input } from '../..'; - type ComponentPropsWithoutRef = React.ComponentPropsWithoutRef; /** @@ -29,9 +28,9 @@ export const SearchInputToggle = React.forwardRef { + const closeModal = React.useCallback(() => { setShowModal(false); - }; + }, []); const ACTIONS: Record) => void> = { ArrowDown: () => focus('next'), @@ -42,6 +41,7 @@ export const SearchInputToggle = React.forwardRef) => { + console.log(e); const handler = ACTIONS[e.key]; if (handler) {