diff --git a/src/AlignButtons/AlignButtons.jsx b/src/AlignButtons/AlignButtons.jsx new file mode 100644 index 0000000000000000000000000000000000000000..8a6ea9514e0b3b127b16d1804267b89eca130ea9 --- /dev/null +++ b/src/AlignButtons/AlignButtons.jsx @@ -0,0 +1,40 @@ +import {Button} from "@wordpress/components"; +function AlignButtons(props) { + + const {label, onChange} = props; + + const handleChange = function (newAlignment) { + if (onChange) { + onChange(newAlignment); + } + } + + return ( + <div className='fi-field-wrapper'> + <div className='fi-field-label-wrapper'> + <span className='fi-field-label'>{label}</span> + </div> + <div className='fi-field-buttons-wrapper fi-alignbuttons-wrapper'> + <Button + icon="editor-alignleft" + className="has-dashicons" + onClick={() => handleChange('left')} + /> + <Button + icon="editor-aligncenter" + className="has-dashicons" + onClick={() => handleChange('center')} + /> + <Button + icon="editor-alignright" + className="has-dashicons" + onClick={() => handleChange('right')} + /> + </div> + </div> + ); +} + +export default AlignButtons; + + diff --git a/src/BlockPlaceholders/BlockPlaceholders.jsx b/src/BlockPlaceholders/BlockPlaceholders.jsx new file mode 100644 index 0000000000000000000000000000000000000000..e47a2397f38ed50f2571cf714f9b73330ffb53df --- /dev/null +++ b/src/BlockPlaceholders/BlockPlaceholders.jsx @@ -0,0 +1,21 @@ +import {__} from "@wordpress/i18n"; +import {PanelBody} from "@wordpress/components"; +import Placeholder from "./Placeholder"; + +function BlockPlaceholders(props) { + const {placeholders,children} = props; + return ( + <PanelBody title={__('Placeholders', 'flexible-invoices-core')}> + { children && <p className='fi-placeholders-list-description'>{children}</p> } + { + placeholders.map((placeholder) => { + return <Placeholder label={placeholder.label}>{placeholder.description}</Placeholder> + }) + } + </PanelBody> + ); +} + +export default BlockPlaceholders; + + diff --git a/src/BlockPlaceholders/Placeholder.jsx b/src/BlockPlaceholders/Placeholder.jsx new file mode 100644 index 0000000000000000000000000000000000000000..ca2e902ac1e3aa4f74ea6c43e5de9b00717d9fa0 --- /dev/null +++ b/src/BlockPlaceholders/Placeholder.jsx @@ -0,0 +1,14 @@ +function Placeholder(props) { + const {label, children} = props; + return ( + <div> + <input type='text' disabled value={label}/> + <p className='fi-placeholders-list-description'>{children}</p> + <hr/> + </div> + ); +} + +export default Placeholder; + + diff --git a/src/ColorSelector/ColorSelector.jsx b/src/ColorSelector/ColorSelector.jsx new file mode 100644 index 0000000000000000000000000000000000000000..021c49710ed847df50667beae0b2b5118bb48fbf --- /dev/null +++ b/src/ColorSelector/ColorSelector.jsx @@ -0,0 +1,63 @@ +import {ColorPicker} from "@wordpress/components"; +import {useState} from "react"; + +function ColorSelector(props) { + + const {label, onChange, value, enableAlpha = true, returnFormat = 'rgb'} = props; + const [isPopupActive, setIsPopupActive] = useState(false); + + const handleColorChange = function (newColor) { + let color = newColor; + if (returnFormat === 'hex') { + color = newColor.hex; + } else if (returnFormat === 'hsv') { + color = newColor.hsv; + } else if (returnFormat === 'hsl') { + color = newColor.hsl; + } else if (returnFormat === 'rgb') { + if (enableAlpha === true) { + color = `rgba(${newColor.rgb.r}, ${newColor.rgb.g}, ${newColor.rgb.b}, ${newColor.rgb.a})`; + } else { + color = `rgb(${newColor.rgb.r}, ${newColor.rgb.g}, ${newColor.rgb.b})`; + } + } + + + onChange(color); + } + + return ( + <div className='fi-field-wrapper'> + <div className='fi-field-label-wrapper'> + <span className='fi-field-label'>{label}</span> + </div> + <div className='fi-field-buttons-wrapper fi-colorpicker-wrapper fi-input-with-columns' style={{ + width: '216px', //Width of the ColorPicker element + border: '1px solid #8c8f94', + borderRadius: '0px', + }}> + <div className='fi-color-preview' style={{ + background: value, + height: '32px', + width: '100%' + }} + onClick={() => { + setIsPopupActive(!isPopupActive) + }} + ></div> + </div> + {isPopupActive && + <div className='fi-field-buttons-wrapper fi-colorpicker-wrapper'> + <ColorPicker + enableAlpha={enableAlpha} + color={value} + onChangeComplete={handleColorChange} + /> + </div>} + </div> + ); +} + +export default ColorSelector; + + diff --git a/src/DuoInput/DuoInput.jsx b/src/DuoInput/DuoInput.jsx new file mode 100644 index 0000000000000000000000000000000000000000..a49700478344e7b26aeff0f83a21399b5365ed18 --- /dev/null +++ b/src/DuoInput/DuoInput.jsx @@ -0,0 +1,43 @@ +import NumberWithUnit from "../NumberWithUnit/NumberWithUnit"; + +function DuoInput(props) { + + const {label, onChange, values, layout = 'column'} = props; + + + const keys = Object.keys(values); + const valuesArray = Object.values(values); + const handleChange = (side, value) => { + const changedSide = keys[side]; + const newValues = {...values, [changedSide]: value}; + + if (onChange) { + onChange(newValues); + } + }; + return ( + <div className='fi-field-wrapper'> + <div className='fi-field-label-wrapper'> + <span className='fi-field-label'>{label}</span> + </div> + <div className='fi-field-buttons-wrapper fi-duo-fields-wrapper' style={{flexDirection: layout }}> + <div className='fi-duo-fields'> + <NumberWithUnit + className='fi-duo-field fi-duo-field-input' + value={valuesArray[0]} + onChange={(e) => { + handleChange(0, e) + }} + /> + <NumberWithUnit + className='fi-duo-field fi-duo-field-input' + value={valuesArray[1]} + onChange={(e) => handleChange(1, e)} + /> + </div> + </div> + </div> + ); +} + +export default DuoInput; diff --git a/src/FlexibleTable/FlexibleTable.jsx b/src/FlexibleTable/FlexibleTable.jsx new file mode 100644 index 0000000000000000000000000000000000000000..6b8b09033fb4453d5b6567f63cbba0a1518a5810 --- /dev/null +++ b/src/FlexibleTable/FlexibleTable.jsx @@ -0,0 +1,426 @@ +import {__} from '@wordpress/i18n'; +import { + RichText, + InspectorControls, + useBlockProps, +} from '@wordpress/block-editor'; +import { + PanelBody, + ToggleControl, +} from '@wordpress/components'; +import {DragDropContext, Draggable, Droppable} from "react-beautiful-dnd"; +import ColorSelector from "../ColorSelector/ColorSelector"; +import NumberWithUnit from "../NumberWithUnit/NumberWithUnit"; +import AlignButtons from "../AlignButtons/AlignButtons"; +import FontStyles from "../FontStyles/FontStyles"; +import QuatroInput from "../QuatroInput/QuatroInput"; +import BlockPlaceholders from "../BlockPlaceholders/BlockPlaceholders"; + +export default function Edit({attributes, setAttributes, placeholders, footer, additionalOptions }) { + const { + headers, + rows, + states, + + headerBackground, + headerTextColor, + headerTextAlign, + headerFontWeight, + headerFontStyle, + headerTextDecoration, + headerFontSize, + + headerBorderRowWidthTop, + headerBorderRowWidthLeft, + headerBorderRowWidthRight, + headerBorderRowWidthBottom, + headerBorderRowColor, + headerBorderCellWidthTop, + headerBorderCellWidthLeft, + headerBorderCellWidthRight, + headerBorderCellWidthBottom, + headerBorderCellColor, + + bodyBackground, + multipleBodyBackground, + bodyBackgroundOdd, + bodyTextColor, + bodyTextAlign, + bodyFontWeight, + bodyFontStyle, + bodyTextDecoration, + bodyFontSize, + + bodyBorderRowWidthTop, + bodyBorderRowWidthLeft, + bodyBorderRowWidthRight, + bodyBorderRowWidthBottom, + bodyBorderRowColor, + bodyBorderCellWidthTop, + bodyBorderCellWidthLeft, + bodyBorderCellWidthRight, + bodyBorderCellWidthBottom, + bodyBorderCellColor, + + } = attributes; + + const blockProps = useBlockProps(); + + const handleMultipleAttributesChange = (newValues) => { + setAttributes({...attributes, ...newValues}); + } + + const updateHeader = (index, value) => { + const newHeaders = [...headers]; + newHeaders[index] = value; + setAttributes({headers: newHeaders}); + }; + + const updateCell = (index, value) => { + const newRows = [...rows]; + newRows[index] = value; + setAttributes({rows: newRows}); + }; + + const toggleColumn = (index, value) => { + const newStates = [...states]; + newStates[index] = value; + setAttributes({states: newStates}); + }; + + const handleDragEnd = (result) => { + if (!result.destination) { + return; + } + + const {source, destination} = result; + const newHeaders = [...headers]; + const newStates = [...states]; + const newRows = [...rows]; + + const [movedHeader] = newHeaders.splice(source.index, 1); + newHeaders.splice(destination.index, 0, movedHeader); + + const [movedState] = newStates.splice(source.index, 1); + newStates.splice(destination.index, 0, movedState); + + const [movedRow] = newRows.splice(source.index, 1); + newRows.splice(destination.index, 0, movedRow); + + setAttributes({ + headers: newHeaders, + states: newStates, + rows: newRows + }); + }; + + return ( + <> + <InspectorControls> + <PanelBody title={__("Table columns", "flexible-invoices-core")}> + <DragDropContext onDragEnd={handleDragEnd}> + <Droppable droppableId="table-columns"> + {(provided) => ( + <ul + {...provided.droppableProps} + ref={provided.innerRef} + style={{padding: 0, listStyle: "none"}} + > + {headers.map((header, index) => ( + <Draggable key={header} draggableId={header} index={index}> + {(provided) => ( + <li + ref={provided.innerRef} + {...provided.draggableProps} + {...provided.dragHandleProps} + className="fi-settings-toggle" + style={{ + ...provided.draggableProps.style, + }} + > + <div className="fi-settings-toggle-header"> + <span className="dashicons dashicons-ellipsis"></span> + <span>{header}</span> + </div> + <ToggleControl + checked={states[index]} + onChange={(newValue) => toggleColumn(index, newValue)} + /> + </li> + )} + </Draggable> + ))} + {provided.placeholder} + </ul> + )} + </Droppable> + </DragDropContext> + </PanelBody> + <PanelBody title={__('Header appearance', 'flexible-invoices-core')}> + <ColorSelector + label={__('Text Color', 'flexible-invoices-core')} + value={headerTextColor} + enableAlpha={false} + onChange={(value) => setAttributes({headerTextColor: value})} + /> + <ColorSelector + label={__('Background Color', 'flexible-invoices-core')} + value={headerBackground} + onChange={(value) => setAttributes({headerBackground: value})} + /> + <NumberWithUnit + label={__('Font Size', 'flexible-invoices-core')} + value={headerFontSize} + onChange={(value) => setAttributes({headerFontSize: value})} + /> + <AlignButtons + label={__('Text Align', 'flexible-invoices-core')} + onChange={(value) => setAttributes({headerTextAlign: value})} + /> + <FontStyles + label={__('Font style', 'flexible-invoices-core')} + onChange={(newFontStyles) => setAttributes({ + ...attributes, + headerFontStyle: newFontStyles.fontStyle, + headerFontWeight: newFontStyles.fontWeight, + headerTextDecoration: newFontStyles.textDecoration + })} + values={ + { + fontStyle: headerFontStyle, + fontWeight: headerFontWeight, + textDecoration: headerTextDecoration + } + } + /> + <ColorSelector + label={__('Border row color', 'flexible-invoices-core')} + value={headerBorderRowColor} + enableAlpha={false} + returnFormat={'hex'} + onChange={(value) => setAttributes({headerBorderRowColor: value})} + /> + <QuatroInput + label={__("Border row width", 'flexible-invoices-core')} + values={ + { + headerBorderRowWidthTop: headerBorderRowWidthTop, + headerBorderRowWidthLeft: headerBorderRowWidthLeft, + headerBorderRowWidthRight: headerBorderRowWidthRight, + headerBorderRowWidthBottom: headerBorderRowWidthBottom, + } + } + onChange={handleMultipleAttributesChange} + /> + <ColorSelector + label={__('Border cell color', 'flexible-invoices-core')} + value={headerBorderCellColor} + enableAlpha={false} + returnFormat={'hex'} + onChange={(value) => setAttributes({headerBorderCellColor: value})} + /> + <QuatroInput + label={__("Border cell width", 'flexible-invoices-core')} + values={ + { + headerBorderCellWidthTop: headerBorderCellWidthTop, + headerBorderCellWidthLeft: headerBorderCellWidthLeft, + headerBorderCellWidthRight: headerBorderCellWidthRight, + headerBorderCellWidthBottom: headerBorderCellWidthBottom, + } + } + onChange={handleMultipleAttributesChange} + /> + + </PanelBody> + <PanelBody title={__('Body appearance', 'flexible-invoices-core')}> + <ColorSelector + label={__('Text Color', 'flexible-invoices-core')} + value={bodyTextColor} + enableAlpha={false} + onChange={(value) => setAttributes({bodyTextColor: value})} + /> + <ColorSelector + label={__('Background Color', 'flexible-invoices-core')} + value={bodyBackground} + enableAlpha={false} + onChange={(value) => setAttributes({bodyBackground: value})} + /> + + <ToggleControl + label={__('Duo color table', 'flexible-invoices-core')} + checked={multipleBodyBackground} + onChange={(newValue) => setAttributes({multipleBodyBackground: newValue})} + /> + + {multipleBodyBackground ? <ColorSelector + label={__('Background color (odd rows)', 'flexible-invoices-core')} + value={bodyBackgroundOdd} + onChange={(value) => setAttributes({bodyBackgroundOdd: value})} + /> : ''} + + <NumberWithUnit + label={__('Font size', 'flexible-invoices-core')} + value={bodyFontSize} + onChange={(value) => setAttributes({bodyFontSize: value})} + /> + <AlignButtons + label={__('Text align', 'flexible-invoices-core')} + onChange={(value) => setAttributes({bodyTextAlign: value})} + /> + <FontStyles + label={__('Font style', 'flexible-invoices-core')} + onChange={(newFontStyles) => setAttributes({ + ...attributes, + bodyFontStyle: newFontStyles.fontStyle, + bodyFontWeight: newFontStyles.fontWeight, + bodyTextDecoration: newFontStyles.textDecoration + })} + values={ + { + fontStyle: bodyFontStyle, + fontWeight: bodyFontWeight, + textDecoration: bodyTextDecoration + } + } + /> + <ColorSelector + label={__('Border row color', 'flexible-invoices-core')} + value={bodyBorderRowColor} + enableAlpha={false} + onChange={(value) => setAttributes({bodyBorderRowColor: value})} + /> + <QuatroInput + label={__("Border row width", 'flexible-invoices-core')} + values={ + { + bodyBorderRowWidthTop: bodyBorderRowWidthTop, + bodyBorderRowWidthLeft: bodyBorderRowWidthLeft, + bodyBorderRowWidthRight: bodyBorderRowWidthRight, + bodyBorderRowWidthBottom: bodyBorderRowWidthBottom, + } + } + onChange={handleMultipleAttributesChange} + /> + <ColorSelector + label={__('Border cell color', 'flexible-invoices-core')} + value={bodyBorderCellColor} + enableAlpha={false} + onChange={(value) => setAttributes({bodyBorderCellColor: value})} + /> + <QuatroInput + label={__("Border cell width", 'flexible-invoices-core')} + values={ + { + bodyBorderCellWidthTop: bodyBorderCellWidthTop, + bodyBorderCellWidthLeft: bodyBorderCellWidthLeft, + bodyBorderCellWidthRight: bodyBorderCellWidthRight, + bodyBorderCellWidthBottom: bodyBorderCellWidthBottom, + } + } + onChange={handleMultipleAttributesChange} + /> + </PanelBody> + {additionalOptions} + {placeholders && <BlockPlaceholders + placeholders={placeholders} + />} + </InspectorControls> + <div {...blockProps}> + <table className="fitb-item-table has-background" style={{ + borderCollapse: 'collapse' + }}> + <thead className={"fitb-item-table-header"} style={{ + borderStyle: "solid", + borderColor: headerBorderRowColor, + borderTopWidth: headerBorderRowWidthTop, + borderLeftWidth: headerBorderRowWidthLeft, + borderRightWidth: headerBorderRowWidthRight, + borderBottomWidth: headerBorderRowWidthBottom, + }}> + <tr className={"fitb-item-table-header-row"} style={{ + background: headerBackground, + }}> + {headers.map((header, index) => ( + states[index] ? + <th className={"fitb-item-table-header-cell"} key={index} + style={{ + borderStyle: "solid", + borderColor: headerBorderCellColor, + borderTopWidth: headerBorderCellWidthTop, + borderLeftWidth: headerBorderCellWidthLeft, + borderRightWidth: headerBorderCellWidthRight, + borderBottomWidth: headerBorderCellWidthBottom, + }}> + <RichText + tagName="div" + key={index} + value={header} + style={{ + color: headerTextColor, + textAlign: headerTextAlign, + fontStyle: headerFontStyle, + textDecoration: headerTextDecoration, + fontSize: headerFontSize, + fontWeight: headerFontWeight, + }} + onChange={(value) => updateHeader(index, value)} + /> + </th> : '' + ))} + </tr> + </thead> + <tbody className={"fitb-item-table-body"}> + + {Array.from({length: 2}).map((_, index) => ( + <tr className={"fitb-item-table-row"} style={{ + background: (multipleBodyBackground && index === 1) ? bodyBackgroundOdd : bodyBackground, + borderStyle: "solid", + borderColor: bodyBorderRowColor, + borderTopWidth: bodyBorderRowWidthTop, + borderLeftWidth: bodyBorderRowWidthLeft, + borderRightWidth: bodyBorderRowWidthRight, + borderBottomWidth: bodyBorderRowWidthBottom, + }}> + {rows.map((row, index) => ( + states[index] ? + <td className={"fitb-item-table-cell"} key={index} + style={{ + borderStyle: "solid", + borderColor: bodyBorderCellColor, + borderTopWidth: bodyBorderCellWidthTop, + borderLeftWidth: bodyBorderCellWidthLeft, + borderRightWidth: bodyBorderCellWidthRight, + borderBottomWidth: bodyBorderCellWidthBottom, + }}> + <RichText + tagName="div" + key={index} + value={row} + style={{ + color: bodyTextColor, + textAlign: bodyTextAlign, + fontStyle: bodyFontStyle, + fontSize: bodyFontSize, + textDecoration: bodyTextDecoration, + fontWeight: bodyFontWeight, + }} + onChange={(value) => + updateCell(index, value) + } + /> + </td> : '' + ))} + </tr> + ))} + </tbody> + {footer && + <tfoot> + {footer} + </tfoot> + } + </table> + </div> + </> + ); +} diff --git a/src/FontStyles/FontStyles.jsx b/src/FontStyles/FontStyles.jsx new file mode 100644 index 0000000000000000000000000000000000000000..a3dc1bad4adf6a7212c62a8ba386940ed9b979ea --- /dev/null +++ b/src/FontStyles/FontStyles.jsx @@ -0,0 +1,103 @@ +import {Button} from "@wordpress/components"; +import {useState} from "react"; + +function FontStyles(props) { + + const {label, onChange, values} = props; + + const [isItalic, setIsItalic] = useState(values.fontStyle === 'italic'); + const [isBold, setIsBold] = useState(values.fontWeight === 'bold'); + const [isUnderline, setIsUnderline] = useState(values.textDecoration.includes('underline')); + const [isLineThrough, setIsLineThrough] = useState(values.textDecoration.includes('line-through')); + + const fontStyle = isItalic ? 'italic' : 'normal'; + const fontWeight = isBold ? 'bold' : 'normal'; + const textDecoration = isUnderline ? 'underline' : isLineThrough ? 'line-through' : 'none'; + + const handleChange = function (updatedValues) { + console.log([updatedValues, textDecoration]); + const newStyles = { + fontStyle: updatedValues.fontStyle || fontStyle, + fontWeight: updatedValues.fontWeight || fontWeight, + textDecoration: (updatedValues.textDecoration === '' ? 'none' : updatedValues.textDecoration) || textDecoration + }; + setIsItalic( newStyles.fontStyle === 'italic'); + setIsBold( newStyles.fontWeight === 'bold'); + setIsUnderline( newStyles.textDecoration.includes('underline')); + setIsLineThrough( newStyles.textDecoration.includes('line-through')); + console.log(newStyles); + + if (onChange) { + onChange(newStyles); + } + }; + + + const handleButtonPress = function (styleToChange) { + switch (styleToChange) { + case 'bold': + setIsBold(prev => { + const newValue = !prev; + handleChange({fontWeight: newValue ? 'bold' : 'normal'}); + return newValue; + }); + break; + case 'italic': + setIsItalic(prev => { + const newValue = !prev; + handleChange({fontStyle: newValue ? 'italic' : 'normal'}); + return newValue; + }); + break; + case 'underline': + setIsUnderline(prev => { + const newValue = !prev; + handleChange({textDecoration: (newValue ? 'underline ' : '') + (isLineThrough ? 'line-through' : '')}); + return newValue; + }); + break; + case 'line-through': + setIsLineThrough(prev => { + const newValue = !prev; + handleChange({textDecoration: (newValue ? 'line-through ' : '') + (isUnderline ? 'underline' : '')}); + return newValue; + }); + break; + default: + break; + } + }; + + + return ( + <div className='fi-field-wrapper'> + <div className='fi-field-label-wrapper'> + <span className='fi-field-label'>{label}</span> + </div> + <div className='fi-field-buttons-wrapper fi-fontstylingbuttons-wrapper'> + <Button + icon="editor-italic" + className={"has-dashicons" + (isItalic ? ' fi-btn-active' : '')} + onClick={() => handleButtonPress('italic')} + /> + <Button + icon="editor-bold" + className={"has-dashicons" + (isBold ? ' fi-btn-active' : '')} + onClick={() => handleButtonPress('bold')} + /> + <Button + icon="editor-strikethrough" + className={"has-dashicons" + (isLineThrough ? ' fi-btn-active' : '')} + onClick={() => handleButtonPress('line-through')} + /> + <Button + icon="editor-underline" + className={"has-dashicons" + (isUnderline ? ' fi-btn-active' : '')} + onClick={() => handleButtonPress('underline')} + /> + </div> + </div> + ); +} + +export default FontStyles; diff --git a/src/NumberWithUnit/NumberWithUnit.jsx b/src/NumberWithUnit/NumberWithUnit.jsx new file mode 100644 index 0000000000000000000000000000000000000000..79524bc2683d513bc7885ab7c921ad3bcbf3ed0e --- /dev/null +++ b/src/NumberWithUnit/NumberWithUnit.jsx @@ -0,0 +1,69 @@ +import {SelectControl, TextControl} from "@wordpress/components"; +import {useState} from "react"; + +function NumberWithUnit(props) { + + const {label, onChange, value, className} = props; + + const splitValues = function (fontSize) { + const match = fontSize.match(/^(\d+)([a-z%]+)$/i); + if (!match) { + return {size: "16", unit: "px"}; + } + return { + size: match[1], + unit: match[2] + }; + } + + const [unit, setUnit] = useState(splitValues(value).unit); + const [size, setSize] = useState(splitValues(value).size); + + + + const handleChange = (newSize, newUnit) => { + if (onChange) { + onChange(newSize + newUnit); + } + }; + + + return ( + <div className='fi-field-wrapper'> + <div className='fi-field-label-wrapper'> + <span className='fi-field-label'>{label}</span> + </div> + <div className={'fi-field-buttons-wrapper fi-input-with-columns fi-numberwithfields-wrapper' + ' ' + className}> + <TextControl + style={{flex: 3}} + type={'number'} + placeholder={'16'} + value={size} + onChange={(value) => { + setSize(value); + handleChange(value, unit); + }} + /> + <SelectControl + options={[ + {label: 'px', value: 'px'}, + {label: '%', value: '%'}, + {label: 'em', value: 'em'}, + {label: 'pt', value: 'pt'}, + ]} + style={{minWidth:'56px'}} + value={unit} + onChange={(value) => { + setUnit(value); + handleChange(size, value); + }} + + /> + </div> + </div> + ); +} + +export default NumberWithUnit; + + diff --git a/src/QuatroInput/QuatroInput.jsx b/src/QuatroInput/QuatroInput.jsx new file mode 100644 index 0000000000000000000000000000000000000000..545d3e392ccd50b4c8382ee1ddfd40388d2efda7 --- /dev/null +++ b/src/QuatroInput/QuatroInput.jsx @@ -0,0 +1,87 @@ +import NumberWithUnit from "../NumberWithUnit/NumberWithUnit"; + +function QuatroInput(props) { + + const {label, onChange, values, layout = 'cross'} = props; + + + const keys = Object.keys(values); + const valuesArray = Object.values(values); + const handleChange = (side, value) => { + const changedSide = keys[side]; + const newValues = {...values, [changedSide]: value}; + + if (onChange) { + onChange(newValues); + } + }; + return ( + <div className='fi-field-wrapper'> + <div className='fi-field-label-wrapper'> + <span className='fi-field-label'>{label}</span> + </div> + {layout === 'cross' && + <div className='fi-field-buttons-wrapper fi-quatro-fields-wrapper'> + <div className='fi-quatro-fields'> + <NumberWithUnit + className='fi-quatro-field fi-quatro-field-input' + value={valuesArray[0]} + onChange={(e) => { + handleChange(0, e) + }} + /> + </div> + <div className='fi-quatro-fields fields-mid'> + <NumberWithUnit + className='fi-quatro-field fi-quatro-field-input' + value={valuesArray[1]} + onChange={(e) => handleChange(1, e)} + /> + <NumberWithUnit + className='fi-quatro-field fi-quatro-field-input' + value={valuesArray[2]} + onChange={(e) => handleChange(2, e)} + /> + </div> + <div className='fi-quatro-fields'> + <NumberWithUnit + className='fi-quatro-field fi-quatro-field-input' + value={valuesArray[3]} + onChange={(e) => handleChange(3, e)} + /> + </div> + </div>} + {layout === 'box' && + <div className='fi-field-buttons-wrapper fi-quatro-fields-wrapper'> + <div className='fi-quatro-fields'> + <NumberWithUnit + className='fi-quatro-field fi-quatro-field-input' + value={valuesArray[0]} + onChange={(e) => { + handleChange(0, e) + }} + /> + <NumberWithUnit + className='fi-quatro-field fi-quatro-field-input' + value={valuesArray[1]} + onChange={(e) => handleChange(1, e)} + /> + </div> + <div className='fi-quatro-fields fields-mid'> + <NumberWithUnit + className='fi-quatro-field fi-quatro-field-input' + value={valuesArray[2]} + onChange={(e) => handleChange(2, e)} + /> + <NumberWithUnit + className='fi-quatro-field fi-quatro-field-input' + value={valuesArray[3]} + onChange={(e) => handleChange(3, e)} + /> + </div> + </div>} + </div> + ); +} + +export default QuatroInput;