diff --git a/.eslintrc.js b/.eslintrc.js index 09de32a91bca3c..67c52117399cc5 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -446,6 +446,7 @@ module.exports = { '!(src|x-pack)/plugins/**/(public|server)/mocks/index.{js,mjs,ts}', '!(src|x-pack)/plugins/**/(public|server)/(index|mocks).{js,mjs,ts,tsx}', '!(src|x-pack)/plugins/**/__stories__/index.{js,mjs,ts,tsx}', + '!(src|x-pack)/plugins/**/__fixtures__/index.{js,mjs,ts,tsx}', ], allowSameFolder: true, errorMessage: 'Plugins may only import from top-level public and server modules.', diff --git a/.i18nrc.json b/.i18nrc.json index 732644b43e1f7c..65ea4d522af5c6 100644 --- a/.i18nrc.json +++ b/.i18nrc.json @@ -18,6 +18,7 @@ "expressions": "src/plugins/expressions", "expressionError": "src/plugins/expression_error", "expressionRevealImage": "src/plugins/expression_reveal_image", + "expressionShape": "src/plugins/expression_shape", "inputControl": "src/plugins/input_control_vis", "inspector": "src/plugins/inspector", "inspectorViews": "src/legacy/core_plugins/inspector_views", diff --git a/docs/developer/plugin-list.asciidoc b/docs/developer/plugin-list.asciidoc index c1535e8a2146f0..8e08e5f4db1f98 100644 --- a/docs/developer/plugin-list.asciidoc +++ b/docs/developer/plugin-list.asciidoc @@ -99,6 +99,10 @@ want to incorporate their own functions, types, and renderers into the service for use in their own application. +|{kib-repo}blob/{branch}/src/plugins/expression_shape/README.md[expressionShape] +|Expression Shape plugin adds a shape function to the expression plugin and an associated renderer. The renderer will display the given shape with selected decorations. + + |{kib-repo}blob/{branch}/src/plugins/home/README.md[home] |Moves the legacy ui/registry/feature_catalogue module for registering "features" that should be shown in the home page's feature catalogue to a service within a "home" plugin. The feature catalogue refered to here should not be confused with the "feature" plugin for registering features used to derive UI capabilities for feature controls. diff --git a/packages/kbn-optimizer/limits.yml b/packages/kbn-optimizer/limits.yml index 49d4bdbc2de64b..7a2c9095e20111 100644 --- a/packages/kbn-optimizer/limits.yml +++ b/packages/kbn-optimizer/limits.yml @@ -114,3 +114,4 @@ pageLoadAssetSize: cases: 144442 expressionError: 22127 userSetup: 18532 + expressionShape: 30033 diff --git a/src/dev/storybook/aliases.ts b/src/dev/storybook/aliases.ts index 15497258d45747..51ed25bfc69f66 100644 --- a/src/dev/storybook/aliases.ts +++ b/src/dev/storybook/aliases.ts @@ -19,6 +19,7 @@ export const storybookAliases = { embeddable: 'src/plugins/embeddable/.storybook', expression_error: 'src/plugins/expression_error/.storybook', expression_reveal_image: 'src/plugins/expression_reveal_image/.storybook', + expression_shape: 'src/plugins/expression_shape/.storybook', infra: 'x-pack/plugins/infra/.storybook', security_solution: 'x-pack/plugins/security_solution/.storybook', ui_actions_enhanced: 'x-pack/plugins/ui_actions_enhanced/.storybook', diff --git a/src/plugins/expression_shape/.storybook/main.js b/src/plugins/expression_shape/.storybook/main.js new file mode 100644 index 00000000000000..742239e638b8ac --- /dev/null +++ b/src/plugins/expression_shape/.storybook/main.js @@ -0,0 +1,10 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +// eslint-disable-next-line import/no-commonjs +module.exports = require('@kbn/storybook').defaultConfig; diff --git a/src/plugins/expression_shape/README.md b/src/plugins/expression_shape/README.md new file mode 100755 index 00000000000000..a7e86b6524275c --- /dev/null +++ b/src/plugins/expression_shape/README.md @@ -0,0 +1,9 @@ +# expressionShape + +Expression Shape plugin adds a `shape` function to the expression plugin and an associated renderer. The renderer will display the given shape with selected decorations. + +--- + +## Development + +See the [kibana contributing guide](https://github.com/elastic/kibana/blob/master/CONTRIBUTING.md) for instructions setting up your development environment. diff --git a/src/plugins/expression_shape/__fixtures__/function_specs.ts b/src/plugins/expression_shape/__fixtures__/function_specs.ts new file mode 100644 index 00000000000000..c75cb5c61caa1d --- /dev/null +++ b/src/plugins/expression_shape/__fixtures__/function_specs.ts @@ -0,0 +1,12 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { shapeFunction } from '../common/expression_functions'; +import { ExpressionFunction } from '../../../../src/plugins/expressions'; + +export const functionSpecs = [shapeFunction].map((fn) => new ExpressionFunction(fn())); diff --git a/src/plugins/expression_shape/__fixtures__/index.ts b/src/plugins/expression_shape/__fixtures__/index.ts new file mode 100644 index 00000000000000..048c916b21b251 --- /dev/null +++ b/src/plugins/expression_shape/__fixtures__/index.ts @@ -0,0 +1,9 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +export * from './function_specs'; diff --git a/src/plugins/expression_shape/common/constants.ts b/src/plugins/expression_shape/common/constants.ts new file mode 100644 index 00000000000000..ba048e376dabc8 --- /dev/null +++ b/src/plugins/expression_shape/common/constants.ts @@ -0,0 +1,11 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +export const PLUGIN_ID = 'expressionShape'; +export const PLUGIN_NAME = 'expressionShape'; +export const SVG = 'SVG'; diff --git a/src/plugins/expression_shape/common/expression_functions/index.ts b/src/plugins/expression_shape/common/expression_functions/index.ts new file mode 100644 index 00000000000000..fb19cf244a9ddd --- /dev/null +++ b/src/plugins/expression_shape/common/expression_functions/index.ts @@ -0,0 +1,9 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +export { shapeFunction } from './shape_function'; diff --git a/src/plugins/expression_shape/common/expression_functions/shape_function.ts b/src/plugins/expression_shape/common/expression_functions/shape_function.ts new file mode 100644 index 00000000000000..8ee11c937599ff --- /dev/null +++ b/src/plugins/expression_shape/common/expression_functions/shape_function.ts @@ -0,0 +1,106 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { i18n } from '@kbn/i18n'; +import { ExpressionShapeFunction, Shape } from '../types'; +import { SVG } from '../constants'; +import { getAvailableShapes } from '../lib'; + +export const strings = { + help: i18n.translate('expressionShape.functions.shapeHelpText', { + defaultMessage: 'Creates a shape.', + }), + args: { + shape: i18n.translate('expressionShape.functions.shape.args.shapeHelpText', { + defaultMessage: 'Pick a shape.', + }), + border: i18n.translate('expressionShape.functions.shape.args.borderHelpText', { + defaultMessage: 'An {SVG} color for the border outlining the shape.', + values: { + SVG, + }, + }), + borderWidth: i18n.translate('expressionShape.functions.shape.args.borderWidthHelpText', { + defaultMessage: 'The thickness of the border.', + }), + fill: i18n.translate('expressionShape.functions.shape.args.fillHelpText', { + defaultMessage: 'An {SVG} color to fill the shape.', + values: { + SVG, + }, + }), + maintainAspect: i18n.translate('expressionShape.functions.shape.args.maintainAspectHelpText', { + defaultMessage: `Maintain the shape's original aspect ratio?`, + }), + }, +}; + +export const errors = { + invalidShape: (shape: string) => + new Error( + i18n.translate('expressionShape.functions.shape.invalidShapeErrorMessage', { + defaultMessage: "Invalid value: '{shape}'. Such a shape doesn't exist.", + values: { + shape, + }, + }) + ), +}; + +export const shapeFunction: ExpressionShapeFunction = () => { + const { help, args: argHelp } = strings; + + return { + name: 'shape', + aliases: [], + inputTypes: ['null'], + help, + args: { + shape: { + types: ['string'], + help: argHelp.shape, + aliases: ['_'], + default: 'square', + options: Object.values(Shape), + }, + border: { + types: ['string'], + aliases: ['stroke'], + help: argHelp.border, + }, + borderWidth: { + types: ['number'], + aliases: ['strokeWidth'], + help: argHelp.borderWidth, + default: 0, + }, + fill: { + types: ['string'], + help: argHelp.fill, + default: 'black', + }, + maintainAspect: { + types: ['boolean'], + help: argHelp.maintainAspect, + default: false, + options: [true, false], + }, + }, + fn: (input, args) => { + const avaliableShapes = getAvailableShapes(); + if (!avaliableShapes.includes(args.shape)) { + throw errors.invalidShape(args.shape); + } + + return { + type: 'shape', + ...args, + }; + }, + }; +}; diff --git a/src/plugins/expression_shape/common/index.ts b/src/plugins/expression_shape/common/index.ts new file mode 100755 index 00000000000000..7a56f49eb38cbf --- /dev/null +++ b/src/plugins/expression_shape/common/index.ts @@ -0,0 +1,12 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +export * from './constants'; +export * from './types'; + +export { getAvailableShapes } from './lib/available_shapes'; diff --git a/src/plugins/expression_shape/common/lib/available_shapes.ts b/src/plugins/expression_shape/common/lib/available_shapes.ts new file mode 100644 index 00000000000000..a8883f76e0c98f --- /dev/null +++ b/src/plugins/expression_shape/common/lib/available_shapes.ts @@ -0,0 +1,11 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { Shape } from '../types'; + +export const getAvailableShapes = () => Object.values(Shape); diff --git a/src/plugins/expression_shape/common/lib/index.ts b/src/plugins/expression_shape/common/lib/index.ts new file mode 100644 index 00000000000000..d62a0d96078be5 --- /dev/null +++ b/src/plugins/expression_shape/common/lib/index.ts @@ -0,0 +1,10 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +export * from './view_box'; +export * from './available_shapes'; diff --git a/src/plugins/expression_shape/common/lib/view_box.ts b/src/plugins/expression_shape/common/lib/view_box.ts new file mode 100644 index 00000000000000..3028d7a846ed4c --- /dev/null +++ b/src/plugins/expression_shape/common/lib/view_box.ts @@ -0,0 +1,52 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { ParentNodeParams, ViewBoxParams } from '../types'; + +export function viewBoxToString(viewBox?: ViewBoxParams): undefined | string { + if (!viewBox) return; + return `${viewBox?.minX} ${viewBox?.minY} ${viewBox?.width} ${viewBox?.height}`; +} + +function getMinxAndWidth(viewBoxParams: ViewBoxParams, { borderOffset, width }: ParentNodeParams) { + let { minX, width: shapeWidth } = viewBoxParams; + if (width) { + const xOffset = (shapeWidth / width) * borderOffset; + minX -= xOffset; + shapeWidth += xOffset * 2; + } else { + shapeWidth = 0; + } + + return [minX, shapeWidth]; +} + +function getMinyAndHeight( + viewBoxParams: ViewBoxParams, + { borderOffset, height }: ParentNodeParams +) { + let { minY, height: shapeHeight } = viewBoxParams; + if (height) { + const yOffset = (shapeHeight / height) * borderOffset; + minY -= yOffset; + shapeHeight += yOffset * 2; + } else { + shapeHeight = 0; + } + + return [minY, shapeHeight]; +} + +export function getViewBox( + viewBoxParams: ViewBoxParams, + parentNodeParams: ParentNodeParams +): ViewBoxParams { + const [minX, width] = getMinxAndWidth(viewBoxParams, parentNodeParams); + const [minY, height] = getMinyAndHeight(viewBoxParams, parentNodeParams); + return { minX, minY, width, height }; +} diff --git a/src/plugins/expression_shape/common/types/expression_functions.ts b/src/plugins/expression_shape/common/types/expression_functions.ts new file mode 100644 index 00000000000000..4f0fad62fde049 --- /dev/null +++ b/src/plugins/expression_shape/common/types/expression_functions.ts @@ -0,0 +1,46 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ +import { ExpressionFunctionDefinition } from 'src/plugins/expressions'; + +export enum Shape { + ARROW = 'arrow', + ARROW_MULTI = 'arrowMulti', + BOOKMARK = 'bookmark', + CIRCLE = 'circle', + CROSS = 'cross', + HEXAGON = 'hexagon', + KITE = 'kite', + PENTAGON = 'pentagon', + RHOMBUS = 'rhombus', + SEMICIRCLE = 'semicircle', + SPEECH_BUBBLE = 'speechBubble', + SQUARE = 'square', + STAR = 'star', + TAG = 'tag', + TRIANGLE = 'triangle', + TRIANGLE_RIGHT = 'triangleRight', +} + +interface Arguments { + border: string; + borderWidth: number; + shape: Shape; + fill: string; + maintainAspect: boolean; +} + +export interface Output extends Arguments { + type: 'shape'; +} + +export type ExpressionShapeFunction = () => ExpressionFunctionDefinition< + 'shape', + number | null, + Arguments, + Output +>; diff --git a/src/plugins/expression_shape/common/types/expression_renderers.ts b/src/plugins/expression_shape/common/types/expression_renderers.ts new file mode 100644 index 00000000000000..c61d8292ddff65 --- /dev/null +++ b/src/plugins/expression_shape/common/types/expression_renderers.ts @@ -0,0 +1,35 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ +import { Shape } from './expression_functions'; + +export type OriginString = 'bottom' | 'left' | 'top' | 'right'; +export interface ShapeRendererConfig { + border: string; + borderWidth: number; + shape: Shape; + fill: string; + maintainAspect: boolean; +} + +export interface NodeDimensions { + width: number; + height: number; +} + +export interface ParentNodeParams { + borderOffset: number; + width: number; + height: number; +} + +export interface ViewBoxParams { + minX: number; + minY: number; + width: number; + height: number; +} diff --git a/src/plugins/expression_shape/common/types/index.ts b/src/plugins/expression_shape/common/types/index.ts new file mode 100644 index 00000000000000..ec934e7affe88b --- /dev/null +++ b/src/plugins/expression_shape/common/types/index.ts @@ -0,0 +1,9 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ +export * from './expression_functions'; +export * from './expression_renderers'; diff --git a/src/plugins/expression_shape/jest.config.js b/src/plugins/expression_shape/jest.config.js new file mode 100644 index 00000000000000..a390c0154bbd0b --- /dev/null +++ b/src/plugins/expression_shape/jest.config.js @@ -0,0 +1,13 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +module.exports = { + preset: '@kbn/test', + rootDir: '../../..', + roots: ['/src/plugins/expression_shape'], +}; diff --git a/src/plugins/expression_shape/kibana.json b/src/plugins/expression_shape/kibana.json new file mode 100755 index 00000000000000..1a868288a2df8c --- /dev/null +++ b/src/plugins/expression_shape/kibana.json @@ -0,0 +1,13 @@ +{ + "id": "expressionShape", + "version": "1.0.0", + "kibanaVersion": "kibana", + "server": true, + "ui": true, + "extraPublicDirs": [ + "common" + ], + "requiredPlugins": ["expressions", "presentationUtil"], + "optionalPlugins": [], + "requiredBundles": [] +} diff --git a/src/plugins/expression_shape/public/components/reusable/index.tsx b/src/plugins/expression_shape/public/components/reusable/index.tsx new file mode 100644 index 00000000000000..0e78432a0ceb4b --- /dev/null +++ b/src/plugins/expression_shape/public/components/reusable/index.tsx @@ -0,0 +1,11 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +export * from './shape_drawer'; +export * from './utils'; +export * from './types'; diff --git a/src/plugins/expression_shape/public/components/reusable/shape_drawer.tsx b/src/plugins/expression_shape/public/components/reusable/shape_drawer.tsx new file mode 100644 index 00000000000000..b976dfad389b3b --- /dev/null +++ b/src/plugins/expression_shape/public/components/reusable/shape_drawer.tsx @@ -0,0 +1,23 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import React, { forwardRef, Ref, useImperativeHandle } from 'react'; +import { ShapeDrawerProps, ShapeRef } from './types'; + +function ShapeDrawerComponent(props: ShapeDrawerProps, ref: Ref) { + const { shapeType, getShape } = props; + const Shape = getShape(shapeType); + + if (!Shape) throw new Error("Shape doesn't exist."); + + useImperativeHandle(ref, () => ({ getData: () => Shape.data }), [Shape]); + + return ; +} + +export const ShapeDrawer = forwardRef(ShapeDrawerComponent); diff --git a/src/plugins/expression_shape/public/components/reusable/shape_factory.tsx b/src/plugins/expression_shape/public/components/reusable/shape_factory.tsx new file mode 100644 index 00000000000000..9e775616726bfc --- /dev/null +++ b/src/plugins/expression_shape/public/components/reusable/shape_factory.tsx @@ -0,0 +1,49 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import React from 'react'; +import { viewBoxToString } from '../../../common/lib'; +import { ShapeProps, SvgConfig, SvgElementTypes } from './types'; + +const getShapeComponent = (svgParams: SvgConfig) => + function Shape({ shapeAttributes, shapeContentAttributes }: ShapeProps) { + const { viewBox: initialViewBox, shapeProps, shapeType } = svgParams; + + const viewBox = shapeAttributes?.viewBox + ? viewBoxToString(shapeAttributes?.viewBox) + : viewBoxToString(initialViewBox); + + const SvgContentElement = getShapeContentElement(shapeType); + return ( + + + + ); + }; + +function getShapeContentElement(type?: SvgElementTypes) { + switch (type) { + case SvgElementTypes.circle: + return (props: SvgConfig['shapeProps']) => ; + case SvgElementTypes.rect: + return (props: SvgConfig['shapeProps']) => ; + case SvgElementTypes.path: + return (props: SvgConfig['shapeProps']) => ; + default: + return (props: SvgConfig['shapeProps']) => ; + } +} + +export const createShape = (props: SvgConfig) => { + return { + Component: getShapeComponent(props), + data: props, + }; +}; + +export type ShapeType = ReturnType; diff --git a/src/plugins/expression_shape/public/components/reusable/types.tsx b/src/plugins/expression_shape/public/components/reusable/types.tsx new file mode 100644 index 00000000000000..f779633e08a87a --- /dev/null +++ b/src/plugins/expression_shape/public/components/reusable/types.tsx @@ -0,0 +1,83 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { Ref, SVGProps } from 'react'; +import { ViewBoxParams } from '../../../common/types'; +import type { ShapeType } from './shape_factory'; + +export interface ShapeProps { + shapeAttributes?: ShapeAttributes; + shapeContentAttributes?: ShapeContentAttributes; +} + +export enum SvgElementTypes { + polygon, + circle, + rect, + path, +} + +export interface ShapeAttributes { + fill?: SVGProps['fill']; + stroke?: SVGProps['stroke']; + width?: SVGProps['width']; + height?: SVGProps['height']; + viewBox?: ViewBoxParams; + overflow?: SVGProps['overflow']; + preserveAspectRatio?: SVGProps['preserveAspectRatio']; +} + +export interface ShapeContentAttributes { + strokeWidth?: SVGProps['strokeWidth']; + stroke?: SVGProps['stroke']; + fill?: SVGProps['fill']; + vectorEffect?: SVGProps['vectorEffect']; + strokeMiterlimit?: SVGProps['strokeMiterlimit']; +} + +interface CircleParams { + r: SVGProps['r']; + cx: SVGProps['cx']; + cy: SVGProps['cy']; +} + +interface RectParams { + x: SVGProps['x']; + y: SVGProps['y']; + width: SVGProps['width']; + height: SVGProps['height']; +} + +interface PathParams { + d: SVGProps['d']; +} + +interface PolygonParams { + points?: SVGProps['points']; + strokeLinejoin?: SVGProps['strokeLinejoin']; +} + +type SpecificShapeContentAttributes = CircleParams | RectParams | PathParams | PolygonParams; + +export interface SvgConfig { + shapeType?: SvgElementTypes; + viewBox: ViewBoxParams; + shapeProps: ShapeContentAttributes & SpecificShapeContentAttributes; +} + +export type ShapeDrawerProps = { + shapeType: string; + getShape: (shapeType: string) => ShapeType | undefined; + ref: Ref; +} & ShapeProps; + +export interface ShapeRef { + getData: () => SvgConfig; +} + +export type { ShapeType }; diff --git a/src/plugins/expression_shape/public/components/reusable/utils.ts b/src/plugins/expression_shape/public/components/reusable/utils.ts new file mode 100644 index 00000000000000..72fed421dabe05 --- /dev/null +++ b/src/plugins/expression_shape/public/components/reusable/utils.ts @@ -0,0 +1,19 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { SvgConfig } from './types'; + +export const getDefaultShapeData = (): SvgConfig => ({ + viewBox: { + minX: 0, + minY: 0, + width: 0, + height: 0, + }, + shapeProps: {}, +}); diff --git a/src/plugins/expression_shape/public/components/shape/index.ts b/src/plugins/expression_shape/public/components/shape/index.ts new file mode 100644 index 00000000000000..12c852090ab4d9 --- /dev/null +++ b/src/plugins/expression_shape/public/components/shape/index.ts @@ -0,0 +1,12 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { lazy } from 'react'; + +export const LazyShapeComponent = lazy(() => import('./shape_component')); +export const LazyShapeDrawer = lazy(() => import('./shape_drawer')); diff --git a/src/plugins/expression_shape/public/components/shape/shape_component.tsx b/src/plugins/expression_shape/public/components/shape/shape_component.tsx new file mode 100644 index 00000000000000..9e7aba33f5834c --- /dev/null +++ b/src/plugins/expression_shape/public/components/shape/shape_component.tsx @@ -0,0 +1,93 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import React, { useState, useEffect, useCallback, RefCallback } from 'react'; +import { useResizeObserver } from '@elastic/eui'; +import { withSuspense } from '../../../../presentation_util/public'; +import { + ShapeRef, + ShapeAttributes, + ShapeContentAttributes, + SvgConfig, + getDefaultShapeData, +} from '../reusable'; +import { Dimensions, ShapeComponentProps } from './types'; +import { getViewBox } from '../../../common/lib'; +import { LazyShapeDrawer } from '../..'; + +const ShapeDrawer = withSuspense(LazyShapeDrawer); + +function ShapeComponent({ + onLoaded, + parentNode, + shape: shapeType, + fill, + border, + borderWidth, + maintainAspect, +}: ShapeComponentProps) { + const parentNodeDimensions = useResizeObserver(parentNode); + const [dimensions, setDimensions] = useState({ + width: parentNode.offsetWidth, + height: parentNode.offsetHeight, + }); + const [shapeData, setShapeData] = useState(getDefaultShapeData()); + + useEffect(() => { + setDimensions({ + width: parentNode.offsetWidth, + height: parentNode.offsetHeight, + }); + onLoaded(); + }, [parentNode, parentNodeDimensions, onLoaded]); + + const shapeRef = useCallback>((node) => { + if (node !== null) setShapeData(node.getData()); + }, []); + + const strokeWidth = Math.max(borderWidth, 0); + + const shapeContentAttributes: ShapeContentAttributes = { + strokeWidth: String(strokeWidth), + vectorEffect: 'non-scaling-stroke', + strokeMiterlimit: '999', + }; + if (fill) shapeContentAttributes.fill = fill; + if (border) shapeContentAttributes.stroke = border; + + const { width, height } = dimensions; + + const shapeAttributes: ShapeAttributes = { + width, + height, + overflow: 'visible', + preserveAspectRatio: maintainAspect ? 'xMidYMid meet' : 'none', + viewBox: getViewBox(shapeData.viewBox, { + borderOffset: strokeWidth, + width, + height, + }), + }; + + parentNode.style.lineHeight = '0'; + + return ( +
+ +
+ ); +} + +// default export required for React.Lazy +// eslint-disable-next-line import/no-default-export +export { ShapeComponent as default }; diff --git a/src/plugins/expression_shape/public/components/shape/shape_drawer.tsx b/src/plugins/expression_shape/public/components/shape/shape_drawer.tsx new file mode 100644 index 00000000000000..90906c203332a7 --- /dev/null +++ b/src/plugins/expression_shape/public/components/shape/shape_drawer.tsx @@ -0,0 +1,20 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ +import React, { Ref } from 'react'; +import { ShapeDrawer, ShapeRef } from '../reusable'; +import { getShape } from './shapes'; +import { ShapeDrawerComponentProps } from './types'; + +const ShapeDrawerComponent = React.forwardRef( + (props: ShapeDrawerComponentProps, ref: Ref) => ( + + ) +); + +// eslint-disable-next-line import/no-default-export +export { ShapeDrawerComponent as default }; diff --git a/src/plugins/expression_shape/public/components/shape/shapes/arrow.tsx b/src/plugins/expression_shape/public/components/shape/shapes/arrow.tsx new file mode 100644 index 00000000000000..9ae5dafaed0eef --- /dev/null +++ b/src/plugins/expression_shape/public/components/shape/shapes/arrow.tsx @@ -0,0 +1,20 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ +import { createShape } from '../../reusable/shape_factory'; + +export const Arrow = createShape({ + viewBox: { + minX: 0, + minY: 0, + width: 100, + height: 100, + }, + shapeProps: { + points: '0,40 60,40 60,20 95,50 60,80 60,60 0,60', + }, +}); diff --git a/src/plugins/expression_shape/public/components/shape/shapes/arrow_multi.tsx b/src/plugins/expression_shape/public/components/shape/shapes/arrow_multi.tsx new file mode 100644 index 00000000000000..d8ba48fe1a9248 --- /dev/null +++ b/src/plugins/expression_shape/public/components/shape/shapes/arrow_multi.tsx @@ -0,0 +1,20 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ +import { createShape } from '../../reusable/shape_factory'; + +export const ArrowMulti = createShape({ + viewBox: { + minX: 0, + minY: 0, + width: 100, + height: 60, + }, + shapeProps: { + points: '5,30 25,10 25,20 75,20 75,10 95,30 75,50 75,40 25,40 25,50', + }, +}); diff --git a/src/plugins/expression_shape/public/components/shape/shapes/bookmark.tsx b/src/plugins/expression_shape/public/components/shape/shapes/bookmark.tsx new file mode 100644 index 00000000000000..47e60a4c6a2455 --- /dev/null +++ b/src/plugins/expression_shape/public/components/shape/shapes/bookmark.tsx @@ -0,0 +1,21 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { createShape } from '../../reusable/shape_factory'; + +export const Bookmark = createShape({ + viewBox: { + minX: 0, + minY: 0, + width: 60, + height: 100, + }, + shapeProps: { + points: '0,0 60,0 60,95 30,75 0,95 0,0', + }, +}); diff --git a/src/plugins/expression_shape/public/components/shape/shapes/circle.tsx b/src/plugins/expression_shape/public/components/shape/shapes/circle.tsx new file mode 100644 index 00000000000000..271efc2ea6c455 --- /dev/null +++ b/src/plugins/expression_shape/public/components/shape/shapes/circle.tsx @@ -0,0 +1,25 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { createShape } from '../../reusable/shape_factory'; +import { SvgElementTypes } from '../../reusable/types'; + +export const Circle = createShape({ + viewBox: { + minX: 0, + minY: 0, + width: 100, + height: 100, + }, + shapeProps: { + r: '45', + cx: '50', + cy: '50', + }, + shapeType: SvgElementTypes.circle, +}); diff --git a/src/plugins/expression_shape/public/components/shape/shapes/cross.tsx b/src/plugins/expression_shape/public/components/shape/shapes/cross.tsx new file mode 100644 index 00000000000000..8e85860f850994 --- /dev/null +++ b/src/plugins/expression_shape/public/components/shape/shapes/cross.tsx @@ -0,0 +1,21 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { createShape } from '../../reusable/shape_factory'; + +export const Cross = createShape({ + viewBox: { + minX: 0, + minY: 0, + width: 100, + height: 100, + }, + shapeProps: { + points: '30,0 70,0 70,30 100,30 100,70 70,70 70,100 30,100 30,70 0,70 0,30 30,30', + }, +}); diff --git a/src/plugins/expression_shape/public/components/shape/shapes/hexagon.tsx b/src/plugins/expression_shape/public/components/shape/shapes/hexagon.tsx new file mode 100644 index 00000000000000..b51b48c93c9e1b --- /dev/null +++ b/src/plugins/expression_shape/public/components/shape/shapes/hexagon.tsx @@ -0,0 +1,22 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { createShape } from '../../reusable/shape_factory'; + +export const Hexagon = createShape({ + viewBox: { + minX: 0, + minY: 0, + width: 100, + height: 100, + }, + shapeProps: { + points: + '70.000, 15.359 30.000, 15.359 10.000, 50.000 30.000, 84.641 70.000, 84.641 90.000, 50.000', + }, +}); diff --git a/src/plugins/expression_shape/public/components/shape/shapes/index.ts b/src/plugins/expression_shape/public/components/shape/shapes/index.ts new file mode 100644 index 00000000000000..90a47ea722600f --- /dev/null +++ b/src/plugins/expression_shape/public/components/shape/shapes/index.ts @@ -0,0 +1,46 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { Arrow as arrow } from './arrow'; +import { ArrowMulti as arrowMulti } from './arrow_multi'; +import { Bookmark as bookmark } from './bookmark'; +import { Cross as cross } from './cross'; +import { Circle as circle } from './circle'; +import { Hexagon as hexagon } from './hexagon'; +import { Kite as kite } from './kite'; +import { Pentagon as pentagon } from './pentagon'; +import { Rhombus as rhombus } from './rhombus'; +import { Semicircle as semicircle } from './semicircle'; +import { SpeechBubble as speechBubble } from './speech_bubble'; +import { Square as square } from './square'; +import { Star as star } from './star'; +import { Tag as tag } from './tag'; +import { Triangle as triangle } from './triangle'; +import { TriangleRight as triangleRight } from './triangle_right'; +import { ShapeType } from '../../reusable'; + +const shapes: { [key: string]: ShapeType } = { + arrow, + arrowMulti, + bookmark, + cross, + circle, + hexagon, + kite, + pentagon, + rhombus, + semicircle, + speechBubble, + square, + star, + tag, + triangle, + triangleRight, +}; + +export const getShape = (shapeType: string) => shapes[shapeType]; diff --git a/src/plugins/expression_shape/public/components/shape/shapes/kite.tsx b/src/plugins/expression_shape/public/components/shape/shapes/kite.tsx new file mode 100644 index 00000000000000..52dde23dee4f6e --- /dev/null +++ b/src/plugins/expression_shape/public/components/shape/shapes/kite.tsx @@ -0,0 +1,21 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { createShape } from '../../reusable/shape_factory'; + +export const Kite = createShape({ + viewBox: { + minX: 0, + minY: 0, + width: 100, + height: 150, + }, + shapeProps: { + points: '50,10 10,50 50,140 90,50', + }, +}); diff --git a/src/plugins/expression_shape/public/components/shape/shapes/pentagon.tsx b/src/plugins/expression_shape/public/components/shape/shapes/pentagon.tsx new file mode 100644 index 00000000000000..f26f9808a0f1ee --- /dev/null +++ b/src/plugins/expression_shape/public/components/shape/shapes/pentagon.tsx @@ -0,0 +1,21 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { createShape } from '../../reusable/shape_factory'; + +export const Pentagon = createShape({ + viewBox: { + minX: 0, + minY: 0, + width: 100, + height: 100, + }, + shapeProps: { + points: '50.0000, 14.0000 11.9577, 41.6393 26.4886, 86.3607 73.5114, 86.3607 88.0423, 41.6393', + }, +}); diff --git a/src/plugins/expression_shape/public/components/shape/shapes/rhombus.tsx b/src/plugins/expression_shape/public/components/shape/shapes/rhombus.tsx new file mode 100644 index 00000000000000..6ef967bf6e5d79 --- /dev/null +++ b/src/plugins/expression_shape/public/components/shape/shapes/rhombus.tsx @@ -0,0 +1,21 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { createShape } from '../../reusable/shape_factory'; + +export const Rhombus = createShape({ + viewBox: { + minX: 0, + minY: 0, + width: 100, + height: 100, + }, + shapeProps: { + points: '50,10 10,50 50,90 90,50', + }, +}); diff --git a/src/plugins/expression_shape/public/components/shape/shapes/semicircle.tsx b/src/plugins/expression_shape/public/components/shape/shapes/semicircle.tsx new file mode 100644 index 00000000000000..a8a088bd86a768 --- /dev/null +++ b/src/plugins/expression_shape/public/components/shape/shapes/semicircle.tsx @@ -0,0 +1,23 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { createShape } from '../../reusable/shape_factory'; +import { SvgElementTypes } from '../../reusable/types'; + +export const Semicircle = createShape({ + viewBox: { + minX: 0, + minY: 0, + width: 100, + height: 100, + }, + shapeProps: { + d: 'M 5,50 h 90 A 45 45 180 1 0 5,50 Z', + }, + shapeType: SvgElementTypes.path, +}); diff --git a/src/plugins/expression_shape/public/components/shape/shapes/speech_bubble.tsx b/src/plugins/expression_shape/public/components/shape/shapes/speech_bubble.tsx new file mode 100644 index 00000000000000..5465897207eaa3 --- /dev/null +++ b/src/plugins/expression_shape/public/components/shape/shapes/speech_bubble.tsx @@ -0,0 +1,22 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { createShape } from '../../reusable/shape_factory'; + +export const SpeechBubble = createShape({ + viewBox: { + minX: 0, + minY: 0, + width: 100, + height: 100, + }, + shapeProps: { + points: '0,0 100,0 100,70 40,70 20,85 25,70 0,70', + strokeLinejoin: 'round', + }, +}); diff --git a/src/plugins/expression_shape/public/components/shape/shapes/square.tsx b/src/plugins/expression_shape/public/components/shape/shapes/square.tsx new file mode 100644 index 00000000000000..1fb582e69139f3 --- /dev/null +++ b/src/plugins/expression_shape/public/components/shape/shapes/square.tsx @@ -0,0 +1,26 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { createShape } from '../../reusable/shape_factory'; +import { SvgElementTypes } from '../../reusable/types'; + +export const Square = createShape({ + viewBox: { + minX: 0, + minY: 0, + width: 100, + height: 100, + }, + shapeProps: { + x: '0', + y: '0', + width: '100', + height: '100', + }, + shapeType: SvgElementTypes.rect, +}); diff --git a/src/plugins/expression_shape/public/components/shape/shapes/star.tsx b/src/plugins/expression_shape/public/components/shape/shapes/star.tsx new file mode 100644 index 00000000000000..a3ccff0387e8a5 --- /dev/null +++ b/src/plugins/expression_shape/public/components/shape/shapes/star.tsx @@ -0,0 +1,22 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { createShape } from '../../reusable/shape_factory'; + +export const Star = createShape({ + viewBox: { + minX: 0, + minY: 0, + width: 100, + height: 100, + }, + shapeProps: { + points: + '41.183, 37.865 12.652, 37.865 35.734, 54.635 26.917, 81.771 50.000, 65.000 73.265, 81.904 64.266, 54.635 87.348, 37.865 58.817, 37.865 50.07, 10.515', + }, +}); diff --git a/src/plugins/expression_shape/public/components/shape/shapes/tag.tsx b/src/plugins/expression_shape/public/components/shape/shapes/tag.tsx new file mode 100644 index 00000000000000..4c6cdac23b1e04 --- /dev/null +++ b/src/plugins/expression_shape/public/components/shape/shapes/tag.tsx @@ -0,0 +1,21 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { createShape } from '../../reusable/shape_factory'; + +export const Tag = createShape({ + viewBox: { + minX: 0, + minY: 0, + width: 100, + height: 60, + }, + shapeProps: { + points: '0,0 75,0 90,30 75,60 0,60', + }, +}); diff --git a/src/plugins/expression_shape/public/components/shape/shapes/triangle.tsx b/src/plugins/expression_shape/public/components/shape/shapes/triangle.tsx new file mode 100644 index 00000000000000..b8823bd9043509 --- /dev/null +++ b/src/plugins/expression_shape/public/components/shape/shapes/triangle.tsx @@ -0,0 +1,21 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { createShape } from '../../reusable/shape_factory'; + +export const Triangle = createShape({ + viewBox: { + minX: 0, + minY: 0, + width: 100, + height: 100, + }, + shapeProps: { + points: '50.000, 20.000 15.359, 80.000 84.641, 80.000', + }, +}); diff --git a/src/plugins/expression_shape/public/components/shape/shapes/triangle_right.tsx b/src/plugins/expression_shape/public/components/shape/shapes/triangle_right.tsx new file mode 100644 index 00000000000000..6d054263681956 --- /dev/null +++ b/src/plugins/expression_shape/public/components/shape/shapes/triangle_right.tsx @@ -0,0 +1,21 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { createShape } from '../../reusable/shape_factory'; + +export const TriangleRight = createShape({ + viewBox: { + minX: 0, + minY: 0, + width: 100, + height: 100, + }, + shapeProps: { + points: '0, 10 0, 100 90, 100', + }, +}); diff --git a/src/plugins/expression_shape/public/components/shape/types.ts b/src/plugins/expression_shape/public/components/shape/types.ts new file mode 100644 index 00000000000000..d99d4c386db531 --- /dev/null +++ b/src/plugins/expression_shape/public/components/shape/types.ts @@ -0,0 +1,22 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { IInterpreterRenderHandlers } from '../../../../../../src/plugins/expressions'; +import { ShapeRendererConfig } from '../../../common/types'; +import { ShapeDrawerProps } from '../reusable/types'; + +export interface ShapeComponentProps extends ShapeRendererConfig { + onLoaded: IInterpreterRenderHandlers['done']; + parentNode: HTMLElement; +} + +export interface Dimensions { + width: number; + height: number; +} +export type ShapeDrawerComponentProps = Omit; diff --git a/x-pack/plugins/canvas/canvas_plugin_src/renderers/shape/__stories__/__snapshots__/shape.stories.storyshot b/src/plugins/expression_shape/public/expression_renderers/__stories__/__snapshots__/shape.stories.storyshot similarity index 100% rename from x-pack/plugins/canvas/canvas_plugin_src/renderers/shape/__stories__/__snapshots__/shape.stories.storyshot rename to src/plugins/expression_shape/public/expression_renderers/__stories__/__snapshots__/shape.stories.storyshot diff --git a/x-pack/plugins/canvas/canvas_plugin_src/renderers/shape/__stories__/shape.stories.tsx b/src/plugins/expression_shape/public/expression_renderers/__stories__/shape_renderer.stories.tsx similarity index 59% rename from x-pack/plugins/canvas/canvas_plugin_src/renderers/shape/__stories__/shape.stories.tsx rename to src/plugins/expression_shape/public/expression_renderers/__stories__/shape_renderer.stories.tsx index ab8d517c67114a..10ac3df88e81cd 100644 --- a/x-pack/plugins/canvas/canvas_plugin_src/renderers/shape/__stories__/shape.stories.tsx +++ b/src/plugins/expression_shape/public/expression_renderers/__stories__/shape_renderer.stories.tsx @@ -1,15 +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 - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. */ import React from 'react'; import { storiesOf } from '@storybook/react'; -import { shape } from '../'; -import { Render } from '../../__stories__/render'; -import { Shape } from '../../../functions/common/shape'; +import { shapeRenderer as shape } from '../'; +import { Render } from '../../../../presentation_util/public/__stories__'; +import { Shape } from '../../../common/types'; storiesOf('renderers/shape', module).add('default', () => { const config = { diff --git a/src/plugins/expression_shape/public/expression_renderers/index.ts b/src/plugins/expression_shape/public/expression_renderers/index.ts new file mode 100644 index 00000000000000..7dba64d7728dba --- /dev/null +++ b/src/plugins/expression_shape/public/expression_renderers/index.ts @@ -0,0 +1,13 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { shapeRenderer } from './shape_renderer'; + +export const renderers = [shapeRenderer]; + +export { shapeRenderer }; diff --git a/src/plugins/expression_shape/public/expression_renderers/shape_renderer.tsx b/src/plugins/expression_shape/public/expression_renderers/shape_renderer.tsx new file mode 100644 index 00000000000000..09a0fe53fbe744 --- /dev/null +++ b/src/plugins/expression_shape/public/expression_renderers/shape_renderer.tsx @@ -0,0 +1,51 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ +import React from 'react'; +import { render, unmountComponentAtNode } from 'react-dom'; +import { I18nProvider } from '@kbn/i18n/react'; +import { ExpressionRenderDefinition, IInterpreterRenderHandlers } from 'src/plugins/expressions'; +import { i18n } from '@kbn/i18n'; +import { withSuspense } from '../../../presentation_util/public'; +import { ShapeRendererConfig } from '../../common/types'; +import { LazyShapeComponent } from '../components/shape'; + +const strings = { + getDisplayName: () => + i18n.translate('expressionShape.renderer.shape.displayName', { + defaultMessage: 'Shape', + }), + getHelpDescription: () => + i18n.translate('expressionShape.renderer.shape.helpDescription', { + defaultMessage: 'Render a basic shape', + }), +}; + +const ShapeComponent = withSuspense(LazyShapeComponent); + +export const shapeRenderer = (): ExpressionRenderDefinition => ({ + name: 'shape', + displayName: strings.getDisplayName(), + help: strings.getHelpDescription(), + reuseDomNode: true, + render: async ( + domNode: HTMLElement, + config: ShapeRendererConfig, + handlers: IInterpreterRenderHandlers + ) => { + handlers.onDestroy(() => { + unmountComponentAtNode(domNode); + }); + + render( + + + , + domNode + ); + }, +}); diff --git a/src/plugins/expression_shape/public/index.ts b/src/plugins/expression_shape/public/index.ts new file mode 100755 index 00000000000000..c5933a8cd06ed0 --- /dev/null +++ b/src/plugins/expression_shape/public/index.ts @@ -0,0 +1,22 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { ExpressionShapePlugin } from './plugin'; + +export type { ExpressionShapePluginSetup, ExpressionShapePluginStart } from './plugin'; + +export function plugin() { + return new ExpressionShapePlugin(); +} + +export * from './expression_renderers'; +export { LazyShapeDrawer } from './components/shape'; +export { getDefaultShapeData } from './components/reusable'; +export * from './components/shape/types'; +export * from './components/reusable/types'; +export * from '../common/types'; diff --git a/src/plugins/expression_shape/public/plugin.ts b/src/plugins/expression_shape/public/plugin.ts new file mode 100755 index 00000000000000..cb28f97acd697c --- /dev/null +++ b/src/plugins/expression_shape/public/plugin.ts @@ -0,0 +1,33 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { CoreSetup, CoreStart, Plugin } from '../../../core/public'; +import { ExpressionsStart, ExpressionsSetup } from '../../expressions/public'; +import { shapeRenderer } from './expression_renderers'; + +interface SetupDeps { + expressions: ExpressionsSetup; +} + +interface StartDeps { + expression: ExpressionsStart; +} + +export type ExpressionShapePluginSetup = void; +export type ExpressionShapePluginStart = void; + +export class ExpressionShapePlugin + implements Plugin { + public setup(core: CoreSetup, { expressions }: SetupDeps): ExpressionShapePluginSetup { + expressions.registerRenderer(shapeRenderer); + } + + public start(core: CoreStart): ExpressionShapePluginStart {} + + public stop() {} +} diff --git a/src/plugins/expression_shape/server/index.ts b/src/plugins/expression_shape/server/index.ts new file mode 100644 index 00000000000000..79da7a954c5501 --- /dev/null +++ b/src/plugins/expression_shape/server/index.ts @@ -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 + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { ExpressionShapePlugin } from './plugin'; + +export type { ExpressionShapePluginSetup, ExpressionShapePluginStart } from './plugin'; + +export function plugin() { + return new ExpressionShapePlugin(); +} diff --git a/src/plugins/expression_shape/server/plugin.ts b/src/plugins/expression_shape/server/plugin.ts new file mode 100644 index 00000000000000..c03acaa04f1ecc --- /dev/null +++ b/src/plugins/expression_shape/server/plugin.ts @@ -0,0 +1,33 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { CoreSetup, CoreStart, Plugin } from '../../../core/public'; +import { ExpressionsServerStart, ExpressionsServerSetup } from '../../expressions/server'; +import { shapeFunction } from '../common/expression_functions'; + +interface SetupDeps { + expressions: ExpressionsServerSetup; +} + +interface StartDeps { + expression: ExpressionsServerStart; +} + +export type ExpressionShapePluginSetup = void; +export type ExpressionShapePluginStart = void; + +export class ExpressionShapePlugin + implements Plugin { + public setup(core: CoreSetup, { expressions }: SetupDeps): ExpressionShapePluginSetup { + expressions.registerFunction(shapeFunction); + } + + public start(core: CoreStart): ExpressionShapePluginStart {} + + public stop() {} +} diff --git a/src/plugins/expression_shape/tsconfig.json b/src/plugins/expression_shape/tsconfig.json new file mode 100644 index 00000000000000..5fab51496c97e7 --- /dev/null +++ b/src/plugins/expression_shape/tsconfig.json @@ -0,0 +1,22 @@ +{ + "extends": "../../../tsconfig.base.json", + "compilerOptions": { + "composite": true, + "outDir": "./target/types", + "emitDeclarationOnly": true, + "declaration": true, + "declarationMap": true, + "isolatedModules": true + }, + "include": [ + "common/**/*", + "public/**/*", + "server/**/*", + "__fixtures__/**/*", + ], + "references": [ + { "path": "../../core/tsconfig.json" }, + { "path": "../presentation_util/tsconfig.json" }, + { "path": "../expressions/tsconfig.json" }, + ] +} diff --git a/src/plugins/presentation_util/public/components/index.tsx b/src/plugins/presentation_util/public/components/index.tsx index 508a1f49830314..007fe05ddc4851 100644 --- a/src/plugins/presentation_util/public/components/index.tsx +++ b/src/plugins/presentation_util/public/components/index.tsx @@ -6,7 +6,7 @@ * Side Public License, v 1. */ -import React, { Suspense, ComponentType, ReactElement } from 'react'; +import React, { Suspense, ComponentType, ReactElement, Ref } from 'react'; import { EuiLoadingSpinner, EuiErrorBoundary } from '@elastic/eui'; /** @@ -14,16 +14,19 @@ import { EuiLoadingSpinner, EuiErrorBoundary } from '@elastic/eui'; * @param Component A component deferred by `React.lazy` * @param fallback A fallback component to render while things load; default is `EuiLoadingSpinner` */ -export const withSuspense =

( +export const withSuspense =

( Component: ComponentType

, fallback: ReactElement | null = -) => (props: P) => ( - - - - - -); +) => + React.forwardRef((props: P, ref: Ref) => { + return ( + + + + + + ); + }); export const LazyLabsBeakerButton = React.lazy(() => import('./labs/labs_beaker_button')); @@ -34,3 +37,5 @@ export const LazyDashboardPicker = React.lazy(() => import('./dashboard_picker') export const LazySavedObjectSaveModalDashboard = React.lazy( () => import('./saved_object_save_modal_dashboard') ); + +export * from './types'; diff --git a/src/plugins/presentation_util/public/index.ts b/src/plugins/presentation_util/public/index.ts index 1e26011ff58ae6..f771a73c1df2b3 100644 --- a/src/plugins/presentation_util/public/index.ts +++ b/src/plugins/presentation_util/public/index.ts @@ -38,6 +38,8 @@ export { withSuspense, } from './components'; +export * from './components/types'; + export { AddFromLibraryButton, PrimaryActionButton, diff --git a/x-pack/plugins/canvas/__fixtures__/function_specs.ts b/x-pack/plugins/canvas/__fixtures__/function_specs.ts index d82436434c0278..ff6c5643920803 100644 --- a/x-pack/plugins/canvas/__fixtures__/function_specs.ts +++ b/x-pack/plugins/canvas/__fixtures__/function_specs.ts @@ -8,7 +8,9 @@ import { functions as browserFns } from '../canvas_plugin_src/functions/browser'; import { ExpressionFunction } from '../../../../src/plugins/expressions'; import { initFunctions } from '../public/functions'; +import { functionSpecs as shapeFunctionSpecs } from '../../../../src/plugins/expression_shape/__fixtures__'; export const functionSpecs = browserFns .concat(...(initFunctions({} as any) as any)) - .map((fn) => new ExpressionFunction(fn())); + .map((fn) => new ExpressionFunction(fn())) + .concat(...shapeFunctionSpecs); diff --git a/x-pack/plugins/canvas/canvas_plugin_src/functions/common/index.ts b/x-pack/plugins/canvas/canvas_plugin_src/functions/common/index.ts index 9da646e6958612..5e7f837d9c6861 100644 --- a/x-pack/plugins/canvas/canvas_plugin_src/functions/common/index.ts +++ b/x-pack/plugins/canvas/canvas_plugin_src/functions/common/index.ts @@ -44,7 +44,6 @@ import { rounddate } from './rounddate'; import { rowCount } from './rowCount'; import { repeatImage } from './repeat_image'; import { seriesStyle } from './seriesStyle'; -import { shape } from './shape'; import { sort } from './sort'; import { staticColumn } from './staticColumn'; import { string } from './string'; @@ -96,7 +95,6 @@ export const functions = [ rounddate, rowCount, seriesStyle, - shape, sort, staticColumn, string, diff --git a/x-pack/plugins/canvas/canvas_plugin_src/functions/common/shape.ts b/x-pack/plugins/canvas/canvas_plugin_src/functions/common/shape.ts deleted file mode 100644 index a40aa50e856d17..00000000000000 --- a/x-pack/plugins/canvas/canvas_plugin_src/functions/common/shape.ts +++ /dev/null @@ -1,87 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { ExpressionFunctionDefinition } from 'src/plugins/expressions'; -import { getFunctionHelp } from '../../../i18n'; - -export enum Shape { - ARROW = 'arrow', - ARROW_MULTI = 'arrowMulti', - BOOKMARK = 'bookmark', - CIRCLE = 'circle', - CROSS = 'cross', - HEXAGON = 'hexagon', - KITE = 'kite', - PENTAGON = 'pentagon', - RHOMBUS = 'rhombus', - SEMICIRCLE = 'semicircle', - SPEECH_BUBBLE = 'speechBubble', - SQUARE = 'square', - STAR = 'star', - TAG = 'tag', - TRIANGLE = 'triangle', - TRIANGLE_RIGHT = 'triangleRight', -} - -interface Arguments { - border: string; - borderWidth: number; - shape: Shape; - fill: string; - maintainAspect: boolean; -} - -export interface Output extends Arguments { - type: 'shape'; -} - -export function shape(): ExpressionFunctionDefinition<'shape', null, Arguments, Output> { - const { help, args: argHelp } = getFunctionHelp().shape; - - return { - name: 'shape', - aliases: [], - type: 'shape', - inputTypes: ['null'], - help, - args: { - shape: { - types: ['string'], - help: argHelp.shape, - aliases: ['_'], - default: 'square', - options: Object.values(Shape), - }, - border: { - types: ['string'], - aliases: ['stroke'], - help: argHelp.border, - }, - borderWidth: { - types: ['number'], - aliases: ['strokeWidth'], - help: argHelp.borderWidth, - default: 0, - }, - fill: { - types: ['string'], - help: argHelp.fill, - default: 'black', - }, - maintainAspect: { - types: ['boolean'], - help: argHelp.maintainAspect, - default: false, - options: [true, false], - }, - }, - fn: (input, args) => ({ - type: 'shape', - ...args, - }), - }; -} diff --git a/x-pack/plugins/canvas/canvas_plugin_src/renderers/core.ts b/x-pack/plugins/canvas/canvas_plugin_src/renderers/core.ts index 906f1646757a7f..d04e342ccb9e3b 100644 --- a/x-pack/plugins/canvas/canvas_plugin_src/renderers/core.ts +++ b/x-pack/plugins/canvas/canvas_plugin_src/renderers/core.ts @@ -12,7 +12,6 @@ import { pie } from './pie'; import { plot } from './plot'; import { progress } from './progress'; import { repeatImage } from './repeat_image'; -import { shape } from './shape'; import { table } from './table'; import { text } from './text'; @@ -24,7 +23,6 @@ export const renderFunctions = [ plot, progress, repeatImage, - shape, table, text, ]; diff --git a/x-pack/plugins/canvas/canvas_plugin_src/renderers/external.ts b/x-pack/plugins/canvas/canvas_plugin_src/renderers/external.ts index 1d032aa829bc07..f24fad04fab50f 100644 --- a/x-pack/plugins/canvas/canvas_plugin_src/renderers/external.ts +++ b/x-pack/plugins/canvas/canvas_plugin_src/renderers/external.ts @@ -7,6 +7,7 @@ import { revealImageRenderer } from '../../../../../src/plugins/expression_reveal_image/public'; import { errorRenderer, debugRenderer } from '../../../../../src/plugins/expression_error/public'; +import { shapeRenderer } from '../../../../../src/plugins/expression_shape/public'; -export const renderFunctions = [revealImageRenderer, errorRenderer, debugRenderer]; +export const renderFunctions = [revealImageRenderer, debugRenderer, errorRenderer, shapeRenderer]; export const renderFunctionFactories = []; diff --git a/x-pack/plugins/canvas/canvas_plugin_src/renderers/shape/index.ts b/x-pack/plugins/canvas/canvas_plugin_src/renderers/shape/index.ts deleted file mode 100644 index ca6c1fc2fb7be5..00000000000000 --- a/x-pack/plugins/canvas/canvas_plugin_src/renderers/shape/index.ts +++ /dev/null @@ -1,91 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { RendererStrings } from '../../../i18n'; -import { shapes } from './shapes'; -import { RendererFactory } from '../../../types'; -import { Output } from '../../functions/common/shape'; - -const { shape: strings } = RendererStrings; - -export const shape: RendererFactory = () => ({ - name: 'shape', - displayName: strings.getDisplayName(), - help: strings.getHelpDescription(), - reuseDomNode: true, - render(domNode, config, handlers) { - const { shape: shapeType, fill, border, borderWidth, maintainAspect } = config; - - const parser = new DOMParser(); - const shapeSvg = parser - .parseFromString(shapes[shapeType], 'image/svg+xml') - .getElementsByTagName('svg') - .item(0)!; - - const shapeContent = shapeSvg.firstElementChild!; - - if (fill) { - shapeContent.setAttribute('fill', fill); - } - if (border) { - shapeContent.setAttribute('stroke', border); - } - const strokeWidth = Math.max(borderWidth, 0); - shapeContent.setAttribute('stroke-width', String(strokeWidth)); - shapeContent.setAttribute('stroke-miterlimit', '999'); - shapeContent.setAttribute('vector-effect', 'non-scaling-stroke'); - - shapeSvg.setAttribute('preserveAspectRatio', maintainAspect ? 'xMidYMid meet' : 'none'); - shapeSvg.setAttribute('overflow', 'visible'); - - const initialViewBox = shapeSvg - .getAttribute('viewBox')! - .split(' ') - .map((v) => parseInt(v, 10)); - - const draw = () => { - const width = domNode.offsetWidth; - const height = domNode.offsetHeight; - - // adjust viewBox based on border width - let [minX, minY, shapeWidth, shapeHeight] = initialViewBox; - const borderOffset = strokeWidth; - - if (width) { - const xOffset = (shapeWidth / width) * borderOffset; - minX -= xOffset; - shapeWidth += xOffset * 2; - } else { - shapeWidth = 0; - } - - if (height) { - const yOffset = (shapeHeight / height) * borderOffset; - minY -= yOffset; - shapeHeight += yOffset * 2; - } else { - shapeHeight = 0; - } - - shapeSvg.setAttribute('width', String(width)); - shapeSvg.setAttribute('height', String(height)); - shapeSvg.setAttribute('viewBox', [minX, minY, shapeWidth, shapeHeight].join(' ')); - - const oldShape = domNode.firstElementChild; - if (oldShape) { - domNode.removeChild(oldShape); - } - - domNode.style.lineHeight = '0'; - domNode.appendChild(shapeSvg); - }; - - draw(); - handlers.done(); - handlers.onResize(draw); // debouncing avoided for fluidity - }, -}); diff --git a/x-pack/plugins/canvas/canvas_plugin_src/renderers/shape/shapes/arrow.svg b/x-pack/plugins/canvas/canvas_plugin_src/renderers/shape/shapes/arrow.svg deleted file mode 100644 index 2048bf5992c705..00000000000000 --- a/x-pack/plugins/canvas/canvas_plugin_src/renderers/shape/shapes/arrow.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - \ No newline at end of file diff --git a/x-pack/plugins/canvas/canvas_plugin_src/renderers/shape/shapes/arrow_multi.svg b/x-pack/plugins/canvas/canvas_plugin_src/renderers/shape/shapes/arrow_multi.svg deleted file mode 100644 index 0d1fcfd435ad40..00000000000000 --- a/x-pack/plugins/canvas/canvas_plugin_src/renderers/shape/shapes/arrow_multi.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - \ No newline at end of file diff --git a/x-pack/plugins/canvas/canvas_plugin_src/renderers/shape/shapes/bookmark.svg b/x-pack/plugins/canvas/canvas_plugin_src/renderers/shape/shapes/bookmark.svg deleted file mode 100644 index 5cb144bd3367a7..00000000000000 --- a/x-pack/plugins/canvas/canvas_plugin_src/renderers/shape/shapes/bookmark.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - \ No newline at end of file diff --git a/x-pack/plugins/canvas/canvas_plugin_src/renderers/shape/shapes/circle.svg b/x-pack/plugins/canvas/canvas_plugin_src/renderers/shape/shapes/circle.svg deleted file mode 100644 index d4024c138b710e..00000000000000 --- a/x-pack/plugins/canvas/canvas_plugin_src/renderers/shape/shapes/circle.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - \ No newline at end of file diff --git a/x-pack/plugins/canvas/canvas_plugin_src/renderers/shape/shapes/cross.svg b/x-pack/plugins/canvas/canvas_plugin_src/renderers/shape/shapes/cross.svg deleted file mode 100644 index 72f0b7b6d556a2..00000000000000 --- a/x-pack/plugins/canvas/canvas_plugin_src/renderers/shape/shapes/cross.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - \ No newline at end of file diff --git a/x-pack/plugins/canvas/canvas_plugin_src/renderers/shape/shapes/hexagon.svg b/x-pack/plugins/canvas/canvas_plugin_src/renderers/shape/shapes/hexagon.svg deleted file mode 100644 index e1096039b44a87..00000000000000 --- a/x-pack/plugins/canvas/canvas_plugin_src/renderers/shape/shapes/hexagon.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - \ No newline at end of file diff --git a/x-pack/plugins/canvas/canvas_plugin_src/renderers/shape/shapes/index.ts b/x-pack/plugins/canvas/canvas_plugin_src/renderers/shape/shapes/index.ts deleted file mode 100644 index e5c0d22f5c3878..00000000000000 --- a/x-pack/plugins/canvas/canvas_plugin_src/renderers/shape/shapes/index.ts +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import arrow from '!!raw-loader!./arrow.svg'; -import arrowMulti from '!!raw-loader!./arrow_multi.svg'; -import bookmark from '!!raw-loader!./bookmark.svg'; -import cross from '!!raw-loader!./cross.svg'; -import circle from '!!raw-loader!./circle.svg'; -import hexagon from '!!raw-loader!./hexagon.svg'; -import kite from '!!raw-loader!./kite.svg'; -import pentagon from '!!raw-loader!./pentagon.svg'; -import rhombus from '!!raw-loader!./rhombus.svg'; -import semicircle from '!!raw-loader!./semicircle.svg'; -import speechBubble from '!!raw-loader!./speech_bubble.svg'; -import square from '!!raw-loader!./square.svg'; -import star from '!!raw-loader!./star.svg'; -import tag from '!!raw-loader!./tag.svg'; -import triangle from '!!raw-loader!./triangle.svg'; -import triangleRight from '!!raw-loader!./triangle_right.svg'; - -export const shapes = { - arrow, - arrowMulti, - bookmark, - cross, - circle, - hexagon, - kite, - pentagon, - rhombus, - semicircle, - speechBubble, - square, - star, - tag, - triangle, - triangleRight, -}; diff --git a/x-pack/plugins/canvas/canvas_plugin_src/renderers/shape/shapes/kite.svg b/x-pack/plugins/canvas/canvas_plugin_src/renderers/shape/shapes/kite.svg deleted file mode 100644 index 76121bf0c57581..00000000000000 --- a/x-pack/plugins/canvas/canvas_plugin_src/renderers/shape/shapes/kite.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - \ No newline at end of file diff --git a/x-pack/plugins/canvas/canvas_plugin_src/renderers/shape/shapes/pentagon.svg b/x-pack/plugins/canvas/canvas_plugin_src/renderers/shape/shapes/pentagon.svg deleted file mode 100644 index 578b095479b70f..00000000000000 --- a/x-pack/plugins/canvas/canvas_plugin_src/renderers/shape/shapes/pentagon.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - \ No newline at end of file diff --git a/x-pack/plugins/canvas/canvas_plugin_src/renderers/shape/shapes/rhombus.svg b/x-pack/plugins/canvas/canvas_plugin_src/renderers/shape/shapes/rhombus.svg deleted file mode 100644 index 9512d458f174a5..00000000000000 --- a/x-pack/plugins/canvas/canvas_plugin_src/renderers/shape/shapes/rhombus.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - \ No newline at end of file diff --git a/x-pack/plugins/canvas/canvas_plugin_src/renderers/shape/shapes/semicircle.svg b/x-pack/plugins/canvas/canvas_plugin_src/renderers/shape/shapes/semicircle.svg deleted file mode 100644 index 48b9928d33a28e..00000000000000 --- a/x-pack/plugins/canvas/canvas_plugin_src/renderers/shape/shapes/semicircle.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - \ No newline at end of file diff --git a/x-pack/plugins/canvas/canvas_plugin_src/renderers/shape/shapes/speech_bubble.svg b/x-pack/plugins/canvas/canvas_plugin_src/renderers/shape/shapes/speech_bubble.svg deleted file mode 100644 index 1feebc4d5de4b8..00000000000000 --- a/x-pack/plugins/canvas/canvas_plugin_src/renderers/shape/shapes/speech_bubble.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - \ No newline at end of file diff --git a/x-pack/plugins/canvas/canvas_plugin_src/renderers/shape/shapes/square.svg b/x-pack/plugins/canvas/canvas_plugin_src/renderers/shape/shapes/square.svg deleted file mode 100644 index f964547722bbcb..00000000000000 --- a/x-pack/plugins/canvas/canvas_plugin_src/renderers/shape/shapes/square.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/x-pack/plugins/canvas/canvas_plugin_src/renderers/shape/shapes/star.svg b/x-pack/plugins/canvas/canvas_plugin_src/renderers/shape/shapes/star.svg deleted file mode 100644 index 66749baef6bca7..00000000000000 --- a/x-pack/plugins/canvas/canvas_plugin_src/renderers/shape/shapes/star.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - \ No newline at end of file diff --git a/x-pack/plugins/canvas/canvas_plugin_src/renderers/shape/shapes/tag.svg b/x-pack/plugins/canvas/canvas_plugin_src/renderers/shape/shapes/tag.svg deleted file mode 100644 index 845d81c9dabe6c..00000000000000 --- a/x-pack/plugins/canvas/canvas_plugin_src/renderers/shape/shapes/tag.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - \ No newline at end of file diff --git a/x-pack/plugins/canvas/canvas_plugin_src/renderers/shape/shapes/triangle.svg b/x-pack/plugins/canvas/canvas_plugin_src/renderers/shape/shapes/triangle.svg deleted file mode 100644 index 6642aaf7ed0ac8..00000000000000 --- a/x-pack/plugins/canvas/canvas_plugin_src/renderers/shape/shapes/triangle.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - \ No newline at end of file diff --git a/x-pack/plugins/canvas/canvas_plugin_src/renderers/shape/shapes/triangle_right.svg b/x-pack/plugins/canvas/canvas_plugin_src/renderers/shape/shapes/triangle_right.svg deleted file mode 100644 index e3b6050654fd80..00000000000000 --- a/x-pack/plugins/canvas/canvas_plugin_src/renderers/shape/shapes/triangle_right.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - \ No newline at end of file diff --git a/x-pack/plugins/canvas/canvas_plugin_src/uis/views/shape.js b/x-pack/plugins/canvas/canvas_plugin_src/uis/views/shape.js index b06a2339b3aeb2..1c84b0b27fd198 100644 --- a/x-pack/plugins/canvas/canvas_plugin_src/uis/views/shape.js +++ b/x-pack/plugins/canvas/canvas_plugin_src/uis/views/shape.js @@ -5,7 +5,7 @@ * 2.0. */ -import { shapes } from '../../renderers/shape/shapes'; +import { getAvailableShapes } from '../../../../../../src/plugins/expression_shape/common'; import { ViewStrings } from '../../../i18n'; const { Shape: strings } = ViewStrings; @@ -21,7 +21,7 @@ export const shape = () => ({ displayName: strings.getShapeDisplayName(), argType: 'shape', options: { - shapes, + shapes: getAvailableShapes(), }, }, { diff --git a/x-pack/plugins/canvas/i18n/functions/dict/shape.ts b/x-pack/plugins/canvas/i18n/functions/dict/shape.ts deleted file mode 100644 index 70b295607ec14f..00000000000000 --- a/x-pack/plugins/canvas/i18n/functions/dict/shape.ts +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { i18n } from '@kbn/i18n'; -import { shape } from '../../../canvas_plugin_src/functions/common/shape'; -import { FunctionHelp } from '../function_help'; -import { FunctionFactory } from '../../../types'; -import { SVG } from '../../constants'; - -export const help: FunctionHelp> = { - help: i18n.translate('xpack.canvas.functions.shapeHelpText', { - defaultMessage: 'Creates a shape.', - }), - args: { - shape: i18n.translate('xpack.canvas.functions.shape.args.shapeHelpText', { - defaultMessage: 'Pick a shape.', - }), - border: i18n.translate('xpack.canvas.functions.shape.args.borderHelpText', { - defaultMessage: 'An {SVG} color for the border outlining the shape.', - values: { - SVG, - }, - }), - borderWidth: i18n.translate('xpack.canvas.functions.shape.args.borderWidthHelpText', { - defaultMessage: 'The thickness of the border.', - }), - fill: i18n.translate('xpack.canvas.functions.shape.args.fillHelpText', { - defaultMessage: 'An {SVG} color to fill the shape.', - values: { - SVG, - }, - }), - maintainAspect: i18n.translate('xpack.canvas.functions.shape.args.maintainAspectHelpText', { - defaultMessage: `Maintain the shape's original aspect ratio?`, - }), - }, -}; diff --git a/x-pack/plugins/canvas/i18n/functions/function_help.ts b/x-pack/plugins/canvas/i18n/functions/function_help.ts index b72d410ddd63f4..4368e2c8a6084a 100644 --- a/x-pack/plugins/canvas/i18n/functions/function_help.ts +++ b/x-pack/plugins/canvas/i18n/functions/function_help.ts @@ -64,7 +64,6 @@ import { help as savedMap } from './dict/saved_map'; import { help as savedSearch } from './dict/saved_search'; import { help as savedVisualization } from './dict/saved_visualization'; import { help as seriesStyle } from './dict/series_style'; -import { help as shape } from './dict/shape'; import { help as sort } from './dict/sort'; import { help as staticColumn } from './dict/static_column'; import { help as string } from './dict/string'; @@ -224,7 +223,6 @@ export const getFunctionHelp = (): FunctionHelpDict => ({ savedSearch, savedVisualization, seriesStyle, - shape, sort, staticColumn, string, diff --git a/x-pack/plugins/canvas/i18n/renderers.ts b/x-pack/plugins/canvas/i18n/renderers.ts index fa1fbc063dbe6e..fcdb3382af4ea8 100644 --- a/x-pack/plugins/canvas/i18n/renderers.ts +++ b/x-pack/plugins/canvas/i18n/renderers.ts @@ -129,16 +129,6 @@ export const RendererStrings = { defaultMessage: 'Repeat an image a given number of times', }), }, - shape: { - getDisplayName: () => - i18n.translate('xpack.canvas.renderer.shape.displayName', { - defaultMessage: 'Shape', - }), - getHelpDescription: () => - i18n.translate('xpack.canvas.renderer.shape.helpDescription', { - defaultMessage: 'Render a basic shape', - }), - }, table: { getDisplayName: () => i18n.translate('xpack.canvas.renderer.table.displayName', { diff --git a/x-pack/plugins/canvas/kibana.json b/x-pack/plugins/canvas/kibana.json index 545eae742a89e5..a98fc3d210c112 100644 --- a/x-pack/plugins/canvas/kibana.json +++ b/x-pack/plugins/canvas/kibana.json @@ -13,6 +13,7 @@ "expressionError", "expressionRevealImage", "expressions", + "expressionShape", "features", "inspector", "presentationUtil", diff --git a/x-pack/plugins/canvas/public/components/shape_picker/__stories__/__snapshots__/shape_picker.stories.storyshot b/x-pack/plugins/canvas/public/components/shape_picker/__stories__/__snapshots__/shape_picker.stories.storyshot index 70192deca5325c..3dc608196805a3 100644 --- a/x-pack/plugins/canvas/public/components/shape_picker/__stories__/__snapshots__/shape_picker.stories.storyshot +++ b/x-pack/plugins/canvas/public/components/shape_picker/__stories__/__snapshots__/shape_picker.stories.storyshot @@ -15,14 +15,18 @@ exports[`Storyshots components/Shapes/ShapePicker default 1`] = ` >

- - ", - } - } - /> + > + + + +
- - ", - } - } - /> + > + + + +
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+
diff --git a/x-pack/plugins/canvas/public/components/shape_picker/__stories__/shape_picker.stories.tsx b/x-pack/plugins/canvas/public/components/shape_picker/__stories__/shape_picker.stories.tsx index f6357e3976c23c..5fdea5591f538c 100644 --- a/x-pack/plugins/canvas/public/components/shape_picker/__stories__/shape_picker.stories.tsx +++ b/x-pack/plugins/canvas/public/components/shape_picker/__stories__/shape_picker.stories.tsx @@ -9,9 +9,8 @@ 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'; +import { getAvailableShapes } from '../../../../../../../src/plugins/expression_shape/common'; storiesOf('components/Shapes/ShapePicker', module).add('default', () => ( - + )); diff --git a/x-pack/plugins/canvas/public/components/shape_picker/shape_picker.tsx b/x-pack/plugins/canvas/public/components/shape_picker/shape_picker.tsx index 78cd989543ca90..e06a199f85feee 100644 --- a/x-pack/plugins/canvas/public/components/shape_picker/shape_picker.tsx +++ b/x-pack/plugins/canvas/public/components/shape_picker/shape_picker.tsx @@ -9,29 +9,24 @@ import React, { FC } from 'react'; import PropTypes from 'prop-types'; import { EuiFlexGrid, EuiFlexItem, EuiLink } from '@elastic/eui'; import { ShapePreview } from '../shape_preview'; +import { Shape } from '../../../../../../src/plugins/expression_shape/common'; interface Props { - shapes: { - [key: string]: string; - }; + shapes: Shape[]; onChange?: (key: string) => void; } -export const ShapePicker: FC = ({ shapes, onChange = () => {} }) => { - return ( - - {Object.keys(shapes) - .sort() - .map((shapeKey) => ( - - onChange(shapeKey)}> - - - - ))} - - ); -}; +export const ShapePicker: FC = ({ shapes, onChange = () => {} }) => ( + + {shapes.sort().map((shapeKey) => ( + + onChange(shapeKey)}> + + + + ))} + +); ShapePicker.propTypes = { onChange: PropTypes.func, diff --git a/x-pack/plugins/canvas/public/components/shape_picker_popover/__stories__/__snapshots__/shape_picker_popover.stories.storyshot b/x-pack/plugins/canvas/public/components/shape_picker_popover/__stories__/__snapshots__/shape_picker_popover.stories.storyshot index aca6e9770573c0..247616e8429564 100644 --- a/x-pack/plugins/canvas/public/components/shape_picker_popover/__stories__/__snapshots__/shape_picker_popover.stories.storyshot +++ b/x-pack/plugins/canvas/public/components/shape_picker_popover/__stories__/__snapshots__/shape_picker_popover.stories.storyshot @@ -53,14 +53,21 @@ exports[`Storyshots components/Shapes/ShapePickerPopover interactive 1`] = ` >
- - ", - } - } - /> + > + + + +
@@ -90,14 +97,21 @@ exports[`Storyshots components/Shapes/ShapePickerPopover shape selected 1`] = ` >
- - ", - } - } - /> + > + + + +
diff --git a/x-pack/plugins/canvas/public/components/shape_picker_popover/__stories__/shape_picker_popover.stories.tsx b/x-pack/plugins/canvas/public/components/shape_picker_popover/__stories__/shape_picker_popover.stories.tsx index f91f509318b475..babc03b8f6763b 100644 --- a/x-pack/plugins/canvas/public/components/shape_picker_popover/__stories__/shape_picker_popover.stories.tsx +++ b/x-pack/plugins/canvas/public/components/shape_picker_popover/__stories__/shape_picker_popover.stories.tsx @@ -9,18 +9,20 @@ 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'; +import { + getAvailableShapes, + Shape, +} from '../../../../../../../src/plugins/expression_shape/common'; class Interactive extends React.Component<{}, { value: string }> { public state = { - value: 'square', + value: Shape.SQUARE, }; public render() { return ( this.setState({ value })} value={this.state.value} /> @@ -29,9 +31,15 @@ class Interactive extends React.Component<{}, { value: string }> { } storiesOf('components/Shapes/ShapePickerPopover', module) - .add('default', () => ) + .add('default', () => ( + + )) .add('shape selected', () => ( - + )) .add('interactive', () => , { info: { diff --git a/x-pack/plugins/canvas/public/components/shape_picker_popover/shape_picker_popover.tsx b/x-pack/plugins/canvas/public/components/shape_picker_popover/shape_picker_popover.tsx index cb3556c2c0fef4..5701c3cb1e799e 100644 --- a/x-pack/plugins/canvas/public/components/shape_picker_popover/shape_picker_popover.tsx +++ b/x-pack/plugins/canvas/public/components/shape_picker_popover/shape_picker_popover.tsx @@ -11,13 +11,12 @@ import { EuiLink, EuiPanel } from '@elastic/eui'; import { Popover } from '../popover'; import { ShapePicker } from '../shape_picker'; import { ShapePreview } from '../shape_preview'; +import { Shape } from '../../../../../../src/plugins/expression_shape/common'; interface Props { - shapes: { - [key: string]: string; - }; + shapes: Shape[]; onChange?: (key: string) => void; - value?: string; + value?: Shape; ariaLabel?: string; } @@ -25,7 +24,7 @@ export const ShapePickerPopover: FC = ({ shapes, onChange, value, ariaLab const button = (handleClick: React.MouseEventHandler) => ( - + ); diff --git a/x-pack/plugins/canvas/public/components/shape_preview/__stories__/__snapshots__/shape_preview.stories.storyshot b/x-pack/plugins/canvas/public/components/shape_preview/__stories__/__snapshots__/shape_preview.stories.storyshot index 8c7ff2e92b86d8..747938d33f532c 100644 --- a/x-pack/plugins/canvas/public/components/shape_preview/__stories__/__snapshots__/shape_preview.stories.storyshot +++ b/x-pack/plugins/canvas/public/components/shape_preview/__stories__/__snapshots__/shape_preview.stories.storyshot @@ -3,25 +3,36 @@ exports[`Storyshots components/Shapes/ShapePreview arrow 1`] = `
- - ", - } - } -/> +> + + + +
`; exports[`Storyshots components/Shapes/ShapePreview square 1`] = `
- - ", - } - } -/> +> + + + +
`; diff --git a/x-pack/plugins/canvas/public/components/shape_preview/__stories__/shape_preview.stories.tsx b/x-pack/plugins/canvas/public/components/shape_preview/__stories__/shape_preview.stories.tsx index 1a135bae1c096a..de7ce4b411860a 100644 --- a/x-pack/plugins/canvas/public/components/shape_preview/__stories__/shape_preview.stories.tsx +++ b/x-pack/plugins/canvas/public/components/shape_preview/__stories__/shape_preview.stories.tsx @@ -8,9 +8,8 @@ import { storiesOf } from '@storybook/react'; import React from 'react'; import { ShapePreview } from '../shape_preview'; - -import { shapes } from '../../../../canvas_plugin_src/renderers/shape/shapes'; +import { Shape } from '../../../../../../../src/plugins/expression_shape/public'; storiesOf('components/Shapes/ShapePreview', module) - .add('arrow', () => ) - .add('square', () => ); + .add('arrow', () => ) + .add('square', () => ); diff --git a/x-pack/plugins/canvas/public/components/shape_preview/shape_preview.tsx b/x-pack/plugins/canvas/public/components/shape_preview/shape_preview.tsx index 7fbb28b771f39a..22d0d8cca84ef1 100644 --- a/x-pack/plugins/canvas/public/components/shape_preview/shape_preview.tsx +++ b/x-pack/plugins/canvas/public/components/shape_preview/shape_preview.tsx @@ -5,45 +5,55 @@ * 2.0. */ -import React, { FC } from 'react'; +import React, { FC, RefCallback, useCallback, useState } from 'react'; import PropTypes from 'prop-types'; +import { + LazyShapeDrawer, + Shape, + ShapeDrawerComponentProps, + getDefaultShapeData, + SvgConfig, + ShapeRef, + ViewBoxParams, +} from '../../../../../../src/plugins/expression_shape/public'; +import { withSuspense } from '../../../../../../src/plugins/presentation_util/public'; interface Props { - shape?: string; + shape?: Shape; +} + +const ShapeDrawer = withSuspense(LazyShapeDrawer); + +function getViewBox(defaultWidth: number, defaultViewBox: ViewBoxParams): ViewBoxParams { + const { minX, minY, width, height } = defaultViewBox; + return { + minX: minX - defaultWidth / 2, + minY: minY - defaultWidth / 2, + width: width + defaultWidth, + height: height + defaultWidth, + }; } export const ShapePreview: FC = ({ shape }) => { - if (!shape) { - return
; - } - - const weight = 5; - const parser = new DOMParser(); - 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 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; - minY -= weight / 2; - width += weight; - height += weight; - shapeSvg.setAttribute('viewBox', [minX, minY, width, height].join(' ')); + const [shapeData, setShapeData] = useState(getDefaultShapeData()); + + const shapeRef = useCallback>((node) => { + if (node !== null) setShapeData(node.getData()); + }, []); + if (!shape) return
; return ( - // eslint-disable-next-line react/no-danger -
+
+ +
); }; diff --git a/x-pack/plugins/canvas/shareable_runtime/supported_renderers.js b/x-pack/plugins/canvas/shareable_runtime/supported_renderers.js index df894a65afab17..bb5880b7f40a9b 100644 --- a/x-pack/plugins/canvas/shareable_runtime/supported_renderers.js +++ b/x-pack/plugins/canvas/shareable_runtime/supported_renderers.js @@ -12,7 +12,6 @@ import { metric } from '../canvas_plugin_src/renderers/metric'; import { pie } from '../canvas_plugin_src/renderers/pie'; import { plot } from '../canvas_plugin_src/renderers/plot'; import { progress } from '../canvas_plugin_src/renderers/progress'; -import { shape } from '../canvas_plugin_src/renderers/shape'; import { table } from '../canvas_plugin_src/renderers/table'; import { text } from '../canvas_plugin_src/renderers/text'; import { revealImageRenderer as revealImage } from '../../../../src/plugins/expression_reveal_image/public'; @@ -20,6 +19,7 @@ import { errorRenderer as error, debugRenderer as debug, } from '../../../../src/plugins/expression_error/public'; +import { shapeRenderer as shape } from '../../../../src/plugins/expression_shape/public'; /** * This is a collection of renderers which are bundled with the runtime. If diff --git a/x-pack/plugins/canvas/storybook/storyshots.test.tsx b/x-pack/plugins/canvas/storybook/storyshots.test.tsx index 643bd1dc22041d..f99a1ed5d4335a 100644 --- a/x-pack/plugins/canvas/storybook/storyshots.test.tsx +++ b/x-pack/plugins/canvas/storybook/storyshots.test.tsx @@ -39,19 +39,6 @@ jest.mock('../public/lib/ui_metric', () => ({ trackCanvasUiMetric: () => {} })); // 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: ` - - `, - square: ` - - `, - }, -})); - // Mock react-datepicker dep used by eui to avoid rendering the entire large component jest.mock('@elastic/eui/packages/react-datepicker', () => { return { diff --git a/x-pack/plugins/canvas/tsconfig.json b/x-pack/plugins/canvas/tsconfig.json index bf9544a173f16f..8c97a78da7f0fc 100644 --- a/x-pack/plugins/canvas/tsconfig.json +++ b/x-pack/plugins/canvas/tsconfig.json @@ -33,6 +33,7 @@ { "path": "../../../src/plugins/expressions/tsconfig.json" }, { "path": "../../../src/plugins/expression_error/tsconfig.json" }, { "path": "../../../src/plugins/expression_reveal_image/tsconfig.json" }, + { "path": "../../../src/plugins/expression_shape/tsconfig.json" }, { "path": "../../../src/plugins/home/tsconfig.json" }, { "path": "../../../src/plugins/inspector/tsconfig.json" }, { "path": "../../../src/plugins/kibana_legacy/tsconfig.json" }, diff --git a/x-pack/plugins/translations/translations/ja-JP.json b/x-pack/plugins/translations/translations/ja-JP.json index e67f70daf740d9..a3fb72f10d6f94 100644 --- a/x-pack/plugins/translations/translations/ja-JP.json +++ b/x-pack/plugins/translations/translations/ja-JP.json @@ -6347,12 +6347,12 @@ "xpack.canvas.functions.seriesStyle.args.pointsHelpText": "線上の点のサイズです。", "xpack.canvas.functions.seriesStyle.args.stackHelpText": "数列をスタックするかを指定します。数字はスタック ID です。同じスタック ID の数列は一緒にスタックされます。", "xpack.canvas.functions.seriesStyleHelpText": "チャートの数列のプロパティの説明に使用されるオブジェクトを作成します。{plotFn} や {pieFn} のように、チャート関数内で {seriesStyleFn} を使用します。", - "xpack.canvas.functions.shape.args.borderHelpText": "図形の外郭の {SVG} カラーです。", - "xpack.canvas.functions.shape.args.borderWidthHelpText": "境界の太さです。", - "xpack.canvas.functions.shape.args.fillHelpText": "図形を塗りつぶす {SVG} カラーです。", - "xpack.canvas.functions.shape.args.maintainAspectHelpText": "図形の元の横縦比を維持しますか?", - "xpack.canvas.functions.shape.args.shapeHelpText": "図形を選択します。", - "xpack.canvas.functions.shapeHelpText": "図形を作成します。", + "expressionShape.functions.shape.args.borderHelpText": "図形の外郭の {SVG} カラーです。", + "expressionShape.functions.shape.args.borderWidthHelpText": "境界の太さです。", + "expressionShape.functions.shape.args.fillHelpText": "図形を塗りつぶす {SVG} カラーです。", + "expressionShape.functions.shape.args.maintainAspectHelpText": "図形の元の横縦比を維持しますか?", + "expressionShape.functions.shape.args.shapeHelpText": "図形を選択します。", + "expressionShape.functions.shapeHelpText": "図形を作成します。", "xpack.canvas.functions.sort.args.byHelpText": "並べ替えの基準となる列です。指定されていない場合、{DATATABLE}は初めの列で並べられます。", "xpack.canvas.functions.sort.args.reverseHelpText": "並び順を反転させます。指定されていない場合、{DATATABLE}は昇順で並べられます。", "xpack.canvas.functions.sortHelpText": "{DATATABLE}を指定された列で並べ替えます。", @@ -6509,8 +6509,8 @@ "xpack.canvas.renderer.progress.helpDescription": "エレメントのパーセンテージを示す進捗インジケーターをレンダリングします", "xpack.canvas.renderer.repeatImage.displayName": "画像の繰り返し", "xpack.canvas.renderer.repeatImage.helpDescription": "画像を指定回数繰り返し表示します", - "xpack.canvas.renderer.shape.displayName": "形状", - "xpack.canvas.renderer.shape.helpDescription": "基本的な図形をレンダリングします", + "expressionShape.renderer.shape.displayName": "形状", + "expressionShape.renderer.shape.helpDescription": "基本的な図形をレンダリングします", "xpack.canvas.renderer.table.displayName": "データテーブル", "xpack.canvas.renderer.table.helpDescription": "表形式データを {HTML} としてレンダリングします", "xpack.canvas.renderer.text.displayName": "プレインテキスト", diff --git a/x-pack/plugins/translations/translations/zh-CN.json b/x-pack/plugins/translations/translations/zh-CN.json index 57ddc50e1b91cc..63c55aef492258 100644 --- a/x-pack/plugins/translations/translations/zh-CN.json +++ b/x-pack/plugins/translations/translations/zh-CN.json @@ -6071,8 +6071,6 @@ "xpack.canvas.elements.progressWheelHelpText": "将进度显示为轮盘的一部分", "xpack.canvas.elements.repeatImageDisplayName": "图像重复", "xpack.canvas.elements.repeatImageHelpText": "使图像重复 N 次", - "xpack.canvas.elements.revealImageDisplayName": "图像显示", - "xpack.canvas.elements.revealImageHelpText": "显示图像特定百分比", "xpack.canvas.elements.shapeDisplayName": "形状", "xpack.canvas.elements.shapeHelpText": "可定制的形状", "xpack.canvas.elements.tableDisplayName": "数据表", @@ -6386,12 +6384,12 @@ "xpack.canvas.functions.seriesStyle.args.pointsHelpText": "折线图上的点大小。", "xpack.canvas.functions.seriesStyle.args.stackHelpText": "指定是否应堆叠序列。数字为堆叠 ID。具有相同堆叠 ID 的序列将堆叠在一起。", "xpack.canvas.functions.seriesStyleHelpText": "创建用于在图表上描述序列属性的对象。在绘图函数 (如 {plotFn} 或 {pieFn} ) 内使用 {seriesStyleFn}。", - "xpack.canvas.functions.shape.args.borderHelpText": "形状轮廓边框的 {SVG} 颜色。", - "xpack.canvas.functions.shape.args.borderWidthHelpText": "边框的粗细。", - "xpack.canvas.functions.shape.args.fillHelpText": "填充形状的 {SVG} 颜色。", - "xpack.canvas.functions.shape.args.maintainAspectHelpText": "维持形状的原始纵横比?", - "xpack.canvas.functions.shape.args.shapeHelpText": "选取形状。", - "xpack.canvas.functions.shapeHelpText": "创建形状。", + "expressionShape.functions.shape.args.borderHelpText": "形状轮廓边框的 {SVG} 颜色。", + "expressionShape.functions.shape.args.borderWidthHelpText": "边框的粗细。", + "expressionShape.functions.shape.args.fillHelpText": "填充形状的 {SVG} 颜色。", + "expressionShape.functions.shape.args.maintainAspectHelpText": "维持形状的原始纵横比?", + "expressionShape.functions.shape.args.shapeHelpText": "选取形状。", + "expressionShape.functions.shapeHelpText": "创建形状。", "xpack.canvas.functions.sort.args.byHelpText": "排序依据的列。如果未指定,则 {DATATABLE} 按第一列排序。", "xpack.canvas.functions.sort.args.reverseHelpText": "反转排序顺序。如果未指定,则 {DATATABLE} 按升序排序。", "xpack.canvas.functions.sortHelpText": "按指定列对 {DATATABLE} 进行排序。", @@ -6548,8 +6546,8 @@ "xpack.canvas.renderer.progress.helpDescription": "呈现显示元素百分比的进度指示", "xpack.canvas.renderer.repeatImage.displayName": "图像重复", "xpack.canvas.renderer.repeatImage.helpDescription": "重复图像给定次数", - "xpack.canvas.renderer.shape.displayName": "形状", - "xpack.canvas.renderer.shape.helpDescription": "呈现基本形状", + "expressionShape.renderer.shape.displayName": "形状", + "expressionShape.renderer.shape.helpDescription": "呈现基本形状", "xpack.canvas.renderer.table.displayName": "数据表", "xpack.canvas.renderer.table.helpDescription": "将表格数据呈现为 {HTML}", "xpack.canvas.renderer.text.displayName": "纯文本",