styles repeater buttons, remove and duplicate
This commit is contained in:
@@ -32,6 +32,18 @@
|
||||
}
|
||||
}
|
||||
|
||||
&.btn-error {
|
||||
border: $stroke-width solid $error;
|
||||
color: $error;
|
||||
background: none;
|
||||
|
||||
&:hover {
|
||||
background: lighten($error, 22.5%);
|
||||
border: $stroke-width solid $error;
|
||||
color: $black;
|
||||
}
|
||||
}
|
||||
|
||||
&.btn-small {
|
||||
padding: base(0) base(.25) base(.04);
|
||||
border-radius: 3px;
|
||||
|
||||
27
src/client/components/controls/RepeatFieldButton/index.js
Normal file
27
src/client/components/controls/RepeatFieldButton/index.js
Normal file
@@ -0,0 +1,27 @@
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
import './index.scss';
|
||||
import Button from '../Button';
|
||||
import Crosshair from '../../graphics/Crosshair';
|
||||
|
||||
const baseClass = 'repeat-field-button';
|
||||
|
||||
const RepeatFieldButton = ({ onClick }) => {
|
||||
return (
|
||||
<div className={baseClass}>
|
||||
<Button
|
||||
onClick={onClick}
|
||||
type="secondary"
|
||||
>
|
||||
<Crosshair />
|
||||
</Button>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
RepeatFieldButton.propTypes = {
|
||||
onClick: PropTypes.func.isRequired,
|
||||
};
|
||||
|
||||
export default RepeatFieldButton;
|
||||
28
src/client/components/controls/RepeatFieldButton/index.scss
Normal file
28
src/client/components/controls/RepeatFieldButton/index.scss
Normal file
@@ -0,0 +1,28 @@
|
||||
@import '../../../scss/styles.scss';
|
||||
|
||||
.repeat-field-button {
|
||||
width: calc(100% + #{base(2)});
|
||||
margin-left: base(-1);
|
||||
padding: base(1) 0;
|
||||
position: relative;
|
||||
|
||||
&:before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
background: $light-gray;
|
||||
height: 2px;
|
||||
width: 100%;
|
||||
left: 0;
|
||||
bottom: 50%;
|
||||
}
|
||||
|
||||
.btn {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
background: white;
|
||||
margin: 0;
|
||||
padding: base(.25) base(.75);
|
||||
}
|
||||
}
|
||||
@@ -101,7 +101,7 @@ const Form = (props) => {
|
||||
});
|
||||
|
||||
dispatchFields({
|
||||
type: 'replace',
|
||||
type,
|
||||
value: {
|
||||
...stateWithoutFields,
|
||||
...reindexedRows,
|
||||
|
||||
@@ -4,9 +4,15 @@ import PropTypes from 'prop-types';
|
||||
import FormContext from '../../Form/Context';
|
||||
import Section from '../../../layout/Section';
|
||||
import RenderFields from '../../RenderFields';
|
||||
import RepeatFieldButton from '../../../controls/RepeatFieldButton';
|
||||
import Button from '../../../controls/Button';
|
||||
import X from '../../../graphics/X';
|
||||
|
||||
|
||||
import './index.scss';
|
||||
|
||||
const baseClass = 'field-repeater';
|
||||
|
||||
const Repeater = (props) => {
|
||||
const formContext = useContext(FormContext);
|
||||
const { adjustRows } = formContext;
|
||||
@@ -47,36 +53,37 @@ const Repeater = (props) => {
|
||||
const iterableInternalRowCount = Array.from(Array(internalRowCount).keys());
|
||||
|
||||
return (
|
||||
<div className="field-repeater">
|
||||
<Section heading={label}>
|
||||
<div className={baseClass}>
|
||||
<Section
|
||||
heading={label}
|
||||
className="repeater"
|
||||
>
|
||||
|
||||
{iterableInternalRowCount.map((_, rowIndex) => {
|
||||
return (
|
||||
<React.Fragment key={rowIndex}>
|
||||
<h2>{`Repeater Item ${rowIndex}`}</h2>
|
||||
<div className={`${baseClass}__section-inner`}>
|
||||
<Button
|
||||
className="delete"
|
||||
onClick={() => removeRow({ rowIndex })}
|
||||
type="error"
|
||||
>
|
||||
<X />
|
||||
</Button>
|
||||
<h2>{`${label} - Item ${rowIndex}`}</h2>
|
||||
|
||||
<RenderFields
|
||||
fields={fields.map((field) => {
|
||||
return ({
|
||||
...field,
|
||||
name: `${name}.${rowIndex}.${field.name}`,
|
||||
defaultValue: initialRows[rowIndex] ? initialRows[rowIndex][field.name] : null,
|
||||
});
|
||||
})}
|
||||
/>
|
||||
<RenderFields
|
||||
fields={fields.map((field) => {
|
||||
return ({
|
||||
...field,
|
||||
name: `${name}.${rowIndex}.${field.name}`,
|
||||
defaultValue: initialRows[rowIndex] ? initialRows[rowIndex][field.name] : null,
|
||||
});
|
||||
})}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<button
|
||||
onClick={() => addNewRow({ rowIndex })}
|
||||
type="button"
|
||||
>
|
||||
{`Add after ${rowIndex}`}
|
||||
</button>
|
||||
<button
|
||||
onClick={() => removeRow({ rowIndex })}
|
||||
type="button"
|
||||
>
|
||||
{`Remove ${rowIndex}`}
|
||||
</button>
|
||||
<RepeatFieldButton onClick={() => addNewRow({ rowIndex })} />
|
||||
</React.Fragment>
|
||||
);
|
||||
})}
|
||||
|
||||
@@ -1,3 +1,57 @@
|
||||
@import '../../../../scss/styles.scss';
|
||||
|
||||
.field-repeater {
|
||||
// background: red;
|
||||
.content {
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
&__section-inner {
|
||||
padding: base(1);
|
||||
margin-right: base(1);
|
||||
background: $light-gray;
|
||||
flex-direction: column;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.repeat-field-button {
|
||||
.btn {
|
||||
@include color-svg($primary);
|
||||
height: 30px;
|
||||
width: 30px;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
padding: 0;
|
||||
transform: translate(-50%, -50%);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
|
||||
&:hover {
|
||||
@include color-svg(white);
|
||||
}
|
||||
|
||||
.crosshair {
|
||||
padding: 3px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.btn.delete {
|
||||
position: absolute;
|
||||
height: 30px;
|
||||
width: 30px;
|
||||
margin: 0;
|
||||
top: base(1);
|
||||
right: base(1);
|
||||
padding: 3px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
|
||||
.x {
|
||||
@include color-svg($error);
|
||||
height: 15px;
|
||||
width: 15px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
45
src/client/components/graphics/Crosshair/index.js
Normal file
45
src/client/components/graphics/Crosshair/index.js
Normal file
@@ -0,0 +1,45 @@
|
||||
import React from 'react';
|
||||
|
||||
const Crosshair = () => {
|
||||
return (
|
||||
<svg
|
||||
width="20px"
|
||||
height="20px"
|
||||
viewBox="0 0 20 20"
|
||||
version="1.1"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
className="crosshair"
|
||||
>
|
||||
<g
|
||||
stroke="none"
|
||||
strokeWidth="1"
|
||||
fill="none"
|
||||
fillRule="evenodd"
|
||||
strokeLinecap="square"
|
||||
>
|
||||
<g
|
||||
className="stroke"
|
||||
transform="translate(-0.500000, -0.500000)"
|
||||
>
|
||||
<line
|
||||
x1="11"
|
||||
y1="1"
|
||||
x2="11"
|
||||
y2="20"
|
||||
id="Line"
|
||||
/>
|
||||
<line
|
||||
x1="10.5"
|
||||
y1="0.5"
|
||||
x2="10.5"
|
||||
y2="19.5"
|
||||
id="Line"
|
||||
transform="translate(10.500000, 10.000000) rotate(90.000000) translate(-10.500000, -10.000000) "
|
||||
/>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
);
|
||||
};
|
||||
|
||||
export default Crosshair;
|
||||
39
src/client/components/graphics/X/index.js
Normal file
39
src/client/components/graphics/X/index.js
Normal file
@@ -0,0 +1,39 @@
|
||||
import React from 'react';
|
||||
|
||||
import './index.scss';
|
||||
|
||||
const X = () => {
|
||||
return (
|
||||
<svg
|
||||
width="22px"
|
||||
height="20px"
|
||||
viewBox="0 0 22 20"
|
||||
version="1.1"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
className="x"
|
||||
>
|
||||
<g
|
||||
stroke="none"
|
||||
strokeWidth="2"
|
||||
fill="none"
|
||||
fillRule="evenodd"
|
||||
>
|
||||
<g
|
||||
className="stroke"
|
||||
transform="translate(1.000000, 0.000000)"
|
||||
>
|
||||
<path
|
||||
d="M0,0 C6.66666667,6.66666667 13.3333333,13.3333333 20,20"
|
||||
/>
|
||||
<path
|
||||
d="M0,0 C6.66666667,6.66666667 13.3333333,13.3333333 20,20"
|
||||
id="Path"
|
||||
transform="translate(10.000000, 10.000000) scale(-1, 1) translate(-10.000000, -10.000000) "
|
||||
/>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
);
|
||||
};
|
||||
|
||||
export default X;
|
||||
3
src/client/components/graphics/X/index.scss
Normal file
3
src/client/components/graphics/X/index.scss
Normal file
@@ -0,0 +1,3 @@
|
||||
.x {
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user