From dfd2af14995a1ee0ea76dfeafd9d1ce2b0381532 Mon Sep 17 00:00:00 2001 From: Jarrod Flesch Date: Fri, 27 Mar 2020 15:48:02 -0400 Subject: [PATCH] refactor: merges the FlexibleRow and RepeaterRow into a single DraggableSection component --- .../RepeaterRow => DraggableSection}/index.js | 48 ++++--- .../index.scss | 23 +++- .../field-types/Flexible/FlexibleRow/index.js | 125 ------------------ .../forms/field-types/Flexible/index.js | 6 +- .../Repeater/RepeaterRow/index.scss | 90 ------------- .../forms/field-types/Repeater/index.js | 40 +++--- .../forms/field-types/Repeater/index.scss | 2 + src/client/components/layout/Section/index.js | 38 +++--- .../components/layout/Section/index.scss | 19 ++- 9 files changed, 112 insertions(+), 279 deletions(-) rename src/client/components/forms/{field-types/Repeater/RepeaterRow => DraggableSection}/index.js (74%) rename src/client/components/forms/{field-types/Flexible/FlexibleRow => DraggableSection}/index.scss (76%) delete mode 100644 src/client/components/forms/field-types/Flexible/FlexibleRow/index.js delete mode 100644 src/client/components/forms/field-types/Repeater/RepeaterRow/index.scss diff --git a/src/client/components/forms/field-types/Repeater/RepeaterRow/index.js b/src/client/components/forms/DraggableSection/index.js similarity index 74% rename from src/client/components/forms/field-types/Repeater/RepeaterRow/index.js rename to src/client/components/forms/DraggableSection/index.js index 9b82743c5f..1763e5458c 100644 --- a/src/client/components/forms/field-types/Repeater/RepeaterRow/index.js +++ b/src/client/components/forms/DraggableSection/index.js @@ -3,16 +3,26 @@ import PropTypes from 'prop-types'; import AnimateHeight from 'react-animate-height'; import { Draggable } from 'react-beautiful-dnd'; -import RenderFields from '../../../RenderFields'; -import IconButton from '../../../../controls/IconButton'; +import RenderFields from '../RenderFields'; // eslint-disable-line import/no-cycle +import IconButton from '../../controls/IconButton'; import './index.scss'; -const baseClass = 'repeater-row'; +const baseClass = 'draggable-section'; + +const DraggableSection = (props) => { + const { + addRow, + removeRow, + rowIndex, + parentName, + renderFields, + defaultValue, + dispatchCollapsibleStates, + collapsibleStates, + singularName, + } = props; -const RepeaterRow = ({ - addRow, removeRow, rowIndex, parentName, fields, defaultValue, dispatchCollapsibleStates, collapsibleStates, -}) => { const handleCollapseClick = () => { dispatchCollapsibleStates({ type: 'UPDATE_COLLAPSIBLE_STATUS', @@ -34,12 +44,15 @@ const RepeaterRow = ({ >
- {`${rowIndex + 1 > 9 ? rowIndex + 1 : `0${rowIndex + 1}`}`} + {`${singularName} ${rowIndex + 1}`}
@@ -55,13 +68,6 @@ const RepeaterRow = ({ onClick={removeRow} size="small" /> - -
@@ -72,7 +78,7 @@ const RepeaterRow = ({ > { + fields={renderFields.map((field) => { const fieldName = `${parentName}.${rowIndex}.${field.name}`; return ({ ...field, @@ -89,22 +95,24 @@ const RepeaterRow = ({ ); }; -RepeaterRow.defaultProps = { +DraggableSection.defaultProps = { rowCount: null, defaultValue: null, collapsibleStates: [], + singularName: '', }; -RepeaterRow.propTypes = { +DraggableSection.propTypes = { addRow: PropTypes.func.isRequired, removeRow: PropTypes.func.isRequired, rowIndex: PropTypes.number.isRequired, parentName: PropTypes.string.isRequired, - fields: PropTypes.arrayOf(PropTypes.shape({})).isRequired, + singularName: PropTypes.string, + renderFields: PropTypes.arrayOf(PropTypes.shape({})).isRequired, rowCount: PropTypes.number, defaultValue: PropTypes.oneOfType([PropTypes.string, PropTypes.number, PropTypes.shape({})]), dispatchCollapsibleStates: PropTypes.func.isRequired, collapsibleStates: PropTypes.arrayOf(PropTypes.bool), }; -export default RepeaterRow; +export default DraggableSection; diff --git a/src/client/components/forms/field-types/Flexible/FlexibleRow/index.scss b/src/client/components/forms/DraggableSection/index.scss similarity index 76% rename from src/client/components/forms/field-types/Flexible/FlexibleRow/index.scss rename to src/client/components/forms/DraggableSection/index.scss index dbaa9483be..55692a7524 100644 --- a/src/client/components/forms/field-types/Flexible/FlexibleRow/index.scss +++ b/src/client/components/forms/DraggableSection/index.scss @@ -1,11 +1,17 @@ -@import '../../../../../scss/styles.scss'; +@import '../../../scss/styles.scss'; -.flexible-row { +.draggable-section { background: $light-gray; flex-direction: column; position: relative; margin-top: base(.5); + .field-type, + .missing-field { + padding-left: 0; + padding-right: 0; + } + &:hover { @include shadow-sm; } @@ -74,7 +80,18 @@ @include color-svg($primary); &:hover { - background: lighten($primary, 50%); + background: $primary; + @include color-svg($black); + } + } + + .icon-button--crossOut { + border-color: $black; + @include color-svg($black); + + &:hover { + background: $black; + @include color-svg(white); } } } diff --git a/src/client/components/forms/field-types/Flexible/FlexibleRow/index.js b/src/client/components/forms/field-types/Flexible/FlexibleRow/index.js deleted file mode 100644 index e7b01b5412..0000000000 --- a/src/client/components/forms/field-types/Flexible/FlexibleRow/index.js +++ /dev/null @@ -1,125 +0,0 @@ -import React from 'react'; -import PropTypes from 'prop-types'; -import AnimateHeight from 'react-animate-height'; -import { Draggable } from 'react-beautiful-dnd'; - -// eslint-disable-next-line import/no-cycle -import RenderFields from '../../../RenderFields'; -import IconButton from '../../../../controls/IconButton'; - -import './index.scss'; - -const baseClass = 'flexible-row'; - -const FlexibleRow = (props) => { - const { - addRow, - removeRow, - rowIndex, - parentName, - block, - defaultValue, - dispatchCollapsibleStates, - collapsibleStates, - } = props; - - const handleCollapseClick = () => { - dispatchCollapsibleStates({ - type: 'UPDATE_COLLAPSIBLE_STATUS', - collapsibleIndex: rowIndex, - }); - }; - - return ( - - {(providedDrag) => { - return ( -
-
-
- -
- {`${block.labels.singular} ${rowIndex + 1 > 9 ? rowIndex + 1 : `0${rowIndex + 1}`}`} -
- -
- - - - - - -
-
- - - { - const fieldName = `${parentName}.${rowIndex}.${field.name}`; - return ({ - ...field, - name: fieldName, - defaultValue: defaultValue?.[field.name], - }); - })} - /> - -
- ); - }} - - ); -}; - -FlexibleRow.defaultProps = { - defaultValue: null, - collapsibleStates: [], -}; - -FlexibleRow.propTypes = { - block: PropTypes.shape({ - labels: PropTypes.shape({ - singular: PropTypes.string, - }), - fields: PropTypes.arrayOf(PropTypes.shape({})).isRequired, - slug: PropTypes.string, - }).isRequired, - addRow: PropTypes.func.isRequired, - removeRow: PropTypes.func.isRequired, - rowIndex: PropTypes.number.isRequired, - parentName: PropTypes.string.isRequired, - fieldState: PropTypes.shape({}).isRequired, - defaultValue: PropTypes.oneOfType([PropTypes.string, PropTypes.number, PropTypes.shape({})]), - dispatchCollapsibleStates: PropTypes.func.isRequired, - collapsibleStates: PropTypes.arrayOf(PropTypes.bool), -}; - -export default FlexibleRow; diff --git a/src/client/components/forms/field-types/Flexible/index.js b/src/client/components/forms/field-types/Flexible/index.js index 7abd4a11e7..801ff39f67 100644 --- a/src/client/components/forms/field-types/Flexible/index.js +++ b/src/client/components/forms/field-types/Flexible/index.js @@ -7,9 +7,9 @@ import { ModalContext } from '@trbl/react-modal'; import FormContext from '../../Form/Context'; import Section from '../../../layout/Section'; -import FlexibleRow from './FlexibleRow'; // eslint-disable-line import/no-cycle import AddRowModal from './AddRowModal'; import collapsibleReducer from './reducer'; +import DraggableSection from '../../DraggableSection'; // eslint-disable-line import/no-cycle import './index.scss'; @@ -113,14 +113,14 @@ const Flexible = (props) => { const blockToRender = blocks.find(block => block.slug === blockType); return ( - openAddRowModal(rowIndex)} removeRow={() => removeRow(rowIndex)} rowIndex={rowIndex} fieldState={fieldState} - block={blockToRender} + renderFields={blockToRender.fields} defaultValue={defaultValue[rowIndex]} dispatchCollapsibleStates={dispatchCollapsibleStates} collapsibleStates={collapsibleStates} diff --git a/src/client/components/forms/field-types/Repeater/RepeaterRow/index.scss b/src/client/components/forms/field-types/Repeater/RepeaterRow/index.scss deleted file mode 100644 index c4ed968145..0000000000 --- a/src/client/components/forms/field-types/Repeater/RepeaterRow/index.scss +++ /dev/null @@ -1,90 +0,0 @@ -@import '../../../../../scss/styles.scss'; - -.repeater-row { - background: $light-gray; - flex-direction: column; - position: relative; - margin-top: base(.5); - - &:hover { - @include shadow-sm; - } - - &__collapse__icon { - &--open { - svg { - transform: rotate(90deg); - } - } - - &--closed { - svg { - transform: rotate(-90deg); - } - } - } - - &__header { - padding: base(.75) base(1); - display: flex; - align-items: center; - position: relative; - - &__drag-handle { - width: 100%; - height: 100%; - position: absolute; - left: 0; - z-index: 1; - } - - // elements above the drag handle - &__controls, - &__header__row-index { - position: relative; - z-index: 2; - } - - &__row-index { - font-family: $font-body; - font-size: base(.5); - } - - &__heading { - font-family: $font-body; - margin: 0; - font-size: base(.65); - } - - &__controls { - margin-left: auto; - - .btn { - margin-top: 0; - margin-bottom: 0; - } - - .icon-button--crossOut, - .icon-button--crosshair { - margin-right: base(.25); - } - - .icon-button--crosshair { - border-color: $primary; - @include color-svg($primary); - - &:hover { - background: lighten($primary, 50%); - } - } - } - } - - &__content { - box-shadow: inset 0px 1px 0px white; - - > div { - padding: base(.75) base(1); - } - } -} diff --git a/src/client/components/forms/field-types/Repeater/index.js b/src/client/components/forms/field-types/Repeater/index.js index a9d8ed1881..afc02dc78b 100644 --- a/src/client/components/forms/field-types/Repeater/index.js +++ b/src/client/components/forms/field-types/Repeater/index.js @@ -6,7 +6,7 @@ import { DragDropContext, Droppable } from 'react-beautiful-dnd'; import FormContext from '../../Form/Context'; import Section from '../../../layout/Section'; -import RepeaterRow from './RepeaterRow'; // eslint-disable-line import/no-cycle +import DraggableSection from '../../DraggableSection'; // eslint-disable-line import/no-cycle import collapsibleReducer from './reducer'; import './index.scss'; @@ -24,6 +24,7 @@ const Repeater = (props) => { name, fields, defaultValue, + singularName, } = props; const addRow = (rowIndex) => { @@ -82,7 +83,6 @@ const Repeater = (props) => {
addRow(0)} useAddRowButton @@ -94,22 +94,24 @@ const Repeater = (props) => { {...provided.droppableProps} > {rowCount !== 0 - && Array.from(Array(rowCount).keys()).map((_, rowIndex) => { - return ( - addRow(rowIndex)} - removeRow={() => removeRow(rowIndex)} - rowIndex={rowIndex} - fields={fields} - rowCount={rowCount} - defaultValue={defaultValue[rowIndex]} - dispatchCollapsibleStates={dispatchCollapsibleStates} - collapsibleStates={collapsibleStates} - /> - ); - }) + && Array.from(Array(rowCount).keys()).map((_, rowIndex) => { + return ( + addRow(rowIndex)} + removeRow={() => removeRow(rowIndex)} + rowIndex={rowIndex} + fieldState={fieldState} + renderFields={fields} + rowCount={rowCount} + defaultValue={defaultValue[rowIndex]} + dispatchCollapsibleStates={dispatchCollapsibleStates} + collapsibleStates={collapsibleStates} + /> + ); + }) } {provided.placeholder}
@@ -124,6 +126,7 @@ const Repeater = (props) => { Repeater.defaultProps = { label: '', + singularName: '', defaultValue: [], }; @@ -135,6 +138,7 @@ Repeater.propTypes = { PropTypes.shape({}), ).isRequired, label: PropTypes.string, + singularName: PropTypes.string, name: PropTypes.string.isRequired, }; diff --git a/src/client/components/forms/field-types/Repeater/index.scss b/src/client/components/forms/field-types/Repeater/index.scss index 62f8e60c0b..e315eca647 100644 --- a/src/client/components/forms/field-types/Repeater/index.scss +++ b/src/client/components/forms/field-types/Repeater/index.scss @@ -1,3 +1,5 @@ +@import '../../../../scss/styles.scss'; + .field-type.repeater { background: white; } diff --git a/src/client/components/layout/Section/index.js b/src/client/components/layout/Section/index.js index 1577e31899..761890841e 100644 --- a/src/client/components/layout/Section/index.js +++ b/src/client/components/layout/Section/index.js @@ -4,6 +4,7 @@ import AnimateHeight from 'react-animate-height'; import './index.scss'; import IconButton from '../../controls/IconButton'; +import Button from '../../controls/Button'; const baseClass = 'section'; @@ -28,25 +29,13 @@ const Section = (props) => {
{heading && ( -
+
setIsSectionOpen(state => !state)} + role="button" + tabIndex={0} + >

{heading}

-
- {(rowCount === 0 && useAddRowButton) - && ( - addInitialRow()} - /> - )} - setIsSectionOpen(state => !state)} - /> -
)} {children @@ -54,8 +43,19 @@ const Section = (props) => { + {(rowCount === 0 && useAddRowButton) + && ( +
+ +
+ )} {children}
)} diff --git a/src/client/components/layout/Section/index.scss b/src/client/components/layout/Section/index.scss index 017bd6e5c6..848350554f 100644 --- a/src/client/components/layout/Section/index.scss +++ b/src/client/components/layout/Section/index.scss @@ -3,18 +3,35 @@ section.section { @include shadow; margin: base(1) 0; + transition: 300ms ease; - header { + &:hover { + box-shadow: 0 22px 65px rgba(0,0,0,.15); + } + + .section__collapsible-header { border-bottom: 1px solid $light-gray; display: flex; align-items: center; @include pad; + outline: 0; + + &:hover { + cursor: pointer; + } * { margin-bottom: 0; } } + .section__add-button-wrap { + .btn { + margin: 0; + margin-top: base(.5); + } + } + &__content { display: flex; flex-wrap: wrap;