Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
67 changes: 23 additions & 44 deletions src/packages/input/input.taro.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import {
} from '@tarojs/components'
import { MaskClose } from '@nutui/icons-react-taro'
import Taro, { ENV_TYPE, getEnv } from '@tarojs/taro'
import { BaseEventOrig } from '@tarojs/components/types/common'
import { formatNumber } from './utils'
import { useConfig, useRtl } from '@/packages/configprovider/index.taro'
import { BasicComponent, ComponentDefaults } from '@/utils/typings'
Expand All @@ -39,7 +40,7 @@ export interface InputProps extends BasicComponent {
autoFocus: boolean
confirmType: InputConfirmType
plain: boolean
formatter?: (value: string) => void
formatter?: (value: string) => string
onChange?: (value: string) => void
onBlur?: (value: string) => void
onFocus?: (value: string, height?: number) => void
Expand Down Expand Up @@ -153,23 +154,14 @@ export const Input = forwardRef(
trigger: InputFormatTrigger = 'onChange'
) => {
let val = value
if (type === 'number') {
val = formatNumber(val, false, true)
}
if (type === 'digit') {
val = formatNumber(val, true, true)
}
if (formatter && trigger === formatTrigger) {
val = formatter(val)
}
if (type === 'number') val = formatNumber(val, false, true)
if (type === 'digit') val = formatNumber(val, true, true)
if (formatter && trigger === formatTrigger) val = formatter(val)

setValue(val)
const eventHandler = props[trigger]
if (
eventHandler &&
typeof eventHandler === 'function' &&
trigger !== 'onChange'
) {
eventHandler(val)
if (trigger !== 'onChange') {
const eventHandler = props[trigger]
eventHandler?.(val)
}
forceUpdate()
}
Expand All @@ -185,31 +177,31 @@ export const Input = forwardRef(
setActive(true)
}

const handleInput = (value: string) => {
updateValue(value, 'onChange')
const handleInput = (event: BaseEventOrig) => {
updateValue((event.detail || event.currentTarget).value, 'onChange')
}

const handleBlur = (event: any) => {
const val = Taro.getEnv() === 'WEB' ? (event.target as any).value : value
updateValue(val, 'onBlur')
setTimeout(() => {
setActive(false)
}, 200)
setTimeout(() => setActive(false), 200)
}
const inputType = (type: any) => {
if (getEnv() === ENV_TYPE.WEB) {
if (type === 'digit') {
return 'text'
}
if (type === 'number') {
return 'tel'
}
if (type === 'digit') return 'text'
if (type === 'number') return 'tel'
} else if (type === 'password') {
return 'text'
}
return type
}

const getTextAlign = () => {
if (rtl) {
if (align === 'right') return 'left'
if (align === 'left') return 'right'
}
return align
}
return (
<View
className={`${inputClass()} ${className || ''}`}
Expand All @@ -223,18 +215,7 @@ export const Input = forwardRef(
name={name}
className="nut-input-native"
ref={inputRef}
style={{
// eslint-disable-next-line no-nested-ternary
textAlign: rtl
? // eslint-disable-next-line no-nested-ternary
align === 'right'
? // eslint-disable-next-line no-nested-ternary
'left'
: align === 'left'
? 'right'
: 'center'
: align,
}}
style={getTextAlign()}
type={inputType(type) as any}
password={type === 'password'}
maxlength={maxLength}
Expand All @@ -247,9 +228,7 @@ export const Input = forwardRef(
confirmType={confirmType}
onBlur={handleBlur}
onFocus={handleFocus}
onInput={(e: any) => {
handleInput((e.detail || e.currentTarget).value)
}}
onInput={handleInput}
/>
<View
style={{
Expand Down
168 changes: 68 additions & 100 deletions src/packages/input/input.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import React, {
useCallback,
useRef,
HTMLInputTypeAttribute,
forwardRef,
HTMLInputTypeAttribute,
MouseEvent,
useCallback,
useImperativeHandle,
useRef,
useState,
MouseEvent,
} from 'react'
import { MaskClose } from '@nutui/icons-react'
import { formatNumber } from './utils'
Expand Down Expand Up @@ -34,15 +34,15 @@
autoFocus: boolean
confirmType: InputConfirmType
plain: boolean
formatter?: (value: string) => void
formatter?: (value: string) => string
onChange?: (value: string) => void
onBlur?: (value: string) => void
onFocus?: (value: string) => void
onClear?: (value: string) => void
onClick?: (value: MouseEvent<HTMLDivElement>) => void
onClick?: (event: MouseEvent<HTMLDivElement>) => void
}

const defaultProps = {
const defaultProps: InputProps = {
...ComponentDefaults,
type: 'text',
name: '',
Expand Down Expand Up @@ -71,6 +71,7 @@
) => {
const rtl = useRtl()
const { locale } = useConfig()

const {
type,
name,
Expand All @@ -97,129 +98,102 @@
onCompositionStart,
onCompositionEnd,
...rest
} = {
...defaultProps,
...props,
}
} = { ...defaultProps, ...props }

const [value, setValue] = usePropsValue<string>({
value: _value,
defaultValue,
finalValue: '',
onChange,
})

const inputRef = useRef<HTMLInputElement>(null)
const composingRef = useRef(false)
const [active, setActive] = useState(false)

useImperativeHandle(ref, () => {
return {
clear: () => {
setValue('')
},
focus: () => {
inputRef.current?.focus()
},
blur: () => {
inputRef.current?.blur()
},
get nativeElement() {
return inputRef.current
},
}
})
useImperativeHandle(ref, () => ({
clear: () => setValue(''),
focus: () => inputRef.current?.focus(),
blur: () => inputRef.current?.blur(),
get nativeElement() {
return inputRef.current
},

Check warning on line 120 in src/packages/input/input.tsx

View check run for this annotation

Codecov / codecov/patch

src/packages/input/input.tsx#L119-L120

Added lines #L119 - L120 were not covered by tests
}))

const inputClass = useCallback(() => {
const getInputClass = useCallback(() => {
const classPrefix = 'nut-input'
return [
classPrefix,
disabled ? `${classPrefix}-disabled` : '',
`${disabled ? `${classPrefix}-disabled` : ''}`,
readOnly ? `${classPrefix}-readonly` : '',
plain ? `${classPrefix}-plain` : `${classPrefix}-container`,
`${plain ? `${classPrefix}-plain` : `${classPrefix}-container`}`,
]
.filter(Boolean)
.join(' ')
}, [disabled])
}, [disabled, readOnly, plain])

const updateValue = (
value: any,
trigger: InputFormatTrigger = 'onChange'
const handleValueUpdate = (
inputValue: string,
trigger: InputFormatTrigger
) => {
let val = value
let updatedValue = inputValue

if (type === 'number') {
val = formatNumber(val, false, true)
}
if (type === 'digit') {
val = formatNumber(val, true, true)
}
if (formatter && trigger === formatTrigger) {
val = formatter(val)
}
setValue(val)
const eventHandler = props[trigger]
if (
eventHandler &&
typeof eventHandler === 'function' &&
trigger !== 'onChange'
) {
eventHandler(val)
if (type === 'number')
updatedValue = formatNumber(updatedValue, false, true)
if (type === 'digit')
updatedValue = formatNumber(updatedValue, true, true)
if (formatter && trigger === formatTrigger)
updatedValue = formatter(updatedValue)

setValue(updatedValue)

if (trigger !== 'onChange') {
const eventHandler = props[trigger]
eventHandler?.(updatedValue)
}
}

const handleFocus = (event: Event) => {
const val: any = (event.target as any).value
onFocus && onFocus(val)
const handleFocus = (event: React.FocusEvent<HTMLInputElement>) => {
onFocus?.(event.target.value)
setActive(true)
}

const handleInput = (value: string) => {
updateValue(value, 'onChange')
const handleBlur = (event: React.FocusEvent<HTMLInputElement>) => {
handleValueUpdate(event.target.value, 'onBlur')
setTimeout(() => setActive(false), 200)
}

const handleBlur = (event: Event) => {
const val: any = (event.target as any).value
updateValue(val, 'onBlur')
setTimeout(() => {
setActive(false)
}, 200)
const handleInputChange = (event: React.ChangeEvent<HTMLInputElement>) => {
handleValueUpdate(event.target.value, 'onChange')
}

const inputType = (type: string) => {
if (type === 'digit') {
return 'text'
}
if (type === 'number') {
return 'tel'
const getInputType = (inputType: InputType) => {
if (inputType === 'digit') return 'text'
if (inputType === 'number') return 'tel'
return inputType
}

const getTextAlign = () => {
if (rtl) {
if (align === 'right') return 'left'
if (align === 'left') return 'right'
}
return type
return align
}

return (
<div
className={`${inputClass()} ${className || ''}`}
className={`${getInputClass()} ${className || ''}`}
style={style}
onClick={(e) => {
onClick && onClick(e)
}}
onClick={onClick}
>
<input
{...rest}
ref={inputRef}
name={name}
className="nut-input-native"
ref={inputRef}
style={{
// eslint-disable-next-line no-nested-ternary
textAlign: rtl
? // eslint-disable-next-line no-nested-ternary
align === 'right'
? // eslint-disable-next-line no-nested-ternary
'left'
: align === 'left'
? 'right'
: 'center'
: align,
}}
type={inputType(type)}
style={{ textAlign: getTextAlign() }}
type={getInputType(type)}
maxLength={maxLength}
placeholder={
placeholder === undefined ? locale.placeholder : placeholder
Expand All @@ -229,15 +203,9 @@
value={value}
autoFocus={autoFocus}
enterKeyHint={confirmType}
onBlur={(e: any) => {
handleBlur(e)
}}
onFocus={(e: any) => {
handleFocus(e)
}}
onChange={(e: any) => {
handleInput(e.currentTarget.value)
}}
onFocus={handleFocus}
onBlur={handleBlur}
onChange={handleInputChange}
onCompositionStart={(e) => {
composingRef.current = true
onCompositionStart?.(e)
Expand All @@ -247,19 +215,19 @@
onCompositionEnd?.(e)
}}
/>
{clearable && !readOnly && active && value.length > 0 ? (
{clearable && !readOnly && active && value.length > 0 && (
<span
style={{ display: 'flex', alignItems: 'center', cursor: 'pointer' }}
onClick={() => {
if (!disabled) {
setValue('')
onClear && onClear('')
onClear?.('')

Check warning on line 224 in src/packages/input/input.tsx

View check run for this annotation

Codecov / codecov/patch

src/packages/input/input.tsx#L224

Added line #L224 was not covered by tests
}
}}
>
{clearIcon || <MaskClose className="nut-input-clear" />}
</span>
) : null}
)}
</div>
)
}
Expand Down
Loading