Skip to content

Commit

Permalink
[form-builder] Make inputs focusable and manage form builder focus (#393
Browse files Browse the repository at this point in the history
)
  • Loading branch information
bjoerge committed Jan 9, 2018
1 parent 22128da commit 8588a39
Show file tree
Hide file tree
Showing 59 changed files with 1,369 additions and 710 deletions.
31 changes: 18 additions & 13 deletions packages/@sanity/components/src/fieldsets/DefaultFieldset.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,8 @@ import defaultStyles from 'part:@sanity/components/fieldsets/default-style'
import PropTypes from 'prop-types'
import React from 'react'
import ArrowDropDown from 'part:@sanity/base/arrow-drop-down'
import Styleable from '../utilities/Styleable'

class Fieldset extends React.Component {
export default class Fieldset extends React.Component {
static propTypes = {
description: PropTypes.string,
legend: PropTypes.string.isRequired,
Expand Down Expand Up @@ -42,16 +41,24 @@ class Fieldset extends React.Component {
}

render() {
const {fieldset, legend, description, columns, level, className, children, collapsable, transparent, styles, ...rest} = this.props
const {fieldset, legend, description, columns, level, className, children, collapsable, transparent, ...rest} = this.props
const {isOpen} = this.state
const levelString = `level${level}`
const rootClass = `
${styles.root}
${styles[`columns${columns}`] || ''}
${styles[levelString] || ''}
${transparent ? styles.transparent : ''}
${className || ''}
`

const styles = {
...defaultStyles,
...this.props.styles
}

const rootClass = [
styles.root,
styles[`columns${columns}`],
styles[`level${level}`],
transparent && styles.transparent,
className
]
.filter(Boolean)
.join(' ')

return (
<fieldset {...rest} className={rootClass} data-nesting-level={level}>
<div className={styles.inner}>
Expand Down Expand Up @@ -82,5 +89,3 @@ class Fieldset extends React.Component {
)
}
}

export default Styleable(Fieldset, defaultStyles)
12 changes: 11 additions & 1 deletion packages/@sanity/components/src/selects/DefaultSelect.js
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,16 @@ export default class DefaultSelect extends React.Component {
this.props.onChange(this.props.items[event.target.value])
}

focus() {
if (this._input) {
this._input.focus()
}
}

setInput = el => {
this._input = el
}

render() {
const {hasError, items, value, disabled, hasFocus, ...rest} = this.props
return (
Expand All @@ -50,6 +60,7 @@ export default class DefaultSelect extends React.Component {
disabled={disabled}
value={value && items.indexOf(value)}
autoComplete="off"
ref={this.setInput}
>
{!value && <option />}
{
Expand All @@ -60,7 +71,6 @@ export default class DefaultSelect extends React.Component {
})
}
</select>
<div className={styles.focusHelper} />
<div className={styles.icon}>
<FaAngleDown color="inherit" />
</div>
Expand Down
9 changes: 9 additions & 0 deletions packages/@sanity/components/src/selects/SearchableSelect.js
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,14 @@ export default class SearchableSelect extends React.Component {
}
}

setInput = input => {
this._input = input
}

focus() {
this._input.focus()
}

handleFocus = event => {
this.setState({
hasFocus: true
Expand Down Expand Up @@ -153,6 +161,7 @@ export default class SearchableSelect extends React.Component {
onInputChange={this.handleInputChange}
width={width}
isSelected={hasFocus}
ref={this.setInput}
/>
</div>
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,14 @@ export default class StatelessSearchableSelect extends React.PureComponent {
this._rootNode = node
}

setInput = input => {
this._input = input
}

focus() {
this._input.focus()
}

render() {
const {
onClear,
Expand Down Expand Up @@ -145,6 +153,7 @@ export default class StatelessSearchableSelect extends React.PureComponent {
value={inputValue || ''}
selected={isInputSelected}
disabled={disabled}
ref={this.setInput}
/>
{
onClear && inputValue && (
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1 @@
import TextInput from './TextInput'
import styles from 'part:@sanity/components/textinputs/default-style'
import Styleable from '../utilities/Styleable'

export default Styleable(TextInput, styles)
export {default} from './TextInput'
57 changes: 17 additions & 40 deletions packages/@sanity/components/src/textinputs/TextInput.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,43 +2,28 @@ import PropTypes from 'prop-types'
import React from 'react'
import CloseIcon from 'part:@sanity/base/close-icon'
import classNames from 'classnames'
import defaultStyles from 'part:@sanity/components/textinputs/default-style'

const NOOP = () => {}

const VALID_TYPES = [
'color',
'date',
'email',
'month',
'password',
'search',
'tel',
'text',
'number',
'url',
'week',
]

export default class DefaultTextInput extends React.PureComponent {
static propTypes = {
value: PropTypes.oneOfType([
PropTypes.string,
PropTypes.number
]),
type: PropTypes.oneOf(VALID_TYPES),
type: PropTypes.string,
onClear: PropTypes.func,
onFocus: PropTypes.func,
onBlur: PropTypes.func,
isClearable: PropTypes.bool,
isSelected: PropTypes.bool,
disabled: PropTypes.bool,
autoComplete: PropTypes.string,
hasError: PropTypes.bool,
styles: PropTypes.shape({
container: PropTypes.string,
input: PropTypes.string,
isClearable: PropTypes.string,
focusHelper: PropTypes.string,
clearButton: PropTypes.string,
inputOnDisabled: PropTypes.string,
inputOnError: PropTypes.string,
Expand All @@ -49,7 +34,6 @@ export default class DefaultTextInput extends React.PureComponent {
static defaultProps = {
value: '',
type: 'text',
isSelected: false,
hasError: false,
isClearable: false,
disabled: false,
Expand All @@ -60,43 +44,37 @@ export default class DefaultTextInput extends React.PureComponent {
styles: {}
}

componentDidMount() {
const {isSelected} = this.props
this.setSelected(isSelected)
// this.setState({hasFocus: this._input === document.activeElement})
}

componentWillReceiveProps(nextProps) {
if (nextProps.isSelected !== this.props.isSelected) {
this.setSelected(nextProps.isSelected)
select() {
if (this._input) {
this._input.select()
}
}

select = () => {
this._input.select()
focus() {
if (this._input) {
this._input.focus()
}
}

setInputElement = element => {
setInput = element => {
this._input = element
}

setSelected(isSelected) {
if (isSelected) {
this._input.select()
}
}

render() {
const {
onClear,
hasError,
isClearable,
disabled,
isSelected,
styles,
styles: passedStyles,
...rest
} = this.props

const styles = {
...defaultStyles,
...passedStyles
}

return (
<div
className={classNames(styles.container, [
Expand All @@ -106,12 +84,11 @@ export default class DefaultTextInput extends React.PureComponent {
])}
>
<input
ref={this.setInputElement}
ref={this.setInput}
{...rest}
className={classNames(styles.input, [hasError && styles.inputOnError])}
disabled={disabled}
/>
<div className={styles.focusHelper} />
{isClearable && (
<button className={styles.clearButton} onClick={onClear}>
<CloseIcon color="inherit" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,15 +26,6 @@
padding-right: 2em;
}

.focusHelper {
composes: focusHelper from 'part:@sanity/base/theme/forms/text-input-style';
background-color: transparent;

@nest .hasFocus & {
background-color: var(--brand-primary);
}
}

.clearButton {
z-index: 1;
top: 0.35em;
Expand Down
48 changes: 21 additions & 27 deletions packages/@sanity/components/src/toggles/Checkbox.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,47 +4,41 @@ import styles from 'part:@sanity/components/toggles/checkbox-style'

export default class Checkbox extends React.Component {
static propTypes = {
value: PropTypes.bool,
label: PropTypes.string,
onChange: PropTypes.func,
onFocus: PropTypes.func,
onBlur: PropTypes.func,
checked: PropTypes.bool,
disabled: PropTypes.bool,
hasFocus: PropTypes.bool,
children: PropTypes.node
}

static defaultProps = {
onChange() {},
onFocus() {},
onBlur() {}
children: PropTypes.any,
onFocus: PropTypes.func,
onBlur: PropTypes.func,
}

state = {
hasFocus: false
}

handleMouseUp = () => {
this.setState({hasFocus: false})
handleFocus = event => {
this.setState({hasFocus: true})
this.props.onFocus(event)
}

handleFocus = () => {
this.setState({hasFocus: true})
handleBlur = event => {
this.setState({hasFocus: false})
this.props.onBlur(event)
}

handleChange = event => {
this.props.onChange(event, this.props.value)
focus() {
if (this._input) {
this._input.focus()
}
}

handleBlur = () => {
window.setTimeout(() => {
this.props.onBlur(this.props.value)
}, 0.001)
setInput = el => {
this._input = el
}

render() {
const {disabled, hasFocus, value, checked, label, children} = this.props
const {disabled, checked, label, children, ...rest} = this.props
const {hasFocus} = this.state

return (
<label
Expand All @@ -55,16 +49,16 @@ export default class Checkbox extends React.Component {
${checked ? styles.isChecked : styles.unChecked}
${hasFocus ? styles.hasFocus : ''}
`}
onMouseUp={this.handleMouseUp}
onBlur={this.handleBlur}
>
<input
{...rest}
className={styles.input}
type="checkbox"
value={String(value)}
onChange={this.handleChange}
disabled={disabled}
checked={checked}
ref={this.setInput}
onFocus={this.handleFocus}
onBlur={this.handleBlur}
/>
<div className={styles.label}>
{children || label}
Expand Down
Loading

0 comments on commit 8588a39

Please sign in to comment.