Skip to content

Commit c55c5a3

Browse files
authored
feat: 数字键盘 customKey 支持单独定制 title,用于无障碍读屏 (#6956)
* feat: 数字键盘 customKey 支持单独定制 title,用于无障碍读屏 * fix: cr * feat: 简化对 key 配置的消费逻辑 * docs: update english docs * fix: cr * feat: 补充 aria-label
1 parent 489d444 commit c55c5a3

File tree

6 files changed

+56
-17
lines changed

6 files changed

+56
-17
lines changed

src/components/number-keyboard/index.en.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,12 +23,12 @@ tips: It is recommended to open the demo on the mobile side for better preview e
2323
### Props
2424

2525
| Name | Description | Type | Default |
26-
| --- | --- | --- | --- |
26+
| --- | --- | --- | --- | --- | --- | --- |
2727
| afterClose | Callback when the keyboard is completely put away | `() => void` | - |
2828
| afterShow | Callback when the keyboard is completely bounced | `() => void` | - |
2929
| closeOnConfirm | Whether to automatically close when the ok button is clicked | `boolean` | `true` |
3030
| confirmText | The text of the confirm button, if `null` is set, it would be shown | `string \| null` | `null` |
31-
| customKey | Customized button | `string \| [string, string]` | - |
31+
| customKey | Customized button | `string | { key: string; title: string } | (string | { key: string; title: string })[]` | - |
3232
| destroyOnClose | Destroy `dom` when not visible | `boolean` | `false` |
3333
| forceRender | Render content forcely | `boolean` | `false` |
3434
| getContainer | To get the specified mounted HTML node, the default is `body`, if `null` returned, it would be rendered to the current node | `HTMLElement \| () => HTMLElement \| null` | `() => document.body` |

src/components/number-keyboard/index.zh.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,12 +23,12 @@ tips: 仅移动端下删除按钮支持长按快删(通过 touchStart/touchEnd
2323
### 属性
2424

2525
| 属性 | 说明 | 类型 | 默认值 |
26-
| --- | --- | --- | --- |
26+
| --- | --- | --- | --- | --- | --- | --- |
2727
| afterClose | 键盘完全收起回调 | `() => void` | - |
2828
| afterShow | 键盘完全弹出回调 | `() => void` | - |
2929
| closeOnConfirm | 是否在点击确定按钮时自动关闭 | `boolean` | `true` |
3030
| confirmText | 完成按钮文案,`null` 不展示 | `string \| null` | `null` |
31-
| customKey | 自定义按钮 | `string \| [string, string]` | - |
31+
| customKey | 自定义按钮 | `string | { key: string; title: string } | (string | { key: string; title: string })[]` | - |
3232
| destroyOnClose | 不可见时是否销毁 `DOM` 结构 | `boolean` | `false` |
3333
| forceRender | 强制渲染内容 | `boolean` | `false` |
3434
| getContainer | 指定挂载的 HTML 节点,默认为 `body`,如果为 `null` 的话,会渲染到当前节点 | `HTMLElement \| () => HTMLElement \| null` | `() => document.body` |

src/components/number-keyboard/number-keyboard.tsx

Lines changed: 16 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -12,11 +12,13 @@ import SafeArea from '../safe-area'
1212

1313
const classPrefix = 'adm-number-keyboard'
1414

15+
type CustomKeyType = string | { key: string; title: string }
16+
1517
export type NumberKeyboardProps = {
1618
visible?: boolean
1719
title?: string
1820
confirmText?: string | null
19-
customKey?: string | [string, string]
21+
customKey?: CustomKeyType | CustomKeyType[]
2022
randomOrder?: boolean
2123
showCloseButton?: boolean
2224
onInput?: (v: string) => void
@@ -161,27 +163,31 @@ export const NumberKeyboard: FC<NumberKeyboardProps> = p => {
161163
onKeyPress(e, 'BACKSPACE')
162164
}
163165

164-
const renderKey = (key: string, index: number) => {
165-
const isNumberKey = /^\d$/.test(key)
166-
const isBackspace = key === 'BACKSPACE'
166+
const renderKey = (key: CustomKeyType, index: number) => {
167+
const keyConfig = typeof key === 'string' ? { key, title: key } : key
168+
const realKey = keyConfig.key
169+
const isNumberKey = /^\d$/.test(realKey)
170+
const isBackspace = realKey === 'BACKSPACE'
171+
const title = isBackspace ? locale.Input.clear : keyConfig.title
167172
const className = classNames(`${classPrefix}-key`, {
168173
[`${classPrefix}-key-number`]: isNumberKey,
169-
[`${classPrefix}-key-sign`]: !isNumberKey && key,
174+
[`${classPrefix}-key-sign`]: !isNumberKey && realKey,
170175
[`${classPrefix}-key-mid`]:
171176
index === 9 && !!confirmText && keys.length < 12,
172177
})
173178

174-
const ariaProps = key
179+
const ariaProps = realKey
175180
? {
176181
role: 'button',
177-
title: isBackspace ? locale.Input.clear : key,
182+
title,
183+
'aria-label': title,
178184
tabIndex: -1,
179185
}
180186
: undefined
181187

182188
return (
183189
<div
184-
key={key}
190+
key={realKey}
185191
className={className}
186192
// 仅为 backspace 绑定,支持长按快速删除
187193
onTouchStart={isBackspace ? onBackspaceTouchStart : undefined}
@@ -193,11 +199,11 @@ export const NumberKeyboard: FC<NumberKeyboardProps> = p => {
193199
// backspace touchend 时会 preventDefault 阻止其后续 click 事件
194200
onClick={(e: MouseEvent<HTMLDivElement>) => {
195201
stopContinueClear()
196-
onKeyPress(e, key)
202+
onKeyPress(e, realKey)
197203
}}
198204
{...ariaProps}
199205
>
200-
{isBackspace ? <TextDeletionOutline /> : key}
206+
{isBackspace ? <TextDeletionOutline /> : realKey}
201207
</div>
202208
)
203209
}

src/components/number-keyboard/tests/number-keyboard.test.tsx

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -161,6 +161,28 @@ describe('NumberKeyboard', () => {
161161
expect(onInput).toBeCalledWith('.')
162162
})
163163

164+
test('render with customKey and title', () => {
165+
const onInput = jest.fn()
166+
render(
167+
<NumberKeyboard
168+
customKey={['-', { key: '.', title: '小数点' }]}
169+
visible
170+
onInput={onInput}
171+
/>
172+
)
173+
const left = screen.getByText('-')
174+
const right = screen.getByText('.')
175+
expect(left).toBeInTheDocument()
176+
expect(right).toBeInTheDocument()
177+
expect(left.title).toBe('-')
178+
expect(right.title).toBe('小数点')
179+
180+
mockClick(left)
181+
expect(onInput).toBeCalledWith('-')
182+
mockClick(right)
183+
expect(onInput).toBeCalledWith('.')
184+
})
185+
164186
test('render with multiple customKeys and confirmText', () => {
165187
render(
166188
<NumberKeyboard customKey={['-', '.']} visible confirmText='confirm' />

src/components/virtual-input/demos/demo1.tsx

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,12 @@ export default () => {
1313
<VirtualInput
1414
placeholder='请输入内容'
1515
cursor={{ movable: true }}
16-
keyboard={<NumberKeyboard confirmText='确定' customKey='.' />}
16+
keyboard={
17+
<NumberKeyboard
18+
confirmText='确定'
19+
customKey={{ key: '.', title: '小数点' }}
20+
/>
21+
}
1722
/>
1823
</DemoBlock>
1924

@@ -57,7 +62,7 @@ export default () => {
5762
/>
5863
</DemoBlock>
5964

60-
<DemoBlock title='只支持金额数字输入,配合 NumberKeyboard 使用'>
65+
<DemoBlock title='只支持两位小数的金额输入,配合 NumberKeyboard 使用'>
6166
<VirtualInput
6267
value={value || '0'}
6368
cursor={{ movable: true }}
@@ -71,7 +76,12 @@ export default () => {
7176
}
7277
}}
7378
placeholder='请输入内容'
74-
keyboard={<NumberKeyboard confirmText='确定' customKey='.' />}
79+
keyboard={
80+
<NumberKeyboard
81+
confirmText='确定'
82+
customKey={{ key: '.', title: '小数点' }}
83+
/>
84+
}
7585
style={{
7686
'--font-size': '40px',
7787
}}

src/components/virtual-input/index.en.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ When you need to use it with the virtual keyboard.
2323
| onFocus | Triggered when element get focus | `() => void` | - |
2424
| placeholder | The placeholder text | `string` | - |
2525
| value | The input value | `string` | `''` |
26+
| cursor | Cursor related configuration, `movable` indicates whether it can be adjusted, `onMove` is the cursor movement callback | `{ movable?: boolean; onMove?: (position: number) => void }` | `{ movable: false }` |
2627

2728
Strictly speaking, VirtualInput is not a form field component. It just displays the data.
2829

0 commit comments

Comments
 (0)