Skip to content

Commit

Permalink
Merge pull request #724 from open-sausages/pulls/4/ticken-the-insert-…
Browse files Browse the repository at this point in the history
…here-line

Make the HoverBar more visible
  • Loading branch information
robbieaverill authored Aug 27, 2019
2 parents cc68796 + ce72d57 commit 2424f4b
Show file tree
Hide file tree
Showing 7 changed files with 207 additions and 184 deletions.
2 changes: 1 addition & 1 deletion client/dist/js/bundle.js

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion client/dist/styles/bundle.css

Large diffs are not rendered by default.

6 changes: 5 additions & 1 deletion client/src/components/ElementEditor/ElementList.js
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ class ElementList extends Component {
return <div>{i18n._t('ElementList.ADD_BLOCKS', 'Add blocks to place your content')}</div>;
}

const output = blocks.map((element) => (
let output = blocks.map((element) => (
<div key={element.ID}>
<ElementComponent
element={element}
Expand All @@ -70,6 +70,10 @@ class ElementList extends Component {
</div>
));

output = [
<HoverBarComponent key={0} areaId={areaId} elementId={0} elementTypes={allowedElementTypes} />
].concat(output);

const dragIndicatorIndex = this.getDragIndicatorIndex();
if (isDraggingOver && dragIndicatorIndex !== null) {
output.splice(dragIndicatorIndex, 0, <DragIndicatorComponent key="DropIndicator" />);
Expand Down
176 changes: 46 additions & 130 deletions client/src/components/ElementEditor/HoverBar.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,47 @@
/* global window */
import React, { Component } from 'react';
import PropTypes from 'prop-types';
import classNames from 'classnames';
import prefixClassNames from '../../lib/prefixClassNames';
import { inject } from 'lib/Injector';
import { elementTypeType } from 'types/elementTypeType';
import i18n from 'i18n';

const classNames = prefixClassNames('element-editor__hover-bar');

/**
* Render an hoverbar without any state
*/
function StatelessHoverBar({
AddElementPopoverComponent,
elementTypes,
elementId,
areaId,
popoverOpen,
onToggle }) {
const lineClasses = `${classNames('-line')} font-icon-plus-circled`;
const areaClasses = classNames('-area', { '-area--focus': popoverOpen });
const label = i18n._t('ElementAddNewButton.ADD_BLOCK', 'Add block');

return (
<div className={classNames('')} id={`AddBlockArea_${elementId}`}>
<button className={areaClasses} onClick={onToggle} aria-label={label} title={label}>
<span className={classNames('-area-inner')}>
<span id={`AddBlockHoverBar_${elementId}`} className={lineClasses} />
</span>
</button>
<AddElementPopoverComponent
placement="bottom"
target={`AddBlockHoverBar_${elementId}`}
isOpen={popoverOpen}
elementTypes={elementTypes}
toggle={onToggle}
container={`#AddBlockArea_${elementId}`}
areaId={areaId}
insertAfterElement={elementId}
/>
</div>
);
}

/**
* The HoverBar component used in the context of an ElementEditor allows CMS users to add available
Expand All @@ -12,151 +50,29 @@ import { elementTypeType } from 'types/elementTypeType';
class HoverBar extends Component {
constructor(props) {
super(props);

this.handleMouseEnter = this.handleMouseEnter.bind(this);
this.handleMouseLeave = this.handleMouseLeave.bind(this);
this.renderHoverBar = this.renderHoverBar.bind(this);
this.toggle = this.toggle.bind(this);

this.state = {
timeoutRef: null,
delayAreaActive: false,
instAreaActive: false,
popoverOpen: false
};
}

/**
* Handle mouse entering the hover area between two elements. Calculates if mouse entered via
* 'delayed' or 'instantaneous' hover area and 'activates' these areas with a time out in the
* former case and instantaneously in the latter.
*
* @param event
*/
handleMouseEnter(event) {
const { elementId } = this.props;

// padding of elemental editor + width of font-icon
const plusButtonWidth = 50;

const addBlockAreaContainer = window.document.getElementById(`AddBlockArea_${elementId}`);
const clientWidth = addBlockAreaContainer.clientWidth;
const offsetLeft = addBlockAreaContainer.getBoundingClientRect().left;
const mousePos = event.pageX - offsetLeft;
const delayArea = clientWidth - plusButtonWidth;

// mouse entered within 'delay' hover area
if (mousePos < delayArea) {
const timeoutRef = setTimeout(() => {
this.setState({
delayAreaActive: true,
});
}, 200);

this.setState({
timeoutRef,
});
} else {
// mouse entered within 'instantaneous' hover area
this.setState({
instAreaActive: true,
});
}
}

/**
* Handles mouse leaving the hover area between two elements.
* 'Deactivates' both the 'delayed' and 'instantaneous' hover area sections, unless the popover
* is rendered.
*
*/
handleMouseLeave() {
clearTimeout(this.state.timeoutRef);

if (this.state.popoverOpen) {
return;
}
this.setState({ delayAreaActive: false, instAreaActive: false });
}

toggle() {
this.setState({
popoverOpen: !this.state.popoverOpen
});
}

/**
* Render a hover bar. Styling depends on the hover area section that triggered this function.
*
* @returns {DOMElement}
*/
renderHoverBar(calledInstantaneously) {
const { elementId } = this.props;

const hoverBarClassNames = classNames(
'font-icon-plus-circled',
'element-editor__add-block-hover-bar',
{
'element-editor__add-block-hover-bar--delay': !calledInstantaneously,
'element-editor__add-block-hover-bar--inst': calledInstantaneously,
}
);

return (
<button
id={`AddBlockHoverBar_${elementId}`}
className={hoverBarClassNames}
onClick={this.toggle}
/>
);
}

/**
* Render the hover bar container and the hover area. Conditionally render the hover bar and the
* injected popover.
*
* @returns {DOMElement}
*/
render() {
const {
AddElementPopoverComponent,
elementTypes,
elementId,
areaId,
} = this.props;
const { popoverOpen } = this.state;

return (
<div className="element-editor__add-block-area-container" id={`AddBlockArea_${elementId}`}>
<div
className="element-editor__add-block-area"
onMouseEnter={this.handleMouseEnter}
onMouseLeave={this.handleMouseLeave}
>
{/* render the hover bar in the corresponding style */}
{
(this.state.delayAreaActive && this.renderHoverBar(false)) ||
(this.state.instAreaActive && this.renderHoverBar(true))
}
{/* render the popover */}
{(this.state.delayAreaActive || this.state.instAreaActive) &&
<AddElementPopoverComponent
placement="bottom-end"
target={`AddBlockHoverBar_${elementId}`}
isOpen={popoverOpen}
elementTypes={elementTypes}
toggle={this.toggle}
container={`#AddBlockArea_${elementId}`}
areaId={areaId}
insertAfterElement={elementId}
/>
}
</div>
</div>
);
const props = {
...this.state,
...this.props,
onToggle: this.toggle
};
return <StatelessHoverBar {...props} />;
}
}


HoverBar.propTypes = {
elementTypes: PropTypes.arrayOf(elementTypeType).isRequired,
elementId: PropTypes.oneOfType([PropTypes.string, PropTypes.number]).isRequired,
Expand Down
120 changes: 69 additions & 51 deletions client/src/components/ElementEditor/HoverBar.scss
Original file line number Diff line number Diff line change
@@ -1,65 +1,83 @@
.element-editor__add-block-area-container {
height: 0;
display: flex;
width: 100%;
position: relative;
align-items: center;
}

.element-editor__add-block-area {
background-color: transparent;
min-height: $spacer * 1.5;
width: 100%;
margin: 0;
padding: 0;
border: 0;
outline: 0;
transition: 0s;
}
$transition: all ease .2s;

.element-editor__add-block-hover-bar {
align-self: center;
width: 100%;
-webkit-appearance: button;
border: 0;
position: absolute;
display: flex;
justify-content: flex-end;
padding: 0;
top: 50%;
transform: translateY(-66%);
.element-editor {

&:before {
font-size: 1.5rem;
background-image: radial-gradient(#fff 50%, transparent 50%);
// Fallback for IE11 & other browsers that don't support the calc() below
transform: translateY(-35%);
// position plus 'button' to be able to modify it's z-index
&__hover-bar {
height: 0;
display: flex;
width: 100%;
position: relative;
z-index: 2;
margin-right: $panel-padding-x/2;
display: block;
height: 1em;
align-items: center;
}

&--delay {
background-color: $border-color-dark;
max-height: 3px;
&__hover-bar-area {
background-color: transparent;
min-height: $spacer * 1.5;
width: 100%;
margin: 0;
padding: 0;
border: none;
outline: none;
transition: $transition;
position: relative;

&:before {
transform: translateY(calc((3px/2) + -50%));
color: $border-color-dark;
&:hover, &:focus, &--focus {
outline: none;

.element-editor__hover-bar-area-inner {
margin: 0 20px;
}

.element-editor__hover-bar-line {
opacity: 1;
border-radius: 5px;
max-height: 5px;
&:before {
transform: translateY(calc(3px + -50%)) scale(1);
}
}
}
}

&--inst {
background-color: $component-active-bg;
max-height: 5px;
&__hover-bar-area-inner {
margin: 0 0;
display: block;
position: relative;
transition: $transition;
}

&__hover-bar-line {
background-color: $blue;
transition: $transition;
opacity: 0;
align-self: center;
width: 100%;
border: 0;
position: absolute;
display: flex;
justify-content: flex-end;
padding: 0;
top: 50%;
transform: translateY(-66%);
max-height: 0;
border-radius: 0;

&:before {
transform: translateY(calc((5px/2) + -50%));
color: $component-active-bg;
font-size: 1.5rem;
background-image: radial-gradient(#fff 50%, transparent 50%);
// position plus 'button' to be able to modify it's z-index
position: relative;
z-index: 2;
margin-right: 50%;
right: -.5em;
display: block;
height: 1em;
// IE-11 fallback
transform: translateY(-35%);
transform: translateY(calc(-1px + -50%)) scale(0);
transition: $transition;
color: $blue;
}
}
}

}
33 changes: 33 additions & 0 deletions client/src/lib/prefixClassNames.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import classNames from 'classnames';

/**
* Utility method wrap around classeNames to prefix the return class names
* @param {string} cssPrefix
* @returns {Function}
*/
const prefixClassNames = (cssPrefix) => (...args) => {
const prefix = (str) => `${cssPrefix}${str}`;

const prefixArgs = args.map(arg => {
if (!arg && arg !== '') {
return false;
}

if (typeof arg === 'object') {
return Array.isArray(arg) ?
arg.map(prefix) :
Object.entries(arg).reduce(
(accumulator, [key, value]) => (
Object.assign({}, accumulator, { [prefix(key)]: value })
),
{}
);
}

return prefix(arg);
});

return classNames(...prefixArgs);
};

export default prefixClassNames;
Loading

0 comments on commit 2424f4b

Please sign in to comment.