Skip to content

Commit

Permalink
Add new Toolbar.Popover component to display anything in a Toolbar (#…
Browse files Browse the repository at this point in the history
…5692)

* Introduce popover component for Toolbar

* Add some very basic styling for the Toolbar Popover
  • Loading branch information
danrot committed Dec 10, 2020
1 parent cf13845 commit 7c24e0b
Show file tree
Hide file tree
Showing 16 changed files with 300 additions and 210 deletions.
Original file line number Diff line number Diff line change
@@ -1,61 +1,22 @@
// @flow
import React from 'react';
import type {ElementRef} from 'react';
import {action, observable} from 'mobx';
import {observer} from 'mobx-react';
import classNames from 'classnames';
import Popover from '../Popover';
import type {DropdownOption, Dropdown as DropdownProps} from './types';
import Button from './Button';
import Popover from './Popover';
import OptionList from './OptionList';
import dropdownStyles from './dropdown.scss';

@observer
class Dropdown extends React.Component<DropdownProps> {
@observable open: boolean = false;

static defaultProps = {
showText: true,
};

@observable buttonRef: ?ElementRef<'button'>;

@action setButtonRef = (ref: ?ElementRef<'button'>) => {
if (ref) {
this.buttonRef = ref;
}
};

@action close = () => {
this.open = false;
};

@action toggle = () => {
this.open = !this.open;
};

componentDidUpdate() {
const {disabled} = this.props;

if (disabled) {
this.close();
}
}

handleButtonClick = () => {
this.toggle();
};

handleOptionListClick = (option: DropdownOption) => {
if (option.onClick) {
option.onClick();
}
};

handleOptionListClose = () => {
this.close();
};

render() {
const {
icon,
Expand All @@ -67,48 +28,27 @@ class Dropdown extends React.Component<DropdownProps> {
loading,
showText,
} = this.props;
const dropdownClass = classNames(
dropdownStyles.dropdown,
{
[dropdownStyles[size]]: size,
}
);

const allChildrenDisabled = options.every((option) => option.disabled);

return (
<div className={dropdownClass}>
<Button
active={this.open}
buttonRef={this.setButtonRef}
disabled={disabled || allChildrenDisabled}
hasOptions={true}
icon={icon}
label={showText ? label : undefined}
loading={loading}
onClick={this.handleButtonClick}
size={size}
skin={skin}
/>
<Popover
anchorElement={this.buttonRef}
onClose={this.handleOptionListClose}
open={this.open}
>
{
(setPopoverElementRef, popoverStyle) => (
<div ref={setPopoverElementRef} style={popoverStyle}>
<OptionList
onClose={this.handleOptionListClose}
onOptionClick={this.handleOptionListClick}
options={options}
skin={skin}
/>
</div>
)
}
</Popover>
</div>
<Popover
disabled={disabled || allChildrenDisabled}
icon={icon}
label={showText ? label : undefined}
loading={loading}
size={size}
skin={skin}
>
{(onClose) => (
<OptionList
onClose={onClose}
onOptionClick={this.handleOptionListClick}
options={options}
skin={skin}
/>
)}
</Popover>
);
}
}
Expand Down
104 changes: 104 additions & 0 deletions src/Sulu/Bundle/AdminBundle/Resources/js/components/Toolbar/Popover.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
// @flow
import React from 'react';
import type {ElementRef} from 'react';
import {action, observable} from 'mobx';
import {observer} from 'mobx-react';
import classNames from 'classnames';
import PopoverComponent from '../Popover';
import type {Popover as PopoverProps} from './types';
import Button from './Button';
import popoverStyles from './popover.scss';

@observer
class Popover extends React.Component<PopoverProps> {
@observable open: boolean = false;

static defaultProps = {
showText: true,
};

@observable buttonRef: ?ElementRef<'button'>;

@action setButtonRef = (ref: ?ElementRef<'button'>) => {
if (ref) {
this.buttonRef = ref;
}
};

@action close = () => {
this.open = false;
};

@action toggle = () => {
this.open = !this.open;
};

componentDidUpdate() {
const {disabled} = this.props;

if (disabled) {
this.close();
}
}

handleButtonClick = () => {
this.toggle();
};

handlePopoverClose = () => {
this.close();
};

render() {
const {
children,
className,
icon,
size,
skin,
label,
disabled,
loading,
showText,
} = this.props;
const popoverClass = classNames(
className,
popoverStyles.popover,
{
[popoverStyles[size]]: size,
}
);

return (
<div className={popoverClass}>
<Button
active={this.open}
buttonRef={this.setButtonRef}
disabled={disabled}
hasOptions={true}
icon={icon}
label={showText ? label : undefined}
loading={loading}
onClick={this.handleButtonClick}
size={size}
skin={skin}
/>
<PopoverComponent
anchorElement={this.buttonRef}
onClose={this.handlePopoverClose}
open={this.open}
>
{
(setPopoverElementRef, popoverStyle) => (
<div className={popoverStyles[skin]} ref={setPopoverElementRef} style={popoverStyle}>
{children(this.close)}
</div>
)
}
</PopoverComponent>
</div>
);
}
}

export default Popover;
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
The `Toolbar` component serves as container for `Controls`. The `Controls` component groups components which provide
the user interaction like `Button`, `Select` or `Dropdown`.
the user interaction like `Button`, `Toggler`, `Select` or `Dropdown`. Additionally the `Popover` component exists,
which shows a button that hides the return value of the `children` prop and shows it on a click.

```javascript
<Toolbar>
Expand Down Expand Up @@ -38,6 +39,9 @@ component you can group the items by using the `Items` component.
</Toolbar.Items>
</Toolbar.Controls>
<Toolbar.Controls>
<Toolbar.Popover label="Show content">
{() => 'Content'}
</Toolbar.Popover>
<Toolbar.Select
label="Chose an option"
onClick={() => null}
Expand Down Expand Up @@ -78,6 +82,9 @@ The appearance of the `Toolbar` can be changed by passing the attribute `skin`.
</Toolbar.Items>
</Toolbar.Controls>
<Toolbar.Controls>
<Toolbar.Popover label="Show content">
{() => 'Content'}
</Toolbar.Popover>
<Toolbar.Select
label="Chose an option"
onClick={() => null}
Expand Down
Loading

0 comments on commit 7c24e0b

Please sign in to comment.