Skip to content

Commit

Permalink
feat(TextArea): add enterkeyhint and onEnterPress (#6598)
Browse files Browse the repository at this point in the history
* feat(TextArea): add `enterkeyhint` and `onEnterPress`

* chore: test case for `teatarea`

* feat: `useInputHandleKeyDown` hook

* fix: export `useInputHandleKeyDown` in `Input`

* chore: move `useInputHandleKeyDown`

* chore: adjust code

---------

Co-authored-by: 二货机器人 <[email protected]>
  • Loading branch information
susiwen8 and zombieJ authored Apr 16, 2024
1 parent 5730b89 commit 8bd3d17
Show file tree
Hide file tree
Showing 4 changed files with 87 additions and 24 deletions.
32 changes: 8 additions & 24 deletions src/components/input/input.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,10 @@ import { CloseCircleFill } from 'antd-mobile-icons'
import { NativeProps, withNativeProps } from '../../utils/native-props'
import { mergeProps } from '../../utils/with-default-props'
import classNames from 'classnames'
import { useIsomorphicLayoutEffect } from 'ahooks'
import { bound } from '../../utils/bound'
import { isIOS } from '../../utils/validate'
import { useConfig } from '../config-provider'
import useInputHandleKeyDown from './useInputHandleKeyDown'

const classPrefix = `adm-input`

Expand Down Expand Up @@ -45,6 +45,7 @@ export type InputProps = Pick<
| 'placeholder'
| 'readOnly'
| 'disabled'
| 'enterKeyHint'
> & {
value?: string
defaultValue?: string
Expand All @@ -53,14 +54,6 @@ export type InputProps = Pick<
onlyShowClearWhenFocus?: boolean
onClear?: () => void
onEnterPress?: (e: React.KeyboardEvent<HTMLInputElement>) => void
enterKeyHint?:
| 'enter'
| 'done'
| 'go'
| 'next'
| 'previous'
| 'search'
| 'send'
min?: number
max?: number
} & NativeProps<
Expand All @@ -87,6 +80,12 @@ export const Input = forwardRef<InputRef, InputProps>((p, ref) => {
const compositionStartRef = useRef(false)
const nativeInputRef = useRef<HTMLInputElement>(null)
const { locale } = useConfig()
const handleKeydown = useInputHandleKeyDown({
onEnterPress: props.onEnterPress,
onKeyDown: props.onKeyDown,
nativeInputRef,
enterKeyHint: props.enterKeyHint,
})

useImperativeHandle(ref, () => ({
clear: () => {
Expand All @@ -103,21 +102,6 @@ export const Input = forwardRef<InputRef, InputProps>((p, ref) => {
},
}))

const handleKeydown = (e: React.KeyboardEvent<HTMLInputElement>) => {
if (props.onEnterPress && (e.code === 'Enter' || e.keyCode === 13)) {
props.onEnterPress(e)
}
props.onKeyDown?.(e)
}

useIsomorphicLayoutEffect(() => {
if (!props.enterKeyHint) return
nativeInputRef.current?.setAttribute('enterkeyhint', props.enterKeyHint)
return () => {
nativeInputRef.current?.removeAttribute('enterkeyhint')
}
}, [props.enterKeyHint])

function checkValue() {
let nextValue = value
if (props.type === 'number') {
Expand Down
37 changes: 37 additions & 0 deletions src/components/input/useInputHandleKeyDown.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import { useIsomorphicLayoutEffect } from 'ahooks'

interface InputHandleKeyDownType<T> {
onEnterPress?: (e: React.KeyboardEvent<T>) => void
onKeyDown?: (e: React.KeyboardEvent<T>) => void
enterKeyHint?: React.InputHTMLAttributes<HTMLInputElement>['enterKeyHint']
nativeInputRef: React.RefObject<T>
}

export default function useInputHandleKeyDown<
T extends HTMLInputElement | HTMLTextAreaElement,
>({
onEnterPress,
onKeyDown,
nativeInputRef,
enterKeyHint,
}: InputHandleKeyDownType<T>) {
const handleKeydown = (e: React.KeyboardEvent<T>) => {
if (onEnterPress && (e.code === 'Enter' || e.keyCode === 13)) {
onEnterPress(e)
}
onKeyDown?.(e)
}

useIsomorphicLayoutEffect(() => {
const ele = nativeInputRef.current

if (!enterKeyHint || !ele) return

ele.setAttribute('enterkeyhint', enterKeyHint)
return () => {
ele.removeAttribute('enterkeyhint')
}
}, [enterKeyHint])

return handleKeydown
}
23 changes: 23 additions & 0 deletions src/components/text-area/tests/text-area.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -142,4 +142,27 @@ describe('TextArea', () => {
const textarea = getByRole('textbox')
expect(textarea).toHaveAttribute('rows', '1')
})

test('should works with `onEnterPress`', async () => {
const onEnterPress = jest.fn()
const { getByRole } = render(
<TextArea defaultValue={'testValue'} onEnterPress={onEnterPress} />
)
const textarea = getByRole('textbox') as HTMLTextAreaElement
expect(textarea).toBeInTheDocument()
act(() => {
textarea.focus()
})
fireEvent.keyDown(textarea, { code: 'Enter' })
expect(onEnterPress).toBeCalledTimes(1)
fireEvent.keyUp(textarea, { code: 'Enter' })

fireEvent.keyDown(textarea, { keyCode: 13 })
expect(onEnterPress).toBeCalledTimes(2)
fireEvent.keyUp(textarea, { keyCode: 13 })

fireEvent.keyDown(textarea, { keyCode: 14 })
expect(onEnterPress).toBeCalledTimes(2)
fireEvent.keyUp(textarea, { keyCode: 14 })
})
})
19 changes: 19 additions & 0 deletions src/components/text-area/text-area.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { NativeProps, withNativeProps } from '../../utils/native-props'
import { usePropsValue } from '../../utils/use-props-value'
import { mergeProps } from '../../utils/with-default-props'
import { devError } from '../../utils/dev-log'
import useInputHandleKeyDown from '../../components/input/useInputHandleKeyDown'

const classPrefix = 'adm-text-area'

Expand All @@ -24,6 +25,7 @@ export type TextAreaProps = Pick<
| 'onCompositionStart'
| 'onCompositionEnd'
| 'onClick'
| 'onKeyDown'
> & {
onChange?: (val: string) => void
value?: string
Expand All @@ -39,6 +41,15 @@ export type TextAreaProps = Pick<
maxRows?: number
}
id?: string
onEnterPress?: (e: React.KeyboardEvent<HTMLTextAreaElement>) => void
enterKeyHint?:
| 'enter'
| 'done'
| 'go'
| 'next'
| 'previous'
| 'search'
| 'send'
} & NativeProps<
| '--font-size'
| '--color'
Expand Down Expand Up @@ -82,6 +93,13 @@ export const TextArea = forwardRef<TextAreaRef, TextAreaProps>(
// https://github.com/ant-design/ant-design-mobile/issues/6051
const hiddenTextAreaRef = useRef<HTMLTextAreaElement>(null)

const handleKeydown = useInputHandleKeyDown({
onEnterPress: props.onEnterPress,
onKeyDown: props.onKeyDown,
nativeInputRef: nativeTextAreaRef,
enterKeyHint: props.enterKeyHint,
})

useImperativeHandle(ref, () => ({
clear: () => {
setValue('')
Expand Down Expand Up @@ -182,6 +200,7 @@ export const TextArea = forwardRef<TextAreaRef, TextAreaProps>(
onFocus={props.onFocus}
onBlur={props.onBlur}
onClick={props.onClick}
onKeyDown={handleKeydown}
/>
{count}

Expand Down

0 comments on commit 8bd3d17

Please sign in to comment.