diff --git a/.github/upload-preview.mjs b/.github/upload-preview.mjs index 056f705cf1c..704f2347538 100644 --- a/.github/upload-preview.mjs +++ b/.github/upload-preview.mjs @@ -18,7 +18,7 @@ if (!uploadFolder) { } const uploadFolderName = path.basename(uploadFolder); -let uploadURL = `${repo}-${prnum ? `pr-${prnum}` : prbranch}`.replace(/[/|.]/g, '-'); +let uploadURL = `pf-react-${prnum ? `pr-${prnum}` : prbranch}`.replace(/[/|.]/g, '-'); switch (uploadFolderName) { case 'coverage': @@ -26,7 +26,7 @@ switch (uploadFolderName) { break; case 'public': if (!prnum && prbranch === 'main') { - uploadURL = 'react-staging.patternfly.org'; + uploadURL = 'pf-react-staging.patternfly.org'; } else { uploadURL += '.surge.sh'; } diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 7e72c39fbbb..48d843a595e 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,9 +1,11 @@ # Contributing to PatternFly React -> ### Looking for a quick guide to PatternFly React Contribution? [Go Here](./packages/react-core/CONTRIBUTING.md) +> **Looking for a quick guide to PatternFly React Contribution?** [Go Here](./packages/react-core/CONTRIBUTING.md) ## Outline +- [Quick Start for New Contributors](#quick-start-for-new-contributors) +- [Community Contributors Hall of Fame](#community-contributors-hall-of-fame) - [Code of Conduct](#code-of-conduct) - [Issues and Project Board](#issues-and-project-board) - [Issue Labels](#issue-labels) @@ -14,21 +16,58 @@ - [Creating Issues for New Components](#creating-issues-for-new-components) - [Contributing Components](#contributing-components) - [Adding Styling for your Components](#adding-styling-for-your-components) - - [Using Generators](#using-generators) + - [Guidelines and Requirements](#guidelines-and-requirements) - [React Component Requirements](#react-component-requirements) - [Code Consistency](#code-consistency) - [Code Contribution Guidelines](#code-contribution-guidelines) +- [Troubleshooting](#troubleshooting) - [Becoming a Maintainer](#becoming-a-maintainer) - [How do I become a maintainer?](#how-do-i-become-a-maintainer) - [How do I lose maintainers status?](#how-do-i-lose-maintainers-status) - [Quick Tips for New Maintainers](#quick-tips-for-new-maintainers) +## Quick Start for New Contributors + +New to contributing to PatternFly React? Here's how to get started quickly: + +1. **🍴 Fork and Clone**: Fork the repository and clone it locally +2. **📦 Install Dependencies**: Run `yarn install` to install dependencies +3. **🏗️ Build**: Run `yarn build` to build the project +4. **🔍 Find an Issue**: Look for issues labeled [`good first issue`](https://github.com/patternfly/patternfly-react/labels/good%20first%20issue) +5. **🌿 Create a Branch**: Create a new branch for your changes +6. **✅ Test**: Run `yarn test` to ensure tests pass +7. **📝 Submit PR**: Create a pull request with a clear description + +**Need help?** Join us on [PatternFly Slack](https://patternfly.slack.com/) in the `#patternfly-react` channel! + +## Community Contributors Hall of Fame + +We want to recognize and celebrate our amazing community contributors who have made significant contributions to PatternFly React in the past year! 🎉 + +### Top Community Contributors (Last 12 Months as on July 1, 2025) + +The following contributors (excluding PatternFly team members and bots) have made outstanding contributions to the project: + +1. **@Mash707** - 49 contributions +2. **@adamviktora** - 10 contributions +3. **@logonoff** - 5 contributions + +### Notable Contributors + +Thank you to all our community contributors for helping make PatternFly React better! Every contribution, whether it's code, documentation, bug reports, or feature requests, helps improve the library for everyone. + +*This list is updated periodically and reflects contributions over the past 12 months. If you'd like to join this list, check out our [contribution guidelines](#contribution-process) below!* + ## Code of conduct This project is governed by the [Contributor Covenant version 2.1][1]. All contributors and participants agree to abide by its terms. To report violations, send an email to [patternfly@redhat.com][2]. +## AI-assisted development guidelines + +Please reference [PatternFly's AI-assisted development guidelines](https://github.com/patternfly/.github/blob/main/CONTRIBUTING.md) if you'd like to contribute code generated using AI. + ## Issues and project board We use issues to track work items, such as bug reports and feature requests. Issues can be found in the [issue tracker](https://github.com/patternfly/patternfly-react/issues) or [project board](https://github.com/orgs/patternfly/projects/7). We use the project board to help visualize and manage status of an issue, and we use labels to help prioritize and identify issues. @@ -124,22 +163,7 @@ Inside the package directory: - Add a Sass file to the `sass/patternfly-react/` directory and use the file name `_.scss` - Import the Sass file into `sass/patternfly-react/_patternfly-react.scss` using `@import "";` -### Using generators - -To make contributing components and packages easier a generator utility has been provided. - -To start the generator run: - -```sh -yarn generate -``` -Follow the prompts to generate the desired component or package. - -Currently the following generators are provided - -- PatternFly component -- Package ## Guidelines and requirements @@ -179,51 +203,36 @@ Please ensure that all React UI components contributed meet the following guidel Adhering to the following process is the best way to get your work included in the project: -1. [Fork](https://help.github.com/fork-a-repo/) the project, clone your fork, and configure the remotes: - -```sh -# Clone your fork of the repo into the current directory -git clone https://github.com//patternfly-react.git -# Navigate to the newly cloned directory -cd patternfly-react -# Assign the original repo to a remote called "upstream" -git remote add upstream https://github.com/patternfly/patternfly-react.git -# Fetch the code and branches from remote repo "upstream" -git fetch upstream -``` +1. **Fork and set up the repository** ([More information about forks from GitHub](https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/working-with-forks/fork-a-repo)) -2. Set up tooling +2. **Set up your development environment** -[Install Node.js](https://nodejs.org/en/download/package-manager) version 22 (or higher), and make sure to [enable Corepack](https://nodejs.org/api/corepack.html). Then install the project dependencies and build it by running: +**Prerequisites:** +- [Node.js](https://nodejs.org/en/download/package-manager) version 22 or higher +- [Enable Corepack](https://nodejs.org/api/corepack.html) for package manager management +- Git configured with your GitHub account +**Setup commands:** ```sh +# Install dependencies yarn install -yarn build -``` - -3. Create a branch: -```sh -git checkout -b my-branch upstream/main -``` +# Build the project +yarn build -4. Generate your component +# Run tests to verify setup +yarn test -```sh -# Run the tool to Generate the component scaffolding - yarn generate +# Start development server (optional) +yarn start ``` -- When you select the option to generate a PatternFly component, a structure resembling the following is generated - ```text - packages/react-core/src/[type]/[ComponentName]/ - index.js - Barrel File exporting public exports - ComponentName.js - Component Implementation - ComponentName.test.js - Component Tests - ComponentName.md - Component Docs - ``` +**Verify your setup:** +- All tests should pass +- Build should complete without errors +- Development server should start (if running yarn start) -5. Develop your component. After development is complete, run build and ensure tests and lint standards pass. +3. **Develop your component** - After development is complete, run build and ensure tests and lint standards pass. ```sh yarn build @@ -234,26 +243,9 @@ Ensure no lint errors are introduced in `yarn-error.log` after running this comm ***Note to Windows users:*** you may need to change the path for the lint script in package.json to be `node_modules/eslint/bin/eslint` -6. Add a commit using `git commit`: - -This project uses [`lerna`](https://lernajs.io/) to do automatic releases and generate a changelog based on the commit history. So we follow [a convention][3] for commit messages. Please follow this convention for your commit messages. - -7. Rebase - -Use `git rebase` (not `git merge`) to sync your work from time to time. Ensure all commits related to a single issue have been [squashed](https://github.com/ginatrapani/todo.txt-android/wiki/Squash-All-Commits-Related-to-a-Single-Issue-into-a-Single-Commit). - -```sh -git fetch upstream -git rebase upstream/main -``` +4. **Follow commit conventions** - This project uses [`lerna`](https://lernajs.io/) to do automatic releases and generate a changelog based on the commit history. So we follow [conventional commit formatting](https://www.conventionalcommits.org/en/v1.0.0/) for all commit messages. Please follow this convention for your commit messages. -8. Push - -```sh -git push origin my-branch -``` - -9. Create a pull request +5. **Create a pull request** [Open a pull request](https://help.github.com/articles/using-pull-requests/) with a clear title and description against the `main` branch. Please be sure to include all of the following in your PR: @@ -276,6 +268,35 @@ Please help in ensuring all relevant issues are closed and that any subsequent i - If an issue in Core will affect a component in PF-React, this issue should link to the main PF-React issue. - The CSS Developers and UX Designers should be tagged to review their respective PF-React issue. +## Troubleshooting + +### Common Issues and Solutions + +**Build Failures:** +- Ensure you're using Node.js version 22 or higher: `node --version` +- Clear node_modules and reinstall: `rm -rf node_modules && yarn install` +- Clear yarn cache: `yarn cache clean` + +**Test Failures:** +- Run tests in watch mode for debugging: `yarn test --watch` +- Update snapshots if components have intentionally changed: `yarn test -u` + +**Linting Errors:** +- Auto-fix linting issues: `yarn lint --fix` +- Format code with Prettier: `yarn prettier` + +**Development Server Issues:** +- Clear cache and restart: `rm -rf node_modules/.cache && rm -rf packages/react-docs/.cache && yarn start` + +**Integration Issues:** +- Ensure your branch is up to date with the latest changes before submitting PR +- Squash commits related to a single issue before submitting + +**Still having issues?** +- Check existing [GitHub issues](https://github.com/patternfly/patternfly-react/issues) +- Ask for help in [PatternFly Slack](https://patternfly.slack.com/) `#patternfly-react` channel +- Create a new issue with detailed error information + ## Becoming a maintainer The documentation for becoming a maintainer has been taken from [Foreman](https://theforeman.org/handbook.html#Becomingamaintainer) and adapted for the PatternFly project. diff --git a/lerna.json b/lerna.json index 69ac0a90549..c0c2c7cbe39 100644 --- a/lerna.json +++ b/lerna.json @@ -24,7 +24,7 @@ } }, "version": "independent", - "allowBranch": ["main", "v4", "5.0.x", "v5"], + "allowBranch": ["main", "v4", "5.0.x", "6.3.x", "v5"], "packages": ["packages/*", "packages/react-integration/demo-app-ts"], "$schema": "node_modules/lerna/schemas/lerna-schema.json" } diff --git a/package.json b/package.json index 8a00c85d12b..31df586552d 100644 --- a/package.json +++ b/package.json @@ -8,7 +8,7 @@ "url": "https://github.com/patternfly/patternfly-react.git" }, "engines": { - "node": ">=22.14.0" + "node": ">=22.17.1" }, "packageManager": "yarn@4.7.0", "keywords": [ @@ -26,10 +26,11 @@ "devDependencies": { "@babel/core": "^7.24.7", "@babel/plugin-transform-modules-commonjs": "^7.24.7", + "@babel/preset-env": "^7.28.3", "@babel/preset-react": "^7.24.7", "@babel/preset-typescript": "^7.24.7", - "@eslint/compat": "^1.2.8", - "@eslint/js": "^9.22.0", + "@eslint/compat": "^1.3.1", + "@eslint/js": "^9.32.0", "@octokit/rest": "^21.1.1", "@rollup/plugin-commonjs": "^26.0.3", "@rollup/plugin-node-resolve": "^15.3.1", @@ -40,17 +41,17 @@ "@testing-library/react": "^16.2.0", "@testing-library/user-event": "^14.6.1", "@types/jest": "29.5.14", - "@types/node": "^22.13.10", - "@types/react": "^18.3.18", - "@types/react-dom": "^18.3.5", + "@types/node": "^22.16.5", + "@types/react": "^18.3.23", + "@types/react-dom": "^18.3.7", "babel-jest": "^29.7.0", "concurrently": "^9.1.2", - "eslint": "^9.22.0", + "eslint": "^9.32.0", "eslint-config-prettier": "^10.1.5", "eslint-plugin-markdown": "^5.1.0", "eslint-plugin-prettier": "^5.2.6", "eslint-plugin-react": "^7.37.4", - "eslint-plugin-react-compiler": "19.0.0-beta-e552027-20250112", + "eslint-plugin-react-compiler": "19.0.0-beta-ebf51a3-20250411", "eslint-plugin-react-hooks": "^5.2.0", "eslint-plugin-testing-library": "^7.1.1", "fs-extra": "^11.3.0", diff --git a/packages/code-connect/components/AboutModal/AboutModal.figma.tsx b/packages/code-connect/components/AboutModal/AboutModal.figma.tsx new file mode 100644 index 00000000000..fb15f4065b1 --- /dev/null +++ b/packages/code-connect/components/AboutModal/AboutModal.figma.tsx @@ -0,0 +1,63 @@ +import figma from '@figma/code-connect'; +import { AboutModal, Button, Content } from '@patternfly/react-core'; + +/** + * PatternFly AboutModal integration for Figma Code Connect + * @see https://www.patternfly.org/components/about-modal + */ + +figma.connect( + AboutModal, + 'https://www.figma.com/design/aEBBvq0J3EPXxHvv6WgDx9/PatternFly-6--Components-Test?node-id=2879-13973&t=15CEJpGgVui7qP5Q-11', + { + props: { + productName: figma.string('Product name') + }, + example: ({ productName }) => { + /* eslint-disable */ + const [isOpen, setIsOpen] = React.useState(false); + /* eslint-enable */ + + return ( + <> + + setIsOpen(false)} + productName={productName} + trademark="Copyright © 2024" + brandImageSrc="/assets/images/brand.svg" + brandImageAlt="Brand Image Alt Text" + backgroundImageSrc="/assets/images/background.png" + > + +
+
CFME version
+
5.5.3.4.20102789036450
+
Cloudforms Version
+
4.1
+
Server name
+
40DemoMaster
+
User name
+
Administrator
+
User role
+
EvmRole-super_administrator
+
Browser version
+
601.2
+
Browser OS
+
Mac
+
+
+
+ + ); + } + } +); diff --git a/packages/code-connect/components/Accordion/Accordion.figma.tsx b/packages/code-connect/components/Accordion/Accordion.figma.tsx new file mode 100644 index 00000000000..9ef35289b62 --- /dev/null +++ b/packages/code-connect/components/Accordion/Accordion.figma.tsx @@ -0,0 +1,27 @@ +import figma from '@figma/code-connect'; +import { Accordion } from '@patternfly/react-core'; + +// Documentation for Accordion can be found at https://www.patternfly.org/components/accordion + +figma.connect( + Accordion, + 'https://www.figma.com/file/aEBBvq0J3EPXxHvv6WgDx9/PatternFly-6%3A-Components-Test?node-id=2621-623', + { + props: { + // enum + displaySize: figma.enum('Type', { 'Large Bordered': 'lg' }), + isBordered: figma.enum('Type', { + Bordered: true, + 'Large Bordered': true + }), + togglePosition: figma.enum('Caret position', { Left: 'start' }), + + children: figma.children('Accordion toggle') + }, + example: (props) => ( + + {props.children} + + ) + } +); diff --git a/packages/code-connect/components/Accordion/AccordionToggle.figma.tsx b/packages/code-connect/components/Accordion/AccordionToggle.figma.tsx new file mode 100644 index 00000000000..4f5708cdb6a --- /dev/null +++ b/packages/code-connect/components/Accordion/AccordionToggle.figma.tsx @@ -0,0 +1,34 @@ +import figma from '@figma/code-connect'; +import { AccordionItem, AccordionToggle, AccordionContent } from '@patternfly/react-core'; + +// Documentation for AccordionToggle can be found at https://www.patternfly.org/components/accordion +// Note: Adding on onClick event is recommended to initialize AccordionToggle + +figma.connect( + AccordionToggle, + 'https://www.figma.com/design/aEBBvq0J3EPXxHvv6WgDx9/PatternFly-6--Components-Test?node-id=1423-687', + { + props: { + // string + expandText: figma.string('Expand Text'), + + // enum + open: figma.enum('State', { Expanded: true }), + toggleTextExpanded: figma.enum('State', { + Default: figma.string('Toggle Text'), + Hover: figma.string('Toggle Text'), + Expanded: figma.string('Toggle Text Expanded') + }) + }, + example: (props) => ( + + {}} id=""> + {props.toggleTextExpanded} + + +

{props.expandText}

+
+
+ ) + } +); diff --git a/packages/code-connect/components/ActionList/ActionList.figma.tsx b/packages/code-connect/components/ActionList/ActionList.figma.tsx new file mode 100644 index 00000000000..e92199479ab --- /dev/null +++ b/packages/code-connect/components/ActionList/ActionList.figma.tsx @@ -0,0 +1,20 @@ +import figma from '@figma/code-connect'; +import { ActionList } from '@patternfly/react-core'; + +// TODO: DESIGN: Add ActionListGroup component +// TODO: DESIGN: Add ActionListItem component +// Documentation for ActionList can be found at https://www.patternfly.org/components/action-list + +figma.connect( + ActionList, + 'https://www.figma.com/design/aEBBvq0J3EPXxHvv6WgDx9/PatternFly-6--Components-Test?node-id=6780-15839', + { + props: { + // enum + isIconList: figma.enum('Type', { 'Action icons only': true }), + + children: figma.children('*') + }, + example: (props) => {props.children} + } +); diff --git a/packages/code-connect/components/Alert/InlineAlert.figma.tsx b/packages/code-connect/components/Alert/InlineAlert.figma.tsx new file mode 100644 index 00000000000..e78a587fa5e --- /dev/null +++ b/packages/code-connect/components/Alert/InlineAlert.figma.tsx @@ -0,0 +1,33 @@ +import figma from '@figma/code-connect'; +import { Alert } from '@patternfly/react-core'; + +// Documentation for Alert can be found at https://www.patternfly.org/components/alert + +figma.connect( + Alert, + 'https://www.figma.com/design/aEBBvq0J3EPXxHvv6WgDx9/PatternFly-6--Components-Test?node-id=1110-2698', + { + props: { + // string + description: figma.string('✏️ Title'), + title: figma.string('✏️ Title'), + + // boolean + isExpandable: figma.boolean('Expandable'), + + // enum + variant: figma.enum('Type', { + Info: 'info', + Success: 'success', + Warning: 'warning', + Danger: 'danger', + Custom: 'custom' + }) + }, + example: (props) => ( + + {props.description} + + ) + } +); diff --git a/packages/code-connect/components/Alert/InlineAlertGroup.figma.tsx b/packages/code-connect/components/Alert/InlineAlertGroup.figma.tsx new file mode 100644 index 00000000000..cefe226d00b --- /dev/null +++ b/packages/code-connect/components/Alert/InlineAlertGroup.figma.tsx @@ -0,0 +1,19 @@ +import figma from '@figma/code-connect'; +import { AlertGroup } from '@patternfly/react-core'; + +// Documentation for Alert can be found at https://www.patternfly.org/components/alert + +figma.connect( + AlertGroup, + 'https://www.figma.com/design/aEBBvq0J3EPXxHvv6WgDx9/PatternFly-6--Components-Test?node-id=1110-2780', + { + props: { + children: figma.children('*') + }, + example: (props) => ( + + {props.children} + + ) + } +); diff --git a/packages/code-connect/components/Alert/InlinePlainAlert.figma.tsx b/packages/code-connect/components/Alert/InlinePlainAlert.figma.tsx new file mode 100644 index 00000000000..2da8fbeb2e7 --- /dev/null +++ b/packages/code-connect/components/Alert/InlinePlainAlert.figma.tsx @@ -0,0 +1,32 @@ +import figma from '@figma/code-connect'; +import { Alert } from '@patternfly/react-core'; + +// Documentation for Alert can be found at https://www.patternfly.org/components/alert + +figma.connect( + Alert, + 'https://www.figma.com/design/aEBBvq0J3EPXxHvv6WgDx9/PatternFly-6--Components-Test?node-id=1110-2754', + { + props: { + // string + description: figma.string('✏️ Title'), + title: figma.string('✏️ Title'), + + // enum + variant: figma.enum('Type', { + Info: 'info', + Success: 'success', + Warning: 'warning', + Danger: 'danger', + Custom: 'custom' + }), + + children: figma.children('*') + }, + example: (props) => ( + + {props.description} + + ) + } +); diff --git a/packages/code-connect/components/Alert/OverflowFooter.figma.tsx b/packages/code-connect/components/Alert/OverflowFooter.figma.tsx new file mode 100644 index 00000000000..04a73853b41 --- /dev/null +++ b/packages/code-connect/components/Alert/OverflowFooter.figma.tsx @@ -0,0 +1,42 @@ +import figma from '@figma/code-connect'; +import { Alert, AlertActionCloseButton, AlertGroup } from '@patternfly/react-core'; + +// Documentation for Alert can be found at https://www.patternfly.org/components/alert + +figma.connect( + AlertGroup, + 'https://www.figma.com/design/aEBBvq0J3EPXxHvv6WgDx9/PatternFly-6--Components-Test?node-id=1110-2784', + { + props: { + overflowMessage: figma.string('✏️ Title') + }, + example: (props) => ( + {}} overflowMessage={props.overflowMessage}> + {}} />} + key={1} + /> + {}} />} + key={2} + /> + {}} />} + key={3} + /> + {}} />} + key={4} + /> + + ) + } +); diff --git a/packages/code-connect/components/Alert/ToastAlert.figma.tsx b/packages/code-connect/components/Alert/ToastAlert.figma.tsx new file mode 100644 index 00000000000..b7d1ef87d50 --- /dev/null +++ b/packages/code-connect/components/Alert/ToastAlert.figma.tsx @@ -0,0 +1,40 @@ +import figma from '@figma/code-connect'; +import { Alert } from '@patternfly/react-core'; + +// Documentation for Alert can be found at https://www.patternfly.org/components/alert + +figma.connect( + Alert, + 'https://www.figma.com/design/aEBBvq0J3EPXxHvv6WgDx9/PatternFly-6--Components-Test?node-id=1110-2587', + { + props: { + // string + description: figma.string('✏️ Title'), + title: figma.string('✏️ Title'), + + // boolean + isExpandable: figma.boolean('Expandable'), + + // enum + variant: figma.enum('Type', { + Custom: 'custom', + Danger: 'danger', + Info: 'info', + Success: 'success', + Warning: 'warning' + }) + }, + example: (props) => ( + + {props.description} + + ) + } +); diff --git a/packages/code-connect/components/Alert/ToastAlertGroup.figma.tsx b/packages/code-connect/components/Alert/ToastAlertGroup.figma.tsx new file mode 100644 index 00000000000..7a16c09a440 --- /dev/null +++ b/packages/code-connect/components/Alert/ToastAlertGroup.figma.tsx @@ -0,0 +1,19 @@ +import figma from '@figma/code-connect'; +import { AlertGroup } from '@patternfly/react-core'; + +// Documentation for AlertGroup can be found at https://www.patternfly.org/components/alert + +figma.connect( + AlertGroup, + 'https://www.figma.com/design/aEBBvq0J3EPXxHvv6WgDx9/PatternFly-6--Components-Test?node-id=1110-2821', + { + props: { + children: figma.children('*') + }, + example: (props) => ( + + {props.children} + + ) + } +); diff --git a/packages/code-connect/components/Avatar/Avatar.figma.tsx b/packages/code-connect/components/Avatar/Avatar.figma.tsx new file mode 100644 index 00000000000..8959f3c1c9c --- /dev/null +++ b/packages/code-connect/components/Avatar/Avatar.figma.tsx @@ -0,0 +1,26 @@ +import figma from '@figma/code-connect'; +import { Avatar } from '@patternfly/react-core'; + +// Documentation for Avatar can be found at https://www.patternfly.org/components/avatar + +figma.connect( + Avatar, + 'https://www.figma.com/design/aEBBvq0J3EPXxHvv6WgDx9/PatternFly-6%3A-Components-Test?node-id=1561-4342', + { + props: { + // boolean + isBordered: figma.boolean('Bordered'), + + // enum + size: figma.enum('Size', { + small: 'sm', + med: 'md', + lg: 'lg', + XL: 'xl' + }) + }, + example: (props) => ( + + ) + } +); diff --git a/packages/code-connect/components/BackToTop/BackToTop.figma.tsx b/packages/code-connect/components/BackToTop/BackToTop.figma.tsx new file mode 100644 index 00000000000..c6c58f7724e --- /dev/null +++ b/packages/code-connect/components/BackToTop/BackToTop.figma.tsx @@ -0,0 +1,15 @@ +import figma from '@figma/code-connect'; +import { BackToTop } from '@patternfly/react-core'; + +// Documentation for BackToTop can be found at https://www.patternfly.org/components/back-to-top + +figma.connect( + BackToTop, + 'https://www.figma.com/design/aEBBvq0J3EPXxHvv6WgDx9/PatternFly-6--Components-Test?node-id=1521-958', + { + props: { + text: figma.string('Text') + }, + example: (props) => + } +); diff --git a/packages/code-connect/components/Backdrop/Backdrop.figma.tsx b/packages/code-connect/components/Backdrop/Backdrop.figma.tsx new file mode 100644 index 00000000000..3c6e02acc70 --- /dev/null +++ b/packages/code-connect/components/Backdrop/Backdrop.figma.tsx @@ -0,0 +1,12 @@ +import figma from '@figma/code-connect'; +import { Backdrop } from '@patternfly/react-core'; + +// Documentation for Backdrop can be found at https://www.patternfly.org/components/backdrop + +figma.connect( + Backdrop, + 'https://www.figma.com/design/aEBBvq0J3EPXxHvv6WgDx9/PatternFly-6%3A-Components-Test?node-id=2873-2900', + { + example: () => + } +); diff --git a/packages/code-connect/components/BackgroundImage/BackgroundImage.figma.tsx b/packages/code-connect/components/BackgroundImage/BackgroundImage.figma.tsx new file mode 100644 index 00000000000..bc8654807bc --- /dev/null +++ b/packages/code-connect/components/BackgroundImage/BackgroundImage.figma.tsx @@ -0,0 +1,12 @@ +import figma from '@figma/code-connect'; +import { BackgroundImage } from '@patternfly/react-core'; + +// Documentation for BackgroundImage can be found at https://www.patternfly.org/components/background-image + +figma.connect( + BackgroundImage, + 'https://www.figma.com/design/aEBBvq0J3EPXxHvv6WgDx9/PatternFly-6--Components-Test?node-id=2722-13543', + { + example: () => + } +); diff --git a/packages/code-connect/components/Badge/Badge.figma.tsx b/packages/code-connect/components/Badge/Badge.figma.tsx new file mode 100644 index 00000000000..d45e66a0a9a --- /dev/null +++ b/packages/code-connect/components/Badge/Badge.figma.tsx @@ -0,0 +1,24 @@ +import figma from '@figma/code-connect'; +import { Badge } from '@patternfly/react-core'; + +// Documentation for Badge can be found at https://www.patternfly.org/components/badge + +figma.connect( + Badge, + 'https://www.figma.com/design/aEBBvq0J3EPXxHvv6WgDx9/PatternFly-6--Components-Test?node-id=1259-1132', + { + props: { + // string + text: figma.string('Text'), + + // enum + isDisabled: figma.enum('Type', { disabled: true }), + isRead: figma.enum('Type', { Read: true }) + }, + example: (props) => ( + + {props.text} + + ) + } +); diff --git a/packages/code-connect/components/Banner/NonStatusBanner.figma.tsx b/packages/code-connect/components/Banner/NonStatusBanner.figma.tsx new file mode 100644 index 00000000000..5b11678d0c7 --- /dev/null +++ b/packages/code-connect/components/Banner/NonStatusBanner.figma.tsx @@ -0,0 +1,28 @@ +import figma from '@figma/code-connect'; +import { Banner } from '@patternfly/react-core'; + +// Documentation for Banner can be found at https://www.patternfly.org/components/banner + +figma.connect( + Banner, + 'https://www.figma.com/design/aEBBvq0J3EPXxHvv6WgDx9/PatternFly-6%3A-Components-Test?node-id=221-1443', + { + props: { + // string + text: figma.string('✏️ Center text'), + + // enum + color: figma.enum('Color', { + Red: 'red', + Orangered: 'orangered', + Orange: 'orange', + Yellow: 'yellow', + Green: 'green', + Teal: 'teal', + Blue: 'blue', + Purple: 'purple' + }) + }, + example: (props) => {props.text} + } +); diff --git a/packages/code-connect/components/Banner/StatusBanner.figma.tsx b/packages/code-connect/components/Banner/StatusBanner.figma.tsx new file mode 100644 index 00000000000..83272bdd787 --- /dev/null +++ b/packages/code-connect/components/Banner/StatusBanner.figma.tsx @@ -0,0 +1,36 @@ +import figma from '@figma/code-connect'; +import { Banner } from '@patternfly/react-core'; + +// Documentation for Banner can be found at https://www.patternfly.org/components/banner + +figma.connect( + Banner, + 'https://www.figma.com/design/aEBBvq0J3EPXxHvv6WgDx9/PatternFly-6%3A-Components-Test?node-id=221-937', + { + props: { + // string + text: figma.string('✏️ Center text'), + + // enum + status: figma.enum('Status', { + Success: 'success', + Warning: 'warning', + Danger: 'danger', + Info: 'info', + Custom: 'custom' + }), + screenReaderText: figma.enum('Status', { + Success: 'Success banner screen reader text', + Warning: 'Warning banner screen reader text', + Danger: 'Danger banner screen reader text', + Info: 'Info banner screen reader text', + Custom: 'Custom banner screen reader text' + }) + }, + example: (props) => ( + + {props.text} + + ) + } +); diff --git a/packages/code-connect/components/Brand/FullLogo.figma.tsx b/packages/code-connect/components/Brand/FullLogo.figma.tsx new file mode 100644 index 00000000000..28f7f91f853 --- /dev/null +++ b/packages/code-connect/components/Brand/FullLogo.figma.tsx @@ -0,0 +1,14 @@ +import figma from '@figma/code-connect'; +import { Brand } from '@patternfly/react-core'; + +// Documentation for Brand can be found at https://www.patternfly.org/components/brand + +figma.connect( + Brand, + 'https://www.figma.com/design/aEBBvq0J3EPXxHvv6WgDx9/PatternFly-6--Components-Test?node-id=2104-3689', + { + example: () => ( + + ) + } +); diff --git a/packages/code-connect/components/Brand/MastheadLogo.figma.tsx b/packages/code-connect/components/Brand/MastheadLogo.figma.tsx new file mode 100644 index 00000000000..c78c3da6801 --- /dev/null +++ b/packages/code-connect/components/Brand/MastheadLogo.figma.tsx @@ -0,0 +1,21 @@ +import figma from '@figma/code-connect'; +import { Brand } from '@patternfly/react-core'; + +// Documentation for Brand can be found at https://www.patternfly.org/components/brand + +figma.connect( + Brand, + 'https://www.figma.com/design/aEBBvq0J3EPXxHvv6WgDx9/PatternFly-6--Components-Test?node-id=2104-3644', + { + example: () => ( + + + + + + + + + ) + } +); diff --git a/packages/code-connect/components/Breadcrumbs/Breadcrumb.figma.tsx b/packages/code-connect/components/Breadcrumbs/Breadcrumb.figma.tsx new file mode 100644 index 00000000000..6ad19b534e8 --- /dev/null +++ b/packages/code-connect/components/Breadcrumbs/Breadcrumb.figma.tsx @@ -0,0 +1,15 @@ +import figma from '@figma/code-connect'; +import { Breadcrumb } from '@patternfly/react-core'; + +// Documentation for Breadcrumb can be found at https://www.patternfly.org/components/breadcrumb + +figma.connect( + Breadcrumb, + 'https://www.figma.com/design/aEBBvq0J3EPXxHvv6WgDx9/PatternFly-6%3A-Components-Test?node-id=3362-283', + { + props: { + children: figma.children('*') + }, + example: (props) => {props.children} + } +); diff --git a/packages/code-connect/components/Breadcrumbs/BreadcrumbItem.figma.tsx b/packages/code-connect/components/Breadcrumbs/BreadcrumbItem.figma.tsx new file mode 100644 index 00000000000..6e834534dcc --- /dev/null +++ b/packages/code-connect/components/Breadcrumbs/BreadcrumbItem.figma.tsx @@ -0,0 +1,22 @@ +import figma from '@figma/code-connect'; +import { BreadcrumbItem } from '@patternfly/react-core'; + +// Documentation for BreadcrumbItem can be found at https://www.patternfly.org/components/breadcrumb + +figma.connect( + BreadcrumbItem, + 'https://www.figma.com/design/aEBBvq0J3EPXxHvv6WgDx9/PatternFly-6--Components-Test?node-id=3362-74', + { + props: { + // string + text: figma.string('Text'), + + // enum + to: figma.enum('State', { + Link: '#', + Hover: '#' + }) + }, + example: (props) => {props.text} + } +); diff --git a/packages/code-connect/components/Breadcrumbs/ExpandableBreadcrumbs.figma.tsx b/packages/code-connect/components/Breadcrumbs/ExpandableBreadcrumbs.figma.tsx new file mode 100644 index 00000000000..22a8eaaf0da --- /dev/null +++ b/packages/code-connect/components/Breadcrumbs/ExpandableBreadcrumbs.figma.tsx @@ -0,0 +1,70 @@ +import figma from '@figma/code-connect'; +import { Badge, BreadcrumbItem, Dropdown, DropdownItem, DropdownList, Icon, MenuToggle } from '@patternfly/react-core'; +import AngleLeftIcon from '@patternfly/react-icons/dist/esm/icons/angle-left-icon'; + +// Documentation for BreadcrumbItem can be found at https://www.patternfly.org/components/breadcrumb + +figma.connect( + BreadcrumbItem, + 'https://www.figma.com/design/aEBBvq0J3EPXxHvv6WgDx9/PatternFly-6--Components-Test?node-id=19922-43760', + { + props: {}, + example: () => ( + + {}} + onOpenChange={() => {}} + toggle={() => ( + + 01 + + } + onClick={() => {}} + isExpanded={false} + variant="plainText" + /> + )} + isOpen={false} + > + + + + + } + key="edit" + > + Edit + + , + + + + } + key="action" + > + Deployment + + , + + + + } + key="apps" + > + Applications + + + + + ) + } +); diff --git a/packages/code-connect/components/ClipboardCopy/ClipboardCopyBasic.figma.tsx b/packages/code-connect/components/ClipboardCopy/ClipboardCopyBasic.figma.tsx new file mode 100644 index 00000000000..8f5047d7e1c --- /dev/null +++ b/packages/code-connect/components/ClipboardCopy/ClipboardCopyBasic.figma.tsx @@ -0,0 +1,37 @@ +import figma from '@figma/code-connect'; +import { ClipboardCopy } from '@patternfly/react-core'; + +// TODO: DESIGN: ClipboardCopy is using InputGroup improperly. There's no InputGroup wrapper for InputGroupItems + +figma.connect( + ClipboardCopy, + 'https://www.figma.com/design/aEBBvq0J3EPXxHvv6WgDx9/PatternFly-6--Components-Test?node-id=9914-75835', + { + props: { + // enum + isExpanded: figma.enum('State', { Expanded: true }), + isReadOnly: figma.enum('State', { 'Read only': true }), + expansion: figma.enum('State', { + Expanded: 'expansion', + false: undefined + }), + + inputText: figma.nestedProps('Input Group Items', { + value: figma.string('✏️ Input text') + }) + }, + example: (props) => ( + // Documentation for ClipboardCopy can be found at https://www.patternfly.org/components/clipboard-copy + {}} + clickTip="Copied" + hoverTip="Copy" + isExpanded={props.isExpanded} + isReadOnly={props.isReadOnly} + variant={props.expansion} + > + {props.inputText.value} + + ) + } +); diff --git a/packages/code-connect/components/ClipboardCopy/ClipboardCopyInlineCompact.figma.tsx b/packages/code-connect/components/ClipboardCopy/ClipboardCopyInlineCompact.figma.tsx new file mode 100644 index 00000000000..5a990fae565 --- /dev/null +++ b/packages/code-connect/components/ClipboardCopy/ClipboardCopyInlineCompact.figma.tsx @@ -0,0 +1,19 @@ +import figma from '@figma/code-connect'; +import { ClipboardCopy } from '@patternfly/react-core'; + +// Documentation for ClipboardCopy can be found at https://www.patternfly.org/components/clipboard-copy + +figma.connect( + ClipboardCopy, + 'https://www.figma.com/design/aEBBvq0J3EPXxHvv6WgDx9/PatternFly-6--Components-Test?node-id=9914-75768', + { + props: { + children: figma.children('*') + }, + example: (props) => ( + {}} variant="inline-compact"> + {props.children} + + ) + } +); diff --git a/packages/code-connect/components/CodeBlock/CodeBlock.figma.tsx b/packages/code-connect/components/CodeBlock/CodeBlock.figma.tsx new file mode 100644 index 00000000000..1f0c5696ec1 --- /dev/null +++ b/packages/code-connect/components/CodeBlock/CodeBlock.figma.tsx @@ -0,0 +1,43 @@ +import figma from '@figma/code-connect'; +import { CodeBlock, CodeBlockCode, ExpandableSection, ExpandableSectionToggle } from '@patternfly/react-core'; + +// TODO: DESIGN: Configure Actions layer to contain CodeBlockAction components + +figma.connect( + CodeBlock, + 'https://www.figma.com/design/aEBBvq0J3EPXxHvv6WgDx9/PatternFly-6--Components-Test?node-id=9802-5857', + { + props: { + editorText: 'code block code', + + actions: `action1, action2, action3, action4, action5`, + + // boolean + expandableSectionToggle: figma.boolean('Expandable', { + true: ( + {}} contentId="code-block-id"> + Show More + + ), + false: undefined + }), + expandableSectionContent: figma.boolean('Expandable', { + true: ( + + Expandable content + + ), + false: undefined + }) + }, + example: (props) => ( + + + {props.editorText} + {props.expandableSectionContent} + + {props.expandableSectionToggle} + + ) + } +); diff --git a/packages/code-connect/components/CodeEditor/CodeEditor.figma.tsx b/packages/code-connect/components/CodeEditor/CodeEditor.figma.tsx new file mode 100644 index 00000000000..640c9412d02 --- /dev/null +++ b/packages/code-connect/components/CodeEditor/CodeEditor.figma.tsx @@ -0,0 +1,42 @@ +import figma from '@figma/code-connect'; +import { CodeEditor } from '@patternfly/react-code-editor'; + +// TODO: DESIGN: Add support for actions, wrap each action in the appropriate compnent +// TODO: DESIGN: When shortcuts is removed, presentation breaks +// TODO: DESIGN: configure options for actions +// TODO: DESIGN: Add viewshortcuts +// TODO: DESIGN: ifshortcuts is true +// Documentation for CodeEditor can be found at https://www.patternfly.org/components/code-editor + +figma.connect( + CodeEditor, + 'https://www.figma.com/design/aEBBvq0J3EPXxHvv6WgDx9/PatternFly-6--Components-Test?node-id=16994-184502', + { + props: { + // boolean + hasCustomControls: '', + isUploadEnabled: figma.boolean('Action 1'), + isCopyEnabled: figma.boolean('Action 2'), + isDownloadEnabled: figma.boolean('Action 3'), + showsLineNumbers: figma.boolean('Show Line Numbers'), + + // enum + isMinimapVisible: figma.enum('Type', { 'Mini Map': true }) + }, + example: (props) => ( + <> + + + ) + } +); diff --git a/packages/code-connect/components/DataList/DataList.figma.tsx b/packages/code-connect/components/DataList/DataList.figma.tsx new file mode 100644 index 00000000000..cceb9c61217 --- /dev/null +++ b/packages/code-connect/components/DataList/DataList.figma.tsx @@ -0,0 +1,23 @@ +import figma from '@figma/code-connect'; +import { DataList } from '@patternfly/react-core'; + +// TODO: DESIGN: Separate examples, rename files to match their react counterparts. +// Documentation for DataList can be found at https://www.patternfly.org/components/data-list + +figma.connect( + DataList, + 'https://www.figma.com/design/aEBBvq0J3EPXxHvv6WgDx9/PatternFly-6--Components-Test?node-id=6649-80542', + { + props: { + // enum + isCompact: figma.enum('Size', { Compact: true }), + + children: figma.children('*') + }, + example: (props) => ( + + {props.children} + + ) + } +); diff --git a/packages/code-connect/components/DataList/_1BuildItYourselfBasicRows.figma.tsx b/packages/code-connect/components/DataList/_1BuildItYourselfBasicRows.figma.tsx new file mode 100644 index 00000000000..6c8d4ecfe33 --- /dev/null +++ b/packages/code-connect/components/DataList/_1BuildItYourselfBasicRows.figma.tsx @@ -0,0 +1,18 @@ +import figma from '@figma/code-connect'; +import { DataListItem, DataListItemRow } from '@patternfly/react-core'; + +figma.connect( + DataListItemRow, + 'https://www.figma.com/design/aEBBvq0J3EPXxHvv6WgDx9/PatternFly-6--Components-Test?node-id=6649-69488&m=dev', + { + props: { + children: figma.children('*') + }, + example: (props) => ( + // aria-labelledby should point to an ID within the DataListItemRow/DataListItemCell + + {props.children} + + ) + } +); diff --git a/packages/code-connect/components/DataList/_1BuildItYourselfClickableRows.figma.tsx b/packages/code-connect/components/DataList/_1BuildItYourselfClickableRows.figma.tsx new file mode 100644 index 00000000000..f06513ba576 --- /dev/null +++ b/packages/code-connect/components/DataList/_1BuildItYourselfClickableRows.figma.tsx @@ -0,0 +1,20 @@ +import figma from '@figma/code-connect'; +import { DataListItem, DataListItemRow } from '@patternfly/react-core'; + +// Documentation for DataListItemRow can be found at https://www.patternfly.org/components/data-list + +figma.connect( + DataListItemRow, + 'https://www.figma.com/design/aEBBvq0J3EPXxHvv6WgDx9/PatternFly-6--Components-Test?node-id=6649-96947', + { + props: { + children: figma.children('*') + }, + example: (props) => ( + // aria-labelledby should point to an ID within the DataListItemRow/DataListItemCell + + {props.children} + + ) + } +); diff --git a/packages/code-connect/components/DataList/_1BuildItYourselfDraggableRows.figma.tsx b/packages/code-connect/components/DataList/_1BuildItYourselfDraggableRows.figma.tsx new file mode 100644 index 00000000000..f1c90db7194 --- /dev/null +++ b/packages/code-connect/components/DataList/_1BuildItYourselfDraggableRows.figma.tsx @@ -0,0 +1,26 @@ +import figma from '@figma/code-connect'; +import { DataList } from '@patternfly/react-core'; + +// Documentation for DataListItemRow can be found at https://www.patternfly.org/components/data-list +// This variant has been refactored to use the DragDropSort component. +// In order to use this variant, you must wrap the DataList component in a DragDropSort component. + +figma.connect( + DataList, + 'https://www.figma.com/design/aEBBvq0J3EPXxHvv6WgDx9/PatternFly-6--Components-Test?node-id=19618-55289', + { + example: () => + 'Draggable DataList variant has been refactored to use the DragDropSort component. The design is the same, but the implementation is different. This component variant requires refactoring to work within the new context. For more information, see the example at https://www.patternfly.org/components/data-list/#draggable.' + // Code example: + // { + // setItems(newItems); + // }} + // variant="DataList" + // overlayProps={{ isCompact: true }} + // > + // + // + } +); diff --git a/packages/code-connect/components/DataList/_2BaseComponentsActionCell.figma.tsx b/packages/code-connect/components/DataList/_2BaseComponentsActionCell.figma.tsx new file mode 100644 index 00000000000..75c18d6e8bf --- /dev/null +++ b/packages/code-connect/components/DataList/_2BaseComponentsActionCell.figma.tsx @@ -0,0 +1,16 @@ +import figma from '@figma/code-connect'; +import { DataListAction } from '@patternfly/react-core'; + +// Documentation for DataListItemRow can be found at https://www.patternfly.org/components/data-list + +figma.connect( + DataListAction, + 'https://www.figma.com/design/aEBBvq0J3EPXxHvv6WgDx9/PatternFly-6--Components-Test?node-id=6596-33965', + { + example: () => ( + + 'Action' + + ) + } +); diff --git a/packages/code-connect/components/DataList/_2BaseComponentsContentCell.figma.tsx b/packages/code-connect/components/DataList/_2BaseComponentsContentCell.figma.tsx new file mode 100644 index 00000000000..a7d4356a90e --- /dev/null +++ b/packages/code-connect/components/DataList/_2BaseComponentsContentCell.figma.tsx @@ -0,0 +1,44 @@ +import figma from '@figma/code-connect'; +import { Icon, DataListCell, DataListItem, DataListItemCells, DataListItemRow } from '@patternfly/react-core'; + +// TODO: DESIGN: Either name layers uniquely or create a dataListCell component to house +// Documentation for DataList can be found at https://www.patternfly.org/components/data-list + +figma.connect( + DataListCell, + 'https://www.figma.com/design/aEBBvq0J3EPXxHvv6WgDx9/PatternFly-6--Components-Test?node-id=6596-33934', + { + props: { + showDescriptionText: figma.boolean('Show description text'), + + // enum + isIcon: figma.enum('Type', { + 'Filled - Plain text': true + }), + isFilled: figma.enum('Type', { + 'Filled - Plain text': true, + 'Filled - Link text': true + }), + + primaryContent: 'Main content', + secondaryContent: 'Second content block' + }, + example: (props) => ( + + + + + , + + {props.primaryContent} + , + {props.secondaryContent} + ]} + /> + + + ) + } +); diff --git a/packages/code-connect/components/DataList/_2BaseComponentsControlCell.figma.tsx b/packages/code-connect/components/DataList/_2BaseComponentsControlCell.figma.tsx new file mode 100644 index 00000000000..c709bd6ed9f --- /dev/null +++ b/packages/code-connect/components/DataList/_2BaseComponentsControlCell.figma.tsx @@ -0,0 +1,49 @@ +import figma from '@figma/code-connect'; +import { + // DataListAction, + DataListCheck, + DataListControl, + DataListToggle +} from '@patternfly/react-core'; + +// TODO: 2. Base Components/Control cell - These cells need unique names. Either create components for DataListCell, +// DataListToggle, DataListDragButton, DataListAction, DataListCheck +// These component specifics are unreachable unless separated into their own entities +// Documentation for DataListControl can be found at https://www.patternfly.org/components/data-list + +// const selectableCell = { +// +// return ( +// <> +// {props.isSelectable} +// {props.isExpandable} +// {props.isDraggable} +// +// {props.children} +// +// +// ); +// }; + +figma.connect( + DataListControl, + 'https://www.figma.com/design/aEBBvq0J3EPXxHvv6WgDx9/PatternFly-6--Components-Test?node-id=6596-34013', + { + props: { + isExpandable: figma.boolean('Row expansion', { + true: {}} isExpanded={false} id="toggle1" aria-controls="expand1" />, + false: undefined + }), + isSelectable: figma.boolean('Row select', { + true: , + false: undefined + }) + }, + example: (props) => ( + <> + {props.isSelectable} + {props.isExpandable} + + ) + } +); diff --git a/packages/code-connect/components/DatePicker/BaseComponentsCalendarDay.figma.tsx b/packages/code-connect/components/DatePicker/BaseComponentsCalendarDay.figma.tsx new file mode 100644 index 00000000000..8fde324c68f --- /dev/null +++ b/packages/code-connect/components/DatePicker/BaseComponentsCalendarDay.figma.tsx @@ -0,0 +1,15 @@ +import figma from '@figma/code-connect'; +import { CalendarMonth } from '@patternfly/react-core'; + +// Documentation for CalendarMonth can be found at https://www.patternfly.org/components/calendar-month + +figma.connect( + CalendarMonth, + 'https://www.figma.com/design/aEBBvq0J3EPXxHvv6WgDx9/PatternFly-6--Components-Test?node-id=7741-2677', + { + props: { + date: '2025-06-16' + }, + example: (props) => {}} onMonthChange={() => {}} /> + } +); diff --git a/packages/code-connect/components/DatePicker/CalendarMonth.figma.tsx b/packages/code-connect/components/DatePicker/CalendarMonth.figma.tsx new file mode 100644 index 00000000000..0f226f5a427 --- /dev/null +++ b/packages/code-connect/components/DatePicker/CalendarMonth.figma.tsx @@ -0,0 +1,51 @@ +import figma from '@figma/code-connect'; +import { CalendarMonth, Title } from '@patternfly/react-core'; + +// Documentation for CalendarMonth can be found at https://www.patternfly.org/components/calendar-month +const sharedProps = { + inlineProps: { + component: 'article', + title: ( + + Select your favorite date + + ) + } +}; + +figma.connect( + CalendarMonth, + 'https://www.figma.com/design/aEBBvq0J3EPXxHvv6WgDx9/PatternFly-6--Components-Test?node-id=7958-136846', + { + props: { + ...sharedProps, + date: '2025-06-16' + }, + example: (props) => ( + {}} onMonthChange={() => {}} /> + ) + } +); + +figma.connect( + CalendarMonth, + 'https://www.figma.com/design/aEBBvq0J3EPXxHvv6WgDx9/PatternFly-6--Components-Test?node-id=7958-136846', + { + props: { + ...sharedProps, + variant: { Type: 'With date range' }, + startDate: new Date(2020, 10, 11), + endDate: new Date(2020, 10, 24) + }, + example: (props) => ( + {}} + onMonthChange={() => {}} + rangeStart={props.startDate} + /> + ) + } +); diff --git a/packages/code-connect/components/DatePicker/DateAndTimePicker.figma.tsx b/packages/code-connect/components/DatePicker/DateAndTimePicker.figma.tsx new file mode 100644 index 00000000000..8d7366ab344 --- /dev/null +++ b/packages/code-connect/components/DatePicker/DateAndTimePicker.figma.tsx @@ -0,0 +1,94 @@ +import figma from '@figma/code-connect'; +import { + Button, + CalendarMonth, + Dropdown, + DropdownItem, + DropdownList, + InputGroup, + InputGroupItem, + MenuToggle, + Popover, + TextInput, + TimePicker +} from '@patternfly/react-core'; +import OutlinedCalendarAltIcon from '@patternfly/react-icons/dist/esm/icons/outlined-calendar-alt-icon'; +import OutlinedClockIcon from '@patternfly/react-icons/dist/esm/icons/outlined-clock-icon'; + +// Documentation for TimePicker can be found at https://www.patternfly.org/components/time-picker + +const sharedProps = { + time: ( + {}} + isOpen={false} + onOpenChange={() => {}} + toggle={(toggleRef) => ( + {}} + isExpanded={false} + aria-label="Time picker" + icon={} + /> + )} + > + + + Action + + + Operation + + + + ), + calendarButton: ( + + + + + + ) + } +); + +figma.connect( + DescriptionListTerm, + 'https://www.figma.com/design/aEBBvq0J3EPXxHvv6WgDx9/PatternFly-6--Components-Test?node-id=36279-2532', + { + variant: { 'Has help text': true, 'Inline edit toggle': false }, + props: { + // string + label: figma.string('✏️ Label'), + + // enum + icon: figma.enum('Icon ⎆', { + true: , + false: undefined + }) + }, + example: (props) => ( + + {props.label}} bodyContent={
This is the help text
}> + + {props.icon} + {props.label} + +
+
+ ) + } +); + +figma.connect( + DescriptionListTerm, + 'https://www.figma.com/design/aEBBvq0J3EPXxHvv6WgDx9/PatternFly-6--Components-Test?node-id=36279-2532', + { + props: { + // string + label: figma.string('✏️ Label'), + + // enum + icon: figma.enum('Icon ⎆', { + true: , + false: undefined + }) + }, + example: (props) => {props.label} + } +); diff --git a/packages/code-connect/components/Divider/Divider.figma.tsx b/packages/code-connect/components/Divider/Divider.figma.tsx new file mode 100644 index 00000000000..18189ce4f65 --- /dev/null +++ b/packages/code-connect/components/Divider/Divider.figma.tsx @@ -0,0 +1,61 @@ +import figma from '@figma/code-connect'; +import { Divider, Flex, FlexItem } from '@patternfly/react-core'; + +// Documentation for Divider can be found at https://www.patternfly.org/components/divider + +figma.connect( + Divider, + 'https://www.figma.com/design/aEBBvq0J3EPXxHvv6WgDx9/PatternFly-6%3A-Components-Test?node-id=2764-6708', + { + props: { + // TODO: Figma allows optional insets, but default to insetMd + inset: figma.boolean('With insets', { + true: { default: 'insetMd' }, + false: { default: 'insetNone' } + }), + // TODO: This is a good example of how properties in Figma and props in React would benefit from naming consistency + // React is looking for orientation, figma is defining orientation as 'Direction' + orientation: figma.enum('Direction', { + Horizontal: { default: undefined }, + Vertical: { default: 'vertical' } + }) + }, + example: (props) => ( + + first item + + + ) + } +); + +figma.connect( + Divider, + 'https://www.figma.com/design/aEBBvq0J3EPXxHvv6WgDx9/PatternFly-6%3A-Components-Test?node-id=2764-6708', + { + props: { + // TODO: Figma allows optional insets, but default to insetMd + inset: figma.boolean('With insets', { + true: { default: 'insetMd' }, + false: { default: 'insetNone' } + }), + // TODO: This is a good example of how properties in Figma and props in React would benefit from naming consistency + // React is looking for orientation, figma is defining orientation as 'Direction' + orientation: figma.enum('Direction', { + Horizontal: { default: undefined }, + Vertical: { default: 'vertical' } + }) + }, + example: (props) => ( + + ) + } +); diff --git a/packages/code-connect/components/Drawer/Drawer.figma.tsx b/packages/code-connect/components/Drawer/Drawer.figma.tsx new file mode 100644 index 00000000000..d2b54f2ed8a --- /dev/null +++ b/packages/code-connect/components/Drawer/Drawer.figma.tsx @@ -0,0 +1,74 @@ +import figma from '@figma/code-connect'; +import { + Drawer, + DrawerActions, + DrawerCloseButton, + DrawerContent, + DrawerContentBody, + DrawerHead, + DrawerPanelBody, + DrawerPanelContent, + DrawerPanelDescription +} from '@patternfly/react-core'; + +// TODO: DESIGN: Drawer is not using base components, rather it's using layers. Layers should be replaced with base components. +// Panel content is currently static. Once updated to components, it will be updated to be dynamic. +// Documentation for Drawer can be found at https://www.patternfly.org/components/drawer + +figma.connect( + Drawer, + 'https://www.figma.com/design/aEBBvq0J3EPXxHvv6WgDx9/PatternFly-6--Components-Test?node-id=8034-7676', + { + props: { + // boolean + isExpanded: true, + colorVariant: figma.enum('Background', { + Secondary: 'secondary', + Primary: undefined + }), + + // enum + isInline: figma.enum('Type', { Inline: true }), + position: figma.enum('Position', { + 'Left In Main Content Area': 'start', + 'Right - Full Page': undefined, + 'Left - Full Page': 'start', + 'Right Full Page': undefined, + 'Bottom Full Page': 'bottom', + 'Bottom In Main Content Area': 'bottom', + 'Right In Main Content Area': undefined + }) + + // Once updatedted to use child components, this will be used to render content. + // panelContent: figma.children(['Drawer Header', 'Drawer Tabs', 'Drawer Content']) + }, + example: (props) => ( + {}} + > + + + Drawer panel header + + {}} /> + + + Drawer panel description + Drawer panel body + + } + > + Drawer body content + + + ) + } +); diff --git a/packages/code-connect/components/Drawer/DrawerContent.figma.tsx b/packages/code-connect/components/Drawer/DrawerContent.figma.tsx new file mode 100644 index 00000000000..c9fe8b29897 --- /dev/null +++ b/packages/code-connect/components/Drawer/DrawerContent.figma.tsx @@ -0,0 +1,15 @@ +import figma from '@figma/code-connect'; +import { DrawerContent } from '@patternfly/react-core'; + +// Documentation for DrawerContent can be found at https://www.patternfly.org/components/drawer + +figma.connect( + DrawerContent, + 'https://www.figma.com/design/aEBBvq0J3EPXxHvv6WgDx9/PatternFly-6--Components-Test?node-id=35627-47890', + { + props: { + panelContent: figma.children('*') + }, + example: (props) => + } +); diff --git a/packages/code-connect/components/DualListSelector/DualListHeader.figma.tsx b/packages/code-connect/components/DualListSelector/DualListHeader.figma.tsx new file mode 100644 index 00000000000..bfca4eb4ce8 --- /dev/null +++ b/packages/code-connect/components/DualListSelector/DualListHeader.figma.tsx @@ -0,0 +1,65 @@ +import figma from '@figma/code-connect'; +import { Button, ButtonVariant, DualListSelectorPane, SearchInput } from '@patternfly/react-core'; +import TimesIcon from '@patternfly/react-icons/dist/esm/icons/times-icon'; + +// Documentation for DualListHeader can be found at https://www.patternfly.org/components/dual-list-selector + +figma.connect( + DualListSelectorPane, + 'https://www.figma.com/design/aEBBvq0J3EPXxHvv6WgDx9/PatternFly-6--Components-Test?node-id=21279-116172', + { + props: { + icon: , // placeholder icon + + // string + itemInformation: figma.string('Item information'), + title: figma.string('Header text'), + + // boolean + onSearch: figma.boolean('Has search bar', { + true: () => {}, + false: undefined + }), + isSearchable: figma.boolean('Has search bar', { + true: ( + {}} onClear={() => {}} aria-label={paneSearchLabel} /> + ), + false: undefined + }), + actions: figma.boolean('Has search bar', { + true: [ + + + + + + + + + + + + + + ) + } +); diff --git a/packages/code-connect/components/FileUpload/MultipleFileUpload.figma.tsx b/packages/code-connect/components/FileUpload/MultipleFileUpload.figma.tsx new file mode 100644 index 00000000000..d57533f9693 --- /dev/null +++ b/packages/code-connect/components/FileUpload/MultipleFileUpload.figma.tsx @@ -0,0 +1,70 @@ +import figma from '@figma/code-connect'; +import { + FileUpload, + MultipleFileUpload, + MultipleFileUploadMain, + MultipleFileUploadStatus, + MultipleFileUploadStatusItem +} from '@patternfly/react-core'; +import UploadIcon from '@patternfly/react-icons/dist/esm/icons/upload-icon'; + +// TODO: DESIGN: Add status toggle text +// TODO: DESIGN: Add status toggle icon +// TODO: DESIGN: Add text separator +// TODO: DESIGN: Add info text +// TODO: DESIGN: Add status toggle text +// TODO: DESIGN: Add status toggle icon + +figma.connect( + FileUpload, + 'https://www.figma.com/design/aEBBvq0J3EPXxHvv6WgDx9/PatternFly-6--Components-Test?node-id=8949-96128', + { + props: { + // static + titleText: 'Drag and drop files here', + titleTextSeparator: 'or', + infoText: 'Accepted file types: JPEG, Doc, PDF, PNG', + + // enum + isHorizontal: figma.enum('Layout', { Horizontal: true }), + + children: figma.children('*') + }, + example: (props) => ( + // Documentation for FileUpload can be found at https://www.patternfly.org/components/file-upload + {}} + > + } + titleText={props.titleText} + titleTextSeparator={props.titleTextSeparator} + /> + + + {}} + onReadSuccess={() => {}} + onReadFail={() => {}} + /> + + + ) + } +); diff --git a/packages/code-connect/components/FileUpload/SimpleFileUpload.figma.tsx b/packages/code-connect/components/FileUpload/SimpleFileUpload.figma.tsx new file mode 100644 index 00000000000..f64e56b0379 --- /dev/null +++ b/packages/code-connect/components/FileUpload/SimpleFileUpload.figma.tsx @@ -0,0 +1,61 @@ +import figma from '@figma/code-connect'; +import { FileUpload, FileUploadHelperText, HelperText, HelperTextItem } from '@patternfly/react-core'; + +// TODO: DESIGN: Add filename placeholder +// TODO: DESIGN: Add browse button text +// TODO: DESIGN: Add FileUploadHelperText + +figma.connect( + FileUpload, + 'https://www.figma.com/design/aEBBvq0J3EPXxHvv6WgDx9/PatternFly-6--Components-Test?node-id=8949-96043', + { + props: { + // boolean + showHelperText: figma.boolean('Show helper text'), + hideDefaultPreview: figma.boolean('Show text preview box', { + true: false, + false: true + }), + helperText: figma.boolean('Show helper text', { + true: ( + + + Upload a CSV file + + + ), + false: undefined + }), + + // enum + allowEditingUploadedText: figma.enum('State', { 'Uploaded + Editable': true }), + isLoading: figma.enum('State', { 'In progress upload': true }), + isValidated: figma.enum('State', { + 'Invalid upload': 'error', + 'Uploaded + Editable': 'success', + 'Uploaded + Not Editable': 'success' + }) + }, + example: (props) => ( + // Documentation for FileUpload can be found at https://www.patternfly.org/components/file-upload + {}} + onDataChange={() => {}} + onTextChange={() => {}} + onReadStarted={() => {}} + onReadFinished={() => {}} + onClearClick={() => {}} + > + {props.helperText} + + ) + } +); diff --git a/packages/code-connect/components/Hint/Hint.figma.tsx b/packages/code-connect/components/Hint/Hint.figma.tsx new file mode 100644 index 00000000000..99116bb3c58 --- /dev/null +++ b/packages/code-connect/components/Hint/Hint.figma.tsx @@ -0,0 +1,95 @@ +import figma from '@figma/code-connect'; +import { + Hint, + HintBody, + HintFooter, + HintTitle, + DropdownList, + Dropdown, + DropdownItem, + Divider +} from '@patternfly/react-core'; +import EllipsisVIcon from '@patternfly/react-icons/dist/esm/icons/ellipsis-v-icon'; +import MenuToggle from '@patternfly/react-core/dist/js/components/MenuToggle/MenuToggle'; + +// TODO: DESIGN: Use dropdown from figma for actions +// TODO: DESIGN: Create hint title +// TODO: DESIGN: Create hint body +// TODO: DESIGN: Create hint footer + +// Note: Figma will not render conditional props within React components. +// This means that the , , and tags will not be properly render figma.string() +// Documentation for Hint can be found at https://www.patternfly.org/components/hint + +figma.connect( + Hint, + 'https://www.figma.com/design/aEBBvq0J3EPXxHvv6WgDx9/PatternFly-6--Components-Test?node-id=1118-3329', + { + props: { + // Pre-defined title options (enum works, boolean with JSX doesn't) + hintTitle: figma.enum('Show Title', { + false: undefined, + true: Hint title + }), + + // Pre-defined body options + hintBody: figma.enum('Show Body', { + false: undefined, + true: This is hint body text that provides helpful information. + }), + + // Pre-defined footer options + hintFooter: figma.enum('Show Footer', { + false: undefined, + true: Footer content or link + }) + }, + example: (props) => ( + {}} + onOpenChange={() => {}} + toggle={(toggleRef) => ( + {}} + isExpanded={false} + icon={} + /> + )} + > + + + Action + + {}}> + Link + + + Disabled Action + + + Disabled Link + + + + Separated Action + + {}}> + Separated Link + + + + } + > + {props.hintTitle} + {props.hintBody} + {props.hintFooter} + + ) + } +); diff --git a/packages/code-connect/components/InlineEdit/FieldSpecificInlineEdit.figma.tsx b/packages/code-connect/components/InlineEdit/FieldSpecificInlineEdit.figma.tsx new file mode 100644 index 00000000000..38ec11644d0 --- /dev/null +++ b/packages/code-connect/components/InlineEdit/FieldSpecificInlineEdit.figma.tsx @@ -0,0 +1,53 @@ +import figma from '@figma/code-connect'; + +// Inline edit is NOT a React component +// Documentation for InlineEdit can be found at https://www.patternfly.org/components/inline-edit + +figma.connect('https://www.figma.com/design/aEBBvq0J3EPXxHvv6WgDx9/PatternFly-6--Components-Test?node-id=1664-8856', { + props: {}, + example: () => ( +
+
+
+ Static value +
+
+ +
+
+
+
+ + + +
+
+
+ +
+
+ +
+
+
+
+ ) +}); diff --git a/packages/code-connect/components/InlineEdit/InlineEditActionGroup.figma.tsx b/packages/code-connect/components/InlineEdit/InlineEditActionGroup.figma.tsx new file mode 100644 index 00000000000..0837009b006 --- /dev/null +++ b/packages/code-connect/components/InlineEdit/InlineEditActionGroup.figma.tsx @@ -0,0 +1,24 @@ +import figma from '@figma/code-connect'; + +// Inline edit is NOT a React component +// Documentation for InlineEdit can be found at https://www.patternfly.org/components/inline-edit + +figma.connect('https://www.figma.com/design/aEBBvq0J3EPXxHvv6WgDx9/PatternFly-6--Components-Test?node-id=1664-5805', { + props: {}, + example: () => ( +
+
+
+ +
+
+ +
+
+
+ ) +}); diff --git a/packages/code-connect/components/InlineEdit/InlineEditToggle.figma.tsx b/packages/code-connect/components/InlineEdit/InlineEditToggle.figma.tsx new file mode 100644 index 00000000000..d20bca9228b --- /dev/null +++ b/packages/code-connect/components/InlineEdit/InlineEditToggle.figma.tsx @@ -0,0 +1,25 @@ +import figma from '@figma/code-connect'; + +// Inline edit is NOT a React component +// Documentation for InlineEdit can be found at https://www.patternfly.org/components/inline-edit + +figma.connect('https://www.figma.com/design/aEBBvq0J3EPXxHvv6WgDx9/PatternFly-6--Components-Test?node-id=1664-8905', { + props: {}, + example: () => ( +
+
+ +
+
+ ) +}); diff --git a/packages/code-connect/figma.config.json b/packages/code-connect/figma.config.json new file mode 100644 index 00000000000..2537e14be2b --- /dev/null +++ b/packages/code-connect/figma.config.json @@ -0,0 +1,33 @@ +{ + "codeConnect": { + "parser": "react", + "include": [ + "components/DatePicker/*.tsx", + "components/EmptyState/*.tsx", + "components/FileUpload/*.tsx", + "components/Hint/*.tsx", + "components/InlineEdit/*.tsx" + ], + "paths": { + "src/components": "src/components" + }, + "aliases": { + "@patternfly/react-core": "." + }, + "importPaths": { + "src/components": "src/components" + }, + "options": { + "instanceSwapper": { + "enabled": true + }, + "development": { + "enabled": true, + "verbose": true + }, + "production": { + "enabled": false + } + } + } +} \ No newline at end of file diff --git a/packages/eslint-plugin-patternfly-react/CHANGELOG.md b/packages/eslint-plugin-patternfly-react/CHANGELOG.md index 1d65b2768c2..4bdb7fa1ab0 100644 --- a/packages/eslint-plugin-patternfly-react/CHANGELOG.md +++ b/packages/eslint-plugin-patternfly-react/CHANGELOG.md @@ -3,6 +3,20 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# 6.4.0 (2025-10-16) + +**Note:** Version bump only for package eslint-plugin-patternfly-react + +# [6.4.0-prerelease.1](https://github.com/patternfly/patternfly-react/compare/eslint-plugin-patternfly-react@6.3.1-prerelease.0...eslint-plugin-patternfly-react@6.4.0-prerelease.1) (2025-09-26) + +### Bug Fixes + +- updated to 6.4.0-prerelease ([df46ac6](https://github.com/patternfly/patternfly-react/commit/df46ac6bed381eb3e01e5573f77d79301b02b7fa)) + +## [6.3.1-prerelease.0](https://github.com/patternfly/patternfly-react/compare/eslint-plugin-patternfly-react@6.3.0...eslint-plugin-patternfly-react@6.3.1-prerelease.0) (2025-07-28) + +**Note:** Version bump only for package eslint-plugin-patternfly-react + # 6.3.0 (2025-07-22) **Note:** Version bump only for package eslint-plugin-patternfly-react diff --git a/packages/eslint-plugin-patternfly-react/package.json b/packages/eslint-plugin-patternfly-react/package.json index c42d04a590f..845b87ee6ab 100644 --- a/packages/eslint-plugin-patternfly-react/package.json +++ b/packages/eslint-plugin-patternfly-react/package.json @@ -1,6 +1,6 @@ { "name": "eslint-plugin-patternfly-react", - "version": "6.3.0", + "version": "6.4.0", "type": "commonjs", "exports": { ".": "./lib/index.js" @@ -25,6 +25,6 @@ }, "homepage": "https://github.com/patternfly/patternfly-react/blob/main/packages/eslint-plugin-patternfly-react/README.md", "peerDependencies": { - "eslint": ">=9.22.0" + "eslint": ">=9.32.0" } } diff --git a/packages/react-charts/CHANGELOG.md b/packages/react-charts/CHANGELOG.md index 79aee1d0faf..19deb37c9df 100644 --- a/packages/react-charts/CHANGELOG.md +++ b/packages/react-charts/CHANGELOG.md @@ -3,6 +3,42 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [8.4.0](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-charts@8.4.0-prerelease.4...@patternfly/react-charts@8.4.0) (2025-10-16) + +**Note:** Version bump only for package @patternfly/react-charts + +# [8.4.0-prerelease.4](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-charts@8.4.0-prerelease.3...@patternfly/react-charts@8.4.0-prerelease.4) (2025-10-16) + +**Note:** Version bump only for package @patternfly/react-charts + +# [8.4.0-prerelease.3](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-charts@8.4.0-prerelease.2...@patternfly/react-charts@8.4.0-prerelease.3) (2025-10-01) + +### Bug Fixes + +- Bumped echarts and core. ([#12023](https://github.com/patternfly/patternfly-react/issues/12023)) ([1d4d075](https://github.com/patternfly/patternfly-react/commit/1d4d075730c3645394c774bfc5233ea786e29e43)) + +# [8.4.0-prerelease.2](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-charts@8.3.1-prerelease.3...@patternfly/react-charts@8.4.0-prerelease.2) (2025-09-26) + +### Bug Fixes + +- updated to 6.4.0-prerelease ([df46ac6](https://github.com/patternfly/patternfly-react/commit/df46ac6bed381eb3e01e5573f77d79301b02b7fa)) + +## [8.3.1-prerelease.3](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-charts@8.3.1-prerelease.2...@patternfly/react-charts@8.3.1-prerelease.3) (2025-09-26) + +**Note:** Version bump only for package @patternfly/react-charts + +## [8.3.1-prerelease.2](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-charts@8.3.1-prerelease.1...@patternfly/react-charts@8.3.1-prerelease.2) (2025-09-24) + +**Note:** Version bump only for package @patternfly/react-charts + +## [8.3.1-prerelease.1](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-charts@8.3.1-prerelease.0...@patternfly/react-charts@8.3.1-prerelease.1) (2025-09-05) + +**Note:** Version bump only for package @patternfly/react-charts + +## [8.3.1-prerelease.0](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-charts@8.3.0...@patternfly/react-charts@8.3.1-prerelease.0) (2025-07-28) + +**Note:** Version bump only for package @patternfly/react-charts + # 8.3.0 (2025-07-22) **Note:** Version bump only for package @patternfly/react-charts diff --git a/packages/react-charts/package.json b/packages/react-charts/package.json index 0e5792a2d66..d328f6e8bba 100644 --- a/packages/react-charts/package.json +++ b/packages/react-charts/package.json @@ -1,6 +1,6 @@ { "name": "@patternfly/react-charts", - "version": "8.3.0", + "version": "8.4.0", "description": "This library provides a set of React chart components for use with the PatternFly reference implementation.", "main": "dist/js/index.js", "module": "dist/esm/index.js", @@ -51,7 +51,7 @@ "jest-canvas-mock": "^2.5.2" }, "peerDependencies": { - "echarts": "^5.6.0", + "echarts": "^5.6.0 || ^6.0.0", "react": "^17 || ^18 || ^19", "react-dom": "^17 || ^18 || ^19", "victory-area": "^37.3.6", diff --git a/packages/react-charts/src/echarts/components/Line/__tests__/__snapshots__/Line.test.tsx.snap b/packages/react-charts/src/echarts/components/Line/__tests__/__snapshots__/Line.test.tsx.snap index ccc5369f37d..336a0e0cd73 100644 --- a/packages/react-charts/src/echarts/components/Line/__tests__/__snapshots__/Line.test.tsx.snap +++ b/packages/react-charts/src/echarts/components/Line/__tests__/__snapshots__/Line.test.tsx.snap @@ -28,80 +28,80 @@ exports[`renders component 1`] = ` /> @@ -110,7 +110,7 @@ exports[`renders component 1`] = ` fill="#1f1f1f" style="font-size: 14px; font-family: var(--pf-v6-chart-global--FontFamily, 'Red Hat Text', 'RedHatText', 'Noto Sans Arabic', 'Noto Sans Hebrew', 'Noto Sans JP', 'Noto Sans KR', 'Noto Sans Malayalam', 'Noto Sans SC', 'Noto Sans TC', 'Noto Sans Thai', Helvetica, Arial, sans-serif);" text-anchor="middle" - transform="translate(160 338)" + transform="translate(195 328)" y="0.5" > 2015 @@ -120,7 +120,7 @@ exports[`renders component 1`] = ` fill="#1f1f1f" style="font-size: 14px; font-family: var(--pf-v6-chart-global--FontFamily, 'Red Hat Text', 'RedHatText', 'Noto Sans Arabic', 'Noto Sans Hebrew', 'Noto Sans JP', 'Noto Sans KR', 'Noto Sans Malayalam', 'Noto Sans SC', 'Noto Sans TC', 'Noto Sans Thai', Helvetica, Arial, sans-serif);" text-anchor="middle" - transform="translate(320 338)" + transform="translate(345 328)" y="0.5" > 2016 @@ -130,7 +130,7 @@ exports[`renders component 1`] = ` fill="#1f1f1f" style="font-size: 14px; font-family: var(--pf-v6-chart-global--FontFamily, 'Red Hat Text', 'RedHatText', 'Noto Sans Arabic', 'Noto Sans Hebrew', 'Noto Sans JP', 'Noto Sans KR', 'Noto Sans Malayalam', 'Noto Sans SC', 'Noto Sans TC', 'Noto Sans Thai', Helvetica, Arial, sans-serif);" text-anchor="middle" - transform="translate(480 338)" + transform="translate(495 328)" y="0.5" > 2017 @@ -140,7 +140,7 @@ exports[`renders component 1`] = ` fill="#1f1f1f" style="font-size: 14px; font-family: var(--pf-v6-chart-global--FontFamily, 'Red Hat Text', 'RedHatText', 'Noto Sans Arabic', 'Noto Sans Hebrew', 'Noto Sans JP', 'Noto Sans KR', 'Noto Sans Malayalam', 'Noto Sans SC', 'Noto Sans TC', 'Noto Sans Thai', Helvetica, Arial, sans-serif);" text-anchor="middle" - transform="translate(640 338)" + transform="translate(645 328)" y="0.5" > 2018 @@ -149,7 +149,7 @@ exports[`renders component 1`] = ` clip-path="url(#zr0-c0)" > @@ -215,7 +215,7 @@ exports[`renders component 1`] = ` id="zr0-c0" > @@ -223,7 +223,7 @@ exports[`renders component 1`] = ` id="zr0-c1" > @@ -231,7 +231,7 @@ exports[`renders component 1`] = ` id="zr0-c2" > @@ -239,7 +239,7 @@ exports[`renders component 1`] = ` id="zr0-c3" > @@ -258,8 +258,8 @@ exports[`renders title 1`] = ` dominant-baseline="central" fill="#1f1f1f" style="font-size: 14px; font-family: var(--pf-v6-chart-global--FontFamily, 'Red Hat Text', 'RedHatText', 'Noto Sans Arabic', 'Noto Sans Hebrew', 'Noto Sans JP', 'Noto Sans KR', 'Noto Sans Malayalam', 'Noto Sans SC', 'Noto Sans TC', 'Noto Sans Thai', Helvetica, Arial, sans-serif); font-weight: bold;" - text-anchor="start" - transform="translate(5 5)" + text-anchor="middle" + transform="translate(400 20)" xml:space="preserve" y="0.5" > diff --git a/packages/react-charts/src/echarts/components/Sankey/__tests__/__snapshots__/Sankey.test.tsx.snap b/packages/react-charts/src/echarts/components/Sankey/__tests__/__snapshots__/Sankey.test.tsx.snap index 66802d6a2b7..7cf03d7d4a6 100644 --- a/packages/react-charts/src/echarts/components/Sankey/__tests__/__snapshots__/Sankey.test.tsx.snap +++ b/packages/react-charts/src/echarts/components/Sankey/__tests__/__snapshots__/Sankey.test.tsx.snap @@ -164,19 +164,19 @@ exports[`renders component 1`] = ` @@ -208,8 +208,8 @@ exports[`renders title 1`] = ` dominant-baseline="central" fill="#1f1f1f" style="font-size: 14px; font-family: var(--pf-v6-chart-global--FontFamily, 'Red Hat Text', 'RedHatText', 'Noto Sans Arabic', 'Noto Sans Hebrew', 'Noto Sans JP', 'Noto Sans KR', 'Noto Sans Malayalam', 'Noto Sans SC', 'Noto Sans TC', 'Noto Sans Thai', Helvetica, Arial, sans-serif); font-weight: bold;" - text-anchor="start" - transform="translate(5 5)" + text-anchor="middle" + transform="translate(400 20)" xml:space="preserve" y="0.5" > diff --git a/packages/react-charts/src/victory/components/ChartPie/examples/ChartPie.md b/packages/react-charts/src/victory/components/ChartPie/examples/ChartPie.md index 0f1c92e2abd..41fe48515a8 100644 --- a/packages/react-charts/src/victory/components/ChartPie/examples/ChartPie.md +++ b/packages/react-charts/src/victory/components/ChartPie/examples/ChartPie.md @@ -17,92 +17,21 @@ The examples below are based on the [Victory](https://formidable.com/open-source ## Examples ### Basic with right aligned legend -```js -import { ChartPie } from '@patternfly/react-charts/victory'; +```ts file = "ChartPieBasicRightLegend.tsx" -
- `${datum.x}: ${datum.y}`} - legendData={[{ name: 'Cats: 35' }, { name: 'Dogs: 55' }, { name: 'Birds: 10' }]} - legendOrientation="vertical" - legendPosition="right" - name="chart1" - padding={{ - bottom: 20, - left: 20, - right: 140, // Adjusted to accommodate legend - top: 20 - }} - width={350} - /> -
``` ### Multi-color (ordered) with bottom aligned legend -```js -import { ChartPie, ChartThemeColor } from '@patternfly/react-charts/victory'; +```ts file = "ChartPieMultiColorBottomLegend.tsx" -
- `${datum.x}: ${datum.y}`} - legendData={[{ name: 'Cats: 35' }, { name: 'Dogs: 55' }, { name: 'Birds: 10' }]} - legendPosition="bottom" - name="chart3" - padding={{ - bottom: 65, - left: 20, - right: 20, - top: 20 - }} - themeColor={ChartThemeColor.multiOrdered} - width={300} - /> -
``` ### Custom color scale This demonstrates how to apply a custom color scale. -```js -import { ChartPie, ChartThemeColor } from '@patternfly/react-charts/victory'; -import chart_theme_blue_ColorScale_100 from '@patternfly/react-tokens/dist/esm/chart_theme_blue_ColorScale_100'; -import chart_theme_yellow_ColorScale_100 from '@patternfly/react-tokens/dist/esm/chart_theme_yellow_ColorScale_100'; -import chart_theme_orange_ColorScale_300 from '@patternfly/react-tokens/dist/esm/chart_theme_orange_ColorScale_300'; +```ts file = "ChartPieCustomColorScale.tsx" -
- `${datum.x}`} - legendData={[{ name: 'Sky' }, { name: 'Shady side of pyramid' }, { name: 'Sunny side of pyramid' }]} - legendOrientation="vertical" - legendPosition="right" - name="chart2" - padding={{ - bottom: 20, - left: 20, - right: 240, // Adjusted to accommodate legend - top: 20 - }} - themeColor={ChartThemeColor.orange} - width={450} - /> -
``` ## Documentation diff --git a/packages/react-charts/src/victory/components/ChartPie/examples/ChartPieBasicRightLegend.tsx b/packages/react-charts/src/victory/components/ChartPie/examples/ChartPieBasicRightLegend.tsx new file mode 100644 index 00000000000..293f88205fd --- /dev/null +++ b/packages/react-charts/src/victory/components/ChartPie/examples/ChartPieBasicRightLegend.tsx @@ -0,0 +1,40 @@ +import { ChartPie } from '@patternfly/react-charts/victory'; + +interface PetData { + x?: string; + y?: number; + name?: string; +} + +export const ChartPieBasicRightLegend: React.FunctionComponent = () => { + const data: PetData[] = [ + { x: 'Cats', y: 35 }, + { x: 'Dogs', y: 55 }, + { x: 'Birds', y: 10 } + ]; + const legendData: PetData[] = [{ name: 'Cats: 35' }, { name: 'Dogs: 55' }, { name: 'Birds: 10' }]; + + return ( +
+ `${datum.x}: ${datum.y}`} + legendData={legendData} + legendOrientation="vertical" + legendPosition="right" + name="chart1" + padding={{ + bottom: 20, + left: 20, + right: 140, // Adjusted to accommodate legend + top: 20 + }} + width={350} + /> +
+ ); +}; diff --git a/packages/react-charts/src/victory/components/ChartPie/examples/ChartPieCustomColorScale.tsx b/packages/react-charts/src/victory/components/ChartPie/examples/ChartPieCustomColorScale.tsx new file mode 100644 index 00000000000..b531671f617 --- /dev/null +++ b/packages/react-charts/src/victory/components/ChartPie/examples/ChartPieCustomColorScale.tsx @@ -0,0 +1,51 @@ +import { ChartPie, ChartThemeColor } from '@patternfly/react-charts/victory'; +import chart_theme_blue_ColorScale_100 from '@patternfly/react-tokens/dist/esm/chart_theme_blue_ColorScale_100'; +import chart_theme_yellow_ColorScale_100 from '@patternfly/react-tokens/dist/esm/chart_theme_yellow_ColorScale_100'; +import chart_theme_orange_ColorScale_300 from '@patternfly/react-tokens/dist/esm/chart_theme_orange_ColorScale_300'; + +interface Data { + x?: string; + y?: number; + name?: string; +} + +export const ChartPieCustomColorScale: React.FunctionComponent = () => { + const data: Data[] = [ + { x: 'Sky', y: 38 }, + { x: 'Shady side of pyramid', y: 7 }, + { x: 'Sunny side of pyramid', y: 17 }, + { x: 'Sky', y: 38 } + ]; + const legendData: Data[] = [{ name: 'Sky' }, { name: 'Shady side of pyramid' }, { name: 'Sunny side of pyramid' }]; + + return ( +
+ `${datum.x}`} + legendData={legendData} + legendOrientation="vertical" + legendPosition="right" + name="chart2" + padding={{ + bottom: 20, + left: 20, + right: 240, // Adjusted to accommodate legend + top: 20 + }} + themeColor={ChartThemeColor.orange} + width={450} + /> +
+ ); +}; diff --git a/packages/react-charts/src/victory/components/ChartPie/examples/ChartPieMultiColorBottomLegend.tsx b/packages/react-charts/src/victory/components/ChartPie/examples/ChartPieMultiColorBottomLegend.tsx new file mode 100644 index 00000000000..670c01ac2a7 --- /dev/null +++ b/packages/react-charts/src/victory/components/ChartPie/examples/ChartPieMultiColorBottomLegend.tsx @@ -0,0 +1,40 @@ +import { ChartPie, ChartThemeColor } from '@patternfly/react-charts/victory'; + +interface PetData { + x?: string; + y?: number; + name?: string; +} + +export const ChartPieMultiColorBottomLegend: React.FunctionComponent = () => { + const data: PetData[] = [ + { x: 'Cats', y: 35 }, + { x: 'Dogs', y: 55 }, + { x: 'Birds', y: 10 } + ]; + const legendData: PetData[] = [{ name: 'Cats: 35' }, { name: 'Dogs: 55' }, { name: 'Birds: 10' }]; + + return ( +
+ `${datum.x}: ${datum.y}`} + legendData={legendData} + legendPosition="bottom" + name="chart3" + padding={{ + bottom: 65, + left: 20, + right: 20, + top: 20 + }} + themeColor={ChartThemeColor.multiOrdered} + width={300} + /> +
+ ); +}; diff --git a/packages/react-charts/src/victory/components/ChartScatter/examples/ChartScatter.md b/packages/react-charts/src/victory/components/ChartScatter/examples/ChartScatter.md index 78afbc3459a..90400d6c9a4 100644 --- a/packages/react-charts/src/victory/components/ChartScatter/examples/ChartScatter.md +++ b/packages/react-charts/src/victory/components/ChartScatter/examples/ChartScatter.md @@ -13,7 +13,6 @@ propComponents: [ hideDarkMode: true --- -import { createRef } from 'react'; import { Chart, ChartArea, @@ -25,6 +24,7 @@ ChartThemeColor, ChartVoronoiContainer, } from '@patternfly/react-charts/victory'; import { getResizeObserver } from '@patternfly/react-core'; +import { useEffect, useRef, useState } from 'react'; ## Introduction Note: PatternFly React charts live in its own package at [@patternfly/react-charts](https://www.npmjs.com/package/@patternfly/react-charts)! @@ -33,296 +33,24 @@ The examples below are based on the [Victory](https://formidable.com/open-source ## Examples ### Basic -```js -import { Chart, ChartAxis, ChartGroup, ChartScatter, ChartVoronoiContainer } from '@patternfly/react-charts/victory'; +```ts file = "ChartScatterBasic.tsx" -
- `${datum.name}: ${datum.y}`} - constrainToVisibleArea - /> - } - height={275} - maxDomain={{y: 8}} - minDomain={{y: 0}} - name="chart1" - width={450} - > - - - - - - -
``` ### Line chart This demonstrates how to add interactive data points to a line chart. -```js -import { Chart, ChartAxis, ChartGroup, ChartLine, ChartScatter, ChartThemeColor, ChartVoronoiContainer } from '@patternfly/react-charts/victory'; -import { getResizeObserver } from '@patternfly/react-core'; - -class ScatterLineChart extends React.Component { - constructor(props) { - super(props); - this.containerRef = createRef(); - this.observer = () => {}; - this.state = { - width: 0 - }; - this.handleResize = () => { - if (this.containerRef.current && this.containerRef.current.clientWidth) { - this.setState({ width: this.containerRef.current.clientWidth }); - } - }; - - this.series = [ - { - datapoints: [ - { name: 'Cats', x: '2015', y: 1 }, - { name: 'Cats', x: '2016', y: 2 }, - { name: 'Cats', x: '2017', y: 5 }, - { name: 'Cats', x: '2018', y: 3 } - ], - legendItem: { name: 'Cats' } - }, - { - datapoints: [ - { name: 'Dogs', x: '2015', y: 2 }, - { name: 'Dogs', x: '2016', y: 1 }, - { name: 'Dogs', x: '2017', y: 7 }, - { name: 'Dogs', x: '2018', y: 4 } - ], - legendItem: { name: 'Dogs' }, - style: { - data: { - strokeDasharray: '3,3' - } - } - }, - { - datapoints: [ - { name: 'Birds', x: '2015', y: 3 }, - { name: 'Birds', x: '2016', y: 4 }, - { name: 'Birds', x: '2017', y: 9 }, - { name: 'Birds', x: '2018', y: 5 } - ], - legendItem: { name: 'Birds' } - }, - { - datapoints: [ - { name: 'Mice', x: '2015', y: 3 }, - { name: 'Mice', x: '2016', y: 3 }, - { name: 'Mice', x: '2017', y: 8 }, - { name: 'Mice', x: '2018', y: 7 } - ], - legendItem: { name: 'Mice' } - }]; - } - - componentDidMount() { - this.observer = getResizeObserver(this.containerRef.current, this.handleResize); - this.handleResize(); - } - - componentWillUnmount() { - this.observer(); - } - - render() { - const { width } = this.state; +```ts file = "ChartScatterLineChart.tsx" - return ( -
-
- datum.childName.includes('line-') ? `${datum.name}: ${datum.y}` : null} - constrainToVisibleArea - /> - } - legendData={this.series.map(s => s.legendItem)} - legendPosition="bottom-left" - height={275} - maxDomain={{y: 10}} - minDomain={{y: 0}} - name="chart2" - padding={{ - bottom: 75, // Adjusted to accommodate legend - left: 50, - right: 50, - top: 50 - }} - themeColor={ChartThemeColor.orange} - width={width} - > - - - - {this.series.map((s, idx) => { - return ( - - ); - })} - - - {this.series.map((s, idx) => { - return ( - - ); - })} - - -
-
- ); - } -} ``` ### Area chart This demonstrates how to add interactive data points to an area chart. -```js -import { Chart, ChartArea, ChartAxis, ChartGroup, ChartScatter, ChartThemeColor, ChartVoronoiContainer } from '@patternfly/react-charts/victory'; -import { getResizeObserver } from '@patternfly/react-core'; -// import '@patternfly/patternfly/patternfly-charts.css'; // For mixed blend mode - -class ScatterAreaChart extends React.Component { - constructor(props) { - super(props); - this.containerRef = createRef(); - this.observer = () => {}; - this.state = { - width: 0 - }; - this.handleResize = () => { - if (this.containerRef.current && this.containerRef.current.clientWidth) { - this.setState({ width: this.containerRef.current.clientWidth }); - } - }; - - this.series = [ - { - datapoints: [ - { name: 'Cats', x: '2015', y: 3 }, - { name: 'Cats', x: '2016', y: 4 }, - { name: 'Cats', x: '2017', y: 8 }, - { name: 'Cats', x: '2018', y: 6 } - ], - legendItem: { name: 'Cats' } - }, - { - datapoints: [ - { name: 'Dogs', x: '2015', y: 2 }, - { name: 'Dogs', x: '2016', y: 3 }, - { name: 'Dogs', x: '2017', y: 4 }, - { name: 'Dogs', x: '2018', y: 5 }, - { name: 'Dogs', x: '2019', y: 6 } - ], - legendItem: { name: 'Dogs' } - }, - { - datapoints: [ - { name: 'Birds', x: '2015', y: 1 }, - { name: 'Birds', x: '2016', y: 2 }, - { name: 'Birds', x: '2017', y: 3 }, - { name: 'Birds', x: '2018', y: 2 }, - { name: 'Birds', x: '2019', y: 4 } - ], - legendItem: { name: 'Birds' } - }]; - } - - componentDidMount() { - this.observer = getResizeObserver(this.containerRef.current, this.handleResize); - this.handleResize(); - } - - componentWillUnmount() { - this.observer(); - } - - render() { - const { width } = this.state; +```ts file = "ChartScatterAreaChart.tsx" - return ( -
-
- datum.childName.includes('area-') ? `${datum.name}: ${datum.y}` : null} - constrainToVisibleArea - /> - } - height={225} - legendData={this.series.map(s => s.legendItem)} - legendPosition="bottom-left" - name="chart3" - padding={{ - bottom: 75, // Adjusted to accommodate legend - left: 50, - right: 50, - top: 50, - }} - maxDomain={{y: 9}} - themeColor={ChartThemeColor.multiUnordered} - width={width} - > - - - - {this.series.map((s, idx) => { - return ( - - ); - })} - - - {this.series.map((s, idx) => { - return ( - - ); - })} - - -
-
- ); - } -} ``` ## Documentation diff --git a/packages/react-charts/src/victory/components/ChartScatter/examples/ChartScatterAreaChart.tsx b/packages/react-charts/src/victory/components/ChartScatter/examples/ChartScatterAreaChart.tsx new file mode 100644 index 00000000000..d9c6dc41713 --- /dev/null +++ b/packages/react-charts/src/victory/components/ChartScatter/examples/ChartScatterAreaChart.tsx @@ -0,0 +1,107 @@ +import { + Chart, + ChartArea, + ChartAxis, + ChartGroup, + ChartScatter, + ChartThemeColor, + ChartVoronoiContainer +} from '@patternfly/react-charts/victory'; +import { getResizeObserver } from '@patternfly/react-core'; +import { useState, useRef, useEffect } from 'react'; + +export const ChartScatterAreaChart: React.FunctionComponent = () => { + const containerRef = useRef(null); + const observer = useRef(() => {}); + const [width, setWidth] = useState(0); + + const handleResize = () => { + if (containerRef.current && containerRef.current.clientWidth) { + setWidth(containerRef.current.clientWidth); + } + }; + + const series = [ + { + datapoints: [ + { name: 'Cats', x: '2015', y: 3 }, + { name: 'Cats', x: '2016', y: 4 }, + { name: 'Cats', x: '2017', y: 8 }, + { name: 'Cats', x: '2018', y: 6 } + ], + legendItem: { name: 'Cats' } + }, + { + datapoints: [ + { name: 'Dogs', x: '2015', y: 2 }, + { name: 'Dogs', x: '2016', y: 3 }, + { name: 'Dogs', x: '2017', y: 4 }, + { name: 'Dogs', x: '2018', y: 5 }, + { name: 'Dogs', x: '2019', y: 6 } + ], + legendItem: { name: 'Dogs' } + }, + { + datapoints: [ + { name: 'Birds', x: '2015', y: 1 }, + { name: 'Birds', x: '2016', y: 2 }, + { name: 'Birds', x: '2017', y: 3 }, + { name: 'Birds', x: '2018', y: 2 }, + { name: 'Birds', x: '2019', y: 4 } + ], + legendItem: { name: 'Birds' } + } + ]; + + useEffect(() => { + observer.current = getResizeObserver(containerRef.current, handleResize); + handleResize(); + + return () => { + observer.current(); + }; + }, []); + + return ( +
+
+ (datum.childName.includes('area-') ? `${datum.name}: ${datum.y}` : null)} + constrainToVisibleArea + /> + } + height={225} + legendData={series.map((s) => s.legendItem)} + legendPosition="bottom-left" + name="chart3" + padding={{ + bottom: 75, // Adjusted to accommodate legend + left: 50, + right: 50, + top: 50 + }} + maxDomain={{ y: 9 }} + themeColor={ChartThemeColor.multiUnordered} + width={width} + > + + + + {series.map((s, idx) => ( + + ))} + + + {series.map((s, idx) => ( + + ))} + + +
+
+ ); +}; diff --git a/packages/react-charts/src/victory/components/ChartScatter/examples/ChartScatterBasic.tsx b/packages/react-charts/src/victory/components/ChartScatter/examples/ChartScatterBasic.tsx new file mode 100644 index 00000000000..abaec09b802 --- /dev/null +++ b/packages/react-charts/src/victory/components/ChartScatter/examples/ChartScatterBasic.tsx @@ -0,0 +1,39 @@ +import { Chart, ChartAxis, ChartGroup, ChartScatter, ChartVoronoiContainer } from '@patternfly/react-charts/victory'; + +interface PetData { + name: string; + x: string; + y: number; +} + +export const ChartScatterBasic: React.FunctionComponent = () => { + const data: PetData[] = [ + { name: 'Cats', x: '2015', y: 1 }, + { name: 'Cats', x: '2016', y: 2 }, + { name: 'Cats', x: '2017', y: 5 }, + { name: 'Cats', x: '2018', y: 4 } + ]; + + return ( +
+ `${datum.name}: ${datum.y}`} constrainToVisibleArea /> + } + height={275} + maxDomain={{ y: 8 }} + minDomain={{ y: 0 }} + name="chart1" + width={450} + > + + + + + + +
+ ); +}; diff --git a/packages/react-charts/src/victory/components/ChartScatter/examples/ChartScatterLineChart.tsx b/packages/react-charts/src/victory/components/ChartScatter/examples/ChartScatterLineChart.tsx new file mode 100644 index 00000000000..7466aa240d8 --- /dev/null +++ b/packages/react-charts/src/victory/components/ChartScatter/examples/ChartScatterLineChart.tsx @@ -0,0 +1,119 @@ +import { + Chart, + ChartAxis, + ChartGroup, + ChartLine, + ChartScatter, + ChartThemeColor, + ChartVoronoiContainer +} from '@patternfly/react-charts/victory'; +import { getResizeObserver } from '@patternfly/react-core'; +import { useEffect, useRef, useState } from 'react'; + +export const ChartScatterLineChart: React.FunctionComponent = () => { + const containerRef = useRef(null); + const observer = useRef(() => {}); + const [width, setWidth] = useState(0); + + const handleResize = () => { + if (containerRef.current && containerRef.current.clientWidth) { + setWidth(containerRef.current.clientWidth); + } + }; + const series = [ + { + datapoints: [ + { name: 'Cats', x: '2015', y: 1 }, + { name: 'Cats', x: '2016', y: 2 }, + { name: 'Cats', x: '2017', y: 5 }, + { name: 'Cats', x: '2018', y: 3 } + ], + legendItem: { name: 'Cats' } + }, + { + datapoints: [ + { name: 'Dogs', x: '2015', y: 2 }, + { name: 'Dogs', x: '2016', y: 1 }, + { name: 'Dogs', x: '2017', y: 7 }, + { name: 'Dogs', x: '2018', y: 4 } + ], + legendItem: { name: 'Dogs' }, + style: { + data: { + strokeDasharray: '3,3' + } + } + }, + { + datapoints: [ + { name: 'Birds', x: '2015', y: 3 }, + { name: 'Birds', x: '2016', y: 4 }, + { name: 'Birds', x: '2017', y: 9 }, + { name: 'Birds', x: '2018', y: 5 } + ], + legendItem: { name: 'Birds' } + }, + { + datapoints: [ + { name: 'Mice', x: '2015', y: 3 }, + { name: 'Mice', x: '2016', y: 3 }, + { name: 'Mice', x: '2017', y: 8 }, + { name: 'Mice', x: '2018', y: 7 } + ], + legendItem: { name: 'Mice' } + } + ]; + + useEffect(() => { + observer.current = getResizeObserver(containerRef.current, handleResize); + handleResize(); + + return () => { + observer.current(); + }; + }, []); + + return ( +
+
+ (datum.childName.includes('line-') ? `${datum.name}: ${datum.y}` : null)} + constrainToVisibleArea + /> + } + legendData={series.map((s) => s.legendItem)} + legendPosition="bottom-left" + height={275} + maxDomain={{ y: 10 }} + minDomain={{ y: 0 }} + name="chart2" + padding={{ + bottom: 75, // Adjusted to accommodate legend + left: 50, + right: 50, + top: 50 + }} + themeColor={ChartThemeColor.orange} + width={width} + > + + + + {series.map((s, idx) => ( + + ))} + + + {series.map((s, idx) => ( + + ))} + + +
+
+ ); +}; diff --git a/packages/react-charts/src/victory/components/ChartStack/examples/ChartStack.md b/packages/react-charts/src/victory/components/ChartStack/examples/ChartStack.md index baf17cfb888..92bef38d902 100644 --- a/packages/react-charts/src/victory/components/ChartStack/examples/ChartStack.md +++ b/packages/react-charts/src/victory/components/ChartStack/examples/ChartStack.md @@ -11,7 +11,6 @@ propComponents: [ hideDarkMode: true --- -import { createRef } from 'react'; import { Chart, ChartArea, @@ -25,6 +24,7 @@ import { createContainer } from '@patternfly/react-charts/victory'; import { getResizeObserver } from '@patternfly/react-core'; +import { useEffect, useRef, useState } from 'react'; ## Introduction Note: PatternFly React charts live in its own package at [@patternfly/react-charts](https://www.npmjs.com/package/@patternfly/react-charts)! @@ -33,380 +33,34 @@ The examples below are based on the [Victory](https://formidable.com/open-source ## Examples ### Basic with right aligned legend -```js -import { Chart, ChartAxis, ChartBar, ChartStack, ChartVoronoiContainer } from '@patternfly/react-charts/victory'; +```ts file = "ChartStackBasicRightLegend.tsx" -
- `${datum.name}: ${datum.y}`} constrainToVisibleArea />} - domainPadding={{ x: [30, 25] }} - legendData={[{ name: 'Cats' }, { name: 'Dogs' }, { name: 'Birds' }, { name: 'Mice' }]} - legendOrientation="vertical" - legendPosition="right" - height={250} - name="chart1" - padding={{ - bottom: 50, - left: 50, - right: 200, // Adjusted to accommodate legend - top: 50 - }} - width={600} - > - - - - - - - - - -
``` ### Horizontal with bottom aligned legend -```js -import { Chart, ChartAxis, ChartBar, ChartStack, ChartThemeColor, ChartVoronoiContainer } from '@patternfly/react-charts/victory'; +```ts file = "ChartStackBottomLegend.tsx" -
- `${datum.name}: ${datum.y}`} constrainToVisibleArea />} - domainPadding={{ x: [30, 25] }} - legendData={[{ name: 'Cats' }, { name: 'Dogs' }, { name: 'Birds' }, { name: 'Mice' }]} - legendPosition="bottom" - height={275} - name="chart2" - padding={{ - bottom: 75, // Adjusted to accommodate legend - left: 50, - right: 50, - top: 50 - }} - themeColor={ChartThemeColor.yellow} - width={450} - > - - - - - - - - - -
``` ### Multi-color (ordered) horizontal with bottom aligned legend This demonstrates an alternate way of applying tooltips using data labels. -```js -import { Chart, ChartBar, ChartAxis, ChartStack, ChartThemeColor, ChartTooltip } from '@patternfly/react-charts/victory'; +```ts file = "ChartStackMultiColorOrdered.tsx" -
- - - - - } - /> - } - /> - } - /> - } - /> - - -
``` ### Monthly data with responsive container -```js -import { Chart, ChartAxis, ChartBar, ChartStack, ChartTooltip } from '@patternfly/react-charts/victory'; -import { getResizeObserver } from '@patternfly/react-core'; - -class MonthlyResponsiveStack extends React.Component { - constructor(props) { - super(props); - this.containerRef = createRef(); - this.observer = () => {}; - this.state = { - width: 0 - }; - - this.handleResize = () => { - if(this.containerRef.current && this.containerRef.current.clientWidth){ - this.setState({ width: this.containerRef.current.clientWidth }); - } - }; - - this.bars = []; - for(let i = 1; i < 32; i++){ - this.bars.push({ x: `Aug. ${i}`, y: Math.floor(Math.random() * 6) + 1 }); - }; - - this.renderSocketBars = () => { - let socketBars = this.bars.map((tick, index) => { - return { - x: tick.x, - y: tick.y, - name: 'Sockets', - label: `${tick.x} Sockets: ${tick.y}` - }; - }); - return } />; - } - - this.renderCoresBars = () => { - let coresBars = this.bars.map((tick, index) => { - return { - x: tick.x, - y: tick.y, - name: 'Cores', - label: `${tick.x} Cores: ${tick.y}` - }; - }); - return } />; - } - - this.renderNodesBars = () => { - let nodesBars = this.bars.map((tick, index) => { - return { - key: index, - x: tick.x, - y: tick.y, - name: 'Nodes', - label: `${tick.x} Nodes: ${tick.y}` - }; - }); - return } />; - } +```ts file = "ChartStackMonthlyResponsive.tsx" - this.getTickValues = (offset = 2) => { - let tickValues = []; - for(let i = 1; i < 32; i++){ - if (i % offset == 0){ - tickValues.push(`Aug. ${i}`); - } - } - return tickValues; - } - } - - componentDidMount() { - this.observer = getResizeObserver(this.containerRef.current, this.handleResize); - this.handleResize(); - } - - componentWillUnmount() { - this.observer(); - } - - render(){ - const { width } = this.state; - return ( -
-
- - - - - { this.renderSocketBars() } - { this.renderCoresBars() } - { this.renderNodesBars() } - - -
-
- ) - } -} ``` ### Multi-color (unordered) responsive container This demonstrates monthly data with a bottom aligned legend and responsiveness for mobile. -```js -import { Chart, ChartArea, ChartAxis, ChartStack, ChartLegendTooltip, ChartThemeColor, createContainer } from '@patternfly/react-charts/victory'; -import { getResizeObserver } from '@patternfly/react-core'; - -class MultiColorChart extends React.Component { - constructor(props) { - super(props); - this.containerRef = createRef(); - this.observer = () => {}; - this.state = { - width: 0 - }; - this.handleResize = () => { - if(this.containerRef.current && this.containerRef.current.clientWidth){ - this.setState({ width: this.containerRef.current.clientWidth }); - } - }; - } - - componentDidMount() { - this.observer = getResizeObserver(this.containerRef.current, this.handleResize); - this.handleResize(); - } - - componentWillUnmount() { - this.observer(); - } +```ts file = "ChartStackMultiColorUnordered.tsx" - render() { - const { width } = this.state; - - // Note: Container order is important - const CursorVoronoiContainer = createContainer("voronoi", "cursor"); - const legendData = [{ childName: 'cats', name: 'Cats' }, { childName: 'dogs', name: 'Dogs' }, { childName: 'birds', name: 'Birds' }]; - - return ( -
-
- `${datum.y !== null ? datum.y : 'no data'}`} - labelComponent={ datum.x}/>} - mouseFollowTooltips - voronoiDimension="x" - voronoiPadding={50} - /> - } - legendData={legendData} - legendPosition="bottom-left" - height={225} - name="chart5" - padding={{ - bottom: 75, // Adjusted to accomodate legend - left: 50, - right: 50, - top: 50, - }} - maxDomain={{y: 30}} - themeColor={ChartThemeColor.multiUnordered} - width={width} - > - - - - - - - - -
-
- ); - } -} ``` ## Documentation diff --git a/packages/react-charts/src/victory/components/ChartStack/examples/ChartStackBasicRightLegend.tsx b/packages/react-charts/src/victory/components/ChartStack/examples/ChartStackBasicRightLegend.tsx new file mode 100644 index 00000000000..a135dff5b0d --- /dev/null +++ b/packages/react-charts/src/victory/components/ChartStack/examples/ChartStackBasicRightLegend.tsx @@ -0,0 +1,68 @@ +import { Chart, ChartAxis, ChartBar, ChartStack, ChartVoronoiContainer } from '@patternfly/react-charts/victory'; + +interface PetData { + name: string; + x: string; + y: number; +} + +export const ChartStackBasicRightLegend: React.FunctionComponent = () => { + const data1: PetData[] = [ + { name: 'Cats', x: '2015', y: 1 }, + { name: 'Cats', x: '2016', y: 2 }, + { name: 'Cats', x: '2017', y: 5 }, + { name: 'Cats', x: '2018', y: 3 } + ]; + const data2: PetData[] = [ + { name: 'Dogs', x: '2015', y: 2 }, + { name: 'Dogs', x: '2016', y: 1 }, + { name: 'Dogs', x: '2017', y: 7 }, + { name: 'Dogs', x: '2018', y: 4 } + ]; + const data3: PetData[] = [ + { name: 'Birds', x: '2015', y: 4 }, + { name: 'Birds', x: '2016', y: 4 }, + { name: 'Birds', x: '2017', y: 9 }, + { name: 'Birds', x: '2018', y: 7 } + ]; + const data4: PetData[] = [ + { name: 'Mice', x: '2015', y: 3 }, + { name: 'Mice', x: '2016', y: 3 }, + { name: 'Mice', x: '2017', y: 8 }, + { name: 'Mice', x: '2018', y: 5 } + ]; + + return ( +
+ `${datum.name}: ${datum.y}`} constrainToVisibleArea /> + } + domainPadding={{ x: [30, 25] }} + legendData={[{ name: 'Cats' }, { name: 'Dogs' }, { name: 'Birds' }, { name: 'Mice' }]} + legendOrientation="vertical" + legendPosition="right" + height={250} + name="chart1" + padding={{ + bottom: 50, + left: 50, + right: 200, // Adjusted to accommodate legend + top: 50 + }} + width={600} + > + + + + + + + + + +
+ ); +}; diff --git a/packages/react-charts/src/victory/components/ChartStack/examples/ChartStackBottomLegend.tsx b/packages/react-charts/src/victory/components/ChartStack/examples/ChartStackBottomLegend.tsx new file mode 100644 index 00000000000..3f5906a1a5c --- /dev/null +++ b/packages/react-charts/src/victory/components/ChartStack/examples/ChartStackBottomLegend.tsx @@ -0,0 +1,75 @@ +import { + Chart, + ChartAxis, + ChartBar, + ChartStack, + ChartThemeColor, + ChartVoronoiContainer +} from '@patternfly/react-charts/victory'; + +interface PetData { + name: string; + x: string; + y: number; +} + +export const ChartStackBottomLegend: React.FunctionComponent = () => { + const data1: PetData[] = [ + { name: 'Cats', x: '2015', y: 1 }, + { name: 'Cats', x: '2016', y: 2 }, + { name: 'Cats', x: '2017', y: 5 }, + { name: 'Cats', x: '2018', y: 3 } + ]; + const data2: PetData[] = [ + { name: 'Dogs', x: '2015', y: 2 }, + { name: 'Dogs', x: '2016', y: 1 }, + { name: 'Dogs', x: '2017', y: 7 }, + { name: 'Dogs', x: '2018', y: 4 } + ]; + const data3: PetData[] = [ + { name: 'Birds', x: '2015', y: 4 }, + { name: 'Birds', x: '2016', y: 4 }, + { name: 'Birds', x: '2017', y: 9 }, + { name: 'Birds', x: '2018', y: 7 } + ]; + const data4: PetData[] = [ + { name: 'Mice', x: '2015', y: 3 }, + { name: 'Mice', x: '2016', y: 3 }, + { name: 'Mice', x: '2017', y: 8 }, + { name: 'Mice', x: '2018', y: 5 } + ]; + + return ( +
+ `${datum.name}: ${datum.y}`} constrainToVisibleArea /> + } + domainPadding={{ x: [30, 25] }} + legendData={[{ name: 'Cats' }, { name: 'Dogs' }, { name: 'Birds' }, { name: 'Mice' }]} + legendPosition="bottom" + height={275} + name="chart2" + padding={{ + bottom: 75, // Adjusted to accommodate legend + left: 50, + right: 50, + top: 50 + }} + themeColor={ChartThemeColor.yellow} + width={450} + > + + + + + + + + + +
+ ); +}; diff --git a/packages/react-charts/src/victory/components/ChartStack/examples/ChartStackMonthlyResponsive.tsx b/packages/react-charts/src/victory/components/ChartStack/examples/ChartStackMonthlyResponsive.tsx new file mode 100644 index 00000000000..2cd320a132d --- /dev/null +++ b/packages/react-charts/src/victory/components/ChartStack/examples/ChartStackMonthlyResponsive.tsx @@ -0,0 +1,107 @@ +import { Chart, ChartAxis, ChartBar, ChartStack, ChartTooltip } from '@patternfly/react-charts/victory'; +import { getResizeObserver } from '@patternfly/react-core'; +import { useEffect, useRef, useState } from 'react'; + +interface Bar { + x: string; + y: number; +} + +export const ChartStackMonthlyResponsive: React.FunctionComponent = () => { + const containerRef = useRef(null); + const observer = useRef(() => {}); + const [width, setWidth] = useState(0); + + const handleResize = () => { + if (containerRef.current && containerRef.current.clientWidth) { + setWidth(containerRef.current.clientWidth); + } + }; + const bars: Bar[] = []; + for (let i = 1; i < 32; i++) { + bars.push({ x: `Aug. ${i}`, y: Math.floor(Math.random() * 6) + 1 }); + } + + const renderSocketBars = () => { + const socketBars = bars.map((tick, index) => ({ + key: index, + x: tick.x, + y: tick.y, + name: 'Sockets', + label: `${tick.x} Sockets: ${tick.y}` + })); + return } />; + }; + + const renderCoresBars = () => { + const coresBars = bars.map((tick, index) => ({ + key: index, + x: tick.x, + y: tick.y, + name: 'Cores', + label: `${tick.x} Cores: ${tick.y}` + })); + return } />; + }; + + const renderNodesBars = () => { + const nodesBars = bars.map((tick, index) => ({ + key: index, + x: tick.x, + y: tick.y, + name: 'Nodes', + label: `${tick.x} Nodes: ${tick.y}` + })); + return } />; + }; + + const getTickValues = (offset = 2) => { + const tickValues = []; + for (let i = 1; i < 32; i++) { + if (i % offset === 0) { + tickValues.push(`Aug. ${i}`); + } + } + return tickValues; + }; + + useEffect(() => { + observer.current = getResizeObserver(containerRef.current, handleResize); + handleResize(); + + return () => { + observer.current(); + }; + }, []); + + return ( +
+
+ + + + + {renderSocketBars()} + {renderCoresBars()} + {renderNodesBars()} + + +
+
+ ); +}; diff --git a/packages/react-charts/src/victory/components/ChartStack/examples/ChartStackMultiColorOrdered.tsx b/packages/react-charts/src/victory/components/ChartStack/examples/ChartStackMultiColorOrdered.tsx new file mode 100644 index 00000000000..39eb4222bfb --- /dev/null +++ b/packages/react-charts/src/victory/components/ChartStack/examples/ChartStackMultiColorOrdered.tsx @@ -0,0 +1,74 @@ +import { + Chart, + ChartBar, + ChartAxis, + ChartStack, + ChartThemeColor, + ChartTooltip +} from '@patternfly/react-charts/victory'; + +interface PetData { + name?: string; + x?: string; + y?: number; + label?: string; +} + +export const ChartStackMultiColorOrdered: React.FunctionComponent = () => { + const data1: PetData[] = [ + { name: 'Cats', x: '2015', y: 1, label: 'Cats: 1' }, + { name: 'Cats', x: '2016', y: 2, label: 'Cats: 2' }, + { name: 'Cats', x: '2017', y: 5, label: 'Cats: 5' }, + { name: 'Cats', x: '2018', y: 3, label: 'Cats: 3' } + ]; + const data2: PetData[] = [ + { name: 'Dogs', x: '2015', y: 2, label: 'Dogs: 2' }, + { name: 'Dogs', x: '2016', y: 1, label: 'Dogs: 1' }, + { name: 'Dogs', x: '2017', y: 7, label: 'Dogs: 7' }, + { name: 'Dogs', x: '2018', y: 4, label: 'Dogs: 4' } + ]; + const data3: PetData[] = [ + { name: 'Birds', x: '2015', y: 4, label: 'Birds: 4' }, + { name: 'Birds', x: '2016', y: 4, label: 'Birds: 4' }, + { name: 'Birds', x: '2017', y: 9, label: 'Birds: 9' }, + { name: 'Birds', x: '2018', y: 7, label: 'Birds: 7' } + ]; + const data4: PetData[] = [ + { name: 'Mice', x: '2015', y: 3, label: 'Mice: 3' }, + { name: 'Mice', x: '2016', y: 3, label: 'Mice: 3' }, + { name: 'Mice', x: '2017', y: 8, label: 'Mice: 8' }, + { name: 'Mice', x: '2018', y: 5, label: 'Mice: 5' } + ]; + const legendData: PetData[] = [{ name: 'Cats' }, { name: 'Dogs' }, { name: 'Birds' }, { name: 'Mice' }]; + + return ( +
+ + + + + } /> + } /> + } /> + } /> + + +
+ ); +}; diff --git a/packages/react-charts/src/victory/components/ChartStack/examples/ChartStackMultiColorUnordered.tsx b/packages/react-charts/src/victory/components/ChartStack/examples/ChartStackMultiColorUnordered.tsx new file mode 100644 index 00000000000..a714e23bde2 --- /dev/null +++ b/packages/react-charts/src/victory/components/ChartStack/examples/ChartStackMultiColorUnordered.tsx @@ -0,0 +1,114 @@ +import { + Chart, + ChartArea, + ChartAxis, + ChartStack, + ChartLegendTooltip, + ChartThemeColor, + createContainer +} from '@patternfly/react-charts/victory'; +import { getResizeObserver } from '@patternfly/react-core'; +import { useEffect, useRef, useState } from 'react'; + +interface Data { + x: string; + y: number; +} + +export const ChartStackMultiColorUnordered: React.FunctionComponent = () => { + const containerRef = useRef(null); + const observer = useRef(() => {}); + const [width, setWidth] = useState(0); + + const handleResize = () => { + if (containerRef.current && containerRef.current.clientWidth) { + setWidth(containerRef.current.clientWidth); + } + }; + + useEffect(() => { + observer.current = getResizeObserver(containerRef.current, handleResize); + handleResize(); + + return () => { + observer.current(); + }; + }, []); + + // Note: Container order is important + const CursorVoronoiContainer = createContainer('voronoi', 'cursor'); + const legendData = [ + { childName: 'cats', name: 'Cats' }, + { childName: 'dogs', name: 'Dogs' }, + { childName: 'birds', name: 'Birds' } + ]; + const data1: Data[] = [ + { x: 'Sunday', y: 6 }, + { x: 'Monday', y: 2 }, + { x: 'Tuesday', y: 8 }, + { x: 'Wednesday', y: 15 }, + { x: 'Thursday', y: 6 }, + { x: 'Friday', y: 2 }, + { x: 'Saturday', y: 0 } + ]; + const data2: Data[] = [ + { x: 'Sunday', y: 4 }, + { x: 'Monday', y: 5 }, + { x: 'Tuesday', y: 7 }, + { x: 'Wednesday', y: 6 }, + { x: 'Thursday', y: 10 }, + { x: 'Friday', y: 3 }, + { x: 'Saturday', y: 5 } + ]; + const data3: Data[] = [ + { x: 'Sunday', y: 8 }, + { x: 'Monday', y: 18 }, + { x: 'Tuesday', y: 14 }, + { x: 'Wednesday', y: 8 }, + { x: 'Thursday', y: 6 }, + { x: 'Friday', y: 8 }, + { x: 'Saturday', y: 12 } + ]; + + return ( +
+
+ `${datum.y !== null ? datum.y : 'no data'}`} + labelComponent={ datum.x} />} + mouseFollowTooltips + voronoiDimension="x" + voronoiPadding={50} + /> + } + legendData={legendData} + legendPosition="bottom-left" + height={225} + name="chart5" + padding={{ + bottom: 75, // Adjusted to accomodate legend + left: 50, + right: 50, + top: 50 + }} + maxDomain={{ y: 30 }} + themeColor={ChartThemeColor.multiUnordered} + width={width} + > + + + + + + + + +
+
+ ); +}; diff --git a/packages/react-charts/src/victory/components/ChartTheme/examples/ChartTheme.md b/packages/react-charts/src/victory/components/ChartTheme/examples/ChartTheme.md index 8b9d8dc4849..095131377d6 100644 --- a/packages/react-charts/src/victory/components/ChartTheme/examples/ChartTheme.md +++ b/packages/react-charts/src/victory/components/ChartTheme/examples/ChartTheme.md @@ -36,440 +36,48 @@ The examples below are based on the [Victory](https://formidable.com/open-source This demonstrates how to apply basic theme colors. -```js -import { Chart, ChartAxis, ChartGroup, ChartLine, ChartThemeColor, ChartVoronoiContainer } from '@patternfly/react-charts/victory'; +```ts file = "ChartThemeGreen.tsx" -
- `${datum.name}: ${datum.y}`} constrainToVisibleArea />} - legendData={[{ name: 'Cats' }, { name: 'Dogs', symbol: { type: 'dash' } }, { name: 'Birds' }, { name: 'Mice' }]} - legendPosition="bottom" - height={275} - maxDomain={{y: 10}} - minDomain={{y: 0}} - name="chart1" - padding={{ - bottom: 75, // Adjusted to accommodate legend - left: 50, - right: 50, - top: 50 - }} - themeColor={ChartThemeColor.green} - width={450} - > - - - - - - - - - -
``` ### Multi-color (ordered) This demonstrates how to apply theme colors for ordered charts like bar, donut, pie, and stack. -```js -import { ChartDonut, ChartThemeColor } from '@patternfly/react-charts/victory'; +```ts file = "ChartThemeMultiColorOrdered.tsx" -
- `${datum.x}: ${datum.y}%`} - legendData={[{ name: 'Cats: 35' }, { name: 'Dogs: 55' }, { name: 'Birds: 10' }]} - legendOrientation="vertical" - legendPosition="right" - name="chart2" - padding={{ - bottom: 20, - left: 20, - right: 140, // Adjusted to accommodate legend - top: 20 - }} - subTitle="Pets" - title="100" - themeColor={ChartThemeColor.multiOrdered} - width={350} - /> -
``` ### Multi color (unordered) This demonstrates how to apply theme colors for unordered charts like area, line, and sparkline. -```js -import { Chart, ChartArea, ChartAxis, ChartGroup, ChartThemeColor, ChartVoronoiContainer } from '@patternfly/react-charts/victory'; +```ts file = "ChartThemeMultiColorUnordered.tsx" -
- `${datum.name}: ${datum.y}`} constrainToVisibleArea />} - legendData={[{ name: 'Cats' }, { name: 'Dogs' }, { name: 'Birds' }]} - legendOrientation="vertical" - legendPosition="right" - height={200} - maxDomain={{y: 9}} - name="chart3" - padding={{ - bottom: 50, - left: 50, - right: 200, // Adjusted to accommodate legend - top: 50 - }} - themeColor={ChartThemeColor.multiUnordered} - width={800} - > - - - - - - - - -
``` ### Custom color scale This demonstrates an alternate way of applying a custom color scale and fill colors to individual charts. -```js -import { Chart, ChartAxis, ChartBar, ChartLegend, ChartStack, ChartThemeColor, ChartTooltip } from '@patternfly/react-charts/victory'; -import chart_color_blue_300 from '@patternfly/react-tokens/dist/esm/chart_color_blue_300'; -import chart_color_green_300 from '@patternfly/react-tokens/dist/esm/chart_color_green_300'; -import chart_color_yellow_300 from '@patternfly/react-tokens/dist/esm/chart_color_yellow_300'; -import chart_color_purple_300 from '@patternfly/react-tokens/dist/esm/chart_color_purple_300'; +```ts file = "ChartThemeCustomColorScale.tsx" -
- - } - legendPosition="bottom-left" - height={275} - name="chart4" - padding={{ - bottom: 75, // Adjusted to accommodate legend - left: 50, - right: 50, - top: 50 - }} - themeColor={ChartThemeColor.multiOrdered} - width={450} - > - - - - } - /> - } - /> - } - /> - } - /> - - -
``` ### Custom stroke color This demonstrates an alternate way of applying custom stroke and fill colors to a threshold chart. -```js -import { Chart, ChartAxis, ChartGroup, ChartLine, ChartThemeColor, ChartThreshold, ChartVoronoiContainer } from '@patternfly/react-charts/victory'; -import chart_color_blue_300 from '@patternfly/react-tokens/dist/esm/chart_color_blue_300'; +```ts file = "ChartThemeCustomStrokeColor.tsx" -
- `${datum.name}: ${datum.y}`} constrainToVisibleArea />} - legendData={[ - { name: 'Cats' }, - { name: 'Birds' }, - { name: 'Mice' }, - { name: 'Cats Threshold', symbol: { fill: chart_color_blue_300.var, type: 'threshold' }} - ]} - legendPosition="bottom" - height={275} - maxDomain={{y: 10}} - minDomain={{y: 0}} - name="chart5" - padding={{ - bottom: 75, // Adjusted to accommodate legend - left: 50, - right: 50, - top: 50 - }} - themeColor={ChartThemeColor.multiUnordered} - width={450} - > - - - - - - - - - -
``` ### Custom theme This demonstrates custom theme properties, which may be applied across multiple charts. -```js -import { Chart, ChartBar, ChartAxis, ChartGroup, ChartThemeColor, ChartVoronoiContainer, getCustomTheme } from '@patternfly/react-charts/victory'; -import chart_color_blue_300 from '@patternfly/react-tokens/dist/esm/chart_color_blue_300'; -import chart_color_green_300 from '@patternfly/react-tokens/dist/esm/chart_color_green_300'; -import chart_color_teal_300 from '@patternfly/react-tokens/dist/esm/chart_color_teal_300'; -import chart_color_yellow_300 from '@patternfly/react-tokens/dist/esm/chart_color_yellow_300'; - -class MultiColorChart extends React.Component { - constructor(props) { - super(props); - - // Colors - this.colorScale = [ - chart_color_blue_300.var, - chart_color_green_300.var, - chart_color_teal_300.var, - chart_color_yellow_300.var - ]; - - // Layout - this.layoutProps = { - padding: { - bottom: 50, - left: 50, - right: 200, // Adjusted to accommodate legend - top: 50 - } - }; - - // Victory theme properties only - this.themeProps = { - bar: { - colorScale: this.colorScale, - ...this.layoutProps, - }, - chart: { - colorScale: this.colorScale, - ...this.layoutProps, - }, - group: { - colorScale: this.colorScale, - ...this.layoutProps, - }, - legend: { - colorScale: this.colorScale - } - }; - - // Applies theme color and variant to base theme - this.myCustomTheme = getCustomTheme( - ChartThemeColor.default, - this.themeProps - ); - } +```ts file = "ChartThemeCustomTheme.tsx" - render() { - return ( -
- `${datum.name}: ${datum.y}`} constrainToVisibleArea />} - domain={{y: [0,9]}} - domainPadding={{ x: [30, 25] }} - legendData={[{ name: 'Cats' }, { name: 'Dogs' }, { name: 'Birds' }, { name: 'Mice' }]} - legendOrientation="vertical" - legendPosition="right" - height={250} - name="chart6" - theme={this.myCustomTheme} - width={600} - > - - - - - - - - - -
- ); - } -} ``` ## Documentation diff --git a/packages/react-charts/src/victory/components/ChartTheme/examples/ChartThemeCustomColorScale.tsx b/packages/react-charts/src/victory/components/ChartTheme/examples/ChartThemeCustomColorScale.tsx new file mode 100644 index 00000000000..bc40b1952c9 --- /dev/null +++ b/packages/react-charts/src/victory/components/ChartTheme/examples/ChartThemeCustomColorScale.tsx @@ -0,0 +1,109 @@ +import { + Chart, + ChartAxis, + ChartBar, + ChartLegend, + ChartStack, + ChartThemeColor, + ChartTooltip +} from '@patternfly/react-charts/victory'; +import chart_color_blue_300 from '@patternfly/react-tokens/dist/esm/chart_color_blue_300'; +import chart_color_green_300 from '@patternfly/react-tokens/dist/esm/chart_color_green_300'; +import chart_color_yellow_300 from '@patternfly/react-tokens/dist/esm/chart_color_yellow_300'; +import chart_color_purple_300 from '@patternfly/react-tokens/dist/esm/chart_color_purple_300'; + +interface PetData { + name?: string; + symbol?: { fill: string }; + x?: string; + y?: number; + label?: string; +} + +export const ChartThemeCustomColorScale: React.FunctionComponent = () => { + const data1: PetData[] = [ + { + name: 'Cats', + symbol: { fill: chart_color_blue_300.var } + }, + { + name: 'Dogs', + symbol: { fill: chart_color_yellow_300.var } + }, + { + name: 'Birds', + symbol: { fill: chart_color_green_300.var } + }, + { + name: 'Mice', + symbol: { fill: chart_color_purple_300.var } + } + ]; + + const data2: PetData[] = [ + { name: 'Cats', x: '2015', y: 1, label: 'Cats: 1' }, + { name: 'Cats', x: '2016', y: 2, label: 'Cats: 2' }, + { name: 'Cats', x: '2017', y: 5, label: 'Cats: 5' }, + { name: 'Cats', x: '2018', y: 3, label: 'Cats: 3' } + ]; + + const data3: PetData[] = [ + { name: 'Dogs', x: '2015', y: 2, label: 'Dogs: 2' }, + { name: 'Dogs', x: '2016', y: 1, label: 'Dogs: 1' }, + { name: 'Dogs', x: '2017', y: 7, label: 'Dogs: 7' }, + { name: 'Dogs', x: '2018', y: 4, label: 'Dogs: 4' } + ]; + + const data4: PetData[] = [ + { name: 'Birds', x: '2015', y: 4, label: 'Birds: 4' }, + { name: 'Birds', x: '2016', y: 4, label: 'Birds: 4' }, + { name: 'Birds', x: '2017', y: 9, label: 'Birds: 9' }, + { name: 'Birds', x: '2018', y: 7, label: 'Birds: 7' } + ]; + + const data5: PetData[] = [ + { name: 'Mice', x: '2015', y: 3, label: 'Mice: 3' }, + { name: 'Mice', x: '2016', y: 3, label: 'Mice: 3' }, + { name: 'Mice', x: '2017', y: 8, label: 'Mice: 8' }, + { name: 'Mice', x: '2018', y: 5, label: 'Mice: 5' } + ]; + + return ( +
+ } + legendPosition="bottom-left" + height={275} + name="chart4" + padding={{ + bottom: 75, // Adjusted to accommodate legend + left: 50, + right: 50, + top: 50 + }} + themeColor={ChartThemeColor.multiOrdered} + width={450} + > + + + + } /> + } /> + } /> + } /> + + +
+ ); +}; diff --git a/packages/react-charts/src/victory/components/ChartTheme/examples/ChartThemeCustomStrokeColor.tsx b/packages/react-charts/src/victory/components/ChartTheme/examples/ChartThemeCustomStrokeColor.tsx new file mode 100644 index 00000000000..ce4d86275cd --- /dev/null +++ b/packages/react-charts/src/victory/components/ChartTheme/examples/ChartThemeCustomStrokeColor.tsx @@ -0,0 +1,97 @@ +import { + Chart, + ChartAxis, + ChartGroup, + ChartLine, + ChartThemeColor, + ChartThreshold, + ChartVoronoiContainer +} from '@patternfly/react-charts/victory'; +import chart_color_blue_300 from '@patternfly/react-tokens/dist/esm/chart_color_blue_300'; + +interface PetData { + name?: string; + symbol?: { fill: string; type: string }; + x?: string; + y?: number; +} + +export const ChartThemeCustomStrokeColor: React.FunctionComponent = () => { + const legendData: PetData[] = [ + { name: 'Cats' }, + { name: 'Birds' }, + { name: 'Mice' }, + { name: 'Cats Threshold', symbol: { fill: chart_color_blue_300.var, type: 'threshold' } } + ]; + + const data1: PetData[] = [ + { name: 'Cats', x: '2015', y: 1 }, + { name: 'Cats', x: '2016', y: 2 }, + { name: 'Cats', x: '2017', y: 5 }, + { name: 'Cats', x: '2018', y: 3 } + ]; + + const data2: PetData[] = [ + { name: 'Birds', x: '2015', y: 3 }, + { name: 'Birds', x: '2016', y: 4 }, + { name: 'Birds', x: '2017', y: 9 }, + { name: 'Birds', x: '2018', y: 5 } + ]; + + const data3: PetData[] = [ + { name: 'Mice', x: '2015', y: 3 }, + { name: 'Mice', x: '2016', y: 3 }, + { name: 'Mice', x: '2017', y: 8 }, + { name: 'Mice', x: '2018', y: 7 } + ]; + + const data4: PetData[] = [ + { name: 'Cats Threshold', x: '2015', y: 5 }, + { name: 'Cats Threshold', x: '2016', y: 5 }, + { name: 'Cats Threshold', x: '2016', y: 6 }, + { name: 'Cats Threshold', x: '2017', y: 6 }, + { name: 'Cats Threshold', x: '2018', y: 6 } + ]; + + return ( +
+ `${datum.name}: ${datum.y}`} constrainToVisibleArea /> + } + legendData={legendData} + legendPosition="bottom" + height={275} + maxDomain={{ y: 10 }} + minDomain={{ y: 0 }} + name="chart5" + padding={{ + bottom: 75, // Adjusted to accommodate legend + left: 50, + right: 50, + top: 50 + }} + themeColor={ChartThemeColor.multiUnordered} + width={450} + > + + + + + + + + + +
+ ); +}; diff --git a/packages/react-charts/src/victory/components/ChartTheme/examples/ChartThemeCustomTheme.tsx b/packages/react-charts/src/victory/components/ChartTheme/examples/ChartThemeCustomTheme.tsx new file mode 100644 index 00000000000..425fd4dc36b --- /dev/null +++ b/packages/react-charts/src/victory/components/ChartTheme/examples/ChartThemeCustomTheme.tsx @@ -0,0 +1,119 @@ +import { + Chart, + ChartBar, + ChartAxis, + ChartGroup, + ChartThemeColor, + ChartVoronoiContainer, + getCustomTheme +} from '@patternfly/react-charts/victory'; +import chart_color_blue_300 from '@patternfly/react-tokens/dist/esm/chart_color_blue_300'; +import chart_color_green_300 from '@patternfly/react-tokens/dist/esm/chart_color_green_300'; +import chart_color_teal_300 from '@patternfly/react-tokens/dist/esm/chart_color_teal_300'; +import chart_color_yellow_300 from '@patternfly/react-tokens/dist/esm/chart_color_yellow_300'; + +interface PetData { + name?: string; + x?: string; + y?: number; +} + +export const ChartThemeCustomTheme: React.FunctionComponent = () => { + const colorScale = [ + chart_color_blue_300.var, + chart_color_green_300.var, + chart_color_teal_300.var, + chart_color_yellow_300.var + ]; + + const layoutProps = { + padding: { + bottom: 50, + left: 50, + right: 200, // Adjusted to accommodate legend + top: 50 + } + }; + + // Victory theme properties only + const themeProps = { + bar: { + colorScale, + ...layoutProps + }, + chart: { + colorScale, + ...layoutProps + }, + group: { + colorScale, + ...layoutProps + }, + legend: { + colorScale + } + }; + + // Applies theme color and variant to base theme + const myCustomTheme = getCustomTheme(ChartThemeColor.default, themeProps); + + const legendData: PetData[] = [{ name: 'Cats' }, { name: 'Dogs' }, { name: 'Birds' }, { name: 'Mice' }]; + + const data1: PetData[] = [ + { name: 'Cats', x: '2015', y: 1 }, + { name: 'Cats', x: '2016', y: 2 }, + { name: 'Cats', x: '2017', y: 5 }, + { name: 'Cats', x: '2018', y: 3 } + ]; + + const data2: PetData[] = [ + { name: 'Dogs', x: '2015', y: 2 }, + { name: 'Dogs', x: '2016', y: 1 }, + { name: 'Dogs', x: '2017', y: 7 }, + { name: 'Dogs', x: '2018', y: 4 } + ]; + + const data3: PetData[] = [ + { name: 'Birds', x: '2015', y: 4 }, + { name: 'Birds', x: '2016', y: 4 }, + { name: 'Birds', x: '2017', y: 9 }, + { name: 'Birds', x: '2018', y: 7 } + ]; + + const data4: PetData[] = [ + { name: 'Mice', x: '2015', y: 3 }, + { name: 'Mice', x: '2016', y: 3 }, + { name: 'Mice', x: '2017', y: 8 }, + { name: 'Mice', x: '2018', y: 5 } + ]; + + return ( +
+ `${datum.name}: ${datum.y}`} constrainToVisibleArea /> + } + domain={{ y: [0, 9] }} + domainPadding={{ x: [30, 25] }} + legendData={legendData} + legendOrientation="vertical" + legendPosition="right" + height={250} + name="chart6" + theme={myCustomTheme} + width={600} + > + + + + + + + + + +
+ ); +}; diff --git a/packages/react-charts/src/victory/components/ChartTheme/examples/ChartThemeGreen.tsx b/packages/react-charts/src/victory/components/ChartTheme/examples/ChartThemeGreen.tsx new file mode 100644 index 00000000000..59b3bb0b4c3 --- /dev/null +++ b/packages/react-charts/src/victory/components/ChartTheme/examples/ChartThemeGreen.tsx @@ -0,0 +1,94 @@ +import { + Chart, + ChartAxis, + ChartGroup, + ChartLine, + ChartThemeColor, + ChartVoronoiContainer +} from '@patternfly/react-charts/victory'; + +interface PetData { + name?: string; + symbol?: { type: string }; + x?: string; + y?: number; +} + +export const ChartThemeGreen: React.FunctionComponent = () => { + const legendData: PetData[] = [ + { name: 'Cats' }, + { name: 'Dogs', symbol: { type: 'dash' } }, + { name: 'Birds' }, + { name: 'Mice' } + ]; + + const data1: PetData[] = [ + { name: 'Cats', x: '2015', y: 1 }, + { name: 'Cats', x: '2016', y: 2 }, + { name: 'Cats', x: '2017', y: 5 }, + { name: 'Cats', x: '2018', y: 3 } + ]; + + const data2: PetData[] = [ + { name: 'Dogs', x: '2015', y: 2 }, + { name: 'Dogs', x: '2016', y: 1 }, + { name: 'Dogs', x: '2017', y: 7 }, + { name: 'Dogs', x: '2018', y: 4 } + ]; + + const data3: PetData[] = [ + { name: 'Birds', x: '2015', y: 3 }, + { name: 'Birds', x: '2016', y: 4 }, + { name: 'Birds', x: '2017', y: 9 }, + { name: 'Birds', x: '2018', y: 5 } + ]; + + const data4: PetData[] = [ + { name: 'Mice', x: '2015', y: 3 }, + { name: 'Mice', x: '2016', y: 3 }, + { name: 'Mice', x: '2017', y: 8 }, + { name: 'Mice', x: '2018', y: 7 } + ]; + + return ( +
+ `${datum.name}: ${datum.y}`} constrainToVisibleArea /> + } + legendData={legendData} + legendPosition="bottom" + height={275} + maxDomain={{ y: 10 }} + minDomain={{ y: 0 }} + name="chart1" + padding={{ + bottom: 75, // Adjusted to accommodate legend + left: 50, + right: 50, + top: 50 + }} + themeColor={ChartThemeColor.green} + width={450} + > + + + + + + + + + +
+ ); +}; diff --git a/packages/react-charts/src/victory/components/ChartTheme/examples/ChartThemeMultiColorOrdered.tsx b/packages/react-charts/src/victory/components/ChartTheme/examples/ChartThemeMultiColorOrdered.tsx new file mode 100644 index 00000000000..8727fbe9f74 --- /dev/null +++ b/packages/react-charts/src/victory/components/ChartTheme/examples/ChartThemeMultiColorOrdered.tsx @@ -0,0 +1,43 @@ +import { ChartDonut, ChartThemeColor } from '@patternfly/react-charts/victory'; + +interface PetData { + x?: string; + y?: number; + name?: string; +} + +export const ChartThemeMultiColorOrdered: React.FunctionComponent = () => { + const data: PetData[] = [ + { x: 'Cats', y: 35 }, + { x: 'Dogs', y: 55 }, + { x: 'Birds', y: 10 } + ]; + + const legendData: PetData[] = [{ name: 'Cats: 35' }, { name: 'Dogs: 55' }, { name: 'Birds: 10' }]; + + return ( +
+ `${datum.x}: ${datum.y}%`} + legendData={legendData} + legendOrientation="vertical" + legendPosition="right" + name="chart2" + padding={{ + bottom: 20, + left: 20, + right: 140, // Adjusted to accommodate legend + top: 20 + }} + subTitle="Pets" + title="100" + themeColor={ChartThemeColor.multiOrdered} + width={350} + /> +
+ ); +}; diff --git a/packages/react-charts/src/victory/components/ChartTheme/examples/ChartThemeMultiColorUnordered.tsx b/packages/react-charts/src/victory/components/ChartTheme/examples/ChartThemeMultiColorUnordered.tsx new file mode 100644 index 00000000000..1dcf6e38b9b --- /dev/null +++ b/packages/react-charts/src/victory/components/ChartTheme/examples/ChartThemeMultiColorUnordered.tsx @@ -0,0 +1,75 @@ +import { + Chart, + ChartArea, + ChartAxis, + ChartGroup, + ChartThemeColor, + ChartVoronoiContainer +} from '@patternfly/react-charts/victory'; + +interface PetData { + x?: string; + y?: number; + name?: string; +} + +export const ChartThemeMultiColorUnordered: React.FunctionComponent = () => { + const data1: PetData[] = [ + { name: 'Cats', x: '2015', y: 3 }, + { name: 'Cats', x: '2016', y: 4 }, + { name: 'Cats', x: '2017', y: 8 }, + { name: 'Cats', x: '2018', y: 6 } + ]; + + const data2: PetData[] = [ + { name: 'Dogs', x: '2015', y: 2 }, + { name: 'Dogs', x: '2016', y: 3 }, + { name: 'Dogs', x: '2017', y: 4 }, + { name: 'Dogs', x: '2018', y: 5 }, + { name: 'Dogs', x: '2019', y: 6 } + ]; + + const data3: PetData[] = [ + { name: 'Birds', x: '2015', y: 1 }, + { name: 'Birds', x: '2016', y: 2 }, + { name: 'Birds', x: '2017', y: 3 }, + { name: 'Birds', x: '2018', y: 2 }, + { name: 'Birds', x: '2019', y: 4 } + ]; + + const legendData: PetData[] = [{ name: 'Cats' }, { name: 'Dogs' }, { name: 'Birds' }]; + + return ( +
+ `${datum.name}: ${datum.y}`} constrainToVisibleArea /> + } + legendData={legendData} + legendOrientation="vertical" + legendPosition="right" + height={200} + maxDomain={{ y: 9 }} + name="chart3" + padding={{ + bottom: 50, + left: 50, + right: 200, // Adjusted to accommodate legend + top: 50 + }} + themeColor={ChartThemeColor.multiUnordered} + width={800} + > + + + + + + + + +
+ ); +}; diff --git a/packages/react-charts/src/victory/components/ChartThreshold/examples/ChartThreshold.md b/packages/react-charts/src/victory/components/ChartThreshold/examples/ChartThreshold.md index 5f393993846..1e21b77d3ea 100644 --- a/packages/react-charts/src/victory/components/ChartThreshold/examples/ChartThreshold.md +++ b/packages/react-charts/src/victory/components/ChartThreshold/examples/ChartThreshold.md @@ -25,6 +25,7 @@ import { import { getResizeObserver } from '@patternfly/react-core'; import chart_color_blue_300 from '@patternfly/react-tokens/dist/esm/chart_color_blue_300'; import chart_color_orange_300 from '@patternfly/react-tokens/dist/esm/chart_color_orange_300'; +import { useEffect, useRef, useState } from 'react'; ## Introduction @@ -35,146 +36,8 @@ The examples below are based on the [Victory](https://formidable.com/open-source ## Examples ### Multi-color (unordered) with responsive container -```js -import { - Chart, - ChartArea, - ChartAxis, - ChartLegend, - ChartGroup, - ChartThreshold, - ChartThemeColor, - ChartVoronoiContainer -} from '@patternfly/react-charts/victory'; -import { getResizeObserver } from '@patternfly/react-core'; -import chart_color_blue_300 from '@patternfly/react-tokens/dist/esm/chart_color_blue_300'; -import chart_color_orange_300 from '@patternfly/react-tokens/dist/esm/chart_color_orange_300'; - -class MultiColorChart extends React.Component { - constructor(props) { - super(props); - this.containerRef = createRef(); - this.observer = () => {}; - this.state = { - width: 0 - }; - this.handleResize = () => { - if (this.containerRef.current && this.containerRef.current.clientWidth) { - this.setState({ width: this.containerRef.current.clientWidth }); - } - }; - } - - componentDidMount() { - this.observer = getResizeObserver(this.containerRef.current, this.handleResize); - this.handleResize(); - } - - componentWillUnmount() { - this.observer(); - } - - render() { - const { width } = this.state; - const itemsPerRow = width > 650 ? 4 : 2; +```ts file = "ChartThresholdMultiColorOrdered.tsx" - return ( -
-
- `${datum.name}: ${datum.y}`} - constrainToVisibleArea - /> - } - legendPosition="bottom-left" - legendComponent={ - - } - height={250} - padding={{ - bottom: 100, // Adjusted to accomodate legend - left: 50, - right: 50, - top: 50 - }} - maxDomain={{ y: 9 }} - name="chart1" - themeColor={ChartThemeColor.multiUnordered} - width={width} - > - - - - - - - - - -
-
- ); - } -} ``` ## Documentation diff --git a/packages/react-charts/src/victory/components/ChartThreshold/examples/ChartThresholdMultiColorOrdered.tsx b/packages/react-charts/src/victory/components/ChartThreshold/examples/ChartThresholdMultiColorOrdered.tsx new file mode 100644 index 00000000000..1d51e58eccf --- /dev/null +++ b/packages/react-charts/src/victory/components/ChartThreshold/examples/ChartThresholdMultiColorOrdered.tsx @@ -0,0 +1,136 @@ +import { + Chart, + ChartArea, + ChartAxis, + ChartLegend, + ChartGroup, + ChartThreshold, + ChartThemeColor, + ChartVoronoiContainer +} from '@patternfly/react-charts/victory'; +import { getResizeObserver } from '@patternfly/react-core'; +import chart_color_blue_300 from '@patternfly/react-tokens/dist/esm/chart_color_blue_300'; +import chart_color_orange_300 from '@patternfly/react-tokens/dist/esm/chart_color_orange_300'; +import { useEffect, useRef, useState } from 'react'; + +interface PetData { + name?: string; + symbol?: { fill: string; type: string }; + x?: number; + y?: number; +} + +export const ChartThresholdMultiColorOrdered: React.FunctionComponent = () => { + const containerRef = useRef(null); + const observer = useRef(() => {}); + const [width, setWidth] = useState(0); + + const handleResize = () => { + if (containerRef.current && containerRef.current.clientWidth) { + setWidth(containerRef.current.clientWidth); + } + }; + + useEffect(() => { + observer.current = getResizeObserver(containerRef.current, handleResize); + handleResize(); + + return () => { + observer.current(); + }; + }, []); + + const itemsPerRow = width > 650 ? 4 : 2; + + const data1: PetData[] = [ + { name: 'Cats' }, + { name: 'Birds' }, + { + name: 'Cats Threshold', + symbol: { fill: chart_color_blue_300.var, type: 'threshold' } + }, + { + name: 'Birds Threshold', + symbol: { fill: chart_color_orange_300.var, type: 'threshold' } + } + ]; + + const data2: PetData[] = [ + { name: 'Cats', x: 1, y: 3 }, + { name: 'Cats', x: 2, y: 4 }, + { name: 'Cats', x: 3, y: 8 }, + { name: 'Cats', x: 4, y: 6 } + ]; + + const data3: PetData[] = [ + { name: 'Birds', x: 1, y: 2 }, + { name: 'Birds', x: 2, y: 3 }, + { name: 'Birds', x: 3, y: 4 }, + { name: 'Birds', x: 4, y: 5 }, + { name: 'Birds', x: 5, y: 6 } + ]; + + const data4: PetData[] = [ + { name: 'Cats Threshold', x: 0, y: 4 }, + { name: 'Cats Threshold', x: 3, y: 4 }, + { name: 'Cats Threshold', x: 3, y: 6 }, + { name: 'Cats Threshold', x: 5, y: 6 } + ]; + + const data5: PetData[] = [ + { name: 'Birds Threshold', x: 0, y: 2 }, + { name: 'Birds Threshold', x: 2, y: 2 }, + { name: 'Birds Threshold', x: 2, y: 3 }, + { name: 'Birds Threshold', x: 5, y: 3 } + ]; + + return ( +
+
+ `${datum.name}: ${datum.y}`} constrainToVisibleArea /> + } + legendPosition="bottom-left" + legendComponent={} + height={250} + padding={{ + bottom: 100, // Adjusted to accomodate legend + left: 50, + right: 50, + top: 50 + }} + maxDomain={{ y: 9 }} + name="chart1" + themeColor={ChartThemeColor.multiUnordered} + width={width} + > + + + + + + + + + +
+
+ ); +}; diff --git a/packages/react-charts/src/victory/components/ChartTooltip/examples/ChartTooltip.md b/packages/react-charts/src/victory/components/ChartTooltip/examples/ChartTooltip.md index 5950df0c986..8a67a44fb26 100644 --- a/packages/react-charts/src/victory/components/ChartTooltip/examples/ChartTooltip.md +++ b/packages/react-charts/src/victory/components/ChartTooltip/examples/ChartTooltip.md @@ -5,7 +5,7 @@ propComponents: ['ChartTooltip'] hideDarkMode: true --- -import { createRef } from 'react'; +import { useRef, useState, useEffect } from 'react'; import { Chart, ChartArea, @@ -48,847 +48,86 @@ The examples below are based on the [Victory](https://formidable.com/open-source This demonstrates how to use a voronoi container to display tooltips. -```js -import { Chart, ChartArea, ChartAxis, ChartGroup, ChartVoronoiContainer } from '@patternfly/react-charts/victory'; - -
- `${datum.name}: ${datum.y}`} constrainToVisibleArea />} - legendData={[{ name: 'Cats' }, { name: 'Dogs' }, { name: 'Birds' }]} - legendOrientation="vertical" - legendPosition="right" - height={200} - maxDomain={{y: 9}} - name="chart1" - padding={{ - bottom: 50, - left: 50, - right: 200, // Adjusted to accommodate legend - top: 50 - }} - width={800} - > - - - - - - - - -
+```ts file = "ChartTooltipVoronoi.tsx" + ``` ### Combined cursor and voronoi containers This demonstrates how to combine cursor and voronoi containers to display tooltips along with a vertical cursor. -```js -import { Chart, ChartAxis, ChartGroup, ChartLine, ChartThemeColor, createContainer } from '@patternfly/react-charts/victory'; - -class CombinedCursorVoronoiContainer extends React.Component { - render() { - // Note: Container order is important - const CursorVoronoiContainer = createContainer("voronoi", "cursor"); - - return ( -
- `${datum.name}: ${datum.y}`} - mouseFollowTooltips - voronoiDimension="x" - voronoiPadding={50} - /> - } - legendData={[{ name: 'Cats' }, { name: 'Dogs', symbol: { type: 'dash' } }, { name: 'Birds' }, { name: 'Mice' }]} - legendPosition="bottom" - height={275} - maxDomain={{y: 10}} - minDomain={{y: 0}} - name="chart2" - padding={{ - bottom: 75, // Adjusted to accommodate legend - left: 50, - right: 50, - top: 50 - }} - themeColor={ChartThemeColor.orange} - width={450} - > - - - - - - - - - -
- ); - } -} +```ts file = "ChartTooltipCombinedCursorVoronoi.tsx" + ``` ### Embedded legend This demonstrates how to embed a legend within a tooltip. Combining cursor and voronoi containers is required to display tooltips with a vertical cursor. -```js -import { Chart, ChartAxis, ChartGroup, ChartLegendTooltip, ChartLine, ChartThemeColor, createContainer } from '@patternfly/react-charts/victory'; - -class EmbeddedLegend extends React.Component { - render() { - // Note: Container order is important - const CursorVoronoiContainer = createContainer("voronoi", "cursor"); - const legendData = [{ childName: 'cats', name: 'Cats' }, { childName: 'dogs', name: 'Dogs', symbol: { type: 'dash' }}, { childName: 'birds', name: 'Birds' }, { childName: 'mice', name: 'Mice' }]; - - return ( -
- `${datum.y !== null ? datum.y : 'no data'}`} - labelComponent={ datum.x}/>} - mouseFollowTooltips - voronoiDimension="x" - voronoiPadding={50} - /> - } - legendData={legendData} - legendPosition="bottom" - height={275} - maxDomain={{y: 10}} - minDomain={{y: 0}} - name="chart3" - padding={{ - bottom: 75, // Adjusted to accommodate legend - left: 50, - right: 50, - top: 50 - }} - themeColor={ChartThemeColor.green} - width={450} - > - - - - - - - - - -
- ); - } -} +```ts file = "ChartTooltipEmbeddedLegend.tsx" + ``` ### Embedded HTML This demonstrates how to embed HTML within a tooltip. Combining cursor and voronoi containers is required to display tooltips with a vertical cursor. -```js -import { Chart, ChartArea, ChartAxis, ChartCursorTooltip, ChartGroup, ChartPoint, ChartThemeColor, createContainer } from '@patternfly/react-charts/victory'; - -class EmbeddedHtml extends React.Component { - constructor(props) { - super(props); - this.baseStyles = { - color: '#f0f0f0', - fontFamily: '"Red Hat Text", "RedHatText", "Noto Sans Arabic", "Noto Sans Hebrew", "Noto Sans JP", "Noto Sans KR", "Noto Sans Malayalam", "Noto Sans SC", "Noto Sans TC", "Noto Sans Thai", Helvetica, Arial, sans-serif', - fontSize: '14px' - }; - } - - render() { - // Note: Container order is important - const CursorVoronoiContainer = createContainer("voronoi", "cursor"); - const legendData = [{ name: 'Cats' }, { name: 'Dogs' }, { name: 'Birds' }]; - - // Custom HTML component to create a legend layout - const HtmlLegendContent = ({datum, legendData, text, theme, title, x, y, ...rest}) => ( - - - - - - - - - - {text.map((val, index) => ( - - - - - - ))} - -
{title(datum)}
- - - - { - - } - - - - {legendData[index].name}{val}
-
-
- ); - - return ( -
- `${datum.y !== null ? datum.y : 'no data'}`} - labelComponent={ - width > center.x + flyoutWidth + 10 ? offset : -offset}} - // flyoutComponent={} - flyoutHeight={110} - flyoutWidth={({ datum }) => datum.y === null ? 160 : 125 } - labelComponent={ datum.x} />} - /> - } - mouseFollowTooltips - voronoiDimension="x" - voronoiPadding={50} - /> - } - legendData={legendData} - legendPosition="bottom-left" - height={225} - name="chart4" - padding={{ - bottom: 75, // Adjusted to accommodate legend - left: 50, - right: 50, - top: 50, - }} - maxDomain={{y: 9}} - themeColor={ChartThemeColor.multiUnordered} - width={650} - > - - - - - - - - -
- ); - } -} +```ts file = "ChartTooltipEmbeddedHtml.tsx" + ``` ### Embedded legend with custom font size This demonstrates how to embed a legend within a tooltip, but with a custom font size. Combining cursor and voronoi containers is required to display tooltips with a vertical cursor. -```js -import { Chart, ChartAxis, ChartGroup, ChartLegendTooltip, ChartLegend, ChartLine, ChartLegendTooltipContent, ChartLegendTooltipLabel, ChartThemeColor, createContainer } from '@patternfly/react-charts/victory'; - -class EmbeddedLegendAlt extends React.Component { - render() { - // Note: Container order is important - const CursorVoronoiContainer = createContainer("voronoi", "cursor"); - const legendData = [{ childName: 'cats', name: 'Cats' }, { childName: 'dogs', name: 'Dogs', symbol: { type: 'dash' }}, { childName: 'birds', name: 'Birds' }, { childName: 'mice', name: 'Mice' }]; - - const legend = ; - const legendTooltipLabel = ; - const legendTooltipContent = ; - - return ( -
- `${datum.y !== null ? datum.y : 'no data'}`} - labelComponent={ datum.x} />} - mouseFollowTooltips - voronoiDimension="x" - voronoiPadding={50} - /> - } - legendData={legendData} - legendPosition="bottom" - height={275} - maxDomain={{y: 10}} - minDomain={{y: 0}} - name="chart5" - padding={{ - bottom: 75, // Adjusted to accommodate legend - left: 50, - right: 50, - top: 50 - }} - themeColor={ChartThemeColor.yellow} - width={450} - > - - - - - - - - - -
- ); - } -} +```ts file = "ChartTooltipEmbeddedCustomFontSize.tsx" + ``` ### Data label This demonstrates an alternate way of applying tooltips using data labels. -```js -import { Chart, ChartAxis, ChartBar, ChartStack, ChartThemeColor, ChartTooltip } from '@patternfly/react-charts/victory'; - -
- - - - - } - /> - } - /> - } - /> - } - /> - - -
+```ts file = "ChartTooltipDataLabel.tsx" + ``` ### Fixed tooltip This demonstrates how to adjust the tooltip position and label radius -```js -import { ChartDonut, ChartThemeColor, ChartTooltip } from '@patternfly/react-charts/victory'; - -
- } - labelRadius={46} - labels={({ datum }) => `${datum.x}: ${datum.y}%`} - name="chart5" - subTitle="Pets" - title="100" - themeColor={ChartThemeColor.teal} - width={150} - /> -
+```ts file = "ChartTooltipFixed.tsx" + ``` ### Legend This demonstrates an approach for applying tooltips to a legend using a custom legend label component. -```js -import { ChartLabel, ChartLegend, ChartPie, ChartThemeColor } from '@patternfly/react-charts/victory'; -import { Tooltip } from '@patternfly/react-core'; - -class TooltipPieChart extends React.Component { - constructor(props) { - super(props); - - // Custom legend label component - // Note: Tooltip wraps children with a div tag, so we add a reference to ChartLabel instead - this.LegendLabel = ({datum, ...rest}) => { - const ref = createRef(); - return ( - - - - - ); - } - - // Custom legend component - this.getLegend = (legendData) => ( - } - /> - ); - } - - render() { - return ( -
- `${datum.x}: ${datum.y}`} - legendComponent={this.getLegend([ - { name: 'Cats: 35' }, - { name: 'Dogs: 55' }, - { name: 'Birds: 10' } - ])} - legendPosition="bottom" - name="chart7" - padding={{ - bottom: 65, - left: 20, - right: 20, - top: 20 - }} - themeColor={ChartThemeColor.multiOrdered} - width={300} - /> -
- ); - } -} +```ts file = "ChartTooltipLegend.tsx" + ``` ### Left aligned This demonstrates how to customize tooltip label alignment using theme properties. -```js -import { Chart, ChartAxis, ChartGroup, ChartLine, ChartThemeColor, ChartVoronoiContainer, getCustomTheme } from '@patternfly/react-charts/victory'; - -class TooltipThemeChart extends React.Component { - constructor(props) { - super(props); - - // Victory theme properties only - this.themeProps = { - voronoi: { - style: { - labels: { - textAnchor: 'start' // Align tooltip labels left - } - } - } - }; - - // Applies theme color and variant to base theme - this.myCustomTheme = getCustomTheme( - ChartThemeColor.default, - this.themeProps - ); - } - - render() { - return ( -
- `${datum.name}: ${datum.y}`} constrainToVisibleArea voronoiDimension="x"/>} - legendData={[{ name: 'Cats' }, { name: 'Dogs', symbol: { type: 'dash' } }, { name: 'Birds' }, { name: 'Mice' }]} - legendOrientation="vertical" - legendPosition="right" - height={250} - maxDomain={{y: 10}} - minDomain={{y: 0}} - name="chart8" - padding={{ - bottom: 50, - left: 50, - right: 200, // Adjusted to accommodate legend - top: 50 - }} - theme={this.myCustomTheme} - width={600} - > - - - - - - - - - -
- ); - } -} +```ts file = "ChartTooltipLeftAligned.tsx" + ``` ### CSS overflow This demonstrates an alternate way of applying tooltips using CSS overflow instead of constrainToVisibleArea. -```js -import { ChartArea, ChartGroup, ChartLabel, ChartThemeColor, ChartVoronoiContainer } from '@patternfly/react-charts/victory'; - -// Workaround for documentation-framework issue https://github.com/patternfly/patternfly-react/issues/11455 -const sheet = (() => { - var style = document.createElement("style"); - document.head.appendChild(style); - return style.sheet; -})(); - -sheet.insertRule(".ws-react-charts-tooltip-overflow { margin-left: 50px; margin-top: 50px; height: 135px; }", sheet.cssRules.length); -sheet.insertRule(".ws-react-charts-tooltip-overflow svg { overflow: visible; }", sheet.cssRules.length); - -
-
- `${datum.name}: ${datum.y}`} />} - height={100} - maxDomain={{y: 9}} - name="chart9" - padding={0} - themeColor={ChartThemeColor.green} - width={400} - > - - - -
-
+```ts file = "ChartTooltipCssOverflow.tsx" + ``` ### Wrapped chart This demonstrates an alternate way of applying tooltips by wrapping charts with the Tooltip component. -```js -import { ChartDonutThreshold, ChartDonutUtilization } from '@patternfly/react-charts/victory'; -import { Button, Tooltip, TooltipPosition } from '@patternfly/react-core'; - -class TooltipChart extends React.Component { - constructor(props) { - super(props); - this.state = { - isVisible: false - }; - this.showTooltip = () => { - this.setState({ isVisible: !this.state.isVisible }); - }; - } - - render() { - const { isVisible } = this.state; - - return ( -
-
- My custom tooltip
} isVisible={isVisible} position={TooltipPosition.right} trigger="manual"> - null} - name="chart10" - > - null} - subTitle="of 100 GBps" - title="45%" - /> - - -
-
- -
- - ); - } -} +```ts file = "ChartTooltipWrappedChart.tsx" + ``` ## Documentation diff --git a/packages/react-charts/src/victory/components/ChartTooltip/examples/ChartTooltipCombinedCursorVoronoi.tsx b/packages/react-charts/src/victory/components/ChartTooltip/examples/ChartTooltipCombinedCursorVoronoi.tsx new file mode 100644 index 00000000000..763610b524d --- /dev/null +++ b/packages/react-charts/src/victory/components/ChartTooltip/examples/ChartTooltipCombinedCursorVoronoi.tsx @@ -0,0 +1,102 @@ +import { + Chart, + ChartAxis, + ChartGroup, + ChartLine, + ChartThemeColor, + createContainer +} from '@patternfly/react-charts/victory'; + +interface PetData { + name?: string; + symbol?: { type: string }; + x?: string; + y?: number; +} + +export const ChartTooltipCombinedCursorVoronoi: React.FunctionComponent = () => { + // Note: Container order is important + const CursorVoronoiContainer = createContainer('voronoi', 'cursor'); + const legendData: PetData[] = [ + { name: 'Cats' }, + { name: 'Dogs', symbol: { type: 'dash' } }, + { name: 'Birds' }, + { name: 'Mice' } + ]; + + const data1: PetData[] = [ + { name: 'Cats', x: '2015', y: 1 }, + { name: 'Cats', x: '2016', y: 2 }, + { name: 'Cats', x: '2017', y: 5 }, + { name: 'Cats', x: '2018', y: 3 } + ]; + + const data2: PetData[] = [ + { name: 'Dogs', x: '2015', y: 2 }, + { name: 'Dogs', x: '2016', y: 1 }, + { name: 'Dogs', x: '2017', y: 7 }, + { name: 'Dogs', x: '2018', y: 4 } + ]; + + const data3: PetData[] = [ + { name: 'Birds', x: '2015', y: 3 }, + { name: 'Birds', x: '2016', y: 4 }, + { name: 'Birds', x: '2017', y: 9 }, + { name: 'Birds', x: '2018', y: 5 } + ]; + + const data4: PetData[] = [ + { name: 'Mice', x: '2015', y: 3 }, + { name: 'Mice', x: '2016', y: 3 }, + { name: 'Mice', x: '2017', y: 8 }, + { name: 'Mice', x: '2018', y: 7 } + ]; + + return ( +
+ `${datum.name}: ${datum.y}`} + mouseFollowTooltips + voronoiDimension="x" + voronoiPadding={50} + /> + } + legendData={legendData} + legendPosition="bottom" + height={275} + maxDomain={{ y: 10 }} + minDomain={{ y: 0 }} + name="chart2" + padding={{ + bottom: 75, // Adjusted to accommodate legend + left: 50, + right: 50, + top: 50 + }} + themeColor={ChartThemeColor.orange} + width={450} + > + + + + + + + + + +
+ ); +}; diff --git a/packages/react-charts/src/victory/components/ChartTooltip/examples/ChartTooltipCssOverflow.tsx b/packages/react-charts/src/victory/components/ChartTooltip/examples/ChartTooltipCssOverflow.tsx new file mode 100644 index 00000000000..3933f0deb34 --- /dev/null +++ b/packages/react-charts/src/victory/components/ChartTooltip/examples/ChartTooltipCssOverflow.tsx @@ -0,0 +1,58 @@ +import { + ChartArea, + ChartGroup, + ChartLabel, + ChartThemeColor, + ChartVoronoiContainer +} from '@patternfly/react-charts/victory'; +import { useEffect } from 'react'; + +interface PetData { + name: string; + x: string; + y: number; +} + +export const ChartTooltipCssOverflow: React.FunctionComponent = () => { + // Workaround for documentation-framework issue https://github.com/patternfly/patternfly-react/issues/11455 + useEffect(() => { + const sheet = (() => { + const style = document.createElement('style'); + document.head.appendChild(style); + return style.sheet; + })(); + + sheet.insertRule( + '.ws-react-charts-tooltip-overflow { margin-left: 50px; margin-top: 50px; height: 135px; }', + sheet.cssRules.length + ); + sheet.insertRule('.ws-react-charts-tooltip-overflow svg { overflow: visible; }', sheet.cssRules.length); + }, []); + + const data: PetData[] = [ + { name: 'Cats', x: '2015', y: 3 }, + { name: 'Cats', x: '2016', y: 4 }, + { name: 'Cats', x: '2017', y: 8 }, + { name: 'Cats', x: '2018', y: 6 } + ]; + return ( +
+
+ `${datum.name}: ${datum.y}`} />} + height={100} + maxDomain={{ y: 9 }} + name="chart9" + padding={0} + themeColor={ChartThemeColor.green} + width={400} + > + + + +
+
+ ); +}; diff --git a/packages/react-charts/src/victory/components/ChartTooltip/examples/ChartTooltipDataLabel.tsx b/packages/react-charts/src/victory/components/ChartTooltip/examples/ChartTooltipDataLabel.tsx new file mode 100644 index 00000000000..f834f852f83 --- /dev/null +++ b/packages/react-charts/src/victory/components/ChartTooltip/examples/ChartTooltipDataLabel.tsx @@ -0,0 +1,77 @@ +import { + Chart, + ChartAxis, + ChartBar, + ChartStack, + ChartThemeColor, + ChartTooltip +} from '@patternfly/react-charts/victory'; + +interface PetData { + name?: string; + x?: string; + y?: number; + label?: string; +} + +export const ChartTooltipDataLabel: React.FunctionComponent = () => { + const legendData: PetData[] = [{ name: 'Cats' }, { name: 'Dogs' }, { name: 'Birds' }, { name: 'Mice' }]; + const data1: PetData[] = [ + { name: 'Cats', x: '2015', y: 1, label: 'Cats: 1' }, + { name: 'Cats', x: '2016', y: 2, label: 'Cats: 2' }, + { name: 'Cats', x: '2017', y: 5, label: 'Cats: 5' }, + { name: 'Cats', x: '2018', y: 3, label: 'Cats: 3' } + ]; + + const data2: PetData[] = [ + { name: 'Dogs', x: '2015', y: 2, label: 'Dogs: 2' }, + { name: 'Dogs', x: '2016', y: 1, label: 'Dogs: 1' }, + { name: 'Dogs', x: '2017', y: 7, label: 'Dogs: 7' }, + { name: 'Dogs', x: '2018', y: 4, label: 'Dogs: 4' } + ]; + + const data3: PetData[] = [ + { name: 'Birds', x: '2015', y: 4, label: 'Birds: 4' }, + { name: 'Birds', x: '2016', y: 4, label: 'Birds: 4' }, + { name: 'Birds', x: '2017', y: 9, label: 'Birds: 9' }, + { name: 'Birds', x: '2018', y: 7, label: 'Birds: 7' } + ]; + + const data4: PetData[] = [ + { name: 'Mice', x: '2015', y: 3, label: 'Mice: 3' }, + { name: 'Mice', x: '2016', y: 3, label: 'Mice: 3' }, + { name: 'Mice', x: '2017', y: 8, label: 'Mice: 8' }, + { name: 'Mice', x: '2018', y: 5, label: 'Mice: 5' } + ]; + + return ( +
+ + + + + } /> + } /> + } /> + } /> + + +
+ ); +}; diff --git a/packages/react-charts/src/victory/components/ChartTooltip/examples/ChartTooltipEmbeddedCustomFontSize.tsx b/packages/react-charts/src/victory/components/ChartTooltip/examples/ChartTooltipEmbeddedCustomFontSize.tsx new file mode 100644 index 00000000000..35e09573ed4 --- /dev/null +++ b/packages/react-charts/src/victory/components/ChartTooltip/examples/ChartTooltipEmbeddedCustomFontSize.tsx @@ -0,0 +1,121 @@ +import { + Chart, + ChartAxis, + ChartGroup, + ChartLegendTooltip, + ChartLegend, + ChartLine, + ChartLegendTooltipContent, + ChartLegendTooltipLabel, + ChartThemeColor, + createContainer +} from '@patternfly/react-charts/victory'; + +interface PetData { + childName?: string; + name?: string; + symbol?: { type: string }; + x?: string; + y?: number | null; +} + +export const ChartTooltipEmbeddedLegendFont: React.FunctionComponent = () => { + // Note: Container order is important + const CursorVoronoiContainer = createContainer('voronoi', 'cursor'); + const legendData: PetData[] = [ + { childName: 'cats', name: 'Cats' }, + { childName: 'dogs', name: 'Dogs', symbol: { type: 'dash' } }, + { childName: 'birds', name: 'Birds' }, + { childName: 'mice', name: 'Mice' } + ]; + + const legend = ; + const legendTooltipLabel = ; + const legendTooltipContent = ( + + ); + + const data1: PetData[] = [ + { name: 'Cats', x: '2015', y: 1 }, + { name: 'Cats', x: '2016', y: 2 }, + { name: 'Cats', x: '2017', y: 5 }, + { name: 'Cats', x: '2018', y: 3 } + ]; + + const data2: PetData[] = [ + { name: 'Dogs', x: '2015', y: 2 }, + { name: 'Dogs', x: '2016', y: 1 }, + { name: 'Dogs', x: '2017', y: 7 }, + { name: 'Dogs', x: '2018', y: 4 } + ]; + + const data3: PetData[] = [ + { name: 'Birds', x: '2015', y: 3 }, + { name: 'Birds', x: '2016', y: 4 }, + { name: 'Birds', x: '2017', y: 9 }, + { name: 'Birds', x: '2018', y: 5 } + ]; + + const data4: PetData[] = [ + { name: 'Mice', x: '2015', y: 3 }, + { name: 'Mice', x: '2016', y: null }, + { name: 'Mice', x: '2017', y: 8 }, + { name: 'Mice', x: '2018', y: 7 } + ]; + + return ( +
+ `${datum.y !== null ? datum.y : 'no data'}`} + labelComponent={ + datum.x} + /> + } + mouseFollowTooltips + voronoiDimension="x" + voronoiPadding={50} + /> + } + legendData={legendData} + legendPosition="bottom" + height={275} + maxDomain={{ y: 10 }} + minDomain={{ y: 0 }} + name="chart5" + padding={{ + bottom: 75, // Adjusted to accommodate legend + left: 50, + right: 50, + top: 50 + }} + themeColor={ChartThemeColor.yellow} + width={450} + > + + + + + + + + + +
+ ); +}; diff --git a/packages/react-charts/src/victory/components/ChartTooltip/examples/ChartTooltipEmbeddedHtml.tsx b/packages/react-charts/src/victory/components/ChartTooltip/examples/ChartTooltipEmbeddedHtml.tsx new file mode 100644 index 00000000000..d339f2fc868 --- /dev/null +++ b/packages/react-charts/src/victory/components/ChartTooltip/examples/ChartTooltipEmbeddedHtml.tsx @@ -0,0 +1,149 @@ +import { + Chart, + ChartArea, + ChartAxis, + ChartCursorTooltip, + ChartGroup, + ChartPoint, + ChartThemeColor, + createContainer +} from '@patternfly/react-charts/victory'; + +interface PetData { + name?: string; + x?: string; + y?: number | null; +} + +export const ChartTooltipEmbeddedHtml: React.FunctionComponent = () => { + const baseStyles = { + color: '#f0f0f0', + fontFamily: + '"Red Hat Text", "RedHatText", "Noto Sans Arabic", "Noto Sans Hebrew", "Noto Sans JP", "Noto Sans KR", "Noto Sans Malayalam", "Noto Sans SC", "Noto Sans TC", "Noto Sans Thai", Helvetica, Arial, sans-serif', + fontSize: '14px' + }; + + // Note: Container order is important + const CursorVoronoiContainer = createContainer('voronoi', 'cursor'); + const legendData: PetData[] = [{ name: 'Cats' }, { name: 'Dogs' }, { name: 'Birds' }]; + + const data1: PetData[] = [ + { name: 'Cats', x: '2015', y: 3 }, + { name: 'Cats', x: '2016', y: 4 }, + { name: 'Cats', x: '2017', y: 8 }, + { name: 'Cats', x: '2018', y: 6 }, + { name: 'Cats', x: '2019', y: null } + ]; + + const data2: PetData[] = [ + { name: 'Dogs', x: '2015', y: 2 }, + { name: 'Dogs', x: '2016', y: 3 }, + { name: 'Dogs', x: '2017', y: 4 }, + { name: 'Dogs', x: '2018', y: 5 }, + { name: 'Dogs', x: '2019', y: 6 } + ]; + + const data3: PetData[] = [ + { name: 'Birds', x: '2015', y: 1 }, + { name: 'Birds', x: '2016', y: 2 }, + { name: 'Birds', x: '2017', y: 3 }, + { name: 'Birds', x: '2018', y: 2 }, + { name: 'Birds', x: '2019', y: 4 } + ]; + + // Custom HTML component to create a legend layout + const HtmlLegendContent = ({ datum, legendData, text, theme, title, x, y, ..._rest }) => ( + + + + + + + + + + {text.map((val, index) => ( + + + + + + ))} + +
+ {title(datum)} +
+ + + + { + + } + + + + {legendData[index].name}{val}
+
+
+ ); + + return ( +
+ `${datum.y !== null ? datum.y : 'no data'}`} + labelComponent={ + width > center.x + flyoutWidth + 10 ? offset : -offset}} + // flyoutComponent={} + flyoutHeight={110} + flyoutWidth={({ datum }) => (datum.y === null ? 160 : 125)} + labelComponent={ datum.x} />} + /> + } + mouseFollowTooltips + voronoiDimension="x" + voronoiPadding={50} + /> + } + legendData={legendData} + legendPosition="bottom-left" + height={225} + name="chart4" + padding={{ + bottom: 75, // Adjusted to accommodate legend + left: 50, + right: 50, + top: 50 + }} + maxDomain={{ y: 9 }} + themeColor={ChartThemeColor.multiUnordered} + width={650} + > + + + + + + + + +
+ ); +}; diff --git a/packages/react-charts/src/victory/components/ChartTooltip/examples/ChartTooltipEmbeddedLegend.tsx b/packages/react-charts/src/victory/components/ChartTooltip/examples/ChartTooltipEmbeddedLegend.tsx new file mode 100644 index 00000000000..fc4fc6c1dd3 --- /dev/null +++ b/packages/react-charts/src/victory/components/ChartTooltip/examples/ChartTooltipEmbeddedLegend.tsx @@ -0,0 +1,106 @@ +import { + Chart, + ChartAxis, + ChartGroup, + ChartLegendTooltip, + ChartLine, + ChartThemeColor, + createContainer +} from '@patternfly/react-charts/victory'; + +interface PetData { + childName?: string; + name?: string; + symbol?: { type: string }; + x?: string; + y?: number; +} + +export const ChartTooltipEmbeddedLegend: React.FunctionComponent = () => { + // Note: Container order is important + const CursorVoronoiContainer = createContainer('voronoi', 'cursor'); + const legendData: PetData[] = [ + { childName: 'cats', name: 'Cats' }, + { childName: 'dogs', name: 'Dogs', symbol: { type: 'dash' } }, + { childName: 'birds', name: 'Birds' }, + { childName: 'mice', name: 'Mice' } + ]; + + const data1: PetData[] = [ + { name: 'Cats', x: '2015', y: 1 }, + { name: 'Cats', x: '2016', y: 2 }, + { name: 'Cats', x: '2017', y: 5 }, + { name: 'Cats', x: '2018', y: 3 } + ]; + + const data2: PetData[] = [ + { name: 'Dogs', x: '2015', y: 2 }, + { name: 'Dogs', x: '2016', y: 1 }, + { name: 'Dogs', x: '2017', y: 7 }, + { name: 'Dogs', x: '2018', y: 4 } + ]; + + const data3: PetData[] = [ + { name: 'Birds', x: '2015', y: 3 }, + { name: 'Birds', x: '2016', y: 4 }, + { name: 'Birds', x: '2017', y: 9 }, + { name: 'Birds', x: '2018', y: 5 } + ]; + + const data4: PetData[] = [ + { name: 'Mice', x: '2015', y: 3 }, + { name: 'Mice', x: '2016', y: null }, + { name: 'Mice', x: '2017', y: 8 }, + { name: 'Mice', x: '2018', y: 7 } + ]; + + return ( +
+ `${datum.y !== null ? datum.y : 'no data'}`} + labelComponent={ datum.x} />} + mouseFollowTooltips + voronoiDimension="x" + voronoiPadding={50} + /> + } + legendData={legendData} + legendPosition="bottom" + height={275} + maxDomain={{ y: 10 }} + minDomain={{ y: 0 }} + name="chart3" + padding={{ + bottom: 75, // Adjusted to accommodate legend + left: 50, + right: 50, + top: 50 + }} + themeColor={ChartThemeColor.green} + width={450} + > + + + + + + + + + +
+ ); +}; diff --git a/packages/react-charts/src/victory/components/ChartTooltip/examples/ChartTooltipFixed.tsx b/packages/react-charts/src/victory/components/ChartTooltip/examples/ChartTooltipFixed.tsx new file mode 100644 index 00000000000..92a3552644f --- /dev/null +++ b/packages/react-charts/src/victory/components/ChartTooltip/examples/ChartTooltipFixed.tsx @@ -0,0 +1,34 @@ +import { ChartDonut, ChartThemeColor, ChartTooltip } from '@patternfly/react-charts/victory'; + +interface PetData { + x: string; + y: number; +} + +export const ChartTooltipFixed: React.FunctionComponent = () => { + const data: PetData[] = [ + { x: 'Cats', y: 35 }, + { x: 'Dogs', y: 55 }, + { x: 'Birds', y: 10 } + ]; + + return ( +
+ } + labelRadius={46} + labels={({ datum }) => `${datum.x}: ${datum.y}%`} + name="chart5" + subTitle="Pets" + title="100" + themeColor={ChartThemeColor.teal} + width={150} + /> +
+ ); +}; diff --git a/packages/react-charts/src/victory/components/ChartTooltip/examples/ChartTooltipLeftAligned.tsx b/packages/react-charts/src/victory/components/ChartTooltip/examples/ChartTooltipLeftAligned.tsx new file mode 100644 index 00000000000..cf2b6adbf03 --- /dev/null +++ b/packages/react-charts/src/victory/components/ChartTooltip/examples/ChartTooltipLeftAligned.tsx @@ -0,0 +1,114 @@ +import { + Chart, + ChartAxis, + ChartGroup, + ChartLine, + ChartThemeColor, + ChartVoronoiContainer, + getCustomTheme +} from '@patternfly/react-charts/victory'; + +interface PetData { + name?: string; + symbol?: { type: string }; + x?: string; + y?: number; +} + +export const ChartTooltipLeftAligned: React.FunctionComponent = () => { + // Victory theme properties only + const themeProps = { + voronoi: { + style: { + labels: { + textAnchor: 'start' // Align tooltip labels left + } + } + } + }; + + // Applies theme color and variant to base theme + const myCustomTheme = getCustomTheme(ChartThemeColor.default, themeProps); + + const legendData: PetData[] = [ + { name: 'Cats' }, + { name: 'Dogs', symbol: { type: 'dash' } }, + { name: 'Birds' }, + { name: 'Mice' } + ]; + + const data1: PetData[] = [ + { name: 'Cats', x: '2015', y: 1 }, + { name: 'Cats', x: '2016', y: 2 }, + { name: 'Cats', x: '2017', y: 5 }, + { name: 'Cats', x: '2018', y: 3 } + ]; + + const data2: PetData[] = [ + { name: 'Dogs', x: '2015', y: 2 }, + { name: 'Dogs', x: '2016', y: 1 }, + { name: 'Dogs', x: '2017', y: 7 }, + { name: 'Dogs', x: '2018', y: 4 } + ]; + + const data3: PetData[] = [ + { name: 'Birds', x: '2015', y: 3 }, + { name: 'Birds', x: '2016', y: 4 }, + { name: 'Birds', x: '2017', y: 9 }, + { name: 'Birds', x: '2018', y: 5 } + ]; + + const data4: PetData[] = [ + { name: 'Mice', x: '2015', y: 3 }, + { name: 'Mice', x: '2016', y: 3 }, + { name: 'Mice', x: '2017', y: 8 }, + { name: 'Mice', x: '2018', y: 7 } + ]; + + return ( +
+ `${datum.name}: ${datum.y}`} + constrainToVisibleArea + voronoiDimension="x" + /> + } + legendData={legendData} + legendOrientation="vertical" + legendPosition="right" + height={250} + maxDomain={{ y: 10 }} + minDomain={{ y: 0 }} + name="chart8" + padding={{ + bottom: 50, + left: 50, + right: 200, // Adjusted to accommodate legend + top: 50 + }} + theme={myCustomTheme} + width={600} + > + + + + + + + + + +
+ ); +}; diff --git a/packages/react-charts/src/victory/components/ChartTooltip/examples/ChartTooltipLegend.tsx b/packages/react-charts/src/victory/components/ChartTooltip/examples/ChartTooltipLegend.tsx new file mode 100644 index 00000000000..c60b74a25f3 --- /dev/null +++ b/packages/react-charts/src/victory/components/ChartTooltip/examples/ChartTooltipLegend.tsx @@ -0,0 +1,55 @@ +import { ChartLabel, ChartLegend, ChartPie, ChartThemeColor } from '@patternfly/react-charts/victory'; +import { Tooltip } from '@patternfly/react-core'; +import { useRef } from 'react'; + +interface PetData { + x: string; + y: number; +} + +export const ChartTooltipLegend: React.FunctionComponent = () => { + // Custom legend label component + // Note: Tooltip wraps children with a div tag, so we add a reference to ChartLabel instead + const LegendLabel = ({ datum, ...rest }) => { + const ref = useRef(null); + return ( + + + + + ); + }; + + // Custom legend component + const getLegend = (legendData) => } />; + + const data: PetData[] = [ + { x: 'Cats', y: 35 }, + { x: 'Dogs', y: 55 }, + { x: 'Birds', y: 10 } + ]; + + return ( +
+ `${datum.x}: ${datum.y}`} + legendComponent={getLegend([{ name: 'Cats: 35' }, { name: 'Dogs: 55' }, { name: 'Birds: 10' }])} + legendPosition="bottom" + name="chart7" + padding={{ + bottom: 65, + left: 20, + right: 20, + top: 20 + }} + themeColor={ChartThemeColor.multiOrdered} + width={300} + /> +
+ ); +}; diff --git a/packages/react-charts/src/victory/components/ChartTooltip/examples/ChartTooltipVoronoi.tsx b/packages/react-charts/src/victory/components/ChartTooltip/examples/ChartTooltipVoronoi.tsx new file mode 100644 index 00000000000..11afad2adc7 --- /dev/null +++ b/packages/react-charts/src/victory/components/ChartTooltip/examples/ChartTooltipVoronoi.tsx @@ -0,0 +1,67 @@ +import { Chart, ChartArea, ChartAxis, ChartGroup, ChartVoronoiContainer } from '@patternfly/react-charts/victory'; + +interface PetData { + name?: string; + x?: string; + y?: number; +} + +export const ChartTooltipVoronoi: React.FunctionComponent = () => { + const legendData: PetData[] = [{ name: 'Cats' }, { name: 'Dogs' }, { name: 'Birds' }]; + + const data1: PetData[] = [ + { name: 'Cats', x: '2015', y: 3 }, + { name: 'Cats', x: '2016', y: 4 }, + { name: 'Cats', x: '2017', y: 8 }, + { name: 'Cats', x: '2018', y: 6 } + ]; + + const data2: PetData[] = [ + { name: 'Dogs', x: '2015', y: 2 }, + { name: 'Dogs', x: '2016', y: 3 }, + { name: 'Dogs', x: '2017', y: 4 }, + { name: 'Dogs', x: '2018', y: 5 }, + { name: 'Dogs', x: '2019', y: 6 } + ]; + + const data3: PetData[] = [ + { name: 'Birds', x: '2015', y: 1 }, + { name: 'Birds', x: '2016', y: 2 }, + { name: 'Birds', x: '2017', y: 3 }, + { name: 'Birds', x: '2018', y: 2 }, + { name: 'Birds', x: '2019', y: 4 } + ]; + + return ( +
+ `${datum.name}: ${datum.y}`} constrainToVisibleArea /> + } + legendData={legendData} + legendOrientation="vertical" + legendPosition="right" + height={200} + maxDomain={{ y: 9 }} + name="chart1" + padding={{ + bottom: 50, + left: 50, + right: 200, // Adjusted to accommodate legend + top: 50 + }} + width={800} + > + + + + + + + + +
+ ); +}; diff --git a/packages/react-charts/src/victory/components/ChartTooltip/examples/ChartTooltipWrappedChart.tsx b/packages/react-charts/src/victory/components/ChartTooltip/examples/ChartTooltipWrappedChart.tsx new file mode 100644 index 00000000000..b56f1b69b6e --- /dev/null +++ b/packages/react-charts/src/victory/components/ChartTooltip/examples/ChartTooltipWrappedChart.tsx @@ -0,0 +1,54 @@ +import { ChartDonutThreshold, ChartDonutUtilization } from '@patternfly/react-charts/victory'; +import { Button, Tooltip, TooltipPosition } from '@patternfly/react-core'; +import { useState } from 'react'; + +interface Data { + x: string; + y: number; +} + +export const ChartTooltipWrappedChart: React.FunctionComponent = () => { + const [isVisible, setIsVisible] = useState(false); + + const showTooltip = () => { + setIsVisible(!isVisible); + }; + + const data: Data[] = [ + { x: 'Warning at 60%', y: 60 }, + { x: 'Danger at 90%', y: 90 } + ]; + + return ( +
+
+ My custom tooltip
} + isVisible={isVisible} + position={TooltipPosition.right} + trigger="manual" + > + null} + name="chart10" + > + null} + subTitle="of 100 GBps" + title="45%" + /> + + +
+
+ +
+ + ); +}; diff --git a/packages/react-charts/src/victory/components/Patterns/examples/PatternsAll.tsx b/packages/react-charts/src/victory/components/Patterns/examples/PatternsAll.tsx new file mode 100644 index 00000000000..448f5f9b7a2 --- /dev/null +++ b/packages/react-charts/src/victory/components/Patterns/examples/PatternsAll.tsx @@ -0,0 +1,101 @@ +import { ChartPie, ChartThemeColor } from '@patternfly/react-charts/victory'; +import { getResizeObserver } from '@patternfly/react-core'; +import { useEffect, useRef, useState } from 'react'; + +interface PetData { + x?: string; + y?: number; + name?: string; +} + +export const PatternsAll: React.FunctionComponent = () => { + const containerRef = useRef(null); + const observer = useRef(() => {}); + const [extraHeight, setExtraHeight] = useState(0); + const [width, setWidth] = useState(0); + + const handleResize = () => { + if (containerRef.current && containerRef.current.clientWidth) { + setWidth(containerRef.current.clientWidth); + } + }; + const handleLegendAllowWrap = (newExtraHeight) => { + if (newExtraHeight !== extraHeight) { + setExtraHeight(newExtraHeight); + } + }; + const getHeight = (baseHeight) => baseHeight + extraHeight; + + useEffect(() => { + observer.current = getResizeObserver(containerRef.current, handleResize); + handleResize(); + + return () => { + observer.current(); + }; + }, []); + + const height = getHeight(260); + + const data: PetData[] = [ + { x: 'Cats', y: 6 }, + { x: 'Dogs', y: 6 }, + { x: 'Birds', y: 6 }, + { x: 'Fish', y: 6 }, + { x: 'Rabbits', y: 6 }, + { x: 'Squirels', y: 6 }, + { x: 'Chipmunks', y: 6 }, + { x: 'Bats', y: 6 }, + { x: 'Ducks', y: 6 }, + { x: 'Geese', y: 6 }, + { x: 'Bobcats', y: 6 }, + { x: 'Foxes', y: 6 }, + { x: 'Coyotes', y: 6 }, + { x: 'Deer', y: 6 }, + { x: 'Bears', y: 10 } + ]; + + const legendData: PetData[] = [ + { name: 'Cats: 6' }, + { name: 'Dogs: 6' }, + { name: 'Birds: 6' }, + { name: 'Fish: 6' }, + { name: 'Rabbits: 6' }, + { name: 'Squirels: 6' }, + { name: 'Chipmunks: 6' }, + { name: 'Bats: 6' }, + { name: 'Ducks: 6' }, + { name: 'Geese: 6' }, + { name: 'Bobcat: 6' }, + { name: 'Foxes: 6' }, + { name: 'Coyotes: 6' }, + { name: 'Deer: 6' }, + { name: 'Bears: 6' } + ]; + + return ( +
+ `${datum.x}: ${datum.y}`} + legendData={legendData} + legendAllowWrap={handleLegendAllowWrap} + legendPosition="bottom" + name="chart12" + padding={{ + bottom: getHeight(50), // This must be adjusted to maintain the aspec ratio + left: 20, + right: 20, + top: 20 + }} + themeColor={ChartThemeColor.multiOrdered} + width={width} + /> +
+ ); +}; diff --git a/packages/react-charts/src/victory/components/Patterns/examples/PatternsBarChart.tsx b/packages/react-charts/src/victory/components/Patterns/examples/PatternsBarChart.tsx new file mode 100644 index 00000000000..584be31d4c6 --- /dev/null +++ b/packages/react-charts/src/victory/components/Patterns/examples/PatternsBarChart.tsx @@ -0,0 +1,80 @@ +import { + Chart, + ChartAxis, + ChartBar, + ChartGroup, + ChartThemeColor, + ChartVoronoiContainer +} from '@patternfly/react-charts/victory'; + +interface PetData { + x?: string; + y?: number; + name?: string; +} + +export const PatternsBarChart: React.FunctionComponent = () => { + const legendData: PetData[] = [{ name: 'Cats' }, { name: 'Dogs' }, { name: 'Birds' }, { name: 'Mice' }]; + const data1: PetData[] = [ + { name: 'Cats', x: '2015', y: 1 }, + { name: 'Cats', x: '2016', y: 2 }, + { name: 'Cats', x: '2017', y: 5 }, + { name: 'Cats', x: '2018', y: 3 } + ]; + + const data2: PetData[] = [ + { name: 'Dogs', x: '2015', y: 2 }, + { name: 'Dogs', x: '2016', y: 1 }, + { name: 'Dogs', x: '2017', y: 7 }, + { name: 'Dogs', x: '2018', y: 4 } + ]; + + const data3: PetData[] = [ + { name: 'Birds', x: '2015', y: 4 }, + { name: 'Birds', x: '2016', y: 4 }, + { name: 'Birds', x: '2017', y: 9 }, + { name: 'Birds', x: '2018', y: 7 } + ]; + + const data4: PetData[] = [ + { name: 'Mice', x: '2015', y: 3 }, + { name: 'Mice', x: '2016', y: 3 }, + { name: 'Mice', x: '2017', y: 8 }, + { name: 'Mice', x: '2018', y: 5 } + ]; + + return ( +
+ `${datum.name}: ${datum.y}`} constrainToVisibleArea /> + } + domainPadding={{ x: [30, 25] }} + legendData={legendData} + legendPosition="bottom" + hasPatterns + height={275} + name="chart2" + padding={{ + bottom: 75, // Adjusted to accommodate legend + left: 50, + right: 50, + top: 50 + }} + themeColor={ChartThemeColor.purple} + width={450} + > + + + + + + + + + +
+ ); +}; diff --git a/packages/react-charts/src/victory/components/Patterns/examples/PatternsBasicPieChart.tsx b/packages/react-charts/src/victory/components/Patterns/examples/PatternsBasicPieChart.tsx new file mode 100644 index 00000000000..b14049f62a6 --- /dev/null +++ b/packages/react-charts/src/victory/components/Patterns/examples/PatternsBasicPieChart.tsx @@ -0,0 +1,41 @@ +import { ChartPie } from '@patternfly/react-charts/victory'; + +interface PetData { + x?: string; + y?: number; + name?: string; +} + +export const PatternsBasicPieChart: React.FunctionComponent = () => { + const data: PetData[] = [ + { x: 'Cats', y: 35 }, + { x: 'Dogs', y: 55 }, + { x: 'Birds', y: 10 } + ]; + const legendData: PetData[] = [{ name: 'Cats: 35' }, { name: 'Dogs: 55' }, { name: 'Birds: 10' }]; + + return ( +
+ `${datum.x}: ${datum.y}`} + legendData={legendData} + legendOrientation="vertical" + legendPosition="right" + name="chart1" + padding={{ + bottom: 20, + left: 20, + right: 140, // Adjusted to accommodate legend + top: 20 + }} + width={350} + /> +
+ ); +}; diff --git a/packages/react-charts/src/victory/components/Patterns/examples/PatternsCustomColorScale.tsx b/packages/react-charts/src/victory/components/Patterns/examples/PatternsCustomColorScale.tsx new file mode 100644 index 00000000000..c2a3e10f414 --- /dev/null +++ b/packages/react-charts/src/victory/components/Patterns/examples/PatternsCustomColorScale.tsx @@ -0,0 +1,44 @@ +import { ChartPie } from '@patternfly/react-charts/victory'; +import chart_color_blue_300 from '@patternfly/react-tokens/dist/esm/chart_color_blue_300'; +import chart_color_yellow_300 from '@patternfly/react-tokens/dist/esm/chart_color_yellow_300'; +import chart_color_green_300 from '@patternfly/react-tokens/dist/esm/chart_color_green_300'; + +interface PetData { + x?: string; + y?: number; + name?: string; +} + +export const PatternsCustomColorScale: React.FunctionComponent = () => { + const data: PetData[] = [ + { x: 'Cats', y: 35 }, + { x: 'Dogs', y: 55 }, + { x: 'Birds', y: 10 } + ]; + const legendData: PetData[] = [{ name: 'Cats: 35' }, { name: 'Dogs: 55' }, { name: 'Birds: 10' }]; + return ( +
+ `${datum.x}: ${datum.y}`} + legendData={legendData} + legendOrientation="vertical" + legendPosition="right" + name="chart10" + padding={{ + bottom: 20, + left: 20, + right: 140, // Adjusted to accommodate legend + top: 20 + }} + width={350} + /> +
+ ); +}; diff --git a/packages/react-charts/src/victory/components/Patterns/examples/PatternsCustomDefs.tsx b/packages/react-charts/src/victory/components/Patterns/examples/PatternsCustomDefs.tsx new file mode 100644 index 00000000000..583a72dadc8 --- /dev/null +++ b/packages/react-charts/src/victory/components/Patterns/examples/PatternsCustomDefs.tsx @@ -0,0 +1,75 @@ +import { ChartPie, ChartThemeColor } from '@patternfly/react-charts/victory'; +import chart_color_blue_300 from '@patternfly/react-tokens/dist/esm/chart_color_blue_300'; +import chart_color_green_300 from '@patternfly/react-tokens/dist/esm/chart_color_green_300'; + +interface PetData { + x?: string; + y?: number; + name?: string; +} + +export const PatternsCustomDefs: React.FunctionComponent = () => { + const data: PetData[] = [ + { x: 'Cats', y: 35 }, + { x: 'Dogs', y: 55 }, + { x: 'Birds', y: 10 } + ]; + const legendData: PetData[] = [{ name: 'Cats: 35' }, { name: 'Dogs: 55' }, { name: 'Birds: 10' }]; + + return ( +
+ + + + + + + + + + + `${datum.x}: ${datum.y}`} + legendData={legendData} + legendOrientation="vertical" + legendPosition="right" + name="chart11" + padding={{ + bottom: 20, + left: 20, + right: 140, // Adjusted to accommodate legend + top: 20 + }} + patternScale={['url("#pattern1")', 'url("#pattern2")', null]} + themeColor={ChartThemeColor.multiUnordered} + width={350} + /> +
+ ); +}; diff --git a/packages/react-charts/src/victory/components/Patterns/examples/PatternsCustomVisibility.tsx b/packages/react-charts/src/victory/components/Patterns/examples/PatternsCustomVisibility.tsx new file mode 100644 index 00000000000..8b5f46345a7 --- /dev/null +++ b/packages/react-charts/src/victory/components/Patterns/examples/PatternsCustomVisibility.tsx @@ -0,0 +1,50 @@ +import { ChartPie, ChartThemeColor } from '@patternfly/react-charts/victory'; + +interface PetData { + x?: string; + y?: number; + name?: string; +} + +export const PatternsCustomVisibility: React.FunctionComponent = () => { + const data: PetData[] = [ + { x: 'Cats', y: 15 }, + { x: 'Dogs', y: 15 }, + { x: 'Birds', y: 15 }, + { x: 'Fish', y: 25 }, + { x: 'Rabbits', y: 30 } + ]; + const legendData: PetData[] = [ + { name: 'Cats: 15' }, + { name: 'Dogs: 15' }, + { name: 'Birds: 15' }, + { name: 'Fish: 25' }, + { name: 'Rabbits: 30' } + ]; + + return ( +
+ `${datum.x}: ${datum.y}`} + legendData={legendData} + legendOrientation="vertical" + legendPosition="right" + name="chart9" + padding={{ + bottom: 20, + left: 20, + right: 140, // Adjusted to accommodate legend + top: 20 + }} + themeColor={ChartThemeColor.multiUnordered} + width={350} + /> +
+ ); +}; diff --git a/packages/react-charts/src/victory/components/Patterns/examples/PatternsDonutChart.tsx b/packages/react-charts/src/victory/components/Patterns/examples/PatternsDonutChart.tsx new file mode 100644 index 00000000000..45bf8af7574 --- /dev/null +++ b/packages/react-charts/src/victory/components/Patterns/examples/PatternsDonutChart.tsx @@ -0,0 +1,44 @@ +import { ChartDonut, ChartThemeColor } from '@patternfly/react-charts/victory'; + +interface PetData { + x?: string; + y?: number; + name?: string; +} + +export const PatternsDonutChart: React.FunctionComponent = () => { + const legendData: PetData[] = [{ name: 'Cats: 35' }, { name: 'Dogs: 55' }, { name: 'Birds: 10' }]; + + const data: PetData[] = [ + { x: 'Cats', y: 35 }, + { x: 'Dogs', y: 55 }, + { x: 'Birds', y: 10 } + ]; + + return ( +
+ `${datum.x}: ${datum.y}%`} + legendData={legendData} + legendOrientation="vertical" + legendPosition="right" + name="chart4" + padding={{ + bottom: 20, + left: 20, + right: 140, // Adjusted to accommodate legend + top: 20 + }} + subTitle="Pets" + title="100" + themeColor={ChartThemeColor.yellow} + width={350} + /> +
+ ); +}; diff --git a/packages/react-charts/src/victory/components/Patterns/examples/PatternsDonutUtilizationChart.tsx b/packages/react-charts/src/victory/components/Patterns/examples/PatternsDonutUtilizationChart.tsx new file mode 100644 index 00000000000..e32e688be1c --- /dev/null +++ b/packages/react-charts/src/victory/components/Patterns/examples/PatternsDonutUtilizationChart.tsx @@ -0,0 +1,40 @@ +import { ChartDonutUtilization, ChartThemeColor } from '@patternfly/react-charts/victory'; + +interface Data { + x?: string; + y?: number; + name?: string; +} + +export const PatternsDonutUtilizationChart: React.FunctionComponent = () => { + const data: Data = { x: 'Storage capacity', y: 45 }; + const legendData: Data[] = [{ name: `Storage capacity: 45%` }, { name: 'Unused' }]; + + return ( +
+ (datum.x ? `${datum.x}: ${datum.y}%` : null)} + legendData={legendData} + legendPosition="bottom" + name="chart5" + padding={{ + bottom: 65, // Adjusted to accommodate legend + left: 20, + right: 20, + top: 20 + }} + subTitle="of 100 GBps" + title="45%" + themeColor={ChartThemeColor.green} + thresholds={[{ value: 60 }, { value: 90 }]} + width={300} + /> +
+ ); +}; diff --git a/packages/react-charts/src/victory/components/Patterns/examples/PatternsDonutUtilizationThreshold.tsx b/packages/react-charts/src/victory/components/Patterns/examples/PatternsDonutUtilizationThreshold.tsx new file mode 100644 index 00000000000..20de55e1613 --- /dev/null +++ b/packages/react-charts/src/victory/components/Patterns/examples/PatternsDonutUtilizationThreshold.tsx @@ -0,0 +1,52 @@ +import { ChartDonutThreshold, ChartDonutUtilization, ChartThemeColor } from '@patternfly/react-charts/victory'; + +interface Data { + x?: string; + y?: number; + name?: string; +} + +export const PatternsDonutUtilizationThreshold: React.FunctionComponent = () => { + const data1: Data[] = [ + { x: 'Warning at 60%', y: 60 }, + { x: 'Danger at 90%', y: 90 } + ]; + const data2: Data = { x: 'Storage capacity', y: 45 }; + const legendData: Data[] = [ + { name: `Storage capacity: 45%` }, + { name: 'Warning threshold at 60%' }, + { name: 'Danger threshold at 90%' } + ]; + + return ( +
+ (datum.x ? datum.x : null)} + name="chart6" + padding={{ + bottom: 65, // Adjusted to accommodate legend + left: 20, + right: 20, + top: 20 + }} + width={675} + > + (datum.x ? `${datum.x}: ${datum.y}%` : null)} + legendData={legendData} + legendPosition="bottom" + subTitle="of 100 GBps" + title="45%" + themeColor={ChartThemeColor.orange} + /> + +
+ ); +}; diff --git a/packages/react-charts/src/victory/components/Patterns/examples/PatternsInteractiveAreaChart.tsx b/packages/react-charts/src/victory/components/Patterns/examples/PatternsInteractiveAreaChart.tsx new file mode 100644 index 00000000000..a310c6b50ed --- /dev/null +++ b/packages/react-charts/src/victory/components/Patterns/examples/PatternsInteractiveAreaChart.tsx @@ -0,0 +1,184 @@ +import { + Chart, + ChartArea, + ChartAxis, + ChartGroup, + ChartLegend, + ChartLegendTooltip, + ChartScatter, + ChartThemeColor, + createContainer, + getInteractiveLegendEvents, + getInteractiveLegendItemStyles +} from '@patternfly/react-charts/victory'; +import { getResizeObserver } from '@patternfly/react-core'; +import { useEffect, useRef, useState } from 'react'; + +export const PatternsInteractiveAreaChart: React.FunctionComponent = () => { + const containerRef = useRef(null); + const observer = useRef(() => {}); + const [hiddenSeries, setHiddenSeries] = useState(new Set()); + const [width, setWidth] = useState(0); + + const series = [ + { + datapoints: [ + { x: '2015', y: 3 }, + { x: '2016', y: 4 }, + { x: '2017', y: 8 }, + { x: '2018', y: 6 } + ], + legendItem: { name: 'Cats' } + }, + { + datapoints: [ + { x: '2015', y: 2 }, + { x: '2016', y: 3 }, + { x: '2017', y: 4 }, + { x: '2018', y: 5 }, + { x: '2019', y: 6 } + ], + legendItem: { name: 'Dogs' } + }, + { + datapoints: [ + { x: '2015', y: 1 }, + { x: '2016', y: 2 }, + { x: '2017', y: 3 }, + { x: '2018', y: 2 }, + { x: '2019', y: 4 } + ], + legendItem: { name: 'Birds' } + } + ]; + + // Returns groups of chart names associated with each data series + const getChartNames = () => { + const result = []; + series.map((_, index) => { + // Each group of chart names are hidden / shown together + result.push([`area-${index}`, `scatter-${index}`]); + }); + return result; + }; + + // Returns onMouseOver, onMouseOut, and onClick events for the interactive legend + const getEvents = () => + getInteractiveLegendEvents({ + chartNames: getChartNames(), + isHidden, + legendName: 'chart8-ChartLegend', + onLegendClick: handleLegendClick + }); + + // Returns legend data styled per hiddenSeries + const getLegendData = () => + series.map((s, index) => ({ + childName: `area-${index}`, // Sync tooltip legend with the series associated with given chart name + ...s.legendItem, // name property + ...getInteractiveLegendItemStyles(hiddenSeries.has(index)) // hidden styles + })); + + // Hide each data series individually + const handleLegendClick = (props) => { + if (!hiddenSeries.delete(props.index)) { + hiddenSeries.add(props.index); + } + setHiddenSeries(new Set(hiddenSeries)); + }; + + // Set chart width per current window size + const handleResize = () => { + if (containerRef.current && containerRef.current.clientWidth) { + setWidth(containerRef.current.clientWidth); + } + }; + + // Returns true if data series is hidden + const isHidden = (index) => hiddenSeries.has(index); + + const isDataAvailable = () => hiddenSeries.size !== series.length; + + // Note: Container order is important + const CursorVoronoiContainer = createContainer('voronoi', 'cursor'); + + const cursorVoronoiContainer = ( + (datum.childName.includes('area-') && datum.y !== null ? `${datum.y}` : null)} + labelComponent={ datum.x} />} + mouseFollowTooltips + voronoiDimension="x" + voronoiPadding={50} + /> + ); + + useEffect(() => { + observer.current = getResizeObserver(containerRef.current, handleResize); + handleResize(); + + return () => { + observer.current(); + }; + }, []); + + // Tips: + // 1. Omitting hidden components will reassign color scale, use null data instead or custom colors + // 2. Set domain or tick axis labels to account for when all data series are hidden + // 3. Omit tooltip for ChartScatter component by checking childName prop + // 4. Omit tooltip when all data series are hidden + // 5. Clone original container to ensure tooltip events are not lost when data series are hidden / shown + const container = cloneElement(cursorVoronoiContainer, { + disable: !isDataAvailable() + }); + + return ( +
+
+ } + legendPosition="bottom-left" + name="chart8" + padding={{ + bottom: 75, // Adjusted to accommodate legend + left: 50, + right: 50, + top: 50 + }} + maxDomain={{ y: 9 }} + themeColor={ChartThemeColor.multiUnordered} + width={width} + > + + + + {series.map((s, index) => ( + (active ? 5 : 3)} + /> + ))} + + + {series.map((s, index) => ( + + ))} + + +
+
+ ); +}; diff --git a/packages/react-charts/src/victory/components/Patterns/examples/PatternsInteractivePieChart.tsx b/packages/react-charts/src/victory/components/Patterns/examples/PatternsInteractivePieChart.tsx new file mode 100644 index 00000000000..b5ba8388fa3 --- /dev/null +++ b/packages/react-charts/src/victory/components/Patterns/examples/PatternsInteractivePieChart.tsx @@ -0,0 +1,101 @@ +import { + Chart, + ChartLegend, + ChartThemeColor, + ChartPie, + getInteractiveLegendEvents, + getInteractiveLegendItemStyles +} from '@patternfly/react-charts/victory'; +import { useState } from 'react'; + +interface PetData { + x?: string; + y?: number; +} + +export const PatternsInteractivePieChart: React.FunctionComponent = () => { + const [hiddenSeries, setHiddenSeries] = useState(new Set()); + + const series = [ + { + datapoints: { x: 'Cats', y: 25 }, + legendItem: { name: 'Cats: 35' } + }, + { + datapoints: { x: 'Dogs', y: 25 }, + legendItem: { name: 'Dogs: 25' } + }, + { + datapoints: { x: 'Birds', y: 10 }, + legendItem: { name: 'Birds: 10' } + } + ]; + + // Returns groups of chart names associated with each data series + const getChartNames = () => { + const result = []; + series.map((_, _index) => { + // Provide names for each series hidden / shown -- use the same name for a pie chart + result.push(['pie']); + }); + return result; + }; + + // Returns onMouseOver, onMouseOut, and onClick events for the interactive legend + const getEvents = () => + getInteractiveLegendEvents({ + chartNames: getChartNames(), + isHidden, + legendName: 'chart7-ChartLegend', + onLegendClick: handleLegendClick + }); + + // Returns legend data styled per hiddenSeries + const getLegendData = () => + series.map((s, index) => ({ + ...s.legendItem, // name property + ...getInteractiveLegendItemStyles(hiddenSeries.has(index)) // hidden styles + })); + + // Hide each data series individually + const handleLegendClick = (props) => { + if (!hiddenSeries.delete(props.index)) { + hiddenSeries.add(props.index); + } + setHiddenSeries(new Set(hiddenSeries)); + }; + + // Returns true if data series is hidden + const isHidden = (index) => hiddenSeries.has(index); + + const data: PetData[] = []; + series.map((s, index) => { + data.push(!hiddenSeries.has(index) ? s.datapoints : { y: null }); + }); + + return ( +
+ } + legendPosition="bottom" + name="chart7" + padding={{ + bottom: 65, + left: 20, + right: 20, + top: 20 + }} + showAxis={false} + themeColor={ChartThemeColor.multiUnordered} + width={500} + > + `${datum.x}: ${datum.y}`} name="pie" /> + +
+ ); +}; diff --git a/packages/react-charts/src/victory/components/Patterns/examples/PatternsStackChart.tsx b/packages/react-charts/src/victory/components/Patterns/examples/PatternsStackChart.tsx new file mode 100644 index 00000000000..2b285360cef --- /dev/null +++ b/packages/react-charts/src/victory/components/Patterns/examples/PatternsStackChart.tsx @@ -0,0 +1,81 @@ +import { + Chart, + ChartAxis, + ChartBar, + ChartStack, + ChartThemeColor, + ChartVoronoiContainer +} from '@patternfly/react-charts/victory'; + +interface PetData { + x?: string; + y?: number; + name?: string; +} + +export const PatternsStackChart: React.FunctionComponent = () => { + const legendData: PetData[] = [{ name: 'Cats' }, { name: 'Dogs' }, { name: 'Birds' }, { name: 'Mice' }]; + const data1: PetData[] = [ + { name: 'Cats', x: '2015', y: 1 }, + { name: 'Cats', x: '2016', y: 2 }, + { name: 'Cats', x: '2017', y: 5 }, + { name: 'Cats', x: '2018', y: 3 } + ]; + + const data2: PetData[] = [ + { name: 'Dogs', x: '2015', y: 2 }, + { name: 'Dogs', x: '2016', y: 1 }, + { name: 'Dogs', x: '2017', y: 7 }, + { name: 'Dogs', x: '2018', y: 4 } + ]; + + const data3: PetData[] = [ + { name: 'Birds', x: '2015', y: 4 }, + { name: 'Birds', x: '2016', y: 4 }, + { name: 'Birds', x: '2017', y: 9 }, + { name: 'Birds', x: '2018', y: 7 } + ]; + + const data4: PetData[] = [ + { name: 'Mice', x: '2015', y: 3 }, + { name: 'Mice', x: '2016', y: 3 }, + { name: 'Mice', x: '2017', y: 8 }, + { name: 'Mice', x: '2018', y: 5 } + ]; + + return ( +
+ `${datum.name}: ${datum.y}`} constrainToVisibleArea /> + } + domainPadding={{ x: [30, 25] }} + legendData={legendData} + legendOrientation="vertical" + legendPosition="right" + hasPatterns + height={250} + name="chart3" + padding={{ + bottom: 50, + left: 50, + right: 200, // Adjusted to accommodate legend + top: 50 + }} + themeColor={ChartThemeColor.green} + width={600} + > + + + + + + + + + +
+ ); +}; diff --git a/packages/react-charts/src/victory/components/Patterns/examples/patterns.md b/packages/react-charts/src/victory/components/Patterns/examples/patterns.md index 7a54238e22a..6e6d1b6ca0a 100644 --- a/packages/react-charts/src/victory/components/Patterns/examples/patterns.md +++ b/packages/react-charts/src/victory/components/Patterns/examples/patterns.md @@ -21,6 +21,7 @@ hideDarkMode: true --- import { cloneElement, createRef } from 'react'; +import { useEffect, useRef, useState } from 'react'; import { Chart, ChartArea, @@ -56,749 +57,84 @@ The examples below are based on the [Victory](https://formidable.com/open-source ## Examples ### Basic pie chart -```js -import { ChartPie } from '@patternfly/react-charts/victory'; - -
- `${datum.x}: ${datum.y}`} - legendData={[{ name: 'Cats: 35' }, { name: 'Dogs: 55' }, { name: 'Birds: 10' }]} - legendOrientation="vertical" - legendPosition="right" - name="chart1" - padding={{ - bottom: 20, - left: 20, - right: 140, // Adjusted to accommodate legend - top: 20 - }} - width={350} - /> -
+```ts file = "PatternsBasicPieChart.tsx" + ``` ### Bar chart -```js -import { Chart, ChartAxis, ChartBar, ChartGroup, ChartThemeColor, ChartVoronoiContainer } from '@patternfly/react-charts/victory'; - -
- `${datum.name}: ${datum.y}`} constrainToVisibleArea />} - domainPadding={{ x: [30, 25] }} - legendData={[{ name: 'Cats' }, { name: 'Dogs' }, { name: 'Birds' }, { name: 'Mice' }]} - legendPosition="bottom" - hasPatterns - height={275} - name="chart2" - padding={{ - bottom: 75, // Adjusted to accommodate legend - left: 50, - right: 50, - top: 50 - }} - themeColor={ChartThemeColor.purple} - width={450} - > - - - - - - - - - -
+```ts file = "PatternsBarChart.tsx" + ``` ### Stack chart -```js -import { Chart, ChartAxis, ChartBar, ChartStack, ChartThemeColor, ChartVoronoiContainer } from '@patternfly/react-charts/victory'; - -
- `${datum.name}: ${datum.y}`} constrainToVisibleArea />} - domainPadding={{ x: [30, 25] }} - legendData={[{ name: 'Cats' }, { name: 'Dogs' }, { name: 'Birds' }, { name: 'Mice' }]} - legendOrientation="vertical" - legendPosition="right" - hasPatterns - height={250} - name="chart3" - padding={{ - bottom: 50, - left: 50, - right: 200, // Adjusted to accommodate legend - top: 50 - }} - themeColor={ChartThemeColor.green} - width={600} - > - - - - - - - - - -
+```ts file = "PatternsStackChart.tsx" + ``` ### Donut chart -```js -import { ChartDonut, ChartThemeColor } from '@patternfly/react-charts/victory'; - -
- `${datum.x}: ${datum.y}%`} - legendData={[{ name: 'Cats: 35' }, { name: 'Dogs: 55' }, { name: 'Birds: 10' }]} - legendOrientation="vertical" - legendPosition="right" - name="chart4" - padding={{ - bottom: 20, - left: 20, - right: 140, // Adjusted to accommodate legend - top: 20 - }} - subTitle="Pets" - title="100" - themeColor={ChartThemeColor.yellow} - width={350} - /> -
+```ts file = "PatternsDonutChart.tsx" + ``` ### Donut utilization chart This demonstrates how to hide a pattern for the static, unused portion of the donut utilization chart. -```js -import { ChartDonutUtilization, ChartThemeColor } from '@patternfly/react-charts/victory'; - -
- datum.x ? `${datum.x}: ${datum.y}%` : null} - legendData={[{ name: `Storage capacity: 45%` }, { name: 'Unused' }]} - legendPosition="bottom" - name="chart5" - padding={{ - bottom: 65, // Adjusted to accommodate legend - left: 20, - right: 20, - top: 20 - }} - subTitle="of 100 GBps" - title="45%" - themeColor={ChartThemeColor.green} - thresholds={[{ value: 60 }, { value: 90 }]} - width={300} - /> -
+```ts file = "PatternsDonutUtilizationChart.tsx" + ``` ### Donut utilization chart with thresholds This demonstrates how to apply patterns to thresholds. -```js -import { ChartDonutThreshold, ChartDonutUtilization, ChartThemeColor } from '@patternfly/react-charts/victory'; - -
- datum.x ? datum.x : null} - name="chart6" - padding={{ - bottom: 65, // Adjusted to accommodate legend - left: 20, - right: 20, - top: 20 - }} - width={675} - > - datum.x ? `${datum.x}: ${datum.y}%` : null} - legendData={[{ name: `Storage capacity: 45%` }, { name: 'Warning threshold at 60%' }, { name: 'Danger threshold at 90%' }]} - legendPosition="bottom" - subTitle="of 100 GBps" - title="45%" - themeColor={ChartThemeColor.orange} - /> - -
+```ts file = "PatternsDonutUtilizationThreshold.tsx" + ``` ### Interactive legend with pie chart This demonstrates how to add an interactive legend to a pie chart using events such as `onMouseOver`, `onMouseOut`, and `onClick`. -```js -import { - Chart, - ChartLegend, - ChartThemeColor, - ChartPie, - getInteractiveLegendEvents, - getInteractiveLegendItemStyles -} from '@patternfly/react-charts/victory'; +```ts file = "PatternsInteractivePieChart.tsx" -class InteractivePieLegendChart extends React.Component { - constructor(props) { - super(props); - this.state = { - hiddenSeries: new Set(), - width: 0 - }; - this.series = [{ - datapoints: { x: 'Cats', y: 25 }, - legendItem: { name: 'Cats: 35' } - }, { - datapoints: { x: 'Dogs', y: 25 }, - legendItem: { name: 'Dogs: 25' } - }, { - datapoints: { x: 'Birds', y: 10 }, - legendItem: { name: 'Birds: 10' } - }]; - - // Returns groups of chart names associated with each data series - this.getChartNames = () => { - const result = []; - this.series.map((_, index) => { - // Provide names for each series hidden / shown -- use the same name for a pie chart - result.push(['pie']); - }); - return result; - }; - - // Returns onMouseOver, onMouseOut, and onClick events for the interactive legend - this.getEvents = () => getInteractiveLegendEvents({ - chartNames: this.getChartNames(), - isHidden: this.isHidden, - legendName: 'chart7-ChartLegend', - onLegendClick: this.handleLegendClick - }); - - // Returns legend data styled per hiddenSeries - this.getLegendData = () => { - const { hiddenSeries } = this.state; - return this.series.map((s, index) => { - return { - ...s.legendItem, // name property - ...getInteractiveLegendItemStyles(hiddenSeries.has(index)) // hidden styles - }; - }); - }; - - // Hide each data series individually - this.handleLegendClick = (props) => { - if (!this.state.hiddenSeries.delete(props.index)) { - this.state.hiddenSeries.add(props.index); - } - this.setState({ hiddenSeries: new Set(this.state.hiddenSeries) }); - }; - - // Returns true if data series is hidden - this.isHidden = (index) => { - const { hiddenSeries } = this.state; // Skip if already hidden - return hiddenSeries.has(index); - }; - }; - - render() { - const { hiddenSeries, width } = this.state; - - const data = []; - this.series.map((s, index) => { - data.push(!hiddenSeries.has(index) ? s.datapoints : { y: null }); - }); - - return ( -
- } - legendPosition="bottom" - name="chart7" - padding={{ - bottom: 65, - left: 20, - right: 20, - top: 20 - }} - showAxis={false} - themeColor={ChartThemeColor.multiUnordered} - width={500} - > - `${datum.x}: ${datum.y}`} - name="pie" - /> - -
- ); - } -} ``` ### Interactive legend with area chart This demonstrates how to add an interactive legend using events such as `onMouseOver`, `onMouseOut`, and `onClick`. -```js -import { - Chart, - ChartArea, - ChartAxis, - ChartGroup, - ChartLegend, - ChartLegendTooltip, - ChartScatter, - ChartThemeColor, - createContainer, - getInteractiveLegendEvents, - getInteractiveLegendItemStyles -} from '@patternfly/react-charts/victory'; -import { getResizeObserver } from '@patternfly/react-core'; -// import '@patternfly/patternfly/patternfly-charts.css'; // For mixed blend mode - -class InteractiveLegendChart extends React.Component { - constructor(props) { - super(props); - this.containerRef = createRef(); - this.observer = () => {}; - this.state = { - hiddenSeries: new Set(), - width: 0 - }; - this.series = [{ - datapoints: [ - { x: '2015', y: 3 }, - { x: '2016', y: 4 }, - { x: '2017', y: 8 }, - { x: '2018', y: 6 } - ], - legendItem: { name: 'Cats' } - }, { - datapoints: [ - { x: '2015', y: 2 }, - { x: '2016', y: 3 }, - { x: '2017', y: 4 }, - { x: '2018', y: 5 }, - { x: '2019', y: 6 } - ], - legendItem: { name: 'Dogs' } - }, { - datapoints: [ - { x: '2015', y: 1 }, - { x: '2016', y: 2 }, - { x: '2017', y: 3 }, - { x: '2018', y: 2 }, - { x: '2019', y: 4 } - ], - legendItem: { name: 'Birds' } - }]; - - // Returns groups of chart names associated with each data series - this.getChartNames = () => { - const result = []; - this.series.map((_, index) => { - // Each group of chart names are hidden / shown together - result.push([`area-${index}`, `scatter-${index}`]); - }); - return result; - }; - - // Returns onMouseOver, onMouseOut, and onClick events for the interactive legend - this.getEvents = () => getInteractiveLegendEvents({ - chartNames: this.getChartNames(), - isHidden: this.isHidden, - legendName: 'chart8-ChartLegend', - onLegendClick: this.handleLegendClick - }); - - // Returns legend data styled per hiddenSeries - this.getLegendData = () => { - const { hiddenSeries } = this.state; - return this.series.map((s, index) => { - return { - childName: `area-${index}`, // Sync tooltip legend with the series associated with given chart name - ...s.legendItem, // name property - ...getInteractiveLegendItemStyles(hiddenSeries.has(index)) // hidden styles - }; - }); - }; - - // Hide each data series individually - this.handleLegendClick = (props) => { - if (!this.state.hiddenSeries.delete(props.index)) { - this.state.hiddenSeries.add(props.index); - } - this.setState({ hiddenSeries: new Set(this.state.hiddenSeries) }); - }; - - // Set chart width per current window size - this.handleResize = () => { - if (this.containerRef.current && this.containerRef.current.clientWidth) { - this.setState({ width: this.containerRef.current.clientWidth }); - } - }; - - // Returns true if data series is hidden - this.isHidden = (index) => { - const { hiddenSeries } = this.state; // Skip if already hidden - return hiddenSeries.has(index); - }; - - this.isDataAvailable = () => { - const { hiddenSeries } = this.state; - return hiddenSeries.size !== this.series.length; - }; - - // Note: Container order is important - const CursorVoronoiContainer = createContainer("voronoi", "cursor"); - - this.cursorVoronoiContainer = ( - datum.childName.includes('area-') && datum.y !== null ? `${datum.y}` : null} - labelComponent={ datum.x}/>} - mouseFollowTooltips - voronoiDimension="x" - voronoiPadding={50} - /> - ); - }; - - componentDidMount() { - this.observer = getResizeObserver(this.containerRef.current, this.handleResize); - this.handleResize(); - } - - componentWillUnmount() { - this.observer(); - } - - // Tips: - // 1. Omitting hidden components will reassign color scale, use null data instead or custom colors - // 2. Set domain or tick axis labels to account for when all data series are hidden - // 3. Omit tooltip for ChartScatter component by checking childName prop - // 4. Omit tooltip when all data series are hidden - // 5. Clone original container to ensure tooltip events are not lost when data series are hidden / shown - render() { - const { hiddenSeries, width } = this.state; - - const container = cloneElement( - this.cursorVoronoiContainer, - { - disable: !this.isDataAvailable() - } - ); - - return ( -
-
- } - legendPosition="bottom-left" - name="chart8" - padding={{ - bottom: 75, // Adjusted to accommodate legend - left: 50, - right: 50, - top: 50, - }} - maxDomain={{y: 9}} - themeColor={ChartThemeColor.multiUnordered} - width={width} - > - - - - {this.series.map((s, index) => { - return ( - (active ? 5 : 3)} - /> - ); - })} - - - {this.series.map((s, index) => { - return ( - - ); - })} - - -
-
- ); - } -} +```ts file = "PatternsInteractiveAreaChart.tsx" + ``` ### Custom pattern visibility This demonstrates how to omit patterns from pie chart segments. -```js -import { ChartPie, ChartThemeColor } from '@patternfly/react-charts/victory'; - -
- `${datum.x}: ${datum.y}`} - legendData={[{ name: 'Cats: 15' }, { name: 'Dogs: 15' }, { name: 'Birds: 15' }, { name: 'Fish: 25' }, { name: 'Rabbits: 30' }]} - legendOrientation="vertical" - legendPosition="right" - name="chart9" - padding={{ - bottom: 20, - left: 20, - right: 140, // Adjusted to accommodate legend - top: 20 - }} - themeColor={ChartThemeColor.multiUnordered} - width={350} - /> -
+```ts file = "PatternsCustomVisibility.tsx" + ``` ### Custom color scale This demonstrates how to apply a custom color scale to patterns. -```js -import { ChartPie } from '@patternfly/react-charts/victory'; -import chart_color_blue_300 from '@patternfly/react-tokens/dist/esm/chart_color_blue_300'; -import chart_color_yellow_300 from '@patternfly/react-tokens/dist/esm/chart_color_yellow_300'; -import chart_color_green_300 from '@patternfly/react-tokens/dist/esm/chart_color_green_300'; +```ts file = "PatternsCustomColorScale.tsx" -
- `${datum.x}: ${datum.y}`} - legendData={[{ name: 'Cats: 35' }, { name: 'Dogs: 55' }, { name: 'Birds: 10' }]} - legendOrientation="vertical" - legendPosition="right" - name="chart10" - padding={{ - bottom: 20, - left: 20, - right: 140, // Adjusted to accommodate legend - top: 20 - }} - width={350} - /> -
``` ### Custom pattern defs This demonstrates how to create custom patterns. -```js -import { ChartPie, ChartThemeColor } from '@patternfly/react-charts/victory'; -import chart_color_blue_300 from '@patternfly/react-tokens/dist/esm/chart_color_blue_300'; -import chart_color_green_300 from '@patternfly/react-tokens/dist/esm/chart_color_green_300'; +```ts file = "PatternsCustomDefs.tsx" -
- - - - - - - - - - - `${datum.x}: ${datum.y}`} - legendData={[{ name: 'Cats: 35' }, { name: 'Dogs: 55' }, { name: 'Birds: 10' }]} - legendOrientation="vertical" - legendPosition="right" - name="chart11" - padding={{ - bottom: 20, - left: 20, - right: 140, // Adjusted to accommodate legend - top: 20 - }} - patternScale={[ 'url("#pattern1")', 'url("#pattern2")', null ]} - themeColor={ChartThemeColor.multiUnordered} - width={350} - /> -
``` ### All patterns -```js -import { ChartPie, ChartThemeColor } from '@patternfly/react-charts/victory'; -import { getResizeObserver } from '@patternfly/react-core'; +```ts file = "PatternsAll.tsx" -class PatternsPie extends React.Component { - constructor(props) { - super(props); - this.containerRef = createRef(); - this.observer = () => {}; - this.state = { - extraHeight: 0, - width: 0 - }; - this.handleResize = () => { - if (this.containerRef.current && this.containerRef.current.clientWidth) { - this.setState({ width: this.containerRef.current.clientWidth }); - } - }; - this.handleLegendAllowWrap = (extraHeight) => { - if (extraHeight !== this.state.extraHeight) { - this.setState({ extraHeight }); - } - } - this.getHeight = (baseHeight) => { - const { extraHeight } = this.state; - return baseHeight + extraHeight; - }; - } - - componentDidMount() { - this.observer = getResizeObserver(this.containerRef.current, this.handleResize); - this.handleResize(); - } - - componentWillUnmount() { - this.observer(); - } - - render() { - const { width } = this.state; - const height = this.getHeight(260); - return ( -
- `${datum.x}: ${datum.y}`} - legendData={[ - { name: 'Cats: 6' }, - { name: 'Dogs: 6' }, - { name: 'Birds: 6' }, - { name: 'Fish: 6' }, - { name: 'Rabbits: 6' }, - { name: 'Squirels: 6' }, - { name: 'Chipmunks: 6' }, - { name: 'Bats: 6' }, - { name: 'Ducks: 6' }, - { name: 'Geese: 6' }, - { name: 'Bobcat: 6' }, - { name: 'Foxes: 6' }, - { name: 'Coyotes: 6' }, - { name: 'Deer: 6' }, - { name: 'Bears: 6' }, - ]} - legendAllowWrap={this.handleLegendAllowWrap} - legendPosition="bottom" - name="chart12" - padding={{ - bottom: this.getHeight(50), // This must be adjusted to maintain the aspec ratio - left: 20, - right: 20, - top: 20 - }} - themeColor={ChartThemeColor.multiOrdered} - width={width} - /> -
- ); - } -} ``` ## Documentation diff --git a/packages/react-charts/src/victory/components/ResizeObserver/examples/ResizeObserverResponsiveBullet.tsx b/packages/react-charts/src/victory/components/ResizeObserver/examples/ResizeObserverResponsiveBullet.tsx new file mode 100644 index 00000000000..54d38838e66 --- /dev/null +++ b/packages/react-charts/src/victory/components/ResizeObserver/examples/ResizeObserverResponsiveBullet.tsx @@ -0,0 +1,84 @@ +import { ChartBullet } from '@patternfly/react-charts/victory'; +import { getResizeObserver } from '@patternfly/react-core'; +import { useEffect, useRef, useState } from 'react'; + +interface Data { + name?: string; + y?: number; +} + +export const ResizeObserverResponsiveBullet: React.FunctionComponent = () => { + const containerRef = useRef(null); + const observer = useRef(() => {}); + const [extraHeight, setExtraHeight] = useState(0); + const [width, setWidth] = useState(0); + + const handleResize = () => { + if (containerRef.current && containerRef.current.clientWidth) { + setWidth(containerRef.current.clientWidth); + } + }; + + const handleLegendAllowWrap = (newExtraHeight) => { + if (newExtraHeight !== extraHeight) { + setExtraHeight(newExtraHeight); + } + }; + + const getHeight = (baseHeight) => baseHeight + extraHeight; + + useEffect(() => { + observer.current = getResizeObserver(containerRef.current, handleResize); + handleResize(); + + return () => { + observer.current(); + }; + }, []); + + const height = getHeight(200); + const comparativeWarningMeasureData: Data[] = [{ name: 'Warning', y: 88 }]; + const comparativeWarningMeasureLegendData: Data[] = [{ name: 'Warning' }]; + const primarySegmentedMeasureData: Data[] = [ + { name: 'Measure', y: 25 }, + { name: 'Measure', y: 60 } + ]; + const primarySegmentedMeasureLegendData: Data[] = [{ name: 'Measure 1' }, { name: 'Measure 2' }]; + const qualitativeRangeData: Data[] = [ + { name: 'Range', y: 50 }, + { name: 'Range', y: 75 } + ]; + const qualitativeRangeLegendData: Data[] = [{ name: 'Range 1' }, { name: 'Range 2' }]; + + return ( +
+ `${datum.name}: ${datum.y}`} + legendAllowWrap={handleLegendAllowWrap} + legendPosition="bottom-left" + maxDomain={{ y: 100 }} + name="chart1" + padding={{ + bottom: 50, + left: 50, + right: 50, + top: 100 // Adjusted to accommodate labels + }} + primarySegmentedMeasureData={primarySegmentedMeasureData} + primarySegmentedMeasureLegendData={primarySegmentedMeasureLegendData} + qualitativeRangeData={qualitativeRangeData} + qualitativeRangeLegendData={qualitativeRangeLegendData} + subTitle="Measure details" + title="Text label" + titlePosition="top-left" + width={width} + /> +
+ ); +}; diff --git a/packages/react-charts/src/victory/components/ResizeObserver/examples/ResizeObserverResponsiveStack.tsx b/packages/react-charts/src/victory/components/ResizeObserver/examples/ResizeObserverResponsiveStack.tsx new file mode 100644 index 00000000000..80af5a32c82 --- /dev/null +++ b/packages/react-charts/src/victory/components/ResizeObserver/examples/ResizeObserverResponsiveStack.tsx @@ -0,0 +1,111 @@ +import { Chart, ChartAxis, ChartBar, ChartStack, ChartTooltip } from '@patternfly/react-charts/victory'; +import { getResizeObserver } from '@patternfly/react-core'; +import { useEffect, useRef, useState } from 'react'; + +interface Data { + name?: string; + x?: string; + y?: number; +} + +export const ResizeObserverResponsiveStack: React.FunctionComponent = () => { + const containerRef = useRef(null); + const observer = useRef(() => {}); + const [width, setWidth] = useState(0); + + const handleResize = () => { + if (containerRef.current && containerRef.current.clientWidth) { + setWidth(containerRef.current.clientWidth); + } + }; + + const bars: Data[] = []; + for (let i = 1; i < 32; i++) { + bars.push({ x: `Aug. ${i}`, y: Math.floor(Math.random() * 6) + 1 }); + } + + const renderSocketBars = () => { + const socketBars = bars.map((tick, index) => ({ + key: index, + x: tick.x, + y: tick.y, + name: 'Sockets', + label: `${tick.x} Sockets: ${tick.y}` + })); + return } />; + }; + + const renderCoresBars = () => { + const coresBars = bars.map((tick, index) => ({ + key: index, + x: tick.x, + y: tick.y, + name: 'Cores', + label: `${tick.x} Cores: ${tick.y}` + })); + return } />; + }; + + const renderNodesBars = () => { + const nodesBars = bars.map((tick, index) => ({ + key: index, + x: tick.x, + y: tick.y, + name: 'Nodes', + label: `${tick.x} Nodes: ${tick.y}` + })); + return } />; + }; + + const getTickValues = (offset = 2) => { + const tickValues: string[] = []; + for (let i = 1; i < 32; i++) { + if (i % offset === 0) { + tickValues.push(`Aug. ${i}`); + } + } + return tickValues; + }; + + useEffect(() => { + observer.current = getResizeObserver(containerRef.current, handleResize); + handleResize(); + + return () => { + observer.current(); + }; + }, []); + + const legendData: Data[] = [{ name: 'Sockets' }, { name: 'Cores' }, { name: 'Nodes' }]; + + return ( +
+
+ + + + + {renderSocketBars()} + {renderCoresBars()} + {renderNodesBars()} + + +
+
+ ); +}; diff --git a/packages/react-charts/src/victory/components/ResizeObserver/examples/ResizeObserverResponsiveThreshold.tsx b/packages/react-charts/src/victory/components/ResizeObserver/examples/ResizeObserverResponsiveThreshold.tsx new file mode 100644 index 00000000000..f5330eaa594 --- /dev/null +++ b/packages/react-charts/src/victory/components/ResizeObserver/examples/ResizeObserverResponsiveThreshold.tsx @@ -0,0 +1,147 @@ +import { + Chart, + ChartArea, + ChartAxis, + ChartLegend, + ChartGroup, + ChartThreshold, + ChartThemeColor, + ChartVoronoiContainer +} from '@patternfly/react-charts/victory'; +import { getResizeObserver } from '@patternfly/react-core'; +import chart_color_blue_300 from '@patternfly/react-tokens/dist/esm/chart_color_blue_300'; +import chart_color_orange_300 from '@patternfly/react-tokens/dist/esm/chart_color_orange_300'; +import { useEffect, useRef, useState } from 'react'; + +interface PetData { + name?: string; + symbol?: { fill: string; type: string }; + x?: number; + y?: number; +} + +export const ResizeObserverResponsiveThreshold: React.FunctionComponent = () => { + const containerRef = useRef(null); + const observer = useRef(() => {}); + const [extraHeight, setExtraHeight] = useState(0); + const [width, setWidth] = useState(0); + + const handleResize = () => { + if (containerRef.current && containerRef.current.clientWidth) { + setWidth(containerRef.current.clientWidth); + } + }; + + const handleLegendAllowWrap = (newExtraHeight) => { + if (newExtraHeight !== extraHeight) { + setExtraHeight(newExtraHeight); + } + }; + + const getHeight = (baseHeight) => baseHeight + extraHeight; + + const getPadding = () => ({ + bottom: 100 + extraHeight, // Adjusted to accomodate legend + left: 50, + right: 50, + top: 50 + }); + + useEffect(() => { + observer.current = getResizeObserver(containerRef.current, handleResize); + handleResize(); + + return () => { + observer.current(); + }; + }, []); + + const height = getHeight(250); + const data1: PetData[] = [ + { name: 'Cats' }, + { + name: 'Cats Threshold', + symbol: { fill: chart_color_blue_300.var, type: 'threshold' } + }, + { name: 'Birds' }, + { + name: 'Birds Threshold', + symbol: { fill: chart_color_orange_300.var, type: 'threshold' } + } + ]; + + const data2: PetData[] = [ + { name: 'Cats', x: 1, y: 3 }, + { name: 'Cats', x: 2, y: 4 }, + { name: 'Cats', x: 3, y: 8 }, + { name: 'Cats', x: 4, y: 6 } + ]; + + const data3: PetData[] = [ + { name: 'Birds', x: 1, y: 2 }, + { name: 'Birds', x: 2, y: 3 }, + { name: 'Birds', x: 3, y: 4 }, + { name: 'Birds', x: 4, y: 5 }, + { name: 'Birds', x: 5, y: 6 } + ]; + + const data4: PetData[] = [ + { name: 'Cats Threshold', x: 0, y: 4 }, + { name: 'Cats Threshold', x: 3, y: 4 }, + { name: 'Cats Threshold', x: 3, y: 6 }, + { name: 'Cats Threshold', x: 5, y: 6 } + ]; + + const data5: PetData[] = [ + { name: 'Birds Threshold', x: 0, y: 2 }, + { name: 'Birds Threshold', x: 2, y: 2 }, + { name: 'Birds Threshold', x: 2, y: 3 }, + { name: 'Birds Threshold', x: 5, y: 3 } + ]; + + return ( +
+
+ `${datum.name}: ${datum.y}`} constrainToVisibleArea /> + } + legendAllowWrap={handleLegendAllowWrap} + legendPosition="bottom-left" + legendComponent={} + height={height} + name="chart2" + padding={getPadding()} + maxDomain={{ y: 9 }} + themeColor={ChartThemeColor.multiUnordered} + width={width} + > + + + + + + + + + +
+
+ ); +}; diff --git a/packages/react-charts/src/victory/components/ResizeObserver/examples/resizeObserver.md b/packages/react-charts/src/victory/components/ResizeObserver/examples/resizeObserver.md index ae20c1e35fe..2c6210ad0b2 100644 --- a/packages/react-charts/src/victory/components/ResizeObserver/examples/resizeObserver.md +++ b/packages/react-charts/src/victory/components/ResizeObserver/examples/resizeObserver.md @@ -17,7 +17,7 @@ propComponents: [ hideDarkMode: true --- -import { createRef } from 'react'; +import { useEffect, useRef, useState } from 'react'; import { Chart, ChartArea, @@ -52,361 +52,24 @@ the parent container may be set to the same height and/or width. This demonstrates how to use a `ResizeObserver` to update the chart's width, while its height remains fixed. The `legendAllowWrap` prop is used to automatically wrap legend items. -```js -import { ChartBullet } from '@patternfly/react-charts/victory'; -import { getResizeObserver } from '@patternfly/react-core'; - -class BulletChart extends React.Component { - constructor(props) { - super(props); - this.containerRef = createRef(); - this.observer = () => {}; - this.state = { - extraHeight: 0, - width: 0 - }; - this.handleResize = () => { - if (this.containerRef.current && this.containerRef.current.clientWidth) { - this.setState({ width: this.containerRef.current.clientWidth }); - } - }; - this.handleLegendAllowWrap = (extraHeight) => { - if (extraHeight !== this.state.extraHeight) { - this.setState({ extraHeight }); - } - } - this.getHeight = (baseHeight) => { - const { extraHeight } = this.state; - return baseHeight + extraHeight; - }; - } - - componentDidMount() { - this.observer = getResizeObserver(this.containerRef.current, this.handleResize); - this.handleResize(); - } - - componentWillUnmount() { - this.observer(); - } +```ts file = "ResizeObserverResponsiveBullet.tsx" - render() { - const { width } = this.state; - const height = this.getHeight(200); - return ( -
- `${datum.name}: ${datum.y}`} - legendAllowWrap={this.handleLegendAllowWrap} - legendPosition="bottom-left" - maxDomain={{y: 100}} - name="chart1" - padding={{ - bottom: 50, - left: 50, - right: 50, - top: 100 // Adjusted to accommodate labels - }} - primarySegmentedMeasureData={[{ name: 'Measure', y: 25 }, { name: 'Measure', y: 60 }]} - primarySegmentedMeasureLegendData={[{ name: 'Measure 1' }, { name: 'Measure 2' }]} - qualitativeRangeData={[{ name: 'Range', y: 50 }, { name: 'Range', y: 75 }]} - qualitativeRangeLegendData={[{ name: 'Range 1' }, { name: 'Range 2' }]} - subTitle="Measure details" - title="Text label" - titlePosition="top-left" - width={width} - /> -
- ); - } -} ``` ### Responsive threshold chart with wrapping legend This demonstrates how to use a `ResizeObserver` to update the chart's width, while its height remains fixed. In this example, `itemsPerRow` is used to wrap legend items manually. -```js -import { - Chart, - ChartArea, - ChartAxis, - ChartLegend, - ChartGroup, - ChartThreshold, - ChartThemeColor, - ChartVoronoiContainer -} from '@patternfly/react-charts/victory'; -import { getResizeObserver } from '@patternfly/react-core'; -import chart_color_blue_300 from '@patternfly/react-tokens/dist/esm/chart_color_blue_300'; -import chart_color_orange_300 from '@patternfly/react-tokens/dist/esm/chart_color_orange_300'; - -class MultiColorChart extends React.Component { - constructor(props) { - super(props); - this.containerRef = createRef(); - this.observer = () => {}; - this.state = { - extraHeight: 0, - width: 0 - }; - this.handleResize = () => { - if (this.containerRef.current && this.containerRef.current.clientWidth) { - this.setState({ width: this.containerRef.current.clientWidth }); - } - }; - this.handleLegendAllowWrap = (extraHeight) => { - if (extraHeight !== this.state.extraHeight) { - this.setState({ extraHeight }); - } - } - this.getHeight = (baseHeight) => { - const { extraHeight } = this.state; - return baseHeight + extraHeight; - }; - this.getPadding = () => { - const { extraHeight } = this.state; - return { - bottom: 100 + extraHeight, // Adjusted to accomodate legend - left: 50, - right: 50, - top: 50, - }; - }; - } - - componentDidMount() { - this.observer = getResizeObserver(this.containerRef.current, this.handleResize); - this.handleResize(); - } - - componentWillUnmount() { - this.observer(); - } +```ts file = "ResizeObserverResponsiveThreshold.tsx" - render() { - const { width } = this.state; - const height = this.getHeight(250); - - return ( -
-
- `${datum.name}: ${datum.y}`} - constrainToVisibleArea - /> - } - legendAllowWrap={this.handleLegendAllowWrap} - legendPosition="bottom-left" - legendComponent={ - - } - height={height} - name="chart2" - padding={this.getPadding()} - maxDomain={{ y: 9 }} - themeColor={ChartThemeColor.multiUnordered} - width={width} - > - - - - - - - - - -
-
- ); - } -} ``` ### Responsive stack chart with reducible axis tick labels This demonstrates how to use a `ResizeObserver` to update the chart's width, while its height remains fixed. In this example, `fixLabelOverlap` is used to dynamically adjust the number of axis tick labels. -```js -import { Chart, ChartAxis, ChartBar, ChartStack, ChartTooltip } from '@patternfly/react-charts/victory'; -import { getResizeObserver } from '@patternfly/react-core'; - -class MonthlyResponsiveStack extends React.Component { - constructor(props) { - super(props); - this.containerRef = createRef(); - this.observer = () => {}; - this.state = { - width: 0 - }; - - this.handleResize = () => { - if(this.containerRef.current && this.containerRef.current.clientWidth){ - this.setState({ width: this.containerRef.current.clientWidth }); - } - }; - - this.bars = []; - for(let i = 1; i < 32; i++){ - this.bars.push({ x: `Aug. ${i}`, y: Math.floor(Math.random() * 6) + 1 }); - }; - - this.renderSocketBars = () => { - let socketBars = this.bars.map((tick, index) => { - return { - x: tick.x, - y: tick.y, - name: 'Sockets', - label: `${tick.x} Sockets: ${tick.y}` - }; - }); - return } />; - } - - this.renderCoresBars = () => { - let coresBars = this.bars.map((tick, index) => { - return { - x: tick.x, - y: tick.y, - name: 'Cores', - label: `${tick.x} Cores: ${tick.y}` - }; - }); - return } />; - } - - this.renderNodesBars = () => { - let nodesBars = this.bars.map((tick, index) => { - return { - key: index, - x: tick.x, - y: tick.y, - name: 'Nodes', - label: `${tick.x} Nodes: ${tick.y}` - }; - }); - return } />; - } - - this.getTickValues = (offset = 2) => { - let tickValues = []; - for(let i = 1; i < 32; i++){ - if (i % offset == 0){ - tickValues.push(`Aug. ${i}`); - } - } - return tickValues; - } - } - - componentDidMount() { - this.observer = getResizeObserver(this.containerRef.current, this.handleResize); - this.handleResize(); - } - - componentWillUnmount() { - this.observer(); - } +```ts file = "ResizeObserverResponsiveStack.tsx" - render(){ - const { width } = this.state; - return ( -
-
- - - - - { this.renderSocketBars() } - { this.renderCoresBars() } - { this.renderNodesBars() } - - -
-
- ) - } -} ``` ## Documentation diff --git a/packages/react-charts/src/victory/components/Skeletons/examples/SkeletonsAreaChart.tsx b/packages/react-charts/src/victory/components/Skeletons/examples/SkeletonsAreaChart.tsx new file mode 100644 index 00000000000..f9a758b240f --- /dev/null +++ b/packages/react-charts/src/victory/components/Skeletons/examples/SkeletonsAreaChart.tsx @@ -0,0 +1,85 @@ +import { + Chart, + ChartArea, + ChartAxis, + ChartGroup, + ChartThemeColor, + ChartVoronoiContainer +} from '@patternfly/react-charts/victory'; +import { Switch } from '@patternfly/react-core'; +import { useState } from 'react'; + +interface PetData { + name?: string; + x?: string; + y?: number; +} + +export const SkeletonsAreaChart: React.FunctionComponent = () => { + const [isChecked, setIsChecked] = useState(true); + + const handleChange = (_event: React.FormEvent, checked: boolean) => { + setIsChecked(checked); + }; + + const legendData: PetData[] = [{ name: 'Cats' }, { name: 'Dogs' }, { name: 'Birds' }]; + const data1: PetData[] = [ + { name: 'Cats', x: '2015', y: 3 }, + { name: 'Cats', x: '2016', y: 4 }, + { name: 'Cats', x: '2017', y: 8 }, + { name: 'Cats', x: '2018', y: 6 } + ]; + + const data2: PetData[] = [ + { name: 'Dogs', x: '2015', y: 2 }, + { name: 'Dogs', x: '2016', y: 3 }, + { name: 'Dogs', x: '2017', y: 4 }, + { name: 'Dogs', x: '2018', y: 5 }, + { name: 'Dogs', x: '2019', y: 6 } + ]; + + const data3: PetData[] = [ + { name: 'Birds', x: '2015', y: 1 }, + { name: 'Birds', x: '2016', y: 2 }, + { name: 'Birds', x: '2017', y: 3 }, + { name: 'Birds', x: '2018', y: 2 }, + { name: 'Birds', x: '2019', y: 4 } + ]; + + return ( + <> + +
+ `${datum.name}: ${datum.y}`} constrainToVisibleArea /> + } + legendData={legendData} + legendOrientation="vertical" + legendPosition="right" + height={200} + maxDomain={{ y: 9 }} + name="chart1" + padding={{ + bottom: 50, + left: 50, + right: 200, // Adjusted to accommodate legend + top: 50 + }} + themeColor={isChecked ? ChartThemeColor.skeleton : ChartThemeColor.blue} + width={800} + > + + + + + + + + +
+ + ); +}; diff --git a/packages/react-charts/src/victory/components/Skeletons/examples/SkeletonsBarChart.tsx b/packages/react-charts/src/victory/components/Skeletons/examples/SkeletonsBarChart.tsx new file mode 100644 index 00000000000..35e8c2ceecb --- /dev/null +++ b/packages/react-charts/src/victory/components/Skeletons/examples/SkeletonsBarChart.tsx @@ -0,0 +1,92 @@ +import { Switch } from '@patternfly/react-core'; +import { + Chart, + ChartBar, + ChartAxis, + ChartGroup, + ChartThemeColor, + ChartVoronoiContainer +} from '@patternfly/react-charts/victory'; +import { useState } from 'react'; + +interface PetData { + name?: string; + x?: string; + y?: number; +} + +export const SkeletonsBarChart: React.FunctionComponent = () => { + const [isChecked, setIsChecked] = useState(true); + + const handleChange = (_event: React.FormEvent, checked: boolean) => { + setIsChecked(checked); + }; + + const legendData: PetData[] = [{ name: 'Cats' }, { name: 'Dogs' }, { name: 'Birds' }, { name: 'Mice' }]; + const data1: PetData[] = [ + { name: 'Cats', x: '2015', y: 1 }, + { name: 'Cats', x: '2016', y: 2 }, + { name: 'Cats', x: '2017', y: 5 }, + { name: 'Cats', x: '2018', y: 3 } + ]; + + const data2: PetData[] = [ + { name: 'Dogs', x: '2015', y: 2 }, + { name: 'Dogs', x: '2016', y: 1 }, + { name: 'Dogs', x: '2017', y: 7 }, + { name: 'Dogs', x: '2018', y: 4 } + ]; + + const data3: PetData[] = [ + { name: 'Birds', x: '2015', y: 4 }, + { name: 'Birds', x: '2016', y: 4 }, + { name: 'Birds', x: '2017', y: 9 }, + { name: 'Birds', x: '2018', y: 7 } + ]; + + const data4: PetData[] = [ + { name: 'Mice', x: '2015', y: 3 }, + { name: 'Mice', x: '2016', y: 3 }, + { name: 'Mice', x: '2017', y: 8 }, + { name: 'Mice', x: '2018', y: 5 } + ]; + + return ( + <> + +
+ `${datum.name}: ${datum.y}`} constrainToVisibleArea /> + } + domain={{ y: [0, 9] }} + domainPadding={{ x: [30, 25] }} + legendData={legendData} + legendOrientation="vertical" + legendPosition="right" + height={250} + name="chart2" + padding={{ + bottom: 50, + left: 50, + right: 200, // Adjusted to accommodate legend + top: 50 + }} + themeColor={isChecked ? ChartThemeColor.skeleton : ChartThemeColor.blue} + width={600} + > + + + + + + + + + +
+ + ); +}; diff --git a/packages/react-charts/src/victory/components/Skeletons/examples/SkeletonsBoxPlotChart.tsx b/packages/react-charts/src/victory/components/Skeletons/examples/SkeletonsBoxPlotChart.tsx new file mode 100644 index 00000000000..6a89f4ca625 --- /dev/null +++ b/packages/react-charts/src/victory/components/Skeletons/examples/SkeletonsBoxPlotChart.tsx @@ -0,0 +1,56 @@ +import { Switch } from '@patternfly/react-core'; +import { Chart, ChartAxis, ChartBoxPlot, ChartThemeColor } from '@patternfly/react-charts/victory'; +import { useState } from 'react'; + +interface PetData { + name?: string; + x?: string; + y?: number[]; +} + +export const SkeletonsBoxPlotChart: React.FunctionComponent = () => { + const [isChecked, setIsChecked] = useState(true); + + const handleChange = (_event: React.FormEvent, checked: boolean) => { + setIsChecked(checked); + }; + + const legendData: PetData[] = [{ name: 'Cats' }]; + const data: PetData[] = [ + { name: 'Cats', x: '2015', y: [1, 2, 3, 5] }, + { name: 'Cats', x: '2016', y: [3, 2, 8, 10] }, + { name: 'Cats', x: '2017', y: [2, 8, 6, 5] }, + { name: 'Cats', x: '2018', y: [1, 3, 2, 9] } + ]; + + return ( + <> + +
+ + + + + +
+ + ); +}; diff --git a/packages/react-charts/src/victory/components/Skeletons/examples/SkeletonsBulletChart.tsx b/packages/react-charts/src/victory/components/Skeletons/examples/SkeletonsBulletChart.tsx new file mode 100644 index 00000000000..27ce6fa524b --- /dev/null +++ b/packages/react-charts/src/victory/components/Skeletons/examples/SkeletonsBulletChart.tsx @@ -0,0 +1,63 @@ +import { Switch } from '@patternfly/react-core'; +import { ChartBullet, ChartLegend, ChartThemeColor } from '@patternfly/react-charts/victory'; +import { useState } from 'react'; + +interface Data { + name?: string; + y?: number; +} + +export const SkeletonsBulletChart: React.FunctionComponent = () => { + const [isChecked, setIsChecked] = useState(true); + + const handleChange = (_event: React.FormEvent, checked: boolean) => { + setIsChecked(checked); + }; + + const comparativeWarningMeasureData: Data[] = [{ name: 'Warning', y: 88 }]; + const comparativeWarningMeasureLegendData: Data[] = [{ name: 'Warning' }]; + const primarySegmentedMeasureData: Data[] = [ + { name: 'Measure', y: 25 }, + { name: 'Measure', y: 60 } + ]; + const primarySegmentedMeasureLegendData: Data[] = [{ name: 'Measure' }, { name: 'Measure' }]; + const qualitativeRangeData: Data[] = [ + { name: 'Range', y: 50 }, + { name: 'Range', y: 75 } + ]; + const qualitativeRangeLegendData: Data[] = [{ name: 'Range' }, { name: 'Range' }]; + + return ( + <> + +
+ `${datum.name}: ${datum.y}`} + legendComponent={} + maxDomain={{ y: 100 }} + name="chart4" + padding={{ + bottom: 50, + left: 150, // Adjusted to accommodate labels + right: 50, + top: 50 + }} + primarySegmentedMeasureData={primarySegmentedMeasureData} + primarySegmentedMeasureLegendData={primarySegmentedMeasureLegendData} + qualitativeRangeData={qualitativeRangeData} + qualitativeRangeLegendData={qualitativeRangeLegendData} + subTitle="Details" + title="Text label" + themeColor={isChecked ? ChartThemeColor.skeleton : ChartThemeColor.blue} + width={600} + /> +
+ + ); +}; diff --git a/packages/react-charts/src/victory/components/Skeletons/examples/SkeletonsDonutChart.tsx b/packages/react-charts/src/victory/components/Skeletons/examples/SkeletonsDonutChart.tsx new file mode 100644 index 00000000000..dcc2b31f7fd --- /dev/null +++ b/packages/react-charts/src/victory/components/Skeletons/examples/SkeletonsDonutChart.tsx @@ -0,0 +1,42 @@ +import { Switch } from '@patternfly/react-core'; +import { ChartDonut, ChartThemeColor } from '@patternfly/react-charts/victory'; +import { useState } from 'react'; + +interface PetData { + name?: string; + x?: string; + y?: number; +} + +export const SkeletonsDonutChart: React.FunctionComponent = () => { + const [isChecked, setIsChecked] = useState(true); + + const handleChange = (_event: React.FormEvent, checked: boolean) => { + setIsChecked(checked); + }; + + const data: PetData[] = [ + { x: 'Cats', y: 35 }, + { x: 'Dogs', y: 55 }, + { x: 'Birds', y: 10 } + ]; + + return ( + <> + +
+ `${datum.x}: ${datum.y}%`} + name="chart5" + subTitle="Pets" + themeColor={isChecked ? ChartThemeColor.skeleton : ChartThemeColor.blue} + title="100" + /> +
+ + ); +}; diff --git a/packages/react-charts/src/victory/components/Skeletons/examples/SkeletonsDonutUtilizationChart.tsx b/packages/react-charts/src/victory/components/Skeletons/examples/SkeletonsDonutUtilizationChart.tsx new file mode 100644 index 00000000000..1ab3ac3537d --- /dev/null +++ b/packages/react-charts/src/victory/components/Skeletons/examples/SkeletonsDonutUtilizationChart.tsx @@ -0,0 +1,54 @@ +import { Switch } from '@patternfly/react-core'; +import { ChartDonutUtilization, ChartThemeColor } from '@patternfly/react-charts/victory'; +import { useState } from 'react'; + +interface Data { + name?: string; + x?: string; + y?: number; +} + +export const SkeletonsDonutUtilizationChart: React.FunctionComponent = () => { + const [isChecked, setIsChecked] = useState(true); + + const handleChange = (_event: React.FormEvent, checked: boolean) => { + setIsChecked(checked); + }; + + const legendData: Data[] = [{ name: `Storage capacity: 75%` }, { name: 'Unused' }]; + const data: Data = { x: 'GBps capacity', y: 35 }; + + return ( + <> + +
+ (datum.x ? `${datum.x}: ${datum.y}%` : null)} + legendData={legendData} + legendOrientation="vertical" + name="chart6" + padding={{ + bottom: 20, + left: 20, + right: 225, // Adjusted to accommodate legend + top: 20 + }} + subTitle="of 100 GBps" + title="35%" + thresholds={[{ value: 60 }, { value: 90 }]} + themeColor={isChecked ? ChartThemeColor.skeleton : ChartThemeColor.blue} + width={435} + /> +
+ + ); +}; diff --git a/packages/react-charts/src/victory/components/Skeletons/examples/SkeletonsDonutUtilizationThreshold.tsx b/packages/react-charts/src/victory/components/Skeletons/examples/SkeletonsDonutUtilizationThreshold.tsx new file mode 100644 index 00000000000..6f46040edac --- /dev/null +++ b/packages/react-charts/src/victory/components/Skeletons/examples/SkeletonsDonutUtilizationThreshold.tsx @@ -0,0 +1,51 @@ +import { Switch } from '@patternfly/react-core'; +import { ChartDonutThreshold, ChartDonutUtilization, ChartThemeColor } from '@patternfly/react-charts/victory'; +import { useState } from 'react'; + +interface Data { + x: string; + y: number; +} + +export const SkeletonsDonutUtilizationThreshold: React.FunctionComponent = () => { + const [isChecked, setIsChecked] = useState(true); + + const handleChange = (_event: React.FormEvent, checked: boolean) => { + setIsChecked(checked); + }; + + const data1: Data[] = [ + { x: 'Warning at 60%', y: 60 }, + { x: 'Danger at 90%', y: 90 } + ]; + const data2: Data = { x: 'Storage capacity', y: 45 }; + + return ( + <> + +
+ (datum.x ? datum.x : null)} + name="chart7" + themeColor={isChecked ? ChartThemeColor.skeleton : ChartThemeColor.blue} + > + (datum.x ? `${datum.x}: ${datum.y}%` : null)} + subTitle="of 100 GBps" + title="45%" + /> + +
+ + ); +}; diff --git a/packages/react-charts/src/victory/components/Skeletons/examples/SkeletonsLineChart.tsx b/packages/react-charts/src/victory/components/Skeletons/examples/SkeletonsLineChart.tsx new file mode 100644 index 00000000000..0a3c54ebecb --- /dev/null +++ b/packages/react-charts/src/victory/components/Skeletons/examples/SkeletonsLineChart.tsx @@ -0,0 +1,105 @@ +import { Switch } from '@patternfly/react-core'; +import { + Chart, + ChartVoronoiContainer, + ChartGroup, + ChartAxis, + ChartLine, + ChartThemeColor +} from '@patternfly/react-charts/victory'; +import { useState } from 'react'; + +interface PetData { + name?: string; + symbol?: { type: string }; + x?: string; + y?: number; +} + +export const SkeletonsLineChart: React.FunctionComponent = () => { + const [isChecked, setIsChecked] = useState(true); + + const handleChange = (_event: React.FormEvent, checked: boolean) => { + setIsChecked(checked); + }; + + const legendData: PetData[] = [ + { name: 'Cats' }, + { name: 'Dogs', symbol: { type: 'dash' } }, + { name: 'Birds' }, + { name: 'Mice' } + ]; + const data1: PetData[] = [ + { name: 'Cats', x: '2015', y: 1 }, + { name: 'Cats', x: '2016', y: 2 }, + { name: 'Cats', x: '2017', y: 5 }, + { name: 'Cats', x: '2018', y: 3 } + ]; + + const data2: PetData[] = [ + { name: 'Dogs', x: '2015', y: 2 }, + { name: 'Dogs', x: '2016', y: 1 }, + { name: 'Dogs', x: '2017', y: 7 }, + { name: 'Dogs', x: '2018', y: 4 } + ]; + + const data3: PetData[] = [ + { name: 'Birds', x: '2015', y: 3 }, + { name: 'Birds', x: '2016', y: 4 }, + { name: 'Birds', x: '2017', y: 9 }, + { name: 'Birds', x: '2018', y: 5 } + ]; + + const data4: PetData[] = [ + { name: 'Mice', x: '2015', y: 3 }, + { name: 'Mice', x: '2016', y: 3 }, + { name: 'Mice', x: '2017', y: 8 }, + { name: 'Mice', x: '2018', y: 7 } + ]; + + return ( + <> + +
+ `${datum.name}: ${datum.y}`} constrainToVisibleArea /> + } + legendData={legendData} + legendOrientation="vertical" + legendPosition="right" + height={250} + maxDomain={{ y: 10 }} + minDomain={{ y: 0 }} + name="chart8" + padding={{ + bottom: 50, + left: 50, + right: 200, // Adjusted to accommodate legend + top: 50 + }} + themeColor={isChecked ? ChartThemeColor.skeleton : ChartThemeColor.blue} + width={600} + > + + + + + + + + + +
+ + ); +}; diff --git a/packages/react-charts/src/victory/components/Skeletons/examples/SkeletonsPieChart.tsx b/packages/react-charts/src/victory/components/Skeletons/examples/SkeletonsPieChart.tsx new file mode 100644 index 00000000000..41deb950a77 --- /dev/null +++ b/packages/react-charts/src/victory/components/Skeletons/examples/SkeletonsPieChart.tsx @@ -0,0 +1,52 @@ +import { Switch } from '@patternfly/react-core'; +import { ChartPie, ChartThemeColor } from '@patternfly/react-charts/victory'; +import { useState } from 'react'; + +interface PetData { + name?: string; + x?: string; + y?: number; +} + +export const SkeletonsPieChart: React.FunctionComponent = () => { + const [isChecked, setIsChecked] = useState(true); + + const handleChange = (_event: React.FormEvent, checked: boolean) => { + setIsChecked(checked); + }; + + const data: PetData[] = [ + { x: 'Cats', y: 35 }, + { x: 'Dogs', y: 55 }, + { x: 'Birds', y: 10 } + ]; + const legendData: PetData[] = [{ name: 'Cats: 35' }, { name: 'Dogs: 55' }, { name: 'Birds: 10' }]; + + return ( + <> + +
+ `${datum.x}: ${datum.y}`} + legendData={legendData} + legendOrientation="vertical" + legendPosition="right" + name="chart9" + padding={{ + bottom: 20, + left: 20, + right: 140, // Adjusted to accommodate legend + top: 20 + }} + themeColor={isChecked ? ChartThemeColor.skeleton : ChartThemeColor.blue} + width={350} + /> +
+ + ); +}; diff --git a/packages/react-charts/src/victory/components/Skeletons/examples/SkeletonsScatterChart.tsx b/packages/react-charts/src/victory/components/Skeletons/examples/SkeletonsScatterChart.tsx new file mode 100644 index 00000000000..657e0270bd9 --- /dev/null +++ b/packages/react-charts/src/victory/components/Skeletons/examples/SkeletonsScatterChart.tsx @@ -0,0 +1,58 @@ +import { Switch } from '@patternfly/react-core'; +import { + Chart, + ChartVoronoiContainer, + ChartGroup, + ChartAxis, + ChartScatter, + ChartThemeColor +} from '@patternfly/react-charts/victory'; +import { useState } from 'react'; + +interface PetData { + name?: string; + x?: string; + y?: number; +} + +export const SkeletonsScatterChart: React.FunctionComponent = () => { + const [isChecked, setIsChecked] = useState(true); + + const handleChange = (_event: React.FormEvent, checked: boolean) => { + setIsChecked(checked); + }; + + const data: PetData[] = [ + { name: 'Cats', x: '2015', y: 1 }, + { name: 'Cats', x: '2016', y: 2 }, + { name: 'Cats', x: '2017', y: 5 }, + { name: 'Cats', x: '2018', y: 4 } + ]; + + return ( + <> + +
+ `${datum.name}: ${datum.y}`} constrainToVisibleArea /> + } + height={275} + maxDomain={{ y: 8 }} + minDomain={{ y: 0 }} + name="chart10" + themeColor={isChecked ? ChartThemeColor.skeleton : ChartThemeColor.blue} + width={450} + > + + + + + + +
+ + ); +}; diff --git a/packages/react-charts/src/victory/components/Skeletons/examples/SkeletonsStackChart.tsx b/packages/react-charts/src/victory/components/Skeletons/examples/SkeletonsStackChart.tsx new file mode 100644 index 00000000000..2dcb61460bb --- /dev/null +++ b/packages/react-charts/src/victory/components/Skeletons/examples/SkeletonsStackChart.tsx @@ -0,0 +1,91 @@ +import { Switch } from '@patternfly/react-core'; +import { + Chart, + ChartVoronoiContainer, + ChartAxis, + ChartStack, + ChartBar, + ChartThemeColor +} from '@patternfly/react-charts/victory'; +import { useState } from 'react'; + +interface PetData { + name?: string; + x?: string; + y?: number; +} + +export const SkeletonsStackChart: React.FunctionComponent = () => { + const [isChecked, setIsChecked] = useState(true); + + const handleChange = (_event: React.FormEvent, checked: boolean) => { + setIsChecked(checked); + }; + + const legendData: PetData[] = [{ name: 'Cats' }, { name: 'Dogs' }, { name: 'Birds' }, { name: 'Mice' }]; + const data1: PetData[] = [ + { name: 'Cats', x: '2015', y: 1 }, + { name: 'Cats', x: '2016', y: 2 }, + { name: 'Cats', x: '2017', y: 5 }, + { name: 'Cats', x: '2018', y: 3 } + ]; + + const data2: PetData[] = [ + { name: 'Dogs', x: '2015', y: 2 }, + { name: 'Dogs', x: '2016', y: 1 }, + { name: 'Dogs', x: '2017', y: 7 }, + { name: 'Dogs', x: '2018', y: 4 } + ]; + + const data3: PetData[] = [ + { name: 'Birds', x: '2015', y: 4 }, + { name: 'Birds', x: '2016', y: 4 }, + { name: 'Birds', x: '2017', y: 9 }, + { name: 'Birds', x: '2018', y: 7 } + ]; + + const data4: PetData[] = [ + { name: 'Mice', x: '2015', y: 3 }, + { name: 'Mice', x: '2016', y: 3 }, + { name: 'Mice', x: '2017', y: 8 }, + { name: 'Mice', x: '2018', y: 5 } + ]; + + return ( + <> + +
+ `${datum.name}: ${datum.y}`} constrainToVisibleArea /> + } + domainPadding={{ x: [30, 25] }} + legendData={legendData} + legendOrientation="vertical" + legendPosition="right" + height={250} + name="chart11" + padding={{ + bottom: 50, + left: 50, + right: 200, // Adjusted to accommodate legend + top: 50 + }} + themeColor={isChecked ? ChartThemeColor.skeleton : ChartThemeColor.blue} + width={600} + > + + + + + + + + + +
+ + ); +}; diff --git a/packages/react-charts/src/victory/components/Skeletons/examples/SkeletonsThresholdChart.tsx b/packages/react-charts/src/victory/components/Skeletons/examples/SkeletonsThresholdChart.tsx new file mode 100644 index 00000000000..55c8d2ee6a5 --- /dev/null +++ b/packages/react-charts/src/victory/components/Skeletons/examples/SkeletonsThresholdChart.tsx @@ -0,0 +1,102 @@ +import { Switch } from '@patternfly/react-core'; +import { + Chart, + ChartArea, + ChartAxis, + ChartGroup, + ChartLegend, + ChartThemeColor, + ChartThreshold, + ChartVoronoiContainer +} from '@patternfly/react-charts/victory'; +import chart_color_blue_300 from '@patternfly/react-tokens/dist/esm/chart_color_blue_300'; +import { useState } from 'react'; + +interface PetData { + name?: string; + symbol?: { fill: string | undefined; type: string }; + x?: number; + y?: number; +} + +export const SkeletonsThresholdChart: React.FunctionComponent = () => { + const [isChecked, setIsChecked] = useState(true); + + const handleChange = (_event: React.FormEvent, checked: boolean) => { + setIsChecked(checked); + }; + + const data1: PetData[] = [ + { name: 'Cats' }, + { name: 'Birds' }, + { + name: 'Threshold', + symbol: { fill: isChecked ? undefined : chart_color_blue_300.var, type: 'threshold' } + } + ]; + + const data2: PetData[] = [ + { name: 'Cats', x: 1, y: 3 }, + { name: 'Cats', x: 2, y: 4 }, + { name: 'Cats', x: 3, y: 8 }, + { name: 'Cats', x: 4, y: 6 } + ]; + + const data3: PetData[] = [ + { name: 'Birds', x: 1, y: 2 }, + { name: 'Birds', x: 2, y: 3 }, + { name: 'Birds', x: 3, y: 4 }, + { name: 'Birds', x: 4, y: 5 }, + { name: 'Birds', x: 5, y: 6 } + ]; + + const data4: PetData[] = [ + { name: 'Cats Threshold', x: 0, y: 5 }, + { name: 'Cats Threshold', x: 3, y: 5 }, + { name: 'Cats Threshold', x: 3, y: 7 }, + { name: 'Cats Threshold', x: 5, y: 7 } + ]; + + return ( + <> + +
+ `${datum.name}: ${datum.y}`} constrainToVisibleArea /> + } + legendPosition="bottom-left" + legendComponent={} + height={250} + padding={{ + bottom: 100, // Adjusted to accommodate legend + left: 50, + right: 50, + top: 50 + }} + maxDomain={{ y: 9 }} + name="chart12" + themeColor={isChecked ? ChartThemeColor.skeleton : ChartThemeColor.blue} + width={800} + > + + + + + + + + +
+ + ); +}; diff --git a/packages/react-charts/src/victory/components/Skeletons/examples/skeletons.md b/packages/react-charts/src/victory/components/Skeletons/examples/skeletons.md index 950ae09a827..c42d5981666 100644 --- a/packages/react-charts/src/victory/components/Skeletons/examples/skeletons.md +++ b/packages/react-charts/src/victory/components/Skeletons/examples/skeletons.md @@ -35,725 +35,63 @@ The examples below are based on the [Victory](https://formidable.com/open-source ## Examples ### Area chart -```js -import { Chart, ChartArea, ChartAxis, ChartGroup, ChartThemeColor, ChartVoronoiContainer } from '@patternfly/react-charts/victory'; -import { Switch } from '@patternfly/react-core'; +```ts file = "SkeletonsAreaChart.tsx" -export const ChartAreaSkeleton: React.FunctionComponent = () => { - const [isChecked, setIsChecked] = useState(true); - - const handleChange = (_event: React.FormEvent, checked: boolean) => { - setIsChecked(checked); - }; - - return ( - <> - -
- `${datum.name}: ${datum.y}`} constrainToVisibleArea />} - legendData={[{ name: 'Cats' }, { name: 'Dogs' }, { name: 'Birds' }]} - legendOrientation="vertical" - legendPosition="right" - height={200} - maxDomain={{y: 9}} - name="chart1" - padding={{ - bottom: 50, - left: 50, - right: 200, // Adjusted to accommodate legend - top: 50 - }} - themeColor={isChecked ? ChartThemeColor.skeleton : ChartThemeColor.blue} - width={800} - > - - - - - - - - -
- - ); -} ``` ### Bar chart -```js -import { Switch } from '@patternfly/react-core'; -import { Chart, ChartBar, ChartAxis, ChartGroup, ChartThemeColor, ChartVoronoiContainer } from '@patternfly/react-charts/victory'; - -export const ChartBarSkeleton: React.FunctionComponent = () => { - const [isChecked, setIsChecked] = useState(true); - - const handleChange = (_event: React.FormEvent, checked: boolean) => { - setIsChecked(checked); - }; +```ts file = "SkeletonsBarChart.tsx" - return ( - <> - -
- `${datum.name}: ${datum.y}`} constrainToVisibleArea />} - domain={{y: [0,9]}} - domainPadding={{ x: [30, 25] }} - legendData={[{ name: 'Cats' }, { name: 'Dogs' }, { name: 'Birds' }, { name: 'Mice' }]} - legendOrientation="vertical" - legendPosition="right" - height={250} - name="chart2" - padding={{ - bottom: 50, - left: 50, - right: 200, // Adjusted to accommodate legend - top: 50 - }} - themeColor={isChecked ? ChartThemeColor.skeleton : ChartThemeColor.blue} - width={600} - > - - - - - - - - - -
- - ); -} ``` ### Box plot chart -```js -import { Switch } from '@patternfly/react-core' -import { Chart, ChartAxis, ChartBoxPlot, ChartThemeColor } from '@patternfly/react-charts/victory'; +```ts file = "SkeletonsBoxPlotChart.tsx" -export const ChartBoxPlotSkeleton: React.FunctionComponent = () => { - const [isChecked, setIsChecked] = useState(true); - - const handleChange = (_event: React.FormEvent, checked: boolean) => { - setIsChecked(checked); - }; - - return ( - <> - -
- - - - - -
- - ); -} ``` ### Bullet chart -```js -import { Switch } from '@patternfly/react-core'; -import { Chart, ChartAxis, ChartBullet, ChartLegend, ChartThemeColor } from '@patternfly/react-charts/victory'; - -export const ChartBulletSkeleton: React.FunctionComponent = () => { - const [isChecked, setIsChecked] = useState(true); +```ts file = "SkeletonsBulletChart.tsx" - const handleChange = (_event: React.FormEvent, checked: boolean) => { - setIsChecked(checked); - }; - - return ( - <> - -
- `${datum.name}: ${datum.y}`} - legendComponent={} - maxDomain={{y: 100}} - name="chart4" - padding={{ - bottom: 50, - left: 150, // Adjusted to accommodate labels - right: 50, - top: 50 - }} - primarySegmentedMeasureData={[{ name: 'Measure', y: 25 }, { name: 'Measure', y: 60 }]} - primarySegmentedMeasureLegendData={[{ name: 'Measure' }, { name: 'Measure' }]} - qualitativeRangeData={[{ name: 'Range', y: 50 }, { name: 'Range', y: 75 }]} - qualitativeRangeLegendData={[{ name: 'Range' }, { name: 'Range' }]} - subTitle="Details" - title="Text label" - themeColor={isChecked ? ChartThemeColor.skeleton : ChartThemeColor.blue} - width={600} - /> -
- - ); -} ``` ### Donut chart -```js -import { Switch } from '@patternfly/react-core'; -import { Chart, ChartAxis, ChartDonut, ChartThemeColor } from '@patternfly/react-charts/victory'; - -export const ChartDonutSkeleton: React.FunctionComponent = () => { - const [isChecked, setIsChecked] = useState(true); - - const handleChange = (_event: React.FormEvent, checked: boolean) => { - setIsChecked(checked); - }; +```ts file = "SkeletonsDonutChart.tsx" - return ( - <> - -
- `${datum.x}: ${datum.y}%`} - name="chart5" - subTitle="Pets" - themeColor={isChecked ? ChartThemeColor.skeleton : ChartThemeColor.blue} - title="100" - /> -
- - ); -} ``` ### Donut utilization chart -```js -import { Switch } from '@patternfly/react-core'; -import { Chart, ChartAxis, ChartDonutUtilization, ChartThemeColor } from '@patternfly/react-charts/victory'; +```ts file = "SkeletonsDonutUtilizationChart.tsx" -export const ChartDonutUtilizationSkeleton: React.FunctionComponent = () => { - const [isChecked, setIsChecked] = useState(true); - - const handleChange = (_event: React.FormEvent, checked: boolean) => { - setIsChecked(checked); - }; - - return ( - <> - -
- datum.x ? `${datum.x}: ${datum.y}%` : null} - legendData={[{ name: `Storage capacity: 75%` }, { name: 'Unused' }]} - legendOrientation="vertical" - name="chart6" - padding={{ - bottom: 20, - left: 20, - right: 225, // Adjusted to accommodate legend - top: 20 - }} - subTitle="of 100 GBps" - title="35%" - thresholds={[{ value: 60 }, { value: 90 }]} - themeColor={isChecked ? ChartThemeColor.skeleton : ChartThemeColor.blue} - width={435} - /> -
- - ); -} ``` ### Donut utilization threshold -```js -import { Switch } from '@patternfly/react-core'; -import { Chart, ChartAxis, ChartDonutThreshold, ChartDonutUtilization, ChartThemeColor } from '@patternfly/react-charts/victory'; - -export const ChartDonutUtilizationSkeleton: React.FunctionComponent = () => { - const [isChecked, setIsChecked] = useState(true); +```ts file = "SkeletonsDonutUtilizationThreshold.tsx" - const handleChange = (_event: React.FormEvent, checked: boolean) => { - setIsChecked(checked); - }; - - return ( - <> - -
- datum.x ? datum.x : null} - name="chart7" - themeColor={isChecked ? ChartThemeColor.skeleton : ChartThemeColor.blue} - > - datum.x ? `${datum.x}: ${datum.y}%` : null} - subTitle="of 100 GBps" - title="45%" - /> - -
- - ); -} ``` ### Line chart -```js -import { Switch } from '@patternfly/react-core'; -import { Chart, ChartVoronoiContainer, ChartGroup, ChartAxis, ChartLine, ChartThemeColor } from '@patternfly/react-charts/victory'; - -export const ChartLineSkeleton: React.FunctionComponent = () => { - const [isChecked, setIsChecked] = useState(true); - - const handleChange = (_event: React.FormEvent, checked: boolean) => { - setIsChecked(checked); - }; +```ts file = "SkeletonsLineChart.tsx" - return ( - <> - -
- `${datum.name}: ${datum.y}`} constrainToVisibleArea />} - legendData={[{ name: 'Cats' }, { name: 'Dogs', symbol: { type: 'dash' } }, { name: 'Birds' }, { name: 'Mice' }]} - legendOrientation="vertical" - legendPosition="right" - height={250} - maxDomain={{y: 10}} - minDomain={{y: 0}} - name="chart8" - padding={{ - bottom: 50, - left: 50, - right: 200, // Adjusted to accommodate legend - top: 50 - }} - themeColor={isChecked ? ChartThemeColor.skeleton : ChartThemeColor.blue} - width={600} - > - - - - - - - - - -
- - ); -} ``` ### Pie chart -```js -import { Switch } from '@patternfly/react-core'; -import { Chart, ChartAxis, ChartPie, ChartThemeColor } from '@patternfly/react-charts/victory'; +```ts file = "SkeletonsPieChart.tsx" -export const ChartPieSkeleton: React.FunctionComponent = () => { - const [isChecked, setIsChecked] = useState(true); - - const handleChange = (_event: React.FormEvent, checked: boolean) => { - setIsChecked(checked); - }; - - return ( - <> - -
- `${datum.x}: ${datum.y}`} - legendData={[{ name: 'Cats: 35' }, { name: 'Dogs: 55' }, { name: 'Birds: 10' }]} - legendOrientation="vertical" - legendPosition="right" - name="chart9" - padding={{ - bottom: 20, - left: 20, - right: 140, // Adjusted to accommodate legend - top: 20 - }} - themeColor={isChecked ? ChartThemeColor.skeleton : ChartThemeColor.blue} - width={350} - /> -
- - ); -} ``` ### Scatter chart -```js -import { Switch } from '@patternfly/react-core'; -import { Chart, ChartVoronoiContainer, ChartGroup, ChartAxis, ChartScatter, ChartThemeColor } from '@patternfly/react-charts/victory'; - -export const ChartScatterSkeleton: React.FunctionComponent = () => { - const [isChecked, setIsChecked] = useState(true); +```ts file = "SkeletonsScatterChart.tsx" - const handleChange = (_event: React.FormEvent, checked: boolean) => { - setIsChecked(checked); - }; - - return ( - <> - -
- `${datum.name}: ${datum.y}`} - constrainToVisibleArea - /> - } - height={275} - maxDomain={{y: 8}} - minDomain={{y: 0}} - name="chart10" - themeColor={isChecked ? ChartThemeColor.skeleton : ChartThemeColor.blue} - width={450} - > - - - - - - -
- - ); -} ``` ### Stack chart -```js -import { Switch } from '@patternfly/react-core'; -import { Chart, ChartVoronoiContainer, ChartAxis, ChartStack, ChartBar, ChartThemeColor } from '@patternfly/react-charts/victory'; - -export const ChartStackSkeleton: React.FunctionComponent = () => { - const [isChecked, setIsChecked] = useState(true); - - const handleChange = (_event: React.FormEvent, checked: boolean) => { - setIsChecked(checked); - }; +```ts file = "SkeletonsStackChart.tsx" - return ( - <> - -
- `${datum.name}: ${datum.y}`} constrainToVisibleArea />} - domainPadding={{ x: [30, 25] }} - legendData={[{ name: 'Cats' }, { name: 'Dogs' }, { name: 'Birds' }, { name: 'Mice' }]} - legendOrientation="vertical" - legendPosition="right" - height={250} - name="chart11" - padding={{ - bottom: 50, - left: 50, - right: 200, // Adjusted to accommodate legend - top: 50 - }} - themeColor={isChecked ? ChartThemeColor.skeleton : ChartThemeColor.blue} - width={600} - > - - - - - - - - - -
- - ); -} ``` ### Threshold chart -```js -import { Switch } from '@patternfly/react-core'; -import { Chart, ChartArea, ChartAxis, ChartGroup, ChartLegend, ChartThemeColor, ChartThreshold, ChartVoronoiContainer } from '@patternfly/react-charts/victory'; -import chart_color_blue_300 from '@patternfly/react-tokens/dist/esm/chart_color_blue_300'; - -export const ChartThresholdSkeleton: React.FunctionComponent = () => { - const [isChecked, setIsChecked] = useState(true); - - const handleChange = (_event: React.FormEvent, checked: boolean) => { - setIsChecked(checked); - }; +```ts file = "SkeletonsThresholdChart.tsx" - return ( - <> - -
- `${datum.name}: ${datum.y}`} - constrainToVisibleArea - /> - } - legendPosition="bottom-left" - legendComponent={ - - } - height={250} - padding={{ - bottom: 100, // Adjusted to accommodate legend - left: 50, - right: 50, - top: 50 - }} - maxDomain={{ y: 9 }} - name="chart12" - themeColor={isChecked ? ChartThemeColor.skeleton : ChartThemeColor.blue} - width={800} - > - - - - - - - - -
- - ); -} ``` ## Documentation diff --git a/packages/react-charts/src/victory/components/Sparkline/examples/SparklineBasic.tsx b/packages/react-charts/src/victory/components/Sparkline/examples/SparklineBasic.tsx new file mode 100644 index 00000000000..ab40f027cff --- /dev/null +++ b/packages/react-charts/src/victory/components/Sparkline/examples/SparklineBasic.tsx @@ -0,0 +1,46 @@ +import { + ChartArea, + ChartContainer, + ChartGroup, + ChartLabel, + ChartVoronoiContainer +} from '@patternfly/react-charts/victory'; + +interface PetData { + name: string; + x: string; + y: number; +} + +export const SparklineBasic: React.FunctionComponent = () => { + const data: PetData[] = [ + { name: 'Cats', x: '2015', y: 3 }, + { name: 'Cats', x: '2016', y: 4 }, + { name: 'Cats', x: '2017', y: 8 }, + { name: 'Cats', x: '2018', y: 6 } + ]; + + return ( +
+
+ `${datum.name}: ${datum.y}`} constrainToVisibleArea /> + } + height={100} + maxDomain={{ y: 9 }} + name="chart1" + padding={0} + width={400} + > + + +
+ + + +
+ ); +}; diff --git a/packages/react-charts/src/victory/components/Sparkline/examples/SparklineGreen.tsx b/packages/react-charts/src/victory/components/Sparkline/examples/SparklineGreen.tsx new file mode 100644 index 00000000000..f5ba9ec5ac1 --- /dev/null +++ b/packages/react-charts/src/victory/components/Sparkline/examples/SparklineGreen.tsx @@ -0,0 +1,62 @@ +import { + ChartArea, + ChartContainer, + ChartGroup, + ChartLabel, + ChartThemeColor, + ChartVoronoiContainer +} from '@patternfly/react-charts/victory'; +import { useEffect } from 'react'; + +interface PetData { + name: string; + x: string; + y: number; +} + +export const SparklineGreen: React.FunctionComponent = () => { + const data: PetData[] = [ + { name: 'Cats', x: '2015', y: 3 }, + { name: 'Cats', x: '2016', y: 4 }, + { name: 'Cats', x: '2017', y: 8 }, + { name: 'Cats', x: '2018', y: 6 } + ]; + + useEffect(() => { + // Workaround for documentation-framework issue https://github.com/patternfly/patternfly-react/issues/11455 + const sheet = (() => { + const style = document.createElement('style'); + document.head.appendChild(style); + return style.sheet; + })(); + + sheet.insertRule( + '.ws-react-charts-sparkline-overflow { margin-left: 50px; margin-top: 50px; height: 135px; }', + sheet.cssRules.length + ); + sheet.insertRule('.ws-react-charts-sparkline-overflow svg { overflow: visible; }', sheet.cssRules.length); + }, []); + + return ( +
+
+ `${datum.name}: ${datum.y}`} />} + height={100} + maxDomain={{ y: 9 }} + name="chart2" + padding={0} + themeColor={ChartThemeColor.green} + width={400} + > + + +
+ + + +
+ ); +}; diff --git a/packages/react-charts/src/victory/components/Sparkline/examples/sparkline.md b/packages/react-charts/src/victory/components/Sparkline/examples/sparkline.md index c069de4dcbd..cd9821cb949 100644 --- a/packages/react-charts/src/victory/components/Sparkline/examples/sparkline.md +++ b/packages/react-charts/src/victory/components/Sparkline/examples/sparkline.md @@ -12,6 +12,7 @@ hideDarkMode: true --- import { ChartArea, ChartContainer, ChartGroup, ChartLabel, ChartThemeColor, ChartVoronoiContainer } from '@patternfly/react-charts/victory'; +import { useEffect } from 'react';