Comparing version 0.20.0-beta1 to 0.20.0-beta2
{ | ||
"name": "gestalt", | ||
"version": "0.20.0-beta1", | ||
"version": "0.20.0-beta2", | ||
"license": "SEE LICENSE IN LICENSE", | ||
@@ -5,0 +5,0 @@ "homepage": "https://pinterest.github.io/gestalt", |
// @flow | ||
/* eslint-disable react/no-unused-prop-types */ | ||
import React, { PropTypes } from 'react'; | ||
import React, { Component, PropTypes } from 'react'; | ||
import classnames from 'classnames'; | ||
@@ -19,55 +19,70 @@ import styles from './Button.css'; | ||
type GestaltContext = { | ||
inputDevice: '' | 'key' | 'mouse' | 'touch' | ||
gestalt: { | ||
inputDevice: '' | 'key' | 'mouse' | 'touch', | ||
subscribe: () => void, | ||
} | ||
} | ||
export default function Button(props: Props, context: GestaltContext) { | ||
const { | ||
accessibilityExpanded, | ||
accessibilityHaspopup, | ||
color = 'gray', | ||
disabled = false, | ||
inline = false, | ||
onClick, | ||
text, | ||
type = 'button', | ||
} = props; | ||
export default class Button extends Component { | ||
const { inputDevice = 'key' } = context; | ||
static propTypes = { | ||
accessibilityExpanded: PropTypes.bool, | ||
accessibilityHaspopup: PropTypes.bool, | ||
color: PropTypes.oneOf(['blue', 'gray', 'red']), | ||
disabled: PropTypes.bool, | ||
inline: PropTypes.bool, | ||
onClick: PropTypes.func, | ||
text: PropTypes.string.isRequired, | ||
type: PropTypes.oneOf(['button', 'submit']), | ||
}; | ||
const classes = classnames(styles.button, { | ||
[styles.disableFocusOutline]: inputDevice !== 'key', | ||
[styles.disabled]: disabled, | ||
[styles.enabled]: !disabled, | ||
[styles[color]]: !disabled, | ||
[styles.inline]: inline, | ||
[styles.block]: !inline, | ||
}); | ||
static contextTypes = { | ||
gestalt: React.PropTypes.func | ||
}; | ||
return ( | ||
<button | ||
aria-expanded={accessibilityExpanded} | ||
aria-haspopup={accessibilityHaspopup} | ||
className={classes} | ||
disabled={disabled} | ||
onClick={onClick} | ||
type={type} | ||
> | ||
{text} | ||
</button> | ||
); | ||
} | ||
componentDidMount() { | ||
if (this.context.gestalt) { | ||
this.context.gestalt.subscribe(() => this.forceUpdate()); | ||
} | ||
} | ||
Button.contextTypes = { | ||
inputDevice: React.PropTypes.string | ||
}; | ||
context: GestaltContext; | ||
props: Props; | ||
Button.propTypes = { | ||
accessibilityExpanded: PropTypes.bool, | ||
accessibilityHaspopup: PropTypes.bool, | ||
color: PropTypes.oneOf(['blue', 'gray', 'red']), | ||
disabled: PropTypes.bool, | ||
inline: PropTypes.bool, | ||
onClick: PropTypes.func, | ||
text: PropTypes.string.isRequired, | ||
type: PropTypes.oneOf(['button', 'submit']), | ||
}; | ||
render() { | ||
const { | ||
accessibilityExpanded, | ||
accessibilityHaspopup, | ||
color = 'gray', | ||
disabled = false, | ||
inline = false, | ||
onClick, | ||
text, | ||
type = 'button', | ||
} = this.props; | ||
const disableFocusOutline = this.context && this.context.gestalt && this.context.gestalt.inputDevice !== 'key'; | ||
const classes = classnames(styles.button, { | ||
[styles.disableFocusOutline]: disableFocusOutline, | ||
[styles.disabled]: disabled, | ||
[styles.enabled]: !disabled, | ||
[styles[color]]: !disabled, | ||
[styles.inline]: inline, | ||
[styles.block]: !inline, | ||
}); | ||
return ( | ||
<button | ||
aria-expanded={accessibilityExpanded} | ||
aria-haspopup={accessibilityHaspopup} | ||
className={classes} | ||
disabled={disabled} | ||
onClick={onClick} | ||
type={type} | ||
> | ||
{text} | ||
</button> | ||
); | ||
} | ||
} |
@@ -9,2 +9,9 @@ // @flow | ||
type GestaltContext = { | ||
gestalt: { | ||
inputDevice: '' | 'key' | 'mouse' | 'touch', | ||
subscribe: () => void, | ||
} | ||
} | ||
export default class Card extends Component { | ||
@@ -17,8 +24,6 @@ static PropTypes = { | ||
static contextTypes = { | ||
inputDevice: React.PropTypes.string | ||
} | ||
gestalt: React.PropTypes.func | ||
}; | ||
static context: { | ||
inputDevice: '' | 'key' | 'mouse' | 'touch' | ||
} | ||
static context: GestaltContext | ||
@@ -35,2 +40,8 @@ static props: {| | ||
componentDidMount() { | ||
if (this.context.gestalt) { | ||
this.context.gestalt.subscribe(() => this.forceUpdate()); | ||
} | ||
} | ||
hoverTimer: number; | ||
@@ -64,3 +75,3 @@ | ||
const { inputDevice = 'key' } = this.context; | ||
const disableFocusOutline = this.context && this.context.gestalt && this.context.gestalt.inputDevice !== 'key'; | ||
@@ -75,3 +86,3 @@ const classes = classnames(styles.card, { | ||
aria-label={accessibilityLabel} | ||
disableFocusStyles={inputDevice !== 'key'} | ||
disableFocusStyles={disableFocusOutline} | ||
onBlur={this.handleBlur} | ||
@@ -78,0 +89,0 @@ onFocus={this.handleFocus} |
@@ -9,6 +9,21 @@ // @flow | ||
type State = { | ||
inputDevice: string, | ||
}; | ||
class Gestalt { | ||
constructor(inputDevice: string) { | ||
this.inputDevice = inputDevice; | ||
this.subscriptions = []; | ||
} | ||
inputDevice: string; | ||
subscriptions: Array<*>; | ||
setInputDevice(inputDevice: string) { | ||
this.inputDevice = inputDevice; | ||
this.subscriptions.forEach(f => f()); | ||
} | ||
subscribe(f: () => void) { | ||
this.subscriptions.push(f); | ||
} | ||
} | ||
/** | ||
@@ -20,3 +35,3 @@ * Context provider to see which type of input | ||
static childContextTypes = { | ||
inputDevice: React.PropTypes.string, | ||
gestalt: React.PropTypes.object, | ||
}; | ||
@@ -27,37 +42,31 @@ | ||
this.state = { | ||
inputDevice: 'key', | ||
}; | ||
this.gestalt = new Gestalt('key'); | ||
} | ||
state: State; | ||
getChildContext() { | ||
return { | ||
inputDevice: this.state.inputDevice, | ||
gestalt: this.gestalt, | ||
}; | ||
} | ||
shouldComponentUpdate(nextProps: Props, nextState: State) { | ||
return this.state.inputDevice !== nextState.inputDevice; | ||
} | ||
onKeyDown = () => { | ||
this.setState({ | ||
inputDevice: 'key', | ||
}); | ||
if (this.gestalt.inputDevice !== 'key') { | ||
this.gestalt.setInputDevice('key'); | ||
} | ||
} | ||
onMouseDown = () => { | ||
this.setState({ | ||
inputDevice: 'mouse', | ||
}); | ||
if (this.gestalt.inputDevice !== 'mouse') { | ||
this.gestalt.setInputDevice('mouse'); | ||
} | ||
} | ||
onTouchStart = () => { | ||
this.setState({ | ||
inputDevice: 'touch', | ||
}); | ||
if (this.gestalt.inputDevice !== 'touch') { | ||
this.gestalt.setInputDevice('touch'); | ||
} | ||
} | ||
gestalt: Gestalt; | ||
render() { | ||
@@ -64,0 +73,0 @@ return ( |
@@ -41,75 +41,89 @@ // @flow | ||
type GestaltContext = { | ||
inputDevice: '' | 'key' | 'mouse' | 'touch' | ||
gestalt: { | ||
inputDevice: '' | 'key' | 'mouse' | 'touch', | ||
subscribe: () => void, | ||
} | ||
} | ||
export default function IconButton(props: Props, context: GestaltContext) { | ||
const { | ||
accessibilityExpanded, | ||
accessibilityHaspopup, | ||
accessibilityLabel, | ||
bgColor = 'transparent', | ||
iconColor = defaultIconButtonIconColors[bgColor], | ||
icon, | ||
onClick, | ||
size = 'md', | ||
tabIndex, | ||
} = props; | ||
export default class IconButton extends React.Component { | ||
static contextTypes = { | ||
gestalt: React.PropTypes.func | ||
}; | ||
const { inputDevice = 'key' } = context; | ||
static props: Props; | ||
static context: GestaltContext; | ||
const inlineStyle = { | ||
height: buttonSize[size], | ||
width: buttonSize[size], | ||
propTypes = { | ||
accessibilityExpanded: PropTypes.bool, | ||
accessibilityHaspopup: PropTypes.bool, | ||
accessibilityLabel: PropTypes.string.isRequired, | ||
bgColor: PropTypes.oneOf( | ||
['transparent', 'lightGray'] | ||
), | ||
icon: PropTypes.oneOf(Object.keys(icons)).isRequired, | ||
iconColor: PropTypes.oneOf( | ||
['gray', 'darkGray', 'red', 'blue'] | ||
), | ||
onClick: PropTypes.func, | ||
size: PropTypes.oneOf( | ||
['xs', 'sm', 'md', 'lg', 'xl'] | ||
), | ||
tabIndex: PropTypes.oneOf([-1, 0]), | ||
}; | ||
const iconSize = buttonSize[size] / 2; | ||
componentDidMount() { | ||
if (this.context.gestalt) { | ||
this.context.gestalt.subscribe(() => this.forceUpdate()); | ||
} | ||
} | ||
return ( | ||
<button | ||
aria-expanded={accessibilityExpanded} | ||
aria-haspopup={accessibilityHaspopup} | ||
aria-label={accessibilityLabel} | ||
className={classnames( | ||
styles.button, | ||
styles[bgColor], { | ||
[styles.disableFocusOutline]: inputDevice !== 'key' | ||
} | ||
)} | ||
onClick={onClick} | ||
style={inlineStyle} | ||
tabIndex={tabIndex} | ||
> | ||
<Box xs={{ display: 'flex' }} alignItems="center" justifyContent="center"> | ||
{/* | ||
We're explicitly setting an empty string as a label on the Icon since we | ||
already have an aria-label on the button container. | ||
This is similar to having empty `alt` attributes: | ||
https://davidwalsh.name/accessibility-tip-empty-alt-attributes | ||
*/} | ||
<Icon color={iconColor} icon={icon} size={iconSize} accessibilityLabel="" /> | ||
</Box> | ||
</button> | ||
); | ||
} | ||
render() { | ||
const { | ||
accessibilityExpanded, | ||
accessibilityHaspopup, | ||
accessibilityLabel, | ||
bgColor = 'transparent', | ||
iconColor = defaultIconButtonIconColors[bgColor], | ||
icon, | ||
onClick, | ||
size = 'md', | ||
tabIndex, | ||
} = this.props; | ||
IconButton.contextTypes = { | ||
inputDevice: React.PropTypes.string | ||
}; | ||
const disableFocusOutline = this.context && this.context.gestalt && this.context.gestalt.inputDevice !== 'key'; | ||
IconButton.propTypes = { | ||
accessibilityExpanded: PropTypes.bool, | ||
accessibilityHaspopup: PropTypes.bool, | ||
accessibilityLabel: PropTypes.string.isRequired, | ||
bgColor: PropTypes.oneOf( | ||
['transparent', 'lightGray'] | ||
), | ||
icon: PropTypes.oneOf(Object.keys(icons)).isRequired, | ||
iconColor: PropTypes.oneOf( | ||
['gray', 'darkGray', 'red', 'blue'] | ||
), | ||
onClick: PropTypes.func, | ||
size: PropTypes.oneOf( | ||
['xs', 'sm', 'md', 'lg', 'xl'] | ||
), | ||
tabIndex: PropTypes.oneOf([-1, 0]), | ||
}; | ||
const inlineStyle = { | ||
height: buttonSize[size], | ||
width: buttonSize[size], | ||
}; | ||
const iconSize = buttonSize[size] / 2; | ||
return ( | ||
<button | ||
aria-expanded={accessibilityExpanded} | ||
aria-haspopup={accessibilityHaspopup} | ||
aria-label={accessibilityLabel} | ||
className={classnames( | ||
styles.button, | ||
styles[bgColor], { | ||
[styles.disableFocusOutline]: disableFocusOutline | ||
} | ||
)} | ||
onClick={onClick} | ||
style={inlineStyle} | ||
tabIndex={tabIndex} | ||
> | ||
<Box xs={{ display: 'flex' }} alignItems="center" justifyContent="center"> | ||
{/* | ||
We're explicitly setting an empty string as a label on the Icon since we | ||
already have an aria-label on the button container. | ||
This is similar to having empty `alt` attributes: | ||
https://davidwalsh.name/accessibility-tip-empty-alt-attributes | ||
*/} | ||
<Icon color={iconColor} icon={icon} size={iconSize} accessibilityLabel="" /> | ||
</Box> | ||
</button> | ||
); | ||
} | ||
} |
@@ -36,35 +36,50 @@ // @flow | ||
type GestaltContext = { | ||
inputDevice: '' | 'key' | 'mouse' | 'touch' | ||
}; | ||
export default function Link(props: LinkProps, context: GestaltContext) { | ||
const { inputDevice = 'key' } = context; | ||
const { color = 'darkGray', inline = false } = props; | ||
return ( | ||
// eslint-disable-next-line jsx-a11y/anchor-has-content | ||
<a | ||
{...omit(PropBlacklist, props)} | ||
className={ | ||
cx( | ||
styles.link, | ||
colors[color], | ||
(inline ? styles.inline : styles.block), | ||
(inputDevice !== 'key' ? styles.disableFocusOutline : '') | ||
) | ||
} | ||
/> | ||
); | ||
gestalt: { | ||
inputDevice: '' | 'key' | 'mouse' | 'touch', | ||
subscribe: () => void, | ||
} | ||
} | ||
Link.contextTypes = { | ||
inputDevice: React.PropTypes.string | ||
}; | ||
export default class Link extends React.Component { | ||
static contextTypes = { | ||
gestalt: React.PropTypes.func | ||
}; | ||
Link.propTypes = { | ||
// eslint-disable-next-line react/no-unused-prop-types | ||
children: PropTypes.node.isRequired, | ||
color: PropTypes.oneOf(['white', 'darkGray', 'gray', 'red', 'blue']), | ||
// eslint-disable-next-line react/no-unused-prop-types | ||
href: PropTypes.string.isRequired, | ||
inline: PropTypes.bool | ||
}; | ||
static props: LinkProps; | ||
static context: GestaltContext; | ||
static propTypes = { | ||
// eslint-disable-next-line react/no-unused-prop-types | ||
children: PropTypes.node.isRequired, | ||
color: PropTypes.oneOf(['white', 'darkGray', 'gray', 'red', 'blue']), | ||
// eslint-disable-next-line react/no-unused-prop-types | ||
href: PropTypes.string.isRequired, | ||
inline: PropTypes.bool | ||
}; | ||
componentDidMount() { | ||
if (this.context.gestalt) { | ||
this.context.gestalt.subscribe(() => this.forceUpdate()); | ||
} | ||
} | ||
render() { | ||
const disableFocusOutline = this.context && this.context.gestalt && this.context.gestalt.inputDevice !== 'key'; | ||
const { color = 'darkGray', inline = false } = this.props; | ||
return ( | ||
// eslint-disable-next-line jsx-a11y/anchor-has-content | ||
<a | ||
{...omit(PropBlacklist, this.props)} | ||
className={ | ||
cx( | ||
styles.link, | ||
colors[color], | ||
(inline ? styles.inline : styles.block), | ||
(disableFocusOutline ? styles.disableFocusOutline : '') | ||
) | ||
} | ||
/> | ||
); | ||
} | ||
} |
@@ -20,3 +20,2 @@ // @flow | ||
scrollContainer: HTMLElement, | ||
serverRender: boolean, | ||
|}; | ||
@@ -92,3 +91,3 @@ | ||
gridItems: [], | ||
serverItems: props.serverRender ? this.serverItems(props.items) : null, | ||
serverItems: this.serverItems(props.items), | ||
minHeight: 0, | ||
@@ -769,8 +768,2 @@ mounted: false, | ||
}), | ||
/** | ||
* Whether or not this instance is server rendered. | ||
* TODO: If true, generate and output CSS for the initial server render. | ||
*/ | ||
serverRender: React.PropTypes.bool, | ||
}; | ||
@@ -783,3 +776,2 @@ | ||
scrollContainer: typeof window !== 'undefined' ? window : null, | ||
serverRender: false, | ||
loadItems: () => {}, | ||
@@ -786,0 +778,0 @@ }; |
@@ -6,2 +6,3 @@ // @flow | ||
import TextField from '../TextField'; | ||
import GestaltProvider from '../../GestaltProvider/GestaltProvider'; | ||
import { ns } from '../../../.corkboard/cards'; | ||
@@ -45,27 +46,29 @@ | ||
return ( | ||
<div className="px2"> | ||
<div className="py2"> | ||
<label htmlFor="email">With a placeholder</label> | ||
<TextField | ||
id="email" | ||
onChange={newValue => atom.reset({ placeholderValue: newValue })} | ||
placeholder="Email Address" | ||
value={atom.deref().placeholderValue} | ||
type="email" | ||
/> | ||
<GestaltProvider> | ||
<div className="px2"> | ||
<div className="py2"> | ||
<label htmlFor="email">With a placeholder</label> | ||
<TextField | ||
id="email" | ||
onChange={newValue => atom.reset({ placeholderValue: newValue })} | ||
placeholder="Email Address" | ||
value={atom.deref().placeholderValue} | ||
type="email" | ||
/> | ||
</div> | ||
<div className="py2"> | ||
<label htmlFor="password">With a password</label> | ||
<TextField | ||
id="password" | ||
type="password" | ||
value="abcdef" | ||
{...state} | ||
onChange={newValue => atom.set(props => ({ | ||
...props, | ||
value: newValue, | ||
}))} | ||
/> | ||
</div> | ||
</div> | ||
<div className="py2"> | ||
<label htmlFor="password">With a password</label> | ||
<TextField | ||
id="password" | ||
type="password" | ||
value="abcdef" | ||
{...state} | ||
onChange={newValue => atom.set(props => ({ | ||
...props, | ||
value: newValue, | ||
}))} | ||
/> | ||
</div> | ||
</div> | ||
</GestaltProvider> | ||
); | ||
@@ -72,0 +75,0 @@ }); |
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
1586763
26323