Skip to content

Commit

Permalink
Feat: Shape Element (elastic#745)
Browse files Browse the repository at this point in the history
* Added shape function

* Added color arg type

* Added shape render function

* Added shapes

* Added shape components and shape arg type

* Cleaned up shapes

* Added stroke-miterlimit to prevent corners from beveling

* Removed unused prop and id from shape_picker_mini

* Added default values to color, number, shape, and toggle. Generated id in popover

* Updated default shape element expression

* Fixed falsy check for borderWidth to allow 0. Changed default color arg value to black
  • Loading branch information
cqliu1 authored Jul 11, 2018
1 parent ac728e4 commit 676d544
Show file tree
Hide file tree
Showing 43 changed files with 407 additions and 5 deletions.
2 changes: 2 additions & 0 deletions common/functions/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ import { rowCount } from './rowCount';
import { repeatImage } from './repeatImage';
import { revealImage } from './revealImage';
import { seriesStyle } from './seriesStyle';
import { shape } from './shape';
import { sort } from './sort';
import { staticColumn } from './staticColumn';
import { string } from './string';
Expand Down Expand Up @@ -90,6 +91,7 @@ export const commonFunctions = [
rounddate,
rowCount,
seriesStyle,
shape,
sort,
staticColumn,
string,
Expand Down
1 change: 1 addition & 0 deletions common/functions/shape/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { shape } from './shape';
46 changes: 46 additions & 0 deletions common/functions/shape/shape.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
export const shape = () => ({
name: 'shape',
aliases: [],
type: 'shape',
help: 'Create a shape',
context: {
types: ['null'],
},
args: {
_: {
types: ['string', 'null'],
help: 'Pick a shape',
aliases: ['shape'],
default: 'square',
},
fill: {
types: ['string', 'null'],
help: 'Valid CSS color string',
default: 'black',
},
border: {
types: ['string', 'null'],
aliases: ['stroke'],
help: 'Valid CSS color string',
},
borderWidth: {
types: ['number', 'null'],
aliases: ['strokeWidth'],
help: 'Thickness of the border',
default: '0',
},
maintainAspect: {
types: ['boolean'],
help: 'Select true to maintain aspect ratio',
default: false,
},
},
fn: (context, { _, fill, border, borderWidth, maintainAspect }) => ({
type: 'shape',
shape: _,
fill,
border,
borderWidth,
maintainAspect,
}),
});
2 changes: 2 additions & 0 deletions common/types/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import { nullType } from './null';
import { number } from './number';
import { pointseries } from './pointseries';
import { render } from './render';
import { shape } from './shape';
import { string } from './string';
import { style } from './style';

Expand All @@ -22,6 +23,7 @@ export const typeSpecs = [
nullType,
pointseries,
render,
shape,
string,
style,
];
12 changes: 12 additions & 0 deletions common/types/shape.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
export const shape = () => ({
name: 'shape',
to: {
render: input => {
return {
type: 'render',
as: 'shape',
value: input,
};
},
},
});
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@
"moment": "^2.20.1",
"object-path-immutable": "^0.5.3",
"prop-types": "^15.6.1",
"raw-loader": "0.5.1",
"react": "^16.2.0",
"react-bootstrap": "^0.32.1",
"react-datetime": "^2.14.0",
Expand Down Expand Up @@ -136,4 +137,4 @@
"sinon": "^4.5.0",
"through2": "^2.0.3"
}
}
}
3 changes: 2 additions & 1 deletion public/components/popover/popover.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import React, { PureComponent } from 'react';
import PropTypes from 'prop-types';
import { Popover as BootstrapPopover, Overlay } from 'react-bootstrap';
import uuid from 'uuid/v4';

// mapping for EUI popover positions to bootstrap placements
const anchorPositions = {
Expand Down Expand Up @@ -59,7 +60,7 @@ export class Popover extends PureComponent {
// TODO: replace bootstrap popover with EuiPopover https://github.com/elastic/kibana-canvas/issues/612
// Pending https://github.com/elastic/eui/issues/873
const popover = (
<BootstrapPopover id={id} className={panelClassName} title={title}>
<BootstrapPopover id={id || `popover-${uuid()}`} className={panelClassName} title={title}>
{children({ closePopover: this.closePopover })}
</BootstrapPopover>
);
Expand Down
5 changes: 5 additions & 0 deletions public/components/shape_picker/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import { pure } from 'recompose';

import { ShapePicker as Component } from './shape_picker';

export const ShapePicker = pure(Component);
26 changes: 26 additions & 0 deletions public/components/shape_picker/shape_picker.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import React from 'react';
import PropTypes from 'prop-types';
import { EuiFlexGrid, EuiFlexItem, EuiLink } from '@elastic/eui';
import { shapes } from '../../render_functions/shape/shapes';
import { ShapePreview } from '../shape_preview';

export const ShapePicker = ({ onChange }) => {
return (
<EuiFlexGrid gutterSize="s" columns={4}>
{Object.keys(shapes)
.sort()
.map(shapeKey => (
<EuiFlexItem key={shapeKey}>
<EuiLink onClick={() => onChange(shapeKey)}>
<ShapePreview value={shapeKey} />
</EuiLink>
</EuiFlexItem>
))}
</EuiFlexGrid>
);
};

ShapePicker.propTypes = {
value: PropTypes.string,
onChange: PropTypes.func,
};
5 changes: 5 additions & 0 deletions public/components/shape_picker_mini/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import { pure } from 'recompose';

import { ShapePickerMini as Component } from './shape_picker_mini';

export const ShapePickerMini = pure(Component);
30 changes: 30 additions & 0 deletions public/components/shape_picker_mini/shape_picker_mini.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import React from 'react';
import PropTypes from 'prop-types';
import { EuiLink } from '@elastic/eui';
import { Popover } from '../popover';
import { ShapePicker } from '../shape_picker/';
import { ShapePreview } from '../shape_preview';

export const ShapePickerMini = ({ onChange, value, anchorPosition }) => {
const button = handleClick => (
<EuiLink style={{ fontSize: 0 }} onClick={handleClick}>
<ShapePreview value={value} />
</EuiLink>
);

return (
<Popover
panelClassName="canvas canvasShapePickerMini--popover"
button={button}
anchorPosition={anchorPosition}
>
{() => <ShapePicker onChange={onChange} value={value} />}
</Popover>
);
};

ShapePickerMini.propTypes = {
value: PropTypes.string,
onChange: PropTypes.func,
anchorPosition: PropTypes.string,
};
3 changes: 3 additions & 0 deletions public/components/shape_picker_mini/shape_picker_mini.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
.canvasShapePickerMini--popover {
width: 220px;
}
5 changes: 5 additions & 0 deletions public/components/shape_preview/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import { pure } from 'recompose';

import { ShapePreview as Component } from './shape_preview';

export const ShapePreview = pure(Component);
11 changes: 11 additions & 0 deletions public/components/shape_preview/shape_preview.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import React from 'react';
import PropTypes from 'prop-types';
import { shapes } from '../../render_functions/shape/shapes';

export const ShapePreview = ({ value }) => {
return <div className="canvasShapePreview" dangerouslySetInnerHTML={{ __html: shapes[value] }} />;
};

ShapePreview.propTypes = {
value: PropTypes.string,
};
10 changes: 10 additions & 0 deletions public/components/shape_preview/shape_preview.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
.canvasShapePreview {
width: $euiSizeXXL;
height: $euiSizeXXL;

svg {
fill: black;
width: 100%;
height: 100%;
}
}
4 changes: 2 additions & 2 deletions public/elements/index.js
Original file line number Diff line number Diff line change
@@ -1,25 +1,25 @@
import { debug } from './debug';
import { dropdownFilter } from './dropdown_filter';
//import { grid } from './grid';
import { image } from './image';
import { repeatImage } from './repeatImage';
import { revealImage } from './revealImage';
import { markdown } from './markdown';
import { pie } from './pie';
import { plot } from './plot';
import { shape } from './shape';
import { table } from './table';
import { timeFilter } from './time_filter';

export const elementSpecs = [
timeFilter,
dropdownFilter,
debug,
//grid,
image,
repeatImage,
revealImage,
markdown,
plot,
pie,
shape,
table,
];
7 changes: 7 additions & 0 deletions public/elements/shape/header.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions public/elements/shape/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { shape } from './shape';
12 changes: 12 additions & 0 deletions public/elements/shape/shape.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import header from './header.svg';

export const shape = () => ({
name: 'shape',
displayName: 'Shape',
help: 'A customizable shape',
width: 200,
height: 200,
image: header,
expression:
'shape "square" fill="#4cbce4" border="rgba(255,255,255,0)" borderWidth=0 maintainAspect=true | render',
});
29 changes: 29 additions & 0 deletions public/expression_types/arg_types/color.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import React from 'react';
import PropTypes from 'prop-types';
import { EuiFlexGroup, EuiFlexItem } from '@elastic/eui';
import { templateFromReactComponent } from '../../lib/template_from_react_component';
import { ColorPickerMini } from '../../components/color_picker_mini/';

const ColorArgInput = ({ onValueChange, argValue, workpad }) => (
<EuiFlexGroup gutterSize="s">
<EuiFlexItem grow={false}>
<ColorPickerMini value={argValue} onChange={onValueChange} colors={workpad.colors} />
</EuiFlexItem>
</EuiFlexGroup>
);

ColorArgInput.propTypes = {
argValue: PropTypes.any.isRequired,
onValueChange: PropTypes.func.isRequired,
workpad: PropTypes.shape({
colors: PropTypes.array.isRequired,
}).isRequired,
};

export const color = () => ({
name: 'color',
displayName: 'Color',
help: 'Color picker',
simpleTemplate: templateFromReactComponent(ColorArgInput),
default: '#000000',
});
6 changes: 5 additions & 1 deletion public/expression_types/arg_types/index.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { axisConfig } from './axis_config';
import { color } from './color';
import { containerStyle } from './container_style';
import { datacolumn } from './datacolumn';
import { font } from './font';
Expand All @@ -7,21 +8,24 @@ import { number } from './number';
import { palette } from './palette';
import { select } from './select';
import { seriesStyle } from './series_style';
import { shape } from './shape';
import { string } from './string';
import { textarea } from './textarea';
import { toggle } from './toggle';

export const argTypeSpecs = [
axisConfig,
color,
containerStyle,
datacolumn,
font,
imageUpload,
number,
palette,
select,
string,
seriesStyle,
shape,
string,
textarea,
toggle,
];
1 change: 1 addition & 0 deletions public/expression_types/arg_types/number.js
Original file line number Diff line number Diff line change
Expand Up @@ -56,4 +56,5 @@ export const number = () => ({
displayName: 'number',
help: 'Input a number',
simpleTemplate: templateFromReactComponent(EnhancedNumberArgInput),
default: '0',
});
27 changes: 27 additions & 0 deletions public/expression_types/arg_types/shape.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import React from 'react';
import PropTypes from 'prop-types';
import { EuiFlexGroup, EuiFlexItem } from '@elastic/eui';
import { shapes } from '../../render_functions/shape/shapes';
import { templateFromReactComponent } from '../../lib/template_from_react_component';
import { ShapePickerMini } from '../../components/shape_picker_mini/';

const ShapeArgInput = ({ onValueChange, argValue }) => (
<EuiFlexGroup gutterSize="s">
<EuiFlexItem grow={false}>
<ShapePickerMini value={argValue} onChange={onValueChange} shapes={shapes} />
</EuiFlexItem>
</EuiFlexGroup>
);

ShapeArgInput.propTypes = {
argValue: PropTypes.any.isRequired,
onValueChange: PropTypes.func.isRequired,
};

export const shape = () => ({
name: 'shape',
displayName: 'Shape',
help: 'Shape picker',
simpleTemplate: templateFromReactComponent(ShapeArgInput),
default: '"square"',
});
1 change: 1 addition & 0 deletions public/expression_types/arg_types/toggle.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,4 +20,5 @@ export const toggle = () => ({
displayName: 'Toggle',
help: 'A true/false toggle switch',
simpleTemplate: templateFromReactComponent(ToggleArgInput),
default: 'false',
});
2 changes: 2 additions & 0 deletions public/expression_types/views/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { plot } from './plot';
import { repeatImage } from './repeatImage';
import { revealImage } from './revealImage';
import { render } from './render';
import { shape } from './shape';
import { table } from './table';
import { timefilterControl } from './timefilterControl';

Expand All @@ -18,6 +19,7 @@ export const viewSpecs = [
repeatImage,
revealImage,
render,
shape,
table,
timefilterControl,
];
Loading

0 comments on commit 676d544

Please sign in to comment.