Merged PR 18: Add support for custom SVG
Some checks failed
continuous-integration/drone/push Build is failing
Some checks failed
continuous-integration/drone/push Build is failing
Add support for custom SVG Add userData back into IProperties Added library interweave Update example
This commit is contained in:
parent
82eae4971e
commit
e96e4f123b
8 changed files with 109 additions and 9 deletions
|
@ -31,6 +31,7 @@ module.exports = {
|
|||
'@typescript-eslint/semi': ['warn', 'always'],
|
||||
'no-unused-vars': 'off',
|
||||
'@typescript-eslint/no-unused-vars': 'error',
|
||||
'@typescript-eslint/ban-types': ['error'],
|
||||
'react-hooks/rules-of-hooks': 'error', // Checks rules of Hooks
|
||||
'react-hooks/exhaustive-deps': 'warn' // Checks effect dependencies
|
||||
}
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
},
|
||||
"dependencies": {
|
||||
"@heroicons/react": "^1.0.6",
|
||||
"interweave": "^13.0.0",
|
||||
"react": "^18.2.0",
|
||||
"react-dom": "^18.2.0",
|
||||
"react-svg-pan-zoom": "^3.11.0",
|
||||
|
|
15
pnpm-lock.yaml
generated
15
pnpm-lock.yaml
generated
|
@ -24,6 +24,7 @@ specifiers:
|
|||
eslint-plugin-promise: ^6.0.0
|
||||
eslint-plugin-react: ^7.30.1
|
||||
eslint-plugin-react-hooks: ^4.6.0
|
||||
interweave: ^13.0.0
|
||||
jsdom: ^20.0.0
|
||||
postcss: ^8.4.14
|
||||
react: ^18.2.0
|
||||
|
@ -38,6 +39,7 @@ specifiers:
|
|||
|
||||
dependencies:
|
||||
'@heroicons/react': 1.0.6_react@18.2.0
|
||||
interweave: 13.0.0_react@18.2.0
|
||||
react: 18.2.0
|
||||
react-dom: 18.2.0_react@18.2.0
|
||||
react-svg-pan-zoom: 3.11.0_react@18.2.0
|
||||
|
@ -1522,6 +1524,10 @@ packages:
|
|||
engines: {node: '>=6'}
|
||||
dev: true
|
||||
|
||||
/escape-html/1.0.3:
|
||||
resolution: {integrity: sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==}
|
||||
dev: false
|
||||
|
||||
/escape-string-regexp/1.0.5:
|
||||
resolution: {integrity: sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==}
|
||||
engines: {node: '>=0.8.0'}
|
||||
|
@ -2177,6 +2183,15 @@ packages:
|
|||
side-channel: 1.0.4
|
||||
dev: true
|
||||
|
||||
/interweave/13.0.0_react@18.2.0:
|
||||
resolution: {integrity: sha512-Mckwj+ix/VtrZu1bRBIIohwrsXj12ZTvJCoYUMZlJmgtvIaQCj0i77eSZ63ckbA1TsPrz2VOvLW9/kTgm5d+mw==}
|
||||
peerDependencies:
|
||||
react: ^16.8.0 || ^17.0.0 || ^18.0.0
|
||||
dependencies:
|
||||
escape-html: 1.0.3
|
||||
react: 18.2.0
|
||||
dev: false
|
||||
|
||||
/is-bigint/1.0.4:
|
||||
resolution: {integrity: sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==}
|
||||
dependencies:
|
||||
|
|
|
@ -218,7 +218,9 @@ export function AddContainer(
|
|||
isRigidBody: false,
|
||||
isAnchor: false,
|
||||
XPositionReference: containerConfig.XPositionReference ?? XPositionReference.Left,
|
||||
style: containerConfig.Style
|
||||
customSVG: containerConfig.CustomSVG,
|
||||
style: containerConfig.Style,
|
||||
userData: containerConfig.UserData
|
||||
};
|
||||
|
||||
// Create the container
|
||||
|
|
|
@ -1,9 +1,11 @@
|
|||
import * as React from 'react';
|
||||
import { Interweave, Node } from 'interweave';
|
||||
import { XPositionReference } from '../../../Enums/XPositionReference';
|
||||
import { IContainerModel } from '../../../Interfaces/IContainerModel';
|
||||
import { DIMENSION_MARGIN } from '../../../utils/default';
|
||||
import { getDepth } from '../../../utils/itertools';
|
||||
import { Dimension } from './Dimension';
|
||||
import IProperties from '../../../Interfaces/IProperties';
|
||||
|
||||
interface IContainerProps {
|
||||
model: IContainerModel
|
||||
|
@ -33,6 +35,14 @@ export const Container: React.FC<IContainerProps> = (props: IContainerProps) =>
|
|||
props.model.properties.style
|
||||
);
|
||||
|
||||
const svg = (props.model.properties.customSVG != null)
|
||||
? CreateReactCustomSVG(props.model.properties.customSVG, props.model.properties)
|
||||
: (<rect
|
||||
width={props.model.properties.width}
|
||||
height={props.model.properties.height}
|
||||
style={style}
|
||||
>
|
||||
</rect>);
|
||||
// Dimension props
|
||||
const depth = getDepth(props.model);
|
||||
const dimensionMargin = DIMENSION_MARGIN * (depth + 1);
|
||||
|
@ -79,12 +89,7 @@ export const Container: React.FC<IContainerProps> = (props: IContainerProps) =>
|
|||
text={text}
|
||||
/>
|
||||
{ dimensionChildren }
|
||||
<rect
|
||||
width={props.model.properties.width}
|
||||
height={props.model.properties.height}
|
||||
style={style}
|
||||
>
|
||||
</rect>
|
||||
{ svg }
|
||||
<text
|
||||
x={xText}
|
||||
y={yText}
|
||||
|
@ -141,3 +146,63 @@ export function restoreX(x: number, width: number, xPositionReference = XPositio
|
|||
}
|
||||
return transformedX;
|
||||
}
|
||||
|
||||
function CreateReactCustomSVG(customSVG: string, props: IProperties): React.ReactNode {
|
||||
return <Interweave
|
||||
tagName='g'
|
||||
disableLineBreaks={true}
|
||||
content={customSVG}
|
||||
allowElements={true}
|
||||
transform={(node, children) => transform(node, children, props)}
|
||||
/>;
|
||||
}
|
||||
|
||||
function transform(node: HTMLElement, children: Node[], props: IProperties): React.ReactNode {
|
||||
const supportedTags = ['line', 'path', 'rect'];
|
||||
if (supportedTags.includes(node.tagName.toLowerCase())) {
|
||||
const attributes: {[att: string]: string | object | null} = {};
|
||||
node.getAttributeNames().forEach(attName => {
|
||||
const attributeValue = node.getAttribute(attName);
|
||||
if (attributeValue === null) {
|
||||
attributes[attName] = attributeValue;
|
||||
return;
|
||||
}
|
||||
|
||||
if (attributeValue.startsWith('{userData.') && attributeValue.endsWith('}')) {
|
||||
// support for userData
|
||||
if (props.userData === undefined) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const userDataKey = attributeValue.replace(/userData\./, '');
|
||||
|
||||
const prop = Object.entries(props.userData).find(([key]) => `{${key}}` === userDataKey);
|
||||
if (prop !== undefined) {
|
||||
attributes[camelize(attName)] = prop[1];
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (attributeValue.startsWith('{{') && attributeValue.endsWith('}}')) {
|
||||
// support for object
|
||||
const stringObject = attributeValue.slice(1, -1);
|
||||
const object: JSON = JSON.parse(stringObject);
|
||||
attributes[camelize(attName)] = object;
|
||||
return;
|
||||
}
|
||||
|
||||
const prop = Object.entries(props).find(([key]) => `{${key}}` === attributeValue);
|
||||
if (prop !== undefined) {
|
||||
attributes[camelize(attName)] = prop[1];
|
||||
return;
|
||||
}
|
||||
attributes[camelize(attName)] = attributeValue;
|
||||
});
|
||||
return React.createElement(node.tagName.toLowerCase(), attributes, children);
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
function camelize(str: string): any {
|
||||
return str.split('-').map((word, index) => index > 0 ? word.charAt(0).toUpperCase() + word.slice(1) : word).join('');
|
||||
}
|
||||
|
|
|
@ -11,5 +11,7 @@ export interface IAvailableContainer {
|
|||
DefaultY?: number
|
||||
AddMethod?: AddMethod
|
||||
XPositionReference?: XPositionReference
|
||||
CustomSVG?: string
|
||||
Style: React.CSSProperties
|
||||
UserData?: object
|
||||
}
|
||||
|
|
|
@ -20,5 +20,7 @@ export default interface IProperties {
|
|||
isRigidBody: boolean
|
||||
isAnchor: boolean
|
||||
XPositionReference: XPositionReference
|
||||
customSVG?: string
|
||||
style?: React.CSSProperties
|
||||
userData?: object
|
||||
}
|
||||
|
|
|
@ -76,11 +76,23 @@ const GetSVGLayoutConfiguration = () => {
|
|||
},
|
||||
{
|
||||
Type: 'Remplissage',
|
||||
CustomSVG: `
|
||||
<rect width="{width}" height="{height}" style="{style}"></rect>
|
||||
<rect width="{width}" height="{height}" stroke="black" fill-opacity="0"></rect>
|
||||
<line x1="0" y1="0" x2="{width}" y2="{height}" stroke="black" style='{{ "transform":"scaleY(0.5)"}}'></line>
|
||||
<line x1="{width}" y1="0" x2="0" y2="{height}" stroke="black" style='{userData.styleLine}'></line>
|
||||
`
|
||||
,
|
||||
Style: {
|
||||
fillOpacity: 1,
|
||||
strokeWidth: 2,
|
||||
stroke: '#bfdbfe',
|
||||
strokeWidth: 1,
|
||||
fill: '#bfdbfe'
|
||||
},
|
||||
UserData: {
|
||||
styleLine: {
|
||||
transform: "scaleY(0.5) translateY(100%)",
|
||||
transformBox: "fill-box"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue