Skip to content

Commit

Permalink
Feat: Element container style UI (elastic#154)
Browse files Browse the repository at this point in the history
* chore: make labeled select generic component

decouple it from the extended input template so it can be reused

* feat: add container style argType UI

* feat: add border radius to border form

* chore: separate background color and image

also, don't automatically append the 'px' on padding and border radius

* fix: make labeled select value optional

* feat: add container appearance form

* fix: correctly build border property

also make the value argument optional

* feat: set the container ast

also set the expected types on css values to string instead of number, since we're using the px values
  • Loading branch information
w33ble authored Sep 7, 2017
1 parent c11060d commit 6e8a426
Show file tree
Hide file tree
Showing 16 changed files with 265 additions and 52 deletions.
14 changes: 8 additions & 6 deletions common/functions/containerStyle/containerStyle.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,25 +13,27 @@ export default new Fn({
help: 'Valid CSS border string',
},
borderRadius: {
types: ['number', 'null'],
types: ['string', 'null'],
help: 'Number of pixels to use when rounding the border',
},
padding: {
types: ['number', 'null'],
types: ['string', 'null'],
help: 'Content distance in pixels from border',
},
background: {
backgroundColor: {
types: ['string', 'null'],
help: 'Valid CSS background color string',
},
backgroundImage: {
types: ['string', 'null'],
help: 'Valid CSS background string',
help: 'Value CSS background image string',
},
opacity: {
types: ['number', 'null'],
help: 'A number between 0 and 1 representing the degree of transparency of the element',
},
},
fn: (context, args) => {
args.borderRadius = `${args.borderRadius}px`;
args.padding = `${args.padding}px`;
return { type: 'containerStyle', ...args };
},
});
2 changes: 1 addition & 1 deletion common/functions/render/render.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ export default new Fn({
},
containerStyle: {
types: ['containerStyle', 'null'],
help: 'Background, border and opacity',
help: 'Style for the container, including background, border, and opacity',
},
},
fn: (context, args) => {
Expand Down
2 changes: 1 addition & 1 deletion public/components/color_picker/color_picker.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ export const ColorPicker = ({ onChange, value, colors, addColor, removeColor })

return (
<div>
<ColorPalette onChange={onChange} value={value} colors={colors} />
<ColorPalette onChange={onChange} value={value} colors={colors} />
<ColorManager onChange={onChange} value={value} addColor={addColor} removeColor={removeColor}/>
</div>
);
Expand Down
8 changes: 4 additions & 4 deletions public/components/color_picker_mini/color_picker_mini.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,10 @@ export const ColorPickerMini = ({ onChange, value, placement }) => {
<div className="canvas__color-picker-mini">

<OverlayTrigger
rootClose
overlay={picker}
placement={placement || 'bottom'}
trigger="click"
rootClose
overlay={picker}
placement={placement || 'bottom'}
trigger="click"
>
<div><ColorDot value={value}/></div>
</OverlayTrigger>
Expand Down
4 changes: 4 additions & 0 deletions public/components/labeled_select/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
import { pure } from 'recompose';
import { LabeledSelect as Component } from './labeled_select';

export const LabeledSelect = pure(Component);
Original file line number Diff line number Diff line change
Expand Up @@ -2,31 +2,33 @@ import React from 'react';
import PropTypes from 'prop-types';
import { ControlLabel, FormControl } from 'react-bootstrap';

export const LabeledSelect = ({ label, value, argName, onChange }) => (
<div className={`canvas__argtype--seriesStyle--${argName}`}>
const mapToOptions = (val) => {
const tuple = (!Array.isArray(val)) ? [val] : val;
return (<option value={tuple[0]} key={tuple[0]}>{tuple[1] || tuple[0]}</option>);
};

export const LabeledSelect = ({ label, value, values, className, onChange }) => (
<div className={className}>
<FormControl
componentClass="select"
value={value}
onChange={ev => onChange(argName, ev)}
onChange={onChange}
>
<option value="0">None</option>
<option value="1">1</option>
<option value="2">2</option>
<option value="3">3</option>
<option value="4">4</option>
<option value="5">5</option>
<option>--</option>
{values.map(mapToOptions)}
</FormControl>
<ControlLabel>{label}</ControlLabel>

<ControlLabel>{label}</ControlLabel>
</div>
);

LabeledSelect.propTypes = {
label: PropTypes.string.isRequired,
className: PropTypes.string,
value: PropTypes.oneOfType([
PropTypes.string,
PropTypes.number,
]).isRequired,
argName: PropTypes.string.isRequired,
]),
values: PropTypes.array.isRequired,
onChange: PropTypes.func.isRequired,
};
15 changes: 2 additions & 13 deletions public/components/positionable/positionable.js
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ const PositionableLifecycle = lifecycle({

});

const PositionableComponent = ({ position, children, interact }) => {
const PositionableComponent = ({ position, children, interact }) => {
function setWrapperNode(domNode) {
wrapperNode = domNode;
}
Expand All @@ -98,25 +98,14 @@ const PositionableComponent = ({ position, children, interact }) => {

const stepChild = React.cloneElement(child, { size: { height, width } });

/*
if (!interact) {
return (
<div className="canvas--positionable"
ref={setWrapperNode}
style={newStyle}>
{stepChild}
</div>
);
} else {
*/
return (
<div className="canvas--positionable canvas--interactable"
ref={setWrapperNode}
style={newStyle}>

{stepChild}

{!interact ? null : (
{interact && (
<div>
<div className="canvas--interactable-actions">
<div className="canvas--interactable-action canvas--interactable-rotate-handle">
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import React from 'react';
import PropTypes from 'prop-types';
import { ControlLabel } from 'react-bootstrap';
import { ColorPickerMini } from '../../../components/color_picker_mini';
import { LabeledSelect } from '../../../components/labeled_select';

const paddings = [['0px', 'None'], '1px', '2px', '3px', '4px', '5px', '6px', '7px', '8px', '9px', '10px'];
const opacities = [[1, '100%'], [0.9, '90%'], [0.7, '70%'], [0.5, '50%'], [0.3, '30%'], [0.1, '10%']];

export const AppearanceForm = ({ className, padding, opacity, backgroundColor, onChange }) => {
const namedChange = name => ev => onChange(name, ev.target.value);

return (
<div className={className}>
<LabeledSelect
className="padding"
label="Padding"
value={padding}
values={paddings}
onChange={namedChange('padding')}
/>

<LabeledSelect
className="opacity"
label="Opacity"
value={opacity}
values={opacities}
onChange={namedChange('opacity')}
/>

<div className="border-color">
<ColorPickerMini
value={backgroundColor}
onChange={color => onChange('backgroundColor', color)} />
<ControlLabel>BG Color</ControlLabel>
</div>
</div>
);
};

AppearanceForm.propTypes = {
padding: PropTypes.oneOfType([
PropTypes.string,
PropTypes.number,
]),
backgroundColor: PropTypes.string,
opacity: PropTypes.oneOfType([
PropTypes.string,
PropTypes.number,
]),
onChange: PropTypes.func.isRequired,
className: PropTypes.string,
};
66 changes: 66 additions & 0 deletions public/expression_types/arg_types/container_style/border_form.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
import React from 'react';
import PropTypes from 'prop-types';
import { ControlLabel } from 'react-bootstrap';
import { ColorPickerMini } from '../../../components/color_picker_mini';
import { LabeledSelect } from '../../../components/labeled_select';

const widths = [['0px', 'None'], '1px', '2px', '3px', '4px', '5px', '6px', '7px', '8px', '9px', '10px'];
const styles = ['solid', 'dotted', 'dashed', 'double', 'groove', 'ridge', 'inset', 'outset'];

export const BorderForm = ({ className, value, radius, onChange }) => {
const border = value || '';
const [ borderWidth, borderStyle, borderColor ] = border.split(' ');

const namedChange = name => ev => {
const val = ev.target.value;

if (name === 'borderWidth') return onChange('border', `${val} ${borderStyle} ${borderColor}`);
if (name === 'borderStyle') return onChange('border', `${borderWidth} ${val} ${borderColor}`);

onChange(name, ev.target.value);
};

const borderColorChange = color => onChange('border', `${borderWidth} ${borderStyle} ${color}`);

return (
<div className={className}>
<LabeledSelect
className="border-width"
label="Width"
value={borderWidth}
values={[ ...widths ]}
onChange={namedChange('borderWidth')}
/>

<LabeledSelect
className="border-style"
label="Style"
value={borderStyle}
values={styles}
onChange={namedChange('borderStyle')}
/>

<LabeledSelect
className="border-radius"
label="Radius"
value={radius}
values={[ ...widths ]}
onChange={namedChange('borderRadius')}
/>

<div className="border-color">
<ColorPickerMini
value={borderColor}
onChange={borderColorChange} />
<ControlLabel>Color</ControlLabel>
</div>
</div>
);
};

BorderForm.propTypes = {
value: PropTypes.string,
radius: PropTypes.string,
onChange: PropTypes.func.isRequired,
className: PropTypes.string,
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
import React from 'react';
import PropTypes from 'prop-types';
import { get } from 'lodash';
import { set } from 'object-path-immutable';
import { ArgType } from '../../arg_type';
import { getStringType } from '../../../../common/types/get_type';
import { BorderForm } from './border_form';
import { AppearanceForm } from './appearance_form';

import './container_style.less';

const template = ({ onValueChange, argValue }) => {
const args = get(argValue, 'chain.0.arguments', {});

const getArgValue = (args, name, alt) => get(args, [name, 0, 'value'], alt);

const setArgValue = (args, name, val) => {
const value = {
value: val,
type: getStringType(val),
};
const newValue = set(argValue, ['chain', 0, 'arguments', name, 0], value);
onValueChange(newValue);
};

return (
<div className="canvas__argtype--containerStyle">
<div>
<label>Appearance</label>
<AppearanceForm
className="canvas__argtype--containerStyle--appearance"
padding={getArgValue(args, 'padding')}
backgroundColor={getArgValue(args, 'backgroundColor')}
opacity={getArgValue(args, 'opacity')}
onChange={(...blah) => setArgValue(args, ...blah)}
/>

<label>Border</label>
<BorderForm
className="canvas__argtype--containerStyle--border"
value={getArgValue(args, 'border', '')}
radius={getArgValue(args, 'borderRadius')}
onChange={(...blah) => setArgValue(args, ...blah)} />
</div>
</div>
);
};

template.propTypes = {
onValueChange: PropTypes.func.isRequired,
argValue: PropTypes.object.isRequired,
};

export const containerStyle = () => new ArgType('containerStyle', {
displayName: 'Image Upload',
description: 'Select or upload an image',
template: template,
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
@import (reference) "../../../style/variables";

.canvas__argtype--containerStyle {
.canvas__argtype--containerStyle--appearance,
.canvas__argtype--containerStyle--border {
display: flex;

& > * {
margin-right: @spacingXS;
flex: 1;

.control-label {
display: block;
margin-top: @spacingXS;
}
}
}
}
1 change: 1 addition & 0 deletions public/expression_types/arg_types/container_style/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { containerStyle } from './container_style';
11 changes: 6 additions & 5 deletions public/expression_types/arg_types/index.js
Original file line number Diff line number Diff line change
@@ -1,18 +1,19 @@
import { containerStyle } from './container_style';
import { datacolumn } from './datacolumn';
import { expression } from './expression';
import { imageUpload } from './image_upload';
import { seriesStyle } from './series_style';
import { palette } from './palette';
import { select } from './select';
import { seriesStyle } from './series_style';
import { textarea } from './textarea';
import { palette } from './palette';


export default [
containerStyle,
datacolumn,
expression,
imageUpload,
seriesStyle,
palette,
select,
seriesStyle,
textarea,
palette,
];
1 change: 0 additions & 1 deletion public/expression_types/arg_types/palette.js
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,6 @@ const template = ({ onValueChange, argValue }) => {
template.propTypes = {
onValueChange: PropTypes.func.isRequired,
argValue: PropTypes.object.isRequired,
typeInstance: PropTypes.object,
};

export const palette = () => new ArgType('palette', {
Expand Down
Loading

0 comments on commit 6e8a426

Please sign in to comment.