) => {
+ if (disabled) return
+ onIconClick && onIconClick(e)
+ }
+ const iconProps = useMemo(() => ({
+ ratio: heightRatio,
+ clickable: iconClickable,
+ onClick: iconClickHandler,
+ }), [heightRatio, iconClickable])
+
useEffect(() => {
if (value === undefined) return
setSelfValue(value)
}, [value])
-
+
return (
{children &&
{children}}
@@ -225,10 +205,11 @@ const Input: React.FC
> = ({
`}
)
-}
+})
-type InputComponent = React.FC
& {
+type InputComponent
= React.ForwardRefExoticComponent
& {
Textarea: typeof Textarea
+ Password: typeof InputPassword
}
type ComponentProps = Partial & Omit & NativeAttrs
diff --git a/components/input/password-icon.tsx b/components/input/password-icon.tsx
new file mode 100644
index 0000000..4ec8c3e
--- /dev/null
+++ b/components/input/password-icon.tsx
@@ -0,0 +1,27 @@
+import React from 'react'
+
+interface Props {
+ visible: boolean
+}
+
+const PasswordIcon: React.FC = ({ visible }) => {
+ return (
+
+ )
+}
+
+export default PasswordIcon
diff --git a/components/input/password.tsx b/components/input/password.tsx
new file mode 100644
index 0000000..e6ff7d5
--- /dev/null
+++ b/components/input/password.tsx
@@ -0,0 +1,51 @@
+import React, { useImperativeHandle, useMemo, useRef, useState } from 'react'
+import withDefaults from '../utils/with-defaults'
+import { Props, defaultProps } from './input-props'
+import PasswordIcon from './password-icon'
+import Input from './input'
+
+interface PasswordProps extends Props {
+ hideToggle?: boolean
+}
+
+const passwordDefaultProps = {
+ ...defaultProps,
+ hideToggle: false,
+}
+
+type NativeAttrs = Omit, keyof PasswordProps>
+export type InputPasswordProps = PasswordProps & typeof passwordDefaultProps & NativeAttrs
+
+const InputPassword = React.forwardRef>(({
+ hideToggle, children, ...props
+}, ref: React.Ref) => {
+ const inputRef = useRef(null)
+ const [visible, setVisible] = useState(false)
+ useImperativeHandle(ref, () => inputRef.current)
+
+ const iconClickHandler = () => {
+ setVisible(v => !v)
+ /* istanbul ignore next */
+ if (inputRef && inputRef.current) {
+ inputRef.current.focus()
+ }
+ }
+
+ const inputProps = useMemo(() => ({
+ ...props,
+ ref: inputRef,
+ iconClickable: true,
+ onIconClick: iconClickHandler,
+ type: visible ? 'text' : 'password',
+ }), [props, iconClickHandler, visible, inputRef])
+ const icon = useMemo(() => {
+ if (hideToggle) return null
+ return
+ }, [hideToggle, visible])
+
+ return (
+ {children}
+ )
+})
+
+export default withDefaults(InputPassword, passwordDefaultProps)
diff --git a/pages/en-us/components/input.mdx b/pages/en-us/components/input.mdx
index 7fbee60..9cd494b 100644
--- a/pages/en-us/components/input.mdx
+++ b/pages/en-us/components/input.mdx
@@ -118,10 +118,17 @@ Retrieve text input from a user.
scope={{ Input }}
code={`
<>
-
+
>
`} />
+
+`} />
+
void` | - | - |
| **onChange** | change event | `(e: React.ChangeEvent) => void` | - | - |
| **onClearClick** | clear icon event | `(e: React.MouseEvent) => void` | - | - |
| ... | native props | `InputHTMLAttributes` | `'alt', 'type', 'className', ...` | - |
+Input.Password.Props
+
+| Attribute | Description | Type | Accepted values | Default
+| ---------- | ---------- | ---- | -------------- | ------ |
+| **hideToggle** | hide toggle icon | `boolean` | - | `false` |
+| ... | input props | `Input.Props` | [Input.Props](#input.props) | - |
+
+InputSizes
+
+```ts
+type InputSizes = 'mini'
+ | 'small'
+ | 'medium'
+ | 'large'
+```
+
+InputStatus
+
+```ts
+type InputStatus = 'default'
+ | 'secondary'
+ | 'success'
+ | 'warning'
+ | 'error'
+```
+
useInput
```ts
diff --git a/pages/zh-cn/components/input.mdx b/pages/zh-cn/components/input.mdx
index 6a23487..88c2b16 100644
--- a/pages/zh-cn/components/input.mdx
+++ b/pages/zh-cn/components/input.mdx
@@ -112,13 +112,21 @@ export const meta = {
>
`} />
+
+`} />
+
-
+
>
`} />
@@ -169,8 +177,8 @@ export const meta = {
| **value** | 命令式设定输入框的值 | `string` | - | - |
| **initialValue** | 初始值 | `string` | - | - |
| **placeholder** | 占位文本 | `string` | - | - |
-| **size** | 输入框大小 | `NormalSizes` | `'mini', 'small', 'medium', 'large'` | `medium` |
-| **status** | 输入框状态 | `NormalTypes` | `'default', 'secondary', 'success', 'warning', 'error'` | `default` |
+| **size** | 输入框大小 | `NormalSizes` | [InputSizes](#inputsizes) | `medium` |
+| **status** | 输入框状态 | `NormalTypes` | [InputStatus](#inputstatus) | `default` |
| **readOnly** | 是否设置输入框为只读 | `boolean` | - | `false` |
| **disabled** | 是否禁用输入框 | `boolean` | - | `false` |
| **clearable** | 是否展示清除按钮 | `boolean` | - | `false` |
@@ -178,10 +186,38 @@ export const meta = {
| **icon** | 输入框图标 | `React.ReactNode` | - | - |
| **labelRight** | 居于右侧的文本标签 | `string` | - | - |
| **iconRight** | 居于右侧的图标 | `React.ReactNode` | - | - |
+| **iconClickable** | 图标是否可点击 | `boolean` | - | `false` |
+| **onIconClick** | 图标点击事件 | `(e: React.ChangeEvent) => void` | - | - |
| **onChange** | 输入框变化事件 | `(e: React.ChangeEvent) => void` | - | - |
| **onClearClick** | 清除按钮的点击事件 | `(e: React.MouseEvent) => void` | - | - |
| ... | 原生属性 | `InputHTMLAttributes` | `'alt', 'type', 'className', ...` | - |
+Input.Password.Props
+
+| 属性 | 描述 | 类型 | 推荐值 | 默认
+| ---------- | ---------- | ---- | -------------- | ------ |
+| **hideToggle** | 隐藏切换密码的按钮 | `boolean` | - | `false` |
+| ... | 输入框组件属性 | `Input.Props` | [Input.Props](#input.props) | - |
+
+InputSizes
+
+```ts
+type InputSizes = 'mini'
+ | 'small'
+ | 'medium'
+ | 'large'
+```
+
+InputStatus
+
+```ts
+type InputStatus = 'default'
+ | 'secondary'
+ | 'success'
+ | 'warning'
+ | 'error'
+```
+
useInput
```ts