Skip to content

Commit

Permalink
feat: add draft inputbox component
Browse files Browse the repository at this point in the history
  • Loading branch information
mumiao committed Nov 30, 2020
1 parent 629e343 commit 6fd365e
Show file tree
Hide file tree
Showing 3 changed files with 275 additions and 0 deletions.
160 changes: 160 additions & 0 deletions src/components/inputBox/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,160 @@
import './style.scss';
import * as React from 'react';
import { prefixClaName, classNames } from 'mo/common/className';

interface IInputBox {
readonly autoSelect?: boolean;
readonly autoFocus?: boolean;
readonly children?: React.ReactNode;
readonly style?: React.CSSProperties;
readonly bsStyle?: 'success' | 'warning' | 'error';
readonly flexibleHeight?: boolean;
readonly id?: string;
readonly placeholder?: string;
readonly type?: string;
readonly value?: string;
readonly onChange?: (value: string | number) => void;
readonly onBlur?: (e: Event) => void;
readonly onKeyPress?: (
keyCode: number,
keyChar: number | string,
key: number
) => void;
readonly onFocus?: (e: Event) => void;
}

export default class InputBox extends React.Component<IInputBox> {
private autoSelected: boolean;
private id: string | undefined;

constructor(props: IInputBox) {
super(props);
this.autoSelected = false;
this.id = this.props.id;
}

componentWillUnmount() {
this.autoSelected = false;
}

getStyleClass() {
let bsStyle = this.props.bsStyle;

return classNames(
bsStyle === 'success' ? 'has-success' : '',
bsStyle === 'warning' ? 'has-warning' : '',
bsStyle === 'error' ? 'has-error' : ''
);
}

renderFlexibleHeight() {
const { flexibleHeight } = this.props;
if (flexibleHeight) {
return (
<textarea
ref={this.onRef.bind(this)}
onKeyPress={this.onKeyPress.bind(this)}
onBlur={this.onBlur.bind(this)}
onFocus={this.onFocus.bind(this)}
onChange={this.onChange.bind(this)}
placeholder={this.props.placeholder}
className={classNames('input')}
autoCorrect="off"
autoCapitalize="off"
spellCheck="false"
>
{this.props.value}
</textarea>
);
} else {
return (
<input
ref={this.onRef.bind(this)}
onKeyPress={this.onKeyPress.bind(this)}
onBlur={this.onBlur.bind(this)}
onFocus={this.onFocus.bind(this)}
onChange={this.onChange.bind(this)}
value={this.props.value}
placeholder={this.props.placeholder}
wrap="off"
className={classNames('input')}
type={this.props.type}
autoCorrect="off"
autoCapitalize="off"
spellCheck="false"
/>
);
}
}

/**
* onRef gets the ref of the input/textarea element after rendering or componentUnMount
*/
onRef(ref) {
if (ref && this.props.autoFocus) {
ref.focus();
}
// only autoselect once
if (
ref &&
this.props.autoSelect &&
ref.setSelectionRange &&
this.autoSelected === false
) {
ref.setSelectionRange(0, this.getValueFromElement(ref).length);
this.autoSelected = true;
}
}

/**
* Returns the value from the element or empty string.
*/
getValueFromElement(element) {
let value = '';
// get value
if (element.type === 'text') {
value = element.value;
} else if (element.type === 'textarea') {
value = element.innerText;
}

return value;
}

onChange(e) {
e.preventDefault();
let value;
value = this.getValueFromElement(e.target);
if (this.props.onChange) {
this.props.onChange(value);
}
}

onKeyPress(e) {
this.props.onKeyPress?.(e.keyCode, e.keyChar, e.key);
}

onBlur(e) {
this.props.onBlur?.(e);
}

onFocus(e) {
e.preventDefault();

if (this.props.onFocus) {
this.props.onFocus(e);
}
}

render() {
const { style } = this.props;
return (
<div
className={classNames(prefixClaName('inputbox'), 'idle')}
style={style}
>
<div className="wrapper">{this.renderFlexibleHeight()}</div>
</div>
);
}
}
86 changes: 86 additions & 0 deletions src/components/inputBox/style.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
@import 'mo/style/common';
$InputBox: 'inputbox';

#{prefix($InputBox)} {
background-color: rgb(60, 60, 60);
box-sizing: border-box;
color: rgb(204, 204, 204);
display: block;
/* Customizable */
font-size: inherit;
overflow: hidden;
padding: 0;
position: relative;

.idle {
border: 1px solid transparent;
}

>.wrapper>.input,
>.wrapper>.mirror {
padding: 4px;
}

>.wrapper {
height: 100%;
position: relative;
width: 100%;

>.input {
background-color: inherit;
border: 1px solid transparent;
box-sizing: border-box;
color: inherit;
color: rgb(204, 204, 204);
display: inline-block;
font-family: inherit;
font-size: inherit;
height: 100%;
line-height: inherit;
padding-right: 66px;
resize: none;
width: 100%;

&:focus {
outline-color: #007fd4;
}
}
}

>input {
text-overflow: ellipsis;
}

>textarea.input {
background-color: inherit;
color: rgb(204, 204, 204);
display: block;
-ms-overflow-style: none;
padding-right: 66px;

&:focus {
outline-color: #007fd4;
}
}

>textarea.input::-webkit-scrollbar {
display: none;
/* Chrome + Safari: hide scrollbar */
}

>textarea.input.empty {
white-space: nowrap;
}

>.mirror {
box-sizing: border-box;
display: inline-block;
left: 0;
position: absolute;
top: 0;
visibility: hidden;
white-space: pre-wrap;
width: 100%;
word-wrap: break-word;
}
}
29 changes: 29 additions & 0 deletions stories/components/15-InputBox.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import * as React from 'react';
import InpuxBox from 'mo/components/inputBox';
import { storiesOf } from '@storybook/react';
import { withKnobs } from '@storybook/addon-knobs';
const stories = storiesOf('InpuxBox', module);
stories.addDecorator(withKnobs);

stories.add('Basic Usage', () => {
const styled: React.CSSProperties = {
background: '#1e1e1e',
height: 100,
padding: 10,
};
return (
<>
<h2>简述</h2>
<p>Inputbox</p>
<h3>使用示例 1 - 基本使用</h3>
<div style={styled}>
<InpuxBox placeholder="Search" />
<InpuxBox
placeholder="replace"
flexibleHeight={true}
style={{ marginTop: 10 }}
/>
</div>
</>
);
});

0 comments on commit 6fd365e

Please sign in to comment.