From fe767700ac067bc06d7b47e5a30c17a3dc133e64 Mon Sep 17 00:00:00 2001 From: Sivan Duijn <sivanduijn@gmail.com> Date: Sat, 5 Mar 2022 16:41:22 +0100 Subject: [PATCH] feat(querybuilder): added custom edge lines and auto drag attributes along --- .../customFlowLines/connection.tsx | 73 +++++++++++++++++++ .../customFlowLines/connectionDrag.tsx | 41 +++++++++++ .../attributepill/attributepill.module.scss | 12 ++- .../attributepill/attributepill.tsx | 13 +++- .../customFlowPills/entitypill/entitypill.tsx | 24 +++--- .../relationpill/relationpill.tsx | 16 ++-- .../querybuilder/querybuilder.module.scss | 8 ++ .../querybuilder/querybuilder.stories.tsx | 28 ++++--- .../components/querybuilder/querybuilder.tsx | 14 +++- libs/querybuilder/usecases/src/index.ts | 1 + .../usecases/src/lib/attribute/checkInput.ts | 2 + .../usecases/src/lib/connPointsOnPills.ts | 14 ++++ .../src/lib/createReactFlowElements.ts | 30 +++++++- .../store/src/lib/colorPaletteConfigSlice.ts | 3 + .../src/lib/mapColorsConfigToMuiTheme.ts | 24 ++++++ package.json | 2 + yarn.lock | 39 +++++++++- 17 files changed, 300 insertions(+), 44 deletions(-) create mode 100644 apps/web-graphpolaris/src/components/querybuilder/customFlowLines/connection.tsx create mode 100644 apps/web-graphpolaris/src/components/querybuilder/customFlowLines/connectionDrag.tsx create mode 100644 apps/web-graphpolaris/src/components/querybuilder/querybuilder.module.scss create mode 100644 libs/querybuilder/usecases/src/lib/connPointsOnPills.ts diff --git a/apps/web-graphpolaris/src/components/querybuilder/customFlowLines/connection.tsx b/apps/web-graphpolaris/src/components/querybuilder/customFlowLines/connection.tsx new file mode 100644 index 000000000..618f67b6b --- /dev/null +++ b/apps/web-graphpolaris/src/components/querybuilder/customFlowLines/connection.tsx @@ -0,0 +1,73 @@ +import { handles } from '@graphpolaris/querybuilder/usecases'; +import React from 'react'; +import { EdgeProps, getSmoothStepPath, Position } from 'react-flow-renderer'; + +/** + * A custom query element edge line component. + * @param {EdgeProps} param0 The coordinates for the start and end point, the id and the style. + */ +export default function ConnectionLine({ + id, + sourceX, + sourceY, + targetX, + targetY, + style, + sourceHandleId, + targetHandleId, +}: EdgeProps) { + //Centering the line + sourceY -= 3; + targetY -= 3; + + // Correct line positions with hardcoded numbers, because react flow lacks this functionality + // if (sourceHandleId == ) sourceX += 2; + + // if (targetHandleId == Handles.ToAttributeHandle) targetX += 2; + + let spos: Position = Position.Bottom; + if (sourceHandleId == handles.relation.fromEntity) { + spos = Position.Left; + sourceX += 7; + sourceY += 3; + } else if (sourceHandleId == handles.relation.toEntity) { + spos = Position.Right; + sourceX -= 2; + sourceY -= 3; + } else if ( + sourceHandleId !== undefined && + sourceHandleId !== null && + sourceHandleId.includes('functionHandle') + ) { + spos = Position.Top; + sourceX -= 4; + sourceY += 3; + } + + let tpos: Position = Position.Bottom; + if (targetHandleId == handles.relation.fromEntity) { + tpos = Position.Left; + targetX += 7; + targetY += 3; + } else if (targetHandleId == handles.relation.toEntity) { + tpos = Position.Right; + targetX -= 2; + targetY -= 3; + } + + // Create smoothstep line + const path = getSmoothStepPath({ + sourceX: sourceX, + sourceY: sourceY, + sourcePosition: spos, + targetX: targetX, + targetY: targetY, + targetPosition: tpos, + }); + + return ( + <g stroke="#2e2e2e"> + <path id={id} fill="none" strokeWidth={3} style={style} d={path} /> + </g> + ); +} diff --git a/apps/web-graphpolaris/src/components/querybuilder/customFlowLines/connectionDrag.tsx b/apps/web-graphpolaris/src/components/querybuilder/customFlowLines/connectionDrag.tsx new file mode 100644 index 000000000..9932aecdd --- /dev/null +++ b/apps/web-graphpolaris/src/components/querybuilder/customFlowLines/connectionDrag.tsx @@ -0,0 +1,41 @@ +import React from 'react'; +import { ConnectionLineComponentProps } from 'react-flow-renderer'; + +/** + * A custom query element to render the line when connecting flow elements. + * @param {ConnectionLineComponentProps} param0 Source and target coordinates of the edges. + */ +export default function ConnectionDragLine({ + sourceX, + sourceY, + targetX, + targetY, +}: ConnectionLineComponentProps) { + return ( + <g> + <path + fill="none" + stroke="#222" + strokeWidth={2.5} + className="animated" + d={`M${sourceX},${sourceY}L ${targetX},${targetY}`} + /> + <circle + cx={sourceX} + cy={sourceY} + fill="#fff" + r={3} + stroke="#222" + strokeWidth={1.5} + /> + <circle + cx={targetX} + cy={targetY} + fill="#fff" + r={3} + stroke="#222" + strokeWidth={1.5} + /> + </g> + ); +} diff --git a/apps/web-graphpolaris/src/components/querybuilder/customFlowPills/attributepill/attributepill.module.scss b/apps/web-graphpolaris/src/components/querybuilder/customFlowPills/attributepill/attributepill.module.scss index 5d3bd74fb..9ba5ba22c 100644 --- a/apps/web-graphpolaris/src/components/querybuilder/customFlowPills/attributepill/attributepill.module.scss +++ b/apps/web-graphpolaris/src/components/querybuilder/customFlowPills/attributepill/attributepill.module.scss @@ -35,22 +35,26 @@ .attributeInput { float: right; - padding: 0 2ch 0 0; + padding: 0 1ch 0 0; display: flex; align-items: center; input { - background-color: lightgray; + background-color: rgba(100, 100, 100, 0.1); font-family: monospace; font-size: variables.$fontsize; - border: 1px solid darkgrey; + border: 1px solid rgba(100, 100, 100, 0.3); border-radius: 2px; height: variables.$height; outline: none; transition: border 0.3s; + color: black; + &::placeholder { + color: black; + } &:focus { - border: 1px solid grey; + border: 1px solid rgba(0, 0, 0, 0.3); } } } diff --git a/apps/web-graphpolaris/src/components/querybuilder/customFlowPills/attributepill/attributepill.tsx b/apps/web-graphpolaris/src/components/querybuilder/customFlowPills/attributepill/attributepill.tsx index 2c98aacf4..a2a70d95b 100644 --- a/apps/web-graphpolaris/src/components/querybuilder/customFlowPills/attributepill/attributepill.tsx +++ b/apps/web-graphpolaris/src/components/querybuilder/customFlowPills/attributepill/attributepill.tsx @@ -4,8 +4,6 @@ import { } from '@graphpolaris/querybuilder/usecases'; import { useTheme } from '@mui/material'; import React, { useMemo, useState } from 'react'; -import { Handle, Position } from 'react-flow-renderer'; -import { Handles } from '../entitypill/entitypill'; import styles from './attributepill.module.scss'; import AttributeOperatorSelect from './operatorselect'; @@ -15,7 +13,6 @@ import AttributeOperatorSelect from './operatorselect'; */ export const AttributeRFPill = React.memo(({ data }: { data: any }) => { const theme = useTheme(); - const [readonly, setReadonly] = useState(true); const [value, setValue] = useState(data?.value || ''); const onChange = (e: any) => { @@ -37,11 +34,19 @@ export const AttributeRFPill = React.memo(({ data }: { data: any }) => { [data?.datatype] ); + // Determine the backgroundcolor based on if the attribute is connected to a entity or relation + let bgcolor; + if (data?.attributeOfA == 'entity') + bgcolor = theme.palette.queryBuilder.entity.lighterbg; + else if (data?.attributeOfA == 'relation') + bgcolor = theme.palette.queryBuilder.relation.lighterbg; + else bgcolor = theme.palette.queryBuilder.attribute.background; + return ( <div className={styles.attribute} style={{ - background: theme.palette.queryBuilder.attribute.background, + background: bgcolor, color: theme.palette.queryBuilder.text, }} > diff --git a/apps/web-graphpolaris/src/components/querybuilder/customFlowPills/entitypill/entitypill.tsx b/apps/web-graphpolaris/src/components/querybuilder/customFlowPills/entitypill/entitypill.tsx index bf0b15f7d..2598bf458 100644 --- a/apps/web-graphpolaris/src/components/querybuilder/customFlowPills/entitypill/entitypill.tsx +++ b/apps/web-graphpolaris/src/components/querybuilder/customFlowPills/entitypill/entitypill.tsx @@ -1,3 +1,4 @@ +import { handles } from '@graphpolaris/querybuilder/usecases'; import { useTheme } from '@mui/material'; import React, { useEffect } from 'react'; import { FlowElement, Handle, Position } from 'react-flow-renderer'; @@ -10,16 +11,16 @@ import styles from './entitypill.module.scss'; // }, // }; -/** Links need handles to what they are connected to (and which side) */ -export enum Handles { - RelationLeft = 'leftEntityHandle', //target - RelationRight = 'rightEntityHandle', //target - ToAttributeHandle = 'attributesHandle', //target - ToRelation = 'relationsHandle', //source - Attribute = 'AttributeHandle', //source - ReceiveFunction = 'receiveFunctionHandle', //target - FunctionBase = 'functionHandle_', // + name from FunctionTypes args //source -} +// /** Links need handles to what they are connected to (and which side) */ +// export enum Handles { +// RelationLeft = 'leftEntityHandle', //target +// RelationRight = 'rightEntityHandle', //target +// ToAttributeHandle = 'attributesHandle', //target +// ToRelation = 'relationsHandle', //source +// Attribute = 'AttributeHandle', //source +// ReceiveFunction = 'receiveFunctionHandle', //target +// FunctionBase = 'functionHandle_', // + name from FunctionTypes args //source +// } /** * Component to render an entity flow element @@ -37,10 +38,11 @@ export const EntityRFPill = React.memo(({ data }: { data: any }) => { }} > <Handle - id={Handles.ToRelation} + id={handles.entity.relation} type="source" position={Position.Bottom} className={styles.handleLeft} + style={data?.isConnected ? { backgroundColor: '#2e2e2e' } : {}} /> {/* <Handle id={Handles.ToAttributeHandle} diff --git a/apps/web-graphpolaris/src/components/querybuilder/customFlowPills/relationpill/relationpill.tsx b/apps/web-graphpolaris/src/components/querybuilder/customFlowPills/relationpill/relationpill.tsx index 64612837e..34c0d57eb 100644 --- a/apps/web-graphpolaris/src/components/querybuilder/customFlowPills/relationpill/relationpill.tsx +++ b/apps/web-graphpolaris/src/components/querybuilder/customFlowPills/relationpill/relationpill.tsx @@ -1,6 +1,6 @@ +import { handles } from '@graphpolaris/querybuilder/usecases'; import { useTheme } from '@mui/material'; import { Handle, Position } from 'react-flow-renderer'; -import { Handles } from '../entitypill/entitypill'; import styles from './relationpill.module.scss'; @@ -61,19 +61,25 @@ export default function RelationRFPill({ data }: { data: any }) { }} > <Handle - id={Handles.RelationLeft} - type="source" + id={handles.relation.fromEntity} + type="target" position={Position.Left} className={styles.handleLeft} + style={ + data?.isFromEntityConnected ? { borderRightColor: '#2e2e2e' } : {} // TODO: this should be color from theme + } /> <span className={styles.content} title={data.name}> {data.name} </span> <Handle - id={Handles.RelationRight} - type="target" + id={handles.relation.toEntity} + type="source" position={Position.Right} className={styles.handleRight} + style={ + data?.isToEntityConnected ? { borderLeftColor: '#2e2e2e' } : {} + } /> </div> <div diff --git a/apps/web-graphpolaris/src/components/querybuilder/querybuilder.module.scss b/apps/web-graphpolaris/src/components/querybuilder/querybuilder.module.scss new file mode 100644 index 000000000..db83f4696 --- /dev/null +++ b/apps/web-graphpolaris/src/components/querybuilder/querybuilder.module.scss @@ -0,0 +1,8 @@ +.reactflow { + width: 100%; + height: 500px; + + // :global(.react-flow__edges) { + // z-index: 4 !important; + // } +} diff --git a/apps/web-graphpolaris/src/components/querybuilder/querybuilder.stories.tsx b/apps/web-graphpolaris/src/components/querybuilder/querybuilder.stories.tsx index a3de1a494..9727183be 100644 --- a/apps/web-graphpolaris/src/components/querybuilder/querybuilder.stories.tsx +++ b/apps/web-graphpolaris/src/components/querybuilder/querybuilder.stories.tsx @@ -5,15 +5,12 @@ import { setQuerybuilderNodes, } from '@graphpolaris/shared/data-access/store'; import { GraphPolarisThemeProvider } from '@graphpolaris/shared/data-access/theme'; -import { AnyAction, configureStore, Store } from '@reduxjs/toolkit'; -import { - ComponentMeta, - ComponentStory, - ReactFramework, -} from '@storybook/react'; +import { configureStore } from '@reduxjs/toolkit'; +import { ComponentMeta, ComponentStory } from '@storybook/react'; import { Provider } from 'react-redux'; import QueryBuilder from './querybuilder'; import { MultiGraph } from 'graphology'; +import { handles } from '@graphpolaris/querybuilder/usecases'; export default { component: QueryBuilder, @@ -51,20 +48,27 @@ graph.addNode('3', { }); graph.addNode('4', { type: 'attribute', - x: 170, - y: 180, + x: 130, + y: 120, name: 'Attr bool', datatype: 'bool', operator: 'EQ', }); graph.addEdge('2', '1', { type: 'attribute_connection' }); graph.addEdge('3', '1', { type: 'attribute_connection' }); -graph.addEdge('4', '1', { type: 'attribute_connection' }); -// graph.addEdge('0', '1', { type: 'entity_relation' }); +graph.addEdge('4', '0', { type: 'attribute_connection' }); +graph.addEdge('0', '1', { + type: 'entity_relation', + targetHandle: handles.relation.fromEntity, +}); +// graph.addEdge('1', '0', { +// type: 'entity_relation', +// sourceHandle: handles.relation.entity, +// }); mockStore.dispatch(setQuerybuilderNodes(graph.export())); -export const NoData = Template.bind({}); -NoData.decorators = [ +export const Simple = Template.bind({}); +Simple.decorators = [ (story) => ( <Provider store={mockStore}> <GraphPolarisThemeProvider>{story()}</GraphPolarisThemeProvider> diff --git a/apps/web-graphpolaris/src/components/querybuilder/querybuilder.tsx b/apps/web-graphpolaris/src/components/querybuilder/querybuilder.tsx index dd90aded3..8e42ebf76 100644 --- a/apps/web-graphpolaris/src/components/querybuilder/querybuilder.tsx +++ b/apps/web-graphpolaris/src/components/querybuilder/querybuilder.tsx @@ -16,6 +16,9 @@ import ReactFlow, { Background, Node, } from 'react-flow-renderer'; +import styles from './querybuilder.module.scss'; +import ConnectionLine from './customFlowLines/connection'; +import ConnectionDragLine from './customFlowLines/connectionDrag'; import AttributeRFPill from './customFlowPills/attributepill/attributepill'; import EntityRFPill from './customFlowPills/entitypill/entitypill'; import RelationRFPill from './customFlowPills/relationpill/relationpill'; @@ -25,6 +28,9 @@ const nodeTypes = { relation: RelationRFPill, attribute: AttributeRFPill, }; +const edgeTypes = { + connection: ConnectionLine, +}; const onLoad = (reactFlowInstance: any) => { setTimeout(() => reactFlowInstance.fitView(), 0); @@ -36,8 +42,6 @@ const QueryBuilder = (props: {}) => { const elements = useMemo(() => createReactFlowElements(nodes), [nodes]); - const graphStyles = { width: '100%', height: '500px' }; - const onNodeDrag = ( event: React.MouseEvent<Element, MouseEvent>, node: Node<any> @@ -64,12 +68,14 @@ const QueryBuilder = (props: {}) => { <ReactFlowProvider> <ReactFlow elements={elements} - style={graphStyles} snapGrid={[10, 10]} - // snapToGrid={true} + // snapToGrid nodeTypes={nodeTypes} + edgeTypes={edgeTypes} + connectionLineComponent={ConnectionDragLine} onLoad={onLoad} onNodeDrag={onNodeDrag} + className={styles.reactflow} > <Background gap={10} size={0.7} /> </ReactFlow> diff --git a/libs/querybuilder/usecases/src/index.ts b/libs/querybuilder/usecases/src/index.ts index b0e1230da..587b11ec5 100644 --- a/libs/querybuilder/usecases/src/index.ts +++ b/libs/querybuilder/usecases/src/index.ts @@ -1,3 +1,4 @@ export * from './lib/attribute/getAttributeBoolOperators'; export * from './lib/attribute/checkInput'; export * from './lib/createReactFlowElements'; +export * from './lib/connPointsOnPills'; diff --git a/libs/querybuilder/usecases/src/lib/attribute/checkInput.ts b/libs/querybuilder/usecases/src/lib/attribute/checkInput.ts index 8c8b0e625..f48dd787c 100644 --- a/libs/querybuilder/usecases/src/lib/attribute/checkInput.ts +++ b/libs/querybuilder/usecases/src/lib/attribute/checkInput.ts @@ -22,6 +22,8 @@ export function CheckDatatypeConstraint(type: string, str: string): string { isBoolean(str) ? (res = toBoolean(str)) : (res = ''); break; case 'int': + case 'float': + case 'number': isNumber(str) ? (res = '' + parseFloat(str)) : (res = ''); break; default: diff --git a/libs/querybuilder/usecases/src/lib/connPointsOnPills.ts b/libs/querybuilder/usecases/src/lib/connPointsOnPills.ts new file mode 100644 index 000000000..355bdd8e5 --- /dev/null +++ b/libs/querybuilder/usecases/src/lib/connPointsOnPills.ts @@ -0,0 +1,14 @@ +// This file describes the connection points (handles) on a query builder pill +// For example the connection from entity to left relation handle + +export const handles = { + entity: { + /** The handle for a connection from an entity to a relation pill */ + relation: 'entity:to_relation', + }, + relation: { + /** The handle for a connection from a relation to an entity pill */ + toEntity: 'relation:to_entity', + fromEntity: 'relation:from_entity', + }, +}; diff --git a/libs/querybuilder/usecases/src/lib/createReactFlowElements.ts b/libs/querybuilder/usecases/src/lib/createReactFlowElements.ts index 21e0dcea1..76b9e83c4 100644 --- a/libs/querybuilder/usecases/src/lib/createReactFlowElements.ts +++ b/libs/querybuilder/usecases/src/lib/createReactFlowElements.ts @@ -11,15 +11,40 @@ export function createReactFlowElements(graph: Graph): Elements<Node | Edge> { switch (attributes.type) { case 'entity': + data = { + name: attributes.name, + isConnected: graph + .neighbors(node) + .some((nb) => graph.getNodeAttribute(nb, 'type') == 'relation'), + }; + break; case 'relation': - data = { name: attributes.name }; + data = { + name: attributes.name, + isFromEntityConnected: graph + .inNeighbors(node) + .some((nb) => graph.getNodeAttribute(nb, 'type') == 'entity'), + isToEntityConnected: graph + .outNeighbors(node) + .some((nb) => graph.getNodeAttribute(nb, 'type') == 'entity'), + }; break; - case 'attribute': + case 'attribute': { + const ERNeighbors = graph.outNeighbors(node).filter((nb) => { + const type = graph.getNodeAttribute(nb, 'type'); + return type == 'entity' || type == 'relation'; + }); + let attributeOfA = ''; + if (ERNeighbors.length > 0) + attributeOfA = graph.getNodeAttribute(ERNeighbors[0], 'type'); data = { name: attributes.name, datatype: attributes.datatype, operator: attributes.operator, + attributeOfA: attributeOfA, }; + break; + } } const RFNode: Node = { @@ -39,6 +64,7 @@ export function createReactFlowElements(graph: Graph): Elements<Node | Edge> { id: edge, source: source, target: target, + type: 'connection', sourceHandle: attributes.sourceHandle, targetHandle: attributes.targetHandle, }; diff --git a/libs/shared/data-access/store/src/lib/colorPaletteConfigSlice.ts b/libs/shared/data-access/store/src/lib/colorPaletteConfigSlice.ts index 521f63b8a..64d340262 100644 --- a/libs/shared/data-access/store/src/lib/colorPaletteConfigSlice.ts +++ b/libs/shared/data-access/store/src/lib/colorPaletteConfigSlice.ts @@ -10,12 +10,15 @@ export interface ExtraColorsForMui5 { text: string; entity: { background: string; + lighterbg?: string; }; relation: { background: string; + lighterbg?: string; }; attribute: { background: string; + lighterbg?: string; }; }; } diff --git a/libs/shared/data-access/theme/src/lib/mapColorsConfigToMuiTheme.ts b/libs/shared/data-access/theme/src/lib/mapColorsConfigToMuiTheme.ts index 975bb3ed0..aa9a6de51 100644 --- a/libs/shared/data-access/theme/src/lib/mapColorsConfigToMuiTheme.ts +++ b/libs/shared/data-access/theme/src/lib/mapColorsConfigToMuiTheme.ts @@ -1,5 +1,6 @@ import { ColorPaletteConfig } from '@graphpolaris/shared/data-access/store'; import { ThemeOptions } from '@mui/material/styles'; +import Color from 'color'; /** Maps our color palette config (stored in redux) to the mui 5 theme format */ export default function MapColorsConfigToMuiTheme( @@ -20,11 +21,22 @@ export default function MapColorsConfigToMuiTheme( background: colorsConfig.darkPalette.custom.queryBuilder.entity .background, + lighterbg: Color( + colorsConfig.darkPalette.custom.queryBuilder.entity.background + ) + .lighten(0.2) + .toString(), }, relation: { background: colorsConfig.darkPalette.custom.queryBuilder.relation .background, + lighterbg: Color( + colorsConfig.darkPalette.custom.queryBuilder.relation + .background + ) + .lighten(0.2) + .toString(), }, attribute: { background: @@ -43,11 +55,23 @@ export default function MapColorsConfigToMuiTheme( background: colorsConfig.lightPalette.custom.queryBuilder.entity .background, + lighterbg: Color( + colorsConfig.lightPalette.custom.queryBuilder.entity + .background + ) + .lighten(0.2) + .toString(), }, relation: { background: colorsConfig.lightPalette.custom.queryBuilder.relation .background, + lighterbg: Color( + colorsConfig.lightPalette.custom.queryBuilder.relation + .background + ) + .lighten(0.2) + .toString(), }, attribute: { background: diff --git a/package.json b/package.json index c2b43c245..cf9c8e848 100644 --- a/package.json +++ b/package.json @@ -18,6 +18,7 @@ "@types/cytoscape": "^3.19.4", "@types/react-grid-layout": "^1.3.0", "@types/styled-components": "^5.1.21", + "color": "^4.2.1", "core-js": "^3.6.5", "cytoscape": "^3.21.0", "graphology": "^0.24.0", @@ -59,6 +60,7 @@ "@svgr/webpack": "^5.4.0", "@testing-library/react": "12.1.2", "@testing-library/react-hooks": "7.0.2", + "@types/color": "^3.0.3", "@types/jest": "27.0.2", "@types/node": "16.11.7", "@types/react": "17.0.30", diff --git a/yarn.lock b/yarn.lock index 898701c93..2beea9136 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4072,7 +4072,7 @@ dependencies: "@types/node" "*" -"@types/color-convert@^2.0.0": +"@types/color-convert@*", "@types/color-convert@^2.0.0": version "2.0.0" resolved "https://registry.yarnpkg.com/@types/color-convert/-/color-convert-2.0.0.tgz#8f5ee6b9e863dcbee5703f5a517ffb13d3ea4e22" integrity sha512-m7GG7IKKGuJUXvkZ1qqG3ChccdIM/qBBo913z+Xft0nKCX4hAU/IxKwZBU4cpRZ7GS5kV4vOblUkILtSShCPXQ== @@ -4084,6 +4084,13 @@ resolved "https://registry.yarnpkg.com/@types/color-name/-/color-name-1.1.1.tgz#1c1261bbeaa10a8055bbc5d8ab84b7b2afc846a0" integrity sha512-rr+OQyAjxze7GgWrSaJwydHStIhHq2lvY3BOC2Mj7KnzI7XK0Uw1TOOdI9lDoajEbSWLiYgoo4f1R51erQfhPQ== +"@types/color@^3.0.3": + version "3.0.3" + resolved "https://registry.yarnpkg.com/@types/color/-/color-3.0.3.tgz#e6d8d72b7aaef4bb9fe80847c26c7c786191016d" + integrity sha512-X//qzJ3d3Zj82J9sC/C18ZY5f43utPbAJ6PhYt/M7uG6etcF6MRpKdN880KBy43B0BMzSfeT96MzrsNjFI3GbA== + dependencies: + "@types/color-convert" "*" + "@types/connect-history-api-fallback@^1.3.5": version "1.3.5" resolved "https://registry.yarnpkg.com/@types/connect-history-api-fallback/-/connect-history-api-fallback-1.3.5.tgz#d1f7a8a09d0ed5a57aee5ae9c18ab9b803205dae" @@ -6581,16 +6588,32 @@ color-name@1.1.3: resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25" integrity sha1-p9BVi9icQveV3UIyj3QIMcpTvCU= -color-name@~1.1.4: +color-name@^1.0.0, color-name@~1.1.4: version "1.1.4" resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2" integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== +color-string@^1.9.0: + version "1.9.0" + resolved "https://registry.yarnpkg.com/color-string/-/color-string-1.9.0.tgz#63b6ebd1bec11999d1df3a79a7569451ac2be8aa" + integrity sha512-9Mrz2AQLefkH1UvASKj6v6hj/7eWgjnT/cVsR8CumieLoT+g900exWeNogqtweI8dxloXN9BDQTYro1oWu/5CQ== + dependencies: + color-name "^1.0.0" + simple-swizzle "^0.2.2" + color-support@^1.1.2: version "1.1.3" resolved "https://registry.yarnpkg.com/color-support/-/color-support-1.1.3.tgz#93834379a1cc9a0c61f82f52f0d04322251bd5a2" integrity sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg== +color@^4.2.1: + version "4.2.1" + resolved "https://registry.yarnpkg.com/color/-/color-4.2.1.tgz#498aee5fce7fc982606c8875cab080ac0547c884" + integrity sha512-MFJr0uY4RvTQUKvPq7dh9grVOTYSFeXja2mBXioCGjnjJoXrAp9jJ1NQTDR73c9nwBSAQiNKloKl5zq9WB9UPw== + dependencies: + color-convert "^2.0.1" + color-string "^1.9.0" + colord@^2.9.1: version "2.9.2" resolved "https://registry.yarnpkg.com/colord/-/colord-2.9.2.tgz#25e2bacbbaa65991422c07ea209e2089428effb1" @@ -10489,6 +10512,11 @@ is-arrayish@^0.2.1: resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d" integrity sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0= +is-arrayish@^0.3.1: + version "0.3.2" + resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.3.2.tgz#4574a2ae56f7ab206896fb431eaeed066fdf8f03" + integrity sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ== + is-bigint@^1.0.1: version "1.0.4" resolved "https://registry.yarnpkg.com/is-bigint/-/is-bigint-1.0.4.tgz#08147a1875bc2b32005d41ccd8291dffc6691df3" @@ -15262,6 +15290,13 @@ signal-exit@^3.0.0, signal-exit@^3.0.2, signal-exit@^3.0.3: resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.6.tgz#24e630c4b0f03fea446a2bd299e62b4a6ca8d0af" integrity sha512-sDl4qMFpijcGw22U5w63KmD3cZJfBuFlVNbVMKje2keoKML7X2UzWbc4XrmEbDwg0NXJc3yv4/ox7b+JWb57kQ== +simple-swizzle@^0.2.2: + version "0.2.2" + resolved "https://registry.yarnpkg.com/simple-swizzle/-/simple-swizzle-0.2.2.tgz#a4da6b635ffcccca33f70d17cb92592de95e557a" + integrity sha1-pNprY1/8zMoz9w0Xy5JZLeleVXo= + dependencies: + is-arrayish "^0.3.1" + sisteransi@^1.0.5: version "1.0.5" resolved "https://registry.yarnpkg.com/sisteransi/-/sisteransi-1.0.5.tgz#134d681297756437cc05ca01370d3a7a571075ed" -- GitLab