adjusts the group styles and refactors how the block panels are composed

This commit is contained in:
Jarrod Flesch
2020-07-28 01:13:33 -04:00
parent 4d99594021
commit c1814cbc3f
10 changed files with 281 additions and 162 deletions

View File

@@ -23,95 +23,89 @@ const ActionPanel = (props) => {
const classes = [
baseClass,
`${baseClass}--vertical-alignment-${verticalAlignment}`,
].filter(Boolean).join(' ');
return (
<div className={classes}>
<div className={`${baseClass}__controls-container`}>
<div className={`${baseClass}__controls`}>
<Popup
showOnHover
size="wide"
color="dark"
horizontalAlign="center"
buttonType="custom"
button={(
<Button
className={`${baseClass}__remove-row`}
round
buttonStyle="none"
icon="x"
iconPosition="left"
iconStyle="with-border"
onClick={removeRow}
/>
)}
>
Remove&nbsp;
{singularLabel}
</Popup>
{blockType === 'blocks'
? (
<Popup
buttonType="custom"
size="large"
horizontalAlign="right"
button={(
<Button
className={`${baseClass}__add-row`}
round
buttonStyle="none"
icon="plus"
iconPosition="left"
iconStyle="with-border"
/>
)}
render={({ close }) => (
<BlockSelector
blocks={blocks}
addRow={addRow}
addRowIndex={rowIndex}
close={close}
parentIsHovered={isHovered}
watchParentHover
/>
)}
/>
)
: (
<Popup
showOnHover
size="wide"
color="dark"
horizontalAlign="center"
horizontalAlign="right"
buttonType="custom"
button={(
<Button
className={`${baseClass}__remove-row`}
className={`${baseClass}__add-row`}
round
buttonStyle="none"
icon="x"
icon="plus"
iconPosition="left"
iconStyle="with-border"
onClick={removeRow}
onClick={addRow}
/>
)}
>
Remove&nbsp;
Add&nbsp;
{singularLabel}
</Popup>
{blockType === 'blocks'
? (
<Popup
buttonType="custom"
size="large"
horizontalAlign="right"
button={(
<Button
className={`${baseClass}__add-row`}
round
buttonStyle="none"
icon="plus"
iconPosition="left"
iconStyle="with-border"
/>
)}
render={({ close }) => (
<BlockSelector
blocks={blocks}
addRow={addRow}
addRowIndex={rowIndex}
close={close}
parentIsHovered={isHovered}
watchParentHover
/>
)}
/>
)
: (
<Popup
showOnHover
size="wide"
color="dark"
horizontalAlign="right"
buttonType="custom"
button={(
<Button
className={`${baseClass}__add-row`}
round
buttonStyle="none"
icon="plus"
iconPosition="left"
iconStyle="with-border"
onClick={addRow}
/>
)}
>
Add&nbsp;
{singularLabel}
</Popup>
)}
</div>
</div>
)}
</div>
);
};
ActionPanel.defaultProps = {
singularLabel: 'Row',
verticalAlignment: 'center',
blockType: null,
isHovered: false,
blocks: [],
@@ -125,7 +119,6 @@ ActionPanel.propTypes = {
blocks: PropTypes.arrayOf(
PropTypes.shape({}),
),
verticalAlignment: PropTypes.oneOf(['top', 'center', 'sticky']),
isHovered: PropTypes.bool,
rowIndex: PropTypes.number.isRequired,
};

View File

@@ -1,14 +1,11 @@
@import '../../../../scss/styles';
.action-panel {
padding: 0 base(.5);
padding-left: base(.75);
margin-bottom: base(1);
&:hover {
z-index: $z-nav;
}
<<<<<<< Updated upstream
&__controls-container {
position: relative;
height: 100%;
@@ -38,6 +35,8 @@
}
}
=======
>>>>>>> Stashed changes
&__remove-row {
margin: 0 0 base(.3);
}
@@ -45,17 +44,4 @@
&__add-row {
margin: base(.3) 0 0;
}
@include mid-break {
&__controls {
opacity: 1;
visibility: visible;
}
&--vertical-alignment-sticky {
.action-panel__controls {
top: 100px;
}
}
}
}

View File

@@ -2,64 +2,53 @@ import React from 'react';
import PropTypes from 'prop-types';
import Button from '../../../elements/Button';
import RenderFieldGutter from '../../RenderFieldGutter';
import './index.scss';
const baseClass = 'position-panel';
const PositionPanel = (props) => {
const {
dragHandleProps, moveRow, positionIndex, verticalAlignment, rowCount,
} = props;
const { moveRow, positionIndex, rowCount } = props;
const adjustedIndex = positionIndex + 1;
const classes = [
baseClass,
`${baseClass}--vertical-alignment-${verticalAlignment}`,
].filter(Boolean).join(' ');
return (
<div
className={classes}
{...dragHandleProps}
>
<div className={`${baseClass}__controls-container`}>
<div className={`${baseClass}__controls`}>
<div className={classes}>
<Button
className={`${baseClass}__move-backward ${positionIndex === 0 ? 'first-row' : ''}`}
buttonStyle="none"
icon="chevron"
round
onClick={() => moveRow(positionIndex, positionIndex - 1)}
/>
<Button
className={`${baseClass}__move-backward ${positionIndex === 0 ? 'first-row' : ''}`}
buttonStyle="none"
icon="chevron"
round
onClick={() => moveRow(positionIndex, positionIndex - 1)}
/>
{(adjustedIndex && typeof positionIndex === 'number') &&
<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 ${(positionIndex === rowCount - 1) ? 'last-row' : ''}`}
buttonStyle="none"
icon="chevron"
round
onClick={() => moveRow(positionIndex, positionIndex + 1)}
/>
</div>
</div>
<Button
className={`${baseClass}__move-forward ${(positionIndex === rowCount - 1) ? 'last-row' : ''}`}
buttonStyle="none"
icon="chevron"
round
onClick={() => moveRow(positionIndex, positionIndex + 1)}
/>
</div>
);
};
PositionPanel.defaultProps = {
verticalAlignment: 'center',
positionIndex: null,
};
PositionPanel.propTypes = {
dragHandleProps: PropTypes.shape({}).isRequired,
positionIndex: PropTypes.number.isRequired,
positionIndex: PropTypes.number,
moveRow: PropTypes.func.isRequired,
verticalAlignment: PropTypes.oneOf(['top', 'center', 'sticky']),
rowCount: PropTypes.number.isRequired,
};

View File

@@ -1,8 +1,7 @@
@import '../../../../scss/styles';
$controls-top-adjustment: base(.1);
.position-panel {
<<<<<<< Updated upstream
padding-right: base(1);
margin-bottom: base(1);
@@ -34,6 +33,8 @@ $controls-top-adjustment: base(.1);
}
}
=======
>>>>>>> Stashed changes
&__move-backward {
transform: rotate(.5turn);
margin: 0;
@@ -51,24 +52,14 @@ $controls-top-adjustment: base(.1);
}
@include large-break {
padding-right: base(1);
padding-right: 0;
&__controls {
padding-right: base(.75);
}
}
}
// External scopes
.field-type.blocks {
.position-panel {
&__controls-container {
min-height: calc(100% + #{$controls-top-adjustment});
}
&__controls {
margin-top: - $controls-top-adjustment;
}
@include mid-break {
padding-right: 0;
}
}

View File

@@ -6,10 +6,12 @@ import { Draggable } from 'react-beautiful-dnd';
import ActionPanel from './ActionPanel';
import SectionTitle from './SectionTitle';
import PositionPanel from './PositionPanel';
import Button from '../../elements/Button';
import RenderFieldGutter from '../RenderFieldGutter';
import RenderFields from '../RenderFields';
import './index.scss';
import Button from '../../elements/Button';
const baseClass = 'draggable-section';
@@ -58,13 +60,17 @@ const DraggableSection = (props) => {
>
<div className={`${baseClass}__content-wrapper`}>
<PositionPanel
<RenderFieldGutter
variant="left"
dragHandleProps={providedDrag.dragHandleProps}
moveRow={moveRow}
rowCount={rowCount}
positionIndex={rowIndex}
verticalAlignment={positionPanelVerticalAlignment}
/>
>
<PositionPanel
moveRow={moveRow}
rowCount={rowCount}
positionIndex={rowIndex}
verticalAlignment={positionPanelVerticalAlignment}
/>
</RenderFieldGutter>
<div className={`${baseClass}__render-fields-wrapper`}>
@@ -102,15 +108,17 @@ const DraggableSection = (props) => {
</AnimateHeight>
</div>
<ActionPanel
rowIndex={rowIndex}
addRow={addRow}
removeRow={removeRow}
singularLabel={singularLabel}
verticalAlignment={actionPanelVerticalAlignment}
isHovered={isHovered}
{...props}
/>
<RenderFieldGutter variant="right" className="actions" dragHandleProps={providedDrag.dragHandleProps}>
<ActionPanel
rowIndex={rowIndex}
addRow={addRow}
removeRow={removeRow}
singularLabel={singularLabel}
verticalAlignment={actionPanelVerticalAlignment}
isHovered={isHovered}
{...props}
/>
</RenderFieldGutter>
</div>
</div>
)}

View File

@@ -5,26 +5,26 @@
//////////////////////
@mixin relatively-position-panels {
.position-panel {
.render-field-gutter {
position: relative;
right: 0;
}
.action-panel {
.render-field-gutter.actions {
position: relative;
left: 0;
}
}
@mixin absolutely-position-panels {
.position-panel {
.render-field-gutter {
position: absolute;
top: 0; right: 100%; bottom: 0;
}
.action-panel {
.render-field-gutter.actions {
position: absolute;
top: 0; bottom: 0; left: 100%;
top: 0; bottom: 0; left: 100%; right: unset;
}
}
@@ -58,6 +58,10 @@
margin: 0 0 0 auto;
transform: rotate(.5turn);
.btn__icon {
background-color: white;
}
&--is-closed {
transform: rotate(0turn);
}
@@ -69,8 +73,8 @@
}
&.is-hovered > div {
> .position-panel {
.position-panel__controls-container {
> .render-field-gutter {
.render-field-gutter__content-container:not(&.actions) {
box-shadow: #{$style-stroke-width-m} 0px 0px 0px $color-dark-gray;
}
@@ -146,6 +150,14 @@
@include relatively-position-panels();
}
.field-type.group {
@include absolutely-position-panels();
@include mid-break {
@include relatively-position-panels();
}
}
// remove padding above array rows to level
// the line with the top of the input label
.field-type.array {

View File

@@ -0,0 +1,42 @@
import React from 'react';
import PropTypes from 'prop-types';
import './index.scss';
const baseClass = 'render-field-gutter';
const RenderFieldGutter = (props) => {
const { children, variant, verticalAlignment, className, dragHandleProps } = props;
const classes = [
baseClass,
`${baseClass}--${variant}`,
`${baseClass}--v-align-${verticalAlignment}`,
className && className
].filter(Boolean).join(' ');
return (
<div className={classes} {...dragHandleProps}>
<div className={`${baseClass}__content-container`}>
<div className={`${baseClass}__content`}>
{children}
</div>
</div>
</div>
);
}
const { oneOf } = PropTypes;
RenderFieldGutter.defaultProps = {
variant: 'left',
verticalAlignment: 'sticky',
dragHandleProps: {},
}
RenderFieldGutter.propTypes = {
variant: oneOf(['left', 'right']),
verticalAlignment: PropTypes.oneOf(['top', 'center', 'sticky']),
}
export default RenderFieldGutter;

View File

@@ -0,0 +1,72 @@
@import '../../../scss/styles.scss';
$controls-top-adjustment: base(.1);
.render-field-gutter {
padding-right: base(1.25);
margin-bottom: base(1);
&--right {
padding-right: 0;
padding-left: base(1.25);
.render-field-gutter__content {
margin-bottom: base(1);
}
.render-field-gutter__content-container {
padding-right: 0;
box-shadow: none;
}
}
&--v-align-top {
.render-field-gutter__content {
justify-content: flex-start;
}
}
&--v-align-sticky {
.render-field-gutter__content {
position: sticky;
top: $top-header-offset;
height: unset;
}
}
&__content-container {
padding-right: base(.75);
position: relative;
min-height: 100%;
box-shadow: #{$style-stroke-width-s} 0px 0px 0px $color-light-gray;
}
&__content {
display: flex;
flex-direction: column;
justify-content: center;
height: 100%;
}
@include mid-break {
padding-right: base(1);
&--right {
padding-right: 0;
}
}
}
// External scopes
.field-type.blocks {
.render-field-gutter {
&__content-container {
min-height: calc(100% + #{$controls-top-adjustment});
}
&__content {
margin-top: - $controls-top-adjustment;
}
}
}

View File

@@ -2,9 +2,12 @@ import React from 'react';
import PropTypes from 'prop-types';
import RenderFields, { useRenderedFields } from '../../RenderFields';
import withCondition from '../../withCondition';
import RenderFieldGutter from '../../RenderFieldGutter';
import './index.scss';
const baseClass = 'group';
const Group = (props) => {
const {
label, fields, name, path: pathFromProps, fieldTypes,
@@ -16,15 +19,19 @@ const Group = (props) => {
return (
<div className="field-type group">
<h3>{label}</h3>
<RenderFields
fieldTypes={fieldTypes}
customComponentsPath={`${customComponentsPath}${name}.fields.`}
fieldSchema={fields.map((subField) => ({
...subField,
path: `${path}${subField.name ? `.${subField.name}` : ''}`,
}))}
/>
<h3 className={`${baseClass}__title`}>{label}</h3>
<div className={`${baseClass}__fields-wrapper`}>
<RenderFieldGutter />
<RenderFields
fieldTypes={fieldTypes}
customComponentsPath={`${customComponentsPath}${name}.fields.`}
fieldSchema={fields.map((subField) => ({
...subField,
path: `${path}${subField.name ? `.${subField.name}` : ''}`,
}))}
/>
</div>
</div>
);
};

View File

@@ -1,3 +1,22 @@
.field-group {
@import '../../../../scss/styles.scss';
.group {
&__fields-wrapper {
position: relative;
}
.render-fields {
width: 100%;
}
@include mid-break {
&__fields-wrapper {
display: flex;
}
.render-field-gutter__content-container {
padding-right: 0;
padding-left: 2px;
}
}
}