Skip to content

Commit

Permalink
Fix(inputitem): add wai-aria suppport for the money type InputItem (#…
Browse files Browse the repository at this point in the history
…2538)

* Fix(inputitem): add wai-aria suppport for the money type InputItem

The money type InputItem is simulated with the div tag, rather than the origin
input tag. To support wai-aria needs a little more work, for the div tag, by adding
role of `textbox` make div perform like input in aria mode

For the CustomKeyboard, it will lead to wrong focus when not adding aria
supoort for backspace and keyboard canceling

Fixed: #2419, #2418

* Fix(inputitem): remove extra useless custom keyboard instance

In the money type of InputItem, the CustomKeyboard will create as many times as the InputItem is
used.The inner variable `customNumberKeyboard` will point to the latest custom keyboard instance
which can avoid the repeat appearing animation. But when the InputItem is render async, since the
`customNumberKeyboard` points to the latest custom keyboard instance, the operation for previous
custom keyboard instance such as add hidden class  will be invalid

To Solve this problem, remove the useless instances of custom keyboard
everytime one InputItem is being blured

Fixed: #2475
  • Loading branch information
KgTong authored and warmhug committed May 18, 2018
1 parent 42f07a9 commit 5a8ae68
Show file tree
Hide file tree
Showing 11 changed files with 94 additions and 25 deletions.
73 changes: 56 additions & 17 deletions components/input-item/CustomInput.tsx
Expand Up @@ -6,8 +6,10 @@ import CustomKeyboard from './CustomKeyboard';
import Portal from './Portal';
import { InputEventHandler } from './PropsType';

const IS_REACT_16 = !!ReactDOM.createPortal;
let instanceArr: any = [];
let customNumberKeyboard: CustomKeyboard | null = null;
const IS_REACT_16 = !!ReactDOM.createPortal;

export interface NumberInputProps {
placeholder?: string;
disabled?: boolean;
Expand All @@ -20,6 +22,8 @@ export interface NumberInputProps {
onFocus?: InputEventHandler;
onBlur?: InputEventHandler;
confirmLabel: any;
backspaceLabel: any;
cancelKeyboardLabel: any;
maxLength?: number;
type?: string;
style?: React.CSSProperties;
Expand Down Expand Up @@ -61,7 +65,7 @@ class NumberInput extends React.Component<NumberInputProps, any> {
}
}

componentDidMount() {
componentDidUpdate() {
this.renderCustomKeyboard();
}

Expand All @@ -82,38 +86,58 @@ class NumberInput extends React.Component<NumberInputProps, any> {
}

saveRef = (el: CustomKeyboard | null) => {
if (IS_REACT_16) {
if (IS_REACT_16 && el) {
customNumberKeyboard = el;
instanceArr.push({ el, container: this.container });
}
}

getComponent() {
const { keyboardPrefixCls, confirmLabel } = this.props;
const {
confirmLabel,
backspaceLabel,
cancelKeyboardLabel,
keyboardPrefixCls,
} = this.props;

return (
<CustomKeyboard
ref={this.saveRef}
onClick={this.onKeyboardClick}
preixCls={keyboardPrefixCls}
prefixCls={keyboardPrefixCls}
confirmLabel={confirmLabel}
backspaceLabel={backspaceLabel}
cancelKeyboardLabel={cancelKeyboardLabel}
/>
);
}

getContainer() {
let container = document.querySelector(
`#${this.props.keyboardPrefixCls}-container`,
);
if (!container) {
container = document.createElement('div');
container.setAttribute('id', `${this.props.keyboardPrefixCls}-container`);
document.body.appendChild(container);
const { keyboardPrefixCls } = this.props;

if (IS_REACT_16) {
if (!this.container) {
const container = document.createElement('div');
container.setAttribute('id', `${keyboardPrefixCls}-container-${(new Date().getTime())}`);
document.body.appendChild(container);
this.container = container;
}
} else {
let container = document.querySelector(
`#${keyboardPrefixCls}-container`,
);
if (!container) {
container = document.createElement('div');
container.setAttribute('id', `${keyboardPrefixCls}-container`);
document.body.appendChild(container);
}
this.container = container;
}
this.container = container;
return container;
return this.container;
}

renderCustomKeyboard() {
if (IS_REACT_16 || customNumberKeyboard) {
if (IS_REACT_16) {
return;
}
customNumberKeyboard = ReactDOM.unstable_renderSubtreeIntoContainer(
Expand All @@ -130,6 +154,16 @@ class NumberInput extends React.Component<NumberInputProps, any> {
}
}

removeCurrentExtraKeyboard = () => {
instanceArr = instanceArr.filter((item: any) => {
const { el, container } = item;
if (el && container && el !== customNumberKeyboard) {
(container as any).parentNode.removeChild(container);
}
return el === customNumberKeyboard;
});
}

unLinkInput = () => {
if (
customNumberKeyboard &&
Expand All @@ -145,6 +179,10 @@ class NumberInput extends React.Component<NumberInputProps, any> {
}
// for unmount
this.removeBlurListener();

if (IS_REACT_16) {
this.removeCurrentExtraKeyboard();
}
}

onInputBlur = (value: string) => {
Expand Down Expand Up @@ -267,12 +305,11 @@ class NumberInput extends React.Component<NumberInputProps, any> {
return null;
}

const portal = (
return (
<Portal getContainer={() => this.getContainer()}>
{this.getComponent()}
</Portal>
);
return portal;
}

render() {
Expand All @@ -294,6 +331,8 @@ class NumberInput extends React.Component<NumberInputProps, any> {
<div className="fake-input-placeholder">{placeholder}</div>
)}
<div
role="textbox"
aria-label={value || placeholder}
className={fakeInputCls}
ref={el => (this.inputRef = el)}
onClick={preventKeyboard ? () => {} : this.onFakeInputClick}
Expand Down
11 changes: 10 additions & 1 deletion components/input-item/CustomKeyboard.tsx
Expand Up @@ -96,7 +96,12 @@ class CustomKeyboard extends React.Component<any, any> {
);
}
render() {
const { prefixCls, confirmLabel } = this.props;
const {
prefixCls,
confirmLabel,
backspaceLabel,
cancelKeyboardLabel,
} = this.props;

const wrapperCls = classnames(
`${prefixCls}-wrapper`,
Expand All @@ -113,6 +118,8 @@ class CustomKeyboard extends React.Component<any, any> {
this.renderKeyboardItem(item, index),
)}
<KeyboardItem
role="button"
aria-label={backspaceLabel}
className="keyboard-delete"
rowSpan={2}
onClick={this.onKeyboardClick}
Expand Down Expand Up @@ -144,6 +151,8 @@ class CustomKeyboard extends React.Component<any, any> {
this.renderKeyboardItem(item, index),
)}
<KeyboardItem
role="button"
aria-label={cancelKeyboardLabel}
className="keyboard-hide"
onClick={this.onKeyboardClick}
/>
Expand Down
4 changes: 0 additions & 4 deletions components/input-item/Portal.tsx
Expand Up @@ -13,10 +13,6 @@ export default class Portal extends React.Component<PortalProps, any> {
this.container = this.props.getContainer();
}

shouldComponentUpdate() {
return false;
}

render() {
if (this.props.children) {
return createPortal(this.props.children, this.container);
Expand Down
Expand Up @@ -610,7 +610,9 @@ exports[`renders ./components/input-item/demo/money.md correctly 1`] = `
class="fake-input-container fake-input-container-left"
>
<div
aria-label="100"
class="fake-input"
role="textbox"
>
100
</div>
Expand Down Expand Up @@ -644,7 +646,9 @@ exports[`renders ./components/input-item/demo/money.md correctly 1`] = `
start from right
</div>
<div
aria-label="start from right"
class="fake-input"
role="textbox"
/>
</div>
</div>
Expand Down Expand Up @@ -673,7 +677,9 @@ exports[`renders ./components/input-item/demo/money.md correctly 1`] = `
money format
</div>
<div
aria-label="money format"
class="fake-input"
role="textbox"
/>
</div>
</div>
Expand Down
13 changes: 11 additions & 2 deletions components/input-item/index.tsx
Expand Up @@ -224,9 +224,16 @@ class InputItem extends React.Component<InputItemProps, any> {
() => require('./locale/zh_CN'),
);

const { confirmLabel } = _locale;
const {
confirmLabel,
backspaceLabel,
cancelKeyboardLabel,
} = _locale;

const { placeholder, focus } = this.state;
const {
focus,
placeholder,
} = this.state;

const wrapCls = classnames(
`${prefixListCls}-item`,
Expand Down Expand Up @@ -297,6 +304,8 @@ class InputItem extends React.Component<InputItemProps, any> {
prefixCls={prefixCls}
style={style}
confirmLabel={confirmLabel}
backspaceLabel={backspaceLabel}
cancelKeyboardLabel={cancelKeyboardLabel}
moneyKeyboardAlign={moneyKeyboardAlign}
/>
) : (
Expand Down
2 changes: 2 additions & 0 deletions components/input-item/locale/en_US.tsx
@@ -1,3 +1,5 @@
export default {
confirmLabel: 'Done',
backspaceLabel: 'Backspace',
cancelKeyboardLabel: 'CancelKeyboard',
};
2 changes: 2 additions & 0 deletions components/input-item/locale/ru_RU.tsx
@@ -1,3 +1,5 @@
export default {
confirmLabel: 'Ок',
backspaceLabel: 'возврат на одну позицию',
cancelKeyboardLabel: 'Отменить клавиатуру',
};
2 changes: 2 additions & 0 deletions components/input-item/locale/sv_SE.tsx
@@ -1,3 +1,5 @@
export default {
confirmLabel: 'Ok',
backspaceLabel: 'Backspace',
cancelKeyboardLabel: 'CancelKeyboard',
};
2 changes: 2 additions & 0 deletions components/input-item/locale/zh_CN.tsx
@@ -1,3 +1,5 @@
export default {
confirmLabel: '确定',
backspaceLabel: '退格',
cancelKeyboardLabel: '撤销键盘',
};
Expand Up @@ -174,7 +174,9 @@ exports[`renders ./components/locale-provider/demo/basic.md correctly 1`] = `
money input
</div>
<div
aria-label="money input"
class="fake-input"
role="textbox"
/>
</div>
</div>
Expand Down
2 changes: 1 addition & 1 deletion components/modal/style/Dialog.less
Expand Up @@ -34,7 +34,7 @@
display: flex;
align-items: center;
justify-content: center;
// fixed a layer issue with animated Tabs in the x5 kernel browser
// fixed a layer issue with animated Tabs in the x5 kernel browser
transform: translateZ(1px);
&-popup {
display: block;
Expand Down

0 comments on commit 5a8ae68

Please sign in to comment.