diff --git a/src/js/common/dom.js b/src/js/common/dom.js index 213b80c5..76a7e4de 100644 --- a/src/js/common/dom.js +++ b/src/js/common/dom.js @@ -703,7 +703,7 @@ class DOM { removeEmpty = element => { const parent = element.parentElement const type = componentType(element) - const children = parent.getElementsByClassName(`formeo-${type}s`) + const children = parent.getElementsByClassName(`formeo-${type}`) this.remove(element) if (!children.length) { if (!this.isStage(parent)) { @@ -917,13 +917,13 @@ class DOM { return styleSheet.insertRule(`${selector} { ${propStr} }`, rulesLength) } } - btnTemplate = ({ content, title }) => ({ + btnTemplate = ({ title = '', ...rest }) => ({ tag: 'button', attrs: { type: 'button', title, }, - content, + ...rest, }) isControls = node => componentType(node) === CONTROL_GROUP_CLASSNAME diff --git a/src/js/common/utils.js b/src/js/common/utils.js index da41c578..01a7d5ca 100644 --- a/src/js/common/utils.js +++ b/src/js/common/utils.js @@ -74,7 +74,7 @@ export const closestFtype = el => { * @return {String} component type or undefined */ export const componentType = node => { - const classMatch = node.className.match(COMPONENT_TYPE_CLASSNAMES_REGEXP) + const classMatch = node.className && node.className.match(COMPONENT_TYPE_CLASSNAMES_REGEXP) return classMatch && COMPONENT_TYPE_CLASSNAMES_LOOKUP[classMatch[0]] } diff --git a/src/js/components/columns/column.js b/src/js/components/columns/column.js index d96d961c..4db43cfa 100644 --- a/src/js/components/columns/column.js +++ b/src/js/components/columns/column.js @@ -13,7 +13,7 @@ const DEFAULT_DATA = () => width: '100%', }, children: [], - className: 'f-column', + className: COLUMN_CLASSNAME, }) const DOM_CONFIGS = { diff --git a/src/js/components/controls/form/textarea.js b/src/js/components/controls/form/textarea.js index ab267ca0..d27cecc4 100644 --- a/src/js/components/controls/form/textarea.js +++ b/src/js/components/controls/form/textarea.js @@ -19,7 +19,7 @@ class TextAreaControl extends Control { // let endHeight = target.style.height; // if (startHeight !== endHeight) { // //eslint-disable-next-line - // let fieldId = closest(target, '.stage-fields').id; + // let fieldId = closest(target, '.stage-field').id; // const field = d.fields.get(fieldId).instance; // field.addAttribute('style', `height: ${endHeight}`); // } diff --git a/src/js/components/rows/row.js b/src/js/components/rows/row.js index f7e470ff..22ee22a3 100644 --- a/src/js/components/rows/row.js +++ b/src/js/components/rows/row.js @@ -16,7 +16,7 @@ const DEFAULT_DATA = () => inputGroup: false, // is repeatable input-group? }, children: [], - className: ['f-row'], + className: [ROW_CLASSNAME], }) /** diff --git a/src/js/constants.js b/src/js/constants.js index acb18e58..5d2eb0a0 100644 --- a/src/js/constants.js +++ b/src/js/constants.js @@ -12,9 +12,9 @@ export const FALLBACK_SVG_SPRITE = 'https://draggable.github.io/formeo/assets/im export const CONTROL_GROUP_CLASSNAME = 'control-group' export const STAGE_CLASSNAME = `${PACKAGE_NAME}-stage` -export const ROW_CLASSNAME = `${PACKAGE_NAME}-rows` -export const COLUMN_CLASSNAME = `${PACKAGE_NAME}-columns` -export const FIELD_CLASSNAME = `${PACKAGE_NAME}-fields` +export const ROW_CLASSNAME = `${PACKAGE_NAME}-row` +export const COLUMN_CLASSNAME = `${PACKAGE_NAME}-column` +export const FIELD_CLASSNAME = `${PACKAGE_NAME}-field` export const CHILD_CLASSNAME_MAP = new Map([ [STAGE_CLASSNAME, ROW_CLASSNAME], diff --git a/src/js/renderer.js b/src/js/renderer.js index 1dac501e..ca4f37d8 100644 --- a/src/js/renderer.js +++ b/src/js/renderer.js @@ -1,6 +1,7 @@ import isEqual from 'lodash/isEqual' import dom from './common/dom' import { uuid, isAddress, isExternalAddress } from './common/utils' +import { STAGE_CLASSNAME } from './constants' const processOptions = ({ container, ...opts }) => { const processedOptions = { @@ -13,16 +14,30 @@ const processOptions = ({ container, ...opts }) => { const baseId = id => id.replace(/^f-/, '') const recursiveNewIds = elem => { + elem.setAttribute('id', `f-${uuid()}`) const elems = elem.querySelectorAll('*') const elemsLength = elems.length for (let i = 0; i < elemsLength; i++) { const element = elems[i] if (element.id) { - element.setAttribute('id', uuid()) + element.setAttribute('id', `f-${uuid()}`) } } } +const createRemoveButton = () => + dom.render( + dom.btnTemplate({ + className: 'remove-input-group', + children: dom.icon('remove'), + action: { + mouseover: ({ target }) => target.parentElement.classList.add('will-remove'), + mouseleave: ({ target }) => target.parentElement.classList.remove('will-remove'), + click: ({ target }) => target.parentElement.remove(), + }, + }) + ) + const addButton = () => dom.render({ tag: 'button', @@ -35,27 +50,14 @@ const addButton = () => click: e => { const fInputGroup = e.target.parentElement const elem = e.target.previousSibling.cloneNode(true) - elem.id = uuid() - dom.remove(elem.querySelector('.remove-input-group')) recursiveNewIds(elem) + const existingRemoveButton = elem.querySelector('.remove-input-group') + if (existingRemoveButton) { + dom.remove(existingRemoveButton) + } fInputGroup.insertBefore(elem, fInputGroup.lastChild) - elem.appendChild(removeButton()) - }, - }, - }) - -const removeButton = () => - dom.render({ - tag: 'button', - className: 'remove-input-group', - children: dom.icon('remove'), - action: { - mouseover: ({ target }) => target.parentElement.classList.add('will-remove'), - mouseleave: ({ target }) => target.parentElement.classList.remove('will-remove'), - click: ({ target }) => { - const currentInputGroup = target.parentElement - dom.remove(currentInputGroup) + elem.appendChild(createRemoveButton()) }, }, }) @@ -122,7 +124,7 @@ export default class FormeoRenderer { return this.makeInputGroup(row) } - return dom.render(row) + return row }) processColumns = rowId => { @@ -154,21 +156,16 @@ export default class FormeoRenderer { * @param {Object} componentData * @return {NodeElement} inputGroup-ified component */ - makeInputGroup = data => { - data.children.push(removeButton()) - const inputGroupWrap = { - id: uuid(), - className: 'f-input-group-wrap', - children: [data, addButton()], - } - - return dom.render(inputGroupWrap) - } + makeInputGroup = data => ({ + id: uuid(), + className: 'f-input-group-wrap', + children: [data, addButton()], + }) get processedData() { return Object.values(this.form.stages).map(stage => { stage.children = this.processRows(stage.id) - stage.className = 'f-stage' + stage.className = STAGE_CLASSNAME return dom.render(stage) }) } diff --git a/src/sass/_render.scss b/src/sass/_render.scss index 5a99058d..8f19a2b8 100644 --- a/src/sass/_render.scss +++ b/src/sass/_render.scss @@ -1,10 +1,10 @@ -.f-row, -.f-column, -.f-field { +.formeo-row, +.formeo-column, +.formeo-field { position: relative; } -.f-row { +.formeo-row { margin-bottom: 1em; flex-direction: row; justify-content: flex-start; @@ -17,6 +17,10 @@ transition: background-color 200ms; padding: space(); + &:last-child { + margin-bottom: 0; + } + &.will-remove { background-color: $remove-bg; box-shadow: 0 0 3px 1px $brand-error inset; @@ -25,9 +29,9 @@ .f-input-group-wrap { @include clearfix; - .f-row:first-of-type{ - .remove-input-group{ - display:none; + .formeo-row:first-of-type { + .remove-input-group { + display: none; } } } @@ -79,7 +83,7 @@ max-height: 100%; } -.f-column { +.formeo-column { padding: 0 space(); float: left; max-width: none; diff --git a/src/sass/base/rtl/_group-actions.scss b/src/sass/base/rtl/_group-actions.scss index a3ea761b..fb9cfa95 100644 --- a/src/sass/base/rtl/_group-actions.scss +++ b/src/sass/base/rtl/_group-actions.scss @@ -29,7 +29,7 @@ } } -.formeo-fields { +.formeo-field { &.hovering-field, &.editing-field { .field-actions { diff --git a/src/sass/base/rtl/_row.scss b/src/sass/base/rtl/_row.scss index eeb173d3..50d76f99 100644 --- a/src/sass/base/rtl/_row.scss +++ b/src/sass/base/rtl/_row.scss @@ -1,4 +1,4 @@ -.formeo-rows { +.formeo-row { &::before { border-bottom-left-radius: $border-radius; border-bottom-right-radius: 0; diff --git a/src/sass/components/_column.scss b/src/sass/components/_column.scss index f00530e5..3c094643 100644 --- a/src/sass/components/_column.scss +++ b/src/sass/components/_column.scss @@ -1,4 +1,4 @@ -.formeo-columns { +.formeo-column { transition: background-color 125ms ease-in-out, box-shadow 125ms, width 250ms; position: relative; background-color: $white; @@ -92,7 +92,7 @@ border-top-left-radius: 0; } - .formeo-fields { + .formeo-field { opacity: 0.5; } @@ -127,7 +127,7 @@ } .editing-row { - .formeo-columns, + .formeo-column, .empty { border-radius: $border-radius; height: 60px; @@ -137,7 +137,7 @@ min-height: 0; } - .formeo-fields { + .formeo-field { display: none; } diff --git a/src/sass/components/_field.scss b/src/sass/components/_field.scss index 9b93f658..4b977223 100644 --- a/src/sass/components/_field.scss +++ b/src/sass/components/_field.scss @@ -1,4 +1,4 @@ -.formeo-fields { +.formeo-field { min-height: $icon-size; position: relative; padding: space(); diff --git a/src/sass/components/_group-actions.scss b/src/sass/components/_group-actions.scss index 79c7b802..51773dcd 100644 --- a/src/sass/components/_group-actions.scss +++ b/src/sass/components/_group-actions.scss @@ -55,7 +55,7 @@ } } -.formeo-fields { +.formeo-field { &.hovering-field, &.editing-field { .field-actions { diff --git a/src/sass/components/_row.scss b/src/sass/components/_row.scss index ae60912f..2a770c38 100644 --- a/src/sass/components/_row.scss +++ b/src/sass/components/_row.scss @@ -1,4 +1,4 @@ -.formeo-rows { +.formeo-row { > .children { @extend %display-row; min-height: space(4); @@ -51,7 +51,7 @@ width: 100px; } - .formeo-columns { + .formeo-column { opacity: 0.5; } } @@ -65,14 +65,14 @@ } &.resizing-columns { - .formeo-columns { + .formeo-column { transition: none; } } &.editing-row { &.hovering-row { - .formeo-columns { + .formeo-column { opacity: 1; } } diff --git a/src/sass/components/_stage.scss b/src/sass/components/_stage.scss index 80255348..5475f2c0 100644 --- a/src/sass/components/_stage.scss +++ b/src/sass/components/_stage.scss @@ -35,12 +35,12 @@ } &.removing-all-fields { - .formeo-rows { + .formeo-row { transition: margin-top 250ms ease-in; } } - & > .formeo-fields { + & > .formeo-field { background-color: $white; } }