adds refined repeater styles and popup on hover

This commit is contained in:
Jarrod Flesch
2020-06-17 16:38:40 -04:00
parent 926d8504c6
commit 8febfd4ed0
8 changed files with 187 additions and 51 deletions

View File

@@ -10,7 +10,7 @@ const baseClass = 'popup';
const Popup = (props) => {
const {
render, align, size, button, children,
render, align, size, color, pointerAlignment, button, children, showOnHover,
} = props;
const [active, setActive] = useState(false);
@@ -54,18 +54,34 @@ const Popup = (props) => {
baseClass,
`${baseClass}--align-${align}`,
`${baseClass}--size-${size}`,
`${baseClass}--color-${color}`,
`${baseClass}--pointer-alignment-${pointerAlignment}`,
`${baseClass}--vertical-align-${verticalAlign}`,
active && `${baseClass}--active`,
].filter(Boolean).join(' ');
return (
<div className={classes}>
<button
type="button"
onClick={() => setActive(!active)}
>
{button}
</button>
{showOnHover
? (
<div
className={`${baseClass}__on-hover-watch`}
onMouseEnter={() => setActive(true)}
onMouseLeave={() => setActive(false)}
>
{button}
</div>
)
: (
<button
type="button"
onClick={() => setActive(!active)}
>
{button}
</button>
)
}
<div
className={`${baseClass}__content`}
ref={ref}
@@ -84,16 +100,23 @@ const Popup = (props) => {
Popup.defaultProps = {
align: 'center',
size: 'small',
color: 'light',
pointerAlignment: 'left',
children: undefined,
render: undefined,
button: undefined,
showOnHover: false,
};
Popup.propTypes = {
render: PropTypes.func,
children: PropTypes.node,
align: PropTypes.oneOf(['left', 'center', 'right']),
size: PropTypes.oneOf(['small', 'large']),
button: PropTypes.node.isRequired,
pointerAlignment: PropTypes.oneOf(['left', 'center', 'right']),
size: PropTypes.oneOf(['small', 'large', 'wide']),
color: PropTypes.oneOf(['light', 'dark']),
button: PropTypes.node,
showOnHover: PropTypes.bool,
};
export default Popup;

View File

@@ -77,6 +77,57 @@
}
}
&--size-wide {
.popup__content {
@include shadow-sm;
&:after {
border: 12px solid transparent;
border-top-color: white;
}
}
.popup__scroll {
padding: base(.25) base(.5);
}
&.popup--align-left {
.popup__content {
left: - base(.5);
&:after {
left: base(.425);
}
}
}
}
&--color-dark {
.popup__content {
background: $color-dark-gray;
color: white;
&:after {
border-top-color: $color-dark-gray;
}
}
}
////////////////////////////////
// POINTER POSITION
////////////////////////////////
&--pointer-alignment-center {
.popup__content {
left: 50%;
transform: translateX(-50%);
&:after {
left: 50%;
transform: translateX(-50%);
}
}
}
////////////////////////////////
// ACTIVE
////////////////////////////////

View File

@@ -1,34 +1,60 @@
import React from 'react';
import React, { useState } from 'react';
import PropTypes from 'prop-types';
import Button from '../../../elements/Button';
import Popup from '../../../elements/Popup';
import './index.scss';
const baseClass = 'action-handle';
const ActionHandle = (props) => {
const { addRow, removeRow } = props;
const { addRow, removeRow, singularLabel } = props;
const [addRowPopupActive, setAddRowPopupActive] = useState(false);
const [removeRowPopupActive, setRemoveRowPopupActive] = useState(false);
return (
<div className={baseClass}>
<Button
className={`${baseClass}__remove-row`}
icon="x"
buttonStyle="icon-label"
iconPosition="left"
iconColor="light-gray"
onClick={() => removeRow()}
/>
<Popup
showOnHover
size="wide"
color="dark"
pointerAlignment="center"
button={(
<Button
className={`${baseClass}__remove-row`}
icon="x"
buttonStyle="icon-label"
iconPosition="left"
iconColor="light-gray"
onClick={() => removeRow()}
/>
)}
>
Remove&nbsp;
{`${singularLabel ?? 'Row'}`}
</Popup>
<Button
className={`${baseClass}__add-row`}
icon="plus"
buttonStyle="icon-label"
iconPosition="left"
iconColor="light-gray"
onClick={() => addRow()}
/>
<Popup
showOnHover
size="wide"
color="dark"
pointerAlignment="center"
button={(
<Button
className={`${baseClass}__add-row`}
icon="plus"
buttonStyle="icon-label"
iconPosition="left"
iconColor="light-gray"
onClick={() => addRow()}
/>
)}
>
Add&nbsp;
{`${singularLabel ?? 'Row'}`}
</Popup>
</div>
);
};

View File

@@ -5,17 +5,18 @@
flex-direction: column;
align-items: center;
justify-content: center;
padding: base(.5) base(.5) base(.5) 0;
margin-left: base(.5);
padding: base(.5) base(.5) base(.5) base(.5);
margin-bottom: base(1);
position: absolute;
top: 0; bottom: 0; left: 100%;
&__remove-row {
margin: 0 0 base(.3);
opacity: 0;
}
&__add-row {
margin: base(.3) 0 0;
opacity: 0;
}
}

View File

@@ -17,23 +17,25 @@ const PositionHandle = (props) => {
className={baseClass}
{...dragHandleProps}
>
<Button
className={`${baseClass}__move-backward`}
icon="chevron"
buttonStyle="icon-label"
onClick={() => moveRow(positionIndex, positionIndex - 1)}
removeIconBorder
/>
<div className={`${baseClass}__border-wrap`}>
<Button
className={`${baseClass}__move-backward`}
icon="chevron"
buttonStyle="icon-label"
onClick={() => moveRow(positionIndex, positionIndex - 1)}
removeIconBorder
/>
<div className={`${baseClass}__current-position`}>{adjustedIndex >= 10 ? adjustedIndex : `0${adjustedIndex}`}</div>
<div className={`${baseClass}__current-position`}>{adjustedIndex >= 10 ? adjustedIndex : `0${adjustedIndex}`}</div>
<Button
className={`${baseClass}__move-forward`}
icon="chevron"
buttonStyle="icon-label"
onClick={() => moveRow(positionIndex, positionIndex + 1)}
removeIconBorder
/>
<Button
className={`${baseClass}__move-forward`}
icon="chevron"
buttonStyle="icon-label"
onClick={() => moveRow(positionIndex, positionIndex + 1)}
removeIconBorder
/>
</div>
</div>
);
};

View File

@@ -5,23 +5,33 @@
flex-direction: column;
align-items: center;
justify-content: center;
padding: base(.5) base(.5) base(.5) 0;
margin-right: base(.75);
padding: base(.5) base(.75) 0 0;
margin-bottom: base(1);
border-right: $style-stroke-width solid $color-light-gray;
position: absolute;
top: 0; right: 100%; bottom: 0;
&__border-wrap {
display: flex;
flex-direction: column;
justify-content: center;
box-shadow: #{$style-stroke-width-s} 0px 0px 0px $color-light-gray;
padding-right: base(.5);
height: 100%;
}
&__move-backward {
transform: rotate(.5turn);
margin: 0 0 base(.25);
opacity: 0;
}
&__move-forward {
margin: base(.25) 0 0;
opacity: 0;
}
&__current-position {
text-align: center;
color: $color-gray;
}
}

View File

@@ -1,4 +1,4 @@
import React, { useRef } from 'react';
import React, { useRef, useState } from 'react';
import PropTypes from 'prop-types';
import AnimateHeight from 'react-animate-height';
import { Draggable } from 'react-beautiful-dnd';
@@ -32,6 +32,7 @@ const DraggableSection = (props) => {
} = props;
const draggableRef = useRef(null);
const [isHovered, setIsHovered] = useState(false);
const handleCollapseClick = () => {
draggableRef.current.focus();
@@ -45,6 +46,7 @@ const DraggableSection = (props) => {
const classes = [
baseClass,
draggableIsOpen && 'is-open',
isHovered && 'is-hovered',
].filter(Boolean).join(' ');
return (
@@ -57,6 +59,8 @@ const DraggableSection = (props) => {
<div
ref={providedDrag.innerRef}
className={classes}
onMouseEnter={() => setIsHovered(true)}
onMouseLeave={() => setIsHovered(false)}
{...providedDrag.draggableProps}
>
@@ -87,6 +91,7 @@ const DraggableSection = (props) => {
<ActionHandle
removeRow={removeRow}
addRow={addRow}
singularLabel={singularLabel}
/>
{/* <AnimateHeight
className={`${baseClass}__content`}

View File

@@ -8,9 +8,27 @@
width: 100%;
}
&:hover {
.position-handle {
border-right: $style-stroke-width-m solid $color-dark-gray;
&.is-hovered {
> .position-handle {
.position-handle__border-wrap {
box-shadow: #{$style-stroke-width-m} 0px 0px 0px $color-dark-gray;
}
.position-handle__move-forward,
.position-handle__move-backward {
opacity: 1;
}
.position-handle__current-position {
color: $color-dark-gray;
}
}
> .action-handle {
.action-handle__add-row,
.action-handle__remove-row {
opacity: 1;
}
}
}
}