diff --git a/packages/react-charts/.gitignore b/packages/react-charts/.gitignore new file mode 100644 index 00000000000..a37bdb9af90 --- /dev/null +++ b/packages/react-charts/.gitignore @@ -0,0 +1,2 @@ +/next +/components diff --git a/packages/react-charts/package.json b/packages/react-charts/package.json index 1f2ec651d1a..c6383d209b9 100644 --- a/packages/react-charts/package.json +++ b/packages/react-charts/package.json @@ -5,6 +5,13 @@ "main": "dist/js/index.js", "module": "dist/esm/index.js", "types": "dist/esm/index.d.ts", + "typesVersions": { + "*": { + "next": [ + "dist/esm/next/index.d.ts" + ] + } + }, "patternfly:src": "src/", "sideEffects": [ "*.css", @@ -30,6 +37,7 @@ "dependencies": { "@patternfly/react-styles": "workspace:^", "@patternfly/react-tokens": "workspace:^", + "echarts": "^5.5.1", "hoist-non-react-statics": "^3.3.2", "lodash": "^4.17.21", "tslib": "^2.6.3", @@ -56,10 +64,12 @@ "react-dom": "^17 || ^18" }, "scripts": { - "clean": "rimraf dist", - "build:single:packages": "node ../../scripts/build-single-packages.js --config single-packages.config.json" + "build:single:packages": "node ../../scripts/build-single-packages.js --config single-packages.config.json", + "clean": "rimraf dist components next", + "subpaths": "node ../../scripts/exportSubpaths.js --config subpaths.config.json" }, "devDependencies": { + "@types/echarts": "^4.9.22", "@types/lodash": "^4.17.6", "fs-extra": "^11.2.0" } diff --git a/packages/react-charts/single-packages.config.json b/packages/react-charts/single-packages.config.json index 4a9651bb17d..8b418fd2095 100644 --- a/packages/react-charts/single-packages.config.json +++ b/packages/react-charts/single-packages.config.json @@ -1,4 +1,4 @@ { "packageName": "@patternfly/react-charts", - "exclude": ["dist/esm/deprecated/index.js", "dist/esm/next/index.js"] + "exclude": ["dist/esm/deprecated/index.js"] } diff --git a/packages/react-charts/src/next/components/Sankey/Sankey.test.tsx b/packages/react-charts/src/next/components/Sankey/Sankey.test.tsx new file mode 100644 index 00000000000..6200445d59e --- /dev/null +++ b/packages/react-charts/src/next/components/Sankey/Sankey.test.tsx @@ -0,0 +1,62 @@ +import * as React from 'react'; +import { render } from '@testing-library/react'; +import { Sankey } from './Sankey'; + +const data = [ + { + name: 'a' + }, + { + name: 'b' + }, + { + name: 'a1' + }, + { + name: 'a2' + }, + { + name: 'b1' + }, + { + name: 'c' + } +]; + +const links = [ + { + source: 'a', + target: 'a1', + value: 5 + }, + { + source: 'a', + target: 'a2', + value: 3 + }, + { + source: 'b', + target: 'b1', + value: 8 + }, + { + source: 'a', + target: 'b1', + value: 3 + }, + { + source: 'b1', + target: 'a1', + value: 1 + }, + { + source: 'b1', + target: 'c', + value: 2 + } +]; + +test('renders component data', () => { + const { asFragment } = render(); + expect(asFragment()).toMatchSnapshot(); +}); diff --git a/packages/react-charts/src/next/components/Sankey/Sankey.tsx b/packages/react-charts/src/next/components/Sankey/Sankey.tsx new file mode 100644 index 00000000000..21816d3d731 --- /dev/null +++ b/packages/react-charts/src/next/components/Sankey/Sankey.tsx @@ -0,0 +1,93 @@ +import * as React from 'react'; +import * as echarts from 'echarts'; +import { useRef } from 'react'; +// import { BarChart, SankeyChart } from 'echarts/charts'; +// import { CanvasRenderer } from 'echarts/renderers'; + +// import { +// TitleComponent, +// TooltipComponent, +// GridComponent, +// DatasetComponent, +// TransformComponent +// } from 'echarts/components'; + +// Register the required components +// echarts.use([ +// BarChart, +// SankeyChart, +// TitleComponent, +// TooltipComponent, +// GridComponent, +// DatasetComponent, +// TransformComponent, +// LabelLayout, +// UniversalTransition, +// CanvasRenderer +// ]); + +import { theme } from './theme'; + +/** + */ +export interface SankeyProps { + height?: number; + id?: string; + lineStyle?: any; + series: any[]; + title?: any; + tooltip?: any; + width?: number; +} + +export const Sankey: React.FunctionComponent = ({ + height, + id, + lineStyle = { + color: 'source', + opacity: 0.6 + }, + series, + title, + tooltip = { + trigger: 'item', + triggerOn: 'mousemove' + }, + width +}: SankeyProps) => { + const containerRef = useRef(); + const echart = useRef(); + + React.useEffect(() => { + echarts.registerTheme('pf-v5-sankey', theme); + echart.current = echarts.init(containerRef.current, 'pf-v5-sankey'); // renderer: 'svg' + + const newSeries = series.map((serie: any) => ({ + emphasis: { + focus: 'adjacency' + }, + layout: 'none', + lineStyle, + type: 'sankey', + ...serie + })); + + echart.current.setOption({ + series: newSeries, + title, + tooltip + }); + }, [containerRef, lineStyle, series, title, tooltip]); + + React.useEffect(() => { + echart?.current.resize(); + }, [height, width]); + + const getSize = () => ({ + ...(height && { height: `${height}px` }), + ...(width && { width: `${width}px` }) + }); + + return
; +}; +Sankey.displayName = 'Sankey'; diff --git a/packages/react-charts/src/next/components/Sankey/examples/Basic.tsx b/packages/react-charts/src/next/components/Sankey/examples/Basic.tsx new file mode 100644 index 00000000000..22b4d9aad5b --- /dev/null +++ b/packages/react-charts/src/next/components/Sankey/examples/Basic.tsx @@ -0,0 +1,91 @@ +import React from 'react'; +import { Sankey } from '@patternfly/react-charts/next'; +import { getResizeObserver } from '@patternfly/react-core'; + +export const FormBasic: React.FunctionComponent = () => { + const data = [ + { + name: 'a' + }, + { + name: 'b' + }, + { + name: 'a1' + }, + { + name: 'a2' + }, + { + name: 'b1' + }, + { + name: 'c' + } + ]; + + const links = [ + { + source: 'a', + target: 'a1', + value: 5 + }, + { + source: 'a', + target: 'a2', + value: 3 + }, + { + source: 'b', + target: 'b1', + value: 8 + }, + { + source: 'a', + target: 'b1', + value: 3 + }, + { + source: 'b1', + target: 'a1', + value: 1 + }, + { + source: 'b1', + target: 'c', + value: 2 + } + ]; + + // let observer = () => {}; + const containerRef = React.useRef(); + const [width, setWidth] = React.useState(0); + + React.useEffect(() => { + const handleResize = () => { + if (containerRef.current && containerRef.current.clientWidth) { + setWidth(containerRef.current.clientWidth); + } + }; + let observer = () => {}; + observer = getResizeObserver(containerRef.current, handleResize); + + return () => { + observer(); + }; + }, [containerRef, width]); + + return ( +
+ +
+ ); +}; diff --git a/packages/react-charts/src/next/components/Sankey/examples/Sankey.md b/packages/react-charts/src/next/components/Sankey/examples/Sankey.md new file mode 100644 index 00000000000..07a9a5d85cb --- /dev/null +++ b/packages/react-charts/src/next/components/Sankey/examples/Sankey.md @@ -0,0 +1,21 @@ +--- +id: Sankey +section: charts +propComponents: [ + 'Sankey', +] +hideDarkMode: true +beta: true +--- + +## Introduction +Note: PatternFly React charts live in its own package at [@patternfly/react-charts](https://www.npmjs.com/package/@patternfly/react-charts)! + +PatternFly React charts are based on the [Apache ECharts](https://echarts.apache.org/) chart library, along with additional functionality, custom components, and theming for PatternFly. This provides a collection of React based components you can use to build PatternFly patterns with consistent markup, styling, and behavior. + +## Examples +### Basic + +```ts file="./Basic.tsx" + +``` diff --git a/packages/react-charts/src/next/components/Sankey/index.ts b/packages/react-charts/src/next/components/Sankey/index.ts new file mode 100644 index 00000000000..4bb44aaee6a --- /dev/null +++ b/packages/react-charts/src/next/components/Sankey/index.ts @@ -0,0 +1 @@ +export * from './Sankey'; diff --git a/packages/react-charts/src/next/components/Sankey/theme.ts b/packages/react-charts/src/next/components/Sankey/theme.ts new file mode 100644 index 00000000000..25f60788dcc --- /dev/null +++ b/packages/react-charts/src/next/components/Sankey/theme.ts @@ -0,0 +1,365 @@ +/* eslint-disable camelcase */ +import chart_theme_blue_ColorScale_100 from '@patternfly/react-tokens/dist/esm/chart_theme_blue_ColorScale_100'; +import chart_theme_blue_ColorScale_200 from '@patternfly/react-tokens/dist/esm/chart_theme_blue_ColorScale_200'; +import chart_theme_blue_ColorScale_300 from '@patternfly/react-tokens/dist/esm/chart_theme_blue_ColorScale_300'; +import chart_theme_blue_ColorScale_400 from '@patternfly/react-tokens/dist/esm/chart_theme_blue_ColorScale_400'; +import chart_theme_blue_ColorScale_500 from '@patternfly/react-tokens/dist/esm/chart_theme_blue_ColorScale_500'; + +// Color scale +// See https://docs.google.com/document/d/1cw10pJFXWruB1SA8TQwituxn5Ss6KpxYPCOYGrH8qAY/edit +const COLOR_SCALE = [ + chart_theme_blue_ColorScale_100.value, + chart_theme_blue_ColorScale_200.value, + chart_theme_blue_ColorScale_300.value, + chart_theme_blue_ColorScale_400.value, + chart_theme_blue_ColorScale_500.value +]; + +export const theme = { + color: COLOR_SCALE, + backgroundColor: 'rgba(0,0,0,0)', + textStyle: {}, + title: { + textStyle: { + color: '#464646' + }, + subtextStyle: { + color: '#6e7079' + } + }, + line: { + itemStyle: { + borderWidth: 1 + }, + lineStyle: { + width: 2 + }, + symbolSize: 4, + symbol: 'emptyCircle', + smooth: false + }, + radar: { + itemStyle: { + borderWidth: 1 + }, + lineStyle: { + width: 2 + }, + symbolSize: 4, + symbol: 'emptyCircle', + smooth: false + }, + bar: { + itemStyle: { + barBorderWidth: 0, + barBorderColor: '#ccc' + } + }, + pie: { + itemStyle: { + borderWidth: 0, + borderColor: '#ccc' + } + }, + scatter: { + itemStyle: { + borderWidth: 0, + borderColor: '#ccc' + } + }, + boxplot: { + itemStyle: { + borderWidth: 0, + borderColor: '#ccc' + } + }, + parallel: { + itemStyle: { + borderWidth: 0, + borderColor: '#ccc' + } + }, + sankey: { + itemStyle: { + borderWidth: 0, + borderColor: '#ccc' + } + }, + funnel: { + itemStyle: { + borderWidth: 0, + borderColor: '#ccc' + } + }, + gauge: { + itemStyle: { + borderWidth: 0, + borderColor: '#ccc' + } + }, + candlestick: { + itemStyle: { + color: '#eb5454', + color0: '#47b262', + borderColor: '#eb5454', + borderColor0: '#47b262', + borderWidth: 1 + } + }, + graph: { + itemStyle: { + borderWidth: 0, + borderColor: '#ccc' + }, + lineStyle: { + width: 1, + color: '#aaaaaa' + }, + symbolSize: 4, + symbol: 'emptyCircle', + smooth: false, + color: ['#5470c6', '#91cc75', '#fac858', '#ee6666', '#73c0de', '#3ba272', '#fc8452', '#9a60b4', '#ea7ccc'], + label: { + color: '#eeeeee' + } + }, + map: { + itemStyle: { + areaColor: '#eee', + borderColor: '#444', + borderWidth: 0.5 + }, + label: { + color: '#000' + }, + emphasis: { + itemStyle: { + areaColor: 'rgba(255,215,0,0.8)', + borderColor: '#444', + borderWidth: 1 + }, + label: { + color: 'rgb(100,0,0)' + } + } + }, + geo: { + itemStyle: { + areaColor: '#eee', + borderColor: '#444', + borderWidth: 0.5 + }, + label: { + color: '#000' + }, + emphasis: { + itemStyle: { + areaColor: 'rgba(255,215,0,0.8)', + borderColor: '#444', + borderWidth: 1 + }, + label: { + color: 'rgb(100,0,0)' + } + } + }, + categoryAxis: { + axisLine: { + show: true, + lineStyle: { + color: '#6E7079' + } + }, + axisTick: { + show: true, + lineStyle: { + color: '#6E7079' + } + }, + axisLabel: { + show: true, + color: '#6E7079' + }, + splitLine: { + show: false, + lineStyle: { + color: ['#E0E6F1'] + } + }, + splitArea: { + show: false, + areaStyle: { + color: ['rgba(250,250,250,0.2)', 'rgba(210,219,238,0.2)'] + } + } + }, + valueAxis: { + axisLine: { + show: false, + lineStyle: { + color: '#6E7079' + } + }, + axisTick: { + show: false, + lineStyle: { + color: '#6E7079' + } + }, + axisLabel: { + show: true, + color: '#6E7079' + }, + splitLine: { + show: true, + lineStyle: { + color: ['#E0E6F1'] + } + }, + splitArea: { + show: false, + areaStyle: { + color: ['rgba(250,250,250,0.2)', 'rgba(210,219,238,0.2)'] + } + } + }, + logAxis: { + axisLine: { + show: false, + lineStyle: { + color: '#6E7079' + } + }, + axisTick: { + show: false, + lineStyle: { + color: '#6E7079' + } + }, + axisLabel: { + show: true, + color: '#6E7079' + }, + splitLine: { + show: true, + lineStyle: { + color: ['#E0E6F1'] + } + }, + splitArea: { + show: false, + areaStyle: { + color: ['rgba(250,250,250,0.2)', 'rgba(210,219,238,0.2)'] + } + } + }, + timeAxis: { + axisLine: { + show: true, + lineStyle: { + color: '#6E7079' + } + }, + axisTick: { + show: true, + lineStyle: { + color: '#6E7079' + } + }, + axisLabel: { + show: true, + color: '#6E7079' + }, + splitLine: { + show: false, + lineStyle: { + color: ['#E0E6F1'] + } + }, + splitArea: { + show: false, + areaStyle: { + color: ['rgba(250,250,250,0.2)', 'rgba(210,219,238,0.2)'] + } + } + }, + toolbox: { + iconStyle: { + borderColor: '#999999' + }, + emphasis: { + iconStyle: { + borderColor: '#666666' + } + } + }, + legend: { + textStyle: { + color: '#333333' + } + }, + tooltip: { + axisPointer: { + lineStyle: { + color: '#cccccc', + width: 1 + }, + crossStyle: { + color: '#cccccc', + width: 1 + } + } + }, + timeline: { + lineStyle: { + color: '#dae1f5', + width: 2 + }, + itemStyle: { + color: '#a4b1d7', + borderWidth: 1 + }, + controlStyle: { + color: '#a4b1d7', + borderColor: '#a4b1d7', + borderWidth: 1 + }, + checkpointStyle: { + color: '#316bf3', + borderColor: '#ffffff' + }, + label: { + color: '#a4b1d7' + }, + emphasis: { + itemStyle: { + color: '#ffffff' + }, + controlStyle: { + color: '#a4b1d7', + borderColor: '#a4b1d7', + borderWidth: 1 + }, + label: { + color: '#a4b1d7' + } + } + }, + visualMap: { + color: ['#bf444c', '#d88273', '#f6efa6'] + }, + dataZoom: { + handleSize: 'undefined%', + textStyle: {} + }, + markPoint: { + label: { + color: '#eeeeee' + }, + emphasis: { + label: { + color: '#eeeeee' + } + } + } +}; diff --git a/packages/react-charts/src/next/components/index.ts b/packages/react-charts/src/next/components/index.ts new file mode 100644 index 00000000000..4bb44aaee6a --- /dev/null +++ b/packages/react-charts/src/next/components/index.ts @@ -0,0 +1 @@ +export * from './Sankey'; diff --git a/packages/react-charts/src/next/index.ts b/packages/react-charts/src/next/index.ts new file mode 100644 index 00000000000..07635cbbc8e --- /dev/null +++ b/packages/react-charts/src/next/index.ts @@ -0,0 +1 @@ +export * from './components'; diff --git a/packages/react-charts/subpaths.config.json b/packages/react-charts/subpaths.config.json new file mode 100644 index 00000000000..0e15baf4e1f --- /dev/null +++ b/packages/react-charts/subpaths.config.json @@ -0,0 +1,4 @@ +{ + "packageName": "@patternfly/react-charts", + "paths": ["next", "components"] +} diff --git a/packages/react-charts/tsconfig.json b/packages/react-charts/tsconfig.json index 30bec2faa4a..cfd3101ef1b 100644 --- a/packages/react-charts/tsconfig.json +++ b/packages/react-charts/tsconfig.json @@ -1,9 +1,14 @@ { "extends": "../tsconfig.base.json", "compilerOptions": { + "jsx": "react", "rootDir": "./src", "outDir": "./dist/esm", - "tsBuildInfoFile": "dist/esm.tsbuildinfo" + "tsBuildInfoFile": "dist/esm.tsbuildinfo", + "baseUrl": ".", + "paths": { + "./next": ["./src/next"] + } }, "include": [ "./src/*", diff --git a/packages/react-core/package.json b/packages/react-core/package.json index d10cadf9c7c..6e9ca2d7344 100644 --- a/packages/react-core/package.json +++ b/packages/react-core/package.json @@ -38,7 +38,6 @@ }, "homepage": "https://github.com/patternfly/patternfly-react#readme", "scripts": { - "build:umd": "rollup -c --environment IS_PRODUCTION", "build:single:packages": "node ../../scripts/build-single-packages.js --config single-packages.config.json", "clean": "rimraf dist components layouts helpers next deprecated", "generate": "node scripts/copyStyles.js", diff --git a/packages/react-docs/patternfly-docs/patternfly-docs.source.js b/packages/react-docs/patternfly-docs/patternfly-docs.source.js index 4abe46ebab2..0a70ad824f4 100644 --- a/packages/react-docs/patternfly-docs/patternfly-docs.source.js +++ b/packages/react-docs/patternfly-docs/patternfly-docs.source.js @@ -39,8 +39,9 @@ module.exports = (baseSourceMD, sourceProps) => { sourceMD(path.join(reactTablePath, '/deprecated/components/**/examples/*.md'), 'react-deprecated'); sourceMD(path.join(reactTablePath, '/**/demos/*.md'), 'react-demos'); - // Charts MD (no demos yet) - sourceMD(path.join(reactChartsPath, '/**/examples/*.md'), 'react'); + // Charts MD + sourceMD(path.join(reactChartsPath, '/components/**/examples/*.md'), 'react'); + sourceMD(path.join(reactChartsPath, '/next/components/**/examples/*.md'), 'react-next'); // Code Editor MD sourceMD(path.join(reactCodeEditorPath, '/**/examples/*.md'), 'react'); diff --git a/yarn.lock b/yarn.lock index 358ebc96886..c71bf9685ce 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3167,7 +3167,9 @@ __metadata: dependencies: "@patternfly/react-styles": "workspace:^" "@patternfly/react-tokens": "workspace:^" + "@types/echarts": "npm:^4.9.22" "@types/lodash": "npm:^4.17.6" + echarts: "npm:^5.5.1" fs-extra: "npm:^11.2.0" hoist-non-react-statics: "npm:^3.3.2" lodash: "npm:^4.17.21" @@ -4275,6 +4277,15 @@ __metadata: languageName: node linkType: hard +"@types/echarts@npm:^4.9.22": + version: 4.9.22 + resolution: "@types/echarts@npm:4.9.22" + dependencies: + "@types/zrender": "npm:*" + checksum: 10c0/00e5e6f75b4a1ee46df0286fc1fe5b42773970280576317723d7174678598d0aeb2bac36870276ac1e65bf053241443334ef37ae97a84c1b782abdb980991f39 + languageName: node + linkType: hard + "@types/eslint-scope@npm:^3.7.3": version: 3.7.7 resolution: "@types/eslint-scope@npm:3.7.7" @@ -4780,6 +4791,13 @@ __metadata: languageName: node linkType: hard +"@types/zrender@npm:*": + version: 4.0.6 + resolution: "@types/zrender@npm:4.0.6" + checksum: 10c0/baaf25731115fe18cb281bf38e6d414964307532381d8479edf7a4b25baecec737fed620802380fa126139e506d56d62d70fe8142c5c386e340fa91aa988dddd + languageName: node + linkType: hard + "@typescript-eslint/eslint-plugin@npm:7.16.1": version: 7.16.1 resolution: "@typescript-eslint/eslint-plugin@npm:7.16.1" @@ -8728,6 +8746,16 @@ __metadata: languageName: node linkType: hard +"echarts@npm:^5.5.1": + version: 5.5.1 + resolution: "echarts@npm:5.5.1" + dependencies: + tslib: "npm:2.3.0" + zrender: "npm:5.6.0" + checksum: 10c0/2f7e3037f17fda99d977092767943f4d9b0c8f886f86701ec88591707713b5e5fd683e56086b6ba5245b322f088184bdb06eac488234c20a1869b08cb6b4e523 + languageName: node + linkType: hard + "editions@npm:^2.2.0": version: 2.3.1 resolution: "editions@npm:2.3.1" @@ -20065,6 +20093,13 @@ __metadata: languageName: node linkType: hard +"tslib@npm:2.3.0": + version: 2.3.0 + resolution: "tslib@npm:2.3.0" + checksum: 10c0/a845aed84e7e7dbb4c774582da60d7030ea39d67307250442d35c4c5dd77e4b44007098c37dd079e100029c76055f2a362734b8442ba828f8cc934f15ed9be61 + languageName: node + linkType: hard + "tslib@npm:^1.8.1, tslib@npm:^1.9.0": version: 1.14.1 resolution: "tslib@npm:1.14.1" @@ -22045,3 +22080,12 @@ __metadata: checksum: 10c0/856117aa15cf5103d2a2fb173f0ab4acb12b4b4d0ed3ab249fdbbf612e55d1cadfd27a6110940e24746fb0a78cf640b522cc8bca76f30a3b00b66e90cf82abe0 languageName: node linkType: hard + +"zrender@npm:5.6.0": + version: 5.6.0 + resolution: "zrender@npm:5.6.0" + dependencies: + tslib: "npm:2.3.0" + checksum: 10c0/f7c5a1739dfec60b9bead0d0657c47868391b1009cc82a603f9dbf247fa625df28dcdb3e7b2e18404657e2c987f95e0e1bb5613519c2d823854f3dda44e2ee96 + languageName: node + linkType: hard