adjusts the group styles and refactors how the block panels are composed
This commit is contained in:
@@ -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
|
||||
{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
|
||||
Add
|
||||
{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
|
||||
{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,
|
||||
};
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
};
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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>
|
||||
)}
|
||||
|
||||
@@ -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 {
|
||||
|
||||
42
src/client/components/forms/RenderFieldGutter/index.js
Normal file
42
src/client/components/forms/RenderFieldGutter/index.js
Normal 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;
|
||||
72
src/client/components/forms/RenderFieldGutter/index.scss
Normal file
72
src/client/components/forms/RenderFieldGutter/index.scss
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user