mirror of
https://github.com/elastic/kibana.git
synced 2025-04-23 09:19:04 -04:00
* Shapes stories + TS * Merging storybook into shapes-ts-stories * A few tweaks
This commit is contained in:
parent
d7a228a37c
commit
15ddcb9992
19 changed files with 332 additions and 26 deletions
|
@ -9,8 +9,22 @@ import initStoryshots, { multiSnapshotWithOptions } from '@storybook/addon-story
|
|||
import styleSheetSerializer from 'jest-styled-components/src/styleSheetSerializer';
|
||||
import { addSerializer } from 'jest-specific-snapshot';
|
||||
|
||||
// Mock EUI generated ids to be consistently predictable for snapshots.
|
||||
jest.mock(`@elastic/eui/lib/components/form/form_row/make_id`, () => () => `generated-id`);
|
||||
|
||||
// Jest automatically mocks SVGs to be a plain-text string that isn't an SVG. Canvas uses
|
||||
// them in examples, so let's mock a few for tests.
|
||||
jest.mock('../canvas_plugin_src/renderers/shape/shapes', () => ({
|
||||
shapes: {
|
||||
arrow: `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100">
|
||||
<polygon points="0,40 60,40 60,20 95,50 60,80 60,60 0,60" />
|
||||
</svg>`,
|
||||
square: `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100">
|
||||
<rect x="0" y="0" width="100" height="100" />
|
||||
</svg>`,
|
||||
},
|
||||
}));
|
||||
|
||||
addSerializer(styleSheetSerializer);
|
||||
|
||||
// Initialize Storyshots and build the Jest Snapshots
|
||||
|
|
|
@ -8,12 +8,12 @@ import React from 'react';
|
|||
import PropTypes from 'prop-types';
|
||||
import { EuiFlexGroup, EuiFlexItem } from '@elastic/eui';
|
||||
import { templateFromReactComponent } from '../../../public/lib/template_from_react_component';
|
||||
import { ShapePickerMini } from '../../../public/components/shape_picker_mini/';
|
||||
import { ShapePickerPopover } from '../../../public/components/shape_picker_popover/';
|
||||
|
||||
const ShapeArgInput = ({ onValueChange, argValue, typeInstance }) => (
|
||||
<EuiFlexGroup gutterSize="s">
|
||||
<EuiFlexItem grow={false}>
|
||||
<ShapePickerMini
|
||||
<ShapePickerPopover
|
||||
value={argValue}
|
||||
onChange={onValueChange}
|
||||
shapes={typeInstance.options.shapes}
|
||||
|
|
|
@ -0,0 +1,48 @@
|
|||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`Storyshots components/Shapes/ShapePicker default 1`] = `
|
||||
<div
|
||||
className="euiFlexGrid euiFlexGrid--gutterSmall euiFlexGrid--fourths euiFlexGrid--responsive canvasShapePicker"
|
||||
>
|
||||
<div
|
||||
className="euiFlexItem"
|
||||
>
|
||||
<button
|
||||
className="euiLink euiLink--primary"
|
||||
onClick={[Function]}
|
||||
type="button"
|
||||
>
|
||||
<div
|
||||
className="canvasShapePreview"
|
||||
dangerouslySetInnerHTML={
|
||||
Object {
|
||||
"__html": "<svg xmlns=\\"http://www.w3.org/2000/svg\\" viewBox=\\"-2.5 -2.5 105 105\\" fill=\\"none\\" stroke=\\"black\\">
|
||||
<polygon points=\\"0,40 60,40 60,20 95,50 60,80 60,60 0,60\\"></polygon>
|
||||
</svg>",
|
||||
}
|
||||
}
|
||||
/>
|
||||
</button>
|
||||
</div>
|
||||
<div
|
||||
className="euiFlexItem"
|
||||
>
|
||||
<button
|
||||
className="euiLink euiLink--primary"
|
||||
onClick={[Function]}
|
||||
type="button"
|
||||
>
|
||||
<div
|
||||
className="canvasShapePreview"
|
||||
dangerouslySetInnerHTML={
|
||||
Object {
|
||||
"__html": "<svg xmlns=\\"http://www.w3.org/2000/svg\\" viewBox=\\"-2.5 -2.5 105 105\\" fill=\\"none\\" stroke=\\"black\\">
|
||||
<rect x=\\"0\\" y=\\"0\\" width=\\"100\\" height=\\"100\\"></rect>
|
||||
</svg>",
|
||||
}
|
||||
}
|
||||
/>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
|
@ -0,0 +1,16 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import { action } from '@storybook/addon-actions';
|
||||
import { storiesOf } from '@storybook/react';
|
||||
import React from 'react';
|
||||
import { ShapePicker } from '../shape_picker';
|
||||
|
||||
import { shapes } from '../../../../canvas_plugin_src/renderers/shape/shapes';
|
||||
|
||||
storiesOf('components/Shapes/ShapePicker', module).add('default', () => (
|
||||
<ShapePicker shapes={shapes} onChange={action('onChange')} />
|
||||
));
|
|
@ -0,0 +1,3 @@
|
|||
.canvasShapePicker {
|
||||
width: ($euiSizeXXL * 4) + ($euiSizeS * 4);
|
||||
}
|
|
@ -9,9 +9,16 @@ import PropTypes from 'prop-types';
|
|||
import { EuiFlexGrid, EuiFlexItem, EuiLink } from '@elastic/eui';
|
||||
import { ShapePreview } from '../shape_preview';
|
||||
|
||||
export const ShapePicker = ({ shapes, onChange }) => {
|
||||
interface Props {
|
||||
shapes: {
|
||||
[key: string]: string;
|
||||
};
|
||||
onChange?: (key: string) => void;
|
||||
}
|
||||
|
||||
export const ShapePicker = ({ shapes, onChange = () => {} }: Props) => {
|
||||
return (
|
||||
<EuiFlexGrid gutterSize="s" columns={4}>
|
||||
<EuiFlexGrid gutterSize="s" columns={4} className="canvasShapePicker">
|
||||
{Object.keys(shapes)
|
||||
.sort()
|
||||
.map(shapeKey => (
|
|
@ -1,3 +0,0 @@
|
|||
.canvasShapePickerMini--popover {
|
||||
width: 220px;
|
||||
}
|
|
@ -0,0 +1,108 @@
|
|||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`Storyshots components/Shapes/ShapePickerPopover default 1`] = `
|
||||
<div
|
||||
className="euiPopover euiPopover--anchorDownCenter"
|
||||
container={null}
|
||||
onKeyDown={[Function]}
|
||||
onMouseDown={[Function]}
|
||||
onMouseUp={[Function]}
|
||||
onTouchEnd={[Function]}
|
||||
onTouchStart={[Function]}
|
||||
>
|
||||
<div
|
||||
className="euiPopover__anchor"
|
||||
>
|
||||
<button
|
||||
className="euiLink euiLink--primary"
|
||||
onClick={[Function]}
|
||||
style={
|
||||
Object {
|
||||
"fontSize": 0,
|
||||
}
|
||||
}
|
||||
type="button"
|
||||
>
|
||||
<div
|
||||
className="canvasShapePreview"
|
||||
/>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`Storyshots components/Shapes/ShapePickerPopover interactive 1`] = `
|
||||
<div
|
||||
className="euiPopover euiPopover--anchorDownCenter"
|
||||
container={null}
|
||||
onKeyDown={[Function]}
|
||||
onMouseDown={[Function]}
|
||||
onMouseUp={[Function]}
|
||||
onTouchEnd={[Function]}
|
||||
onTouchStart={[Function]}
|
||||
>
|
||||
<div
|
||||
className="euiPopover__anchor"
|
||||
>
|
||||
<button
|
||||
className="euiLink euiLink--primary"
|
||||
onClick={[Function]}
|
||||
style={
|
||||
Object {
|
||||
"fontSize": 0,
|
||||
}
|
||||
}
|
||||
type="button"
|
||||
>
|
||||
<div
|
||||
className="canvasShapePreview"
|
||||
dangerouslySetInnerHTML={
|
||||
Object {
|
||||
"__html": "<svg xmlns=\\"http://www.w3.org/2000/svg\\" viewBox=\\"-2.5 -2.5 105 105\\" fill=\\"none\\" stroke=\\"black\\">
|
||||
<rect x=\\"0\\" y=\\"0\\" width=\\"100\\" height=\\"100\\"></rect>
|
||||
</svg>",
|
||||
}
|
||||
}
|
||||
/>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`Storyshots components/Shapes/ShapePickerPopover shape selected 1`] = `
|
||||
<div
|
||||
className="euiPopover euiPopover--anchorDownCenter"
|
||||
container={null}
|
||||
onKeyDown={[Function]}
|
||||
onMouseDown={[Function]}
|
||||
onMouseUp={[Function]}
|
||||
onTouchEnd={[Function]}
|
||||
onTouchStart={[Function]}
|
||||
>
|
||||
<div
|
||||
className="euiPopover__anchor"
|
||||
>
|
||||
<button
|
||||
className="euiLink euiLink--primary"
|
||||
onClick={[Function]}
|
||||
style={
|
||||
Object {
|
||||
"fontSize": 0,
|
||||
}
|
||||
}
|
||||
type="button"
|
||||
>
|
||||
<div
|
||||
className="canvasShapePreview"
|
||||
dangerouslySetInnerHTML={
|
||||
Object {
|
||||
"__html": "<svg xmlns=\\"http://www.w3.org/2000/svg\\" viewBox=\\"-2.5 -2.5 105 105\\" fill=\\"none\\" stroke=\\"black\\">
|
||||
<rect x=\\"0\\" y=\\"0\\" width=\\"100\\" height=\\"100\\"></rect>
|
||||
</svg>",
|
||||
}
|
||||
}
|
||||
/>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
|
@ -0,0 +1,40 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import { action } from '@storybook/addon-actions';
|
||||
import { storiesOf } from '@storybook/react';
|
||||
import React from 'react';
|
||||
import { ShapePickerPopover } from '../shape_picker_popover';
|
||||
|
||||
import { shapes } from '../../../../canvas_plugin_src/renderers/shape/shapes';
|
||||
|
||||
class Interactive extends React.Component<{}, { value: string }> {
|
||||
public state = {
|
||||
value: 'square',
|
||||
};
|
||||
|
||||
public render() {
|
||||
return (
|
||||
<ShapePickerPopover
|
||||
shapes={shapes}
|
||||
onChange={value => this.setState({ value })}
|
||||
value={this.state.value}
|
||||
/>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
storiesOf('components/Shapes/ShapePickerPopover', module)
|
||||
.add('default', () => <ShapePickerPopover shapes={shapes} onChange={action('onChange')} />)
|
||||
.add('shape selected', () => (
|
||||
<ShapePickerPopover shapes={shapes} onChange={action('onChange')} value="square" />
|
||||
))
|
||||
.add('interactive', () => <Interactive />, {
|
||||
info: {
|
||||
source: false,
|
||||
propTablesExclude: [Interactive],
|
||||
},
|
||||
});
|
|
@ -6,6 +6,6 @@
|
|||
|
||||
import { pure } from 'recompose';
|
||||
|
||||
import { ShapePickerMini as Component } from './shape_picker_mini';
|
||||
import { ShapePickerPopover as Component } from './shape_picker_popover';
|
||||
|
||||
export const ShapePickerMini = pure(Component);
|
||||
export const ShapePickerPopover = pure(Component);
|
|
@ -7,29 +7,41 @@
|
|||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { EuiLink } from '@elastic/eui';
|
||||
// @ts-ignore untyped local
|
||||
import { Popover } from '../popover';
|
||||
import { ShapePicker } from '../shape_picker/';
|
||||
import { ShapePicker } from '../shape_picker';
|
||||
import { ShapePreview } from '../shape_preview';
|
||||
|
||||
export const ShapePickerMini = ({ shapes, onChange, value, anchorPosition }) => {
|
||||
const button = handleClick => (
|
||||
export enum AnchorPosition {
|
||||
TOP = 'top',
|
||||
BOTTOM = 'bottom',
|
||||
LEFT = 'left',
|
||||
RIGHT = 'right',
|
||||
}
|
||||
interface Props {
|
||||
shapes: {
|
||||
[key: string]: string;
|
||||
};
|
||||
onChange?: (key: string) => void;
|
||||
value?: string;
|
||||
anchorPosition?: AnchorPosition;
|
||||
}
|
||||
|
||||
export const ShapePickerPopover = ({ shapes, onChange, value, anchorPosition }: Props) => {
|
||||
const button = (handleClick: () => unknown) => (
|
||||
<EuiLink style={{ fontSize: 0 }} onClick={handleClick}>
|
||||
<ShapePreview shape={shapes[value]} />
|
||||
<ShapePreview shape={value ? shapes[value] : undefined} />
|
||||
</EuiLink>
|
||||
);
|
||||
|
||||
return (
|
||||
<Popover
|
||||
panelClassName="canvas canvasShapePickerMini--popover"
|
||||
button={button}
|
||||
anchorPosition={anchorPosition}
|
||||
>
|
||||
<Popover panelClassName="canvas" button={button} anchorPosition={anchorPosition}>
|
||||
{() => <ShapePicker onChange={onChange} shapes={shapes} />}
|
||||
</Popover>
|
||||
);
|
||||
};
|
||||
|
||||
ShapePickerMini.propTypes = {
|
||||
ShapePickerPopover.propTypes = {
|
||||
shapes: PropTypes.object.isRequired,
|
||||
value: PropTypes.string,
|
||||
onChange: PropTypes.func,
|
|
@ -0,0 +1,27 @@
|
|||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`Storyshots components/Shapes/ShapePreview arrow 1`] = `
|
||||
<div
|
||||
className="canvasShapePreview"
|
||||
dangerouslySetInnerHTML={
|
||||
Object {
|
||||
"__html": "<svg xmlns=\\"http://www.w3.org/2000/svg\\" viewBox=\\"-2.5 -2.5 105 105\\" fill=\\"none\\" stroke=\\"black\\">
|
||||
<polygon points=\\"0,40 60,40 60,20 95,50 60,80 60,60 0,60\\"></polygon>
|
||||
</svg>",
|
||||
}
|
||||
}
|
||||
/>
|
||||
`;
|
||||
|
||||
exports[`Storyshots components/Shapes/ShapePreview square 1`] = `
|
||||
<div
|
||||
className="canvasShapePreview"
|
||||
dangerouslySetInnerHTML={
|
||||
Object {
|
||||
"__html": "<svg xmlns=\\"http://www.w3.org/2000/svg\\" viewBox=\\"-2.5 -2.5 105 105\\" fill=\\"none\\" stroke=\\"black\\">
|
||||
<rect x=\\"0\\" y=\\"0\\" width=\\"100\\" height=\\"100\\"></rect>
|
||||
</svg>",
|
||||
}
|
||||
}
|
||||
/>
|
||||
`;
|
|
@ -0,0 +1,15 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import { storiesOf } from '@storybook/react';
|
||||
import React from 'react';
|
||||
import { ShapePreview } from '../shape_preview';
|
||||
|
||||
import { shapes } from '../../../../canvas_plugin_src/renderers/shape/shapes';
|
||||
|
||||
storiesOf('components/Shapes/ShapePreview', module)
|
||||
.add('arrow', () => <ShapePreview shape={shapes.arrow} />)
|
||||
.add('square', () => <ShapePreview shape={shapes.square} />);
|
|
@ -7,17 +7,31 @@
|
|||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
export const ShapePreview = ({ shape }) => {
|
||||
interface Props {
|
||||
shape?: string;
|
||||
}
|
||||
|
||||
export const ShapePreview = ({ shape }: Props) => {
|
||||
if (!shape) {
|
||||
return <div className="canvasShapePreview" />;
|
||||
}
|
||||
|
||||
const weight = 5;
|
||||
const parser = new DOMParser();
|
||||
const [shapeSvg] = parser.parseFromString(shape, 'image/svg+xml').getElementsByTagName('svg');
|
||||
const shapeSvg = parser
|
||||
.parseFromString(shape, 'image/svg+xml')
|
||||
.getElementsByTagName('svg')
|
||||
.item(0);
|
||||
|
||||
if (!shapeSvg) {
|
||||
throw new Error('An unexpected error occurred: the SVG was not parseable');
|
||||
}
|
||||
|
||||
shapeSvg.setAttribute('fill', 'none');
|
||||
shapeSvg.setAttribute('stroke', 'black');
|
||||
|
||||
const initialViewBox = shapeSvg
|
||||
.getAttribute('viewBox')
|
||||
.split(' ')
|
||||
.map(v => parseInt(v, 10));
|
||||
const viewBox = shapeSvg.getAttribute('viewBox') || '0 0 0 0';
|
||||
const initialViewBox = viewBox.split(' ').map((v: string) => parseInt(v, 10));
|
||||
|
||||
let [minX, minY, width, height] = initialViewBox;
|
||||
minX -= weight / 2;
|
|
@ -44,7 +44,7 @@
|
|||
@import '../components/remove_icon/remove_icon';
|
||||
@import '../components/rotation_handle/rotation_handle';
|
||||
@import '../components/shape_preview/shape_preview';
|
||||
@import '../components/shape_picker_mini/shape_picker_mini';
|
||||
@import '../components/shape_picker/shape_picker';
|
||||
@import '../components/sidebar/sidebar';
|
||||
@import '../components/sidebar_header/sidebar_header';
|
||||
@import '../components/toolbar/toolbar';
|
||||
|
|
5
x-pack/plugins/canvas/types/webpack.d.ts
vendored
5
x-pack/plugins/canvas/types/webpack.d.ts
vendored
|
@ -5,3 +5,8 @@
|
|||
*/
|
||||
|
||||
declare module '*.png';
|
||||
|
||||
declare module '*.svg' {
|
||||
const content: string;
|
||||
export = content;
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue