Skip to content

Commit

Permalink
[components] Fix stacking (#297)
Browse files Browse the repository at this point in the history
[form-builder] Make block editor part of same escape stack

[components] Add a util component for capturing outside clicks

[components] Use CaptureOutsideClicks in Sticky portal

[components] Misc. cleanup

[components] Make Stacked keep the topmost element as state, and pass to children

[components] Wrap <Stacked inside root element
  • Loading branch information
bjoerge committed Nov 7, 2017
1 parent 4f61ac8 commit 0ba11ff
Show file tree
Hide file tree
Showing 19 changed files with 433 additions and 302 deletions.
5 changes: 4 additions & 1 deletion packages/@sanity/base/sanity.json
Original file line number Diff line number Diff line change
Expand Up @@ -228,7 +228,10 @@
"name": "part:@sanity/base/schema-type",
"description": "Schema types provided by plugins, for easy usage in studio schemas"
},

{
"name": "part:@sanity/components/layer-stack",
"description": "Keep control over stacking layers in portals"
},
{
"implements": "part:@sanity/base/sanity-root",
"path": "components/SanityRoot.js"
Expand Down
1 change: 1 addition & 0 deletions packages/@sanity/components/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@
"in-publish": "^2.0.0",
"lodash": "^4.17.4",
"lost": "^8.0.0",
"nano-pubsub": "^1.0.2",
"postcss-cssnext": "^3.0.2",
"react-addons-css-transition-group": "^15.4.1",
"react-addons-shallow-compare": "^15.4.1",
Expand Down
16 changes: 16 additions & 0 deletions packages/@sanity/components/sanity.json
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,10 @@
"name": "part:@sanity/components/utilities/image-loader",
"description": "Image loader utility"
},
{
"name": "part:@sanity/components/utilities/stacked-escapable",
"description": "A stacked escapable utility"
},
{
"name": "part:@sanity/components/fileinput/default",
"description": "<Input type=file />"
Expand Down Expand Up @@ -603,6 +607,18 @@
"implements": "part:@sanity/components/utilities/image-loader",
"path": "utilities/ImageLoader.js"
},
{
"implements": "part:@sanity/components/utilities/stacked-escapable",
"path": "utilities/StackedEscapable.js"
},
{
"implements": "part:@sanity/components/utilities/escapable",
"path": "utilities/Escapable.js"
},
{
"implements": "part:@sanity/components/utilities/stacked",
"path": "utilities/Stacked.js"
},
{
"implements": "part:@sanity/components/imageinput/image-select",
"path": "imageinput/common/ImageSelect.js"
Expand Down
13 changes: 10 additions & 3 deletions packages/@sanity/components/src/buttons/DropDownButton.js
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,12 @@ class DropDownButton extends React.PureComponent {
this._menuElement = element
}

handleCloseMenu = () => {
this.setState({
menuOpened: !this.state.menuOpened
})
}

handleOnClick = event => {
this.setState({
menuOpened: !this.state.menuOpened,
Expand Down Expand Up @@ -160,7 +166,8 @@ class DropDownButton extends React.PureComponent {
useOverlay={false}
addPadding={false}
scrollIntoView={false}
onClose={this.handleClose}
onClickOutside={this.handleClose}
onEscape={this.handleClose}
>
<div
ref={this.setMenuElement}
Expand All @@ -171,8 +178,8 @@ class DropDownButton extends React.PureComponent {
isOpen
className={menuClassName}
onAction={this.handleAction}
onClickOutside={this.handleClickOutside}
onClose={this.handleClose}
onClickOutside={this.handleCloseMenu}
onClose={this.handleCloseMenu}
/>
</div>
</StickyPortal>
Expand Down
80 changes: 32 additions & 48 deletions packages/@sanity/components/src/dialogs/ConfirmDialog.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import CheckIcon from 'part:@sanity/base/circle-check-icon'
import styles from './styles/ConfirmDialog.css'
import Button from 'part:@sanity/components/buttons/default'
import Portal from 'react-portal'
import StackedEscapable from '../utilities/StackedEscapable'

export default class DefaultDialog extends React.PureComponent {
static propTypes = {
Expand All @@ -32,32 +33,13 @@ export default class DefaultDialog extends React.PureComponent {
cancelButtonText: 'Cancel'
}

componentDidMount() {
window.addEventListener('keydown', this.handleKeyDown, false)
}

componentWillUnmount() {
window.removeEventListener('keydown', this.handleKeyDown, false)
}

isClosable() {
return typeof this.props.onClose === 'function'
}

handleKeyDown = event => {
if (event.key === 'Escape') {
this.props.onCancel()
}
}

handleDialogClick = event => {
event.stopPropagation()
}

setDialogElement = element => {
this.dialog = element
}

render() {
const {
color,
Expand All @@ -70,39 +52,41 @@ export default class DefaultDialog extends React.PureComponent {
} = this.props

return (
<Portal isOpened>
<div
className={`${styles.root} ${styles[color]} ${className}`}
ref={this.setDialogElement}
onClick={onCancel}
>
<div className={styles.dialog} onClick={this.handleDialogClick}>
<div className={styles.inner}>
<div className={styles.content}>
{this.props.children}
</div>
<StackedEscapable onEscape={onCancel}>
<Portal isOpened>
<div
className={`${styles.root} ${styles[color]} ${className}`}
ref={this.setDialogElement}
onClick={onCancel}
>
<div className={styles.dialog} onClick={this.handleDialogClick}>
<div className={styles.inner}>
<div className={styles.content}>
{this.props.children}
</div>

<div className={styles.footer}>
<Button
onClick={onCancel}
icon={CloseIcon}
kind="secondary"
>
{cancelButtonText}
</Button>
<Button
onClick={onConfirm}
color={confirmColor}
icon={CheckIcon}
autoFocus
>
{confirmButtonText}
</Button>
<div className={styles.footer}>
<Button
onClick={onCancel}
icon={CloseIcon}
kind="secondary"
>
{cancelButtonText}
</Button>
<Button
onClick={onConfirm}
color={confirmColor}
icon={CheckIcon}
autoFocus
>
{confirmButtonText}
</Button>
</div>
</div>
</div>
</div>
</div>
</Portal>
</Portal>
</StackedEscapable>
)
}
}
119 changes: 50 additions & 69 deletions packages/@sanity/components/src/dialogs/DefaultDialog.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import CloseIcon from 'part:@sanity/base/close-icon'
import styles from 'part:@sanity/components/dialogs/default-style'
import Button from 'part:@sanity/components/buttons/default'
import Portal from 'react-portal'
import StackedEscapable from '../utilities/StackedEscapable'

export default class DefaultDialog extends React.PureComponent {
static propTypes = {
Expand Down Expand Up @@ -43,32 +44,10 @@ export default class DefaultDialog extends React.PureComponent {
}
}

componentDidMount() {
window.addEventListener('keydown', this.handleKeyDown, false)
}

componentWillUnmount() {
window.removeEventListener('keydown', this.handleKeyDown, false)
}

isClosable() {
return typeof this.props.onClose === 'function'
}

handleKeyDown = event => {
if (event.key === 'Escape' && this.isClosable()) {
this.props.onClose()
}
}

openDialogElement() {
this.props.onOpen()
}

handleCloseClick = event => {
this.props.onClose()
}

handleDialogClick = event => {
event.stopPropagation()
}
Expand All @@ -93,63 +72,65 @@ export default class DefaultDialog extends React.PureComponent {
`

return (
<Portal isOpened={isOpen} onClose={onClose}>
<div className={classNames} ref={this.setDialogElement} onClick={this.handleCloseClick}>
<div className={styles.dialog} onClick={this.handleDialogClick}>
{
!showHeader && onClose && (
<button className={styles.closeButtonOutside} onClick={this.handleCloseClick}>
<CloseIcon color="inherit" />
</button>
)
}
<div className={styles.inner}>
<StackedEscapable onEscape={onClose}>
<Portal isOpened={isOpen}>
<div className={classNames} ref={this.setDialogElement} onClick={this.handleCloseClick}>
<div className={styles.dialog} onClick={this.handleDialogClick}>
{
showHeader && onClose && (
<div className={styles.header}>
<h1 className={styles.title}>{title}</h1>
<button className={styles.closeButton} onClick={this.handleCloseClick}>
<CloseIcon color="inherit" />
</button>
</div>
!showHeader && onClose && (
<button className={styles.closeButtonOutside} onClick={onClose}>
<CloseIcon color="inherit" />
</button>
)
}
<div className={styles.content}>
{this.props.children}
</div>

<div className={styles.footer}>
<div className={styles.inner}>
{
actions.length > 0 && <div className={styles.functions}>
{
actions.map((action, i) => {
return (
<Button
key={i}
onClick={this.handleActionClick}
data-action-index={i}
color={action.color}
disabled={action.disabled}
kind={action.kind}
autoFocus={action.autoFocus}
className={`
showHeader && onClose && (
<div className={styles.header}>
<h1 className={styles.title}>{title}</h1>
<button className={styles.closeButton} onClick={onClose}>
<CloseIcon color="inherit" />
</button>
</div>
)
}
<div className={styles.content}>
{this.props.children}
</div>

<div className={styles.footer}>
{
actions.length > 0 && <div className={styles.functions}>
{
actions.map((action, i) => {
return (
<Button
key={i}
onClick={this.handleActionClick}
data-action-index={i}
color={action.color}
disabled={action.disabled}
kind={action.kind}
autoFocus={action.autoFocus}
className={`
${styles.button}
${styles[`button_${action.kind}`] || styles.button}
`
}
>
{action.title}
</Button>
)
})
}
</div>
}
}
>
{action.title}
</Button>
)
})
}
</div>
}
</div>
</div>
</div>
</div>
</div>
</Portal>
</Portal>
</StackedEscapable>
)
}
}

0 comments on commit 0ba11ff

Please sign in to comment.