diff --git a/.github/ISSUE_TEMPLATE/PF6_alpha_bug_request.md b/.github/ISSUE_TEMPLATE/PF6_alpha_bug_request.md deleted file mode 100644 index 1251cfa2a1f..00000000000 --- a/.github/ISSUE_TEMPLATE/PF6_alpha_bug_request.md +++ /dev/null @@ -1,17 +0,0 @@ ---- -name: PF6 alpha bug -about: Report a bug discovered while testing the PatternFly 6 alphas -title: "[short description]" -labels: 'v6 alpha bug' -assignees: '' - ---- - -**Please describe the issue** - -**Are there visuals for this issue? Please provide screenshots** -Include screenshots or links to Marvel or other mockups. - -**Could you point to a branch or draft PR where this issue exists? Please provide a link to the code** - -**Any other information?** diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md index 1fe791a2d1e..f808ffbd94e 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -2,7 +2,7 @@ name: Bug report about: Help us to improve PatternFly title: Bug - [Component] - [short description] -labels: bug +type: bug assignees: '' --- diff --git a/.github/ISSUE_TEMPLATE/devX_request.md b/.github/ISSUE_TEMPLATE/devX_request.md index a23e1d4c962..10bfbe40624 100644 --- a/.github/ISSUE_TEMPLATE/devX_request.md +++ b/.github/ISSUE_TEMPLATE/devX_request.md @@ -2,7 +2,7 @@ name: Developer experience about: Suggest an enhancement to the developer experience (DX). DX enhancements improve experience for those building UIs with PatternFly, but have little to no end user impact. title: "[short description]" -labels: DevX +type: DevX assignees: '' --- diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md deleted file mode 100644 index dd2e13a2e0a..00000000000 --- a/.github/ISSUE_TEMPLATE/feature_request.md +++ /dev/null @@ -1,19 +0,0 @@ ---- -name: Feature request -about: Suggest a new feature for PatternFly. Features augment or impact end user experience and requires design input. -title: "[Component] - [short description]" -labels: Feature -assignees: '' - ---- - -**Is this a new component or an extension of an existing one?** -What is the existing component, if any? - -**Describe the feature** -A clear and concise description of the new feature. What is the expected behavior? - -**Are there visuals for this feature? If applicable, please include examples for each state and for varying widths** -Include screenshots or links to Marvel or other mockups. - -**Any other information?** diff --git a/.github/ISSUE_TEMPLATE/feature_request.yml b/.github/ISSUE_TEMPLATE/feature_request.yml new file mode 100644 index 00000000000..7e9c1bb19c3 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature_request.yml @@ -0,0 +1,99 @@ +name: Feature request +description: Suggest a new feature or component for PatternFly. +title: "[Component] - [short description]" +labels: ["extension", "needs-triage"] +body: + - type: markdown + attributes: + value: | + ### Thanks for helping improve PatternFly! + Please fill out this form to help the team understand your proposal. + + - type: dropdown + id: category + attributes: + label: Is this a new component or an extension? + options: + - New Component + - Variant of an existing component + - Enhancement to a current feature + validations: + required: true + + - type: input + id: existing_component + attributes: + label: Existing Component + description: If this is a variant or enhancement, which component does it impact? + placeholder: e.g., Table, Select, Wizard + validations: + required: false + + - type: textarea + id: description + attributes: + label: Describe the feature + description: A clear and concise description of the new feature. + placeholder: What is the expected behavior? Is there any specific error handling? + validations: + required: true + + - type: textarea + id: user_story + attributes: + label: User Story + description: Providing context helps us understand the priority. + placeholder: As a [user role], I want to [action] so that [benefit]. + validations: + required: true + + - type: textarea + id: visuals + attributes: + label: Visuals & Mockups + description: Include links to Figma or upload screenshots for desktop/mobile views. + placeholder: | + - Figma link: + - Screenshots: (Drag images here) + validations: + required: false + + - type: textarea + id: interaction_states + attributes: + label: Interaction States & Variations + description: Describe the behavior across different states. + placeholder: | + - Initial/Empty: + - Loading: + - Error/Validation: + - Mobile/Responsive Viewport: + validations: + required: true + + - type: textarea + id: accessibility + attributes: + label: Accessibility (A11y) + description: Specific keyboard interaction or focus management requirements. + placeholder: e.g., Tab navigation, ARIA labels, or focus traps. + validations: + required: false + + - type: input + id: product_release + attributes: + label: Product & Target Release + description: If applicable, what is your product and target release date? + placeholder: e.g., OpenShift 4.15 + validations: + required: false + + - type: checkboxes + id: contribution_check + attributes: + label: Contribution + options: + - label: I am interested in contributing this feature. + - label: I have searched for similar existing requests. + required: true diff --git a/.github/ISSUE_TEMPLATE/tech_debt_request.md b/.github/ISSUE_TEMPLATE/tech_debt_request.md index bb551dde84e..fe899df86a0 100644 --- a/.github/ISSUE_TEMPLATE/tech_debt_request.md +++ b/.github/ISSUE_TEMPLATE/tech_debt_request.md @@ -2,7 +2,7 @@ name: Tech debt about: Improvements to code that do not affect either user or product developers’ experiences. title: "[short description]" -labels: 'Tech debt' +type: 'Tech debt' assignees: '' --- diff --git a/.github/actions/setup-project/action.yml b/.github/actions/setup-project/action.yml index f47422f31c7..07aaccbecde 100644 --- a/.github/actions/setup-project/action.yml +++ b/.github/actions/setup-project/action.yml @@ -14,7 +14,7 @@ runs: - name: Set up Node.js uses: actions/setup-node@v4 with: - node-version: 20 + node-version: 22 check-latest: true - name: Enable Corepack @@ -44,23 +44,8 @@ runs: shell: bash run: yarn install --immutable - - uses: actions/cache@v4 - if: inputs.skip-build != 'true' && inputs.skip-build-cache != 'true' - id: cache-build - name: Cache build - with: - path: | - packages/*/dist - packages/*/next - packages/*/deprecated - packages/*/components - packages/react-styles/css - packages/react-core/layouts - packages/react-core/helpers - key: ${{ runner.os }}-build-${{ hashFiles('yarn.lock', '**/package.json', 'packages/**', '!**/node_modules', '!**/dist') }} - - name: Run build - if: inputs.skip-build != 'true' && steps.cache-build.outputs.cache-hit != 'true' + if: inputs.skip-build != 'true' shell: bash run: yarn build && yarn build:umd env: diff --git a/.github/promote.sh b/.github/promote.sh index 3b362000571..d8700acd96e 100755 --- a/.github/promote.sh +++ b/.github/promote.sh @@ -12,11 +12,11 @@ echo "//registry.npmjs.org/:_authToken=${NPM_TOKEN}" > ~/.npmrc # Update their versions and changelogs according to angular commit guidelines # https://github.com/angular/angular/blob/master/CONTRIBUTING.md#commit -# if [[ ! -z "${PATTERNFLY_VERSION}" ]]; then -# echo "Updating to @patternfly/patternfly: ${PATTERNFLY_VERSION}" -# npm pkg set dependencies.@patternfly/patternfly=${PATTERNFLY_VERSION} --workspace @patternfly/react-docs -# npm pkg set devDependencies.@patternfly/patternfly=${PATTERNFLY_VERSION} --workspace @patternfly/react-core --workspace @patternfly/react-styles --workspace @patternfly/react-tokens --workspace @patternfly/react-icons -# fi +#if [[ ! -z "${PATTERNFLY_VERSION}" ]]; then +# echo "Updating to @patternfly/patternfly: ${PATTERNFLY_VERSION}" +# npm pkg set dependencies.@patternfly/patternfly=${PATTERNFLY_VERSION} --workspace @patternfly/react-docs +# npm pkg set devDependencies.@patternfly/patternfly=${PATTERNFLY_VERSION} --workspace @patternfly/react-core --workspace @patternfly/react-styles --workspace @patternfly/react-tokens --workspace @patternfly/react-icons +#fi # publish to npm # yarn run lerna publish --conventional-commits --conventional-graduate --no-private --dist-tag=latest --yes diff --git a/.github/renovate.json b/.github/renovate.json index 40c9e921143..663f5774573 100644 --- a/.github/renovate.json +++ b/.github/renovate.json @@ -11,6 +11,5 @@ ], "enabled": false } - ], - "baseBranches": ["main", "v5"] + ] } 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/.github/workflows/add-new-issues-to-project.yml b/.github/workflows/add-new-issues-to-project.yml deleted file mode 100644 index 5430657d628..00000000000 --- a/.github/workflows/add-new-issues-to-project.yml +++ /dev/null @@ -1,14 +0,0 @@ -name: Add new issues to PatternFly Issues project -on: - issues: - types: - - opened -jobs: - add-to-project: - name: Add issue to project - runs-on: ubuntu-latest - steps: - - uses: actions/add-to-project@v1.0.2 - with: - project-url: https://github.com/orgs/patternfly/projects/7 - github-token: ${{ secrets.GH_PROJECTS }} diff --git a/.github/workflows/documentation.yml b/.github/workflows/documentation.yml index ba9dbe11555..279a8cd7f46 100644 --- a/.github/workflows/documentation.yml +++ b/.github/workflows/documentation.yml @@ -1,6 +1,8 @@ name: Documentation on: pull_request_target: + issue_comment: + types: [created] workflow_call: secrets: SURGE_LOGIN: @@ -10,17 +12,26 @@ on: GH_PR_TOKEN: required: true jobs: + check-permissions: + uses: patternfly/.github/.github/workflows/check-team-membership.yml@fdb52a63a2220ec8a3b6c2d43f312cda708ffa06 + secrets: inherit + deploy: name: Build, test & deploy runs-on: ubuntu-latest + needs: check-permissions + if: >- + always() && + !cancelled() && + (github.event_name == 'workflow_call' || needs.check-permissions.outputs.allowed == 'true') env: SURGE_LOGIN: ${{ secrets.SURGE_LOGIN }} SURGE_TOKEN: ${{ secrets.SURGE_TOKEN }} GH_PR_TOKEN: ${{ secrets.GH_PR_TOKEN }} - GH_PR_NUM: ${{ github.event.number }} + GH_PR_NUM: ${{ needs.check-permissions.outputs.pr-number }} steps: - name: Check out project from PR branch - if: github.event_name == 'pull_request_target' + if: github.event_name == 'pull_request_target' || github.event_name == 'issue_comment' uses: actions/checkout@v4 with: # Checkout the merge commit so that we can access the PR's changes. @@ -28,9 +39,8 @@ jobs: ref: refs/pull/${{ env.GH_PR_NUM }}/head - name: Check out project - if: github.event_name != 'pull_request_target' + if: github.event_name == 'workflow_call' uses: actions/checkout@v4 - - name: Set up and build project uses: ./.github/actions/setup-project diff --git a/.github/workflows/label-pf-team-issue.yml b/.github/workflows/label-pf-team-issue.yml new file mode 100644 index 00000000000..8ead60e27e8 --- /dev/null +++ b/.github/workflows/label-pf-team-issue.yml @@ -0,0 +1,9 @@ +name: Label PF Team issues +on: + issues: + types: + - opened +jobs: + label: + uses: patternfly/.github/.github/workflows/add-pf-team-label-workflow.yml@fdb52a63a2220ec8a3b6c2d43f312cda708ffa06 + secrets: inherit diff --git a/.github/workflows/stale.yml b/.github/workflows/stale.yml index f5642d8c9ad..ad0513875e2 100644 --- a/.github/workflows/stale.yml +++ b/.github/workflows/stale.yml @@ -9,10 +9,8 @@ jobs: - uses: actions/stale@v9 with: days-before-stale: 60 - days-before-close: 14 - exempt-issue-labels: accessibility,breaking change :boom:,security,pinned - stale-issue-label: wontfix + days-before-close: -1 + exempt-issue-labels: breaking change :boom:,pinned + stale-issue-label: stale stale-issue-message: This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. stale-pr-message: This PR has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. - close-issue-message: 'This issue has been closed because it has not had activity since being marked as stale.' - close-pr-message: 'This PR has been closed because it has not had activity since being marked as stale.' diff --git a/.prettierignore b/.prettierignore new file mode 100644 index 00000000000..2adc63e5c96 --- /dev/null +++ b/.prettierignore @@ -0,0 +1,4 @@ +# Generated icon files - these are auto-generated and should not be formatted +packages/react-icons/scripts/icons/rhIcons*.mjs +packages/react-icons/scripts/icons/rhdsIcons*.mjs + diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index a97a77bec58..cb81f3e8134 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,34 +1,72 @@ # 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) - [PR Labels](#pr-labels) - - [Project Board Columns](#project-board-columns) - [Contribution Process](#contribution-process) - [Creating Issues for Bugs](#creating-issues-for-bugs) - [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. @@ -37,16 +75,9 @@ We use issues to track work items, such as bug reports and feature requests. Iss Our issue tracker utilizes several labels to help organize and identify issues. Here's what they represent and how we use them: -- `bug` - A bug is a _demonstrable problem_ that is caused by the code in the repository. Please check if the issue has already been reported before reporting a new bug. -- `DevX` - Suggest an enhancement to the developer experience (DX). DX enhancements improve experience for those building UIs with PatternFly, but have little to know end user impact. -- `Feature` - Suggest a new feature for PatternFly. Features augment or impact end user experience and requires design input. - `breaking change` - this issue warrants a major release and potentially changes APIs for downstream consumers. -- `Tech debt` - Improvements to code that do not affect either user or product developers’ experiences. -- `documentation` - this issue affects documentation only. -- `css` - this issue affects CSS or has stylistic changes. - `good first issue` - Issues that are ideal for new contributors. - `wontfix` - The issue is legitimate, but it is not something the team is currently able or willing to fix or implement. Issues with this label may be revisited in the future. -- `p1`, `p2`, `p3` - These are priority labels. ### PR labels @@ -57,17 +88,9 @@ Since the components in patternfly-react are based on patternfly, we want to mak - `css approved` - The issue has been reviewed and approved by a member of the css team. - `ux approved` - The issue has been reviewed and approved by a member of the ux team. -### Project board columns - -The project board uses the following columns to track issues: +### Integration with Jira -- `Backlog` - Issues that are ready to be worked and available for any contributor to take. -- `Needs info` - Issues that require any work that would be completed outside of this repo related to css, design or research. For example some component contributions will require updates to css in the core [patternfly](https://github.com/patternfly/patternfly) repo. -- `Not started` - Issues that are ready to be worked and are already assigned. -- `In Progress` - Issues that are actively being worked. -- `PR in Review` - Issues for which a PR is open and are ready for review. - -Issues can be manually added to the project board from either the issue page or the project board page. +We sync our issues to PatternFly's private Jira board. Once an issue is sync'd, a link is added to the issue description in GitHub if someone were to want to track the Jira ticket. Any issue can be assigned an assignee in GitHub or Jira and that information will be sync'd. If an issue is closed in Jira, it will also be closed in GitHub. ## Contribution process @@ -79,7 +102,6 @@ If you find a bug within the repo, please help us track the issue by following t - If it does exist, but doesn’t capture key details that you have noticed, please add a comment to the existing bug. 2. Create an issue if one doesn’t already exist. - Provide details like what component is affected, steps to reproduce, and any other information that is critical to addressing the issue - - Assign the label “bug” to the issue ### Creating issues for new components @@ -87,7 +109,6 @@ To create an issue for adding a new component to the repo, please observe the fo 1. If the component does not yet exist as a PatternFly component, please do not start coding yet. Components contributed to PatternFly-React should have a design pattern in PatternFly or be approved PatternFly-Extension components. 2. If the component exists in PatternFly core (meaning CSS and the pattern design exists), then create an issue with the following details: - - Assign the label `enhancement` to the issue - Include the text “Component -“ in the beginning of the title if the issue captures a new component - If the component is documented as a [PatternFly library pattern](http://www.patternfly.org/pattern-library/), include a link to it. 3. If a component is not in PatternFly, but you feel it would be a good addition to the library, please do the following: @@ -124,22 +145,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 +185,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 20 (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 + +# Build the project yarn build -``` -3. Create a branch: +# Run tests to verify setup +yarn test -```sh -git checkout -b my-branch upstream/main +# Start development server (optional) +yarn start ``` -4. Generate your component - -```sh -# Run the tool to Generate the component scaffolding - yarn generate -``` +**Verify your setup:** +- All tests should pass +- Build should complete without errors +- Development server should start (if running 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 - ``` - -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 +225,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 -``` - -8. Push +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. -```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 +250,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/GETTING-STARTED.md b/GETTING-STARTED.md index abd574d3573..4a89c98dec4 100644 --- a/GETTING-STARTED.md +++ b/GETTING-STARTED.md @@ -1,5 +1,5 @@ # PatternFly React Getting Started - + This README is intended to further detail some of the steps mentioned in the PatternFly React [Contributing Guide](./CONTRIBUTING.md#code-consistency) and help new contributors getting started with PatternFly React. ## Learning React diff --git a/README.md b/README.md index 860aaec83aa..6ad8857abff 100644 --- a/README.md +++ b/README.md @@ -1,12 +1,12 @@ # PatternFly React - + [![lerna](https://img.shields.io/badge/maintained%20with-lerna-green.svg?style=for-the-badge)](https://lernajs.io/) [![PatternFly npm badge](https://img.shields.io/npm/v/@patternfly/react-core.svg?label=PF%20Core&style=for-the-badge)](https://www.npmjs.com/package/@patternfly/react-core) This project provides a set of React components for the [PatternFly project](https://patternfly.org). **Community:** [PatternFly website](https://www.patternfly.org) | [Slack](https://slack.patternfly.org) | [Medium](https://medium.com/patternfly) | [Mailing list](https://www.redhat.com/mailman/listinfo/patternfly) - + ### Table of contents 1. [PatternFly React packages](#patternfly-react-packages) 2. [Setup](#Setup) @@ -16,7 +16,7 @@ This project provides a set of React components for the [PatternFly project](htt Using PatternFly 3? Take a look at the [PatternFly 3 React component information](https://github.com/patternfly/patternfly-react/blob/patternfly-3/README.md). ### PatternFly React packages - + | Package link | Description | | --- | --- | | **:blue_heart: Core packages** | @@ -27,17 +27,16 @@ Using PatternFly 3? Take a look at the [PatternFly 3 React component information |   [@patternfly/react-styles](./packages/react-styles/README.md) | PatternFly CSS styles | |   [@patternfly/react-tokens](./packages/react-tokens/README.md) | PatternFly CSS variable tokens | | **:yellow_heart: Extension packages** | -|   [@patternfly/react-log-viewer](https://github.com/patternfly/react-log-viewer/README.md) | Virtualized log viewer component | -|   [@patternfly/react-catalog-view-extension](https://github.com/patternfly/react-catalog-view/README.md) | Catalog view extension | -|   [@patternfly/react-topology](https://github.com/patternfly/react-topology/README.md) | Topology components | +|   [@patternfly/react-log-viewer](https://github.com/patternfly/react-log-viewer/blob/main/README.md) | Virtualized log viewer component | +|   [@patternfly/react-catalog-view-extension](https://github.com/patternfly/react-catalog-view/blob/main/README.md) | Catalog view extension | +|   [@patternfly/react-topology](https://github.com/patternfly/react-topology/blob/main/README.md) | Topology components | | **:open_file_folder: Supporting packages** | |   [@patternfly/react-docs](./packages/react-docs/README.md) | Gatsby documentation site for components | |   [@patternfly/react-integration](./packages/react-integration/README.md) | Cypress integration tests | | **:x: Deprecated packages** | -|   [@patternfly/react-inline-edit-extension](./packages/react-inline-edit-extension/README.md) | Table inline edit extension | -|   [@patternfly/react-virtualized-extension](https://github.com/patternfly/react-virtualized-extension/README.md) | Table and list row virtualization extension | +|   [@patternfly/react-virtualized-extension](https://github.com/patternfly/react-virtualized-extension/blob/main/README.md) | Table and list row virtualization extension | -### Setup +### Setup Before you begin, check out this [overview of PatternFly](http://patternfly.org/get-started/about) to get familiar with the basic elements of the design system. diff --git a/babel.config.js b/babel.config.js index a5caef7249f..48db1c06484 100644 --- a/babel.config.js +++ b/babel.config.js @@ -1,4 +1,4 @@ module.exports = { - presets: ['@babel/preset-typescript', '@babel/preset-react'], + presets: ['@babel/preset-typescript', ['@babel/preset-react', { runtime: 'automatic' }]], plugins: ['@babel/plugin-transform-modules-commonjs'] }; diff --git a/eslint.config-md.mjs b/eslint.config-md.mjs index 9fcc90a813d..da009687858 100644 --- a/eslint.config-md.mjs +++ b/eslint.config-md.mjs @@ -30,7 +30,19 @@ export default [ 'react/jsx-uses-react': 'error', 'react/jsx-uses-vars': 'error', 'react/no-unknown-property': 'error', - 'react/jsx-no-undef': 'error' + 'react/jsx-no-undef': 'error', + 'no-restricted-imports': [ + 'error', + { + paths: [ + { + name: 'react', + importNames: ['default'], + message: 'Please use named imports when importing from React.' + } + ] + } + ] } } ]; diff --git a/eslint.config.mjs b/eslint.config.mjs index 3ba59a8a05e..567da2b099c 100644 --- a/eslint.config.mjs +++ b/eslint.config.mjs @@ -2,8 +2,9 @@ import { fixupPluginRules } from '@eslint/compat'; import js from '@eslint/js'; import patternflyReact from 'eslint-plugin-patternfly-react'; import eslintPluginPrettierRecommended from 'eslint-plugin-prettier/recommended'; +import reactCompiler from 'eslint-plugin-react-compiler'; import reactHooks from 'eslint-plugin-react-hooks'; -import reactRecommended from 'eslint-plugin-react/configs/recommended.js'; +import react from 'eslint-plugin-react'; import testingLibrary from 'eslint-plugin-testing-library'; import globals from 'globals'; import tseslint from 'typescript-eslint'; @@ -15,18 +16,23 @@ export default [ '**/css', 'packages/react-core/src/helpers/Popper/thirdparty', 'packages/react-docs/patternfly-docs/generated', + 'packages/react-docs/coverage', '.history/*', - 'packages/react-docs/static' + 'packages/react-docs/static', + 'packages/react-docs/public', + '**/.cache' ] }, js.configs.recommended, ...tseslint.configs.recommended, - reactRecommended, + react.configs.flat.recommended, + react.configs.flat['jsx-runtime'], eslintPluginPrettierRecommended, { plugins: { 'patternfly-react': fixupPluginRules(patternflyReact), - 'react-hooks': fixupPluginRules(reactHooks) + 'react-hooks': fixupPluginRules(reactHooks), + 'react-compiler': reactCompiler }, languageOptions: { globals: { @@ -42,6 +48,10 @@ export default [ }, rules: { ...reactHooks.configs.recommended.rules, + '@typescript-eslint/no-wrapper-object-types': 'off', + '@typescript-eslint/no-empty-object-type': 'off', + '@typescript-eslint/no-unsafe-function-type': 'off', + '@typescript-eslint/no-unused-expressions': ['error', { allowShortCircuit: true, allowTernary: true }], '@typescript-eslint/ban-ts-comment': 'off', '@typescript-eslint/adjacent-overload-signatures': 'error', '@typescript-eslint/array-type': 'error', @@ -61,11 +71,12 @@ export default [ '@typescript-eslint/no-unused-vars': [ 'error', { - argsIgnorePattern: '^_' + argsIgnorePattern: '^_', + caughtErrors: 'none' } ], '@typescript-eslint/no-use-before-define': 'off', - '@typescript-eslint/no-var-requires': 'off', + '@typescript-eslint/no-require-imports': 'off', '@typescript-eslint/prefer-for-of': 'error', '@typescript-eslint/prefer-function-type': 'error', '@typescript-eslint/prefer-namespace-keyword': 'error', @@ -75,7 +86,9 @@ export default [ camelcase: [ 'error', { - ignoreDestructuring: true + ignoreDestructuring: true, + allow: ['^t_[global|chart]', '^chart_'] + // TODO: Remove 'chart_' from the allowed patterns after updating all chart examples to use the 't_chart_' format } ], 'constructor-super': 'error', @@ -95,6 +108,18 @@ export default [ 'no-eval': 'error', 'no-new-wrappers': 'error', 'no-prototype-builtins': 'off', + 'no-restricted-imports': [ + 'error', + { + paths: [ + { + name: 'react', + importNames: ['default'], + message: 'Please use named imports when importing from React.' + } + ] + } + ], 'no-shadow': 'off', 'no-throw-literal': 'error', 'no-trailing-spaces': 'off', @@ -118,6 +143,7 @@ export default [ radix: ['error', 'as-needed'], 'react/prop-types': 0, 'react/display-name': 0, + 'react-compiler/react-compiler': 'warn', 'react-hooks/exhaustive-deps': 'warn', 'react/no-unescaped-entities': ['error', { forbid: ['>', '}'] }], 'spaced-comment': 'error', diff --git a/jest.config.ts b/jest.config.ts index fb0926a5ee7..7263343f2c9 100644 --- a/jest.config.ts +++ b/jest.config.ts @@ -19,9 +19,9 @@ const config: Config = { '^.+\\.m?[jt]sx?$': 'babel-jest', '^.+\\.svg$': 'jest-transform-stub' }, - setupFilesAfterEnv: ['/packages/testSetup.ts'], + setupFilesAfterEnv: ['/packages/testSetup.ts', 'jest-canvas-mock'], testPathIgnorePatterns: ['/packages/react-integration/'], - transformIgnorePatterns: ['node_modules/victory-*/', '/node_modules/(?!(case-anything)/)'], + transformIgnorePatterns: ['/node_modules/victory-*/', '/node_modules/(?!(case-anything|echarts|zrender)/)'], coveragePathIgnorePatterns: ['/dist/'], moduleNameMapper: { '\\.(css|less)$': '/packages/react-styles/__mocks__/styleMock.js' 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 3689b896dc6..f1d16ae8737 100644 --- a/package.json +++ b/package.json @@ -8,9 +8,9 @@ "url": "https://github.com/patternfly/patternfly-react.git" }, "engines": { - "node": ">=20.14.0" + "node": ">=22.17.1" }, - "packageManager": "yarn@4.3.0", + "packageManager": "yarn@4.7.0", "keywords": [ "react", "patternfly", @@ -24,59 +24,62 @@ }, "homepage": "https://github.com/patternfly/patternfly-react#readme", "devDependencies": { - "@babel/core": "^7.24.7", - "@babel/plugin-transform-modules-commonjs": "^7.24.7", - "@babel/preset-react": "^7.24.7", - "@babel/preset-typescript": "^7.24.7", - "@eslint/compat": "^1.1.1", - "@eslint/js": "^9.7.0", - "@octokit/rest": "^20.1.1", - "@rollup/plugin-commonjs": "^26.0.1", - "@rollup/plugin-node-resolve": "^15.2.3", + "@babel/core": "^7.28.5", + "@babel/plugin-transform-modules-commonjs": "^7.27.1", + "@babel/preset-env": "^7.28.5", + "@babel/preset-react": "^7.28.5", + "@babel/preset-typescript": "^7.28.5", + "@eslint/compat": "^1.4.1", + "@eslint/js": "^9.32.0", + "@octokit/rest": "^21.1.1", + "@rhds/icons": "^2.1.0", + "@rollup/plugin-commonjs": "^26.0.3", + "@rollup/plugin-node-resolve": "^15.3.1", "@rollup/plugin-replace": "^5.0.7", "@rollup/plugin-terser": "^0.4.4", - "@testing-library/dom": "^10.1.0", - "@testing-library/jest-dom": "^6.4.6", - "@testing-library/react": "^16.0.0", - "@testing-library/user-event": "^14.5.2", - "@types/jest": "29.5.12", - "@types/node": "^20.14.2", - "@types/react": "^18.3.3", - "@types/react-dom": "^18.3.0", + "@testing-library/dom": "^10.4.1", + "@testing-library/jest-dom": "^6.9.1", + "@testing-library/react": "^16.3.2", + "@testing-library/user-event": "^14.6.1", + "@types/jest": "29.5.14", + "@types/node": "^22.16.5", + "@types/react": "^18.3.28", + "@types/react-dom": "^18.3.7", "babel-jest": "^29.7.0", - "concurrently": "^8.2.2", - "eslint": "^9.7.0", - "eslint-config-prettier": "^9.1.0", + "concurrently": "^9.2.1", + "eslint": "^9.32.0", + "eslint-config-prettier": "^10.1.8", "eslint-plugin-markdown": "^5.1.0", - "eslint-plugin-prettier": "^5.2.1", - "eslint-plugin-react": "^7.34.2", - "eslint-plugin-react-hooks": "^4.6.2", - "eslint-plugin-testing-library": "^6.2.2", - "fs-extra": "^11.2.0", - "glob": "^10.4.5", - "globals": "^15.8.0", - "husky": "^9.0.11", + "eslint-plugin-prettier": "^5.5.5", + "eslint-plugin-react": "^7.37.5", + "eslint-plugin-react-compiler": "19.0.0-beta-ebf51a3-20250411", + "eslint-plugin-react-hooks": "^5.2.0", + "eslint-plugin-testing-library": "^7.16.2", + "fs-extra": "^11.3.3", + "glob": "^11.1.0", + "globals": "^15.15.0", + "husky": "^9.1.7", "jest": "^29.7.0", "jest-environment-jsdom": "^29.7.0", "jest-transform-stub": "^2.0.0", - "lerna": "^8.1.4", - "lint-staged": "^15.2.10", + "lerna": "^8.2.4", + "lint-staged": "^15.5.2", "mutation-observer": "^1.0.3", - "plop": "^4.0.1", - "prettier": "^3.3.3", - "publint": "^0.2.10", + "plop": "^4.0.5", + "prettier": "^3.8.1", + "publint": "^0.3.18", "react": "^18.3.1", "react-dom": "^18.3.1", - "rimraf": "^5.0.10", - "rollup": "^4.18.0", - "rollup-plugin-scss": "^4.0.0", + "rimraf": "^6.1.3", + "rollup": "^4.57.1", + "rollup-plugin-scss": "^4.0.1", "rollup-plugin-svg": "^2.0.0", - "sass": "^1.77.5", - "surge": "^0.23.1", + "sass": "^1.86.0", + "surge": "^0.24.6", "ts-node": "^10.9.2", - "ts-patch": "^3.2.1", + "ts-patch": "^3.3.0", "typescript": "^5.4.5", - "typescript-eslint": "^7.16.1" + "typescript-eslint": "^8.22.0" }, "scripts": { "build": "yarn clean && yarn build:generate && yarn build:esm && yarn build:cjs && yarn build:subpaths && yarn build:single:packages", diff --git a/packages/eslint-plugin-patternfly-react/CHANGELOG.md b/packages/eslint-plugin-patternfly-react/CHANGELOG.md index f71d72a28fb..b2cf3039e2d 100644 --- a/packages/eslint-plugin-patternfly-react/CHANGELOG.md +++ b/packages/eslint-plugin-patternfly-react/CHANGELOG.md @@ -3,6 +3,104 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# 6.5.0 (2026-05-20) + +### Reverts + +- Revert "chore(release): releasing packages [ci skip]" ([7185856](https://github.com/patternfly/patternfly-react/commit/7185856d4985da5129bbabd6c460049e7048dd2a)) + +# [6.5.0-prerelease.11](https://github.com/patternfly/patternfly-react/compare/eslint-plugin-patternfly-react@6.5.0-prerelease.1...eslint-plugin-patternfly-react@6.5.0-prerelease.11) (2025-12-16) + +**Note:** Version bump only for package eslint-plugin-patternfly-react + +# [6.5.0-prerelease.1](https://github.com/patternfly/patternfly-react/compare/eslint-plugin-patternfly-react@6.4.0...eslint-plugin-patternfly-react@6.5.0-prerelease.1) (2025-10-30) + +**Note:** Version bump only for package eslint-plugin-patternfly-react + +# 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 + +# [6.3.0-prerelease.1](https://github.com/patternfly/patternfly-react/compare/eslint-plugin-patternfly-react@6.3.0-prerelease.0...eslint-plugin-patternfly-react@6.3.0-prerelease.1) (2025-07-22) + +### Reverts + +- Revert "chore(release): releasing packages [ci skip]" ([40999d7](https://github.com/patternfly/patternfly-react/commit/40999d70a7a3aeadbe8f40fe96bb01ab3a6219d4)) + +# 6.2.0 (2025-04-07) + +**Note:** Version bump only for package eslint-plugin-patternfly-react + +# [6.2.0-prerelease.6](https://github.com/patternfly/patternfly-react/compare/eslint-plugin-patternfly-react@6.2.0-prerelease.5...eslint-plugin-patternfly-react@6.2.0-prerelease.6) (2025-03-10) + +**Note:** Version bump only for package eslint-plugin-patternfly-react + +# [6.2.0-prerelease.5](https://github.com/patternfly/patternfly-react/compare/eslint-plugin-patternfly-react@6.2.0-prerelease.4...eslint-plugin-patternfly-react@6.2.0-prerelease.5) (2025-02-24) + +**Note:** Version bump only for package eslint-plugin-patternfly-react + +# [6.2.0-prerelease.4](https://github.com/patternfly/patternfly-react/compare/eslint-plugin-patternfly-react@6.2.0-prerelease.3...eslint-plugin-patternfly-react@6.2.0-prerelease.4) (2025-02-12) + +**Note:** Version bump only for package eslint-plugin-patternfly-react + +# [6.2.0-prerelease.3](https://github.com/patternfly/patternfly-react/compare/eslint-plugin-patternfly-react@6.2.0-prerelease.2...eslint-plugin-patternfly-react@6.2.0-prerelease.3) (2025-02-10) + +**Note:** Version bump only for package eslint-plugin-patternfly-react + +# [6.2.0-prerelease.2](https://github.com/patternfly/patternfly-react/compare/eslint-plugin-patternfly-react@6.2.0-prerelease.1...eslint-plugin-patternfly-react@6.2.0-prerelease.2) (2025-01-27) + +**Note:** Version bump only for package eslint-plugin-patternfly-react + +# [6.2.0-prerelease.1](https://github.com/patternfly/patternfly-react/compare/eslint-plugin-patternfly-react@6.2.0-prerelease.0...eslint-plugin-patternfly-react@6.2.0-prerelease.1) (2025-01-24) + +**Note:** Version bump only for package eslint-plugin-patternfly-react + +# [6.2.0-prerelease.0](https://github.com/patternfly/patternfly-react/compare/eslint-plugin-patternfly-react@6.1.0...eslint-plugin-patternfly-react@6.2.0-prerelease.0) (2025-01-06) + +**Note:** Version bump only for package eslint-plugin-patternfly-react + +# 6.1.0 (2024-12-16) + +### Bug Fixes + +- Update promote.sh to release 6.1.0 ([2b5106f](https://github.com/patternfly/patternfly-react/commit/2b5106ff88ce207d4a9ed2066fd390009e81fb79)) + +# [6.1.0-prerelease.1](https://github.com/patternfly/patternfly-react/compare/eslint-plugin-patternfly-react@6.1.0-prerelease.0...eslint-plugin-patternfly-react@6.1.0-prerelease.1) (2024-10-30) + +### Bug Fixes + +- update patternfly-react home page ([#11126](https://github.com/patternfly/patternfly-react/issues/11126)) ([51f3c8e](https://github.com/patternfly/patternfly-react/commit/51f3c8efbef93d86517df3b4c751331097d9a7c8)) + +# 6.1.0-prerelease.0 (2024-10-24) + +**Note:** Version bump only for package eslint-plugin-patternfly-react + +# 6.0.0 (2024-10-24) + +**Note:** Version bump only for package eslint-plugin-patternfly-react + +# [6.0.0-prerelease.2](https://github.com/patternfly/patternfly-react/compare/eslint-plugin-patternfly-react@6.0.0-prerelease.1...eslint-plugin-patternfly-react@6.0.0-prerelease.2) (2024-09-10) + +**Note:** Version bump only for package eslint-plugin-patternfly-react + +# [6.0.0-prerelease.1](https://github.com/patternfly/patternfly-react/compare/eslint-plugin-patternfly-react@5.2.0-alpha.7...eslint-plugin-patternfly-react@6.0.0-prerelease.1) (2024-09-07) + +**Note:** Version bump only for package eslint-plugin-patternfly-react + # [5.2.0-alpha.7](https://github.com/patternfly/patternfly-react/compare/eslint-plugin-patternfly-react@5.2.0-alpha.6...eslint-plugin-patternfly-react@5.2.0-alpha.7) (2024-08-12) - chore(eslint-plugin)!: remove dependencies from ESLint plugin (#10752) ([61a6194](https://github.com/patternfly/patternfly-react/commit/61a61941022d19f8c120db2d2712d1d707e9d5f6)), closes [#10752](https://github.com/patternfly/patternfly-react/issues/10752) [#10740](https://github.com/patternfly/patternfly-react/issues/10740) diff --git a/packages/eslint-plugin-patternfly-react/package.json b/packages/eslint-plugin-patternfly-react/package.json index 83a581c4124..9ef256e50d6 100644 --- a/packages/eslint-plugin-patternfly-react/package.json +++ b/packages/eslint-plugin-patternfly-react/package.json @@ -1,7 +1,10 @@ { "name": "eslint-plugin-patternfly-react", - "version": "6.0.0-prerelease.0", - "main": "./lib/index.js", + "version": "6.5.0", + "type": "commonjs", + "exports": { + ".": "./lib/index.js" + }, "license": "MIT", "publishConfig": { "access": "public", @@ -9,7 +12,7 @@ }, "repository": { "type": "git", - "url": "https://github.com/patternfly/patternfly-react.git" + "url": "git+https://github.com/patternfly/patternfly-react.git" }, "author": "Red Hat", "keywords": [ @@ -20,8 +23,8 @@ "bugs": { "url": "https://github.com/patternfly/patternfly-react/issues" }, - "homepage": "https://github.com/patternfly/patternfly-react/blob/main/packages/eslint-plugin/README.md", + "homepage": "https://github.com/patternfly/patternfly-react/blob/main/packages/eslint-plugin-patternfly-react/README.md", "peerDependencies": { - "eslint": ">=5" + "eslint": ">=9.32.0" } } diff --git a/packages/react-charts/.gitignore b/packages/react-charts/.gitignore new file mode 100644 index 00000000000..3e0402f878e --- /dev/null +++ b/packages/react-charts/.gitignore @@ -0,0 +1,4 @@ +/deprecated +/echarts +/next +/victory diff --git a/packages/react-charts/CHANGELOG.md b/packages/react-charts/CHANGELOG.md index 6159320820c..6880ff56aa0 100644 --- a/packages/react-charts/CHANGELOG.md +++ b/packages/react-charts/CHANGELOG.md @@ -3,6 +3,587 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [8.6.0-prerelease.1](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-charts@8.5.1-prerelease.0...@patternfly/react-charts@8.6.0-prerelease.1) (2026-05-26) + +### Bug Fixes + +- updated to do 6.6.0 prereleases. ([#12434](https://github.com/patternfly/patternfly-react/issues/12434)) ([6e09ce8](https://github.com/patternfly/patternfly-react/commit/6e09ce8322ff13354991d901782231d437249aa6)) + +## [8.5.1-prerelease.0](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-charts@8.5.0...@patternfly/react-charts@8.5.1-prerelease.0) (2026-05-21) + +**Note:** Version bump only for package @patternfly/react-charts + +# 8.5.0 (2026-05-20) + +### Reverts + +- Revert "chore(release): releasing packages [ci skip]" ([7185856](https://github.com/patternfly/patternfly-react/commit/7185856d4985da5129bbabd6c460049e7048dd2a)) + +# [8.5.0-prerelease.32](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-charts@8.5.0-prerelease.31...@patternfly/react-charts@8.5.0-prerelease.32) (2026-05-19) + +**Note:** Version bump only for package @patternfly/react-charts + +# [8.5.0-prerelease.31](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-charts@8.5.0-prerelease.30...@patternfly/react-charts@8.5.0-prerelease.31) (2026-05-14) + +**Note:** Version bump only for package @patternfly/react-charts + +# [8.5.0-prerelease.30](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-charts@8.5.0-prerelease.29...@patternfly/react-charts@8.5.0-prerelease.30) (2026-05-13) + +**Note:** Version bump only for package @patternfly/react-charts + +# [8.5.0-prerelease.29](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-charts@8.5.0-prerelease.28...@patternfly/react-charts@8.5.0-prerelease.29) (2026-05-12) + +**Note:** Version bump only for package @patternfly/react-charts + +# [8.5.0-prerelease.28](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-charts@8.5.0-prerelease.27...@patternfly/react-charts@8.5.0-prerelease.28) (2026-05-12) + +### Features + +- **react-charts:** add high contrast ([#12419](https://github.com/patternfly/patternfly-react/issues/12419)) ([e9c801c](https://github.com/patternfly/patternfly-react/commit/e9c801c84067fb9ed42d10d19deadf8dfca55289)) + +# [8.5.0-prerelease.27](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-charts@8.5.0-prerelease.26...@patternfly/react-charts@8.5.0-prerelease.27) (2026-05-08) + +**Note:** Version bump only for package @patternfly/react-charts + +# [8.5.0-prerelease.26](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-charts@8.5.0-prerelease.25...@patternfly/react-charts@8.5.0-prerelease.26) (2026-05-08) + +**Note:** Version bump only for package @patternfly/react-charts + +# [8.5.0-prerelease.25](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-charts@8.5.0-prerelease.24...@patternfly/react-charts@8.5.0-prerelease.25) (2026-05-07) + +**Note:** Version bump only for package @patternfly/react-charts + +# [8.5.0-prerelease.24](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-charts@8.5.0-prerelease.23...@patternfly/react-charts@8.5.0-prerelease.24) (2026-04-28) + +**Note:** Version bump only for package @patternfly/react-charts + +# [8.5.0-prerelease.23](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-charts@8.5.0-prerelease.22...@patternfly/react-charts@8.5.0-prerelease.23) (2026-04-24) + +**Note:** Version bump only for package @patternfly/react-charts + +# [8.5.0-prerelease.22](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-charts@8.5.0-prerelease.21...@patternfly/react-charts@8.5.0-prerelease.22) (2026-04-24) + +**Note:** Version bump only for package @patternfly/react-charts + +# [8.5.0-prerelease.21](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-charts@8.5.0-prerelease.20...@patternfly/react-charts@8.5.0-prerelease.21) (2026-04-20) + +**Note:** Version bump only for package @patternfly/react-charts + +# [8.5.0-prerelease.20](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-charts@8.5.0-prerelease.19...@patternfly/react-charts@8.5.0-prerelease.20) (2026-04-13) + +**Note:** Version bump only for package @patternfly/react-charts + +# [8.5.0-prerelease.19](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-charts@8.5.0-prerelease.18...@patternfly/react-charts@8.5.0-prerelease.19) (2026-04-06) + +**Note:** Version bump only for package @patternfly/react-charts + +# [8.5.0-prerelease.18](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-charts@8.5.0-prerelease.17...@patternfly/react-charts@8.5.0-prerelease.18) (2026-04-01) + +**Note:** Version bump only for package @patternfly/react-charts + +# [8.5.0-prerelease.17](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-charts@8.5.0-prerelease.16...@patternfly/react-charts@8.5.0-prerelease.17) (2026-03-27) + +**Note:** Version bump only for package @patternfly/react-charts + +# [8.5.0-prerelease.16](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-charts@8.5.0-prerelease.15...@patternfly/react-charts@8.5.0-prerelease.16) (2026-03-19) + +**Note:** Version bump only for package @patternfly/react-charts + +# [8.5.0-prerelease.15](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-charts@8.5.0-prerelease.14...@patternfly/react-charts@8.5.0-prerelease.15) (2026-02-24) + +**Note:** Version bump only for package @patternfly/react-charts + +# [8.5.0-prerelease.14](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-charts@8.5.0-prerelease.13...@patternfly/react-charts@8.5.0-prerelease.14) (2026-02-18) + +**Note:** Version bump only for package @patternfly/react-charts + +# [8.5.0-prerelease.13](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-charts@8.5.0-prerelease.12...@patternfly/react-charts@8.5.0-prerelease.13) (2026-02-05) + +**Note:** Version bump only for package @patternfly/react-charts + +# [8.5.0-prerelease.12](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-charts@8.5.0-prerelease.11...@patternfly/react-charts@8.5.0-prerelease.12) (2026-01-28) + +**Note:** Version bump only for package @patternfly/react-charts + +# [8.5.0-prerelease.11](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-charts@8.5.0-prerelease.10...@patternfly/react-charts@8.5.0-prerelease.11) (2026-01-09) + +**Note:** Version bump only for package @patternfly/react-charts + +# [8.5.0-prerelease.10](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-charts@8.5.0-prerelease.9...@patternfly/react-charts@8.5.0-prerelease.10) (2025-12-17) + +**Note:** Version bump only for package @patternfly/react-charts + +# [8.5.0-prerelease.9](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-charts@8.5.0-prerelease.6...@patternfly/react-charts@8.5.0-prerelease.9) (2025-12-16) + +**Note:** Version bump only for package @patternfly/react-charts + +# [8.5.0-prerelease.6](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-charts@8.5.0-prerelease.5...@patternfly/react-charts@8.5.0-prerelease.6) (2025-11-14) + +### Bug Fixes + +- Moves items to new nav. ([#12013](https://github.com/patternfly/patternfly-react/issues/12013)) ([ddd0696](https://github.com/patternfly/patternfly-react/commit/ddd0696796134c7d0f9583ce56e26b0df47156cb)) + +# [8.5.0-prerelease.5](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-charts@8.5.0-prerelease.4...@patternfly/react-charts@8.5.0-prerelease.5) (2025-11-12) + +**Note:** Version bump only for package @patternfly/react-charts + +# [8.5.0-prerelease.4](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-charts@8.5.0-prerelease.3...@patternfly/react-charts@8.5.0-prerelease.4) (2025-11-06) + +**Note:** Version bump only for package @patternfly/react-charts + +# [8.5.0-prerelease.3](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-charts@8.5.0-prerelease.2...@patternfly/react-charts@8.5.0-prerelease.3) (2025-11-05) + +**Note:** Version bump only for package @patternfly/react-charts + +# [8.5.0-prerelease.2](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-charts@8.5.0-prerelease.1...@patternfly/react-charts@8.5.0-prerelease.2) (2025-10-31) + +**Note:** Version bump only for package @patternfly/react-charts + +# [8.5.0-prerelease.1](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-charts@8.4.0...@patternfly/react-charts@8.5.0-prerelease.1) (2025-10-30) + +**Note:** Version bump only for package @patternfly/react-charts + +# [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 + +# [8.3.0-prerelease.22](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-charts@8.4.0-prerelease.0...@patternfly/react-charts@8.3.0-prerelease.22) (2025-07-22) + +### Reverts + +- Revert "chore(release): releasing packages [ci skip]" ([40999d7](https://github.com/patternfly/patternfly-react/commit/40999d70a7a3aeadbe8f40fe96bb01ab3a6219d4)) + +# [8.3.0-prerelease.21](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-charts@8.3.0-prerelease.20...@patternfly/react-charts@8.3.0-prerelease.21) (2025-07-18) + +**Note:** Version bump only for package @patternfly/react-charts + +# [8.3.0-prerelease.20](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-charts@8.3.0-prerelease.19...@patternfly/react-charts@8.3.0-prerelease.20) (2025-07-17) + +**Note:** Version bump only for package @patternfly/react-charts + +# [8.3.0-prerelease.19](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-charts@8.3.0-prerelease.18...@patternfly/react-charts@8.3.0-prerelease.19) (2025-07-11) + +**Note:** Version bump only for package @patternfly/react-charts + +# [8.3.0-prerelease.18](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-charts@8.3.0-prerelease.17...@patternfly/react-charts@8.3.0-prerelease.18) (2025-07-02) + +**Note:** Version bump only for package @patternfly/react-charts + +# [8.3.0-prerelease.17](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-charts@8.3.0-prerelease.16...@patternfly/react-charts@8.3.0-prerelease.17) (2025-06-23) + +**Note:** Version bump only for package @patternfly/react-charts + +# [8.3.0-prerelease.16](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-charts@8.3.0-prerelease.15...@patternfly/react-charts@8.3.0-prerelease.16) (2025-06-20) + +**Note:** Version bump only for package @patternfly/react-charts + +# [8.3.0-prerelease.15](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-charts@8.3.0-prerelease.14...@patternfly/react-charts@8.3.0-prerelease.15) (2025-06-18) + +**Note:** Version bump only for package @patternfly/react-charts + +# [8.3.0-prerelease.14](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-charts@8.3.0-prerelease.13...@patternfly/react-charts@8.3.0-prerelease.14) (2025-06-17) + +**Note:** Version bump only for package @patternfly/react-charts + +# [8.3.0-prerelease.13](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-charts@8.3.0-prerelease.12...@patternfly/react-charts@8.3.0-prerelease.13) (2025-06-13) + +**Note:** Version bump only for package @patternfly/react-charts + +# [8.3.0-prerelease.12](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-charts@8.3.0-prerelease.11...@patternfly/react-charts@8.3.0-prerelease.12) (2025-06-13) + +**Note:** Version bump only for package @patternfly/react-charts + +# [8.3.0-prerelease.11](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-charts@8.3.0-prerelease.10...@patternfly/react-charts@8.3.0-prerelease.11) (2025-06-11) + +**Note:** Version bump only for package @patternfly/react-charts + +# [8.3.0-prerelease.10](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-charts@8.3.0-prerelease.9...@patternfly/react-charts@8.3.0-prerelease.10) (2025-05-21) + +**Note:** Version bump only for package @patternfly/react-charts + +# [8.3.0-prerelease.9](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-charts@8.3.0-prerelease.8...@patternfly/react-charts@8.3.0-prerelease.9) (2025-05-20) + +**Note:** Version bump only for package @patternfly/react-charts + +# [8.3.0-prerelease.8](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-charts@8.3.0-prerelease.7...@patternfly/react-charts@8.3.0-prerelease.8) (2025-05-20) + +**Note:** Version bump only for package @patternfly/react-charts + +# [8.3.0-prerelease.7](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-charts@8.3.0-prerelease.6...@patternfly/react-charts@8.3.0-prerelease.7) (2025-05-19) + +**Note:** Version bump only for package @patternfly/react-charts + +# [8.3.0-prerelease.6](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-charts@8.3.0-prerelease.5...@patternfly/react-charts@8.3.0-prerelease.6) (2025-05-19) + +**Note:** Version bump only for package @patternfly/react-charts + +# [8.3.0-prerelease.5](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-charts@8.3.0-prerelease.4...@patternfly/react-charts@8.3.0-prerelease.5) (2025-05-15) + +**Note:** Version bump only for package @patternfly/react-charts + +# [8.3.0-prerelease.4](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-charts@8.3.0-prerelease.3...@patternfly/react-charts@8.3.0-prerelease.4) (2025-05-15) + +**Note:** Version bump only for package @patternfly/react-charts + +# [8.3.0-prerelease.3](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-charts@8.3.0-prerelease.2...@patternfly/react-charts@8.3.0-prerelease.3) (2025-05-15) + +**Note:** Version bump only for package @patternfly/react-charts + +# [8.3.0-prerelease.2](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-charts@8.3.0-prerelease.1...@patternfly/react-charts@8.3.0-prerelease.2) (2025-04-29) + +**Note:** Version bump only for package @patternfly/react-charts + +# [8.3.0-prerelease.1](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-charts@8.2.1-prerelease.1...@patternfly/react-charts@8.3.0-prerelease.1) (2025-04-24) + +**Note:** Version bump only for package @patternfly/react-charts + +## [8.2.1-prerelease.1](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-charts@8.2.1-prerelease.0...@patternfly/react-charts@8.2.1-prerelease.1) (2025-04-21) + +### Features + +- **version:** testing react 19 ([#11754](https://github.com/patternfly/patternfly-react/issues/11754)) ([b981588](https://github.com/patternfly/patternfly-react/commit/b9815886da3adc7a96bc2d48adacf86e8a752e61)) + +## [8.2.1-prerelease.0](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-charts@8.2.0...@patternfly/react-charts@8.2.1-prerelease.0) (2025-04-14) + +**Note:** Version bump only for package @patternfly/react-charts + +# 8.2.0 (2025-04-07) + +**Note:** Version bump only for package @patternfly/react-charts + +# [8.2.0-prerelease.28](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-charts@8.2.0-prerelease.27...@patternfly/react-charts@8.2.0-prerelease.28) (2025-04-01) + +**Note:** Version bump only for package @patternfly/react-charts + +# [8.2.0-prerelease.27](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-charts@8.2.0-prerelease.26...@patternfly/react-charts@8.2.0-prerelease.27) (2025-03-26) + +### Bug Fixes + +- **charts:** tooltip must call value formatter ([#11711](https://github.com/patternfly/patternfly-react/issues/11711)) ([ec4d8fc](https://github.com/patternfly/patternfly-react/commit/ec4d8fc5647b808420b3b975804e1348f14b1223)) + +# [8.2.0-prerelease.26](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-charts@8.2.0-prerelease.25...@patternfly/react-charts@8.2.0-prerelease.26) (2025-03-20) + +### Features + +- **charts:** Sankey and Line charts, based on Apache ECharts ([#11616](https://github.com/patternfly/patternfly-react/issues/11616)) ([f2479b1](https://github.com/patternfly/patternfly-react/commit/f2479b10dc6a96e97bfa1b0bb4bc3da789b9e93b)) + +# [8.2.0-prerelease.25](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-charts@8.2.0-prerelease.24...@patternfly/react-charts@8.2.0-prerelease.25) (2025-03-11) + +**Note:** Version bump only for package @patternfly/react-charts + +# [8.2.0-prerelease.24](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-charts@8.2.0-prerelease.23...@patternfly/react-charts@8.2.0-prerelease.24) (2025-03-10) + +**Note:** Version bump only for package @patternfly/react-charts + +# [8.2.0-prerelease.23](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-charts@8.2.0-prerelease.22...@patternfly/react-charts@8.2.0-prerelease.23) (2025-03-10) + +**Note:** Version bump only for package @patternfly/react-charts + +# [8.2.0-prerelease.22](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-charts@8.2.0-prerelease.21...@patternfly/react-charts@8.2.0-prerelease.22) (2025-03-06) + +**Note:** Version bump only for package @patternfly/react-charts + +# [8.2.0-prerelease.21](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-charts@8.2.0-prerelease.20...@patternfly/react-charts@8.2.0-prerelease.21) (2025-03-05) + +**Note:** Version bump only for package @patternfly/react-charts + +# [8.2.0-prerelease.20](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-charts@8.2.0-prerelease.19...@patternfly/react-charts@8.2.0-prerelease.20) (2025-03-03) + +**Note:** Version bump only for package @patternfly/react-charts + +# [8.2.0-prerelease.19](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-charts@8.2.0-prerelease.18...@patternfly/react-charts@8.2.0-prerelease.19) (2025-02-27) + +**Note:** Version bump only for package @patternfly/react-charts + +# [8.2.0-prerelease.18](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-charts@8.2.0-prerelease.17...@patternfly/react-charts@8.2.0-prerelease.18) (2025-02-25) + +**Note:** Version bump only for package @patternfly/react-charts + +# [8.2.0-prerelease.17](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-charts@8.2.0-prerelease.16...@patternfly/react-charts@8.2.0-prerelease.17) (2025-02-24) + +**Note:** Version bump only for package @patternfly/react-charts + +# [8.2.0-prerelease.16](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-charts@8.2.0-prerelease.15...@patternfly/react-charts@8.2.0-prerelease.16) (2025-02-20) + +**Note:** Version bump only for package @patternfly/react-charts + +# [8.2.0-prerelease.15](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-charts@8.2.0-prerelease.14...@patternfly/react-charts@8.2.0-prerelease.15) (2025-02-14) + +**Note:** Version bump only for package @patternfly/react-charts + +# [8.2.0-prerelease.14](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-charts@8.2.0-prerelease.13...@patternfly/react-charts@8.2.0-prerelease.14) (2025-02-12) + +**Note:** Version bump only for package @patternfly/react-charts + +# [8.2.0-prerelease.13](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-charts@8.2.0-prerelease.12...@patternfly/react-charts@8.2.0-prerelease.13) (2025-01-28) + +**Note:** Version bump only for package @patternfly/react-charts + +# [8.2.0-prerelease.12](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-charts@8.2.0-prerelease.11...@patternfly/react-charts@8.2.0-prerelease.12) (2025-01-24) + +**Note:** Version bump only for package @patternfly/react-charts + +# [8.2.0-prerelease.11](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-charts@8.2.0-prerelease.10...@patternfly/react-charts@8.2.0-prerelease.11) (2025-01-24) + +**Note:** Version bump only for package @patternfly/react-charts + +# [8.2.0-prerelease.10](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-charts@8.2.0-prerelease.9...@patternfly/react-charts@8.2.0-prerelease.10) (2025-01-23) + +**Note:** Version bump only for package @patternfly/react-charts + +# [8.2.0-prerelease.9](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-charts@8.2.0-prerelease.8...@patternfly/react-charts@8.2.0-prerelease.9) (2025-01-21) + +**Note:** Version bump only for package @patternfly/react-charts + +# [8.2.0-prerelease.8](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-charts@8.2.0-prerelease.7...@patternfly/react-charts@8.2.0-prerelease.8) (2025-01-17) + +**Note:** Version bump only for package @patternfly/react-charts + +# [8.2.0-prerelease.7](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-charts@8.2.0-prerelease.6...@patternfly/react-charts@8.2.0-prerelease.7) (2025-01-15) + +**Note:** Version bump only for package @patternfly/react-charts + +# [8.2.0-prerelease.6](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-charts@8.2.0-prerelease.5...@patternfly/react-charts@8.2.0-prerelease.6) (2025-01-14) + +**Note:** Version bump only for package @patternfly/react-charts + +# [8.2.0-prerelease.5](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-charts@8.2.0-prerelease.4...@patternfly/react-charts@8.2.0-prerelease.5) (2025-01-14) + +**Note:** Version bump only for package @patternfly/react-charts + +# [8.2.0-prerelease.4](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-charts@8.2.0-prerelease.3...@patternfly/react-charts@8.2.0-prerelease.4) (2025-01-10) + +**Note:** Version bump only for package @patternfly/react-charts + +# [8.2.0-prerelease.3](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-charts@8.2.0-prerelease.2...@patternfly/react-charts@8.2.0-prerelease.3) (2025-01-08) + +**Note:** Version bump only for package @patternfly/react-charts + +# [8.2.0-prerelease.2](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-charts@8.2.0-prerelease.1...@patternfly/react-charts@8.2.0-prerelease.2) (2025-01-07) + +### Bug Fixes + +- **charts:** fix Victory 37.3.4 issues ([#11356](https://github.com/patternfly/patternfly-react/issues/11356)) ([9c88a1c](https://github.com/patternfly/patternfly-react/commit/9c88a1c14784dd4e83f03528734366883ad5c133)) + +# [8.2.0-prerelease.1](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-charts@8.2.0-prerelease.0...@patternfly/react-charts@8.2.0-prerelease.1) (2025-01-06) + +**Note:** Version bump only for package @patternfly/react-charts + +# [8.2.0-prerelease.0](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-charts@8.1.1-prerelease.0...@patternfly/react-charts@8.2.0-prerelease.0) (2025-01-06) + +**Note:** Version bump only for package @patternfly/react-charts + +## [8.1.1-prerelease.0](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-charts@8.1.0...@patternfly/react-charts@8.1.1-prerelease.0) (2024-12-18) + +**Note:** Version bump only for package @patternfly/react-charts + +# 8.1.0 (2024-12-16) + +### Bug Fixes + +- Update promote.sh to release 6.1.0 ([2b5106f](https://github.com/patternfly/patternfly-react/commit/2b5106ff88ce207d4a9ed2066fd390009e81fb79)) + +# [8.1.0-prerelease.18](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-charts@8.1.0-prerelease.17...@patternfly/react-charts@8.1.0-prerelease.18) (2024-12-10) + +**Note:** Version bump only for package @patternfly/react-charts + +# [8.1.0-prerelease.17](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-charts@8.1.0-prerelease.16...@patternfly/react-charts@8.1.0-prerelease.17) (2024-12-04) + +**Note:** Version bump only for package @patternfly/react-charts + +# [8.1.0-prerelease.16](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-charts@8.1.0-prerelease.15...@patternfly/react-charts@8.1.0-prerelease.16) (2024-11-25) + +**Note:** Version bump only for package @patternfly/react-charts + +# [8.1.0-prerelease.15](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-charts@8.1.0-prerelease.14...@patternfly/react-charts@8.1.0-prerelease.15) (2024-11-20) + +**Note:** Version bump only for package @patternfly/react-charts + +# [8.1.0-prerelease.14](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-charts@8.1.0-prerelease.13...@patternfly/react-charts@8.1.0-prerelease.14) (2024-11-19) + +**Note:** Version bump only for package @patternfly/react-charts + +# [8.1.0-prerelease.13](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-charts@8.1.0-prerelease.12...@patternfly/react-charts@8.1.0-prerelease.13) (2024-11-19) + +**Note:** Version bump only for package @patternfly/react-charts + +# [8.1.0-prerelease.12](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-charts@8.1.0-prerelease.11...@patternfly/react-charts@8.1.0-prerelease.12) (2024-11-19) + +**Note:** Version bump only for package @patternfly/react-charts + +# [8.1.0-prerelease.11](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-charts@8.1.0-prerelease.10...@patternfly/react-charts@8.1.0-prerelease.11) (2024-11-19) + +**Note:** Version bump only for package @patternfly/react-charts + +# [8.1.0-prerelease.10](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-charts@8.1.0-prerelease.9...@patternfly/react-charts@8.1.0-prerelease.10) (2024-11-18) + +### Bug Fixes + +- **deps:** update dependency tslib to ^2.8.1 ([#11222](https://github.com/patternfly/patternfly-react/issues/11222)) ([7c90e9b](https://github.com/patternfly/patternfly-react/commit/7c90e9bff23083f097e78246570be60dacfb27c0)) + +# [8.1.0-prerelease.9](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-charts@8.1.0-prerelease.8...@patternfly/react-charts@8.1.0-prerelease.9) (2024-11-18) + +**Note:** Version bump only for package @patternfly/react-charts + +# [8.1.0-prerelease.8](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-charts@8.1.0-prerelease.7...@patternfly/react-charts@8.1.0-prerelease.8) (2024-11-15) + +**Note:** Version bump only for package @patternfly/react-charts + +# [8.1.0-prerelease.7](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-charts@8.1.0-prerelease.6...@patternfly/react-charts@8.1.0-prerelease.7) (2024-11-15) + +**Note:** Version bump only for package @patternfly/react-charts + +# [8.1.0-prerelease.6](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-charts@8.1.0-prerelease.5...@patternfly/react-charts@8.1.0-prerelease.6) (2024-11-15) + +**Note:** Version bump only for package @patternfly/react-charts + +# [8.1.0-prerelease.5](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-charts@8.1.0-prerelease.4...@patternfly/react-charts@8.1.0-prerelease.5) (2024-11-14) + +**Note:** Version bump only for package @patternfly/react-charts + +# [8.1.0-prerelease.4](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-charts@8.1.0-prerelease.3...@patternfly/react-charts@8.1.0-prerelease.4) (2024-11-14) + +**Note:** Version bump only for package @patternfly/react-charts + +# [8.1.0-prerelease.3](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-charts@8.1.0-prerelease.2...@patternfly/react-charts@8.1.0-prerelease.3) (2024-11-13) + +**Note:** Version bump only for package @patternfly/react-charts + +# [8.1.0-prerelease.2](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-charts@8.1.0-prerelease.1...@patternfly/react-charts@8.1.0-prerelease.2) (2024-11-06) + +**Note:** Version bump only for package @patternfly/react-charts + +# [8.1.0-prerelease.1](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-charts@8.1.0-prerelease.0...@patternfly/react-charts@8.1.0-prerelease.1) (2024-10-30) + +### Bug Fixes + +- **charts:** update font-family ([#11122](https://github.com/patternfly/patternfly-react/issues/11122)) ([e2d9e39](https://github.com/patternfly/patternfly-react/commit/e2d9e3922801f96336993037dda91eeb150c465e)) + +# 8.1.0-prerelease.0 (2024-10-24) + +**Note:** Version bump only for package @patternfly/react-charts + +# 8.0.0 (2024-10-24) + +**Note:** Version bump only for package @patternfly/react-charts + +# [8.0.0-prerelease.15](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-charts@8.0.0-prerelease.14...@patternfly/react-charts@8.0.0-prerelease.15) (2024-10-23) + +### Bug Fixes + +- **charts:** update Victory packages to be optional peer dependencies ([#11128](https://github.com/patternfly/patternfly-react/issues/11128)) ([09a8f38](https://github.com/patternfly/patternfly-react/commit/09a8f38fbe2d8c1d2fb4d607440a8f14271224c8)) + +# [8.0.0-prerelease.14](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-charts@8.0.0-prerelease.13...@patternfly/react-charts@8.0.0-prerelease.14) (2024-10-02) + +**Note:** Version bump only for package @patternfly/react-charts + +# [8.0.0-prerelease.13](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-charts@8.0.0-prerelease.12...@patternfly/react-charts@8.0.0-prerelease.13) (2024-09-30) + +### Features + +- **charts:** import charts from @patternfly/react-charts/victory ([#11091](https://github.com/patternfly/patternfly-react/issues/11091)) ([2d3921b](https://github.com/patternfly/patternfly-react/commit/2d3921b7dab1733fce0a640e7d64d01fc21dbac1)) + +# [8.0.0-prerelease.12](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-charts@8.0.0-prerelease.11...@patternfly/react-charts@8.0.0-prerelease.12) (2024-09-26) + +**Note:** Version bump only for package @patternfly/react-charts + +# [8.0.0-prerelease.11](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-charts@8.0.0-prerelease.10...@patternfly/react-charts@8.0.0-prerelease.11) (2024-09-24) + +**Note:** Version bump only for package @patternfly/react-charts + +# [8.0.0-prerelease.10](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-charts@8.0.0-prerelease.9...@patternfly/react-charts@8.0.0-prerelease.10) (2024-09-19) + +### Bug Fixes + +- **charts:** defaultProps deprecation warning ([#11019](https://github.com/patternfly/patternfly-react/issues/11019)) ([#11027](https://github.com/patternfly/patternfly-react/issues/11027)) ([fc44673](https://github.com/patternfly/patternfly-react/commit/fc44673efe193d37e400b4e87c0f300a205eefbc)) + +# [8.0.0-prerelease.9](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-charts@8.0.0-prerelease.8...@patternfly/react-charts@8.0.0-prerelease.9) (2024-09-18) + +### Bug Fixes + +- **generate tokens:** prefix tokens with a t\_ ([#11002](https://github.com/patternfly/patternfly-react/issues/11002)) ([0dac6b8](https://github.com/patternfly/patternfly-react/commit/0dac6b88b9f560975627c80c6e8ab816d8b78ac9)) + +# [8.0.0-prerelease.8](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-charts@8.0.0-prerelease.7...@patternfly/react-charts@8.0.0-prerelease.8) (2024-09-11) + +**Note:** Version bump only for package @patternfly/react-charts + +# [8.0.0-prerelease.7](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-charts@8.0.0-prerelease.6...@patternfly/react-charts@8.0.0-prerelease.7) (2024-09-11) + +### Bug Fixes + +- **charts:** victoryCreateContainer breakage (v6) ([#10925](https://github.com/patternfly/patternfly-react/issues/10925)) ([4a815fb](https://github.com/patternfly/patternfly-react/commit/4a815fb80f0c53c53947fcc53002111bfbf02a4d)) + +# [8.0.0-prerelease.6](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-charts@8.0.0-prerelease.5...@patternfly/react-charts@8.0.0-prerelease.6) (2024-09-10) + +### Bug Fixes + +- **deps:** update dependency victory-chart to ^37.1.1 ([#10956](https://github.com/patternfly/patternfly-react/issues/10956)) ([ece3987](https://github.com/patternfly/patternfly-react/commit/ece39872f3b7ef6893d3deeedefb64baa60fbd67)) + +# [8.0.0-prerelease.5](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-charts@8.0.0-prerelease.4...@patternfly/react-charts@8.0.0-prerelease.5) (2024-09-10) + +### Bug Fixes + +- **deps:** update dependency victory-box-plot to ^37.1.1 ([#10954](https://github.com/patternfly/patternfly-react/issues/10954)) ([fa15a66](https://github.com/patternfly/patternfly-react/commit/fa15a66a71f6bac482173bb01ced9b70101530f8)) + +# [8.0.0-prerelease.4](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-charts@8.0.0-prerelease.3...@patternfly/react-charts@8.0.0-prerelease.4) (2024-09-10) + +### Bug Fixes + +- **deps:** update dependency victory-area to ^37.1.1 ([#10951](https://github.com/patternfly/patternfly-react/issues/10951)) ([4491d63](https://github.com/patternfly/patternfly-react/commit/4491d630cf58bb7729a66b93bda2f62a6b94e012)) +- **deps:** update dependency victory-bar to ^37.1.1 ([#10953](https://github.com/patternfly/patternfly-react/issues/10953)) ([8564fff](https://github.com/patternfly/patternfly-react/commit/8564fffd3deff057b52aac5d3dbbd0b2cb06ac0e)) + +# [8.0.0-prerelease.3](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-charts@8.0.0-prerelease.2...@patternfly/react-charts@8.0.0-prerelease.3) (2024-09-10) + +### Bug Fixes + +- **deps:** update dependency victory-axis to ^37.1.1 ([#10952](https://github.com/patternfly/patternfly-react/issues/10952)) ([879e1e8](https://github.com/patternfly/patternfly-react/commit/879e1e88da35382d7475da63c89ecfa061ecf5a9)) + +# [8.0.0-prerelease.2](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-charts@8.0.0-prerelease.1...@patternfly/react-charts@8.0.0-prerelease.2) (2024-09-10) + +### Bug Fixes + +- **deps:** update dependency tslib to ^2.7.0 ([#10949](https://github.com/patternfly/patternfly-react/issues/10949)) ([024b3cc](https://github.com/patternfly/patternfly-react/commit/024b3cc4b1afd4ba9f2dc774c0842712d4fbab1a)) + +# [8.0.0-prerelease.1](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-charts@8.0.0-alpha.39...@patternfly/react-charts@8.0.0-prerelease.1) (2024-09-07) + +**Note:** Version bump only for package @patternfly/react-charts + # [8.0.0-alpha.39](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-charts@8.0.0-alpha.38...@patternfly/react-charts@8.0.0-alpha.39) (2024-08-27) **Note:** Version bump only for package @patternfly/react-charts diff --git a/packages/react-charts/README.md b/packages/react-charts/README.md index b249e79b697..eb38bc5fd29 100644 --- a/packages/react-charts/README.md +++ b/packages/react-charts/README.md @@ -6,14 +6,20 @@ This package provides PatternFly charting components for [PatternFly][patternfly ```sh yarn add @patternfly/react-charts +yarn add victory ``` or ```sh npm install @patternfly/react-charts --save +npm install victory --save ``` +Note that Victory is now an optional peer dependency, allowing future chart libraries to be installed without including Victory dependencies and vice versa + - You may choose to install the single "victory" package to cover all features + - Or, install packages based on the features used in your app (e.g., "victory-core", "victory-tooltip", etc.). + # Usage #### Pre-requisites @@ -27,7 +33,7 @@ import '@patternfly/react-core/dist/styles/base.css'; #### Example Component Usage ```js -import { Area } from '@patternfly/react-charts'; +import { Area } from '@patternfly/react-charts/victory'; export default ; diff --git a/packages/react-charts/package.json b/packages/react-charts/package.json index 37aefc84993..c5985f66b84 100644 --- a/packages/react-charts/package.json +++ b/packages/react-charts/package.json @@ -1,10 +1,20 @@ { "name": "@patternfly/react-charts", - "version": "8.0.0-prerelease.0", + "version": "8.6.0-prerelease.1", "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", "types": "dist/esm/index.d.ts", + "typesVersions": { + "*": { + "echarts": [ + "dist/esm/echarts/index.d.ts" + ], + "victory": [ + "dist/esm/victory/index.d.ts" + ] + } + }, "patternfly:src": "src/", "sideEffects": [ "*.css", @@ -32,36 +42,95 @@ "@patternfly/react-styles": "workspace:^", "@patternfly/react-tokens": "workspace:^", "hoist-non-react-statics": "^3.3.2", - "lodash": "^4.17.21", - "tslib": "^2.6.3", - "victory-area": "^37.0.2", - "victory-axis": "^37.0.2", - "victory-bar": "^37.0.2", - "victory-box-plot": "^37.0.2", - "victory-chart": "^37.0.2", - "victory-core": "^37.0.2", - "victory-create-container": "^37.0.2", - "victory-cursor-container": "^37.0.2", - "victory-group": "^37.0.2", - "victory-legend": "^37.0.2", - "victory-line": "^37.0.2", - "victory-pie": "^37.0.2", - "victory-scatter": "^37.0.2", - "victory-stack": "^37.0.2", - "victory-tooltip": "^37.0.2", - "victory-voronoi-container": "^37.0.2", - "victory-zoom-container": "^37.0.2" + "lodash": "^4.17.23", + "tslib": "^2.8.1" + }, + "devDependencies": { + "@types/lodash": "^4.17.24", + "fs-extra": "^11.3.3", + "jest-canvas-mock": "^2.5.2" }, "peerDependencies": { - "react": "^17 || ^18", - "react-dom": "^17 || ^18" + "echarts": "^5.6.0 || ^6.0.0", + "react": "^17 || ^18 || ^19", + "react-dom": "^17 || ^18 || ^19", + "victory-area": "^37.3.6", + "victory-axis": "^37.3.6", + "victory-bar": "^37.3.6", + "victory-box-plot": "^37.3.6", + "victory-chart": "^37.3.6", + "victory-core": "^37.3.6", + "victory-create-container": "^37.3.6", + "victory-cursor-container": "^37.3.6", + "victory-group": "^37.3.6", + "victory-legend": "^37.3.6", + "victory-line": "^37.3.6", + "victory-pie": "^37.3.6", + "victory-scatter": "^37.3.6", + "victory-stack": "^37.3.6", + "victory-tooltip": "^37.3.6", + "victory-voronoi-container": "^37.3.6", + "victory-zoom-container": "^37.3.6" }, - "scripts": { - "clean": "rimraf dist", - "build:single:packages": "node ../../scripts/build-single-packages.mjs --config single-packages.config.json" + "peerDependenciesMeta": { + "echarts": { + "optional": true + }, + "victory-area": { + "optional": true + }, + "victory-axis": { + "optional": true + }, + "victory-bar": { + "optional": true + }, + "victory-box-plot": { + "optional": true + }, + "victory-chart": { + "optional": true + }, + "victory-core": { + "optional": true + }, + "victory-create-container": { + "optional": true + }, + "victory-cursor-container": { + "optional": true + }, + "victory-group": { + "optional": true + }, + "victory-legend": { + "optional": true + }, + "victory-line": { + "optional": true + }, + "victory-pie": { + "optional": true + }, + "victory-scatter": { + "optional": true + }, + "victory-stack": { + "optional": true + }, + "victory-tooltip": { + "optional": true + }, + "victory-voronoi-container": { + "optional": true + }, + "victory-zoom-container": { + "optional": true + } }, - "devDependencies": { - "@types/lodash": "^4.17.5", - "fs-extra": "^11.2.0" + "scripts": { + "clean": "rimraf dist echarts victory", + "build:single:packages": "node ../../scripts/build-single-packages.mjs --config single-packages.config.json", + "subpaths": "node ../../scripts/exportSubpaths.mjs --config subpaths.config.json" } } diff --git a/packages/react-charts/single-packages.config.json b/packages/react-charts/single-packages.config.json index 4a9651bb17d..274428abad0 100644 --- a/packages/react-charts/single-packages.config.json +++ b/packages/react-charts/single-packages.config.json @@ -1,4 +1,4 @@ { "packageName": "@patternfly/react-charts", - "exclude": ["dist/esm/deprecated/index.js", "dist/esm/next/index.js"] + "exclude": ["dist/esm/echarts/deprecated/index.js", "dist/esm/echarts/next/index.js", "dist/esm/victory/deprecated/index.js", "dist/esm/victory/next/index.js"] } diff --git a/packages/react-charts/src/components/ChartArea/examples/ChartArea.md b/packages/react-charts/src/components/ChartArea/examples/ChartArea.md deleted file mode 100644 index 9ef037db121..00000000000 --- a/packages/react-charts/src/components/ChartArea/examples/ChartArea.md +++ /dev/null @@ -1,283 +0,0 @@ ---- -id: Area chart -section: charts -propComponents: [ - 'Chart', - 'ChartArea', - 'ChartAxis', - 'ChartGroup', - 'ChartThreshold', - 'ChartVoronoiContainer' -] -hideDarkMode: true ---- - -import { Chart, ChartArea, ChartAxis, ChartGroup, ChartThreshold, ChartThemeColor, ChartLegendTooltip, ChartVoronoiContainer, createContainer } from '@patternfly/react-charts'; -import { getResizeObserver } from '@patternfly/react-core'; - -## Introduction -Note: PatternFly React charts live in its own package at [@patternfly/react-charts](https://www.npmjs.com/package/@patternfly/react-charts)! - -PatternFly React charts are based on the [Victory](https://formidable.com/open-source/victory/docs/victory-chart/) chart library, along with additional functionality, custom components, and theming for PatternFly. This provides a collection of React based components you can use to build PatternFly patterns with consistent markup, styling, and behavior. - -## Examples -### Basic with right aligned legend -```js -import React from 'react'; -import { Chart, ChartArea, ChartAxis, ChartGroup, ChartVoronoiContainer } from '@patternfly/react-charts'; -// import '@patternfly/patternfly/patternfly-charts.css'; // Required for mix-blend-mode CSS property - -
- `${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} - > - - - - - - - - -
-``` - -### Teal with bottom aligned legend and axis label - -This demonstrates how to combine cursor and voronoi containers to display tooltips along with a cursor. - -```js -import React from 'react'; -import { Chart, ChartArea, ChartAxis, ChartGroup, ChartThemeColor, ChartLegendTooltip, createContainer } from '@patternfly/react-charts'; -// import '@patternfly/patternfly/patternfly-charts.css'; // Required for mix-blend-mode CSS property - -class BottomAlignedLegend extends React.Component { - render() { - // 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}`} - labelComponent={ datum.x}/>} - mouseFollowTooltips - voronoiDimension="x" - voronoiPadding={50} - /> - } - legendData={legendData} - legendPosition="bottom" - height={250} - name="chart2" - padding={{ - bottom: 100, // Adjusted to accommodate legend - left: 50, - right: 50, - top: 50, - }} - maxDomain={{y: 9}} - themeColor={ChartThemeColor.teal} - width={650} - > - - - - - - - - -
- ); - } -} -``` - -### Multi-color (unordered) bottom-left aligned legend and responsive container -```js -import React from 'react'; -import { Chart, ChartArea, ChartAxis, ChartGroup, ChartThemeColor, ChartVoronoiContainer } from '@patternfly/react-charts'; -import { getResizeObserver } from '@patternfly/react-core'; -// import '@patternfly/patternfly/patternfly-charts.css'; // Required for mix-blend-mode CSS property - -class MultiColorChart extends React.Component { - constructor(props) { - super(props); - this.containerRef = React.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; - - return ( -
- `${datum.name}: ${datum.y}`} constrainToVisibleArea />} - legendData={[{ name: 'Cats' }, { name: 'Dogs' }, { name: 'Birds' }]} - legendPosition="bottom-left" - height={225} - name="chart3" - padding={{ - bottom: 75, // Adjusted to accommodate legend - left: 50, - right: 50, - top: 50, - }} - maxDomain={{y: 9}} - themeColor={ChartThemeColor.multiUnordered} - width={width} - > - - - - - - - - -
- ); - } -} -``` - -## Documentation -### Tips -- See Victory's [FAQ](https://formidable.com/open-source/victory/docs/faq) -- For single data points or zero values, you may want to set the `domain` prop -- `ChartLegend` may be used as a standalone component, instead of using `legendData` -- The `theme` and `themeColor` props should be applied at the most top level component -- Use `ChartGroup` to apply theme color scales and other properties to multiple components - -### Note -Currently, the generated documentation below is not able to resolve type definitions from Victory imports. For the -components used in the examples above, Victory pass-thru props are also documented here: - -- For `Chart` props, see [VictoryChart](https://formidable.com/open-source/victory/docs/victory-chart) -- For `ChartArea` props, see [VictoryArea](https://formidable.com/open-source/victory/docs/victory-area) -- For `ChartAxis` props, see [VictoryAxis](https://formidable.com/open-source/victory/docs/victory-axis) -- For `ChartGroup` props, see [VictoryGroup](https://formidable.com/open-source/victory/docs/victory-group) -- For `ChartVoronoiContainer` props, see [VictoryVoronoiContainer](https://formidable.com/open-source/victory/docs/victory-voronoi-container) diff --git a/packages/react-charts/src/components/ChartBar/examples/ChartBar.md b/packages/react-charts/src/components/ChartBar/examples/ChartBar.md deleted file mode 100644 index a441a78b924..00000000000 --- a/packages/react-charts/src/components/ChartBar/examples/ChartBar.md +++ /dev/null @@ -1,224 +0,0 @@ ---- -id: Bar chart -section: charts -propComponents: [ - 'Chart', - 'ChartAxis', - 'ChartBar', - 'ChartGroup', - 'ChartVoronoiContainer' -] -hideDarkMode: true ---- - -import { Chart, ChartAxis, ChartBar, ChartGroup, ChartThemeColor, ChartTooltip, ChartVoronoiContainer } from '@patternfly/react-charts'; -import { VictoryZoomContainer } from 'victory-zoom-container'; - -## Introduction -Note: PatternFly React charts live in its own package at [@patternfly/react-charts](https://www.npmjs.com/package/@patternfly/react-charts)! - -PatternFly React charts are based on the [Victory](https://formidable.com/open-source/victory/docs/victory-chart/) chart library, along with additional functionality, custom components, and theming for PatternFly. This provides a collection of React based components you can use to build PatternFly patterns with consistent markup, styling, and behavior. - -## Examples -### Basic with right aligned legend -```js -import React from 'react'; -import { Chart, ChartAxis, ChartBar, ChartGroup, ChartVoronoiContainer } from '@patternfly/react-charts'; - -
- `${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="chart1" - padding={{ - bottom: 50, - left: 50, - right: 200, // Adjusted to accommodate legend - top: 50 - }} - width={600} - > - - - - - - - - - -
-``` - -### Purple with bottom aligned legend - -This demonstrates an alternate way of applying tooltips using data labels. - -```js -import React from 'react'; -import { Chart, ChartAxis, ChartBar, ChartGroup, ChartThemeColor, ChartTooltip } from '@patternfly/react-charts'; - -class EmbeddedLegend extends React.Component { - render() { - const label = ({ datum }) => `${datum.name}: ${datum.y}`; - - return ( -
- - - - - } - /> - } - /> - } - /> - } - /> - - -
- ); - } -} -``` - -### Multi-color (ordered) with bottom-left aligned legend - -This demonstrates zoom for both the x and y axis. - -```js -import React from 'react'; -import { Chart, ChartAxis, ChartBar, ChartGroup, ChartThemeColor } from '@patternfly/react-charts'; -import { VictoryZoomContainer } from 'victory-zoom-container'; - -
- } - domainPadding={{ x: [30, 25] }} - legendData={[{ name: 'Cats' }, { name: 'Dogs' }, { name: 'Birds' }, { name: 'Mice' }]} - legendPosition="bottom-left" - height={400} - name="chart3" - padding={{ - bottom: 75, // Adjusted to accommodate legend - left: 50, - right: 100, // Adjusted to accommodate tooltip - top: 50 - }} - themeColor={ChartThemeColor.multiOrdered} - width={450} - > - - - - - - - - - -
-``` - -### Single with right aligned legend -```js -import React from 'react'; -import { Chart, ChartBar, ChartVoronoiContainer } from '@patternfly/react-charts'; - -
- `${datum.name}: ${datum.y}`} constrainToVisibleArea />} - domain={{y: [0,9]}} - domainPadding={{ x: [30, 25] }} - legendData={[{ name: 'Cats' }]} - legendOrientation="vertical" - legendPosition="right" - height={250} - name="chart4" - padding={{ - bottom: 50, - left: 50, - right: 200, // Adjusted to accommodate legend - top: 50 - }} - width={600} - > - - -
-``` - -## Documentation -### Tips -- See Victory's [FAQ](https://formidable.com/open-source/victory/docs/faq) -- For single data points or zero values, you may want to set the `domain` prop -- `ChartLegend` may be used as a standalone component, instead of using `legendData` -- The `theme` and `themeColor` props should be applied at the most top level component -- Use `ChartGroup` to apply theme color scales and other properties to multiple components - -### Note -Currently, the generated documentation below is not able to resolve type definitions from Victory imports. For the -components used in the examples above, Victory pass-thru props are also documented here: - -- For `Chart` props, see [VictoryChart](https://formidable.com/open-source/victory/docs/victory-chart) -- For `ChartAxis` props, see [VictoryAxis](https://formidable.com/open-source/victory/docs/victory-axis) -- For `ChartBar` props, see [VictoryBar](https://formidable.com/open-source/victory/docs/victory-bar) -- For `ChartGroup` props, see [VictoryGroup](https://formidable.com/open-source/victory/docs/victory-group) -- For `ChartVoronoiContainer` props, see [VictoryVoronoiContainer](https://formidable.com/open-source/victory/docs/victory-voronoi-container) diff --git a/packages/react-charts/src/components/ChartBoxPlot/examples/ChartBoxPlot.md b/packages/react-charts/src/components/ChartBoxPlot/examples/ChartBoxPlot.md deleted file mode 100644 index 0a3a788cefb..00000000000 --- a/packages/react-charts/src/components/ChartBoxPlot/examples/ChartBoxPlot.md +++ /dev/null @@ -1,350 +0,0 @@ ---- -id: Box plot chart -section: charts -propComponents: [ - 'Chart', - 'ChartAxis', - 'ChartBoxPlot', - 'ChartCursorFlyout', - 'ChartCursorTooltip', - 'ChartVoronoiContainer' -] -hideDarkMode: true ---- - -import { Chart, ChartAxis, ChartBoxPlot, ChartCursorFlyout, ChartCursorTooltip, ChartLegendTooltip, ChartThemeColor, ChartThreshold, ChartVoronoiContainer, createContainer } from '@patternfly/react-charts'; -import { VictoryZoomContainer } from 'victory-zoom-container'; -import chart_color_orange_300 from '@patternfly/react-tokens/dist/esm/chart_color_orange_300'; - -## Introduction -Note: PatternFly React charts live in its own package at [@patternfly/react-charts](https://www.npmjs.com/package/@patternfly/react-charts)! - -PatternFly React charts are based on the [Victory](https://formidable.com/open-source/victory/docs/victory-chart/) chart library, along with additional functionality, custom components, and theming for PatternFly. This provides a collection of React based components you can use to build PatternFly patterns with consistent markup, styling, and behavior. - - -## Examples -### Basic with right aligned legend -```js -import React from 'react'; -import { Chart, ChartAxis, ChartBoxPlot } from '@patternfly/react-charts'; - -
- - - - - -
-``` - -### Labels with bottom aligned legend - -This demonstrates how to display labels. - -```js -import React from 'react'; -import { Chart, ChartAxis, ChartBoxPlot } from '@patternfly/react-charts'; - -
- - - - - -
-``` - -### 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 React from 'react'; -import { Chart, ChartAxis, ChartBoxPlot, ChartLegendTooltip, ChartThemeColor, ChartThreshold, createContainer } from '@patternfly/react-charts'; -import chart_color_orange_300 from '@patternfly/react-tokens/dist/esm/chart_color_orange_300'; - -class EmbeddedLegend extends React.Component { - render() { - // Note: Container order is important - const CursorVoronoiContainer = createContainer("voronoi", "cursor"); - const legendData = [ - { - childName: 'limit', - name: 'Limit', - symbol: { fill: chart_color_orange_300.var, type: 'threshold' } - }, - { childName: 'cats', name: 'Cats' }, - // Force extra space below for line wrapping - { - childName: 'cats', - name: '', - symbol: { fill: 'none' } - }, - { - childName: 'cats', - name: '', - symbol: { fill: 'none' } - }, - ]; - const labelFormatter = (datum) => { - // With box plot data, datum.y will also be an array - if (datum && (datum._min || datum._median || datum._max || datum._q1 || datum._q3)) { - return `Min: ${datum._min}, Max: ${datum._max}\nMedian: ${datum._median}\nQ1: ${datum._q1}, Q3: ${datum._q3}`; - } - const yVal = Array.isArray(datum.y) ? datum.y[0] : datum.y; - return yVal !== null ? yVal : 'no data'; - } - return ( -
- labelFormatter(datum)} - labelComponent={ datum.x} />} - mouseFollowTooltips - voronoiDimension="x" - voronoiPadding={50} - /> - } - domain={{y: [0, 13]}} - domainPadding={{ x: [30, 25] }} - legendData={legendData} - legendPosition="bottom" - height={350} - name="chart5" - padding={{ - bottom: 75, // Adjusted to accommodate legend - left: 50, - right: 50, - top: 50 - }} - themeColor={ChartThemeColor.green} - width={600} - > - - - - - -
- ); - } -} -``` - -### 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 React from 'react'; -import { Chart, ChartAxis, ChartBoxPlot, ChartCursorTooltip, ChartThemeColor, createContainer } from '@patternfly/react-charts'; - -class EmbeddedHtml extends React.Component { - constructor(props) { - super(props); - this.baseStyles = { - color: '#f0f0f0', - fontFamily: 'RedHatText, Overpass, overpass, helvetica, arial, sans-serif', - fontSize: '14px' - }; - this.leftColumn = { - paddingLeft: '10px', - width: '50%' - } - this.rightColumn = { - paddingRight: '20px', - textAlign: 'right', - width: '50%' - } - } - - render() { - // Note: Container order is important - const CursorVoronoiContainer = createContainer("voronoi", "cursor"); - const legendData = [{ name: 'Cats' }]; - - // Custom HTML component to create a legend layout - const HtmlLegendContent = ({datum, text, title, x, y, ...rest}) => ( - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
{title(datum)}
Max{datum._max}
Median{datum._median}
Min{datum._min}
Q1{datum._q1}
Q3{datum._q3}
-
-
- ); - - return ( -
- `${datum.y}`} - labelComponent={ - datum.x} />} - /> - } - mouseFollowTooltips - voronoiDimension="x" - voronoiPadding={50} - /> - } - domain={{y: [0, 12]}} - domainPadding={{ x: [30, 25] }} - legendData={legendData} - legendPosition="bottom" - height={300} - name="chart4" - padding={{ - bottom: 75, // Adjusted to accommodate legend - left: 50, - right: 50, - top: 50, - }} - maxDomain={{y: 9}} - themeColor={ChartThemeColor.orange} - width={600} - > - - - - -
- ); - } -} -``` - -## Documentation -### Tips -- See Victory's [FAQ](https://formidable.com/open-source/victory/docs/faq) -- For single data points or zero values, you may want to set the `domain` prop -- The `theme` and `themeColor` props should be applied at the most top level component - -### Note -Currently, the generated documentation below is not able to resolve type definitions from Victory imports. For the -components used in the examples above, Victory pass-thru props are also documented here: - -- For `Chart` props, see [VictoryChart](https://formidable.com/open-source/victory/docs/victory-chart) -- For `ChartAxis` props, see [VictoryAxis](https://formidable.com/open-source/victory/docs/victory-axis) -- For `ChartBoxPlot` props, see [VictoryBoxPlot](https://formidable.com/open-source/victory/docs/victory-box-plot) -- For `ChartVoronoiContainer` props, see [VictoryVoronoiContainer](https://formidable.com/open-source/victory/docs/victory-voronoi-container) diff --git a/packages/react-charts/src/components/ChartBullet/examples/ChartBullet.md b/packages/react-charts/src/components/ChartBullet/examples/ChartBullet.md deleted file mode 100644 index de285fe2e7e..00000000000 --- a/packages/react-charts/src/components/ChartBullet/examples/ChartBullet.md +++ /dev/null @@ -1,942 +0,0 @@ ---- -id: Bullet chart -section: charts -propComponents: [ - 'ChartAxis', - 'ChartBullet', - 'ChartContainer' -] -hideDarkMode: true ---- - -import { ChartAxis, ChartBullet, ChartContainer, ChartThemeColor } from '@patternfly/react-charts'; -import { getResizeObserver } from '@patternfly/react-core'; - -## Introduction -Note: PatternFly React charts live in its own package at [@patternfly/react-charts](https://www.npmjs.com/package/@patternfly/react-charts)! - -PatternFly React charts are based on the [Victory](https://formidable.com/open-source/victory/docs/victory-chart/) chart library, along with additional functionality, custom components, and theming for PatternFly. This provides a collection of React based components you can use to build PatternFly patterns with consistent markup, styling, and behavior. - -## Examples -### Basic -```js -import React from 'react'; -import { ChartBullet } from '@patternfly/react-charts'; - -
- `${datum.name}: ${datum.y}`} - maxDomain={{y: 100}} - name="chart1" - primarySegmentedMeasureData={[{ name: 'Measure', y: 60 }]} - qualitativeRangeData={[{ name: 'Range', y: 50 }, { name: 'Range', y: 75 }]} - width={600} - /> -
-``` - -### Segmented primary measure -```js -import React from 'react'; -import { ChartBullet } from '@patternfly/react-charts'; - -
- `${datum.name}: ${datum.y}`} - maxDomain={{y: 100}} - name="chart2" - 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 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" - width={600} - /> -
-``` - -### Responsive container with bottom aligned legend - -This demonstrates a responsive legend which wraps when items are wider than its container. - -```js -import React from 'react'; -import { ChartBullet } from '@patternfly/react-charts'; -import { getResizeObserver } from '@patternfly/react-core'; - -class BulletChart extends React.Component { - constructor(props) { - super(props); - this.containerRef = React.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(200); - return ( -
- `${datum.name}: ${datum.y}`} - legendAllowWrap={this.handleLegendAllowWrap} - legendPosition="bottom-left" - maxDomain={{y: 100}} - name="chart3" - 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} - /> -
- ); - } -} -``` - -### Primary measure dot -```js -import React from 'react'; -import { ChartBullet } from '@patternfly/react-charts'; - -
- `${datum.name}: ${datum.y}`} - maxDomain={{y: 100}} - name="chart4" - padding={{ - bottom: 50, - left: 150, // Adjusted to accommodate labels - right: 50, - top: 50 - }} - primaryDotMeasureData={[{ name: 'Measure', y: 25 }, { name: 'Measure', y: 60 }]} - primaryDotMeasureLegendData={[{ 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" - width={600} - /> -
-``` - -### Error measure and custom axis ticks - -This is a green bullet chart with error measure and custom axis ticks with 3 legend items per row. - -```js -import React from 'react'; -import { ChartAxis, ChartBullet } from '@patternfly/react-charts'; - -
- } - comparativeErrorMeasureData={[{name: 'Error', y: 120}]} - comparativeErrorMeasureLegendData={[{ name: 'Error' }]} - comparativeWarningMeasureData={[{name: 'Warning', y: 80}]} - comparativeWarningMeasureLegendData={[{ name: 'Warning' }]} - constrainToVisibleArea - height={200} - labels={({ datum }) => `${datum.name}: ${datum.y}`} - legendItemsPerRow={3} - name="chart5" - padding={{ - bottom: 50, - left: 150, // Adjusted to accommodate labels - right: 50, - top: 50 - }} - primarySegmentedMeasureData={[{ name: 'Measure', y: 25 }, { name: 'Measure', y: 75 }]} - primarySegmentedMeasureLegendData={[{ name: 'Measure 1' }, { name: 'Measure 2' }]} - qualitativeRangeData={[{ name: 'Range', y: 65 }, { name: 'Range', y: 100 }, { name: 'Range', y: 150 }]} - qualitativeRangeLegendData={[{ name: 'Range 1' }, { name: 'Range 2' }]} - themeColor={ChartThemeColor.green} - subTitle="Measure details" - title="Text label" - width={600} - /> -
-``` - -### Primary measure outside range - -This is a yellow bullet chart with primary measure greater than max range. - -```js -import React from 'react'; -import { ChartBullet } from '@patternfly/react-charts'; - -
- `${datum.name}: ${datum.y}`} - height={200} - maxDomain={{y: 125}} - minDomain={{y: 50}} - name="chart6" - padding={{ - bottom: 50, - left: 150, // Adjusted to accommodate labels - right: 75, - top: 50 - }} - primarySegmentedMeasureData={[{ name: 'Measure', y: 75 }, { name: 'Measure', y: 135 }]} - primarySegmentedMeasureLegendData={[{ name: 'Measure 1' }, { name: 'Measure 2' }]} - qualitativeRangeData={[{ name: 'Range', y: 85 }, { name: 'Range', y: 125 }]} - qualitativeRangeLegendData={[{ name: 'Range 1' }, { name: 'Range 2' }]} - themeColor={ChartThemeColor.yellow} - subTitle="Measure details" - title="Text label" - width={600} - /> -
-``` - -### Negative primary measure - -This bullet chart with negative primary measure is for measures considered to be bad when they are low. - -```js -import React from 'react'; -import { ChartBullet } from '@patternfly/react-charts'; - -
- `${datum.name}: ${datum.y}`} - maxDomain={{y: 75}} - minDomain={{y: -25}} - name="chart7" - padding={{ - bottom: 50, - left: 150, // Adjusted to accommodate labels - right: 50, - top: 65 - }} - primarySegmentedMeasureData={[{ name: 'Measure', y: -15 }]} - primarySegmentedMeasureLegendData={[{ name: 'Measure 1' }]} - qualitativeRangeData={[{ name: 'Range', y: 25, y0: -25 }, { name: 'Range', y: 50 }]} - qualitativeRangeLegendData={[{ name: 'Range 1' }, { name: 'Range 2' }]} - subTitle="Measure details" - title="Text label" - width={600} - /> -
-``` - -### Reversed with right aligned legend - -This reversed bullet chart with right aligned legend is for measures considered to be good when they are low. - -```js -import React from 'react'; -import { ChartBullet } from '@patternfly/react-charts'; - -
- `${datum.name}: ${datum.y}`} - legendPosition="right" - legendOrientation="vertical" - maxDomain={{y: 0}} - minDomain={{y: -100}} - name="chart8" - padding={{ - bottom: 50, - left: 150, // Adjusted to accommodate labels - right: 150, // Adjusted to accommodate legend - top: 80 - }} - primarySegmentedMeasureData={[{ name: 'Measure', y: -60 }, { name: 'Measure', y: -25 }]} - 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" - width={700} - /> -
-``` - -### Negative and positive primary measures - -This bullet chart with negative and positive primary measures has 4 legend items per row. - -```js -import React from 'react'; -import { ChartBullet } from '@patternfly/react-charts'; - -
- `${datum.name}: ${datum.y}`} - legendItemsPerRow={4} - maxDomain={{y: 75}} - minDomain={{y: -25}} - name="chart9" - padding={{ - bottom: 50, - left: 150, // Adjusted to accommodate labels - right: 50, - top: 65 - }} - primarySegmentedMeasureData={[{ name: 'Measure', y: -10 }, { name: 'Measure', y: -20 }, { name: 'Measure', y: 10 }, { name: 'Measure', y: 40 }]} - primarySegmentedMeasureLegendData={[{ name: 'Measure 1' }, { name: 'Measure 2' }, { name: 'Measure 3' }, { name: 'Measure 4' }]} - qualitativeRangeData={[{ name: 'Range', y: 25, y0: -25 }, { name: 'Range', y: 50 }]} - qualitativeRangeLegendData={[{ name: 'Range 1' }, { name: 'Range 2' }]} - subTitle="Measure details" - title="Text label" - width={600} - /> -
-``` - -### Vertical with segmented primary measure -```js -import React from 'react'; -import { ChartBullet } from '@patternfly/react-charts'; - -
- `${datum.name}: ${datum.y}`} - maxDomain={{y: 100}} - name="chart10" - padding={{ - bottom: 125, // Adjusted to accommodate legend - left: 400, - right: 50, - top: 50 - }} - 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" - width={500} - /> -
-``` - -### Vertical primary measure outside max range -```js -import React from 'react'; -import { ChartBullet } from '@patternfly/react-charts'; - -
- `${datum.name}: ${datum.y}`} - maxDomain={{y: 125}} - minDomain={{y: 50}} - name="chart11" - padding={{ - bottom: 125, // Adjusted to accommodate legend - left: 400, - right: 50, - top: 50 // Adjusted to accommodate primary segmented measure tooltip - }} - primarySegmentedMeasureData={[{ name: 'Measure', y: 75 }, { name: 'Measure', y: 135 }]} - primarySegmentedMeasureLegendData={[{ name: 'Measure 1' }, { name: 'Measure 2' }]} - qualitativeRangeData={[{ name: 'Range', y: 85 }, { name: 'Range', y: 125 }]} - qualitativeRangeLegendData={[{ name: 'Range 1' }, { name: 'Range 2' }]} - subTitle="Measure details" - title="Text label" - themeColor={ChartThemeColor.yellow} - width={500} - /> -
-``` - -### Custom labels -```js -import React from 'react'; -import { ChartAxis, ChartBullet } from '@patternfly/react-charts'; - -
- { - switch (val) { - case 0: - return 'New'; - case 25: - return 'Beginner'; - case 50: - return 'Intermediate'; - case 75: - return 'Advanced'; - case 100: - return 'Expert'; - } - }} - /> - } - comparativeWarningMeasureData={[{ name: 'Warning', y: 88 }]} - constrainToVisibleArea - height={150} - labels={({ datum }) => `${datum.name}: ${datum.y}`} - maxDomain={{y: 100}} - name="chart12" - primarySegmentedMeasureData={[{ name: 'Measure', y: 60 }]} - qualitativeRangeData={[{ name: 'Range', y: 50 }, { name: 'Range', y: 75 }]} - width={600} - /> -
-``` - -### Custom size -```js -import React from 'react'; -import { ChartBullet } from '@patternfly/react-charts'; - -
- `${datum.name}: ${datum.y}`} - maxDomain={{y: 100}} - name="chart13" - padding={{ - bottom: 50, - left: 150, // Adjusted to accomodate labels - right: 50, - top: 50 - }} - primarySegmentedMeasureData={[{ name: 'Measure', y: 60 }]} - primarySegmentedMeasureLegendData={[{ name: 'Measure 1' }]} - qualitativeRangeData={[{ name: 'Range', y: 50 }, { name: 'Range', y: 75 }]} - qualitativeRangeLegendData={[{ name: 'Range 1' }, { name: 'Range 2' }]} - subTitle="Measure details" - title="Text label" - width={600} - /> -
-``` - -### Horizontal group -```js -import React from 'react'; -import { ChartBullet, ChartContainer } from '@patternfly/react-charts'; - -
- - `${datum.name}: ${datum.y}`} - maxDomain={{y: 100}} - name="chart14" - padding={{ - bottom: 100, // Adjusted to accommodate legend - left: 150, // Adjusted to accommodate labels - right: 50, - top: 75 - }} - primarySegmentedMeasureData={[{ name: 'Measure', y: 15 }, { name: 'Measure', y: 50 }]} - qualitativeRangeData={[{ name: 'Range', y: 40 }, { name: 'Range', y: 65 }]} - standalone={false} - subTitle="Measure details" - title="Text label" - width={600} - /> - `${datum.name}: ${datum.y}`} - maxDomain={{y: 100}} - name="chart15" - padding={{ - bottom: 100, // Adjusted to accommodate legend - left: 150, // Adjusted to accommodate labels - right: 50, - top: 300 - }} - primarySegmentedMeasureData={[{ name: 'Measure', y: 25 }, { name: 'Measure', y: 60 }]} - qualitativeRangeData={[{ name: 'Range', y: 50 }, { name: 'Range', y: 75 }]} - standalone={false} - subTitle="Measure details" - title="Text label" - width={600} - /> - `${datum.name}: ${datum.y}`} - maxDomain={{y: 100}} - name="chart16" - padding={{ - bottom: 100, // Adjusted to accommodate legend - left: 150, // Adjusted to accommodate labels - right: 50, - top: 525 - }} - primarySegmentedMeasureData={[{ name: 'Measure', y: 35 }, { name: 'Measure', y: 70 }]} - qualitativeRangeData={[{ name: 'Range', y: 60 }, { name: 'Range', y: 85 }]} - standalone={false} - subTitle="Measure details" - title="Text label" - width={600} - /> - `${datum.name}: ${datum.y}`} - maxDomain={{y: 100}} - name="chart17" - padding={{ - bottom: 100, // Adjusted to accommodate legend - left: 150, // Adjusted to accommodate labels - right: 50, - top: 750 - }} - primarySegmentedMeasureData={[{ name: 'Measure', y: 15 }, { name: 'Measure', y: 50 }]} - primarySegmentedMeasureLegendData={[{ name: 'Measure 1' }, { name: 'Measure 2' }]} - qualitativeRangeData={[{ name: 'Range', y: 40 }, { name: 'Range', y: 65 }]} - qualitativeRangeLegendData={[{ name: 'Range 1' }, { name: 'Range 2' }]} - standalone={false} - subTitle="Measure details" - title="Text label" - width={600} - /> - -
-``` - -### Vertical group -```js -import React from 'react'; -import { ChartBullet, ChartContainer } from '@patternfly/react-charts'; - -
- - `${datum.name}: ${datum.y}`} - maxDomain={{y: 100}} - name="chart18" - padding={{ - bottom: 125, // Adjusted to accommodate legend - left: 50, - right: 50, - top: 50 - }} - primarySegmentedMeasureData={[{ name: 'Measure', y: 15 }, { name: 'Measure', y: 50 }]} - primarySegmentedMeasureLegendData={[{ name: 'Measure 1' }, { name: 'Measure 2' }]} - qualitativeRangeData={[{ name: 'Range', y: 40 }, { name: 'Range', y: 65 }]} - qualitativeRangeLegendData={[{ name: 'Range 1' }, { name: 'Range 2' }]} - standalone={false} - subTitle="Measure details" - title="Text label" - width={500} - /> - `${datum.name}: ${datum.y}`} - maxDomain={{y: 100}} - name="chart19" - padding={{ - bottom: 125, // Adjusted to accommodate legend - left: 300, - right: 50, - top: 50 - }} - primarySegmentedMeasureData={[{ name: 'Measure', y: 25 }, { name: 'Measure', y: 60 }]} - qualitativeRangeData={[{ name: 'Range', y: 50 }, { name: 'Range', y: 75 }]} - standalone={false} - subTitle="Measure details" - title="Text label" - width={500} - /> - `${datum.name}: ${datum.y}`} - maxDomain={{y: 100}} - name="chart20" - padding={{ - bottom: 125, // Adjusted to accommodate legend - left: 550, - right: 50, - top: 50 - }} - primarySegmentedMeasureData={[{ name: 'Measure', y: 35 }, { name: 'Measure', y: 70 }]} - qualitativeRangeData={[{ name: 'Range', y: 60 }, { name: 'Range', y: 85 }]} - standalone={false} - subTitle="Measure details" - title="Text label" - width={500} - /> - `${datum.name}: ${datum.y}`} - maxDomain={{y: 100}} - name="chart21" - padding={{ - bottom: 125, // Adjusted to accommodate legend - left: 800, - right: 50, - top: 50 - }} - primarySegmentedMeasureData={[{ name: 'Measure', y: 15 }, { name: 'Measure', y: 50 }]} - qualitativeRangeData={[{ name: 'Range', y: 40 }, { name: 'Range', y: 65 }]} - standalone={false} - subTitle="Measure details" - title="Text label" - width={500} - /> - -
-``` - -### Horizontal group with title -```js -import React from 'react'; -import { ChartBullet, ChartContainer } from '@patternfly/react-charts'; - -
- - `${datum.name}: ${datum.y}`} - maxDomain={{y: 100}} - name="chart22" - padding={{ - bottom: 100, // Adjusted to accommodate legend - left: 150, // Adjusted to accommodate labels - right: 50, - top: 275 // Adjusted to accommodate group labels - }} - primarySegmentedMeasureData={[{ name: 'Measure', y: 15 }, { name: 'Measure', y: 50 }]} - qualitativeRangeData={[{ name: 'Range', y: 40 }, { name: 'Range', y: 65 }]} - standalone={false} - subTitle="Measure details" - title="Text label" - width={600} - /> - `${datum.name}: ${datum.y}`} - maxDomain={{y: 100}} - name="chart23" - padding={{ - bottom: 100, // Adjusted to accommodate legend - left: 150, // Adjusted to accommodate labels - right: 50, - top: 500 // Adjusted to accommodate group labels - }} - primarySegmentedMeasureData={[{ name: 'Measure', y: 25 }, { name: 'Measure', y: 60 }]} - qualitativeRangeData={[{ name: 'Range', y: 50 }, { name: 'Range', y: 75 }]} - standalone={false} - subTitle="Measure details" - title="Text label" - width={600} - /> - `${datum.name}: ${datum.y}`} - maxDomain={{y: 100}} - name="chart24" - padding={{ - bottom: 100, // Adjusted to accommodate legend - left: 150, // Adjusted to accommodate labels - right: 50, - top: 725 // Adjusted to accommodate group labels - }} - primarySegmentedMeasureData={[{ name: 'Measure', y: 35 }, { name: 'Measure', y: 70 }]} - qualitativeRangeData={[{ name: 'Range', y: 60 }, { name: 'Range', y: 85 }]} - standalone={false} - subTitle="Measure details" - title="Text label" - width={600} - /> - `${datum.name}: ${datum.y}`} - maxDomain={{y: 100}} - name="chart25" - padding={{ - bottom: 100, // Adjusted to accommodate legend - left: 150, // Adjusted to accommodate labels - right: 50, - top: 950 // Adjusted to accommodate group labels - }} - primarySegmentedMeasureData={[{ name: 'Measure', y: 15 }, { name: 'Measure', y: 50 }]} - primarySegmentedMeasureLegendData={[{ name: 'Measure 1' }, { name: 'Measure 2' }]} - qualitativeRangeData={[{ name: 'Range', y: 40 }, { name: 'Range', y: 65 }]} - qualitativeRangeLegendData={[{ name: 'Range 1' }, { name: 'Range 2' }]} - standalone={false} - subTitle="Measure details" - title="Text label" - width={600} - /> - -
-``` - -### Vertical group with title -```js -import React from 'react'; -import { ChartBullet, ChartContainer } from '@patternfly/react-charts'; - -
- - `${datum.name}: ${datum.y}`} - maxDomain={{y: 100}} - name="chart26" - padding={{ - bottom: 125, // Adjusted to accommodate legend - left: 50, - right: 50, - top: 150 // Adjusted to accommodate group labels - }} - primarySegmentedMeasureData={[{ name: 'Measure', y: 15 }, { name: 'Measure', y: 50 }]} - primarySegmentedMeasureLegendData={[{ name: 'Measure 1' }, { name: 'Measure 2' }]} - qualitativeRangeData={[{ name: 'Range', y: 40 }, { name: 'Range', y: 65 }]} - qualitativeRangeLegendData={[{ name: 'Range 1' }, { name: 'Range 2' }]} - standalone={false} - subTitle="Measure details" - title="Text label" - width={500} - /> - `${datum.name}: ${datum.y}`} - maxDomain={{y: 100}} - name="chart27" - padding={{ - bottom: 125, // Adjusted to accommodate legend - left: 300, - right: 50, - top: 150 // Adjusted to accommodate group labels - }} - primarySegmentedMeasureData={[{ name: 'Measure', y: 25 }, { name: 'Measure', y: 60 }]} - qualitativeRangeData={[{ name: 'Range', y: 50 }, { name: 'Range', y: 75 }]} - standalone={false} - subTitle="Measure details" - title="Text label" - width={500} - /> - `${datum.name}: ${datum.y}`} - maxDomain={{y: 100}} - name="chart28" - padding={{ - bottom: 125, // Adjusted to accommodate legend - left: 550, - right: 50, - top: 150 // Adjusted to accommodate group labels - }} - primarySegmentedMeasureData={[{ name: 'Measure', y: 35 }, { name: 'Measure', y: 70 }]} - qualitativeRangeData={[{ name: 'Range', y: 60 }, { name: 'Range', y: 85 }]} - standalone={false} - subTitle="Measure details" - title="Text label" - width={500} - /> - `${datum.name}: ${datum.y}`} - maxDomain={{y: 100}} - name="chart29" - padding={{ - bottom: 125, // Adjusted to accommodate legend - left: 800, - right: 50, - top: 150 // Adjusted to accommodate group labels - }} - primarySegmentedMeasureData={[{ name: 'Measure', y: 15 }, { name: 'Measure', y: 50 }]} - qualitativeRangeData={[{ name: 'Range', y: 40 }, { name: 'Range', y: 65 }]} - standalone={false} - subTitle="Measure details" - title="Text label" - width={500} - /> - -
-``` - -## Documentation -### Tips -- See Victory's [FAQ](https://formidable.com/open-source/victory/docs/faq) -- `ChartLegend` may be used as a standalone component, instead of using `legendData` - -### Note -Currently, the generated documentation below is not able to resolve type definitions from Victory imports. For the -components used in the examples above, Victory pass-thru props are also documented here: - -- For `ChartAxis` props, see [VictoryAxis](https://formidable.com/open-source/victory/docs/victory-axis) -- For `ChartBullet` props, see [VictoryBar](https://formidable.com/open-source/victory/docs/victory-bar) -- For `ChartContainer` props, see [VictoryContainer](https://formidable.com/open-source/victory/docs/victory-container) diff --git a/packages/react-charts/src/components/ChartContainer/__snapshots__/ChartContainer.test.tsx.snap b/packages/react-charts/src/components/ChartContainer/__snapshots__/ChartContainer.test.tsx.snap deleted file mode 100644 index 85249c83342..00000000000 --- a/packages/react-charts/src/components/ChartContainer/__snapshots__/ChartContainer.test.tsx.snap +++ /dev/null @@ -1,154 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`ChartContainer 1`] = ` - -
- -
- -
-
-
-`; - -exports[`ChartContainer 2`] = ` - -
- -
- -
-
-
-`; - -exports[`renders container via ChartLegend 1`] = ` - -
- - - - - - - - Average number of pets - - - - - Cats - - - - - Dogs - - - - -
- -
-
-
-`; diff --git a/packages/react-charts/src/components/ChartDonut/examples/ChartDonut.md b/packages/react-charts/src/components/ChartDonut/examples/ChartDonut.md deleted file mode 100644 index b8a74f4541d..00000000000 --- a/packages/react-charts/src/components/ChartDonut/examples/ChartDonut.md +++ /dev/null @@ -1,249 +0,0 @@ ---- -id: Donut chart -section: charts -propComponents: [ - 'ChartDonut' -] -hideDarkMode: true ---- - -import { ChartDonut, ChartThemeColor } from '@patternfly/react-charts'; - -## Introduction -Note: PatternFly React charts live in its own package at [@patternfly/react-charts](https://www.npmjs.com/package/@patternfly/react-charts)! - -PatternFly React charts are based on the [Victory](https://formidable.com/open-source/victory/docs/victory-chart/) chart library, along with additional functionality, custom components, and theming for PatternFly. This provides a collection of React based components you can use to build PatternFly patterns with consistent markup, styling, and behavior. - -## Examples -### Basic -```js -import React from 'react'; -import { ChartDonut } from '@patternfly/react-charts'; - -
- `${datum.x}: ${datum.y}%`} - name="chart1" - subTitle="Pets" - title="100" - /> -
-``` - -### Right aligned legend -```js -import React from 'react'; -import { ChartDonut } from '@patternfly/react-charts'; - -
- `${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" - width={350} - /> -
-``` - -### Multi-color (ordered) with right aligned legend -```js -import React from 'react'; -import { ChartDonut, ChartThemeColor } from '@patternfly/react-charts'; - -
- `${datum.x}: ${datum.y}%`} - legendData={[{ name: 'Cats: 35' }, { name: 'Dogs: 55' }, { name: 'Birds: 10' }]} - legendOrientation="vertical" - legendPosition="right" - name="chart3" - padding={{ - bottom: 20, - left: 20, - right: 140, // Adjusted to accommodate legend - top: 20 - }} - subTitle="Pets" - title="100" - themeColor={ChartThemeColor.multiOrdered} - width={350} - /> -
-``` - -### Bottom aligned legend -```js -import React from 'react'; -import { ChartDonut } from '@patternfly/react-charts'; - -
- `${datum.x}: ${datum.y}%`} - legendData={[{ name: 'Cats: 35' }, { name: 'Dogs: 55' }, { name: 'Birds: 10' }]} - legendPosition="bottom" - legendWidth={225} - name="chart4" - padding={{ - bottom: 65, // Adjusted to accommodate legend - left: 20, - right: 20, - top: 20 - }} - subTitle="Pets" - title="100" - width={300} - /> -
-``` - -### Small -```js -import React from 'react'; -import { ChartDonut } from '@patternfly/react-charts'; - -
- `${datum.x}: ${datum.y}%`} - name="chart5" - subTitle="Pets" - title="100" - width={150} - /> -
-``` - -### Small with right aligned legend -```js -import React from 'react'; -import { ChartDonut } from '@patternfly/react-charts'; - -
- `${datum.x}: ${datum.y}%`} - legendData={[{ name: 'Cats: 35' }, { name: 'Dogs: 55' }, { name: 'Birds: 10' }]} - legendOrientation="vertical" - legendPosition="right" - name="chart6" - padding={{ - bottom: 20, - left: 20, - right: 145, // Adjusted to accommodate legend - top: 20 - }} - subTitle="Pets" - title="100" - width={275} - /> -
-``` - -### Small with bottom aligned subtitle -```js -import React from 'react'; -import { ChartDonut } from '@patternfly/react-charts'; - -
- `${datum.x}: ${datum.y}%`} - legendData={[{ name: 'Cats: 35' }, { name: 'Dogs: 55' }, { name: 'Birds: 10' }]} - legendOrientation="vertical" - legendPosition="right" - name="chart7" - padding={{ - bottom: 25, // Adjusted to accommodate subTitle - left: 20, - right: 145, // Adjusted to accommodate legend - top: 20 - }} - subTitle="Pets" - subTitlePosition="bottom" - title="100" - width={275} - /> -
-``` - -### Small with right aligned subtitle -```js -import React from 'react'; -import { ChartDonut } from '@patternfly/react-charts'; - -
- `${datum.x}: ${datum.y}%`} - legendData={[{ name: 'Cats: 35' }, { name: 'Dogs: 55' }, { name: 'Birds: 10' }]} - legendPosition="bottom" - name="chart8" - padding={{ - bottom: 70, // Adjusted to accommodate legend - left: 20, - right: 50, // Adjusted to accommodate subTitle - top: 20 - }} - subTitle="Pets" - subTitlePosition="right" - title="100" - width={300} - /> -
-``` - -## Documentation -### Tips -- See Victory's [FAQ](https://formidable.com/open-source/victory/docs/faq) -- For single data points or zero values, you may want to set the `domain` prop -- `ChartLegend` may be used as a standalone component, instead of using `legendData` - -### Note -Currently, the generated documentation below is not able to resolve type definitions from Victory imports. For the -components used in the examples above, Victory pass-thru props are also documented here: - -- For `ChartDonut` props, see [VictoryPie](https://formidable.com/open-source/victory/docs/victory-pie) diff --git a/packages/react-charts/src/components/ChartDonutUtilization/examples/ChartDonutUtilization.md b/packages/react-charts/src/components/ChartDonutUtilization/examples/ChartDonutUtilization.md deleted file mode 100644 index 512e3b26458..00000000000 --- a/packages/react-charts/src/components/ChartDonutUtilization/examples/ChartDonutUtilization.md +++ /dev/null @@ -1,812 +0,0 @@ ---- -id: Donut utilization chart -section: charts -propComponents: [ - 'ChartDonutThreshold', - 'ChartDonutUtilization' -] -hideDarkMode: true ---- - -import { ChartDonutThreshold, ChartDonutUtilization, ChartThemeColor } from '@patternfly/react-charts'; - -## Introduction -Note: PatternFly React charts live in its own package at [@patternfly/react-charts](https://www.npmjs.com/package/@patternfly/react-charts)! - -PatternFly React charts are based on the [Victory](https://formidable.com/open-source/victory/docs/victory-chart/) chart library, along with additional functionality, custom components, and theming for PatternFly. This provides a collection of React based components you can use to build PatternFly patterns with consistent markup, styling, and behavior. - -## Donut utilization examples -### Basic -```js -import React from 'react'; -import { ChartDonutUtilization } from '@patternfly/react-charts'; - -
- datum.x ? `${datum.x}: ${datum.y}%` : null} - name="chart1" - subTitle="of 100 GBps" - title="75%" - /> -
-``` - -### Right aligned legend -```js -import React from 'react'; -import { ChartDonutUtilization } from '@patternfly/react-charts'; - -class DonutUtilizationChart extends React.Component { - constructor(props) { - super(props); - this.state = { - spacer: '', - used: 0 - }; - } - - componentDidMount() { - this.interval = setInterval(() => { - const { used } = this.state; - const val = (used + 10) % 100; - this.setState({ - spacer: val < 10 ? ' ' : '', - used: val - }); - }, 1000); - } - - componentWillUnmount() { - clearInterval(this.interval); - } - - render() { - const { spacer, used } = this.state; - return ( -
- datum.x ? `${datum.x}: ${datum.y}%` : null} - legendData={[{ name: `Storage capacity: ${spacer}${used}%` }, { name: 'Unused' }]} - legendOrientation="vertical" - name="chart2" - padding={{ - bottom: 20, - left: 20, - right: 225, // Adjusted to accommodate legend - top: 20 - }} - subTitle="of 100 GBps" - title={`${used}%`} - thresholds={[{ value: 60 }, { value: 90 }]} - width={435} - /> -
- ); - } -} -``` - -### Inverted with right aligned legend -```js -import React from 'react'; -import { ChartDonutUtilization } from '@patternfly/react-charts'; - -class InvertedDonutUtilizationChart extends React.Component { - constructor(props) { - super(props); - this.state = { - spacer: '', - used: 100 - }; - } - - componentDidMount() { - this.interval = setInterval(() => { - const { used } = this.state; - const val = (((used - 10) % 100) + 100) % 100; - this.setState({ - spacer: val < 10 ? ' ' : '', - used: val - }); - }, 1000); - } - - componentWillUnmount() { - clearInterval(this.interval); - } - - render() { - const { spacer, used } = this.state; - return ( -
- datum.x ? `${datum.x}: ${datum.y}%` : null} - legendData={[{ name: `Storage capacity: ${spacer}${used}%` }, { name: 'Unused' }]} - legendOrientation="vertical" - name="chart3" - padding={{ - bottom: 20, - left: 20, - right: 225, // Adjusted to accommodate legend - top: 20 - }} - subTitle="of 100 GBps" - title={`${used}%`} - thresholds={[{ value: 60 }, { value: 20 }]} - width={435} - /> -
- ); - } -} -``` - -### Right aligned vertical legend -```js -import React from 'react'; -import { ChartDonutUtilization, ChartThemeColor } from '@patternfly/react-charts'; - -class VerticalLegendUtilizationChart extends React.Component { - constructor(props) { - super(props); - this.state = { - spacer: '', - used: 0 - }; - } - - componentDidMount() { - this.interval = setInterval(() => { - const { used } = this.state; - const val = (used + 10) % 100; - this.setState({ - spacer: val < 10 ? ' ' : '', - used: val - }); - }, 1000); - } - - componentWillUnmount() { - clearInterval(this.interval); - } - - render() { - const { spacer, used } = this.state; - return ( -
- datum.x ? `${datum.x}: ${datum.y}%` : null} - legendData={[{ name: `Storage capacity: ${spacer}${used}%` }, { name: 'Unused' }]} - legendOrientation="vertical" - legendPosition="bottom" - name="chart4" - padding={{ - bottom: 75, // Adjusted to accommodate legend - left: 20, - right: 20, - top: 20 - }} - subTitle="of 100 GBps" - title={`${used}%`} - themeColor={ChartThemeColor.green} - thresholds={[{ value: 60 }, { value: 90 }]} - width={230} - /> -
- ); - } -} -``` - -### Bottom aligned legend -```js -import React from 'react'; -import { ChartDonutUtilization } from '@patternfly/react-charts'; - -
- 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%" - thresholds={[{ value: 60 }, { value: 90 }]} - width={300} - /> -
-``` - -### Small -```js -import React from 'react'; -import { ChartDonutUtilization } from '@patternfly/react-charts'; - -
- datum.x ? `${datum.x}: ${datum.y}%` : null} - name="chart6" - subTitle="of 100 GBps" - title="75%" - width={175} - /> -
-``` - -### Small with right aligned legend -```js -import React from 'react'; -import { ChartDonutUtilization } from '@patternfly/react-charts'; - -class UtilizationChart extends React.Component { - constructor(props) { - super(props); - this.state = { - spacer: '', - used: 0 - }; - } - - componentDidMount() { - this.interval = setInterval(() => { - const { used } = this.state; - const val = (used + 10) % 100; - this.setState({ - spacer: val < 10 ? ' ' : '', - used: val - }); - }, 1000); - } - - componentWillUnmount() { - clearInterval(this.interval); - } - - render() { - const { spacer, used } = this.state; - return ( -
- datum.x ? `${datum.x}: ${datum.y}%` : null} - legendData={[{ name: `Storage capacity: ${spacer}${used}%` }, { name: 'Unused' }]} - legendOrientation="vertical" - name="chart7" - padding={{ - bottom: 20, - left: 20, - right: 195, // Adjusted to accommodate legend - top: 20 - }} - subTitle="of 100 GBps" - title={`${used}%`} - thresholds={[{ value: 60 }, { value: 90 }]} - width={350} - /> -
- ); - } -} -``` - -### Small with bottom aligned subtitle - -This is a small donut utilization chart with bottom aligned legend and right aligned subtitle. - -```js -import React from 'react'; -import { ChartDonutUtilization } from '@patternfly/react-charts'; - -
- datum.x ? `${datum.x}: ${datum.y}%` : null} - legendData={[{ name: `Storage capacity: 45%` }, { name: 'Unused' }]} - legendOrientation="vertical" - name="chart8" - padding={{ - bottom: 25, // Adjusted to accommodate subTitle - left: 20, - right: 195, // Adjusted to accommodate legend - top: 20 - }} - subTitle="of 100 GBps" - subTitlePosition="bottom" - title="45%" - thresholds={[{ value: 60 }, { value: 90 }]} - width={350} - /> -
-``` - -### Small with right aligned subtitle -```js -import React from 'react'; -import { ChartDonutUtilization } from '@patternfly/react-charts'; - -
- datum.x ? `${datum.x}: ${datum.y}%` : null} - legendData={[{ name: `Storage capacity: 45%` }, { name: 'Unused' }]} - legendPosition="bottom" - name="chart9" - padding={{ - bottom: 45, // Adjusted to accommodate legend - left: 20, - right: 20, - top: 20 - }} - subTitle="of 100 GBps" - subTitlePosition="right" - title="45%" - thresholds={[{ value: 60 }, { value: 90 }]} - width={350} - /> -
-``` - -## Donut utilization threshold examples -### Static thresholds -```js -import React from 'react'; -import { ChartDonutThreshold, ChartDonutUtilization } from '@patternfly/react-charts'; - -
- datum.x ? datum.x : null} - name="chart10" - > - datum.x ? `${datum.x}: ${datum.y}%` : null} - subTitle="of 100 GBps" - title="45%" - /> - -
-``` - -### Static thresholds with right aligned legend -```js -import React from 'react'; -import { ChartDonutThreshold, ChartDonutUtilization } from '@patternfly/react-charts'; - -class ThresholdChart extends React.Component { - constructor(props) { - super(props); - this.state = { - used: 0 - }; - } - - componentDidMount() { - this.interval = setInterval(() => { - const { used } = this.state; - this.setState({ used: (used + 10) % 100 }); - }, 1000); - } - - componentWillUnmount() { - clearInterval(this.interval); - } - - render() { - const { used } = this.state; - return ( -
- datum.x ? datum.x : null} - name="chart11" - padding={{ - bottom: 20, - left: 20, - right: 290, // Adjusted to accommodate legend - top: 20 - }} - width={500} - > - datum.x ? `${datum.x}: ${datum.y}%` : null} - legendData={[{ name: `Storage capacity: ${used}%` }, { name: 'Warning threshold at 60%' }, { name: 'Danger threshold at 90%' }]} - legendOrientation="vertical" - subTitle="of 100 GBps" - title={`${used}%`} - thresholds={[{ value: 60 }, { value: 90 }]} - /> - -
- ); - } -} -``` - -### Inverted static thresholds with right aligned legend -```js -import React from 'react'; -import { ChartDonutThreshold, ChartDonutUtilization } from '@patternfly/react-charts'; - -class InvertedThresholdChart extends React.Component { - constructor(props) { - super(props); - this.state = { - spacer: '', - used: 100 - }; - } - - componentDidMount() { - this.interval = setInterval(() => { - const { used } = this.state; - const val = (((used - 10) % 100) + 100) % 100; - this.setState({ - spacer: val < 10 ? ' ' : '', - used: val - }); - }, 1000); - } - - componentWillUnmount() { - clearInterval(this.interval); - } - - render() { - const { used } = this.state; - return ( -
- datum.x ? datum.x : null} - name="chart12" - padding={{ - bottom: 20, - left: 20, - right: 290, // Adjusted to accommodate legend - top: 20 - }} - width={500} - > - datum.x ? `${datum.x}: ${datum.y}%` : null} - legendData={[{ name: `Storage capacity: ${used}%` }, { name: 'Warning threshold at 60%' }, { name: 'Danger threshold at 20%' }]} - legendOrientation="vertical" - subTitle="of 100 GBps" - title={`${used}%`} - thresholds={[{ value: 60 }, { value: 20 }]} - /> - -
- ); - } -} -``` - -### Static thresholds with custom legend -```js -import React from 'react'; -import { ChartDonutThreshold, ChartDonutUtilization, ChartThemeColor } from '@patternfly/react-charts'; - -class CustomLegendThresholdChart extends React.Component { - constructor(props) { - super(props); - this.state = { - used: 0 - }; - } - - componentDidMount() { - this.interval = setInterval(() => { - const { used } = this.state; - this.setState({ used: (used + 10) % 100 }); - }, 1000); - } - - componentWillUnmount() { - clearInterval(this.interval); - } - - render() { - const { used } = this.state; - return ( -
- datum.x ? datum.x : null} - name="chart13" - padding={{ - bottom: 125, // Adjusted to accommodate legend - left: 20, - right: 20, - top: 20 - }} - width={230} - > - datum.x ? `${datum.x}: ${datum.y}%` : null} - legendData={[{ name: `Storage capacity: ${used}%` }, { name: 'Warning threshold at 60%' }, { name: 'Danger threshold at 90%' }]} - legendOrientation="vertical" - legendPosition="bottom" - subTitle="of 100 GBps" - title={`${used}%`} - themeColor={ChartThemeColor.green} - thresholds={[{ value: 60 }, { value: 90 }]} - /> - -
- ); - } -} -``` - -### Static thresholds with bottom aligned legend -```js -import React from 'react'; -import { ChartDonutThreshold, ChartDonutUtilization } from '@patternfly/react-charts'; - -
- datum.x ? datum.x : null} - name="chart14" - 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%" - /> - -
-``` - -### Small with static thresholds -```js -import React from 'react'; -import { ChartDonutThreshold, ChartDonutUtilization } from '@patternfly/react-charts'; - -
- datum.x ? datum.x : null} - name="chart15" - width={185} - > - datum.x ? `${datum.x}: ${datum.y}%` : null} - subTitle="of 100 GBps" - title="45%" - /> - -
-``` - -### Small with static thresholds and right aligned legend -```js -import React from 'react'; -import { ChartDonutThreshold, ChartDonutUtilization } from '@patternfly/react-charts'; - -class ThresholdChart extends React.Component { - constructor(props) { - super(props); - this.state = { - used: 0 - }; - } - - componentDidMount() { - this.interval = setInterval(() => { - const { used } = this.state; - this.setState({ used: (used + 10) % 100 }); - }, 1000); - } - - componentWillUnmount() { - clearInterval(this.interval); - } - - render() { - const { used } = this.state; - return ( -
- datum.x ? datum.x : null} - name="chart16" - padding={{ - bottom: 20, - left: 20, - right: 260, // Adjusted to accommodate legend - top: 20 - }} - width={425} - > - datum.x ? `${datum.x}: ${datum.y}%` : null} - legendData={[{ name: `Storage capacity: ${used}%` }, { name: 'Warning threshold at 60%' }, { name: 'Danger threshold at 90%' }]} - legendOrientation="vertical" - subTitle="of 100 GBps" - title={`${used}%`} - thresholds={[{ value: 60 }, { value: 90 }]} - /> - -
- ); - } -} -``` - -### Small with subtitle - -This is a small donut utilization chart with static thresholds with right aligned legend and bottom aligned subtitle. - -```js -import React from 'react'; -import { ChartDonutThreshold, ChartDonutUtilization } from '@patternfly/react-charts'; - -
- datum.x ? datum.x : null} - name="chart17" - padding={{ - bottom: 30, // Adjusted to accommodate label - left: 20, - right: 260, // Adjusted to accommodate legend - top: 20 - }} - subTitlePosition="bottom" - width={425} - > - datum.x ? `${datum.x}: ${datum.y}%` : null} - legendData={[{ name: `Storage capacity: 45%` }, { name: 'Warning threshold at 60%' }, { name: 'Danger threshold at 90%' }]} - legendOrientation="vertical" - subTitle="of 100 GBps" - title="45%" - thresholds={[{ value: 60 }, { value: 90 }]} - /> - -
-``` - -### Small with thresholds and right aligned subtitle -```js -import React from 'react'; -import { ChartDonutThreshold, ChartDonutUtilization } from '@patternfly/react-charts'; - -
- datum.x ? datum.x : null} - name="chart18" - padding={{ - bottom: 60, // Adjusted to accommodate legend - left: 20, - right: 20, - top: 20 - }} - subTitlePosition="right" - 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%" - thresholds={[{ value: 60 }, { value: 90 }]} - /> - -
-``` - -## Documentation -### Tips -- See Victory's [FAQ](https://formidable.com/open-source/victory/docs/faq) -- For single data points or zero values, you may want to set the `domain` prop -- `ChartLegend` may be used as a standalone component, instead of using `legendData` - -### Note -Currently, the generated documentation below is not able to resolve type definitions from Victory imports. For the -components used in the examples above, Victory pass-thru props are also documented here: - -- For `ChartDonutThreshold` props, see [VictoryPie](https://formidable.com/open-source/victory/docs/victory-pie) -- For `ChartDonutUtilization` props, see [VictoryPie](https://formidable.com/open-source/victory/docs/victory-pie) diff --git a/packages/react-charts/src/components/ChartLegend/__snapshots__/ChartLegend.test.tsx.snap b/packages/react-charts/src/components/ChartLegend/__snapshots__/ChartLegend.test.tsx.snap deleted file mode 100644 index ca8580b7ac6..00000000000 --- a/packages/react-charts/src/components/ChartLegend/__snapshots__/ChartLegend.test.tsx.snap +++ /dev/null @@ -1,294 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`ChartLegend 1`] = ` - -
- - - - - - - Series 1 - - - - - Series 2 - - - -
- -
-
-
-`; - -exports[`ChartLegend 2`] = ` - -
- - - - - - - Series 1 - - - - - Series 2 - - - -
- -
-
-
-`; - -exports[`renders component data 1`] = ` - -
- - - - - - - Average number of pets - - - - - Cats - - - - - Dogs - - - -
- -
-
-
-`; diff --git a/packages/react-charts/src/components/ChartLegend/examples/ChartLegend.md b/packages/react-charts/src/components/ChartLegend/examples/ChartLegend.md deleted file mode 100644 index e98fdc29276..00000000000 --- a/packages/react-charts/src/components/ChartLegend/examples/ChartLegend.md +++ /dev/null @@ -1,864 +0,0 @@ ---- -id: Legends -section: charts -propComponents: [ - 'Chart', - 'ChartArea', - 'ChartAxis', - 'ChartBar', - 'ChartBullet', - 'ChartDonut', - 'ChartGroup', - 'ChartLabel', - 'ChartLegend', - 'ChartLegendTooltip', - 'ChartLine', - 'ChartPie', - 'ChartScatter', - 'ChartVoronoiContainer' -] -hideDarkMode: true ---- - -import { - Chart, - ChartArea, - ChartAxis, - ChartBar, - ChartBullet, - ChartContainer, - ChartDonut, - ChartGroup, - ChartLabel, - ChartLegend, - ChartLegendTooltip, - ChartLine, - ChartPie, - ChartScatter, - ChartThemeColor, - ChartVoronoiContainer, - createContainer, - getInteractiveLegendEvents, - getInteractiveLegendItemStyles -} from '@patternfly/react-charts'; -import { getResizeObserver } from '@patternfly/react-core'; -import chart_color_black_500 from '@patternfly/react-tokens/dist/esm/chart_color_black_500'; -import '@patternfly/patternfly/patternfly-charts.css'; - -## Introduction -Note: PatternFly React charts live in its own package at [@patternfly/react-charts](https://www.npmjs.com/package/@patternfly/react-charts)! - -PatternFly React charts are based on the [Victory](https://formidable.com/open-source/victory/docs/victory-chart/) chart library, along with additional functionality, custom components, and theming for PatternFly. This provides a collection of React based components you can use to build PatternFly patterns with consistent markup, styling, and behavior. - -## Examples -### Basic with right aligned legend -```js -import React from 'react'; -import { ChartDonut } from '@patternfly/react-charts'; - -
- `${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 - }} - subTitle="Pets" - title="100" - width={350} - /> -
-``` - -### Bottom aligned legend -```js -import React from 'react'; -import { Chart, ChartAxis, ChartBar, ChartGroup, ChartThemeColor, ChartVoronoiContainer } from '@patternfly/react-charts'; - -
- `${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.purple} - width={450} - > - - - - - - - - - -
-``` - -### Responsive bottom-left aligned legend - -This demonstrates a responsive legend which wraps when items are wider than its container. - -```js -import React from 'react'; -import { ChartBullet } from '@patternfly/react-charts'; -import { getResizeObserver } from '@patternfly/react-core'; - -class BulletChart extends React.Component { - constructor(props) { - super(props); - this.containerRef = React.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(200); - return ( -
- `${datum.name}: ${datum.y}`} - legendAllowWrap={this.handleLegendAllowWrap} - legendPosition="bottom-left" - maxDomain={{y: 100}} - name="chart3" - 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} - /> -
- ); - } -} -``` - -### Standalone legend - -This demonstrates a standalone legend vs. using the `legendData` property. - -```js -import React from 'react'; -import { Chart, ChartAxis, ChartGroup, ChartLegend, ChartLine, ChartThemeColor, ChartVoronoiContainer } from '@patternfly/react-charts'; - -
- `${datum.name}: ${datum.y}`} constrainToVisibleArea />} - height={275} - maxDomain={{y: 10}} - minDomain={{y: 0}} - name="chart4" - padding={{ - bottom: 75, // Adjusted to accommodate legend - left: 50, - right: 50, - top: 50 - }} - themeColor={ChartThemeColor.green} - width={450} - > - - - - - - - - - - -
-``` - -### Interactive legend - -This demonstrates how to add an interactive legend using events such as `onMouseOver`, `onMouseOut`, and `onClick`. - -```js -import React from 'react'; -import { - Chart, - ChartArea, - ChartAxis, - ChartGroup, - ChartLegend, - ChartLegendTooltip, - ChartScatter, - ChartThemeColor, - createContainer, - getInteractiveLegendEvents, - getInteractiveLegendItemStyles, -} from '@patternfly/react-charts'; -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 = React.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: 'chart5-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 = React.cloneElement( - this.cursorVoronoiContainer, - { - disable: !this.isDataAvailable() - } - ); - - return ( -
-
- } - legendPosition="bottom-left" - name="chart5" - 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 ( - - ); - })} - - -
-
- ); - } -} -``` - -### 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 React from 'react'; -import { - Chart, - ChartLegend, - ChartThemeColor, - ChartPie, - getInteractiveLegendEvents, - getInteractiveLegendItemStyles -} from '@patternfly/react-charts'; - -class InteractivePieLegendChart extends React.Component { - constructor(props) { - super(props); - this.state = { - hiddenSeries: new Set(), - width: 0 - }; - this.series = [{ - datapoints: { x: 'Cats', y: 35 }, - legendItem: { name: 'Cats: 35' } - }, { - datapoints: { x: 'Dogs', y: 55 }, - legendItem: { name: 'Dogs: 55' } - }, { - 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: 'chart6-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="chart6" - padding={{ - bottom: 65, - left: 20, - right: 20, - top: 20 - }} - showAxis={false} - themeColor={ChartThemeColor.multiUnordered} - width={300} - > - `${datum.x}: ${datum.y}`} - name="pie" - /> - -
- ); - } -} -``` - -### Legend tooltips - -This demonstrates an approach for applying tooltips to a legend using a custom label component. These tooltips are keyboard navigable. - -```js -import React from 'react'; -import { ChartLabel, ChartLegend, ChartPie, ChartThemeColor } from '@patternfly/react-charts'; -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 use a reference to ChartLabel instead - this.LegendLabel = ({datum, ...rest}) => { - const ref = React.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} - /> -
- ); - } -} -``` - -### Legend links - -This demonstrates an approach for applying links to a legend using a custom label component. These links are keyboard navigable. - -```js -import React from 'react'; -import { Chart, ChartAxis, ChartGroup, ChartLabel, ChartLegend, ChartLine, ChartVoronoiContainer } from '@patternfly/react-charts'; - -class LegendLinkPieChart extends React.Component { - constructor(props) { - super(props); - - // Custom legend label compoenent - this.LegendLabel = ({datum, ...rest}) => ( - - - - ); - - // Custom legend component - this.getLegend = (legendData) => ( - } - /> - ); - } - - render() { - return ( -
- `${datum.name}: ${datum.y}`} constrainToVisibleArea />} - legendComponent={this.getLegend([ - { name: 'Cats' }, - { name: 'Dogs' }, - { name: 'Birds' }, - { name: 'Mice'} - ])} - legendData={[{ name: 'Cats' }, { name: 'Dogs', symbol: { type: 'dash' } }, { name: 'Birds' }, { name: 'Mice' }]} - legendPosition="bottom" - height={275} - maxDomain={{y: 10}} - minDomain={{y: 0}} - name="chart8" - padding={{ - bottom: 75, // Adjusted to accommodate legend - left: 50, - right: 50, - top: 50 - }} - width={450} - > - } /> - } /> - - - - - - - -
- ); - } -} -``` - -### Legend layout - -This demonstrates an approach for applying a different legend layout and styles using a custom label component. - -```js -import React from 'react'; -import { ChartLabel, ChartLegend, ChartDonut, ChartThemeColor } from '@patternfly/react-charts'; -import { Tooltip } from '@patternfly/react-core'; - -class LegendLayoutPieChart extends React.Component { - constructor(props) { - super(props); - - // Custom legend label compoenent - this.LegendLabel = ({values, ...rest}) => ( - - ); - - // Custom legend component - this.getLegend = (legendData, values) => ( - } - rowGutter={20} - /> - ); - } - - render() { - return ( -
- `${datum.x}: ${datum.y}`} - legendComponent={this.getLegend([ - { name: 'Cats' }, - { name: 'Dogs' }, - { name: 'Birds' } - ], [ 35, 55, 10 ])} - legendOrientation="vertical" - legendPosition="right" - name="chart9" - padding={{ - bottom: 20, - left: 20, - right: 140, // Adjusted to accommodate legend - top: 20 - }} - subTitle="Pets" - title="100" - themeColor={ChartThemeColor.multiOrdered} - width={375} - /> -
- ); - } -} -``` - -## Documentation -### Tips -- See Victory's [FAQ](https://formidable.com/open-source/victory/docs/faq) -- `ChartLegend` may be used as a standalone component, instead of using `legendData` - -### Note -Currently, the generated documentation below is not able to resolve type definitions from Victory imports. For the -components used in the examples above, Victory pass-thru props are also documented here: - -- For `Chart` props, see [VictoryChart](https://formidable.com/open-source/victory/docs/victory-chart) -- For `ChartArea` props, see [VictoryArea](https://formidable.com/open-source/victory/docs/victory-area) -- For `ChartAxis` props, see [VictoryAxis](https://formidable.com/open-source/victory/docs/victory-axis) -- For `ChartBar` props, see [VictoryBar](https://formidable.com/open-source/victory/docs/victory-bar) -- For `ChartBullet` props, see [VictoryBar](https://formidable.com/open-source/victory/docs/victory-bar) -- For `ChartDonut` props, see [VictoryPie](https://formidable.com/open-source/victory/docs/victory-pie) -- For `ChartGroup` props, see [VictoryGroup](https://formidable.com/open-source/victory/docs/victory-group) -- For `ChartLabel` props, see [VictoryLabel](https://formidable.com/open-source/victory/docs/victory-label) -- For `ChartLegend` props, see [VictoryLegend](https://formidable.com/open-source/victory/docs/victory-legend) -- For `ChartLine` props, see [VictoryLine](https://formidable.com/open-source/victory/docs/victory-line) -- For `ChartPie` props, see [VictoryPie](https://formidable.com/open-source/victory/docs/victory-pie) -- For `ChartScatter` props, see [VictoryScatter](https://formidable.com/open-source/victory/docs/victory-scatter) -- For `ChartVoronoiContainer` props, see [VictoryVoronoiContainer](https://formidable.com/open-source/victory/docs/victory-voronoi-container) diff --git a/packages/react-charts/src/components/ChartLine/examples/ChartLine.md b/packages/react-charts/src/components/ChartLine/examples/ChartLine.md deleted file mode 100644 index ac2155d2cb2..00000000000 --- a/packages/react-charts/src/components/ChartLine/examples/ChartLine.md +++ /dev/null @@ -1,315 +0,0 @@ ---- -id: Line chart -section: charts -propComponents: [ - 'Chart', - 'ChartAxis', - 'ChartGroup', - 'ChartLine', - 'ChartVoronoiContainer' -] -hideDarkMode: true ---- - -import { Chart, ChartAxis, ChartGroup, ChartLine, ChartThemeColor, ChartLegendTooltip, ChartVoronoiContainer, createContainer } from '@patternfly/react-charts'; -import { getResizeObserver } from '@patternfly/react-core'; -import { VictoryZoomContainer } from 'victory-zoom-container'; - -## Introduction -Note: PatternFly React charts live in its own package at [@patternfly/react-charts](https://www.npmjs.com/package/@patternfly/react-charts)! - -PatternFly React charts are based on the [Victory](https://formidable.com/open-source/victory/docs/victory-chart/) chart library, along with additional functionality, custom components, and theming for PatternFly. This provides a collection of React based components you can use to build PatternFly patterns with consistent markup, styling, and behavior. - -## Examples -### Basic with right aligned legend -```js -import React from 'react'; -import { Chart, ChartAxis, ChartGroup, ChartLine, ChartVoronoiContainer } from '@patternfly/react-charts'; - -
- `${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="chart1" - padding={{ - bottom: 50, - left: 50, - right: 200, // Adjusted to accommodate legend - top: 50 - }} - width={600} - > - - - - - - - - - -
-``` - -### Green with bottom aligned legend - -This demonstrates how to combine cursor and voronoi containers to display tooltips along with a cursor. - -```js -import React from 'react'; -import { Chart, ChartAxis, ChartGroup, ChartLine, ChartThemeColor, ChartLegendTooltip, createContainer } from '@patternfly/react-charts'; - -class BottomAlignedLegend 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}`} - labelComponent={ datum.x}/>} - 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.green} - width={450} - > - - - - - - - - - -
- ); - } -} -``` - -### Multi-color (unordered) with responsive container - -This demonstrates zoom for the x axis only. - -```js -import React from 'react'; -import { Chart, ChartAxis, ChartGroup, ChartLine, ChartThemeColor } from '@patternfly/react-charts'; -import { getResizeObserver } from '@patternfly/react-core'; -import { VictoryZoomContainer } from 'victory-zoom-container'; - -class MultiColorChart extends React.Component { - constructor(props) { - super(props); - this.containerRef = React.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; - - return ( -
-
- } - legendData={[{ name: 'Cats' }, { name: 'Dogs', symbol: { type: 'dash' } }, { name: 'Birds' }, { name: 'Mice' }]} - legendPosition="bottom-left" - 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.multiUnordered} - width={width} - > - - - - - - - - - -
-
- ); - } -} -``` - -## Documentation -### Tips -- See Victory's [FAQ](https://formidable.com/open-source/victory/docs/faq) -- For single data points or zero values, you may want to set the `domain` prop -- `ChartLegend` may be used as a standalone component, instead of using `legendData` -- The `theme` and `themeColor` props should be applied at the most top level component -- Use `ChartGroup` to apply theme color scales and other properties to multiple components - -### Note -Currently, the generated documentation below is not able to resolve type definitions from Victory imports. For the -components used in the examples above, Victory pass-thru props are also documented here: - -- For `Chart` props, see [VictoryChart](https://formidable.com/open-source/victory/docs/victory-chart) -- For `ChartAxis` props, see [VictoryAxis](https://formidable.com/open-source/victory/docs/victory-axis) -- For `ChartGroup` props, see [VictoryGroup](https://formidable.com/open-source/victory/docs/victory-group) -- For `ChartLine` props, see [Victoryline](https://formidable.com/open-source/victory/docs/victory-line) -- For `ChartVoronoiContainer` props, see [VictoryVoronoiContainer](https://formidable.com/open-source/victory/docs/victory-voronoi-container) -- For `VictoryZoomContainer` props, see [VictoryZoomContainerline](https://formidable.com/open-source/victory/docs/victory-zoom-container) diff --git a/packages/react-charts/src/components/ChartPie/examples/ChartPie.md b/packages/react-charts/src/components/ChartPie/examples/ChartPie.md deleted file mode 100644 index 883c9435a28..00000000000 --- a/packages/react-charts/src/components/ChartPie/examples/ChartPie.md +++ /dev/null @@ -1,111 +0,0 @@ ---- -id: Pie chart -section: charts -propComponents: ['ChartPie'] -hideDarkMode: true ---- - -import { ChartPie, ChartThemeColor } from '@patternfly/react-charts'; - -## Introduction -Note: PatternFly React charts live in its own package at [@patternfly/react-charts](https://www.npmjs.com/package/@patternfly/react-charts)! - -PatternFly React charts are based on the [Victory](https://formidable.com/open-source/victory/docs/victory-chart/) chart library, along with additional functionality, custom components, and theming for PatternFly. This provides a collection of React based components you can use to build PatternFly patterns with consistent markup, styling, and behavior. - -## Examples -### Basic with right aligned legend -```js -import React from 'react'; -import { ChartPie } from '@patternfly/react-charts'; - -
- `${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} - /> -
-``` - -### Orange with right aligned legend -```js -import React from 'react'; -import { ChartPie, ChartThemeColor } from '@patternfly/react-charts'; - -
- `${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 - }} - themeColor={ChartThemeColor.orange} - width={350} - /> -
-``` - -### Multi-color (ordered) with bottom aligned legend -```js -import React from 'react'; -import { ChartPie, ChartThemeColor } from '@patternfly/react-charts'; - -
- `${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} - /> -
-``` - -## Documentation -### Tips -- See Victory's [FAQ](https://formidable.com/open-source/victory/docs/faq) -- For single data points or zero values, you may want to set the `domain` prop -- `ChartLegend` may be used as a standalone component, instead of using `legendData` - -### Note -Currently, the generated documentation below is not able to resolve type definitions from Victory imports. For the -components used in the examples above, Victory pass-thru props are also documented here: - -- For `ChartPie` props, see [VictoryPie](https://formidable.com/open-source/victory/docs/victory-pie) diff --git a/packages/react-charts/src/components/ChartPoint/__snapshots__/ChartPoint.test.tsx.snap b/packages/react-charts/src/components/ChartPoint/__snapshots__/ChartPoint.test.tsx.snap deleted file mode 100644 index 2587247fd40..00000000000 --- a/packages/react-charts/src/components/ChartPoint/__snapshots__/ChartPoint.test.tsx.snap +++ /dev/null @@ -1,304 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`ChartPoint 1`] = ` - -
- - - - - - - Series 1 - - - - - Series 2 - - - -
- -
-
-
-`; - -exports[`ChartPoint 2`] = ` - -
- - - - - - - Series 1 - - - - - Series 2 - - - -
- -
-
-
-`; - -exports[`renders component data 1`] = ` - -
- - - - - - - Average number of pets - - - - - Cats - - - - - Dogs - - - -
- -
-
-
-`; diff --git a/packages/react-charts/src/components/ChartScatter/examples/ChartScatter.md b/packages/react-charts/src/components/ChartScatter/examples/ChartScatter.md deleted file mode 100644 index 7a30806b291..00000000000 --- a/packages/react-charts/src/components/ChartScatter/examples/ChartScatter.md +++ /dev/null @@ -1,344 +0,0 @@ ---- -id: Scatter chart -section: charts -propComponents: [ -'Chart', -'ChartArea', -'ChartAxis', -'ChartGroup', -'ChartLine', -'ChartScatter', -'ChartVoronoiContainer' -] -hideDarkMode: true ---- - -import { -Chart, -ChartArea, -ChartAxis, -ChartGroup, -ChartLine, -ChartScatter, -ChartThemeColor, -ChartVoronoiContainer, -} from '@patternfly/react-charts'; -import { getResizeObserver } from '@patternfly/react-core'; - -## Introduction -Note: PatternFly React charts live in its own package at [@patternfly/react-charts](https://www.npmjs.com/package/@patternfly/react-charts)! - -PatternFly React charts are based on the [Victory](https://formidable.com/open-source/victory/docs/victory-chart/) chart library, along with additional functionality, custom components, and theming for PatternFly. This provides a collection of React based components you can use to build PatternFly patterns with consistent markup, styling, and behavior. - -## Examples -### Basic -```js -import React from 'react'; -import { Chart, ChartAxis, ChartGroup, ChartScatter, ChartVoronoiContainer } from '@patternfly/react-charts'; - -
- `${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 React from 'react'; -import { Chart, ChartAxis, ChartGroup, ChartLine, ChartScatter, ChartThemeColor, ChartVoronoiContainer } from '@patternfly/react-charts'; -import { getResizeObserver } from '@patternfly/react-core'; - -class ScatterLineChart extends React.Component { - constructor(props) { - super(props); - this.containerRef = React.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; - - 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 React from 'react'; -import { Chart, ChartArea, ChartAxis, ChartGroup, ChartScatter, ChartThemeColor, ChartVoronoiContainer } from '@patternfly/react-charts'; -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 = React.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; - - 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 - -- For single data points or zero values, you may want to set the `domain` prop. See Victory's FAQ - -### Note -Currently, the generated documentation below is not able to resolve type definitions from Victory imports. For the -components used in the examples above, Victory pass-thru props are also documented here: - -- For `Chart` props, see [VictoryChart](https://formidable.com/open-source/victory/docs/victory-chart) -- For `ChartArea` props, see [VictoryArea](https://formidable.com/open-source/victory/docs/victory-area) -- For `ChartAxis` props, see [VictoryAxis](https://formidable.com/open-source/victory/docs/victory-axis) -- For `ChartGroup` props, see [VictoryGroup](https://formidable.com/open-source/victory/docs/victory-group) -- For `ChartLine` props, see [VictoryLine](https://formidable.com/open-source/victory/docs/victory-line) -- For `ChartScatter` props, see [VictoryScatter](https://formidable.com/open-source/victory/docs/victory-scatter) -- For `ChartVoronoiContainer` props, see [VictoryVoronoiContainer](https://formidable.com/open-source/victory/docs/victory-voronoi-container) diff --git a/packages/react-charts/src/components/ChartStack/examples/ChartStack.md b/packages/react-charts/src/components/ChartStack/examples/ChartStack.md deleted file mode 100644 index 98f2184f9eb..00000000000 --- a/packages/react-charts/src/components/ChartStack/examples/ChartStack.md +++ /dev/null @@ -1,433 +0,0 @@ ---- -id: Stack chart -section: charts -propComponents: [ - 'Chart', - 'ChartArea', - 'ChartBar', - 'ChartStack', - 'ChartTooltip' -] -hideDarkMode: true ---- - -import { - Chart, - ChartArea, - ChartAxis, - ChartBar, - ChartStack, - ChartLegendTooltip, - ChartThemeColor, - ChartTooltip, - ChartVoronoiContainer, - createContainer -} from '@patternfly/react-charts'; -import { getResizeObserver } from '@patternfly/react-core'; - -## Introduction -Note: PatternFly React charts live in its own package at [@patternfly/react-charts](https://www.npmjs.com/package/@patternfly/react-charts)! - -PatternFly React charts are based on the [Victory](https://formidable.com/open-source/victory/docs/victory-chart/) chart library, along with additional functionality, custom components, and theming for PatternFly. This provides a collection of React based components you can use to build PatternFly patterns with consistent markup, styling, and behavior. - -## Examples -### Basic with right aligned legend -```js -import React from 'react'; -import { Chart, ChartAxis, ChartBar, ChartStack, ChartVoronoiContainer } from '@patternfly/react-charts'; - -
- `${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 React from 'react'; -import { Chart, ChartAxis, ChartBar, ChartStack, ChartThemeColor, ChartVoronoiContainer } from '@patternfly/react-charts'; - -
- `${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 React from 'react'; -import { Chart, ChartBar, ChartAxis, ChartStack, ChartThemeColor, ChartTooltip } from '@patternfly/react-charts'; - -
- - - - - } - /> - } - /> - } - /> - } - /> - - -
-``` - -### Monthly data with responsive container -```js -import React from 'react'; -import { Chart, ChartAxis, ChartBar, ChartStack, ChartTooltip } from '@patternfly/react-charts'; -import { getResizeObserver } from '@patternfly/react-core'; - -class MonthlyResponsiveStack extends React.Component { - constructor(props) { - super(props); - this.containerRef = React.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(); - } - - 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 React from 'react'; -import { Chart, ChartArea, ChartAxis, ChartStack, ChartLegendTooltip, ChartThemeColor, createContainer } from '@patternfly/react-charts'; -import { getResizeObserver } from '@patternfly/react-core'; - -class MultiColorChart extends React.Component { - constructor(props) { - super(props); - this.containerRef = React.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; - - // 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 -### Tips -- See Victory's [FAQ](https://formidable.com/open-source/victory/docs/faq) -- For single data points or zero values, you may want to set the `domain` prop -- `ChartLegend` may be used as a standalone component, instead of using `legendData` -- Themes are inherited, so a default theme may override `themeColor` for a child component -- The `theme` and `themeColor` props should be applied at the most top level component - -### Note -Currently, the generated documentation below is not able to resolve type definitions from Victory imports. For the -components used in the examples above, Victory pass-thru props are also documented here: - -- For `Chart` props, see [VictoryChart](https://formidable.com/open-source/victory/docs/victory-chart) -- For `ChartArea` props, see [VictoryArea](https://formidable.com/open-source/victory/docs/victory-area) -- For `ChartAxis` props, see [VictoryAxis](https://formidable.com/open-source/victory/docs/victory-axis) -- For `ChartBar` props, see [VictoryBar](https://formidable.com/open-source/victory/docs/victory-bar) -- For `ChartStack` props, see [VictoryStack](https://formidable.com/open-source/victory/docs/victory-stack) -- For `ChartTooltip` props, see [VictoryTooltip](https://formidable.com/open-source/victory/docs/victory-tooltip) diff --git a/packages/react-charts/src/components/ChartTheme/examples/ChartTheme.md b/packages/react-charts/src/components/ChartTheme/examples/ChartTheme.md deleted file mode 100644 index 09d42df01f2..00000000000 --- a/packages/react-charts/src/components/ChartTheme/examples/ChartTheme.md +++ /dev/null @@ -1,491 +0,0 @@ ---- -id: Themes -section: charts -hideDarkMode: true ---- - -import { - Chart, - ChartArea, - ChartAxis, - ChartBar, - ChartDonut, - ChartGroup, - ChartLegend, - ChartLine, - ChartStack, - ChartThemeColor, - ChartThreshold, - ChartTooltip, - ChartVoronoiContainer, - getCustomTheme -} from '@patternfly/react-charts'; -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'; -import chart_color_purple_300 from '@patternfly/react-tokens/dist/esm/chart_color_purple_300'; - -## Introduction -Note: PatternFly React charts live in its own package at [@patternfly/react-charts](https://www.npmjs.com/package/@patternfly/react-charts)! - -PatternFly React charts are based on the [Victory](https://formidable.com/open-source/victory/docs/victory-chart/) chart library, along with additional functionality, custom components, and theming for PatternFly. This provides a collection of React based components you can use to build PatternFly patterns with consistent markup, styling, and behavior. - -## Examples -### Green - -This demonstrates how to apply basic theme colors. - -```js -import React from 'react'; -import { Chart, ChartAxis, ChartGroup, ChartLine, ChartThemeColor, ChartVoronoiContainer } from '@patternfly/react-charts'; - -
- `${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 React from 'react'; -import { ChartDonut, ChartThemeColor } from '@patternfly/react-charts'; - -
- `${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 React from 'react'; -import { Chart, ChartArea, ChartAxis, ChartGroup, ChartVoronoiContainer } from '@patternfly/react-charts'; - -
- `${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 React from 'react'; -import { Chart, ChartAxis, ChartBar, ChartLegend, ChartStack, ChartThemeColor, ChartTooltip } from '@patternfly/react-charts'; -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'; - -
- - } - 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 React from 'react'; -import { Chart, ChartAxis, ChartGroup, ChartLine, ChartThemeColor, ChartThreshold, ChartVoronoiContainer } from '@patternfly/react-charts'; -import chart_color_blue_300 from '@patternfly/react-tokens/dist/esm/chart_color_blue_300'; - -
- `${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 React from 'react'; -import { Chart, ChartBar, ChartAxis, ChartGroup, ChartThemeColor, ChartVoronoiContainer, getCustomTheme } from '@patternfly/react-charts'; -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 - ); - } - - 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 - -### Tips -- See Victory's [FAQ](https://formidable.com/open-source/victory/docs/faq) -- The `theme` and `themeColor` props should be applied at the most top level component -- Use `ChartGroup` to apply theme color scales and other properties to multiple components - -### Note -Currently, the generated documentation below is not able to resolve type definitions from Victory imports. For the components used in the examples above, Victory pass-thru props are also documented here: - -- For theme props, see [VictoryTheme](https://formidable.com/open-source/victory/docs/victory-theme) diff --git a/packages/react-charts/src/components/ChartTheme/themes/colors/skeleton-theme.ts b/packages/react-charts/src/components/ChartTheme/themes/colors/skeleton-theme.ts deleted file mode 100644 index 9b58ce91fbf..00000000000 --- a/packages/react-charts/src/components/ChartTheme/themes/colors/skeleton-theme.ts +++ /dev/null @@ -1,35 +0,0 @@ -/* eslint-disable camelcase */ -import { ColorTheme, ColorComponentTheme } from '../skeleton-theme'; -import chart_bullet_qualitative_range_ColorScale_100 from '@patternfly/react-tokens/dist/esm/chart_bullet_qualitative_range_ColorScale_100'; -import chart_bullet_qualitative_range_ColorScale_200 from '@patternfly/react-tokens/dist/esm/chart_bullet_qualitative_range_ColorScale_200'; -import chart_bullet_qualitative_range_ColorScale_300 from '@patternfly/react-tokens/dist/esm/chart_bullet_qualitative_range_ColorScale_300'; -import chart_bullet_qualitative_range_ColorScale_400 from '@patternfly/react-tokens/dist/esm/chart_bullet_qualitative_range_ColorScale_400'; -import chart_bullet_qualitative_range_ColorScale_500 from '@patternfly/react-tokens/dist/esm/chart_bullet_qualitative_range_ColorScale_500'; - -// Color scale -// See https://docs.google.com/document/d/1cw10pJFXWruB1SA8TQwituxn5Ss6KpxYPCOYGrH8qAY/edit -const COLOR_SCALE = [ - chart_bullet_qualitative_range_ColorScale_100.var, - chart_bullet_qualitative_range_ColorScale_200.var, - chart_bullet_qualitative_range_ColorScale_300.var, - chart_bullet_qualitative_range_ColorScale_400.var, - chart_bullet_qualitative_range_ColorScale_500.var -]; - -/** - * Skeleton color theme - * @private - * @beta - */ -export const SkeletonColorTheme = ColorTheme({ - COLOR_SCALE -}); - -/** - * Skeleton color theme - * @private - * @beta - */ -export const SkeletonColorComponentTheme = ColorComponentTheme({ - COLOR_SCALE -}); diff --git a/packages/react-charts/src/components/ChartThreshold/examples/ChartThreshold.md b/packages/react-charts/src/components/ChartThreshold/examples/ChartThreshold.md deleted file mode 100644 index efe5fb1a30a..00000000000 --- a/packages/react-charts/src/components/ChartThreshold/examples/ChartThreshold.md +++ /dev/null @@ -1,196 +0,0 @@ ---- -id: Threshold chart -section: charts -propComponents: [ - 'Chart', - 'ChartAxis', - 'ChartGroup', - 'ChartThreshold', - 'ChartVoronoiContainer' -] -hideDarkMode: true ---- - -import { - Chart, - ChartArea, - ChartAxis, - ChartGroup, - ChartLegend, - ChartThreshold, - ChartThemeColor, - ChartVoronoiContainer -} from '@patternfly/react-charts'; -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'; - - -## Introduction -Note: PatternFly React charts live in its own package at [@patternfly/react-charts](https://www.npmjs.com/package/@patternfly/react-charts)! - -PatternFly React charts are based on the [Victory](https://formidable.com/open-source/victory/docs/victory-chart/) chart library, - along with additional functionality, custom components, and theming for PatternFly. This provides a collection of React based components you can use to build PatternFly patterns with consistent markup, styling, and behavior. - -## Examples -### Multi-color (unordered) with responsive container -```js -import React from 'react'; -import { - Chart, - ChartArea, - ChartAxis, - ChartLegend, - ChartGroup, - ChartThreshold, - ChartThemeColor, - ChartVoronoiContainer -} from '@patternfly/react-charts'; -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 = React.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; - - 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 -### Tips -- See Victory's [FAQ](https://formidable.com/open-source/victory/docs/faq) -- For single data points or zero values, you may want to set the `domain` prop -- `ChartLegend` may be used as a standalone component, instead of using `legendData` - -### Note -Currently, the generated documentation below is not able to resolve type definitions from Victory imports. For the -components used in the examples above, Victory pass-thru props are also documented here: - - - For `Chart` props, see [VictoryChart](https://formidable.com/open-source/victory/docs/victory-chart) - - For `ChartArea` props, see [VictoryArea](https://formidable.com/open-source/victory/docs/victory-area) - - For `ChartAxis` props, see [VictoryAxis](https://formidable.com/open-source/victory/docs/victory-axis) - - For `ChartGroup` props, see [VictoryGroup](https://formidable.com/open-source/victory/docs/victory-group) - - For `ChartLegend` props, see [VictoryLegend](https://formidable.com/open-source/victory/docs/victory-legend) - - For `ChartThreshold` props, see [VictoryLine](https://formidable.com/open-source/victory/docs/victory-line) - - For `ChartVoronoiContainer` props, see [VictoryVoronoiContainer](https://formidable.com/open-source/victory/docs/victory-voronoi-container) diff --git a/packages/react-charts/src/components/ChartTooltip/examples/ChartTooltip.md b/packages/react-charts/src/components/ChartTooltip/examples/ChartTooltip.md deleted file mode 100644 index b7dabf72630..00000000000 --- a/packages/react-charts/src/components/ChartTooltip/examples/ChartTooltip.md +++ /dev/null @@ -1,899 +0,0 @@ ---- -id: Tooltips -section: charts -propComponents: ['ChartTooltip'] -hideDarkMode: true ---- - -import { - Chart, - ChartArea, - ChartAxis, - ChartBar, - ChartContainer, - ChartCursorFlyout, - ChartCursorTooltip, - ChartDonut, - ChartDonutThreshold, - ChartDonutUtilization, - ChartGroup, - ChartLabel, - ChartLegend, - ChartLegendTooltip, - ChartLegendTooltipContent, - ChartLegendTooltipLabel, - ChartLine, - ChartPie, - ChartPoint, - ChartStack, - ChartThemeColor, - ChartTooltip, - ChartVoronoiContainer, - createContainer, - getCustomTheme -} from '@patternfly/react-charts'; -import './chart-tooltip.css'; - -## Introduction -Note: PatternFly React charts live in its own package at [@patternfly/react-charts](https://www.npmjs.com/package/@patternfly/react-charts)! - -PatternFly React charts are based on the [Victory](https://formidable.com/open-source/victory/docs/victory-chart/) chart library, along with additional functionality, custom components, and theming for PatternFly. This provides a collection of React based components you can use to build PatternFly patterns with consistent markup, styling, and behavior. - -## Examples -### Voronoi container - -This demonstrates how to use a voronoi container to display tooltips. - -```js -import React from 'react'; -import { Chart, ChartArea, ChartAxis, ChartGroup, ChartVoronoiContainer } from '@patternfly/react-charts'; - -
- `${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} - > - - - - - - - - -
-``` - -### Combined cursor and voronoi containers - -This demonstrates how to combine cursor and voronoi containers to display tooltips along with a vertical cursor. - -```js -import React from 'react'; -import { Chart, ChartAxis, ChartGroup, ChartLine, ChartThemeColor, createContainer } from '@patternfly/react-charts'; - -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} - > - - - - - - - - - -
- ); - } -} -``` - -### 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 React from 'react'; -import { Chart, ChartAxis, ChartGroup, ChartLegendTooltip, ChartLine, ChartThemeColor, createContainer } from '@patternfly/react-charts'; - -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} - > - - - - - - - - - -
- ); - } -} -``` - -### 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 React from 'react'; -import { Chart, ChartArea, ChartAxis, ChartCursorTooltip, ChartGroup, ChartPoint, ChartThemeColor, createContainer } from '@patternfly/react-charts'; - -class EmbeddedHtml extends React.Component { - constructor(props) { - super(props); - this.baseStyles = { - color: '#f0f0f0', - fontFamily: 'RedHatText, Overpass, overpass, 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} - > - - - - - - - - -
- ); - } -} -``` - -### 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 React from 'react'; -import { Chart, ChartAxis, ChartGroup, ChartLegendTooltip, ChartLegend, ChartLine, ChartLegendTooltipContent, ChartLegendTooltipLabel, ChartThemeColor, createContainer } from '@patternfly/react-charts'; - -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} - > - - - - - - - - - -
- ); - } -} -``` - -### Data label - -This demonstrates an alternate way of applying tooltips using data labels. - -```js -import React from 'react'; -import { Chart, ChartAxis, ChartBar, ChartStack, ChartThemeColor, ChartTooltip } from '@patternfly/react-charts'; - -
- - - - - } - /> - } - /> - } - /> - } - /> - - -
-``` - -### Fixed tooltip -This demonstrates how to adjust the tooltip position and label radius -```js -import React from 'react'; -import { ChartDonut, ChartTooltip } from '@patternfly/react-charts'; - -
- } - labelRadius={46} - labels={({ datum }) => `${datum.x}: ${datum.y}%`} - name="chart5" - subTitle="Pets" - title="100" - themeColor={ChartThemeColor.teal} - width={150} - /> -
-``` - -### Legend - -This demonstrates an approach for applying tooltips to a legend using a custom legend label component. - -```js -import React from 'react'; -import { ChartLabel, ChartLegend, ChartPie, ChartThemeColor } from '@patternfly/react-charts'; -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 = React.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} - /> -
- ); - } -} -``` - -### Left aligned - -This demonstrates how to customize tooltip label alignment using theme properties. - -```js -import React from 'react'; -import { Chart, ChartAxis, ChartGroup, ChartLine, ChartThemeColor, ChartVoronoiContainer, getCustomTheme } from '@patternfly/react-charts'; - -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} - > - - - - - - - - - -
- ); - } -} -``` - -### CSS overflow - -This demonstrates an alternate way of applying tooltips using CSS overflow instead of constrainToVisibleArea. - -```js -import React from 'react'; -import { ChartArea, ChartGroup, ChartLabel, ChartThemeColor, ChartVoronoiContainer } from '@patternfly/react-charts'; - -
-
- `${datum.name}: ${datum.y}`} />} - height={100} - maxDomain={{y: 9}} - name="chart9" - padding={0} - themeColor={ChartThemeColor.green} - width={400} - > - - - -
-
-``` - -### Wrapped chart - -This demonstrates an alternate way of applying tooltips by wrapping charts with the Tooltip component. - -```js -import React from 'react'; -import { ChartDonutThreshold, ChartDonutUtilization } from '@patternfly/react-charts'; -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%" - /> - - -
-
- -
- - ); - } -} -``` - -## Documentation -### Tips -- See Victory's [FAQ](https://formidable.com/open-source/victory/docs/faq) - -### Note -Currently, the generated documentation below is not able to resolve type definitions from Victory imports. For the -components used in the examples above, Victory pass-thru props are also documented here: - -- For `ChartTooltip` props, see [VictoryTooltip](https://formidable.com/open-source/victory/docs/victory-tooltip) diff --git a/packages/react-charts/src/components/Patterns/examples/patterns.md b/packages/react-charts/src/components/Patterns/examples/patterns.md deleted file mode 100644 index f4ee30f25aa..00000000000 --- a/packages/react-charts/src/components/Patterns/examples/patterns.md +++ /dev/null @@ -1,836 +0,0 @@ ---- -id: Patterns -section: charts -propComponents: [ - 'Chart', - 'ChartArea', - 'ChartAxis', - 'ChartBar', - 'ChartDonut', - 'ChartDonutThreshold', - 'ChartDonutUtilization', - 'ChartGroup', - 'ChartLegend', - 'ChartLegendTooltip', - 'ChartPie', - 'ChartScatter', - 'ChartStack', - 'ChartVoronoiContainer' -] -hideDarkMode: true ---- - -import { - Chart, - ChartArea, - ChartAxis, - ChartBar, - ChartDonut, - ChartDonutThreshold, - ChartDonutUtilization, - ChartGroup, - ChartLegend, - ChartLegendTooltip, - ChartPie, - ChartScatter, - ChartStack, - ChartThemeColor, - ChartVoronoiContainer, - createContainer, - getInteractiveLegendEvents, - getInteractiveLegendItemStyles -} from '@patternfly/react-charts'; -import { getResizeObserver } from '@patternfly/react-core'; -import chart_color_black_500 from '@patternfly/react-tokens/dist/esm/chart_color_black_500'; -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'; -import '@patternfly/patternfly/patternfly-charts.css'; - -## Introduction -Note: PatternFly React charts live in its own package at [@patternfly/react-charts](https://www.npmjs.com/package/@patternfly/react-charts)! - -PatternFly React charts are based on the [Victory](https://formidable.com/open-source/victory/docs/victory-chart/) chart library, along with additional functionality, custom components, and theming for PatternFly. This provides a collection of React based components you can use to build PatternFly patterns with consistent markup, styling, and behavior. - -## Examples -### Basic pie chart -```js -import React from 'react'; -import { ChartPie } from '@patternfly/react-charts'; - -
- `${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} - /> -
-``` - -### Bar chart -```js -import React from 'react'; -import { Chart, ChartAxis, ChartBar, ChartGroup, ChartThemeColor, ChartVoronoiContainer } from '@patternfly/react-charts'; - -
- `${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} - > - - - - - - - - - -
-``` - -### Stack chart -```js -import React from 'react'; -import { Chart, ChartAxis, ChartBar, ChartStack, ChartThemeColor, ChartVoronoiContainer } from '@patternfly/react-charts'; - -
- `${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} - > - - - - - - - - - -
-``` - -### Donut chart -```js -import React from 'react'; -import { ChartDonut, ChartThemeColor } from '@patternfly/react-charts'; - -
- `${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} - /> -
-``` - -### Donut utilization chart - -This demonstrates how to hide a pattern for the static, unused portion of the donut utilization chart. - -```js -import React from 'react'; -import { ChartDonutUtilization, ChartThemeColor } from '@patternfly/react-charts'; - -
- 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} - /> -
-``` - -### Donut utilization chart with thresholds - -This demonstrates how to apply patterns to thresholds. - -```js -import React from 'react'; -import { ChartDonutThreshold, ChartDonutUtilization, ChartThemeColor } from '@patternfly/react-charts'; - -
- 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} - /> - -
-``` - -### 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 React from 'react'; -import { - Chart, - ChartLegend, - ChartThemeColor, - ChartPie, - getInteractiveLegendEvents, - getInteractiveLegendItemStyles -} from '@patternfly/react-charts'; - -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 React from 'react'; -import { - Chart, - ChartArea, - ChartAxis, - ChartGroup, - ChartLegend, - ChartLegendTooltip, - ChartScatter, - ChartThemeColor, - createContainer, - getInteractiveLegendEvents, - getInteractiveLegendItemStyles -} from '@patternfly/react-charts'; -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 = React.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 = React.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 ( - - ); - })} - - -
-
- ); - } -} -``` - -### Custom pattern visibility - -This demonstrates how to omit patterns from pie chart segments. - -```js -import React from 'react'; -import { ChartPie, ChartThemeColor } from '@patternfly/react-charts'; - -
- `${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} - /> -
-``` - -### Custom color scale - -This demonstrates how to apply a custom color scale to patterns. - -```js -import React from 'react'; -import { ChartPie } from '@patternfly/react-charts'; -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'; - -
- `${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 React from 'react'; -import { ChartPie, ChartThemeColor } from '@patternfly/react-charts'; -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'; - -
- - - - - - - - - - - `${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 React from 'react'; -import { ChartPie, ChartThemeColor } from '@patternfly/react-charts'; -import { getResizeObserver } from '@patternfly/react-core'; - -class PatternsPie extends React.Component { - constructor(props) { - super(props); - this.containerRef = React.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 -### Tips -- See Victory's [FAQ](https://formidable.com/open-source/victory/docs/faq) -- `ChartLegend` may be used as a standalone component, instead of using `legendData` - -### Note -Currently, the generated documentation below is not able to resolve type definitions from Victory imports. For the -components used in the examples above, Victory pass-thru props are also documented here: - -- For `Chart` props, see [VictoryChart](https://formidable.com/open-source/victory/docs/victory-chart) -- For `ChartArea` props, see [VictoryArea](https://formidable.com/open-source/victory/docs/victory-area) -- For `ChartAxis` props, see [VictoryAxis](https://formidable.com/open-source/victory/docs/victory-axis) -- For `ChartBar` props, see [VictoryBar](https://formidable.com/open-source/victory/docs/victory-bar) -- For `ChartDonut` props, see [VictoryPie](https://formidable.com/open-source/victory/docs/victory-pie) -- For `ChartDonutThreshold` props, see [VictoryPie](https://formidable.com/open-source/victory/docs/victory-pie) -- For `ChartDonutUtilization` props, see [VictoryPie](https://formidable.com/open-source/victory/docs/victory-pie) -- For `ChartGroup` props, see [VictoryGroup](https://formidable.com/open-source/victory/docs/victory-group) -- For `ChartLegend` props, see [VictoryLegend](https://formidable.com/open-source/victory/docs/victory-legend) -- For `ChartPie` props, see [VictoryPie](https://formidable.com/open-source/victory/docs/victory-pie) -- For `ChartScatter` props, see [VictoryScatter](https://formidable.com/open-source/victory/docs/victory-scatter) -- For `ChartStack` props, see [VictoryStack](https://formidable.com/open-source/victory/docs/victory-stack) -- For `ChartVoronoiContainer` props, see [VictoryVoronoiContainer](https://formidable.com/open-source/victory/docs/victory-voronoi-container) diff --git a/packages/react-charts/src/components/ResizeObserver/examples/resizeObserver.md b/packages/react-charts/src/components/ResizeObserver/examples/resizeObserver.md deleted file mode 100644 index 11e5ab5ca33..00000000000 --- a/packages/react-charts/src/components/ResizeObserver/examples/resizeObserver.md +++ /dev/null @@ -1,434 +0,0 @@ ---- -id: Resize observer -section: charts -propComponents: [ - 'Chart', - 'ChartArea', - 'ChartAxis', - 'ChartBar', - 'ChartBullet', - 'ChartGroup', - 'ChartLegend', - 'ChartStack', - 'ChartThreshold', - 'ChartTooltip', - 'ChartVoronoiContainer' -] -hideDarkMode: true ---- - -import { - Chart, - ChartArea, - ChartAxis, - ChartBar, - ChartBullet, - ChartGroup, - ChartLegend, - ChartStack, - ChartThemeColor, - ChartThreshold, - ChartTooltip, - ChartVoronoiContainer -} from '@patternfly/react-charts'; -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 '@patternfly/patternfly/patternfly-charts.css'; - -## Introduction -Note: PatternFly React charts live in its own package at [@patternfly/react-charts](https://www.npmjs.com/package/@patternfly/react-charts)! - -PatternFly React charts are based on the [Victory](https://formidable.com/open-source/victory/docs/victory-chart/) chart library, along with additional functionality, custom components, and theming for PatternFly. This provides a collection of React based components you can use to build PatternFly patterns with consistent markup, styling, and behavior. - -Charts scale within the parent container by default, so the `width` and `height` props do not actually determine the -width and height of the chart in number of pixels, but instead define an aspect ratio for the chart. The exact number -of pixels will depend on the size of the container the chart is rendered into. In order to maintain the aspect ratio, -the parent container may be set to the same height and/or width. - -## Examples -### Responsive bullet chart with wrapping legend - -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 React from 'react'; -import { ChartBullet } from '@patternfly/react-charts'; -import { getResizeObserver } from '@patternfly/react-core'; - -class BulletChart extends React.Component { - constructor(props) { - super(props); - this.containerRef = React.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(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 React from 'react'; -import { - Chart, - ChartArea, - ChartAxis, - ChartLegend, - ChartGroup, - ChartThreshold, - ChartThemeColor, - ChartVoronoiContainer -} from '@patternfly/react-charts'; -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 = React.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(); - } - - 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 React from 'react'; -import { Chart, ChartAxis, ChartBar, ChartStack, ChartTooltip } from '@patternfly/react-charts'; -import { getResizeObserver } from '@patternfly/react-core'; - -class MonthlyResponsiveStack extends React.Component { - constructor(props) { - super(props); - this.containerRef = React.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(); - } - - render(){ - const { width } = this.state; - return ( -
-
- - - - - { this.renderSocketBars() } - { this.renderCoresBars() } - { this.renderNodesBars() } - - -
-
- ) - } -} -``` - -## Documentation -### Tips -- See Victory's [FAQ](https://formidable.com/open-source/victory/docs/faq) -- `ChartLegend` may be used as a standalone component, instead of using `legendData` - -### Note -Currently, the generated documentation below is not able to resolve type definitions from Victory imports. For the -components used in the examples above, Victory pass-thru props are also documented here: - -- For `Chart` props, see [VictoryChart](https://formidable.com/open-source/victory/docs/victory-chart) -- For `ChartArea` props, see [VictoryArea](https://formidable.com/open-source/victory/docs/victory-area) -- For `ChartAxis` props, see [VictoryAxis](https://formidable.com/open-source/victory/docs/victory-axis) -- For `ChartBar` props, see [VictoryBar](https://formidable.com/open-source/victory/docs/victory-bar) -- For `ChartBullet` props, see [VictoryBar](https://formidable.com/open-source/victory/docs/victory-bar) -- For `ChartGroup` props, see [VictoryGroup](https://formidable.com/open-source/victory/docs/victory-group) -- For `ChartLegend` props, see [VictoryLegend](https://formidable.com/open-source/victory/docs/victory-legend) -- For `ChartLine` props, see [Victoryline](https://formidable.com/open-source/victory/docs/victory-line) -- For `ChartStack` props, see [VictoryStack](https://formidable.com/open-source/victory/docs/victory-stack) -- For `ChartTooltip` props, see [VictoryTooltip](https://formidable.com/open-source/victory/docs/victory-tooltip) -- For `ChartThreshold` props, see [VictoryLine](https://formidable.com/open-source/victory/docs/victory-line) -- For `ChartVoronoiContainer` props, see [VictoryVoronoiContainer](https://formidable.com/open-source/victory/docs/victory-voronoi-container) diff --git a/packages/react-charts/src/components/Skeletons/examples/skeletons.md b/packages/react-charts/src/components/Skeletons/examples/skeletons.md deleted file mode 100644 index d32653575ef..00000000000 --- a/packages/react-charts/src/components/Skeletons/examples/skeletons.md +++ /dev/null @@ -1,798 +0,0 @@ ---- -id: Skeletons -section: charts -propComponents: [ - 'Chart', - 'ChartArea', - 'ChartAxis', - 'ChartBar', - 'ChartBoxPlot', - 'ChartBullet', - 'ChartDonut', - 'ChartDonutThreshold', - 'ChartDonutUtilization', - 'ChartLegend', - 'ChartLine', - 'ChartGroup', - 'ChartPie', - 'ChartScatter', - 'ChartStack', - 'ChartThreshold', - 'ChartVoronoiContainer' -] -hideDarkMode: true -beta: true ---- - -import { Chart, ChartArea, ChartAxis, ChartBar, ChartBoxPlot, ChartBullet, ChartDonut, ChartDonutThreshold, ChartDonutUtilization, ChartLegend, ChartLine, ChartGroup, ChartPie, ChartScatter, ChartStack, ChartThemeColor, ChartThreshold, ChartVoronoiContainer } from '@patternfly/react-charts'; -import { getResizeObserver } from '@patternfly/react-core'; -import chart_color_blue_300 from '@patternfly/react-tokens/dist/esm/chart_color_blue_300'; - -## Introduction -Note: PatternFly React charts live in its own package at [@patternfly/react-charts](https://www.npmjs.com/package/@patternfly/react-charts)! - -PatternFly React charts are based on the [Victory](https://formidable.com/open-source/victory/docs/victory-chart/) chart library, along with additional functionality, custom components, and theming for PatternFly. This provides a collection of React based components you can use to build PatternFly patterns with consistent markup, styling, and behavior. - -## Examples -### Area chart -```js -import React from 'react'; -import { Chart, ChartArea, ChartAxis, ChartGroup, ChartVoronoiContainer } from '@patternfly/react-charts'; -import { Switch } from '@patternfly/react-core'; - -export const ChartAreaSkeleton: React.FunctionComponent = () => { - const [isChecked, setIsChecked] = React.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 React from 'react'; -import { Switch } from '@patternfly/react-core'; -import { Chart, ChartBar, ChartAxis, ChartGroup, ChartVoronoiContainer } from '@patternfly/react-charts'; - -export const ChartBarSkeleton: React.FunctionComponent = () => { - const [isChecked, setIsChecked] = React.useState(true); - - const handleChange = (_event: React.FormEvent, checked: boolean) => { - setIsChecked(checked); - }; - - 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 React from 'react'; -import { Switch } from '@patternfly/react-charts' -import { Chart, ChartAxis, ChartBoxPlot } from '@patternfly/react-charts'; - -export const ChartBoxPlotSkeleton: React.FunctionComponent = () => { - const [isChecked, setIsChecked] = React.useState(true); - - const handleChange = (_event: React.FormEvent, checked: boolean) => { - setIsChecked(checked); - }; - - return ( - <> - -
- - - - - -
- - ); -} -``` - -### Bullet chart -```js -import React from 'react'; -import { Switch } from '@patternfly/react-core'; -import { Chart, ChartAxis, ChartBullet, ChartLegend } from '@patternfly/react-charts'; - -export const ChartBulletSkeleton: React.FunctionComponent = () => { - const [isChecked, setIsChecked] = React.useState(true); - - 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 React from 'react'; -import { Switch } from '@patternfly/react-core'; -import { Chart, ChartAxis, ChartDonut } from '@patternfly/react-charts'; - -export const ChartDonutSkeleton: React.FunctionComponent = () => { - const [isChecked, setIsChecked] = React.useState(true); - - const handleChange = (_event: React.FormEvent, checked: boolean) => { - setIsChecked(checked); - }; - - return ( - <> - -
- `${datum.x}: ${datum.y}%`} - name="chart5" - subTitle="Pets" - themeColor={isChecked ? ChartThemeColor.skeleton : ChartThemeColor.blue} - title="100" - /> -
- - ); -} -``` - -### Donut utilization chart -```js -import React from 'react'; -import { Switch } from '@patternfly/react-core'; -import { Chart, ChartAxis, ChartDonutUtilization } from '@patternfly/react-charts'; - -export const ChartDonutUtilizationSkeleton: React.FunctionComponent = () => { - const [isChecked, setIsChecked] = React.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 React from 'react'; -import { Switch } from '@patternfly/react-core'; -import { Chart, ChartAxis, ChartDonutThreshold, ChartDonutUtilization } from '@patternfly/react-charts'; - -export const ChartDonutUtilizationSkeleton: React.FunctionComponent = () => { - const [isChecked, setIsChecked] = React.useState(true); - - 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 React from 'react'; -import { Switch } from '@patternfly/react-core'; -import { Chart, ChartVoronoiContainer, ChartGroup, ChartAxis, ChartLine } from '@patternfly/react-charts'; - -export const ChartLineSkeleton: React.FunctionComponent = () => { - const [isChecked, setIsChecked] = React.useState(true); - - const handleChange = (_event: React.FormEvent, checked: boolean) => { - setIsChecked(checked); - }; - - 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 React from 'react'; -import { Switch } from '@patternfly/react-core'; -import { Chart, ChartAxis, ChartPie } from '@patternfly/react-charts'; - -export const ChartPieSkeleton: React.FunctionComponent = () => { - const [isChecked, setIsChecked] = React.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 React from 'react'; -import { Switch } from '@patternfly/react-core'; -import { Chart, ChartVoronoiContainer, ChartGroup, ChartAxis, ChartScatter } from '@patternfly/react-charts'; - -export const ChartScatterSkeleton: React.FunctionComponent = () => { - const [isChecked, setIsChecked] = React.useState(true); - - 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 React from 'react'; -import { Switch } from '@patternfly/react-core'; -import { Chart, ChartVoronoiContainer, ChartAxis, ChartStack, ChartBar } from '@patternfly/react-charts'; - -export const ChartStackSkeleton: React.FunctionComponent = () => { - const [isChecked, setIsChecked] = React.useState(true); - - const handleChange = (_event: React.FormEvent, checked: boolean) => { - setIsChecked(checked); - }; - - 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 React from 'react'; -import { Switch } from '@patternfly/react-core'; -import { Chart, ChartVoronoiContainer, ChartLegend, ChartAxis, ChartThreshold, ChartGroup, ChartArea } from '@patternfly/react-charts';import chart_color_blue_300 from '@patternfly/react-tokens/dist/esm/chart_color_blue_300'; - -export const ChartThresholdSkeleton: React.FunctionComponent = () => { - const [isChecked, setIsChecked] = React.useState(true); - - const handleChange = (_event: React.FormEvent, checked: boolean) => { - setIsChecked(checked); - }; - - 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="chart12" - themeColor={isChecked ? ChartThemeColor.skeleton : ChartThemeColor.blue} - width={800} - > - - - - - - - - -
- - ); -} -``` - -## Documentation -### Tips -- It's best for skeletons not to include interactions such as tooltips, cursors, interactive legends, etc. -- See Victory's [FAQ](https://formidable.com/open-source/victory/docs/faq) -- For single data points or zero values, you may want to set the `domain` prop -- `ChartLegend` may be used as a standalone component, instead of using `legendData` -- The `theme` and `themeColor` props should be applied at the most top level component -- Use `ChartGroup` to apply theme color scales and other properties to multiple components - -### Note -Currently, the generated documentation below is not able to resolve type definitions from Victory imports. For the -components used in the examples above, Victory pass-thru props are also documented here: - -- For `Chart` props, see [VictoryChart](https://formidable.com/open-source/victory/docs/victory-chart) -- For `ChartArea` props, see [VictoryArea](https://formidable.com/open-source/victory/docs/victory-area) -- For `ChartAxis` props, see [VictoryAxis](https://formidable.com/open-source/victory/docs/victory-axis) -- For `ChartBar` props, see [VictoryBar](https://formidable.com/open-source/victory/docs/victory-bar) -- For `ChartBoxPlot` props, see [VictoryBoxPlot](https://formidable.com/open-source/victory/docs/victory-box-plot) -- For `ChartBullet` props, see [VictoryBar](https://formidable.com/open-source/victory/docs/victory-bar) -- For `ChartDonut` props, see [VictoryPie](https://formidable.com/open-source/victory/docs/victory-pie) -- For `ChartDonutThreshold` props, see [VictoryPie](https://formidable.com/open-source/victory/docs/victory-pie) -- For `ChartDonutUtilization` props, see [VictoryPie](https://formidable.com/open-source/victory/docs/victory-pie) -- For `ChartLine` props, see [Victoryline](https://formidable.com/open-source/victory/docs/victory-line) -- For `ChartGroup` props, see [VictoryGroup](https://formidable.com/open-source/victory/docs/victory-group) -- For `ChartPie` props, see [VictoryPie](https://formidable.com/open-source/victory/docs/victory-pie) -- For `ChartScatter` props, see [VictoryScatter](https://formidable.com/open-source/victory/docs/victory-scatter) -- For `ChartStack` props, see [VictoryStack](https://formidable.com/open-source/victory/docs/victory-stack) -- For `ChartThreshold` props, see [VictoryLine](https://formidable.com/open-source/victory/docs/victory-line) -- For `ChartVoronoiContainer` props, see [VictoryVoronoiContainer](https://formidable.com/open-source/victory/docs/victory-voronoi-container) diff --git a/packages/react-charts/src/components/Sparkline/examples/sparkline.md b/packages/react-charts/src/components/Sparkline/examples/sparkline.md deleted file mode 100644 index ca9bc2b6f9c..00000000000 --- a/packages/react-charts/src/components/Sparkline/examples/sparkline.md +++ /dev/null @@ -1,108 +0,0 @@ ---- -id: Sparkline chart -section: charts -propComponents: [ - 'ChartArea', - 'ChartContainer', - 'ChartGroup', - 'ChartLabel', - 'ChartVoronoiContainer' -] -hideDarkMode: true ---- - -import { ChartArea, ChartContainer, ChartGroup, ChartLabel, ChartThemeColor, ChartVoronoiContainer } from '@patternfly/react-charts'; -import './sparkline.css'; - -## Introduction -Note: PatternFly React charts live in its own package at [@patternfly/react-charts](https://www.npmjs.com/package/@patternfly/react-charts)! - -PatternFly React charts are based on the [Victory](https://formidable.com/open-source/victory/docs/victory-chart/) chart library, along with additional functionality, custom components, and theming for PatternFly. This provides a collection of React based components you can use to build PatternFly patterns with consistent markup, styling, and behavior. - -## Examples -### Basic -```js -import React from 'react'; -import { ChartArea, ChartContainer, ChartGroup, ChartLabel, ChartVoronoiContainer } from '@patternfly/react-charts'; - -
-
- `${datum.name}: ${datum.y}`} constrainToVisibleArea />} - height={100} - maxDomain={{y: 9}} - name="chart1" - padding={0} - width={400} - > - - -
- - - -
-``` - -### Green - -This demonstrates an alternate way of applying tooltips using CSS overflow - -```js -import React from 'react'; -import { ChartArea, ChartContainer, ChartGroup, ChartLabel, ChartThemeColor, ChartVoronoiContainer } from '@patternfly/react-charts'; - -
-
- `${datum.name}: ${datum.y}`} />} - height={100} - maxDomain={{y: 9}} - name="chart2" - padding={0} - themeColor={ChartThemeColor.green} - width={400} - > - - -
- - - -
-``` - -## Documentation -### Tips -- See Victory's [FAQ](https://formidable.com/open-source/victory/docs/faq) -- For single data points or zero values, you may want to set the `domain` prop -- Use `ChartGroup` in place of `Chart` when an axis and labels are not desired -- Themes are inherited, so a default theme may override `themeColor` for a child component -- The `theme` and `themeColor` props should be applied at the most top level component - -### Note -Currently, the generated documentation below is not able to resolve type definitions from Victory imports. For the -components used in the examples above, Victory pass-thru props are also documented here: - -- For `ChartArea` props, see [VictoryArea](https://formidable.com/open-source/victory/docs/victory-area) -- For `ChartGroup` props, see [VictoryGroup](https://formidable.com/open-source/victory/docs/victory-group) -- For `ChartLabel` props, see [VictoryLabel](https://formidable.com/open-source/victory/docs/victory-label) -- For `ChartVoronoiContainer` props, see [VictoryVoronoiContainer](https://formidable.com/open-source/victory/docs/victory-voronoi-container) diff --git a/packages/react-charts/src/echarts/__mocks__/echarts.ts b/packages/react-charts/src/echarts/__mocks__/echarts.ts new file mode 100644 index 00000000000..52c5c5c2c22 --- /dev/null +++ b/packages/react-charts/src/echarts/__mocks__/echarts.ts @@ -0,0 +1,6 @@ +const echarts: any = jest.createMockFromModule('echarts'); +echarts.init = jest.fn(() => ({ + setOption: jest.fn(), + dispose: jest.fn() +})); +module.exports = echarts; diff --git a/packages/react-charts/src/echarts/components/Charts/Charts.tsx b/packages/react-charts/src/echarts/components/Charts/Charts.tsx new file mode 100644 index 00000000000..ae9002fd9a3 --- /dev/null +++ b/packages/react-charts/src/echarts/components/Charts/Charts.tsx @@ -0,0 +1,252 @@ +import { FunctionComponent, useEffect } from 'react'; +import { useCallback, useReducer, useRef } from 'react'; +import cloneDeep from 'lodash/cloneDeep'; +import defaultsDeep from 'lodash/defaultsDeep'; + +import * as echarts from 'echarts/core'; +import { EChartsInitOpts } from 'echarts/types/dist/echarts'; +import { EChartsOption } from 'echarts/types/dist/option'; +import { TooltipOption } from 'echarts/types/dist/shared'; + +import { getLineSeries } from '../Line'; +import { getSankeySeries } from '../Sankey'; + +import { ThemeDefinition } from '../themes/Theme'; +import { getMutationObserver } from '../utils/observe'; +import { getClassName } from '../utils/styles'; +import { getTheme } from '../utils/theme'; +import { getLegendTooltip, getSankeyTooltip } from '../utils/tooltip'; +import { ThemeColor } from '../themes/ThemeColor'; + +/** + * See https://echarts.apache.org/en/option.html#tooltip + * + * @public + * @beta + */ +export interface TooltipOptionProps extends TooltipOption { + /** + * The destination label shown in the tooltip -- for Sankey only + */ + destinationLabel?: string; + /** + * The source label shown in the tooltip -- for Sankey only + */ + sourceLabel?: string; +} + +/** + * See https://echarts.apache.org/en/option.html + * + * @public + * @beta + */ +export interface ChartsOptionProps extends EChartsOption { + /** + * Tooltip component -- see https://echarts.apache.org/en/option.html#tooltip + */ + tooltip?: TooltipOptionProps | TooltipOptionProps[]; +} + +/** + * This component is based on the Apache ECharts chart library. It provides additional functionality, custom + * components, and theming for PatternFly. This provides a collection of React based components you can use to build + * PatternFly patterns with consistent markup, styling, and behavior. + * + * See https://echarts.apache.org/en/api.html#echarts + * + * @public + * @beta + */ +export interface ChartsProps { + /** + * The className prop specifies a class name that will be applied to outermost element + */ + className?: string; + /** + * Specify height explicitly, in pixels + */ + height?: number; + /** + * The id prop specifies an ID that will be applied to outermost element. + */ + id?: string; + /** + * Flag indicating to use the legend tooltip (default). This may be overridden by the `option.tooltip` property. + */ + isLegendTooltip?: boolean; + /** + * Flag indicating to use the SVG renderer (default). This may be overridden by the `opts.renderer` property. + */ + isSvgRenderer?: boolean; + /** + * This creates a Mutation Observer to watch the given DOM selector. + * + * When the pf-v6-theme-dark selector is added or removed, this component will be notified to update its computed + * theme styles. However, if the dark theme is not updated dynamically (e.g., via a toggle), there is no need to add + * this Mutation Observer. + * + * Note: Don't provide ".pf-v6-theme-dark" as the node selector as it won't exist in the page for light theme. + * The underlying querySelectorAll() function needs to find the element the dark theme selector will be added to. + * + * See https://developer.mozilla.org/en-US/docs/Web/API/Document_Object_Model/Locating_DOM_elements_using_selectors + * + * @propType string + * @example + * @example + * @example + */ + nodeSelector?: string; + /** + * ECharts uses this object to configure its properties; for example, series, title, and tooltip + * + * See https://echarts.apache.org/en/option.html + */ + option?: ChartsOptionProps; + /** + * Optional chart configuration + * + * See https://echarts.apache.org/en/api.html#echarts.init + */ + opts?: EChartsInitOpts; + /** + * The theme prop specifies a theme to use for determining styles and layout properties for a component. Any styles or + * props defined in theme may be overwritten by props specified on the component instance. + * + * See https://echarts.apache.org/handbook/en/concepts/style/#theme + */ + theme?: ThemeDefinition; + /** + * Specifies the theme color. Valid values are 'blue', 'green', 'multi', etc. + * + * Note: Not compatible with theme prop + * + * @example themeColor={ChartThemeColor.blue} + */ + themeColor?: string; + /** + * Specify width explicitly, in pixels + */ + width?: number; +} +export const Charts: FunctionComponent = ({ + className, + height, + id, + isLegendTooltip = true, + isSvgRenderer = true, + nodeSelector, + option, + opts, + theme, + themeColor, + width, + ...rest +}: ChartsProps) => { + const containerRef = useRef(null); + const echart = useRef(null); + const [update, forceUpdate] = useReducer((x) => x + 1, 0); + + const getSize = () => ({ + ...(height && { height: `${height}px` }), + ...(width && { width: `${width}px` }) + }); + + const getTooltip = useCallback( + (series: any[], tooltipType: string, isSkeleton: boolean, echart) => { + // Skeleton should not have any interactions + if (isSkeleton) { + return undefined; + } else if (tooltipType === 'sankey') { + return getSankeyTooltip(series, option); + } else if (tooltipType === 'legend') { + return getLegendTooltip(series, option, echart); + } + return option.tooltip; + }, + [option] + ); + + const getSeries = useCallback( + (chartTheme: ThemeDefinition, isSkeleton: boolean) => { + let tooltipType; + const series: any = cloneDeep(option?.series); + const newSeries = []; + + series.map((serie: any) => { + switch (serie.type) { + case 'sankey': + tooltipType = 'sankey'; // Overrides legend tooltip + newSeries.push(getSankeySeries(serie, chartTheme, isSkeleton)); + break; + case 'line': + if (!tooltipType) { + tooltipType = 'legend'; + } + newSeries.push(getLineSeries(serie, chartTheme, isSkeleton)); + break; + default: + newSeries.push(serie); + break; + } + }); + return { series, tooltipType }; + }, + [option?.series] + ); + + useEffect(() => { + const isSkeleton = themeColor === ThemeColor.skeleton; + const chartTheme = theme ? theme : getTheme(themeColor); + const renderer = isSvgRenderer ? 'svg' : 'canvas'; + + echart.current = echarts.init( + containerRef.current, + chartTheme, + defaultsDeep(opts, { height, renderer, width }) // height and width are necessary here for unit tests + ); + + const { series, tooltipType } = getSeries(chartTheme, isSkeleton); + echart.current?.setOption({ + ...option, + ...(isLegendTooltip && { tooltip: getTooltip(series, tooltipType, isSkeleton, echart.current) }), + series + }); + + return () => { + echart.current?.dispose(); + }; + }, [ + containerRef, + getSeries, + getTooltip, + height, + isLegendTooltip, + isSvgRenderer, + option, + opts, + theme, + themeColor, + update, + width + ]); + + // Resize observer + useEffect(() => { + echart.current?.resize(); + }, [height, width]); + + // Dark theme observer + useEffect(() => { + let observer = () => {}; + observer = getMutationObserver(nodeSelector, () => { + forceUpdate(); + }); + return () => { + observer(); + }; + }, [nodeSelector]); + + return
; +}; +Charts.displayName = 'Charts'; diff --git a/packages/react-charts/src/echarts/components/Charts/docs/Charts.tsx b/packages/react-charts/src/echarts/components/Charts/docs/Charts.tsx new file mode 100644 index 00000000000..dbd01f55105 --- /dev/null +++ b/packages/react-charts/src/echarts/components/Charts/docs/Charts.tsx @@ -0,0 +1,411 @@ +import { EChartsInitOpts } from 'echarts/types/dist/echarts'; +import { EChartsOption } from 'echarts/types/dist/option'; +import { + AngleAxisOption, + AriaOption, + AxisPointerOption, + BrushOption, + CalendarOption, + DatasetOption, + DataZoomComponentOption, + GeoOption, + GraphicComponentLooseOption, + GridOption, + LegendComponentOption, + ParallelCoordinateSystemOption, + PolarOption, + RadarOption, + RadiusAxisOption, + SingleAxisOption, + TimelineOption, + TitleOption, + ToolboxComponentOption, + VisualMapComponentOption, + XAXisOption, + YAXisOption +} from 'echarts/types/dist/shared'; + +// The properties below exist to document properties in the example docs. Some EChart types are not exported and too +// complex to recreate here. Attempting to duplicate each EChart type would be error-prone. For documentation purposes, +// we shall define simple types here, which avoids having to duplicate EChart's complex object types. + +/** + * See https://echarts.apache.org/en/option.html#tooltip + * + * @private Not intended as public API and subject to change + */ +export interface TooltipOptionProps { + /** + * Whether to show tooltip content all the time -- see https://echarts.apache.org/en/option.html#tooltip.alwaysShowContent + */ + alwaysShowContent?: boolean; + /** + * Which DOM element to append the tooltip to -- see https://echarts.apache.org/en/option.html#tooltip.appendTo + */ + appendTo?: string | HTMLElement | Function; + /** + * Configuration item for axisPointer -- see https://echarts.apache.org/en/option.html#tooltip.axisPointer + */ + axisPointer?: Object; + /** + * The background color of tooltip's floating layer -- see https://echarts.apache.org/en/option.html#tooltip.backgroundColor + */ + backgroundColor?: string; + /** + * The border color of tooltip's floating layer -- see https://echarts.apache.org/en/option.html#tooltip.borderColor + */ + borderColor?: string; + /** + * The border width of tooltip's floating layer -- see https://echarts.apache.org/en/option.html#tooltip.borderWidth + */ + borderWidth?: number; + /** + * Specify the classes for the tooltip root DOM -- see https://echarts.apache.org/en/option.html#tooltip.className + */ + className?: string; + /** + * Whether confine tooltip content in the view rect of chart instance -- see https://echarts.apache.org/en/option.html#tooltip.confine + */ + confine?: boolean; + /** + * The destination label shown in the tooltip -- for Sankey only + */ + destinationLabel?: string; + /** + * Whether mouse is allowed to enter the floating layer of tooltip -- see https://echarts.apache.org/en/option.html#tooltip.enterable + */ + enterable?: boolean; + /** + * Extra CSS style for floating layer -- see https://echarts.apache.org/en/option.html#tooltip.extraCssText + */ + extraCssText?: string; + /** + * The content formatter of tooltip's floating layer -- see https://echarts.apache.org/en/option.html#tooltip.formatter + */ + formatter?: string | Function; + /** + * Delay time for hiding tooltip -- see https://echarts.apache.org/en/option.html#tooltip.hideDelay + */ + hideDelay?: number; + /** + * Tooltip order for multiple series -- see https://echarts.apache.org/en/option.html#tooltip.order + */ + order?: string; + /** + * The floating layer of tooltip space around content -- see https://echarts.apache.org/en/option.html#tooltip.padding + */ + padding?: number; + /** + * The position of the tooltip's floating layer -- see https://echarts.apache.org/en/option.html#tooltip.position + */ + position?: string[]; + /** + * Render mode for tooltip -- see https://echarts.apache.org/en/option.html#tooltip.renderMode + */ + renderMode?: string; + /** + * Whether to show the tooltip component -- see https://echarts.apache.org/en/option.html#tooltip.show + */ + show?: boolean; + /** + * Whether to show the tooltip floating layer -- see https://echarts.apache.org/en/option.html#tooltip.showContent + */ + showContent?: boolean; + /** + * Delay time for showing tooltip -- see https://echarts.apache.org/en/option.html#tooltip.showDelay + */ + showDelay?: number; + /** + * The source label shown in the tooltip -- for Sankey only + */ + sourceLabel?: string; + /** + * The text style of tooltip's floating layer -- see https://echarts.apache.org/en/option.html#tooltip.textStyle + */ + textStyle?: Object; + /** + * The transition duration of tooltip's animation, in seconds -- see https://echarts.apache.org/en/option.html#tooltip.transitionDuration + */ + transitionDuration?: number; + /** + * Type of triggering -- see https://echarts.apache.org/en/option.html#tooltip.trigger + */ + trigger?: string; + /** + * Conditions to trigger tooltip -- see https://echarts.apache.org/en/option.html#tooltip.triggerOn + */ + triggerOn?: 'mousemove' | 'click' | 'mousemove|click' | 'none'; + /** + * Callback function for formatting the value section in tooltip -- see https://echarts.apache.org/en/option.html#tooltip.valueFormatter + */ + valueFormatter?: string; +} + +/** + * See https://echarts.apache.org/en/option.html + * + * @private Not intended as public API and subject to change + */ +export interface ChartsOptionProps { + /** + * The angle axis in Polar Coordinate -- see https://echarts.apache.org/en/option.html#angleAxis + */ + angleAxis?: AngleAxisOption | AngleAxisOption[]; + /** + * Whether to enable animation -- see https://echarts.apache.org/en/option.html#animation + */ + animation?: boolean; + /** + * Delay before updating the first animation -- see https://echarts.apache.org/en/option.html#animationDelay + */ + animationDelay?: number; + /** + * Delay before updating animation -- see https://echarts.apache.org/en/option.html#animationDelayUpdate + */ + animationDelayUpdate?: number; + /** + * Duration of the first animation -- see https://echarts.apache.org/en/option.html#animationDuration + */ + animationDuration?: number; + /** + * Time for animation to complete -- see https://echarts.apache.org/en/option.html#animationDurationUpdate + */ + animationDurationUpdate?: number; + /** + * Easing method used for the first animation -- see https://echarts.apache.org/en/option.html#animationEasing + */ + animationEasing?: string; + /** + * Easing method used for animation -- see https://echarts.apache.org/en/option.html#animationEasingUpdate + */ + animationEasingUpdate?: string; + /** + * Whether to set graphic number threshold to animation -- see https://echarts.apache.org/en/option.html#animationThreshold + */ + animationThreshold?: number; + /** + * The W3C has developed the WAI-ARIA, the Accessible Rich Internet Applications Suite, which is dedicated to making web content and web applications accessible -- see https://echarts.apache.org/en/option.html#aria + */ + aria?: AriaOption; + /** + * This is the global configurations of axisPointer -- see https://echarts.apache.org/en/option.html#axisPointer + */ + axisPointer?: AxisPointerOption | AxisPointerOption[]; + /** + * Background color - see https://echarts.apache.org/en/option.html#backgroundColor + */ + backgroundColor?: string; + /** + * Sets the type of compositing operation to apply when drawing a new shape -- see https://echarts.apache.org/en/option.html#blendMode + */ + blendMode?: string; + /** + * Brush is an area-selecting component -- see https://echarts.apache.org/en/option.html#brush + */ + brush?: BrushOption | BrushOption[]; + /** + * Calendar coordinates -- see https://echarts.apache.org/en/option.html#calendar + */ + calendar?: CalendarOption | CalendarOption[]; + /** + * The color list of palette -- see https://echarts.apache.org/en/option.html#color + */ + color?: string[]; + /** + * Dataset brings convenience in data management separated with styles and enables data reuse by different series -- see https://echarts.apache.org/en/option.html#dataset + */ + dataset?: DatasetOption | DatasetOption[]; + /** + * Data zoom component is used for zooming a specific area -- see https://echarts.apache.org/en/option.html#dataZoom + */ + dataZoom?: DataZoomComponentOption | DataZoomComponentOption[]; + /** + * ECharts will automatically detect it via backgroundColor by default and adjust the text color accordingly - see https://echarts.apache.org/en/option.html#darkMode + */ + darkMode?: boolean | 'auto'; + /** + * ECharts will automatically detect it via backgroundColor by default and adjust the text color accordingly -- see https://echarts.apache.org/en/option.html#darkMode + */ + /** + * Geographic coordinate system component -- see https://echarts.apache.org/en/option.html#geo + */ + geo?: GeoOption | GeoOption[]; + /** + * Graphic component enables creating graphic elements in ECharts -- see https://echarts.apache.org/en/option.html#graphic + */ + graphic?: GraphicComponentLooseOption | GraphicComponentLooseOption[]; + /** + * Drawing grid in rectangular coordinate -- see https://echarts.apache.org/en/option.html#grid + */ + grid?: GridOption | GridOption[]; + /** + * When the number of element of the whole chart is larger than hoverLayerThreshold, a separate hover layer is used to render hovered elements -- see https://echarts.apache.org/en/option.html#hoverLayerThreshold + */ + hoverLayerThreshold?: number; + /** + * Legend component -- see https://echarts.apache.org/en/option.html#legend + */ + legend?: LegendComponentOption | LegendComponentOption[]; + /** + * See Responsive Mobile-End for details -- see https://echarts.apache.org/en/option.html#media + */ + media?: Object; + /** + * Option array used in timeline -- see https://echarts.apache.org/en/option.html#options + */ + options?: EChartsOption[]; + /** + * Parallel Coordinates is a common way of visualizing high-dimensional geometry and analyzing multivariate data -- see https://echarts.apache.org/en/option.html#parallel + */ + parallel?: ParallelCoordinateSystemOption | ParallelCoordinateSystemOption[]; + /** + * This component is the coordinate axis for parallel coordinate -- see https://echarts.apache.org/en/option.html#parallelAxis + * + * @type ParallelAxisOption | ParallelAxisOption[] + */ + parallelAxis?: Object; + /** + * Polar coordinate can be used in scatter and line chart -- see https://echarts.apache.org/en/option.html#polar + */ + polar?: PolarOption | PolarOption[]; + /** + * Coordinate for radar charts -- see https://echarts.apache.org/en/option.html#radar + */ + radar?: RadarOption | RadarOption[]; + /** + * Radial axis of polar coordinate -- see https://echarts.apache.org/en/option.html#radiusAxis + */ + radiusAxis?: RadiusAxisOption | RadiusAxisOption[]; + /** + * Properties for various chart types -- see https://echarts.apache.org/en/option.html#series + * + * @type SeriesOption | SeriesOption[] + */ + series?: Object; + /** + * An axis with a single dimension -- see https://echarts.apache.org/en/option.html#singleAxis + */ + singleAxis?: SingleAxisOption | SingleAxisOption[]; + /** + * Animation configurations of state switchment -- see https://echarts.apache.org/en/option.html#stateAnimation + */ + stateAnimation?: Object; + /** + * Timeline component -- see https://echarts.apache.org/en/option.html#timeline + * + * @type TimelineOption | SliderTimelineOption + */ + timeline?: TimelineOption | Object; + /** + * Title component, including main title and subtitle -- see https://echarts.apache.org/en/option.html#title + */ + title?: TitleOption | TitleOption[]; + /** + * A group of utility tools -- see https://echarts.apache.org/en/option.html#toolbox + */ + toolbox?: ToolboxComponentOption | ToolboxComponentOption[]; + /** + * Tooltip component -- see https://echarts.apache.org/en/option.html#tooltip + */ + tooltip?: TooltipOptionProps | TooltipOptionProps[]; + /** + * Whether to use UTC in display -- see https://echarts.apache.org/en/option.html#useUTC + */ + useUTC?: boolean; + /** + * Visual map is a type of component for visual encoding -- see https://echarts.apache.org/en/option.html#visualMap + */ + visualMap?: VisualMapComponentOption | VisualMapComponentOption[]; + /** + * The x-axis in cartesian(rectangular) coordinate -- see https://echarts.apache.org/en/option.html#xAxis + */ + xAxis?: XAXisOption | XAXisOption[]; + /** + * The y-axis in cartesian(rectangular) coordinate -- see https://echarts.apache.org/en/option.html#yAxis + */ + yAxis?: YAXisOption | YAXisOption[]; +} + +/** + * This component is based on the Apache ECharts chart library. It provides additional functionality, custom + * components, and theming for PatternFly. This provides a collection of React based components you can use to build + * PatternFly patterns with consistent markup, styling, and behavior. + * + * See https://echarts.apache.org/en/api.html#echarts + * + * @private Not intended as public API and subject to change + * @beta + */ +export interface Charts { + /** + * The className prop specifies a class name that will be applied to outermost element + */ + className?: string; + /** + * Specify height explicitly, in pixels + */ + height?: number; + /** + * The id prop specifies an ID that will be applied to outermost element. + */ + id?: string; + /** + * Flag indicating to use the legend tooltip (default). This may be overridden by the `option.tooltip` property. + */ + isLegendTooltip?: boolean; + /** + * Flag indicating to use the SVG renderer (default). This may be overridden by the `opts.renderer` property. + */ + isSvgRenderer?: boolean; + /** + * This creates a Mutation Observer to watch the given DOM selector. + * + * When the pf-v6-theme-dark selector is added or removed, this component will be notified to update its computed + * theme styles. However, if the dark theme is not updated dynamically (e.g., via a toggle), there is no need to add + * this Mutation Observer. + * + * Note: Don't provide ".pf-v6-theme-dark" as the node selector as it won't exist in the page for light theme. + * The underlying querySelectorAll() function needs to find the element the dark theme selector will be added to. + * + * See https://developer.mozilla.org/en-US/docs/Web/API/Document_Object_Model/Locating_DOM_elements_using_selectors + * + * @propType string + * @example + * @example + * @example + */ + nodeSelector?: string; + /** + * ECharts uses this object to configure its properties; for example, series, title, and tooltip + * + * See https://echarts.apache.org/en/option.html + */ + option?: ChartsOptionProps; + /** + * Optional chart configuration + * + * See https://echarts.apache.org/en/api.html#echarts.init + */ + opts?: EChartsInitOpts; + /** + * The theme prop specifies a theme to use for determining styles and layout properties for a component. Any styles or + * props defined in theme may be overwritten by props specified on the component instance. + * + * See https://echarts.apache.org/handbook/en/concepts/style/#theme + * + * @type ThemeDefinition + */ + theme?: any; + /** + * Specifies the theme color. Valid values are 'blue', 'green', 'multi', etc. + * + * Note: Not compatible with theme prop + * + * @example themeColor={ChartThemeColor.blue} + */ + themeColor?: string; + /** + * Specify width explicitly, in pixels + */ + width?: number; +} diff --git a/packages/react-charts/src/echarts/components/Charts/index.ts b/packages/react-charts/src/echarts/components/Charts/index.ts new file mode 100644 index 00000000000..36eda29c1da --- /dev/null +++ b/packages/react-charts/src/echarts/components/Charts/index.ts @@ -0,0 +1 @@ +export * from './Charts'; diff --git a/packages/react-charts/src/echarts/components/Line/Line.tsx b/packages/react-charts/src/echarts/components/Line/Line.tsx new file mode 100644 index 00000000000..8010ed87caf --- /dev/null +++ b/packages/react-charts/src/echarts/components/Line/Line.tsx @@ -0,0 +1,22 @@ +import defaultsDeep from 'lodash/defaultsDeep'; + +import { ThemeDefinition } from '../themes/Theme'; + +/** + * Returns series properties for Line chart + * + * @param serie + * @param theme + * @param isSkeleton + * @private Not intended as public API and subject to change + */ +export const getLineSeries = (serie: any, theme: ThemeDefinition, isSkeleton: boolean) => { + const defaults = { + emphasis: { + ...(isSkeleton ? { disabled: true } : { focus: 'adjacency' }) + }, + showSymbol: false, + type: 'line' + }; + return defaultsDeep(serie, defaults); +}; diff --git a/packages/react-charts/src/echarts/components/Line/__tests__/Line.test.tsx b/packages/react-charts/src/echarts/components/Line/__tests__/Line.test.tsx new file mode 100644 index 00000000000..a089e491d09 --- /dev/null +++ b/packages/react-charts/src/echarts/components/Line/__tests__/Line.test.tsx @@ -0,0 +1,90 @@ +import { setupJestCanvasMock } from 'jest-canvas-mock'; +import { render, screen } from '@testing-library/react'; +import { Charts } from '../../Charts'; + +import * as echarts from 'echarts/core'; +import { LineChart } from 'echarts/charts'; +import { GridComponent, TitleComponent, TooltipComponent } from 'echarts/components'; +import { SVGRenderer } from 'echarts/renderers'; + +// Register required components +echarts.use([GridComponent, LineChart, SVGRenderer, TitleComponent, TooltipComponent]); + +beforeEach(() => { + jest.resetAllMocks(); + jest.mock('echarts'); + setupJestCanvasMock(); +}); + +const props: any = { + height: 400, + id: 'line-chart', + option: { + xAxis: { + type: 'category', + data: ['2015', '2016', '2017', '2018'] + }, + yAxis: { + axisLabel: { + formatter: (value) => (value !== 0 ? `${value}` : '') + }, + splitNumber: 3, + type: 'value' + }, + series: [ + { + data: [1, 2, 5, 3], + name: 'Cats', + type: 'line' + }, + { + data: [2, 1, 7, 4], + name: 'Dogs', + lineStyle: { + type: 'dashed' + }, + type: 'line' + }, + { + data: [3, 4, 9, 5], + name: 'Birds', + type: 'line' + }, + { + data: [3, 3, 8, 7], + name: 'Mice', + type: 'line' + } + ], + title: { + text: 'This is a Line chart' + } + }, + width: 800 +}; + +// Remove dynamic _echarts_instance_ ID +const removeInstanceID = (fragment) => { + fragment.getElementById('line-chart').removeAttribute('_echarts_instance_'); + return fragment; +}; + +test('renders component', () => { + const { asFragment } = render(); + expect(removeInstanceID(asFragment())).toMatchSnapshot(); +}); + +test('renders title', async () => { + render(); + + const title = await screen.findByText(props.option.title.text); + expect(title).toMatchSnapshot(); +}); + +test('renders height and width', async () => { + const { asFragment } = render(); + + const svg = asFragment().querySelector('svg'); + expect(svg).toHaveAttribute('height', `${props.height}`); + expect(svg).toHaveAttribute('width', `${props.width}`); +}); 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 new file mode 100644 index 00000000000..336a0e0cd73 --- /dev/null +++ b/packages/react-charts/src/echarts/components/Line/__tests__/__snapshots__/Line.test.tsx.snap @@ -0,0 +1,268 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`renders component 1`] = ` + +
+
+ + + + + + + + + + + + + + + + + + + + + 2015 + + + 2016 + + + 2017 + + + 2018 + + + + + + + + + + + + + + + + This is a Line chart + + + + + + + + + + + + + + + + + +
+
+
+ +`; + +exports[`renders title 1`] = ` + + This is a Line chart + +`; diff --git a/packages/react-charts/src/echarts/components/Line/examples/Basic.tsx b/packages/react-charts/src/echarts/components/Line/examples/Basic.tsx new file mode 100644 index 00000000000..22c5eef7997 --- /dev/null +++ b/packages/react-charts/src/echarts/components/Line/examples/Basic.tsx @@ -0,0 +1,69 @@ +import { FunctionComponent } from 'react'; +import { Charts } from '@patternfly/react-charts/echarts'; + +import * as echarts from 'echarts/core'; +import { LineChart } from 'echarts/charts'; +import { GridComponent, TitleComponent, TooltipComponent } from 'echarts/components'; +import { SVGRenderer } from 'echarts/renderers'; + +// Register required components +echarts.use([GridComponent, LineChart, SVGRenderer, TitleComponent, TooltipComponent]); + +export const Basic: FunctionComponent = () => ( + (value !== 0 ? `${value}` : '') + }, + splitNumber: 3, + type: 'value' + }, + series: [ + { + data: [1, 2, 5, 3], + name: 'Cats', + type: 'line' + }, + { + data: [2, 1, 7, 4], + name: 'Dogs', + lineStyle: { + type: 'dashed' + }, + type: 'line' + }, + { + data: [3, 4, 9, 5], + name: 'Birds', + type: 'line' + }, + { + data: [3, 3, 8, 7], + name: 'Mice', + type: 'line' + } + ], + title: { + left: 'center', + text: 'This is a Line chart' + } + }} + width={825} + /> +); diff --git a/packages/react-charts/src/echarts/components/Line/examples/Responsive.tsx b/packages/react-charts/src/echarts/components/Line/examples/Responsive.tsx new file mode 100644 index 00000000000..7905aa65a0c --- /dev/null +++ b/packages/react-charts/src/echarts/components/Line/examples/Responsive.tsx @@ -0,0 +1,88 @@ +import { FunctionComponent, useEffect, useRef, useState } from 'react'; +import { Charts, ThemeColor } from '@patternfly/react-charts/echarts'; +import { getResizeObserver } from '@patternfly/react-core'; + +import * as echarts from 'echarts/core'; +import { LineChart } from 'echarts/charts'; +import { GridComponent, TitleComponent, TooltipComponent } from 'echarts/components'; +import { SVGRenderer } from 'echarts/renderers'; + +// Register required components +echarts.use([GridComponent, LineChart, SVGRenderer, TitleComponent, TooltipComponent]); + +export const Responsive: FunctionComponent = () => { + const containerRef = useRef(); + const [width, setWidth] = useState(0); + + useEffect(() => { + const handleResize = () => { + if (containerRef.current && containerRef.current.clientWidth) { + setWidth(containerRef.current.clientWidth); + } + }; + let observer = () => {}; + observer = getResizeObserver(containerRef.current, handleResize); + + return () => { + observer(); + }; + }, [containerRef, width]); + + return ( +
+ (value !== 0 ? `${value}` : '') + }, + splitNumber: 3, + type: 'value' + }, + series: [ + { + data: [1, 2, 5, 3], + name: 'Cats', + type: 'line' + }, + { + data: [2, 1, 7, 4], + name: 'Dogs', + lineStyle: { + type: 'dashed' + }, + type: 'line' + }, + { + data: [3, 4, 9, 5], + name: 'Birds', + type: 'line' + }, + { + data: [3, 3, 8, 7], + name: 'Mice', + type: 'line' + } + ], + title: { + left: 'center', + text: 'This is a Line chart', + type: 'line' + } + }} + themeColor={ThemeColor.green} + width={width} + /> +
+ ); +}; diff --git a/packages/react-charts/src/echarts/components/Line/examples/Skeleton.tsx b/packages/react-charts/src/echarts/components/Line/examples/Skeleton.tsx new file mode 100644 index 00000000000..f41a82d6ae7 --- /dev/null +++ b/packages/react-charts/src/echarts/components/Line/examples/Skeleton.tsx @@ -0,0 +1,75 @@ +import { FormEvent, FunctionComponent, useState } from 'react'; +import { Charts, ThemeColor } from '@patternfly/react-charts/echarts'; +import { Switch } from '@patternfly/react-core'; + +import * as echarts from 'echarts/core'; +import { LineChart } from 'echarts/charts'; +import { GridComponent, TitleComponent, TooltipComponent } from 'echarts/components'; +import { SVGRenderer } from 'echarts/renderers'; + +// Register required components +echarts.use([GridComponent, LineChart, SVGRenderer, TitleComponent, TooltipComponent]); + +export const Skeleton: FunctionComponent = () => { + const [isChecked, setIsChecked] = useState(true); + + const handleChange = (_event: FormEvent, checked: boolean) => { + setIsChecked(checked); + }; + + return ( + <> + + + + ); +}; diff --git a/packages/react-charts/src/echarts/components/Line/examples/Theme.tsx b/packages/react-charts/src/echarts/components/Line/examples/Theme.tsx new file mode 100644 index 00000000000..3b3225f5530 --- /dev/null +++ b/packages/react-charts/src/echarts/components/Line/examples/Theme.tsx @@ -0,0 +1,92 @@ +import { FunctionComponent } from 'react'; +import { getComputedStyleValue, getCustomTheme, Charts, ThemeColor } from '@patternfly/react-charts/echarts'; + +import * as echarts from 'echarts/core'; +import { LineChart } from 'echarts/charts'; +import { GridComponent, TitleComponent, TooltipComponent } from 'echarts/components'; +import { SVGRenderer } from 'echarts/renderers'; + +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_purple_300 from '@patternfly/react-tokens/dist/esm/chart_color_purple_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'; + +// Register required components +echarts.use([GridComponent, LineChart, SVGRenderer, TitleComponent, TooltipComponent]); + +export const Theme: FunctionComponent = () => { + const myCustomTheme = getCustomTheme(ThemeColor.default, { + color: [ + getComputedStyleValue(chart_color_purple_300), + getComputedStyleValue(chart_color_blue_300), + getComputedStyleValue(chart_color_green_300), + getComputedStyleValue(chart_color_teal_300), + getComputedStyleValue(chart_color_yellow_300) + ] + }); + + return ( + (value !== 0 ? `${value}` : '') + }, + splitNumber: 3, + type: 'value' + }, + series: [ + { + data: [1, 2, 5, 3], + name: 'Cats', + symbol: 'rect', + type: 'line' + }, + { + data: [2, 1, 7, 4], + name: 'Dogs', + lineStyle: { + type: 'dashed' + }, + symbol: 'arrow', + type: 'line' + }, + { + data: [3, 4, 9, 5], + name: 'Birds', + symbol: 'circle', + type: 'line' + }, + { + data: [3, 3, 8, 7], + name: 'Mice', + symbol: 'emptyCircle', + type: 'line' + } + ], + title: { + left: 'center', + text: 'This is a Line chart' + } + }} + theme={myCustomTheme} + width={825} + /> + ); +}; diff --git a/packages/react-charts/src/echarts/components/Line/examples/index.md b/packages/react-charts/src/echarts/components/Line/examples/index.md new file mode 100644 index 00000000000..c440cf73d37 --- /dev/null +++ b/packages/react-charts/src/echarts/components/Line/examples/index.md @@ -0,0 +1,62 @@ +--- +id: Line chart +section: components +subsection: charts +propComponents: [ + { + component: 'Charts', + source: 'ECharts-docs' + }, + { + component: 'ChartsOptionProps', + source: 'ECharts-docs' + }, + { + component: 'TooltipOptionProps', + source: 'ECharts-docs' + } +] +beta: true +--- +import { FunctionComponent, useEffect, useRef, useState } from 'react'; +import * as echarts from 'echarts'; +import { LineChart } from 'echarts/charts'; +import { GridComponent, TitleComponent, ToolboxComponent, TooltipComponent } from 'echarts/components'; +import { SVGRenderer } from 'echarts/renderers'; +import { getComputedStyleValue, getCustomTheme, Charts, ThemeColor } from '@patternfly/react-charts/echarts'; + +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_purple_300 from '@patternfly/react-tokens/dist/esm/chart_color_purple_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'; + +## Introduction +Note: PatternFly React charts live in its own package at [@patternfly/react-charts](https://www.npmjs.com/package/@patternfly/react-charts)! + +The examples below are based on the [Apache ECharts](https://echarts.apache.org/) chart library, along with additional functionality, custom components, and theming for PatternFly. This provides a collection of React based components you can use to build PatternFly patterns with consistent markup, styling, and behavior. + +## Examples +### Basic with right aligned legend + +```ts file="./Basic.tsx" + +``` + +### Green with responsive container and bottom aligned legend +```ts file="./Responsive.tsx" + +``` + +### Custom theme +This demonstrates how to create a color scale via a custom theme, which may be applied to multiple charts. + +```ts file="./Theme.tsx" + +``` + +### Skeleton + +```ts file="./Skeleton.tsx" + +``` diff --git a/packages/react-charts/src/echarts/components/Line/index.ts b/packages/react-charts/src/echarts/components/Line/index.ts new file mode 100644 index 00000000000..34a969a3d62 --- /dev/null +++ b/packages/react-charts/src/echarts/components/Line/index.ts @@ -0,0 +1 @@ +export * from './Line'; diff --git a/packages/react-charts/src/echarts/components/Sankey/Sankey.tsx b/packages/react-charts/src/echarts/components/Sankey/Sankey.tsx new file mode 100644 index 00000000000..5fd03095354 --- /dev/null +++ b/packages/react-charts/src/echarts/components/Sankey/Sankey.tsx @@ -0,0 +1,32 @@ +import defaultsDeep from 'lodash/defaultsDeep'; + +import { ThemeDefinition } from '../themes/Theme'; + +/** + * Returns series properties for Sankey chart + * + * @param serie + * @param theme + * @param isSkeleton + * @private Not intended as public API and subject to change + */ +export const getSankeySeries = (serie: any, theme: ThemeDefinition, isSkeleton: boolean) => { + const defaults = { + data: serie.data.map((datum: any, index: number) => ({ + itemStyle: { + color: theme?.color[index % theme?.color.length] + } + })), + ...(isSkeleton ? { draggable: false } : {}), + emphasis: { + ...(isSkeleton ? { disabled: true } : { focus: 'adjacency' }) + }, + layout: 'none', + lineStyle: { + color: 'source', + opacity: 0.6 + }, + type: 'sankey' + }; + return defaultsDeep(serie, defaults); +}; diff --git a/packages/react-charts/src/echarts/components/Sankey/__tests__/Sankey.test.tsx b/packages/react-charts/src/echarts/components/Sankey/__tests__/Sankey.test.tsx new file mode 100644 index 00000000000..a0910906a2f --- /dev/null +++ b/packages/react-charts/src/echarts/components/Sankey/__tests__/Sankey.test.tsx @@ -0,0 +1,109 @@ +import { setupJestCanvasMock } from 'jest-canvas-mock'; +import { render, screen } from '@testing-library/react'; +import { Charts } from '../../Charts'; + +import * as echarts from 'echarts/core'; +import { SankeyChart } from 'echarts/charts'; +import { TitleComponent, TooltipComponent } from 'echarts/components'; +import { SVGRenderer } from 'echarts/renderers'; + +// Register required components +echarts.use([SankeyChart, SVGRenderer, TitleComponent, TooltipComponent]); + +beforeEach(() => { + jest.resetAllMocks(); + jest.mock('echarts'); + setupJestCanvasMock(); +}); + +const data = [ + { + name: 'a' + }, + { + name: 'b' + }, + { + name: 'a1' + }, + { + name: 'a2' + }, + { + name: 'b1' + }, + { + name: 'c' + } +]; + +const links = [ + { + source: 'a', + target: 'a1', + value: 5 + }, + { + source: 'a', + target: 'a2', + value: 3 + }, + { + source: 'b', + target: 'b1', + value: 8 + }, + { + source: 'a', + target: 'b1', + value: 3 + }, + { + source: 'b1', + target: 'a1', + value: 1 + }, + { + source: 'b1', + target: 'c', + value: 2 + } +]; + +const props: any = { + height: 400, + id: 'sankey-chart', + option: { + series: [{ data, links, type: 'sankey' }], + title: { + text: 'This is a Sankey chart' + } + }, + width: 800 +}; + +// Remove dynamic _echarts_instance_ ID +const removeInstanceID = (fragment) => { + fragment.getElementById('sankey-chart').removeAttribute('_echarts_instance_'); + return fragment; +}; + +test('renders component', () => { + const { asFragment } = render(); + expect(removeInstanceID(asFragment())).toMatchSnapshot(); +}); + +test('renders title', async () => { + render(); + + const title = await screen.findByText(props.option.title.text); + expect(title).toMatchSnapshot(); +}); + +test('renders height and width', async () => { + const { asFragment } = render(); + + const svg = asFragment().querySelector('svg'); + expect(svg).toHaveAttribute('height', `${props.height}`); + expect(svg).toHaveAttribute('width', `${props.width}`); +}); 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 new file mode 100644 index 00000000000..7cf03d7d4a6 --- /dev/null +++ b/packages/react-charts/src/echarts/components/Sankey/__tests__/__snapshots__/Sankey.test.tsx.snap @@ -0,0 +1,218 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`renders component 1`] = ` + +
+
+ + + + + + + + + + + + + + + + + + a + + + b + + + a1 + + + a2 + + + b1 + + + c + + + + + This is a Sankey chart + + + + + + + + +
+
+
+ +`; + +exports[`renders title 1`] = ` + + This is a Sankey chart + +`; diff --git a/packages/react-charts/src/echarts/components/Sankey/examples/Basic.tsx b/packages/react-charts/src/echarts/components/Sankey/examples/Basic.tsx new file mode 100644 index 00000000000..f970a3b137f --- /dev/null +++ b/packages/react-charts/src/echarts/components/Sankey/examples/Basic.tsx @@ -0,0 +1,87 @@ +import { FunctionComponent } from 'react'; +import { Charts } from '@patternfly/react-charts/echarts'; + +import * as echarts from 'echarts/core'; +import { SankeyChart } from 'echarts/charts'; +import { TitleComponent, TooltipComponent } from 'echarts/components'; +import { SVGRenderer } from 'echarts/renderers'; + +// Register required components +echarts.use([SankeyChart, SVGRenderer, TitleComponent, TooltipComponent]); + +export const Basic: FunctionComponent = () => { + const data = [ + { + name: 'a' + }, + { + name: 'b' + }, + { + name: 'a1' + }, + { + name: 'a2' + }, + { + name: 'b1' + }, + { + name: 'c' + } + ]; + + const links = [ + { + source: 'a', + target: 'a1', + value: 5 + }, + { + source: 'a', + target: 'a2', + value: 3 + }, + { + source: 'b', + target: 'b1', + value: 8 + }, + { + source: 'a', + target: 'b1', + value: 3 + }, + { + source: 'b1', + target: 'a1', + value: 1 + }, + { + source: 'b1', + target: 'c', + value: 2 + } + ]; + + return ( + `${value} GiB` + } + }} + width={825} + /> + ); +}; diff --git a/packages/react-charts/src/echarts/components/Sankey/examples/Responsive.tsx b/packages/react-charts/src/echarts/components/Sankey/examples/Responsive.tsx new file mode 100644 index 00000000000..778cc25cca1 --- /dev/null +++ b/packages/react-charts/src/echarts/components/Sankey/examples/Responsive.tsx @@ -0,0 +1,108 @@ +import { FunctionComponent, useEffect, useRef, useState } from 'react'; +import { Charts, ThemeColor } from '@patternfly/react-charts/echarts'; +import { getResizeObserver } from '@patternfly/react-core'; + +import * as echarts from 'echarts/core'; +import { SankeyChart } from 'echarts/charts'; +import { TitleComponent, TooltipComponent } from 'echarts/components'; +import { SVGRenderer } from 'echarts/renderers'; + +// Register required components +echarts.use([SankeyChart, SVGRenderer, TitleComponent, TooltipComponent]); + +export const Responsive: FunctionComponent = () => { + const data = [ + { + name: 'a' + }, + { + name: 'b' + }, + { + name: 'a1' + }, + { + name: 'a2' + }, + { + name: 'b1' + }, + { + name: 'c' + } + ]; + + const links = [ + { + source: 'a', + target: 'a1', + value: 5 + }, + { + source: 'a', + target: 'a2', + value: 3 + }, + { + source: 'b', + target: 'b1', + value: 8 + }, + { + source: 'a', + target: 'b1', + value: 3 + }, + { + source: 'b1', + target: 'a1', + value: 1 + }, + { + source: 'b1', + target: 'c', + value: 2 + } + ]; + + const containerRef = useRef(); + const [width, setWidth] = useState(0); + + useEffect(() => { + const handleResize = () => { + if (containerRef.current && containerRef.current.clientWidth) { + setWidth(containerRef.current.clientWidth); + } + }; + let observer = () => {}; + observer = getResizeObserver(containerRef.current, handleResize); + + return () => { + observer(); + }; + }, [containerRef, width]); + + return ( +
+ `${value} GiB` + } + }} + themeColor={ThemeColor.multiUnordered} + width={width} + /> +
+ ); +}; diff --git a/packages/react-charts/src/echarts/components/Sankey/examples/Skeleton.tsx b/packages/react-charts/src/echarts/components/Sankey/examples/Skeleton.tsx new file mode 100644 index 00000000000..ef0b126c05f --- /dev/null +++ b/packages/react-charts/src/echarts/components/Sankey/examples/Skeleton.tsx @@ -0,0 +1,98 @@ +import { FormEvent, FunctionComponent, useState } from 'react'; +import { Charts, ThemeColor } from '@patternfly/react-charts/echarts'; +import { Switch } from '@patternfly/react-core'; + +import * as echarts from 'echarts/core'; +import { SankeyChart } from 'echarts/charts'; +import { TitleComponent, TooltipComponent } from 'echarts/components'; +import { SVGRenderer } from 'echarts/renderers'; + +// Register required components +echarts.use([SankeyChart, SVGRenderer, TitleComponent, TooltipComponent]); + +export const Skeleton: FunctionComponent = () => { + const [isChecked, setIsChecked] = useState(true); + + const handleChange = (_event: FormEvent, checked: boolean) => { + setIsChecked(checked); + }; + + const data = [ + { + name: 'a' + }, + { + name: 'b' + }, + { + name: 'a1' + }, + { + name: 'a2' + }, + { + name: 'b1' + }, + { + name: 'c' + } + ]; + + const links = [ + { + source: 'a', + target: 'a1', + value: 5 + }, + { + source: 'a', + target: 'a2', + value: 3 + }, + { + source: 'b', + target: 'b1', + value: 8 + }, + { + source: 'a', + target: 'b1', + value: 3 + }, + { + source: 'b1', + target: 'a1', + value: 1 + }, + { + source: 'b1', + target: 'c', + value: 2 + } + ]; + + return ( + <> + + `${value} GiB` + } + }} + themeColor={isChecked ? ThemeColor.skeleton : ThemeColor.green} + width={825} + /> + + ); +}; diff --git a/packages/react-charts/src/echarts/components/Sankey/examples/Theme.tsx b/packages/react-charts/src/echarts/components/Sankey/examples/Theme.tsx new file mode 100644 index 00000000000..3f2963ae149 --- /dev/null +++ b/packages/react-charts/src/echarts/components/Sankey/examples/Theme.tsx @@ -0,0 +1,104 @@ +import { FunctionComponent } from 'react'; +import { getComputedStyleValue, getCustomTheme, Charts, ThemeColor } from '@patternfly/react-charts/echarts'; + +import * as echarts from 'echarts/core'; +import { SankeyChart } from 'echarts/charts'; +import { TitleComponent, TooltipComponent } from 'echarts/components'; +import { SVGRenderer } from 'echarts/renderers'; + +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_purple_300 from '@patternfly/react-tokens/dist/esm/chart_color_purple_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'; + +// Register required components +echarts.use([SankeyChart, SVGRenderer, TitleComponent, TooltipComponent]); + +export const Theme: FunctionComponent = () => { + const data = [ + { + name: 'a' + }, + { + name: 'b' + }, + { + name: 'a1' + }, + { + name: 'a2' + }, + { + name: 'b1' + }, + { + name: 'c' + } + ]; + + const links = [ + { + source: 'a', + target: 'a1', + value: 5 + }, + { + source: 'a', + target: 'a2', + value: 3 + }, + { + source: 'b', + target: 'b1', + value: 8 + }, + { + source: 'a', + target: 'b1', + value: 3 + }, + { + source: 'b1', + target: 'a1', + value: 1 + }, + { + source: 'b1', + target: 'c', + value: 2 + } + ]; + + const myCustomTheme = getCustomTheme(ThemeColor.default, { + color: [ + getComputedStyleValue(chart_color_purple_300), + getComputedStyleValue(chart_color_blue_300), + getComputedStyleValue(chart_color_green_300), + getComputedStyleValue(chart_color_teal_300), + getComputedStyleValue(chart_color_yellow_300) + ] + }); + + return ( + `${value} GiB` + } + }} + theme={myCustomTheme} + width={825} + /> + ); +}; diff --git a/packages/react-charts/src/echarts/components/Sankey/examples/Toolbox.tsx b/packages/react-charts/src/echarts/components/Sankey/examples/Toolbox.tsx new file mode 100644 index 00000000000..73453276ba6 --- /dev/null +++ b/packages/react-charts/src/echarts/components/Sankey/examples/Toolbox.tsx @@ -0,0 +1,117 @@ +import { FunctionComponent, useEffect, useRef, useState } from 'react'; +import { Charts, ThemeColor } from '@patternfly/react-charts/echarts'; +import { getResizeObserver } from '@patternfly/react-core'; + +import * as echarts from 'echarts/core'; +import { SankeyChart } from 'echarts/charts'; +import { TitleComponent, ToolboxComponent, TooltipComponent } from 'echarts/components'; +import { SVGRenderer } from 'echarts/renderers'; + +// Register required components +echarts.use([SankeyChart, SVGRenderer, TitleComponent, ToolboxComponent, TooltipComponent]); + +export const Toolbox: FunctionComponent = () => { + const data = [ + { + name: 'a' + }, + { + name: 'b' + }, + { + name: 'a1' + }, + { + name: 'a2' + }, + { + name: 'b1' + }, + { + name: 'c' + } + ]; + + const links = [ + { + source: 'a', + target: 'a1', + value: 5 + }, + { + source: 'a', + target: 'a2', + value: 3 + }, + { + source: 'b', + target: 'b1', + value: 8 + }, + { + source: 'a', + target: 'b1', + value: 3 + }, + { + source: 'b1', + target: 'a1', + value: 1 + }, + { + source: 'b1', + target: 'c', + value: 2 + } + ]; + + // let observer = () => {}; + const containerRef = useRef(); + const [width, setWidth] = useState(0); + + useEffect(() => { + const handleResize = () => { + if (containerRef.current && containerRef.current.clientWidth) { + setWidth(containerRef.current.clientWidth); + } + }; + let observer = () => {}; + observer = getResizeObserver(containerRef.current, handleResize); + + return () => { + observer(); + }; + }, [containerRef, width]); + + return ( +
+ `${value} GiB` + } + }} + themeColor={ThemeColor.teal} + width={width} + /> +
+ ); +}; diff --git a/packages/react-charts/src/echarts/components/Sankey/examples/index.md b/packages/react-charts/src/echarts/components/Sankey/examples/index.md new file mode 100644 index 00000000000..26670100e7f --- /dev/null +++ b/packages/react-charts/src/echarts/components/Sankey/examples/index.md @@ -0,0 +1,72 @@ +--- +id: Sankey chart +section: components +subsection: charts +propComponents: [ + { + component: 'Charts', + source: 'ECharts-docs' + }, + { + component: 'ChartsOptionProps', + source: 'ECharts-docs' + }, + { + component: 'TooltipOptionProps', + source: 'ECharts-docs' + } +] +beta: true +--- + +import { FunctionComponent, useEffect, useRef, useState } from 'react'; +import * as echarts from 'echarts'; +import { SankeyChart } from 'echarts/charts'; +import { TitleComponent, ToolboxComponent, TooltipComponent } from 'echarts/components'; +import { SVGRenderer } from 'echarts/renderers'; +import { getComputedStyleValue, getCustomTheme, Charts, ThemeColor } from '@patternfly/react-charts/echarts'; + +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_purple_300 from '@patternfly/react-tokens/dist/esm/chart_color_purple_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'; + +## Introduction +Note: PatternFly React charts live in its own package at [@patternfly/react-charts](https://www.npmjs.com/package/@patternfly/react-charts)! + +The examples below are based on the [Apache ECharts](https://echarts.apache.org/) chart library, along with additional functionality, custom components, and theming for PatternFly. This provides a collection of React based components you can use to build PatternFly patterns with consistent markup, styling, and behavior. + +## Examples +### Basic + +```ts file="./Basic.tsx" + +``` + +### Multi-color (unordered) with responsive container + +```ts file="./Responsive.tsx" + +``` + +### Teal color with responsive container and toolbox + +This demonstrates how to import `ToolboxComponent` for use with ECharts + +```ts file="./Toolbox.tsx" + +``` + +### Custom theme +This demonstrates how to create a color scale via a custom theme, which may be applied to multiple charts. + +```ts file="./Theme.tsx" + +``` + +### Skeleton + +```ts file="./Skeleton.tsx" + +``` diff --git a/packages/react-charts/src/echarts/components/Sankey/index.ts b/packages/react-charts/src/echarts/components/Sankey/index.ts new file mode 100644 index 00000000000..4bb44aaee6a --- /dev/null +++ b/packages/react-charts/src/echarts/components/Sankey/index.ts @@ -0,0 +1 @@ +export * from './Sankey'; diff --git a/packages/react-charts/src/echarts/components/index.ts b/packages/react-charts/src/echarts/components/index.ts new file mode 100644 index 00000000000..45429a5ccd4 --- /dev/null +++ b/packages/react-charts/src/echarts/components/index.ts @@ -0,0 +1,4 @@ +export * from './Charts'; +export * from './themes/ThemeColor'; +export { getCustomTheme, getTheme } from './utils/theme'; +export { getComputedStyleValue } from './utils/styles'; diff --git a/packages/react-charts/src/echarts/components/themes/Theme.ts b/packages/react-charts/src/echarts/components/themes/Theme.ts new file mode 100644 index 00000000000..07e6787b6c4 --- /dev/null +++ b/packages/react-charts/src/echarts/components/themes/Theme.ts @@ -0,0 +1,15 @@ +import { ThemeOption } from 'echarts/types/src/util/types'; + +/** + * Theme definition interface + * + * @public + */ +export interface ThemeDefinitionInterface extends ThemeOption {} + +/** + * Theme definition type + * + * @public + */ +export type ThemeDefinition = ThemeDefinitionInterface; diff --git a/packages/react-charts/src/echarts/components/themes/ThemeColor.ts b/packages/react-charts/src/echarts/components/themes/ThemeColor.ts new file mode 100644 index 00000000000..15cb8830f2b --- /dev/null +++ b/packages/react-charts/src/echarts/components/themes/ThemeColor.ts @@ -0,0 +1,55 @@ +interface ThemeColorInterface { + blue: string; + teal: string; + default: string; + yellow: string; + gray: string; + green: string; + multi: string; + multiOrdered: string; + multiUnordered: string; + orange: string; + purple: string; + skeleton: string; +} + +/** + * The color family to be applied to a theme. For example, 'blue' represents an ordered list of colors + * (i.e., a color scale) composed of the blue color family defined by PatternFly core. + * + * For example, the 'blue' color scale looks like: + * + * chart_color_blue_100 + * chart_color_blue_200 + * chart_color_blue_300 + * chart_color_blue_400 + * chart_color_blue_500 + * + * In this case, the chart_color_blue_100 value would be applied to the first data point in a chart. + * The chart_color_blue_200 value would be applied to the second data point in a chart. And so on... + * + * If legend data is provided to a chart, those colors would be synced with the legend as well. + * + * The 'multiOrdered' color family is intended for ordered charts; donut, pie, bar, & stack + * The 'multiUnordered' color family is intended for unordered charts; area & line + * The 'multi' defaults to the 'multiOrdered' color family + * + * Note: These values are not intended to be applied directly as a component's fill style. For example, "multi" would + * not be a valid fill color. Please use chart variables from PatternFly core (e.g., via the react-charts package) + * + * @public + */ +export const ThemeColor: ThemeColorInterface = { + blue: 'blue', + teal: 'teal', + default: 'blue', + yellow: 'yellow', + gray: 'gray', + green: 'green', + multi: 'multi', + multiOrdered: 'multi-ordered', + multiUnordered: 'multi-unordered', + orange: 'orange', + purple: 'purple', + skeleton: 'skeleton' +}; diff --git a/packages/react-charts/src/echarts/components/themes/base-theme.ts b/packages/react-charts/src/echarts/components/themes/base-theme.ts new file mode 100644 index 00000000000..d69479efbb5 --- /dev/null +++ b/packages/react-charts/src/echarts/components/themes/base-theme.ts @@ -0,0 +1,252 @@ +import chart_echarts_bar_item_style_BarBorderWidth from '@patternfly/react-tokens/dist/esm/chart_echarts_bar_item_style_BarBorderColor'; +import chart_echarts_boxplot_item_style_BorderWidth from '@patternfly/react-tokens/dist/esm/chart_echarts_boxplot_item_style_BorderWidth'; +import chart_echarts_candlestick_item_style_BorderWidth from '@patternfly/react-tokens/dist/esm/chart_echarts_candlestick_item_style_BorderWidth'; +import chart_echarts_datazoom_HandleSize from '@patternfly/react-tokens/dist/esm/chart_echarts_datazoom_HandleSize'; +import chart_echarts_funnel_item_style_BorderWidth from '@patternfly/react-tokens/dist/esm/chart_echarts_funnel_item_style_BorderWidth'; +import chart_echarts_gauge_item_style_BorderWidth from '@patternfly/react-tokens/dist/esm/chart_echarts_gauge_item_style_BorderWidth'; +import chart_echarts_geo_emphasis_item_style_BorderWidth from '@patternfly/react-tokens/dist/esm/chart_echarts_gauge_item_style_BorderWidth'; +import chart_echarts_geo_item_style_BorderWidth from '@patternfly/react-tokens/dist/esm/chart_echarts_gauge_item_style_BorderWidth'; +import chart_echarts_global_axis_BoundaryGap from '@patternfly/react-tokens/dist/esm/chart_echarts_global_axis_BoundaryGap'; +import chart_echarts_global_axis_axis_label_Show from '@patternfly/react-tokens/dist/esm/chart_echarts_global_axis_axis_label_Show'; +import chart_echarts_global_axis_axis_line_Show from '@patternfly/react-tokens/dist/esm/chart_echarts_global_axis_axis_line_Show'; +import chart_echarts_global_axis_axis_tick_Show from '@patternfly/react-tokens/dist/esm/chart_echarts_global_axis_axis_tick_Show'; +import chart_echarts_global_axis_split_area_Show from '@patternfly/react-tokens/dist/esm/chart_echarts_global_axis_split_area_Show'; +import chart_echarts_global_axis_split_line_Show from '@patternfly/react-tokens/dist/esm/chart_echarts_global_axis_split_line_Show'; +import chart_echarts_graph_item_style_BorderWidth from '@patternfly/react-tokens/dist/esm/chart_echarts_graph_item_style_BorderWidth'; +import chart_echarts_graph_line_style_BorderWidth from '@patternfly/react-tokens/dist/esm/chart_echarts_graph_line_style_BorderWidth'; +import chart_echarts_graph_Smooth from '@patternfly/react-tokens/dist/esm/chart_echarts_graph_Smooth'; +import chart_echarts_graph_Symbol from '@patternfly/react-tokens/dist/esm/chart_echarts_graph_Symbol'; +import chart_echarts_graph_SymbolSize from '@patternfly/react-tokens/dist/esm/chart_echarts_graph_SymbolSize'; +import chart_echarts_line_item_style_BorderWidth from '@patternfly/react-tokens/dist/esm/chart_echarts_line_item_style_BorderWidth'; +import chart_echarts_line_line_style_BorderWidth from '@patternfly/react-tokens/dist/esm/chart_echarts_line_line_style_BorderWidth'; +import chart_echarts_line_Smooth from '@patternfly/react-tokens/dist/esm/chart_echarts_line_Smooth'; +import chart_echarts_line_Symbol from '@patternfly/react-tokens/dist/esm/chart_echarts_line_Symbol'; +import chart_echarts_line_SymbolSize from '@patternfly/react-tokens/dist/esm/chart_echarts_line_SymbolSize'; +import chart_echarts_map_emphasis_item_style_BorderWidth from '@patternfly/react-tokens/dist/esm/chart_echarts_map_emphasis_item_style_BorderWidth'; +import chart_echarts_map_item_style_BorderWidth from '@patternfly/react-tokens/dist/esm/chart_echarts_map_item_style_BorderWidth'; +import chart_echarts_parallel_item_style_BorderWidth from '@patternfly/react-tokens/dist/esm/chart_echarts_parallel_item_style_BorderWidth'; +import chart_echarts_pie_item_style_BorderWidth from '@patternfly/react-tokens/dist/esm/chart_echarts_pie_item_style_BorderWidth'; +import chart_echarts_radar_item_style_BorderWidth from '@patternfly/react-tokens/dist/esm/chart_echarts_radar_item_style_BorderWidth'; +import chart_echarts_radar_line_style_BorderWidth from '@patternfly/react-tokens/dist/esm/chart_echarts_radar_line_style_BorderWidth'; +import chart_echarts_radar_Smooth from '@patternfly/react-tokens/dist/esm/chart_echarts_radar_Smooth'; +import chart_echarts_radar_Symbol from '@patternfly/react-tokens/dist/esm/chart_echarts_radar_Symbol'; +import chart_echarts_radar_SymbolSize from '@patternfly/react-tokens/dist/esm/chart_echarts_radar_SymbolSize'; +import chart_echarts_sankey_item_style_BorderWidth from '@patternfly/react-tokens/dist/esm/chart_echarts_sankey_item_style_BorderWidth'; +import chart_echarts_scatter_item_style_BorderWidth from '@patternfly/react-tokens/dist/esm/chart_echarts_scatter_item_style_BorderWidth'; +import chart_echarts_timeline_control_style_BorderWidth from '@patternfly/react-tokens/dist/esm/chart_echarts_timeline_control_style_BorderWidth'; +import chart_echarts_timeline_emphasis_control_style_BorderWidth from '@patternfly/react-tokens/dist/esm/chart_echarts_timeline_emphasis_control_style_BorderWidth'; +import chart_echarts_timeline_item_style_BorderWidth from '@patternfly/react-tokens/dist/esm/chart_echarts_timeline_item_style_BorderWidth'; +import chart_echarts_timeline_line_style_Width from '@patternfly/react-tokens/dist/esm/chart_echarts_timeline_line_style_Width'; +import chart_echarts_tooltip_axis_pointer_cross_style_Width from '@patternfly/react-tokens/dist/esm/chart_echarts_tooltip_axis_pointer_cross_style_Width'; +import chart_echarts_tooltip_axis_pointer_line_style_Width from '@patternfly/react-tokens/dist/esm/chart_echarts_tooltip_axis_pointer_line_style_Width'; +import chart_global_FontFamily from '@patternfly/react-tokens/dist/esm/chart_global_FontFamily'; +import chart_global_FontSize_sm from '@patternfly/react-tokens/dist/esm/chart_global_FontSize_sm'; + +import { ThemeDefinition } from './Theme'; +import { getComputedStyleValue } from '../utils/styles'; + +/** + * Base theme containing EChart properties only + * + * @private Not intended as public API and subject to change + */ +export const BaseTheme = (): ThemeDefinition => { + const textProps = { + fontFamily: chart_global_FontFamily.var.replace(/"/g, "'"), // Well-formed XML + fontSize: chart_global_FontSize_sm.value + }; + + const axisProps = { + boundaryGap: getComputedStyleValue(chart_echarts_global_axis_BoundaryGap), + axisLabel: { + ...textProps, + show: getComputedStyleValue(chart_echarts_global_axis_axis_label_Show) + }, + axisLine: { + lineStyle: {}, + show: getComputedStyleValue(chart_echarts_global_axis_axis_line_Show) + }, + axisTick: { + lineStyle: {}, + show: getComputedStyleValue(chart_echarts_global_axis_axis_tick_Show) + }, + splitArea: { + areaStyle: {}, + show: getComputedStyleValue(chart_echarts_global_axis_split_area_Show) + }, + splitLine: { + lineStyle: {}, + show: getComputedStyleValue(chart_echarts_global_axis_split_line_Show) // Grid + } + }; + + return { + bar: { + itemStyle: { + barBorderWidth: getComputedStyleValue(chart_echarts_bar_item_style_BarBorderWidth) + } + }, + boxplot: { + itemStyle: { + borderWidth: getComputedStyleValue(chart_echarts_boxplot_item_style_BorderWidth) + } + }, + candlestick: { + itemStyle: { + borderWidth: getComputedStyleValue(chart_echarts_candlestick_item_style_BorderWidth) + } + }, + categoryAxis: { ...axisProps }, + dataZoom: { + handleSize: getComputedStyleValue(chart_echarts_datazoom_HandleSize), + textStyle: { ...textProps } + }, + funnel: { + itemStyle: { + borderWidth: getComputedStyleValue(chart_echarts_funnel_item_style_BorderWidth) + } + }, + gauge: { + itemStyle: { + borderWidth: getComputedStyleValue(chart_echarts_gauge_item_style_BorderWidth) + } + }, + geo: { + emphasis: { + itemStyle: { + borderWidth: getComputedStyleValue(chart_echarts_geo_emphasis_item_style_BorderWidth) + }, + label: {} + }, + itemStyle: { + borderWidth: getComputedStyleValue(chart_echarts_geo_item_style_BorderWidth) + }, + label: {} + }, + graph: { + itemStyle: { + borderWidth: getComputedStyleValue(chart_echarts_graph_item_style_BorderWidth) + }, + label: {}, + lineStyle: { + width: getComputedStyleValue(chart_echarts_graph_line_style_BorderWidth) + }, + smooth: getComputedStyleValue(chart_echarts_graph_Smooth), + symbolSize: getComputedStyleValue(chart_echarts_graph_SymbolSize), + symbol: getComputedStyleValue(chart_echarts_graph_Symbol) + }, + label: { + ...textProps + }, + legend: { + textStyle: { ...textProps } + }, + line: { + itemStyle: { + borderWidth: getComputedStyleValue(chart_echarts_line_item_style_BorderWidth) + }, + lineStyle: { + width: getComputedStyleValue(chart_echarts_line_line_style_BorderWidth) + }, + smooth: getComputedStyleValue(chart_echarts_line_Smooth), + symbolSize: getComputedStyleValue(chart_echarts_line_SymbolSize), + symbol: getComputedStyleValue(chart_echarts_line_Symbol) + }, + logAxis: { ...axisProps }, + map: { + emphasis: { + itemStyle: { + borderWidth: getComputedStyleValue(chart_echarts_map_emphasis_item_style_BorderWidth) + }, + label: {} + }, + itemStyle: { + borderWidth: getComputedStyleValue(chart_echarts_map_item_style_BorderWidth) + }, + label: { + label: {} + } + }, + markPoint: { + emphasis: { + label: {} + }, + label: {} + }, + parallel: { + itemStyle: { + borderWidth: getComputedStyleValue(chart_echarts_parallel_item_style_BorderWidth) + } + }, + pie: { + itemStyle: { + borderWidth: getComputedStyleValue(chart_echarts_pie_item_style_BorderWidth) + } + }, + radar: { + itemStyle: { + borderWidth: getComputedStyleValue(chart_echarts_radar_item_style_BorderWidth) + }, + lineStyle: { + width: getComputedStyleValue(chart_echarts_radar_line_style_BorderWidth) + }, + smooth: getComputedStyleValue(chart_echarts_radar_Smooth), + symbolSize: getComputedStyleValue(chart_echarts_radar_SymbolSize), + symbol: getComputedStyleValue(chart_echarts_radar_Symbol) + }, + sankey: { + itemStyle: { + borderWidth: getComputedStyleValue(chart_echarts_sankey_item_style_BorderWidth) + } + }, + scatter: { + itemStyle: { + borderWidth: getComputedStyleValue(chart_echarts_scatter_item_style_BorderWidth) + } + }, + textStyle: { ...textProps }, + timeAxis: { ...axisProps }, + timeline: { + emphasis: { + controlStyle: { + borderWidth: getComputedStyleValue(chart_echarts_timeline_emphasis_control_style_BorderWidth) + }, + itemStyle: {}, + label: {} + }, + checkpointStyle: {}, + controlStyle: { + borderWidth: getComputedStyleValue(chart_echarts_timeline_control_style_BorderWidth) + }, + itemStyle: { + borderWidth: getComputedStyleValue(chart_echarts_timeline_item_style_BorderWidth) + }, + label: {}, + lineStyle: { + width: getComputedStyleValue(chart_echarts_timeline_line_style_Width) + } + }, + title: { + subtextStyle: { ...textProps }, + textStyle: { ...textProps } + }, + toolbox: { + emphasis: { + iconStyle: {} + }, + iconStyle: {} + }, + tooltip: { + axisPointer: { + crossStyle: { + width: getComputedStyleValue(chart_echarts_tooltip_axis_pointer_cross_style_Width) + }, + lineStyle: { + width: getComputedStyleValue(chart_echarts_tooltip_axis_pointer_line_style_Width) + } + } + }, + valueAxis: { ...axisProps }, + visualMap: {} + }; +}; diff --git a/packages/react-charts/src/echarts/components/themes/color-theme.ts b/packages/react-charts/src/echarts/components/themes/color-theme.ts new file mode 100644 index 00000000000..e53ae0e3679 --- /dev/null +++ b/packages/react-charts/src/echarts/components/themes/color-theme.ts @@ -0,0 +1,252 @@ +import chart_echarts_BackgroundColor from '@patternfly/react-tokens/dist/esm/chart_echarts_BackgroundColor'; +import chart_echarts_bar_item_style_BarBorderColor from '@patternfly/react-tokens/dist/esm/chart_echarts_bar_item_style_BarBorderColor'; +import chart_echarts_boxplot_item_style_BorderColor from '@patternfly/react-tokens/dist/esm/chart_echarts_boxplot_item_style_BorderColor'; +import chart_echarts_candlestick_item_style_positive_BorderColor from '@patternfly/react-tokens/dist/esm/chart_echarts_candlestick_item_style_positive_BorderColor'; +import chart_echarts_candlestick_item_style_positive_Color from '@patternfly/react-tokens/dist/esm/chart_echarts_candlestick_item_style_positive_Color'; +import chart_echarts_candlestick_item_style_negative_Color from '@patternfly/react-tokens/dist/esm/chart_echarts_candlestick_item_style_negative_Color'; +import chart_echarts_candlestick_item_style_negative_BorderColor from '@patternfly/react-tokens/dist/esm/chart_echarts_candlestick_item_style_negative_BorderColor'; +import chart_echarts_funnel_item_style_BorderColor from '@patternfly/react-tokens/dist/esm/chart_echarts_funnel_item_style_BorderColor'; +import chart_echarts_gauge_item_style_BorderColor from '@patternfly/react-tokens/dist/esm/chart_echarts_gauge_item_style_BorderColor'; +import chart_echarts_geo_emphasis_item_style_BorderColor from '@patternfly/react-tokens/dist/esm/chart_echarts_geo_emphasis_item_style_BorderColor'; +import chart_echarts_geo_item_style_BorderColor from '@patternfly/react-tokens/dist/esm/chart_echarts_geo_item_style_BorderColor'; +import chart_echarts_global_axis_axis_line_item_style_Color from '@patternfly/react-tokens/dist/esm/chart_echarts_global_axis_axis_line_item_style_Color'; +import chart_echarts_global_axis_axis_tick_item_style_Color from '@patternfly/react-tokens/dist/esm/chart_echarts_global_axis_axis_tick_item_style_Color'; +import chart_echarts_global_axis_split_area_area_style_Color from '@patternfly/react-tokens/dist/esm/chart_echarts_global_axis_split_area_area_style_Color'; +import chart_echarts_global_label_Color from '@patternfly/react-tokens/dist/esm/chart_echarts_global_label_Color'; +import chart_echarts_graph_item_style_BorderColor from '@patternfly/react-tokens/dist/esm/chart_echarts_graph_item_style_BorderColor'; +import chart_echarts_graph_line_style_Color from '@patternfly/react-tokens/dist/esm/chart_echarts_graph_line_style_Color'; +import chart_echarts_map_emphasis_item_style_BorderColor from '@patternfly/react-tokens/dist/esm/chart_echarts_map_emphasis_item_style_BorderColor'; +import chart_echarts_map_item_style_BorderColor from '@patternfly/react-tokens/dist/esm/chart_echarts_map_item_style_BorderColor'; +import chart_echarts_parallel_item_style_BorderColor from '@patternfly/react-tokens/dist/esm/chart_echarts_parallel_item_style_BorderColor'; +import chart_echarts_pie_item_style_BorderColor from '@patternfly/react-tokens/dist/esm/chart_echarts_pie_item_style_BorderColor'; +import chart_echarts_sankey_item_style_BorderColor from '@patternfly/react-tokens/dist/esm/chart_echarts_sankey_item_style_BorderColor'; +import chart_echarts_scatter_item_style_BorderColor from '@patternfly/react-tokens/dist/esm/chart_echarts_scatter_item_style_BorderColor'; +import chart_echarts_tooltip_axis_pointer_cross_style_Color from '@patternfly/react-tokens/dist/esm/chart_echarts_tooltip_axis_pointer_cross_style_Color'; +import chart_echarts_tooltip_axis_pointer_line_style_Color from '@patternfly/react-tokens/dist/esm/chart_echarts_tooltip_axis_pointer_line_style_Color'; +import chart_echarts_toolbox_emphasis_item_style_BorderColor from '@patternfly/react-tokens/dist/esm/chart_echarts_toolbox_emphasis_item_style_BorderColor'; +import chart_echarts_toolbox_item_style_BorderColor from '@patternfly/react-tokens/dist/esm/chart_echarts_toolbox_item_style_BorderColor'; +import chart_echarts_timeline_emphasis_control_style_Color from '@patternfly/react-tokens/dist/esm/chart_echarts_timeline_emphasis_control_style_Color'; +import chart_echarts_timeline_emphasis_item_style_Color from '@patternfly/react-tokens/dist/esm/chart_echarts_timeline_emphasis_item_style_Color'; +import chart_echarts_timeline_emphasis_control_style_BorderColor from '@patternfly/react-tokens/dist/esm/chart_echarts_timeline_emphasis_control_style_BorderColor'; +import chart_echarts_timeline_checkpoint_style_Color from '@patternfly/react-tokens/dist/esm/chart_echarts_timeline_checkpoint_style_Color'; +import chart_echarts_timeline_checkpoint_style_BorderColor from '@patternfly/react-tokens/dist/esm/chart_echarts_timeline_checkpoint_style_BorderColor'; +import chart_echarts_timeline_control_style_Color from '@patternfly/react-tokens/dist/esm/chart_echarts_timeline_control_style_Color'; +import chart_echarts_timeline_control_style_BorderColor from '@patternfly/react-tokens/dist/esm/chart_echarts_timeline_control_style_BorderColor'; +import chart_echarts_timeline_item_style_Color from '@patternfly/react-tokens/dist/esm/chart_echarts_timeline_item_style_Color'; +import chart_echarts_timeline_line_style_Color from '@patternfly/react-tokens/dist/esm/chart_echarts_timeline_line_style_Color'; +import chart_echarts_tooltip_backgroundColor from '@patternfly/react-tokens/dist/esm/chart_echarts_tooltip_backgroundColor'; +import chart_echarts_tooltip_text_Style_Color from '@patternfly/react-tokens/dist/esm/chart_echarts_tooltip_text_Style_Color'; + +import { ThemeDefinition } from './Theme'; +import { getComputedStyleValue } from '../utils/styles'; + +interface ColorThemeInterface { + COLOR_SCALE: string[]; +} + +/** + * ECharts color theme + * + * @private Not intended as public API and subject to change + * @beta + */ +export const ColorTheme = (props: ColorThemeInterface): ThemeDefinition => { + const { COLOR_SCALE } = props; + + const labelProps = { + color: getComputedStyleValue(chart_echarts_global_label_Color) + }; + + const axisProps = { + axisLabel: { ...labelProps }, + axisLine: { + lineStyle: { + color: getComputedStyleValue(chart_echarts_global_axis_axis_line_item_style_Color) + } + }, + axisTick: { + lineStyle: { + color: getComputedStyleValue(chart_echarts_global_axis_axis_tick_item_style_Color) + } + }, + splitArea: { + areaStyle: { + color: getComputedStyleValue(chart_echarts_global_axis_split_area_area_style_Color) + } + }, + splitLine: { + lineStyle: { + color: getComputedStyleValue(chart_echarts_global_axis_axis_tick_item_style_Color) // Grid + } + } + }; + + return { + color: COLOR_SCALE, // See https://echarts.apache.org/en/option.html#color + backgroundColor: getComputedStyleValue(chart_echarts_BackgroundColor), // See https://echarts.apache.org/en/option.html#backgroundColor + bar: { + itemStyle: { + barBorderColor: getComputedStyleValue(chart_echarts_bar_item_style_BarBorderColor) + } + }, + boxplot: { + itemStyle: { + borderColor: getComputedStyleValue(chart_echarts_boxplot_item_style_BorderColor) + } + }, + candlestick: { + itemStyle: { + borderColor: getComputedStyleValue(chart_echarts_candlestick_item_style_negative_BorderColor), + borderColor0: getComputedStyleValue(chart_echarts_candlestick_item_style_positive_BorderColor), + color: getComputedStyleValue(chart_echarts_candlestick_item_style_negative_Color), + color0: getComputedStyleValue(chart_echarts_candlestick_item_style_positive_Color) + } + }, + categoryAxis: { ...axisProps }, + dataZoom: {}, + funnel: { + itemStyle: { + borderColor: getComputedStyleValue(chart_echarts_funnel_item_style_BorderColor) + } + }, + gauge: { + itemStyle: { + borderColor: getComputedStyleValue(chart_echarts_gauge_item_style_BorderColor) + } + }, + geo: { + emphasis: { + itemStyle: { + areaColor: COLOR_SCALE[1], + borderColor: getComputedStyleValue(chart_echarts_geo_emphasis_item_style_BorderColor) + }, + label: { ...labelProps } + }, + itemStyle: { + areaColor: COLOR_SCALE[0], + borderColor: getComputedStyleValue(chart_echarts_geo_item_style_BorderColor) + }, + label: { ...labelProps } + }, + graph: { + color: COLOR_SCALE, + itemStyle: { + borderColor: getComputedStyleValue(chart_echarts_graph_item_style_BorderColor) + }, + label: { ...labelProps }, + lineStyle: { + color: getComputedStyleValue(chart_echarts_graph_line_style_Color) + } + }, + label: { ...labelProps }, + legend: { + textStyle: { + color: getComputedStyleValue(chart_echarts_global_label_Color) + } + }, + line: {}, + logAxis: { ...axisProps }, + map: { + emphasis: { + itemStyle: { + areaColor: COLOR_SCALE[1], + borderColor: getComputedStyleValue(chart_echarts_map_emphasis_item_style_BorderColor) + }, + label: { ...labelProps } + }, + itemStyle: { + areaColor: COLOR_SCALE[0], + borderColor: getComputedStyleValue(chart_echarts_map_item_style_BorderColor) + }, + label: { ...labelProps } + }, + markPoint: { + emphasis: { + label: { ...labelProps } + }, + label: { ...labelProps } + }, + parallel: { + itemStyle: { + borderColor: getComputedStyleValue(chart_echarts_parallel_item_style_BorderColor) + } + }, + pie: { + itemStyle: { + borderColor: getComputedStyleValue(chart_echarts_pie_item_style_BorderColor) + } + }, + radar: {}, + sankey: { + itemStyle: { + borderColor: getComputedStyleValue(chart_echarts_sankey_item_style_BorderColor) + } + }, + scatter: { + itemStyle: { + borderColor: getComputedStyleValue(chart_echarts_scatter_item_style_BorderColor) + } + }, + textStyle: {}, + timeAxis: { ...axisProps }, + timeline: { + emphasis: { + controlStyle: { + color: getComputedStyleValue(chart_echarts_timeline_emphasis_control_style_Color), + borderColor: getComputedStyleValue(chart_echarts_timeline_emphasis_control_style_BorderColor) + }, + itemStyle: { + color: getComputedStyleValue(chart_echarts_timeline_emphasis_item_style_Color) + }, + label: { ...labelProps } + }, + checkpointStyle: { + color: getComputedStyleValue(chart_echarts_timeline_checkpoint_style_Color), + borderColor: getComputedStyleValue(chart_echarts_timeline_checkpoint_style_BorderColor) + }, + controlStyle: { + color: getComputedStyleValue(chart_echarts_timeline_control_style_Color), + borderColor: getComputedStyleValue(chart_echarts_timeline_control_style_BorderColor) + }, + itemStyle: { + color: getComputedStyleValue(chart_echarts_timeline_item_style_Color) + }, + label: { ...labelProps }, + lineStyle: { + color: getComputedStyleValue(chart_echarts_timeline_line_style_Color) + } + }, + title: { + subtextStyle: { ...labelProps }, + textStyle: { ...labelProps } + }, + toolbox: { + emphasis: { + iconStyle: { + borderColor: getComputedStyleValue(chart_echarts_toolbox_emphasis_item_style_BorderColor) + } + }, + iconStyle: { + borderColor: getComputedStyleValue(chart_echarts_toolbox_item_style_BorderColor) + } + }, + tooltip: { + backgroundColor: getComputedStyleValue(chart_echarts_tooltip_backgroundColor), + axisPointer: { + crossStyle: { + color: getComputedStyleValue(chart_echarts_tooltip_axis_pointer_cross_style_Color) + }, + lineStyle: { + color: getComputedStyleValue(chart_echarts_tooltip_axis_pointer_line_style_Color) + } + }, + textStyle: { + color: getComputedStyleValue(chart_echarts_tooltip_text_Style_Color) + } + }, + valueAxis: { ...axisProps }, + visualMap: { + color: COLOR_SCALE + } + }; +}; diff --git a/packages/react-charts/src/echarts/components/themes/colors/blue-theme.ts b/packages/react-charts/src/echarts/components/themes/colors/blue-theme.ts new file mode 100644 index 00000000000..e908cbf3f7e --- /dev/null +++ b/packages/react-charts/src/echarts/components/themes/colors/blue-theme.ts @@ -0,0 +1,23 @@ +import chart_theme_blue_ColorScale_100 from '@patternfly/react-tokens/dist/esm/chart_theme_blue_ColorScale_100'; +import chart_theme_blue_ColorScale_200 from '@patternfly/react-tokens/dist/esm/chart_theme_blue_ColorScale_200'; +import chart_theme_blue_ColorScale_300 from '@patternfly/react-tokens/dist/esm/chart_theme_blue_ColorScale_300'; +import chart_theme_blue_ColorScale_400 from '@patternfly/react-tokens/dist/esm/chart_theme_blue_ColorScale_400'; +import chart_theme_blue_ColorScale_500 from '@patternfly/react-tokens/dist/esm/chart_theme_blue_ColorScale_500'; +import { ColorTheme } from '../color-theme'; +import { getComputedStyleValue } from '../../utils/styles'; + +/** + * Blue color theme -- see https://docs.google.com/document/d/1cw10pJFXWruB1SA8TQwituxn5Ss6KpxYPCOYGrH8qAY/edit + * + * @private Not intended as public API and subject to change + */ +export const getBlueColorTheme = () => + ColorTheme({ + COLOR_SCALE: [ + getComputedStyleValue(chart_theme_blue_ColorScale_100), + getComputedStyleValue(chart_theme_blue_ColorScale_200), + getComputedStyleValue(chart_theme_blue_ColorScale_300), + getComputedStyleValue(chart_theme_blue_ColorScale_400), + getComputedStyleValue(chart_theme_blue_ColorScale_500) + ] + }); diff --git a/packages/react-charts/src/echarts/components/themes/colors/gray-theme.ts b/packages/react-charts/src/echarts/components/themes/colors/gray-theme.ts new file mode 100644 index 00000000000..e3b11d2d893 --- /dev/null +++ b/packages/react-charts/src/echarts/components/themes/colors/gray-theme.ts @@ -0,0 +1,23 @@ +import chart_theme_gray_ColorScale_100 from '@patternfly/react-tokens/dist/esm/chart_theme_gray_ColorScale_100'; +import chart_theme_gray_ColorScale_200 from '@patternfly/react-tokens/dist/esm/chart_theme_gray_ColorScale_200'; +import chart_theme_gray_ColorScale_300 from '@patternfly/react-tokens/dist/esm/chart_theme_gray_ColorScale_300'; +import chart_theme_gray_ColorScale_400 from '@patternfly/react-tokens/dist/esm/chart_theme_gray_ColorScale_400'; +import chart_theme_gray_ColorScale_500 from '@patternfly/react-tokens/dist/esm/chart_theme_gray_ColorScale_500'; +import { ColorTheme } from '../color-theme'; +import { getComputedStyleValue } from '../../utils/styles'; + +/** + * Gray color theme -- see https://docs.google.com/document/d/1cw10pJFXWruB1SA8TQwituxn5Ss6KpxYPCOYGrH8qAY/edit + * + * @private Not intended as public API and subject to change + */ +export const getGrayColorTheme = () => + ColorTheme({ + COLOR_SCALE: [ + getComputedStyleValue(chart_theme_gray_ColorScale_100), + getComputedStyleValue(chart_theme_gray_ColorScale_200), + getComputedStyleValue(chart_theme_gray_ColorScale_300), + getComputedStyleValue(chart_theme_gray_ColorScale_400), + getComputedStyleValue(chart_theme_gray_ColorScale_500) + ] + }); diff --git a/packages/react-charts/src/echarts/components/themes/colors/green-theme.ts b/packages/react-charts/src/echarts/components/themes/colors/green-theme.ts new file mode 100644 index 00000000000..5d979253a81 --- /dev/null +++ b/packages/react-charts/src/echarts/components/themes/colors/green-theme.ts @@ -0,0 +1,23 @@ +import chart_theme_green_ColorScale_100 from '@patternfly/react-tokens/dist/esm/chart_theme_green_ColorScale_100'; +import chart_theme_green_ColorScale_200 from '@patternfly/react-tokens/dist/esm/chart_theme_green_ColorScale_200'; +import chart_theme_green_ColorScale_300 from '@patternfly/react-tokens/dist/esm/chart_theme_green_ColorScale_300'; +import chart_theme_green_ColorScale_400 from '@patternfly/react-tokens/dist/esm/chart_theme_green_ColorScale_400'; +import chart_theme_green_ColorScale_500 from '@patternfly/react-tokens/dist/esm/chart_theme_green_ColorScale_500'; +import { ColorTheme } from '../color-theme'; +import { getComputedStyleValue } from '../../utils/styles'; + +/** + * Green color theme -- see https://docs.google.com/document/d/1cw10pJFXWruB1SA8TQwituxn5Ss6KpxYPCOYGrH8qAY/edit + * + * @private Not intended as public API and subject to change + */ +export const getGreenColorTheme = () => + ColorTheme({ + COLOR_SCALE: [ + getComputedStyleValue(chart_theme_green_ColorScale_100), + getComputedStyleValue(chart_theme_green_ColorScale_200), + getComputedStyleValue(chart_theme_green_ColorScale_300), + getComputedStyleValue(chart_theme_green_ColorScale_400), + getComputedStyleValue(chart_theme_green_ColorScale_500) + ] + }); diff --git a/packages/react-charts/src/echarts/components/themes/colors/multi-ordered-theme.ts b/packages/react-charts/src/echarts/components/themes/colors/multi-ordered-theme.ts new file mode 100644 index 00000000000..3844eea21f7 --- /dev/null +++ b/packages/react-charts/src/echarts/components/themes/colors/multi-ordered-theme.ts @@ -0,0 +1,64 @@ +import chart_theme_multi_color_ordered_ColorScale_100 from '@patternfly/react-tokens/dist/esm/chart_theme_multi_color_ordered_ColorScale_100'; +import chart_theme_multi_color_ordered_ColorScale_200 from '@patternfly/react-tokens/dist/esm/chart_theme_multi_color_ordered_ColorScale_200'; +import chart_theme_multi_color_ordered_ColorScale_300 from '@patternfly/react-tokens/dist/esm/chart_theme_multi_color_ordered_ColorScale_300'; +import chart_theme_multi_color_ordered_ColorScale_400 from '@patternfly/react-tokens/dist/esm/chart_theme_multi_color_ordered_ColorScale_400'; +import chart_theme_multi_color_ordered_ColorScale_500 from '@patternfly/react-tokens/dist/esm/chart_theme_multi_color_ordered_ColorScale_500'; +import chart_theme_multi_color_ordered_ColorScale_600 from '@patternfly/react-tokens/dist/esm/chart_theme_multi_color_ordered_ColorScale_600'; +import chart_theme_multi_color_ordered_ColorScale_700 from '@patternfly/react-tokens/dist/esm/chart_theme_multi_color_ordered_ColorScale_700'; +import chart_theme_multi_color_ordered_ColorScale_800 from '@patternfly/react-tokens/dist/esm/chart_theme_multi_color_ordered_ColorScale_800'; +import chart_theme_multi_color_ordered_ColorScale_900 from '@patternfly/react-tokens/dist/esm/chart_theme_multi_color_ordered_ColorScale_900'; +import chart_theme_multi_color_ordered_ColorScale_1000 from '@patternfly/react-tokens/dist/esm/chart_theme_multi_color_ordered_ColorScale_1000'; +import chart_theme_multi_color_ordered_ColorScale_1100 from '@patternfly/react-tokens/dist/esm/chart_theme_multi_color_ordered_ColorScale_1100'; +import chart_theme_multi_color_ordered_ColorScale_1200 from '@patternfly/react-tokens/dist/esm/chart_theme_multi_color_ordered_ColorScale_1200'; +import chart_theme_multi_color_ordered_ColorScale_1300 from '@patternfly/react-tokens/dist/esm/chart_theme_multi_color_ordered_ColorScale_1300'; +import chart_theme_multi_color_ordered_ColorScale_1400 from '@patternfly/react-tokens/dist/esm/chart_theme_multi_color_ordered_ColorScale_1400'; +import chart_theme_multi_color_ordered_ColorScale_1500 from '@patternfly/react-tokens/dist/esm/chart_theme_multi_color_ordered_ColorScale_1500'; +import chart_theme_multi_color_ordered_ColorScale_1600 from '@patternfly/react-tokens/dist/esm/chart_theme_multi_color_ordered_ColorScale_1600'; +import chart_theme_multi_color_ordered_ColorScale_1700 from '@patternfly/react-tokens/dist/esm/chart_theme_multi_color_ordered_ColorScale_1700'; +import chart_theme_multi_color_ordered_ColorScale_1800 from '@patternfly/react-tokens/dist/esm/chart_theme_multi_color_ordered_ColorScale_1800'; +import chart_theme_multi_color_ordered_ColorScale_1900 from '@patternfly/react-tokens/dist/esm/chart_theme_multi_color_ordered_ColorScale_1900'; +import chart_theme_multi_color_ordered_ColorScale_2000 from '@patternfly/react-tokens/dist/esm/chart_theme_multi_color_ordered_ColorScale_2000'; +import chart_theme_multi_color_ordered_ColorScale_2100 from '@patternfly/react-tokens/dist/esm/chart_theme_multi_color_ordered_ColorScale_2100'; +import chart_theme_multi_color_ordered_ColorScale_2200 from '@patternfly/react-tokens/dist/esm/chart_theme_multi_color_ordered_ColorScale_2200'; +import chart_theme_multi_color_ordered_ColorScale_2300 from '@patternfly/react-tokens/dist/esm/chart_theme_multi_color_ordered_ColorScale_2300'; +import chart_theme_multi_color_ordered_ColorScale_2400 from '@patternfly/react-tokens/dist/esm/chart_theme_multi_color_ordered_ColorScale_2400'; +import chart_theme_multi_color_ordered_ColorScale_2500 from '@patternfly/react-tokens/dist/esm/chart_theme_multi_color_ordered_ColorScale_2500'; +import { ColorTheme } from '../color-theme'; +import { getComputedStyleValue } from '../../utils/styles'; + +/** + * Multi-color ordered theme -- see https://docs.google.com/document/d/1cw10pJFXWruB1SA8TQwituxn5Ss6KpxYPCOYGrH8qAY/edit + * + * @private Not intended as public API and subject to change + */ +export const getMultiColorOrderedTheme = () => + ColorTheme({ + // The color order below (minus the purple color family) improves the color contrast in ordered charts; donut, pie, bar, & stack + COLOR_SCALE: [ + getComputedStyleValue(chart_theme_multi_color_ordered_ColorScale_100), + getComputedStyleValue(chart_theme_multi_color_ordered_ColorScale_200), + getComputedStyleValue(chart_theme_multi_color_ordered_ColorScale_300), + getComputedStyleValue(chart_theme_multi_color_ordered_ColorScale_400), + getComputedStyleValue(chart_theme_multi_color_ordered_ColorScale_500), + getComputedStyleValue(chart_theme_multi_color_ordered_ColorScale_600), + getComputedStyleValue(chart_theme_multi_color_ordered_ColorScale_700), + getComputedStyleValue(chart_theme_multi_color_ordered_ColorScale_800), + getComputedStyleValue(chart_theme_multi_color_ordered_ColorScale_900), + getComputedStyleValue(chart_theme_multi_color_ordered_ColorScale_1000), + getComputedStyleValue(chart_theme_multi_color_ordered_ColorScale_1100), + getComputedStyleValue(chart_theme_multi_color_ordered_ColorScale_1200), + getComputedStyleValue(chart_theme_multi_color_ordered_ColorScale_1300), + getComputedStyleValue(chart_theme_multi_color_ordered_ColorScale_1400), + getComputedStyleValue(chart_theme_multi_color_ordered_ColorScale_1500), + getComputedStyleValue(chart_theme_multi_color_ordered_ColorScale_1600), + getComputedStyleValue(chart_theme_multi_color_ordered_ColorScale_1700), + getComputedStyleValue(chart_theme_multi_color_ordered_ColorScale_1800), + getComputedStyleValue(chart_theme_multi_color_ordered_ColorScale_1900), + getComputedStyleValue(chart_theme_multi_color_ordered_ColorScale_2000), + getComputedStyleValue(chart_theme_multi_color_ordered_ColorScale_2100), + getComputedStyleValue(chart_theme_multi_color_ordered_ColorScale_2200), + getComputedStyleValue(chart_theme_multi_color_ordered_ColorScale_2300), + getComputedStyleValue(chart_theme_multi_color_ordered_ColorScale_2400), + getComputedStyleValue(chart_theme_multi_color_ordered_ColorScale_2500) + ] + }); diff --git a/packages/react-charts/src/echarts/components/themes/colors/multi-unordered-theme.ts b/packages/react-charts/src/echarts/components/themes/colors/multi-unordered-theme.ts new file mode 100644 index 00000000000..6e4b9ea8103 --- /dev/null +++ b/packages/react-charts/src/echarts/components/themes/colors/multi-unordered-theme.ts @@ -0,0 +1,84 @@ +import chart_theme_multi_color_unordered_ColorScale_100 from '@patternfly/react-tokens/dist/esm/chart_theme_multi_color_unordered_ColorScale_100'; +import chart_theme_multi_color_unordered_ColorScale_200 from '@patternfly/react-tokens/dist/esm/chart_theme_multi_color_unordered_ColorScale_200'; +import chart_theme_multi_color_unordered_ColorScale_300 from '@patternfly/react-tokens/dist/esm/chart_theme_multi_color_unordered_ColorScale_300'; +import chart_theme_multi_color_unordered_ColorScale_400 from '@patternfly/react-tokens/dist/esm/chart_theme_multi_color_unordered_ColorScale_400'; +import chart_theme_multi_color_unordered_ColorScale_500 from '@patternfly/react-tokens/dist/esm/chart_theme_multi_color_unordered_ColorScale_500'; +import chart_theme_multi_color_unordered_ColorScale_600 from '@patternfly/react-tokens/dist/esm/chart_theme_multi_color_unordered_ColorScale_600'; +import chart_theme_multi_color_unordered_ColorScale_700 from '@patternfly/react-tokens/dist/esm/chart_theme_multi_color_unordered_ColorScale_700'; +import chart_theme_multi_color_unordered_ColorScale_800 from '@patternfly/react-tokens/dist/esm/chart_theme_multi_color_unordered_ColorScale_800'; +import chart_theme_multi_color_unordered_ColorScale_900 from '@patternfly/react-tokens/dist/esm/chart_theme_multi_color_unordered_ColorScale_900'; +import chart_theme_multi_color_unordered_ColorScale_1000 from '@patternfly/react-tokens/dist/esm/chart_theme_multi_color_unordered_ColorScale_1000'; +import chart_theme_multi_color_unordered_ColorScale_1100 from '@patternfly/react-tokens/dist/esm/chart_theme_multi_color_unordered_ColorScale_1100'; +import chart_theme_multi_color_unordered_ColorScale_1200 from '@patternfly/react-tokens/dist/esm/chart_theme_multi_color_unordered_ColorScale_1200'; +import chart_theme_multi_color_unordered_ColorScale_1300 from '@patternfly/react-tokens/dist/esm/chart_theme_multi_color_unordered_ColorScale_1300'; +import chart_theme_multi_color_unordered_ColorScale_1400 from '@patternfly/react-tokens/dist/esm/chart_theme_multi_color_unordered_ColorScale_1400'; +import chart_theme_multi_color_unordered_ColorScale_1500 from '@patternfly/react-tokens/dist/esm/chart_theme_multi_color_unordered_ColorScale_1500'; +import chart_theme_multi_color_unordered_ColorScale_1600 from '@patternfly/react-tokens/dist/esm/chart_theme_multi_color_unordered_ColorScale_1600'; +import chart_theme_multi_color_unordered_ColorScale_1700 from '@patternfly/react-tokens/dist/esm/chart_theme_multi_color_unordered_ColorScale_1700'; +import chart_theme_multi_color_unordered_ColorScale_1800 from '@patternfly/react-tokens/dist/esm/chart_theme_multi_color_unordered_ColorScale_1800'; +import chart_theme_multi_color_unordered_ColorScale_1900 from '@patternfly/react-tokens/dist/esm/chart_theme_multi_color_unordered_ColorScale_1900'; +import chart_theme_multi_color_unordered_ColorScale_2000 from '@patternfly/react-tokens/dist/esm/chart_theme_multi_color_unordered_ColorScale_2000'; +import chart_theme_multi_color_unordered_ColorScale_2100 from '@patternfly/react-tokens/dist/esm/chart_theme_multi_color_unordered_ColorScale_2100'; +import chart_theme_multi_color_unordered_ColorScale_2200 from '@patternfly/react-tokens/dist/esm/chart_theme_multi_color_unordered_ColorScale_2200'; +import chart_theme_multi_color_unordered_ColorScale_2300 from '@patternfly/react-tokens/dist/esm/chart_theme_multi_color_unordered_ColorScale_2300'; +import chart_theme_multi_color_unordered_ColorScale_2400 from '@patternfly/react-tokens/dist/esm/chart_theme_multi_color_unordered_ColorScale_2400'; +import chart_theme_multi_color_unordered_ColorScale_2500 from '@patternfly/react-tokens/dist/esm/chart_theme_multi_color_unordered_ColorScale_2500'; +import chart_theme_multi_color_unordered_ColorScale_2600 from '@patternfly/react-tokens/dist/esm/chart_theme_multi_color_unordered_ColorScale_2600'; +import chart_theme_multi_color_unordered_ColorScale_2700 from '@patternfly/react-tokens/dist/esm/chart_theme_multi_color_unordered_ColorScale_2700'; +import chart_theme_multi_color_unordered_ColorScale_2800 from '@patternfly/react-tokens/dist/esm/chart_theme_multi_color_unordered_ColorScale_2800'; +import chart_theme_multi_color_unordered_ColorScale_2900 from '@patternfly/react-tokens/dist/esm/chart_theme_multi_color_unordered_ColorScale_2900'; +import chart_theme_multi_color_unordered_ColorScale_3000 from '@patternfly/react-tokens/dist/esm/chart_theme_multi_color_unordered_ColorScale_3000'; +import chart_theme_multi_color_unordered_ColorScale_3100 from '@patternfly/react-tokens/dist/esm/chart_theme_multi_color_unordered_ColorScale_3100'; +import chart_theme_multi_color_unordered_ColorScale_3200 from '@patternfly/react-tokens/dist/esm/chart_theme_multi_color_unordered_ColorScale_3200'; +import chart_theme_multi_color_unordered_ColorScale_3300 from '@patternfly/react-tokens/dist/esm/chart_theme_multi_color_unordered_ColorScale_3300'; +import chart_theme_multi_color_unordered_ColorScale_3400 from '@patternfly/react-tokens/dist/esm/chart_theme_multi_color_unordered_ColorScale_3400'; +import chart_theme_multi_color_unordered_ColorScale_3500 from '@patternfly/react-tokens/dist/esm/chart_theme_multi_color_unordered_ColorScale_3500'; +import { ColorTheme } from '../color-theme'; +import { getComputedStyleValue } from '../../utils/styles'; + +/** + * Multi-color unordered theme -- see https://github.com/patternfly/patternfly-next/issues/1551 + * + * @private Not intended as public API and subject to change + */ +export const getMultiColorUnorderedTheme = () => + ColorTheme({ + // The color order below improves the color contrast in unordered charts; area & line + COLOR_SCALE: [ + getComputedStyleValue(chart_theme_multi_color_unordered_ColorScale_100), + getComputedStyleValue(chart_theme_multi_color_unordered_ColorScale_200), + getComputedStyleValue(chart_theme_multi_color_unordered_ColorScale_300), + getComputedStyleValue(chart_theme_multi_color_unordered_ColorScale_400), + getComputedStyleValue(chart_theme_multi_color_unordered_ColorScale_500), + getComputedStyleValue(chart_theme_multi_color_unordered_ColorScale_600), + getComputedStyleValue(chart_theme_multi_color_unordered_ColorScale_700), + getComputedStyleValue(chart_theme_multi_color_unordered_ColorScale_800), + getComputedStyleValue(chart_theme_multi_color_unordered_ColorScale_900), + getComputedStyleValue(chart_theme_multi_color_unordered_ColorScale_1000), + getComputedStyleValue(chart_theme_multi_color_unordered_ColorScale_1100), + getComputedStyleValue(chart_theme_multi_color_unordered_ColorScale_1200), + getComputedStyleValue(chart_theme_multi_color_unordered_ColorScale_1300), + getComputedStyleValue(chart_theme_multi_color_unordered_ColorScale_1400), + getComputedStyleValue(chart_theme_multi_color_unordered_ColorScale_1500), + getComputedStyleValue(chart_theme_multi_color_unordered_ColorScale_1600), + getComputedStyleValue(chart_theme_multi_color_unordered_ColorScale_1700), + getComputedStyleValue(chart_theme_multi_color_unordered_ColorScale_1800), + getComputedStyleValue(chart_theme_multi_color_unordered_ColorScale_1900), + getComputedStyleValue(chart_theme_multi_color_unordered_ColorScale_2000), + getComputedStyleValue(chart_theme_multi_color_unordered_ColorScale_2100), + getComputedStyleValue(chart_theme_multi_color_unordered_ColorScale_2200), + getComputedStyleValue(chart_theme_multi_color_unordered_ColorScale_2300), + getComputedStyleValue(chart_theme_multi_color_unordered_ColorScale_2400), + getComputedStyleValue(chart_theme_multi_color_unordered_ColorScale_2500), + getComputedStyleValue(chart_theme_multi_color_unordered_ColorScale_2600), + getComputedStyleValue(chart_theme_multi_color_unordered_ColorScale_2700), + getComputedStyleValue(chart_theme_multi_color_unordered_ColorScale_2800), + getComputedStyleValue(chart_theme_multi_color_unordered_ColorScale_2900), + getComputedStyleValue(chart_theme_multi_color_unordered_ColorScale_3000), + getComputedStyleValue(chart_theme_multi_color_unordered_ColorScale_3100), + getComputedStyleValue(chart_theme_multi_color_unordered_ColorScale_3200), + getComputedStyleValue(chart_theme_multi_color_unordered_ColorScale_3300), + getComputedStyleValue(chart_theme_multi_color_unordered_ColorScale_3400), + getComputedStyleValue(chart_theme_multi_color_unordered_ColorScale_3500) + ] + }); diff --git a/packages/react-charts/src/echarts/components/themes/colors/orange-theme.ts b/packages/react-charts/src/echarts/components/themes/colors/orange-theme.ts new file mode 100644 index 00000000000..af1aab797b0 --- /dev/null +++ b/packages/react-charts/src/echarts/components/themes/colors/orange-theme.ts @@ -0,0 +1,23 @@ +import chart_theme_orange_ColorScale_100 from '@patternfly/react-tokens/dist/esm/chart_theme_orange_ColorScale_100'; +import chart_theme_orange_ColorScale_200 from '@patternfly/react-tokens/dist/esm/chart_theme_orange_ColorScale_200'; +import chart_theme_orange_ColorScale_300 from '@patternfly/react-tokens/dist/esm/chart_theme_orange_ColorScale_300'; +import chart_theme_orange_ColorScale_400 from '@patternfly/react-tokens/dist/esm/chart_theme_orange_ColorScale_400'; +import chart_theme_orange_ColorScale_500 from '@patternfly/react-tokens/dist/esm/chart_theme_orange_ColorScale_500'; +import { ColorTheme } from '../color-theme'; +import { getComputedStyleValue } from '../../utils/styles'; + +/** + * Orange color theme -- see https://docs.google.com/document/d/1cw10pJFXWruB1SA8TQwituxn5Ss6KpxYPCOYGrH8qAY/edit + * + * @private Not intended as public API and subject to change + */ +export const getOrangeColorTheme = () => + ColorTheme({ + COLOR_SCALE: [ + getComputedStyleValue(chart_theme_orange_ColorScale_100), + getComputedStyleValue(chart_theme_orange_ColorScale_200), + getComputedStyleValue(chart_theme_orange_ColorScale_300), + getComputedStyleValue(chart_theme_orange_ColorScale_400), + getComputedStyleValue(chart_theme_orange_ColorScale_500) + ] + }); diff --git a/packages/react-charts/src/echarts/components/themes/colors/purple-theme.ts b/packages/react-charts/src/echarts/components/themes/colors/purple-theme.ts new file mode 100644 index 00000000000..39acfb38bf4 --- /dev/null +++ b/packages/react-charts/src/echarts/components/themes/colors/purple-theme.ts @@ -0,0 +1,23 @@ +import chart_theme_purple_ColorScale_100 from '@patternfly/react-tokens/dist/esm/chart_theme_purple_ColorScale_100'; +import chart_theme_purple_ColorScale_200 from '@patternfly/react-tokens/dist/esm/chart_theme_purple_ColorScale_200'; +import chart_theme_purple_ColorScale_300 from '@patternfly/react-tokens/dist/esm/chart_theme_purple_ColorScale_300'; +import chart_theme_purple_ColorScale_400 from '@patternfly/react-tokens/dist/esm/chart_theme_purple_ColorScale_400'; +import chart_theme_purple_ColorScale_500 from '@patternfly/react-tokens/dist/esm/chart_theme_purple_ColorScale_500'; +import { ColorTheme } from '../color-theme'; +import { getComputedStyleValue } from '../../utils/styles'; + +/** + * Purple ordered theme -- see https://docs.google.com/document/d/1cw10pJFXWruB1SA8TQwituxn5Ss6KpxYPCOYGrH8qAY/edit + * + * @private Not intended as public API and subject to change + */ +export const getPurpleColorTheme = () => + ColorTheme({ + COLOR_SCALE: [ + getComputedStyleValue(chart_theme_purple_ColorScale_100), + getComputedStyleValue(chart_theme_purple_ColorScale_200), + getComputedStyleValue(chart_theme_purple_ColorScale_300), + getComputedStyleValue(chart_theme_purple_ColorScale_400), + getComputedStyleValue(chart_theme_purple_ColorScale_500) + ] + }); diff --git a/packages/react-charts/src/echarts/components/themes/colors/skeleton-theme.ts b/packages/react-charts/src/echarts/components/themes/colors/skeleton-theme.ts new file mode 100644 index 00000000000..ae86b726454 --- /dev/null +++ b/packages/react-charts/src/echarts/components/themes/colors/skeleton-theme.ts @@ -0,0 +1,23 @@ +import chart_skeleton_ColorScale_100 from '@patternfly/react-tokens/dist/esm/chart_skeleton_ColorScale_100'; +import chart_skeleton_ColorScale_200 from '@patternfly/react-tokens/dist/esm/chart_skeleton_ColorScale_200'; +import chart_skeleton_ColorScale_300 from '@patternfly/react-tokens/dist/esm/chart_skeleton_ColorScale_300'; +import chart_skeleton_ColorScale_400 from '@patternfly/react-tokens/dist/esm/chart_skeleton_ColorScale_400'; +import chart_skeleton_ColorScale_500 from '@patternfly/react-tokens/dist/esm/chart_skeleton_ColorScale_500'; +import { ColorTheme } from '../skeleton-theme'; +import { getComputedStyleValue } from '../../utils/styles'; + +/** + * Skeleton color theme + * + * @private Not intended as public API and subject to change + */ +export const getSkeletonColorTheme = () => + ColorTheme({ + COLOR_SCALE: [ + getComputedStyleValue(chart_skeleton_ColorScale_100), + getComputedStyleValue(chart_skeleton_ColorScale_200), + getComputedStyleValue(chart_skeleton_ColorScale_300), + getComputedStyleValue(chart_skeleton_ColorScale_400), + getComputedStyleValue(chart_skeleton_ColorScale_500) + ] + }); diff --git a/packages/react-charts/src/echarts/components/themes/colors/teal-theme.ts b/packages/react-charts/src/echarts/components/themes/colors/teal-theme.ts new file mode 100644 index 00000000000..0ad045831e3 --- /dev/null +++ b/packages/react-charts/src/echarts/components/themes/colors/teal-theme.ts @@ -0,0 +1,23 @@ +import chart_theme_teal_ColorScale_100 from '@patternfly/react-tokens/dist/esm/chart_theme_teal_ColorScale_100'; +import chart_theme_teal_ColorScale_200 from '@patternfly/react-tokens/dist/esm/chart_theme_teal_ColorScale_200'; +import chart_theme_teal_ColorScale_300 from '@patternfly/react-tokens/dist/esm/chart_theme_teal_ColorScale_300'; +import chart_theme_teal_ColorScale_400 from '@patternfly/react-tokens/dist/esm/chart_theme_teal_ColorScale_400'; +import chart_theme_teal_ColorScale_500 from '@patternfly/react-tokens/dist/esm/chart_theme_teal_ColorScale_500'; +import { ColorTheme } from '../color-theme'; +import { getComputedStyleValue } from '../../utils/styles'; + +/** + * Teal color theme -- see https://docs.google.com/document/d/1cw10pJFXWruB1SA8TQwituxn5Ss6KpxYPCOYGrH8qAY/edit + * + * @private Not intended as public API and subject to change + */ +export const getTealColorTheme = () => + ColorTheme({ + COLOR_SCALE: [ + getComputedStyleValue(chart_theme_teal_ColorScale_100), + getComputedStyleValue(chart_theme_teal_ColorScale_200), + getComputedStyleValue(chart_theme_teal_ColorScale_300), + getComputedStyleValue(chart_theme_teal_ColorScale_400), + getComputedStyleValue(chart_theme_teal_ColorScale_500) + ] + }); diff --git a/packages/react-charts/src/echarts/components/themes/colors/yellow-theme.ts b/packages/react-charts/src/echarts/components/themes/colors/yellow-theme.ts new file mode 100644 index 00000000000..466159466ad --- /dev/null +++ b/packages/react-charts/src/echarts/components/themes/colors/yellow-theme.ts @@ -0,0 +1,23 @@ +import chart_theme_yellow_ColorScale_100 from '@patternfly/react-tokens/dist/esm/chart_theme_yellow_ColorScale_100'; +import chart_theme_yellow_ColorScale_200 from '@patternfly/react-tokens/dist/esm/chart_theme_yellow_ColorScale_200'; +import chart_theme_yellow_ColorScale_300 from '@patternfly/react-tokens/dist/esm/chart_theme_yellow_ColorScale_300'; +import chart_theme_yellow_ColorScale_400 from '@patternfly/react-tokens/dist/esm/chart_theme_yellow_ColorScale_400'; +import chart_theme_yellow_ColorScale_500 from '@patternfly/react-tokens/dist/esm/chart_theme_yellow_ColorScale_500'; +import { ColorTheme } from '../color-theme'; +import { getComputedStyleValue } from '../../utils/styles'; + +/** + * Yellow color theme -- see https://docs.google.com/document/d/1cw10pJFXWruB1SA8TQwituxn5Ss6KpxYPCOYGrH8qAY/edit + * + * @private Not intended as public API and subject to change + */ +export const getYellowColorTheme = () => + ColorTheme({ + COLOR_SCALE: [ + getComputedStyleValue(chart_theme_yellow_ColorScale_100), + getComputedStyleValue(chart_theme_yellow_ColorScale_200), + getComputedStyleValue(chart_theme_yellow_ColorScale_300), + getComputedStyleValue(chart_theme_yellow_ColorScale_400), + getComputedStyleValue(chart_theme_yellow_ColorScale_500) + ] + }); diff --git a/packages/react-charts/src/echarts/components/themes/skeleton-theme.ts b/packages/react-charts/src/echarts/components/themes/skeleton-theme.ts new file mode 100644 index 00000000000..76adeea2815 --- /dev/null +++ b/packages/react-charts/src/echarts/components/themes/skeleton-theme.ts @@ -0,0 +1,212 @@ +import chart_echarts_BackgroundColor from '@patternfly/react-tokens/dist/esm/chart_echarts_BackgroundColor'; +import chart_echarts_global_axis_axis_line_item_style_Color from '@patternfly/react-tokens/dist/esm/chart_echarts_global_axis_axis_line_item_style_Color'; +import chart_echarts_global_axis_axis_tick_item_style_Color from '@patternfly/react-tokens/dist/esm/chart_echarts_global_axis_axis_tick_item_style_Color'; +import chart_echarts_skeleton_label_Color from '@patternfly/react-tokens/dist/esm/chart_echarts_skeleton_label_Color'; + +import { ThemeDefinition } from '../themes/Theme'; +import { getComputedStyleValue } from '../utils/styles'; + +interface ColorThemeInterface { + COLOR_SCALE: string[]; +} + +/** + * ECharts skeleton color theme + * + * @private Not intended as public API and subject to change + */ +export const ColorTheme = (props: ColorThemeInterface): ThemeDefinition => { + const { COLOR_SCALE } = props; + + const labelProps = { + backgroundColor: COLOR_SCALE[0], + color: getComputedStyleValue(chart_echarts_skeleton_label_Color) + }; + + const axisProps = { + axisLabel: { ...labelProps }, + axisLine: { + lineStyle: { + color: getComputedStyleValue(chart_echarts_global_axis_axis_line_item_style_Color) + } + }, + axisTick: { + lineStyle: { + color: getComputedStyleValue(chart_echarts_global_axis_axis_tick_item_style_Color) + } + }, + splitArea: { + areaStyle: { + color: COLOR_SCALE + } + }, + splitLine: { + lineStyle: { + color: [COLOR_SCALE[0]] + } + } + }; + + return { + color: COLOR_SCALE, + backgroundColor: getComputedStyleValue(chart_echarts_BackgroundColor), // See https://echarts.apache.org/en/option.html#backgroundColor + bar: { + itemStyle: { + barBorderColor: COLOR_SCALE[0] + } + }, + boxplot: { + itemStyle: { + borderColor: COLOR_SCALE[0] + } + }, + candlestick: { + itemStyle: { + borderColor: COLOR_SCALE[0], + borderColor0: COLOR_SCALE[1], + color: COLOR_SCALE[0], + color0: COLOR_SCALE[1] + } + }, + categoryAxis: { ...axisProps }, + dataZoom: {}, + funnel: { + itemStyle: { + borderColor: COLOR_SCALE[0] + } + }, + gauge: { + itemStyle: { + borderColor: COLOR_SCALE[0] + } + }, + geo: { + emphasis: { + itemStyle: { + areaColor: COLOR_SCALE[0], + borderColor: COLOR_SCALE[0] + }, + label: { ...labelProps } + }, + itemStyle: { + areaColor: COLOR_SCALE[0], + borderColor: COLOR_SCALE[0] + }, + label: { ...labelProps } + }, + graph: { + color: COLOR_SCALE, + itemStyle: { + borderColor: COLOR_SCALE[0] + }, + label: { ...labelProps }, + lineStyle: { + color: COLOR_SCALE[0] + } + }, + label: { ...labelProps }, + legend: { + textStyle: { ...labelProps } + }, + line: {}, + logAxis: { ...axisProps }, + map: { + emphasis: { + itemStyle: { + areaColor: COLOR_SCALE[0], + borderColor: COLOR_SCALE[0] + }, + label: { ...labelProps } + }, + itemStyle: { + areaColor: COLOR_SCALE[0], + borderColor: COLOR_SCALE[0] + }, + label: { ...labelProps } + }, + markPoint: { + emphasis: { + label: { ...labelProps } + }, + label: { ...labelProps } + }, + parallel: { + itemStyle: { + borderColor: COLOR_SCALE[0] + } + }, + pie: { + itemStyle: { + borderColor: COLOR_SCALE[0] + } + }, + radar: {}, + sankey: { + itemStyle: { + borderColor: COLOR_SCALE[0] + } + }, + scatter: { + itemStyle: { + borderColor: COLOR_SCALE[0] + } + }, + textStyle: {}, + timeAxis: { ...axisProps }, + timeline: { + emphasis: { + controlStyle: { + color: COLOR_SCALE[0], + borderColor: COLOR_SCALE[0] + }, + itemStyle: { + color: COLOR_SCALE[0] + }, + label: { ...labelProps } + }, + checkpointStyle: { + color: COLOR_SCALE[0], + borderColor: COLOR_SCALE[0] + }, + controlStyle: { + color: COLOR_SCALE[0], + borderColor: COLOR_SCALE[0] + }, + itemStyle: { + color: COLOR_SCALE[0] + }, + label: { ...labelProps }, + lineStyle: { + color: COLOR_SCALE[0] + } + }, + title: { + subtextStyle: { ...labelProps }, + textStyle: { ...labelProps } + }, + toolbox: { + emphasis: { + iconStyle: { + borderColor: COLOR_SCALE[0] + } + }, + iconStyle: { + borderColor: COLOR_SCALE[0] + } + }, + tooltip: { + axisPointer: { + crossStyle: { + color: COLOR_SCALE[0] + }, + lineStyle: { + color: COLOR_SCALE[0] + } + } + }, + valueAxis: { ...axisProps }, + visualMap: { + color: COLOR_SCALE + } + }; +}; diff --git a/packages/react-charts/src/echarts/components/utils/observe.ts b/packages/react-charts/src/echarts/components/utils/observe.ts new file mode 100644 index 00000000000..293776f91a8 --- /dev/null +++ b/packages/react-charts/src/echarts/components/utils/observe.ts @@ -0,0 +1,37 @@ +/** + * Mutation Observer Helper function -- see developer.mozilla.org/en-US/docs/Web/API/MutationObserver/observe + * + * @param {string} selector The DOM selector to watch + * @param {object} opt MutationObserver options + * @param {function} cb Pass Mutation object to a callback function + * @private Not intended as public API and subject to change + */ +export const observe = (selector: any, opt: any, cb: any) => { + let unobserve: any; + + if (selector) { + const Obs = new MutationObserver((m) => [...m].forEach(cb)); + document.querySelectorAll(selector).forEach((el) => Obs.observe(el, opt)); + unobserve = () => Obs.disconnect(); + } + return () => { + if (unobserve) { + unobserve(); + } + }; +}; + +// See https://stackoverflow.com/questions/17134823/detect-element-style-changes-with-javascript +export const getMutationObserver = (nodeSelector: string, cb: any) => + observe( + nodeSelector, + { + attributesList: ['style'], // Only the "style" attribute + attributeOldValue: true // Report also the oldValue + }, + (m: any) => { + if (cb) { + cb(m); + } + } + ); diff --git a/packages/react-charts/src/echarts/components/utils/styles.ts b/packages/react-charts/src/echarts/components/utils/styles.ts new file mode 100644 index 00000000000..862be8950dd --- /dev/null +++ b/packages/react-charts/src/echarts/components/utils/styles.ts @@ -0,0 +1,50 @@ +/** + * Copied from exenv + * + * @private Not intended as public API and subject to change + */ +export const canUseDOM = !!(typeof window !== 'undefined' && window.document && window.document.createElement); + +/** + * Returns the class name that will be applied to the outermost div rendered by the chart's container + * + * @private Not intended as public API and subject to change + */ +export const getClassName = (className: string) => { + let cleanClassName; + + // Cleanup class name + if (className) { + cleanClassName = className + .replace(/pf-v6-c-chart/g, '') + .replace(/pf-c-chart/g, '') + .replace(/\s+/g, ' ') + .trim(); + } + return cleanClassName?.length ? `pf-v6-c-chart ${cleanClassName}` : 'pf-v6-c-chart'; +}; + +/** + * Get computed style value -- see https://github.com/apache/echarts/issues/19743 + * + * Note that Victory uses the style property to apply CSS variables. However, ECharts' LineChart uses `fill` and + * `stroke` attributes, which doesn't work with CSS variables. In addition, using CSS variables with Sankey + * causes sever flashing during mouse hover. Therefore, we will obtain the CSS computed value from the DOM. + * + * @public + * @beta + */ +export const getComputedStyleValue = (token: { name: string; value: string | number; var: string }) => { + let result: any; + + if (canUseDOM) { + result = window.getComputedStyle(document.body)?.getPropertyValue(token.name); + + if (result === '') { + result = undefined; + } else if (!isNaN(result) || result === 'true' || result === 'false') { + result = JSON.parse(result); + } + } + return result !== undefined ? result : token.value; +}; diff --git a/packages/react-charts/src/echarts/components/utils/symbol.tsx b/packages/react-charts/src/echarts/components/utils/symbol.tsx new file mode 100644 index 00000000000..1c1bc4032fa --- /dev/null +++ b/packages/react-charts/src/echarts/components/utils/symbol.tsx @@ -0,0 +1,165 @@ +import { getComputedStyleValue } from './styles'; + +import chart_echarts_BackgroundColor from '@patternfly/react-tokens/dist/esm/chart_echarts_BackgroundColor'; + +const enum SymbolType { + arrow = 'arrow', + circle = 'circle', + diamond = 'diamond', + emptyArrow = 'emptyArrow', + emptyCircle = 'emptyCircle', + emptyDiamond = 'emptyDiamond', + emptyPin = 'emptyPin', + emptyRect = 'emptyRect', + emptyRoundRect = 'emptyRoundRect', + emptySquare = 'emptySquare', + emptyTriangle = 'emptyTriangle', + pin = 'pin', + rect = 'rect', + roundRect = 'roundRect', + square = 'square', + triangle = 'triangle' +} + +// ECharts icon types -- see https://svg-path.com/ +const symbols = { + arrow: 'M12.5 7L19.9667 18.2L12.5 15.4L5.0333 18.2L12.5 7Z', + circle: 'M18.1 7A5.6 5.6 0 1 1 18.1 6.9994Z', + diamond: 'M12.5 1.4L18.1 7L12.5 12.6L6.9 7Z', + emptyArrow: 'M12.5 7L19.9667 18.2L12.5 15.4L5.0333 18.2L12.5 7Z', + emptyCircle: 'M18.1 7A5.6 5.6 0 1 1 18.1 6.9994Z', + emptyDiamond: 'M12.5 1.4L18.1 7L12.5 12.6L6.9 7Z', + emptyPin: + 'M9.4642 2.04A3.36 3.36 0 1 1 15.5358 2.04C14.6718 3.8615 12.5 4.648 12.5 7C12.5 4.648 10.3282 3.8615 9.4642 2.04Z', + emptyRect: 'M6.9,1.4 l14.2,0 l0,11.2 l-14.2,0 Z', + emptyRoundRect: + 'M9.7,1.4 L18.3,1.4 A2.8,2.8,0,0,1,21.1,4.2 L21.1,9.8 A2.8,2.8,0,0,1,18.3,12.6 L9.7,12.6 A2.8,2.8,0,0,1,6.9,9.8 L6.9,4.2 A2.8,2.8,0,0,1,9.7,1.4 Z', + emptySquare: 'M6.9 1.4l11.2 0l0 11.2l-11.2 0Z', + emptyTriangle: 'M12.5 1.4L18.1 12.5L12.5 12.5L6.9 12.5Z', + pin: 'M9.4642 2.04A3.36 3.36 0 1 1 15.5358 2.04C14.6718 3.8615 12.5 4.648 12.5 7C12.5 4.648 10.3282 3.8615 9.4642 2.04Z', + rect: 'M6.9,1.4 l18.2,0 l0,11.2 l-18.2,0 Z', + roundRect: + 'M9.7,1.4 L22.3,1.4 A2.8,2.8,0,0,1,25.1,4.2 L25.1,9.8 A2.8,2.8,0,0,1,22.3,12.6 L9.7,12.6 A2.8,2.8,0,0,1,6.9,9.8 L6.9,4.2 A2.8,2.8,0,0,1,9.7,1.4 Z', + square: 'M6.9 1.4l11.2 0l0 11.2l-11.2 0Z', + triangle: 'M12.5 1.4L18.1 12.5L12.5 12.5L6.9 12.5Z' +}; + +/** + * Returns marker -- see https://github.com/apache/echarts/issues/19826 + * + * @param serie + * @param symbol + * @param color + * @private Not intended as public API and subject to change + */ +export const getMarker = (serie: any, symbol: string, color: string = '') => { + const size = 18; + let path; + let pathStyle = `fill:${color};`; + const svgStyle = 'vertical-align: middle;'; + + let transform; + + // Set marker type + switch (symbol) { + case SymbolType.arrow: + case SymbolType.circle: + case SymbolType.diamond: + case SymbolType.emptyArrow: + case SymbolType.emptyCircle: + case SymbolType.emptyDiamond: + case SymbolType.emptyPin: + case SymbolType.emptyRect: + case SymbolType.emptyRoundRect: + case SymbolType.emptySquare: + case SymbolType.emptyTriangle: + case SymbolType.pin: + case SymbolType.rect: + case SymbolType.roundRect: + case SymbolType.square: + case SymbolType.triangle: + path = symbols[symbol]; + break; + default: + path = symbols.square; + break; + } + + // Set path style for EChart symbols + switch (symbol) { + case SymbolType.emptyArrow: + case SymbolType.emptyCircle: + case SymbolType.emptyDiamond: + case SymbolType.emptyPin: + case SymbolType.emptyRect: + case SymbolType.emptyRoundRect: + case SymbolType.emptySquare: + case SymbolType.emptyTriangle: + pathStyle = `fill:${getComputedStyleValue(chart_echarts_BackgroundColor)}; stroke:${color}; stroke-width:2`; + break; + default: + pathStyle = `fill:${color}; margin-left:-50px;`; + } + + // Set SVG style for EChart symbols + switch (symbol) { + case SymbolType.arrow: + case SymbolType.emptyArrow: + transform = `translate(-5 -5)`; + break; + case SymbolType.emptyDiamond: + transform = `translate(-5 5)`; + break; + case SymbolType.emptyRect: + case SymbolType.emptyRoundRect: + transform = `translate(-5 0)`; + break; + case SymbolType.pin: + transform = `translate(-5 5)`; + break; + case SymbolType.rect: + transform = `translate(-7 0)`; + break; + case SymbolType.roundRect: + transform = `translate(-7 0)`; + break; + default: + transform = `translate(-5 0)`; + break; + } + + const marker = ``; + const svg = `${marker}`; + + return svg; +}; + +/** + * Returns default symbol + * + * @param series + * @param seriesIndex + * @param echart + * @private Not intended as public API and subject to change + */ +export const getSymbol = (series: any, seriesIndex: number, echart: any) => { + const ase = echart?.getModel().findComponents({ mainType: 'series' }); + const data = ase[seriesIndex].getData(); + const symbol = data?.getVisual('symbol')?.replace(/"/g, ''); + + if (!symbol) { + const serie = series[seriesIndex]; + if (serie?.symbol) { + return serie?.symbol; + } + switch (serie?.type) { + case 'bar': + return SymbolType.rect; + case 'line': + return SymbolType.square; + default: + break; + } + } + return symbol; +}; diff --git a/packages/react-charts/src/echarts/components/utils/theme.ts b/packages/react-charts/src/echarts/components/utils/theme.ts new file mode 100644 index 00000000000..f4f9c996c6a --- /dev/null +++ b/packages/react-charts/src/echarts/components/utils/theme.ts @@ -0,0 +1,68 @@ +import cloneDeep from 'lodash/cloneDeep'; +import merge from 'lodash/merge'; +import { ThemeColor } from '../themes/ThemeColor'; +import { ThemeDefinition } from '../themes/Theme'; +import { BaseTheme } from '../themes/base-theme'; +import { getBlueColorTheme } from '../themes/colors/blue-theme'; +import { getTealColorTheme } from '../themes/colors/teal-theme'; +import { getYellowColorTheme } from '../themes/colors/yellow-theme'; +import { getGrayColorTheme } from '../themes/colors/gray-theme'; +import { getGreenColorTheme } from '../themes/colors/green-theme'; +import { getSkeletonColorTheme } from '../themes/colors/skeleton-theme'; +import { getMultiColorOrderedTheme } from '../themes/colors/multi-ordered-theme'; +import { getMultiColorUnorderedTheme } from '../themes/colors/multi-unordered-theme'; +import { getOrangeColorTheme } from '../themes/colors/orange-theme'; +import { getPurpleColorTheme } from '../themes/colors/purple-theme'; + +/** + * Apply custom properties to base and color themes + * + * @param themeColor The theme color to merge with custom theme + * @param customTheme The custom theme to merge + * @public + * @beta + */ +export const getCustomTheme = (themeColor: string, customTheme: ThemeDefinition): ThemeDefinition => + merge(getTheme(themeColor), customTheme); + +/** + * Returns base theme for given color + * @public + * @beta + */ +export const getTheme = (themeColor: string): ThemeDefinition => { + const baseTheme = cloneDeep(BaseTheme()); + return merge(baseTheme, getThemeColors(themeColor)); +}; + +/** + * Returns computed theme colors + * @private Not intended as public API and subject to change + */ +const getThemeColors = (themeColor: string) => { + switch (themeColor) { + case ThemeColor.blue: + return getBlueColorTheme(); + case ThemeColor.teal: + return getTealColorTheme(); + case ThemeColor.yellow: + return getYellowColorTheme(); + case ThemeColor.gray: + return getGrayColorTheme(); + case ThemeColor.green: + return getGreenColorTheme(); + case ThemeColor.multi: + case ThemeColor.multiOrdered: + return getMultiColorOrderedTheme(); + case ThemeColor.multiUnordered: + return getMultiColorUnorderedTheme(); + case ThemeColor.orange: + return getOrangeColorTheme(); + case ThemeColor.purple: + return getPurpleColorTheme(); + case ThemeColor.skeleton: + return getSkeletonColorTheme(); + default: + return getBlueColorTheme(); + } +}; diff --git a/packages/react-charts/src/echarts/components/utils/tooltip.tsx b/packages/react-charts/src/echarts/components/utils/tooltip.tsx new file mode 100644 index 00000000000..6c3558a0c3d --- /dev/null +++ b/packages/react-charts/src/echarts/components/utils/tooltip.tsx @@ -0,0 +1,102 @@ +import defaultsDeep from 'lodash/defaultsDeep'; + +import { ChartsOptionProps } from '../Charts'; +import { getMarker, getSymbol } from './symbol'; + +/** + * Returns a custom legend tooltip for Line charts + * + * @param series + * @param option + * @param echart + * @private Not intended as public API and subject to change + */ +export const getLegendTooltip = (series: any[], option: ChartsOptionProps, echart: any) => { + const tooltip = option?.tooltip as any; + const valueFormatter = tooltip?.valueFormatter ? tooltip.valueFormatter : (value: number | string) => value; + + const defaults = { + confine: true, + formatter: (params: any) => { + let result = ''; + params?.map((param, index) => { + if (index === 0) { + result += `

${param.name}

`; + } + const symbol = getSymbol(series, param.seriesIndex, echart); + const marker = getMarker(series[param.seriesIndex], symbol, param.color); + const formattedValue = valueFormatter(param.value, param.dataIndex); + const seriesName = `${param.seriesName}`; + const value = `${formattedValue}`; + + result += `

${marker}${seriesName}${value}

`; + }); + return result; + }, + trigger: 'axis' + }; + return defaultsDeep(tooltip, defaults); +}; + +/** + * Returns source and target colors from given series + * + * @param series + * @param formatterParams + * @private Not intended as public API and subject to change + */ +const getItemColor = (series: any[], formatterParams: any) => { + const serie = series[formatterParams.seriesIndex]; + const sourceData = serie?.data.find((datum: any) => datum.name === formatterParams.data?.source); + const targetData = serie?.data.find((datum: any) => datum.name === formatterParams.data?.target); + const sourceColor = sourceData?.itemStyle?.color; + const targetColor = targetData?.itemStyle?.color; + return { sourceColor, targetColor }; +}; + +/** + * Returns a custom legend tooltip for Sankey chart + * + * @param series + * @param option + * @private Not intended as public API and subject to change + */ +export const getSankeyTooltip = (series: any[], option: ChartsOptionProps) => { + const symbolSize = '10px'; + const tooltip = option?.tooltip as any; + const sourceLabel = tooltip?.sourceLabel ? tooltip.sourceLabel : ''; + const destinationLabel = tooltip?.destinationLabel ? tooltip.destinationLabel : ''; + const valueFormatter = tooltip?.valueFormatter ? tooltip.valueFormatter : (value: number | string) => value; + + const defaults = { + confine: true, + formatter: (params: any) => { + let result; + if (params?.data?.source && params?.data?.target) { + const { sourceColor, targetColor } = getItemColor(series, params); + result = ` +

${sourceLabel}

+
+ ${params.data.source} +

${destinationLabel}

+

+

+ ${params.data.target} + + ${valueFormatter(params.value, params.dataIndex)} + +

+ `; + } else { + result = ` +
+ ${params.name} ${valueFormatter(params.value, params.dataIndex)} + `; + } + return result.replace(/\s\s+/g, ' '); + }, + trigger: 'item', + triggerOn: 'mousemove' + }; + return defaultsDeep(tooltip, defaults); +}; diff --git a/packages/react-charts/src/index.ts b/packages/react-charts/src/echarts/index.ts similarity index 100% rename from packages/react-charts/src/index.ts rename to packages/react-charts/src/echarts/index.ts diff --git a/packages/react-charts/src/echarts/typings/echarts.d.ts b/packages/react-charts/src/echarts/typings/echarts.d.ts new file mode 100644 index 00000000000..497834cab88 --- /dev/null +++ b/packages/react-charts/src/echarts/typings/echarts.d.ts @@ -0,0 +1,7 @@ +import * as echarts from 'echarts/types/dist/core'; + +declare module 'echarts' { + export const registerTheme: echarts.registerTheme; + export const init: echarts.init; + export type ECharts = any; +} diff --git a/packages/react-charts/src/components/Chart/Chart.test.tsx b/packages/react-charts/src/victory/components/Chart/Chart.test.tsx similarity index 97% rename from packages/react-charts/src/components/Chart/Chart.test.tsx rename to packages/react-charts/src/victory/components/Chart/Chart.test.tsx index 160c3bfb7c7..e7ec1c59d35 100644 --- a/packages/react-charts/src/components/Chart/Chart.test.tsx +++ b/packages/react-charts/src/victory/components/Chart/Chart.test.tsx @@ -1,4 +1,3 @@ -import * as React from 'react'; import { render } from '@testing-library/react'; import { Chart } from './Chart'; import { ChartGroup } from '../ChartGroup/ChartGroup'; diff --git a/packages/react-charts/src/components/Chart/Chart.tsx b/packages/react-charts/src/victory/components/Chart/Chart.tsx similarity index 95% rename from packages/react-charts/src/components/Chart/Chart.tsx rename to packages/react-charts/src/victory/components/Chart/Chart.tsx index 16686373e15..41790cf2f91 100644 --- a/packages/react-charts/src/components/Chart/Chart.tsx +++ b/packages/react-charts/src/victory/components/Chart/Chart.tsx @@ -1,7 +1,6 @@ -import * as React from 'react'; +import { Children, cloneElement, isValidElement, useEffect } from 'react'; import hoistNonReactStatics from 'hoist-non-react-statics'; -/* eslint-disable camelcase */ import chart_legend_Margin from '@patternfly/react-tokens/dist/esm/chart_legend_Margin'; import { @@ -30,7 +29,6 @@ import { getComputedLegend, getLegendItemsExtraHeight, getLegendMaxTextWidth } f import { getPaddingForSide } from '../ChartUtils/chart-padding'; import { getPatternDefs, mergePatternData, useDefaultPatternProps } from '../ChartUtils/chart-patterns'; import { getChartTheme } from '../ChartUtils/chart-theme-types'; -import { useEffect } from 'react'; import { ChartLabel } from '../ChartLabel/ChartLabel'; import { ChartPoint } from '../ChartPoint/ChartPoint'; import { ChartThemeColor } from '../ChartTheme/ChartThemeColor'; @@ -69,9 +67,9 @@ export interface ChartProps extends VictoryChartProps { * The backgroundComponent prop takes a component instance which will be responsible for rendering a background if the * Chart's style component includes background styles. The new element created from the passed backgroundComponent * will be provided with the following properties calculated by Chart: height, polar, scale, style, x, y, width. - * All of these props on Background should take prececence over what VictoryChart is trying to set. + * All of these props on Background should take precedence over what VictoryChart is trying to set. */ - backgroundComponent?: React.ReactElement; + backgroundComponent?: React.ReactElement; /** * The children to render with the chart */ @@ -95,14 +93,14 @@ export interface ChartProps extends VictoryChartProps { /** * Note: This prop should not be set manually. * - * @private + * @private Not intended as public API and subject to change * @hide */ defaultAxes?: AxesType; /** * Note: This prop should not be set manually. * - * @private + * @private Not intended as public API and subject to change * @hide */ defaultPolarAxes?: AxesType; @@ -152,7 +150,7 @@ export interface ChartProps extends VictoryChartProps { * events. The eventKey may optionally be used to select a single element by index rather than * an entire set. The eventHandlers object should be given as an object whose keys are standard * event names (i.e. onClick) and whose values are event callbacks. The return value - * of an event handler is used to modify elemnts. The return value should be given + * of an event handler is used to modify elements. The return value should be given * as an object or an array of objects with optional target and eventKey keys, * and a mutation key whose value is a function. The target and eventKey keys * will default to those corresponding to the element the event handler was attached to. @@ -349,7 +347,7 @@ export interface ChartProps extends VictoryChartProps { /** * Note: This prop should not be set manually. * - * @private + * @private Not intended as public API and subject to change * @hide */ prependDefaultAxes?: boolean; @@ -392,7 +390,7 @@ export interface ChartProps extends VictoryChartProps { * * Note: This prop should not be set manually. * - * @private + * @private Not intended as public API and subject to change * @hide */ sharedEvents?: { events: any[]; getEventState: Function }; @@ -513,7 +511,7 @@ export const Chart: React.FunctionComponent = ({ containerComponent.props.labelComponent && containerComponent.props.labelComponent.type.displayName === 'ChartLegendTooltip' ) { - labelComponent = React.cloneElement(containerComponent.props.labelComponent, { + labelComponent = cloneElement(containerComponent.props.labelComponent, { theme, ...(defaultPatternScale && { patternScale: defaultPatternScale }), ...containerComponent.props.labelComponent.props @@ -521,7 +519,7 @@ export const Chart: React.FunctionComponent = ({ } // Clone so users can override container props - const container = React.cloneElement(containerComponent, { + const container = cloneElement(containerComponent, { desc: ariaDesc, title: ariaTitle, theme, @@ -536,7 +534,7 @@ export const Chart: React.FunctionComponent = ({ legendXOffset = getLegendMaxTextWidth(legendData, theme); } - const legend = React.cloneElement(legendComponent, { + const legend = cloneElement(legendComponent, { data: legendData, ...(name && { name: `${name}-${(legendComponent as any).type.displayName}` }), orientation: legendOrientation, @@ -544,14 +542,14 @@ export const Chart: React.FunctionComponent = ({ themeColor, ...(legendDirection === 'rtl' && { dataComponent: legendComponent.props.dataComponent ? ( - React.cloneElement(legendComponent.props.dataComponent, { transform: `translate(${legendXOffset})` }) + cloneElement(legendComponent.props.dataComponent, { transform: `translate(${legendXOffset})` }) ) : ( ) }), ...(legendDirection === 'rtl' && { labelComponent: legendComponent.props.labelComponent ? ( - React.cloneElement(legendComponent.props.labelComponent, { direction: 'rtl', dx: legendXOffset - 30 }) + cloneElement(legendComponent.props.labelComponent, { direction: 'rtl', dx: legendXOffset - 30 }) ) : ( ) @@ -570,8 +568,8 @@ export const Chart: React.FunctionComponent = ({ let legendTitleHeight = legend.props.title ? 10 : 0; // Adjust for axis label - React.Children.toArray(children).map((child: any) => { - if (child.type.role === 'axis' && child.props.label && !child.props.dependentAxis) { + Children.toArray(children).map((child: any) => { + if (child.type.role === 'axis' && child.props.label && child.props.fixAxisLabelHeight) { xAxisLabelHeight = getLabelTextSize({ text: child.props.label, theme }).height + 10; legendTitleHeight = 0; } @@ -608,10 +606,10 @@ export const Chart: React.FunctionComponent = ({ // Render children const renderChildren = () => - React.Children.toArray(children).map((child, index) => { - if (React.isValidElement(child)) { - const { ...childProps } = child.props; - return React.cloneElement(child, { + Children.toArray(children).map((child, index) => { + if (isValidElement(child)) { + const { ...childProps } = child.props as any; + return cloneElement(child, { colorScale, ...(defaultPatternScale && { patternScale: defaultPatternScale }), ...(name && diff --git a/packages/react-charts/src/components/Chart/__snapshots__/Chart.test.tsx.snap b/packages/react-charts/src/victory/components/Chart/__snapshots__/Chart.test.tsx.snap similarity index 65% rename from packages/react-charts/src/components/Chart/__snapshots__/Chart.test.tsx.snap rename to packages/react-charts/src/victory/components/Chart/__snapshots__/Chart.test.tsx.snap index 5d14bd92897..a4fce2ae5da 100644 --- a/packages/react-charts/src/components/Chart/__snapshots__/Chart.test.tsx.snap +++ b/packages/react-charts/src/victory/components/Chart/__snapshots__/Chart.test.tsx.snap @@ -9,7 +9,7 @@ exports[`Chart 1`] = ` @@ -19,7 +19,7 @@ exports[`Chart 1`] = ` @@ -63,7 +63,7 @@ exports[`Chart 1`] = ` @@ -94,7 +94,7 @@ exports[`Chart 1`] = ` @@ -125,7 +125,7 @@ exports[`Chart 1`] = ` @@ -156,7 +156,7 @@ exports[`Chart 1`] = ` @@ -188,7 +188,7 @@ exports[`Chart 1`] = ` @@ -232,7 +232,7 @@ exports[`Chart 1`] = ` @@ -263,7 +263,7 @@ exports[`Chart 1`] = ` @@ -294,7 +294,7 @@ exports[`Chart 1`] = ` @@ -325,7 +325,7 @@ exports[`Chart 1`] = ` @@ -353,11 +353,11 @@ exports[`Chart 1`] = `
@@ -375,7 +375,7 @@ exports[`Chart 2`] = ` @@ -385,7 +385,7 @@ exports[`Chart 2`] = ` @@ -429,7 +429,7 @@ exports[`Chart 2`] = ` @@ -460,7 +460,7 @@ exports[`Chart 2`] = ` @@ -491,7 +491,7 @@ exports[`Chart 2`] = ` @@ -522,7 +522,7 @@ exports[`Chart 2`] = ` @@ -554,7 +554,7 @@ exports[`Chart 2`] = ` @@ -598,7 +598,7 @@ exports[`Chart 2`] = ` @@ -629,7 +629,7 @@ exports[`Chart 2`] = ` @@ -660,7 +660,7 @@ exports[`Chart 2`] = ` @@ -691,7 +691,7 @@ exports[`Chart 2`] = ` @@ -719,11 +719,11 @@ exports[`Chart 2`] = `
@@ -741,7 +741,7 @@ exports[`renders axis and component children 1`] = ` @@ -849,7 +849,7 @@ exports[`renders axis and component children 1`] = ` @@ -893,7 +893,7 @@ exports[`renders axis and component children 1`] = ` @@ -924,7 +924,7 @@ exports[`renders axis and component children 1`] = ` @@ -955,7 +955,7 @@ exports[`renders axis and component children 1`] = ` @@ -986,7 +986,7 @@ exports[`renders axis and component children 1`] = ` @@ -1017,7 +1017,7 @@ exports[`renders axis and component children 1`] = ` @@ -1048,7 +1048,7 @@ exports[`renders axis and component children 1`] = ` @@ -1080,7 +1080,7 @@ exports[`renders axis and component children 1`] = ` @@ -1124,7 +1124,7 @@ exports[`renders axis and component children 1`] = ` @@ -1155,7 +1155,7 @@ exports[`renders axis and component children 1`] = ` @@ -1186,7 +1186,7 @@ exports[`renders axis and component children 1`] = ` @@ -1214,11 +1214,11 @@ exports[`renders axis and component children 1`] = `
diff --git a/packages/react-charts/src/components/ChartArea/ChartArea.test.tsx b/packages/react-charts/src/victory/components/ChartArea/ChartArea.test.tsx similarity index 94% rename from packages/react-charts/src/components/ChartArea/ChartArea.test.tsx rename to packages/react-charts/src/victory/components/ChartArea/ChartArea.test.tsx index ee1cc9fc1a6..cec3c0c45ef 100644 --- a/packages/react-charts/src/components/ChartArea/ChartArea.test.tsx +++ b/packages/react-charts/src/victory/components/ChartArea/ChartArea.test.tsx @@ -1,4 +1,3 @@ -import * as React from 'react'; import { render } from '@testing-library/react'; import { ChartArea } from '../ChartArea/ChartArea'; diff --git a/packages/react-charts/src/components/ChartArea/ChartArea.tsx b/packages/react-charts/src/victory/components/ChartArea/ChartArea.tsx similarity index 98% rename from packages/react-charts/src/components/ChartArea/ChartArea.tsx rename to packages/react-charts/src/victory/components/ChartArea/ChartArea.tsx index b093f358cff..0978e7d8eb7 100644 --- a/packages/react-charts/src/components/ChartArea/ChartArea.tsx +++ b/packages/react-charts/src/victory/components/ChartArea/ChartArea.tsx @@ -1,4 +1,4 @@ -import * as React from 'react'; +import { cloneElement } from 'react'; import hoistNonReactStatics from 'hoist-non-react-statics'; import { AnimatePropTypeInterface, @@ -129,7 +129,7 @@ export interface ChartAreaProps extends VictoryAreaProps { * Since ChartArea only renders a single element, the eventKey property is not used. * The eventHandlers object should be given as an object whose keys are standard * event names (i.e. onClick) and whose values are event callbacks. The return value - * of an event handler is used to modify elemnts. The return value should be given + * of an event handler is used to modify elements. The return value should be given * as an object or an array of objects with optional target and eventKey keys, * and a mutation key whose value is a function. The target and eventKey keys * will default to those corresponding to the element the event handler was attached to. @@ -311,7 +311,7 @@ export interface ChartAreaProps extends VictoryAreaProps { * * Note: This prop should not be set manually. * - * @private + * @private Not intended as public API and subject to change * @hide */ sharedEvents?: { events: any[]; getEventState: Function }; @@ -433,7 +433,7 @@ export const ChartArea: React.FunctionComponent = ({ ...rest }: ChartAreaProps) => { // Clone so users can override container props - const container = React.cloneElement(containerComponent, { + const container = cloneElement(containerComponent, { theme, ...containerComponent.props }); diff --git a/packages/react-charts/src/components/ChartArea/__snapshots__/ChartArea.test.tsx.snap b/packages/react-charts/src/victory/components/ChartArea/__snapshots__/ChartArea.test.tsx.snap similarity index 82% rename from packages/react-charts/src/components/ChartArea/__snapshots__/ChartArea.test.tsx.snap rename to packages/react-charts/src/victory/components/ChartArea/__snapshots__/ChartArea.test.tsx.snap index f4f3ce7bc1e..2dbee18d2fd 100644 --- a/packages/react-charts/src/components/ChartArea/__snapshots__/ChartArea.test.tsx.snap +++ b/packages/react-charts/src/victory/components/ChartArea/__snapshots__/ChartArea.test.tsx.snap @@ -9,7 +9,7 @@ exports[`ChartArea 1`] = ` @@ -34,16 +34,16 @@ exports[`ChartArea 1`] = ` d="M50,250L57,246L64,242L71,238L78,234L85,230L92,226L99,222L106,218L113,214.00000000000003L120,210L127,206L134,202L141,198L148,194L155,190L162,185.99999999999997L169,181.99999999999997L176,178L183,174L190,170L197,166.00000000000003L204,162L211,158L218,154L225,150L232,146L239,142L246.00000000000003,138L252.99999999999997,134L260,130L267,126L274,122L281,117.99999999999999L288,113.99999999999999L295,109.99999999999999L302,106L309,102L316,98L323,94L330,89.99999999999999L337,85.99999999999999L344,82L351,78L358,74L365,70L372,65.99999999999999L379,61.999999999999986L386,58.00000000000001L393,54.00000000000001L400,50L400,250L393,250L386,250L379,250L372,250L365,250L358,250L351,250L344,250L337,250L330,250L323,250L316,250L309,250L302,250L295,250L288,250L281,250L274,250L267,250L260,250L252.99999999999997,250L246.00000000000003,250L239,250L232,250L225,250L218,250L211,250L204,250L197,250L190,250L183,250L176,250L169,250L162,250L155,250L148,250L141,250L134,250L127,250L120,250L113,250L106,250L99,250L92,250L85,250L78,250L71,250L64,250L57,250L50,250Z" role="presentation" shape-rendering="auto" - style="fill: var(--pf-v6-chart-theme--blue--ColorScale--100, #0066cc); fill-opacity: 0.3; stroke-width: 2; stroke: var(--pf-v6-chart-theme--blue--ColorScale--100, #0066cc);" + style="fill: var(--pf-v6-chart-theme--blue--ColorScale--100, #0066cc); fill-opacity: var(--pf-v6-chart-area--Opacity, 30%); stroke-width: 2; stroke: var(--pf-v6-chart-theme--blue--ColorScale--100, #0066cc);" />
@@ -61,7 +61,7 @@ exports[`ChartArea 2`] = ` @@ -86,16 +86,16 @@ exports[`ChartArea 2`] = ` d="M50,250L57,246L64,242L71,238L78,234L85,230L92,226L99,222L106,218L113,214.00000000000003L120,210L127,206L134,202L141,198L148,194L155,190L162,185.99999999999997L169,181.99999999999997L176,178L183,174L190,170L197,166.00000000000003L204,162L211,158L218,154L225,150L232,146L239,142L246.00000000000003,138L252.99999999999997,134L260,130L267,126L274,122L281,117.99999999999999L288,113.99999999999999L295,109.99999999999999L302,106L309,102L316,98L323,94L330,89.99999999999999L337,85.99999999999999L344,82L351,78L358,74L365,70L372,65.99999999999999L379,61.999999999999986L386,58.00000000000001L393,54.00000000000001L400,50L400,250L393,250L386,250L379,250L372,250L365,250L358,250L351,250L344,250L337,250L330,250L323,250L316,250L309,250L302,250L295,250L288,250L281,250L274,250L267,250L260,250L252.99999999999997,250L246.00000000000003,250L239,250L232,250L225,250L218,250L211,250L204,250L197,250L190,250L183,250L176,250L169,250L162,250L155,250L148,250L141,250L134,250L127,250L120,250L113,250L106,250L99,250L92,250L85,250L78,250L71,250L64,250L57,250L50,250Z" role="presentation" shape-rendering="auto" - style="fill: var(--pf-v6-chart-theme--blue--ColorScale--100, #0066cc); fill-opacity: 0.3; stroke-width: 2; stroke: var(--pf-v6-chart-theme--blue--ColorScale--100, #0066cc);" + style="fill: var(--pf-v6-chart-theme--blue--ColorScale--100, #0066cc); fill-opacity: var(--pf-v6-chart-area--Opacity, 30%); stroke-width: 2; stroke: var(--pf-v6-chart-theme--blue--ColorScale--100, #0066cc);" />
@@ -113,7 +113,7 @@ exports[`renders component data 1`] = ` @@ -138,16 +138,16 @@ exports[`renders component data 1`] = ` d="M50,192.85714285714286L166.66666666666666,135.71428571428572L283.3333333333333,67.14285714285712L400,50L400,250L283.3333333333333,250L166.66666666666666,250L50,250Z" role="presentation" shape-rendering="auto" - style="fill: var(--pf-v6-chart-theme--blue--ColorScale--100, #0066cc); fill-opacity: 0.3; stroke-width: 2; stroke: var(--pf-v6-chart-theme--blue--ColorScale--100, #0066cc);" + style="fill: var(--pf-v6-chart-theme--blue--ColorScale--100, #0066cc); fill-opacity: var(--pf-v6-chart-area--Opacity, 30%); stroke-width: 2; stroke: var(--pf-v6-chart-theme--blue--ColorScale--100, #0066cc);" />
diff --git a/packages/react-charts/src/victory/components/ChartArea/examples/ChartArea.md b/packages/react-charts/src/victory/components/ChartArea/examples/ChartArea.md new file mode 100644 index 00000000000..8211352198d --- /dev/null +++ b/packages/react-charts/src/victory/components/ChartArea/examples/ChartArea.md @@ -0,0 +1,60 @@ +--- +id: Area chart +section: components +subsection: charts +propComponents: [ + 'Chart', + 'ChartArea', + 'ChartAxis', + 'ChartGroup', + 'ChartThreshold', + 'ChartVoronoiContainer' +] +hideDarkMode: true +--- +import { createRef } from 'react'; +import { Chart, ChartArea, ChartAxis, ChartGroup, ChartThreshold, ChartThemeColor, ChartLegendTooltip, ChartVoronoiContainer, createContainer } from '@patternfly/react-charts/victory'; +import { getResizeObserver } from '@patternfly/react-core'; + +## Introduction +Note: PatternFly React charts live in its own package at [@patternfly/react-charts](https://www.npmjs.com/package/@patternfly/react-charts)! + +The examples below are based on the [Victory](https://formidable.com/open-source/victory/docs/victory-chart/) chart library, along with additional functionality, custom components, and theming for PatternFly. This provides a collection of React based components you can use to build PatternFly patterns with consistent markup, styling, and behavior. + +## Examples +### Basic with right aligned legend + +```ts file = "ChartAreaRightAlignedLegend.tsx" + +``` + +### Teal with bottom aligned legend and axis label + +This demonstrates how to combine cursor and voronoi containers to display tooltips along with a cursor. + +```ts file = "ChartAreaBottomLegend.tsx" + +``` + +### Multi-color (unordered) bottom-left aligned legend and responsive container +```ts file = "ChartAreaMultiColorResponsive.tsx" + +``` + +## Documentation +### Tips +- See Victory's [FAQ](https://formidable.com/open-source/victory/docs/faq) +- For single data points or zero values, you may want to set the `domain` prop +- `ChartLegend` may be used as a standalone component, instead of using `legendData` +- The `theme` and `themeColor` props should be applied at the most top level component +- Use `ChartGroup` to apply theme color scales and other properties to multiple components + +### Note +Currently, the generated documentation below is not able to resolve type definitions from Victory imports. For the +components used in the examples above, Victory pass-thru props are also documented here: + +- For `Chart` props, see [VictoryChart](https://formidable.com/open-source/victory/docs/victory-chart) +- For `ChartArea` props, see [VictoryArea](https://formidable.com/open-source/victory/docs/victory-area) +- For `ChartAxis` props, see [VictoryAxis](https://formidable.com/open-source/victory/docs/victory-axis) +- For `ChartGroup` props, see [VictoryGroup](https://formidable.com/open-source/victory/docs/victory-group) +- For `ChartVoronoiContainer` props, see [VictoryVoronoiContainer](https://formidable.com/open-source/victory/docs/victory-voronoi-container) diff --git a/packages/react-charts/src/victory/components/ChartArea/examples/ChartAreaBottomLegend.tsx b/packages/react-charts/src/victory/components/ChartArea/examples/ChartAreaBottomLegend.tsx new file mode 100644 index 00000000000..29e88b6f6c2 --- /dev/null +++ b/packages/react-charts/src/victory/components/ChartArea/examples/ChartAreaBottomLegend.tsx @@ -0,0 +1,87 @@ +import { + Chart, + ChartArea, + ChartAxis, + ChartGroup, + ChartThemeColor, + ChartLegendTooltip, + createContainer +} from '@patternfly/react-charts/victory'; + +interface PetData { + x: string; + y: number; +} + +export const ChartAreaBottomLegend: React.FunctionComponent = () => { + // 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 catsData: PetData[] = [ + { x: '2015', y: 3 }, + { x: '2016', y: 4 }, + { x: '2017', y: 8 }, + { x: '2018', y: 6 } + ]; + + const dogsData: PetData[] = [ + { x: '2015', y: 2 }, + { x: '2016', y: 3 }, + { x: '2017', y: 4 }, + { x: '2018', y: 5 }, + { x: '2019', y: 6 } + ]; + + const birdsData: PetData[] = [ + { x: '2015', y: 1 }, + { x: '2016', y: 2 }, + { x: '2017', y: 3 }, + { x: '2018', y: 2 }, + { x: '2019', y: 4 } + ]; + + return ( +
+ `${datum.y}`} + labelComponent={ datum.x} />} + mouseFollowTooltips + voronoiDimension="x" + voronoiPadding={50} + /> + } + legendData={legendData} + legendPosition="bottom" + height={250} + name="chart2" + padding={{ + bottom: 100, // Adjusted to accommodate legend + left: 50, + right: 50, + top: 50 + }} + maxDomain={{ y: 9 }} + themeColor={ChartThemeColor.teal} + width={650} + > + + + + + + + + +
+ ); +}; diff --git a/packages/react-charts/src/victory/components/ChartArea/examples/ChartAreaMultiColorResponsive.tsx b/packages/react-charts/src/victory/components/ChartArea/examples/ChartAreaMultiColorResponsive.tsx new file mode 100644 index 00000000000..8f6a91ca622 --- /dev/null +++ b/packages/react-charts/src/victory/components/ChartArea/examples/ChartAreaMultiColorResponsive.tsx @@ -0,0 +1,91 @@ +import { + Chart, + ChartArea, + ChartAxis, + ChartGroup, + ChartThemeColor, + ChartVoronoiContainer +} from '@patternfly/react-charts/victory'; +import { getResizeObserver } from '@patternfly/react-core'; + +interface PetData { + name: string; + x: string; + y: number; +} +export const ChartAreaMultiColorResponsive: React.FunctionComponent = () => { + const [width, setWidth] = React.useState(0); + const containerRef = React.useRef(null); + + const catsData: 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 dogsData: 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 birdsData: 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 = [{ name: 'Cats' }, { name: 'Dogs' }, { name: 'Birds' }]; + + const handleResize = () => { + if (containerRef.current && containerRef.current.clientWidth) { + setWidth(containerRef.current.clientWidth); + } + }; + React.useEffect(() => { + const observer = getResizeObserver(containerRef.current, handleResize); + handleResize(); + + return () => { + observer(); + }; + }, []); + + return ( +
+ `${datum.name}: ${datum.y}`} constrainToVisibleArea /> + } + legendData={legendData} + legendPosition="bottom-left" + height={225} + name="chart3" + padding={{ + bottom: 75, // Adjusted to accommodate legend + left: 50, + right: 50, + top: 50 + }} + maxDomain={{ y: 9 }} + themeColor={ChartThemeColor.multiUnordered} + width={width} + > + + + + + + + + +
+ ); +}; diff --git a/packages/react-charts/src/victory/components/ChartArea/examples/ChartAreaRightAlignedLegend.tsx b/packages/react-charts/src/victory/components/ChartArea/examples/ChartAreaRightAlignedLegend.tsx new file mode 100644 index 00000000000..0a88f0bc89e --- /dev/null +++ b/packages/react-charts/src/victory/components/ChartArea/examples/ChartAreaRightAlignedLegend.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 ChartAreaRightAlignedLegend: React.FunctionComponent = () => { + const catsData: 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 dogsData: 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 birdsData: 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 = [{ name: 'Cats' }, { name: 'Dogs' }, { name: 'Birds' }]; + + 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/components/ChartAxis/ChartAxis.test.tsx b/packages/react-charts/src/victory/components/ChartAxis/ChartAxis.test.tsx similarity index 98% rename from packages/react-charts/src/components/ChartAxis/ChartAxis.test.tsx rename to packages/react-charts/src/victory/components/ChartAxis/ChartAxis.test.tsx index dc4eae0592f..1e85ca81f32 100644 --- a/packages/react-charts/src/components/ChartAxis/ChartAxis.test.tsx +++ b/packages/react-charts/src/victory/components/ChartAxis/ChartAxis.test.tsx @@ -1,4 +1,3 @@ -import * as React from 'react'; import { render } from '@testing-library/react'; import { Chart } from '../Chart/Chart'; import { ChartGroup } from '../ChartGroup/ChartGroup'; diff --git a/packages/react-charts/src/components/ChartAxis/ChartAxis.tsx b/packages/react-charts/src/victory/components/ChartAxis/ChartAxis.tsx similarity index 97% rename from packages/react-charts/src/components/ChartAxis/ChartAxis.tsx rename to packages/react-charts/src/victory/components/ChartAxis/ChartAxis.tsx index b8ad8c9a1fd..4d48dd5a684 100644 --- a/packages/react-charts/src/components/ChartAxis/ChartAxis.tsx +++ b/packages/react-charts/src/victory/components/ChartAxis/ChartAxis.tsx @@ -1,4 +1,4 @@ -import * as React from 'react'; +import { cloneElement } from 'react'; import hoistNonReactStatics from 'hoist-non-react-statics'; import { AnimatePropTypeInterface, @@ -117,7 +117,7 @@ export interface ChartAxisProps extends VictoryAxisProps { * single element by index rather than an entire set. The eventHandlers object * should be given as an object whose keys are standard event names (i.e. onClick) * and whose values are event callbacks. The return value of an event handler - * be used to modify other elemnts. The return value should be given as an object or + * be used to modify other elements. The return value should be given as an object or * an array of objects with optional target and eventKey keys, and a mutation * key whose value is a function. The target and eventKey keys will default to those * corresponding to the element the event handler was attached to. The mutation @@ -157,6 +157,10 @@ export interface ChartAxisProps extends VictoryAxisProps { * @propType object[] */ externalEventMutations?: EventCallbackInterface[]; + /** + * When true, this prop adjusts the height between the axis label and bottom positioned legend + */ + fixAxisLabelHeight?: boolean; /** * When true, this prop reduces the number of tick labels to fit the length of the axis. * Labels are removed at approximately even intervals from the original array of labels. @@ -301,7 +305,7 @@ export interface ChartAxisProps extends VictoryAxisProps { * * Note: This prop should not be set manually. * - * @private + * @private Not intended as public API and subject to change * @hide */ sharedEvents?: { events: any[]; getEventState: Function }; @@ -454,13 +458,13 @@ export const ChartAxis: React.FunctionComponent = ({ const componentTheme = getComponentTheme(themeColor); // Clone so users can override container props - const container = React.cloneElement(containerComponent, { + const container = cloneElement(containerComponent, { theme, ...containerComponent.props }); const getAxisLabelComponent = () => - React.cloneElement(axisLabelComponent, { + cloneElement(axisLabelComponent, { ...(name && { id: () => `${name}-${(axisLabelComponent as any).type.displayName}` }), @@ -469,7 +473,7 @@ export const ChartAxis: React.FunctionComponent = ({ }); const getTickLabelComponent = () => - React.cloneElement(tickLabelComponent, { + cloneElement(tickLabelComponent, { ...(name && { id: (props: any) => `${name}-${(tickLabelComponent as any).type.displayName}-${props.index}` }), diff --git a/packages/react-charts/src/components/ChartAxis/__snapshots__/ChartAxis.test.tsx.snap b/packages/react-charts/src/victory/components/ChartAxis/__snapshots__/ChartAxis.test.tsx.snap similarity index 64% rename from packages/react-charts/src/components/ChartAxis/__snapshots__/ChartAxis.test.tsx.snap rename to packages/react-charts/src/victory/components/ChartAxis/__snapshots__/ChartAxis.test.tsx.snap index 115364b475c..2a2d7f87f09 100644 --- a/packages/react-charts/src/components/ChartAxis/__snapshots__/ChartAxis.test.tsx.snap +++ b/packages/react-charts/src/victory/components/ChartAxis/__snapshots__/ChartAxis.test.tsx.snap @@ -9,14 +9,14 @@ exports[`ChartAxis 1`] = ` @@ -60,7 +60,7 @@ exports[`ChartAxis 1`] = ` @@ -91,7 +91,7 @@ exports[`ChartAxis 1`] = ` @@ -122,7 +122,7 @@ exports[`ChartAxis 1`] = ` @@ -153,7 +153,7 @@ exports[`ChartAxis 1`] = ` @@ -184,7 +184,7 @@ exports[`ChartAxis 1`] = ` @@ -211,11 +211,11 @@ exports[`ChartAxis 1`] = `
@@ -233,14 +233,14 @@ exports[`ChartAxis 2`] = ` @@ -284,7 +284,7 @@ exports[`ChartAxis 2`] = ` @@ -315,7 +315,7 @@ exports[`ChartAxis 2`] = ` @@ -346,7 +346,7 @@ exports[`ChartAxis 2`] = ` @@ -377,7 +377,7 @@ exports[`ChartAxis 2`] = ` @@ -408,7 +408,7 @@ exports[`ChartAxis 2`] = ` @@ -435,11 +435,11 @@ exports[`ChartAxis 2`] = `
@@ -457,7 +457,7 @@ exports[`renders component data 1`] = ` @@ -565,7 +565,7 @@ exports[`renders component data 1`] = ` @@ -609,7 +609,7 @@ exports[`renders component data 1`] = ` @@ -640,7 +640,7 @@ exports[`renders component data 1`] = ` @@ -672,7 +672,7 @@ exports[`renders component data 1`] = ` @@ -716,7 +716,7 @@ exports[`renders component data 1`] = ` @@ -747,7 +747,7 @@ exports[`renders component data 1`] = ` @@ -775,11 +775,11 @@ exports[`renders component data 1`] = `
diff --git a/packages/react-charts/src/components/ChartBar/ChartBar.test.tsx b/packages/react-charts/src/victory/components/ChartBar/ChartBar.test.tsx similarity index 97% rename from packages/react-charts/src/components/ChartBar/ChartBar.test.tsx rename to packages/react-charts/src/victory/components/ChartBar/ChartBar.test.tsx index 99b54355d0c..3a1fee8d1b3 100644 --- a/packages/react-charts/src/components/ChartBar/ChartBar.test.tsx +++ b/packages/react-charts/src/victory/components/ChartBar/ChartBar.test.tsx @@ -1,4 +1,3 @@ -import * as React from 'react'; import { render } from '@testing-library/react'; import { Chart } from '../Chart/Chart'; import { ChartGroup } from '../ChartGroup/ChartGroup'; diff --git a/packages/react-charts/src/components/ChartBar/ChartBar.tsx b/packages/react-charts/src/victory/components/ChartBar/ChartBar.tsx similarity index 98% rename from packages/react-charts/src/components/ChartBar/ChartBar.tsx rename to packages/react-charts/src/victory/components/ChartBar/ChartBar.tsx index 2ff75d0b927..449b79065f6 100644 --- a/packages/react-charts/src/components/ChartBar/ChartBar.tsx +++ b/packages/react-charts/src/victory/components/ChartBar/ChartBar.tsx @@ -1,4 +1,4 @@ -import * as React from 'react'; +import { cloneElement } from 'react'; import hoistNonReactStatics from 'hoist-non-react-statics'; import { AnimatePropTypeInterface, @@ -169,7 +169,7 @@ export interface ChartBarProps extends VictoryBarProps { * The eventKey may optionally be used to select a single element by index rather than an entire * set. The eventHandlers object should be given as an object whose keys are standard * event names (i.e. onClick) and whose values are event callbacks. The return value - * of an event handler is used to modify elemnts. The return value should be given + * of an event handler is used to modify elements. The return value should be given * as an object or an array of objects with optional target and eventKey keys, * and a mutation key whose value is a function. The target and eventKey keys * will default to those corresponding to the element the event handler was attached to. @@ -306,7 +306,7 @@ export interface ChartBarProps extends VictoryBarProps { * * Note: This prop should not be set manually. * - * @private + * @private Not intended as public API and subject to change * @hide */ polar?: boolean; @@ -350,7 +350,7 @@ export interface ChartBarProps extends VictoryBarProps { * * Note: This prop should not be set manually. * - * @private + * @private Not intended as public API and subject to change * @hide */ sharedEvents?: { events: any[]; getEventState: Function }; @@ -471,7 +471,7 @@ export const ChartBar: React.FunctionComponent = ({ ...rest }: ChartBarProps) => { // Clone so users can override container props - const container = React.cloneElement(containerComponent, { + const container = cloneElement(containerComponent, { theme, ...containerComponent.props }); @@ -482,4 +482,4 @@ export const ChartBar: React.FunctionComponent = ({ ChartBar.displayName = 'ChartBar'; // Note: VictoryBar.getDomain & VictoryBar.role must be hoisted -hoistNonReactStatics(ChartBar, VictoryBar); +hoistNonReactStatics(ChartBar, VictoryBar, { getBaseProps: true }); diff --git a/packages/react-charts/src/components/ChartBar/__snapshots__/ChartBar.test.tsx.snap b/packages/react-charts/src/victory/components/ChartBar/__snapshots__/ChartBar.test.tsx.snap similarity index 72% rename from packages/react-charts/src/components/ChartBar/__snapshots__/ChartBar.test.tsx.snap rename to packages/react-charts/src/victory/components/ChartBar/__snapshots__/ChartBar.test.tsx.snap index ea191a767b6..489cd174ea7 100644 --- a/packages/react-charts/src/components/ChartBar/__snapshots__/ChartBar.test.tsx.snap +++ b/packages/react-charts/src/victory/components/ChartBar/__snapshots__/ChartBar.test.tsx.snap @@ -9,7 +9,7 @@ exports[`ChartBar 1`] = ` @@ -29,7 +29,7 @@ A 0 0 0 0 1, 55, 250 index="0" role="presentation" shape-rendering="auto" - style="fill: var(--pf-v6-chart-theme--blue--ColorScale--100, #0066cc); stroke: var(--pf-v6-chart-bar--data--stroke, none); padding: 8px; stroke-width: 0;" + style="fill: var(--pf-v6-chart-theme--blue--ColorScale--100, #0066cc); stroke: var(--pf-v6-chart-bar--data--stroke, #ffffff); padding: 8px; stroke-width: var(--pf-v6-chart-bar--data-stroke--Width, 0px);" />
@@ -101,7 +101,7 @@ exports[`ChartBar 2`] = ` @@ -121,7 +121,7 @@ A 0 0 0 0 1, 55, 250 index="0" role="presentation" shape-rendering="auto" - style="fill: var(--pf-v6-chart-theme--blue--ColorScale--100, #0066cc); stroke: var(--pf-v6-chart-bar--data--stroke, none); padding: 8px; stroke-width: 0;" + style="fill: var(--pf-v6-chart-theme--blue--ColorScale--100, #0066cc); stroke: var(--pf-v6-chart-bar--data--stroke, #ffffff); padding: 8px; stroke-width: var(--pf-v6-chart-bar--data-stroke--Width, 0px);" />
@@ -193,7 +193,7 @@ exports[`renders component data 1`] = ` @@ -214,7 +214,7 @@ A 0 0 0 0 1, 68.5, 150 index="0" role="presentation" shape-rendering="auto" - style="fill: var(--pf-v6-chart-theme--blue--ColorScale--100, #0066cc); stroke: var(--pf-v6-chart-bar--data--stroke, none); width: 6px; padding: 8px; stroke-width: 0;" + style="fill: var(--pf-v6-chart-theme--blue--ColorScale--100, #0066cc); stroke: var(--pf-v6-chart-bar--data--stroke, #ffffff); width: 6px; padding: 8px; stroke-width: var(--pf-v6-chart-bar--data-stroke--Width, 0px);" /> @@ -461,7 +461,7 @@ A 0 0 0 0 1, 246.5, 150 @@ -505,7 +505,7 @@ A 0 0 0 0 1, 246.5, 150 @@ -536,7 +536,7 @@ A 0 0 0 0 1, 246.5, 150 @@ -567,7 +567,7 @@ A 0 0 0 0 1, 246.5, 150 @@ -599,7 +599,7 @@ A 0 0 0 0 1, 246.5, 150 @@ -643,7 +643,7 @@ A 0 0 0 0 1, 246.5, 150 @@ -674,7 +674,7 @@ A 0 0 0 0 1, 246.5, 150 @@ -705,7 +705,7 @@ A 0 0 0 0 1, 246.5, 150 @@ -733,11 +733,11 @@ A 0 0 0 0 1, 246.5, 150
diff --git a/packages/react-charts/src/victory/components/ChartBar/examples/ChartBar.md b/packages/react-charts/src/victory/components/ChartBar/examples/ChartBar.md new file mode 100644 index 00000000000..29f57c11b9e --- /dev/null +++ b/packages/react-charts/src/victory/components/ChartBar/examples/ChartBar.md @@ -0,0 +1,76 @@ +--- +id: Bar chart +section: components +subsection: charts +propComponents: ['Chart', 'ChartAxis', 'ChartBar', 'ChartGroup', 'ChartLabel', 'ChartVoronoiContainer'] +hideDarkMode: true +--- + +import { Chart, ChartAxis, ChartBar, ChartGroup, ChartLabel, ChartThemeColor, ChartTooltip, ChartVoronoiContainer } from '@patternfly/react-charts/victory'; +import { VictoryZoomContainer } from 'victory-zoom-container'; +import t_global_color_status_danger_100 from '@patternfly/react-tokens/dist/esm/t_global_color_status_danger_100'; +import t_global_color_status_info_100 from '@patternfly/react-tokens/dist/esm/t_global_color_status_info_100'; +import t_global_color_status_warning_100 from '@patternfly/react-tokens/dist/esm/t_global_color_status_warning_100'; + +## Introduction + +Note: PatternFly React charts live in its own package at [@patternfly/react-charts](https://www.npmjs.com/package/@patternfly/react-charts)! + +The examples below are based on the [Victory](https://formidable.com/open-source/victory/docs/victory-chart/) chart library, along with additional functionality, custom components, and theming for PatternFly. This provides a collection of React based components you can use to build PatternFly patterns with consistent markup, styling, and behavior. + +## Examples + +### Basic with right aligned legend + +```ts file = "ChartBarRightAlignedLegend.tsx" + +``` + +### Purple with bottom aligned legend + +This demonstrates an alternate way of applying tooltips using data labels. + +```ts file = "ChartBarBottomLegend.tsx" +``` + +### Multi-color (ordered) with bottom-left aligned legend + +This demonstrates zoom for both the x and y axis. + +```ts file = "ChartBarMultiColorOrdered.tsx" + +``` + +### Single with right aligned legend + +```ts file = "ChartBarSingleLegend.tsx" +``` + +### Alerts timeline + +A gnatt-like chart using `y` and `y0` data properties for alert start/end dates + +```ts file = "ChartBarAlertsTimeline.tsx" + +``` + +## Documentation + +### Tips + +- See Victory's [FAQ](https://formidable.com/open-source/victory/docs/faq) +- For single data points or zero values, you may want to set the `domain` prop +- `ChartLegend` may be used as a standalone component, instead of using `legendData` +- The `theme` and `themeColor` props should be applied at the most top level component +- Use `ChartGroup` to apply theme color scales and other properties to multiple components + +### Note + +Currently, the generated documentation below is not able to resolve type definitions from Victory imports. For the +components used in the examples above, Victory pass-thru props are also documented here: + +- For `Chart` props, see [VictoryChart](https://formidable.com/open-source/victory/docs/victory-chart) +- For `ChartAxis` props, see [VictoryAxis](https://formidable.com/open-source/victory/docs/victory-axis) +- For `ChartBar` props, see [VictoryBar](https://formidable.com/open-source/victory/docs/victory-bar) +- For `ChartGroup` props, see [VictoryGroup](https://formidable.com/open-source/victory/docs/victory-group) +- For `ChartVoronoiContainer` props, see [VictoryVoronoiContainer](https://formidable.com/open-source/victory/docs/victory-voronoi-container) diff --git a/packages/react-charts/src/victory/components/ChartBar/examples/ChartBarAlertsTimeline.tsx b/packages/react-charts/src/victory/components/ChartBar/examples/ChartBarAlertsTimeline.tsx new file mode 100644 index 00000000000..00abbd0699f --- /dev/null +++ b/packages/react-charts/src/victory/components/ChartBar/examples/ChartBarAlertsTimeline.tsx @@ -0,0 +1,193 @@ +import { + Chart, + ChartAxis, + ChartBar, + ChartGroup, + ChartLabel, + ChartTooltip, + ChartVoronoiContainer +} from '@patternfly/react-charts/victory'; +import t_global_color_status_danger_100 from '@patternfly/react-tokens/dist/esm/t_global_color_status_danger_100'; +import t_global_color_status_info_100 from '@patternfly/react-tokens/dist/esm/t_global_color_status_info_100'; +import t_global_color_status_warning_100 from '@patternfly/react-tokens/dist/esm/t_global_color_status_warning_100'; + +interface AlertData { + y0: Date; + y: Date; + severity: string; + x?: number; + fill?: string; +} + +export const ChartBarAlertsTimeline: React.FunctionComponent = () => { + // Start = y0, end = y + const alerts = [ + [ + { y0: new Date('2024-08-06T01:30:00'), y: new Date('2024-08-09T02:30:00'), severity: 'danger' }, + { y0: new Date('2024-08-10T05:30:00'), y: new Date('2024-08-10T20:00:00'), severity: 'danger' }, + { y0: new Date('2024-08-12T10:00:00'), y: new Date('2024-08-13T10:30:00'), severity: 'danger' } + ], + [ + { y0: new Date('2024-08-06T01:30:00'), y: new Date('2024-08-07T02:30:00'), severity: 'danger' }, + { y0: new Date('2024-08-07T07:30:00'), y: new Date('2024-08-09T09:30:00'), severity: 'danger' }, + { y0: new Date('2024-08-10T05:30:00'), y: new Date('2024-08-10T20:00:00'), severity: 'warn' }, + { y0: new Date('2024-08-12T10:00:00'), y: new Date('2024-08-13T10:30:00'), severity: 'danger' } + ], + [ + { y0: new Date('2024-08-06T01:30:00'), y: new Date('2024-08-07T02:30:00'), severity: 'danger' }, + { y0: new Date('2024-08-08T07:30:00'), y: new Date('2024-08-09T09:30:00'), severity: 'danger' }, + { y0: new Date('2024-08-10T05:30:00'), y: new Date('2024-08-10T20:00:00'), severity: 'info' }, + { y0: new Date('2024-08-12T10:00:00'), y: new Date('2024-08-13T10:30:00'), severity: 'warn' } + ], + [ + { y0: new Date('2024-08-06T01:30:00'), y: new Date('2024-08-08T02:30:00'), severity: 'info' }, + { y0: new Date('2024-08-08T07:30:00'), y: new Date('2024-08-09T09:30:00'), severity: 'info' }, + { y0: new Date('2024-08-10T05:30:00'), y: new Date('2024-08-11T20:00:00'), severity: 'warn' }, + { y0: new Date('2024-08-12T10:00:00'), y: new Date('2024-08-13T10:30:00'), severity: 'info' } + ], + [ + { y0: new Date('2024-08-06T01:30:00'), y: new Date('2024-08-07T02:30:00'), severity: 'warn' }, + { y0: new Date('2024-08-08T07:30:00'), y: new Date('2024-08-09T09:30:00'), severity: 'warn' }, + { y0: new Date('2024-08-09T11:30:00'), y: new Date('2024-08-10T20:00:00'), severity: 'warn' }, + { y0: new Date('2024-08-12T10:00:00'), y: new Date('2024-08-13T10:30:00'), severity: 'warn' } + ], + [ + { y0: new Date('2024-08-06T01:30:00'), y: new Date('2024-08-08T02:30:00'), severity: 'warn' }, + { y0: new Date('2024-08-08T07:30:00'), y: new Date('2024-08-09T09:30:00'), severity: 'warn' }, + { y0: new Date('2024-08-10T05:30:00'), y: new Date('2024-08-11T20:00:00'), severity: 'warn' }, + { y0: new Date('2024-08-12T10:00:00'), y: new Date('2024-08-13T10:30:00'), severity: 'warn' } + ], + [ + { y0: new Date('2024-08-06T01:30:00'), y: new Date('2024-08-07T02:30:00'), severity: 'warn' }, + { y0: new Date('2024-08-07T04:30:00'), y: new Date('2024-08-08T05:30:00'), severity: 'warn' }, + { y0: new Date('2024-08-08T07:30:00'), y: new Date('2024-08-09T09:30:00'), severity: 'warn' }, + { y0: new Date('2024-08-10T05:30:00'), y: new Date('2024-08-10T20:00:00'), severity: 'warn' }, + { y0: new Date('2024-08-11T05:30:00'), y: new Date('2024-08-11T20:00:00'), severity: 'warn' }, + { y0: new Date('2024-08-12T10:00:00'), y: new Date('2024-08-13T10:30:00'), severity: 'warn' } + ], + [ + { y0: new Date('2024-08-06T01:30:00'), y: new Date('2024-08-08T02:30:00'), severity: 'warn' }, + { y0: new Date('2024-08-08T07:30:00'), y: new Date('2024-08-09T09:30:00'), severity: 'warn' }, + { y0: new Date('2024-08-10T05:30:00'), y: new Date('2024-08-11T20:00:00'), severity: 'warn' }, + { y0: new Date('2024-08-12T10:00:00'), y: new Date('2024-08-13T10:30:00'), severity: 'warn' } + ] + ]; + + const legendData = [ + { name: 'Danger', symbol: { fill: t_global_color_status_danger_100.var } }, + + { name: 'Info', symbol: { fill: t_global_color_status_info_100.var } }, + + { name: 'Warning', symbol: { fill: t_global_color_status_warning_100.var } } + ]; + + const getSeverityColor = (severity) => { + if (severity === 'danger') { + return t_global_color_status_danger_100.var; + } else if (severity === 'warn') { + return t_global_color_status_warning_100.var; + } else { + return t_global_color_status_info_100.var; + } + }; + + const formatDate = (date: Date, isTime: boolean) => { + const dateString = date?.toLocaleDateString('en-US', { month: 'short', day: 'numeric' }); + const timeString = date?.toLocaleTimeString('en-US', { hour12: false }); + return isTime ? `${dateString} ${timeString}` : dateString; + }; + + const getChart = (alert: AlertData[], index: number) => { + const data: AlertData[] = []; + + alert?.map((datum) => { + data.push({ + ...datum, + x: alerts.length - index, + fill: getSeverityColor(datum.severity) + }); + }); + + if (data?.length === 0) { + return null; + } + return ( + datum.fill, + stroke: ({ datum }) => datum.fill + } + }} + /> + ); + }; + + return ( +
+ -(x - x0) / 2} // Position tooltip so pointer appears centered + dy={-5} // Position tooltip so pointer appears above bar + labelComponent={} + orientation="top" // Mimic bullet chart tooltip orientation + /> + } + labels={({ datum }) => + `Severity: ${datum.severity}\nStart: ${formatDate(new Date(datum.y0), true)}\nEnd: ${formatDate(new Date(datum.y), true)}` + } + /> + } + domainPadding={{ x: [20, 20], y: [20, 20] }} + legendData={legendData} + legendPosition="bottom-left" + height={400} + name="chart5" + padding={{ + bottom: 75, // Adjusted to accommodate legend + left: 100, + right: 50, // Adjusted to accommodate tooltip + top: 50 + }} + width={450} + > + new Date(t).toLocaleDateString('en-US', { month: 'short', day: 'numeric' })} + tickValues={[ + new Date('2024-08-06T00:00:00'), + new Date('2024-08-08T00:00:00'), + new Date('2024-08-10T00:00:00'), + new Date('2024-08-12T00:00:00') + ]} + /> + } + label="Incidents" + padding={{ top: 20, bottom: 60 }} + style={{ + axis: { + stroke: 'transparent' + }, + ticks: { + stroke: 'transparent' + }, + tickLabels: { + fill: 'transparent' + } + }} + /> + {alerts.map((alert, index) => getChart(alert, index))} + +
+ ); +}; diff --git a/packages/react-charts/src/victory/components/ChartBar/examples/ChartBarBottomLegend.tsx b/packages/react-charts/src/victory/components/ChartBar/examples/ChartBarBottomLegend.tsx new file mode 100644 index 00000000000..64998f46dcb --- /dev/null +++ b/packages/react-charts/src/victory/components/ChartBar/examples/ChartBarBottomLegend.tsx @@ -0,0 +1,83 @@ +import { + Chart, + ChartAxis, + ChartBar, + ChartGroup, + ChartThemeColor, + ChartTooltip +} from '@patternfly/react-charts/victory'; + +interface PetData { + name: string; + x: string; + y: number; + label: string; +} + +export const ChartBarBottomLegend: React.FunctionComponent = () => { + const label = + () => + ({ datum }) => + `${datum.name}: ${datum.y}`; + + const catsData: PetData[] = [ + { name: 'Cats', x: '2015', y: 1, label }, + { name: 'Cats', x: '2016', y: 2, label }, + { name: 'Cats', x: '2017', y: 5, label }, + { name: 'Cats', x: '2018', y: 3, label } + ]; + + const dogsData: PetData[] = [ + { name: 'Dogs', x: '2015', y: 2, label }, + { name: 'Dogs', x: '2016', y: 1, label }, + { name: 'Dogs', x: '2017', y: 7, label }, + { name: 'Dogs', x: '2018', y: 4, label } + ]; + + const birdsData: PetData[] = [ + { name: 'Birds', x: '2015', y: 4, label }, + { name: 'Birds', x: '2016', y: 4, label }, + { name: 'Birds', x: '2017', y: 9, label }, + { name: 'Birds', x: '2018', y: 7, label } + ]; + + const miceData: PetData[] = [ + { name: 'Mice', x: '2015', y: 3, label }, + { name: 'Mice', x: '2016', y: 3, label }, + { name: 'Mice', x: '2017', y: 8, label }, + { name: 'Mice', x: '2018', y: 5, label } + ]; + + const legendData = [{ name: 'Cats' }, { name: 'Dogs' }, { name: 'Birds' }, { name: 'Mice' }]; + + return ( +
+ + + + + } /> + } /> + } /> + } /> + + +
+ ); +}; diff --git a/packages/react-charts/src/victory/components/ChartBar/examples/ChartBarMultiColorOrdered.tsx b/packages/react-charts/src/victory/components/ChartBar/examples/ChartBarMultiColorOrdered.tsx new file mode 100644 index 00000000000..6d7dc460d28 --- /dev/null +++ b/packages/react-charts/src/victory/components/ChartBar/examples/ChartBarMultiColorOrdered.tsx @@ -0,0 +1,71 @@ +import { Chart, ChartAxis, ChartBar, ChartGroup, ChartThemeColor } from '@patternfly/react-charts/victory'; +import { VictoryZoomContainer } from 'victory-zoom-container'; + +interface PetData { + name: string; + x: string; + y: number; +} + +export const ChartBarMultiColorOrdered: React.FunctionComponent = () => { + const catsData: 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 dogsData: 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 birdsData: 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 miceData: 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 } + ]; + + const legendData = [{ name: 'Cats' }, { name: 'Dogs' }, { name: 'Birds' }, { name: 'Mice' }]; + return ( +
+ } + domainPadding={{ x: [30, 25] }} + legendData={legendData} + legendPosition="bottom-left" + height={400} + name="chart3" + padding={{ + bottom: 75, // Adjusted to accommodate legend + left: 50, + right: 100, // Adjusted to accommodate tooltip + top: 50 + }} + themeColor={ChartThemeColor.multiOrdered} + width={450} + > + + + + + + + + + +
+ ); +}; diff --git a/packages/react-charts/src/victory/components/ChartBar/examples/ChartBarRightAlignedLegend.tsx b/packages/react-charts/src/victory/components/ChartBar/examples/ChartBarRightAlignedLegend.tsx new file mode 100644 index 00000000000..5254fa71226 --- /dev/null +++ b/packages/react-charts/src/victory/components/ChartBar/examples/ChartBarRightAlignedLegend.tsx @@ -0,0 +1,73 @@ +import { Chart, ChartAxis, ChartBar, ChartGroup, ChartVoronoiContainer } from '@patternfly/react-charts/victory'; + +interface PetData { + name: string; + x: string; + y: number; +} + +export const ChartBarRightAlignedLegend: React.FunctionComponent = () => { + const catsData: 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 dogsData: 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 birdsData: 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 miceData: 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 } + ]; + + const legendData = [{ name: 'Cats' }, { name: 'Dogs' }, { name: 'Birds' }, { name: 'Mice' }]; + + return ( +
+ `${datum.name}: ${datum.y}`} constrainToVisibleArea /> + } + domain={{ y: [0, 9] }} + domainPadding={{ x: [30, 25] }} + legendData={legendData} + 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/ChartBar/examples/ChartBarSingleLegend.tsx b/packages/react-charts/src/victory/components/ChartBar/examples/ChartBarSingleLegend.tsx new file mode 100644 index 00000000000..3991e5ffe64 --- /dev/null +++ b/packages/react-charts/src/victory/components/ChartBar/examples/ChartBarSingleLegend.tsx @@ -0,0 +1,45 @@ +import { Chart, ChartBar, ChartVoronoiContainer } from '@patternfly/react-charts/victory'; + +interface PetData { + name: string; + x: string; + y: number; +} + +export const ChartBarSingleLegend: React.FunctionComponent = () => { + const catsData: 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 legendData = [{ name: 'Cats' }]; + return ( +
+ `${datum.name}: ${datum.y}`} constrainToVisibleArea /> + } + domain={{ y: [0, 9] }} + domainPadding={{ x: [30, 25] }} + legendData={legendData} + legendOrientation="vertical" + legendPosition="right" + height={250} + name="chart4" + padding={{ + bottom: 50, + left: 50, + right: 200, // Adjusted to accommodate legend + top: 50 + }} + width={600} + > + + +
+ ); +}; diff --git a/packages/react-charts/src/components/ChartBoxPlot/ChartBoxPlot.test.tsx b/packages/react-charts/src/victory/components/ChartBoxPlot/ChartBoxPlot.test.tsx similarity index 96% rename from packages/react-charts/src/components/ChartBoxPlot/ChartBoxPlot.test.tsx rename to packages/react-charts/src/victory/components/ChartBoxPlot/ChartBoxPlot.test.tsx index 9a478999000..72a7b5c80d6 100644 --- a/packages/react-charts/src/components/ChartBoxPlot/ChartBoxPlot.test.tsx +++ b/packages/react-charts/src/victory/components/ChartBoxPlot/ChartBoxPlot.test.tsx @@ -1,4 +1,3 @@ -import * as React from 'react'; import { render } from '@testing-library/react'; import { Chart } from '../Chart/Chart'; import { ChartBoxPlot } from './ChartBoxPlot'; diff --git a/packages/react-charts/src/components/ChartBoxPlot/ChartBoxPlot.tsx b/packages/react-charts/src/victory/components/ChartBoxPlot/ChartBoxPlot.tsx similarity index 97% rename from packages/react-charts/src/components/ChartBoxPlot/ChartBoxPlot.tsx rename to packages/react-charts/src/victory/components/ChartBoxPlot/ChartBoxPlot.tsx index 3a69f53a43c..1879c95fd50 100644 --- a/packages/react-charts/src/components/ChartBoxPlot/ChartBoxPlot.tsx +++ b/packages/react-charts/src/victory/components/ChartBoxPlot/ChartBoxPlot.tsx @@ -1,4 +1,4 @@ -import * as React from 'react'; +import { cloneElement } from 'react'; import hoistNonReactStatics from 'hoist-non-react-statics'; import { AnimatePropTypeInterface, @@ -157,7 +157,7 @@ export interface ChartBoxPlotProps extends VictoryBoxPlotProps { * The eventKey may optionally be used to select a single element by index rather than an entire * set. The eventHandlers object should be given as an object whose keys are standard * event names (i.e. onClick) and whose values are event callbacks. The return value - * of an event handler is used to modify elemnts. The return value should be given + * of an event handler is used to modify elements. The return value should be given * as an object or an array of objects with optional target and eventKey keys, * and a mutation key whose value is a function. The target and eventKey keys * will default to those corresponding to the element the event handler was attached to. @@ -254,7 +254,7 @@ export interface ChartBoxPlotProps extends VictoryBoxPlotProps { * supplied component, or modified or ignored within the custom component itself. If a maxComponent is not provided, * ChartBoxPlot will use its default Whisker component. */ - maxComponent?: React.ReactElement; + maxComponent?: React.ReactElement; /** * The maxDomain prop defines a maximum domain value for a chart. This prop is useful in situations where the maximum * domain of a chart is static, while the minimum value depends on data or other variable information. If the domain @@ -278,7 +278,7 @@ export interface ChartBoxPlotProps extends VictoryBoxPlotProps { * custom component itself. If maxLabelComponent is omitted, a new ChartLabel will be created with props described * above. */ - maxLabelComponent?: React.ReactElement; + maxLabelComponent?: React.ReactElement; /** * The maxLabels prop defines the labels that will appear above each point. This prop should be given as a boolean, * an array or as a function of the props corresponding to that label. When given as a boolean value, the max value @@ -314,7 +314,7 @@ export interface ChartBoxPlotProps extends VictoryBoxPlotProps { * props may be overridden by passing in props to the supplied component, or modified or ignored within the custom * component itself. If a medianComponent is not provided, ChartBoxPlot will use its default Line component. */ - medianComponent?: React.ReactElement; + medianComponent?: React.ReactElement; /** * The medianLabelComponent prop takes a component instance which will be used to render the label corresponding to * the median value for each box. The new element created from the passed medianLabelComponent will be supplied with @@ -323,7 +323,7 @@ export interface ChartBoxPlotProps extends VictoryBoxPlotProps { * custom component itself. If medianLabelComponent is omitted, a new ChartLabel will be created with props * described above. */ - medianLabelComponent?: React.ReactElement; + medianLabelComponent?: React.ReactElement; /** * The medianLabels prop defines the labels that will appear above each point. This prop should be given as a boolean, * an array or as a function of the props corresponding to that label. When given as a boolean value, the median value @@ -362,7 +362,7 @@ export interface ChartBoxPlotProps extends VictoryBoxPlotProps { * supplied component, or modified or ignored within the custom component itself. If a minComponent is not provided, * ChartBoxPlot will use its default Whisker component. */ - minComponent?: React.ReactElement; + minComponent?: React.ReactElement; /** * The minDomain prop defines a minimum domain value for a chart. This prop is useful in situations where the minimum * domain of a chart is static, while the maximum value depends on data or other variable information. If the domain @@ -386,7 +386,7 @@ export interface ChartBoxPlotProps extends VictoryBoxPlotProps { * custom component itself. If minLabelComponent is omitted, a new ChartLabel will be created with props described * above. */ - minLabelComponent?: React.ReactElement; + minLabelComponent?: React.ReactElement; /** * The minLabels prop defines the labels that will appear above each point. This prop should be given as a boolean, an * array or as a function of the props corresponding to that label. When given as a boolean value, the min value of @@ -425,7 +425,7 @@ export interface ChartBoxPlotProps extends VictoryBoxPlotProps { * * Note: This prop should not be set manually. * - * @private + * @private Not intended as public API and subject to change * @hide */ polar?: boolean; @@ -453,7 +453,7 @@ export interface ChartBoxPlotProps extends VictoryBoxPlotProps { * may be overridden by passing in props to the supplied component, or modified or ignored within the custom component * itself. If a q1Component is not provided, ChartBoxPlot will use its default Box component. */ - q1Component?: React.ReactElement; + q1Component?: React.ReactElement; /** * The q1LabelComponent prop takes a component instance which will be used to render the label corresponding to the q1 * value for each box. The new element created from the passed q1LabelComponent will be supplied with the following @@ -461,7 +461,7 @@ export interface ChartBoxPlotProps extends VictoryBoxPlotProps { * props may be overridden by passing in props to the supplied component, or modified or ignored within the custom * component itself. If q1LabelComponent is omitted, a new ChartLabel will be created with props described above. */ - q1LabelComponent?: React.ReactElement; + q1LabelComponent?: React.ReactElement; /** * The q1Labels prop defines the labels that will appear above each point. This prop should be given as a boolean, an * array or as a function of the props corresponding to that label. When given as a boolean value, the q1 value of @@ -498,7 +498,7 @@ export interface ChartBoxPlotProps extends VictoryBoxPlotProps { * may be overridden by passing in props to the supplied component, or modified or ignored within the custom component * itself. If a q3Component is not provided, ChartBoxPlot will use its default Box component. */ - q3Component?: React.ReactElement; + q3Component?: React.ReactElement; /** * The q3LabelComponent prop takes a component instance which will be used to render the label corresponding to the q3 * value for each box. The new element created from the passed q3LabelComponent will be supplied with the following @@ -506,7 +506,7 @@ export interface ChartBoxPlotProps extends VictoryBoxPlotProps { * props may be overridden by passing in props to the supplied component, or modified or ignored within the custom * component itself. If q3LabelComponent is omitted, a new ChartLabel will be created with props described above. */ - q3LabelComponent?: React.ReactElement; + q3LabelComponent?: React.ReactElement; /** * The q3Labels prop defines the labels that will appear above each point. This prop should be given as a boolean, an * array or as a function of the props corresponding to that label. When given as a boolean value, the q3 value of @@ -559,7 +559,7 @@ export interface ChartBoxPlotProps extends VictoryBoxPlotProps { * * Note: This prop should not be set manually. * - * @private + * @private Not intended as public API and subject to change * @hide */ sharedEvents?: { events: any[]; getEventState: Function }; @@ -685,7 +685,7 @@ export const ChartBoxPlot: React.FunctionComponent = ({ ...rest }: ChartBoxPlotProps) => { // Clone so users can override container props - const container = React.cloneElement(containerComponent, { + const container = cloneElement(containerComponent, { theme, ...containerComponent.props }); diff --git a/packages/react-charts/src/components/ChartBoxPlot/__snapshots__/ChartBoxPlot.test.tsx.snap b/packages/react-charts/src/victory/components/ChartBoxPlot/__snapshots__/ChartBoxPlot.test.tsx.snap similarity index 83% rename from packages/react-charts/src/components/ChartBoxPlot/__snapshots__/ChartBoxPlot.test.tsx.snap rename to packages/react-charts/src/victory/components/ChartBoxPlot/__snapshots__/ChartBoxPlot.test.tsx.snap index bb38a2f8fa3..1b3012183fa 100644 --- a/packages/react-charts/src/components/ChartBoxPlot/__snapshots__/ChartBoxPlot.test.tsx.snap +++ b/packages/react-charts/src/victory/components/ChartBoxPlot/__snapshots__/ChartBoxPlot.test.tsx.snap @@ -9,7 +9,7 @@ exports[`ChartBar 1`] = ` @@ -147,7 +147,7 @@ exports[`ChartBar 1`] = `
@@ -189,7 +189,7 @@ exports[`ChartBar 2`] = ` @@ -327,7 +327,7 @@ exports[`ChartBar 2`] = `
@@ -369,7 +369,7 @@ exports[`renders component data 1`] = ` @@ -635,7 +635,7 @@ exports[`renders component data 1`] = ` @@ -723,7 +723,7 @@ exports[`renders component data 1`] = ` @@ -754,7 +754,7 @@ exports[`renders component data 1`] = ` @@ -785,7 +785,7 @@ exports[`renders component data 1`] = ` @@ -817,7 +817,7 @@ exports[`renders component data 1`] = ` @@ -861,7 +861,7 @@ exports[`renders component data 1`] = ` @@ -892,7 +892,7 @@ exports[`renders component data 1`] = ` @@ -923,7 +923,7 @@ exports[`renders component data 1`] = ` @@ -954,7 +954,7 @@ exports[`renders component data 1`] = ` @@ -982,11 +982,11 @@ exports[`renders component data 1`] = `
diff --git a/packages/react-charts/src/victory/components/ChartBoxPlot/examples/ChartBoxPlot.md b/packages/react-charts/src/victory/components/ChartBoxPlot/examples/ChartBoxPlot.md new file mode 100644 index 00000000000..cccdad20c88 --- /dev/null +++ b/packages/react-charts/src/victory/components/ChartBoxPlot/examples/ChartBoxPlot.md @@ -0,0 +1,69 @@ +--- +id: Box plot chart +section: components +subsection: charts +propComponents: [ + 'Chart', + 'ChartAxis', + 'ChartBoxPlot', + 'ChartCursorFlyout', + 'ChartCursorTooltip', + 'ChartVoronoiContainer' +] +hideDarkMode: true +--- + +import { Chart, ChartAxis, ChartBoxPlot, ChartCursorFlyout, ChartCursorTooltip, ChartLegendTooltip, ChartThemeColor, ChartThreshold, ChartVoronoiContainer, createContainer } from '@patternfly/react-charts/victory'; +import { VictoryZoomContainer } from 'victory-zoom-container'; +import chart_color_orange_300 from '@patternfly/react-tokens/dist/esm/chart_color_orange_300'; + +## Introduction +Note: PatternFly React charts live in its own package at [@patternfly/react-charts](https://www.npmjs.com/package/@patternfly/react-charts)! + +The examples below are based on the [Victory](https://formidable.com/open-source/victory/docs/victory-chart/) chart library, along with additional functionality, custom components, and theming for PatternFly. This provides a collection of React based components you can use to build PatternFly patterns with consistent markup, styling, and behavior. + + +## Examples +### Basic with right aligned legend +```ts file = "ChartBoxPlotRightAlignedLegend.tsx" + +``` + +### Labels with bottom aligned legend + +This demonstrates how to display labels. + +```ts file= "ChartBoxPlotLabelsLegend.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. + +```ts file = "ChartBoxPlotEmbeddedLegend.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. + +```ts file = "ChartBoxPlotEmbeddedHtml.tsx" + +``` + +## Documentation +### Tips +- See Victory's [FAQ](https://formidable.com/open-source/victory/docs/faq) +- For single data points or zero values, you may want to set the `domain` prop +- The `theme` and `themeColor` props should be applied at the most top level component + +### Note +Currently, the generated documentation below is not able to resolve type definitions from Victory imports. For the +components used in the examples above, Victory pass-thru props are also documented here: + +- For `Chart` props, see [VictoryChart](https://formidable.com/open-source/victory/docs/victory-chart) +- For `ChartAxis` props, see [VictoryAxis](https://formidable.com/open-source/victory/docs/victory-axis) +- For `ChartBoxPlot` props, see [VictoryBoxPlot](https://formidable.com/open-source/victory/docs/victory-box-plot) +- For `ChartVoronoiContainer` props, see [VictoryVoronoiContainer](https://formidable.com/open-source/victory/docs/victory-voronoi-container) diff --git a/packages/react-charts/src/victory/components/ChartBoxPlot/examples/ChartBoxPlotEmbeddedHtml.tsx b/packages/react-charts/src/victory/components/ChartBoxPlot/examples/ChartBoxPlotEmbeddedHtml.tsx new file mode 100644 index 00000000000..edf1e21b724 --- /dev/null +++ b/packages/react-charts/src/victory/components/ChartBoxPlot/examples/ChartBoxPlotEmbeddedHtml.tsx @@ -0,0 +1,125 @@ +import { + Chart, + ChartAxis, + ChartBoxPlot, + ChartCursorTooltip, + ChartThemeColor, + createContainer +} from '@patternfly/react-charts/victory'; + +interface PetData { + name: string; + x: string; + y: number[] | number; +} + +export const ChartBoxPlotEmbeddedHtml: 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' + }; + const leftColumn = { + paddingLeft: '10px', + width: '50%' + }; + const rightColumn = { + paddingRight: '20px', + textAlign: 'right', + width: '50%' + }; + + // Note: Container order is important + const CursorVoronoiContainer = createContainer('voronoi', 'cursor'); + const catsData: 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] } + ]; + const legendData = [{ name: 'Cats' }]; + + // Custom HTML component to create a legend layout + const HtmlLegendContent = ({ datum, _text, title, x, y, ..._rest }) => ( + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ {title(datum)} +
Max{datum._max}
Median{datum._median}
Min{datum._min}
Q1{datum._q1}
Q3{datum._q3}
+
+
+ ); + + return ( +
+ `${datum.y}`} + labelComponent={ + datum.x} />} + /> + } + mouseFollowTooltips + voronoiDimension="x" + voronoiPadding={50} + /> + } + domain={{ y: [0, 12] }} + domainPadding={{ x: [30, 25] }} + legendData={legendData} + legendPosition="bottom" + height={300} + name="chart4" + padding={{ + bottom: 75, // Adjusted to accommodate legend + left: 50, + right: 50, + top: 50 + }} + maxDomain={{ y: 9 }} + themeColor={ChartThemeColor.orange} + width={600} + > + + + + +
+ ); +}; diff --git a/packages/react-charts/src/victory/components/ChartBoxPlot/examples/ChartBoxPlotEmbeddedLegend.tsx b/packages/react-charts/src/victory/components/ChartBoxPlot/examples/ChartBoxPlotEmbeddedLegend.tsx new file mode 100644 index 00000000000..fd06bf7064d --- /dev/null +++ b/packages/react-charts/src/victory/components/ChartBoxPlot/examples/ChartBoxPlotEmbeddedLegend.tsx @@ -0,0 +1,106 @@ +import { + Chart, + ChartAxis, + ChartBoxPlot, + ChartLegendTooltip, + ChartThemeColor, + ChartThreshold, + createContainer +} from '@patternfly/react-charts/victory'; +import chart_color_orange_300 from '@patternfly/react-tokens/dist/esm/chart_color_orange_300'; + +interface Data { + name: string; + x: string; + y: number[] | number; +} + +export const ChartBoxPlotEmbeddedLegend: React.FunctionComponent = () => { + const catsData: Data[] = [ + { name: 'Cats', x: '2015', y: [null] }, + { 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] } + ]; + + // Note: Container order is important + const CursorVoronoiContainer = createContainer('voronoi', 'cursor'); + const limitData: Data[] = [ + { name: 'Limit', x: '2015', y: 12 }, + { name: 'Limit', x: '2016', y: 12 }, + { name: 'Limit', x: '2017', y: 12 }, + { name: 'Limit', x: '2018', y: 12 } + ]; + const legendData = [ + { + childName: 'limit', + name: 'Limit', + symbol: { fill: chart_color_orange_300.var, type: 'threshold' } + }, + { childName: 'cats', name: 'Cats' }, + // Force extra space below for line wrapping + { + childName: 'cats', + name: '', + symbol: { fill: 'none' } + }, + { + childName: 'cats', + name: '', + symbol: { fill: 'none' } + } + ]; + const labelFormatter = (datum) => { + // With box plot data, datum.y will also be an array + if (datum && (datum._min || datum._median || datum._max || datum._q1 || datum._q3)) { + return `Min: ${datum._min}, Max: ${datum._max}\nMedian: ${datum._median}\nQ1: ${datum._q1}, Q3: ${datum._q3}`; + } + const yVal = Array.isArray(datum.y) ? datum.y[0] : datum.y; + return yVal !== null ? yVal : 'no data'; + }; + return ( +
+ labelFormatter(datum)} + labelComponent={ datum.x} />} + mouseFollowTooltips + voronoiDimension="x" + voronoiPadding={50} + /> + } + domain={{ y: [0, 13] }} + domainPadding={{ x: [30, 25] }} + legendData={legendData} + legendPosition="bottom" + height={350} + name="chart5" + padding={{ + bottom: 75, // Adjusted to accommodate legend + left: 50, + right: 50, + top: 50 + }} + themeColor={ChartThemeColor.green} + width={600} + > + + + + + +
+ ); +}; diff --git a/packages/react-charts/src/victory/components/ChartBoxPlot/examples/ChartBoxPlotLabelsLegend.tsx b/packages/react-charts/src/victory/components/ChartBoxPlot/examples/ChartBoxPlotLabelsLegend.tsx new file mode 100644 index 00000000000..fc34a6e6104 --- /dev/null +++ b/packages/react-charts/src/victory/components/ChartBoxPlot/examples/ChartBoxPlotLabelsLegend.tsx @@ -0,0 +1,51 @@ +import { Chart, ChartAxis, ChartBoxPlot, ChartThemeColor } from '@patternfly/react-charts/victory'; + +interface PetData { + name: string; + x: string; + y: number[]; +} + +export const ChartBoxPlotLabelsLegend: React.FunctionComponent = () => { + const catsData: 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] } + ]; + const legendData = [{ name: 'Cats' }]; + return ( +
+ + + + + +
+ ); +}; diff --git a/packages/react-charts/src/victory/components/ChartBoxPlot/examples/ChartBoxPlotRightAlignedLegend.tsx b/packages/react-charts/src/victory/components/ChartBoxPlot/examples/ChartBoxPlotRightAlignedLegend.tsx new file mode 100644 index 00000000000..87a8a98b9ef --- /dev/null +++ b/packages/react-charts/src/victory/components/ChartBoxPlot/examples/ChartBoxPlotRightAlignedLegend.tsx @@ -0,0 +1,45 @@ +import { Chart, ChartAxis, ChartBoxPlot, ChartThemeColor } from '@patternfly/react-charts/victory'; + +interface PetData { + name: string; + x: string; + y: number[]; +} + +export const ChartBoxPlotRightAlignedLegend: React.FunctionComponent = () => { + const catsData: 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] } + ]; + + const legendData = [{ name: 'Cats' }]; + return ( +
+ + + + + +
+ ); +}; diff --git a/packages/react-charts/src/components/ChartBullet/ChartBullet.test.tsx b/packages/react-charts/src/victory/components/ChartBullet/ChartBullet.test.tsx similarity index 97% rename from packages/react-charts/src/components/ChartBullet/ChartBullet.test.tsx rename to packages/react-charts/src/victory/components/ChartBullet/ChartBullet.test.tsx index c7986881558..d46d659c501 100644 --- a/packages/react-charts/src/components/ChartBullet/ChartBullet.test.tsx +++ b/packages/react-charts/src/victory/components/ChartBullet/ChartBullet.test.tsx @@ -1,4 +1,3 @@ -import * as React from 'react'; import { render } from '@testing-library/react'; import { ChartAxis } from '../ChartAxis/ChartAxis'; import { ChartLabel } from '../ChartLabel/ChartLabel'; diff --git a/packages/react-charts/src/components/ChartBullet/ChartBullet.tsx b/packages/react-charts/src/victory/components/ChartBullet/ChartBullet.tsx similarity index 97% rename from packages/react-charts/src/components/ChartBullet/ChartBullet.tsx rename to packages/react-charts/src/victory/components/ChartBullet/ChartBullet.tsx index fd79bc04547..dc146b522b9 100644 --- a/packages/react-charts/src/components/ChartBullet/ChartBullet.tsx +++ b/packages/react-charts/src/victory/components/ChartBullet/ChartBullet.tsx @@ -1,4 +1,4 @@ -import * as React from 'react'; +import { cloneElement, Fragment, useEffect } from 'react'; import hoistNonReactStatics from 'hoist-non-react-statics'; import { DataGetterPropType, DomainPropType, PaddingProps } from 'victory-core'; import { VictoryChart } from 'victory-chart'; @@ -28,7 +28,6 @@ import { ChartBulletQualitativeRange } from './ChartBulletQualitativeRange'; import { getBulletDomain } from './utils/chart-bullet-domain'; import { getBulletThemeWithLegendColorScale } from './utils/chart-bullet-theme'; import { getPaddingForSide } from '../ChartUtils/chart-padding'; -import { useEffect } from 'react'; import { ChartPoint } from '../ChartPoint/ChartPoint'; import { ChartLabel } from '../ChartLabel/ChartLabel'; @@ -588,7 +587,7 @@ export const ChartBullet: React.FunctionComponent = ({ }; // Bullet group title - const bulletGroupTitle = React.cloneElement(groupTitleComponent, { + const bulletGroupTitle = cloneElement(groupTitleComponent, { height, ...(name && { name: `${name}-${(groupTitleComponent as any).type.displayName}` }), standalone: false, @@ -600,7 +599,7 @@ export const ChartBullet: React.FunctionComponent = ({ }); // Bullet title - const bulletTitle = React.cloneElement(titleComponent, { + const bulletTitle = cloneElement(titleComponent, { height, horizontal, legendPosition, @@ -617,7 +616,7 @@ export const ChartBullet: React.FunctionComponent = ({ }); // Comparative error measure - const comparativeErrorMeasure = React.cloneElement(comparativeErrorMeasureComponent, { + const comparativeErrorMeasure = cloneElement(comparativeErrorMeasureComponent, { allowTooltip, barWidth: getComparativeMeasureErrorWidth({ height: chartSize.height, @@ -641,7 +640,7 @@ export const ChartBullet: React.FunctionComponent = ({ }); // Comparative warning measure - const comparativeWarningMeasure = React.cloneElement(comparativeWarningMeasureComponent, { + const comparativeWarningMeasure = cloneElement(comparativeWarningMeasureComponent, { allowTooltip, barWidth: getComparativeMeasureWarningWidth({ height: chartSize.height, @@ -665,7 +664,7 @@ export const ChartBullet: React.FunctionComponent = ({ }); // Comparative zero measure - const comparativeZeroMeasure = React.cloneElement(comparativeZeroMeasureComponent, { + const comparativeZeroMeasure = cloneElement(comparativeZeroMeasureComponent, { barWidth: getComparativeMeasureWidth({ height: chartSize.height, horizontal, themeColor, width: chartSize.width }), data: [{ y: 0 }], domain, @@ -693,7 +692,7 @@ export const ChartBullet: React.FunctionComponent = ({ } // Legend - const legend = React.cloneElement(legendComponent, { + const legend = cloneElement(legendComponent, { data: [ ...(primaryDotMeasureLegendData ? primaryDotMeasureLegendData : []), ...(primarySegmentedMeasureLegendData ? primarySegmentedMeasureLegendData : []), @@ -709,14 +708,14 @@ export const ChartBullet: React.FunctionComponent = ({ themeColor, ...(legendDirection === 'rtl' && { dataComponent: legendComponent.props.dataComponent ? ( - React.cloneElement(legendComponent.props.dataComponent, { transform: `translate(${legendXOffset})` }) + cloneElement(legendComponent.props.dataComponent, { transform: `translate(${legendXOffset})` }) ) : ( ) }), ...(legendDirection === 'rtl' && { labelComponent: legendComponent.props.labelComponent ? ( - React.cloneElement(legendComponent.props.labelComponent, { + cloneElement(legendComponent.props.labelComponent, { direction: 'rtl', dx: legendXOffset - 30 }) @@ -728,7 +727,7 @@ export const ChartBullet: React.FunctionComponent = ({ }); // Primary dot measure - const primaryDotMeasure = React.cloneElement(primaryDotMeasureComponent, { + const primaryDotMeasure = cloneElement(primaryDotMeasureComponent, { allowTooltip, constrainToVisibleArea, data: primaryDotMeasureData, @@ -748,7 +747,7 @@ export const ChartBullet: React.FunctionComponent = ({ }); // Primary segmented measure - const primarySegmentedMeasure = React.cloneElement(primarySegmentedMeasureComponent, { + const primarySegmentedMeasure = cloneElement(primarySegmentedMeasureComponent, { allowTooltip, constrainToVisibleArea, barWidth: getPrimarySegmentedMeasureWidth({ @@ -773,7 +772,7 @@ export const ChartBullet: React.FunctionComponent = ({ }); // Qualitative range - const qualitativeRange = React.cloneElement(qualitativeRangeComponent, { + const qualitativeRange = cloneElement(qualitativeRangeComponent, { allowTooltip, constrainToVisibleArea, barWidth: getQualitativeRangeBarWidth({ height: chartSize.height, horizontal, themeColor, width: chartSize.width }), @@ -878,7 +877,7 @@ export const ChartBullet: React.FunctionComponent = ({ }; // Axis component for custom tick values - const axis = React.cloneElement(axisComponent, { + const axis = cloneElement(axisComponent, { dependentAxis: horizontal ? false : true, domain: !horizontal ? domain @@ -902,7 +901,7 @@ export const ChartBullet: React.FunctionComponent = ({ const computedLegend = getLegend(); const bulletChart = ( - + {axis} {bulletGroupTitle} {bulletTitle} @@ -913,7 +912,7 @@ export const ChartBullet: React.FunctionComponent = ({ {comparativeWarningMeasure} {getComparativeZeroMeasure()} {computedLegend} - + ); // Callback to compliment legendAllowWrap @@ -934,7 +933,7 @@ export const ChartBullet: React.FunctionComponent = ({ {bulletChart} ) : ( - {bulletChart} + {bulletChart} ); }; ChartBullet.displayName = 'ChartBullet'; diff --git a/packages/react-charts/src/components/ChartBullet/ChartBulletComparativeErrorMeasure.test.tsx b/packages/react-charts/src/victory/components/ChartBullet/ChartBulletComparativeErrorMeasure.test.tsx similarity index 94% rename from packages/react-charts/src/components/ChartBullet/ChartBulletComparativeErrorMeasure.test.tsx rename to packages/react-charts/src/victory/components/ChartBullet/ChartBulletComparativeErrorMeasure.test.tsx index ee2e3468e30..0888ac5c552 100644 --- a/packages/react-charts/src/components/ChartBullet/ChartBulletComparativeErrorMeasure.test.tsx +++ b/packages/react-charts/src/victory/components/ChartBullet/ChartBulletComparativeErrorMeasure.test.tsx @@ -1,4 +1,3 @@ -import * as React from 'react'; import { render } from '@testing-library/react'; import { ChartBulletComparativeErrorMeasure } from './ChartBulletComparativeErrorMeasure'; diff --git a/packages/react-charts/src/components/ChartBullet/ChartBulletComparativeErrorMeasure.tsx b/packages/react-charts/src/victory/components/ChartBullet/ChartBulletComparativeErrorMeasure.tsx similarity index 98% rename from packages/react-charts/src/components/ChartBullet/ChartBulletComparativeErrorMeasure.tsx rename to packages/react-charts/src/victory/components/ChartBullet/ChartBulletComparativeErrorMeasure.tsx index 9e90749308b..60ad1770418 100644 --- a/packages/react-charts/src/components/ChartBullet/ChartBulletComparativeErrorMeasure.tsx +++ b/packages/react-charts/src/victory/components/ChartBullet/ChartBulletComparativeErrorMeasure.tsx @@ -1,4 +1,4 @@ -import * as React from 'react'; +import { cloneElement, Fragment } from 'react'; import hoistNonReactStatics from 'hoist-non-react-statics'; import { DataGetterPropType, DomainPropType, NumberOrCallback, PaddingProps } from 'victory-core'; import { VictoryBar } from 'victory-bar'; @@ -186,7 +186,7 @@ export const ChartBulletComparativeErrorMeasure: React.FunctionComponent { // Comparative measure component - const measure = React.cloneElement(measureComponent, { + const measure = cloneElement(measureComponent, { allowTooltip, ariaDesc, ariaTitle, @@ -212,7 +212,7 @@ export const ChartBulletComparativeErrorMeasure: React.FunctionComponent ) : ( - {measure} + {measure} ); }; ChartBulletComparativeErrorMeasure.displayName = 'ChartBulletComparativeErrorMeasure'; diff --git a/packages/react-charts/src/components/ChartBullet/ChartBulletComparativeMeasure.test.tsx b/packages/react-charts/src/victory/components/ChartBullet/ChartBulletComparativeMeasure.test.tsx similarity index 94% rename from packages/react-charts/src/components/ChartBullet/ChartBulletComparativeMeasure.test.tsx rename to packages/react-charts/src/victory/components/ChartBullet/ChartBulletComparativeMeasure.test.tsx index 065596c6bb9..e26dfffb9da 100644 --- a/packages/react-charts/src/components/ChartBullet/ChartBulletComparativeMeasure.test.tsx +++ b/packages/react-charts/src/victory/components/ChartBullet/ChartBulletComparativeMeasure.test.tsx @@ -1,4 +1,3 @@ -import * as React from 'react'; import { render } from '@testing-library/react'; import { ChartBulletComparativeMeasure } from './ChartBulletComparativeMeasure'; diff --git a/packages/react-charts/src/components/ChartBullet/ChartBulletComparativeMeasure.tsx b/packages/react-charts/src/victory/components/ChartBullet/ChartBulletComparativeMeasure.tsx similarity index 98% rename from packages/react-charts/src/components/ChartBullet/ChartBulletComparativeMeasure.tsx rename to packages/react-charts/src/victory/components/ChartBullet/ChartBulletComparativeMeasure.tsx index 40b45a68f59..0ef3a57b904 100644 --- a/packages/react-charts/src/components/ChartBullet/ChartBulletComparativeMeasure.tsx +++ b/packages/react-charts/src/victory/components/ChartBullet/ChartBulletComparativeMeasure.tsx @@ -1,4 +1,4 @@ -import * as React from 'react'; +import { cloneElement, Fragment } from 'react'; import hoistNonReactStatics from 'hoist-non-react-statics'; import { DataGetterPropType, DomainPropType, NumberOrCallback, PaddingProps } from 'victory-core'; import { VictoryBar } from 'victory-bar'; @@ -197,7 +197,7 @@ export const ChartBulletComparativeMeasure: React.FunctionComponent { if (horizontal) { @@ -218,7 +218,7 @@ export const ChartBulletComparativeMeasure: React.FunctionComponent - React.cloneElement(measureComponent, { + cloneElement(measureComponent, { barWidth, data: [{ ...dataPoint }], domain, @@ -241,7 +241,7 @@ export const ChartBulletComparativeMeasure: React.FunctionComponent ) : ( - {measure} + {measure} ); }; ChartBulletComparativeMeasure.displayName = 'ChartBulletComparativeMeasure'; diff --git a/packages/react-charts/src/components/ChartBullet/ChartBulletComparativeWarningMeasure.test.tsx b/packages/react-charts/src/victory/components/ChartBullet/ChartBulletComparativeWarningMeasure.test.tsx similarity index 94% rename from packages/react-charts/src/components/ChartBullet/ChartBulletComparativeWarningMeasure.test.tsx rename to packages/react-charts/src/victory/components/ChartBullet/ChartBulletComparativeWarningMeasure.test.tsx index b1bb81c26f4..83b8fbfde6a 100644 --- a/packages/react-charts/src/components/ChartBullet/ChartBulletComparativeWarningMeasure.test.tsx +++ b/packages/react-charts/src/victory/components/ChartBullet/ChartBulletComparativeWarningMeasure.test.tsx @@ -1,4 +1,3 @@ -import * as React from 'react'; import { render } from '@testing-library/react'; import { ChartBulletComparativeWarningMeasure } from './ChartBulletComparativeWarningMeasure'; diff --git a/packages/react-charts/src/components/ChartBullet/ChartBulletComparativeWarningMeasure.tsx b/packages/react-charts/src/victory/components/ChartBullet/ChartBulletComparativeWarningMeasure.tsx similarity index 98% rename from packages/react-charts/src/components/ChartBullet/ChartBulletComparativeWarningMeasure.tsx rename to packages/react-charts/src/victory/components/ChartBullet/ChartBulletComparativeWarningMeasure.tsx index 8ddf308cc92..3dc5b08329c 100644 --- a/packages/react-charts/src/components/ChartBullet/ChartBulletComparativeWarningMeasure.tsx +++ b/packages/react-charts/src/victory/components/ChartBullet/ChartBulletComparativeWarningMeasure.tsx @@ -1,4 +1,4 @@ -import * as React from 'react'; +import { cloneElement, Fragment } from 'react'; import hoistNonReactStatics from 'hoist-non-react-statics'; import { DataGetterPropType, DomainPropType, NumberOrCallback, PaddingProps } from 'victory-core'; import { VictoryBar } from 'victory-bar'; @@ -188,7 +188,7 @@ export const ChartBulletComparativeWarningMeasure: React.FunctionComponent< width = theme.bar.width }: ChartBulletComparativeWarningMeasureProps) => { // Comparative measure component - const measure = React.cloneElement(measureComponent, { + const measure = cloneElement(measureComponent, { allowTooltip, ariaDesc, ariaTitle, @@ -214,7 +214,7 @@ export const ChartBulletComparativeWarningMeasure: React.FunctionComponent< {measure} ) : ( - {measure} + {measure} ); }; ChartBulletComparativeWarningMeasure.displayName = 'ChartBulletComparativeWarningMeasure'; diff --git a/packages/react-charts/src/components/ChartBullet/ChartBulletGroupTitle.test.tsx b/packages/react-charts/src/victory/components/ChartBullet/ChartBulletGroupTitle.test.tsx similarity index 95% rename from packages/react-charts/src/components/ChartBullet/ChartBulletGroupTitle.test.tsx rename to packages/react-charts/src/victory/components/ChartBullet/ChartBulletGroupTitle.test.tsx index 68e7213ac81..6894adecf04 100644 --- a/packages/react-charts/src/components/ChartBullet/ChartBulletGroupTitle.test.tsx +++ b/packages/react-charts/src/victory/components/ChartBullet/ChartBulletGroupTitle.test.tsx @@ -1,4 +1,3 @@ -import * as React from 'react'; import { render } from '@testing-library/react'; import { ChartBulletGroupTitle } from './ChartBulletGroupTitle'; import { ChartLabel } from '../ChartLabel/ChartLabel'; diff --git a/packages/react-charts/src/components/ChartBullet/ChartBulletGroupTitle.tsx b/packages/react-charts/src/victory/components/ChartBullet/ChartBulletGroupTitle.tsx similarity index 97% rename from packages/react-charts/src/components/ChartBullet/ChartBulletGroupTitle.tsx rename to packages/react-charts/src/victory/components/ChartBullet/ChartBulletGroupTitle.tsx index 82d622c5b7b..17a9b1db978 100644 --- a/packages/react-charts/src/components/ChartBullet/ChartBulletGroupTitle.tsx +++ b/packages/react-charts/src/victory/components/ChartBullet/ChartBulletGroupTitle.tsx @@ -1,4 +1,4 @@ -import * as React from 'react'; +import { cloneElement, Fragment } from 'react'; import { PaddingProps, Line, StringOrNumberOrCallback } from 'victory-core'; import { ChartContainer } from '../ChartContainer/ChartContainer'; import { ChartLabel } from '../ChartLabel/ChartLabel'; @@ -154,7 +154,7 @@ export const ChartBulletGroupTitle: React.FunctionComponent `${name}-${(titleComponent as any).type.displayName}` }), style: [ChartBulletStyles.label.groupTitle, ChartBulletStyles.label.subTitle], @@ -191,10 +191,10 @@ export const ChartBulletGroupTitle: React.FunctionComponent + {getTitle()} {getDivider()} - + ); return standalone ? ( @@ -202,7 +202,7 @@ export const ChartBulletGroupTitle: React.FunctionComponent ) : ( - {groupTitle} + {groupTitle} ); }; ChartBulletGroupTitle.displayName = 'ChartBulletGroupTitle'; diff --git a/packages/react-charts/src/components/ChartBullet/ChartBulletPrimaryDotMeasure.test.tsx b/packages/react-charts/src/victory/components/ChartBullet/ChartBulletPrimaryDotMeasure.test.tsx similarity index 94% rename from packages/react-charts/src/components/ChartBullet/ChartBulletPrimaryDotMeasure.test.tsx rename to packages/react-charts/src/victory/components/ChartBullet/ChartBulletPrimaryDotMeasure.test.tsx index c795926f137..42e88fe96a4 100644 --- a/packages/react-charts/src/components/ChartBullet/ChartBulletPrimaryDotMeasure.test.tsx +++ b/packages/react-charts/src/victory/components/ChartBullet/ChartBulletPrimaryDotMeasure.test.tsx @@ -1,4 +1,3 @@ -import * as React from 'react'; import { render } from '@testing-library/react'; import { ChartBulletPrimaryDotMeasure } from './ChartBulletPrimaryDotMeasure'; diff --git a/packages/react-charts/src/components/ChartBullet/ChartBulletPrimaryDotMeasure.tsx b/packages/react-charts/src/victory/components/ChartBullet/ChartBulletPrimaryDotMeasure.tsx similarity index 98% rename from packages/react-charts/src/components/ChartBullet/ChartBulletPrimaryDotMeasure.tsx rename to packages/react-charts/src/victory/components/ChartBullet/ChartBulletPrimaryDotMeasure.tsx index 2c105d600ee..9ee7e48a6d0 100644 --- a/packages/react-charts/src/components/ChartBullet/ChartBulletPrimaryDotMeasure.tsx +++ b/packages/react-charts/src/victory/components/ChartBullet/ChartBulletPrimaryDotMeasure.tsx @@ -1,4 +1,4 @@ -import * as React from 'react'; +import { cloneElement, Fragment } from 'react'; import hoistNonReactStatics from 'hoist-non-react-statics'; import { DataGetterPropType, DomainPropType, PaddingProps } from 'victory-core'; import { VictoryScatter } from 'victory-scatter'; @@ -208,7 +208,7 @@ export const ChartBulletPrimaryDotMeasure: React.FunctionComponent - React.cloneElement(measureComponent, { + cloneElement(measureComponent, { data: [{ ...dataPoint }], domain, height, @@ -245,7 +245,7 @@ export const ChartBulletPrimaryDotMeasure: React.FunctionComponent ) : ( - {measure} + {measure} ); }; ChartBulletPrimaryDotMeasure.displayName = 'ChartBulletPrimaryDotMeasure'; diff --git a/packages/react-charts/src/components/ChartBullet/ChartBulletPrimarySegmentedMeasure.test.tsx b/packages/react-charts/src/victory/components/ChartBullet/ChartBulletPrimarySegmentedMeasure.test.tsx similarity index 94% rename from packages/react-charts/src/components/ChartBullet/ChartBulletPrimarySegmentedMeasure.test.tsx rename to packages/react-charts/src/victory/components/ChartBullet/ChartBulletPrimarySegmentedMeasure.test.tsx index 80b09370953..f5cef6f4737 100644 --- a/packages/react-charts/src/components/ChartBullet/ChartBulletPrimarySegmentedMeasure.test.tsx +++ b/packages/react-charts/src/victory/components/ChartBullet/ChartBulletPrimarySegmentedMeasure.test.tsx @@ -1,4 +1,3 @@ -import * as React from 'react'; import { render } from '@testing-library/react'; import { ChartBulletPrimarySegmentedMeasure } from './ChartBulletPrimarySegmentedMeasure'; diff --git a/packages/react-charts/src/components/ChartBullet/ChartBulletPrimarySegmentedMeasure.tsx b/packages/react-charts/src/victory/components/ChartBullet/ChartBulletPrimarySegmentedMeasure.tsx similarity index 98% rename from packages/react-charts/src/components/ChartBullet/ChartBulletPrimarySegmentedMeasure.tsx rename to packages/react-charts/src/victory/components/ChartBullet/ChartBulletPrimarySegmentedMeasure.tsx index f640058ebc7..14372952dc8 100644 --- a/packages/react-charts/src/components/ChartBullet/ChartBulletPrimarySegmentedMeasure.tsx +++ b/packages/react-charts/src/victory/components/ChartBullet/ChartBulletPrimarySegmentedMeasure.tsx @@ -1,4 +1,4 @@ -import * as React from 'react'; +import { cloneElement, Fragment } from 'react'; import hoistNonReactStatics from 'hoist-non-react-statics'; import { DataGetterPropType, DomainPropType, NumberOrCallback, PaddingProps } from 'victory-core'; import { VictoryBar } from 'victory-bar'; @@ -229,7 +229,7 @@ export const ChartBulletPrimarySegmentedMeasure: React.FunctionComponent { if (horizontal) { @@ -250,7 +250,7 @@ export const ChartBulletPrimarySegmentedMeasure: React.FunctionComponent - React.cloneElement(measureComponent, { + cloneElement(measureComponent, { barWidth, data: [{ ...dataPoint }], domain, @@ -278,7 +278,7 @@ export const ChartBulletPrimarySegmentedMeasure: React.FunctionComponent ) : ( - {measure} + {measure} ); }; ChartBulletPrimarySegmentedMeasure.displayName = 'ChartBulletPrimarySegmentedMeasure'; diff --git a/packages/react-charts/src/components/ChartBullet/ChartBulletQualitativeRange.test.tsx b/packages/react-charts/src/victory/components/ChartBullet/ChartBulletQualitativeRange.test.tsx similarity index 94% rename from packages/react-charts/src/components/ChartBullet/ChartBulletQualitativeRange.test.tsx rename to packages/react-charts/src/victory/components/ChartBullet/ChartBulletQualitativeRange.test.tsx index 7eba951db01..eb895307124 100644 --- a/packages/react-charts/src/components/ChartBullet/ChartBulletQualitativeRange.test.tsx +++ b/packages/react-charts/src/victory/components/ChartBullet/ChartBulletQualitativeRange.test.tsx @@ -1,4 +1,3 @@ -import * as React from 'react'; import { render } from '@testing-library/react'; import { ChartBulletQualitativeRange } from './ChartBulletQualitativeRange'; diff --git a/packages/react-charts/src/components/ChartBullet/ChartBulletQualitativeRange.tsx b/packages/react-charts/src/victory/components/ChartBullet/ChartBulletQualitativeRange.tsx similarity index 98% rename from packages/react-charts/src/components/ChartBullet/ChartBulletQualitativeRange.tsx rename to packages/react-charts/src/victory/components/ChartBullet/ChartBulletQualitativeRange.tsx index 03568b89ef4..857e847226b 100644 --- a/packages/react-charts/src/components/ChartBullet/ChartBulletQualitativeRange.tsx +++ b/packages/react-charts/src/victory/components/ChartBullet/ChartBulletQualitativeRange.tsx @@ -1,4 +1,4 @@ -import * as React from 'react'; +import { cloneElement, Fragment } from 'react'; import hoistNonReactStatics from 'hoist-non-react-statics'; import { DataGetterPropType, DomainPropType, NumberOrCallback, PaddingProps } from 'victory-core'; import { VictoryBar } from 'victory-bar'; @@ -217,7 +217,7 @@ export const ChartBulletQualitativeRange: React.FunctionComponent { if (horizontal) { @@ -238,7 +238,7 @@ export const ChartBulletQualitativeRange: React.FunctionComponent - React.cloneElement(measureComponent, { + cloneElement(measureComponent, { barWidth, data: [{ ...dataPoint }], domain, @@ -266,7 +266,7 @@ export const ChartBulletQualitativeRange: React.FunctionComponent ) : ( - {measure} + {measure} ); }; ChartBulletQualitativeRange.displayName = 'ChartBulletQualitativeRange'; diff --git a/packages/react-charts/src/components/ChartBullet/ChartBulletTitle.test.tsx b/packages/react-charts/src/victory/components/ChartBullet/ChartBulletTitle.test.tsx similarity index 95% rename from packages/react-charts/src/components/ChartBullet/ChartBulletTitle.test.tsx rename to packages/react-charts/src/victory/components/ChartBullet/ChartBulletTitle.test.tsx index a7574058146..884f20e163c 100644 --- a/packages/react-charts/src/components/ChartBullet/ChartBulletTitle.test.tsx +++ b/packages/react-charts/src/victory/components/ChartBullet/ChartBulletTitle.test.tsx @@ -1,4 +1,3 @@ -import * as React from 'react'; import { render } from '@testing-library/react'; import { ChartBulletTitle } from './ChartBulletTitle'; import { ChartLabel } from '../ChartLabel/ChartLabel'; diff --git a/packages/react-charts/src/components/ChartBullet/ChartBulletTitle.tsx b/packages/react-charts/src/victory/components/ChartBullet/ChartBulletTitle.tsx similarity index 98% rename from packages/react-charts/src/components/ChartBullet/ChartBulletTitle.tsx rename to packages/react-charts/src/victory/components/ChartBullet/ChartBulletTitle.tsx index d2d6f595a68..aeb0635c2b7 100644 --- a/packages/react-charts/src/components/ChartBullet/ChartBulletTitle.tsx +++ b/packages/react-charts/src/victory/components/ChartBullet/ChartBulletTitle.tsx @@ -1,4 +1,4 @@ -import * as React from 'react'; +import { cloneElement, Fragment } from 'react'; import { PaddingProps, StringOrNumberOrCallback } from 'victory-core'; import { ChartContainer } from '../ChartContainer/ChartContainer'; import { ChartLabel } from '../ChartLabel/ChartLabel'; @@ -190,7 +190,7 @@ export const ChartBulletTitle: React.FunctionComponent = // The x and y calculations below are used to adjust the position of the title, based on padding and scale. // This ensures that when padding is adjusted, the title moves along with the chart's position. - return React.cloneElement(titleComponent, { + return cloneElement(titleComponent, { ...(showBoth && { capHeight }), ...(name && { id: () => `${name}-${(titleComponent as any).type.displayName}` }), style: [ChartBulletStyles.label.title, ChartBulletStyles.label.subTitle], @@ -227,7 +227,7 @@ export const ChartBulletTitle: React.FunctionComponent = {getTitle()} ) : ( - {getTitle()} + {getTitle()} ); }; ChartBulletTitle.displayName = 'ChartBulletTitle'; diff --git a/packages/react-charts/src/components/ChartBullet/__snapshots__/ChartBullet.test.tsx.snap b/packages/react-charts/src/victory/components/ChartBullet/__snapshots__/ChartBullet.test.tsx.snap similarity index 67% rename from packages/react-charts/src/components/ChartBullet/__snapshots__/ChartBullet.test.tsx.snap rename to packages/react-charts/src/victory/components/ChartBullet/__snapshots__/ChartBullet.test.tsx.snap index 03d99f4767d..79c255660c5 100644 --- a/packages/react-charts/src/components/ChartBullet/__snapshots__/ChartBullet.test.tsx.snap +++ b/packages/react-charts/src/victory/components/ChartBullet/__snapshots__/ChartBullet.test.tsx.snap @@ -4,12 +4,12 @@ exports[`ChartBulletQualitativeRange 1`] = `
@@ -19,7 +19,7 @@ exports[`ChartBulletQualitativeRange 1`] = ` @@ -72,11 +72,11 @@ exports[`ChartBulletQualitativeRange 1`] = `
@@ -89,12 +89,12 @@ exports[`ChartBulletQualitativeRange 2`] = `
@@ -104,7 +104,7 @@ exports[`ChartBulletQualitativeRange 2`] = ` @@ -157,11 +157,11 @@ exports[`ChartBulletQualitativeRange 2`] = `
@@ -174,14 +174,14 @@ exports[`renders component data 1`] = `
@@ -201,7 +201,7 @@ exports[`renders component data 1`] = ` @@ -245,7 +245,7 @@ exports[`renders component data 1`] = ` @@ -276,7 +276,7 @@ exports[`renders component data 1`] = ` @@ -307,7 +307,7 @@ exports[`renders component data 1`] = ` @@ -338,7 +338,7 @@ exports[`renders component data 1`] = ` @@ -380,7 +380,7 @@ A 0 0 0 0 1, 312.5, 85 index="0" role="presentation" shape-rendering="auto" - style="fill: var(--pf-v6-chart-bullet--qualitative-range--ColorScale--200, #e0e0e0); stroke: var(--pf-v6-chart-bar--data--stroke, none); padding: 8px; stroke-width: 0;" + style="fill: var(--pf-v6-chart-bullet--qualitative-range--ColorScale--200, #e0e0e0); stroke: var(--pf-v6-chart-bar--data--stroke, #ffffff); padding: 8px; stroke-width: var(--pf-v6-chart-bar--data-stroke--Width, 0px);" />
diff --git a/packages/react-charts/src/components/ChartBullet/__snapshots__/ChartBulletComparativeErrorMeasure.test.tsx.snap b/packages/react-charts/src/victory/components/ChartBullet/__snapshots__/ChartBulletComparativeErrorMeasure.test.tsx.snap similarity index 64% rename from packages/react-charts/src/components/ChartBullet/__snapshots__/ChartBulletComparativeErrorMeasure.test.tsx.snap rename to packages/react-charts/src/victory/components/ChartBullet/__snapshots__/ChartBulletComparativeErrorMeasure.test.tsx.snap index 1543f8fd6a7..75180d1bb27 100644 --- a/packages/react-charts/src/components/ChartBullet/__snapshots__/ChartBulletComparativeErrorMeasure.test.tsx.snap +++ b/packages/react-charts/src/victory/components/ChartBullet/__snapshots__/ChartBulletComparativeErrorMeasure.test.tsx.snap @@ -4,21 +4,21 @@ exports[`ChartBulletComparativeErrorMeasure 1`] = `
@@ -31,21 +31,21 @@ exports[`ChartBulletComparativeErrorMeasure 2`] = `
@@ -58,12 +58,12 @@ exports[`renders component data 1`] = `
@@ -88,11 +88,11 @@ A 0 0 0 0 1, 225, 104.8
diff --git a/packages/react-charts/src/components/ChartBullet/__snapshots__/ChartBulletComparativeMeasure.test.tsx.snap b/packages/react-charts/src/victory/components/ChartBullet/__snapshots__/ChartBulletComparativeMeasure.test.tsx.snap similarity index 64% rename from packages/react-charts/src/components/ChartBullet/__snapshots__/ChartBulletComparativeMeasure.test.tsx.snap rename to packages/react-charts/src/victory/components/ChartBullet/__snapshots__/ChartBulletComparativeMeasure.test.tsx.snap index 3a6f9e2c072..af43094b9b8 100644 --- a/packages/react-charts/src/components/ChartBullet/__snapshots__/ChartBulletComparativeMeasure.test.tsx.snap +++ b/packages/react-charts/src/victory/components/ChartBullet/__snapshots__/ChartBulletComparativeMeasure.test.tsx.snap @@ -4,21 +4,21 @@ exports[`ChartBulletComparativeMeasure 1`] = `
@@ -31,21 +31,21 @@ exports[`ChartBulletComparativeMeasure 2`] = `
@@ -58,12 +58,12 @@ exports[`renders component data 1`] = `
@@ -88,11 +88,11 @@ A 0 0 0 0 1, 225, 104.8
diff --git a/packages/react-charts/src/components/ChartBullet/__snapshots__/ChartBulletComparativeWarningMeasure.test.tsx.snap b/packages/react-charts/src/victory/components/ChartBullet/__snapshots__/ChartBulletComparativeWarningMeasure.test.tsx.snap similarity index 64% rename from packages/react-charts/src/components/ChartBullet/__snapshots__/ChartBulletComparativeWarningMeasure.test.tsx.snap rename to packages/react-charts/src/victory/components/ChartBullet/__snapshots__/ChartBulletComparativeWarningMeasure.test.tsx.snap index e79be486bf0..9149f42388a 100644 --- a/packages/react-charts/src/components/ChartBullet/__snapshots__/ChartBulletComparativeWarningMeasure.test.tsx.snap +++ b/packages/react-charts/src/victory/components/ChartBullet/__snapshots__/ChartBulletComparativeWarningMeasure.test.tsx.snap @@ -4,21 +4,21 @@ exports[`ChartBulletComparativeZeroMeasure 1`] = `
@@ -31,21 +31,21 @@ exports[`ChartBulletComparativeZeroMeasure 2`] = `
@@ -58,12 +58,12 @@ exports[`renders component data 1`] = `
@@ -88,11 +88,11 @@ A 0 0 0 0 1, 225, 104.8
diff --git a/packages/react-charts/src/components/ChartBullet/__snapshots__/ChartBulletGroupTitle.test.tsx.snap b/packages/react-charts/src/victory/components/ChartBullet/__snapshots__/ChartBulletGroupTitle.test.tsx.snap similarity index 60% rename from packages/react-charts/src/components/ChartBullet/__snapshots__/ChartBulletGroupTitle.test.tsx.snap rename to packages/react-charts/src/victory/components/ChartBullet/__snapshots__/ChartBulletGroupTitle.test.tsx.snap index a90b8b5ea5e..1c8ed3fe9cd 100644 --- a/packages/react-charts/src/components/ChartBullet/__snapshots__/ChartBulletGroupTitle.test.tsx.snap +++ b/packages/react-charts/src/victory/components/ChartBullet/__snapshots__/ChartBulletGroupTitle.test.tsx.snap @@ -4,21 +4,21 @@ exports[`ChartBulletGroupTitle 1`] = `
@@ -31,21 +31,21 @@ exports[`ChartBulletGroupTitle 2`] = `
@@ -58,12 +58,12 @@ exports[`renders component data 1`] = `
@@ -77,7 +77,7 @@ exports[`renders component data 1`] = ` @@ -86,7 +86,7 @@ exports[`renders component data 1`] = ` @@ -94,7 +94,7 @@ exports[`renders component data 1`] = `
diff --git a/packages/react-charts/src/components/ChartBullet/__snapshots__/ChartBulletPrimaryDotMeasure.test.tsx.snap b/packages/react-charts/src/victory/components/ChartBullet/__snapshots__/ChartBulletPrimaryDotMeasure.test.tsx.snap similarity index 59% rename from packages/react-charts/src/components/ChartBullet/__snapshots__/ChartBulletPrimaryDotMeasure.test.tsx.snap rename to packages/react-charts/src/victory/components/ChartBullet/__snapshots__/ChartBulletPrimaryDotMeasure.test.tsx.snap index ad0bc759b1b..9df6374c2d3 100644 --- a/packages/react-charts/src/components/ChartBullet/__snapshots__/ChartBulletPrimaryDotMeasure.test.tsx.snap +++ b/packages/react-charts/src/victory/components/ChartBullet/__snapshots__/ChartBulletPrimaryDotMeasure.test.tsx.snap @@ -4,21 +4,21 @@ exports[`ChartBulletPrimaryDotMeasure 1`] = `
@@ -31,21 +31,21 @@ exports[`ChartBulletPrimaryDotMeasure 2`] = `
@@ -58,12 +58,12 @@ exports[`renders component data 1`] = `
@@ -75,7 +75,7 @@ exports[`renders component data 1`] = ` a 6, 6 0 1,0 -12,0" role="presentation" shape-rendering="auto" - style="fill: var(--pf-v6-chart-theme--blue--ColorScale--100, #0066cc); opacity: 1; stroke: var(--pf-v6-chart-scatter--data--stroke--Color, transparent); stroke-width: 0;" + style="fill: var(--pf-v6-chart-theme--blue--ColorScale--100, #0066cc); opacity: 1; stroke: var(--pf-v6-chart-bullet--bar--stroke--Color, #ffffff); stroke-width: var(--pf-v6-chart-bullet--bar--stroke--Width, 0px);" /> @@ -86,7 +86,7 @@ exports[`renders component data 1`] = ` a 6, 6 0 1,0 -12,0" role="presentation" shape-rendering="auto" - style="fill: var(--pf-v6-chart-theme--blue--ColorScale--100, #0066cc); opacity: 1; stroke: var(--pf-v6-chart-scatter--data--stroke--Color, transparent); stroke-width: 0;" + style="fill: var(--pf-v6-chart-theme--blue--ColorScale--100, #0066cc); opacity: 1; stroke: var(--pf-v6-chart-bullet--bar--stroke--Color, #ffffff); stroke-width: var(--pf-v6-chart-bullet--bar--stroke--Width, 0px);" /> @@ -97,16 +97,16 @@ exports[`renders component data 1`] = ` a 6, 6 0 1,0 -12,0" role="presentation" shape-rendering="auto" - style="fill: var(--pf-v6-chart-theme--blue--ColorScale--100, #0066cc); opacity: 1; stroke: var(--pf-v6-chart-scatter--data--stroke--Color, transparent); stroke-width: 0;" + style="fill: var(--pf-v6-chart-theme--blue--ColorScale--100, #0066cc); opacity: 1; stroke: var(--pf-v6-chart-bullet--bar--stroke--Color, #ffffff); stroke-width: var(--pf-v6-chart-bullet--bar--stroke--Width, 0px);" />
diff --git a/packages/react-charts/src/components/ChartBullet/__snapshots__/ChartBulletPrimarySegmentedMeasure.test.tsx.snap b/packages/react-charts/src/victory/components/ChartBullet/__snapshots__/ChartBulletPrimarySegmentedMeasure.test.tsx.snap similarity index 65% rename from packages/react-charts/src/components/ChartBullet/__snapshots__/ChartBulletPrimarySegmentedMeasure.test.tsx.snap rename to packages/react-charts/src/victory/components/ChartBullet/__snapshots__/ChartBulletPrimarySegmentedMeasure.test.tsx.snap index d7d2d84e482..c9288bc2e40 100644 --- a/packages/react-charts/src/components/ChartBullet/__snapshots__/ChartBulletPrimarySegmentedMeasure.test.tsx.snap +++ b/packages/react-charts/src/victory/components/ChartBullet/__snapshots__/ChartBulletPrimarySegmentedMeasure.test.tsx.snap @@ -4,21 +4,21 @@ exports[`ChartBulletPrimarySegmentedMeasure 1`] = `
@@ -31,21 +31,21 @@ exports[`ChartBulletPrimarySegmentedMeasure 2`] = `
@@ -58,12 +58,12 @@ exports[`renders component data 1`] = `
@@ -83,7 +83,7 @@ A 0 0 0 0 1, 399.99999999976666, 94.3 index="0" role="presentation" shape-rendering="auto" - style="fill: var(--pf-v6-chart-theme--blue--ColorScale--300, #003366); stroke: var(--pf-v6-chart-bar--data--stroke, none); padding: 8px; stroke-width: 0;" + style="fill: var(--pf-v6-chart-theme--blue--ColorScale--300, #003366); stroke: var(--pf-v6-chart-bullet--bar--stroke--Color, #ffffff); padding: 8px; stroke-width: var(--pf-v6-chart-bullet--bar--stroke--Width, 0px);" />
diff --git a/packages/react-charts/src/components/ChartBullet/__snapshots__/ChartBulletQualitativeRange.test.tsx.snap b/packages/react-charts/src/victory/components/ChartBullet/__snapshots__/ChartBulletQualitativeRange.test.tsx.snap similarity index 70% rename from packages/react-charts/src/components/ChartBullet/__snapshots__/ChartBulletQualitativeRange.test.tsx.snap rename to packages/react-charts/src/victory/components/ChartBullet/__snapshots__/ChartBulletQualitativeRange.test.tsx.snap index 6faa4d373ac..3d7835aef62 100644 --- a/packages/react-charts/src/components/ChartBullet/__snapshots__/ChartBulletQualitativeRange.test.tsx.snap +++ b/packages/react-charts/src/victory/components/ChartBullet/__snapshots__/ChartBulletQualitativeRange.test.tsx.snap @@ -4,21 +4,21 @@ exports[`ChartBulletQualitativeRange 1`] = `
@@ -31,21 +31,21 @@ exports[`ChartBulletQualitativeRange 2`] = `
@@ -58,12 +58,12 @@ exports[`renders component data 1`] = `
@@ -83,7 +83,7 @@ A 0 0 0 0 1, 399.99999999976666, 104.8 index="0" role="presentation" shape-rendering="auto" - style="fill: var(--pf-v6-chart-bullet--qualitative-range--ColorScale--300, #c7c7c7); stroke: var(--pf-v6-chart-bar--data--stroke, none); padding: 8px; stroke-width: 0;" + style="fill: var(--pf-v6-chart-bullet--qualitative-range--ColorScale--300, #c7c7c7); stroke: var(--pf-v6-chart-bar--data--stroke, #ffffff); padding: 8px; stroke-width: var(--pf-v6-chart-bar--data-stroke--Width, 0px);" />
diff --git a/packages/react-charts/src/components/ChartBullet/__snapshots__/ChartBulletTitle.test.tsx.snap b/packages/react-charts/src/victory/components/ChartBullet/__snapshots__/ChartBulletTitle.test.tsx.snap similarity index 57% rename from packages/react-charts/src/components/ChartBullet/__snapshots__/ChartBulletTitle.test.tsx.snap rename to packages/react-charts/src/victory/components/ChartBullet/__snapshots__/ChartBulletTitle.test.tsx.snap index 80543d76633..0775de19682 100644 --- a/packages/react-charts/src/components/ChartBullet/__snapshots__/ChartBulletTitle.test.tsx.snap +++ b/packages/react-charts/src/victory/components/ChartBullet/__snapshots__/ChartBulletTitle.test.tsx.snap @@ -4,21 +4,21 @@ exports[`ChartBulletTitle 1`] = `
@@ -31,21 +31,21 @@ exports[`ChartBulletTitle 2`] = `
@@ -58,12 +58,12 @@ exports[`renders component data 1`] = `
@@ -77,7 +77,7 @@ exports[`renders component data 1`] = ` @@ -86,7 +86,7 @@ exports[`renders component data 1`] = ` @@ -95,11 +95,11 @@ exports[`renders component data 1`] = `
diff --git a/packages/react-charts/src/victory/components/ChartBullet/examples/ChartBullet.md b/packages/react-charts/src/victory/components/ChartBullet/examples/ChartBullet.md new file mode 100644 index 00000000000..9484f65b26d --- /dev/null +++ b/packages/react-charts/src/victory/components/ChartBullet/examples/ChartBullet.md @@ -0,0 +1,136 @@ +--- +id: Bullet chart +section: components +subsection: charts +propComponents: [ + 'ChartAxis', + 'ChartBullet', + 'ChartContainer' +] +hideDarkMode: true +--- + +import { createRef } from 'react'; +import { ChartAxis, ChartBullet, ChartContainer, ChartThemeColor } from '@patternfly/react-charts/victory'; +import { getResizeObserver } from '@patternfly/react-core'; + +## Introduction +Note: PatternFly React charts live in its own package at [@patternfly/react-charts](https://www.npmjs.com/package/@patternfly/react-charts)! + +The examples below are based on the [Victory](https://formidable.com/open-source/victory/docs/victory-chart/) chart library, along with additional functionality, custom components, and theming for PatternFly. This provides a collection of React based components you can use to build PatternFly patterns with consistent markup, styling, and behavior. + +## Examples +### Basic +```ts file = "ChartBulletBasic.tsx" +``` + +### Segmented primary measure +```ts file = "ChartBulletSegmentedMeasure.tsx" + +``` + +### Responsive container with bottom aligned legend + +This demonstrates a responsive legend which wraps when items are wider than its container. + +```ts file = "ChartBulletResponsiveLegend.tsx" + +``` + +### Primary measure dot +```ts file = "ChartBulletPrimaryDot.tsx" + +``` + +### Error measure and custom axis ticks + +This is a green bullet chart with error measure and custom axis ticks with 3 legend items per row. + +```ts file = "ChartBulletErrorCustomTicks.tsx" + +``` + +### Primary measure outside range + +This is a yellow bullet chart with primary measure greater than max range. + +```ts file = "ChartBulletOutsideRange.tsx" + +``` + +### Negative primary measure + +This bullet chart with negative primary measure is for measures considered to be bad when they are low. + +```ts file = "ChartBulletNegativeMeasure.tsx" + +``` + +### Reversed with right aligned legend + +This reversed bullet chart with right aligned legend is for measures considered to be good when they are low. + +```ts file = "ChartBulletReversed.tsx" + +``` + +### Negative and positive primary measures + +This bullet chart with negative and positive primary measures has 4 legend items per row. + +```ts file = "ChartBulletNegativePositiveMeasure.tsx" + +``` + +### Vertical with segmented primary measure +```ts file = "ChartBulletVerticalSegmented.tsx" + +``` + +### Vertical primary measure outside max range +```ts file = "ChartBulletVerticalMaxRange.tsx" + +``` + +### Custom labels +```ts file = "ChartBulletCustomLabels.tsx" + +``` + +### Custom size +```ts file = "ChartBulletCustomSize.tsx" + +``` + +### Horizontal group +```ts file = "ChartBulletHorizontalGroup.tsx" + +``` + +### Vertical group +```ts file = "ChartBulletVerticalGroup.tsx" + +``` + +### Horizontal group with title +```ts file = "ChartBulletHorizontalGroupTitle.tsx" + +``` + +### Vertical group with title +```ts file = "ChartBulletVerticalGroupTitle.tsx" + +``` + +## Documentation +### Tips +- See Victory's [FAQ](https://formidable.com/open-source/victory/docs/faq) +- `ChartLegend` may be used as a standalone component, instead of using `legendData` + +### Note +Currently, the generated documentation below is not able to resolve type definitions from Victory imports. For the +components used in the examples above, Victory pass-thru props are also documented here: + +- For `ChartAxis` props, see [VictoryAxis](https://formidable.com/open-source/victory/docs/victory-axis) +- For `ChartBullet` props, see [VictoryBar](https://formidable.com/open-source/victory/docs/victory-bar) +- For `ChartContainer` props, see [VictoryContainer](https://formidable.com/open-source/victory/docs/victory-container) diff --git a/packages/react-charts/src/victory/components/ChartBullet/examples/ChartBulletBasic.tsx b/packages/react-charts/src/victory/components/ChartBullet/examples/ChartBulletBasic.tsx new file mode 100644 index 00000000000..9ae04a4c138 --- /dev/null +++ b/packages/react-charts/src/victory/components/ChartBullet/examples/ChartBulletBasic.tsx @@ -0,0 +1,33 @@ +import { ChartBullet } from '@patternfly/react-charts/victory'; + +interface ChartData { + name: string; + y: number; +} + +export const ChartBulletBasic: React.FunctionComponent = () => { + const comparativeWarningMeasureData: ChartData[] = [{ name: 'Warning', y: 88 }]; + const primarySegmentedMeasureData: ChartData[] = [{ name: 'Measure', y: 60 }]; + const qualitativeRangeData: ChartData[] = [ + { name: 'Range', y: 50 }, + { name: 'Range', y: 75 } + ]; + + return ( +
+ `${datum.name}: ${datum.y}`} + maxDomain={{ y: 100 }} + name="chart1" + primarySegmentedMeasureData={primarySegmentedMeasureData} + qualitativeRangeData={qualitativeRangeData} + width={600} + /> +
+ ); +}; diff --git a/packages/react-charts/src/victory/components/ChartBullet/examples/ChartBulletCustomLabels.tsx b/packages/react-charts/src/victory/components/ChartBullet/examples/ChartBulletCustomLabels.tsx new file mode 100644 index 00000000000..1d1d0209ea8 --- /dev/null +++ b/packages/react-charts/src/victory/components/ChartBullet/examples/ChartBulletCustomLabels.tsx @@ -0,0 +1,52 @@ +import { ChartAxis, ChartBullet } from '@patternfly/react-charts/victory'; + +interface ChartData { + name: string; + y?: number; +} + +export const ChartBulletCustomLabels: React.FunctionComponent = () => { + const comparativeWarningMeasureData: ChartData[] = [{ name: 'Warning', y: 88 }]; + const primarySegmentedMeasureData: ChartData[] = [{ name: 'Measure', y: 60 }]; + const qualitativeRangeData: ChartData[] = [ + { name: 'Range', y: 50 }, + { name: 'Range', y: 75 } + ]; + + return ( +
+ { + switch (val) { + case 0: + return 'New'; + case 25: + return 'Beginner'; + case 50: + return 'Intermediate'; + case 75: + return 'Advanced'; + case 100: + return 'Expert'; + } + }} + /> + } + comparativeWarningMeasureData={comparativeWarningMeasureData} + constrainToVisibleArea + height={150} + labels={({ datum }) => `${datum.name}: ${datum.y}`} + maxDomain={{ y: 100 }} + name="chart12" + primarySegmentedMeasureData={primarySegmentedMeasureData} + qualitativeRangeData={qualitativeRangeData} + width={600} + /> +
+ ); +}; diff --git a/packages/react-charts/src/victory/components/ChartBullet/examples/ChartBulletCustomSize.tsx b/packages/react-charts/src/victory/components/ChartBullet/examples/ChartBulletCustomSize.tsx new file mode 100644 index 00000000000..26c6497048d --- /dev/null +++ b/packages/react-charts/src/victory/components/ChartBullet/examples/ChartBulletCustomSize.tsx @@ -0,0 +1,47 @@ +import { ChartBullet } from '@patternfly/react-charts/victory'; + +interface ChartData { + name: string; + y?: number; +} + +export const ChartBulletCustomSize: React.FunctionComponent = () => { + const comparativeWarningMeasureData: ChartData[] = [{ name: 'Warning', y: 88 }]; + const comparativeWarningMeasureLegendData: ChartData[] = [{ name: 'Warning' }]; + const primarySegmentedMeasureData: ChartData[] = [{ name: 'Measure', y: 60 }]; + const primarySegmentedMeasureLegendData: ChartData[] = [{ name: 'Measure 1' }]; + const qualitativeRangeData: ChartData[] = [ + { name: 'Range', y: 50 }, + { name: 'Range', y: 75 } + ]; + const qualitativeRangeLegendData: ChartData[] = [{ name: 'Range 1' }, { name: 'Range 2' }]; + + return ( +
+ `${datum.name}: ${datum.y}`} + maxDomain={{ y: 100 }} + name="chart13" + padding={{ + bottom: 50, + left: 150, // Adjusted to accommodate labels + right: 50, + top: 50 + }} + primarySegmentedMeasureData={primarySegmentedMeasureData} + primarySegmentedMeasureLegendData={primarySegmentedMeasureLegendData} + qualitativeRangeData={qualitativeRangeData} + qualitativeRangeLegendData={qualitativeRangeLegendData} + subTitle="Measure details" + title="Text label" + width={600} + /> +
+ ); +}; diff --git a/packages/react-charts/src/victory/components/ChartBullet/examples/ChartBulletErrorCustomTicks.tsx b/packages/react-charts/src/victory/components/ChartBullet/examples/ChartBulletErrorCustomTicks.tsx new file mode 100644 index 00000000000..9ad680132ac --- /dev/null +++ b/packages/react-charts/src/victory/components/ChartBullet/examples/ChartBulletErrorCustomTicks.tsx @@ -0,0 +1,57 @@ +import { ChartAxis, ChartBullet, ChartThemeColor } from '@patternfly/react-charts/victory'; + +interface ChartData { + name: string; + y?: number; +} + +export const ChartBulletErrorCustomTicks: React.FunctionComponent = () => { + const comparativeErrorMeasureData: ChartData[] = [{ name: 'Error', y: 120 }]; + const comparativeErrorMeasureLegendData: ChartData[] = [{ name: 'Error' }]; + const comparativeWarningMeasureData: ChartData[] = [{ name: 'Warning', y: 80 }]; + const comparativeWarningMeasureLegendData: ChartData[] = [{ name: 'Warning' }]; + const primarySegmentedMeasureData: ChartData[] = [ + { name: 'Measure', y: 25 }, + { name: 'Measure', y: 75 } + ]; + const primarySegmentedMeasureLegendData: ChartData[] = [{ name: 'Measure 1' }, { name: 'Measure 2' }]; + const qualitativeRangeData: ChartData[] = [ + { name: 'Range', y: 65 }, + { name: 'Range', y: 100 }, + { name: 'Range', y: 150 } + ]; + const qualitativeRangeLegendData: ChartData[] = [{ name: 'Range 1' }, { name: 'Range 2' }]; + + return ( +
+ } + comparativeErrorMeasureData={comparativeErrorMeasureData} + comparativeErrorMeasureLegendData={comparativeErrorMeasureLegendData} + comparativeWarningMeasureData={comparativeWarningMeasureData} + comparativeWarningMeasureLegendData={comparativeWarningMeasureLegendData} + constrainToVisibleArea + height={200} + labels={({ datum }) => `${datum.name}: ${datum.y}`} + legendItemsPerRow={3} + name="chart5" + padding={{ + bottom: 50, + left: 150, // Adjusted to accommodate labels + right: 50, + top: 50 + }} + primarySegmentedMeasureData={primarySegmentedMeasureData} + primarySegmentedMeasureLegendData={primarySegmentedMeasureLegendData} + qualitativeRangeData={qualitativeRangeData} + qualitativeRangeLegendData={qualitativeRangeLegendData} + themeColor={ChartThemeColor.green} + subTitle="Measure details" + title="Text label" + width={600} + /> +
+ ); +}; diff --git a/packages/react-charts/src/victory/components/ChartBullet/examples/ChartBulletHorizontalGroup.tsx b/packages/react-charts/src/victory/components/ChartBullet/examples/ChartBulletHorizontalGroup.tsx new file mode 100644 index 00000000000..0aefa3eec82 --- /dev/null +++ b/packages/react-charts/src/victory/components/ChartBullet/examples/ChartBulletHorizontalGroup.tsx @@ -0,0 +1,120 @@ +import { ChartBullet, ChartContainer } from '@patternfly/react-charts/victory'; + +interface ChartData { + name: string; + y?: number; +} + +export const ChartBulletHorizontalGroup: React.FunctionComponent = () => { + const comparativeWarningMeasureData: ChartData[] = [{ name: 'Warning', y: 78 }]; + const primarySegmentedMeasureData: ChartData[] = [ + { name: 'Measure', y: 15 }, + { name: 'Measure', y: 50 } + ]; + const qualitativeRangeData: ChartData[] = [ + { name: 'Range', y: 40 }, + { name: 'Range', y: 65 } + ]; + + return ( +
+ + `${datum.name}: ${datum.y}`} + maxDomain={{ y: 100 }} + name="chart14" + padding={{ + bottom: 100, // Adjusted to accommodate legend + left: 150, // Adjusted to accommodate labels + right: 50, + top: 75 + }} + primarySegmentedMeasureData={primarySegmentedMeasureData} + qualitativeRangeData={qualitativeRangeData} + standalone={false} + subTitle="Measure details" + title="Text label" + width={600} + /> + `${datum.name}: ${datum.y}`} + maxDomain={{ y: 100 }} + name="chart15" + padding={{ + bottom: 100, // Adjusted to accommodate legend + left: 150, // Adjusted to accommodate labels + right: 50, + top: 300 + }} + primarySegmentedMeasureData={[ + { name: 'Measure', y: 25 }, + { name: 'Measure', y: 60 } + ]} + qualitativeRangeData={[ + { name: 'Range', y: 50 }, + { name: 'Range', y: 75 } + ]} + standalone={false} + subTitle="Measure details" + title="Text label" + width={600} + /> + `${datum.name}: ${datum.y}`} + maxDomain={{ y: 100 }} + name="chart16" + padding={{ + bottom: 100, // Adjusted to accommodate legend + left: 150, // Adjusted to accommodate labels + right: 50, + top: 525 + }} + primarySegmentedMeasureData={[ + { name: 'Measure', y: 35 }, + { name: 'Measure', y: 70 } + ]} + qualitativeRangeData={[ + { name: 'Range', y: 60 }, + { name: 'Range', y: 85 } + ]} + standalone={false} + subTitle="Measure details" + title="Text label" + width={600} + /> + `${datum.name}: ${datum.y}`} + maxDomain={{ y: 100 }} + name="chart17" + padding={{ + bottom: 100, // Adjusted to accommodate legend + left: 150, // Adjusted to accommodate labels + right: 50, + top: 750 + }} + primarySegmentedMeasureData={primarySegmentedMeasureData} + primarySegmentedMeasureLegendData={[{ name: 'Measure 1' }, { name: 'Measure 2' }]} + qualitativeRangeData={qualitativeRangeData} + qualitativeRangeLegendData={[{ name: 'Range 1' }, { name: 'Range 2' }]} + standalone={false} + subTitle="Measure details" + title="Text label" + width={600} + /> + +
+ ); +}; diff --git a/packages/react-charts/src/victory/components/ChartBullet/examples/ChartBulletHorizontalGroupTitle.tsx b/packages/react-charts/src/victory/components/ChartBullet/examples/ChartBulletHorizontalGroupTitle.tsx new file mode 100644 index 00000000000..16f6f6aa776 --- /dev/null +++ b/packages/react-charts/src/victory/components/ChartBullet/examples/ChartBulletHorizontalGroupTitle.tsx @@ -0,0 +1,122 @@ +import { ChartBullet, ChartContainer } from '@patternfly/react-charts/victory'; + +interface ChartData { + name: string; + y?: number; +} + +export const ChartBulletHorizontalGroupTitle: React.FunctionComponent = () => { + const comparativeWarningMeasureData: ChartData[] = [{ name: 'Warning', y: 78 }]; + const primarySegmentedMeasureData: ChartData[] = [ + { name: 'Measure', y: 15 }, + { name: 'Measure', y: 50 } + ]; + const qualitativeRangeData: ChartData[] = [ + { name: 'Range', y: 40 }, + { name: 'Range', y: 65 } + ]; + + return ( +
+ + `${datum.name}: ${datum.y}`} + maxDomain={{ y: 100 }} + name="chart22" + padding={{ + bottom: 100, // Adjusted to accommodate legend + left: 150, // Adjusted to accommodate labels + right: 50, + top: 275 // Adjusted to accommodate group labels + }} + primarySegmentedMeasureData={primarySegmentedMeasureData} + qualitativeRangeData={qualitativeRangeData} + standalone={false} + subTitle="Measure details" + title="Text label" + width={600} + /> + `${datum.name}: ${datum.y}`} + maxDomain={{ y: 100 }} + name="chart23" + padding={{ + bottom: 100, // Adjusted to accommodate legend + left: 150, // Adjusted to accommodate labels + right: 50, + top: 500 // Adjusted to accommodate group labels + }} + primarySegmentedMeasureData={[ + { name: 'Measure', y: 25 }, + { name: 'Measure', y: 60 } + ]} + qualitativeRangeData={[ + { name: 'Range', y: 50 }, + { name: 'Range', y: 75 } + ]} + standalone={false} + subTitle="Measure details" + title="Text label" + width={600} + /> + `${datum.name}: ${datum.y}`} + maxDomain={{ y: 100 }} + name="chart24" + padding={{ + bottom: 100, // Adjusted to accommodate legend + left: 150, // Adjusted to accommodate labels + right: 50, + top: 725 // Adjusted to accommodate group labels + }} + primarySegmentedMeasureData={[ + { name: 'Measure', y: 35 }, + { name: 'Measure', y: 70 } + ]} + qualitativeRangeData={[ + { name: 'Range', y: 60 }, + { name: 'Range', y: 85 } + ]} + standalone={false} + subTitle="Measure details" + title="Text label" + width={600} + /> + `${datum.name}: ${datum.y}`} + maxDomain={{ y: 100 }} + name="chart25" + padding={{ + bottom: 100, // Adjusted to accommodate legend + left: 150, // Adjusted to accommodate labels + right: 50, + top: 950 // Adjusted to accommodate group labels + }} + primarySegmentedMeasureData={primarySegmentedMeasureData} + primarySegmentedMeasureLegendData={[{ name: 'Measure 1' }, { name: 'Measure 2' }]} + qualitativeRangeData={qualitativeRangeData} + qualitativeRangeLegendData={[{ name: 'Range 1' }, { name: 'Range 2' }]} + standalone={false} + subTitle="Measure details" + title="Text label" + width={600} + /> + +
+ ); +}; diff --git a/packages/react-charts/src/victory/components/ChartBullet/examples/ChartBulletNegativeMeasure.tsx b/packages/react-charts/src/victory/components/ChartBullet/examples/ChartBulletNegativeMeasure.tsx new file mode 100644 index 00000000000..b0c26ba3599 --- /dev/null +++ b/packages/react-charts/src/victory/components/ChartBullet/examples/ChartBulletNegativeMeasure.tsx @@ -0,0 +1,49 @@ +import { ChartBullet } from '@patternfly/react-charts/victory'; + +interface ChartData { + name: string; + y?: number; + y0?: number; +} + +export const ChartBulletNegativeMeasure: React.FunctionComponent = () => { + const comparativeWarningMeasureData: ChartData[] = [{ name: 'Warning', y: 60 }]; + const comparativeWarningMeasureLegendData: ChartData[] = [{ name: 'Warning' }]; + const primarySegmentedMeasureData: ChartData[] = [{ name: 'Measure', y: -15 }]; + const primarySegmentedMeasureLegendData: ChartData[] = [{ name: 'Measure 1' }]; + const qualitativeRangeData: ChartData[] = [ + { name: 'Range', y: 25, y0: -25 }, + { name: 'Range', y: 50 } + ]; + const qualitativeRangeLegendData: ChartData[] = [{ name: 'Range 1' }, { name: 'Range 2' }]; + + return ( +
+ `${datum.name}: ${datum.y}`} + maxDomain={{ y: 75 }} + minDomain={{ y: -25 }} + name="chart7" + padding={{ + bottom: 50, + left: 150, // Adjusted to accommodate labels + right: 50, + top: 65 + }} + primarySegmentedMeasureData={primarySegmentedMeasureData} + primarySegmentedMeasureLegendData={primarySegmentedMeasureLegendData} + qualitativeRangeData={qualitativeRangeData} + qualitativeRangeLegendData={qualitativeRangeLegendData} + subTitle="Measure details" + title="Text label" + width={600} + /> +
+ ); +}; diff --git a/packages/react-charts/src/victory/components/ChartBullet/examples/ChartBulletNegativePositiveMeasure.tsx b/packages/react-charts/src/victory/components/ChartBullet/examples/ChartBulletNegativePositiveMeasure.tsx new file mode 100644 index 00000000000..48397f2d121 --- /dev/null +++ b/packages/react-charts/src/victory/components/ChartBullet/examples/ChartBulletNegativePositiveMeasure.tsx @@ -0,0 +1,60 @@ +import { ChartBullet } from '@patternfly/react-charts/victory'; + +interface ChartData { + name: string; + y?: number; + y0?: number; +} + +export const ChartBulletNegativePositiveMeasure: React.FunctionComponent = () => { + const comparativeWarningMeasureData: ChartData[] = [{ name: 'Warning', y: 60 }]; + const comparativeWarningMeasureLegendData: ChartData[] = [{ name: 'Warning' }]; + const primarySegmentedMeasureData: ChartData[] = [ + { name: 'Measure', y: -10 }, + { name: 'Measure', y: -20 }, + { name: 'Measure', y: 10 }, + { name: 'Measure', y: 40 } + ]; + const primarySegmentedMeasureLegendData: ChartData[] = [ + { name: 'Measure 1' }, + { name: 'Measure 2' }, + { name: 'Measure 3' }, + { name: 'Measure 4' } + ]; + const qualitativeRangeData: ChartData[] = [ + { name: 'Range', y: 25, y0: -25 }, + { name: 'Range', y: 50 } + ]; + const qualitativeRangeLegendData: ChartData[] = [{ name: 'Range 1' }, { name: 'Range 2' }]; + + return ( +
+ `${datum.name}: ${datum.y}`} + legendItemsPerRow={4} + maxDomain={{ y: 75 }} + minDomain={{ y: -25 }} + name="chart9" + padding={{ + bottom: 50, + left: 150, // Adjusted to accommodate labels + right: 50, + top: 65 + }} + primarySegmentedMeasureData={primarySegmentedMeasureData} + primarySegmentedMeasureLegendData={primarySegmentedMeasureLegendData} + qualitativeRangeData={qualitativeRangeData} + qualitativeRangeLegendData={qualitativeRangeLegendData} + subTitle="Measure details" + title="Text label" + width={600} + /> +
+ ); +}; diff --git a/packages/react-charts/src/victory/components/ChartBullet/examples/ChartBulletOutsideRange.tsx b/packages/react-charts/src/victory/components/ChartBullet/examples/ChartBulletOutsideRange.tsx new file mode 100644 index 00000000000..577e6e16819 --- /dev/null +++ b/packages/react-charts/src/victory/components/ChartBullet/examples/ChartBulletOutsideRange.tsx @@ -0,0 +1,52 @@ +import { ChartBullet, ChartThemeColor } from '@patternfly/react-charts/victory'; + +interface ChartData { + name: string; + y?: number; +} + +export const ChartBulletOutsideRange: React.FunctionComponent = () => { + const comparativeWarningMeasureData: ChartData[] = [{ name: 'Warning', y: 80 }]; + const comparativeWarningMeasureLegendData: ChartData[] = [{ name: 'Warning' }]; + const primarySegmentedMeasureData: ChartData[] = [ + { name: 'Measure', y: 75 }, + { name: 'Measure', y: 135 } + ]; + const primarySegmentedMeasureLegendData: ChartData[] = [{ name: 'Measure 1' }, { name: 'Measure 2' }]; + const qualitativeRangeData: ChartData[] = [ + { name: 'Range', y: 85 }, + { name: 'Range', y: 125 } + ]; + const qualitativeRangeLegendData: ChartData[] = [{ name: 'Range 1' }, { name: 'Range 2' }]; + + return ( +
+ `${datum.name}: ${datum.y}`} + height={200} + maxDomain={{ y: 125 }} + minDomain={{ y: 50 }} + name="chart6" + padding={{ + bottom: 50, + left: 150, // Adjusted to accommodate labels + right: 75, + top: 50 + }} + primarySegmentedMeasureData={primarySegmentedMeasureData} + primarySegmentedMeasureLegendData={primarySegmentedMeasureLegendData} + qualitativeRangeData={qualitativeRangeData} + qualitativeRangeLegendData={qualitativeRangeLegendData} + themeColor={ChartThemeColor.yellow} + subTitle="Measure details" + title="Text label" + width={600} + /> +
+ ); +}; diff --git a/packages/react-charts/src/victory/components/ChartBullet/examples/ChartBulletPrimaryDot.tsx b/packages/react-charts/src/victory/components/ChartBullet/examples/ChartBulletPrimaryDot.tsx new file mode 100644 index 00000000000..ff4576d7b9d --- /dev/null +++ b/packages/react-charts/src/victory/components/ChartBullet/examples/ChartBulletPrimaryDot.tsx @@ -0,0 +1,50 @@ +import { ChartBullet } from '@patternfly/react-charts/victory'; + +interface ChartData { + name: string; + y?: number; +} + +export const ChartBulletPrimaryDot: React.FunctionComponent = () => { + const comparativeWarningMeasureData: ChartData[] = [{ name: 'Warning', y: 88 }]; + const comparativeWarningMeasureLegendData: ChartData[] = [{ name: 'Warning' }]; + const primaryDotMeasureData: ChartData[] = [ + { name: 'Measure', y: 25 }, + { name: 'Measure', y: 60 } + ]; + const primaryDotMeasureLegendData: ChartData[] = [{ name: 'Measure 1' }, { name: 'Measure 2' }]; + const qualitativeRangeData: ChartData[] = [ + { name: 'Range', y: 50 }, + { name: 'Range', y: 75 } + ]; + const qualitativeRangeLegendData: ChartData[] = [{ name: 'Range 1' }, { name: 'Range 2' }]; + + return ( +
+ `${datum.name}: ${datum.y}`} + maxDomain={{ y: 100 }} + name="chart4" + padding={{ + bottom: 50, + left: 150, // Adjusted to accommodate labels + right: 50, + top: 50 + }} + primaryDotMeasureData={primaryDotMeasureData} + primaryDotMeasureLegendData={primaryDotMeasureLegendData} + qualitativeRangeData={qualitativeRangeData} + qualitativeRangeLegendData={qualitativeRangeLegendData} + subTitle="Measure details" + title="Text label" + width={600} + /> +
+ ); +}; diff --git a/packages/react-charts/src/victory/components/ChartBullet/examples/ChartBulletResponsiveLegend.tsx b/packages/react-charts/src/victory/components/ChartBullet/examples/ChartBulletResponsiveLegend.tsx new file mode 100644 index 00000000000..87487601652 --- /dev/null +++ b/packages/react-charts/src/victory/components/ChartBullet/examples/ChartBulletResponsiveLegend.tsx @@ -0,0 +1,87 @@ +import { ChartBullet } from '@patternfly/react-charts/victory'; +import { getResizeObserver } from '@patternfly/react-core'; + +interface ChartData { + name: string; + y?: number; +} + +export const BulletChartResponsiveLegend: React.FunctionComponent = () => { + const containerRef = React.useRef(null); + const [extraHeight, setExtraHeight] = React.useState(0); + const [width, setWidth] = React.useState(0); + const comparativeWarningMeasureData: ChartData[] = [{ name: 'Warning', y: 88 }]; + const comparativeWarningMeasureLegendData: ChartData[] = [{ name: 'Warning' }]; + const primarySegmentedMeasureData: ChartData[] = [ + { name: 'Measure', y: 25 }, + { name: 'Measure', y: 60 } + ]; + const primarySegmentedMeasureLegendData: ChartData[] = [{ name: 'Measure 1' }, { name: 'Measure 2' }]; + const qualitativeRangeData: ChartData[] = [ + { name: 'Range', y: 50 }, + { name: 'Range', y: 75 } + ]; + const qualitativeRangeLegendData: ChartData[] = [{ name: 'Range 1' }, { name: 'Range 2' }]; + + const handleResize = (): void => { + if (containerRef.current && containerRef.current.clientWidth) { + setWidth(containerRef.current.clientWidth); + } + }; + + const handleLegendAllowWrap = (newExtraHeight: number): void => { + if (newExtraHeight !== extraHeight) { + setExtraHeight(newExtraHeight); + } + }; + + const getHeight = (baseHeight: number): number => baseHeight + extraHeight; + + React.useEffect(() => { + let observer: () => void; + + if (containerRef.current) { + observer = getResizeObserver(containerRef.current, handleResize); + handleResize(); + } + return () => { + if (observer) { + observer(); + } + }; + }, []); + + const height: number = getHeight(200); + + return ( +
+ `${datum.name}: ${datum.y}`} + legendAllowWrap={handleLegendAllowWrap} + legendPosition="bottom-left" + maxDomain={{ y: 100 }} + name="chart3" + 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/ChartBullet/examples/ChartBulletReversed.tsx b/packages/react-charts/src/victory/components/ChartBullet/examples/ChartBulletReversed.tsx new file mode 100644 index 00000000000..0004d2fa717 --- /dev/null +++ b/packages/react-charts/src/victory/components/ChartBullet/examples/ChartBulletReversed.tsx @@ -0,0 +1,54 @@ +import { ChartBullet } from '@patternfly/react-charts/victory'; + +interface ChartData { + name: string; + y?: number; +} + +export const ChartBulletReversed: React.FunctionComponent = () => { + const comparativeWarningMeasureData: ChartData[] = [{ name: 'Warning', y: -88 }]; + const comparativeWarningMeasureLegendData: ChartData[] = [{ name: 'Warning' }]; + const primarySegmentedMeasureData: ChartData[] = [ + { name: 'Measure', y: -60 }, + { name: 'Measure', y: -25 } + ]; + const primarySegmentedMeasureLegendData: ChartData[] = [{ name: 'Measure 1' }, { name: 'Measure 2' }]; + const qualitativeRangeData: ChartData[] = [ + { name: 'Range', y: -50 }, + { name: 'Range', y: -75 } + ]; + const qualitativeRangeLegendData: ChartData[] = [{ name: 'Range 1' }, { name: 'Range 2' }]; + + return ( +
+ `${datum.name}: ${datum.y}`} + legendPosition="right" + legendOrientation="vertical" + maxDomain={{ y: 0 }} + minDomain={{ y: -100 }} + name="chart8" + padding={{ + bottom: 50, + left: 150, // Adjusted to accommodate labels + right: 150, // Adjusted to accommodate legend + top: 80 + }} + primarySegmentedMeasureData={primarySegmentedMeasureData} + primarySegmentedMeasureLegendData={primarySegmentedMeasureLegendData} + qualitativeRangeData={qualitativeRangeData} + qualitativeRangeLegendData={qualitativeRangeLegendData} + subTitle="Measure details" + title="Text label" + width={700} + /> +
+ ); +}; diff --git a/packages/react-charts/src/victory/components/ChartBullet/examples/ChartBulletSegmentedMeasure.tsx b/packages/react-charts/src/victory/components/ChartBullet/examples/ChartBulletSegmentedMeasure.tsx new file mode 100644 index 00000000000..d6704140bc9 --- /dev/null +++ b/packages/react-charts/src/victory/components/ChartBullet/examples/ChartBulletSegmentedMeasure.tsx @@ -0,0 +1,50 @@ +import { ChartBullet } from '@patternfly/react-charts/victory'; + +interface ChartData { + name: string; + y?: number; +} + +export const ChartBulletSegmentedMeasure: React.FunctionComponent = () => { + const comparativeWarningMeasureData: ChartData[] = [{ name: 'Warning', y: 88 }]; + const comparativeWarningMeasureLegendData: ChartData[] = [{ name: 'Warning' }]; + const primarySegmentedMeasureData: ChartData[] = [ + { name: 'Measure', y: 25 }, + { name: 'Measure', y: 60 } + ]; + const primarySegmentedMeasureLegendData: ChartData[] = [{ name: 'Measure 1' }, { name: 'Measure 2' }]; + const qualitativeRangeData: ChartData[] = [ + { name: 'Range', y: 50 }, + { name: 'Range', y: 75 } + ]; + const qualitativeRangeLegendData: ChartData[] = [{ name: 'Range 1' }, { name: 'Range 2' }]; + + return ( +
+ `${datum.name}: ${datum.y}`} + maxDomain={{ y: 100 }} + name="chart2" + padding={{ + bottom: 50, + left: 150, // Adjusted to accommodate labels + right: 50, + top: 50 + }} + primarySegmentedMeasureData={primarySegmentedMeasureData} + primarySegmentedMeasureLegendData={primarySegmentedMeasureLegendData} + qualitativeRangeData={qualitativeRangeData} + qualitativeRangeLegendData={qualitativeRangeLegendData} + subTitle="Measure details" + title="Text label" + width={600} + /> +
+ ); +}; diff --git a/packages/react-charts/src/victory/components/ChartBullet/examples/ChartBulletVerticalGroup.tsx b/packages/react-charts/src/victory/components/ChartBullet/examples/ChartBulletVerticalGroup.tsx new file mode 100644 index 00000000000..a7db62b3ccd --- /dev/null +++ b/packages/react-charts/src/victory/components/ChartBullet/examples/ChartBulletVerticalGroup.tsx @@ -0,0 +1,124 @@ +import { ChartBullet, ChartContainer } from '@patternfly/react-charts/victory'; + +interface ChartData { + name: string; + y?: number; +} + +export const ChartBulletVerticalGroup: React.FunctionComponent = () => { + const comparativeWarningMeasureData: ChartData[] = [{ name: 'Warning', y: 78 }]; + const primarySegmentedMeasureData: ChartData[] = [ + { name: 'Measure', y: 15 }, + { name: 'Measure', y: 50 } + ]; + const qualitativeRangeData: ChartData[] = [ + { name: 'Range', y: 40 }, + { name: 'Range', y: 65 } + ]; + + return ( +
+ + `${datum.name}: ${datum.y}`} + maxDomain={{ y: 100 }} + name="chart18" + padding={{ + bottom: 125, // Adjusted to accommodate legend + left: 50, + right: 50, + top: 50 + }} + primarySegmentedMeasureData={primarySegmentedMeasureData} + primarySegmentedMeasureLegendData={[{ name: 'Measure 1' }, { name: 'Measure 2' }]} + qualitativeRangeData={qualitativeRangeData} + qualitativeRangeLegendData={[{ name: 'Range 1' }, { name: 'Range 2' }]} + standalone={false} + subTitle="Measure details" + title="Text label" + width={500} + /> + `${datum.name}: ${datum.y}`} + maxDomain={{ y: 100 }} + name="chart19" + padding={{ + bottom: 125, // Adjusted to accommodate legend + left: 300, + right: 50, + top: 50 + }} + primarySegmentedMeasureData={[ + { name: 'Measure', y: 25 }, + { name: 'Measure', y: 60 } + ]} + qualitativeRangeData={[ + { name: 'Range', y: 50 }, + { name: 'Range', y: 75 } + ]} + standalone={false} + subTitle="Measure details" + title="Text label" + width={500} + /> + `${datum.name}: ${datum.y}`} + maxDomain={{ y: 100 }} + name="chart20" + padding={{ + bottom: 125, // Adjusted to accommodate legend + left: 550, + right: 50, + top: 50 + }} + primarySegmentedMeasureData={[ + { name: 'Measure', y: 35 }, + { name: 'Measure', y: 70 } + ]} + qualitativeRangeData={[ + { name: 'Range', y: 60 }, + { name: 'Range', y: 85 } + ]} + standalone={false} + subTitle="Measure details" + title="Text label" + width={500} + /> + `${datum.name}: ${datum.y}`} + maxDomain={{ y: 100 }} + name="chart21" + padding={{ + bottom: 125, // Adjusted to accommodate legend + left: 800, + right: 50, + top: 50 + }} + primarySegmentedMeasureData={primarySegmentedMeasureData} + qualitativeRangeData={qualitativeRangeData} + standalone={false} + subTitle="Measure details" + title="Text label" + width={500} + /> + +
+ ); +}; diff --git a/packages/react-charts/src/victory/components/ChartBullet/examples/ChartBulletVerticalGroupTitle.tsx b/packages/react-charts/src/victory/components/ChartBullet/examples/ChartBulletVerticalGroupTitle.tsx new file mode 100644 index 00000000000..a6f334c5602 --- /dev/null +++ b/packages/react-charts/src/victory/components/ChartBullet/examples/ChartBulletVerticalGroupTitle.tsx @@ -0,0 +1,126 @@ +import { ChartBullet, ChartContainer } from '@patternfly/react-charts/victory'; + +interface ChartData { + name: string; + y?: number; +} + +export const ChartBulletVerticalGroupTitle: React.FunctionComponent = () => { + const comparativeWarningMeasureData: ChartData[] = [{ name: 'Warning', y: 78 }]; + const primarySegmentedMeasureData: ChartData[] = [ + { name: 'Measure', y: 15 }, + { name: 'Measure', y: 50 } + ]; + const qualitativeRangeData: ChartData[] = [ + { name: 'Range', y: 40 }, + { name: 'Range', y: 65 } + ]; + + return ( +
+ + `${datum.name}: ${datum.y}`} + maxDomain={{ y: 100 }} + name="chart26" + padding={{ + bottom: 125, // Adjusted to accommodate legend + left: 50, + right: 50, + top: 150 // Adjusted to accommodate group labels + }} + primarySegmentedMeasureData={primarySegmentedMeasureData} + primarySegmentedMeasureLegendData={[{ name: 'Measure 1' }, { name: 'Measure 2' }]} + qualitativeRangeData={qualitativeRangeData} + qualitativeRangeLegendData={[{ name: 'Range 1' }, { name: 'Range 2' }]} + standalone={false} + subTitle="Measure details" + title="Text label" + width={500} + /> + `${datum.name}: ${datum.y}`} + maxDomain={{ y: 100 }} + name="chart27" + padding={{ + bottom: 125, // Adjusted to accommodate legend + left: 300, + right: 50, + top: 150 // Adjusted to accommodate group labels + }} + primarySegmentedMeasureData={[ + { name: 'Measure', y: 25 }, + { name: 'Measure', y: 60 } + ]} + qualitativeRangeData={[ + { name: 'Range', y: 50 }, + { name: 'Range', y: 75 } + ]} + standalone={false} + subTitle="Measure details" + title="Text label" + width={500} + /> + `${datum.name}: ${datum.y}`} + maxDomain={{ y: 100 }} + name="chart28" + padding={{ + bottom: 125, // Adjusted to accommodate legend + left: 550, + right: 50, + top: 150 // Adjusted to accommodate group labels + }} + primarySegmentedMeasureData={[ + { name: 'Measure', y: 35 }, + { name: 'Measure', y: 70 } + ]} + qualitativeRangeData={[ + { name: 'Range', y: 60 }, + { name: 'Range', y: 85 } + ]} + standalone={false} + subTitle="Measure details" + title="Text label" + width={500} + /> + `${datum.name}: ${datum.y}`} + maxDomain={{ y: 100 }} + name="chart29" + padding={{ + bottom: 125, // Adjusted to accommodate legend + left: 800, + right: 50, + top: 150 // Adjusted to accommodate group labels + }} + primarySegmentedMeasureData={primarySegmentedMeasureData} + qualitativeRangeData={qualitativeRangeData} + standalone={false} + subTitle="Measure details" + title="Text label" + width={500} + /> + +
+ ); +}; diff --git a/packages/react-charts/src/victory/components/ChartBullet/examples/ChartBulletVerticalMaxRange.tsx b/packages/react-charts/src/victory/components/ChartBullet/examples/ChartBulletVerticalMaxRange.tsx new file mode 100644 index 00000000000..b43a111e8cd --- /dev/null +++ b/packages/react-charts/src/victory/components/ChartBullet/examples/ChartBulletVerticalMaxRange.tsx @@ -0,0 +1,53 @@ +import { ChartBullet, ChartThemeColor } from '@patternfly/react-charts/victory'; + +interface ChartData { + name: string; + y?: number; +} + +export const ChartBulletVerticalMaxRange: React.FunctionComponent = () => { + const comparativeWarningMeasureData: ChartData[] = [{ name: 'Warning', y: 100 }]; + const comparativeWarningMeasureLegendData: ChartData[] = [{ name: 'Warning' }]; + const primarySegmentedMeasureData: ChartData[] = [ + { name: 'Measure', y: 75 }, + { name: 'Measure', y: 135 } + ]; + const primarySegmentedMeasureLegendData: ChartData[] = [{ name: 'Measure 1' }, { name: 'Measure 2' }]; + const qualitativeRangeData: ChartData[] = [ + { name: 'Range', y: 85 }, + { name: 'Range', y: 125 } + ]; + const qualitativeRangeLegendData: ChartData[] = [{ name: 'Range 1' }, { name: 'Range 2' }]; + + return ( +
+ `${datum.name}: ${datum.y}`} + maxDomain={{ y: 125 }} + minDomain={{ y: 50 }} + name="chart11" + padding={{ + bottom: 125, // Adjusted to accommodate legend + left: 400, + right: 50, + top: 50 // Adjusted to accommodate primary segmented measure tooltip + }} + primarySegmentedMeasureData={primarySegmentedMeasureData} + primarySegmentedMeasureLegendData={primarySegmentedMeasureLegendData} + qualitativeRangeData={qualitativeRangeData} + qualitativeRangeLegendData={qualitativeRangeLegendData} + subTitle="Measure details" + title="Text label" + themeColor={ChartThemeColor.yellow} + width={500} + /> +
+ ); +}; diff --git a/packages/react-charts/src/victory/components/ChartBullet/examples/ChartBulletVerticalSegmented.tsx b/packages/react-charts/src/victory/components/ChartBullet/examples/ChartBulletVerticalSegmented.tsx new file mode 100644 index 00000000000..bbb6b765508 --- /dev/null +++ b/packages/react-charts/src/victory/components/ChartBullet/examples/ChartBulletVerticalSegmented.tsx @@ -0,0 +1,51 @@ +import { ChartBullet } from '@patternfly/react-charts/victory'; + +interface ChartData { + name: string; + y?: number; +} + +export const ChartBulletVerticalSegmented: React.FunctionComponent = () => { + const comparativeWarningMeasureData: ChartData[] = [{ name: 'Warning', y: 88 }]; + const comparativeWarningMeasureLegendData: ChartData[] = [{ name: 'Warning' }]; + const primarySegmentedMeasureData: ChartData[] = [ + { name: 'Measure', y: 25 }, + { name: 'Measure', y: 60 } + ]; + const primarySegmentedMeasureLegendData: ChartData[] = [{ name: 'Measure 1' }, { name: 'Measure 2' }]; + const qualitativeRangeData: ChartData[] = [ + { name: 'Range', y: 50 }, + { name: 'Range', y: 75 } + ]; + const qualitativeRangeLegendData: ChartData[] = [{ name: 'Range 1' }, { name: 'Range 2' }]; + + return ( +
+ `${datum.name}: ${datum.y}`} + maxDomain={{ y: 100 }} + name="chart10" + padding={{ + bottom: 125, // Adjusted to accommodate legend + left: 400, + right: 50, + top: 50 + }} + primarySegmentedMeasureData={primarySegmentedMeasureData} + primarySegmentedMeasureLegendData={primarySegmentedMeasureLegendData} + qualitativeRangeData={qualitativeRangeData} + qualitativeRangeLegendData={qualitativeRangeLegendData} + subTitle="Measure details" + title="Text label" + width={500} + /> +
+ ); +}; diff --git a/packages/react-charts/src/components/ChartBullet/utils/chart-bullet-data.ts b/packages/react-charts/src/victory/components/ChartBullet/utils/chart-bullet-data.ts similarity index 93% rename from packages/react-charts/src/components/ChartBullet/utils/chart-bullet-data.ts rename to packages/react-charts/src/victory/components/ChartBullet/utils/chart-bullet-data.ts index ce591b5237c..509263b92b4 100644 --- a/packages/react-charts/src/components/ChartBullet/utils/chart-bullet-data.ts +++ b/packages/react-charts/src/victory/components/ChartBullet/utils/chart-bullet-data.ts @@ -22,7 +22,8 @@ interface ChartBulletDataInterface { /** * Returns comparative measure data - * @private + * + * @private Not intended as public API and subject to change */ export const getComparativeMeasureData = ({ data, @@ -54,7 +55,8 @@ export const getComparativeMeasureData = ({ /** * Returns comparative error measure data - * @private + * + * @private Not intended as public API and subject to change */ export const getComparativeErrorMeasureData = ({ data, @@ -73,7 +75,8 @@ export const getComparativeErrorMeasureData = ({ /** * Returns comparative warning data - * @private + * + * @private Not intended as public API and subject to change */ export const getComparativeWarningMeasureData = ({ data, @@ -92,7 +95,8 @@ export const getComparativeWarningMeasureData = ({ /** * Returns primary dot measure data - * @private + * + * @private Not intended as public API and subject to change */ export const getPrimaryDotMeasureData = ({ data, @@ -115,7 +119,8 @@ export const getPrimaryDotMeasureData = ({ /** * Returns primary segment measure data - * @private + * + * @private Not intended as public API and subject to change */ export const getPrimarySegmentedMeasureData = ({ data, @@ -182,7 +187,8 @@ export const getPrimarySegmentedMeasureData = ({ /** * Returns qualitative range data - * @private + * + * @private Not intended as public API and subject to change */ export const getQualitativeRangeData = ({ data, diff --git a/packages/react-charts/src/components/ChartBullet/utils/chart-bullet-domain.ts b/packages/react-charts/src/victory/components/ChartBullet/utils/chart-bullet-domain.ts similarity index 97% rename from packages/react-charts/src/components/ChartBullet/utils/chart-bullet-domain.ts rename to packages/react-charts/src/victory/components/ChartBullet/utils/chart-bullet-domain.ts index a7e42a72de1..ce65712311e 100644 --- a/packages/react-charts/src/components/ChartBullet/utils/chart-bullet-domain.ts +++ b/packages/react-charts/src/victory/components/ChartBullet/utils/chart-bullet-domain.ts @@ -1,4 +1,3 @@ -import * as React from 'react'; import { ChartDomain, getDomains } from '../../ChartUtils/chart-domain'; interface ChartBulletDomainInterface { @@ -18,7 +17,8 @@ interface ChartBulletDomainInterface { /** * Returns the bullet chart's min and max domain for comparative / primary measures and qualitative range data - * @private + * + * @private Not intended as public API and subject to change */ export const getBulletDomain = ({ comparativeErrorMeasureComponent, diff --git a/packages/react-charts/src/components/ChartBullet/utils/chart-bullet-size.ts b/packages/react-charts/src/victory/components/ChartBullet/utils/chart-bullet-size.ts similarity index 88% rename from packages/react-charts/src/components/ChartBullet/utils/chart-bullet-size.ts rename to packages/react-charts/src/victory/components/ChartBullet/utils/chart-bullet-size.ts index 65a14cbd217..c477d141d5e 100644 --- a/packages/react-charts/src/components/ChartBullet/utils/chart-bullet-size.ts +++ b/packages/react-charts/src/victory/components/ChartBullet/utils/chart-bullet-size.ts @@ -20,7 +20,8 @@ interface ChartBulletScaleInterface { /** * Scale dimensions - * @private + * + * @private Not intended as public API and subject to change */ const scaleDimensions = ({ defaultSize, @@ -42,13 +43,15 @@ const scaleDimensions = ({ /** * Scale bar width per the given size properties - * @private + * + * @private Not intended as public API and subject to change */ const scaleBarWidth = (props: ChartBulletScaleInterface) => Math.max(scaleDimensions(props), 0); /** * Scale size per the given size properties - * @private + * + * @private Not intended as public API and subject to change */ const scaleSize = ({ value, ...rest }: ChartBulletScaleInterface) => Math.round( @@ -69,7 +72,8 @@ interface ChartBulletSizeInterface { /** * Scale size per the given size properties - * @private + * + * @private Not intended as public API and subject to change */ export const getComparativeMeasureErrorWidth = ({ height, @@ -90,7 +94,8 @@ export const getComparativeMeasureErrorWidth = ({ /** * Returns comparative measure width - * @private + * + * @private Not intended as public API and subject to change */ export const getComparativeMeasureWidth = ({ height, @@ -111,7 +116,8 @@ export const getComparativeMeasureWidth = ({ /** * Returns comparative measure warning width - * @private + * + * @private Not intended as public API and subject to change */ export const getComparativeMeasureWarningWidth = ({ height, @@ -132,7 +138,8 @@ export const getComparativeMeasureWarningWidth = ({ /** * Returns primary dot measure size - * @private + * + * @private Not intended as public API and subject to change */ export const getPrimaryDotMeasureSize = ({ height, @@ -153,7 +160,8 @@ export const getPrimaryDotMeasureSize = ({ /** * Returns primary segmented measure width - * @private + * + * @private Not intended as public API and subject to change */ export const getPrimarySegmentedMeasureWidth = ({ height, @@ -175,7 +183,8 @@ export const getPrimarySegmentedMeasureWidth = ({ /** * Returns qualitative range bar width - * @private + * + * @private Not intended as public API and subject to change */ export const getQualitativeRangeBarWidth = ({ height, diff --git a/packages/react-charts/src/components/ChartBullet/utils/chart-bullet-theme.ts b/packages/react-charts/src/victory/components/ChartBullet/utils/chart-bullet-theme.ts similarity index 95% rename from packages/react-charts/src/components/ChartBullet/utils/chart-bullet-theme.ts rename to packages/react-charts/src/victory/components/ChartBullet/utils/chart-bullet-theme.ts index 2cfb13f9950..7a73ae5ca0f 100644 --- a/packages/react-charts/src/components/ChartBullet/utils/chart-bullet-theme.ts +++ b/packages/react-charts/src/victory/components/ChartBullet/utils/chart-bullet-theme.ts @@ -27,7 +27,8 @@ interface ChartBulletThemeInterface { /** * Returns legend color scale - * @private + * + * @private Not intended as public API and subject to change */ const getLegendColorScale = (computedData: any, legendData: any) => { const colorScale: string[] = []; @@ -43,7 +44,8 @@ const getLegendColorScale = (computedData: any, legendData: any) => { /** * Returns color scale - * @private + * + * @private Not intended as public API and subject to change */ export const getColorScale = ({ comparativeErrorMeasureData, @@ -103,7 +105,8 @@ export const getColorScale = ({ /** * Returns bullet chart theme with legend color scale - * @private + * + * @private Not intended as public API and subject to change */ export const getBulletThemeWithLegendColorScale = ({ comparativeErrorMeasureData, diff --git a/packages/react-charts/src/components/ChartContainer/ChartContainer.test.tsx b/packages/react-charts/src/victory/components/ChartContainer/ChartContainer.test.tsx similarity index 96% rename from packages/react-charts/src/components/ChartContainer/ChartContainer.test.tsx rename to packages/react-charts/src/victory/components/ChartContainer/ChartContainer.test.tsx index 6cf8caa96ac..ddc3ab1ad9c 100644 --- a/packages/react-charts/src/components/ChartContainer/ChartContainer.test.tsx +++ b/packages/react-charts/src/victory/components/ChartContainer/ChartContainer.test.tsx @@ -1,4 +1,3 @@ -import * as React from 'react'; import { render } from '@testing-library/react'; import { ChartLegend } from '../ChartLegend/ChartLegend'; import { ChartLabel } from '../ChartLabel/ChartLabel'; diff --git a/packages/react-charts/src/components/ChartContainer/ChartContainer.tsx b/packages/react-charts/src/victory/components/ChartContainer/ChartContainer.tsx similarity index 94% rename from packages/react-charts/src/components/ChartContainer/ChartContainer.tsx rename to packages/react-charts/src/victory/components/ChartContainer/ChartContainer.tsx index 76cef39c763..59b47e53dde 100644 --- a/packages/react-charts/src/components/ChartContainer/ChartContainer.tsx +++ b/packages/react-charts/src/victory/components/ChartContainer/ChartContainer.tsx @@ -1,4 +1,3 @@ -import * as React from 'react'; import hoistNonReactStatics from 'hoist-non-react-statics'; import { OriginType, VictoryContainer, VictoryContainerProps } from 'victory-core'; import { ChartThemeDefinition } from '../ChartTheme/ChartTheme'; @@ -16,9 +15,9 @@ export interface ChartContainerProps extends VictoryContainerProps { * The children prop specifies the child or children that will be rendered within the container. It will be set by * whatever Victory component is rendering the container. */ - children?: React.ReactElement | React.ReactElement[]; + children?: React.ReactElement | React.ReactElement[]; /** - * The className prop specifies a className that will be applied to the outer-most div rendered by ChartContainer + * The className prop specifies a className that will be applied to the outermost div rendered by ChartContainer */ className?: string; /** @@ -31,14 +30,14 @@ export interface ChartContainerProps extends VictoryContainerProps { * * @example containerRef={(ref) => { this.chartRef = ref; }} */ - containerRef?: React.RefObject; + containerRef?: React.RefObject; /** * The desc prop specifies the description of the chart/SVG to assist with * accessibility for screen readers. The more info about the chart provided in * the description, the more usable it will be for people using screen readers. * This prop defaults to an empty string. * - * @example "Golden retreivers make up 30%, Labs make up 25%, and other dog breeds are + * @example "Golden retrievers make up 30%, Labs make up 25%, and other dog breeds are * not represented above 5% each." */ desc?: string; @@ -75,7 +74,7 @@ export interface ChartContainerProps extends VictoryContainerProps { * * Note: This prop should not be set manually. * - * @private + * @private Not intended as public API and subject to change * @hide */ polar?: boolean; @@ -86,7 +85,7 @@ export interface ChartContainerProps extends VictoryContainerProps { * render in the portal container. This prop defaults to Portal, and should only be overridden when changing rendered * elements from SVG to another type of element e.g., react-native-svg elements. */ - portalComponent?: React.ReactElement; + portalComponent?: React.ReactElement; /** * The portalZIndex prop determines the z-index of the div enclosing the portal component. If a portalZIndex prop is * not set, the z-index of the enclosing div will be set to 99. diff --git a/packages/react-charts/src/victory/components/ChartContainer/__snapshots__/ChartContainer.test.tsx.snap b/packages/react-charts/src/victory/components/ChartContainer/__snapshots__/ChartContainer.test.tsx.snap new file mode 100644 index 00000000000..76924f7620a --- /dev/null +++ b/packages/react-charts/src/victory/components/ChartContainer/__snapshots__/ChartContainer.test.tsx.snap @@ -0,0 +1,154 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`ChartContainer 1`] = ` + +
+ +
+ +
+
+
+`; + +exports[`ChartContainer 2`] = ` + +
+ +
+ +
+
+
+`; + +exports[`renders container via ChartLegend 1`] = ` + +
+ + + + + + + + Average number of pets + + + + + Cats + + + + + Dogs + + + + +
+ +
+
+
+`; diff --git a/packages/react-charts/src/components/ChartCursorContainer/ChartCursorContainer.test.tsx b/packages/react-charts/src/victory/components/ChartCursorContainer/ChartCursorContainer.test.tsx similarity index 97% rename from packages/react-charts/src/components/ChartCursorContainer/ChartCursorContainer.test.tsx rename to packages/react-charts/src/victory/components/ChartCursorContainer/ChartCursorContainer.test.tsx index d85e03bda7d..09896c2eb72 100644 --- a/packages/react-charts/src/components/ChartCursorContainer/ChartCursorContainer.test.tsx +++ b/packages/react-charts/src/victory/components/ChartCursorContainer/ChartCursorContainer.test.tsx @@ -1,4 +1,3 @@ -import * as React from 'react'; import { render } from '@testing-library/react'; import { ChartArea } from '../ChartArea/ChartArea'; import { ChartGroup } from '../ChartGroup/ChartGroup'; diff --git a/packages/react-charts/src/components/ChartCursorContainer/ChartCursorContainer.tsx b/packages/react-charts/src/victory/components/ChartCursorContainer/ChartCursorContainer.tsx similarity index 94% rename from packages/react-charts/src/components/ChartCursorContainer/ChartCursorContainer.tsx rename to packages/react-charts/src/victory/components/ChartCursorContainer/ChartCursorContainer.tsx index 19ce90ca2a9..053e9ec7688 100644 --- a/packages/react-charts/src/components/ChartCursorContainer/ChartCursorContainer.tsx +++ b/packages/react-charts/src/victory/components/ChartCursorContainer/ChartCursorContainer.tsx @@ -1,7 +1,5 @@ -/* eslint-disable camelcase */ +import { cloneElement } from 'react'; import chart_global_label_Fill from '@patternfly/react-tokens/dist/esm/chart_global_label_Fill'; - -import * as React from 'react'; import hoistNonReactStatics from 'hoist-non-react-statics'; import { LineSegment, OriginType, ValueOrAccessor, VictoryLabelProps } from 'victory-core'; import { @@ -28,12 +26,12 @@ export interface ChartCursorContainerProps extends VictoryCursorContainerProps { * * Note: This prop should not be set manually. * - * @private + * @private Not intended as public API and subject to change * @hide */ - children?: React.ReactElement | React.ReactElement[]; + children?: React.ReactElement | React.ReactElement[]; /** - * The className prop specifies a className that will be applied to the outer-most div rendered by the container + * The className prop specifies a className that will be applied to the outermost div rendered by the container */ className?: string; /** @@ -66,7 +64,7 @@ export interface ChartCursorContainerProps extends VictoryCursorContainerProps { * new element created from the passed cursorLabelComponent will be supplied with the following props: x, y, active, * text. If cursorLabelComponent is omitted, a new ChartLabel will be created with the props described above. */ - cursorLabelComponent?: React.ReactElement; + cursorLabelComponent?: React.ReactElement; /** * The cursorLabelOffset prop determines the pixel offset of the cursor label from the cursor point. This prop should * be an Object with x and y properties, or a number to be used for both dimensions. @@ -89,7 +87,7 @@ export interface ChartCursorContainerProps extends VictoryCursorContainerProps { * the description, the more usable it will be for people using screen readers. * This prop defaults to an empty string. * - * @example "Golden retreivers make up 30%, Labs make up 25%, and other dog breeds are + * @example "Golden retrievers make up 30%, Labs make up 25%, and other dog breeds are * not represented above 5% each." */ desc?: string; @@ -139,7 +137,7 @@ export interface ChartCursorContainerProps extends VictoryCursorContainerProps { * * Note: This prop should not be set manually. * - * @private + * @private Not intended as public API and subject to change * @hide */ polar?: boolean; @@ -150,7 +148,7 @@ export interface ChartCursorContainerProps extends VictoryCursorContainerProps { * render in the portal container. This prop defaults to Portal, and should only be overridden when changing rendered * elements from SVG to another type of element e.g., react-native-svg elements. */ - portalComponent?: React.ReactElement; + portalComponent?: React.ReactElement; /** * The portalZIndex prop determines the z-index of the div enclosing the portal component. If a portalZIndex prop is * not set, the z-index of the enclosing div will be set to 99. @@ -212,14 +210,14 @@ export const ChartCursorContainer: React.FunctionComponent { const componentTheme = getComponentTheme(themeColor); const chartClassName = getClassName({ className }); - const chartCursorLabelComponent = React.cloneElement(cursorLabelComponent, { + const chartCursorLabelComponent = cloneElement(cursorLabelComponent, { theme, ...cursorLabelComponent.props, ...(componentTheme?.label && componentTheme.label) // override backgroundStyle }); // Clone so users can override cursor container props - const cursor = React.cloneElement(cursorComponent, { + const cursor = cloneElement(cursorComponent, { style: { strokeColor: chart_global_label_Fill.var }, @@ -239,7 +237,6 @@ export const ChartCursorContainer: React.FunctionComponent
@@ -27,18 +27,18 @@ exports[`ChartVoronoiContainer 2`] = `
@@ -55,7 +55,7 @@ exports[`renders container via ChartGroup 1`] = ` @@ -80,7 +80,7 @@ exports[`renders container via ChartGroup 1`] = ` d="M50,121.42857142857142L75,92.85714285714286L100,58.57142857142856L125,50L125,150L100,150L75,150L50,150Z" role="presentation" shape-rendering="auto" - style="fill: var(--pf-v6-chart-theme--blue--ColorScale--100, #0066cc); width: 6px; fill-opacity: 0.3; stroke-width: 2; stroke: var(--pf-v6-chart-theme--blue--ColorScale--100, #0066cc);" + style="fill: var(--pf-v6-chart-theme--blue--ColorScale--100, #0066cc); width: 6px; fill-opacity: var(--pf-v6-chart-area--Opacity, 30%); stroke-width: 2; stroke: var(--pf-v6-chart-theme--blue--ColorScale--100, #0066cc);" />
diff --git a/packages/react-charts/src/components/ChartCursorTooltip/ChartCursorFlyout.test.tsx b/packages/react-charts/src/victory/components/ChartCursorTooltip/ChartCursorFlyout.test.tsx similarity index 98% rename from packages/react-charts/src/components/ChartCursorTooltip/ChartCursorFlyout.test.tsx rename to packages/react-charts/src/victory/components/ChartCursorTooltip/ChartCursorFlyout.test.tsx index 0e182fab261..0891b5eb8a6 100644 --- a/packages/react-charts/src/components/ChartCursorTooltip/ChartCursorFlyout.test.tsx +++ b/packages/react-charts/src/victory/components/ChartCursorTooltip/ChartCursorFlyout.test.tsx @@ -1,4 +1,3 @@ -import * as React from 'react'; import { render } from '@testing-library/react'; import { ChartArea } from '../ChartArea/ChartArea'; import { ChartGroup } from '../ChartGroup/ChartGroup'; diff --git a/packages/react-charts/src/components/ChartCursorTooltip/ChartCursorFlyout.tsx b/packages/react-charts/src/victory/components/ChartCursorTooltip/ChartCursorFlyout.tsx similarity index 94% rename from packages/react-charts/src/components/ChartCursorTooltip/ChartCursorFlyout.tsx rename to packages/react-charts/src/victory/components/ChartCursorTooltip/ChartCursorFlyout.tsx index d088b02a83f..a4af55aa015 100644 --- a/packages/react-charts/src/components/ChartCursorTooltip/ChartCursorFlyout.tsx +++ b/packages/react-charts/src/victory/components/ChartCursorTooltip/ChartCursorFlyout.tsx @@ -1,4 +1,4 @@ -import * as React from 'react'; +import { cloneElement } from 'react'; import { Helpers, OrientationTypes, Path, VictoryCommonPrimitiveProps } from 'victory-core'; import isPlainObject from 'lodash/isPlainObject'; @@ -102,7 +102,7 @@ interface ChartCursorFlyoutProps extends VictoryCommonPrimitiveProps { dy?: number; height?: number; orientation?: OrientationTypes; - pathComponent?: React.ReactElement; + pathComponent?: React.ReactElement; pointerLength?: number; pointerWidth?: number; width?: number; @@ -111,9 +111,14 @@ interface ChartCursorFlyoutProps extends VictoryCommonPrimitiveProps { } const ChartCursorFlyout = (props: ChartCursorFlyoutProps) => { - props = evaluateProps(props); + props = evaluateProps({ + pathComponent: , + role: 'presentation', + shapeRendering: 'auto', + ...props + }); - return React.cloneElement(props.pathComponent, { + return cloneElement(props.pathComponent, { ...props.events, style: props.style, d: getFlyoutPath(props), @@ -125,10 +130,4 @@ const ChartCursorFlyout = (props: ChartCursorFlyoutProps) => { }); }; -ChartCursorFlyout.defaultProps = { - pathComponent: , - role: 'presentation', - shapeRendering: 'auto' -}; - export { ChartCursorFlyout }; diff --git a/packages/react-charts/src/components/ChartCursorTooltip/ChartCursorTooltip.test.tsx b/packages/react-charts/src/victory/components/ChartCursorTooltip/ChartCursorTooltip.test.tsx similarity index 97% rename from packages/react-charts/src/components/ChartCursorTooltip/ChartCursorTooltip.test.tsx rename to packages/react-charts/src/victory/components/ChartCursorTooltip/ChartCursorTooltip.test.tsx index 840690fa7cc..45c1fcfe6c9 100644 --- a/packages/react-charts/src/components/ChartCursorTooltip/ChartCursorTooltip.test.tsx +++ b/packages/react-charts/src/victory/components/ChartCursorTooltip/ChartCursorTooltip.test.tsx @@ -1,4 +1,3 @@ -import * as React from 'react'; import { render } from '@testing-library/react'; import { ChartArea } from '../ChartArea/ChartArea'; import { ChartGroup } from '../ChartGroup/ChartGroup'; diff --git a/packages/react-charts/src/components/ChartCursorTooltip/ChartCursorTooltip.tsx b/packages/react-charts/src/victory/components/ChartCursorTooltip/ChartCursorTooltip.tsx similarity index 98% rename from packages/react-charts/src/components/ChartCursorTooltip/ChartCursorTooltip.tsx rename to packages/react-charts/src/victory/components/ChartCursorTooltip/ChartCursorTooltip.tsx index 83e600ad0a5..67a283ed8e4 100644 --- a/packages/react-charts/src/components/ChartCursorTooltip/ChartCursorTooltip.tsx +++ b/packages/react-charts/src/victory/components/ChartCursorTooltip/ChartCursorTooltip.tsx @@ -1,4 +1,4 @@ -import * as React from 'react'; +import { cloneElement } from 'react'; import hoistNonReactStatics from 'hoist-non-react-statics'; import { Helpers, @@ -143,7 +143,7 @@ export interface ChartCursorTooltipProps extends ChartTooltipProps { * * Note: This prop should not be set manually. * - * @private + * @private Not intended as public API and subject to change * @hide */ height?: number; @@ -249,7 +249,7 @@ export interface ChartCursorTooltipProps extends ChartTooltipProps { * * Note: This prop should not be set manually. * - * @private + * @private Not intended as public API and subject to change * @hide */ width?: number; @@ -291,7 +291,7 @@ export const ChartCursorTooltip: React.FunctionComponent
diff --git a/packages/react-charts/src/components/ChartCursorTooltip/__snapshots__/ChartCursorTooltip.test.tsx.snap b/packages/react-charts/src/victory/components/ChartCursorTooltip/__snapshots__/ChartCursorTooltip.test.tsx.snap similarity index 72% rename from packages/react-charts/src/components/ChartCursorTooltip/__snapshots__/ChartCursorTooltip.test.tsx.snap rename to packages/react-charts/src/victory/components/ChartCursorTooltip/__snapshots__/ChartCursorTooltip.test.tsx.snap index 8fed25471f3..1440f81d9dd 100644 --- a/packages/react-charts/src/components/ChartCursorTooltip/__snapshots__/ChartCursorTooltip.test.tsx.snap +++ b/packages/react-charts/src/victory/components/ChartCursorTooltip/__snapshots__/ChartCursorTooltip.test.tsx.snap @@ -13,17 +13,17 @@ exports[`allows tooltip via container component 1`] = `
diff --git a/packages/react-charts/src/components/ChartDonut/ChartDonut.test.tsx b/packages/react-charts/src/victory/components/ChartDonut/ChartDonut.test.tsx similarity index 94% rename from packages/react-charts/src/components/ChartDonut/ChartDonut.test.tsx rename to packages/react-charts/src/victory/components/ChartDonut/ChartDonut.test.tsx index 03f4b6cbe4c..7b917f77cdc 100644 --- a/packages/react-charts/src/components/ChartDonut/ChartDonut.test.tsx +++ b/packages/react-charts/src/victory/components/ChartDonut/ChartDonut.test.tsx @@ -1,4 +1,3 @@ -import * as React from 'react'; import { render } from '@testing-library/react'; import { ChartDonut } from './ChartDonut'; diff --git a/packages/react-charts/src/components/ChartDonut/ChartDonut.tsx b/packages/react-charts/src/victory/components/ChartDonut/ChartDonut.tsx similarity index 98% rename from packages/react-charts/src/components/ChartDonut/ChartDonut.tsx rename to packages/react-charts/src/victory/components/ChartDonut/ChartDonut.tsx index 3fb5974533b..8a24a7cb11d 100644 --- a/packages/react-charts/src/components/ChartDonut/ChartDonut.tsx +++ b/packages/react-charts/src/victory/components/ChartDonut/ChartDonut.tsx @@ -1,4 +1,4 @@ -import * as React from 'react'; +import { cloneElement, Fragment } from 'react'; import hoistNonReactStatics from 'hoist-non-react-statics'; import { AnimatePropTypeInterface, @@ -172,7 +172,7 @@ export interface ChartDonutProps extends ChartPieProps { * events. The eventKey may optionally be used to select a single element by index rather than * an entire set. The eventHandlers object should be given as an object whose keys are standard * event names (i.e. onClick) and whose values are event callbacks. The return value - * of an event handler is used to modify elemnts. The return value should be given + * of an event handler is used to modify elements. The return value should be given * as an object or an array of objects with optional target and eventKey keys, * and a mutation key whose value is a function. The target and eventKey keys * will default to those corresponding to the element the event handler was attached to. @@ -402,7 +402,7 @@ export interface ChartDonutProps extends ChartPieProps { * * Note: This prop should not be set manually. * - * @private + * @private Not intended as public API and subject to change * @hide */ sharedEvents?: { events: any[]; getEventState: Function }; @@ -624,10 +624,10 @@ export const ChartDonut: React.FunctionComponent = ({ }); } return ( - + {getTitle({ titles: title, dy: centerSubTitle ? -8 : 0 })} {getSubTitle({ textComponent: subTitleComponent, dy: centerSubTitle ? 15 : 0 })} - + ); }; @@ -641,7 +641,7 @@ export const ChartDonut: React.FunctionComponent = ({ } const subTitleProps = textComponent.props ? textComponent.props : {}; - return React.cloneElement(textComponent, { + return cloneElement(textComponent, { ...(name && { id: `${name}-${(textComponent as any).type.displayName}-subTitle` }), key: 'pf-chart-donut-subtitle', style: ChartDonutStyles.label.subTitle, @@ -674,7 +674,7 @@ export const ChartDonut: React.FunctionComponent = ({ } const titleProps = titleComponent ? titleComponent.props : {}; - return React.cloneElement(titleComponent, { + return cloneElement(titleComponent, { ...(Array.isArray(titles) && { capHeight }), // Use capHeight with multiple labels ...(name && { id: `${name}-${(titleComponent as any).type.displayName}-title` }), key: 'pf-chart-donut-title', @@ -722,7 +722,7 @@ export const ChartDonut: React.FunctionComponent = ({ ); // Clone so users can override container props - const container = React.cloneElement( + const container = cloneElement( containerComponent, { desc: ariaDesc, @@ -736,12 +736,12 @@ export const ChartDonut: React.FunctionComponent = ({ ); return standalone ? ( - {container} + {container} ) : ( - + {chart} {getAllTitles()} - + ); }; ChartDonut.displayName = 'ChartDonut'; diff --git a/packages/react-charts/src/components/ChartDonut/__snapshots__/ChartDonut.test.tsx.snap b/packages/react-charts/src/victory/components/ChartDonut/__snapshots__/ChartDonut.test.tsx.snap similarity index 65% rename from packages/react-charts/src/components/ChartDonut/__snapshots__/ChartDonut.test.tsx.snap rename to packages/react-charts/src/victory/components/ChartDonut/__snapshots__/ChartDonut.test.tsx.snap index 857bef702ff..df3b1b65154 100644 --- a/packages/react-charts/src/components/ChartDonut/__snapshots__/ChartDonut.test.tsx.snap +++ b/packages/react-charts/src/victory/components/ChartDonut/__snapshots__/ChartDonut.test.tsx.snap @@ -4,12 +4,12 @@ exports[`ChartDonut 1`] = `
@@ -18,45 +18,45 @@ exports[`ChartDonut 1`] = ` d="M1.1182570896040502,-94.99341819874444A95,95,0,0,1,60.203957590455154,-73.48798194566699L54.41842631991018,-66.59305426892888A86,86,0,0,0,1.1182570896040516,-85.99272935011163Z" role="presentation" shape-rendering="auto" - style="fill: var(--pf-v6-chart-theme--blue--ColorScale--100, #0066cc); padding: 8px; stroke: var(--pf-v6-chart-pie--data--stroke--Color, transparent); stroke-width: 1;" + style="fill: var(--pf-v6-chart-theme--blue--ColorScale--100, #0066cc); padding: 8px; stroke: var(--pf-v6-chart-donut--pie--data--stroke--Color, rgb(255, 255, 255, 0.0000)); stroke-width: var(--pf-v6-chart-donut--pie--data--stroke--Width, 0px);" transform="translate(115, 115)" />
@@ -69,12 +69,12 @@ exports[`ChartDonut 2`] = `
@@ -83,45 +83,45 @@ exports[`ChartDonut 2`] = ` d="M1.1182570896040502,-94.99341819874444A95,95,0,0,1,60.203957590455154,-73.48798194566699L54.41842631991018,-66.59305426892888A86,86,0,0,0,1.1182570896040516,-85.99272935011163Z" role="presentation" shape-rendering="auto" - style="fill: var(--pf-v6-chart-theme--blue--ColorScale--100, #0066cc); padding: 8px; stroke: var(--pf-v6-chart-pie--data--stroke--Color, transparent); stroke-width: 1;" + style="fill: var(--pf-v6-chart-theme--blue--ColorScale--100, #0066cc); padding: 8px; stroke: var(--pf-v6-chart-donut--pie--data--stroke--Color, rgb(255, 255, 255, 0.0000)); stroke-width: var(--pf-v6-chart-donut--pie--data--stroke--Width, 0px);" transform="translate(115, 115)" />
@@ -134,12 +134,12 @@ exports[`renders component data 1`] = `
@@ -148,31 +148,31 @@ exports[`renders component data 1`] = ` d="M0.9334130156923648,-79.99455444055012A80,80,0,0,1,65.26560040477878,46.26447237139683L57.983888959835994,40.97399932998254A71,71,0,0,0,0.9334130156923663,-70.99386410206263Z" role="presentation" shape-rendering="auto" - style="fill: var(--pf-v6-chart-theme--blue--ColorScale--100, #0066cc); padding: 8px; stroke: var(--pf-v6-chart-pie--data--stroke--Color, transparent); stroke-width: 1;" + style="fill: var(--pf-v6-chart-theme--blue--ColorScale--100, #0066cc); padding: 8px; stroke: var(--pf-v6-chart-donut--pie--data--stroke--Color, rgb(255, 255, 255, 0.0000)); stroke-width: var(--pf-v6-chart-donut--pie--data--stroke--Width, 0px);" transform="translate(100, 100)" />
diff --git a/packages/react-charts/src/victory/components/ChartDonut/examples/ChartDonut.md b/packages/react-charts/src/victory/components/ChartDonut/examples/ChartDonut.md new file mode 100644 index 00000000000..93d9d732e36 --- /dev/null +++ b/packages/react-charts/src/victory/components/ChartDonut/examples/ChartDonut.md @@ -0,0 +1,69 @@ +--- +id: Donut chart +section: components +subsection: charts +propComponents: [ + 'ChartDonut' +] +hideDarkMode: true +--- + +import { ChartDonut, ChartThemeColor } from '@patternfly/react-charts/victory'; + +## Introduction +Note: PatternFly React charts live in its own package at [@patternfly/react-charts](https://www.npmjs.com/package/@patternfly/react-charts)! + +The examples below are based on the [Victory](https://formidable.com/open-source/victory/docs/victory-chart/) chart library, along with additional functionality, custom components, and theming for PatternFly. This provides a collection of React based components you can use to build PatternFly patterns with consistent markup, styling, and behavior. + +## Examples +### Basic +```ts file = "ChartDonutBasic.tsx" + +``` + +### Right aligned legend +```ts file = "ChartDonutRightAlignedLegend.tsx" + +``` + +### Multi-color (ordered) with right aligned legend +```ts file = "ChartDonutMultiColor.tsx" + +``` + +### Bottom aligned legend +```ts file = "ChartDonutBottomAlignedLegend.tsx" + +``` + +### Small +```ts file = "ChartDonutSmall.tsx" + +``` + +### Small with right aligned legend +```ts file = "ChartDonutSmallRightLegend.tsx" + +``` + +### Small with bottom aligned subtitle +```ts file = "ChartDonutSmallBottomSubtitle.tsx" + +``` + +### Small with right aligned subtitle +```ts file = "ChartDonutSmallRightSubtitle.tsx" + +``` + +## Documentation +### Tips +- See Victory's [FAQ](https://formidable.com/open-source/victory/docs/faq) +- For single data points or zero values, you may want to set the `domain` prop +- `ChartLegend` may be used as a standalone component, instead of using `legendData` + +### Note +Currently, the generated documentation below is not able to resolve type definitions from Victory imports. For the +components used in the examples above, Victory pass-thru props are also documented here: + +- For `ChartDonut` props, see [VictoryPie](https://formidable.com/open-source/victory/docs/victory-pie) diff --git a/packages/react-charts/src/victory/components/ChartDonut/examples/ChartDonutBasic.tsx b/packages/react-charts/src/victory/components/ChartDonut/examples/ChartDonutBasic.tsx new file mode 100644 index 00000000000..c0370f8a259 --- /dev/null +++ b/packages/react-charts/src/victory/components/ChartDonut/examples/ChartDonutBasic.tsx @@ -0,0 +1,29 @@ +import { ChartDonut } from '@patternfly/react-charts/victory'; + +interface PetData { + x: string; + y: number; +} + +export const ChartDonutBasic: React.FunctionComponent = () => { + const data: PetData[] = [ + { x: 'Cats', y: 35 }, + { x: 'Dogs', y: 55 }, + { x: 'Birds', y: 10 } + ]; + + return ( +
+ `${datum.x}: ${datum.y}%`} + name="chart1" + subTitle="Pets" + title="100" + /> +
+ ); +}; diff --git a/packages/react-charts/src/victory/components/ChartDonut/examples/ChartDonutBottomAlignedLegend.tsx b/packages/react-charts/src/victory/components/ChartDonut/examples/ChartDonutBottomAlignedLegend.tsx new file mode 100644 index 00000000000..33f5581d8ff --- /dev/null +++ b/packages/react-charts/src/victory/components/ChartDonut/examples/ChartDonutBottomAlignedLegend.tsx @@ -0,0 +1,43 @@ +import { ChartDonut } from '@patternfly/react-charts/victory'; + +interface PetData { + x?: string; + y?: number; + name?: string; +} + +export const ChartDonutBottomAlignedLegend: 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" + legendWidth={225} + name="chart4" + padding={{ + bottom: 65, // Adjusted to accommodate legend + left: 20, + right: 20, + top: 20 + }} + subTitle="Pets" + title="100" + width={300} + /> +
+ ); +}; diff --git a/packages/react-charts/src/victory/components/ChartDonut/examples/ChartDonutMultiColor.tsx b/packages/react-charts/src/victory/components/ChartDonut/examples/ChartDonutMultiColor.tsx new file mode 100644 index 00000000000..ef32201a641 --- /dev/null +++ b/packages/react-charts/src/victory/components/ChartDonut/examples/ChartDonutMultiColor.tsx @@ -0,0 +1,42 @@ +import { ChartDonut, ChartThemeColor } from '@patternfly/react-charts/victory'; + +interface PetData { + x?: string; + y?: number; + name?: string; +} + +export const ChartDonutMultiColor: 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="chart3" + 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/ChartDonut/examples/ChartDonutRightAlignedLegend.tsx b/packages/react-charts/src/victory/components/ChartDonut/examples/ChartDonutRightAlignedLegend.tsx new file mode 100644 index 00000000000..b1419a9d25b --- /dev/null +++ b/packages/react-charts/src/victory/components/ChartDonut/examples/ChartDonutRightAlignedLegend.tsx @@ -0,0 +1,41 @@ +import { ChartDonut } from '@patternfly/react-charts/victory'; + +interface PetData { + x?: string; + y?: number; + name?: string; +} + +export const ChartDonutRightAlignedLegend: 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" + width={350} + /> +
+ ); +}; diff --git a/packages/react-charts/src/victory/components/ChartDonut/examples/ChartDonutSmall.tsx b/packages/react-charts/src/victory/components/ChartDonut/examples/ChartDonutSmall.tsx new file mode 100644 index 00000000000..e238a12be99 --- /dev/null +++ b/packages/react-charts/src/victory/components/ChartDonut/examples/ChartDonutSmall.tsx @@ -0,0 +1,31 @@ +import { ChartDonut } from '@patternfly/react-charts/victory'; + +interface PetData { + x: string; + y: number; +} + +export const ChartDonutSmall: React.FunctionComponent = () => { + const data: PetData[] = [ + { x: 'Cats', y: 35 }, + { x: 'Dogs', y: 55 }, + { x: 'Birds', y: 10 } + ]; + + return ( +
+ `${datum.x}: ${datum.y}%`} + name="chart5" + subTitle="Pets" + title="100" + width={150} + /> +
+ ); +}; diff --git a/packages/react-charts/src/victory/components/ChartDonut/examples/ChartDonutSmallBottomSubtitle.tsx b/packages/react-charts/src/victory/components/ChartDonut/examples/ChartDonutSmallBottomSubtitle.tsx new file mode 100644 index 00000000000..8233d9a10cd --- /dev/null +++ b/packages/react-charts/src/victory/components/ChartDonut/examples/ChartDonutSmallBottomSubtitle.tsx @@ -0,0 +1,43 @@ +import { ChartDonut } from '@patternfly/react-charts/victory'; + +interface PetData { + x?: string; + y?: number; + name?: string; +} + +export const ChartDonutSmallBottomSubtitle: 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="chart7" + padding={{ + bottom: 25, // Adjusted to accommodate subTitle + left: 20, + right: 145, // Adjusted to accommodate legend + top: 20 + }} + subTitle="Pets" + subTitlePosition="bottom" + title="100" + width={275} + /> +
+ ); +}; diff --git a/packages/react-charts/src/victory/components/ChartDonut/examples/ChartDonutSmallRightLegend.tsx b/packages/react-charts/src/victory/components/ChartDonut/examples/ChartDonutSmallRightLegend.tsx new file mode 100644 index 00000000000..b768192bb4a --- /dev/null +++ b/packages/react-charts/src/victory/components/ChartDonut/examples/ChartDonutSmallRightLegend.tsx @@ -0,0 +1,42 @@ +import { ChartDonut } from '@patternfly/react-charts/victory'; + +interface PetData { + x?: string; + y?: number; + name?: string; +} + +export const ChartDonutSmallRightLegend: 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="chart6" + padding={{ + bottom: 20, + left: 20, + right: 145, // Adjusted to accommodate legend + top: 20 + }} + subTitle="Pets" + title="100" + width={275} + /> +
+ ); +}; diff --git a/packages/react-charts/src/victory/components/ChartDonut/examples/ChartDonutSmallRightSubtitle.tsx b/packages/react-charts/src/victory/components/ChartDonut/examples/ChartDonutSmallRightSubtitle.tsx new file mode 100644 index 00000000000..6d52feedf1f --- /dev/null +++ b/packages/react-charts/src/victory/components/ChartDonut/examples/ChartDonutSmallRightSubtitle.tsx @@ -0,0 +1,42 @@ +import { ChartDonut } from '@patternfly/react-charts/victory'; + +interface PetData { + x?: string; + y?: number; + name?: string; +} + +export const ChartDonutSmallRightSubtitle: 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="chart8" + padding={{ + bottom: 70, // Adjusted to accommodate legend + left: 20, + right: 50, // Adjusted to accommodate subTitle + top: 20 + }} + subTitle="Pets" + subTitlePosition="right" + title="100" + width={300} + /> +
+ ); +}; diff --git a/packages/react-charts/src/components/ChartDonutUtilization/ChartDonutThreshold.test.tsx b/packages/react-charts/src/victory/components/ChartDonutUtilization/ChartDonutThreshold.test.tsx similarity index 95% rename from packages/react-charts/src/components/ChartDonutUtilization/ChartDonutThreshold.test.tsx rename to packages/react-charts/src/victory/components/ChartDonutUtilization/ChartDonutThreshold.test.tsx index 913f69b374e..44642d5fd7f 100644 --- a/packages/react-charts/src/components/ChartDonutUtilization/ChartDonutThreshold.test.tsx +++ b/packages/react-charts/src/victory/components/ChartDonutUtilization/ChartDonutThreshold.test.tsx @@ -1,4 +1,3 @@ -import * as React from 'react'; import { render } from '@testing-library/react'; import { ChartDonutThreshold } from './ChartDonutThreshold'; diff --git a/packages/react-charts/src/components/ChartDonutUtilization/ChartDonutThreshold.tsx b/packages/react-charts/src/victory/components/ChartDonutUtilization/ChartDonutThreshold.tsx similarity index 97% rename from packages/react-charts/src/components/ChartDonutUtilization/ChartDonutThreshold.tsx rename to packages/react-charts/src/victory/components/ChartDonutUtilization/ChartDonutThreshold.tsx index 0f890ca31c6..87be22d4bb6 100644 --- a/packages/react-charts/src/components/ChartDonutUtilization/ChartDonutThreshold.tsx +++ b/packages/react-charts/src/victory/components/ChartDonutUtilization/ChartDonutThreshold.tsx @@ -1,4 +1,4 @@ -import * as React from 'react'; +import { Children, cloneElement, Fragment, isValidElement } from 'react'; import { AnimatePropTypeInterface, CategoryPropType, @@ -76,7 +76,7 @@ export interface ChartDonutThresholdProps extends ChartDonutProps { * * Note: This prop should not be set manually. * - * @private + * @private Not intended as public API and subject to change * @hide */ children?: React.ReactElement; @@ -147,7 +147,7 @@ export interface ChartDonutThresholdProps extends ChartDonutProps { * * Note: Overridden by containerComponent * - * @example "Golden retreivers make up 30%, Labs make up 25%, and other dog breeds are + * @example "Golden retrievers make up 30%, Labs make up 25%, and other dog breeds are * not represented above 5% each." */ desc?: string; @@ -170,7 +170,7 @@ export interface ChartDonutThresholdProps extends ChartDonutProps { * events. The eventKey may optionally be used to select a single element by index rather than * an entire set. The eventHandlers object should be given as an object whose keys are standard * event names (i.e. onClick) and whose values are event callbacks. The return value - * of an event handler is used to modify elemnts. The return value should be given + * of an event handler is used to modify elements. The return value should be given * as an object or an array of objects with optional target and eventKey keys, * and a mutation key whose value is a function. The target and eventKey keys * will default to those corresponding to the element the event handler was attached to. @@ -320,7 +320,7 @@ export interface ChartDonutThresholdProps extends ChartDonutProps { * * Note: This prop should not be set manually. * - * @private + * @private Not intended as public API and subject to change * @hide */ sharedEvents?: { events: any[]; getEventState: Function }; @@ -383,7 +383,7 @@ export interface ChartDonutThresholdProps extends ChartDonutProps { * * @example themeColor={ChartThemeColor.blue} * - * @private + * @private Not intended as public API and subject to change * @hide */ themeColor?: string; @@ -500,12 +500,12 @@ export const ChartDonutThreshold: React.FunctionComponent - React.Children.toArray(children).map((child, index) => { - if (React.isValidElement(child)) { - const { data: childData, ...childProps } = child.props; + Children.toArray(children).map((child, index) => { + if (isValidElement(child)) { + const { data: childData, ...childProps } = child.props as any; const datum = Data.formatData([childData], childProps, ['x', 'y']); // Format child data independently of this component's props const dynamicTheme = childProps.theme || getDonutThresholdDynamicTheme(childProps.themeColor || themeColor); - return React.cloneElement(child, { + return cloneElement(child, { ...(hasPatterns && { hasPatterns: true }), // Enable ChartDonutUtilization patterns constrainToVisibleArea, data: childData, @@ -554,7 +554,7 @@ export const ChartDonutThreshold: React.FunctionComponent{container} + {container} ) : ( - + {chart} {renderChildren()} - + ); }; ChartDonutThreshold.displayName = 'ChartDonutThreshold'; diff --git a/packages/react-charts/src/components/ChartDonutUtilization/ChartDonutUtilization.test.tsx b/packages/react-charts/src/victory/components/ChartDonutUtilization/ChartDonutUtilization.test.tsx similarity index 94% rename from packages/react-charts/src/components/ChartDonutUtilization/ChartDonutUtilization.test.tsx rename to packages/react-charts/src/victory/components/ChartDonutUtilization/ChartDonutUtilization.test.tsx index 82e564ed53c..5cb9efefbfe 100644 --- a/packages/react-charts/src/components/ChartDonutUtilization/ChartDonutUtilization.test.tsx +++ b/packages/react-charts/src/victory/components/ChartDonutUtilization/ChartDonutUtilization.test.tsx @@ -1,4 +1,3 @@ -import * as React from 'react'; import { render } from '@testing-library/react'; import { ChartDonutUtilization } from './ChartDonutUtilization'; diff --git a/packages/react-charts/src/components/ChartDonutUtilization/ChartDonutUtilization.tsx b/packages/react-charts/src/victory/components/ChartDonutUtilization/ChartDonutUtilization.tsx similarity index 98% rename from packages/react-charts/src/components/ChartDonutUtilization/ChartDonutUtilization.tsx rename to packages/react-charts/src/victory/components/ChartDonutUtilization/ChartDonutUtilization.tsx index 66ffc28dccb..64f7c39c535 100644 --- a/packages/react-charts/src/components/ChartDonutUtilization/ChartDonutUtilization.tsx +++ b/packages/react-charts/src/victory/components/ChartDonutUtilization/ChartDonutUtilization.tsx @@ -1,4 +1,4 @@ -import * as React from 'react'; +import { cloneElement, Fragment } from 'react'; import hoistNonReactStatics from 'hoist-non-react-statics'; import orderBy from 'lodash/orderBy'; import { @@ -146,7 +146,7 @@ export interface ChartDonutUtilizationProps extends ChartDonutProps { * * Note: Overridden by containerComponent * - * @example "Golden retreivers make up 30%, Labs make up 25%, and other dog breeds are + * @example "Golden retrievers make up 30%, Labs make up 25%, and other dog breeds are * not represented above 5% each." */ desc?: string; @@ -169,7 +169,7 @@ export interface ChartDonutUtilizationProps extends ChartDonutProps { * events. The eventKey may optionally be used to select a single element by index rather than * an entire set. The eventHandlers object should be given as an object whose keys are standard * event names (i.e. onClick) and whose values are event callbacks. The return value - * of an event handler is used to modify elemnts. The return value should be given + * of an event handler is used to modify elements. The return value should be given * as an object or an array of objects with optional target and eventKey keys, * and a mutation key whose value is a function. The target and eventKey keys * will default to those corresponding to the element the event handler was attached to. @@ -260,7 +260,7 @@ export interface ChartDonutUtilizationProps extends ChartDonutProps { * * Note: This prop should not be set manually. * - * @private + * @private Not intended as public API and subject to change * @hide */ isStatic?: boolean; @@ -403,7 +403,7 @@ export interface ChartDonutUtilizationProps extends ChartDonutProps { * * Note: This prop should not be set manually. * - * @private + * @private Not intended as public API and subject to change * @hide */ patternUnshiftIndex?: number; @@ -419,7 +419,7 @@ export interface ChartDonutUtilizationProps extends ChartDonutProps { * * Note: This prop should not be set manually. * - * @private + * @private Not intended as public API and subject to change * @hide */ sharedEvents?: { events: any[]; getEventState: Function }; @@ -695,7 +695,7 @@ export const ChartDonutUtilization: React.FunctionComponent{container} : {chart}; + return standalone ? {container} : {chart}; }; ChartDonutUtilization.displayName = 'ChartDonutUtilization'; diff --git a/packages/react-charts/src/components/ChartDonutUtilization/__snapshots__/ChartDonutThreshold.test.tsx.snap b/packages/react-charts/src/victory/components/ChartDonutUtilization/__snapshots__/ChartDonutThreshold.test.tsx.snap similarity index 62% rename from packages/react-charts/src/components/ChartDonutUtilization/__snapshots__/ChartDonutThreshold.test.tsx.snap rename to packages/react-charts/src/victory/components/ChartDonutUtilization/__snapshots__/ChartDonutThreshold.test.tsx.snap index d99d7b39ada..3aba38aaa53 100644 --- a/packages/react-charts/src/components/ChartDonutUtilization/__snapshots__/ChartDonutThreshold.test.tsx.snap +++ b/packages/react-charts/src/victory/components/ChartDonutUtilization/__snapshots__/ChartDonutThreshold.test.tsx.snap @@ -4,12 +4,12 @@ exports[`ChartDonutThreshold 1`] = `
@@ -18,17 +18,17 @@ exports[`ChartDonutThreshold 1`] = ` d="M5.8170722959499274e-15,-95L5.2659812363336185e-15,-86Z" role="presentation" shape-rendering="auto" - style="fill: var(--pf-v6-chart-donut--threshold--first--Color, #e0e0e0); padding: 8px; stroke: var(--pf-v6-chart-pie--data--stroke--Color, transparent); stroke-width: 1;" + style="fill: var(--pf-v6-chart-donut--threshold--first--Color, #e0e0e0); padding: 8px; stroke: var(--pf-v6-chart-donut--pie--data--stroke--Color, rgb(255, 255, 255, 0.0000)); stroke-width: var(--pf-v6-chart-donut--pie--data--stroke--Width, 0px);" transform="translate(115, 115)" />
@@ -41,12 +41,12 @@ exports[`ChartDonutThreshold 2`] = `
@@ -55,17 +55,17 @@ exports[`ChartDonutThreshold 2`] = ` d="M5.8170722959499274e-15,-95L5.2659812363336185e-15,-86Z" role="presentation" shape-rendering="auto" - style="fill: var(--pf-v6-chart-donut--threshold--first--Color, #e0e0e0); padding: 8px; stroke: var(--pf-v6-chart-pie--data--stroke--Color, transparent); stroke-width: 1;" + style="fill: var(--pf-v6-chart-donut--threshold--first--Color, #e0e0e0); padding: 8px; stroke: var(--pf-v6-chart-donut--pie--data--stroke--Color, rgb(255, 255, 255, 0.0000)); stroke-width: var(--pf-v6-chart-donut--pie--data--stroke--Width, 0px);" transform="translate(115, 115)" />
@@ -78,12 +78,12 @@ exports[`renders component data 1`] = `
@@ -92,38 +92,38 @@ exports[`renders component data 1`] = ` d="M0.9334130156923648,-79.99455444055012A80,80,0,0,1,46.26447237139683,-65.26560040477877L40.97399932998254,-57.983888959835994A71,71,0,0,0,0.9334130156923663,-70.99386410206263Z" role="presentation" shape-rendering="auto" - style="fill: var(--pf-v6-chart-donut--threshold--first--Color, #e0e0e0); padding: 8px; stroke: var(--pf-v6-chart-pie--data--stroke--Color, transparent); stroke-width: 1;" + style="fill: var(--pf-v6-chart-donut--threshold--first--Color, #e0e0e0); padding: 8px; stroke: var(--pf-v6-chart-donut--pie--data--stroke--Color, rgb(255, 255, 255, 0.0000)); stroke-width: var(--pf-v6-chart-donut--pie--data--stroke--Width, 0px);" transform="translate(100, 100)" />
diff --git a/packages/react-charts/src/components/ChartDonutUtilization/__snapshots__/ChartDonutUtilization.test.tsx.snap b/packages/react-charts/src/victory/components/ChartDonutUtilization/__snapshots__/ChartDonutUtilization.test.tsx.snap similarity index 62% rename from packages/react-charts/src/components/ChartDonutUtilization/__snapshots__/ChartDonutUtilization.test.tsx.snap rename to packages/react-charts/src/victory/components/ChartDonutUtilization/__snapshots__/ChartDonutUtilization.test.tsx.snap index b85a92b753c..2752138d859 100644 --- a/packages/react-charts/src/components/ChartDonutUtilization/__snapshots__/ChartDonutUtilization.test.tsx.snap +++ b/packages/react-charts/src/victory/components/ChartDonutUtilization/__snapshots__/ChartDonutUtilization.test.tsx.snap @@ -4,12 +4,12 @@ exports[`ChartDonutUtilization 1`] = `
@@ -18,24 +18,24 @@ exports[`ChartDonutUtilization 1`] = ` d="M5.8170722959499274e-15,-95L5.2659812363336185e-15,-86Z" role="presentation" shape-rendering="auto" - style="fill: var(--pf-v6-chart-theme--blue--ColorScale--100, #0066cc); padding: 8px; stroke: var(--pf-v6-chart-pie--data--stroke--Color, transparent); stroke-width: 1;" + style="fill: var(--pf-v6-chart-theme--blue--ColorScale--100, #0066cc); padding: 8px; stroke: var(--pf-v6-chart-donut--pie--data--stroke--Color, rgb(255, 255, 255, 0.0000)); stroke-width: var(--pf-v6-chart-donut--pie--data--stroke--Width, 0px);" transform="translate(115, 115)" />
@@ -48,12 +48,12 @@ exports[`ChartDonutUtilization 2`] = `
@@ -62,24 +62,24 @@ exports[`ChartDonutUtilization 2`] = ` d="M5.8170722959499274e-15,-95L5.2659812363336185e-15,-86Z" role="presentation" shape-rendering="auto" - style="fill: var(--pf-v6-chart-theme--blue--ColorScale--100, #0066cc); padding: 8px; stroke: var(--pf-v6-chart-pie--data--stroke--Color, transparent); stroke-width: 1;" + style="fill: var(--pf-v6-chart-theme--blue--ColorScale--100, #0066cc); padding: 8px; stroke: var(--pf-v6-chart-donut--pie--data--stroke--Color, rgb(255, 255, 255, 0.0000)); stroke-width: var(--pf-v6-chart-donut--pie--data--stroke--Width, 0px);" transform="translate(115, 115)" />
@@ -92,12 +92,12 @@ exports[`renders component data 1`] = `
@@ -106,24 +106,24 @@ exports[`renders component data 1`] = ` d="M0.9334130156923648,-79.99455444055012A80,80,0,0,1,65.26560040477878,46.26447237139683L57.983888959835994,40.97399932998254A71,71,0,0,0,0.9334130156923663,-70.99386410206263Z" role="presentation" shape-rendering="auto" - style="fill: var(--pf-v6-chart-theme--blue--ColorScale--100, #0066cc); padding: 8px; stroke: var(--pf-v6-chart-pie--data--stroke--Color, transparent); stroke-width: 1;" + style="fill: var(--pf-v6-chart-theme--blue--ColorScale--100, #0066cc); padding: 8px; stroke: var(--pf-v6-chart-donut--pie--data--stroke--Color, rgb(255, 255, 255, 0.0000)); stroke-width: var(--pf-v6-chart-donut--pie--data--stroke--Width, 0px);" transform="translate(100, 100)" />
diff --git a/packages/react-charts/src/victory/components/ChartDonutUtilization/examples/ChartDonutUtilization.md b/packages/react-charts/src/victory/components/ChartDonutUtilization/examples/ChartDonutUtilization.md new file mode 100644 index 00000000000..be17f8b9589 --- /dev/null +++ b/packages/react-charts/src/victory/components/ChartDonutUtilization/examples/ChartDonutUtilization.md @@ -0,0 +1,129 @@ +--- +id: Donut utilization chart +section: components +subsection: charts +propComponents: [ + 'ChartDonutThreshold', + 'ChartDonutUtilization' +] +hideDarkMode: true +--- + +import { ChartDonutThreshold, ChartDonutUtilization, ChartThemeColor } from '@patternfly/react-charts/victory'; +import { useEffect, 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)! + +The examples below are based on the [Victory](https://formidable.com/open-source/victory/docs/victory-chart/) chart library, along with additional functionality, custom components, and theming for PatternFly. This provides a collection of React based components you can use to build PatternFly patterns with consistent markup, styling, and behavior. + +## Donut utilization examples +### Basic +```ts file = "ChartUtilBasic.tsx" + +``` + +### Right aligned legend +```ts file = "ChartUtilRightAlignedLegend.tsx" + +``` + +### Inverted with right aligned legend +```ts file = "ChartUtilInvertedRightLegend.tsx" + +``` + +### Right aligned vertical legend +```ts file = "ChartUtilRightVerticalLegend.tsx" + +``` + +### Bottom aligned legend +```ts file = "ChartUtilBottomAlignedLegend.tsx" + +``` + +### Small +```ts file = "ChartUtilSmall.tsx" + +``` + +### Small with right aligned legend +```ts file = "ChartUtilSmallRightLegend.tsx" + +``` + +### Small with bottom aligned subtitle + +This is a small donut utilization chart with bottom aligned legend and right aligned subtitle. + +```ts file = "ChartUtilSmallBottomSubtitle.tsx" + +``` + +### Small with right aligned subtitle +```ts file = "ChartUtilSmallRightSubtitle.tsx" + +``` + +## Donut utilization threshold examples +### Static thresholds +```ts file = "ChartUtilStatic.tsx" + +``` + +### Static thresholds with right aligned legend +```ts file = "ChartUtilStaticRightLegend.tsx" + +``` + +### Inverted static thresholds with right aligned legend +```ts file = "ChartUtilInvertedStatic.tsx" + +``` + +### Static thresholds with custom legend +```ts file = "ChartUtilStaticCustomLegend.tsx" + +``` + +### Static thresholds with bottom aligned legend +```ts file = "ChartUtilStaticBottomLegend.tsx" + +``` + +### Small with static thresholds +```ts file = "ChartUtilSmallStatic.tsx" + +``` + +### Small with static thresholds and right aligned legend +```ts file = "ChartUtilSmallStaticRightLegend.tsx" + +``` + +### Small with subtitle + +This is a small donut utilization chart with static thresholds with right aligned legend and bottom aligned subtitle. + +```ts file = "ChartUtilSmallSubtitle.tsx" + +``` + +### Small with thresholds and right aligned subtitle +```ts file = "ChartUtilSmallRightAlignedSubtitle.tsx" + +``` + +## Documentation +### Tips +- See Victory's [FAQ](https://formidable.com/open-source/victory/docs/faq) +- For single data points or zero values, you may want to set the `domain` prop +- `ChartLegend` may be used as a standalone component, instead of using `legendData` + +### Note +Currently, the generated documentation below is not able to resolve type definitions from Victory imports. For the +components used in the examples above, Victory pass-thru props are also documented here: + +- For `ChartDonutThreshold` props, see [VictoryPie](https://formidable.com/open-source/victory/docs/victory-pie) +- For `ChartDonutUtilization` props, see [VictoryPie](https://formidable.com/open-source/victory/docs/victory-pie) diff --git a/packages/react-charts/src/victory/components/ChartDonutUtilization/examples/ChartUtilBasic.tsx b/packages/react-charts/src/victory/components/ChartDonutUtilization/examples/ChartUtilBasic.tsx new file mode 100644 index 00000000000..56391d8cbd5 --- /dev/null +++ b/packages/react-charts/src/victory/components/ChartDonutUtilization/examples/ChartUtilBasic.tsx @@ -0,0 +1,25 @@ +import { ChartDonutUtilization } from '@patternfly/react-charts/victory'; + +interface UsageData { + x: string; + y: number; +} + +export const ChartUtilBasic: React.FunctionComponent = () => { + const data: UsageData = { x: 'GBps capacity', y: 75 }; + + return ( +
+ (datum.x ? `${datum.x}: ${datum.y}%` : null)} + name="chart1" + subTitle="of 100 GBps" + title="75%" + /> +
+ ); +}; diff --git a/packages/react-charts/src/victory/components/ChartDonutUtilization/examples/ChartUtilBottomAlignedLegend.tsx b/packages/react-charts/src/victory/components/ChartDonutUtilization/examples/ChartUtilBottomAlignedLegend.tsx new file mode 100644 index 00000000000..0461a403c9b --- /dev/null +++ b/packages/react-charts/src/victory/components/ChartDonutUtilization/examples/ChartUtilBottomAlignedLegend.tsx @@ -0,0 +1,38 @@ +import { ChartDonutUtilization } from '@patternfly/react-charts/victory'; + +interface UsageData { + x?: string; + y?: number; + name?: string; +} + +export const ChartUtilBottomAlignedLegend: React.FunctionComponent = () => { + const data: UsageData = { x: 'Storage capacity', y: 45 }; + const legendData: UsageData[] = [{ 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%" + thresholds={[{ value: 60 }, { value: 90 }]} + width={300} + /> +
+ ); +}; diff --git a/packages/react-charts/src/victory/components/ChartDonutUtilization/examples/ChartUtilInvertedRightLegend.tsx b/packages/react-charts/src/victory/components/ChartDonutUtilization/examples/ChartUtilInvertedRightLegend.tsx new file mode 100644 index 00000000000..193a931da4a --- /dev/null +++ b/packages/react-charts/src/victory/components/ChartDonutUtilization/examples/ChartUtilInvertedRightLegend.tsx @@ -0,0 +1,54 @@ +import { ChartDonutUtilization } from '@patternfly/react-charts/victory'; +import { useEffect, useState } from 'react'; + +interface UsageData { + x?: string; + y?: number; + name?: string; +} + +export const ChartUtilInvertedRightLegend: React.FunctionComponent = () => { + const [spacer, setSpacer] = useState(''); + const [used, setUsed] = useState(0); + + useEffect(() => { + const interval = setInterval(() => { + setUsed((prevUsed) => { + const val = (((prevUsed - 10) % 100) + 100) % 100; + setSpacer(val < 10 ? ' ' : ''); + return val; + }); + }, 1000); + + return () => clearInterval(interval); + }, []); + + const data: UsageData = { x: 'GBps capacity', y: used }; + const legendData: UsageData[] = [{ name: `Storage capacity: ${spacer}${used}%` }, { name: 'Unused' }]; + + return ( +
+ (datum.x ? `${datum.x}: ${datum.y}%` : null)} + legendData={legendData} + legendOrientation="vertical" + name="chart3" + padding={{ + bottom: 20, + left: 20, + right: 225, // Adjusted to accommodate legend + top: 20 + }} + subTitle="of 100 GBps" + title={`${used}%`} + thresholds={[{ value: 60 }, { value: 20 }]} + width={435} + /> +
+ ); +}; diff --git a/packages/react-charts/src/victory/components/ChartDonutUtilization/examples/ChartUtilInvertedStatic.tsx b/packages/react-charts/src/victory/components/ChartDonutUtilization/examples/ChartUtilInvertedStatic.tsx new file mode 100644 index 00000000000..a72f7ef05e3 --- /dev/null +++ b/packages/react-charts/src/victory/components/ChartDonutUtilization/examples/ChartUtilInvertedStatic.tsx @@ -0,0 +1,65 @@ +import { ChartDonutThreshold, ChartDonutUtilization } from '@patternfly/react-charts/victory'; +import { useEffect, useState } from 'react'; + +interface UsageData { + x?: string; + y?: number; + name?: string; +} + +export const ChartUtilInvertedStatic: React.FunctionComponent = () => { + const [used, setUsed] = useState(100); + + useEffect(() => { + const interval = setInterval(() => { + setUsed((prevUsed) => { + const val = (prevUsed - 10 + 100) % 100; + return val; + }); + }, 1000); + + return () => clearInterval(interval); + }, []); + + const dataThreshold: UsageData[] = [ + { x: 'Warning at 60%', y: 60 }, + { x: 'Danger at 20%', y: 20 } + ]; + const dataUtil: UsageData = { x: 'Storage capacity', y: used }; + const legendData: UsageData[] = [ + { name: `Storage capacity: ${used}%` }, + { name: 'Warning threshold at 60%' }, + { name: 'Danger threshold at 20%' } + ]; + + return ( +
+ (datum.x ? datum.x : null)} + name="chart12" + padding={{ + bottom: 20, + left: 20, + right: 290, // Adjusted to accommodate legend + top: 20 + }} + width={500} + > + (datum.x ? `${datum.x}: ${datum.y}%` : null)} + legendData={legendData} + legendOrientation="vertical" + subTitle="of 100 GBps" + title={`${used}%`} + thresholds={[{ value: 60 }, { value: 20 }]} + /> + +
+ ); +}; diff --git a/packages/react-charts/src/victory/components/ChartDonutUtilization/examples/ChartUtilRightAlignedLegend.tsx b/packages/react-charts/src/victory/components/ChartDonutUtilization/examples/ChartUtilRightAlignedLegend.tsx new file mode 100644 index 00000000000..e21b6597f81 --- /dev/null +++ b/packages/react-charts/src/victory/components/ChartDonutUtilization/examples/ChartUtilRightAlignedLegend.tsx @@ -0,0 +1,53 @@ +import { ChartDonutUtilization } from '@patternfly/react-charts/victory'; +import { useEffect, useState } from 'react'; + +interface UsageData { + x?: string; + y?: number; + name?: string; +} + +export const ChartUtilRightAlignedLegend: React.FunctionComponent = () => { + const [spacer, setSpacer] = useState(''); + const [used, setUsed] = useState(0); + + useEffect(() => { + const interval = setInterval(() => { + setUsed((prevUsed) => { + const val = (prevUsed + 10) % 100; + setSpacer(val < 10 ? ' ' : ''); + return val; + }); + }, 1000); + + return () => clearInterval(interval); + }, []); + + const data: UsageData = { x: 'GBps capacity', y: used }; + const legendData: UsageData[] = [{ name: `Storage capacity: ${spacer}${used}%` }, { name: 'Unused' }]; + + return ( +
+ (datum.x ? `${datum.x}: ${datum.y}%` : null)} + legendData={legendData} + legendOrientation="vertical" + name="chart2" + padding={{ + bottom: 20, + left: 20, + right: 225, // Adjusted to accommodate legend + top: 20 + }} + subTitle="of 100 GBps" + title={`${used}%`} + thresholds={[{ value: 60 }, { value: 90 }]} + width={435} + /> +
+ ); +}; diff --git a/packages/react-charts/src/victory/components/ChartDonutUtilization/examples/ChartUtilRightVerticalLegend.tsx b/packages/react-charts/src/victory/components/ChartDonutUtilization/examples/ChartUtilRightVerticalLegend.tsx new file mode 100644 index 00000000000..76626ce71b9 --- /dev/null +++ b/packages/react-charts/src/victory/components/ChartDonutUtilization/examples/ChartUtilRightVerticalLegend.tsx @@ -0,0 +1,56 @@ +import { ChartDonutUtilization, ChartThemeColor } from '@patternfly/react-charts/victory'; +import { useEffect, useState } from 'react'; + +interface UsageData { + x?: string; + y?: number; + name?: string; +} + +export const ChartUtilRightVerticalLegend: React.FunctionComponent = () => { + const [spacer, setSpacer] = useState(''); + const [used, setUsed] = useState(0); + + useEffect(() => { + const interval = setInterval(() => { + setUsed((prevUsed) => { + const val = (prevUsed + 10) % 100; + setSpacer(val < 10 ? ' ' : ''); + return val; + }); + }, 1000); + + return () => clearInterval(interval); + }, []); + + const data: UsageData = { x: 'Storage capacity', y: used }; + const legendData: UsageData[] = [{ name: `Storage capacity: ${spacer}${used}%` }, { name: 'Unused' }]; + + return ( +
+ (datum.x ? `${datum.x}: ${datum.y}%` : null)} + legendData={legendData} + legendOrientation="vertical" + legendPosition="bottom" + name="chart4" + padding={{ + bottom: 75, // Adjusted to accommodate legend + left: 20, + right: 20, + top: 20 + }} + subTitle="of 100 GBps" + title={`${used}%`} + themeColor={ChartThemeColor.green} + thresholds={[{ value: 60 }, { value: 90 }]} + width={230} + /> +
+ ); +}; diff --git a/packages/react-charts/src/victory/components/ChartDonutUtilization/examples/ChartUtilSmall.tsx b/packages/react-charts/src/victory/components/ChartDonutUtilization/examples/ChartUtilSmall.tsx new file mode 100644 index 00000000000..f9a50c298ff --- /dev/null +++ b/packages/react-charts/src/victory/components/ChartDonutUtilization/examples/ChartUtilSmall.tsx @@ -0,0 +1,26 @@ +import { ChartDonutUtilization } from '@patternfly/react-charts/victory'; + +interface UsageData { + x: string; + y: number; +} + +export const ChartUtilSmall: React.FunctionComponent = () => { + const data: UsageData = { x: 'Storage capacity', y: 75 }; + return ( +
+ (datum.x ? `${datum.x}: ${datum.y}%` : null)} + name="chart6" + subTitle="of 100 GBps" + title="75%" + width={175} + /> +
+ ); +}; diff --git a/packages/react-charts/src/victory/components/ChartDonutUtilization/examples/ChartUtilSmallBottomSubtitle.tsx b/packages/react-charts/src/victory/components/ChartDonutUtilization/examples/ChartUtilSmallBottomSubtitle.tsx new file mode 100644 index 00000000000..ebd0008949a --- /dev/null +++ b/packages/react-charts/src/victory/components/ChartDonutUtilization/examples/ChartUtilSmallBottomSubtitle.tsx @@ -0,0 +1,39 @@ +import { ChartDonutUtilization } from '@patternfly/react-charts/victory'; + +interface UsageData { + x?: string; + y?: number; + name?: string; +} + +export const ChartUtilSmallBottomSubtitle: React.FunctionComponent = () => { + const data: UsageData = { x: 'Storage capacity', y: 45 }; + const legendData: UsageData[] = [{ name: `Storage capacity: 45%` }, { name: 'Unused' }]; + + return ( +
+ (datum.x ? `${datum.x}: ${datum.y}%` : null)} + legendData={legendData} + legendOrientation="vertical" + name="chart8" + padding={{ + bottom: 25, // Adjusted to accommodate subTitle + left: 20, + right: 195, // Adjusted to accommodate legend + top: 20 + }} + subTitle="of 100 GBps" + subTitlePosition="bottom" + title="45%" + thresholds={[{ value: 60 }, { value: 90 }]} + width={350} + /> +
+ ); +}; diff --git a/packages/react-charts/src/victory/components/ChartDonutUtilization/examples/ChartUtilSmallRightAlignedSubtitle.tsx b/packages/react-charts/src/victory/components/ChartDonutUtilization/examples/ChartUtilSmallRightAlignedSubtitle.tsx new file mode 100644 index 00000000000..ee21d72ffdc --- /dev/null +++ b/packages/react-charts/src/victory/components/ChartDonutUtilization/examples/ChartUtilSmallRightAlignedSubtitle.tsx @@ -0,0 +1,52 @@ +import { ChartDonutThreshold, ChartDonutUtilization } from '@patternfly/react-charts/victory'; + +interface UsageData { + x?: string; + y?: number; + name?: string; +} + +export const ChartUtilSmallRightAlignedSubtitle: React.FunctionComponent = () => { + const dataThreshold: UsageData[] = [ + { x: 'Warning at 60%', y: 60 }, + { x: 'Danger at 90%', y: 90 } + ]; + const dataUtil: UsageData = { x: 'Storage capacity', y: 45 }; + const legendData: UsageData[] = [ + { name: `Storage capacity: 45%` }, + { name: 'Warning threshold at 60%' }, + { name: 'Danger threshold at 90%' } + ]; + + return ( +
+ (datum.x ? datum.x : null)} + name="chart18" + padding={{ + bottom: 60, // Adjusted to accommodate legend + left: 20, + right: 20, + top: 20 + }} + subTitlePosition="right" + width={675} + > + (datum.x ? `${datum.x}: ${datum.y}%` : null)} + legendData={legendData} + legendPosition="bottom" + subTitle="of 100 GBps" + title="45%" + thresholds={[{ value: 60 }, { value: 90 }]} + /> + +
+ ); +}; diff --git a/packages/react-charts/src/victory/components/ChartDonutUtilization/examples/ChartUtilSmallRightLegend.tsx b/packages/react-charts/src/victory/components/ChartDonutUtilization/examples/ChartUtilSmallRightLegend.tsx new file mode 100644 index 00000000000..78eb2ddd1b3 --- /dev/null +++ b/packages/react-charts/src/victory/components/ChartDonutUtilization/examples/ChartUtilSmallRightLegend.tsx @@ -0,0 +1,54 @@ +import { ChartDonutUtilization } from '@patternfly/react-charts/victory'; +import { useEffect, useState } from 'react'; + +interface UsageData { + x?: string; + y?: number; + name?: string; +} + +export const ChartUtilSmallRightLegend: React.FunctionComponent = () => { + const [spacer, setSpacer] = useState(''); + const [used, setUsed] = useState(0); + + useEffect(() => { + const interval = setInterval(() => { + setUsed((prevUsed) => { + const val = (prevUsed + 10) % 100; + setSpacer(val < 10 ? ' ' : ''); + return val; + }); + }, 1000); + + return () => clearInterval(interval); + }, []); + + const data: UsageData = { x: 'Storage capacity', y: used }; + const legendData: UsageData[] = [{ name: `Storage capacity: ${spacer}${used}%` }, { name: 'Unused' }]; + + return ( +
+ (datum.x ? `${datum.x}: ${datum.y}%` : null)} + legendData={legendData} + legendOrientation="vertical" + name="chart7" + padding={{ + bottom: 20, + left: 20, + right: 195, // Adjusted to accommodate legend + top: 20 + }} + subTitle="of 100 GBps" + title={`${used}%`} + thresholds={[{ value: 60 }, { value: 90 }]} + width={350} + /> +
+ ); +}; diff --git a/packages/react-charts/src/victory/components/ChartDonutUtilization/examples/ChartUtilSmallRightSubtitle.tsx b/packages/react-charts/src/victory/components/ChartDonutUtilization/examples/ChartUtilSmallRightSubtitle.tsx new file mode 100644 index 00000000000..723d517a4e0 --- /dev/null +++ b/packages/react-charts/src/victory/components/ChartDonutUtilization/examples/ChartUtilSmallRightSubtitle.tsx @@ -0,0 +1,39 @@ +import { ChartDonutUtilization } from '@patternfly/react-charts/victory'; + +interface UsageData { + x?: string; + y?: number; + name?: string; +} + +export const ChartUtilSmallRightSubtitle: React.FunctionComponent = () => { + const data: UsageData = { x: 'Storage capacity', y: 45 }; + const legendData: UsageData[] = [{ name: `Storage capacity: 45%` }, { name: 'Unused' }]; + + return ( +
+ (datum.x ? `${datum.x}: ${datum.y}%` : null)} + legendData={legendData} + legendPosition="bottom" + name="chart9" + padding={{ + bottom: 45, // Adjusted to accommodate legend + left: 20, + right: 20, + top: 20 + }} + subTitle="of 100 GBps" + subTitlePosition="right" + title="45%" + thresholds={[{ value: 60 }, { value: 90 }]} + width={350} + /> +
+ ); +}; diff --git a/packages/react-charts/src/victory/components/ChartDonutUtilization/examples/ChartUtilSmallStatic.tsx b/packages/react-charts/src/victory/components/ChartDonutUtilization/examples/ChartUtilSmallStatic.tsx new file mode 100644 index 00000000000..d8dced1e8b7 --- /dev/null +++ b/packages/react-charts/src/victory/components/ChartDonutUtilization/examples/ChartUtilSmallStatic.tsx @@ -0,0 +1,36 @@ +import { ChartDonutThreshold, ChartDonutUtilization } from '@patternfly/react-charts/victory'; + +interface UsageData { + x: string; + y: number; +} + +export const ChartUtilSmallStatic: React.FunctionComponent = () => { + const dataThreshold: UsageData[] = [ + { x: 'Warning at 60%', y: 60 }, + { x: 'Danger at 90%', y: 90 } + ]; + const dataUtil: UsageData = { x: 'Storage capacity', y: 45 }; + + return ( +
+ (datum.x ? datum.x : null)} + name="chart15" + width={185} + > + (datum.x ? `${datum.x}: ${datum.y}%` : null)} + subTitle="of 100 GBps" + title="45%" + /> + +
+ ); +}; diff --git a/packages/react-charts/src/victory/components/ChartDonutUtilization/examples/ChartUtilSmallStaticRightLegend.tsx b/packages/react-charts/src/victory/components/ChartDonutUtilization/examples/ChartUtilSmallStaticRightLegend.tsx new file mode 100644 index 00000000000..7e88687558c --- /dev/null +++ b/packages/react-charts/src/victory/components/ChartDonutUtilization/examples/ChartUtilSmallStaticRightLegend.tsx @@ -0,0 +1,65 @@ +import { ChartDonutThreshold, ChartDonutUtilization } from '@patternfly/react-charts/victory'; +import { useEffect, useState } from 'react'; + +interface UsageData { + x?: string; + y?: number; + name?: string; +} + +export const ChartUtilSmallStaticRightLegend: React.FunctionComponent = () => { + const [used, setUsed] = useState(0); + + useEffect(() => { + const interval = setInterval(() => { + setUsed((prevUsed) => { + const val = (prevUsed + 10) % 100; + return val; + }); + }, 1000); + + return () => clearInterval(interval); + }, []); + + const dataThreshold: UsageData[] = [ + { x: 'Warning at 60%', y: 60 }, + { x: 'Danger at 90%', y: 90 } + ]; + const dataUtil: UsageData = { x: 'Storage capacity', y: used }; + const legendData: UsageData[] = [ + { name: `Storage capacity: ${used}%` }, + { name: 'Warning threshold at 60%' }, + { name: 'Danger threshold at 90%' } + ]; + + return ( +
+ (datum.x ? datum.x : null)} + name="chart16" + padding={{ + bottom: 20, + left: 20, + right: 260, // Adjusted to accommodate legend + top: 20 + }} + width={425} + > + (datum.x ? `${datum.x}: ${datum.y}%` : null)} + legendData={legendData} + legendOrientation="vertical" + subTitle="of 100 GBps" + title={`${used}%`} + thresholds={[{ value: 60 }, { value: 90 }]} + /> + +
+ ); +}; diff --git a/packages/react-charts/src/victory/components/ChartDonutUtilization/examples/ChartUtilSmallSubtitle.tsx b/packages/react-charts/src/victory/components/ChartDonutUtilization/examples/ChartUtilSmallSubtitle.tsx new file mode 100644 index 00000000000..04474836897 --- /dev/null +++ b/packages/react-charts/src/victory/components/ChartDonutUtilization/examples/ChartUtilSmallSubtitle.tsx @@ -0,0 +1,52 @@ +import { ChartDonutThreshold, ChartDonutUtilization } from '@patternfly/react-charts/victory'; + +interface UsageData { + x?: string; + y?: number; + name?: string; +} + +export const ChartUtilSmallSubtitle: React.FunctionComponent = () => { + const dataThreshold: UsageData[] = [ + { x: 'Warning at 60%', y: 60 }, + { x: 'Danger at 90%', y: 90 } + ]; + const dataUtil: UsageData = { x: 'Storage capacity', y: 45 }; + const legendData: UsageData[] = [ + { name: `Storage capacity: 45%` }, + { name: 'Warning threshold at 60%' }, + { name: 'Danger threshold at 90%' } + ]; + + return ( +
+ (datum.x ? datum.x : null)} + name="chart17" + padding={{ + bottom: 30, // Adjusted to accommodate label + left: 20, + right: 260, // Adjusted to accommodate legend + top: 20 + }} + subTitlePosition="bottom" + width={425} + > + (datum.x ? `${datum.x}: ${datum.y}%` : null)} + legendData={legendData} + legendOrientation="vertical" + subTitle="of 100 GBps" + title="45%" + thresholds={[{ value: 60 }, { value: 90 }]} + /> + +
+ ); +}; diff --git a/packages/react-charts/src/victory/components/ChartDonutUtilization/examples/ChartUtilStatic.tsx b/packages/react-charts/src/victory/components/ChartDonutUtilization/examples/ChartUtilStatic.tsx new file mode 100644 index 00000000000..09faef161fd --- /dev/null +++ b/packages/react-charts/src/victory/components/ChartDonutUtilization/examples/ChartUtilStatic.tsx @@ -0,0 +1,34 @@ +import { ChartDonutThreshold, ChartDonutUtilization } from '@patternfly/react-charts/victory'; + +interface UsageData { + x: string; + y: number; +} + +export const ChartUtilStatic: React.FunctionComponent = () => { + const dataThreshold: UsageData[] = [ + { x: 'Warning at 60%', y: 60 }, + { x: 'Danger at 90%', y: 90 } + ]; + const dataUtil: UsageData = { x: 'Storage capacity', y: 45 }; + + return ( +
+ (datum.x ? datum.x : null)} + name="chart10" + > + (datum.x ? `${datum.x}: ${datum.y}%` : null)} + subTitle="of 100 GBps" + title="45%" + /> + +
+ ); +}; diff --git a/packages/react-charts/src/victory/components/ChartDonutUtilization/examples/ChartUtilStaticBottomLegend.tsx b/packages/react-charts/src/victory/components/ChartDonutUtilization/examples/ChartUtilStaticBottomLegend.tsx new file mode 100644 index 00000000000..250c2048145 --- /dev/null +++ b/packages/react-charts/src/victory/components/ChartDonutUtilization/examples/ChartUtilStaticBottomLegend.tsx @@ -0,0 +1,50 @@ +import { ChartDonutThreshold, ChartDonutUtilization } from '@patternfly/react-charts/victory'; + +interface UsageData { + x?: string; + y?: number; + name?: string; +} + +export const ChartUtilStaticBottomLegend: React.FunctionComponent = () => { + const dataThreshold: UsageData[] = [ + { x: 'Warning at 60%', y: 60 }, + { x: 'Danger at 90%', y: 90 } + ]; + const dataUtil: UsageData = { x: 'Storage capacity', y: 45 }; + const legendData: UsageData[] = [ + { name: `Storage capacity: 45%` }, + { name: 'Warning threshold at 60%' }, + { name: 'Danger threshold at 90%' } + ]; + + return ( +
+ (datum.x ? datum.x : null)} + name="chart14" + 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%" + /> + +
+ ); +}; diff --git a/packages/react-charts/src/victory/components/ChartDonutUtilization/examples/ChartUtilStaticCustomLegend.tsx b/packages/react-charts/src/victory/components/ChartDonutUtilization/examples/ChartUtilStaticCustomLegend.tsx new file mode 100644 index 00000000000..b6d3ada2ce8 --- /dev/null +++ b/packages/react-charts/src/victory/components/ChartDonutUtilization/examples/ChartUtilStaticCustomLegend.tsx @@ -0,0 +1,67 @@ +import { ChartDonutThreshold, ChartDonutUtilization, ChartThemeColor } from '@patternfly/react-charts/victory'; +import { useEffect, useState } from 'react'; + +interface UsageData { + x?: string; + y?: number; + name?: string; +} + +export const ChartUtilStaticCustomLegend: React.FunctionComponent = () => { + const [used, setUsed] = useState(0); + + useEffect(() => { + const interval = setInterval(() => { + setUsed((prevUsed) => { + const val = (prevUsed + 10) % 100; + return val; + }); + }, 1000); + + return () => clearInterval(interval); + }, []); + + const dataThreshold: UsageData[] = [ + { x: 'Warning at 60%', y: 60 }, + { x: 'Danger at 90%', y: 90 } + ]; + const dataUtil: UsageData = { x: 'Storage capacity', y: used }; + const legendData: UsageData[] = [ + { name: `Storage capacity: ${used}%` }, + { name: 'Warning threshold at 60%' }, + { name: 'Danger threshold at 90%' } + ]; + + return ( +
+ (datum.x ? datum.x : null)} + name="chart13" + padding={{ + bottom: 125, // Adjusted to accommodate legend + left: 20, + right: 20, + top: 20 + }} + width={230} + > + (datum.x ? `${datum.x}: ${datum.y}%` : null)} + legendData={legendData} + legendOrientation="vertical" + legendPosition="bottom" + subTitle="of 100 GBps" + title={`${used}%`} + themeColor={ChartThemeColor.green} + thresholds={[{ value: 60 }, { value: 90 }]} + /> + +
+ ); +}; diff --git a/packages/react-charts/src/victory/components/ChartDonutUtilization/examples/ChartUtilStaticRightLegend.tsx b/packages/react-charts/src/victory/components/ChartDonutUtilization/examples/ChartUtilStaticRightLegend.tsx new file mode 100644 index 00000000000..57a1a6db5c0 --- /dev/null +++ b/packages/react-charts/src/victory/components/ChartDonutUtilization/examples/ChartUtilStaticRightLegend.tsx @@ -0,0 +1,64 @@ +import { ChartDonutThreshold, ChartDonutUtilization } from '@patternfly/react-charts/victory'; +import { useEffect, useState } from 'react'; + +interface UsageData { + x?: string; + y?: number; + name?: string; +} + +export const ChartUtilStaticRightLegend: React.FunctionComponent = () => { + const [used, setUsed] = useState(0); + + useEffect(() => { + const interval = setInterval(() => { + setUsed((prevUsed) => { + const val = (prevUsed + 10) % 100; + return val; + }); + }, 1000); + + return () => clearInterval(interval); + }, []); + + const dataThreshold: UsageData[] = [ + { x: 'Warning at 60%', y: 60 }, + { x: 'Danger at 90%', y: 90 } + ]; + const dataUtil: UsageData = { x: 'Storage capacity', y: used }; + const legendData: UsageData[] = [ + { name: `Storage capacity: ${used}%` }, + { name: 'Warning threshold at 60%' }, + { name: 'Danger threshold at 90%' } + ]; + + return ( +
+ (datum.x ? datum.x : null)} + name="chart11" + padding={{ + bottom: 20, + left: 20, + right: 290, // Adjusted to accommodate legend + top: 20 + }} + width={500} + > + (datum.x ? `${datum.x}: ${datum.y}%` : null)} + legendData={legendData} + legendOrientation="vertical" + subTitle="of 100 GBps" + title={`${used}%`} + thresholds={[{ value: 60 }, { value: 90 }]} + /> + +
+ ); +}; diff --git a/packages/react-charts/src/components/ChartGroup/ChartGroup.test.tsx b/packages/react-charts/src/victory/components/ChartGroup/ChartGroup.test.tsx similarity index 96% rename from packages/react-charts/src/components/ChartGroup/ChartGroup.test.tsx rename to packages/react-charts/src/victory/components/ChartGroup/ChartGroup.test.tsx index 7b800771eba..5d3c972ff67 100644 --- a/packages/react-charts/src/components/ChartGroup/ChartGroup.test.tsx +++ b/packages/react-charts/src/victory/components/ChartGroup/ChartGroup.test.tsx @@ -1,4 +1,3 @@ -import * as React from 'react'; import { render } from '@testing-library/react'; import { ChartArea } from '../ChartArea/ChartArea'; import { ChartGroup } from './ChartGroup'; diff --git a/packages/react-charts/src/components/ChartGroup/ChartGroup.tsx b/packages/react-charts/src/victory/components/ChartGroup/ChartGroup.tsx similarity index 98% rename from packages/react-charts/src/components/ChartGroup/ChartGroup.tsx rename to packages/react-charts/src/victory/components/ChartGroup/ChartGroup.tsx index 6bb01abb496..a92b3c0eadf 100644 --- a/packages/react-charts/src/components/ChartGroup/ChartGroup.tsx +++ b/packages/react-charts/src/victory/components/ChartGroup/ChartGroup.tsx @@ -1,4 +1,4 @@ -import * as React from 'react'; +import { cloneElement } from 'react'; import hoistNonReactStatics from 'hoist-non-react-statics'; import { AnimatePropTypeInterface, @@ -152,7 +152,7 @@ export interface ChartGroupProps extends VictoryGroupProps { * Since ChartGroup only renders a single element, the eventKey property is not used. * The eventHandlers object should be given as an object whose keys are standard * event names (i.e. onClick) and whose values are event callbacks. The return value - * of an event handler is used to modify elemnts. The return value should be given + * of an event handler is used to modify elements. The return value should be given * as an object or an array of objects with optional target and eventKey keys, * and a mutation key whose value is a function. The target and eventKey keys * will default to those corresponding to the element the event handler was attached to. @@ -355,7 +355,7 @@ export interface ChartGroupProps extends VictoryGroupProps { * * Note: This prop should not be set manually. * - * @private + * @private Not intended as public API and subject to change * @hide */ sharedEvents?: { events: any[]; getEventState: Function }; @@ -479,7 +479,7 @@ export const ChartGroup: React.FunctionComponent = ({ ...rest }: ChartGroupProps) => { // Clone so users can override container props - const container = React.cloneElement(containerComponent, { + const container = cloneElement(containerComponent, { desc: ariaDesc, title: ariaTitle, theme, diff --git a/packages/react-charts/src/components/ChartGroup/__snapshots__/ChartGroup.test.tsx.snap b/packages/react-charts/src/victory/components/ChartGroup/__snapshots__/ChartGroup.test.tsx.snap similarity index 73% rename from packages/react-charts/src/components/ChartGroup/__snapshots__/ChartGroup.test.tsx.snap rename to packages/react-charts/src/victory/components/ChartGroup/__snapshots__/ChartGroup.test.tsx.snap index 5f29cc4b763..afe49088662 100644 --- a/packages/react-charts/src/components/ChartGroup/__snapshots__/ChartGroup.test.tsx.snap +++ b/packages/react-charts/src/victory/components/ChartGroup/__snapshots__/ChartGroup.test.tsx.snap @@ -9,16 +9,16 @@ exports[`ChartGroup 1`] = `
@@ -36,16 +36,16 @@ exports[`ChartGroup 2`] = `
@@ -63,7 +63,7 @@ exports[`renders container children 1`] = ` @@ -88,7 +88,7 @@ exports[`renders container children 1`] = ` d="M50,121.42857142857142L75,92.85714285714286L100,58.57142857142856L125,50L125,150L100,150L75,150L50,150Z" role="presentation" shape-rendering="auto" - style="fill: var(--pf-v6-chart-theme--blue--ColorScale--100, #0066cc); width: 6px; fill-opacity: 0.3; stroke-width: 2; stroke: var(--pf-v6-chart-theme--blue--ColorScale--100, #0066cc);" + style="fill: var(--pf-v6-chart-theme--blue--ColorScale--100, #0066cc); width: 6px; fill-opacity: var(--pf-v6-chart-area--Opacity, 30%); stroke-width: 2; stroke: var(--pf-v6-chart-theme--blue--ColorScale--100, #0066cc);" />
diff --git a/packages/react-charts/src/components/ChartLabel/ChartLabel.test.tsx b/packages/react-charts/src/victory/components/ChartLabel/ChartLabel.test.tsx similarity index 93% rename from packages/react-charts/src/components/ChartLabel/ChartLabel.test.tsx rename to packages/react-charts/src/victory/components/ChartLabel/ChartLabel.test.tsx index 6915a7cbf69..1f9e3f3b461 100644 --- a/packages/react-charts/src/components/ChartLabel/ChartLabel.test.tsx +++ b/packages/react-charts/src/victory/components/ChartLabel/ChartLabel.test.tsx @@ -1,4 +1,3 @@ -import * as React from 'react'; import { render } from '@testing-library/react'; import { ChartLabel } from './ChartLabel'; diff --git a/packages/react-charts/src/components/ChartLabel/ChartLabel.tsx b/packages/react-charts/src/victory/components/ChartLabel/ChartLabel.tsx similarity index 94% rename from packages/react-charts/src/components/ChartLabel/ChartLabel.tsx rename to packages/react-charts/src/victory/components/ChartLabel/ChartLabel.tsx index 00359976b9c..a150694ca73 100644 --- a/packages/react-charts/src/components/ChartLabel/ChartLabel.tsx +++ b/packages/react-charts/src/victory/components/ChartLabel/ChartLabel.tsx @@ -1,4 +1,3 @@ -import * as React from 'react'; import hoistNonReactStatics from 'hoist-non-react-statics'; import defaults from 'lodash/defaults'; import { @@ -45,7 +44,7 @@ export interface ChartLabelProps extends VictoryLabelProps { * * @propType number | string | Function * - * @private + * @private Not intended as public API and subject to change * @hide */ children?: StringOrNumberOrCallback; @@ -54,7 +53,7 @@ export interface ChartLabelProps extends VictoryLabelProps { */ className?: string; /** - * Labels that apply to an entire data series will recieve the entire series as `data` instead of an individual datum + * Labels that apply to an entire data series will receive the entire series as `data` instead of an individual datum * prop. */ data?: any[]; @@ -99,7 +98,7 @@ export interface ChartLabelProps extends VictoryLabelProps { * * Note: This prop should not be set manually. * - * @private + * @private Not intended as public API and subject to change * @hide */ index?: string | number; @@ -111,7 +110,7 @@ export interface ChartLabelProps extends VictoryLabelProps { /** * The labelPlacement prop is used to specify the placement of labels relative to the data point they represent. * This prop may be given as “vertical”, “parallel” or “perpendicular”. This props is particularly useful in polar - * charts, where it may be desireable to position a label either parallel or perpendicular to its corresponding angle. + * charts, where it may be desirable to position a label either parallel or perpendicular to its corresponding angle. * When this prop is not set, perpendicular label placement will be used for polar charts, and vertical label * placement will be used for cartesian charts. * @@ -141,7 +140,7 @@ export interface ChartLabelProps extends VictoryLabelProps { * * Note: This prop should not be set manually. * - * @private + * @private Not intended as public API and subject to change * @hide */ polar?: boolean; @@ -156,7 +155,7 @@ export interface ChartLabelProps extends VictoryLabelProps { * * Note: This prop should not be set manually. * - * @private + * @private Not intended as public API and subject to change * @hide */ scale?: { x?: any; y?: any }; @@ -198,7 +197,7 @@ export interface ChartLabelProps extends VictoryLabelProps { * * Note: This prop should not be set manually. * - * @private + * @private Not intended as public API and subject to change * @hide */ width?: number; diff --git a/packages/react-charts/src/components/ChartLabel/__snapshots__/ChartLabel.test.tsx.snap b/packages/react-charts/src/victory/components/ChartLabel/__snapshots__/ChartLabel.test.tsx.snap similarity index 70% rename from packages/react-charts/src/components/ChartLabel/__snapshots__/ChartLabel.test.tsx.snap rename to packages/react-charts/src/victory/components/ChartLabel/__snapshots__/ChartLabel.test.tsx.snap index 0e7841ee941..3703c9eebb0 100644 --- a/packages/react-charts/src/components/ChartLabel/__snapshots__/ChartLabel.test.tsx.snap +++ b/packages/react-charts/src/victory/components/ChartLabel/__snapshots__/ChartLabel.test.tsx.snap @@ -16,7 +16,7 @@ exports[`renders component text 1`] = ` diff --git a/packages/react-charts/src/components/ChartLegend/ChartLegend.test.tsx b/packages/react-charts/src/victory/components/ChartLegend/ChartLegend.test.tsx similarity index 96% rename from packages/react-charts/src/components/ChartLegend/ChartLegend.test.tsx rename to packages/react-charts/src/victory/components/ChartLegend/ChartLegend.test.tsx index fa40554fc4f..9f42835b0c6 100644 --- a/packages/react-charts/src/components/ChartLegend/ChartLegend.test.tsx +++ b/packages/react-charts/src/victory/components/ChartLegend/ChartLegend.test.tsx @@ -1,4 +1,3 @@ -import * as React from 'react'; import { render } from '@testing-library/react'; import { ChartLegend } from './ChartLegend'; import { ChartLabel } from '../ChartLabel/ChartLabel'; diff --git a/packages/react-charts/src/components/ChartLegend/ChartLegend.tsx b/packages/react-charts/src/victory/components/ChartLegend/ChartLegend.tsx similarity index 98% rename from packages/react-charts/src/components/ChartLegend/ChartLegend.tsx rename to packages/react-charts/src/victory/components/ChartLegend/ChartLegend.tsx index c2af1359289..03efdd8302e 100644 --- a/packages/react-charts/src/components/ChartLegend/ChartLegend.tsx +++ b/packages/react-charts/src/victory/components/ChartLegend/ChartLegend.tsx @@ -1,4 +1,4 @@ -import * as React from 'react'; +import { cloneElement } from 'react'; import hoistNonReactStatics from 'hoist-non-react-statics'; import { BlockProps, @@ -45,7 +45,7 @@ export interface ChartLegendProps extends VictoryLegendProps { /** * The borderPadding specifies the amount of padding that should * be added between the legend items and the border. This prop may be given as - * a number, or asanobject with values specified for top, bottom, left, and right. + * a number, or as an object with values specified for top, bottom, left, and right. * Please note that the default width and height calculated for the border * component is based on approximated text measurements, so padding may need to be adjusted. * @@ -217,7 +217,7 @@ export interface ChartLegendProps extends VictoryLegendProps { * * Note: This prop should not be set manually. * - * @private + * @private Not intended as public API and subject to change * @hide */ sharedEvents?: { events: any[]; getEventState: Function }; @@ -343,21 +343,21 @@ export const ChartLegend: React.FunctionComponent = ({ }; // Clone so users can override container props - const container = React.cloneElement(containerComponent, { + const container = cloneElement(containerComponent, { responsive, theme, ...containerComponent.props }); const getLabelComponent = () => - React.cloneElement(labelComponent, { + cloneElement(labelComponent, { ...(name && { id: (props: any) => `${name}-${(labelComponent as any).type.displayName}-${props.index}` }), ...labelComponent.props, ...(componentTheme?.label && componentTheme.label) // override backgroundStyle }); const getTitleComponent = () => - React.cloneElement(titleComponent, { + cloneElement(titleComponent, { // Victory doesn't appear to call the id function here, but it's valid for label components ...(name && { id: () => `${name}-${(titleComponent as any).type.displayName}` }), ...titleComponent.props, diff --git a/packages/react-charts/src/victory/components/ChartLegend/__snapshots__/ChartLegend.test.tsx.snap b/packages/react-charts/src/victory/components/ChartLegend/__snapshots__/ChartLegend.test.tsx.snap new file mode 100644 index 00000000000..317e45b3fda --- /dev/null +++ b/packages/react-charts/src/victory/components/ChartLegend/__snapshots__/ChartLegend.test.tsx.snap @@ -0,0 +1,294 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`ChartLegend 1`] = ` + +
+ + + + + + + Series 1 + + + + + Series 2 + + + +
+ +
+
+
+`; + +exports[`ChartLegend 2`] = ` + +
+ + + + + + + Series 1 + + + + + Series 2 + + + +
+ +
+
+
+`; + +exports[`renders component data 1`] = ` + +
+ + + + + + + Average number of pets + + + + + Cats + + + + + Dogs + + + +
+ +
+
+
+`; diff --git a/packages/react-charts/src/victory/components/ChartLegend/examples/ChartLegend.md b/packages/react-charts/src/victory/components/ChartLegend/examples/ChartLegend.md new file mode 100644 index 00000000000..cbfe8f07204 --- /dev/null +++ b/packages/react-charts/src/victory/components/ChartLegend/examples/ChartLegend.md @@ -0,0 +1,143 @@ +--- +id: Legends +section: components +subsection: charts +propComponents: [ + 'Chart', + 'ChartArea', + 'ChartAxis', + 'ChartBar', + 'ChartBullet', + 'ChartDonut', + 'ChartGroup', + 'ChartLabel', + 'ChartLegend', + 'ChartLegendTooltip', + 'ChartLine', + 'ChartPie', + 'ChartScatter', + 'ChartVoronoiContainer' +] +hideDarkMode: true +--- + +import { cloneElement, useEffect, useRef, useState } from 'react'; +import { + Chart, + ChartArea, + ChartAxis, + ChartBar, + ChartBullet, + ChartContainer, + ChartDonut, + ChartGroup, + ChartLabel, + ChartLegend, + ChartLegendTooltip, + ChartLine, + ChartPie, + ChartScatter, + ChartThemeColor, + ChartVoronoiContainer, + createContainer, + getInteractiveLegendEvents, + getInteractiveLegendItemStyles +} from '@patternfly/react-charts/victory'; +import { getResizeObserver } from '@patternfly/react-core'; +import chart_color_black_500 from '@patternfly/react-tokens/dist/esm/chart_color_black_500'; +import '@patternfly/patternfly/patternfly-charts.css'; + +## Introduction +Note: PatternFly React charts live in its own package at [@patternfly/react-charts](https://www.npmjs.com/package/@patternfly/react-charts)! + +The examples below are based on the [Victory](https://formidable.com/open-source/victory/docs/victory-chart/) chart library, along with additional functionality, custom components, and theming for PatternFly. This provides a collection of React based components you can use to build PatternFly patterns with consistent markup, styling, and behavior. + +## Examples +### Basic with right aligned legend +```ts file = "ChartLegendBasicRightLegend.tsx" + +``` + +### Bottom aligned legend +```ts file = "ChartLegendBottomAlignedLegend.tsx" + +``` + +### Responsive bottom-left aligned legend + +This demonstrates a responsive legend which wraps when items are wider than its container. + +```ts file = "ChartLegendResponsiveBottomLeft.tsx" + +``` + +### Standalone legend + +This demonstrates a standalone legend vs. using the `legendData` property. + +```ts file = "ChartLegendStandalone.tsx" + +``` + +### Interactive legend + +This demonstrates how to add an interactive legend using events such as `onMouseOver`, `onMouseOut`, and `onClick`. + +```ts file = "ChartLegendInteractive.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`. + +```ts file = "ChartLegendInteractivePieChart.tsx" + +``` + +### Legend tooltips + +This demonstrates an approach for applying tooltips to a legend using a custom label component. These tooltips are keyboard navigable. + +```ts file = "ChartLegendTooltips.tsx" + +``` + +### Legend links + +This demonstrates an approach for applying links to a legend using a custom label component. These links are keyboard navigable. + +```ts file = "ChartLegendLinks.tsx" + +``` + +### Legend layout + +This demonstrates an approach for applying a different legend layout and styles using a custom label component. + +```ts file = "ChartLegendLayout.tsx" + +``` + +## Documentation +### Tips +- See Victory's [FAQ](https://formidable.com/open-source/victory/docs/faq) +- `ChartLegend` may be used as a standalone component, instead of using `legendData` + +### Note +Currently, the generated documentation below is not able to resolve type definitions from Victory imports. For the +components used in the examples above, Victory pass-thru props are also documented here: + +- For `Chart` props, see [VictoryChart](https://formidable.com/open-source/victory/docs/victory-chart) +- For `ChartArea` props, see [VictoryArea](https://formidable.com/open-source/victory/docs/victory-area) +- For `ChartAxis` props, see [VictoryAxis](https://formidable.com/open-source/victory/docs/victory-axis) +- For `ChartBar` props, see [VictoryBar](https://formidable.com/open-source/victory/docs/victory-bar) +- For `ChartBullet` props, see [VictoryBar](https://formidable.com/open-source/victory/docs/victory-bar) +- For `ChartDonut` props, see [VictoryPie](https://formidable.com/open-source/victory/docs/victory-pie) +- For `ChartGroup` props, see [VictoryGroup](https://formidable.com/open-source/victory/docs/victory-group) +- For `ChartLabel` props, see [VictoryLabel](https://formidable.com/open-source/victory/docs/victory-label) +- For `ChartLegend` props, see [VictoryLegend](https://formidable.com/open-source/victory/docs/victory-legend) +- For `ChartLine` props, see [VictoryLine](https://formidable.com/open-source/victory/docs/victory-line) +- For `ChartPie` props, see [VictoryPie](https://formidable.com/open-source/victory/docs/victory-pie) +- For `ChartScatter` props, see [VictoryScatter](https://formidable.com/open-source/victory/docs/victory-scatter) +- For `ChartVoronoiContainer` props, see [VictoryVoronoiContainer](https://formidable.com/open-source/victory/docs/victory-voronoi-container) diff --git a/packages/react-charts/src/victory/components/ChartLegend/examples/ChartLegendBasicRightLegend.tsx b/packages/react-charts/src/victory/components/ChartLegend/examples/ChartLegendBasicRightLegend.tsx new file mode 100644 index 00000000000..1ebb5a2c0a0 --- /dev/null +++ b/packages/react-charts/src/victory/components/ChartLegend/examples/ChartLegendBasicRightLegend.tsx @@ -0,0 +1,41 @@ +import { ChartDonut } from '@patternfly/react-charts/victory'; + +interface PetData { + x?: string; + y?: number; + name?: string; +} + +export const ChartLegendBasicRightLegend: 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 + }} + subTitle="Pets" + title="100" + width={350} + /> +
+ ); +}; diff --git a/packages/react-charts/src/victory/components/ChartLegend/examples/ChartLegendBottomAlignedLegend.tsx b/packages/react-charts/src/victory/components/ChartLegend/examples/ChartLegendBottomAlignedLegend.tsx new file mode 100644 index 00000000000..5b9f412340a --- /dev/null +++ b/packages/react-charts/src/victory/components/ChartLegend/examples/ChartLegendBottomAlignedLegend.tsx @@ -0,0 +1,76 @@ +import { + Chart, + ChartAxis, + ChartBar, + ChartGroup, + ChartThemeColor, + ChartVoronoiContainer +} from '@patternfly/react-charts/victory'; + +interface PetData { + x?: string; + y?: number; + name?: string; +} + +export const ChartLegendBottomAlignedLegend: 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" + 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/ChartLegend/examples/ChartLegendInteractive.tsx b/packages/react-charts/src/victory/components/ChartLegend/examples/ChartLegendInteractive.tsx new file mode 100644 index 00000000000..1cca049d777 --- /dev/null +++ b/packages/react-charts/src/victory/components/ChartLegend/examples/ChartLegendInteractive.tsx @@ -0,0 +1,154 @@ +import { + Chart, + ChartArea, + ChartAxis, + ChartGroup, + ChartLegend, + ChartLegendTooltip, + ChartScatter, + ChartThemeColor, + createContainer, + getInteractiveLegendEvents, + getInteractiveLegendItemStyles +} from '@patternfly/react-charts/victory'; +import { getResizeObserver } from '@patternfly/react-core'; +import { useRef, useState, useEffect } from 'react'; + +export const ChartLegendInteractive: React.FunctionComponent = () => { + const containerRef = useRef(null); + 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 = () => series.map((_, index) => [`area-${index}`, `scatter-${index}`]); + + // Handles legend click to toggle visibility of data series + const handleLegendClick = (props) => { + setHiddenSeries((prev) => { + const newHidden = new Set(prev); + if (!newHidden.delete(props.index)) { + newHidden.add(props.index); + } + return newHidden; + }); + }; + + // Returns legend data styled per hiddenSeries + const getLegendData = () => + series.map((s, index) => ({ + childName: `area-${index}`, + ...s.legendItem, + ...getInteractiveLegendItemStyles(hiddenSeries.has(index)) + })); + + // Returns true if data series is hidden + const isHidden = (index) => hiddenSeries.has(index); + + // Checks if any data series is visible + const isDataAvailable = () => hiddenSeries.size !== series.length; + + // Set chart width per current window size + useEffect(() => { + const observer = getResizeObserver(containerRef.current, () => { + if (containerRef.current?.clientWidth) { + setWidth(containerRef.current.clientWidth); + } + }); + return () => observer(); + }, []); + + // Note: Container order is important + const CursorVoronoiContainer = createContainer('voronoi', 'cursor'); + const container = ( + (datum.childName.includes('area-') && datum.y !== null ? `${datum.y}` : null)} + labelComponent={ datum.x} />} + mouseFollowTooltips + voronoiDimension="x" + voronoiPadding={50} + disable={!isDataAvailable()} + /> + ); + + return ( +
+
+ } + legendPosition="bottom-left" + name="chart5" + padding={{ bottom: 75, 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/ChartLegend/examples/ChartLegendInteractivePieChart.tsx b/packages/react-charts/src/victory/components/ChartLegend/examples/ChartLegendInteractivePieChart.tsx new file mode 100644 index 00000000000..8729019333e --- /dev/null +++ b/packages/react-charts/src/victory/components/ChartLegend/examples/ChartLegendInteractivePieChart.tsx @@ -0,0 +1,95 @@ +import { + Chart, + ChartLegend, + ChartThemeColor, + ChartPie, + getInteractiveLegendEvents, + getInteractiveLegendItemStyles +} from '@patternfly/react-charts/victory'; +import { useState } from 'react'; + +export const ChartLegendInteractivePieChart: React.FunctionComponent = () => { + const [hiddenSeries, setHiddenSeries] = useState>(new Set()); + + const series = [ + { + datapoints: { x: 'Cats', y: 35 }, + legendItem: { name: 'Cats: 35' } + }, + { + datapoints: { x: 'Dogs', y: 55 }, + legendItem: { name: 'Dogs: 55' } + }, + { + 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 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: { index: number }) => { + const newHiddenSeries = new Set(hiddenSeries); + if (newHiddenSeries.delete(props.index)) { + newHiddenSeries.add(props.index); + } + setHiddenSeries(newHiddenSeries); + }; + + // Returns true if data series is hidden + const isHidden = (index: number) => hiddenSeries.has(index); + // Returns onMouseOver, onMouseOut, and onClick events for the interactive legend + const getEvents = () => + getInteractiveLegendEvents({ + chartNames: getChartNames(), + isHidden, + legendName: 'chart6-ChartLegend', + onLegendClick: handleLegendClick + }); + + const data = []; + series.map((s, index) => { + data.push(!hiddenSeries.has(index) ? s.datapoints : { y: null }); + }); + + return ( +
+ } + legendPosition="bottom" + name="chart6" + padding={{ + bottom: 65, + left: 20, + right: 20, + top: 20 + }} + showAxis={false} + themeColor={ChartThemeColor.multiUnordered} + width={300} + > + `${datum.x}: ${datum.y}`} name="pie" /> + +
+ ); +}; diff --git a/packages/react-charts/src/victory/components/ChartLegend/examples/ChartLegendLayout.tsx b/packages/react-charts/src/victory/components/ChartLegend/examples/ChartLegendLayout.tsx new file mode 100644 index 00000000000..f28ab03baac --- /dev/null +++ b/packages/react-charts/src/victory/components/ChartLegend/examples/ChartLegendLayout.tsx @@ -0,0 +1,57 @@ +import { ChartLabel, ChartLegend, ChartDonut, ChartThemeColor } from '@patternfly/react-charts/victory'; + +interface PetData { + x: string; + y: number; +} + +export const ChartLegendLayout: React.FunctionComponent = () => { + // Custom legend label component + const LegendLabel = ({ values, ...rest }) => ( + + ); + + // Custom legend component + const getLegend = (legendData, values) => ( + } + rowGutter={20} + /> + ); + + const data: PetData[] = [ + { x: 'Cats', y: 35 }, + { x: 'Dogs', y: 55 }, + { x: 'Birds', y: 10 } + ]; + + return ( +
+ `${datum.x}: ${datum.y}`} + legendComponent={getLegend([{ name: 'Cats' }, { name: 'Dogs' }, { name: 'Birds' }], [35, 55, 10])} + legendOrientation="vertical" + legendPosition="right" + name="chart9" + padding={{ + bottom: 20, + left: 20, + right: 140, // Adjusted to accommodate legend + top: 20 + }} + subTitle="Pets" + title="100" + themeColor={ChartThemeColor.multiOrdered} + width={375} + /> +
+ ); +}; diff --git a/packages/react-charts/src/victory/components/ChartLegend/examples/ChartLegendLinks.tsx b/packages/react-charts/src/victory/components/ChartLegend/examples/ChartLegendLinks.tsx new file mode 100644 index 00000000000..0a544be49b5 --- /dev/null +++ b/packages/react-charts/src/victory/components/ChartLegend/examples/ChartLegendLinks.tsx @@ -0,0 +1,116 @@ +import { + Chart, + ChartAxis, + ChartGroup, + ChartLabel, + ChartLegend, + ChartLine, + ChartVoronoiContainer +} from '@patternfly/react-charts/victory'; + +interface PetData { + name?: string; + x?: string; + y?: number; + symbol?: { type: string }; +} + +export const ChartLegendLinks: React.FunctionComponent = () => { + // Custom legend label component + const LegendLabel = ({ _datum, ...rest }) => ( + + + + ); + + // Custom legend component + const getLegend = (legendData) => } />; + + 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 + /> + } + legendComponent={getLegend([{ name: 'Cats' }, { name: 'Dogs' }, { name: 'Birds' }, { name: 'Mice' }])} + legendData={legendData} + legendPosition="bottom" + height={275} + maxDomain={{ y: 10 }} + minDomain={{ y: 0 }} + name="chart8" + padding={{ + bottom: 75, // Adjusted to accommodate legend + left: 50, + right: 50, + top: 50 + }} + width={450} + > + } /> + } + /> + + + + + + + +
+ ); +}; diff --git a/packages/react-charts/src/victory/components/ChartLegend/examples/ChartLegendResponsiveBottomLeft.tsx b/packages/react-charts/src/victory/components/ChartLegend/examples/ChartLegendResponsiveBottomLeft.tsx new file mode 100644 index 00000000000..5b2e8151d44 --- /dev/null +++ b/packages/react-charts/src/victory/components/ChartLegend/examples/ChartLegendResponsiveBottomLeft.tsx @@ -0,0 +1,83 @@ +import { ChartBullet } from '@patternfly/react-charts/victory'; +import { getResizeObserver } from '@patternfly/react-core'; +import { useRef, useState, useEffect } from 'react'; + +interface Data { + name?: string; + y?: number; +} + +export const ChartLegendResponsiveBottomLeft: React.FunctionComponent = () => { + const containerRef = useRef(null); + 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: number) => { + if (newExtraHeight !== extraHeight) { + setExtraHeight(newExtraHeight); + } + }; + + const getHeight = (baseHeight: number) => baseHeight + extraHeight; + + useEffect(() => { + const observer = getResizeObserver(containerRef.current, handleResize); + handleResize(); + + return () => { + observer(); + }; + }, []); + + 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' }]; + const height = getHeight(200); + + return ( +
+ `${datum.name}: ${datum.y}`} + legendAllowWrap={handleLegendAllowWrap} + legendPosition="bottom-left" + maxDomain={{ y: 100 }} + name="chart3" + 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/ChartLegend/examples/ChartLegendStandalone.tsx b/packages/react-charts/src/victory/components/ChartLegend/examples/ChartLegendStandalone.tsx new file mode 100644 index 00000000000..374fa17c231 --- /dev/null +++ b/packages/react-charts/src/victory/components/ChartLegend/examples/ChartLegendStandalone.tsx @@ -0,0 +1,90 @@ +import { + Chart, + ChartAxis, + ChartGroup, + ChartLegend, + ChartLine, + ChartThemeColor, + ChartVoronoiContainer +} from '@patternfly/react-charts/victory'; + +interface PetData { + name?: string; + x?: string; + y?: number; + symbol?: { type: string }; +} + +export const ChartLegendStandalone: 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: 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 } + ]; + const data5: PetData[] = [ + { name: 'Cats' }, + { name: 'Dogs', symbol: { type: 'dash' } }, + { name: 'Birds' }, + { name: 'Mice' } + ]; + + return ( +
+ `${datum.name}: ${datum.y}`} constrainToVisibleArea /> + } + height={275} + maxDomain={{ y: 10 }} + minDomain={{ y: 0 }} + name="chart4" + 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/ChartLegend/examples/ChartLegendTooltips.tsx b/packages/react-charts/src/victory/components/ChartLegend/examples/ChartLegendTooltips.tsx new file mode 100644 index 00000000000..1069dabe637 --- /dev/null +++ b/packages/react-charts/src/victory/components/ChartLegend/examples/ChartLegendTooltips.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 ChartLegendTooltips: React.FunctionComponent = () => { + const data: PetData[] = [ + { x: 'Cats', y: 35 }, + { x: 'Dogs', y: 55 }, + { x: 'Birds', y: 10 } + ]; + + // Custom legend label component + // Note: Tooltip wraps children with a div tag, so we use a reference to ChartLabel instead + const LegendLabel = ({ datum, ...rest }) => { + const ref = useRef(null); + return ( + + + + + ); + }; + + // Custom legend component + const getLegend = (legendData) => } />; + + 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/components/ChartLegendTooltip/ChartLegendTooltip.test.tsx b/packages/react-charts/src/victory/components/ChartLegendTooltip/ChartLegendTooltip.test.tsx similarity index 99% rename from packages/react-charts/src/components/ChartLegendTooltip/ChartLegendTooltip.test.tsx rename to packages/react-charts/src/victory/components/ChartLegendTooltip/ChartLegendTooltip.test.tsx index 46928fe7a51..02671cfcf0d 100644 --- a/packages/react-charts/src/components/ChartLegendTooltip/ChartLegendTooltip.test.tsx +++ b/packages/react-charts/src/victory/components/ChartLegendTooltip/ChartLegendTooltip.test.tsx @@ -1,4 +1,3 @@ -import * as React from 'react'; import { render } from '@testing-library/react'; import { Chart } from '../Chart/Chart'; import { ChartAxis } from '../ChartAxis/ChartAxis'; diff --git a/packages/react-charts/src/components/ChartLegendTooltip/ChartLegendTooltip.tsx b/packages/react-charts/src/victory/components/ChartLegendTooltip/ChartLegendTooltip.tsx similarity index 98% rename from packages/react-charts/src/components/ChartLegendTooltip/ChartLegendTooltip.tsx rename to packages/react-charts/src/victory/components/ChartLegendTooltip/ChartLegendTooltip.tsx index 167a7e4244a..7588e9cc5a0 100644 --- a/packages/react-charts/src/components/ChartLegendTooltip/ChartLegendTooltip.tsx +++ b/packages/react-charts/src/victory/components/ChartLegendTooltip/ChartLegendTooltip.tsx @@ -1,4 +1,4 @@ -import * as React from 'react'; +import { cloneElement } from 'react'; import hoistNonReactStatics from 'hoist-non-react-statics'; import { Helpers, @@ -42,7 +42,7 @@ export interface ChartLegendTooltipProps extends Omit - React.cloneElement(labelComponent, { + cloneElement(labelComponent, { center, flyoutHeight: flyoutHeight || getFlyoutHeight(props), flyoutWidth: flyoutWidth || getFlyoutWidth(props), @@ -388,7 +388,7 @@ export const ChartLegendTooltip: React.FunctionComponent : ; - return React.cloneElement(tooltipComponent, { + return cloneElement(tooltipComponent, { activePoints, center, datum, diff --git a/packages/react-charts/src/components/ChartLegendTooltip/ChartLegendTooltipContent.test.tsx b/packages/react-charts/src/victory/components/ChartLegendTooltip/ChartLegendTooltipContent.test.tsx similarity index 95% rename from packages/react-charts/src/components/ChartLegendTooltip/ChartLegendTooltipContent.test.tsx rename to packages/react-charts/src/victory/components/ChartLegendTooltip/ChartLegendTooltipContent.test.tsx index 480a43e19b0..b1ed7c10a4b 100644 --- a/packages/react-charts/src/components/ChartLegendTooltip/ChartLegendTooltipContent.test.tsx +++ b/packages/react-charts/src/victory/components/ChartLegendTooltip/ChartLegendTooltipContent.test.tsx @@ -1,4 +1,3 @@ -import * as React from 'react'; import { render } from '@testing-library/react'; import { ChartLegendTooltipContent } from './ChartLegendTooltipContent'; diff --git a/packages/react-charts/src/components/ChartLegendTooltip/ChartLegendTooltipContent.tsx b/packages/react-charts/src/victory/components/ChartLegendTooltip/ChartLegendTooltipContent.tsx similarity index 97% rename from packages/react-charts/src/components/ChartLegendTooltip/ChartLegendTooltipContent.tsx rename to packages/react-charts/src/victory/components/ChartLegendTooltip/ChartLegendTooltipContent.tsx index d0e75a72afc..87231098f77 100644 --- a/packages/react-charts/src/components/ChartLegendTooltip/ChartLegendTooltipContent.tsx +++ b/packages/react-charts/src/victory/components/ChartLegendTooltip/ChartLegendTooltipContent.tsx @@ -1,4 +1,4 @@ -import * as React from 'react'; +import { cloneElement, Fragment } from 'react'; import hoistNonReactStatics from 'hoist-non-react-statics'; import { Helpers, NumberOrCallback, StringOrNumberOrCallback } from 'victory-core'; import { VictoryLegend } from 'victory-legend'; @@ -26,7 +26,7 @@ export interface ChartLegendTooltipContentProps { * * Note: This prop should not be set manually. * - * @private + * @private Not intended as public API and subject to change * @hide */ activePoints?: any[]; @@ -272,7 +272,7 @@ export const ChartLegendTooltipContent: React.FunctionComponent - React.cloneElement(labelComponent, { + cloneElement(labelComponent, { datum, dx: maxLegendDimensions.width - minLegendDimensions.width, legendData: visibleLegendData, @@ -283,7 +283,7 @@ export const ChartLegendTooltipContent: React.FunctionComponent { const _title = title instanceof Function ? title(datum) : title; - return React.cloneElement(titleComponent, { + return cloneElement(titleComponent, { style: { fill: ChartLegendTooltipStyles.label.fill, fontWeight: ChartLegendTooltipStyles.label.fontWeight @@ -298,7 +298,7 @@ export const ChartLegendTooltipContent: React.FunctionComponent - React.cloneElement(legendComponent, { + cloneElement(legendComponent, { data: getLegendTooltipVisibleData({ activePoints, colorScale: legendProps.colorScale, @@ -319,10 +319,10 @@ export const ChartLegendTooltipContent: React.FunctionComponent + {getTitleComponent()} {getLegendComponent()} - + ); }; ChartLegendTooltipContent.displayName = 'ChartLegendTooltipContent'; diff --git a/packages/react-charts/src/components/ChartLegendTooltip/ChartLegendTooltipLabel.test.tsx b/packages/react-charts/src/victory/components/ChartLegendTooltip/ChartLegendTooltipLabel.test.tsx similarity index 96% rename from packages/react-charts/src/components/ChartLegendTooltip/ChartLegendTooltipLabel.test.tsx rename to packages/react-charts/src/victory/components/ChartLegendTooltip/ChartLegendTooltipLabel.test.tsx index 3fec86c52fa..6b6733b9b4e 100644 --- a/packages/react-charts/src/components/ChartLegendTooltip/ChartLegendTooltipLabel.test.tsx +++ b/packages/react-charts/src/victory/components/ChartLegendTooltip/ChartLegendTooltipLabel.test.tsx @@ -1,4 +1,3 @@ -import * as React from 'react'; import { render } from '@testing-library/react'; import { ChartLegendTooltipLabel } from './ChartLegendTooltipLabel'; import { ChartLabel } from '../ChartLabel/ChartLabel'; diff --git a/packages/react-charts/src/components/ChartLegendTooltip/ChartLegendTooltipLabel.tsx b/packages/react-charts/src/victory/components/ChartLegendTooltip/ChartLegendTooltipLabel.tsx similarity index 93% rename from packages/react-charts/src/components/ChartLegendTooltip/ChartLegendTooltipLabel.tsx rename to packages/react-charts/src/victory/components/ChartLegendTooltip/ChartLegendTooltipLabel.tsx index 5fb9c4bd58b..0e9a2a1beb1 100644 --- a/packages/react-charts/src/components/ChartLegendTooltip/ChartLegendTooltipLabel.tsx +++ b/packages/react-charts/src/victory/components/ChartLegendTooltip/ChartLegendTooltipLabel.tsx @@ -1,4 +1,4 @@ -import * as React from 'react'; +import { cloneElement, Fragment } from 'react'; import hoistNonReactStatics from 'hoist-non-react-statics'; import defaults from 'lodash/defaults'; import { @@ -47,7 +47,7 @@ export interface ChartLegendTooltipLabelProps extends VictoryLabelProps { * * @propType number | string | Function * - * @private + * @private Not intended as public API and subject to change * @hide */ children?: StringOrNumberOrCallback; @@ -56,7 +56,7 @@ export interface ChartLegendTooltipLabelProps extends VictoryLabelProps { */ className?: string; /** - * Labels that apply to an entire data series will recieve the entire series as `data` instead of an individual datum + * Labels that apply to an entire data series will receive the entire series as `data` instead of an individual datum * prop. */ data?: any[]; @@ -97,7 +97,7 @@ export interface ChartLegendTooltipLabelProps extends VictoryLabelProps { * * Note: This prop should not be set manually. * - * @private + * @private Not intended as public API and subject to change * @hide */ index?: string | number; @@ -109,7 +109,7 @@ export interface ChartLegendTooltipLabelProps extends VictoryLabelProps { /** * The labelPlacement prop is used to specify the placement of labels relative to the data point they represent. * This prop may be given as “vertical”, “parallel” or “perpendicular”. This props is particularly useful in polar - * charts, where it may be desireable to position a label either parallel or perpendicular to its corresponding angle. + * charts, where it may be desirable to position a label either parallel or perpendicular to its corresponding angle. * When this prop is not set, perpendicular label placement will be used for polar charts, and vertical label * placement will be used for cartesian charts. * @@ -157,7 +157,7 @@ export interface ChartLegendTooltipLabelProps extends VictoryLabelProps { * * Note: This prop should not be set manually. * - * @private + * @private Not intended as public API and subject to change * @hide */ polar?: boolean; @@ -172,7 +172,7 @@ export interface ChartLegendTooltipLabelProps extends VictoryLabelProps { * * Note: This prop should not be set manually. * - * @private + * @private Not intended as public API and subject to change * @hide */ scale?: { x?: any; y?: any }; @@ -218,7 +218,7 @@ export interface ChartLegendTooltipLabelProps extends VictoryLabelProps { * * Note: This prop should not be set manually. * - * @private + * @private Not intended as public API and subject to change * @hide */ width?: number; @@ -263,7 +263,7 @@ export const ChartLegendTooltipLabel: React.FunctionComponent { const label = legendData && legendData.length ? legendData[index as any].name : undefined; - return React.cloneElement(legendLabelComponent, { + return cloneElement(legendLabelComponent, { style: getStyle({}), text: label, textAnchor: 'start', @@ -275,7 +275,7 @@ export const ChartLegendTooltipLabel: React.FunctionComponent { const _x = x + (Helpers.evaluateProp(dx, undefined) as number); - return React.cloneElement(valueLabelComponent, { + return cloneElement(valueLabelComponent, { style: getStyle(style), text, textAnchor, @@ -288,10 +288,10 @@ export const ChartLegendTooltipLabel: React.FunctionComponent + {legendLabel} {valueLabel} - + ); }; ChartLegendTooltipLabel.displayName = 'ChartLegendTooltipLabel'; diff --git a/packages/react-charts/src/components/ChartLegendTooltip/__snapshots__/ChartLegendTooltip.test.tsx.snap b/packages/react-charts/src/victory/components/ChartLegendTooltip/__snapshots__/ChartLegendTooltip.test.tsx.snap similarity index 65% rename from packages/react-charts/src/components/ChartLegendTooltip/__snapshots__/ChartLegendTooltip.test.tsx.snap rename to packages/react-charts/src/victory/components/ChartLegendTooltip/__snapshots__/ChartLegendTooltip.test.tsx.snap index ab05c8da2b9..19d42ee3bf2 100644 --- a/packages/react-charts/src/components/ChartLegendTooltip/__snapshots__/ChartLegendTooltip.test.tsx.snap +++ b/packages/react-charts/src/victory/components/ChartLegendTooltip/__snapshots__/ChartLegendTooltip.test.tsx.snap @@ -11,15 +11,15 @@ exports[`allows tooltip via container component 1`] = ` style="height: 100%; width: 100%; user-select: none; pointer-events: none; position: relative;" > Average number of pets @@ -29,7 +29,7 @@ exports[`allows tooltip via container component 1`] = ` @@ -73,7 +73,7 @@ exports[`allows tooltip via container component 1`] = ` @@ -104,7 +104,7 @@ exports[`allows tooltip via container component 1`] = ` @@ -135,7 +135,7 @@ exports[`allows tooltip via container component 1`] = ` @@ -167,7 +167,7 @@ exports[`allows tooltip via container component 1`] = ` @@ -221,7 +221,7 @@ exports[`allows tooltip via container component 1`] = ` @@ -262,7 +262,7 @@ exports[`allows tooltip via container component 1`] = ` @@ -300,12 +300,12 @@ exports[`allows tooltip via container component 1`] = ` @@ -484,7 +484,7 @@ exports[`allows tooltip via container component 1`] = ` @@ -501,7 +501,7 @@ exports[`allows tooltip via container component 1`] = ` @@ -518,7 +518,7 @@ exports[`allows tooltip via container component 1`] = ` @@ -528,11 +528,11 @@ exports[`allows tooltip via container component 1`] = `
diff --git a/packages/react-charts/src/components/ChartLegendTooltip/__snapshots__/ChartLegendTooltipContent.test.tsx.snap b/packages/react-charts/src/victory/components/ChartLegendTooltip/__snapshots__/ChartLegendTooltipContent.test.tsx.snap similarity index 100% rename from packages/react-charts/src/components/ChartLegendTooltip/__snapshots__/ChartLegendTooltipContent.test.tsx.snap rename to packages/react-charts/src/victory/components/ChartLegendTooltip/__snapshots__/ChartLegendTooltipContent.test.tsx.snap diff --git a/packages/react-charts/src/components/ChartLegendTooltip/__snapshots__/ChartLegendTooltipLabel.test.tsx.snap b/packages/react-charts/src/victory/components/ChartLegendTooltip/__snapshots__/ChartLegendTooltipLabel.test.tsx.snap similarity index 75% rename from packages/react-charts/src/components/ChartLegendTooltip/__snapshots__/ChartLegendTooltipLabel.test.tsx.snap rename to packages/react-charts/src/victory/components/ChartLegendTooltip/__snapshots__/ChartLegendTooltipLabel.test.tsx.snap index d74aac8b820..b6832ff72af 100644 --- a/packages/react-charts/src/components/ChartLegendTooltip/__snapshots__/ChartLegendTooltipLabel.test.tsx.snap +++ b/packages/react-charts/src/victory/components/ChartLegendTooltip/__snapshots__/ChartLegendTooltipLabel.test.tsx.snap @@ -16,7 +16,7 @@ exports[`renders component text 1`] = ` @@ -33,7 +33,7 @@ exports[`renders component text 1`] = ` diff --git a/packages/react-charts/src/components/ChartLine/ChartLine.test.tsx b/packages/react-charts/src/victory/components/ChartLine/ChartLine.test.tsx similarity index 97% rename from packages/react-charts/src/components/ChartLine/ChartLine.test.tsx rename to packages/react-charts/src/victory/components/ChartLine/ChartLine.test.tsx index 2ac5f0cc718..aabebe15844 100644 --- a/packages/react-charts/src/components/ChartLine/ChartLine.test.tsx +++ b/packages/react-charts/src/victory/components/ChartLine/ChartLine.test.tsx @@ -1,4 +1,3 @@ -import * as React from 'react'; import { render } from '@testing-library/react'; import { Chart } from '../Chart/Chart'; import { ChartGroup } from '../ChartGroup/ChartGroup'; diff --git a/packages/react-charts/src/components/ChartLine/ChartLine.tsx b/packages/react-charts/src/victory/components/ChartLine/ChartLine.tsx similarity index 98% rename from packages/react-charts/src/components/ChartLine/ChartLine.tsx rename to packages/react-charts/src/victory/components/ChartLine/ChartLine.tsx index 993e682ea48..10cf5ed78c0 100644 --- a/packages/react-charts/src/components/ChartLine/ChartLine.tsx +++ b/packages/react-charts/src/victory/components/ChartLine/ChartLine.tsx @@ -1,4 +1,4 @@ -import * as React from 'react'; +import { cloneElement } from 'react'; import hoistNonReactStatics from 'hoist-non-react-statics'; import { AnimatePropTypeInterface, @@ -128,7 +128,7 @@ export interface ChartLineProps extends VictoryLineProps { * Since ChartLine only renders a single element, the eventKey property is not used. * The eventHandlers object should be given as an object whose keys are standard * event names (i.e. onClick) and whose values are event callbacks. The return value - * of an event handler is used to modify elemnts. The return value should be given + * of an event handler is used to modify elements. The return value should be given * as an object or an array of objects with optional target and eventKey keys, * and a mutation key whose value is a function. The target and eventKey keys * will default to those corresponding to the element the event handler was attached to. @@ -271,7 +271,7 @@ export interface ChartLineProps extends VictoryLineProps { * * Note: This prop should not be set manually. * - * @private + * @private Not intended as public API and subject to change * @hide */ polar?: boolean; @@ -315,7 +315,7 @@ export interface ChartLineProps extends VictoryLineProps { * * Note: This prop should not be set manually. * - * @private + * @private Not intended as public API and subject to change * @hide */ sharedEvents?: { events: any[]; getEventState: Function }; @@ -434,7 +434,7 @@ export const ChartLine: React.FunctionComponent = ({ ...rest }: ChartLineProps) => { // Clone so users can override container props - const container = React.cloneElement(containerComponent, { + const container = cloneElement(containerComponent, { theme, ...containerComponent.props }); diff --git a/packages/react-charts/src/components/ChartLine/__snapshots__/ChartLine.test.tsx.snap b/packages/react-charts/src/victory/components/ChartLine/__snapshots__/ChartLine.test.tsx.snap similarity index 72% rename from packages/react-charts/src/components/ChartLine/__snapshots__/ChartLine.test.tsx.snap rename to packages/react-charts/src/victory/components/ChartLine/__snapshots__/ChartLine.test.tsx.snap index 1394235cf2e..9cd8d583862 100644 --- a/packages/react-charts/src/components/ChartLine/__snapshots__/ChartLine.test.tsx.snap +++ b/packages/react-charts/src/victory/components/ChartLine/__snapshots__/ChartLine.test.tsx.snap @@ -9,7 +9,7 @@ exports[`ChartLine 1`] = ` @@ -39,11 +39,11 @@ exports[`ChartLine 1`] = `
@@ -61,7 +61,7 @@ exports[`ChartLine 2`] = ` @@ -91,11 +91,11 @@ exports[`ChartLine 2`] = `
@@ -113,7 +113,7 @@ exports[`renders component data 1`] = ` @@ -221,7 +221,7 @@ exports[`renders component data 1`] = ` @@ -265,7 +265,7 @@ exports[`renders component data 1`] = ` @@ -296,7 +296,7 @@ exports[`renders component data 1`] = ` @@ -327,7 +327,7 @@ exports[`renders component data 1`] = ` @@ -358,7 +358,7 @@ exports[`renders component data 1`] = ` @@ -389,7 +389,7 @@ exports[`renders component data 1`] = ` @@ -420,7 +420,7 @@ exports[`renders component data 1`] = ` @@ -452,7 +452,7 @@ exports[`renders component data 1`] = ` @@ -496,7 +496,7 @@ exports[`renders component data 1`] = ` @@ -527,7 +527,7 @@ exports[`renders component data 1`] = ` @@ -558,7 +558,7 @@ exports[`renders component data 1`] = ` @@ -586,11 +586,11 @@ exports[`renders component data 1`] = `
diff --git a/packages/react-charts/src/victory/components/ChartLine/examples/ChartLine.md b/packages/react-charts/src/victory/components/ChartLine/examples/ChartLine.md new file mode 100644 index 00000000000..312ff2e3cb9 --- /dev/null +++ b/packages/react-charts/src/victory/components/ChartLine/examples/ChartLine.md @@ -0,0 +1,64 @@ +--- +id: Line chart +section: components +subsection: charts +propComponents: [ + 'Chart', + 'ChartAxis', + 'ChartGroup', + 'ChartLine', + 'ChartVoronoiContainer' +] +hideDarkMode: true +--- + +import { useEffect, useRef, useState } from 'react'; +import { Chart, ChartAxis, ChartGroup, ChartLine, ChartThemeColor, ChartLegendTooltip, ChartVoronoiContainer, createContainer } from '@patternfly/react-charts/victory'; +import { getResizeObserver } from '@patternfly/react-core'; +import { VictoryZoomContainer } from 'victory-zoom-container'; + +## Introduction +Note: PatternFly React charts live in its own package at [@patternfly/react-charts](https://www.npmjs.com/package/@patternfly/react-charts)! + +The examples below are based on the [Victory](https://formidable.com/open-source/victory/docs/victory-chart/) chart library, along with additional functionality, custom components, and theming for PatternFly. This provides a collection of React based components you can use to build PatternFly patterns with consistent markup, styling, and behavior. + +## Examples +### Basic with right aligned legend +```ts file = "ChartLineBasicRightLegend.tsx" + +``` + +### Green with bottom aligned legend + +This demonstrates how to combine cursor and voronoi containers to display tooltips along with a cursor. + +```ts file = "ChartLineGreenBottomLegend.tsx" + +``` + +### Multi-color (unordered) with responsive container + +This demonstrates zoom for the x axis only. + +```ts file = "ChartLineMultiColor.tsx" + +``` + +## Documentation +### Tips +- See Victory's [FAQ](https://formidable.com/open-source/victory/docs/faq) +- For single data points or zero values, you may want to set the `domain` prop +- `ChartLegend` may be used as a standalone component, instead of using `legendData` +- The `theme` and `themeColor` props should be applied at the most top level component +- Use `ChartGroup` to apply theme color scales and other properties to multiple components + +### Note +Currently, the generated documentation below is not able to resolve type definitions from Victory imports. For the +components used in the examples above, Victory pass-thru props are also documented here: + +- For `Chart` props, see [VictoryChart](https://formidable.com/open-source/victory/docs/victory-chart) +- For `ChartAxis` props, see [VictoryAxis](https://formidable.com/open-source/victory/docs/victory-axis) +- For `ChartGroup` props, see [VictoryGroup](https://formidable.com/open-source/victory/docs/victory-group) +- For `ChartLine` props, see [Victoryline](https://formidable.com/open-source/victory/docs/victory-line) +- For `ChartVoronoiContainer` props, see [VictoryVoronoiContainer](https://formidable.com/open-source/victory/docs/victory-voronoi-container) +- For `VictoryZoomContainer` props, see [VictoryZoomContainerline](https://formidable.com/open-source/victory/docs/victory-zoom-container) diff --git a/packages/react-charts/src/victory/components/ChartLine/examples/ChartLineBasicRightLegend.tsx b/packages/react-charts/src/victory/components/ChartLine/examples/ChartLineBasicRightLegend.tsx new file mode 100644 index 00000000000..e90bceb462a --- /dev/null +++ b/packages/react-charts/src/victory/components/ChartLine/examples/ChartLineBasicRightLegend.tsx @@ -0,0 +1,83 @@ +import { Chart, ChartAxis, ChartGroup, ChartLine, ChartVoronoiContainer } from '@patternfly/react-charts/victory'; + +interface PetData { + name?: string; + x?: string; + y?: number; + symbol?: { type: string }; +} + +export const ChartLineBasicRightLegend: 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} + legendOrientation="vertical" + legendPosition="right" + height={250} + maxDomain={{ y: 10 }} + minDomain={{ y: 0 }} + 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/ChartLine/examples/ChartLineGreenBottomLegend.tsx b/packages/react-charts/src/victory/components/ChartLine/examples/ChartLineGreenBottomLegend.tsx new file mode 100644 index 00000000000..3be1539ec5e --- /dev/null +++ b/packages/react-charts/src/victory/components/ChartLine/examples/ChartLineGreenBottomLegend.tsx @@ -0,0 +1,102 @@ +import { + Chart, + ChartAxis, + ChartGroup, + ChartLine, + ChartThemeColor, + ChartLegendTooltip, + createContainer +} from '@patternfly/react-charts/victory'; + +interface PetData { + x?: string; + y?: number; + name?: string; + childName?: string; + symbol?: { type: string }; +} + +export const ChartLineGreenBottomLegend: 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[] = [ + { x: '2015', y: 1 }, + { x: '2016', y: 2 }, + { x: '2017', y: 5 }, + { x: '2018', y: 3 } + ]; + const data2: PetData[] = [ + { x: '2015', y: 2 }, + { x: '2016', y: 1 }, + { x: '2017', y: 7 }, + { x: '2018', y: 4 } + ]; + const data3: PetData[] = [ + { x: '2015', y: 3 }, + { x: '2016', y: 4 }, + { x: '2017', y: 9 }, + { x: '2018', y: 5 } + ]; + const data4: PetData[] = [ + { x: '2015', y: 3 }, + { x: '2016', y: 3 }, + { x: '2017', y: 8 }, + { x: '2018', y: 7 } + ]; + + return ( +
+ `${datum.y}`} + labelComponent={ datum.x} />} + 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.green} + width={450} + > + + + + + + + + + +
+ ); +}; diff --git a/packages/react-charts/src/victory/components/ChartLine/examples/ChartLineMultiColor.tsx b/packages/react-charts/src/victory/components/ChartLine/examples/ChartLineMultiColor.tsx new file mode 100644 index 00000000000..03d44fa757c --- /dev/null +++ b/packages/react-charts/src/victory/components/ChartLine/examples/ChartLineMultiColor.tsx @@ -0,0 +1,103 @@ +import { Chart, ChartAxis, ChartGroup, ChartLine, ChartThemeColor } from '@patternfly/react-charts/victory'; +import { getResizeObserver } from '@patternfly/react-core'; +import { useEffect, useRef, useState } from 'react'; +import { VictoryZoomContainer } from 'victory-zoom-container'; + +interface PetData { + x?: string; + y?: number; + name?: string; + symbol?: { type: string }; +} + +export const ChartLineMultiColor: React.FunctionComponent = () => { + const containerRef = useRef(null); + const [width, setWidth] = useState(0); + + const handleResize = () => { + if (containerRef.current && containerRef.current.clientWidth) { + setWidth(containerRef.current.clientWidth); + } + }; + + useEffect(() => { + const observer = getResizeObserver(containerRef.current, handleResize); + handleResize(); + return () => { + observer(); + }; + }, []); + + 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 ( +
+
+ } + legendData={legendData} + legendPosition="bottom-left" + 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.multiUnordered} + width={width} + > + + + + + + + + + +
+
+ ); +}; diff --git a/packages/react-charts/src/components/ChartPie/ChartPie.test.tsx b/packages/react-charts/src/victory/components/ChartPie/ChartPie.test.tsx similarity index 94% rename from packages/react-charts/src/components/ChartPie/ChartPie.test.tsx rename to packages/react-charts/src/victory/components/ChartPie/ChartPie.test.tsx index 03406cfeb54..0a56a343fb7 100644 --- a/packages/react-charts/src/components/ChartPie/ChartPie.test.tsx +++ b/packages/react-charts/src/victory/components/ChartPie/ChartPie.test.tsx @@ -1,4 +1,3 @@ -import * as React from 'react'; import { render } from '@testing-library/react'; import { ChartPie } from './ChartPie'; diff --git a/packages/react-charts/src/components/ChartPie/ChartPie.tsx b/packages/react-charts/src/victory/components/ChartPie/ChartPie.tsx similarity index 97% rename from packages/react-charts/src/components/ChartPie/ChartPie.tsx rename to packages/react-charts/src/victory/components/ChartPie/ChartPie.tsx index bcf31af1be3..45b47fef7a3 100644 --- a/packages/react-charts/src/components/ChartPie/ChartPie.tsx +++ b/packages/react-charts/src/victory/components/ChartPie/ChartPie.tsx @@ -1,4 +1,4 @@ -import * as React from 'react'; +import { cloneElement, Fragment, useEffect } from 'react'; import hoistNonReactStatics from 'hoist-non-react-statics'; import { AnimatePropTypeInterface, @@ -32,7 +32,6 @@ import { getComputedLegend, getLegendItemsExtraHeight, getLegendMaxTextWidth } f import { getPaddingForSide } from '../ChartUtils/chart-padding'; import { getPatternDefs, useDefaultPatternProps } from '../ChartUtils/chart-patterns'; import { getTheme } from '../ChartUtils/chart-theme'; -import { useEffect } from 'react'; import { ChartPoint } from '../ChartPoint/ChartPoint'; import { ChartLabel } from '../ChartLabel/ChartLabel'; @@ -159,7 +158,7 @@ export interface ChartPieProps extends VictoryPieProps { * events. The eventKey may optionally be used to select a single element by index rather than * an entire set. The eventHandlers object should be given as an object whose keys are standard * event names (i.e. onClick) and whose values are event callbacks. The return value - * of an event handler is used to modify elemnts. The return value should be given + * of an event handler is used to modify elements. The return value should be given * as an object or an array of objects with optional target and eventKey keys, * and a mutation key whose value is a function. The target and eventKey keys * will default to those corresponding to the element the event handler was attached to. @@ -384,7 +383,7 @@ export interface ChartPieProps extends VictoryPieProps { * * Note: This prop should not be set manually. * - * @private + * @private Not intended as public API and subject to change * @hide */ patternUnshiftIndex?: number; @@ -400,7 +399,7 @@ export interface ChartPieProps extends VictoryPieProps { * * Note: This prop should not be set manually. * - * @private + * @private Not intended as public API and subject to change * @hide */ sharedEvents?: { events: any[]; getEventState: Function }; @@ -586,7 +585,7 @@ export const ChartPie: React.FunctionComponent = ({ legendXOffset = getLegendMaxTextWidth(legendData, theme); } - const legend = React.cloneElement(legendComponent, { + const legend = cloneElement(legendComponent, { colorScale, data: legendData, ...(name && { name: `${name}-${(legendComponent as any).type.displayName}` }), @@ -596,14 +595,14 @@ export const ChartPie: React.FunctionComponent = ({ themeColor, ...(legendDirection === 'rtl' && { dataComponent: legendComponent.props.dataComponent ? ( - React.cloneElement(legendComponent.props.dataComponent, { transform: `translate(${legendXOffset})` }) + cloneElement(legendComponent.props.dataComponent, { transform: `translate(${legendXOffset})` }) ) : ( ) }), ...(legendDirection === 'rtl' && { labelComponent: legendComponent.props.labelComponent ? ( - React.cloneElement(legendComponent.props.labelComponent, { direction: 'rtl', dx: legendXOffset - 30 }) + cloneElement(legendComponent.props.labelComponent, { direction: 'rtl', dx: legendXOffset - 30 }) ) : ( ) @@ -631,7 +630,7 @@ export const ChartPie: React.FunctionComponent = ({ // Clone so users can override container props const container = standalone - ? React.cloneElement( + ? cloneElement( containerComponent, { desc: ariaDesc, @@ -664,13 +663,13 @@ export const ChartPie: React.FunctionComponent = ({ }, [computedLegend, legendAllowWrap, theme, width]); return standalone ? ( - {container} + {container} ) : ( - + {chart} {computedLegend} {isPatternDefs && getPatternDefs({ patternId, colorScale: defaultColorScale, patternUnshiftIndex })} - + ); }; ChartPie.displayName = 'ChartPie'; diff --git a/packages/react-charts/src/components/ChartPie/__snapshots__/ChartPie.test.tsx.snap b/packages/react-charts/src/victory/components/ChartPie/__snapshots__/ChartPie.test.tsx.snap similarity index 74% rename from packages/react-charts/src/components/ChartPie/__snapshots__/ChartPie.test.tsx.snap rename to packages/react-charts/src/victory/components/ChartPie/__snapshots__/ChartPie.test.tsx.snap index bff1d8f86c6..7a4c38a61d8 100644 --- a/packages/react-charts/src/components/ChartPie/__snapshots__/ChartPie.test.tsx.snap +++ b/packages/react-charts/src/victory/components/ChartPie/__snapshots__/ChartPie.test.tsx.snap @@ -4,12 +4,12 @@ exports[`ChartPie 1`] = `
@@ -18,45 +18,45 @@ exports[`ChartPie 1`] = ` d="M5.8170722959499274e-15,-95A95,95,0,0,1,61.06482292022124,-72.7742220963029L0,0Z" role="presentation" shape-rendering="auto" - style="fill: var(--pf-v6-chart-theme--blue--ColorScale--100, #0066cc); padding: 8px; stroke: var(--pf-v6-chart-pie--data--stroke--Color, transparent); stroke-width: 1;" + style="fill: var(--pf-v6-chart-theme--blue--ColorScale--100, #0066cc); padding: 8px; stroke: var(--pf-v6-chart-pie--data--stroke--Color, #ffffff); stroke-width: var(--pf-v6-chart-pie--data--stroke--Width, 0px);" transform="translate(115, 115)" />
@@ -69,12 +69,12 @@ exports[`ChartPie 2`] = `
@@ -83,45 +83,45 @@ exports[`ChartPie 2`] = ` d="M5.8170722959499274e-15,-95A95,95,0,0,1,61.06482292022124,-72.7742220963029L0,0Z" role="presentation" shape-rendering="auto" - style="fill: var(--pf-v6-chart-theme--blue--ColorScale--100, #0066cc); padding: 8px; stroke: var(--pf-v6-chart-pie--data--stroke--Color, transparent); stroke-width: 1;" + style="fill: var(--pf-v6-chart-theme--blue--ColorScale--100, #0066cc); padding: 8px; stroke: var(--pf-v6-chart-pie--data--stroke--Color, #ffffff); stroke-width: var(--pf-v6-chart-pie--data--stroke--Width, 0px);" transform="translate(115, 115)" />
@@ -134,12 +134,12 @@ exports[`renders component data 1`] = `
@@ -148,31 +148,31 @@ exports[`renders component data 1`] = ` d="M4.898587196589413e-15,-80A80,80,0,0,1,64.7213595499958,47.022820183397855L0,0Z" role="presentation" shape-rendering="auto" - style="fill: var(--pf-v6-chart-theme--blue--ColorScale--100, #0066cc); padding: 8px; stroke: var(--pf-v6-chart-pie--data--stroke--Color, transparent); stroke-width: 1;" + style="fill: var(--pf-v6-chart-theme--blue--ColorScale--100, #0066cc); padding: 8px; stroke: var(--pf-v6-chart-pie--data--stroke--Color, #ffffff); stroke-width: var(--pf-v6-chart-pie--data--stroke--Width, 0px);" transform="translate(100, 100)" />
diff --git a/packages/react-charts/src/victory/components/ChartPie/examples/ChartPie.md b/packages/react-charts/src/victory/components/ChartPie/examples/ChartPie.md new file mode 100644 index 00000000000..2c6fb564b1d --- /dev/null +++ b/packages/react-charts/src/victory/components/ChartPie/examples/ChartPie.md @@ -0,0 +1,48 @@ +--- +id: Pie chart +section: components +subsection: charts +propComponents: ['ChartPie'] +hideDarkMode: true +--- + +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'; + +## Introduction +Note: PatternFly React charts live in its own package at [@patternfly/react-charts](https://www.npmjs.com/package/@patternfly/react-charts)! + +The examples below are based on the [Victory](https://formidable.com/open-source/victory/docs/victory-chart/) chart library, along with additional functionality, custom components, and theming for PatternFly. This provides a collection of React based components you can use to build PatternFly patterns with consistent markup, styling, and behavior. + +## Examples +### Basic with right aligned legend +```ts file = "ChartPieBasicRightLegend.tsx" + +``` + +### Multi-color (ordered) with bottom aligned legend +```ts file = "ChartPieMultiColorBottomLegend.tsx" + +``` + +### Custom color scale + +This demonstrates how to apply a custom color scale. + +```ts file = "ChartPieCustomColorScale.tsx" + +``` + +## Documentation +### Tips +- See Victory's [FAQ](https://formidable.com/open-source/victory/docs/faq) +- For single data points or zero values, you may want to set the `domain` prop +- `ChartLegend` may be used as a standalone component, instead of using `legendData` + +### Note +Currently, the generated documentation below is not able to resolve type definitions from Victory imports. For the +components used in the examples above, Victory pass-thru props are also documented here: + +- For `ChartPie` props, see [VictoryPie](https://formidable.com/open-source/victory/docs/victory-pie) 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/components/ChartPoint/ChartPoint.test.tsx b/packages/react-charts/src/victory/components/ChartPoint/ChartPoint.test.tsx similarity index 96% rename from packages/react-charts/src/components/ChartPoint/ChartPoint.test.tsx rename to packages/react-charts/src/victory/components/ChartPoint/ChartPoint.test.tsx index 7ffa84bef7a..a478e918757 100644 --- a/packages/react-charts/src/components/ChartPoint/ChartPoint.test.tsx +++ b/packages/react-charts/src/victory/components/ChartPoint/ChartPoint.test.tsx @@ -1,4 +1,3 @@ -import * as React from 'react'; import { render } from '@testing-library/react'; import { ChartLabel } from '../ChartLabel/ChartLabel'; import { ChartLegend } from '../ChartLegend/ChartLegend'; diff --git a/packages/react-charts/src/components/ChartPoint/ChartPoint.tsx b/packages/react-charts/src/victory/components/ChartPoint/ChartPoint.tsx similarity index 98% rename from packages/react-charts/src/components/ChartPoint/ChartPoint.tsx rename to packages/react-charts/src/victory/components/ChartPoint/ChartPoint.tsx index 8768f990c66..5bbe892c1cb 100644 --- a/packages/react-charts/src/components/ChartPoint/ChartPoint.tsx +++ b/packages/react-charts/src/victory/components/ChartPoint/ChartPoint.tsx @@ -1,4 +1,4 @@ -import * as React from 'react'; +import { cloneElement } from 'react'; import { Helpers, Path } from 'victory-core'; import { PathHelpers, PathHelpersInterface } from './path-helpers'; @@ -166,7 +166,7 @@ export const ChartPoint: React.FunctionComponent = ({ ...rest }; - return React.cloneElement(pathComponent, { + return cloneElement(pathComponent, { className, clipPath, d: getPath(props), diff --git a/packages/react-charts/src/victory/components/ChartPoint/__snapshots__/ChartPoint.test.tsx.snap b/packages/react-charts/src/victory/components/ChartPoint/__snapshots__/ChartPoint.test.tsx.snap new file mode 100644 index 00000000000..2b5bd7bb4b2 --- /dev/null +++ b/packages/react-charts/src/victory/components/ChartPoint/__snapshots__/ChartPoint.test.tsx.snap @@ -0,0 +1,304 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`ChartPoint 1`] = ` + +
+ + + + + + + Series 1 + + + + + Series 2 + + + +
+ +
+
+
+`; + +exports[`ChartPoint 2`] = ` + +
+ + + + + + + Series 1 + + + + + Series 2 + + + +
+ +
+
+
+`; + +exports[`renders component data 1`] = ` + +
+ + + + + + + Average number of pets + + + + + Cats + + + + + Dogs + + + +
+ +
+
+
+`; diff --git a/packages/react-charts/src/components/ChartPoint/assets/Eyecon.svg b/packages/react-charts/src/victory/components/ChartPoint/assets/Eyecon.svg similarity index 100% rename from packages/react-charts/src/components/ChartPoint/assets/Eyecon.svg rename to packages/react-charts/src/victory/components/ChartPoint/assets/Eyecon.svg diff --git a/packages/react-charts/src/components/ChartPoint/path-helpers.ts b/packages/react-charts/src/victory/components/ChartPoint/path-helpers.ts similarity index 100% rename from packages/react-charts/src/components/ChartPoint/path-helpers.ts rename to packages/react-charts/src/victory/components/ChartPoint/path-helpers.ts diff --git a/packages/react-charts/src/components/ChartScatter/ChartScatter.test.tsx b/packages/react-charts/src/victory/components/ChartScatter/ChartScatter.test.tsx similarity index 97% rename from packages/react-charts/src/components/ChartScatter/ChartScatter.test.tsx rename to packages/react-charts/src/victory/components/ChartScatter/ChartScatter.test.tsx index 841d25a4c67..765735b6623 100644 --- a/packages/react-charts/src/components/ChartScatter/ChartScatter.test.tsx +++ b/packages/react-charts/src/victory/components/ChartScatter/ChartScatter.test.tsx @@ -1,4 +1,3 @@ -import * as React from 'react'; import { render } from '@testing-library/react'; import { Chart } from '../Chart/Chart'; import { ChartGroup } from '../ChartGroup/ChartGroup'; diff --git a/packages/react-charts/src/components/ChartScatter/ChartScatter.tsx b/packages/react-charts/src/victory/components/ChartScatter/ChartScatter.tsx similarity index 98% rename from packages/react-charts/src/components/ChartScatter/ChartScatter.tsx rename to packages/react-charts/src/victory/components/ChartScatter/ChartScatter.tsx index 0727ccb175c..60256cdef8c 100644 --- a/packages/react-charts/src/components/ChartScatter/ChartScatter.tsx +++ b/packages/react-charts/src/victory/components/ChartScatter/ChartScatter.tsx @@ -1,4 +1,4 @@ -import * as React from 'react'; +import { cloneElement } from 'react'; import hoistNonReactStatics from 'hoist-non-react-statics'; import { AnimatePropTypeInterface, @@ -131,7 +131,7 @@ export interface ChartScatterProps extends VictoryScatterProps { * Since ChartScatter only renders a single element, the eventKey property is not used. * The eventHandlers object should be given as an object whose keys are standard * event names (i.e. onClick) and whose values are event callbacks. The return value - * of an event handler is used to modify elemnts. The return value should be given + * of an event handler is used to modify elements. The return value should be given * as an object or an array of objects with optional target and eventKey keys, * and a mutation key whose value is a function. The target and eventKey keys * will default to those corresponding to the element the event handler was attached to. @@ -273,7 +273,7 @@ export interface ChartScatterProps extends VictoryScatterProps { * * Note: This prop should not be set manually. * - * @private + * @private Not intended as public API and subject to change * @hide */ polar?: boolean; @@ -317,7 +317,7 @@ export interface ChartScatterProps extends VictoryScatterProps { * * Note: This prop should not be set manually. * - * @private + * @private Not intended as public API and subject to change * @hide */ sharedEvents?: { events: any[]; getEventState: Function }; @@ -449,7 +449,7 @@ export const ChartScatter: React.FunctionComponent = ({ ...rest }: ChartScatterProps) => { // Clone so users can override container props - const container = React.cloneElement(containerComponent, { + const container = cloneElement(containerComponent, { theme, ...containerComponent.props }); diff --git a/packages/react-charts/src/components/ChartScatter/__snapshots__/ChartScatter.test.tsx.snap b/packages/react-charts/src/victory/components/ChartScatter/__snapshots__/ChartScatter.test.tsx.snap similarity index 87% rename from packages/react-charts/src/components/ChartScatter/__snapshots__/ChartScatter.test.tsx.snap rename to packages/react-charts/src/victory/components/ChartScatter/__snapshots__/ChartScatter.test.tsx.snap index 50b58ebde06..c7d7fcc364c 100644 --- a/packages/react-charts/src/components/ChartScatter/__snapshots__/ChartScatter.test.tsx.snap +++ b/packages/react-charts/src/victory/components/ChartScatter/__snapshots__/ChartScatter.test.tsx.snap @@ -9,7 +9,7 @@ exports[`ChartScatter 1`] = ` @@ -476,11 +476,11 @@ exports[`ChartScatter 1`] = `
@@ -498,7 +498,7 @@ exports[`ChartScatter 2`] = ` @@ -965,11 +965,11 @@ exports[`ChartScatter 2`] = `
@@ -987,7 +987,7 @@ exports[`renders component data 1`] = ` @@ -1151,7 +1151,7 @@ exports[`renders component data 1`] = ` @@ -1195,7 +1195,7 @@ exports[`renders component data 1`] = ` @@ -1226,7 +1226,7 @@ exports[`renders component data 1`] = ` @@ -1257,7 +1257,7 @@ exports[`renders component data 1`] = ` @@ -1288,7 +1288,7 @@ exports[`renders component data 1`] = ` @@ -1319,7 +1319,7 @@ exports[`renders component data 1`] = ` @@ -1350,7 +1350,7 @@ exports[`renders component data 1`] = ` @@ -1382,7 +1382,7 @@ exports[`renders component data 1`] = ` @@ -1426,7 +1426,7 @@ exports[`renders component data 1`] = ` @@ -1457,7 +1457,7 @@ exports[`renders component data 1`] = ` @@ -1488,7 +1488,7 @@ exports[`renders component data 1`] = ` @@ -1519,7 +1519,7 @@ exports[`renders component data 1`] = ` @@ -1550,7 +1550,7 @@ exports[`renders component data 1`] = ` @@ -1581,7 +1581,7 @@ exports[`renders component data 1`] = ` @@ -1609,11 +1609,11 @@ exports[`renders component data 1`] = `
diff --git a/packages/react-charts/src/victory/components/ChartScatter/examples/ChartScatter.md b/packages/react-charts/src/victory/components/ChartScatter/examples/ChartScatter.md new file mode 100644 index 00000000000..47322e03200 --- /dev/null +++ b/packages/react-charts/src/victory/components/ChartScatter/examples/ChartScatter.md @@ -0,0 +1,71 @@ +--- +id: Scatter chart +section: components +subsection: charts +propComponents: [ +'Chart', +'ChartArea', +'ChartAxis', +'ChartGroup', +'ChartLine', +'ChartScatter', +'ChartVoronoiContainer' +] +hideDarkMode: true +--- + +import { +Chart, +ChartArea, +ChartAxis, +ChartGroup, +ChartLine, +ChartScatter, +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)! + +The examples below are based on the [Victory](https://formidable.com/open-source/victory/docs/victory-chart/) chart library, along with additional functionality, custom components, and theming for PatternFly. This provides a collection of React based components you can use to build PatternFly patterns with consistent markup, styling, and behavior. + +## Examples +### Basic +```ts file = "ChartScatterBasic.tsx" + +``` + +### Line chart + +This demonstrates how to add interactive data points to a line chart. + +```ts file = "ChartScatterLineChart.tsx" + +``` + +### Area chart + +This demonstrates how to add interactive data points to an area chart. + +```ts file = "ChartScatterAreaChart.tsx" + +``` + +## Documentation + +- For single data points or zero values, you may want to set the `domain` prop. See Victory's FAQ + +### Note +Currently, the generated documentation below is not able to resolve type definitions from Victory imports. For the +components used in the examples above, Victory pass-thru props are also documented here: + +- For `Chart` props, see [VictoryChart](https://formidable.com/open-source/victory/docs/victory-chart) +- For `ChartArea` props, see [VictoryArea](https://formidable.com/open-source/victory/docs/victory-area) +- For `ChartAxis` props, see [VictoryAxis](https://formidable.com/open-source/victory/docs/victory-axis) +- For `ChartGroup` props, see [VictoryGroup](https://formidable.com/open-source/victory/docs/victory-group) +- For `ChartLine` props, see [VictoryLine](https://formidable.com/open-source/victory/docs/victory-line) +- For `ChartScatter` props, see [VictoryScatter](https://formidable.com/open-source/victory/docs/victory-scatter) +- For `ChartVoronoiContainer` props, see [VictoryVoronoiContainer](https://formidable.com/open-source/victory/docs/victory-voronoi-container) 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/components/ChartStack/ChartStack.test.tsx b/packages/react-charts/src/victory/components/ChartStack/ChartStack.test.tsx similarity index 97% rename from packages/react-charts/src/components/ChartStack/ChartStack.test.tsx rename to packages/react-charts/src/victory/components/ChartStack/ChartStack.test.tsx index 4f546e8900b..0b36c2836f1 100644 --- a/packages/react-charts/src/components/ChartStack/ChartStack.test.tsx +++ b/packages/react-charts/src/victory/components/ChartStack/ChartStack.test.tsx @@ -1,4 +1,3 @@ -import * as React from 'react'; import { render } from '@testing-library/react'; import { Chart } from '../Chart/Chart'; import { ChartBar } from '../ChartBar/ChartBar'; diff --git a/packages/react-charts/src/components/ChartStack/ChartStack.tsx b/packages/react-charts/src/victory/components/ChartStack/ChartStack.tsx similarity index 98% rename from packages/react-charts/src/components/ChartStack/ChartStack.tsx rename to packages/react-charts/src/victory/components/ChartStack/ChartStack.tsx index c22c9dec967..51074b31ba8 100644 --- a/packages/react-charts/src/components/ChartStack/ChartStack.tsx +++ b/packages/react-charts/src/victory/components/ChartStack/ChartStack.tsx @@ -1,4 +1,4 @@ -import * as React from 'react'; +import { cloneElement } from 'react'; import hoistNonReactStatics from 'hoist-non-react-statics'; import { AnimatePropTypeInterface, @@ -61,7 +61,7 @@ export interface ChartStackProps extends VictoryStackProps { * these values for x and y. When categories are not given as an object * When this prop is set on a wrapper component, it will dictate the categories of * its the children. If this prop is not set, any categories on child component - * or catigorical data, will be merged to create a shared set of categories. + * or categorical data, will be merged to create a shared set of categories. * * @propType string[] | { x: string[], y: string[] } * @example ["dogs", "cats", "mice"] @@ -138,7 +138,7 @@ export interface ChartStackProps extends VictoryStackProps { * may optionally be used to select a single element by index or eventKey rather than * an entire set. The eventHandlers object should be given as an object whose keys are standard * event names (i.e. onClick) and whose values are event callbacks. The return value - * of an event handler is used to modify elemnts. The return value should be given + * of an event handler is used to modify elements. The return value should be given * as an object or an array of objects with optional target and eventKey and childName keys, * and a mutation key whose value is a function. The target and eventKey and childName keys * will default to those corresponding to the element the event handler was attached to. @@ -298,7 +298,7 @@ export interface ChartStackProps extends VictoryStackProps { * * Note: This prop should not be set manually. * - * @private + * @private Not intended as public API and subject to change * @hide */ polar?: boolean; @@ -337,7 +337,7 @@ export interface ChartStackProps extends VictoryStackProps { * * Note: This prop should not be set manually. * - * @private + * @private Not intended as public API and subject to change * @hide */ sharedEvents?: { events: any[]; getEventState: Function }; @@ -417,7 +417,7 @@ export const ChartStack: React.FunctionComponent = ({ ...rest }: ChartStackProps) => { // Clone so users can override container props - const container = React.cloneElement(containerComponent, { + const container = cloneElement(containerComponent, { desc: ariaDesc, title: ariaTitle, theme, diff --git a/packages/react-charts/src/components/ChartStack/__snapshots__/ChartStack.test.tsx.snap b/packages/react-charts/src/victory/components/ChartStack/__snapshots__/ChartStack.test.tsx.snap similarity index 75% rename from packages/react-charts/src/components/ChartStack/__snapshots__/ChartStack.test.tsx.snap rename to packages/react-charts/src/victory/components/ChartStack/__snapshots__/ChartStack.test.tsx.snap index 70efc854759..c0e8fdf17f6 100644 --- a/packages/react-charts/src/components/ChartStack/__snapshots__/ChartStack.test.tsx.snap +++ b/packages/react-charts/src/victory/components/ChartStack/__snapshots__/ChartStack.test.tsx.snap @@ -9,16 +9,16 @@ exports[`ChartStack 1`] = `
@@ -36,16 +36,16 @@ exports[`ChartStack 2`] = `
@@ -63,7 +63,7 @@ exports[`renders component data 1`] = ` @@ -84,7 +84,7 @@ A 0 0 0 0 1, 85, 125.86206896551724 index="0" role="presentation" shape-rendering="auto" - style="fill: var(--pf-v6-chart-theme--blue--ColorScale--400, #4394e5); stroke: var(--pf-v6-chart-bar--data--stroke, none); stroke-width: 1; padding: 8px;" + style="fill: var(--pf-v6-chart-theme--blue--ColorScale--400, #4394e5); stroke: var(--pf-v6-chart-bar--data--stroke, #ffffff); stroke-width: 1; padding: 8px;" /> @@ -331,7 +331,7 @@ A 0 0 0 0 1, 229.99999999999997, 150 @@ -375,7 +375,7 @@ A 0 0 0 0 1, 229.99999999999997, 150 @@ -406,7 +406,7 @@ A 0 0 0 0 1, 229.99999999999997, 150 @@ -437,7 +437,7 @@ A 0 0 0 0 1, 229.99999999999997, 150 @@ -469,7 +469,7 @@ A 0 0 0 0 1, 229.99999999999997, 150 @@ -513,7 +513,7 @@ A 0 0 0 0 1, 229.99999999999997, 150 @@ -544,7 +544,7 @@ A 0 0 0 0 1, 229.99999999999997, 150 @@ -575,7 +575,7 @@ A 0 0 0 0 1, 229.99999999999997, 150 @@ -606,7 +606,7 @@ A 0 0 0 0 1, 229.99999999999997, 150 @@ -634,11 +634,11 @@ A 0 0 0 0 1, 229.99999999999997, 150
diff --git a/packages/react-charts/src/victory/components/ChartStack/examples/ChartStack.md b/packages/react-charts/src/victory/components/ChartStack/examples/ChartStack.md new file mode 100644 index 00000000000..10874b7b437 --- /dev/null +++ b/packages/react-charts/src/victory/components/ChartStack/examples/ChartStack.md @@ -0,0 +1,84 @@ +--- +id: Stack chart +section: components +subsection: charts +propComponents: [ + 'Chart', + 'ChartArea', + 'ChartBar', + 'ChartStack', + 'ChartTooltip' +] +hideDarkMode: true +--- + +import { + Chart, + ChartArea, + ChartAxis, + ChartBar, + ChartStack, + ChartLegendTooltip, + ChartThemeColor, + ChartTooltip, + ChartVoronoiContainer, + 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)! + +The examples below are based on the [Victory](https://formidable.com/open-source/victory/docs/victory-chart/) chart library, along with additional functionality, custom components, and theming for PatternFly. This provides a collection of React based components you can use to build PatternFly patterns with consistent markup, styling, and behavior. + +## Examples +### Basic with right aligned legend +```ts file = "ChartStackBasicRightLegend.tsx" + +``` + +### Horizontal with bottom aligned legend +```ts file = "ChartStackBottomLegend.tsx" + +``` + +### Multi-color (ordered) horizontal with bottom aligned legend + +This demonstrates an alternate way of applying tooltips using data labels. + +```ts file = "ChartStackMultiColorOrdered.tsx" + +``` + +### Monthly data with responsive container +```ts file = "ChartStackMonthlyResponsive.tsx" + +``` + +### Multi-color (unordered) responsive container + +This demonstrates monthly data with a bottom aligned legend and responsiveness for mobile. + +```ts file = "ChartStackMultiColorUnordered.tsx" + +``` + +## Documentation +### Tips +- See Victory's [FAQ](https://formidable.com/open-source/victory/docs/faq) +- For single data points or zero values, you may want to set the `domain` prop +- `ChartLegend` may be used as a standalone component, instead of using `legendData` +- Themes are inherited, so a default theme may override `themeColor` for a child component +- The `theme` and `themeColor` props should be applied at the most top level component + +### Note +Currently, the generated documentation below is not able to resolve type definitions from Victory imports. For the +components used in the examples above, Victory pass-thru props are also documented here: + +- For `Chart` props, see [VictoryChart](https://formidable.com/open-source/victory/docs/victory-chart) +- For `ChartArea` props, see [VictoryArea](https://formidable.com/open-source/victory/docs/victory-area) +- For `ChartAxis` props, see [VictoryAxis](https://formidable.com/open-source/victory/docs/victory-axis) +- For `ChartBar` props, see [VictoryBar](https://formidable.com/open-source/victory/docs/victory-bar) +- For `ChartStack` props, see [VictoryStack](https://formidable.com/open-source/victory/docs/victory-stack) +- For `ChartTooltip` props, see [VictoryTooltip](https://formidable.com/open-source/victory/docs/victory-tooltip) 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/components/ChartTheme/ChartStyles.ts b/packages/react-charts/src/victory/components/ChartTheme/ChartStyles.ts similarity index 69% rename from packages/react-charts/src/components/ChartTheme/ChartStyles.ts rename to packages/react-charts/src/victory/components/ChartTheme/ChartStyles.ts index 186d1b1d6e8..06af3473a18 100644 --- a/packages/react-charts/src/components/ChartTheme/ChartStyles.ts +++ b/packages/react-charts/src/victory/components/ChartTheme/ChartStyles.ts @@ -8,42 +8,49 @@ import { ScatterStyles } from './styles/scatter-styles'; /** * Common styles - * @private + * + * @private Not intended as public API and subject to change */ export const ChartCommonStyles = CommonStyles; /** * Bullet styles - * @private + * + * @private Not intended as public API and subject to change */ export const ChartBulletStyles = BulletStyles; /** * Legend tooltip styles - * @private + * + * @private Not intended as public API and subject to change */ export const ChartBoxPlotTooltipStyles = BoxPlotTooltipStyles; /** * Donut styles - * @private + * + * @private Not intended as public API and subject to change */ export const ChartDonutStyles = DonutStyles; /** * Donut utilization styles - * @private + * + * @private Not intended as public API and subject to change */ export const ChartDonutUtilizationStyles = DonutUtilizationStyles; /** * Legend tooltip styles - * @private + * + * @private Not intended as public API and subject to change */ export const ChartLegendTooltipStyles = LegendTooltipStyles; /** * Scatter styles - * @private + * + * @private Not intended as public API and subject to change */ export const ChartScatterStyles = ScatterStyles; diff --git a/packages/react-charts/src/components/ChartTheme/ChartTheme.ts b/packages/react-charts/src/victory/components/ChartTheme/ChartTheme.ts similarity index 91% rename from packages/react-charts/src/components/ChartTheme/ChartTheme.ts rename to packages/react-charts/src/victory/components/ChartTheme/ChartTheme.ts index ad61b6d420f..3bc3a3ac788 100644 --- a/packages/react-charts/src/components/ChartTheme/ChartTheme.ts +++ b/packages/react-charts/src/victory/components/ChartTheme/ChartTheme.ts @@ -2,8 +2,8 @@ import { VictoryThemeDefinition } from 'victory-core'; /** * Chart component theme definition - * @private - * @beta + * + * @private Not intended as public API and subject to change */ export interface ChartComponentThemeDefinitionInterface { axis?: VictoryThemeDefinition; @@ -43,13 +43,14 @@ export interface ChartThemeDefinitionInterface extends VictoryThemeDefinition {} /** * Chart theme definition + * * @public */ export type ChartThemeDefinition = ChartThemeDefinitionInterface; /** * Chart component theme definition - * @private - * @beta + * + * @private Not intended as public API and subject to change */ export type ChartComponentThemeDefinition = ChartComponentThemeDefinitionInterface; diff --git a/packages/react-charts/src/components/ChartTheme/ChartThemeColor.ts b/packages/react-charts/src/victory/components/ChartTheme/ChartThemeColor.ts similarity index 100% rename from packages/react-charts/src/components/ChartTheme/ChartThemeColor.ts rename to packages/react-charts/src/victory/components/ChartTheme/ChartThemeColor.ts diff --git a/packages/react-charts/src/components/ChartTheme/ChartThemeTypes.ts b/packages/react-charts/src/victory/components/ChartTheme/ChartThemeTypes.ts similarity index 73% rename from packages/react-charts/src/components/ChartTheme/ChartThemeTypes.ts rename to packages/react-charts/src/victory/components/ChartTheme/ChartThemeTypes.ts index a9659051ed2..4fd0a3d5fa7 100644 --- a/packages/react-charts/src/components/ChartTheme/ChartThemeTypes.ts +++ b/packages/react-charts/src/victory/components/ChartTheme/ChartThemeTypes.ts @@ -3,13 +3,14 @@ import { BaseComponentTheme, BaseTheme } from './themes/base-theme'; /** * Base theme - * @private + * + * @private Not intended as public API and subject to change */ export const ChartBaseTheme: ChartThemeDefinition = BaseTheme; /** * Base component theme - * @private - * @beta + * + * @private Not intended as public API and subject to change */ export const ChartBaseComponentTheme: ChartComponentThemeDefinition = BaseComponentTheme; diff --git a/packages/react-charts/src/victory/components/ChartTheme/examples/ChartTheme.md b/packages/react-charts/src/victory/components/ChartTheme/examples/ChartTheme.md new file mode 100644 index 00000000000..04d7276771d --- /dev/null +++ b/packages/react-charts/src/victory/components/ChartTheme/examples/ChartTheme.md @@ -0,0 +1,94 @@ +--- +id: Colors for charts +section: components +subsection: charts +hideDarkMode: true +--- + +import { + Chart, + ChartArea, + ChartAxis, + ChartBar, + ChartDonut, + ChartGroup, + ChartLegend, + ChartLine, + ChartStack, + ChartThemeColor, + ChartThreshold, + ChartTooltip, + 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'; +import chart_color_purple_300 from '@patternfly/react-tokens/dist/esm/chart_color_purple_300'; + +## Introduction +Note: PatternFly React charts live in its own package at [@patternfly/react-charts](https://www.npmjs.com/package/@patternfly/react-charts)! + +The examples below are based on the [Victory](https://formidable.com/open-source/victory/docs/victory-chart/) chart library, along with additional functionality, custom components, and theming for PatternFly. This provides a collection of React based components you can use to build PatternFly patterns with consistent markup, styling, and behavior. + +## Examples +### Green + +This demonstrates how to apply basic theme colors. + +```ts file = "ChartThemeGreen.tsx" + +``` + +### Multi-color (ordered) + +This demonstrates how to apply theme colors for ordered charts like bar, donut, pie, and stack. + +```ts file = "ChartThemeMultiColorOrdered.tsx" + +``` + +### Multi color (unordered) + +This demonstrates how to apply theme colors for unordered charts like area, line, and sparkline. + +```ts file = "ChartThemeMultiColorUnordered.tsx" + +``` + +### Custom color scale + +This demonstrates an alternate way of applying a custom color scale and fill colors to individual charts. + +```ts file = "ChartThemeCustomColorScale.tsx" + +``` + +### Custom stroke color + +This demonstrates an alternate way of applying custom stroke and fill colors to a threshold chart. + +```ts file = "ChartThemeCustomStrokeColor.tsx" + +``` + +### Custom theme + +This demonstrates custom theme properties, which may be applied across multiple charts. + +```ts file = "ChartThemeCustomTheme.tsx" + +``` + +## Documentation + +### Tips +- See Victory's [FAQ](https://formidable.com/open-source/victory/docs/faq) +- The `theme` and `themeColor` props should be applied at the most top level component +- Use `ChartGroup` to apply theme color scales and other properties to multiple components + +### Note +Currently, the generated documentation below is not able to resolve type definitions from Victory imports. For the components used in the examples above, Victory pass-thru props are also documented here: + +- For theme props, see [VictoryTheme](https://formidable.com/open-source/victory/docs/victory-theme) 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/components/ChartTheme/styles/box-plot-tooltip-styles.ts b/packages/react-charts/src/victory/components/ChartTheme/styles/box-plot-tooltip-styles.ts similarity index 53% rename from packages/react-charts/src/components/ChartTheme/styles/box-plot-tooltip-styles.ts rename to packages/react-charts/src/victory/components/ChartTheme/styles/box-plot-tooltip-styles.ts index fe488256179..be0f751bc27 100644 --- a/packages/react-charts/src/components/ChartTheme/styles/box-plot-tooltip-styles.ts +++ b/packages/react-charts/src/victory/components/ChartTheme/styles/box-plot-tooltip-styles.ts @@ -1,10 +1,10 @@ -/* eslint-disable camelcase */ -import global_font_weight_heading_bold from '@patternfly/react-tokens/dist/esm/global_font_weight_heading_bold'; +import t_global_font_weight_heading_bold from '@patternfly/react-tokens/dist/esm/t_global_font_weight_heading_bold'; import chart_voronoi_labels_Fill from '@patternfly/react-tokens/dist/esm/chart_voronoi_labels_Fill'; /** * Box plot tooltip styles - * @private + * + * @private Not intended as public API and subject to change */ export const BoxPlotTooltipStyles = { flyout: { @@ -12,6 +12,6 @@ export const BoxPlotTooltipStyles = { }, label: { fill: chart_voronoi_labels_Fill.var, - fontWeight: global_font_weight_heading_bold.value + fontWeight: t_global_font_weight_heading_bold.value } as any }; diff --git a/packages/react-charts/src/components/ChartTheme/styles/bullet-styles.ts b/packages/react-charts/src/victory/components/ChartTheme/styles/bullet-styles.ts similarity index 97% rename from packages/react-charts/src/components/ChartTheme/styles/bullet-styles.ts rename to packages/react-charts/src/victory/components/ChartTheme/styles/bullet-styles.ts index f2302634d85..2978bed08e0 100644 --- a/packages/react-charts/src/components/ChartTheme/styles/bullet-styles.ts +++ b/packages/react-charts/src/victory/components/ChartTheme/styles/bullet-styles.ts @@ -1,4 +1,3 @@ -/* eslint-disable camelcase */ import chart_bullet_axis_tick_count from '@patternfly/react-tokens/dist/esm/chart_bullet_axis_tick_count'; import chart_bullet_comparative_measure_Width from '@patternfly/react-tokens/dist/esm/chart_bullet_comparative_measure_Width'; import chart_bullet_comparative_measure_error_Width from '@patternfly/react-tokens/dist/esm/chart_bullet_comparative_measure_error_Width'; @@ -15,7 +14,8 @@ import chart_global_FontSize_lg from '@patternfly/react-tokens/dist/esm/chart_gl /** * Bullet styles - * @private + * + * @private Not intended as public API and subject to change */ export const BulletStyles = { axisTickCount: chart_bullet_axis_tick_count.value, diff --git a/packages/react-charts/src/components/ChartTheme/styles/common-styles.ts b/packages/react-charts/src/victory/components/ChartTheme/styles/common-styles.ts similarity index 88% rename from packages/react-charts/src/components/ChartTheme/styles/common-styles.ts rename to packages/react-charts/src/victory/components/ChartTheme/styles/common-styles.ts index 7a49d4b763c..05a5d3db21e 100644 --- a/packages/react-charts/src/components/ChartTheme/styles/common-styles.ts +++ b/packages/react-charts/src/victory/components/ChartTheme/styles/common-styles.ts @@ -1,4 +1,3 @@ -/* eslint-disable camelcase */ import chart_global_FontFamily from '@patternfly/react-tokens/dist/esm/chart_global_FontFamily'; import chart_global_FontSize_sm from '@patternfly/react-tokens/dist/esm/chart_global_FontSize_sm'; import chart_global_label_Margin from '@patternfly/react-tokens/dist/esm/chart_global_label_Margin'; @@ -8,13 +7,14 @@ import chart_legend_Margin from '@patternfly/react-tokens/dist/esm/chart_legend_ import chart_legend_position from '@patternfly/react-tokens/dist/esm/chart_legend_position'; // Typography -const TYPOGRAPHY_FONT_FAMILY = chart_global_FontFamily.var; +const TYPOGRAPHY_FONT_FAMILY = chart_global_FontFamily.var.replace(/"/g, "'"); // Well-formed XML const TYPOGRAPHY_LETTER_SPACING = chart_global_letter_spacing.var; const TYPOGRAPHY_FONT_SIZE = chart_global_FontSize_sm.value; /** * Common styles - * @private + * + * @private Not intended as public API and subject to change */ export const CommonStyles = { label: { diff --git a/packages/react-charts/src/components/ChartTheme/styles/donut-styles.ts b/packages/react-charts/src/victory/components/ChartTheme/styles/donut-styles.ts similarity index 93% rename from packages/react-charts/src/components/ChartTheme/styles/donut-styles.ts rename to packages/react-charts/src/victory/components/ChartTheme/styles/donut-styles.ts index f4d4d03d411..8b8f88f39e4 100644 --- a/packages/react-charts/src/components/ChartTheme/styles/donut-styles.ts +++ b/packages/react-charts/src/victory/components/ChartTheme/styles/donut-styles.ts @@ -1,4 +1,3 @@ -/* eslint-disable camelcase */ import chart_global_FontSize_sm from '@patternfly/react-tokens/dist/esm/chart_global_FontSize_sm'; import chart_global_FontSize_2xl from '@patternfly/react-tokens/dist/esm/chart_global_FontSize_2xl'; import chart_donut_label_subtitle_Fill from '@patternfly/react-tokens/dist/esm/chart_donut_label_subtitle_Fill'; @@ -7,7 +6,8 @@ import chart_donut_label_subtitle_position from '@patternfly/react-tokens/dist/e /** * Donut styles - * @private + * + * @private Not intended as public API and subject to change */ export const DonutStyles = { label: { diff --git a/packages/react-charts/src/components/ChartTheme/styles/donut-utilization-styles.ts b/packages/react-charts/src/victory/components/ChartTheme/styles/donut-utilization-styles.ts similarity index 87% rename from packages/react-charts/src/components/ChartTheme/styles/donut-utilization-styles.ts rename to packages/react-charts/src/victory/components/ChartTheme/styles/donut-utilization-styles.ts index ab3f843af78..b5ec3725ff8 100644 --- a/packages/react-charts/src/components/ChartTheme/styles/donut-utilization-styles.ts +++ b/packages/react-charts/src/victory/components/ChartTheme/styles/donut-utilization-styles.ts @@ -1,10 +1,10 @@ -/* eslint-disable camelcase */ import chart_donut_threshold_warning_Color from '@patternfly/react-tokens/dist/esm/chart_donut_threshold_warning_Color'; import chart_donut_threshold_danger_Color from '@patternfly/react-tokens/dist/esm/chart_donut_threshold_danger_Color'; /** * Donut utilization styles - * @private + * + * @private Not intended as public API and subject to change */ export const DonutUtilizationStyles = { thresholds: { diff --git a/packages/react-charts/src/components/ChartTheme/styles/legend-tooltip-styles.ts b/packages/react-charts/src/victory/components/ChartTheme/styles/legend-tooltip-styles.ts similarity index 53% rename from packages/react-charts/src/components/ChartTheme/styles/legend-tooltip-styles.ts rename to packages/react-charts/src/victory/components/ChartTheme/styles/legend-tooltip-styles.ts index 02cd605262b..2d54cf7f2ab 100644 --- a/packages/react-charts/src/components/ChartTheme/styles/legend-tooltip-styles.ts +++ b/packages/react-charts/src/victory/components/ChartTheme/styles/legend-tooltip-styles.ts @@ -1,10 +1,10 @@ -/* eslint-disable camelcase */ -import global_font_weight_heading_bold from '@patternfly/react-tokens/dist/esm/global_font_weight_heading_bold'; +import t_global_font_weight_heading_bold from '@patternfly/react-tokens/dist/esm/t_global_font_weight_heading_bold'; import chart_voronoi_labels_Fill from '@patternfly/react-tokens/dist/esm/chart_voronoi_labels_Fill'; /** * Legend tooltip styles - * @private + * + * @private Not intended as public API and subject to change */ export const LegendTooltipStyles = { flyout: { @@ -12,6 +12,6 @@ export const LegendTooltipStyles = { }, label: { fill: chart_voronoi_labels_Fill.var, - fontWeight: global_font_weight_heading_bold.value + fontWeight: t_global_font_weight_heading_bold.value } as any }; diff --git a/packages/react-charts/src/components/ChartTheme/styles/scatter-styles.ts b/packages/react-charts/src/victory/components/ChartTheme/styles/scatter-styles.ts similarity index 83% rename from packages/react-charts/src/components/ChartTheme/styles/scatter-styles.ts rename to packages/react-charts/src/victory/components/ChartTheme/styles/scatter-styles.ts index e777ee01fd6..c41a20a812f 100644 --- a/packages/react-charts/src/components/ChartTheme/styles/scatter-styles.ts +++ b/packages/react-charts/src/victory/components/ChartTheme/styles/scatter-styles.ts @@ -1,10 +1,10 @@ -/* eslint-disable camelcase */ import chart_scatter_active_size from '@patternfly/react-tokens/dist/esm/chart_scatter_active_size'; import chart_scatter_size from '@patternfly/react-tokens/dist/esm/chart_scatter_size'; /** * Scatter styles - * @private + * + * @private Not intended as public API and subject to change */ export const ScatterStyles = { activeSize: chart_scatter_active_size.value, diff --git a/packages/react-charts/src/components/ChartTheme/themes/base-theme.ts b/packages/react-charts/src/victory/components/ChartTheme/themes/base-theme.ts similarity index 90% rename from packages/react-charts/src/components/ChartTheme/themes/base-theme.ts rename to packages/react-charts/src/victory/components/ChartTheme/themes/base-theme.ts index 03f1615522f..02fdd77d2b1 100644 --- a/packages/react-charts/src/components/ChartTheme/themes/base-theme.ts +++ b/packages/react-charts/src/victory/components/ChartTheme/themes/base-theme.ts @@ -1,4 +1,3 @@ -/* eslint-disable camelcase */ import chart_global_FontFamily from '@patternfly/react-tokens/dist/esm/chart_global_FontFamily'; import chart_global_letter_spacing from '@patternfly/react-tokens/dist/esm/chart_global_letter_spacing'; import chart_global_FontSize_sm from '@patternfly/react-tokens/dist/esm/chart_global_FontSize_sm'; @@ -58,6 +57,8 @@ import chart_legend_gutter_Width from '@patternfly/react-tokens/dist/esm/chart_l import chart_legend_orientation from '@patternfly/react-tokens/dist/esm/chart_legend_orientation'; import chart_legend_title_orientation from '@patternfly/react-tokens/dist/esm/chart_legend_title_orientation'; import chart_legend_data_type from '@patternfly/react-tokens/dist/esm/chart_legend_data_type'; +import chart_legend_data_stroke_Color from '@patternfly/react-tokens/dist/esm/chart_legend_data_stroke_Color'; +import chart_legend_data_stroke_Width from '@patternfly/react-tokens/dist/esm/chart_legend_data_stroke_Width'; import chart_legend_title_Padding from '@patternfly/react-tokens/dist/esm/chart_legend_title_Padding'; import chart_line_data_Fill from '@patternfly/react-tokens/dist/esm/chart_line_data_Fill'; import chart_line_data_Opacity from '@patternfly/react-tokens/dist/esm/chart_line_data_Opacity'; @@ -100,6 +101,8 @@ import chart_donut_pie_Height from '@patternfly/react-tokens/dist/esm/chart_donu import chart_donut_pie_angle_Padding from '@patternfly/react-tokens/dist/esm/chart_donut_pie_angle_Padding'; import chart_donut_pie_Padding from '@patternfly/react-tokens/dist/esm/chart_donut_pie_Padding'; import chart_donut_pie_Width from '@patternfly/react-tokens/dist/esm/chart_donut_pie_Width'; +import chart_donut_pie_data_stroke_Color from '@patternfly/react-tokens/dist/esm/chart_donut_pie_data_stroke_Color'; +import chart_donut_pie_data_stroke_Width from '@patternfly/react-tokens/dist/esm/chart_donut_pie_data_stroke_Width'; import chart_donut_threshold_dynamic_pie_Height from '@patternfly/react-tokens/dist/esm/chart_donut_threshold_dynamic_pie_Height'; import chart_donut_threshold_dynamic_pie_Padding from '@patternfly/react-tokens/dist/esm/chart_donut_threshold_dynamic_pie_Padding'; import chart_donut_threshold_dynamic_pie_Width from '@patternfly/react-tokens/dist/esm/chart_donut_threshold_dynamic_pie_Width'; @@ -114,6 +117,8 @@ import chart_donut_utilization_dynamic_pie_Width from '@patternfly/react-tokens/ import chart_threshold_stroke_dash_array from '@patternfly/react-tokens/dist/esm/chart_threshold_stroke_dash_array'; import chart_threshold_stroke_Width from '@patternfly/react-tokens/dist/esm/chart_threshold_stroke_Width'; import chart_bullet_Height from '@patternfly/react-tokens/dist/esm/chart_bullet_Height'; +import chart_bullet_bar_stroke_Color from '@patternfly/react-tokens/dist/esm/chart_bullet_bar_stroke_Color'; +import chart_bullet_bar_stroke_Width from '@patternfly/react-tokens/dist/esm/chart_bullet_bar_stroke_Width'; import chart_bullet_comparative_measure_error_stroke_Width from '@patternfly/react-tokens/dist/esm/chart_bullet_comparative_measure_error_stroke_Width'; import chart_bullet_comparative_measure_stroke_Width from '@patternfly/react-tokens/dist/esm/chart_bullet_comparative_measure_stroke_Width'; import chart_bullet_comparative_measure_warning_stroke_Width from '@patternfly/react-tokens/dist/esm/chart_bullet_comparative_measure_warning_stroke_Width'; @@ -125,8 +130,8 @@ import { ChartComponentThemeDefinition, ChartThemeDefinition } from '../ChartThe // Typography // // Note: Victory's approximateTextSize function uses specific character widths and does not work with font variables -// See https://github.com/patternfly/patternfly-react/issues/5300 -const TYPOGRAPHY_FONT_FAMILY = chart_global_FontFamily.value.replace(/ /g, ''); +// See https://github.com/patternfly/patternfly-react/issues/5300 and https://github.com/patternfly/patternfly-react/pull/5301 +const TYPOGRAPHY_FONT_FAMILY = chart_global_FontFamily.var.replace(/"/g, "'"); // Well-formed XML const TYPOGRAPHY_LETTER_SPACING = chart_global_letter_spacing.value; const TYPOGRAPHY_FONT_SIZE = chart_global_FontSize_sm.value; @@ -158,7 +163,8 @@ const STROKE_LINE_JOIN = chart_global_stroke_line_join.value; /** * Base theme containing Victory properties only - * @private + * + * @private Not intended as public API and subject to change */ export const BaseTheme: ChartThemeDefinition = { area: { @@ -166,9 +172,9 @@ export const BaseTheme: ChartThemeDefinition = { style: { data: { fill: chart_area_data_Fill.var, - fillOpacity: chart_area_Opacity.value, + fillOpacity: chart_area_Opacity.var, // Omit stroke to add a line border from color scale - // stroke: chart_global_label_stroke.value, + // stroke: chart_global_label_stroke_color.value, strokeWidth: chart_area_stroke_Width.value }, labels: LABEL_CENTERED_PROPS @@ -218,7 +224,7 @@ export const BaseTheme: ChartThemeDefinition = { fill: chart_bar_data_Fill.var, padding: chart_bar_data_Padding.value, stroke: chart_bar_data_stroke.var, - strokeWidth: chart_bar_data_stroke_Width.value + strokeWidth: chart_bar_data_stroke_Width.var }, labels: LABEL_PROPS } @@ -296,7 +302,9 @@ export const BaseTheme: ChartThemeDefinition = { titleOrientation: chart_legend_title_orientation.value, style: { data: { - type: chart_legend_data_type.value + type: chart_legend_data_type.value, + stroke: chart_legend_data_stroke_Color.var, + strokeWidth: chart_legend_data_stroke_Width.var }, labels: LABEL_PROPS, title: { @@ -324,7 +332,7 @@ export const BaseTheme: ChartThemeDefinition = { data: { padding: chart_pie_data_Padding.value, stroke: chart_pie_data_stroke_Color.var, - strokeWidth: chart_pie_data_stroke_Width.value + strokeWidth: chart_pie_data_stroke_Width.var }, labels: { ...LABEL_PROPS, @@ -398,8 +406,8 @@ export const BaseTheme: ChartThemeDefinition = { /** * Base component theme - * @private - * @beta + * + * @private Not intended as public API and subject to change */ export const BaseComponentTheme: ChartComponentThemeDefinition = { axis: { @@ -460,6 +468,14 @@ export const BaseComponentTheme: ChartComponentThemeDefinition = { bulletPrimaryDotMeasure: { group: { height: chart_bullet_Height.value + }, + scatter: { + style: { + data: { + stroke: chart_bullet_bar_stroke_Color.var, + strokeWidth: chart_bullet_bar_stroke_Width.var + } + } } }, bulletPrimaryNegativeMeasure: { @@ -470,6 +486,14 @@ export const BaseComponentTheme: ChartComponentThemeDefinition = { bulletPrimarySegmentedMeasure: { group: { height: chart_bullet_Height.value + }, + bar: { + style: { + data: { + stroke: chart_bullet_bar_stroke_Color.var, + strokeWidth: chart_bullet_bar_stroke_Width.var + } + } } }, bulletQualitativeRange: { @@ -482,14 +506,26 @@ export const BaseComponentTheme: ChartComponentThemeDefinition = { height: chart_donut_pie_Height.value, padding: chart_donut_pie_Padding.value, padAngle: chart_donut_pie_angle_Padding.value, - width: chart_donut_pie_Width.value + width: chart_donut_pie_Width.value, + style: { + data: { + stroke: chart_donut_pie_data_stroke_Color.var, + strokeWidth: chart_donut_pie_data_stroke_Width.var + } + } } as any // Victory is missing padAngle }, donutThresholdDynamic: { pie: { height: chart_donut_threshold_dynamic_pie_Height.value, padding: chart_donut_threshold_dynamic_pie_Padding.value, - width: chart_donut_threshold_dynamic_pie_Width.value + width: chart_donut_threshold_dynamic_pie_Width.value, + style: { + data: { + stroke: chart_donut_pie_data_stroke_Color.var, + strokeWidth: chart_donut_pie_data_stroke_Width.var + } + } } }, donutThresholdStatic: { @@ -497,7 +533,13 @@ export const BaseComponentTheme: ChartComponentThemeDefinition = { height: chart_donut_threshold_static_pie_Height.value, padAngle: chart_donut_threshold_static_pie_angle_Padding.value, padding: chart_donut_threshold_static_pie_Padding.value, - width: chart_donut_threshold_static_pie_Width.value + width: chart_donut_threshold_static_pie_Width.value, + style: { + data: { + stroke: chart_donut_pie_data_stroke_Color.var, + strokeWidth: chart_donut_pie_data_stroke_Width.var + } + } } as any // Victory is missing padAngle }, donutUtilization: { @@ -505,7 +547,13 @@ export const BaseComponentTheme: ChartComponentThemeDefinition = { height: chart_donut_utilization_dynamic_pie_Height.value, padding: chart_donut_utilization_dynamic_pie_Padding.value, padAngle: chart_donut_utilization_dynamic_pie_angle_Padding.value, - width: chart_donut_utilization_dynamic_pie_Width.value + width: chart_donut_utilization_dynamic_pie_Width.value, + style: { + data: { + stroke: chart_donut_pie_data_stroke_Color.var, + strokeWidth: chart_donut_pie_data_stroke_Width.var + } + } } as any // Victory is missing padAngle }, threshold: { diff --git a/packages/react-charts/src/components/ChartTheme/themes/color-theme.ts b/packages/react-charts/src/victory/components/ChartTheme/themes/color-theme.ts similarity index 98% rename from packages/react-charts/src/components/ChartTheme/themes/color-theme.ts rename to packages/react-charts/src/victory/components/ChartTheme/themes/color-theme.ts index fda4be8b3c2..9d910948597 100644 --- a/packages/react-charts/src/components/ChartTheme/themes/color-theme.ts +++ b/packages/react-charts/src/victory/components/ChartTheme/themes/color-theme.ts @@ -1,4 +1,3 @@ -/* eslint-disable camelcase */ import chart_donut_threshold_second_Color from '@patternfly/react-tokens/dist/esm/chart_donut_threshold_second_Color'; import chart_donut_threshold_third_Color from '@patternfly/react-tokens/dist/esm/chart_donut_threshold_third_Color'; import chart_donut_threshold_first_Color from '@patternfly/react-tokens/dist/esm/chart_donut_threshold_first_Color'; @@ -31,7 +30,8 @@ interface ColorThemeInterface { /** * Victory color theme - * @private + * + * @private Not intended as public API and subject to change */ export const ColorTheme = (props: ColorThemeInterface): ChartThemeDefinition => { const { COLOR_SCALE } = props; @@ -107,8 +107,8 @@ export const ColorTheme = (props: ColorThemeInterface): ChartThemeDefinition => /** * Component color theme - * @private - * @beta + * + * @private Not intended as public API and subject to change */ export const ColorComponentTheme = (props: ColorThemeInterface): ChartComponentThemeDefinition => { const { COLOR_SCALE } = props; diff --git a/packages/react-charts/src/components/ChartTheme/themes/colors/blue-theme.ts b/packages/react-charts/src/victory/components/ChartTheme/themes/colors/blue-theme.ts similarity index 90% rename from packages/react-charts/src/components/ChartTheme/themes/colors/blue-theme.ts rename to packages/react-charts/src/victory/components/ChartTheme/themes/colors/blue-theme.ts index 7f5d45e8f78..c07ea2a8170 100644 --- a/packages/react-charts/src/components/ChartTheme/themes/colors/blue-theme.ts +++ b/packages/react-charts/src/victory/components/ChartTheme/themes/colors/blue-theme.ts @@ -1,4 +1,3 @@ -/* eslint-disable camelcase */ import chart_theme_blue_ColorScale_100 from '@patternfly/react-tokens/dist/esm/chart_theme_blue_ColorScale_100'; import chart_theme_blue_ColorScale_200 from '@patternfly/react-tokens/dist/esm/chart_theme_blue_ColorScale_200'; import chart_theme_blue_ColorScale_300 from '@patternfly/react-tokens/dist/esm/chart_theme_blue_ColorScale_300'; @@ -18,7 +17,8 @@ const COLOR_SCALE = [ /** * Blue color theme - * @private + * + * @private Not intended as public API and subject to change */ export const BlueColorTheme = ColorTheme({ COLOR_SCALE @@ -26,8 +26,8 @@ export const BlueColorTheme = ColorTheme({ /** * Blue color component theme - * @private - * @beta + * + * @private Not intended as public API and subject to change */ export const BlueColorComponentTheme = ColorComponentTheme({ COLOR_SCALE diff --git a/packages/react-charts/src/components/ChartTheme/themes/colors/gray-theme.ts b/packages/react-charts/src/victory/components/ChartTheme/themes/colors/gray-theme.ts similarity index 90% rename from packages/react-charts/src/components/ChartTheme/themes/colors/gray-theme.ts rename to packages/react-charts/src/victory/components/ChartTheme/themes/colors/gray-theme.ts index b84cb9d9a49..10e674296ed 100644 --- a/packages/react-charts/src/components/ChartTheme/themes/colors/gray-theme.ts +++ b/packages/react-charts/src/victory/components/ChartTheme/themes/colors/gray-theme.ts @@ -1,4 +1,3 @@ -/* eslint-disable camelcase */ import chart_theme_gray_ColorScale_100 from '@patternfly/react-tokens/dist/esm/chart_theme_gray_ColorScale_100'; import chart_theme_gray_ColorScale_200 from '@patternfly/react-tokens/dist/esm/chart_theme_gray_ColorScale_200'; import chart_theme_gray_ColorScale_300 from '@patternfly/react-tokens/dist/esm/chart_theme_gray_ColorScale_300'; @@ -18,7 +17,8 @@ const COLOR_SCALE = [ /** * Gray color theme - * @private + * + * @private Not intended as public API and subject to change */ export const GrayColorTheme = ColorTheme({ COLOR_SCALE @@ -26,8 +26,8 @@ export const GrayColorTheme = ColorTheme({ /** * Gray component theme - * @private - * @beta + * + * @private Not intended as public API and subject to change */ export const GrayColorComponentTheme = ColorComponentTheme({ COLOR_SCALE diff --git a/packages/react-charts/src/components/ChartTheme/themes/colors/green-theme.ts b/packages/react-charts/src/victory/components/ChartTheme/themes/colors/green-theme.ts similarity index 90% rename from packages/react-charts/src/components/ChartTheme/themes/colors/green-theme.ts rename to packages/react-charts/src/victory/components/ChartTheme/themes/colors/green-theme.ts index 21fe9d393c2..0ab74406194 100644 --- a/packages/react-charts/src/components/ChartTheme/themes/colors/green-theme.ts +++ b/packages/react-charts/src/victory/components/ChartTheme/themes/colors/green-theme.ts @@ -1,4 +1,3 @@ -/* eslint-disable camelcase */ import chart_theme_green_ColorScale_100 from '@patternfly/react-tokens/dist/esm/chart_theme_green_ColorScale_100'; import chart_theme_green_ColorScale_200 from '@patternfly/react-tokens/dist/esm/chart_theme_green_ColorScale_200'; import chart_theme_green_ColorScale_300 from '@patternfly/react-tokens/dist/esm/chart_theme_green_ColorScale_300'; @@ -18,7 +17,8 @@ const COLOR_SCALE = [ /** * Green color theme - * @private + * + * @private Not intended as public API and subject to change */ export const GreenColorTheme = ColorTheme({ COLOR_SCALE @@ -26,8 +26,8 @@ export const GreenColorTheme = ColorTheme({ /** * Green color component theme - * @private - * @beta + * + * @private Not intended as public API and subject to change */ export const GreenColorComponentTheme = ColorComponentTheme({ COLOR_SCALE diff --git a/packages/react-charts/src/components/ChartTheme/themes/colors/multi-ordered-theme.ts b/packages/react-charts/src/victory/components/ChartTheme/themes/colors/multi-ordered-theme.ts similarity index 97% rename from packages/react-charts/src/components/ChartTheme/themes/colors/multi-ordered-theme.ts rename to packages/react-charts/src/victory/components/ChartTheme/themes/colors/multi-ordered-theme.ts index dc383575975..93cf2b092a9 100644 --- a/packages/react-charts/src/components/ChartTheme/themes/colors/multi-ordered-theme.ts +++ b/packages/react-charts/src/victory/components/ChartTheme/themes/colors/multi-ordered-theme.ts @@ -1,4 +1,3 @@ -/* eslint-disable camelcase */ import chart_theme_multi_color_ordered_ColorScale_100 from '@patternfly/react-tokens/dist/esm/chart_theme_multi_color_ordered_ColorScale_100'; import chart_theme_multi_color_ordered_ColorScale_200 from '@patternfly/react-tokens/dist/esm/chart_theme_multi_color_ordered_ColorScale_200'; import chart_theme_multi_color_ordered_ColorScale_300 from '@patternfly/react-tokens/dist/esm/chart_theme_multi_color_ordered_ColorScale_300'; @@ -58,7 +57,8 @@ const COLOR_SCALE = [ /** * Multi-color ordered theme - * @private + * + * @private Not intended as public API and subject to change */ export const MultiColorOrderedTheme = ColorTheme({ COLOR_SCALE @@ -66,8 +66,8 @@ export const MultiColorOrderedTheme = ColorTheme({ /** * Multi-color ordered component theme - * @private - * @beta + * + * @private Not intended as public API and subject to change */ export const MultiColorOrderedComponentTheme = ColorComponentTheme({ COLOR_SCALE diff --git a/packages/react-charts/src/components/ChartTheme/themes/colors/multi-unordered-theme.ts b/packages/react-charts/src/victory/components/ChartTheme/themes/colors/multi-unordered-theme.ts similarity index 98% rename from packages/react-charts/src/components/ChartTheme/themes/colors/multi-unordered-theme.ts rename to packages/react-charts/src/victory/components/ChartTheme/themes/colors/multi-unordered-theme.ts index dd524d32ab4..35f0e0541a6 100644 --- a/packages/react-charts/src/components/ChartTheme/themes/colors/multi-unordered-theme.ts +++ b/packages/react-charts/src/victory/components/ChartTheme/themes/colors/multi-unordered-theme.ts @@ -1,4 +1,3 @@ -/* eslint-disable camelcase */ import chart_theme_multi_color_unordered_ColorScale_100 from '@patternfly/react-tokens/dist/esm/chart_theme_multi_color_unordered_ColorScale_100'; import chart_theme_multi_color_unordered_ColorScale_200 from '@patternfly/react-tokens/dist/esm/chart_theme_multi_color_unordered_ColorScale_200'; import chart_theme_multi_color_unordered_ColorScale_300 from '@patternfly/react-tokens/dist/esm/chart_theme_multi_color_unordered_ColorScale_300'; @@ -78,7 +77,8 @@ const COLOR_SCALE = [ /** * Multi-color unordered theme - * @private + * + * @private Not intended as public API and subject to change */ export const MultiColorUnorderedTheme = ColorTheme({ COLOR_SCALE @@ -86,8 +86,8 @@ export const MultiColorUnorderedTheme = ColorTheme({ /** * Multi-color unordered component theme - * @private - * @beta + * + * @private Not intended as public API and subject to change */ export const MultiColorUnorderedComponentTheme = ColorComponentTheme({ COLOR_SCALE diff --git a/packages/react-charts/src/components/ChartTheme/themes/colors/orange-theme.ts b/packages/react-charts/src/victory/components/ChartTheme/themes/colors/orange-theme.ts similarity index 90% rename from packages/react-charts/src/components/ChartTheme/themes/colors/orange-theme.ts rename to packages/react-charts/src/victory/components/ChartTheme/themes/colors/orange-theme.ts index cb29dcbba91..65f64c2a46f 100644 --- a/packages/react-charts/src/components/ChartTheme/themes/colors/orange-theme.ts +++ b/packages/react-charts/src/victory/components/ChartTheme/themes/colors/orange-theme.ts @@ -1,4 +1,3 @@ -/* eslint-disable camelcase */ import chart_theme_orange_ColorScale_100 from '@patternfly/react-tokens/dist/esm/chart_theme_orange_ColorScale_100'; import chart_theme_orange_ColorScale_200 from '@patternfly/react-tokens/dist/esm/chart_theme_orange_ColorScale_200'; import chart_theme_orange_ColorScale_300 from '@patternfly/react-tokens/dist/esm/chart_theme_orange_ColorScale_300'; @@ -18,7 +17,8 @@ const COLOR_SCALE = [ /** * Orange color theme - * @private + * + * @private Not intended as public API and subject to change */ export const OrangeColorTheme = ColorTheme({ COLOR_SCALE @@ -26,8 +26,8 @@ export const OrangeColorTheme = ColorTheme({ /** * Orange color component theme - * @private - * @beta + * + * @private Not intended as public API and subject to change */ export const OrangeColorComponentTheme = ColorComponentTheme({ COLOR_SCALE diff --git a/packages/react-charts/src/components/ChartTheme/themes/colors/purple-theme.ts b/packages/react-charts/src/victory/components/ChartTheme/themes/colors/purple-theme.ts similarity index 90% rename from packages/react-charts/src/components/ChartTheme/themes/colors/purple-theme.ts rename to packages/react-charts/src/victory/components/ChartTheme/themes/colors/purple-theme.ts index 21ffef53f35..98766913a40 100644 --- a/packages/react-charts/src/components/ChartTheme/themes/colors/purple-theme.ts +++ b/packages/react-charts/src/victory/components/ChartTheme/themes/colors/purple-theme.ts @@ -1,4 +1,3 @@ -/* eslint-disable camelcase */ import chart_theme_purple_ColorScale_100 from '@patternfly/react-tokens/dist/esm/chart_theme_purple_ColorScale_100'; import chart_theme_purple_ColorScale_200 from '@patternfly/react-tokens/dist/esm/chart_theme_purple_ColorScale_200'; import chart_theme_purple_ColorScale_300 from '@patternfly/react-tokens/dist/esm/chart_theme_purple_ColorScale_300'; @@ -18,7 +17,8 @@ const COLOR_SCALE = [ /** * Purple ordered theme - * @private + * + * @private Not intended as public API and subject to change */ export const PurpleColorTheme = ColorTheme({ COLOR_SCALE @@ -26,8 +26,8 @@ export const PurpleColorTheme = ColorTheme({ /** * Purple color component theme - * @private - * @beta + * + * @private Not intended as public API and subject to change */ export const PurpleColorComponentTheme = ColorComponentTheme({ COLOR_SCALE diff --git a/packages/react-charts/src/victory/components/ChartTheme/themes/colors/skeleton-theme.ts b/packages/react-charts/src/victory/components/ChartTheme/themes/colors/skeleton-theme.ts new file mode 100644 index 00000000000..37af537de4a --- /dev/null +++ b/packages/react-charts/src/victory/components/ChartTheme/themes/colors/skeleton-theme.ts @@ -0,0 +1,34 @@ +import { ColorTheme, ColorComponentTheme } from '../skeleton-theme'; +import chart_skeleton_ColorScale_100 from '@patternfly/react-tokens/dist/esm/chart_skeleton_ColorScale_100'; +import chart_skeleton_ColorScale_200 from '@patternfly/react-tokens/dist/esm/chart_skeleton_ColorScale_200'; +import chart_skeleton_ColorScale_300 from '@patternfly/react-tokens/dist/esm/chart_skeleton_ColorScale_300'; +import chart_skeleton_ColorScale_400 from '@patternfly/react-tokens/dist/esm/chart_skeleton_ColorScale_400'; +import chart_skeleton_ColorScale_500 from '@patternfly/react-tokens/dist/esm/chart_skeleton_ColorScale_500'; + +// Color scale +// See https://docs.google.com/document/d/1cw10pJFXWruB1SA8TQwituxn5Ss6KpxYPCOYGrH8qAY/edit +const COLOR_SCALE = [ + chart_skeleton_ColorScale_100.var, + chart_skeleton_ColorScale_200.var, + chart_skeleton_ColorScale_300.var, + chart_skeleton_ColorScale_400.var, + chart_skeleton_ColorScale_500.var +]; + +/** + * Skeleton color theme + * + * @private Not intended as public API and subject to change + */ +export const SkeletonColorTheme = ColorTheme({ + COLOR_SCALE +}); + +/** + * Skeleton color theme + * + * @private Not intended as public API and subject to change + */ +export const SkeletonColorComponentTheme = ColorComponentTheme({ + COLOR_SCALE +}); diff --git a/packages/react-charts/src/components/ChartTheme/themes/colors/teal-theme.ts b/packages/react-charts/src/victory/components/ChartTheme/themes/colors/teal-theme.ts similarity index 90% rename from packages/react-charts/src/components/ChartTheme/themes/colors/teal-theme.ts rename to packages/react-charts/src/victory/components/ChartTheme/themes/colors/teal-theme.ts index 3c6f0c5c5b2..99d7df686f9 100644 --- a/packages/react-charts/src/components/ChartTheme/themes/colors/teal-theme.ts +++ b/packages/react-charts/src/victory/components/ChartTheme/themes/colors/teal-theme.ts @@ -1,4 +1,3 @@ -/* eslint-disable camelcase */ import chart_theme_teal_ColorScale_100 from '@patternfly/react-tokens/dist/esm/chart_theme_teal_ColorScale_100'; import chart_theme_teal_ColorScale_200 from '@patternfly/react-tokens/dist/esm/chart_theme_teal_ColorScale_200'; import chart_theme_teal_ColorScale_300 from '@patternfly/react-tokens/dist/esm/chart_theme_teal_ColorScale_300'; @@ -18,7 +17,8 @@ const COLOR_SCALE = [ /** * Teal color theme - * @private + * + * @private Not intended as public API and subject to change */ export const TealColorTheme = ColorTheme({ COLOR_SCALE @@ -26,8 +26,8 @@ export const TealColorTheme = ColorTheme({ /** * Teal color component theme - * @private - * @beta + * + * @private Not intended as public API and subject to change */ export const TealColorComponentTheme = ColorComponentTheme({ COLOR_SCALE diff --git a/packages/react-charts/src/components/ChartTheme/themes/colors/yellow-theme.ts b/packages/react-charts/src/victory/components/ChartTheme/themes/colors/yellow-theme.ts similarity index 90% rename from packages/react-charts/src/components/ChartTheme/themes/colors/yellow-theme.ts rename to packages/react-charts/src/victory/components/ChartTheme/themes/colors/yellow-theme.ts index 5a512442d3d..87879349956 100644 --- a/packages/react-charts/src/components/ChartTheme/themes/colors/yellow-theme.ts +++ b/packages/react-charts/src/victory/components/ChartTheme/themes/colors/yellow-theme.ts @@ -1,4 +1,3 @@ -/* eslint-disable camelcase */ import chart_theme_yellow_ColorScale_100 from '@patternfly/react-tokens/dist/esm/chart_theme_yellow_ColorScale_100'; import chart_theme_yellow_ColorScale_200 from '@patternfly/react-tokens/dist/esm/chart_theme_yellow_ColorScale_200'; import chart_theme_yellow_ColorScale_300 from '@patternfly/react-tokens/dist/esm/chart_theme_yellow_ColorScale_300'; @@ -18,7 +17,8 @@ const COLOR_SCALE = [ /** * Yellow color theme - * @private + * + * @private Not intended as public API and subject to change */ export const YellowColorTheme = ColorTheme({ COLOR_SCALE @@ -26,8 +26,8 @@ export const YellowColorTheme = ColorTheme({ /** * Yellow color component theme - * @private - * @beta + * + * @private Not intended as public API and subject to change */ export const YellowColorComponentTheme = ColorComponentTheme({ COLOR_SCALE diff --git a/packages/react-charts/src/components/ChartTheme/themes/skeleton-theme.ts b/packages/react-charts/src/victory/components/ChartTheme/themes/skeleton-theme.ts similarity index 96% rename from packages/react-charts/src/components/ChartTheme/themes/skeleton-theme.ts rename to packages/react-charts/src/victory/components/ChartTheme/themes/skeleton-theme.ts index 21863aed04f..682f2325dcd 100644 --- a/packages/react-charts/src/components/ChartTheme/themes/skeleton-theme.ts +++ b/packages/react-charts/src/victory/components/ChartTheme/themes/skeleton-theme.ts @@ -16,7 +16,8 @@ const LABEL_CENTERED_PROPS = { /** * Victory color theme - * @private + * + * @private Not intended as public API and subject to change */ export const ColorTheme = (props: ColorThemeInterface): ChartThemeDefinition => { const { COLOR_SCALE } = props; @@ -123,6 +124,10 @@ export const ColorTheme = (props: ColorThemeInterface): ChartThemeDefinition => labels: LABEL_PROPS, title: { ...LABEL_PROPS + }, + data: { + stroke: 'transparent', + strokeWidth: 0 } } }, @@ -192,8 +197,8 @@ export const ColorTheme = (props: ColorThemeInterface): ChartThemeDefinition => /** * Component color theme - * @private - * @beta + * + * @private Not intended as public API and subject to change */ export const ColorComponentTheme = (props: ColorThemeInterface): ChartComponentThemeDefinition => { const { COLOR_SCALE } = props; diff --git a/packages/react-charts/src/components/ChartThreshold/ChartThreshold.test.tsx b/packages/react-charts/src/victory/components/ChartThreshold/ChartThreshold.test.tsx similarity index 96% rename from packages/react-charts/src/components/ChartThreshold/ChartThreshold.test.tsx rename to packages/react-charts/src/victory/components/ChartThreshold/ChartThreshold.test.tsx index d1f90945439..314240ba9e0 100644 --- a/packages/react-charts/src/components/ChartThreshold/ChartThreshold.test.tsx +++ b/packages/react-charts/src/victory/components/ChartThreshold/ChartThreshold.test.tsx @@ -1,4 +1,3 @@ -import * as React from 'react'; import { render } from '@testing-library/react'; import { Chart } from '../Chart/Chart'; import { ChartGroup } from '../ChartGroup/ChartGroup'; diff --git a/packages/react-charts/src/components/ChartThreshold/ChartThreshold.tsx b/packages/react-charts/src/victory/components/ChartThreshold/ChartThreshold.tsx similarity index 98% rename from packages/react-charts/src/components/ChartThreshold/ChartThreshold.tsx rename to packages/react-charts/src/victory/components/ChartThreshold/ChartThreshold.tsx index 9d6566d8a3d..a0579d7d706 100644 --- a/packages/react-charts/src/components/ChartThreshold/ChartThreshold.tsx +++ b/packages/react-charts/src/victory/components/ChartThreshold/ChartThreshold.tsx @@ -1,4 +1,3 @@ -import * as React from 'react'; import hoistNonReactStatics from 'hoist-non-react-statics'; import cloneDeep from 'lodash/cloneDeep'; import { @@ -126,7 +125,7 @@ export interface ChartThresholdProps extends VictoryLineProps { * Since ChartLine only renders a single element, the eventKey property is not used. * The eventHandlers object should be given as an object whose keys are standard * event names (i.e. onClick) and whose values are event callbacks. The return value - * of an event handler is used to modify elemnts. The return value should be given + * of an event handler is used to modify elements. The return value should be given * as an object or an array of objects with optional target and eventKey keys, * and a mutation key whose value is a function. The target and eventKey keys * will default to those corresponding to the element the event handler was attached to. @@ -269,7 +268,7 @@ export interface ChartThresholdProps extends VictoryLineProps { * * Note: This prop should not be set manually. * - * @private + * @private Not intended as public API and subject to change * @hide */ polar?: boolean; @@ -313,7 +312,7 @@ export interface ChartThresholdProps extends VictoryLineProps { * * Note: This prop should not be set manually. * - * @private + * @private Not intended as public API and subject to change * @hide */ sharedEvents?: { events: any[]; getEventState: Function }; diff --git a/packages/react-charts/src/components/ChartThreshold/__snapshots__/ChartThreshold.test.tsx.snap b/packages/react-charts/src/victory/components/ChartThreshold/__snapshots__/ChartThreshold.test.tsx.snap similarity index 69% rename from packages/react-charts/src/components/ChartThreshold/__snapshots__/ChartThreshold.test.tsx.snap rename to packages/react-charts/src/victory/components/ChartThreshold/__snapshots__/ChartThreshold.test.tsx.snap index 9d9e65dfd54..39d12222996 100644 --- a/packages/react-charts/src/components/ChartThreshold/__snapshots__/ChartThreshold.test.tsx.snap +++ b/packages/react-charts/src/victory/components/ChartThreshold/__snapshots__/ChartThreshold.test.tsx.snap @@ -9,7 +9,7 @@ exports[`ChartThreshold 1`] = ` @@ -39,11 +39,11 @@ exports[`ChartThreshold 1`] = `
@@ -61,7 +61,7 @@ exports[`ChartThreshold 2`] = ` @@ -91,11 +91,11 @@ exports[`ChartThreshold 2`] = `
@@ -113,7 +113,7 @@ exports[`renders component data 1`] = ` @@ -149,7 +149,7 @@ exports[`renders component data 1`] = ` @@ -193,7 +193,7 @@ exports[`renders component data 1`] = ` @@ -224,7 +224,7 @@ exports[`renders component data 1`] = ` @@ -255,7 +255,7 @@ exports[`renders component data 1`] = ` @@ -286,7 +286,7 @@ exports[`renders component data 1`] = ` @@ -318,7 +318,7 @@ exports[`renders component data 1`] = ` @@ -362,7 +362,7 @@ exports[`renders component data 1`] = ` @@ -393,7 +393,7 @@ exports[`renders component data 1`] = ` @@ -424,7 +424,7 @@ exports[`renders component data 1`] = ` @@ -455,7 +455,7 @@ exports[`renders component data 1`] = ` @@ -486,7 +486,7 @@ exports[`renders component data 1`] = ` @@ -514,11 +514,11 @@ exports[`renders component data 1`] = `
diff --git a/packages/react-charts/src/victory/components/ChartThreshold/examples/ChartThreshold.md b/packages/react-charts/src/victory/components/ChartThreshold/examples/ChartThreshold.md new file mode 100644 index 00000000000..179f19f9ec1 --- /dev/null +++ b/packages/react-charts/src/victory/components/ChartThreshold/examples/ChartThreshold.md @@ -0,0 +1,60 @@ +--- +id: Threshold chart +section: components +subsection: charts +propComponents: [ + 'Chart', + 'ChartAxis', + 'ChartGroup', + 'ChartThreshold', + 'ChartVoronoiContainer' +] +hideDarkMode: true +--- + +import { createRef } from 'react'; +import { + Chart, + ChartArea, + ChartAxis, + ChartGroup, + ChartLegend, + 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'; + + +## Introduction +Note: PatternFly React charts live in its own package at [@patternfly/react-charts](https://www.npmjs.com/package/@patternfly/react-charts)! + +The examples below are based on the [Victory](https://formidable.com/open-source/victory/docs/victory-chart/) chart library, + along with additional functionality, custom components, and theming for PatternFly. This provides a collection of React based components you can use to build PatternFly patterns with consistent markup, styling, and behavior. + +## Examples +### Multi-color (unordered) with responsive container +```ts file = "ChartThresholdMultiColorOrdered.tsx" + +``` + +## Documentation +### Tips +- See Victory's [FAQ](https://formidable.com/open-source/victory/docs/faq) +- For single data points or zero values, you may want to set the `domain` prop +- `ChartLegend` may be used as a standalone component, instead of using `legendData` + +### Note +Currently, the generated documentation below is not able to resolve type definitions from Victory imports. For the +components used in the examples above, Victory pass-thru props are also documented here: + + - For `Chart` props, see [VictoryChart](https://formidable.com/open-source/victory/docs/victory-chart) + - For `ChartArea` props, see [VictoryArea](https://formidable.com/open-source/victory/docs/victory-area) + - For `ChartAxis` props, see [VictoryAxis](https://formidable.com/open-source/victory/docs/victory-axis) + - For `ChartGroup` props, see [VictoryGroup](https://formidable.com/open-source/victory/docs/victory-group) + - For `ChartLegend` props, see [VictoryLegend](https://formidable.com/open-source/victory/docs/victory-legend) + - For `ChartThreshold` props, see [VictoryLine](https://formidable.com/open-source/victory/docs/victory-line) + - For `ChartVoronoiContainer` props, see [VictoryVoronoiContainer](https://formidable.com/open-source/victory/docs/victory-voronoi-container) 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/components/ChartTooltip/ChartTooltip.test.tsx b/packages/react-charts/src/victory/components/ChartTooltip/ChartTooltip.test.tsx similarity index 97% rename from packages/react-charts/src/components/ChartTooltip/ChartTooltip.test.tsx rename to packages/react-charts/src/victory/components/ChartTooltip/ChartTooltip.test.tsx index 26a9fdc80ef..136b898918c 100644 --- a/packages/react-charts/src/components/ChartTooltip/ChartTooltip.test.tsx +++ b/packages/react-charts/src/victory/components/ChartTooltip/ChartTooltip.test.tsx @@ -1,4 +1,3 @@ -import * as React from 'react'; import { render } from '@testing-library/react'; import { ChartArea } from '../ChartArea/ChartArea'; import { ChartGroup } from '../ChartGroup/ChartGroup'; diff --git a/packages/react-charts/src/components/ChartTooltip/ChartTooltip.tsx b/packages/react-charts/src/victory/components/ChartTooltip/ChartTooltip.tsx similarity index 98% rename from packages/react-charts/src/components/ChartTooltip/ChartTooltip.tsx rename to packages/react-charts/src/victory/components/ChartTooltip/ChartTooltip.tsx index 05a890bea57..233c7e93b49 100644 --- a/packages/react-charts/src/components/ChartTooltip/ChartTooltip.tsx +++ b/packages/react-charts/src/victory/components/ChartTooltip/ChartTooltip.tsx @@ -1,4 +1,4 @@ -import * as React from 'react'; +import { cloneElement } from 'react'; import hoistNonReactStatics from 'hoist-non-react-statics'; import { NumberOrCallback, @@ -147,7 +147,7 @@ export interface ChartTooltipProps extends VictoryTooltipProps { * * Note: This prop should not be set manually. * - * @private + * @private Not intended as public API and subject to change * @hide */ height?: number; @@ -248,7 +248,7 @@ export interface ChartTooltipProps extends VictoryTooltipProps { * * Note: This prop should not be set manually. * - * @private + * @private Not intended as public API and subject to change * @hide */ width?: number; @@ -272,7 +272,7 @@ export const ChartTooltip: React.FunctionComponent = ({ theme = getTheme(themeColor), ...rest }: ChartTooltipProps) => { - const chartLabelComponent = React.cloneElement(labelComponent, { + const chartLabelComponent = cloneElement(labelComponent, { textAnchor: labelTextAnchor, theme, ...labelComponent.props diff --git a/packages/react-charts/src/components/ChartTooltip/__snapshots__/ChartTooltip.test.tsx.snap b/packages/react-charts/src/victory/components/ChartTooltip/__snapshots__/ChartTooltip.test.tsx.snap similarity index 72% rename from packages/react-charts/src/components/ChartTooltip/__snapshots__/ChartTooltip.test.tsx.snap rename to packages/react-charts/src/victory/components/ChartTooltip/__snapshots__/ChartTooltip.test.tsx.snap index f63b9dd16b7..6fa3536b5b7 100644 --- a/packages/react-charts/src/components/ChartTooltip/__snapshots__/ChartTooltip.test.tsx.snap +++ b/packages/react-charts/src/victory/components/ChartTooltip/__snapshots__/ChartTooltip.test.tsx.snap @@ -13,17 +13,17 @@ exports[`allows tooltip via container component 1`] = `
diff --git a/packages/react-charts/src/victory/components/ChartTooltip/examples/ChartTooltip.md b/packages/react-charts/src/victory/components/ChartTooltip/examples/ChartTooltip.md new file mode 100644 index 00000000000..41561f60db8 --- /dev/null +++ b/packages/react-charts/src/victory/components/ChartTooltip/examples/ChartTooltip.md @@ -0,0 +1,142 @@ +--- +id: Tooltips +section: components +subsection: charts +propComponents: ['ChartTooltip'] +hideDarkMode: true +--- + +import { useRef, useState, useEffect } from 'react'; +import { + Chart, + ChartArea, + ChartAxis, + ChartBar, + ChartContainer, + ChartCursorFlyout, + ChartCursorTooltip, + ChartDonut, + ChartDonutThreshold, + ChartDonutUtilization, + ChartGroup, + ChartLabel, + ChartLegend, + ChartLegendTooltip, + ChartLegendTooltipContent, + ChartLegendTooltipLabel, + ChartLine, + ChartPie, + ChartPoint, + ChartStack, + ChartThemeColor, + ChartTooltip, + ChartVoronoiContainer, + createContainer, + getCustomTheme +} from '@patternfly/react-charts/victory'; + + + +## Introduction +Note: PatternFly React charts live in its own package at [@patternfly/react-charts](https://www.npmjs.com/package/@patternfly/react-charts)! + +The examples below are based on the [Victory](https://formidable.com/open-source/victory/docs/victory-chart/) chart library, along with additional functionality, custom components, and theming for PatternFly. This provides a collection of React based components you can use to build PatternFly patterns with consistent markup, styling, and behavior. + +## Examples +### Voronoi container + +This demonstrates how to use a voronoi container to display tooltips. + +```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. + +```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. + +```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. + +```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. + +```ts file = "ChartTooltipEmbeddedCustomFontSize.tsx" + +``` + +### Data label + +This demonstrates an alternate way of applying tooltips using data labels. + +```ts file = "ChartTooltipDataLabel.tsx" + +``` + +### Fixed tooltip +This demonstrates how to adjust the tooltip position and label radius +```ts file = "ChartTooltipFixed.tsx" + +``` + +### Legend + +This demonstrates an approach for applying tooltips to a legend using a custom legend label component. + +```ts file = "ChartTooltipLegend.tsx" + +``` + +### Left aligned + +This demonstrates how to customize tooltip label alignment using theme properties. + +```ts file = "ChartTooltipLeftAligned.tsx" + +``` + +### CSS overflow + +This demonstrates an alternate way of applying tooltips using CSS overflow instead of constrainToVisibleArea. + +```ts file = "ChartTooltipCssOverflow.tsx" + +``` + +### Wrapped chart + +This demonstrates an alternate way of applying tooltips by wrapping charts with the Tooltip component. + +```ts file = "ChartTooltipWrappedChart.tsx" + +``` + +## Documentation +### Tips +- See Victory's [FAQ](https://formidable.com/open-source/victory/docs/faq) + +### Note +Currently, the generated documentation below is not able to resolve type definitions from Victory imports. For the +components used in the examples above, Victory pass-thru props are also documented here: + +- For `ChartTooltip` props, see [VictoryTooltip](https://formidable.com/open-source/victory/docs/victory-tooltip) 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/components/ChartTooltip/examples/chart-tooltip.css b/packages/react-charts/src/victory/components/ChartTooltip/examples/chart-tooltip.css similarity index 100% rename from packages/react-charts/src/components/ChartTooltip/examples/chart-tooltip.css rename to packages/react-charts/src/victory/components/ChartTooltip/examples/chart-tooltip.css diff --git a/packages/react-charts/src/components/ChartUtils/chart-container.tsx b/packages/react-charts/src/victory/components/ChartUtils/chart-container.tsx similarity index 69% rename from packages/react-charts/src/components/ChartUtils/chart-container.tsx rename to packages/react-charts/src/victory/components/ChartUtils/chart-container.tsx index c5d28afde97..8d45f2d9f6f 100644 --- a/packages/react-charts/src/components/ChartUtils/chart-container.tsx +++ b/packages/react-charts/src/victory/components/ChartUtils/chart-container.tsx @@ -1,7 +1,4 @@ -/* eslint-disable camelcase */ import chart_container_cursor_line_Fill from '@patternfly/react-tokens/dist/esm/chart_container_cursor_line_Fill'; - -import * as React from 'react'; import { ContainerType, createContainer as victoryCreateContainer } from 'victory-create-container'; import { ChartCursorTooltip } from '../ChartCursorTooltip/ChartCursorTooltip'; import { ChartLabel } from '../ChartLabel/ChartLabel'; @@ -26,22 +23,30 @@ import { LineSegment } from 'victory-core'; * @public */ export const createContainer = (behaviorA: ContainerType, behaviorB: ContainerType) => { - const container: any = victoryCreateContainer(behaviorA, behaviorB); + const Container: any = victoryCreateContainer(behaviorA, behaviorB); const isCursor = behaviorA === 'cursor' || behaviorB === 'cursor'; const isVoronoi = behaviorA === 'voronoi' || behaviorB === 'voronoi'; - if (isCursor) { - container.defaultProps.cursorLabelComponent = ; - container.defaultProps.cursorComponent = ( - - ); - } - if (isVoronoi) { - container.defaultProps.labelComponent = ; - } - return container; + const containerWrapper = (props: any) => { + const containerProps = { + ...(isCursor && { + cursorLabelComponent: , + cursorComponent: ( + + ) + }), + ...(isVoronoi && { labelComponent: }), + ...props + }; + return ; + }; + containerWrapper.defaultEvents = Container.defaultEvents; + containerWrapper.displayName = Container.displayName; + containerWrapper.role = Container.role; + + return containerWrapper; }; diff --git a/packages/react-charts/src/components/ChartUtils/chart-domain.ts b/packages/react-charts/src/victory/components/ChartUtils/chart-domain.ts similarity index 94% rename from packages/react-charts/src/components/ChartUtils/chart-domain.ts rename to packages/react-charts/src/victory/components/ChartUtils/chart-domain.ts index d180d3e3c8d..b53e4d81ea8 100644 --- a/packages/react-charts/src/components/ChartUtils/chart-domain.ts +++ b/packages/react-charts/src/victory/components/ChartUtils/chart-domain.ts @@ -1,4 +1,3 @@ -import * as React from 'react'; import { Data, DataGetterPropType } from 'victory-core'; interface DomainInterface { @@ -20,7 +19,8 @@ interface SourcesInterface { /** * Chart domain interface - * @private + * + * @private Not intended as public API and subject to change */ export interface ChartDomain { x: [number, number]; @@ -29,7 +29,8 @@ export interface ChartDomain { /** * Returns the min and max domain for given data - * @private + * + * @private Not intended as public API and subject to change */ export const getDomain = ({ data, maxDomain, minDomain, x, y }: DomainInterface): ChartDomain => { // x-domain @@ -101,7 +102,8 @@ export const getDomain = ({ data, maxDomain, minDomain, x, y }: DomainInterface) /** * Returns the domain for given min and max properties - * @private + * + * @private Not intended as public API and subject to change */ export const getDomains = ({ maxDomain, minDomain, sources }: SourcesInterface): ChartDomain => { const domains: ChartDomain[] = []; diff --git a/packages/react-charts/src/components/ChartUtils/chart-helpers.ts b/packages/react-charts/src/victory/components/ChartUtils/chart-helpers.ts similarity index 75% rename from packages/react-charts/src/components/ChartUtils/chart-helpers.ts rename to packages/react-charts/src/victory/components/ChartUtils/chart-helpers.ts index 0f68f6ccfec..a1e04b29ad6 100644 --- a/packages/react-charts/src/components/ChartUtils/chart-helpers.ts +++ b/packages/react-charts/src/victory/components/ChartUtils/chart-helpers.ts @@ -6,13 +6,15 @@ interface ChartClassNameInterface { /** * Copied from exenv - * @private + * + * @private Not intended as public API and subject to change */ export const canUseDOM = !!(typeof window !== 'undefined' && window.document && window.document.createElement); /** - * Returns the class name that will be applied to the outer-most div rendered by the chart's container - * @private + * Returns the class name that will be applied to the outermost div rendered by the chart's container + * + * @private Not intended as public API and subject to change */ export const getClassName = ({ className }: ChartClassNameInterface) => { let cleanClassName; diff --git a/packages/react-charts/src/components/ChartUtils/chart-interactive-legend.ts b/packages/react-charts/src/victory/components/ChartUtils/chart-interactive-legend.ts similarity index 98% rename from packages/react-charts/src/components/ChartUtils/chart-interactive-legend.ts rename to packages/react-charts/src/victory/components/ChartUtils/chart-interactive-legend.ts index fba78a17d3d..c1124422a97 100644 --- a/packages/react-charts/src/components/ChartUtils/chart-interactive-legend.ts +++ b/packages/react-charts/src/victory/components/ChartUtils/chart-interactive-legend.ts @@ -1,4 +1,3 @@ -/* eslint-disable camelcase */ import chart_area_Opacity from '@patternfly/react-tokens/dist/esm/chart_area_Opacity'; import chart_global_label_Fill from '@patternfly/react-tokens/dist/esm/chart_global_label_Fill'; import { Helpers } from 'victory-core'; @@ -22,7 +21,8 @@ interface ChartInteractiveLegendExtInterface extends ChartInteractiveLegendInter /** * Returns child names for each series, except given ID index - * @private + * + * @private Not intended as public API and subject to change */ const getChildNames = ({ chartNames, omitIndex }: ChartInteractiveLegendExtInterface) => { const result = [] as any; @@ -62,7 +62,8 @@ const getInteractiveLegendItems = ({ chartNames, omitIndex }: ChartInteractiveLe /** * Returns styles for interactive legend items - * @private + * + * @private Not intended as public API and subject to change */ export const getInteractiveLegendItemStyles = (hidden = false) => !hidden diff --git a/packages/react-charts/src/components/ChartUtils/chart-label.ts b/packages/react-charts/src/victory/components/ChartUtils/chart-label.ts similarity index 91% rename from packages/react-charts/src/components/ChartUtils/chart-label.ts rename to packages/react-charts/src/victory/components/ChartUtils/chart-label.ts index 3c94a2c702e..fb1a70922c8 100644 --- a/packages/react-charts/src/components/ChartUtils/chart-label.ts +++ b/packages/react-charts/src/victory/components/ChartUtils/chart-label.ts @@ -32,14 +32,16 @@ interface ChartLabelTextSizeInterface { /** * Returns x coordinate for bullet labels - * @private + * + * @private Not intended as public API and subject to change */ export const getBulletLabelX = ({ chartWidth, dx = 0, labelPosition }: ChartBulletLabelInterface) => labelPosition === 'top' && chartWidth ? Math.round(chartWidth / 2) : dx; /** * Returns y coordinate for bullet labels - * @private + * + * @private Not intended as public API and subject to change */ export const getBulletLabelY = ({ chartHeight, dy = 0, labelPosition }: ChartBulletLabelInterface) => { switch (labelPosition) { @@ -54,7 +56,8 @@ export const getBulletLabelY = ({ chartHeight, dy = 0, labelPosition }: ChartBul /** * Returns x coordinate for pie labels - * @private + * + * @private Not intended as public API and subject to change */ export const getPieLabelX = ({ dx = 0, @@ -87,7 +90,8 @@ export const getPieLabelX = ({ /** * Returns x coordinate for pie labels - * @private + * + * @private Not intended as public API and subject to change */ export const getPieLabelY = ({ dy = 0, height, labelPosition, padding, width }: ChartPieLabelInterface) => { const origin = getPieOrigin({ height, padding, width }); @@ -106,7 +110,8 @@ export const getPieLabelY = ({ dy = 0, height, labelPosition, padding, width }: /** * Returns an approximate size for the give text - * @private + * + * @private Not intended as public API and subject to change */ export const getLabelTextSize = ({ text, theme }: ChartLabelTextSizeInterface): { height: number; width: number } => { const style: any = theme.legend.style.labels; diff --git a/packages/react-charts/src/components/ChartUtils/chart-legend.ts b/packages/react-charts/src/victory/components/ChartUtils/chart-legend.ts similarity index 90% rename from packages/react-charts/src/components/ChartUtils/chart-legend.ts rename to packages/react-charts/src/victory/components/ChartUtils/chart-legend.ts index d2e07752e95..6319a05e5cc 100644 --- a/packages/react-charts/src/components/ChartUtils/chart-legend.ts +++ b/packages/react-charts/src/victory/components/ChartUtils/chart-legend.ts @@ -1,13 +1,13 @@ +import { cloneElement } from 'react'; import defaults from 'lodash/defaults'; -import { Helpers, PaddingProps, TextSize } from 'victory-core'; +import { Helpers, TextSize } from 'victory-core'; +import { ElementPadding } from 'victory-core/src/victory-util/helpers'; import { VictoryLegend } from 'victory-legend'; import { ChartLegendProps } from '../ChartLegend/ChartLegend'; import { ChartCommonStyles } from '../ChartTheme/ChartStyles'; import { ChartThemeDefinition } from '../ChartTheme/ChartTheme'; import { getLabelTextSize } from '../ChartUtils/chart-label'; import { getPieOrigin } from './chart-origin'; -import * as React from 'react'; - interface ChartLegendInterface { allowWrap?: boolean; // Allow legend items to wrap to the next line chartType?: string; // The type of chart (e.g., pie) to lookup for props @@ -17,7 +17,7 @@ interface ChartLegendInterface { height: number; // Overall height of SVG legendComponent: React.ReactElement; // The base legend component to render orientation?: 'horizontal' | 'vertical'; // Orientation of legend - padding: PaddingProps; // Chart padding + padding: ElementPadding; // Chart padding patternScale?: string[]; // Legend symbol patterns position: 'bottom' | 'bottom-left' | 'right'; // The legend position theme: ChartThemeDefinition; // The theme that will be applied to the chart @@ -41,7 +41,7 @@ interface ChartLegendPositionInterface { legendOrientation: 'horizontal' | 'vertical'; // Orientation of legend legendPosition: 'bottom' | 'bottom-left' | 'right'; // Position of legend legendProps: any; // The legend props used to determine width - padding?: PaddingProps; // Chart padding + padding?: ElementPadding; // Chart padding theme: ChartThemeDefinition; // The theme that will be applied to the chart width?: number; // Overall width of SVG } @@ -53,9 +53,9 @@ interface ChartLegendTextMaxSizeInterface { /** * Returns the max text length in a legend data set to calculate the x offset for right aligned legends. - * @private + * + * @private Not intended as public API and subject to change */ - export const getLegendMaxTextWidth = (legendData: any[], theme: ChartThemeDefinition) => { let legendXOffset = 0; legendData.map((data: any) => { @@ -69,7 +69,8 @@ export const getLegendMaxTextWidth = (legendData: any[], theme: ChartThemeDefini /** * Returns a legend which has been positioned per the given chart properties - * @private + * + * @private Not intended as public API and subject to change */ export const getComputedLegend = ({ allowWrap = true, @@ -148,12 +149,13 @@ export const getComputedLegend = ({ x: legendX > 0 ? legendX : 0, y: legendY > 0 ? legendY : 0 }); - return React.cloneElement(legendComponent, legendProps); + return cloneElement(legendComponent, legendProps); }; /** * Returns legend dimensions - * @private + * + * @private Not intended as public API and subject to change */ export const getLegendDimensions = ({ legendData, @@ -174,7 +176,8 @@ export const getLegendDimensions = ({ /** * Returns true if the legend is smaller than its container - * @private + * + * @private Not intended as public API and subject to change */ const doesLegendFit = ({ dx = 0, @@ -187,7 +190,7 @@ const doesLegendFit = ({ theme, width }: ChartLegendPositionInterface) => { - const { left, right } = Helpers.getPadding({ padding }); + const { left, right } = Helpers.getPadding(padding); const chartSize = { height, // Fixed size width: width - left - right @@ -216,7 +219,8 @@ const doesLegendFit = ({ /** * Returns the number of legend items per row - * @private + * + * @private Not intended as public API and subject to change */ const getLegendItemsPerRow = ({ dx, @@ -255,7 +259,8 @@ const getLegendItemsPerRow = ({ /** * Returns the extra height required to accommodate wrapped legend items - * @private + * + * @private Not intended as public API and subject to change */ export const getLegendItemsExtraHeight = ({ legendData, @@ -287,14 +292,16 @@ export const getLegendItemsExtraHeight = ({ /** * Returns x coordinate for legend - * @private + * + * @private Not intended as public API and subject to change */ const getLegendX = ({ chartType, ...rest }: ChartLegendPositionInterface) => chartType === 'pie' ? getPieLegendX(rest) : getChartLegendX(rest); /** * Returns y coordinate for legend - * @private + * + * @private Not intended as public API and subject to change */ const getLegendY = ({ chartType, ...rest }: ChartLegendPositionInterface) => { switch (chartType) { @@ -309,7 +316,8 @@ const getLegendY = ({ chartType, ...rest }: ChartLegendPositionInterface) => { /** * Returns y coordinate for bullet legends - * @private + * + * @private Not intended as public API and subject to change */ const getBulletLegendY = ({ dy = 0, @@ -322,7 +330,7 @@ const getBulletLegendY = ({ theme, width }: ChartLegendPositionInterface) => { - const { left, right } = Helpers.getPadding({ padding }); + const { left, right } = Helpers.getPadding(padding); const chartSize = { height, // Fixed size width: width - left - right @@ -350,7 +358,8 @@ const getBulletLegendY = ({ /** * Returns x coordinate for chart legends - * @private + * + * @private Not intended as public API and subject to change */ const getChartLegendX = ({ dx = 0, @@ -363,7 +372,7 @@ const getChartLegendX = ({ theme, width }: ChartLegendPositionInterface) => { - const { top, bottom, left, right } = Helpers.getPadding({ padding }); + const { top, bottom, left, right } = Helpers.getPadding(padding); const chartSize = { height: Math.abs(height - (bottom + top)), width: Math.abs(width - (left + right)) @@ -389,7 +398,8 @@ const getChartLegendX = ({ /** * Returns y coordinate for chart legends - * @private + * + * @private Not intended as public API and subject to change */ const getChartLegendY = ({ dy = 0, @@ -402,7 +412,7 @@ const getChartLegendY = ({ theme, width }: ChartLegendPositionInterface) => { - const { top, bottom, left, right } = Helpers.getPadding({ padding }); + const { top, bottom, left, right } = Helpers.getPadding(padding); const chartSize = { height: Math.abs(height - (bottom + top)), width: Math.abs(width - (left + right)) @@ -431,7 +441,8 @@ const getChartLegendY = ({ /** * Returns x coordinate for pie legends - * @private + * + * @private Not intended as public API and subject to change */ const getPieLegendX = ({ dx = 0, @@ -465,7 +476,8 @@ const getPieLegendX = ({ /** * Returns y coordinate for pie legends - * @private + * + * @private Not intended as public API and subject to change */ const getPieLegendY = ({ dy = 0, @@ -502,7 +514,8 @@ const getPieLegendY = ({ /** * Returns an approximation of longest text width based on legend styles - * @private + * + * @private Not intended as public API and subject to change */ // eslint-disable-next-line @typescript-eslint/no-unused-vars const getMaxLegendTextSize = ({ legendData, theme }: ChartLegendTextMaxSizeInterface) => { diff --git a/packages/react-charts/src/components/ChartUtils/chart-origin.ts b/packages/react-charts/src/victory/components/ChartUtils/chart-origin.ts similarity index 83% rename from packages/react-charts/src/components/ChartUtils/chart-origin.ts rename to packages/react-charts/src/victory/components/ChartUtils/chart-origin.ts index 7908afb2e25..e2cce4d9e8e 100644 --- a/packages/react-charts/src/components/ChartUtils/chart-origin.ts +++ b/packages/react-charts/src/victory/components/ChartUtils/chart-origin.ts @@ -9,10 +9,11 @@ interface ChartPieOriginInterface { /** * Returns the origin for pie based charts. For example, something with a radius such as pie, donut, donut utilization, * and donut threshold. - * @private + * + * @private Not intended as public API and subject to change */ export const getPieOrigin = ({ height, padding, width }: ChartPieOriginInterface) => { - const { top, bottom, left, right } = Helpers.getPadding({ padding }); + const { top, bottom, left, right } = Helpers.getPadding(padding); const radius = Helpers.getRadius({ height, width, padding }); const offsetX = (width - radius * 2 - left - right) / 2; const offsetY = (height - radius * 2 - top - bottom) / 2; diff --git a/packages/react-charts/src/components/ChartUtils/chart-padding.ts b/packages/react-charts/src/victory/components/ChartUtils/chart-padding.ts similarity index 88% rename from packages/react-charts/src/components/ChartUtils/chart-padding.ts rename to packages/react-charts/src/victory/components/ChartUtils/chart-padding.ts index 6bc970b60b6..a56ef159973 100644 --- a/packages/react-charts/src/components/ChartUtils/chart-padding.ts +++ b/packages/react-charts/src/victory/components/ChartUtils/chart-padding.ts @@ -2,7 +2,8 @@ import { PaddingProps } from 'victory-core'; /** * Helper function to return padding style properties - * @private + * + * @private Not intended as public API and subject to change */ export const getPaddingForSide = ( side: 'bottom' | 'left' | 'right' | 'top', diff --git a/packages/react-charts/src/components/ChartUtils/chart-patterns.tsx b/packages/react-charts/src/victory/components/ChartUtils/chart-patterns.tsx similarity index 88% rename from packages/react-charts/src/components/ChartUtils/chart-patterns.tsx rename to packages/react-charts/src/victory/components/ChartUtils/chart-patterns.tsx index 4eb229483b1..177f3975a9f 100644 --- a/packages/react-charts/src/components/ChartUtils/chart-patterns.tsx +++ b/packages/react-charts/src/victory/components/ChartUtils/chart-patterns.tsx @@ -1,5 +1,6 @@ -import * as React from 'react'; +import { Children, cloneElement, Fragment, isValidElement, useMemo } from 'react'; import uniqueId from 'lodash/uniqueId'; +import cloneDeep from 'lodash/cloneDeep'; interface PatternPropsInterface { children?: any; @@ -17,7 +18,8 @@ interface PatternPropsInterface { /** * Patterns were pulled from v3.0.3 of the script below, which uses the MIT license. * See https://github.com/highcharts/pattern-fill/blob/master/pattern-fill-v2.js - * @private + * + * @private Not intended as public API and subject to change */ const patterns: any = [ // Set 1 @@ -216,13 +218,15 @@ const patterns: any = [ /** * Helper function to return a pattern ID - * @private + * + * @private Not intended as public API and subject to change */ const getPatternId = () => uniqueId('pf-pattern'); /** * Helper function to return pattern defs ID - * @private + * + * @private Not intended as public API and subject to change */ const getPatternDefsId = (prefix: string, index: number) => { const id = `${prefix}:${index}`; @@ -231,7 +235,8 @@ const getPatternDefsId = (prefix: string, index: number) => { /** * Helper function to return pattern defs - * @private + * + * @private Not intended as public API and subject to change */ export const getPatternDefs = ({ colorScale, @@ -248,7 +253,7 @@ export const getPatternDefs = ({ // This is wrapped in an empty tag so Victory does not apply child props to defs const defs = ( - + {colorScale.map((color: string, index: number) => { const { @@ -266,21 +271,23 @@ export const getPatternDefs = ({ ); })} - + ); return defs; }; /** * Helper function to return pattern IDs to use as color scale - * @private + * + * @private Not intended as public API and subject to change */ const getPatternScale = (colorScale: string[], patternId: string) => colorScale.map((val: any, index: number) => `url(#${getPatternDefsId(patternId, index)})`); /** * Helper function to return default color scale - * @private + * + * @private Not intended as public API and subject to change */ const getDefaultColorScale = (colorScale: string[], themeColorScale: string[]) => { const result: string[] = []; @@ -292,7 +299,8 @@ const getDefaultColorScale = (colorScale: string[], themeColorScale: string[]) = /** * Helper function to return default pattern scale - * @private + * + * @private Not intended as public API and subject to change */ const getDefaultPatternScale = ({ colorScale, patternId, patternScale }: PatternPropsInterface) => { if (patternScale) { @@ -304,7 +312,8 @@ const getDefaultPatternScale = ({ colorScale, patternId, patternScale }: Pattern /** * Merge pattern IDs with `data.fill` property, used by interactive pie chart legend - * @private + * + * @private Not intended as public API and subject to change */ export const mergePatternData = (data: any, patternScale: string[]) => { if (!patternScale) { @@ -321,7 +330,8 @@ export const mergePatternData = (data: any, patternScale: string[]) => { /** * Helper function to return default pattern props - * @private + * + * @private Not intended as public API and subject to change */ export const useDefaultPatternProps = ({ colorScale, @@ -330,9 +340,9 @@ export const useDefaultPatternProps = ({ themeColorScale }: PatternPropsInterface) => { const defaultColorScale = getDefaultColorScale(colorScale, themeColorScale); - let defaultPatternScale = patternScale; + let defaultPatternScale = cloneDeep(patternScale); let isPatternDefs = !patternScale && hasPatterns !== undefined; - const patternId = React.useMemo(() => (isPatternDefs ? getPatternId() : undefined), [isPatternDefs]); + const patternId = useMemo(() => (isPatternDefs ? getPatternId() : undefined), [isPatternDefs]); if (isPatternDefs) { defaultPatternScale = getDefaultPatternScale({ @@ -358,12 +368,13 @@ export const useDefaultPatternProps = ({ /** * Helper function to render children with patterns - * @private + * + * @private Not intended as public API and subject to change */ export const renderChildrenWithPatterns = ({ children, patternScale, themeColor }: PatternPropsInterface) => - React.Children.toArray(children).map((child, index) => { - if (React.isValidElement(child)) { - const { ...childProps } = child.props; + Children.toArray(children).map((child, index) => { + if (isValidElement(child)) { + const { ...childProps } = child.props as any; const style = childProps.style ? { ...childProps.style } : {}; // Merge pattern IDs with `style.data.fill` property @@ -374,7 +385,7 @@ export const renderChildrenWithPatterns = ({ children, patternScale, themeColor ...style.data }; } - const _child = React.cloneElement(child, { + const _child = cloneElement(child, { ...(patternScale && { patternScale }), ...(themeColor && { themeColor }), ...childProps, diff --git a/packages/react-charts/src/components/ChartUtils/chart-theme-types.ts b/packages/react-charts/src/victory/components/ChartUtils/chart-theme-types.ts similarity index 84% rename from packages/react-charts/src/components/ChartUtils/chart-theme-types.ts rename to packages/react-charts/src/victory/components/ChartUtils/chart-theme-types.ts index 17fbae280b3..0a9a25bc432 100644 --- a/packages/react-charts/src/components/ChartUtils/chart-theme-types.ts +++ b/packages/react-charts/src/victory/components/ChartUtils/chart-theme-types.ts @@ -4,7 +4,8 @@ import merge from 'lodash/merge'; /** * Returns axis theme - * @private + * + * @private Not intended as public API and subject to change */ export const getAxisTheme = (themeColor: string): ChartThemeDefinition => { const baseTheme = getTheme(themeColor); @@ -14,7 +15,8 @@ export const getAxisTheme = (themeColor: string): ChartThemeDefinition => { /** * Returns bullet chart theme - * @private + * + * @private Not intended as public API and subject to change */ export const getBulletTheme = (themeColor: string): ChartThemeDefinition => { const baseTheme = getTheme(themeColor); @@ -24,7 +26,8 @@ export const getBulletTheme = (themeColor: string): ChartThemeDefinition => { /** * Returns comparative error measure theme for bullet chart - * @private + * + * @private Not intended as public API and subject to change */ export const getBulletComparativeErrorMeasureTheme = (themeColor: string): ChartThemeDefinition => { const baseTheme = getTheme(themeColor); @@ -34,7 +37,8 @@ export const getBulletComparativeErrorMeasureTheme = (themeColor: string): Chart /** * Returns comparative measure theme for bullet chart - * @private + * + * @private Not intended as public API and subject to change */ export const getBulletComparativeMeasureTheme = (themeColor: string): ChartThemeDefinition => { const baseTheme = getTheme(themeColor); @@ -44,7 +48,8 @@ export const getBulletComparativeMeasureTheme = (themeColor: string): ChartTheme /** * Returns comparative warning measure theme for bullet chart - * @private + * + * @private Not intended as public API and subject to change */ export const getBulletComparativeWarningMeasureTheme = (themeColor: string): ChartThemeDefinition => { const baseTheme = getTheme(themeColor); @@ -54,7 +59,8 @@ export const getBulletComparativeWarningMeasureTheme = (themeColor: string): Cha /** * Returns group title theme for bullet chart - * @private + * + * @private Not intended as public API and subject to change */ export const getBulletGroupTitleTheme = (themeColor: string): ChartThemeDefinition => { const baseTheme = getTheme(themeColor); @@ -64,7 +70,8 @@ export const getBulletGroupTitleTheme = (themeColor: string): ChartThemeDefiniti /** * Returns primary dot measure theme for bullet chart - * @private + * + * @private Not intended as public API and subject to change */ export const getBulletPrimaryDotMeasureTheme = (themeColor: string): ChartThemeDefinition => { const baseTheme = getTheme(themeColor); @@ -74,7 +81,8 @@ export const getBulletPrimaryDotMeasureTheme = (themeColor: string): ChartThemeD /** * Returns primary negative measure theme for bullet chart - * @private + * + * @private Not intended as public API and subject to change */ export const getBulletPrimaryNegativeMeasureTheme = (themeColor: string): ChartThemeDefinition => { const baseTheme = getTheme(themeColor); @@ -84,7 +92,8 @@ export const getBulletPrimaryNegativeMeasureTheme = (themeColor: string): ChartT /** * Returns primary segmented measure theme for bullet chart - * @private + * + * @private Not intended as public API and subject to change */ export const getBulletPrimarySegmentedMeasureTheme = (themeColor: string): ChartThemeDefinition => { const baseTheme = getTheme(themeColor); @@ -94,7 +103,8 @@ export const getBulletPrimarySegmentedMeasureTheme = (themeColor: string): Chart /** * Returns qualitative range theme for bullet chart - * @private + * + * @private Not intended as public API and subject to change */ export const getBulletQualitativeRangeTheme = (themeColor: string): ChartThemeDefinition => { const baseTheme = getTheme(themeColor); @@ -104,7 +114,8 @@ export const getBulletQualitativeRangeTheme = (themeColor: string): ChartThemeDe /** * Returns theme for Chart component - * @private + * + * @private Not intended as public API and subject to change */ export const getChartTheme = (themeColor: string, showAxis: boolean): ChartThemeDefinition => { const theme = getTheme(themeColor); @@ -124,7 +135,8 @@ export const getChartTheme = (themeColor: string, showAxis: boolean): ChartTheme /** * Returns donut theme - * @private + * + * @private Not intended as public API and subject to change */ export const getDonutTheme = (themeColor: string): ChartThemeDefinition => { const baseTheme = getTheme(themeColor); @@ -134,7 +146,8 @@ export const getDonutTheme = (themeColor: string): ChartThemeDefinition => { /** * Returns dynamic donut threshold theme - * @private + * + * @private Not intended as public API and subject to change */ export const getDonutThresholdDynamicTheme = (themeColor: string): ChartThemeDefinition => { const baseTheme = getTheme(themeColor); @@ -144,7 +157,8 @@ export const getDonutThresholdDynamicTheme = (themeColor: string): ChartThemeDef /** * Returns static donut threshold theme - * @private + * + * @private Not intended as public API and subject to change */ export const getDonutThresholdStaticTheme = (themeColor: string, invert?: boolean): ChartThemeDefinition => { const baseTheme = getTheme(themeColor); @@ -160,7 +174,8 @@ export const getDonutThresholdStaticTheme = (themeColor: string, invert?: boolea /** * Returns donut utilization theme - * @private + * + * @private Not intended as public API and subject to change */ export const getDonutUtilizationTheme = (themeColor: string): ChartThemeDefinition => { const baseTheme = getTheme(themeColor); @@ -170,7 +185,8 @@ export const getDonutUtilizationTheme = (themeColor: string): ChartThemeDefiniti /** * Returns threshold theme - * @private + * + * @private Not intended as public API and subject to change */ export const getThresholdTheme = (themeColor: string): ChartThemeDefinition => { const baseTheme = getTheme(themeColor); diff --git a/packages/react-charts/src/components/ChartUtils/chart-theme.ts b/packages/react-charts/src/victory/components/ChartUtils/chart-theme.ts similarity index 96% rename from packages/react-charts/src/components/ChartUtils/chart-theme.ts rename to packages/react-charts/src/victory/components/ChartUtils/chart-theme.ts index c0c4ed54a54..9e52be9a229 100644 --- a/packages/react-charts/src/components/ChartUtils/chart-theme.ts +++ b/packages/react-charts/src/victory/components/ChartUtils/chart-theme.ts @@ -32,6 +32,7 @@ export const getCustomTheme = (themeColor: string, customTheme: ChartThemeDefini /** * Returns base theme for given color + * * @public */ export const getTheme = (themeColor: string): ChartThemeDefinition => { @@ -41,8 +42,8 @@ export const getTheme = (themeColor: string): ChartThemeDefinition => { /** * Returns base component theme for given color - * @private - * @beta + * + * @private Not intended as public API and subject to change */ export const getComponentTheme = (themeColor: string): ChartComponentThemeDefinition => { const theme = cloneDeep(ChartBaseComponentTheme); @@ -51,6 +52,7 @@ export const getComponentTheme = (themeColor: string): ChartComponentThemeDefini /** * Returns theme colors + * * @public */ export const getThemeColors = (themeColor: string) => { @@ -83,8 +85,8 @@ export const getThemeColors = (themeColor: string) => { /** * Returns theme component colors - * @private - * @beta + * + * @private Not intended as public API and subject to change */ export const getThemeComponentColors = (themeColor: string) => { switch (themeColor) { diff --git a/packages/react-charts/src/components/ChartUtils/chart-tooltip.ts b/packages/react-charts/src/victory/components/ChartUtils/chart-tooltip.ts similarity index 94% rename from packages/react-charts/src/components/ChartUtils/chart-tooltip.ts rename to packages/react-charts/src/victory/components/ChartUtils/chart-tooltip.ts index 1be193feb2f..323fa2f3911 100644 --- a/packages/react-charts/src/components/ChartUtils/chart-tooltip.ts +++ b/packages/react-charts/src/victory/components/ChartUtils/chart-tooltip.ts @@ -1,4 +1,3 @@ -/* eslint-disable camelcase */ import chart_color_black_500 from '@patternfly/react-tokens/dist/esm/chart_color_black_500'; import { Helpers, OrientationTypes, StringOrNumberOrCallback } from 'victory-core'; import { ChartLegendProps } from '../ChartLegend/ChartLegend'; @@ -48,7 +47,8 @@ interface ChartLegendTooltipVisibleTextInterface { * When using a cursor container, the tooltip can be offset from the cursor point. If offsetCursorDimensionX is true, * the tooltip will appear to the right the vertical cursor. If offsetCursorDimensionY is true, the tooltip will appear * above the vertical cursor. - * @private + * + * @private Not intended as public API and subject to change */ export const getCursorTooltipCenterOffset = ({ offsetCursorDimensionX = false, @@ -74,7 +74,8 @@ export const getCursorTooltipCenterOffset = ({ * When using a cursor container, the tooltip pointer orientation can be adjusted as the cursor approaches the edge of * the chart. If horizontal is true, the tooltip pointer will either be 'left' or 'right'. If horizontal is true, the * tooltip pointer will either be 'top' or 'bottom'. - * @private + * + * @private Not intended as public API and subject to change */ export const getCursorTooltipPoniterOrientation = ({ horizontal = true, @@ -90,9 +91,10 @@ export const getCursorTooltipPoniterOrientation = ({ /** * Returns props associated with legend data - * @private + * + * @private Not intended as public API and subject to change */ -export const getLegendTooltipDataProps = (defaultProps: ChartLegendProps) => +export const getLegendTooltipDataProps = (props: ChartLegendProps) => merge( { borderPadding: 0, @@ -112,18 +114,19 @@ export const getLegendTooltipDataProps = (defaultProps: ChartLegendProps) => } } }, - { ...defaultProps } + { ...props } ); /** * Returns the legend height and width - * @private + * + * @private Not intended as public API and subject to change */ export const getLegendTooltipSize = ({ legendData, legendOrientation = 'vertical', legendProps, - minSpacing = 1, + minSpacing = 2, // Adjust min spacing, see https://issues.redhat.com/browse/COST-5648 text = '', theme }: ChartLegendTooltipFlyoutInterface) => { @@ -219,7 +222,8 @@ export const getLegendTooltipSize = ({ /** * Returns visible legend data, while syncing color scale. If textAsLegendData is true, the text prop is used as * legend data so y values can be passed individually to the label component - * @private + * + * @private Not intended as public API and subject to change */ export const getLegendTooltipVisibleData = ({ activePoints, @@ -268,7 +272,8 @@ export const getLegendTooltipVisibleData = ({ /** * Returns visible text for interactive legends - * @private + * + * @private Not intended as public API and subject to change */ export const getLegendTooltipVisibleText = ({ activePoints, diff --git a/packages/react-charts/src/components/ChartVoronoiContainer/ChartVoronoContainer.test.tsx b/packages/react-charts/src/victory/components/ChartVoronoiContainer/ChartVoronoContainer.test.tsx similarity index 97% rename from packages/react-charts/src/components/ChartVoronoiContainer/ChartVoronoContainer.test.tsx rename to packages/react-charts/src/victory/components/ChartVoronoiContainer/ChartVoronoContainer.test.tsx index 0938c334dee..33bd35b5ad4 100644 --- a/packages/react-charts/src/components/ChartVoronoiContainer/ChartVoronoContainer.test.tsx +++ b/packages/react-charts/src/victory/components/ChartVoronoiContainer/ChartVoronoContainer.test.tsx @@ -1,4 +1,3 @@ -import * as React from 'react'; import { render } from '@testing-library/react'; import { ChartArea } from '../ChartArea/ChartArea'; import { ChartGroup } from '../ChartGroup/ChartGroup'; diff --git a/packages/react-charts/src/components/ChartVoronoiContainer/ChartVoronoiContainer.tsx b/packages/react-charts/src/victory/components/ChartVoronoiContainer/ChartVoronoiContainer.tsx similarity index 96% rename from packages/react-charts/src/components/ChartVoronoiContainer/ChartVoronoiContainer.tsx rename to packages/react-charts/src/victory/components/ChartVoronoiContainer/ChartVoronoiContainer.tsx index 307ff55014b..4c5b063a6ad 100644 --- a/packages/react-charts/src/components/ChartVoronoiContainer/ChartVoronoiContainer.tsx +++ b/packages/react-charts/src/victory/components/ChartVoronoiContainer/ChartVoronoiContainer.tsx @@ -1,4 +1,4 @@ -import * as React from 'react'; +import { cloneElement } from 'react'; import hoistNonReactStatics from 'hoist-non-react-statics'; import { OriginType } from 'victory-core'; import { VictoryVoronoiContainer, VictoryVoronoiContainerProps } from 'victory-voronoi-container'; @@ -38,12 +38,12 @@ export interface ChartVoronoiContainerProps extends VictoryVoronoiContainerProps * * Note: This prop should not be set manually. * - * @private + * @private Not intended as public API and subject to change * @hide */ - children?: React.ReactElement | React.ReactElement[]; + children?: React.ReactElement | React.ReactElement[]; /** - * The className prop specifies a className that will be applied to the outer-most div rendered by the container + * The className prop specifies a className that will be applied to the outermost div rendered by the container */ className?: string; /** @@ -63,7 +63,7 @@ export interface ChartVoronoiContainerProps extends VictoryVoronoiContainerProps * the description, the more usable it will be for people using screen readers. * This prop defaults to an empty string. * - * @example "Golden retreivers make up 30%, Labs make up 25%, and other dog breeds are + * @example "Golden retrievers make up 30%, Labs make up 25%, and other dog breeds are * not represented above 5% each." */ desc?: string; @@ -139,7 +139,7 @@ export interface ChartVoronoiContainerProps extends VictoryVoronoiContainerProps * * Note: This prop should not be set manually. * - * @private + * @private Not intended as public API and subject to change * @hide */ polar?: boolean; @@ -150,7 +150,7 @@ export interface ChartVoronoiContainerProps extends VictoryVoronoiContainerProps * render in the portal container. This prop defaults to Portal, and should only be overridden when changing rendered * elements from SVG to another type of element e.g., react-native-svg elements. */ - portalComponent?: React.ReactElement; + portalComponent?: React.ReactElement; /** * The portalZIndex prop determines the z-index of the div enclosing the portal component. If a portalZIndex prop is * not set, the z-index of the enclosing div will be set to 99. @@ -236,7 +236,7 @@ export const ChartVoronoiContainer: React.FunctionComponent { const chartClassName = getClassName({ className }); - const chartLabelComponent = React.cloneElement(labelComponent, { + const chartLabelComponent = cloneElement(labelComponent, { constrainToVisibleArea, theme, ...labelComponent.props @@ -249,7 +249,6 @@ export const ChartVoronoiContainer: React.FunctionComponent
@@ -27,18 +27,18 @@ exports[`ChartVoronoiContainer 2`] = `
@@ -55,7 +55,7 @@ exports[`renders container via ChartGroup 1`] = ` @@ -80,7 +80,7 @@ exports[`renders container via ChartGroup 1`] = ` d="M50,121.42857142857142L75,92.85714285714286L100,58.57142857142856L125,50L125,150L100,150L75,150L50,150Z" role="presentation" shape-rendering="auto" - style="fill: var(--pf-v6-chart-theme--blue--ColorScale--100, #0066cc); width: 6px; fill-opacity: 0.3; stroke-width: 2; stroke: var(--pf-v6-chart-theme--blue--ColorScale--100, #0066cc);" + style="fill: var(--pf-v6-chart-theme--blue--ColorScale--100, #0066cc); width: 6px; fill-opacity: var(--pf-v6-chart-area--Opacity, 30%); stroke-width: 2; stroke: var(--pf-v6-chart-theme--blue--ColorScale--100, #0066cc);" />
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 new file mode 100644 index 00000000000..a3f4788615f --- /dev/null +++ b/packages/react-charts/src/victory/components/Patterns/examples/patterns.md @@ -0,0 +1,162 @@ +--- +id: Patterns +section: components +subsection: charts +propComponents: [ + 'Chart', + 'ChartArea', + 'ChartAxis', + 'ChartBar', + 'ChartDonut', + 'ChartDonutThreshold', + 'ChartDonutUtilization', + 'ChartGroup', + 'ChartLegend', + 'ChartLegendTooltip', + 'ChartPie', + 'ChartScatter', + 'ChartStack', + 'ChartVoronoiContainer' +] +hideDarkMode: true +--- + +import { cloneElement, createRef } from 'react'; +import { useEffect, useRef, useState } from 'react'; +import { + Chart, + ChartArea, + ChartAxis, + ChartBar, + ChartDonut, + ChartDonutThreshold, + ChartDonutUtilization, + ChartGroup, + ChartLegend, + ChartLegendTooltip, + ChartPie, + ChartScatter, + ChartStack, + ChartThemeColor, + ChartVoronoiContainer, + createContainer, + getInteractiveLegendEvents, + getInteractiveLegendItemStyles +} from '@patternfly/react-charts/victory'; +import { getResizeObserver } from '@patternfly/react-core'; +import chart_color_black_500 from '@patternfly/react-tokens/dist/esm/chart_color_black_500'; +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'; +import '@patternfly/patternfly/patternfly-charts.css'; + +## Introduction +Note: PatternFly React charts live in its own package at [@patternfly/react-charts](https://www.npmjs.com/package/@patternfly/react-charts)! + +The examples below are based on the [Victory](https://formidable.com/open-source/victory/docs/victory-chart/) chart library, along with additional functionality, custom components, and theming for PatternFly. This provides a collection of React based components you can use to build PatternFly patterns with consistent markup, styling, and behavior. + +## Examples +### Basic pie chart +```ts file = "PatternsBasicPieChart.tsx" + +``` + +### Bar chart +```ts file = "PatternsBarChart.tsx" + +``` + +### Stack chart +```ts file = "PatternsStackChart.tsx" + +``` + +### Donut chart +```ts file = "PatternsDonutChart.tsx" + +``` + +### Donut utilization chart + +This demonstrates how to hide a pattern for the static, unused portion of the donut utilization chart. + +```ts file = "PatternsDonutUtilizationChart.tsx" + +``` + +### Donut utilization chart with thresholds + +This demonstrates how to apply patterns to thresholds. + +```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`. + +```ts file = "PatternsInteractivePieChart.tsx" + +``` + +### Interactive legend with area chart + +This demonstrates how to add an interactive legend using events such as `onMouseOver`, `onMouseOut`, and `onClick`. + +```ts file = "PatternsInteractiveAreaChart.tsx" + +``` + +### Custom pattern visibility + +This demonstrates how to omit patterns from pie chart segments. + +```ts file = "PatternsCustomVisibility.tsx" + +``` + +### Custom color scale + +This demonstrates how to apply a custom color scale to patterns. + +```ts file = "PatternsCustomColorScale.tsx" + +``` + +### Custom pattern defs + +This demonstrates how to create custom patterns. + +```ts file = "PatternsCustomDefs.tsx" + +``` + +### All patterns +```ts file = "PatternsAll.tsx" + +``` + +## Documentation +### Tips +- See Victory's [FAQ](https://formidable.com/open-source/victory/docs/faq) +- `ChartLegend` may be used as a standalone component, instead of using `legendData` + +### Note +Currently, the generated documentation below is not able to resolve type definitions from Victory imports. For the +components used in the examples above, Victory pass-thru props are also documented here: + +- For `Chart` props, see [VictoryChart](https://formidable.com/open-source/victory/docs/victory-chart) +- For `ChartArea` props, see [VictoryArea](https://formidable.com/open-source/victory/docs/victory-area) +- For `ChartAxis` props, see [VictoryAxis](https://formidable.com/open-source/victory/docs/victory-axis) +- For `ChartBar` props, see [VictoryBar](https://formidable.com/open-source/victory/docs/victory-bar) +- For `ChartDonut` props, see [VictoryPie](https://formidable.com/open-source/victory/docs/victory-pie) +- For `ChartDonutThreshold` props, see [VictoryPie](https://formidable.com/open-source/victory/docs/victory-pie) +- For `ChartDonutUtilization` props, see [VictoryPie](https://formidable.com/open-source/victory/docs/victory-pie) +- For `ChartGroup` props, see [VictoryGroup](https://formidable.com/open-source/victory/docs/victory-group) +- For `ChartLegend` props, see [VictoryLegend](https://formidable.com/open-source/victory/docs/victory-legend) +- For `ChartPie` props, see [VictoryPie](https://formidable.com/open-source/victory/docs/victory-pie) +- For `ChartScatter` props, see [VictoryScatter](https://formidable.com/open-source/victory/docs/victory-scatter) +- For `ChartStack` props, see [VictoryStack](https://formidable.com/open-source/victory/docs/victory-stack) +- For `ChartVoronoiContainer` props, see [VictoryVoronoiContainer](https://formidable.com/open-source/victory/docs/victory-voronoi-container) 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 new file mode 100644 index 00000000000..4c98bbd440c --- /dev/null +++ b/packages/react-charts/src/victory/components/ResizeObserver/examples/resizeObserver.md @@ -0,0 +1,96 @@ +--- +id: Resize observer +section: components +subsection: charts +propComponents: [ + 'Chart', + 'ChartArea', + 'ChartAxis', + 'ChartBar', + 'ChartBullet', + 'ChartGroup', + 'ChartLegend', + 'ChartStack', + 'ChartThreshold', + 'ChartTooltip', + 'ChartVoronoiContainer' +] +hideDarkMode: true +--- + +import { useEffect, useRef, useState } from 'react'; +import { + Chart, + ChartArea, + ChartAxis, + ChartBar, + ChartBullet, + ChartGroup, + ChartLegend, + ChartStack, + ChartThemeColor, + ChartThreshold, + ChartTooltip, + 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 '@patternfly/patternfly/patternfly-charts.css'; + +## Introduction +Note: PatternFly React charts live in its own package at [@patternfly/react-charts](https://www.npmjs.com/package/@patternfly/react-charts)! + +The examples below are based on the [Victory](https://formidable.com/open-source/victory/docs/victory-chart/) chart library, along with additional functionality, custom components, and theming for PatternFly. This provides a collection of React based components you can use to build PatternFly patterns with consistent markup, styling, and behavior. + +Charts scale within the parent container by default, so the `width` and `height` props do not actually determine the +width and height of the chart in number of pixels, but instead define an aspect ratio for the chart. The exact number +of pixels will depend on the size of the container the chart is rendered into. In order to maintain the aspect ratio, +the parent container may be set to the same height and/or width. + +## Examples +### Responsive bullet chart with wrapping legend + +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. + +```ts file = "ResizeObserverResponsiveBullet.tsx" + +``` + +### 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. + +```ts file = "ResizeObserverResponsiveThreshold.tsx" + +``` + +### 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. + +```ts file = "ResizeObserverResponsiveStack.tsx" + +``` + +## Documentation +### Tips +- See Victory's [FAQ](https://formidable.com/open-source/victory/docs/faq) +- `ChartLegend` may be used as a standalone component, instead of using `legendData` + +### Note +Currently, the generated documentation below is not able to resolve type definitions from Victory imports. For the +components used in the examples above, Victory pass-thru props are also documented here: + +- For `Chart` props, see [VictoryChart](https://formidable.com/open-source/victory/docs/victory-chart) +- For `ChartArea` props, see [VictoryArea](https://formidable.com/open-source/victory/docs/victory-area) +- For `ChartAxis` props, see [VictoryAxis](https://formidable.com/open-source/victory/docs/victory-axis) +- For `ChartBar` props, see [VictoryBar](https://formidable.com/open-source/victory/docs/victory-bar) +- For `ChartBullet` props, see [VictoryBar](https://formidable.com/open-source/victory/docs/victory-bar) +- For `ChartGroup` props, see [VictoryGroup](https://formidable.com/open-source/victory/docs/victory-group) +- For `ChartLegend` props, see [VictoryLegend](https://formidable.com/open-source/victory/docs/victory-legend) +- For `ChartLine` props, see [Victoryline](https://formidable.com/open-source/victory/docs/victory-line) +- For `ChartStack` props, see [VictoryStack](https://formidable.com/open-source/victory/docs/victory-stack) +- For `ChartTooltip` props, see [VictoryTooltip](https://formidable.com/open-source/victory/docs/victory-tooltip) +- For `ChartThreshold` props, see [VictoryLine](https://formidable.com/open-source/victory/docs/victory-line) +- For `ChartVoronoiContainer` props, see [VictoryVoronoiContainer](https://formidable.com/open-source/victory/docs/victory-voronoi-container) 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 new file mode 100644 index 00000000000..7e1c7ae85e0 --- /dev/null +++ b/packages/react-charts/src/victory/components/Skeletons/examples/skeletons.md @@ -0,0 +1,126 @@ +--- +id: Skeletons +section: components +subsection: charts +propComponents: [ + 'Chart', + 'ChartArea', + 'ChartAxis', + 'ChartBar', + 'ChartBoxPlot', + 'ChartBullet', + 'ChartDonut', + 'ChartDonutThreshold', + 'ChartDonutUtilization', + 'ChartLegend', + 'ChartLine', + 'ChartGroup', + 'ChartPie', + 'ChartScatter', + 'ChartStack', + 'ChartThreshold', + 'ChartVoronoiContainer' +] +hideDarkMode: true +--- + +import { useState } from 'react'; +import { Chart, ChartArea, ChartAxis, ChartBar, ChartBoxPlot, ChartBullet, ChartDonut, ChartDonutThreshold, ChartDonutUtilization, ChartLegend, ChartLine, ChartGroup, ChartPie, ChartScatter, ChartStack, ChartThemeColor, ChartThreshold, 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'; + +## Introduction +Note: PatternFly React charts live in its own package at [@patternfly/react-charts](https://www.npmjs.com/package/@patternfly/react-charts)! + +The examples below are based on the [Victory](https://formidable.com/open-source/victory/docs/victory-chart/) chart library, along with additional functionality, custom components, and theming for PatternFly. This provides a collection of React based components you can use to build PatternFly patterns with consistent markup, styling, and behavior. + +## Examples +### Area chart +```ts file = "SkeletonsAreaChart.tsx" + +``` + +### Bar chart +```ts file = "SkeletonsBarChart.tsx" + +``` + +### Box plot chart +```ts file = "SkeletonsBoxPlotChart.tsx" + +``` + +### Bullet chart +```ts file = "SkeletonsBulletChart.tsx" + +``` + +### Donut chart +```ts file = "SkeletonsDonutChart.tsx" + +``` + +### Donut utilization chart +```ts file = "SkeletonsDonutUtilizationChart.tsx" + +``` + +### Donut utilization threshold +```ts file = "SkeletonsDonutUtilizationThreshold.tsx" + +``` + +### Line chart +```ts file = "SkeletonsLineChart.tsx" + +``` + +### Pie chart +```ts file = "SkeletonsPieChart.tsx" + +``` + +### Scatter chart +```ts file = "SkeletonsScatterChart.tsx" + +``` + +### Stack chart +```ts file = "SkeletonsStackChart.tsx" + +``` + +### Threshold chart +```ts file = "SkeletonsThresholdChart.tsx" + +``` + +## Documentation +### Tips +- It's best for skeletons not to include interactions such as tooltips, cursors, interactive legends, etc. +- See Victory's [FAQ](https://formidable.com/open-source/victory/docs/faq) +- For single data points or zero values, you may want to set the `domain` prop +- `ChartLegend` may be used as a standalone component, instead of using `legendData` +- The `theme` and `themeColor` props should be applied at the most top level component +- Use `ChartGroup` to apply theme color scales and other properties to multiple components + +### Note +Currently, the generated documentation below is not able to resolve type definitions from Victory imports. For the +components used in the examples above, Victory pass-thru props are also documented here: + +- For `Chart` props, see [VictoryChart](https://formidable.com/open-source/victory/docs/victory-chart) +- For `ChartArea` props, see [VictoryArea](https://formidable.com/open-source/victory/docs/victory-area) +- For `ChartAxis` props, see [VictoryAxis](https://formidable.com/open-source/victory/docs/victory-axis) +- For `ChartBar` props, see [VictoryBar](https://formidable.com/open-source/victory/docs/victory-bar) +- For `ChartBoxPlot` props, see [VictoryBoxPlot](https://formidable.com/open-source/victory/docs/victory-box-plot) +- For `ChartBullet` props, see [VictoryBar](https://formidable.com/open-source/victory/docs/victory-bar) +- For `ChartDonut` props, see [VictoryPie](https://formidable.com/open-source/victory/docs/victory-pie) +- For `ChartDonutThreshold` props, see [VictoryPie](https://formidable.com/open-source/victory/docs/victory-pie) +- For `ChartDonutUtilization` props, see [VictoryPie](https://formidable.com/open-source/victory/docs/victory-pie) +- For `ChartLine` props, see [Victoryline](https://formidable.com/open-source/victory/docs/victory-line) +- For `ChartGroup` props, see [VictoryGroup](https://formidable.com/open-source/victory/docs/victory-group) +- For `ChartPie` props, see [VictoryPie](https://formidable.com/open-source/victory/docs/victory-pie) +- For `ChartScatter` props, see [VictoryScatter](https://formidable.com/open-source/victory/docs/victory-scatter) +- For `ChartStack` props, see [VictoryStack](https://formidable.com/open-source/victory/docs/victory-stack) +- For `ChartThreshold` props, see [VictoryLine](https://formidable.com/open-source/victory/docs/victory-line) +- For `ChartVoronoiContainer` props, see [VictoryVoronoiContainer](https://formidable.com/open-source/victory/docs/victory-voronoi-container) 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/components/Sparkline/examples/sparkline.css b/packages/react-charts/src/victory/components/Sparkline/examples/sparkline.css similarity index 100% rename from packages/react-charts/src/components/Sparkline/examples/sparkline.css rename to packages/react-charts/src/victory/components/Sparkline/examples/sparkline.css diff --git a/packages/react-charts/src/victory/components/Sparkline/examples/sparkline.md b/packages/react-charts/src/victory/components/Sparkline/examples/sparkline.md new file mode 100644 index 00000000000..6802cb6bde0 --- /dev/null +++ b/packages/react-charts/src/victory/components/Sparkline/examples/sparkline.md @@ -0,0 +1,56 @@ +--- +id: Sparkline chart +section: components +subsection: charts +propComponents: [ + 'ChartArea', + 'ChartContainer', + 'ChartGroup', + 'ChartLabel', + 'ChartVoronoiContainer' +] +hideDarkMode: true +--- + +import { ChartArea, ChartContainer, ChartGroup, ChartLabel, ChartThemeColor, ChartVoronoiContainer } from '@patternfly/react-charts/victory'; +import { useEffect } from 'react'; + + + +## Introduction +Note: PatternFly React charts live in its own package at [@patternfly/react-charts](https://www.npmjs.com/package/@patternfly/react-charts)! + +The examples below are based on the [Victory](https://formidable.com/open-source/victory/docs/victory-chart/) chart library, along with additional functionality, custom components, and theming for PatternFly. This provides a collection of React based components you can use to build PatternFly patterns with consistent markup, styling, and behavior. + +## Examples +### Basic +```ts file = "SparklineBasic.tsx" + +``` + +### Green + +This demonstrates an alternate way of applying tooltips using CSS overflow + +```ts file = "SparklineGreen.tsx" + +``` + +## Documentation +### Tips +- See Victory's [FAQ](https://formidable.com/open-source/victory/docs/faq) +- For single data points or zero values, you may want to set the `domain` prop +- Use `ChartGroup` in place of `Chart` when an axis and labels are not desired +- Themes are inherited, so a default theme may override `themeColor` for a child component +- The `theme` and `themeColor` props should be applied at the most top level component + +### Note +Currently, the generated documentation below is not able to resolve type definitions from Victory imports. For the +components used in the examples above, Victory pass-thru props are also documented here: + +- For `ChartArea` props, see [VictoryArea](https://formidable.com/open-source/victory/docs/victory-area) +- For `ChartGroup` props, see [VictoryGroup](https://formidable.com/open-source/victory/docs/victory-group) +- For `ChartLabel` props, see [VictoryLabel](https://formidable.com/open-source/victory/docs/victory-label) +- For `ChartVoronoiContainer` props, see [VictoryVoronoiContainer](https://formidable.com/open-source/victory/docs/victory-voronoi-container) diff --git a/packages/react-charts/src/components/index.ts b/packages/react-charts/src/victory/components/index.ts similarity index 100% rename from packages/react-charts/src/components/index.ts rename to packages/react-charts/src/victory/components/index.ts diff --git a/packages/react-charts/src/victory/index.ts b/packages/react-charts/src/victory/index.ts new file mode 100644 index 00000000000..07635cbbc8e --- /dev/null +++ b/packages/react-charts/src/victory/index.ts @@ -0,0 +1 @@ +export * from './components'; diff --git a/packages/react-charts/src/typings/hoist.d.ts b/packages/react-charts/src/victory/typings/hoist.d.ts similarity index 100% rename from packages/react-charts/src/typings/hoist.d.ts rename to packages/react-charts/src/victory/typings/hoist.d.ts diff --git a/packages/react-charts/src/typings/victory.d.ts b/packages/react-charts/src/victory/typings/victory.d.ts similarity index 100% rename from packages/react-charts/src/typings/victory.d.ts rename to packages/react-charts/src/victory/typings/victory.d.ts diff --git a/packages/react-charts/subpaths.config.json b/packages/react-charts/subpaths.config.json new file mode 100644 index 00000000000..706c0581100 --- /dev/null +++ b/packages/react-charts/subpaths.config.json @@ -0,0 +1,4 @@ +{ + "packageName": "@patternfly/react-charts", + "paths": ["echarts", "victory"] +} diff --git a/packages/react-charts/tsconfig.json b/packages/react-charts/tsconfig.json index 30bec2faa4a..b163d5d03bf 100644 --- a/packages/react-charts/tsconfig.json +++ b/packages/react-charts/tsconfig.json @@ -3,7 +3,12 @@ "compilerOptions": { "rootDir": "./src", "outDir": "./dist/esm", - "tsBuildInfoFile": "dist/esm.tsbuildinfo" + "tsBuildInfoFile": "dist/esm.tsbuildinfo", + "noImplicitAny": false, + "baseUrl": ".", + "paths": { + "./next": ["./src/echarts/next"] + } }, "include": [ "./src/*", diff --git a/packages/react-code-editor/CHANGELOG.md b/packages/react-code-editor/CHANGELOG.md index aca0c8475c7..639dece0431 100644 --- a/packages/react-code-editor/CHANGELOG.md +++ b/packages/react-code-editor/CHANGELOG.md @@ -3,6 +3,1111 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [6.6.0-prerelease.7](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-code-editor@6.6.0-prerelease.6...@patternfly/react-code-editor@6.6.0-prerelease.7) (2026-06-15) + +**Note:** Version bump only for package @patternfly/react-code-editor + +# [6.6.0-prerelease.6](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-code-editor@6.6.0-prerelease.5...@patternfly/react-code-editor@6.6.0-prerelease.6) (2026-06-11) + +**Note:** Version bump only for package @patternfly/react-code-editor + +# [6.6.0-prerelease.5](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-code-editor@6.6.0-prerelease.4...@patternfly/react-code-editor@6.6.0-prerelease.5) (2026-06-11) + +**Note:** Version bump only for package @patternfly/react-code-editor + +# [6.6.0-prerelease.4](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-code-editor@6.6.0-prerelease.3...@patternfly/react-code-editor@6.6.0-prerelease.4) (2026-06-11) + +**Note:** Version bump only for package @patternfly/react-code-editor + +# [6.6.0-prerelease.3](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-code-editor@6.6.0-prerelease.2...@patternfly/react-code-editor@6.6.0-prerelease.3) (2026-06-10) + +**Note:** Version bump only for package @patternfly/react-code-editor + +# [6.6.0-prerelease.2](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-code-editor@6.6.0-prerelease.1...@patternfly/react-code-editor@6.6.0-prerelease.2) (2026-05-27) + +### Features + +- **CodeEditor:** add isHighContrastTheme ([#12384](https://github.com/patternfly/patternfly-react/issues/12384)) ([bee95e6](https://github.com/patternfly/patternfly-react/commit/bee95e6397fcc7ee326ac8d29d59f65365db02bf)) + +# [6.6.0-prerelease.1](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-code-editor@6.5.1-prerelease.0...@patternfly/react-code-editor@6.6.0-prerelease.1) (2026-05-26) + +### Bug Fixes + +- updated to do 6.6.0 prereleases. ([#12434](https://github.com/patternfly/patternfly-react/issues/12434)) ([6e09ce8](https://github.com/patternfly/patternfly-react/commit/6e09ce8322ff13354991d901782231d437249aa6)) + +## [6.5.1-prerelease.0](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-code-editor@6.5.0...@patternfly/react-code-editor@6.5.1-prerelease.0) (2026-05-21) + +**Note:** Version bump only for package @patternfly/react-code-editor + +# 6.5.0 (2026-05-20) + +### Reverts + +- Revert "chore(release): releasing packages [ci skip]" ([7185856](https://github.com/patternfly/patternfly-react/commit/7185856d4985da5129bbabd6c460049e7048dd2a)) + +# [6.5.0-prerelease.82](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-code-editor@6.5.0-prerelease.81...@patternfly/react-code-editor@6.5.0-prerelease.82) (2026-05-19) + +**Note:** Version bump only for package @patternfly/react-code-editor + +# [6.5.0-prerelease.81](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-code-editor@6.5.0-prerelease.80...@patternfly/react-code-editor@6.5.0-prerelease.81) (2026-05-14) + +**Note:** Version bump only for package @patternfly/react-code-editor + +# [6.5.0-prerelease.80](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-code-editor@6.5.0-prerelease.79...@patternfly/react-code-editor@6.5.0-prerelease.80) (2026-05-13) + +**Note:** Version bump only for package @patternfly/react-code-editor + +# [6.5.0-prerelease.79](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-code-editor@6.5.0-prerelease.78...@patternfly/react-code-editor@6.5.0-prerelease.79) (2026-05-12) + +**Note:** Version bump only for package @patternfly/react-code-editor + +# [6.5.0-prerelease.78](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-code-editor@6.5.0-prerelease.77...@patternfly/react-code-editor@6.5.0-prerelease.78) (2026-05-12) + +**Note:** Version bump only for package @patternfly/react-code-editor + +# [6.5.0-prerelease.77](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-code-editor@6.5.0-prerelease.76...@patternfly/react-code-editor@6.5.0-prerelease.77) (2026-05-08) + +**Note:** Version bump only for package @patternfly/react-code-editor + +# [6.5.0-prerelease.76](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-code-editor@6.5.0-prerelease.75...@patternfly/react-code-editor@6.5.0-prerelease.76) (2026-05-08) + +**Note:** Version bump only for package @patternfly/react-code-editor + +# [6.5.0-prerelease.75](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-code-editor@6.5.0-prerelease.74...@patternfly/react-code-editor@6.5.0-prerelease.75) (2026-05-08) + +**Note:** Version bump only for package @patternfly/react-code-editor + +# [6.5.0-prerelease.74](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-code-editor@6.5.0-prerelease.73...@patternfly/react-code-editor@6.5.0-prerelease.74) (2026-05-07) + +**Note:** Version bump only for package @patternfly/react-code-editor + +# [6.5.0-prerelease.73](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-code-editor@6.5.0-prerelease.72...@patternfly/react-code-editor@6.5.0-prerelease.73) (2026-05-07) + +**Note:** Version bump only for package @patternfly/react-code-editor + +# [6.5.0-prerelease.72](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-code-editor@6.5.0-prerelease.71...@patternfly/react-code-editor@6.5.0-prerelease.72) (2026-05-07) + +**Note:** Version bump only for package @patternfly/react-code-editor + +# [6.5.0-prerelease.71](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-code-editor@6.5.0-prerelease.70...@patternfly/react-code-editor@6.5.0-prerelease.71) (2026-05-05) + +**Note:** Version bump only for package @patternfly/react-code-editor + +# [6.5.0-prerelease.70](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-code-editor@6.5.0-prerelease.69...@patternfly/react-code-editor@6.5.0-prerelease.70) (2026-05-05) + +**Note:** Version bump only for package @patternfly/react-code-editor + +# [6.5.0-prerelease.69](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-code-editor@6.5.0-prerelease.68...@patternfly/react-code-editor@6.5.0-prerelease.69) (2026-05-05) + +**Note:** Version bump only for package @patternfly/react-code-editor + +# [6.5.0-prerelease.68](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-code-editor@6.5.0-prerelease.67...@patternfly/react-code-editor@6.5.0-prerelease.68) (2026-05-01) + +**Note:** Version bump only for package @patternfly/react-code-editor + +# [6.5.0-prerelease.67](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-code-editor@6.5.0-prerelease.66...@patternfly/react-code-editor@6.5.0-prerelease.67) (2026-04-29) + +**Note:** Version bump only for package @patternfly/react-code-editor + +# [6.5.0-prerelease.66](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-code-editor@6.5.0-prerelease.65...@patternfly/react-code-editor@6.5.0-prerelease.66) (2026-04-28) + +**Note:** Version bump only for package @patternfly/react-code-editor + +# [6.5.0-prerelease.65](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-code-editor@6.5.0-prerelease.64...@patternfly/react-code-editor@6.5.0-prerelease.65) (2026-04-27) + +**Note:** Version bump only for package @patternfly/react-code-editor + +# [6.5.0-prerelease.64](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-code-editor@6.5.0-prerelease.63...@patternfly/react-code-editor@6.5.0-prerelease.64) (2026-04-24) + +**Note:** Version bump only for package @patternfly/react-code-editor + +# [6.5.0-prerelease.63](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-code-editor@6.5.0-prerelease.62...@patternfly/react-code-editor@6.5.0-prerelease.63) (2026-04-24) + +**Note:** Version bump only for package @patternfly/react-code-editor + +# [6.5.0-prerelease.62](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-code-editor@6.5.0-prerelease.61...@patternfly/react-code-editor@6.5.0-prerelease.62) (2026-04-20) + +**Note:** Version bump only for package @patternfly/react-code-editor + +# [6.5.0-prerelease.61](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-code-editor@6.5.0-prerelease.60...@patternfly/react-code-editor@6.5.0-prerelease.61) (2026-04-17) + +**Note:** Version bump only for package @patternfly/react-code-editor + +# [6.5.0-prerelease.60](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-code-editor@6.5.0-prerelease.59...@patternfly/react-code-editor@6.5.0-prerelease.60) (2026-04-16) + +**Note:** Version bump only for package @patternfly/react-code-editor + +# [6.5.0-prerelease.59](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-code-editor@6.5.0-prerelease.58...@patternfly/react-code-editor@6.5.0-prerelease.59) (2026-04-15) + +**Note:** Version bump only for package @patternfly/react-code-editor + +# [6.5.0-prerelease.58](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-code-editor@6.5.0-prerelease.57...@patternfly/react-code-editor@6.5.0-prerelease.58) (2026-04-15) + +**Note:** Version bump only for package @patternfly/react-code-editor + +# [6.5.0-prerelease.57](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-code-editor@6.5.0-prerelease.56...@patternfly/react-code-editor@6.5.0-prerelease.57) (2026-04-14) + +**Note:** Version bump only for package @patternfly/react-code-editor + +# [6.5.0-prerelease.56](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-code-editor@6.5.0-prerelease.55...@patternfly/react-code-editor@6.5.0-prerelease.56) (2026-04-13) + +**Note:** Version bump only for package @patternfly/react-code-editor + +# [6.5.0-prerelease.55](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-code-editor@6.5.0-prerelease.54...@patternfly/react-code-editor@6.5.0-prerelease.55) (2026-04-13) + +**Note:** Version bump only for package @patternfly/react-code-editor + +# [6.5.0-prerelease.54](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-code-editor@6.5.0-prerelease.53...@patternfly/react-code-editor@6.5.0-prerelease.54) (2026-04-10) + +### Features + +- **Icons:** updated cog icons to rh settings ([#12345](https://github.com/patternfly/patternfly-react/issues/12345)) ([190da46](https://github.com/patternfly/patternfly-react/commit/190da4621acef4edd1697bb8ebccfd02299ae870)) + +# [6.5.0-prerelease.53](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-code-editor@6.5.0-prerelease.52...@patternfly/react-code-editor@6.5.0-prerelease.53) (2026-04-06) + +**Note:** Version bump only for package @patternfly/react-code-editor + +# [6.5.0-prerelease.52](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-code-editor@6.5.0-prerelease.51...@patternfly/react-code-editor@6.5.0-prerelease.52) (2026-04-03) + +**Note:** Version bump only for package @patternfly/react-code-editor + +# [6.5.0-prerelease.51](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-code-editor@6.5.0-prerelease.50...@patternfly/react-code-editor@6.5.0-prerelease.51) (2026-04-01) + +**Note:** Version bump only for package @patternfly/react-code-editor + +# [6.5.0-prerelease.50](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-code-editor@6.5.0-prerelease.49...@patternfly/react-code-editor@6.5.0-prerelease.50) (2026-04-01) + +**Note:** Version bump only for package @patternfly/react-code-editor + +# [6.5.0-prerelease.49](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-code-editor@6.5.0-prerelease.48...@patternfly/react-code-editor@6.5.0-prerelease.49) (2026-04-01) + +**Note:** Version bump only for package @patternfly/react-code-editor + +# [6.5.0-prerelease.48](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-code-editor@6.5.0-prerelease.47...@patternfly/react-code-editor@6.5.0-prerelease.48) (2026-04-01) + +**Note:** Version bump only for package @patternfly/react-code-editor + +# [6.5.0-prerelease.47](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-code-editor@6.5.0-prerelease.46...@patternfly/react-code-editor@6.5.0-prerelease.47) (2026-03-31) + +**Note:** Version bump only for package @patternfly/react-code-editor + +# [6.5.0-prerelease.46](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-code-editor@6.5.0-prerelease.45...@patternfly/react-code-editor@6.5.0-prerelease.46) (2026-03-31) + +**Note:** Version bump only for package @patternfly/react-code-editor + +# [6.5.0-prerelease.45](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-code-editor@6.5.0-prerelease.44...@patternfly/react-code-editor@6.5.0-prerelease.45) (2026-03-27) + +**Note:** Version bump only for package @patternfly/react-code-editor + +# [6.5.0-prerelease.44](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-code-editor@6.5.0-prerelease.43...@patternfly/react-code-editor@6.5.0-prerelease.44) (2026-03-25) + +**Note:** Version bump only for package @patternfly/react-code-editor + +# [6.5.0-prerelease.43](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-code-editor@6.5.0-prerelease.42...@patternfly/react-code-editor@6.5.0-prerelease.43) (2026-03-25) + +**Note:** Version bump only for package @patternfly/react-code-editor + +# [6.5.0-prerelease.42](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-code-editor@6.5.0-prerelease.41...@patternfly/react-code-editor@6.5.0-prerelease.42) (2026-03-19) + +**Note:** Version bump only for package @patternfly/react-code-editor + +# [6.5.0-prerelease.41](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-code-editor@6.5.0-prerelease.40...@patternfly/react-code-editor@6.5.0-prerelease.41) (2026-03-13) + +**Note:** Version bump only for package @patternfly/react-code-editor + +# [6.5.0-prerelease.40](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-code-editor@6.5.0-prerelease.39...@patternfly/react-code-editor@6.5.0-prerelease.40) (2026-03-05) + +**Note:** Version bump only for package @patternfly/react-code-editor + +# [6.5.0-prerelease.39](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-code-editor@6.5.0-prerelease.38...@patternfly/react-code-editor@6.5.0-prerelease.39) (2026-02-26) + +**Note:** Version bump only for package @patternfly/react-code-editor + +# [6.5.0-prerelease.38](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-code-editor@6.5.0-prerelease.37...@patternfly/react-code-editor@6.5.0-prerelease.38) (2026-02-25) + +**Note:** Version bump only for package @patternfly/react-code-editor + +# [6.5.0-prerelease.37](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-code-editor@6.5.0-prerelease.36...@patternfly/react-code-editor@6.5.0-prerelease.37) (2026-02-24) + +**Note:** Version bump only for package @patternfly/react-code-editor + +# [6.5.0-prerelease.36](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-code-editor@6.5.0-prerelease.35...@patternfly/react-code-editor@6.5.0-prerelease.36) (2026-02-18) + +### Features + +- **icons:** add swap support for mapped rh-ui icons ([#12245](https://github.com/patternfly/patternfly-react/issues/12245)) ([a81ce0e](https://github.com/patternfly/patternfly-react/commit/a81ce0e1b6fdd7a3e85cdd70e5bb667dc7d82801)) + +# [6.5.0-prerelease.35](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-code-editor@6.5.0-prerelease.34...@patternfly/react-code-editor@6.5.0-prerelease.35) (2026-02-06) + +**Note:** Version bump only for package @patternfly/react-code-editor + +# [6.5.0-prerelease.34](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-code-editor@6.5.0-prerelease.33...@patternfly/react-code-editor@6.5.0-prerelease.34) (2026-02-06) + +**Note:** Version bump only for package @patternfly/react-code-editor + +# [6.5.0-prerelease.33](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-code-editor@6.5.0-prerelease.32...@patternfly/react-code-editor@6.5.0-prerelease.33) (2026-02-05) + +**Note:** Version bump only for package @patternfly/react-code-editor + +# [6.5.0-prerelease.32](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-code-editor@6.5.0-prerelease.31...@patternfly/react-code-editor@6.5.0-prerelease.32) (2026-02-05) + +**Note:** Version bump only for package @patternfly/react-code-editor + +# [6.5.0-prerelease.31](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-code-editor@6.5.0-prerelease.30...@patternfly/react-code-editor@6.5.0-prerelease.31) (2026-01-27) + +### Bug Fixes + +- **CodeEditor:** prevent focus loss ([#12211](https://github.com/patternfly/patternfly-react/issues/12211)) ([#12212](https://github.com/patternfly/patternfly-react/issues/12212)) ([61ea8ae](https://github.com/patternfly/patternfly-react/commit/61ea8aeb5e80229fcb7ce2f2b731b745b978fc19)) + +# [6.5.0-prerelease.30](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-code-editor@6.5.0-prerelease.29...@patternfly/react-code-editor@6.5.0-prerelease.30) (2026-01-12) + +**Note:** Version bump only for package @patternfly/react-code-editor + +# [6.5.0-prerelease.29](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-code-editor@6.5.0-prerelease.28...@patternfly/react-code-editor@6.5.0-prerelease.29) (2026-01-09) + +**Note:** Version bump only for package @patternfly/react-code-editor + +# [6.5.0-prerelease.28](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-code-editor@6.5.0-prerelease.27...@patternfly/react-code-editor@6.5.0-prerelease.28) (2026-01-09) + +**Note:** Version bump only for package @patternfly/react-code-editor + +# [6.5.0-prerelease.27](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-code-editor@6.5.0-prerelease.26...@patternfly/react-code-editor@6.5.0-prerelease.27) (2025-12-17) + +**Note:** Version bump only for package @patternfly/react-code-editor + +# [6.5.0-prerelease.26](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-code-editor@6.5.0-prerelease.22...@patternfly/react-code-editor@6.5.0-prerelease.26) (2025-12-16) + +**Note:** Version bump only for package @patternfly/react-code-editor + +# [6.5.0-prerelease.22](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-code-editor@6.5.0-prerelease.21...@patternfly/react-code-editor@6.5.0-prerelease.22) (2025-12-03) + +**Note:** Version bump only for package @patternfly/react-code-editor + +# [6.5.0-prerelease.21](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-code-editor@6.5.0-prerelease.20...@patternfly/react-code-editor@6.5.0-prerelease.21) (2025-12-03) + +**Note:** Version bump only for package @patternfly/react-code-editor + +# [6.5.0-prerelease.20](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-code-editor@6.5.0-prerelease.19...@patternfly/react-code-editor@6.5.0-prerelease.20) (2025-12-01) + +**Note:** Version bump only for package @patternfly/react-code-editor + +# [6.5.0-prerelease.19](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-code-editor@6.5.0-prerelease.18...@patternfly/react-code-editor@6.5.0-prerelease.19) (2025-11-21) + +**Note:** Version bump only for package @patternfly/react-code-editor + +# [6.5.0-prerelease.18](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-code-editor@6.5.0-prerelease.17...@patternfly/react-code-editor@6.5.0-prerelease.18) (2025-11-21) + +**Note:** Version bump only for package @patternfly/react-code-editor + +# [6.5.0-prerelease.17](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-code-editor@6.5.0-prerelease.16...@patternfly/react-code-editor@6.5.0-prerelease.17) (2025-11-20) + +**Note:** Version bump only for package @patternfly/react-code-editor + +# [6.5.0-prerelease.16](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-code-editor@6.5.0-prerelease.15...@patternfly/react-code-editor@6.5.0-prerelease.16) (2025-11-20) + +**Note:** Version bump only for package @patternfly/react-code-editor + +# [6.5.0-prerelease.15](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-code-editor@6.5.0-prerelease.14...@patternfly/react-code-editor@6.5.0-prerelease.15) (2025-11-19) + +**Note:** Version bump only for package @patternfly/react-code-editor + +# [6.5.0-prerelease.14](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-code-editor@6.5.0-prerelease.13...@patternfly/react-code-editor@6.5.0-prerelease.14) (2025-11-17) + +**Note:** Version bump only for package @patternfly/react-code-editor + +# [6.5.0-prerelease.13](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-code-editor@6.5.0-prerelease.12...@patternfly/react-code-editor@6.5.0-prerelease.13) (2025-11-14) + +**Note:** Version bump only for package @patternfly/react-code-editor + +# [6.5.0-prerelease.12](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-code-editor@6.5.0-prerelease.11...@patternfly/react-code-editor@6.5.0-prerelease.12) (2025-11-12) + +**Note:** Version bump only for package @patternfly/react-code-editor + +# [6.5.0-prerelease.11](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-code-editor@6.5.0-prerelease.10...@patternfly/react-code-editor@6.5.0-prerelease.11) (2025-11-10) + +**Note:** Version bump only for package @patternfly/react-code-editor + +# [6.5.0-prerelease.10](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-code-editor@6.5.0-prerelease.9...@patternfly/react-code-editor@6.5.0-prerelease.10) (2025-11-10) + +**Note:** Version bump only for package @patternfly/react-code-editor + +# [6.5.0-prerelease.9](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-code-editor@6.5.0-prerelease.8...@patternfly/react-code-editor@6.5.0-prerelease.9) (2025-11-06) + +**Note:** Version bump only for package @patternfly/react-code-editor + +# [6.5.0-prerelease.8](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-code-editor@6.5.0-prerelease.7...@patternfly/react-code-editor@6.5.0-prerelease.8) (2025-11-06) + +**Note:** Version bump only for package @patternfly/react-code-editor + +# [6.5.0-prerelease.7](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-code-editor@6.5.0-prerelease.6...@patternfly/react-code-editor@6.5.0-prerelease.7) (2025-11-05) + +**Note:** Version bump only for package @patternfly/react-code-editor + +# [6.5.0-prerelease.6](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-code-editor@6.5.0-prerelease.5...@patternfly/react-code-editor@6.5.0-prerelease.6) (2025-11-05) + +**Note:** Version bump only for package @patternfly/react-code-editor + +# [6.5.0-prerelease.5](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-code-editor@6.5.0-prerelease.4...@patternfly/react-code-editor@6.5.0-prerelease.5) (2025-11-05) + +**Note:** Version bump only for package @patternfly/react-code-editor + +# [6.5.0-prerelease.4](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-code-editor@6.5.0-prerelease.3...@patternfly/react-code-editor@6.5.0-prerelease.4) (2025-11-03) + +**Note:** Version bump only for package @patternfly/react-code-editor + +# [6.5.0-prerelease.3](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-code-editor@6.5.0-prerelease.2...@patternfly/react-code-editor@6.5.0-prerelease.3) (2025-11-03) + +**Note:** Version bump only for package @patternfly/react-code-editor + +# [6.5.0-prerelease.2](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-code-editor@6.5.0-prerelease.1...@patternfly/react-code-editor@6.5.0-prerelease.2) (2025-10-31) + +**Note:** Version bump only for package @patternfly/react-code-editor + +# [6.5.0-prerelease.1](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-code-editor@6.4.1-prerelease.9...@patternfly/react-code-editor@6.5.0-prerelease.1) (2025-10-30) + +### Bug Fixes + +- **deps:** update dependency @monaco-editor/react to ^4.7.0 ([#11527](https://github.com/patternfly/patternfly-react/issues/11527)) ([c1581d5](https://github.com/patternfly/patternfly-react/commit/c1581d59e4f8a969726dae6383582a5e0aa48152)) + +## [6.4.1-prerelease.9](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-code-editor@6.4.1-prerelease.8...@patternfly/react-code-editor@6.4.1-prerelease.9) (2025-10-24) + +**Note:** Version bump only for package @patternfly/react-code-editor + +## [6.4.1-prerelease.8](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-code-editor@6.4.1-prerelease.7...@patternfly/react-code-editor@6.4.1-prerelease.8) (2025-10-23) + +**Note:** Version bump only for package @patternfly/react-code-editor + +## [6.4.1-prerelease.7](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-code-editor@6.4.1-prerelease.6...@patternfly/react-code-editor@6.4.1-prerelease.7) (2025-10-23) + +**Note:** Version bump only for package @patternfly/react-code-editor + +## [6.4.1-prerelease.6](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-code-editor@6.4.1-prerelease.5...@patternfly/react-code-editor@6.4.1-prerelease.6) (2025-10-23) + +**Note:** Version bump only for package @patternfly/react-code-editor + +## [6.4.1-prerelease.5](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-code-editor@6.4.1-prerelease.4...@patternfly/react-code-editor@6.4.1-prerelease.5) (2025-10-23) + +**Note:** Version bump only for package @patternfly/react-code-editor + +## [6.4.1-prerelease.4](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-code-editor@6.4.1-prerelease.3...@patternfly/react-code-editor@6.4.1-prerelease.4) (2025-10-23) + +### Bug Fixes + +- **CodeEditorControl:** make icon prop optional ([#12068](https://github.com/patternfly/patternfly-react/issues/12068)) ([bbb502a](https://github.com/patternfly/patternfly-react/commit/bbb502a04e5e7d5dda798ff0afec75db0d8fc689)), closes [#12065](https://github.com/patternfly/patternfly-react/issues/12065) + +## [6.4.1-prerelease.3](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-code-editor@6.4.1-prerelease.2...@patternfly/react-code-editor@6.4.1-prerelease.3) (2025-10-23) + +**Note:** Version bump only for package @patternfly/react-code-editor + +## [6.4.1-prerelease.2](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-code-editor@6.4.1-prerelease.1...@patternfly/react-code-editor@6.4.1-prerelease.2) (2025-10-22) + +**Note:** Version bump only for package @patternfly/react-code-editor + +## [6.4.1-prerelease.1](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-code-editor@6.4.1-prerelease.0...@patternfly/react-code-editor@6.4.1-prerelease.1) (2025-10-21) + +**Note:** Version bump only for package @patternfly/react-code-editor + +## [6.4.1-prerelease.0](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-code-editor@6.4.0...@patternfly/react-code-editor@6.4.1-prerelease.0) (2025-10-21) + +**Note:** Version bump only for package @patternfly/react-code-editor + +# [6.4.0](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-code-editor@6.4.0-prerelease.5...@patternfly/react-code-editor@6.4.0) (2025-10-16) + +**Note:** Version bump only for package @patternfly/react-code-editor + +# [6.4.0-prerelease.5](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-code-editor@6.4.0-prerelease.4...@patternfly/react-code-editor@6.4.0-prerelease.5) (2025-10-16) + +**Note:** Version bump only for package @patternfly/react-code-editor + +# [6.4.0-prerelease.4](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-code-editor@6.4.0-prerelease.3...@patternfly/react-code-editor@6.4.0-prerelease.4) (2025-10-13) + +**Note:** Version bump only for package @patternfly/react-code-editor + +# [6.4.0-prerelease.3](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-code-editor@6.4.0-prerelease.2...@patternfly/react-code-editor@6.4.0-prerelease.3) (2025-10-10) + +**Note:** Version bump only for package @patternfly/react-code-editor + +# [6.4.0-prerelease.2](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-code-editor@6.4.0-prerelease.1...@patternfly/react-code-editor@6.4.0-prerelease.2) (2025-10-01) + +**Note:** Version bump only for package @patternfly/react-code-editor + +# [6.4.0-prerelease.1](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-code-editor@6.3.1-prerelease.22...@patternfly/react-code-editor@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.22](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-code-editor@6.3.1-prerelease.21...@patternfly/react-code-editor@6.3.1-prerelease.22) (2025-09-26) + +**Note:** Version bump only for package @patternfly/react-code-editor + +## [6.3.1-prerelease.21](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-code-editor@6.3.1-prerelease.20...@patternfly/react-code-editor@6.3.1-prerelease.21) (2025-09-25) + +### Features + +- **CodeEditor:** use custom PatternFly monaco theme ([#11785](https://github.com/patternfly/patternfly-react/issues/11785)) ([eed7e65](https://github.com/patternfly/patternfly-react/commit/eed7e6528babba9c7c9bb6e8cb75186e984eac71)) + +## [6.3.1-prerelease.20](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-code-editor@6.3.1-prerelease.19...@patternfly/react-code-editor@6.3.1-prerelease.20) (2025-09-25) + +**Note:** Version bump only for package @patternfly/react-code-editor + +## [6.3.1-prerelease.19](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-code-editor@6.3.1-prerelease.18...@patternfly/react-code-editor@6.3.1-prerelease.19) (2025-09-24) + +**Note:** Version bump only for package @patternfly/react-code-editor + +## [6.3.1-prerelease.18](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-code-editor@6.3.1-prerelease.17...@patternfly/react-code-editor@6.3.1-prerelease.18) (2025-09-24) + +**Note:** Version bump only for package @patternfly/react-code-editor + +## [6.3.1-prerelease.17](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-code-editor@6.3.1-prerelease.16...@patternfly/react-code-editor@6.3.1-prerelease.17) (2025-09-24) + +**Note:** Version bump only for package @patternfly/react-code-editor + +## [6.3.1-prerelease.16](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-code-editor@6.3.1-prerelease.15...@patternfly/react-code-editor@6.3.1-prerelease.16) (2025-09-24) + +**Note:** Version bump only for package @patternfly/react-code-editor + +## [6.3.1-prerelease.15](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-code-editor@6.3.1-prerelease.14...@patternfly/react-code-editor@6.3.1-prerelease.15) (2025-09-23) + +**Note:** Version bump only for package @patternfly/react-code-editor + +## [6.3.1-prerelease.14](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-code-editor@6.3.1-prerelease.13...@patternfly/react-code-editor@6.3.1-prerelease.14) (2025-09-11) + +**Note:** Version bump only for package @patternfly/react-code-editor + +## [6.3.1-prerelease.13](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-code-editor@6.3.1-prerelease.12...@patternfly/react-code-editor@6.3.1-prerelease.13) (2025-09-11) + +**Note:** Version bump only for package @patternfly/react-code-editor + +## [6.3.1-prerelease.12](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-code-editor@6.3.1-prerelease.11...@patternfly/react-code-editor@6.3.1-prerelease.12) (2025-09-10) + +**Note:** Version bump only for package @patternfly/react-code-editor + +## [6.3.1-prerelease.11](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-code-editor@6.3.1-prerelease.10...@patternfly/react-code-editor@6.3.1-prerelease.11) (2025-09-10) + +**Note:** Version bump only for package @patternfly/react-code-editor + +## [6.3.1-prerelease.10](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-code-editor@6.3.1-prerelease.9...@patternfly/react-code-editor@6.3.1-prerelease.10) (2025-09-10) + +**Note:** Version bump only for package @patternfly/react-code-editor + +## [6.3.1-prerelease.9](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-code-editor@6.3.1-prerelease.8...@patternfly/react-code-editor@6.3.1-prerelease.9) (2025-09-09) + +**Note:** Version bump only for package @patternfly/react-code-editor + +## [6.3.1-prerelease.8](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-code-editor@6.3.1-prerelease.7...@patternfly/react-code-editor@6.3.1-prerelease.8) (2025-09-05) + +**Note:** Version bump only for package @patternfly/react-code-editor + +## [6.3.1-prerelease.7](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-code-editor@6.3.1-prerelease.6...@patternfly/react-code-editor@6.3.1-prerelease.7) (2025-08-26) + +**Note:** Version bump only for package @patternfly/react-code-editor + +## [6.3.1-prerelease.6](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-code-editor@6.3.1-prerelease.5...@patternfly/react-code-editor@6.3.1-prerelease.6) (2025-08-18) + +**Note:** Version bump only for package @patternfly/react-code-editor + +## [6.3.1-prerelease.5](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-code-editor@6.3.1-prerelease.4...@patternfly/react-code-editor@6.3.1-prerelease.5) (2025-08-18) + +**Note:** Version bump only for package @patternfly/react-code-editor + +## [6.3.1-prerelease.4](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-code-editor@6.3.1-prerelease.3...@patternfly/react-code-editor@6.3.1-prerelease.4) (2025-08-12) + +**Note:** Version bump only for package @patternfly/react-code-editor + +## [6.3.1-prerelease.3](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-code-editor@6.3.1-prerelease.2...@patternfly/react-code-editor@6.3.1-prerelease.3) (2025-08-05) + +**Note:** Version bump only for package @patternfly/react-code-editor + +## [6.3.1-prerelease.2](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-code-editor@6.3.1-prerelease.1...@patternfly/react-code-editor@6.3.1-prerelease.2) (2025-08-05) + +**Note:** Version bump only for package @patternfly/react-code-editor + +## [6.3.1-prerelease.1](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-code-editor@6.3.1-prerelease.0...@patternfly/react-code-editor@6.3.1-prerelease.1) (2025-08-04) + +**Note:** Version bump only for package @patternfly/react-code-editor + +## [6.3.1-prerelease.0](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-code-editor@6.3.0...@patternfly/react-code-editor@6.3.1-prerelease.0) (2025-07-28) + +**Note:** Version bump only for package @patternfly/react-code-editor + +# 6.3.0 (2025-07-22) + +**Note:** Version bump only for package @patternfly/react-code-editor + +# [6.3.0-prerelease.34](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-code-editor@6.4.0-prerelease.0...@patternfly/react-code-editor@6.3.0-prerelease.34) (2025-07-22) + +### Reverts + +- Revert "chore(release): releasing packages [ci skip]" ([40999d7](https://github.com/patternfly/patternfly-react/commit/40999d70a7a3aeadbe8f40fe96bb01ab3a6219d4)) + +# [6.3.0-prerelease.33](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-code-editor@6.3.0-prerelease.32...@patternfly/react-code-editor@6.3.0-prerelease.33) (2025-07-18) + +**Note:** Version bump only for package @patternfly/react-code-editor + +# [6.3.0-prerelease.32](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-code-editor@6.3.0-prerelease.31...@patternfly/react-code-editor@6.3.0-prerelease.32) (2025-07-17) + +**Note:** Version bump only for package @patternfly/react-code-editor + +# [6.3.0-prerelease.31](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-code-editor@6.3.0-prerelease.30...@patternfly/react-code-editor@6.3.0-prerelease.31) (2025-07-16) + +**Note:** Version bump only for package @patternfly/react-code-editor + +# [6.3.0-prerelease.30](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-code-editor@6.3.0-prerelease.29...@patternfly/react-code-editor@6.3.0-prerelease.30) (2025-07-11) + +**Note:** Version bump only for package @patternfly/react-code-editor + +# [6.3.0-prerelease.29](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-code-editor@6.3.0-prerelease.28...@patternfly/react-code-editor@6.3.0-prerelease.29) (2025-07-02) + +**Note:** Version bump only for package @patternfly/react-code-editor + +# [6.3.0-prerelease.28](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-code-editor@6.3.0-prerelease.27...@patternfly/react-code-editor@6.3.0-prerelease.28) (2025-07-01) + +**Note:** Version bump only for package @patternfly/react-code-editor + +# [6.3.0-prerelease.27](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-code-editor@6.3.0-prerelease.26...@patternfly/react-code-editor@6.3.0-prerelease.27) (2025-06-23) + +**Note:** Version bump only for package @patternfly/react-code-editor + +# [6.3.0-prerelease.26](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-code-editor@6.3.0-prerelease.25...@patternfly/react-code-editor@6.3.0-prerelease.26) (2025-06-20) + +**Note:** Version bump only for package @patternfly/react-code-editor + +# [6.3.0-prerelease.25](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-code-editor@6.3.0-prerelease.24...@patternfly/react-code-editor@6.3.0-prerelease.25) (2025-06-18) + +**Note:** Version bump only for package @patternfly/react-code-editor + +# [6.3.0-prerelease.24](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-code-editor@6.3.0-prerelease.23...@patternfly/react-code-editor@6.3.0-prerelease.24) (2025-06-17) + +**Note:** Version bump only for package @patternfly/react-code-editor + +# [6.3.0-prerelease.23](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-code-editor@6.3.0-prerelease.22...@patternfly/react-code-editor@6.3.0-prerelease.23) (2025-06-17) + +**Note:** Version bump only for package @patternfly/react-code-editor + +# [6.3.0-prerelease.22](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-code-editor@6.3.0-prerelease.21...@patternfly/react-code-editor@6.3.0-prerelease.22) (2025-06-16) + +**Note:** Version bump only for package @patternfly/react-code-editor + +# [6.3.0-prerelease.21](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-code-editor@6.3.0-prerelease.20...@patternfly/react-code-editor@6.3.0-prerelease.21) (2025-06-13) + +**Note:** Version bump only for package @patternfly/react-code-editor + +# [6.3.0-prerelease.20](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-code-editor@6.3.0-prerelease.19...@patternfly/react-code-editor@6.3.0-prerelease.20) (2025-06-13) + +**Note:** Version bump only for package @patternfly/react-code-editor + +# [6.3.0-prerelease.19](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-code-editor@6.3.0-prerelease.18...@patternfly/react-code-editor@6.3.0-prerelease.19) (2025-06-13) + +**Note:** Version bump only for package @patternfly/react-code-editor + +# [6.3.0-prerelease.18](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-code-editor@6.3.0-prerelease.17...@patternfly/react-code-editor@6.3.0-prerelease.18) (2025-06-11) + +**Note:** Version bump only for package @patternfly/react-code-editor + +# [6.3.0-prerelease.17](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-code-editor@6.3.0-prerelease.16...@patternfly/react-code-editor@6.3.0-prerelease.17) (2025-06-02) + +**Note:** Version bump only for package @patternfly/react-code-editor + +# [6.3.0-prerelease.16](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-code-editor@6.3.0-prerelease.15...@patternfly/react-code-editor@6.3.0-prerelease.16) (2025-05-29) + +**Note:** Version bump only for package @patternfly/react-code-editor + +# [6.3.0-prerelease.15](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-code-editor@6.3.0-prerelease.14...@patternfly/react-code-editor@6.3.0-prerelease.15) (2025-05-29) + +**Note:** Version bump only for package @patternfly/react-code-editor + +# [6.3.0-prerelease.14](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-code-editor@6.3.0-prerelease.13...@patternfly/react-code-editor@6.3.0-prerelease.14) (2025-05-21) + +**Note:** Version bump only for package @patternfly/react-code-editor + +# [6.3.0-prerelease.13](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-code-editor@6.3.0-prerelease.12...@patternfly/react-code-editor@6.3.0-prerelease.13) (2025-05-21) + +**Note:** Version bump only for package @patternfly/react-code-editor + +# [6.3.0-prerelease.12](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-code-editor@6.3.0-prerelease.11...@patternfly/react-code-editor@6.3.0-prerelease.12) (2025-05-20) + +**Note:** Version bump only for package @patternfly/react-code-editor + +# [6.3.0-prerelease.11](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-code-editor@6.3.0-prerelease.10...@patternfly/react-code-editor@6.3.0-prerelease.11) (2025-05-16) + +**Note:** Version bump only for package @patternfly/react-code-editor + +# [6.3.0-prerelease.10](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-code-editor@6.3.0-prerelease.9...@patternfly/react-code-editor@6.3.0-prerelease.10) (2025-05-15) + +**Note:** Version bump only for package @patternfly/react-code-editor + +# [6.3.0-prerelease.9](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-code-editor@6.3.0-prerelease.8...@patternfly/react-code-editor@6.3.0-prerelease.9) (2025-05-15) + +**Note:** Version bump only for package @patternfly/react-code-editor + +# [6.3.0-prerelease.8](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-code-editor@6.3.0-prerelease.7...@patternfly/react-code-editor@6.3.0-prerelease.8) (2025-05-13) + +**Note:** Version bump only for package @patternfly/react-code-editor + +# [6.3.0-prerelease.7](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-code-editor@6.3.0-prerelease.6...@patternfly/react-code-editor@6.3.0-prerelease.7) (2025-05-07) + +**Note:** Version bump only for package @patternfly/react-code-editor + +# [6.3.0-prerelease.6](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-code-editor@6.3.0-prerelease.5...@patternfly/react-code-editor@6.3.0-prerelease.6) (2025-05-07) + +**Note:** Version bump only for package @patternfly/react-code-editor + +# [6.3.0-prerelease.5](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-code-editor@6.3.0-prerelease.4...@patternfly/react-code-editor@6.3.0-prerelease.5) (2025-05-07) + +**Note:** Version bump only for package @patternfly/react-code-editor + +# [6.3.0-prerelease.4](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-code-editor@6.3.0-prerelease.3...@patternfly/react-code-editor@6.3.0-prerelease.4) (2025-04-30) + +**Note:** Version bump only for package @patternfly/react-code-editor + +# [6.3.0-prerelease.3](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-code-editor@6.3.0-prerelease.2...@patternfly/react-code-editor@6.3.0-prerelease.3) (2025-04-30) + +**Note:** Version bump only for package @patternfly/react-code-editor + +# [6.3.0-prerelease.2](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-code-editor@6.3.0-prerelease.1...@patternfly/react-code-editor@6.3.0-prerelease.2) (2025-04-28) + +**Note:** Version bump only for package @patternfly/react-code-editor + +# [6.3.0-prerelease.1](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-code-editor@6.2.1-prerelease.14...@patternfly/react-code-editor@6.3.0-prerelease.1) (2025-04-24) + +**Note:** Version bump only for package @patternfly/react-code-editor + +## [6.2.1-prerelease.14](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-code-editor@6.2.1-prerelease.13...@patternfly/react-code-editor@6.2.1-prerelease.14) (2025-04-23) + +**Note:** Version bump only for package @patternfly/react-code-editor + +## [6.2.1-prerelease.13](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-code-editor@6.2.1-prerelease.12...@patternfly/react-code-editor@6.2.1-prerelease.13) (2025-04-22) + +**Note:** Version bump only for package @patternfly/react-code-editor + +## [6.2.1-prerelease.12](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-code-editor@6.2.1-prerelease.11...@patternfly/react-code-editor@6.2.1-prerelease.12) (2025-04-21) + +**Note:** Version bump only for package @patternfly/react-code-editor + +## [6.2.1-prerelease.11](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-code-editor@6.2.1-prerelease.10...@patternfly/react-code-editor@6.2.1-prerelease.11) (2025-04-21) + +**Note:** Version bump only for package @patternfly/react-code-editor + +## [6.2.1-prerelease.10](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-code-editor@6.2.1-prerelease.9...@patternfly/react-code-editor@6.2.1-prerelease.10) (2025-04-21) + +### Features + +- **version:** testing react 19 ([#11754](https://github.com/patternfly/patternfly-react/issues/11754)) ([b981588](https://github.com/patternfly/patternfly-react/commit/b9815886da3adc7a96bc2d48adacf86e8a752e61)) + +## [6.2.1-prerelease.9](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-code-editor@6.2.1-prerelease.8...@patternfly/react-code-editor@6.2.1-prerelease.9) (2025-04-21) + +**Note:** Version bump only for package @patternfly/react-code-editor + +## [6.2.1-prerelease.8](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-code-editor@6.2.1-prerelease.7...@patternfly/react-code-editor@6.2.1-prerelease.8) (2025-04-17) + +**Note:** Version bump only for package @patternfly/react-code-editor + +## [6.2.1-prerelease.7](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-code-editor@6.2.1-prerelease.6...@patternfly/react-code-editor@6.2.1-prerelease.7) (2025-04-15) + +**Note:** Version bump only for package @patternfly/react-code-editor + +## [6.2.1-prerelease.6](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-code-editor@6.2.1-prerelease.5...@patternfly/react-code-editor@6.2.1-prerelease.6) (2025-04-14) + +**Note:** Version bump only for package @patternfly/react-code-editor + +## [6.2.1-prerelease.5](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-code-editor@6.2.1-prerelease.4...@patternfly/react-code-editor@6.2.1-prerelease.5) (2025-04-14) + +**Note:** Version bump only for package @patternfly/react-code-editor + +## [6.2.1-prerelease.4](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-code-editor@6.2.1-prerelease.3...@patternfly/react-code-editor@6.2.1-prerelease.4) (2025-04-14) + +**Note:** Version bump only for package @patternfly/react-code-editor + +## [6.2.1-prerelease.3](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-code-editor@6.2.1-prerelease.2...@patternfly/react-code-editor@6.2.1-prerelease.3) (2025-04-11) + +**Note:** Version bump only for package @patternfly/react-code-editor + +## [6.2.1-prerelease.2](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-code-editor@6.2.1-prerelease.1...@patternfly/react-code-editor@6.2.1-prerelease.2) (2025-04-10) + +**Note:** Version bump only for package @patternfly/react-code-editor + +## [6.2.1-prerelease.1](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-code-editor@6.2.1-prerelease.0...@patternfly/react-code-editor@6.2.1-prerelease.1) (2025-04-08) + +**Note:** Version bump only for package @patternfly/react-code-editor + +## [6.2.1-prerelease.0](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-code-editor@6.2.0...@patternfly/react-code-editor@6.2.1-prerelease.0) (2025-04-08) + +**Note:** Version bump only for package @patternfly/react-code-editor + +# 6.2.0 (2025-04-07) + +**Note:** Version bump only for package @patternfly/react-code-editor + +# [6.2.0-prerelease.40](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-code-editor@6.2.0-prerelease.39...@patternfly/react-code-editor@6.2.0-prerelease.40) (2025-04-01) + +**Note:** Version bump only for package @patternfly/react-code-editor + +# [6.2.0-prerelease.39](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-code-editor@6.2.0-prerelease.38...@patternfly/react-code-editor@6.2.0-prerelease.39) (2025-03-28) + +### Bug Fixes + +- **CodeeEditor:** rendered file input when editor has content ([#11725](https://github.com/patternfly/patternfly-react/issues/11725)) ([61922a9](https://github.com/patternfly/patternfly-react/commit/61922a9b228ec872632c5c3fb5045034092043ab)) + +# [6.2.0-prerelease.38](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-code-editor@6.2.0-prerelease.37...@patternfly/react-code-editor@6.2.0-prerelease.38) (2025-03-27) + +### Bug Fixes + +- **CodeEditor:** added hidden input back when editor is visible ([#11723](https://github.com/patternfly/patternfly-react/issues/11723)) ([0b8936d](https://github.com/patternfly/patternfly-react/commit/0b8936dcff4beee2a7791304350a296c52a3edbe)) + +# [6.2.0-prerelease.37](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-code-editor@6.2.0-prerelease.36...@patternfly/react-code-editor@6.2.0-prerelease.37) (2025-03-26) + +**Note:** Version bump only for package @patternfly/react-code-editor + +# [6.2.0-prerelease.36](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-code-editor@6.2.0-prerelease.35...@patternfly/react-code-editor@6.2.0-prerelease.36) (2025-03-20) + +**Note:** Version bump only for package @patternfly/react-code-editor + +# [6.2.0-prerelease.35](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-code-editor@6.2.0-prerelease.34...@patternfly/react-code-editor@6.2.0-prerelease.35) (2025-03-11) + +**Note:** Version bump only for package @patternfly/react-code-editor + +# [6.2.0-prerelease.34](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-code-editor@6.2.0-prerelease.33...@patternfly/react-code-editor@6.2.0-prerelease.34) (2025-03-11) + +### Bug Fixes + +- **CodeEditor:** only include pf-v6-c-code-editor\_\_upload when hovering is active over an empty state ([#11568](https://github.com/patternfly/patternfly-react/issues/11568)) ([a53c929](https://github.com/patternfly/patternfly-react/commit/a53c9296b8378d5fa6ddf6def3896cb7d6239c80)) + +# [6.2.0-prerelease.33](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-code-editor@6.2.0-prerelease.32...@patternfly/react-code-editor@6.2.0-prerelease.33) (2025-03-11) + +**Note:** Version bump only for package @patternfly/react-code-editor + +# [6.2.0-prerelease.32](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-code-editor@6.2.0-prerelease.31...@patternfly/react-code-editor@6.2.0-prerelease.32) (2025-03-10) + +**Note:** Version bump only for package @patternfly/react-code-editor + +# [6.2.0-prerelease.31](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-code-editor@6.2.0-prerelease.30...@patternfly/react-code-editor@6.2.0-prerelease.31) (2025-03-10) + +**Note:** Version bump only for package @patternfly/react-code-editor + +# [6.2.0-prerelease.30](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-code-editor@6.2.0-prerelease.29...@patternfly/react-code-editor@6.2.0-prerelease.30) (2025-03-06) + +**Note:** Version bump only for package @patternfly/react-code-editor + +# [6.2.0-prerelease.29](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-code-editor@6.2.0-prerelease.28...@patternfly/react-code-editor@6.2.0-prerelease.29) (2025-03-05) + +**Note:** Version bump only for package @patternfly/react-code-editor + +# [6.2.0-prerelease.28](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-code-editor@6.2.0-prerelease.27...@patternfly/react-code-editor@6.2.0-prerelease.28) (2025-03-04) + +**Note:** Version bump only for package @patternfly/react-code-editor + +# [6.2.0-prerelease.27](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-code-editor@6.2.0-prerelease.26...@patternfly/react-code-editor@6.2.0-prerelease.27) (2025-03-03) + +**Note:** Version bump only for package @patternfly/react-code-editor + +# [6.2.0-prerelease.26](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-code-editor@6.2.0-prerelease.25...@patternfly/react-code-editor@6.2.0-prerelease.26) (2025-02-27) + +**Note:** Version bump only for package @patternfly/react-code-editor + +# [6.2.0-prerelease.25](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-code-editor@6.2.0-prerelease.24...@patternfly/react-code-editor@6.2.0-prerelease.25) (2025-02-25) + +**Note:** Version bump only for package @patternfly/react-code-editor + +# [6.2.0-prerelease.24](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-code-editor@6.2.0-prerelease.23...@patternfly/react-code-editor@6.2.0-prerelease.24) (2025-02-24) + +**Note:** Version bump only for package @patternfly/react-code-editor + +# [6.2.0-prerelease.23](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-code-editor@6.2.0-prerelease.22...@patternfly/react-code-editor@6.2.0-prerelease.23) (2025-02-24) + +**Note:** Version bump only for package @patternfly/react-code-editor + +# [6.2.0-prerelease.22](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-code-editor@6.2.0-prerelease.21...@patternfly/react-code-editor@6.2.0-prerelease.22) (2025-02-20) + +### Bug Fixes + +- **FileUpload:** hid input of type file from AT ([#11438](https://github.com/patternfly/patternfly-react/issues/11438)) ([9b41c4f](https://github.com/patternfly/patternfly-react/commit/9b41c4fcc72b3ade937dddf144bb387b9866cb95)) + +# [6.2.0-prerelease.21](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-code-editor@6.2.0-prerelease.20...@patternfly/react-code-editor@6.2.0-prerelease.21) (2025-02-17) + +### Bug Fixes + +- **CodeEditor:** do not include extra div if `headerMainContent` is unset ([#11534](https://github.com/patternfly/patternfly-react/issues/11534)) ([86ff923](https://github.com/patternfly/patternfly-react/commit/86ff9239f935b974896958ff4b3c4af5b8d98825)) +- **CodeEditor:** ensure that handleResize works when viewport shrinks ([#11532](https://github.com/patternfly/patternfly-react/issues/11532)) ([c06dbde](https://github.com/patternfly/patternfly-react/commit/c06dbdec017daa3b84e7af02a2e57b9a7efd0faa)) + +# [6.2.0-prerelease.20](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-code-editor@6.2.0-prerelease.19...@patternfly/react-code-editor@6.2.0-prerelease.20) (2025-02-14) + +**Note:** Version bump only for package @patternfly/react-code-editor + +# [6.2.0-prerelease.19](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-code-editor@6.2.0-prerelease.18...@patternfly/react-code-editor@6.2.0-prerelease.19) (2025-02-13) + +**Note:** Version bump only for package @patternfly/react-code-editor + +# [6.2.0-prerelease.18](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-code-editor@6.2.0-prerelease.17...@patternfly/react-code-editor@6.2.0-prerelease.18) (2025-02-12) + +**Note:** Version bump only for package @patternfly/react-code-editor + +# [6.2.0-prerelease.17](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-code-editor@6.2.0-prerelease.16...@patternfly/react-code-editor@6.2.0-prerelease.17) (2025-02-12) + +**Note:** Version bump only for package @patternfly/react-code-editor + +# [6.2.0-prerelease.16](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-code-editor@6.2.0-prerelease.15...@patternfly/react-code-editor@6.2.0-prerelease.16) (2025-01-28) + +**Note:** Version bump only for package @patternfly/react-code-editor + +# [6.2.0-prerelease.15](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-code-editor@6.2.0-prerelease.14...@patternfly/react-code-editor@6.2.0-prerelease.15) (2025-01-28) + +### Bug Fixes + +- **Button:** updated rendering of aria-disabled attribute ([#11478](https://github.com/patternfly/patternfly-react/issues/11478)) ([058b14f](https://github.com/patternfly/patternfly-react/commit/058b14fc93233860cd604cdfb60f7c666cc0d436)) + +# [6.2.0-prerelease.14](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-code-editor@6.2.0-prerelease.13...@patternfly/react-code-editor@6.2.0-prerelease.14) (2025-01-27) + +**Note:** Version bump only for package @patternfly/react-code-editor + +# [6.2.0-prerelease.13](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-code-editor@6.2.0-prerelease.12...@patternfly/react-code-editor@6.2.0-prerelease.13) (2025-01-27) + +**Note:** Version bump only for package @patternfly/react-code-editor + +# [6.2.0-prerelease.12](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-code-editor@6.2.0-prerelease.11...@patternfly/react-code-editor@6.2.0-prerelease.12) (2025-01-24) + +**Note:** Version bump only for package @patternfly/react-code-editor + +# [6.2.0-prerelease.11](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-code-editor@6.2.0-prerelease.10...@patternfly/react-code-editor@6.2.0-prerelease.11) (2025-01-24) + +**Note:** Version bump only for package @patternfly/react-code-editor + +# [6.2.0-prerelease.10](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-code-editor@6.2.0-prerelease.9...@patternfly/react-code-editor@6.2.0-prerelease.10) (2025-01-23) + +**Note:** Version bump only for package @patternfly/react-code-editor + +# [6.2.0-prerelease.9](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-code-editor@6.2.0-prerelease.8...@patternfly/react-code-editor@6.2.0-prerelease.9) (2025-01-23) + +**Note:** Version bump only for package @patternfly/react-code-editor + +# [6.2.0-prerelease.8](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-code-editor@6.2.0-prerelease.7...@patternfly/react-code-editor@6.2.0-prerelease.8) (2025-01-21) + +**Note:** Version bump only for package @patternfly/react-code-editor + +# [6.2.0-prerelease.7](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-code-editor@6.2.0-prerelease.6...@patternfly/react-code-editor@6.2.0-prerelease.7) (2025-01-20) + +**Note:** Version bump only for package @patternfly/react-code-editor + +# [6.2.0-prerelease.6](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-code-editor@6.2.0-prerelease.5...@patternfly/react-code-editor@6.2.0-prerelease.6) (2025-01-20) + +**Note:** Version bump only for package @patternfly/react-code-editor + +# [6.2.0-prerelease.5](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-code-editor@6.2.0-prerelease.4...@patternfly/react-code-editor@6.2.0-prerelease.5) (2025-01-14) + +**Note:** Version bump only for package @patternfly/react-code-editor + +# [6.2.0-prerelease.4](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-code-editor@6.2.0-prerelease.3...@patternfly/react-code-editor@6.2.0-prerelease.4) (2025-01-14) + +**Note:** Version bump only for package @patternfly/react-code-editor + +# [6.2.0-prerelease.3](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-code-editor@6.2.0-prerelease.2...@patternfly/react-code-editor@6.2.0-prerelease.3) (2025-01-14) + +**Note:** Version bump only for package @patternfly/react-code-editor + +# [6.2.0-prerelease.2](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-code-editor@6.2.0-prerelease.1...@patternfly/react-code-editor@6.2.0-prerelease.2) (2025-01-10) + +**Note:** Version bump only for package @patternfly/react-code-editor + +# [6.2.0-prerelease.1](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-code-editor@6.2.0-prerelease.0...@patternfly/react-code-editor@6.2.0-prerelease.1) (2025-01-10) + +**Note:** Version bump only for package @patternfly/react-code-editor + +# [6.2.0-prerelease.0](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-code-editor@6.1.1-prerelease.2...@patternfly/react-code-editor@6.2.0-prerelease.0) (2025-01-06) + +**Note:** Version bump only for package @patternfly/react-code-editor + +## [6.1.1-prerelease.2](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-code-editor@6.1.1-prerelease.1...@patternfly/react-code-editor@6.1.1-prerelease.2) (2025-01-06) + +**Note:** Version bump only for package @patternfly/react-code-editor + +## [6.1.1-prerelease.1](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-code-editor@6.1.1-prerelease.0...@patternfly/react-code-editor@6.1.1-prerelease.1) (2024-12-19) + +**Note:** Version bump only for package @patternfly/react-code-editor + +## [6.1.1-prerelease.0](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-code-editor@6.1.0...@patternfly/react-code-editor@6.1.1-prerelease.0) (2024-12-18) + +**Note:** Version bump only for package @patternfly/react-code-editor + +# 6.1.0 (2024-12-16) + +### Bug Fixes + +- Update promote.sh to release 6.1.0 ([2b5106f](https://github.com/patternfly/patternfly-react/commit/2b5106ff88ce207d4a9ed2066fd390009e81fb79)) + +# [6.1.0-prerelease.16](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-code-editor@6.1.0-prerelease.15...@patternfly/react-code-editor@6.1.0-prerelease.16) (2024-12-13) + +**Note:** Version bump only for package @patternfly/react-code-editor + +# [6.1.0-prerelease.15](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-code-editor@6.1.0-prerelease.14...@patternfly/react-code-editor@6.1.0-prerelease.15) (2024-12-10) + +**Note:** Version bump only for package @patternfly/react-code-editor + +# [6.1.0-prerelease.14](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-code-editor@6.1.0-prerelease.13...@patternfly/react-code-editor@6.1.0-prerelease.14) (2024-12-04) + +**Note:** Version bump only for package @patternfly/react-code-editor + +# [6.1.0-prerelease.13](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-code-editor@6.1.0-prerelease.12...@patternfly/react-code-editor@6.1.0-prerelease.13) (2024-12-02) + +**Note:** Version bump only for package @patternfly/react-code-editor + +# [6.1.0-prerelease.12](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-code-editor@6.1.0-prerelease.11...@patternfly/react-code-editor@6.1.0-prerelease.12) (2024-12-02) + +**Note:** Version bump only for package @patternfly/react-code-editor + +# [6.1.0-prerelease.11](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-code-editor@6.1.0-prerelease.10...@patternfly/react-code-editor@6.1.0-prerelease.11) (2024-11-25) + +**Note:** Version bump only for package @patternfly/react-code-editor + +# [6.1.0-prerelease.10](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-code-editor@6.1.0-prerelease.9...@patternfly/react-code-editor@6.1.0-prerelease.10) (2024-11-20) + +**Note:** Version bump only for package @patternfly/react-code-editor + +# [6.1.0-prerelease.9](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-code-editor@6.1.0-prerelease.8...@patternfly/react-code-editor@6.1.0-prerelease.9) (2024-11-20) + +### Bug Fixes + +- **deps:** update dependency react-dropzone to v14.3.5 (main) ([#11152](https://github.com/patternfly/patternfly-react/issues/11152)) ([849b347](https://github.com/patternfly/patternfly-react/commit/849b3477cf080fcc047f21824ab742b58dcd81e8)) + +# [6.1.0-prerelease.8](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-code-editor@6.1.0-prerelease.7...@patternfly/react-code-editor@6.1.0-prerelease.8) (2024-11-20) + +**Note:** Version bump only for package @patternfly/react-code-editor + +# [6.1.0-prerelease.7](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-code-editor@6.1.0-prerelease.6...@patternfly/react-code-editor@6.1.0-prerelease.7) (2024-11-19) + +**Note:** Version bump only for package @patternfly/react-code-editor + +# [6.1.0-prerelease.6](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-code-editor@6.1.0-prerelease.5...@patternfly/react-code-editor@6.1.0-prerelease.6) (2024-11-19) + +**Note:** Version bump only for package @patternfly/react-code-editor + +# [6.1.0-prerelease.5](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-code-editor@6.1.0-prerelease.4...@patternfly/react-code-editor@6.1.0-prerelease.5) (2024-11-18) + +### Bug Fixes + +- **deps:** update dependency tslib to ^2.8.1 ([#11222](https://github.com/patternfly/patternfly-react/issues/11222)) ([7c90e9b](https://github.com/patternfly/patternfly-react/commit/7c90e9bff23083f097e78246570be60dacfb27c0)) + +# [6.1.0-prerelease.4](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-code-editor@6.1.0-prerelease.3...@patternfly/react-code-editor@6.1.0-prerelease.4) (2024-11-15) + +**Note:** Version bump only for package @patternfly/react-code-editor + +# [6.1.0-prerelease.3](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-code-editor@6.1.0-prerelease.2...@patternfly/react-code-editor@6.1.0-prerelease.3) (2024-11-14) + +**Note:** Version bump only for package @patternfly/react-code-editor + +# [6.1.0-prerelease.2](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-code-editor@6.1.0-prerelease.1...@patternfly/react-code-editor@6.1.0-prerelease.2) (2024-11-13) + +### Bug Fixes + +- **CodeEditor:** Set default height ([#11014](https://github.com/patternfly/patternfly-react/issues/11014)) ([6ddfc93](https://github.com/patternfly/patternfly-react/commit/6ddfc93376a48028fed46948b08a185e3c9617f6)) + +# [6.1.0-prerelease.1](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-code-editor@6.1.0-prerelease.0...@patternfly/react-code-editor@6.1.0-prerelease.1) (2024-10-30) + +**Note:** Version bump only for package @patternfly/react-code-editor + +# 6.1.0-prerelease.0 (2024-10-24) + +**Note:** Version bump only for package @patternfly/react-code-editor + +# 6.0.0 (2024-10-24) + +**Note:** Version bump only for package @patternfly/react-code-editor + +# [6.0.0-prerelease.23](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-code-editor@6.0.0-prerelease.22...@patternfly/react-code-editor@6.0.0-prerelease.23) (2024-10-23) + +**Note:** Version bump only for package @patternfly/react-code-editor + +# [6.0.0-prerelease.22](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-code-editor@6.0.0-prerelease.21...@patternfly/react-code-editor@6.0.0-prerelease.22) (2024-10-23) + +**Note:** Version bump only for package @patternfly/react-code-editor + +# [6.0.0-prerelease.21](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-code-editor@6.0.0-prerelease.20...@patternfly/react-code-editor@6.0.0-prerelease.21) (2024-10-02) + +**Note:** Version bump only for package @patternfly/react-code-editor + +# [6.0.0-prerelease.20](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-code-editor@6.0.0-prerelease.19...@patternfly/react-code-editor@6.0.0-prerelease.20) (2024-09-30) + +**Note:** Version bump only for package @patternfly/react-code-editor + +# [6.0.0-prerelease.19](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-code-editor@6.0.0-prerelease.18...@patternfly/react-code-editor@6.0.0-prerelease.19) (2024-09-26) + +**Note:** Version bump only for package @patternfly/react-code-editor + +# [6.0.0-prerelease.18](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-code-editor@6.0.0-prerelease.17...@patternfly/react-code-editor@6.0.0-prerelease.18) (2024-09-26) + +**Note:** Version bump only for package @patternfly/react-code-editor + +# [6.0.0-prerelease.17](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-code-editor@6.0.0-prerelease.16...@patternfly/react-code-editor@6.0.0-prerelease.17) (2024-09-24) + +**Note:** Version bump only for package @patternfly/react-code-editor + +# [6.0.0-prerelease.16](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-code-editor@6.0.0-prerelease.15...@patternfly/react-code-editor@6.0.0-prerelease.16) (2024-09-24) + +**Note:** Version bump only for package @patternfly/react-code-editor + +# [6.0.0-prerelease.15](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-code-editor@6.0.0-prerelease.14...@patternfly/react-code-editor@6.0.0-prerelease.15) (2024-09-23) + +### Bug Fixes + +- **table:** update v5 to v6 for docs, description list, draggable, Th ([#10968](https://github.com/patternfly/patternfly-react/issues/10968)) ([db72b52](https://github.com/patternfly/patternfly-react/commit/db72b5287c18d023c094be247a46f9352d50fd7b)) + +# [6.0.0-prerelease.14](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-code-editor@6.0.0-prerelease.13...@patternfly/react-code-editor@6.0.0-prerelease.14) (2024-09-20) + +**Note:** Version bump only for package @patternfly/react-code-editor + +# [6.0.0-prerelease.13](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-code-editor@6.0.0-prerelease.12...@patternfly/react-code-editor@6.0.0-prerelease.13) (2024-09-19) + +**Note:** Version bump only for package @patternfly/react-code-editor + +# [6.0.0-prerelease.12](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-code-editor@6.0.0-prerelease.11...@patternfly/react-code-editor@6.0.0-prerelease.12) (2024-09-18) + +**Note:** Version bump only for package @patternfly/react-code-editor + +# [6.0.0-prerelease.11](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-code-editor@6.0.0-prerelease.10...@patternfly/react-code-editor@6.0.0-prerelease.11) (2024-09-17) + +**Note:** Version bump only for package @patternfly/react-code-editor + +# [6.0.0-prerelease.10](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-code-editor@6.0.0-prerelease.9...@patternfly/react-code-editor@6.0.0-prerelease.10) (2024-09-16) + +**Note:** Version bump only for package @patternfly/react-code-editor + +# [6.0.0-prerelease.9](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-code-editor@6.0.0-prerelease.8...@patternfly/react-code-editor@6.0.0-prerelease.9) (2024-09-13) + +**Note:** Version bump only for package @patternfly/react-code-editor + +# [6.0.0-prerelease.8](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-code-editor@6.0.0-prerelease.7...@patternfly/react-code-editor@6.0.0-prerelease.8) (2024-09-13) + +**Note:** Version bump only for package @patternfly/react-code-editor + +# [6.0.0-prerelease.7](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-code-editor@6.0.0-prerelease.6...@patternfly/react-code-editor@6.0.0-prerelease.7) (2024-09-12) + +**Note:** Version bump only for package @patternfly/react-code-editor + +# [6.0.0-prerelease.6](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-code-editor@6.0.0-prerelease.5...@patternfly/react-code-editor@6.0.0-prerelease.6) (2024-09-12) + +**Note:** Version bump only for package @patternfly/react-code-editor + +# [6.0.0-prerelease.5](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-code-editor@6.0.0-prerelease.4...@patternfly/react-code-editor@6.0.0-prerelease.5) (2024-09-11) + +**Note:** Version bump only for package @patternfly/react-code-editor + +# [6.0.0-prerelease.4](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-code-editor@6.0.0-prerelease.3...@patternfly/react-code-editor@6.0.0-prerelease.4) (2024-09-10) + +**Note:** Version bump only for package @patternfly/react-code-editor + +# [6.0.0-prerelease.3](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-code-editor@6.0.0-prerelease.2...@patternfly/react-code-editor@6.0.0-prerelease.3) (2024-09-10) + +### Bug Fixes + +- **deps:** update dependency tslib to ^2.7.0 ([#10949](https://github.com/patternfly/patternfly-react/issues/10949)) ([024b3cc](https://github.com/patternfly/patternfly-react/commit/024b3cc4b1afd4ba9f2dc774c0842712d4fbab1a)) + +# [6.0.0-prerelease.2](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-code-editor@6.0.0-prerelease.1...@patternfly/react-code-editor@6.0.0-prerelease.2) (2024-09-09) + +**Note:** Version bump only for package @patternfly/react-code-editor + +# [6.0.0-prerelease.1](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-code-editor@6.0.0-alpha.106...@patternfly/react-code-editor@6.0.0-prerelease.1) (2024-09-07) + +**Note:** Version bump only for package @patternfly/react-code-editor + # [6.0.0-alpha.106](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-code-editor@6.0.0-alpha.105...@patternfly/react-code-editor@6.0.0-alpha.106) (2024-08-30) ### Bug Fixes diff --git a/packages/react-code-editor/package.json b/packages/react-code-editor/package.json index 62c2db4040e..b49a9b376c2 100644 --- a/packages/react-code-editor/package.json +++ b/packages/react-code-editor/package.json @@ -1,6 +1,6 @@ { "name": "@patternfly/react-code-editor", - "version": "6.0.0-prerelease.0", + "version": "6.6.0-prerelease.7", "description": "This package provides a PatternFly wrapper for the Monaco code editor\n", "main": "dist/js/index.js", "module": "dist/esm/index.js", @@ -30,18 +30,18 @@ "clean": "rimraf dist" }, "dependencies": { - "@monaco-editor/react": "^4.6.0", + "@monaco-editor/react": "^4.7.0", "@patternfly/react-core": "workspace:^", "@patternfly/react-icons": "workspace:^", "@patternfly/react-styles": "workspace:^", - "react-dropzone": "14.2.3", - "tslib": "^2.6.2" + "react-dropzone": "14.3.5", + "tslib": "^2.8.1" }, "peerDependencies": { - "react": "^17 || ^18", - "react-dom": "^17 || ^18" + "react": "^17 || ^18 || ^19", + "react-dom": "^17 || ^18 || ^19" }, "devDependencies": { - "monaco-editor": "^0.49.0" + "monaco-editor": "^0.55.1" } } diff --git a/packages/react-code-editor/src/components/CodeEditor/CodeEditor.tsx b/packages/react-code-editor/src/components/CodeEditor/CodeEditor.tsx index ac7fc3f5d4b..cfadb403965 100644 --- a/packages/react-code-editor/src/components/CodeEditor/CodeEditor.tsx +++ b/packages/react-code-editor/src/components/CodeEditor/CodeEditor.tsx @@ -1,30 +1,30 @@ -import * as React from 'react'; +import { HTMLProps, ReactNode, useEffect, useMemo, useRef, useState } from 'react'; import { css } from '@patternfly/react-styles'; import styles from '@patternfly/react-styles/css/components/CodeEditor/code-editor'; import fileUploadStyles from '@patternfly/react-styles/css/components/FileUpload/file-upload'; +import monoFont from '@patternfly/react-tokens/dist/esm/t_global_font_family_mono'; +import { Button, ButtonVariant } from '@patternfly/react-core/dist/esm/components/Button'; import { - Button, - ButtonVariant, EmptyState, - EmptyStateBody, EmptyStateActions, - EmptyStateVariant, + EmptyStateBody, EmptyStateFooter, - getResizeObserver, - Popover, - PopoverProps, - TooltipPosition -} from '@patternfly/react-core'; -import Editor, { EditorProps, Monaco } from '@monaco-editor/react'; + EmptyStateVariant +} from '@patternfly/react-core/dist/esm/components/EmptyState'; +import { Popover, PopoverProps } from '@patternfly/react-core/dist/esm/components/Popover'; +import { TooltipPosition } from '@patternfly/react-core/dist/esm/components/Tooltip'; +import { getResizeObserver } from '@patternfly/react-core/dist/esm/helpers/resizeObserver'; +import Editor, { BeforeMount, EditorProps, Monaco } from '@monaco-editor/react'; import type { editor } from 'monaco-editor'; -import CopyIcon from '@patternfly/react-icons/dist/esm/icons/copy-icon'; +import RhUiCopyFillIcon from '@patternfly/react-icons/dist/esm/icons/rh-ui-copy-fill-icon'; import UploadIcon from '@patternfly/react-icons/dist/esm/icons/upload-icon'; import DownloadIcon from '@patternfly/react-icons/dist/esm/icons/download-icon'; -import CodeIcon from '@patternfly/react-icons/dist/esm/icons/code-icon'; +import RhUiCodeIcon from '@patternfly/react-icons/dist/esm/icons/rh-ui-code-icon'; import HelpIcon from '@patternfly/react-icons/dist/esm/icons/help-icon'; import Dropzone, { FileRejection } from 'react-dropzone'; import { CodeEditorContext } from './CodeEditorUtils'; import { CodeEditorControl } from './CodeEditorControl'; +import { defineThemes } from './CodeEditorTheme'; export type ChangeHandler = (value: string, event: editor.IModelContentChangedEvent) => void; export type EditorDidMount = (editor: editor.IStandaloneCodeEditor, monaco: Monaco) => void; @@ -114,7 +114,7 @@ export enum Language { /** The main code editor component. */ -export interface CodeEditorProps extends Omit, 'onChange'> { +export interface CodeEditorProps extends Omit, 'onChange'> { /** Additional classes added to the code editor. */ className?: string; /** Code displayed in code editor. */ @@ -128,7 +128,7 @@ export interface CodeEditorProps extends Omit, ' /** A single node or array of nodes - ideally the code editor controls component - to display * above code editor. */ - customControls?: React.ReactNode | React.ReactNode[]; + customControls?: ReactNode | ReactNode[]; /** Accessible label for the download button. */ downloadButtonAriaLabel?: string; /** Text to display in the tooltip on the download button. */ @@ -138,18 +138,18 @@ export interface CodeEditorProps extends Omit, ' /** Additional props to pass to the monaco editor. */ editorProps?: EditorProps; /** Content to display in space of the code editor when there is no code to display. */ - emptyState?: React.ReactNode; + emptyState?: ReactNode; /** Override default empty state body text. */ - emptyStateBody?: React.ReactNode; + emptyStateBody?: ReactNode; /** Override default empty state button text. */ - emptyStateButton?: React.ReactNode; + emptyStateButton?: ReactNode; /** Override default empty state link text. */ - emptyStateLink?: React.ReactNode; + emptyStateLink?: ReactNode; /** Override default empty state title text. */ - emptyStateTitle?: React.ReactNode; + emptyStateTitle?: ReactNode; /** Editor header main content title. */ headerMainContent?: string; - /** Height of code editor. Defaults to 100%. 'sizeToFit' will automatically change the height + /** Height of code editor. 'sizeToFit' will automatically change the height * to the height of the content. */ height?: string | 'sizeToFit'; @@ -157,6 +157,10 @@ export interface CodeEditorProps extends Omit, ' isCopyEnabled?: boolean; /** Flag indicating the editor is styled using monaco's dark theme. */ isDarkTheme?: boolean; + /** Flag indicating the editor is styled using monaco's high contrast themes. */ + isHighContrastTheme?: boolean; + /** Flag that enables component to consume the available height of its container. If `height` prop is set to 100%, this will also become enabled. */ + isFullHeight?: boolean; /** Flag indicating the editor has a plain header. */ isHeaderPlain?: boolean; /** Flag to add download button to code editor actions. */ @@ -175,13 +179,16 @@ export interface CodeEditorProps extends Omit, ' /** Language displayed in the editor. */ language?: Language; /** The loading screen before the editor will be loaded. Defaults to 'loading...'. */ - loading?: React.ReactNode; + loading?: ReactNode; /** Function which fires each time the content of the code editor is manually changed. Does * not fire when a file is uploaded. */ onChange?: ChangeHandler; /** Function which fires each time the code changes in the code editor. */ onCodeChange?: (value: string) => void; + /** Function which fires when the code is downloaded. Defaults to a function that + * downloads the current editor content. */ + onDownload?: (value: string, fileName: string) => void; /** Callback which fires after the code editor is mounted containing a reference to the * monaco editor and the monaco instance. */ @@ -191,17 +198,17 @@ export interface CodeEditorProps extends Omit, ' /** Refer to Monaco interface {monaco.editor.IEditorOverrideServices}. */ overrideServices?: editor.IEditorOverrideServices; /** Text to show in the button to open the shortcut popover. */ - shortcutsPopoverButtonText: string; + shortcutsPopoverButtonText?: string; /** Properties for the shortcut popover. */ shortcutsPopoverProps?: PopoverProps; /** Flag to show the editor. */ showEditor?: boolean; /** The delay before tooltip fades after code copied. */ - toolTipCopyExitDelay: number; + toolTipCopyExitDelay?: number; /** The entry and exit delay for all tooltips. */ - toolTipDelay: number; + toolTipDelay?: number; /** The max width of the tooltips on all button. */ - toolTipMaxWidth: string; + toolTipMaxWidth?: string; /** The position of tooltips on all buttons. */ toolTipPosition?: | TooltipPosition @@ -226,466 +233,427 @@ export interface CodeEditorProps extends Omit, ' width?: string; } -interface CodeEditorState { - height: string; - prevPropsCode: string; - value: string; - filename: string; - isLoading: boolean; - showEmptyState: boolean; - copied: boolean; -} - -class CodeEditor extends React.Component { - static displayName = 'CodeEditor'; - private editor: editor.IStandaloneCodeEditor | null = null; - private wrapperRef = React.createRef(); - private ref = React.createRef(); - private timer: number | null = null; - private observer = () => {}; - - static defaultProps: CodeEditorProps = { - className: '', - code: '', - onEditorDidMount: () => {}, - language: Language.plaintext, - isDarkTheme: false, - height: '', - width: '', - isLineNumbersVisible: true, - isReadOnly: false, - isLanguageLabelVisible: false, - loading: '', - emptyState: '', - emptyStateTitle: 'Start editing', - emptyStateBody: 'Drag and drop a file or upload one.', - emptyStateButton: 'Browse', - emptyStateLink: 'Start from scratch', - downloadFileName: Date.now().toString(), - isUploadEnabled: false, - isDownloadEnabled: false, - isCopyEnabled: false, - isHeaderPlain: false, - copyButtonAriaLabel: 'Copy code to clipboard', - uploadButtonAriaLabel: 'Upload code', - downloadButtonAriaLabel: 'Download code', - copyButtonToolTipText: 'Copy to clipboard', - uploadButtonToolTipText: 'Upload', - downloadButtonToolTipText: 'Download', - copyButtonSuccessTooltipText: 'Content added to clipboard', - toolTipCopyExitDelay: 1600, - toolTipDelay: 300, - toolTipMaxWidth: '100px', - toolTipPosition: 'top', - customControls: null, - isMinimapVisible: false, - headerMainContent: '', - shortcutsPopoverButtonText: 'View Shortcuts', - shortcutsPopoverProps: { - bodyContent: '', - 'aria-label': 'Keyboard Shortcuts', - ...Popover.defaultProps - }, - showEditor: true, - options: {}, - overrideServices: {}, - onCodeChange: () => {} - }; - - static getExtensionFromLanguage(language: Language) { - switch (language) { - case Language.shell: - return 'sh'; - case Language.ruby: - return 'rb'; - case Language.perl: - return 'pl'; - case Language.python: - return 'py'; - case Language.mysql: - return 'sql'; - case Language.javascript: - return 'js'; - case Language.typescript: - return 'ts'; - case Language.markdown: - return 'md'; - case Language.plaintext: - return 'txt'; - default: - return language.toString(); - } - } - - constructor(props: CodeEditorProps) { - super(props); - this.state = { - height: this.props.height, - prevPropsCode: this.props.code, - value: this.props.code, - filename: '', - isLoading: false, - showEmptyState: true, - copied: false - }; - } - - setHeightToFitContent() { - const contentHeight = this.editor.getContentHeight(); - const layoutInfo = this.editor.getLayoutInfo(); - this.editor.layout({ width: layoutInfo.width, height: contentHeight }); +const getExtensionFromLanguage = (language: Language) => { + switch (language) { + case Language.shell: + return 'sh'; + case Language.ruby: + return 'rb'; + case Language.perl: + return 'pl'; + case Language.python: + return 'py'; + case Language.mysql: + return 'sql'; + case Language.javascript: + return 'js'; + case Language.typescript: + return 'ts'; + case Language.markdown: + return 'md'; + case Language.plaintext: + return 'txt'; + default: + return language.toString(); } +}; + +/** + * Downloads a file to a users device given its string content and a full file name. + */ +const defaultOnDownload = (value: string, fileName: string) => { + const link = document.createElement('a'); + link.href = URL.createObjectURL(new Blob([value], { type: 'text' })); + link.download = fileName; + link.click(); +}; + +export const CodeEditor = ({ + className = '', + code = '', + copyButtonAriaLabel = 'Copy code to clipboard', + copyButtonSuccessTooltipText = 'Content added to clipboard', + copyButtonToolTipText = 'Copy to clipboard', + customControls = null, + downloadButtonAriaLabel = 'Download code', + downloadButtonToolTipText = 'Download', + downloadFileName = Date.now().toString(), + editorProps, + emptyState = '', + emptyStateBody = 'Drag and drop a file or upload one.', + emptyStateButton = 'Browse', + emptyStateLink = 'Start from scratch', + emptyStateTitle = 'Start editing', + headerMainContent = '', + height, + isCopyEnabled = false, + isDarkTheme = false, + isHighContrastTheme = false, + isDownloadEnabled = false, + isFullHeight = false, + isHeaderPlain = false, + isLanguageLabelVisible = false, + isLineNumbersVisible = true, + isMinimapVisible = false, + isReadOnly = false, + isUploadEnabled = false, + language = Language.plaintext, + loading = '', + onChange = () => {}, + onCodeChange = () => {}, + onDownload = defaultOnDownload, + onEditorDidMount = () => {}, + options = {}, + overrideServices = {}, + shortcutsPopoverButtonText = 'View Shortcuts', + shortcutsPopoverProps = { bodyContent: '', 'aria-label': 'Keyboard Shortcuts' }, + showEditor = true, + toolTipCopyExitDelay = 1600, + toolTipDelay = 300, + toolTipMaxWidth = '100px', + toolTipPosition = 'top', + uploadButtonAriaLabel = 'Upload code', + uploadButtonToolTipText = 'Upload', + width = '' +}: CodeEditorProps) => { + const [value, setValue] = useState(code); + const [isLoading, setIsLoading] = useState(false); + const [showEmptyState, setShowEmptyState] = useState(true); + const [copied, setCopied] = useState(false); + + const editorRef = useRef(null); + const wrapperRef = useRef(null); + const ref = useRef(null); + const observer = useRef(() => {}); + + const setHeightToFitContent = () => { + const contentHeight = editorRef.current?.getContentHeight(); + const layoutInfo = editorRef.current?.getLayoutInfo(); + editorRef.current?.layout({ width: layoutInfo.width, height: contentHeight }); + }; - onChange: ChangeHandler = (value, event) => { - if (this.props.height === 'sizeToFit') { - this.setHeightToFitContent(); + const onModelChange: ChangeHandler = (value, event) => { + if (height === 'sizeToFit') { + setHeightToFitContent(); } - if (this.props.onChange) { - this.props.onChange(value, event); + if (onChange) { + onChange(value, event); } - this.setState({ value }); - this.props.onCodeChange(value); + setValue(value); + onCodeChange(value); }; - // this function is only called when the props change - // the only conflict is between props.code and state.value - static getDerivedStateFromProps(nextProps: CodeEditorProps, prevState: CodeEditorState) { - // if the code changes due to the props.code changing - // set the value to props.code - if (nextProps.code !== prevState.prevPropsCode) { - return { - value: nextProps.code, - prevPropsCode: nextProps.code - }; + const handleResize = () => { + if (editorRef.current) { + editorRef.current.layout({ width: 0, height: 0 }); // ensures the editor won't take up more space than it needs + editorRef.current.layout(); } - // else, don't need to change the state.value - // because the onChange function will do all the work - return null; - } + }; - handleResize = () => { - if (this.editor) { - this.editor.layout(); + const handleGlobalKeys = (event: KeyboardEvent) => { + if (wrapperRef.current === document.activeElement && (event.key === 'ArrowDown' || event.key === ' ')) { + editorRef.current?.focus(); + event.preventDefault(); } }; - componentDidMount() { - document.addEventListener('keydown', this.handleGlobalKeys); - this.observer = getResizeObserver(this.ref.current, this.handleResize, true); - this.handleResize(); - } - - componentWillUnmount() { - document.removeEventListener('keydown', this.handleGlobalKeys); - this.observer(); - } + // if the code changes due to the prop changing + // set the value to the code prop + useEffect(() => setValue(code), [code]); + + useEffect(() => { + document.addEventListener('keydown', handleGlobalKeys); + observer.current = getResizeObserver(ref.current, handleResize, true); + handleResize(); + return () => { + document.removeEventListener('keydown', handleGlobalKeys); + observer.current(); + }; + }, []); - handleGlobalKeys = (event: KeyboardEvent) => { - if (this.wrapperRef.current === document.activeElement && (event.key === 'ArrowDown' || event.key === ' ')) { - this.editor?.focus(); - event.preventDefault(); - } + const editorBeforeMount: BeforeMount = (monaco) => { + defineThemes(monaco.editor); + editorProps?.beforeMount?.(monaco); }; - editorDidMount: EditorDidMount = (editor, monaco) => { + const editorDidMount: EditorDidMount = (editor, monaco) => { // eslint-disable-next-line no-bitwise - editor.addCommand(monaco.KeyMod.Shift | monaco.KeyCode.Tab, () => this.wrapperRef.current.focus()); + editor.addCommand(monaco.KeyMod.Shift | monaco.KeyCode.Tab, () => wrapperRef.current.focus()); Array.from(document.getElementsByClassName('monaco-editor')).forEach((editorElement) => editorElement.removeAttribute('role') ); - this.props.onEditorDidMount(editor, monaco); - this.editor = editor; - if (this.props.height === 'sizeToFit') { - this.setHeightToFitContent(); + onEditorDidMount(editor, monaco); + editorRef.current = editor; + if (height === 'sizeToFit') { + setHeightToFitContent(); } }; - handleFileChange = (value: string, filename: string) => { - this.setState({ - value, - filename - }); - this.props.onCodeChange(value); + const handleFileChange = (value: string) => { + setValue(value); + onCodeChange(value); }; - handleFileReadStarted = () => this.setState({ isLoading: true }); - handleFileReadFinished = () => this.setState({ isLoading: false }); + const handleFileReadStarted = () => setIsLoading(true); + const handleFileReadFinished = () => setIsLoading(false); - readFile(fileHandle: Blob) { - return new Promise((resolve, reject) => { + const readFile = (fileHandle: Blob) => + new Promise((resolve, reject) => { const reader = new FileReader(); reader.onload = () => resolve(reader.result as string); reader.onerror = () => reject(reader.error); reader.readAsText(fileHandle); }); - } - onDropAccepted = (acceptedFiles: File[]) => { + const onDropAccepted = (acceptedFiles: File[]) => { if (acceptedFiles.length > 0) { const fileHandle = acceptedFiles[0]; - this.handleFileChange('', fileHandle.name); // Show the filename while reading - this.handleFileReadStarted(); - this.readFile(fileHandle) + handleFileChange(''); // Show the filename while reading + handleFileReadStarted(); + readFile(fileHandle) .then((data) => { - this.handleFileReadFinished(); - this.toggleEmptyState(); - this.handleFileChange(data, fileHandle.name); + handleFileReadFinished(); + setShowEmptyState(false); + handleFileChange(data); }) .catch((error: DOMException) => { // eslint-disable-next-line no-console console.error('error', error); - this.handleFileReadFinished(); - this.handleFileChange('', ''); // Clear the filename field on a failure + handleFileReadFinished(); + handleFileChange(''); }); } }; - onDropRejected = (rejectedFiles: FileRejection[]) => { + const onDropRejected = (rejectedFiles: FileRejection[]) => { if (rejectedFiles.length > 0) { // eslint-disable-next-line no-console console.error('There was an error accepting that dropped file'); // TODO } }; - copyCode = () => { - navigator.clipboard.writeText(this.state.value); - this.setState({ copied: true }); + const copyCode = () => { + navigator.clipboard.writeText(value); + setCopied(true); }; - download = () => { - const { value } = this.state; - const element = document.createElement('a'); - const file = new Blob([value], { type: 'text' }); - element.href = URL.createObjectURL(file); - element.download = `${this.props.downloadFileName}.${CodeEditor.getExtensionFromLanguage(this.props.language)}`; - document.body.appendChild(element); // Required for this to work in FireFox - element.click(); + const editorOptions: editor.IStandaloneEditorConstructionOptions = { + fontFamily: monoFont.var, + scrollBeyondLastLine: height !== 'sizeToFit', + readOnly: isReadOnly, + cursorStyle: 'line', + lineNumbers: isLineNumbersVisible ? 'on' : 'off', + tabIndex: -1, + minimap: { + enabled: isMinimapVisible + }, + ...options }; - toggleEmptyState = () => { - this.setState({ showEmptyState: false }); + const tooltipProps = { + position: toolTipPosition, + exitDelay: toolTipDelay, + entryDelay: toolTipDelay, + maxWidth: toolTipMaxWidth, + trigger: 'mouseenter focus' }; - render() { - const { height, value, isLoading, showEmptyState, copied } = this.state; - const { - isDarkTheme, - width, - className, - isCopyEnabled, - copyButtonSuccessTooltipText, - isReadOnly, - isUploadEnabled, - isLanguageLabelVisible, - copyButtonAriaLabel, - copyButtonToolTipText, - uploadButtonAriaLabel, - uploadButtonToolTipText, - downloadButtonAriaLabel, - downloadButtonToolTipText, - toolTipDelay, - toolTipCopyExitDelay, - toolTipMaxWidth, - toolTipPosition, - isLineNumbersVisible, - isDownloadEnabled, - language, - emptyState: providedEmptyState, - emptyStateTitle, - emptyStateBody, - emptyStateButton, - emptyStateLink, - customControls, - isMinimapVisible, - isHeaderPlain, - headerMainContent, - shortcutsPopoverButtonText, - shortcutsPopoverProps: shortcutsPopoverPropsProp, - showEditor, - options: optionsProp, - overrideServices, - editorProps - } = this.props; - const shortcutsPopoverProps: PopoverProps = { - ...CodeEditor.defaultProps.shortcutsPopoverProps, - ...shortcutsPopoverPropsProp - }; - const options: editor.IStandaloneEditorConstructionOptions = { - scrollBeyondLastLine: height !== 'sizeToFit', - readOnly: isReadOnly, - cursorStyle: 'line', - lineNumbers: isLineNumbersVisible ? 'on' : 'off', - tabIndex: -1, - minimap: { - enabled: isMinimapVisible - }, - ...optionsProp - }; + const hasEditorHeaderContent = + ((isCopyEnabled || isDownloadEnabled) && (!showEmptyState || !!value)) || + isUploadEnabled || + customControls || + headerMainContent || + !!shortcutsPopoverProps.bodyContent; - return ( - - {({ getRootProps, getInputProps, isDragActive, open }) => { - const emptyState = - providedEmptyState || - (isUploadEnabled ? ( - - {emptyStateBody} - {!isReadOnly && ( - - - - - - - - - )} - - ) : ( - - {!isReadOnly && ( - - - - - - )} - - )); - - const tooltipProps = { - position: toolTipPosition, - exitDelay: toolTipDelay, - entryDelay: toolTipDelay, - maxWidth: toolTipMaxWidth, - trigger: 'mouseenter focus' - }; - - const hasEditorHeaderContent = - ((isCopyEnabled || isDownloadEnabled) && (!showEmptyState || !!value)) || - isUploadEnabled || - customControls || - headerMainContent || - !!shortcutsPopoverProps.bodyContent; - - const editorHeaderContent = ( - -
- - {isCopyEnabled && (!showEmptyState || !!value) && ( - } - aria-label={copyButtonAriaLabel} - tooltipProps={{ - ...tooltipProps, - 'aria-live': 'polite', - content:
{copied ? copyButtonSuccessTooltipText : copyButtonToolTipText}
, - exitDelay: copied ? toolTipCopyExitDelay : toolTipDelay, - onTooltipHidden: () => this.setState({ copied: false }) - }} - onClick={this.copyCode} - /> - )} - {isUploadEnabled && ( - } - aria-label={uploadButtonAriaLabel} - tooltipProps={{ content:
{uploadButtonToolTipText}
, ...tooltipProps }} - onClick={open} - /> - )} - {isDownloadEnabled && (!showEmptyState || !!value) && ( - } - aria-label={downloadButtonAriaLabel} - tooltipProps={{ content:
{downloadButtonToolTipText}
, ...tooltipProps }} - onClick={this.download} - /> - )} - {customControls && customControls} -
-
- {
{headerMainContent}
} - {!!shortcutsPopoverProps.bodyContent && ( -
- - - -
- )} -
- ); - - const editorHeader = ( -
- {hasEditorHeaderContent && ( -
{editorHeaderContent}
+ + + + + )} - {isLanguageLabelVisible && ( -
- - - - {language.toUpperCase()} -
+ + ) : ( + + {!isReadOnly && ( + + + + + )} + + )); + + const editorHeaderContent = ( + <> +
+ + {isCopyEnabled && (!showEmptyState || !!value) && ( + } + aria-label={copyButtonAriaLabel} + tooltipProps={{ + ...tooltipProps, + 'aria-live': 'polite', + content:
{copied ? copyButtonSuccessTooltipText : copyButtonToolTipText}
, + exitDelay: copied ? toolTipCopyExitDelay : toolTipDelay, + onTooltipHidden: () => setCopied(false) + }} + onClick={copyCode} + /> + )} + {isUploadEnabled && ( + } + aria-label={uploadButtonAriaLabel} + tooltipProps={{ content:
{uploadButtonToolTipText}
, ...tooltipProps }} + onClick={open} + /> + )} + {isDownloadEnabled && (!showEmptyState || !!value) && ( + } + aria-label={downloadButtonAriaLabel} + tooltipProps={{ content:
{downloadButtonToolTipText}
, ...tooltipProps }} + onClick={() => { + onDownload(value, `${downloadFileName}.${getExtensionFromLanguage(language)}`); + }} + /> + )} + {customControls && customControls} +
- ); - - const editor = ( -
- -
- ); - - return ( -
- {isUploadEnabled || providedEmptyState ? ( -
event.stopPropagation() // Prevents clicking TextArea from opening file dialog - })} - className={css(isLoading && fileUploadStyles.modifiers.loading)} - > - {editorHeader} -
+ {headerMainContent &&
{headerMainContent}
} + {!!shortcutsPopoverProps.bodyContent && ( +
+ + + +
+ )} + + ); + + const editorHeader = ( +
+ {hasEditorHeaderContent &&
{editorHeaderContent}
} + {isLanguageLabelVisible && ( +
+ + + + {language.toUpperCase()} +
+ )} +
+ ); + + const editor = ( +
+ +
+ ); + + return ( +
+ {isUploadEnabled || emptyState ? ( +
event.stopPropagation() // Prevents clicking TextArea from opening file dialog + })} + className={css(styles.codeEditorContainer, isLoading && fileUploadStyles.modifiers.loading)} + > + {editorHeader} +
+ {(showEmptyState || emptyState) && !value ? (
- - {(showEmptyState || providedEmptyState) && !value ? emptyState : editor} + {hiddenFileInput} + {editorEmptyState}
-
+ ) : ( + <> + {hiddenFileInput} + {editor} + + )}
- ) : ( - <> - {editorHeader} - {showEditor &&
{editor}
} - - )} -
- ); - }} - - ); - } -} - -export { CodeEditor }; +
+ ) : ( + <> + {editorHeader} + {showEditor && ( +
+ {hiddenFileInput} + {editor} +
+ )} + + )} +
+ ); + }} + + ); +}; + +CodeEditor.displayName = 'CodeEditor'; diff --git a/packages/react-code-editor/src/components/CodeEditor/CodeEditorControl.tsx b/packages/react-code-editor/src/components/CodeEditor/CodeEditorControl.tsx index f07c9eca00a..aea9def50bf 100644 --- a/packages/react-code-editor/src/components/CodeEditor/CodeEditorControl.tsx +++ b/packages/react-code-editor/src/components/CodeEditor/CodeEditorControl.tsx @@ -1,5 +1,6 @@ -import * as React from 'react'; -import { Button, ButtonProps, Tooltip } from '@patternfly/react-core'; +import { useContext } from 'react'; +import { Button, ButtonProps } from '@patternfly/react-core/dist/esm/components/Button'; +import { Tooltip } from '@patternfly/react-core/dist/esm/components/Tooltip'; import { CodeEditorContext } from './CodeEditorUtils'; /** Allows customizing the code editor controls by passing this sub-component into the @@ -12,7 +13,7 @@ export interface CodeEditorControlProps extends Omit { /** Additional classes added to the code editor control. */ className?: string; /** Icon rendered inside the code editor control. */ - icon: React.ReactNode; + icon?: React.ReactNode; /** Event handler for the click of the button */ onClick: (code: string, event?: any) => void; /** Flag indicating that the button is visible above the code editor. */ @@ -30,7 +31,7 @@ export const CodeEditorControl: React.FunctionComponent tooltipProps = {}, ...props }: CodeEditorControlProps) => { - const context = React.useContext(CodeEditorContext); + const context = useContext(CodeEditorContext); const onCustomClick = (event: React.MouseEvent) => { onClick(context.code, event); diff --git a/packages/react-code-editor/src/components/CodeEditor/CodeEditorTheme.ts b/packages/react-code-editor/src/components/CodeEditor/CodeEditorTheme.ts new file mode 100644 index 00000000000..ff630ef1d83 --- /dev/null +++ b/packages/react-code-editor/src/components/CodeEditor/CodeEditorTheme.ts @@ -0,0 +1,78 @@ +import { colors } from './themeTokenMapping'; +import type { editor as monacoEditor } from 'monaco-editor/esm/vs/editor/editor.api'; + +const createTheme = (mode: 'light' | 'dark'): monacoEditor.IStandaloneThemeData => ({ + base: mode === 'light' ? 'vs' : 'vs-dark', + inherit: true, + colors: { + 'editor.background': colors.background[mode], + 'editor.foreground': colors.foreground[mode], + 'editorLineNumber.activeForeground': colors.foreground[mode], + 'editorLineNumber.foreground': colors.secondaryForeground[mode] + }, + rules: [ + { token: '', foreground: colors.foreground[mode], background: colors.background[mode] }, + { token: 'invalid', foreground: colors.red[mode] }, + { token: 'emphasis', fontStyle: 'italic' }, + { token: 'strong', fontStyle: 'bold' }, + + { token: 'variable', foreground: colors.blue[mode] }, + { token: 'variable.predefined', foreground: colors.teal[mode] }, + { token: 'constant', foreground: colors.orange[mode] }, + { token: 'comment', foreground: colors.gray[mode] }, + { token: 'number', foreground: colors.orange[mode] }, + { token: 'number.hex', foreground: colors.blue[mode] }, + { token: 'regexp', foreground: colors.red[mode] }, + { token: 'annotation', foreground: colors.purple[mode] }, + { token: 'type', foreground: colors.yellow[mode] }, + + { token: 'delimiter', foreground: colors.foreground[mode] }, + { token: 'delimiter.html', foreground: colors.gray[mode] }, + { token: 'delimiter.xml', foreground: colors.blue[mode] }, + + { token: 'tag', foreground: colors.red[mode] }, + { token: 'tag.id.jade', foreground: colors.teal[mode] }, + { token: 'tag.class.jade', foreground: colors.teal[mode] }, + { token: 'meta.scss', foreground: colors.red[mode] }, + { token: 'metatag', foreground: colors.orange[mode] }, + { token: 'metatag.content.html', foreground: colors.red[mode] }, + { token: 'metatag.html', foreground: colors.gray[mode] }, + { token: 'metatag.xml', foreground: colors.gray[mode] }, + { token: 'metatag.php', fontStyle: 'bold' }, + + { token: 'key', foreground: colors.orange[mode] }, + { token: 'string.key.json', foreground: colors.red[mode] }, + { token: 'string.value.json', foreground: colors.blue[mode] }, + + { token: 'attribute.name', foreground: colors.red[mode] }, + { token: 'attribute.value', foreground: colors.blue[mode] }, + { token: 'attribute.value.number', foreground: colors.orange[mode] }, + { token: 'attribute.value.unit', foreground: colors.orange[mode] }, + { token: 'attribute.value.html', foreground: colors.blue[mode] }, + { token: 'attribute.value.xml', foreground: colors.blue[mode] }, + + { token: 'string', foreground: colors.green[mode] }, + { token: 'string.html', foreground: colors.green[mode] }, + { token: 'string.sql', foreground: colors.green[mode] }, + { token: 'string.yaml', foreground: colors.green[mode] }, + + { token: 'keyword', foreground: colors.purple[mode] }, + { token: 'keyword.json', foreground: colors.purple[mode] }, + { token: 'keyword.flow', foreground: colors.purple[mode] }, + { token: 'keyword.flow.scss', foreground: colors.purple[mode] }, + + { token: 'operator.scss', foreground: colors.foreground[mode] }, + { token: 'operator.sql', foreground: colors.foreground[mode] }, + { token: 'operator.swift', foreground: colors.foreground[mode] }, + { token: 'predefined.sql', foreground: colors.purple[mode] } + ] +}); + +/** + * Define the themes `pf-v6-theme-light` and + * `pf-v6-theme-dark` for an instance of Monaco editor. + */ +export const defineThemes = (editor: typeof monacoEditor) => { + editor.defineTheme('pf-v6-theme-light', createTheme('light')); + editor.defineTheme('pf-v6-theme-dark', createTheme('dark')); +}; diff --git a/packages/react-code-editor/src/components/CodeEditor/CodeEditorUtils.ts b/packages/react-code-editor/src/components/CodeEditor/CodeEditorUtils.ts index cfcf938eef6..e1eb224db79 100644 --- a/packages/react-code-editor/src/components/CodeEditor/CodeEditorUtils.ts +++ b/packages/react-code-editor/src/components/CodeEditor/CodeEditorUtils.ts @@ -1,7 +1,7 @@ -import * as React from 'react'; +import { createContext } from 'react'; interface CodeEditorContext { code: string; } -export const CodeEditorContext = React.createContext(null); +export const CodeEditorContext = createContext(null); diff --git a/packages/react-code-editor/src/components/CodeEditor/__test__/CodeEditor.test.tsx b/packages/react-code-editor/src/components/CodeEditor/__test__/CodeEditor.test.tsx index ebdfe4c053c..cf7f8b7d254 100644 --- a/packages/react-code-editor/src/components/CodeEditor/__test__/CodeEditor.test.tsx +++ b/packages/react-code-editor/src/components/CodeEditor/__test__/CodeEditor.test.tsx @@ -1,9 +1,10 @@ -import React from 'react'; import { render, screen, act } from '@testing-library/react'; import { CodeEditor, Language } from '../CodeEditor'; import styles from '@patternfly/react-styles/css/components/CodeEditor/code-editor'; -jest.mock('@monaco-editor/react', () => jest.fn(() =>
)); +jest.mock('@monaco-editor/react', () => + jest.fn((props: any) =>
) +); test('Matches snapshot without props', () => { const { asFragment } = render(); @@ -15,10 +16,9 @@ test('Matches snapshot with control buttons enabled', () => { expect(asFragment()).toMatchSnapshot(); }); -test(`Renders with default classes ${styles.codeEditor}, ${styles.codeEditorMain}, ${styles.codeEditorCode}`, () => { +test(`Renders with default classes ${styles.codeEditor}, ${styles.codeEditorCode}`, () => { render(); expect(screen.getByTestId('mock-editor').parentElement).toHaveClass(styles.codeEditorCode); - expect(screen.getByTestId('mock-editor').parentElement?.parentElement).toHaveClass(styles.codeEditorMain); expect(screen.getByTestId('mock-editor').parentElement?.parentElement?.parentElement).toHaveClass(styles.codeEditor); }); @@ -34,9 +34,9 @@ test(`Renders with ${styles.modifiers.readOnly} when isReadOnly = true`, () => { ); }); -test(`Renders with ${styles.codeEditorUpload} when isUploadEnabled = true`, () => { +test(`Renders with ${styles.codeEditorMain} when isUploadEnabled = true`, () => { render(); - expect(screen.getByTestId('mock-editor').parentElement?.parentElement).toHaveClass(styles.codeEditorUpload); + expect(screen.getByTestId('mock-editor').parentElement?.parentElement).toHaveClass(styles.codeEditorMain); }); test(`Renders with empty state when code = undefined`, () => { @@ -74,3 +74,23 @@ test(`Renders with shortcuts when shortcutsPopoverButtonText is passed`, () => { }); expect(screen.getByText('shortcuts')).toBeInTheDocument(); }); + +test('Uses pf-v6-theme-light by default', () => { + render(); + expect(screen.getByTestId('mock-editor')).toHaveAttribute('data-theme', 'pf-v6-theme-light'); +}); + +test('Uses pf-v6-theme-dark when isDarkTheme is true', () => { + render(); + expect(screen.getByTestId('mock-editor')).toHaveAttribute('data-theme', 'pf-v6-theme-dark'); +}); + +test('Uses hc-light when isHighContrast is true', () => { + render(); + expect(screen.getByTestId('mock-editor')).toHaveAttribute('data-theme', 'hc-light'); +}); + +test('Uses hc-black when both isHighContrast and isDarkTheme are true', () => { + render(); + expect(screen.getByTestId('mock-editor')).toHaveAttribute('data-theme', 'hc-black'); +}); diff --git a/packages/react-code-editor/src/components/CodeEditor/__test__/CodeEditorControl.test.tsx b/packages/react-code-editor/src/components/CodeEditor/__test__/CodeEditorControl.test.tsx index 754d0bb296d..1534638dfb4 100644 --- a/packages/react-code-editor/src/components/CodeEditor/__test__/CodeEditorControl.test.tsx +++ b/packages/react-code-editor/src/components/CodeEditor/__test__/CodeEditorControl.test.tsx @@ -1,4 +1,3 @@ -import React from 'react'; import { render, screen } from '@testing-library/react'; import { CodeEditorControl } from '../CodeEditorControl'; diff --git a/packages/react-code-editor/src/components/CodeEditor/__test__/__snapshots__/CodeEditor.test.tsx.snap b/packages/react-code-editor/src/components/CodeEditor/__test__/__snapshots__/CodeEditor.test.tsx.snap index 5fe4b80e31e..f91566a42f9 100644 --- a/packages/react-code-editor/src/components/CodeEditor/__test__/__snapshots__/CodeEditor.test.tsx.snap +++ b/packages/react-code-editor/src/components/CodeEditor/__test__/__snapshots__/CodeEditor.test.tsx.snap @@ -6,7 +6,7 @@ exports[`Matches snapshot with control buttons enabled 1`] = ` class="pf-v6-c-code-editor" >
@@ -23,10 +23,9 @@ exports[`Matches snapshot with control buttons enabled 1`] = ` style="display: contents;" > @@ -85,10 +95,9 @@ exports[`Matches snapshot with control buttons enabled 1`] = ` style="display: contents;" >
-
+
-
-
-
+ data-testid="mock-editor" + data-theme="pf-v6-theme-light" + />
@@ -156,6 +172,12 @@ exports[`Matches snapshot without props 1`] = `
+
diff --git a/packages/react-code-editor/src/components/CodeEditor/__test__/__snapshots__/CodeEditorControl.test.tsx.snap b/packages/react-code-editor/src/components/CodeEditor/__test__/__snapshots__/CodeEditorControl.test.tsx.snap index d8133ca9353..5751d125bc9 100644 --- a/packages/react-code-editor/src/components/CodeEditor/__test__/__snapshots__/CodeEditorControl.test.tsx.snap +++ b/packages/react-code-editor/src/components/CodeEditor/__test__/__snapshots__/CodeEditorControl.test.tsx.snap @@ -6,9 +6,8 @@ exports[`Matches snapshot 1`] = ` style="display: contents;" > ; @@ -45,9 +45,6 @@ export default ; All component documentation is available on [PatternFly.org](https://www.patternfly.org/components/about-modal). -#### Advanced usage -1. [Applying Overpass font](https://github.com/patternfly/patternfly-react/blob/main/ADVANCED-USAGE-README.md#Applying-Overpass-font) - ### Contribution guidelines All React contributors must first be [PatternFly community contributors](https://www.patternfly.org/contribute/about). If you are already a PatternFly community contributor, check out the [React contribution guidelines](https://github.com/patternfly/patternfly-react/tree/main/CONTRIBUTING.md) to make React contributions. diff --git a/packages/react-core/package.json b/packages/react-core/package.json index 69449a61e1d..7c117abe066 100644 --- a/packages/react-core/package.json +++ b/packages/react-core/package.json @@ -1,6 +1,6 @@ { "name": "@patternfly/react-core", - "version": "6.0.0-prerelease.0", + "version": "6.6.0-prerelease.6", "description": "This library provides a set of common React components for use with the PatternFly reference implementation.", "main": "dist/js/index.js", "module": "dist/esm/index.js", @@ -49,18 +49,18 @@ "@patternfly/react-icons": "workspace:^", "@patternfly/react-styles": "workspace:^", "@patternfly/react-tokens": "workspace:^", - "focus-trap": "7.5.4", - "react-dropzone": "^14.2.3", - "tslib": "^2.6.2" + "focus-trap": "7.6.6", + "react-dropzone": "^14.3.5", + "tslib": "^2.8.1" }, "devDependencies": { - "@patternfly/patternfly": "6.0.0-alpha.226", - "case-anything": "^2.1.13", + "@patternfly/patternfly": "6.6.0-prerelease.9", + "case-anything": "^3.1.2", "css": "^3.0.0", - "fs-extra": "^11.2.0" + "fs-extra": "^11.3.3" }, "peerDependencies": { - "react": "^17 || ^18", - "react-dom": "^17 || ^18" + "react": "^17 || ^18 || ^19", + "react-dom": "^17 || ^18 || ^19" } } diff --git a/packages/react-core/src/components/AboutModal/AboutModal.tsx b/packages/react-core/src/components/AboutModal/AboutModal.tsx index e254f889a04..56c0aeb93c7 100644 --- a/packages/react-core/src/components/AboutModal/AboutModal.tsx +++ b/packages/react-core/src/components/AboutModal/AboutModal.tsx @@ -1,4 +1,3 @@ -import * as React from 'react'; import { css } from '@patternfly/react-styles'; import backgroundImage from '@patternfly/react-tokens/dist/esm/c_about_modal_box_BackgroundImage'; import { AboutModalBoxContent } from './AboutModalBoxContent'; @@ -6,8 +5,8 @@ import { AboutModalBoxHeader } from './AboutModalBoxHeader'; import { AboutModalBoxBrand } from './AboutModalBoxBrand'; import { AboutModalBoxCloseButton } from './AboutModalBoxCloseButton'; import { AboutModalBox } from './AboutModalBox'; -import { Modal, ModalVariant } from '../../deprecated/components/Modal'; -import { GenerateId } from '../../helpers/GenerateId/GenerateId'; +import { Modal, ModalVariant } from '../Modal'; +import { useSSRSafeId } from '../../helpers'; export interface AboutModalProps extends React.HTMLProps { /** Content rendered inside the about modal */ @@ -57,6 +56,8 @@ export const AboutModal: React.FunctionComponent = ({ disableFocusTrap, ...props }: AboutModalProps) => { + const ariaLabelledBy = useSSRSafeId('pf-about-modal-title-'); + if (brandImageSrc && !brandImageAlt) { // eslint-disable-next-line no-console console.error( @@ -74,37 +75,29 @@ export const AboutModal: React.FunctionComponent = ({ return null; } return ( - - {(ariaLabelledBy) => ( - - - - - {productName && } - - {children} - - - - )} - + + + + + {productName && } + + {children} + + + ); }; AboutModal.displayName = 'AboutModal'; diff --git a/packages/react-core/src/components/AboutModal/AboutModalBox.tsx b/packages/react-core/src/components/AboutModal/AboutModalBox.tsx index 18810ca5184..d9ad123f792 100644 --- a/packages/react-core/src/components/AboutModal/AboutModalBox.tsx +++ b/packages/react-core/src/components/AboutModal/AboutModalBox.tsx @@ -1,4 +1,3 @@ -import * as React from 'react'; import { css } from '@patternfly/react-styles'; import styles from '@patternfly/react-styles/css/components/AboutModalBox/about-modal-box'; diff --git a/packages/react-core/src/components/AboutModal/AboutModalBoxBrand.tsx b/packages/react-core/src/components/AboutModal/AboutModalBoxBrand.tsx index b39299dfd49..a948f7d9ab5 100644 --- a/packages/react-core/src/components/AboutModal/AboutModalBoxBrand.tsx +++ b/packages/react-core/src/components/AboutModal/AboutModalBoxBrand.tsx @@ -1,4 +1,3 @@ -import * as React from 'react'; import { css } from '@patternfly/react-styles'; import styles from '@patternfly/react-styles/css/components/AboutModalBox/about-modal-box'; diff --git a/packages/react-core/src/components/AboutModal/AboutModalBoxCloseButton.tsx b/packages/react-core/src/components/AboutModal/AboutModalBoxCloseButton.tsx index 68612db3851..a5f56d87188 100644 --- a/packages/react-core/src/components/AboutModal/AboutModalBoxCloseButton.tsx +++ b/packages/react-core/src/components/AboutModal/AboutModalBoxCloseButton.tsx @@ -1,8 +1,7 @@ -import * as React from 'react'; import { css } from '@patternfly/react-styles'; import styles from '@patternfly/react-styles/css/components/AboutModalBox/about-modal-box'; import { Button } from '../Button'; -import TimesIcon from '@patternfly/react-icons/dist/esm/icons/times-icon'; +import RhMicronsCloseIcon from '@patternfly/react-icons/dist/esm/icons/rh-microns-close-icon'; export interface AboutModalBoxCloseButtonProps extends React.HTMLProps { /** A callback for when the close button is clicked */ @@ -17,7 +16,7 @@ export const AboutModalBoxCloseButton: React.FunctionComponent (
-
); AboutModalBoxCloseButton.displayName = 'AboutModalBoxCloseButton'; diff --git a/packages/react-core/src/components/AboutModal/AboutModalBoxContent.tsx b/packages/react-core/src/components/AboutModal/AboutModalBoxContent.tsx index e5b029e006b..5c0dd191e74 100644 --- a/packages/react-core/src/components/AboutModal/AboutModalBoxContent.tsx +++ b/packages/react-core/src/components/AboutModal/AboutModalBoxContent.tsx @@ -1,4 +1,3 @@ -import * as React from 'react'; import { css } from '@patternfly/react-styles'; import styles from '@patternfly/react-styles/css/components/AboutModalBox/about-modal-box'; import contentStyles from '@patternfly/react-styles/css/components/Content/content'; diff --git a/packages/react-core/src/components/AboutModal/AboutModalBoxHeader.tsx b/packages/react-core/src/components/AboutModal/AboutModalBoxHeader.tsx index 7634e34c136..4fe01e51cee 100644 --- a/packages/react-core/src/components/AboutModal/AboutModalBoxHeader.tsx +++ b/packages/react-core/src/components/AboutModal/AboutModalBoxHeader.tsx @@ -1,4 +1,3 @@ -import * as React from 'react'; import { css } from '@patternfly/react-styles'; import styles from '@patternfly/react-styles/css/components/AboutModalBox/about-modal-box'; import { Title } from '../Title'; diff --git a/packages/react-core/src/components/AboutModal/__tests__/AboutModal.test.tsx b/packages/react-core/src/components/AboutModal/__tests__/AboutModal.test.tsx index e3804acdb91..5d1b01522b5 100644 --- a/packages/react-core/src/components/AboutModal/__tests__/AboutModal.test.tsx +++ b/packages/react-core/src/components/AboutModal/__tests__/AboutModal.test.tsx @@ -1,5 +1,3 @@ -import * as React from 'react'; - import { render, screen } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; diff --git a/packages/react-core/src/components/AboutModal/__tests__/AboutModalBox.test.tsx b/packages/react-core/src/components/AboutModal/__tests__/AboutModalBox.test.tsx index 9587eb1a531..89a6245289b 100644 --- a/packages/react-core/src/components/AboutModal/__tests__/AboutModalBox.test.tsx +++ b/packages/react-core/src/components/AboutModal/__tests__/AboutModalBox.test.tsx @@ -1,4 +1,3 @@ -import * as React from 'react'; import { render } from '@testing-library/react'; import { AboutModalBox } from '../AboutModalBox'; diff --git a/packages/react-core/src/components/AboutModal/__tests__/AboutModalBoxBrand.test.tsx b/packages/react-core/src/components/AboutModal/__tests__/AboutModalBoxBrand.test.tsx index a764474aaab..2e6ac73621f 100644 --- a/packages/react-core/src/components/AboutModal/__tests__/AboutModalBoxBrand.test.tsx +++ b/packages/react-core/src/components/AboutModal/__tests__/AboutModalBoxBrand.test.tsx @@ -1,4 +1,3 @@ -import * as React from 'react'; import { render } from '@testing-library/react'; import { AboutModalBoxBrand } from '../AboutModalBoxBrand'; diff --git a/packages/react-core/src/components/AboutModal/__tests__/AboutModalBoxCloseButton.test.tsx b/packages/react-core/src/components/AboutModal/__tests__/AboutModalBoxCloseButton.test.tsx index 817b526a15b..75c84237b15 100644 --- a/packages/react-core/src/components/AboutModal/__tests__/AboutModalBoxCloseButton.test.tsx +++ b/packages/react-core/src/components/AboutModal/__tests__/AboutModalBoxCloseButton.test.tsx @@ -1,4 +1,3 @@ -import * as React from 'react'; import { render } from '@testing-library/react'; import { AboutModalBoxCloseButton } from '../AboutModalBoxCloseButton'; diff --git a/packages/react-core/src/components/AboutModal/__tests__/AboutModalBoxContent.test.tsx b/packages/react-core/src/components/AboutModal/__tests__/AboutModalBoxContent.test.tsx index 62bf982fae7..e1a8d24b687 100644 --- a/packages/react-core/src/components/AboutModal/__tests__/AboutModalBoxContent.test.tsx +++ b/packages/react-core/src/components/AboutModal/__tests__/AboutModalBoxContent.test.tsx @@ -1,4 +1,3 @@ -import * as React from 'react'; import { render } from '@testing-library/react'; import { AboutModalBoxContent } from '../AboutModalBoxContent'; diff --git a/packages/react-core/src/components/AboutModal/__tests__/AboutModalBoxHeader.test.tsx b/packages/react-core/src/components/AboutModal/__tests__/AboutModalBoxHeader.test.tsx index 5e12a89f70f..a3650189a94 100644 --- a/packages/react-core/src/components/AboutModal/__tests__/AboutModalBoxHeader.test.tsx +++ b/packages/react-core/src/components/AboutModal/__tests__/AboutModalBoxHeader.test.tsx @@ -1,4 +1,3 @@ -import * as React from 'react'; import { render } from '@testing-library/react'; import { AboutModalBoxHeader } from '../AboutModalBoxHeader'; diff --git a/packages/react-core/src/components/AboutModal/__tests__/__snapshots__/AboutModalBoxCloseButton.test.tsx.snap b/packages/react-core/src/components/AboutModal/__tests__/__snapshots__/AboutModalBoxCloseButton.test.tsx.snap index 0d9f3217fe1..a49f0976bb0 100644 --- a/packages/react-core/src/components/AboutModal/__tests__/__snapshots__/AboutModalBoxCloseButton.test.tsx.snap +++ b/packages/react-core/src/components/AboutModal/__tests__/__snapshots__/AboutModalBoxCloseButton.test.tsx.snap @@ -6,10 +6,9 @@ exports[`AboutModalBoxCloseButton Test 1`] = ` class="pf-v6-c-about-modal-box__close" > @@ -42,6 +42,6 @@ export const AboutModalBasic: React.FunctionComponent = () => { - + ); }; diff --git a/packages/react-core/src/components/AboutModal/examples/AboutModalComplexUserPositionedContent.tsx b/packages/react-core/src/components/AboutModal/examples/AboutModalComplexUserPositionedContent.tsx index 70a6fee69a7..45e0d9ce159 100644 --- a/packages/react-core/src/components/AboutModal/examples/AboutModalComplexUserPositionedContent.tsx +++ b/packages/react-core/src/components/AboutModal/examples/AboutModalComplexUserPositionedContent.tsx @@ -1,17 +1,17 @@ -import React from 'react'; +import { Fragment, useState } from 'react'; import { AboutModal, Alert, Button, Content } from '@patternfly/react-core'; import brandImg from '../../assets/PF-IconLogo.svg'; import spacing from '@patternfly/react-styles/css/utilities/Spacing/spacing'; export const AboutModalComplexUserPositionedContent: React.FunctionComponent = () => { - const [isModalOpen, setIsModalOpen] = React.useState(false); + const [isModalOpen, setIsModalOpen] = useState(false); const toggleModal = (_event: React.MouseEvent | KeyboardEvent | MouseEvent) => { setIsModalOpen(!isModalOpen); }; return ( - + @@ -49,6 +49,6 @@ export const AboutModalComplexUserPositionedContent: React.FunctionComponent = ( - + ); }; diff --git a/packages/react-core/src/components/AboutModal/examples/AboutModalWithoutProductName.tsx b/packages/react-core/src/components/AboutModal/examples/AboutModalWithoutProductName.tsx index 0835aa257b2..c9073da724c 100644 --- a/packages/react-core/src/components/AboutModal/examples/AboutModalWithoutProductName.tsx +++ b/packages/react-core/src/components/AboutModal/examples/AboutModalWithoutProductName.tsx @@ -1,16 +1,16 @@ -import React from 'react'; +import { Fragment, useState } from 'react'; import { AboutModal, Button, Content } from '@patternfly/react-core'; import brandImg from '../../assets/PF-IconLogo.svg'; export const AboutModalWithoutProductName: React.FunctionComponent = () => { - const [isModalOpen, setIsModalOpen] = React.useState(false); + const [isModalOpen, setIsModalOpen] = useState(false); const toggleModal = (_event: React.MouseEvent | KeyboardEvent | MouseEvent) => { setIsModalOpen(!isModalOpen); }; return ( - + @@ -42,6 +42,6 @@ export const AboutModalWithoutProductName: React.FunctionComponent = () => { - + ); }; diff --git a/packages/react-core/src/components/Accordion/Accordion.tsx b/packages/react-core/src/components/Accordion/Accordion.tsx index fedc1e21ee0..64b9c16898c 100644 --- a/packages/react-core/src/components/Accordion/Accordion.tsx +++ b/packages/react-core/src/components/Accordion/Accordion.tsx @@ -1,4 +1,3 @@ -import * as React from 'react'; import { css } from '@patternfly/react-styles'; import styles from '@patternfly/react-styles/css/components/Accordion/accordion'; import { AccordionContext } from './AccordionContext'; @@ -16,6 +15,10 @@ export interface AccordionProps extends React.HTMLProps { asDefinitionList?: boolean; /** Flag to indicate the accordion had a border */ isBordered?: boolean; + /** @beta Flag to prevent the accordion from automatically applying plain styling when glass theme is enabled. */ + isNoPlainOnGlass?: boolean; + /** @beta Flag to add plain styling to the accordion. */ + isPlain?: boolean; /** Display size variant. */ displaySize?: 'default' | 'lg'; /** Sets the toggle icon position for all accordion toggles. */ @@ -29,6 +32,8 @@ export const Accordion: React.FunctionComponent = ({ headingLevel = 'h3', asDefinitionList = true, isBordered = false, + isNoPlainOnGlass = false, + isPlain = false, displaySize = 'default', togglePosition = 'end', ...props @@ -39,6 +44,8 @@ export const Accordion: React.FunctionComponent = ({ className={css( styles.accordion, isBordered && styles.modifiers.bordered, + isNoPlainOnGlass && styles.modifiers.noPlainOnGlass, + isPlain && styles.modifiers.plain, togglePosition === 'start' && styles.modifiers.toggleStart, displaySize === 'lg' && styles.modifiers.displayLg, className diff --git a/packages/react-core/src/components/Accordion/AccordionContent.tsx b/packages/react-core/src/components/Accordion/AccordionContent.tsx index f7f5b052f0a..afb495f5988 100644 --- a/packages/react-core/src/components/Accordion/AccordionContent.tsx +++ b/packages/react-core/src/components/Accordion/AccordionContent.tsx @@ -1,4 +1,5 @@ -import * as React from 'react'; +import { useContext, useEffect, useRef, useState } from 'react'; + import { css } from '@patternfly/react-styles'; import styles from '@patternfly/react-styles/css/components/Accordion/accordion'; import { AccordionContext, AccordionItemContext } from './AccordionContext'; @@ -37,11 +38,11 @@ export const AccordionContent: React.FunctionComponent = contentBodyProps, ...props }: AccordionContentProps) => { - const [hasScrollbar, setHasScrollbar] = React.useState(false); - const containerRef = React.useRef(null); - const { isExpanded } = React.useContext(AccordionItemContext); + const [hasScrollbar, setHasScrollbar] = useState(false); + const containerRef = useRef(null); + const { isExpanded } = useContext(AccordionItemContext); - React.useEffect(() => { + useEffect(() => { if (containerRef?.current && isFixed && isExpanded) { const { offsetHeight, scrollHeight } = containerRef.current; diff --git a/packages/react-core/src/components/Accordion/AccordionContext.ts b/packages/react-core/src/components/Accordion/AccordionContext.ts index e92abd418b1..c476f15898e 100644 --- a/packages/react-core/src/components/Accordion/AccordionContext.ts +++ b/packages/react-core/src/components/Accordion/AccordionContext.ts @@ -1,5 +1,4 @@ -import * as React from 'react'; - +import { createContext } from 'react'; interface AccordionContextProps { ContentContainer: React.ElementType; ToggleContainer: React.ElementType; @@ -10,5 +9,5 @@ interface AccordionItemContextProps { isExpanded?: boolean; } -export const AccordionContext = React.createContext>({}); -export const AccordionItemContext = React.createContext({} as AccordionItemContextProps); +export const AccordionContext = createContext>({}); +export const AccordionItemContext = createContext({} as AccordionItemContextProps); diff --git a/packages/react-core/src/components/Accordion/AccordionExpandableContentBody.tsx b/packages/react-core/src/components/Accordion/AccordionExpandableContentBody.tsx index 386c837bf36..ad04610d16a 100644 --- a/packages/react-core/src/components/Accordion/AccordionExpandableContentBody.tsx +++ b/packages/react-core/src/components/Accordion/AccordionExpandableContentBody.tsx @@ -1,4 +1,3 @@ -import * as React from 'react'; import { css } from '@patternfly/react-styles'; import styles from '@patternfly/react-styles/css/components/Accordion/accordion'; diff --git a/packages/react-core/src/components/Accordion/AccordionItem.tsx b/packages/react-core/src/components/Accordion/AccordionItem.tsx index d4ca465ed9e..07c1d7ab16e 100644 --- a/packages/react-core/src/components/Accordion/AccordionItem.tsx +++ b/packages/react-core/src/components/Accordion/AccordionItem.tsx @@ -1,4 +1,3 @@ -import * as React from 'react'; import { css } from '@patternfly/react-styles'; import styles from '@patternfly/react-styles/css/components/Accordion/accordion'; import { AccordionItemContext } from './AccordionContext'; diff --git a/packages/react-core/src/components/Accordion/AccordionToggle.tsx b/packages/react-core/src/components/Accordion/AccordionToggle.tsx index 1cb178e640d..04d3467a57c 100644 --- a/packages/react-core/src/components/Accordion/AccordionToggle.tsx +++ b/packages/react-core/src/components/Accordion/AccordionToggle.tsx @@ -1,11 +1,13 @@ -import * as React from 'react'; +import { useContext } from 'react'; import { css } from '@patternfly/react-styles'; import styles from '@patternfly/react-styles/css/components/Accordion/accordion'; -import AngleRightIcon from '@patternfly/react-icons/dist/esm/icons/angle-right-icon'; +import RhMicronsCaretDownIcon from '@patternfly/react-icons/dist/esm/icons/rh-microns-caret-down-icon'; import { AccordionContext, AccordionItemContext } from './AccordionContext'; -export interface AccordionToggleProps - extends React.DetailedHTMLProps, HTMLButtonElement> { +export interface AccordionToggleProps extends React.DetailedHTMLProps< + React.ButtonHTMLAttributes, + HTMLButtonElement +> { /** Content rendered inside the Accordion toggle */ children?: React.ReactNode; /** Additional classes added to the Accordion Toggle */ @@ -25,11 +27,11 @@ export const AccordionToggle: React.FunctionComponent = ({ }: AccordionToggleProps) => { const renderToggleIcon = () => ( - + ); - const { isExpanded } = React.useContext(AccordionItemContext); + const { isExpanded } = useContext(AccordionItemContext); return ( diff --git a/packages/react-core/src/components/Accordion/__tests__/Accordion.test.tsx b/packages/react-core/src/components/Accordion/__tests__/Accordion.test.tsx index 4d347f5d0eb..7cfe2a82ba7 100644 --- a/packages/react-core/src/components/Accordion/__tests__/Accordion.test.tsx +++ b/packages/react-core/src/components/Accordion/__tests__/Accordion.test.tsx @@ -1,5 +1,4 @@ -import React from 'react'; - +import '@testing-library/jest-dom'; import { render, screen } from '@testing-library/react'; import { Accordion } from '../Accordion'; @@ -123,6 +122,41 @@ test('Renders with pf-m-bordered when isBordered=true', () => { expect(screen.getByText('Test')).toHaveClass('pf-m-bordered'); }); +test(`Renders without class ${styles.modifiers.noPlainOnGlass} by default`, () => { + render(Test); + + expect(screen.getByText('Test')).not.toHaveClass(styles.modifiers.noPlainOnGlass); +}); + +test(`Renders with class ${styles.modifiers.noPlainOnGlass} when isNoPlainOnGlass`, () => { + render(Test); + + expect(screen.getByText('Test')).toHaveClass(styles.modifiers.noPlainOnGlass); +}); + +test(`Renders without class ${styles.modifiers.plain} by default`, () => { + render(Test); + + expect(screen.getByText('Test')).not.toHaveClass(styles.modifiers.plain); +}); + +test(`Renders with class ${styles.modifiers.plain} when isPlain`, () => { + render(Test); + + expect(screen.getByText('Test')).toHaveClass(styles.modifiers.plain); +}); + +test(`applies both ${styles.modifiers.plain} and ${styles.modifiers.noPlainOnGlass} when both isPlain and isNoPlainOnGlass are true`, () => { + render( + + Test + + ); + + expect(screen.getByText('Test')).toHaveClass(styles.modifiers.plain); + expect(screen.getByText('Test')).toHaveClass(styles.modifiers.noPlainOnGlass); +}); + test('Renders without pf-m-display-lg by default', () => { render(Test); diff --git a/packages/react-core/src/components/Accordion/__tests__/AccordionContent.test.tsx b/packages/react-core/src/components/Accordion/__tests__/AccordionContent.test.tsx index 2008005acf8..84f5ef02d43 100644 --- a/packages/react-core/src/components/Accordion/__tests__/AccordionContent.test.tsx +++ b/packages/react-core/src/components/Accordion/__tests__/AccordionContent.test.tsx @@ -1,5 +1,3 @@ -import React from 'react'; - import { render, screen } from '@testing-library/react'; import { AccordionContent } from '../AccordionContent'; diff --git a/packages/react-core/src/components/Accordion/__tests__/AccordionExpandedContentBody.test.tsx b/packages/react-core/src/components/Accordion/__tests__/AccordionExpandedContentBody.test.tsx index 1257a00d99c..3070148b556 100644 --- a/packages/react-core/src/components/Accordion/__tests__/AccordionExpandedContentBody.test.tsx +++ b/packages/react-core/src/components/Accordion/__tests__/AccordionExpandedContentBody.test.tsx @@ -1,5 +1,3 @@ -import React from 'react'; - import { render, screen } from '@testing-library/react'; import { AccordionExpandableContentBody } from '../AccordionExpandableContentBody'; diff --git a/packages/react-core/src/components/Accordion/__tests__/AccordionItem.test.tsx b/packages/react-core/src/components/Accordion/__tests__/AccordionItem.test.tsx index ec3f94b4019..f48a5cfedbe 100644 --- a/packages/react-core/src/components/Accordion/__tests__/AccordionItem.test.tsx +++ b/packages/react-core/src/components/Accordion/__tests__/AccordionItem.test.tsx @@ -1,5 +1,3 @@ -import React from 'react'; - import { render, screen } from '@testing-library/react'; import { AccordionItem } from '../AccordionItem'; import styles from '@patternfly/react-styles/css/components/Accordion/accordion'; diff --git a/packages/react-core/src/components/Accordion/__tests__/AccordionToggle.test.tsx b/packages/react-core/src/components/Accordion/__tests__/AccordionToggle.test.tsx index ca45a0b2c0d..1a67f3deee2 100644 --- a/packages/react-core/src/components/Accordion/__tests__/AccordionToggle.test.tsx +++ b/packages/react-core/src/components/Accordion/__tests__/AccordionToggle.test.tsx @@ -1,12 +1,10 @@ -import React from 'react'; - import { render, screen } from '@testing-library/react'; import { AccordionToggle } from '../AccordionToggle'; import { AccordionContext, AccordionItemContext } from '../AccordionContext'; import styles from '@patternfly/react-styles/css/components/Accordion/accordion'; -jest.mock('@patternfly/react-icons/dist/esm/icons/angle-right-icon', () => () => 'Icon mock'); +jest.mock('@patternfly/react-icons/dist/esm/icons/rh-microns-caret-down-icon', () => () => 'Icon mock'); test('Renders without children', () => { render( diff --git a/packages/react-core/src/components/Accordion/examples/Accordion.md b/packages/react-core/src/components/Accordion/examples/Accordion.md index cac3b5cc699..4713da98e32 100644 --- a/packages/react-core/src/components/Accordion/examples/Accordion.md +++ b/packages/react-core/src/components/Accordion/examples/Accordion.md @@ -1,11 +1,12 @@ --- id: Accordion section: components -cssPrefix: pf-v5-c-accordion +cssPrefix: pf-v6-c-accordion propComponents: ['Accordion', 'AccordionItem', 'AccordionContent', 'AccordionToggle', AccordionExpandableContentBody] --- -import ArrowRightIcon from '@patternfly/react-icons/dist/esm/icons/arrow-right-icon'; +import { useState } from 'react'; +import RhMicronsCaretRightIcon from '@patternfly/react-icons/dist/esm/icons/rh-microns-caret-right-icon'; ## Examples @@ -32,4 +33,4 @@ import ArrowRightIcon from '@patternfly/react-icons/dist/esm/icons/arrow-right-i ### Toggle icon at start ```ts file="./AccordionToggleIconAtStart.tsx" -``` \ No newline at end of file +``` diff --git a/packages/react-core/src/components/Accordion/examples/AccordionBordered.tsx b/packages/react-core/src/components/Accordion/examples/AccordionBordered.tsx index 448b124eccd..f20e362b4bd 100644 --- a/packages/react-core/src/components/Accordion/examples/AccordionBordered.tsx +++ b/packages/react-core/src/components/Accordion/examples/AccordionBordered.tsx @@ -1,4 +1,4 @@ -import React from 'react'; +import { useState } from 'react'; import { Accordion, AccordionItem, @@ -8,11 +8,11 @@ import { Button, Checkbox } from '@patternfly/react-core'; -import ArrowRightIcon from '@patternfly/react-icons/dist/esm/icons/arrow-right-icon'; +import RhMicronsCaretRightIcon from '@patternfly/react-icons/dist/esm/icons/rh-microns-caret-right-icon'; export const AccordionBordered: React.FunctionComponent = () => { - const [expanded, setExpanded] = React.useState('bordered-toggle4'); - const [isDisplayLarge, setIsDisplayLarge] = React.useState(false); + const [expanded, setExpanded] = useState('bordered-toggle4'); + const [isDisplayLarge, setIsDisplayLarge] = useState(false); const displaySize = isDisplayLarge ? 'lg' : 'default'; const onToggle = (id: string) => { @@ -95,7 +95,7 @@ export const AccordionBordered: React.FunctionComponent = () => { diff --git a/packages/react-core/src/components/Accordion/examples/AccordionDefinitionList.tsx b/packages/react-core/src/components/Accordion/examples/AccordionDefinitionList.tsx index d91573f53ce..c0cf781da5d 100644 --- a/packages/react-core/src/components/Accordion/examples/AccordionDefinitionList.tsx +++ b/packages/react-core/src/components/Accordion/examples/AccordionDefinitionList.tsx @@ -1,8 +1,8 @@ -import React from 'react'; +import { useState } from 'react'; import { Accordion, AccordionItem, AccordionContent, AccordionToggle } from '@patternfly/react-core'; export const AccordionDefinitionList: React.FunctionComponent = () => { - const [expanded, setExpanded] = React.useState('def-list-toggle2'); + const [expanded, setExpanded] = useState('def-list-toggle2'); const onToggle = (id: string) => { if (id === expanded) { diff --git a/packages/react-core/src/components/Accordion/examples/AccordionFixedWithMultipleExpandBehavior.tsx b/packages/react-core/src/components/Accordion/examples/AccordionFixedWithMultipleExpandBehavior.tsx index e0375c1056d..2ae7cdd7605 100644 --- a/packages/react-core/src/components/Accordion/examples/AccordionFixedWithMultipleExpandBehavior.tsx +++ b/packages/react-core/src/components/Accordion/examples/AccordionFixedWithMultipleExpandBehavior.tsx @@ -1,8 +1,8 @@ -import React from 'react'; +import { useState } from 'react'; import { Accordion, AccordionItem, AccordionContent, AccordionToggle } from '@patternfly/react-core'; export const AccordionFixedWithMultipleExpandBehavior: React.FunctionComponent = () => { - const [expanded, setExpanded] = React.useState(['ex2-toggle4']); + const [expanded, setExpanded] = useState(['ex2-toggle4']); const toggle = (id) => { const index = expanded.indexOf(id); diff --git a/packages/react-core/src/components/Accordion/examples/AccordionSingleExpandBehavior.tsx b/packages/react-core/src/components/Accordion/examples/AccordionSingleExpandBehavior.tsx index 17359cc4c0d..64e4755485a 100644 --- a/packages/react-core/src/components/Accordion/examples/AccordionSingleExpandBehavior.tsx +++ b/packages/react-core/src/components/Accordion/examples/AccordionSingleExpandBehavior.tsx @@ -1,8 +1,8 @@ -import React from 'react'; +import { useState } from 'react'; import { Accordion, AccordionItem, AccordionContent, AccordionToggle } from '@patternfly/react-core'; export const AccordionSingleExpandBehavior: React.FunctionComponent = () => { - const [expanded, setExpanded] = React.useState('ex-toggle2'); + const [expanded, setExpanded] = useState('ex-toggle2'); const onToggle = (id: string) => { if (id === expanded) { diff --git a/packages/react-core/src/components/Accordion/examples/AccordionToggleIconAtStart.tsx b/packages/react-core/src/components/Accordion/examples/AccordionToggleIconAtStart.tsx index c347feade96..9519d2a8870 100644 --- a/packages/react-core/src/components/Accordion/examples/AccordionToggleIconAtStart.tsx +++ b/packages/react-core/src/components/Accordion/examples/AccordionToggleIconAtStart.tsx @@ -1,8 +1,8 @@ -import React from 'react'; +import { useState } from 'react'; import { Accordion, AccordionItem, AccordionContent, AccordionToggle } from '@patternfly/react-core'; export const AccordionToggleIconAtStart: React.FunctionComponent = () => { - const [expanded, setExpanded] = React.useState('start-toggle-toggle2'); + const [expanded, setExpanded] = useState('start-toggle-toggle2'); const onToggle = (id: string) => { if (id === expanded) { diff --git a/packages/react-core/src/components/ActionList/ActionList.tsx b/packages/react-core/src/components/ActionList/ActionList.tsx index 8dd82ea57eb..00cbf747c44 100644 --- a/packages/react-core/src/components/ActionList/ActionList.tsx +++ b/packages/react-core/src/components/ActionList/ActionList.tsx @@ -1,4 +1,3 @@ -import * as React from 'react'; import { css } from '@patternfly/react-styles'; import styles from '@patternfly/react-styles/css/components/ActionList/action-list'; @@ -9,15 +8,26 @@ export interface ActionListProps extends React.HTMLProps { isIconList?: boolean; /** Additional classes added to the action list */ className?: string; + /** @beta Whether the layout of children is vertical or horizontal. */ + isVertical?: boolean; } export const ActionList: React.FunctionComponent = ({ children, isIconList, className, + isVertical = false, ...props }: ActionListProps) => ( -
+
{children}
); diff --git a/packages/react-core/src/components/ActionList/ActionListGroup.tsx b/packages/react-core/src/components/ActionList/ActionListGroup.tsx index 1e36985b9f7..8e5a22cb3b0 100644 --- a/packages/react-core/src/components/ActionList/ActionListGroup.tsx +++ b/packages/react-core/src/components/ActionList/ActionListGroup.tsx @@ -1,4 +1,3 @@ -import * as React from 'react'; import { css } from '@patternfly/react-styles'; import styles from '@patternfly/react-styles/css/components/ActionList/action-list'; diff --git a/packages/react-core/src/components/ActionList/ActionListItem.tsx b/packages/react-core/src/components/ActionList/ActionListItem.tsx index 2cc829848a3..d6827ff3801 100644 --- a/packages/react-core/src/components/ActionList/ActionListItem.tsx +++ b/packages/react-core/src/components/ActionList/ActionListItem.tsx @@ -1,4 +1,3 @@ -import * as React from 'react'; import { css } from '@patternfly/react-styles'; import styles from '@patternfly/react-styles/css/components/ActionList/action-list'; diff --git a/packages/react-core/src/components/ActionList/__tests__/ActionList.test.tsx b/packages/react-core/src/components/ActionList/__tests__/ActionList.test.tsx index 6512ebdb138..5bb4d943fdb 100644 --- a/packages/react-core/src/components/ActionList/__tests__/ActionList.test.tsx +++ b/packages/react-core/src/components/ActionList/__tests__/ActionList.test.tsx @@ -1,4 +1,3 @@ -import React from 'react'; import { render, screen } from '@testing-library/react'; import { ActionList } from '../ActionList'; import styles from '@patternfly/react-styles/css/components/ActionList/action-list'; @@ -38,6 +37,18 @@ test(`Renders with class ${styles.modifiers.icons} when isIconList is true`, () expect(screen.getByText('Test')).toHaveClass(styles.modifiers.icons); }); +test(`Does not render with class ${styles.modifiers.vertical} by default`, () => { + render(Test); + + expect(screen.getByText('Test')).not.toHaveClass(styles.modifiers.vertical); +}); + +test(`Renders with class ${styles.modifiers.vertical} when isVertical is true`, () => { + render(Test); + + expect(screen.getByText('Test')).toHaveClass(styles.modifiers.vertical); +}); + test('Renders with inherited element props spread to the component', () => { render(Test); diff --git a/packages/react-core/src/components/ActionList/__tests__/ActionListGroup.test.tsx b/packages/react-core/src/components/ActionList/__tests__/ActionListGroup.test.tsx index baf4d2a4515..66a2c8fcb25 100644 --- a/packages/react-core/src/components/ActionList/__tests__/ActionListGroup.test.tsx +++ b/packages/react-core/src/components/ActionList/__tests__/ActionListGroup.test.tsx @@ -1,4 +1,3 @@ -import React from 'react'; import { render, screen } from '@testing-library/react'; import { ActionListGroup } from '../ActionListGroup'; import styles from '@patternfly/react-styles/css/components/ActionList/action-list'; diff --git a/packages/react-core/src/components/ActionList/__tests__/ActionListItem.test.tsx b/packages/react-core/src/components/ActionList/__tests__/ActionListItem.test.tsx index 18b1949d80a..6c14466d16c 100644 --- a/packages/react-core/src/components/ActionList/__tests__/ActionListItem.test.tsx +++ b/packages/react-core/src/components/ActionList/__tests__/ActionListItem.test.tsx @@ -1,4 +1,3 @@ -import React from 'react'; import { render, screen } from '@testing-library/react'; import { ActionListItem } from '../ActionListItem'; import styles from '@patternfly/react-styles/css/components/ActionList/action-list'; diff --git a/packages/react-core/src/components/ActionList/examples/ActionList.md b/packages/react-core/src/components/ActionList/examples/ActionList.md index 5e829c52a72..836a7087ead 100644 --- a/packages/react-core/src/components/ActionList/examples/ActionList.md +++ b/packages/react-core/src/components/ActionList/examples/ActionList.md @@ -1,13 +1,14 @@ --- id: Action list section: components -cssPrefix: pf-v5-c-action-list +cssPrefix: pf-v6-c-action-list propComponents: ['ActionList', 'ActionListGroup', 'ActionListItem'] --- -import TimesIcon from '@patternfly/react-icons/dist/js/icons/times-icon'; +import { Fragment, useState } from 'react'; +import RhMicronsCloseIcon from '@patternfly/react-icons/dist/js/icons/rh-microns-close-icon'; import CheckIcon from '@patternfly/react-icons/dist/js/icons/check-icon'; -import EllipsisVIcon from '@patternfly/react-icons/dist/esm/icons/ellipsis-v-icon'; +import RhUiEllipsisVerticalFillIcon from '@patternfly/react-icons/dist/esm/icons/rh-ui-ellipsis-vertical-fill-icon'; ## Examples @@ -34,3 +35,9 @@ import EllipsisVIcon from '@patternfly/react-icons/dist/esm/icons/ellipsis-v-ico ```ts file="./ActionListWithCancelButton.tsx" ``` + +### Vertical action list + +```ts file="./ActionListVertical.tsx" isBeta + +``` diff --git a/packages/react-core/src/components/ActionList/examples/ActionListMultipleGroups.tsx b/packages/react-core/src/components/ActionList/examples/ActionListMultipleGroups.tsx index 1ea62325003..b9f3ecec657 100644 --- a/packages/react-core/src/components/ActionList/examples/ActionListMultipleGroups.tsx +++ b/packages/react-core/src/components/ActionList/examples/ActionListMultipleGroups.tsx @@ -1,4 +1,3 @@ -import React from 'react'; import { ActionList, ActionListGroup, ActionListItem, Button } from '@patternfly/react-core'; export const ActionListMultipleGroups: React.FunctionComponent = () => ( diff --git a/packages/react-core/src/components/ActionList/examples/ActionListSingleGroup.tsx b/packages/react-core/src/components/ActionList/examples/ActionListSingleGroup.tsx index db018b6c289..4c092a90346 100644 --- a/packages/react-core/src/components/ActionList/examples/ActionListSingleGroup.tsx +++ b/packages/react-core/src/components/ActionList/examples/ActionListSingleGroup.tsx @@ -1,4 +1,4 @@ -import React from 'react'; +import { Fragment, useState } from 'react'; import { ActionList, ActionListGroup, @@ -11,10 +11,10 @@ import { MenuToggleElement, Divider } from '@patternfly/react-core'; -import EllipsisVIcon from '@patternfly/react-icons/dist/esm/icons/ellipsis-v-icon'; +import RhUiEllipsisVerticalFillIcon from '@patternfly/react-icons/dist/esm/icons/rh-ui-ellipsis-vertical-fill-icon'; export const ActionListSingleGroup: React.FunctionComponent = () => { - const [isOpen, setIsOpen] = React.useState(false); + const [isOpen, setIsOpen] = useState(false); const onToggle = () => { setIsOpen(!isOpen); @@ -45,7 +45,7 @@ export const ActionListSingleGroup: React.FunctionComponent = () => { ); return ( - + @@ -84,9 +84,8 @@ export const ActionListSingleGroup: React.FunctionComponent = () => { variant="plain" isExpanded={isOpen} aria-label="Action list single group kebab" - > - - + icon={} + /> )} isOpen={isOpen} onOpenChange={(isOpen: boolean) => setIsOpen(isOpen)} @@ -96,6 +95,6 @@ export const ActionListSingleGroup: React.FunctionComponent = () => { - + ); }; diff --git a/packages/react-core/src/components/ActionList/examples/ActionListVertical.tsx b/packages/react-core/src/components/ActionList/examples/ActionListVertical.tsx new file mode 100644 index 00000000000..c2dfbadd1f9 --- /dev/null +++ b/packages/react-core/src/components/ActionList/examples/ActionListVertical.tsx @@ -0,0 +1,46 @@ +import { ActionList, ActionListGroup, ActionListItem, Button } from '@patternfly/react-core'; +import CheckIcon from '@patternfly/react-icons/dist/esm/icons/check-icon'; +import RhMicronsCloseIcon from '@patternfly/react-icons/dist/esm/icons/rh-microns-close-icon'; + +export const ActionListVertical: React.FunctionComponent = () => ( + <> +

Multiple groups

+ + + + + + + + + + + + + + + + + + +

Icons, in two groups

+ + + + - - )} - -); + ...props +}: AlertGroupProps) => { + const hasAnimations = useHasAnimations(hasAnimationsProp); + const [handleTransitionEnd, setHandleTransitionEnd] = useState<() => void>(() => () => {}); + + const updateTransitionEnd = (onTransitionEnd: () => void) => { + setHandleTransitionEnd(() => onTransitionEnd); + }; + + // Clear transition callback on unmount to prevent memory leaks + useEffect( + () => () => { + setHandleTransitionEnd(() => () => {}); + }, + [] + ); + + const onTransitionEnd = (event: React.TransitionEvent) => { + if (!hasAnimations) { + return; + } + + const prefersReducedMotion = !window.matchMedia('(prefers-reduced-motion: no-preference)')?.matches; + if ( + // If a user has no motion preference, we want to target the grid template rows transition + // so that the onClose is called after the "slide up" animation of other alerts finishes. + // If they have motion preference, we don't need to check for a specific transition since only opacity should fire. + (prefersReducedMotion || (!prefersReducedMotion && event.propertyName === 'grid-template-rows')) && + (event.target as HTMLElement).className.includes(styles.modifiers.offstageRight) + ) { + handleTransitionEnd(); + // Clear the callback after execution to prevent memory retention + setHandleTransitionEnd(() => () => {}); + } + }; + + return ( + +
    + {Children.toArray(children).map((alert, index) => ( +
  • ).props?.id || + `alertGroupItem-${(alert as React.ReactElement).key}` || + index + } + > + {alert} +
  • + ))} + {overflowMessage && ( +
  • + +
  • + )} +
+
+ ); +}; + AlertGroupInline.displayName = 'AlertGroupInline'; diff --git a/packages/react-core/src/components/Alert/AlertIcon.tsx b/packages/react-core/src/components/Alert/AlertIcon.tsx index 04539a9c84c..285b09cafe8 100644 --- a/packages/react-core/src/components/Alert/AlertIcon.tsx +++ b/packages/react-core/src/components/Alert/AlertIcon.tsx @@ -1,18 +1,17 @@ -import * as React from 'react'; import { css } from '@patternfly/react-styles'; import styles from '@patternfly/react-styles/css/components/Alert/alert'; -import CheckCircleIcon from '@patternfly/react-icons/dist/esm/icons/check-circle-icon'; -import ExclamationCircleIcon from '@patternfly/react-icons/dist/esm/icons/exclamation-circle-icon'; -import ExclamationTriangleIcon from '@patternfly/react-icons/dist/esm/icons/exclamation-triangle-icon'; -import InfoCircleIcon from '@patternfly/react-icons/dist/esm/icons/info-circle-icon'; -import BellIcon from '@patternfly/react-icons/dist/esm/icons/bell-icon'; +import RhUiCheckCircleFillIcon from '@patternfly/react-icons/dist/esm/icons/rh-ui-check-circle-fill-icon'; +import RhUiErrorFillIcon from '@patternfly/react-icons/dist/esm/icons/rh-ui-error-fill-icon'; +import RhUiWarningFillIcon from '@patternfly/react-icons/dist/esm/icons/rh-ui-warning-fill-icon'; +import RhUiInformationFillIcon from '@patternfly/react-icons/dist/esm/icons/rh-ui-information-fill-icon'; +import RhUiNotificationFillIcon from '@patternfly/react-icons/dist/esm/icons/rh-ui-notification-fill-icon'; export const variantIcons = { - success: CheckCircleIcon, - danger: ExclamationCircleIcon, - warning: ExclamationTriangleIcon, - info: InfoCircleIcon, - custom: BellIcon + success: RhUiCheckCircleFillIcon, + danger: RhUiErrorFillIcon, + warning: RhUiWarningFillIcon, + info: RhUiInformationFillIcon, + custom: RhUiNotificationFillIcon }; export interface AlertIconProps extends React.HTMLProps { diff --git a/packages/react-core/src/components/Alert/AlertToggleExpandButton.tsx b/packages/react-core/src/components/Alert/AlertToggleExpandButton.tsx index cc54957c516..2e7c7c030a7 100644 --- a/packages/react-core/src/components/Alert/AlertToggleExpandButton.tsx +++ b/packages/react-core/src/components/Alert/AlertToggleExpandButton.tsx @@ -1,7 +1,7 @@ -import * as React from 'react'; +import { useContext } from 'react'; import { Button, ButtonProps, ButtonVariant } from '../Button'; import { AlertContext } from './AlertContext'; -import AngleRightIcon from '@patternfly/react-icons/dist/esm/icons/angle-right-icon'; +import RhMicronsCaretDownIcon from '@patternfly/react-icons/dist/esm/icons/rh-microns-caret-down-icon'; import { css } from '@patternfly/react-styles'; import styles from '@patternfly/react-styles/css/components/Alert/alert'; @@ -23,7 +23,7 @@ export const AlertToggleExpandButton: React.FunctionComponent { - const { title, variantLabel: alertVariantLabel } = React.useContext(AlertContext); + const { title, variantLabel: alertVariantLabel } = useContext(AlertContext); return (
diff --git a/packages/react-core/src/components/Alert/__tests__/__snapshots__/AlertActionCloseButton.test.tsx.snap b/packages/react-core/src/components/Alert/__tests__/__snapshots__/AlertActionCloseButton.test.tsx.snap index 98f1594e1b4..c59f313bb6b 100644 --- a/packages/react-core/src/components/Alert/__tests__/__snapshots__/AlertActionCloseButton.test.tsx.snap +++ b/packages/react-core/src/components/Alert/__tests__/__snapshots__/AlertActionCloseButton.test.tsx.snap @@ -28,11 +28,11 @@ exports[`Matches the snapshot 1`] = ` fill="currentColor" height="1em" role="img" - viewBox="0 0 352 512" + viewBox="0 0 20 20" width="1em" >
diff --git a/packages/react-core/src/components/Alert/examples/Alert.md b/packages/react-core/src/components/Alert/examples/Alert.md index 0ada0b67282..d92ace4e4ef 100644 --- a/packages/react-core/src/components/Alert/examples/Alert.md +++ b/packages/react-core/src/components/Alert/examples/Alert.md @@ -1,44 +1,40 @@ --- id: Alert section: components -cssPrefix: ['pf-v5-c-alert', 'pf-v5-c-alert-group'] +cssPrefix: ['pf-v6-c-alert', 'pf-v6-c-alert-group'] propComponents: ['Alert', 'AlertGroup', 'AlertActionCloseButton', 'AlertActionLink'] ouia: true --- import './alert.css'; -import UsersIcon from '@patternfly/react-icons/dist/esm/icons/users-icon'; -import BoxIcon from '@patternfly/react-icons/dist/esm/icons/box-icon'; +import { Fragment, useEffect, useState } from 'react'; +import RhUiUsersFillIcon from '@patternfly/react-icons/dist/esm/icons/rh-ui-users-fill-icon'; +import RhUiContainerFillIcon from '@patternfly/react-icons/dist/esm/icons/rh-ui-container-fill-icon'; import DatabaseIcon from '@patternfly/react-icons/dist/esm/icons/database-icon'; -import ServerIcon from '@patternfly/react-icons/dist/esm/icons/server-icon'; +import RhUiServerStackFillIcon from '@patternfly/react-icons/dist/esm/icons/rh-ui-server-stack-fill-icon'; import LaptopIcon from '@patternfly/react-icons/dist/esm/icons/laptop-icon'; import buttonStyles from '@patternfly/react-styles/css/components/Button/button'; +Micro animations have been added for `` components within an ``. By default, you must opt into animations, since they can require updates to tests. To enable or disable animations as needed, use the `hasAnimations` property. With animations enabled, we recommend you ensure that dynamically-added alerts are prepended to a list of alerts, rather than appended to the end of it. + +Micro animations are turned on for all examples and demos where alerts are dynamically added. + ## Alert examples ### Alert variants PatternFly supports several alert variants for different scenarios. Each variant has an associated status icon, background, and alert title coded to communicate the severity of an alert. Use the `variant` property to apply the following styling options. If no `variant` is specified, then the variant will be set to "custom". -| Variant | Description | -|---|---| -| Custom | Use for generic messages that should have a custom color set by the associated CSS variable. Should be used when the message has no associated severity. | -| Info | Use for general informational messages | -| Success | Use to indicate that a task or process has been completed successfully | -| Warning | Use to indicate that a non-critical error has occurred| -| Danger | Use to indicate that a critical or blocking error has occurred | - -```ts -import React from 'react'; -import { Alert } from '@patternfly/react-core'; - - - - - - - -; +| Variant | Description | +| ------- | -------------------------------------------------------------------------------------------------------------------------------------------------------- | +| Custom | Use for generic messages that should have a custom color set by the associated CSS variable. Should be used when the message has no associated severity. | +| Info | Use for general informational messages | +| Success | Use to indicate that a task or process has been completed successfully | +| Warning | Use to indicate that a non-critical error has occurred | +| Danger | Use to indicate that a critical or blocking error has occurred | + +```ts file = "AlertVariants.tsx" + ``` ### Alert variations @@ -55,103 +51,16 @@ PatternFly supports several properties and variations that can be used to add ex - If there is not a description passed via `children` prop, then the `component` prop should be set to a non-heading element such as a `span` or `div`. - If there is a description passed via `children` prop, then the `component` prop should be a heading element. Headings should be ordered by their level and heading levels should not be skipped. For example, a heading of an `h2` level should not be followed directly by an `h4`. -```ts -import React from 'react'; -import { Alert, AlertActionCloseButton, AlertActionLink } from '@patternfly/react-core'; - - - - - View details - - console.log('Clicked on Ignore')} - > - Ignore - - - } - > -

Success alert description. This should tell the user more information about the alert.

-
- -

- Success alert description. This should tell the user more information about the alert.{' '} - This is a link. -

-
- console.log('Clicked the close button')} />} - > -

Short alert description.

-
- - -

Short alert description.

-
-; +```ts file = "AlertVariations.tsx" + ``` ### Alert timeout Use the `timeout` property to automatically dismiss an alert after a period of time. If set to `true`, the `timeout` will be 8000 milliseconds. Provide a specific value to dismiss the alert after a different number of milliseconds. -```ts -import React from 'react'; -import { Alert, AlertActionLink, AlertGroup, Button } from '@patternfly/react-core'; - -const AlertTimeout: React.FunctionComponent = () => { - const [alerts, setAlerts] = React.useState([]); - const [newAlertKey, setNewAlertKey] = React.useState(0); - - const onClick = () => { - const timeout = 8000; - setNewAlertKey((key) => key + 1); - setAlerts((prevAlerts) => { - return [ - ...prevAlerts, - - - View details - - console.log('Clicked on Ignore')} - > - Ignore - - - } - key={newAlertKey} - > - This alert will dismiss after {`${timeout / 1000} seconds`} - - ]; - }); - }; - - return ( - - - - {alerts} - - ); -}; +```ts file = "AlertTimeout.tsx" + ``` ### Expandable alerts @@ -162,189 +71,56 @@ It is not recommended to use an expandable alert with a `timeout` in a [toast al See the [toast alert considerations](/components/alert/accessibility#toast-alerts) section of the alert accessibility documentation to understand the accessibility risks associated with using toast alerts. -```ts -import React from 'react'; -import { Alert, AlertActionCloseButton, AlertActionLink } from '@patternfly/react-core'; - - - console.log('Clicked the close button')} />} - > -

Success alert description. This should tell the user more information about the alert.

-
- - - View details - - console.log('Clicked on Ignore')} - > - Ignore - -
- } - > -

Success alert description. This should tell the user more information about the alert.

-
-; +```ts file = "AlertExpandable.tsx" + ``` ### Truncated alerts Use the `truncateTitle` property to shorten a long `title`. Set `truncateTitle` equal to a number (passed in as `{n}`) to reduce the number of lines of text in the alert's `title`. Users may hover over or tab to a truncated `title` to see the full message in a tooltip. -```ts -import React from 'react'; -import { Alert } from '@patternfly/react-core'; - - - - - -; +```ts file = "AlertTruncated.tsx" + ``` ### Custom icons Use the `customIcon` property to replace a default alert icon with a custom icon. -```ts -import React from 'react'; -import { Alert } from '@patternfly/react-core'; -import UsersIcon from '@patternfly/react-icons/dist/esm/icons/users-icon'; -import BoxIcon from '@patternfly/react-icons/dist/esm/icons/box-icon'; -import DatabaseIcon from '@patternfly/react-icons/dist/esm/icons/database-icon'; -import ServerIcon from '@patternfly/react-icons/dist/esm/icons/server-icon'; -import LaptopIcon from '@patternfly/react-icons/dist/esm/icons/laptop-icon'; +```ts file = "AlertCustomIcons.tsx" - - } title="Default alert title" /> - } variant="info" title="Info alert title" /> - } variant="success" title="Success alert title" /> - } variant="warning" title="Warning alert title" /> - } variant="danger" title="Danger alert title" /> -; ``` ### Inline alerts variants Use inline alerts to display an alert inline with content. All alert variants may use the `isInline` property to position alerts in content-heavy areas, such as within forms, wizards, or drawers. -```ts -import React from 'react'; -import { Alert } from '@patternfly/react-core'; - - - - - - -; +```ts file = "AlertInlineVariants.tsx" + ``` ### Inline alert variations All general alert variations can use the `isInline` property to apply inline styling. -```ts -import React from 'react'; -import { Alert, AlertActionCloseButton, AlertActionLink } from '@patternfly/react-core'; - - - - View details - - console.log('Clicked on Ignore')} - > - Ignore - - - } - > -

Success alert description. This should tell the user more information about the alert.

- - -

- Success alert description. This should tell the user more information about the alert.{' '} - This is a link. -

-
- console.log('Clicked the close button')} />} - > -

Short alert description.

-
- - -

Short alert description.

-
-; +```ts file = "AlertInlineVariations.tsx" + ``` ### Plain inline alert variants Use the `isPlain` property to make any inline alert plain. Plain styling removes the colored background but keeps colored text and icons. -```ts -import React from 'react'; -import { Alert } from '@patternfly/react-core'; - - - - - - -; +```ts file = "AlertPlainInlineVariants.tsx" + ``` ### Plain inline alert variations It is not recommended to use a plain inline alert with `actionClose` nor `actionLinks` because these alerts are non-dismissible and should persist until the error or action related to the alert is resolved. -```ts -import React from 'react'; -import { Alert } from '@patternfly/react-core'; - -

Success alert description. This should tell the user more information about the alert.

-
; +```ts file = "AlertPlainInlineVariations.tsx" + ``` ### Static live region alerts @@ -353,33 +129,8 @@ Live region alerts allow you to expose dynamic content changes in a way that can By default, `isLiveRegion`alerts are static. -```ts -import React from 'react'; -import { Alert, AlertActionCloseButton } from '@patternfly/react-core'; - - - console.log('Clicked the close button')} />} - > - This alert uses the recommended isLiveRegion prop to automatically set ARIA attributes and CSS classes. - - console.log('Clicked the close button')} />} - > - You can alternatively omit the isLiveRegion prop to specify ARIA attributes and CSS manually on the - containing element. - -; +```ts file = "AlertStaticLiveRegion.tsx" + ``` ### Dynamic live region alerts @@ -406,11 +157,11 @@ An alert group stacks and positions 2 or more alerts in a live region, either in Alert groups can be one of the following variants: -| Variant | Description | -| --- | --- | +| Variant | Description | +| ------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | Static inline | Static inline alert groups contain alerts that appear when the page loads, and are seen within the normal page content flow. These groups should not contain alerts that will dynamically appear or update. | -| Toast | Toast alert groups contain alerts that typically appear in response to an asynchronous event or user action. These groups are positioned on top of other content at the top right of the page.| -| Dynamic | Dynamic alert groups contain alerts that typically appear in response to a user action, and are seen within the normal page content flow.| +| Toast | Toast alert groups contain alerts that typically appear in response to an asynchronous event or user action. These groups are positioned on top of other content at the top right of the page. | +| Dynamic | Dynamic alert groups contain alerts that typically appear in response to a user action, and are seen within the normal page content flow. | Dynamic alerts that are generated after the page initially loads must be appended to either a toast or dynamic `AlertGroup`, both of which must use the `isLiveRegion` property. New alerts appended to a toast or dynamic group will be announced by assistive technologies the moment the change happens. For information about customizing this announcement, read the [aria-atomic and aria-relevant](/components/alert/accessibility#aria-atomic-and-aria-relevant) section of the alert accessibility documentation. @@ -418,7 +169,7 @@ Dynamic alerts that are generated after the page initially loads must be appende All alert group variants may combine multiple [alert variants](/components/alert) For example, the following static inline alert group includes one "success" alert and one "info" alert. -```ts file="./AlertGroupStatic.tsx" +```ts file="AlertGroupStatic.tsx" ``` @@ -428,7 +179,7 @@ Toast alert groups are created by passing in the `isToast` and `isLiveRegion` pr Click the buttons in the example below to add alerts to a toast group. -```ts file="./AlertGroupToast.tsx" +```ts file="AlertGroupToast.tsx" ``` @@ -452,7 +203,7 @@ The following example shows how alerts can be triggered by an asynchronous event See the [alert accessibility tab](/components/alert/accessibility) for more information on customizing this behavior. -```ts file="./AlertGroupAsync.tsx" +```ts file="AlertGroupAsync.tsx" ``` @@ -460,7 +211,7 @@ See the [alert accessibility tab](/components/alert/accessibility) for more info Click the buttons in the example below to add dynamic alerts to a group. -```ts file="./AlertGroupSingularDynamic.tsx" +```ts file="AlertGroupSingularDynamic.tsx" ``` @@ -476,6 +227,6 @@ In the following example, there can be a maximum of 4 alerts shown at once. You may add multiple alerts to an alert group at once. Click the "add alert collection" button in the example below to add a batch of 3 toast alerts to a group. -```ts file="./AlertGroupMultipleDynamic.tsx" +```ts file="AlertGroupMultipleDynamic.tsx" ``` diff --git a/packages/react-core/src/components/Alert/examples/AlertAsyncLiveRegion.tsx b/packages/react-core/src/components/Alert/examples/AlertAsyncLiveRegion.tsx index d4b7d34c32f..51553032071 100644 --- a/packages/react-core/src/components/Alert/examples/AlertAsyncLiveRegion.tsx +++ b/packages/react-core/src/components/Alert/examples/AlertAsyncLiveRegion.tsx @@ -1,4 +1,4 @@ -import React from 'react'; +import { Fragment, useEffect, useState } from 'react'; import { Alert, AlertGroup, AlertVariant, ToggleGroup, ToggleGroupItem } from '@patternfly/react-core'; interface AlertInfo { @@ -8,15 +8,15 @@ interface AlertInfo { } export const AsyncLiveRegionAlert: React.FunctionComponent = () => { - const [alerts, setAlerts] = React.useState([]); - const [isActive, setIsActive] = React.useState(false); + const [alerts, setAlerts] = useState([]); + const [isActive, setIsActive] = useState(false); const getUniqueId: () => number = () => new Date().getTime(); const addAlert = (alertInfo: AlertInfo) => { - setAlerts((prevAlertInfo) => [...prevAlertInfo, alertInfo]); + setAlerts((prevAlertInfo) => [alertInfo, ...prevAlertInfo]); }; - React.useEffect(() => { + useEffect(() => { let timer = null; if (isActive) { timer = setInterval(() => { @@ -36,26 +36,20 @@ export const AsyncLiveRegionAlert: React.FunctionComponent = () => { }, [isActive, alerts]); return ( - + setIsActive(true)} - /> - setIsActive(false)} + onChange={() => setIsActive(!isActive)} /> - + {alerts.map(({ title, variant, key }) => ( ))} - + ); }; diff --git a/packages/react-core/src/components/Alert/examples/AlertCustomIcons.tsx b/packages/react-core/src/components/Alert/examples/AlertCustomIcons.tsx new file mode 100644 index 00000000000..dd9affbf231 --- /dev/null +++ b/packages/react-core/src/components/Alert/examples/AlertCustomIcons.tsx @@ -0,0 +1,17 @@ +import { Fragment } from 'react'; +import { Alert } from '@patternfly/react-core'; +import RhUiUsersFillIcon from '@patternfly/react-icons/dist/esm/icons/rh-ui-users-fill-icon'; +import RhUiContainerFillIcon from '@patternfly/react-icons/dist/esm/icons/rh-ui-container-fill-icon'; +import DatabaseIcon from '@patternfly/react-icons/dist/esm/icons/database-icon'; +import RhUiServerStackFillIcon from '@patternfly/react-icons/dist/esm/icons/rh-ui-server-stack-fill-icon'; +import LaptopIcon from '@patternfly/react-icons/dist/esm/icons/laptop-icon'; + +export const AlertCustomIcons: React.FunctionComponent = () => ( + + } title="Default alert title" /> + } variant="info" title="Info alert title" /> + } variant="success" title="Success alert title" /> + } variant="warning" title="Warning alert title" /> + } variant="danger" title="Danger alert title" /> + +); diff --git a/packages/react-core/src/components/Alert/examples/AlertDynamicLiveRegion.tsx b/packages/react-core/src/components/Alert/examples/AlertDynamicLiveRegion.tsx index 4a4bcfb74c8..6698cc374c8 100644 --- a/packages/react-core/src/components/Alert/examples/AlertDynamicLiveRegion.tsx +++ b/packages/react-core/src/components/Alert/examples/AlertDynamicLiveRegion.tsx @@ -1,5 +1,5 @@ -import React from 'react'; -import { Alert, AlertGroup, AlertVariant, InputGroup } from '@patternfly/react-core'; +import { Fragment, useState } from 'react'; +import { Alert, AlertGroup, AlertVariant, Flex, FlexItem } from '@patternfly/react-core'; import buttonStyles from '@patternfly/react-styles/css/components/Button/button'; interface AlertInfo { @@ -9,12 +9,12 @@ interface AlertInfo { } export const DynamicLiveRegionAlert: React.FunctionComponent = () => { - const [alerts, setAlerts] = React.useState([]); + const [alerts, setAlerts] = useState([]); const getUniqueId: () => number = () => new Date().getTime(); const btnClasses = [buttonStyles.button, buttonStyles.modifiers.secondary].join(' '); const addAlert = (alertInfo: AlertInfo) => { - setAlerts((prevAlertInfo) => [...prevAlertInfo, alertInfo]); + setAlerts((prevAlertInfo) => [alertInfo, ...prevAlertInfo]); }; const addSuccessAlert = () => { @@ -40,23 +40,29 @@ export const DynamicLiveRegionAlert: React.FunctionComponent = () => { }; return ( - - - - - - - + + + + + + + + + + + + + {alerts.map(({ title, variant, key }) => ( ))} - + ); }; diff --git a/packages/react-core/src/components/Alert/examples/AlertExpandable.tsx b/packages/react-core/src/components/Alert/examples/AlertExpandable.tsx new file mode 100644 index 00000000000..9fe9ab5b53d --- /dev/null +++ b/packages/react-core/src/components/Alert/examples/AlertExpandable.tsx @@ -0,0 +1,36 @@ +import { Fragment } from 'react'; +import { Alert, AlertActionCloseButton, AlertActionLink } from '@patternfly/react-core'; + +export const AlertExpandable: React.FunctionComponent = () => ( + + console.log('Clicked the close button')} />} + > +

Success alert description. This should tell the user more information about the alert.

+
+ + + View details + + console.log('Clicked on Ignore')} + > + Ignore + +
+ } + > +

Success alert description. This should tell the user more information about the alert.

+
+ +); diff --git a/packages/react-core/src/components/Alert/examples/AlertGroupAsync.tsx b/packages/react-core/src/components/Alert/examples/AlertGroupAsync.tsx index 2a2e894ec15..4bcb2a8c7e4 100644 --- a/packages/react-core/src/components/Alert/examples/AlertGroupAsync.tsx +++ b/packages/react-core/src/components/Alert/examples/AlertGroupAsync.tsx @@ -1,4 +1,4 @@ -import React from 'react'; +import { Fragment, useState } from 'react'; import { Alert, AlertProps, @@ -12,8 +12,8 @@ import { import buttonStyles from '@patternfly/react-styles/css/components/Button/button'; export const AlertGroupAsync: React.FunctionComponent = () => { - const [alerts, setAlerts] = React.useState[]>([]); - const [isRunning, setIsRunning] = React.useState(false); + const [alerts, setAlerts] = useState[]>([]); + const [isRunning, setIsRunning] = useState(false); const btnClasses = [buttonStyles.button, buttonStyles.modifiers.secondary].join(' '); @@ -21,12 +21,12 @@ export const AlertGroupAsync: React.FunctionComponent = () => { const addAlert = () => { setAlerts((prevAlerts) => [ - ...prevAlerts, { title: `Async notification ${prevAlerts.length + 1} was added to the queue.`, variant: 'danger', key: getUniqueId() - } + }, + ...prevAlerts ]); }; @@ -45,7 +45,7 @@ export const AlertGroupAsync: React.FunctionComponent = () => { useInterval(addAlert, isRunning ? 4500 : null); return ( - + - + {alerts.map(({ title, variant, key }) => ( { /> ))} - + ); }; diff --git a/packages/react-core/src/components/Alert/examples/AlertGroupMultipleDynamic.tsx b/packages/react-core/src/components/Alert/examples/AlertGroupMultipleDynamic.tsx index bc638abb4f2..311c1f75b7d 100644 --- a/packages/react-core/src/components/Alert/examples/AlertGroupMultipleDynamic.tsx +++ b/packages/react-core/src/components/Alert/examples/AlertGroupMultipleDynamic.tsx @@ -1,20 +1,20 @@ -import React from 'react'; +import { Fragment, useState } from 'react'; import { Alert, AlertProps, AlertGroup, AlertActionCloseButton, AlertVariant, - InputGroup, - InputGroupItem + Flex, + FlexItem } from '@patternfly/react-core'; import buttonStyles from '@patternfly/react-styles/css/components/Button/button'; export const AlertGroupMultipleDynamic: React.FunctionComponent = () => { - const [alerts, setAlerts] = React.useState[]>([]); + const [alerts, setAlerts] = useState[]>([]); const addAlerts = (incomingAlerts: Partial[]) => { - setAlerts((prevAlerts) => [...prevAlerts, ...incomingAlerts]); + setAlerts((prevAlerts) => [...incomingAlerts, ...prevAlerts]); }; const removeAlert = (key: React.Key) => { @@ -34,15 +34,15 @@ export const AlertGroupMultipleDynamic: React.FunctionComponent = () => { }; return ( - - - + + + - - - + + + {alerts.map(({ title, variant, key }) => ( { /> ))} - + ); }; diff --git a/packages/react-core/src/components/Alert/examples/AlertGroupSingularDynamic.tsx b/packages/react-core/src/components/Alert/examples/AlertGroupSingularDynamic.tsx index d70d1584e8b..b4087fb7017 100644 --- a/packages/react-core/src/components/Alert/examples/AlertGroupSingularDynamic.tsx +++ b/packages/react-core/src/components/Alert/examples/AlertGroupSingularDynamic.tsx @@ -1,20 +1,20 @@ -import React from 'react'; +import { Fragment, useState } from 'react'; import { Alert, AlertProps, AlertGroup, AlertActionCloseButton, AlertVariant, - InputGroup, - InputGroupItem + Flex, + FlexItem } from '@patternfly/react-core'; import buttonStyles from '@patternfly/react-styles/css/components/Button/button'; export const AlertGroupSingularDynamic: React.FunctionComponent = () => { - const [alerts, setAlerts] = React.useState[]>([]); + const [alerts, setAlerts] = useState[]>([]); const addAlert = (title: string, variant: AlertProps['variant'], key: React.Key) => { - setAlerts((prevAlerts) => [...prevAlerts, { title, variant, key }]); + setAlerts((prevAlerts) => [{ title, variant, key }, ...prevAlerts]); }; const removeAlert = (key: React.Key) => { @@ -38,25 +38,25 @@ export const AlertGroupSingularDynamic: React.FunctionComponent = () => { }; return ( - - - + + + - - + + - - + + - - - + + + {alerts.map(({ title, variant, key }) => ( { /> ))} - + ); }; diff --git a/packages/react-core/src/components/Alert/examples/AlertGroupSingularDynamicOverflow.tsx b/packages/react-core/src/components/Alert/examples/AlertGroupSingularDynamicOverflow.tsx index f827dbe5048..fa1a140c041 100644 --- a/packages/react-core/src/components/Alert/examples/AlertGroupSingularDynamicOverflow.tsx +++ b/packages/react-core/src/components/Alert/examples/AlertGroupSingularDynamicOverflow.tsx @@ -1,18 +1,18 @@ -import React from 'react'; +import { Fragment, useState } from 'react'; import { Alert, AlertProps, AlertGroup, AlertActionCloseButton, AlertVariant, - InputGroup, - InputGroupItem + Flex, + FlexItem } from '@patternfly/react-core'; import buttonStyles from '@patternfly/react-styles/css/components/Button/button'; export const AlertGroupSingularDynamicOverflow: React.FunctionComponent = () => { - const [alerts, setAlerts] = React.useState[]>([]); - const [overflowMessage, setOverflowMessage] = React.useState(''); + const [alerts, setAlerts] = useState[]>([]); + const [overflowMessage, setOverflowMessage] = useState(''); const maxDisplayed = 4; @@ -25,7 +25,7 @@ export const AlertGroupSingularDynamicOverflow: React.FunctionComponent = () => }; const addAlert = (title: string, variant: AlertProps['variant'], key: React.Key) => { - setAlerts((prevAlerts) => [...prevAlerts, { title, variant, key }]); + setAlerts((prevAlerts) => [{ title, variant, key }, ...prevAlerts]); setOverflowMessage(getOverflowMessage(alerts.length + 1)); }; @@ -57,25 +57,25 @@ export const AlertGroupSingularDynamicOverflow: React.FunctionComponent = () => }; return ( - - - + + + - - + + - - + + - - - + + + {alerts.slice(0, maxDisplayed).map(({ key, variant, title }) => ( /> ))} - + ); }; diff --git a/packages/react-core/src/components/Alert/examples/AlertGroupStatic.tsx b/packages/react-core/src/components/Alert/examples/AlertGroupStatic.tsx index c0afd20e980..1477cefc811 100644 --- a/packages/react-core/src/components/Alert/examples/AlertGroupStatic.tsx +++ b/packages/react-core/src/components/Alert/examples/AlertGroupStatic.tsx @@ -1,11 +1,11 @@ -import React from 'react'; +import { Fragment } from 'react'; import { Alert, AlertGroup } from '@patternfly/react-core'; export const AlertGroupStatic: React.FunctionComponent = () => ( - + - + ); diff --git a/packages/react-core/src/components/Alert/examples/AlertGroupToast.tsx b/packages/react-core/src/components/Alert/examples/AlertGroupToast.tsx index 1bb01c58f83..460eb9ddb6a 100644 --- a/packages/react-core/src/components/Alert/examples/AlertGroupToast.tsx +++ b/packages/react-core/src/components/Alert/examples/AlertGroupToast.tsx @@ -1,20 +1,20 @@ -import React from 'react'; +import { Fragment, useState } from 'react'; import { Alert, AlertProps, AlertGroup, AlertActionCloseButton, AlertVariant, - InputGroup, - InputGroupItem + Flex, + FlexItem } from '@patternfly/react-core'; import buttonStyles from '@patternfly/react-styles/css/components/Button/button'; export const AlertGroupToast: React.FunctionComponent = () => { - const [alerts, setAlerts] = React.useState[]>([]); + const [alerts, setAlerts] = useState[]>([]); const addAlert = (title: string, variant: AlertProps['variant'], key: React.Key) => { - setAlerts((prevAlerts) => [...prevAlerts, { title, variant, key }]); + setAlerts((prevAlerts) => [{ title, variant, key }, ...prevAlerts]); }; const removeAlert = (key: React.Key) => { @@ -38,25 +38,25 @@ export const AlertGroupToast: React.FunctionComponent = () => { }; return ( - - - + + + - - + + - - + + - - - + + + {alerts.map(({ key, variant, title }) => ( { /> ))} - + ); }; diff --git a/packages/react-core/src/components/Alert/examples/AlertGroupToastOverflowCapture.tsx b/packages/react-core/src/components/Alert/examples/AlertGroupToastOverflowCapture.tsx index 88c94e7b4ba..d4f567551dc 100644 --- a/packages/react-core/src/components/Alert/examples/AlertGroupToastOverflowCapture.tsx +++ b/packages/react-core/src/components/Alert/examples/AlertGroupToastOverflowCapture.tsx @@ -1,18 +1,18 @@ -import React from 'react'; +import { Fragment, useState } from 'react'; import { Alert, AlertProps, AlertGroup, AlertActionCloseButton, AlertVariant, - InputGroup, - InputGroupItem + Flex, + FlexItem } from '@patternfly/react-core'; import buttonStyles from '@patternfly/react-styles/css/components/Button/button'; export const AlertGroupToastOverflowCapture: React.FunctionComponent = () => { - const [alerts, setAlerts] = React.useState[]>([]); - const [overflowMessage, setOverflowMessage] = React.useState(''); + const [alerts, setAlerts] = useState[]>([]); + const [overflowMessage, setOverflowMessage] = useState(''); const maxDisplayed = 4; @@ -25,7 +25,7 @@ export const AlertGroupToastOverflowCapture: React.FunctionComponent = () => { }; const addAlert = (title: string, variant: AlertProps['variant'], key: React.Key) => { - setAlerts((prevAlerts) => [...prevAlerts, { title, variant, key }]); + setAlerts((prevAlerts) => [{ title, variant, key }, ...prevAlerts]); setOverflowMessage(getOverflowMessage(alerts.length + 1)); }; @@ -57,25 +57,31 @@ export const AlertGroupToastOverflowCapture: React.FunctionComponent = () => { }; return ( - - - + + + - - + + - - + + - - - + + + {alerts.slice(0, maxDisplayed).map(({ key, variant, title }) => ( { /> ))} - + ); }; diff --git a/packages/react-core/src/components/Alert/examples/AlertInlineVariants.tsx b/packages/react-core/src/components/Alert/examples/AlertInlineVariants.tsx new file mode 100644 index 00000000000..011401c76da --- /dev/null +++ b/packages/react-core/src/components/Alert/examples/AlertInlineVariants.tsx @@ -0,0 +1,12 @@ +import { Fragment } from 'react'; +import { Alert } from '@patternfly/react-core'; + +export const AlertInlineVariants: React.FunctionComponent = () => ( + + + + + + + +); diff --git a/packages/react-core/src/components/Alert/examples/AlertInlineVariations.tsx b/packages/react-core/src/components/Alert/examples/AlertInlineVariations.tsx new file mode 100644 index 00000000000..9e3029a4646 --- /dev/null +++ b/packages/react-core/src/components/Alert/examples/AlertInlineVariations.tsx @@ -0,0 +1,45 @@ +import { Fragment } from 'react'; +import { Alert, AlertActionCloseButton, AlertActionLink } from '@patternfly/react-core'; + +export const AlertInlineVariations: React.FunctionComponent = () => ( + + + + View details + + console.log('Clicked on Ignore')} + > + Ignore + + + } + > +

Success alert description. This should tell the user more information about the alert.

+ + +

+ Success alert description. This should tell the user more information about the alert.{' '} + This is a link. +

+
+ console.log('Clicked the close button')} />} + > +

Short alert description.

+
+ + +

Short alert description.

+
+ +); diff --git a/packages/react-core/src/components/Alert/examples/AlertPlainInlineVariants.tsx b/packages/react-core/src/components/Alert/examples/AlertPlainInlineVariants.tsx new file mode 100644 index 00000000000..2c63b045482 --- /dev/null +++ b/packages/react-core/src/components/Alert/examples/AlertPlainInlineVariants.tsx @@ -0,0 +1,12 @@ +import { Fragment } from 'react'; +import { Alert } from '@patternfly/react-core'; + +export const AlertPlainInlineVariants: React.FunctionComponent = () => ( + + + + + + + +); diff --git a/packages/react-core/src/components/Alert/examples/AlertPlainInlineVariations.tsx b/packages/react-core/src/components/Alert/examples/AlertPlainInlineVariations.tsx new file mode 100644 index 00000000000..0a1cbb368aa --- /dev/null +++ b/packages/react-core/src/components/Alert/examples/AlertPlainInlineVariations.tsx @@ -0,0 +1,7 @@ +import { Alert } from '@patternfly/react-core'; + +export const AlertPlainInlineVariations: React.FunctionComponent = () => ( + +

Success alert description. This should tell the user more information about the alert.

+
+); diff --git a/packages/react-core/src/components/Alert/examples/AlertStaticLiveRegion.tsx b/packages/react-core/src/components/Alert/examples/AlertStaticLiveRegion.tsx new file mode 100644 index 00000000000..b5f3bf17724 --- /dev/null +++ b/packages/react-core/src/components/Alert/examples/AlertStaticLiveRegion.tsx @@ -0,0 +1,29 @@ +import { Fragment } from 'react'; +import { Alert, AlertActionCloseButton } from '@patternfly/react-core'; + +export const AlertStaticLiveRegion: React.FunctionComponent = () => ( + + console.log('Clicked the close button')} />} + > + This alert uses the recommended isLiveRegion prop to automatically set ARIA attributes and CSS + classes. + + console.log('Clicked the close button')} />} + > + You can alternatively omit the isLiveRegion prop to specify ARIA attributes and CSS manually on the + containing element. + + +); diff --git a/packages/react-core/src/components/Alert/examples/AlertTimeout.tsx b/packages/react-core/src/components/Alert/examples/AlertTimeout.tsx new file mode 100644 index 00000000000..57eb3a8ccd4 --- /dev/null +++ b/packages/react-core/src/components/Alert/examples/AlertTimeout.tsx @@ -0,0 +1,45 @@ +import { Fragment, useState } from 'react'; +import { Alert, AlertActionLink, AlertGroup, Button } from '@patternfly/react-core'; + +export const AlertTimeout: React.FunctionComponent = () => { + const [alerts, setAlerts] = useState([]); + const [newAlertKey, setNewAlertKey] = useState(0); + + const onClick = () => { + const timeout = 8000; + setNewAlertKey((key) => key + 1); + setAlerts((prevAlerts) => [ + + + View details + + console.log('Clicked on Ignore')} + > + Ignore + + + } + key={newAlertKey} + > + This alert will dismiss after {`${timeout / 1000} seconds`} + , + ...prevAlerts + ]); + }; + + return ( + + + + {alerts} + + + ); +}; diff --git a/packages/react-core/src/components/Alert/examples/AlertTruncated.tsx b/packages/react-core/src/components/Alert/examples/AlertTruncated.tsx new file mode 100644 index 00000000000..57e903b13d5 --- /dev/null +++ b/packages/react-core/src/components/Alert/examples/AlertTruncated.tsx @@ -0,0 +1,28 @@ +import { Fragment } from 'react'; +import { Alert } from '@patternfly/react-core'; + +export const AlertTruncated: React.FunctionComponent = () => ( + + + + + +); diff --git a/packages/react-core/src/components/Alert/examples/AlertVariants.tsx b/packages/react-core/src/components/Alert/examples/AlertVariants.tsx new file mode 100644 index 00000000000..575b6cee161 --- /dev/null +++ b/packages/react-core/src/components/Alert/examples/AlertVariants.tsx @@ -0,0 +1,12 @@ +import { Fragment } from 'react'; +import { Alert } from '@patternfly/react-core'; + +export const AlertVariants: React.FunctionComponent = () => ( + + + + + + + +); diff --git a/packages/react-core/src/components/Alert/examples/AlertVariations.tsx b/packages/react-core/src/components/Alert/examples/AlertVariations.tsx new file mode 100644 index 00000000000..da6241b4352 --- /dev/null +++ b/packages/react-core/src/components/Alert/examples/AlertVariations.tsx @@ -0,0 +1,43 @@ +import { Fragment } from 'react'; +import { Alert, AlertActionCloseButton, AlertActionLink } from '@patternfly/react-core'; + +export const AlertVariations: React.FunctionComponent = () => ( + + + + View details + + console.log('Clicked on Ignore')} + > + Ignore + + + } + > +

Success alert description. This should tell the user more information about the alert.

+
+ +

+ Success alert description. This should tell the user more information about the alert.{' '} + This is a link. +

+
+ console.log('Clicked the close button')} />} + > +

Short alert description.

+
+ + +

Short alert description.

+
+ +); diff --git a/packages/react-core/src/components/Avatar/Avatar.tsx b/packages/react-core/src/components/Avatar/Avatar.tsx index 8aba318f43d..3de94da6ba1 100644 --- a/packages/react-core/src/components/Avatar/Avatar.tsx +++ b/packages/react-core/src/components/Avatar/Avatar.tsx @@ -1,34 +1,63 @@ -import * as React from 'react'; import styles from '@patternfly/react-styles/css/components/Avatar/avatar'; import { css } from '@patternfly/react-styles'; -export interface AvatarProps - extends React.DetailedHTMLProps, HTMLImageElement> { +export interface AvatarProps extends React.DetailedHTMLProps< + React.ImgHTMLAttributes, + HTMLImageElement +> { + /** Content rendered inside the avatar, such as custom svgs or icons. */ + children?: React.ReactNode; /** Additional classes added to the avatar. */ className?: string; - /** Attribute that specifies the URL of the image for the avatar. */ + /** Specifies the URL of the image for the avatar. */ src?: string; - /** Attribute that specifies the alternate text of the image for the avatar. */ + /** Specifies the alternate text of the image for the avatar. Will instead set the aria-label when using children or initials; to hide the avatar + * from assistive technologies when passing children or initials, pass an empty string to the alt prop. + */ alt: string; /** Flag to indicate the avatar should have a border. */ isBordered?: boolean; /** Size variant of avatar. */ size?: 'sm' | 'md' | 'lg' | 'xl'; + /** Color of the avatar. */ + color?: 'red' | 'orangered' | 'orange' | 'yellow' | 'green' | 'teal' | 'blue' | 'purple' | 'gray'; + /** Initials of the avatar. */ + initials?: string; } export const Avatar: React.FunctionComponent = ({ + children, className, src = '', alt, isBordered, size, + color, + initials, ...props -}: AvatarProps) => ( - {alt} -); +}: AvatarProps) => { + const avatarClasses = css(styles.avatar, styles.modifiers[size], isBordered && styles.modifiers.bordered, className); + const isAltEmptyString = alt === ''; + + if (initials || children) { + return ( +
+ {initials && ( + + )} + {children && children} +
+ ); + } + + return {alt}; +}; Avatar.displayName = 'Avatar'; diff --git a/packages/react-core/src/components/Avatar/__tests__/Avatar.test.tsx b/packages/react-core/src/components/Avatar/__tests__/Avatar.test.tsx index 79326b1896e..366c6173489 100644 --- a/packages/react-core/src/components/Avatar/__tests__/Avatar.test.tsx +++ b/packages/react-core/src/components/Avatar/__tests__/Avatar.test.tsx @@ -1,4 +1,3 @@ -import * as React from 'react'; import { render, screen } from '@testing-library/react'; import { Avatar } from '../Avatar'; import styles from '@patternfly/react-styles/css/components/Avatar/avatar'; @@ -63,6 +62,67 @@ test('Renders with passed aria-label prop', () => { expect(screen.getByRole('img')).toHaveAccessibleName('Avatar test'); }); +test('Renders with passed initials prop', () => { + render(); + expect(screen.getByText('AB')).toBeVisible(); +}); + +test('Renders with passed children prop', () => { + render(Test); + expect(screen.getByText('Test')).toBeVisible(); +}); + +test(`Renders with class name ${styles.modifiers.colorful} when color prop is passed`, () => { + render( + + Test + + ); + expect(screen.getByText('Test')).toHaveClass(styles.modifiers.colorful); +}); + +const colors = ['red', 'orangered', 'orange', 'yellow', 'green', 'teal', 'blue', 'purple', 'gray'] as const; +test.each(colors)('Renders with passed color prop: %s', (color) => { + render( + + Test + + ); + expect(screen.getByText('Test')).toHaveClass(styles.modifiers[color]); +}); + +test('Passes alt prop as aria-label when initials are passed', () => { + render(); + expect(screen.getByRole('img')).toHaveAccessibleName('User avatar'); +}); + +test('Passes alt prop as aria-label when children are passed', () => { + render(Test); + expect(screen.getByRole('img')).toHaveAccessibleName('User avatar'); +}); + +test('Applies aria-hidden="true" when alt is empty string and initials are passed', () => { + render(); + expect(screen.getByRole('img', { hidden: true })).toHaveAttribute('aria-hidden', 'true'); +}); + +test('Applies aria-hidden="true" when alt is empty string and children are passed', () => { + render(Test); + expect(screen.getByRole('img', { hidden: true })).toHaveAttribute('aria-hidden', 'true'); +}); + +test('Does not apply aria-label attribute when alt is empty string and initials are passed', () => { + render(); + const avatar = screen.getByRole('img', { hidden: true }); + expect(avatar).not.toHaveAttribute('aria-label'); +}); + +test('Does not apply aria-label attribute when alt is empty string and children are passed', () => { + render(Test); + const avatar = screen.getByRole('img', { hidden: true }); + expect(avatar).not.toHaveAttribute('aria-label'); +}); + test('Matches the snapshot', () => { const { asFragment } = render(); diff --git a/packages/react-core/src/components/Avatar/examples/Avatar.md b/packages/react-core/src/components/Avatar/examples/Avatar.md index 96252f41fe9..2cbdc0229a5 100644 --- a/packages/react-core/src/components/Avatar/examples/Avatar.md +++ b/packages/react-core/src/components/Avatar/examples/Avatar.md @@ -1,25 +1,53 @@ --- id: Avatar section: components -cssPrefix: pf-v5-c-avatar +cssPrefix: pf-v6-c-avatar propComponents: ['Avatar'] --- -import avatarImg from '../../assets/avatarImg.svg'; +import './avatar.css'; +import { Fragment } from 'react'; +import avatarImg from '../../assets/img_avatar-light.svg'; +import RhUiAiChatbotIcon from '@patternfly/react-icons/dist/esm/icons/rh-ui-ai-chatbot-icon'; ## Examples -### Basic +### Basic usage + +Pass in the `src` property to apply an image for the avatar, or pass `children` for custom content such as icons or svg elements. ```ts file="./AvatarBasic.tsx" + +``` + +### Color modifiers + +Color modifiers add visual interest and automatically include a border. The available colors are: "red," "orangered," "orange," "yellow," "green," "teal," "blue," "purple," and "gray". + +```ts file="./AvatarColorModifiers.tsx" + +``` + +### With initials + +An avatar can display initials by using the `initials` property. It's recommended to pass only a single initial to ensure the text fits inside of the avatar. + +```ts file="./AvatarInitials.tsx" + ``` -### Bordered +### Bordered + +A border can be applied by passing the `isBordered` property to a non-colorful avatar. ```ts file="./AvatarBordered.tsx" + ``` ### Size variations +An avatar can be rendered at different sizes by passing the `size` property. The available sizes are: "sm," "md" (the default size), "lg," and "xl". + ```ts file="./AvatarSizeVariations.tsx" + ``` diff --git a/packages/react-core/src/components/Avatar/examples/AvatarBasic.tsx b/packages/react-core/src/components/Avatar/examples/AvatarBasic.tsx index 42c0f343576..f0facc9f18f 100644 --- a/packages/react-core/src/components/Avatar/examples/AvatarBasic.tsx +++ b/packages/react-core/src/components/Avatar/examples/AvatarBasic.tsx @@ -1,5 +1,34 @@ -import React from 'react'; import { Avatar } from '@patternfly/react-core'; -import avatarImg from '../../assets/avatarImg.svg'; +import avatarImg from '../../assets/img_avatar-light.svg'; -; +const rhdsLogo = ( + + + + + + + + + + + + + + + + + + + + + + +); + +export const AvatarBasic: React.FunctionComponent = () => ( + <> + + {rhdsLogo} + +); diff --git a/packages/react-core/src/components/Avatar/examples/AvatarBordered.tsx b/packages/react-core/src/components/Avatar/examples/AvatarBordered.tsx index bc181e9a192..4986e5f82bf 100644 --- a/packages/react-core/src/components/Avatar/examples/AvatarBordered.tsx +++ b/packages/react-core/src/components/Avatar/examples/AvatarBordered.tsx @@ -1,5 +1,8 @@ -import React from 'react'; import { Avatar } from '@patternfly/react-core'; -import avatarImg from '../../assets/avatarImg.svg'; +import RhUiAiChatbotIcon from '@patternfly/react-icons/dist/esm/icons/rh-ui-ai-chatbot-icon'; -; +export const AvatarBordered: React.FunctionComponent = () => ( + + + +); diff --git a/packages/react-core/src/components/Avatar/examples/AvatarColorModifiers.tsx b/packages/react-core/src/components/Avatar/examples/AvatarColorModifiers.tsx new file mode 100644 index 00000000000..87f2684ede4 --- /dev/null +++ b/packages/react-core/src/components/Avatar/examples/AvatarColorModifiers.tsx @@ -0,0 +1,43 @@ +import { Avatar } from '@patternfly/react-core'; + +const profileSvg = ( + +); + +export const AvatarColorModifiers: React.FunctionComponent = () => ( + <> + + {profileSvg} + + + {profileSvg} + + + {profileSvg} + + + {profileSvg} + + + {profileSvg} + + + {profileSvg} + + + {profileSvg} + + + {profileSvg} + + + {profileSvg} + + +); diff --git a/packages/react-core/src/components/Avatar/examples/AvatarInitials.tsx b/packages/react-core/src/components/Avatar/examples/AvatarInitials.tsx new file mode 100644 index 00000000000..b6990eeea14 --- /dev/null +++ b/packages/react-core/src/components/Avatar/examples/AvatarInitials.tsx @@ -0,0 +1,16 @@ +import { Avatar } from '@patternfly/react-core'; + +export const AvatarInitials: React.FunctionComponent = () => ( + <> + + + + + + + + + + + +); diff --git a/packages/react-core/src/components/Avatar/examples/AvatarSizeVariations.tsx b/packages/react-core/src/components/Avatar/examples/AvatarSizeVariations.tsx index 0d8964830f8..9088e17759c 100644 --- a/packages/react-core/src/components/Avatar/examples/AvatarSizeVariations.tsx +++ b/packages/react-core/src/components/Avatar/examples/AvatarSizeVariations.tsx @@ -1,21 +1,10 @@ -import React from 'react'; import { Avatar } from '@patternfly/react-core'; -import avatarImg from '../../assets/avatarImg.svg'; - - Small -
- -
- Medium -
- -
- Large -
- -
- Extra Large -
- -
; +export const AvatarSizeVariations: React.FunctionComponent = () => ( + <> + + + + + +); diff --git a/packages/react-core/src/components/Avatar/examples/avatar.css b/packages/react-core/src/components/Avatar/examples/avatar.css new file mode 100644 index 00000000000..d2f920ff871 --- /dev/null +++ b/packages/react-core/src/components/Avatar/examples/avatar.css @@ -0,0 +1,7 @@ +.ws-react-c-avatar { + display: flex; + flex-wrap: wrap; + gap: var(--pf-t--global--spacer--sm); + align-items: end; + height: auto !important; +} diff --git a/packages/react-core/src/components/BackToTop/BackToTop.tsx b/packages/react-core/src/components/BackToTop/BackToTop.tsx index 2651bc6731f..7943c890f0e 100644 --- a/packages/react-core/src/components/BackToTop/BackToTop.tsx +++ b/packages/react-core/src/components/BackToTop/BackToTop.tsx @@ -1,7 +1,7 @@ -import * as React from 'react'; +import { forwardRef, useEffect, useState } from 'react'; import styles from '@patternfly/react-styles/css/components/BackToTop/back-to-top'; import { css } from '@patternfly/react-styles'; -import AngleUpIcon from '@patternfly/react-icons/dist/esm/icons/angle-up-icon'; +import RhMicronsCaretUpIcon from '@patternfly/react-icons/dist/esm/icons/rh-microns-caret-up-icon'; import { canUseDOM } from '../../helpers/util'; import { Button } from '../Button'; @@ -26,12 +26,12 @@ const BackToTopBase: React.FunctionComponent = ({ isAlwaysVisible = false, ...props }: BackToTopProps) => { - const [visible, setVisible] = React.useState(isAlwaysVisible); - React.useEffect(() => { + const [visible, setVisible] = useState(isAlwaysVisible); + useEffect(() => { setVisible(isAlwaysVisible); }, [isAlwaysVisible]); - const [scrollElement, setScrollElement] = React.useState(null); + const [scrollElement, setScrollElement] = useState(null); const toggleVisible = () => { if (scrollElement) { @@ -46,7 +46,7 @@ const BackToTopBase: React.FunctionComponent = ({ } }; - React.useEffect(() => { + useEffect(() => { const hasScrollSpy = Boolean(scrollableSelector); if (hasScrollSpy) { const scrollEl = document.querySelector(scrollableSelector) as HTMLElement; @@ -84,14 +84,14 @@ const BackToTopBase: React.FunctionComponent = ({ onClick={handleClick} {...props} > -
); }; -export const BackToTop = React.forwardRef((props: BackToTopProps, ref: React.Ref) => ( +export const BackToTop = forwardRef((props: BackToTopProps, ref: React.Ref) => ( )); BackToTop.displayName = 'BackToTop'; diff --git a/packages/react-core/src/components/BackToTop/__tests__/BackToTop.test.tsx b/packages/react-core/src/components/BackToTop/__tests__/BackToTop.test.tsx index 0ecf6bec452..958e73e1785 100644 --- a/packages/react-core/src/components/BackToTop/__tests__/BackToTop.test.tsx +++ b/packages/react-core/src/components/BackToTop/__tests__/BackToTop.test.tsx @@ -1,4 +1,4 @@ -import React, { RefObject } from 'react'; +import { createRef, RefObject } from 'react'; import { fireEvent, render, screen } from '@testing-library/react'; import { BackToTop } from '../BackToTop'; import userEvent from '@testing-library/user-event'; @@ -76,7 +76,7 @@ test('Renders with passed aria-label', () => { }); test('BackToTop can be accessed via passed innerRef', () => { - const testRef: RefObject = React.createRef(); + const testRef: RefObject = createRef(); render(); global.scrollTo = jest.fn(); testRef.current?.click(); diff --git a/packages/react-core/src/components/BackToTop/__tests__/__snapshots__/BackToTop.test.tsx.snap b/packages/react-core/src/components/BackToTop/__tests__/__snapshots__/BackToTop.test.tsx.snap index 0905c8f41cd..b290d087760 100644 --- a/packages/react-core/src/components/BackToTop/__tests__/__snapshots__/BackToTop.test.tsx.snap +++ b/packages/react-core/src/components/BackToTop/__tests__/__snapshots__/BackToTop.test.tsx.snap @@ -31,11 +31,11 @@ exports[`Matches the snapshot 1`] = ` fill="currentColor" height="1em" role="img" - viewBox="0 0 320 512" + viewBox="0 0 20 20" width="1em" >
diff --git a/packages/react-core/src/components/BackToTop/examples/BackToTop.md b/packages/react-core/src/components/BackToTop/examples/BackToTop.md index 4db0fd2a5ee..17e0107517a 100644 --- a/packages/react-core/src/components/BackToTop/examples/BackToTop.md +++ b/packages/react-core/src/components/BackToTop/examples/BackToTop.md @@ -1,7 +1,7 @@ --- id: Back to top section: components -cssPrefix: pf-v5-c-back-to-top +cssPrefix: pf-v6-c-back-to-top propComponents: ['BackToTop'] --- diff --git a/packages/react-core/src/components/BackToTop/examples/BackToTopBasic.tsx b/packages/react-core/src/components/BackToTop/examples/BackToTopBasic.tsx index 3ff05cc5c52..31190319b2d 100644 --- a/packages/react-core/src/components/BackToTop/examples/BackToTopBasic.tsx +++ b/packages/react-core/src/components/BackToTop/examples/BackToTopBasic.tsx @@ -1,4 +1,3 @@ -import React from 'react'; import { BackToTop } from '@patternfly/react-core'; export const BackToTopBasic: React.FunctionComponent = () => ; diff --git a/packages/react-core/src/components/Backdrop/Backdrop.tsx b/packages/react-core/src/components/Backdrop/Backdrop.tsx index 853bb8de57e..c564a8b7f53 100644 --- a/packages/react-core/src/components/Backdrop/Backdrop.tsx +++ b/packages/react-core/src/components/Backdrop/Backdrop.tsx @@ -1,4 +1,3 @@ -import * as React from 'react'; import { css } from '@patternfly/react-styles'; import styles from '@patternfly/react-styles/css/components/Backdrop/backdrop'; diff --git a/packages/react-core/src/components/Backdrop/__tests__/Backdrop.test.tsx b/packages/react-core/src/components/Backdrop/__tests__/Backdrop.test.tsx index b49797cc25b..927bf1a4c44 100644 --- a/packages/react-core/src/components/Backdrop/__tests__/Backdrop.test.tsx +++ b/packages/react-core/src/components/Backdrop/__tests__/Backdrop.test.tsx @@ -1,4 +1,3 @@ -import React from 'react'; import { render, screen } from '@testing-library/react'; import { Backdrop } from '../Backdrop'; import styles from '@patternfly/react-styles/css/components/Backdrop/backdrop'; diff --git a/packages/react-core/src/components/Backdrop/examples/Backdrop.md b/packages/react-core/src/components/Backdrop/examples/Backdrop.md index c230b8606b1..f0e72adffee 100644 --- a/packages/react-core/src/components/Backdrop/examples/Backdrop.md +++ b/packages/react-core/src/components/Backdrop/examples/Backdrop.md @@ -1,7 +1,7 @@ --- id: Backdrop section: components -cssPrefix: pf-v5-c-backdrop +cssPrefix: pf-v6-c-backdrop propComponents: ['Backdrop'] --- diff --git a/packages/react-core/src/components/Backdrop/examples/BackdropBasic.tsx b/packages/react-core/src/components/Backdrop/examples/BackdropBasic.tsx index 642e27428f7..6a56cbacb1d 100644 --- a/packages/react-core/src/components/Backdrop/examples/BackdropBasic.tsx +++ b/packages/react-core/src/components/Backdrop/examples/BackdropBasic.tsx @@ -1,4 +1,3 @@ -import React from 'react'; import { Backdrop } from '@patternfly/react-core'; export const BackdropBasic: React.FunctionComponent = () => ; diff --git a/packages/react-core/src/components/BackgroundImage/BackgroundImage.tsx b/packages/react-core/src/components/BackgroundImage/BackgroundImage.tsx index 9586f2b5d96..ed7fb875985 100644 --- a/packages/react-core/src/components/BackgroundImage/BackgroundImage.tsx +++ b/packages/react-core/src/components/BackgroundImage/BackgroundImage.tsx @@ -1,5 +1,3 @@ -import React from 'react'; - import { css } from '@patternfly/react-styles'; import styles from '@patternfly/react-styles/css/components/BackgroundImage/background-image'; import cssBackgroundImage from '@patternfly/react-tokens/dist/esm/c_background_image_BackgroundImage'; diff --git a/packages/react-core/src/components/BackgroundImage/__tests__/BackgroundImage.test.tsx b/packages/react-core/src/components/BackgroundImage/__tests__/BackgroundImage.test.tsx index ecd1cb47a6a..870c96469f1 100644 --- a/packages/react-core/src/components/BackgroundImage/__tests__/BackgroundImage.test.tsx +++ b/packages/react-core/src/components/BackgroundImage/__tests__/BackgroundImage.test.tsx @@ -1,4 +1,3 @@ -import React from 'react'; import { render, screen } from '@testing-library/react'; import { BackgroundImage } from '../BackgroundImage'; import styles from '@patternfly/react-styles/css/components/BackgroundImage/background-image'; diff --git a/packages/react-core/src/components/BackgroundImage/examples/BackgroundImage.md b/packages/react-core/src/components/BackgroundImage/examples/BackgroundImage.md index 3da399c73e2..63fb03aae01 100644 --- a/packages/react-core/src/components/BackgroundImage/examples/BackgroundImage.md +++ b/packages/react-core/src/components/BackgroundImage/examples/BackgroundImage.md @@ -1,7 +1,7 @@ --- id: Background image section: components -cssPrefix: pf-v5-c-background-image +cssPrefix: pf-v6-c-background-image propComponents: ['BackgroundImage'] --- diff --git a/packages/react-core/src/components/BackgroundImage/examples/BackgroundImageBasic.tsx b/packages/react-core/src/components/BackgroundImage/examples/BackgroundImageBasic.tsx index 063de040fd1..52b2e7d3c0a 100644 --- a/packages/react-core/src/components/BackgroundImage/examples/BackgroundImageBasic.tsx +++ b/packages/react-core/src/components/BackgroundImage/examples/BackgroundImageBasic.tsx @@ -1,4 +1,3 @@ -import React from 'react'; import { BackgroundImage } from '@patternfly/react-core'; export const BackgroundImageBasic: React.FunctionComponent = () => ( diff --git a/packages/react-core/src/components/Badge/Badge.tsx b/packages/react-core/src/components/Badge/Badge.tsx index 11ed2e84c57..8a625be02d3 100644 --- a/packages/react-core/src/components/Badge/Badge.tsx +++ b/packages/react-core/src/components/Badge/Badge.tsx @@ -1,4 +1,3 @@ -import * as React from 'react'; import { css } from '@patternfly/react-styles'; import styles from '@patternfly/react-styles/css/components/Badge/badge'; diff --git a/packages/react-core/src/components/Badge/__tests__/Badge.test.tsx b/packages/react-core/src/components/Badge/__tests__/Badge.test.tsx index eda05188aa5..12654efc25b 100644 --- a/packages/react-core/src/components/Badge/__tests__/Badge.test.tsx +++ b/packages/react-core/src/components/Badge/__tests__/Badge.test.tsx @@ -1,4 +1,3 @@ -import * as React from 'react'; import { render, screen } from '@testing-library/react'; import { Badge } from '../Badge'; import styles from '@patternfly/react-styles/css/components/Badge/badge'; diff --git a/packages/react-core/src/components/Badge/examples/Badge.md b/packages/react-core/src/components/Badge/examples/Badge.md index 4004819d407..75667fa6d6a 100644 --- a/packages/react-core/src/components/Badge/examples/Badge.md +++ b/packages/react-core/src/components/Badge/examples/Badge.md @@ -1,10 +1,11 @@ --- id: Badge section: components -cssPrefix: pf-v5-c-badge +cssPrefix: pf-v6-c-badge propComponents: ['Badge'] --- +import { Fragment } from 'react'; import './Badge.css'; ## Examples diff --git a/packages/react-core/src/components/Badge/examples/BadgeDisabled.tsx b/packages/react-core/src/components/Badge/examples/BadgeDisabled.tsx index c7d4bdad2f9..decc3995e63 100644 --- a/packages/react-core/src/components/Badge/examples/BadgeDisabled.tsx +++ b/packages/react-core/src/components/Badge/examples/BadgeDisabled.tsx @@ -1,8 +1,8 @@ -import React from 'react'; +import { Fragment } from 'react'; import { Badge } from '@patternfly/react-core'; export const BadgeRead: React.FunctionComponent = () => ( - + 7 @@ -15,5 +15,5 @@ export const BadgeRead: React.FunctionComponent = () => ( 999+ - + ); diff --git a/packages/react-core/src/components/Badge/examples/BadgeRead.tsx b/packages/react-core/src/components/Badge/examples/BadgeRead.tsx index d4ed336b545..fd0ea5fc6ff 100644 --- a/packages/react-core/src/components/Badge/examples/BadgeRead.tsx +++ b/packages/react-core/src/components/Badge/examples/BadgeRead.tsx @@ -1,8 +1,8 @@ -import React from 'react'; +import { Fragment } from 'react'; import { Badge } from '@patternfly/react-core'; export const BadgeRead: React.FunctionComponent = () => ( - + 7 @@ -15,5 +15,5 @@ export const BadgeRead: React.FunctionComponent = () => ( 999+ - + ); diff --git a/packages/react-core/src/components/Badge/examples/BadgeUnread.tsx b/packages/react-core/src/components/Badge/examples/BadgeUnread.tsx index b5bd85255a9..d327227d19d 100644 --- a/packages/react-core/src/components/Badge/examples/BadgeUnread.tsx +++ b/packages/react-core/src/components/Badge/examples/BadgeUnread.tsx @@ -1,8 +1,8 @@ -import React from 'react'; +import { Fragment } from 'react'; import { Badge } from '@patternfly/react-core'; export const BadgeUnread: React.FunctionComponent = () => ( - + 7 @@ -15,5 +15,5 @@ export const BadgeUnread: React.FunctionComponent = () => ( 999+ - + ); diff --git a/packages/react-core/src/components/Banner/Banner.tsx b/packages/react-core/src/components/Banner/Banner.tsx index 5b579f54586..79d042bb3e0 100644 --- a/packages/react-core/src/components/Banner/Banner.tsx +++ b/packages/react-core/src/components/Banner/Banner.tsx @@ -1,4 +1,3 @@ -import * as React from 'react'; import styles from '@patternfly/react-styles/css/components/Banner/banner'; import { css } from '@patternfly/react-styles'; @@ -13,6 +12,8 @@ export interface BannerProps extends React.HTMLProps { className?: string; /** If set to true, the banner sticks to the top of its container */ isSticky?: boolean; + /** If set to true, the banner will have a pill shape */ + isPill?: boolean; /** Text announced by screen readers to indicate the type of banner. This prop should only * be passed in when the banner conveys status/severity. */ @@ -37,6 +38,7 @@ export const Banner: React.FunctionComponent = ( className, screenReaderText, isSticky = false, + isPill = false, color, status, ...props @@ -53,7 +55,13 @@ export const Banner: React.FunctionComponent = ( return (
{screenReaderText && {screenReaderText}} diff --git a/packages/react-core/src/components/Banner/__tests__/Banner.test.tsx b/packages/react-core/src/components/Banner/__tests__/Banner.test.tsx index 37213a605ca..d0741b1ab09 100644 --- a/packages/react-core/src/components/Banner/__tests__/Banner.test.tsx +++ b/packages/react-core/src/components/Banner/__tests__/Banner.test.tsx @@ -1,4 +1,3 @@ -import * as React from 'react'; import { render, screen } from '@testing-library/react'; import { Banner } from '../Banner'; import styles from '@patternfly/react-styles/css/components/Banner/banner'; @@ -122,6 +121,21 @@ test('Renders with inherited element props spread to the component', () => { expect(screen.getByText('Test')).toHaveAccessibleName('Test label'); }); +test(`Renders with class name ${styles.modifiers.pill} when isPill prop is true`, () => { + render(Test); + expect(screen.getByText('Test')).toHaveClass(styles.modifiers.pill); +}); + +test(`Does not render with class name ${styles.modifiers.pill} when isPill is false`, () => { + render(Test); + expect(screen.getByText('Test')).not.toHaveClass(styles.modifiers.pill); +}); + +test(`Does not render with class name ${styles.modifiers.pill} when isPill is undefined`, () => { + render(Test); + expect(screen.getByText('Test')).not.toHaveClass(styles.modifiers.pill); +}); + test('Matches the snapshot', () => { const { asFragment } = render(Test); expect(asFragment()).toMatchSnapshot(); diff --git a/packages/react-core/src/components/Banner/examples/Banner.md b/packages/react-core/src/components/Banner/examples/Banner.md index e075c612aae..2de48c1a11a 100644 --- a/packages/react-core/src/components/Banner/examples/Banner.md +++ b/packages/react-core/src/components/Banner/examples/Banner.md @@ -1,15 +1,15 @@ --- id: Banner section: components -cssPrefix: pf-v5-c-banner +cssPrefix: pf-v6-c-banner propComponents: ['Banner'] --- -import CheckCircleIcon from '@patternfly/react-icons/dist/esm/icons/check-circle-icon'; -import ExclamationCircleIcon from '@patternfly/react-icons/dist/esm/icons/exclamation-circle-icon'; -import ExclamationTriangleIcon from '@patternfly/react-icons/dist/esm/icons/exclamation-triangle-icon'; -import InfoCircleIcon from '@patternfly/react-icons/dist/esm/icons/info-circle-icon'; -import BellIcon from '@patternfly/react-icons/dist/esm/icons/bell-icon'; +import RhUiCheckCircleFillIcon from '@patternfly/react-icons/dist/esm/icons/rh-ui-check-circle-fill-icon'; +import RhUiErrorFillIcon from '@patternfly/react-icons/dist/esm/icons/rh-ui-error-fill-icon'; +import RhUiWarningFillIcon from '@patternfly/react-icons/dist/esm/icons/rh-ui-warning-fill-icon'; +import RhUiInformationFillIcon from '@patternfly/react-icons/dist/esm/icons/rh-ui-information-fill-icon'; +import RhUiNotificationFillIcon from '@patternfly/react-icons/dist/esm/icons/rh-ui-notification-fill-icon'; ## Examples @@ -32,3 +32,11 @@ In the following example, a flex layout is used inside the banner content to sho ```ts file="./BannerStatus.tsx" ``` + +### Pill + +Banners may also have a rounded pill style by passing the `isPill` prop. + +```ts file="./BannerPill.tsx" + +``` diff --git a/packages/react-core/src/components/Banner/examples/BannerBasic.tsx b/packages/react-core/src/components/Banner/examples/BannerBasic.tsx index c9509d7ca35..dae3a5c5af0 100644 --- a/packages/react-core/src/components/Banner/examples/BannerBasic.tsx +++ b/packages/react-core/src/components/Banner/examples/BannerBasic.tsx @@ -1,4 +1,3 @@ -import React from 'react'; import { Banner } from '@patternfly/react-core'; export const BannerBasic: React.FunctionComponent = () => ( diff --git a/packages/react-core/src/components/Banner/examples/BannerPill.tsx b/packages/react-core/src/components/Banner/examples/BannerPill.tsx new file mode 100644 index 00000000000..e6b6e96dbaf --- /dev/null +++ b/packages/react-core/src/components/Banner/examples/BannerPill.tsx @@ -0,0 +1,21 @@ +import { Banner, Flex, FlexItem } from '@patternfly/react-core'; +import RhUiCheckCircleFillIcon from '@patternfly/react-icons/dist/esm/icons/rh-ui-check-circle-fill-icon'; + +export const BannerPill: React.FunctionComponent = () => ( + <> + Default pill banner +
+ + Red pill banner + +
+ + + + + + Success pill banner + + + +); diff --git a/packages/react-core/src/components/Banner/examples/BannerStatus.tsx b/packages/react-core/src/components/Banner/examples/BannerStatus.tsx index 56f60c8de7c..f72e191496c 100644 --- a/packages/react-core/src/components/Banner/examples/BannerStatus.tsx +++ b/packages/react-core/src/components/Banner/examples/BannerStatus.tsx @@ -1,17 +1,16 @@ -import React from 'react'; import { Banner, Flex, FlexItem } from '@patternfly/react-core'; -import CheckCircleIcon from '@patternfly/react-icons/dist/esm/icons/check-circle-icon'; -import ExclamationCircleIcon from '@patternfly/react-icons/dist/esm/icons/exclamation-circle-icon'; -import ExclamationTriangleIcon from '@patternfly/react-icons/dist/esm/icons/exclamation-triangle-icon'; -import InfoCircleIcon from '@patternfly/react-icons/dist/esm/icons/info-circle-icon'; -import BellIcon from '@patternfly/react-icons/dist/esm/icons/bell-icon'; +import RhUiCheckCircleFillIcon from '@patternfly/react-icons/dist/esm/icons/rh-ui-check-circle-fill-icon'; +import RhUiErrorFillIcon from '@patternfly/react-icons/dist/esm/icons/rh-ui-error-fill-icon'; +import RhUiWarningFillIcon from '@patternfly/react-icons/dist/esm/icons/rh-ui-warning-fill-icon'; +import RhUiInformationFillIcon from '@patternfly/react-icons/dist/esm/icons/rh-ui-information-fill-icon'; +import RhUiNotificationFillIcon from '@patternfly/react-icons/dist/esm/icons/rh-ui-notification-fill-icon'; export const BannerStatus: React.FunctionComponent = () => ( <> - + Success banner @@ -20,7 +19,7 @@ export const BannerStatus: React.FunctionComponent = () => ( - + Warning banner @@ -29,7 +28,7 @@ export const BannerStatus: React.FunctionComponent = () => ( - + Danger banner @@ -38,7 +37,7 @@ export const BannerStatus: React.FunctionComponent = () => ( - + Info banner @@ -47,7 +46,7 @@ export const BannerStatus: React.FunctionComponent = () => ( - + Custom banner diff --git a/packages/react-core/src/components/Brand/Brand.tsx b/packages/react-core/src/components/Brand/Brand.tsx index 328bf61fa64..02c3695a9d4 100644 --- a/packages/react-core/src/components/Brand/Brand.tsx +++ b/packages/react-core/src/components/Brand/Brand.tsx @@ -1,12 +1,13 @@ -import * as React from 'react'; import { css } from '@patternfly/react-styles'; import styles from '@patternfly/react-styles/css/components/Brand/brand'; import { setBreakpointCssVars } from '../../helpers'; import cssBrandHeight from '@patternfly/react-tokens/dist/esm/c_brand_Height'; import cssBrandWidth from '@patternfly/react-tokens/dist/esm/c_brand_Width'; -export interface BrandProps - extends React.DetailedHTMLProps, HTMLImageElement> { +export interface BrandProps extends React.DetailedHTMLProps< + React.ImgHTMLAttributes, + HTMLImageElement +> { /** Transforms the Brand into a element from an element. Container for child elements. */ children?: React.ReactNode; /** Additional classes added to the either type of Brand. */ diff --git a/packages/react-core/src/components/Brand/__tests__/Brand.test.tsx b/packages/react-core/src/components/Brand/__tests__/Brand.test.tsx index 9465121f30f..859e858bd25 100644 --- a/packages/react-core/src/components/Brand/__tests__/Brand.test.tsx +++ b/packages/react-core/src/components/Brand/__tests__/Brand.test.tsx @@ -1,4 +1,3 @@ -import * as React from 'react'; import { render, screen } from '@testing-library/react'; import { Brand } from '../Brand'; import '@testing-library/jest-dom'; diff --git a/packages/react-core/src/components/Brand/examples/BrandBasic.tsx b/packages/react-core/src/components/Brand/examples/BrandBasic.tsx index 9e4de1fd4b9..8a4cf455bb0 100644 --- a/packages/react-core/src/components/Brand/examples/BrandBasic.tsx +++ b/packages/react-core/src/components/Brand/examples/BrandBasic.tsx @@ -1,4 +1,3 @@ -import React from 'react'; import { Brand } from '@patternfly/react-core'; import pfLogo from '../../assets/PF-HorizontalLogo-Color.svg'; import pfLogoDark from '../../assets/PF-HorizontalLogo-Reverse.svg'; diff --git a/packages/react-core/src/components/Brand/examples/BrandResponsive.tsx b/packages/react-core/src/components/Brand/examples/BrandResponsive.tsx index b8cdffad8c0..fef2a7bba7a 100644 --- a/packages/react-core/src/components/Brand/examples/BrandResponsive.tsx +++ b/packages/react-core/src/components/Brand/examples/BrandResponsive.tsx @@ -1,4 +1,3 @@ -import React from 'react'; import { Brand } from '@patternfly/react-core'; import pfLogo from '../../assets/PF-HorizontalLogo-Color.svg'; diff --git a/packages/react-core/src/components/Breadcrumb/Breadcrumb.tsx b/packages/react-core/src/components/Breadcrumb/Breadcrumb.tsx index fea9df52ad8..2787047cefd 100644 --- a/packages/react-core/src/components/Breadcrumb/Breadcrumb.tsx +++ b/packages/react-core/src/components/Breadcrumb/Breadcrumb.tsx @@ -1,4 +1,4 @@ -import * as React from 'react'; +import { Children, isValidElement, cloneElement } from 'react'; import styles from '@patternfly/react-styles/css/components/Breadcrumb/breadcrumb'; import { css } from '@patternfly/react-styles'; import { useOUIAProps, OUIAProps } from '../../helpers'; @@ -28,10 +28,10 @@ export const Breadcrumb: React.FunctionComponent = ({ return (
} /> ); expect(screen.getByText('ICON')).toBeVisible(); - expect(screen.getByText('ICON').parentElement?.parentElement).toHaveClass('pf-m-in-progress'); + expect(screen.getByText('ICON').parentElement?.parentElement).toHaveClass(styles.modifiers.inProgress); }); test('Renders as custom component when component is passed', () => { @@ -232,6 +251,352 @@ test('setting tab index through props', () => { expect(screen.getByRole('button')).toHaveAttribute('tabindex', '0'); }); +test('Does not render aria-expanded by default', () => { + render(); + + expect(screen.getByRole('button')).not.toHaveAttribute('aria-expanded'); +}); + +test('Renders with aria-expanded when isExpanded is true', () => { + render(); + + expect(screen.getByRole('button')).toHaveAttribute('aria-expanded', 'true'); +}); + +test('Renders with aria-expanded when isExpanded is false', () => { + render(); + + expect(screen.getByRole('button')).toHaveAttribute('aria-expanded', 'false'); +}); + +// Remove this test when isExpanded prop in Button code is moved to after the spread props +test('Passing aria-expanded overrides isExpanded', () => { + render( + + ); + + expect(screen.getByRole('button')).toHaveAttribute('aria-expanded', 'false'); +}); + +describe('Hamburger button', () => { + test('Throws console error when isHamburger is true and isExpanded is not passed', () => { + const consoleError = jest.spyOn(console, 'error').mockImplementation(); + + render( + ); + + expect(consoleError).not.toHaveBeenCalledWith( + 'Button: you must provide either visible text content or an accessible name via the aria-label or aria-labelledby properties.' + ); + }); + + // TODO: Remove isHamburger in breaking change to throw error for any button that does not have children or aria name + test('Does not throw console error when isHamburger is true and aria-label is passed', () => { + const consoleError = jest.spyOn(console, 'error').mockImplementation(); + + render(
} />); + + expect(screen.queryByText('Custom icon')).not.toBeInTheDocument(); + }); +}); + +describe('Settings button', () => { + // TODO: Remove isSettings in breaking change to throw error for any button that does not have children or aria name + test('Throws console error when isSettings is true and neither children, aria-label nor aria-lablledby are passed', () => { + const consoleError = jest.spyOn(console, 'error').mockImplementation(); + + render(); + + expect(consoleError).not.toHaveBeenCalledWith( + 'Button: you must provide either visible text content or an accessible name via the aria-label or aria-labelledby properties.' + ); + }); + + // TODO: Remove isSettings in breaking change to throw error for any button that does not have children or aria name + test('Does not throw console error when isSettings is true and aria-label is passed', () => { + const consoleError = jest.spyOn(console, 'error').mockImplementation(); + + render(
} />); + + expect(screen.queryByText('Custom icon')).not.toBeInTheDocument(); + }); +}); + +describe('Favorite button', () => { + // TODO: Remove isFavorite in breaking change to throw error for any button that does not have children or aria name + test('Throws console error when isFavorite is true and neither children, aria-label nor aria-lablledby are passed', () => { + const consoleError = jest.spyOn(console, 'error').mockImplementation(); + + render(); + + expect(consoleError).not.toHaveBeenCalledWith( + 'Button: you must provide either visible text content or an accessible name via the aria-label or aria-labelledby properties.' + ); + }); + + // TODO: Remove isFavorite in breaking change to throw error for any button that does not have children or aria name + test('Does not throw console error when isFavorite is true and aria-label is passed', () => { + const consoleError = jest.spyOn(console, 'error').mockImplementation(); + + render(
} />); + expect(screen.queryByText('Icon content')).not.toBeInTheDocument(); + }); +}); + +describe('Dock variant', () => { + test(`Renders with class ${styles.modifiers.docked} when isDocked = true`, () => { + render(); + expect(screen.getByRole('button')).toHaveClass(styles.modifiers.docked); + }); + + test(`Does not render with class ${styles.modifiers.docked} when isDocked is not passed`, () => { + render(); + expect(screen.getByRole('button')).not.toHaveClass(styles.modifiers.docked); + }); + + test(`Renders with class ${styles.modifiers.textExpanded} when isTextExpanded = true and isDocked = true`, () => { + render( + + ); + expect(screen.getByRole('button')).toHaveClass(styles.modifiers.textExpanded); + }); + + test(`Does not render with class ${styles.modifiers.textExpanded} when isTextExpanded is not passed`, () => { + render(); + expect(screen.getByRole('button')).not.toHaveClass(styles.modifiers.textExpanded); + }); + + test(`Does not render with class ${styles.modifiers.textExpanded} when isTextExpanded = true but isDocked is not passed`, () => { + render(); + expect(screen.getByRole('button')).not.toHaveClass(styles.modifiers.textExpanded); + }); + + test(`Renders with both ${styles.modifiers.docked} and ${styles.modifiers.textExpanded} when both props are true`, () => { + render( + + ); + const button = screen.getByRole('button'); + expect(button).toHaveClass(styles.modifiers.docked); + expect(button).toHaveClass(styles.modifiers.textExpanded); + }); +}); + test(`Renders basic button`, () => { const { asFragment } = render(); expect(asFragment()).toMatchSnapshot(); diff --git a/packages/react-core/src/components/Button/__tests__/__snapshots__/Button.test.tsx.snap b/packages/react-core/src/components/Button/__tests__/__snapshots__/Button.test.tsx.snap index 1bf9bbee899..eb99ad0e5ec 100644 --- a/packages/react-core/src/components/Button/__tests__/__snapshots__/Button.test.tsx.snap +++ b/packages/react-core/src/components/Button/__tests__/__snapshots__/Button.test.tsx.snap @@ -3,10 +3,9 @@ exports[`Renders basic button 1`] = ` ``` diff --git a/packages/react-core/src/components/Button/examples/ButtonAriaDisabled.tsx b/packages/react-core/src/components/Button/examples/ButtonAriaDisabled.tsx index 0becd377cff..b1be6cb6990 100644 --- a/packages/react-core/src/components/Button/examples/ButtonAriaDisabled.tsx +++ b/packages/react-core/src/components/Button/examples/ButtonAriaDisabled.tsx @@ -1,12 +1,11 @@ -import React from 'react'; import { Button, Flex, Tooltip } from '@patternfly/react-core'; -import PlusCircleIcon from '@patternfly/react-icons/dist/esm/icons/plus-circle-icon'; +import RhUiAddCircleFillIcon from '@patternfly/react-icons/dist/esm/icons/rh-ui-add-circle-fill-icon'; export const ButtonAriaDisabled: React.FunctionComponent = () => ( <> - ; diff --git a/packages/react-core/src/components/Button/examples/ButtonCallToAction.tsx b/packages/react-core/src/components/Button/examples/ButtonCallToAction.tsx index 3c3887a478e..28da919459a 100644 --- a/packages/react-core/src/components/Button/examples/ButtonCallToAction.tsx +++ b/packages/react-core/src/components/Button/examples/ButtonCallToAction.tsx @@ -1,6 +1,5 @@ -import React from 'react'; import { Button, Flex } from '@patternfly/react-core'; -import ArrowRightIcon from '@patternfly/react-icons/dist/esm/icons/arrow-right-icon'; +import RhMicronsCaretRightIcon from '@patternfly/react-icons/dist/esm/icons/rh-microns-caret-right-icon'; export const ButtonCallToAction: React.FunctionComponent = () => ( @@ -13,7 +12,7 @@ export const ButtonCallToAction: React.FunctionComponent = () => ( - diff --git a/packages/react-core/src/components/Button/examples/ButtonCircle.tsx b/packages/react-core/src/components/Button/examples/ButtonCircle.tsx new file mode 100644 index 00000000000..615bde1efc5 --- /dev/null +++ b/packages/react-core/src/components/Button/examples/ButtonCircle.tsx @@ -0,0 +1,83 @@ +import { Button, Flex } from '@patternfly/react-core'; +import RhMicronsCloseIcon from '@patternfly/react-icons/dist/esm/icons/rh-microns-close-icon'; +import RhUiAddCircleFillIcon from '@patternfly/react-icons/dist/esm/icons/rh-ui-add-circle-fill-icon'; +import RhUiCopyFillIcon from '@patternfly/react-icons/dist/esm/icons/rh-ui-copy-fill-icon'; +import RhUiNotificationFillIcon from '@patternfly/react-icons/dist/esm/icons/rh-ui-notification-fill-icon'; +import UploadIcon from '@patternfly/react-icons/dist/esm/icons/upload-icon'; + +interface LoadingPropsType { + spinnerAriaValueText: string; + spinnerAriaLabelledBy?: string; + spinnerAriaLabel?: string; + isLoading: boolean; +} + +export const ButtonCircle: React.FunctionComponent = () => { + const [isUploading, setIsUploading] = useState(false); + + const uploadingProps = {} as LoadingPropsType; + uploadingProps.spinnerAriaValueText = 'Loading circle variant example'; + uploadingProps.spinnerAriaLabel = 'Uploading circle variant example data'; + uploadingProps.isLoading = isUploading; + + return ( + + +); diff --git a/packages/react-core/src/components/Button/examples/ButtonDisabled.tsx b/packages/react-core/src/components/Button/examples/ButtonDisabled.tsx index e04c6158958..a788dd56a28 100644 --- a/packages/react-core/src/components/Button/examples/ButtonDisabled.tsx +++ b/packages/react-core/src/components/Button/examples/ButtonDisabled.tsx @@ -1,8 +1,7 @@ -import React from 'react'; import { Button, Flex } from '@patternfly/react-core'; -import TimesIcon from '@patternfly/react-icons/dist/esm/icons/times-icon'; -import PlusCircleIcon from '@patternfly/react-icons/dist/esm/icons/plus-circle-icon'; -import CopyIcon from '@patternfly/react-icons/dist/esm/icons/copy-icon'; +import RhMicronsCloseIcon from '@patternfly/react-icons/dist/esm/icons/rh-microns-close-icon'; +import RhUiAddCircleFillIcon from '@patternfly/react-icons/dist/esm/icons/rh-ui-add-circle-fill-icon'; +import RhUiCopyFillIcon from '@patternfly/react-icons/dist/esm/icons/rh-ui-copy-fill-icon'; export const ButtonDisabled: React.FunctionComponent = () => ( <> @@ -26,7 +25,7 @@ export const ButtonDisabled: React.FunctionComponent = () => (
- - - Pressing the Enter or Space keys on the inline link as span above demonstrates this by triggering an alert.

- + ); diff --git a/packages/react-core/src/components/Button/examples/ButtonLinks.tsx b/packages/react-core/src/components/Button/examples/ButtonLinks.tsx index 5a6ec5a1ead..1bd930e6b61 100644 --- a/packages/react-core/src/components/Button/examples/ButtonLinks.tsx +++ b/packages/react-core/src/components/Button/examples/ButtonLinks.tsx @@ -1,4 +1,3 @@ -import React from 'react'; import { Button, Flex } from '@patternfly/react-core'; export const ButtonLinks: React.FunctionComponent = () => ( diff --git a/packages/react-core/src/components/Button/examples/ButtonPlainHasNoPadding.tsx b/packages/react-core/src/components/Button/examples/ButtonPlainHasNoPadding.tsx index 4d46c396d14..6786c7cf58e 100644 --- a/packages/react-core/src/components/Button/examples/ButtonPlainHasNoPadding.tsx +++ b/packages/react-core/src/components/Button/examples/ButtonPlainHasNoPadding.tsx @@ -1,11 +1,10 @@ -import React from 'react'; import { Button } from '@patternfly/react-core'; -import QuestionCircleIcon from '@patternfly/react-icons/dist/esm/icons/question-circle-icon'; +import RhUiQuestionMarkCircleFillIcon from '@patternfly/react-icons/dist/esm/icons/rh-ui-question-mark-circle-fill-icon'; export const ButtonPlainHasNoPadding: React.FunctionComponent = () => (

This is an example of a button - -); diff --git a/packages/react-core/src/components/Button/examples/ButtonSettings.tsx b/packages/react-core/src/components/Button/examples/ButtonSettings.tsx new file mode 100644 index 00000000000..b0e95cfb4c0 --- /dev/null +++ b/packages/react-core/src/components/Button/examples/ButtonSettings.tsx @@ -0,0 +1,10 @@ +import { Button, Flex } from '@patternfly/react-core'; + +export const ButtonSettings: React.FunctionComponent = () => ( + + + +); diff --git a/packages/react-core/src/components/Button/examples/ButtonSmall.tsx b/packages/react-core/src/components/Button/examples/ButtonSmall.tsx index 2fea0b9be89..e031f4ffaed 100644 --- a/packages/react-core/src/components/Button/examples/ButtonSmall.tsx +++ b/packages/react-core/src/components/Button/examples/ButtonSmall.tsx @@ -1,4 +1,3 @@ -import React from 'react'; import { Button, Flex } from '@patternfly/react-core'; export const ButtonSmall: React.FunctionComponent = () => ( diff --git a/packages/react-core/src/components/Button/examples/ButtonStateful.tsx b/packages/react-core/src/components/Button/examples/ButtonStateful.tsx index cb26da9b8f1..055f0b3faad 100644 --- a/packages/react-core/src/components/Button/examples/ButtonStateful.tsx +++ b/packages/react-core/src/components/Button/examples/ButtonStateful.tsx @@ -1,6 +1,5 @@ -import React from 'react'; import { Button, Flex } from '@patternfly/react-core'; -import BellIcon from '@patternfly/react-icons/dist/esm/icons/bell-icon'; +import RhUiNotificationFillIcon from '@patternfly/react-icons/dist/esm/icons/rh-ui-notification-fill-icon'; export const ButtonStateful: React.FunctionComponent = () => ( @@ -8,7 +7,7 @@ export const ButtonStateful: React.FunctionComponent = () => (

Read
-
@@ -16,7 +15,7 @@ export const ButtonStateful: React.FunctionComponent = () => (
Unread
-
@@ -24,7 +23,7 @@ export const ButtonStateful: React.FunctionComponent = () => (
Attention
-
diff --git a/packages/react-core/src/components/Button/examples/ButtonTypes.tsx b/packages/react-core/src/components/Button/examples/ButtonTypes.tsx index fb2fd288835..c07934d7918 100644 --- a/packages/react-core/src/components/Button/examples/ButtonTypes.tsx +++ b/packages/react-core/src/components/Button/examples/ButtonTypes.tsx @@ -1,4 +1,3 @@ -import React from 'react'; import { Button, Flex } from '@patternfly/react-core'; export const ButtonTypes: React.FunctionComponent = () => ( diff --git a/packages/react-core/src/components/Button/examples/ButtonVariations.tsx b/packages/react-core/src/components/Button/examples/ButtonVariations.tsx index 5f2e69de722..cb9820e8585 100644 --- a/packages/react-core/src/components/Button/examples/ButtonVariations.tsx +++ b/packages/react-core/src/components/Button/examples/ButtonVariations.tsx @@ -1,10 +1,9 @@ -import React from 'react'; import { Button, Flex } from '@patternfly/react-core'; -import TimesIcon from '@patternfly/react-icons/dist/esm/icons/times-icon'; -import PlusCircleIcon from '@patternfly/react-icons/dist/esm/icons/plus-circle-icon'; -import ExternalLinkSquareAltIcon from '@patternfly/react-icons/dist/esm/icons/external-link-square-alt-icon'; -import CopyIcon from '@patternfly/react-icons/dist/esm/icons/copy-icon'; -import BellIcon from '@patternfly/react-icons/dist/esm/icons/bell-icon'; +import RhMicronsCloseIcon from '@patternfly/react-icons/dist/esm/icons/rh-microns-close-icon'; +import RhUiExternalLinkFillIcon from '@patternfly/react-icons/dist/esm/icons/rh-ui-external-link-fill-icon'; +import RhUiAddCircleFillIcon from '@patternfly/react-icons/dist/esm/icons/rh-ui-add-circle-fill-icon'; +import RhUiCopyFillIcon from '@patternfly/react-icons/dist/esm/icons/rh-ui-copy-fill-icon'; +import RhUiNotificationFillIcon from '@patternfly/react-icons/dist/esm/icons/rh-ui-notification-fill-icon'; export const ButtonVariations: React.FunctionComponent = () => ( <> @@ -30,10 +29,10 @@ export const ButtonVariations: React.FunctionComponent = () => (
- - - - - - diff --git a/packages/react-core/src/components/Button/examples/ButtonWithCount.tsx b/packages/react-core/src/components/Button/examples/ButtonWithCount.tsx index 644ef31dfd2..e56340ffb5f 100644 --- a/packages/react-core/src/components/Button/examples/ButtonWithCount.tsx +++ b/packages/react-core/src/components/Button/examples/ButtonWithCount.tsx @@ -1,4 +1,3 @@ -import React from 'react'; import { BadgeCountObject, Button, Flex } from '@patternfly/react-core'; export const ButtonWithCount: React.FunctionComponent = () => { diff --git a/packages/react-core/src/components/Button/hamburgerIcon.tsx b/packages/react-core/src/components/Button/hamburgerIcon.tsx new file mode 100644 index 00000000000..70770e054b8 --- /dev/null +++ b/packages/react-core/src/components/Button/hamburgerIcon.tsx @@ -0,0 +1,13 @@ +import styles from '@patternfly/react-styles/css/components/Button/button'; +import { css } from '@patternfly/react-styles'; + +// Because this is such a specific icon that requires being wrapped in a pf-v[current version]-c-button element, +// we don't want to export this to consumers nor include it in the react-icons package as a custom icon. +export const hamburgerIcon = ( + + + + + + +); diff --git a/packages/react-core/src/components/CalendarMonth/CalendarMonth.tsx b/packages/react-core/src/components/CalendarMonth/CalendarMonth.tsx index 0b399271133..c49e32bda61 100644 --- a/packages/react-core/src/components/CalendarMonth/CalendarMonth.tsx +++ b/packages/react-core/src/components/CalendarMonth/CalendarMonth.tsx @@ -1,14 +1,14 @@ -import React, { useEffect } from 'react'; +import { useEffect, useMemo, useRef, useState } from 'react'; import { TextInput } from '../TextInput'; import { Button } from '../Button'; import { Select, SelectList, SelectOption } from '../Select'; import { MenuToggle, MenuToggleElement } from '../MenuToggle'; import { InputGroup, InputGroupItem } from '../InputGroup'; -import AngleLeftIcon from '@patternfly/react-icons/dist/esm/icons/angle-left-icon'; -import AngleRightIcon from '@patternfly/react-icons/dist/esm/icons/angle-right-icon'; +import RhMicronsCaretLeftIcon from '@patternfly/react-icons/dist/esm/icons/rh-microns-caret-left-icon'; +import RhMicronsCaretRightIcon from '@patternfly/react-icons/dist/esm/icons/rh-microns-caret-right-icon'; import { css } from '@patternfly/react-styles'; import styles from '@patternfly/react-styles/css/components/CalendarMonth/calendar-month'; -import { getUniqueId } from '../../helpers/util'; +import { useSSRSafeId } from '../../helpers'; import { isValidDate } from '../../helpers/datetimeUtils'; export enum Weekday { @@ -23,7 +23,7 @@ export enum Weekday { export interface CalendarMonthInlineProps { /** Component wrapping the calendar month when used inline. Recommended to be 'article'. */ - component?: keyof JSX.IntrinsicElements; + component?: keyof React.JSX.IntrinsicElements; /** Title of the calendar rendered above the inline calendar month. Recommended to be a 'title' component. */ title?: React.ReactNode; /** Id of the accessible label of the calendar month. Recommended to map to the title. */ @@ -81,6 +81,13 @@ export interface CalendarProps extends CalendarFormat, Omit void; /** Functions that returns if a date is valid and selectable. */ validators?: ((date: Date) => boolean)[]; + /** The container to append the month select menu to. Defaults to 'inline'. + * If your menu is being cut off you can append it to an element higher up the DOM tree. + * Some examples: + * monthAppendTo={() => document.body}; + * monthAppendTo={document.getElementById('target')} + */ + monthAppendTo?: HTMLElement | ((ref?: HTMLElement) => HTMLElement) | 'inline'; } const buildCalendar = (year: number, month: number, weekStart: number, validators: ((date: Date) => boolean)[]) => { @@ -143,12 +150,13 @@ export const CalendarMonth = ({ cellAriaLabel, isDateFocused = false, inlineProps, + monthAppendTo = 'inline', ...props }: CalendarProps) => { const longMonths = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11] .map((monthNum) => new Date(1990, monthNum)) .map(monthFormat); - const [isSelectOpen, setIsSelectOpen] = React.useState(false); + const [isSelectOpen, setIsSelectOpen] = useState(false); const getInitialDate = () => { if (isValidDate(dateProp)) { @@ -160,18 +168,18 @@ export const CalendarMonth = ({ return today; }; const initialDate = getInitialDate(); - const [focusedDate, setFocusedDate] = React.useState(initialDate); + const [focusedDate, setFocusedDate] = useState(initialDate); // Must be numeric given current header design const yearFormat = (date: Date) => date.getFullYear(); // const yearFormatted = yearFormat(focusedDate); - const [yearInput, setYearInput] = React.useState(yearFormatted.toString()); + const [yearInput, setYearInput] = useState(yearFormatted.toString()); - const [hoveredDate, setHoveredDate] = React.useState(undefined); - const focusRef = React.useRef(); - const [hiddenMonthId] = React.useState(getUniqueId('hidden-month-span')); - const [shouldFocus, setShouldFocus] = React.useState(false); + const [hoveredDate, setHoveredDate] = useState(undefined); + const focusRef = useRef(undefined); + const hiddenMonthId = useSSRSafeId('hidden-month-span'); + const [shouldFocus, setShouldFocus] = useState(false); const isValidated = (date: Date) => validators.every((validator) => validator(date)); const focusedDateValidated = isValidated(focusedDate); @@ -266,7 +274,7 @@ export const CalendarMonth = ({ const nextMonth = addMonth(1); const focusedYear = focusedDate.getFullYear(); const focusedMonth = focusedDate.getMonth(); - const calendar = React.useMemo( + const calendar = useMemo( () => buildCalendar(focusedYear, focusedMonth, weekStart, validators), [focusedYear, focusedMonth, weekStart, validators] ); @@ -292,7 +300,7 @@ export const CalendarMonth = ({ variant="plain" aria-label={prevMonthAriaLabel} onClick={(ev: React.MouseEvent) => onMonthClick(ev, prevMonth)} - icon={} + icon={} />
@@ -319,18 +327,15 @@ export const CalendarMonth = ({ onSelectToggle(isOpen); }} onSelect={(ev, monthNum) => { - // When we put CalendarMonth in a Popover we want the Popover's onDocumentClick - // to see the SelectOption as a child so it doesn't close the Popover. - setTimeout(() => { - setIsSelectOpen(false); - onSelectToggle(false); - const newDate = changeMonth(Number(monthNum as string)); - setFocusedDate(newDate); - setShouldFocus(false); - onMonthChange(ev, newDate); - }, 0); + setIsSelectOpen(false); + onSelectToggle(false); + const newDate = changeMonth(Number(monthNum as string)); + setFocusedDate(newDate); + setShouldFocus(false); + onMonthChange(ev, newDate); }} selected={monthFormatted} + popperProps={{ appendTo: monthAppendTo }} > {longMonths.map((longMonth, index) => ( @@ -358,7 +363,7 @@ export const CalendarMonth = ({ variant="plain" aria-label={nextMonthAriaLabel} onClick={(ev: React.MouseEvent) => onMonthClick(ev, nextMonth)} - icon={} + icon={} />
diff --git a/packages/react-core/src/components/CalendarMonth/__tests__/CalendarMonth.test.tsx b/packages/react-core/src/components/CalendarMonth/__tests__/CalendarMonth.test.tsx index f94e4af16a0..28afa2b5c62 100644 --- a/packages/react-core/src/components/CalendarMonth/__tests__/CalendarMonth.test.tsx +++ b/packages/react-core/src/components/CalendarMonth/__tests__/CalendarMonth.test.tsx @@ -1,5 +1,3 @@ -import React from 'react'; - import { render, screen } from '@testing-library/react'; import { CalendarMonth } from '../CalendarMonth'; diff --git a/packages/react-core/src/components/CalendarMonth/examples/CalendarMonth.md b/packages/react-core/src/components/CalendarMonth/examples/CalendarMonth.md index 0939ade50e6..ab5a6a3005e 100644 --- a/packages/react-core/src/components/CalendarMonth/examples/CalendarMonth.md +++ b/packages/react-core/src/components/CalendarMonth/examples/CalendarMonth.md @@ -2,9 +2,10 @@ id: Calendar month section: components subsection: date-and-time -cssPrefix: pf-v5-c-calendar-month +cssPrefix: pf-v6-c-calendar-month propComponents: ['CalendarMonth', 'CalendarFormat', 'CalendarMonthInlineProps'] --- +import { useState } from 'react'; ## Examples diff --git a/packages/react-core/src/components/CalendarMonth/examples/CalendarMonthDateRange.tsx b/packages/react-core/src/components/CalendarMonth/examples/CalendarMonthDateRange.tsx index 1bdfd79ea46..a2654d98e11 100644 --- a/packages/react-core/src/components/CalendarMonth/examples/CalendarMonthDateRange.tsx +++ b/packages/react-core/src/components/CalendarMonth/examples/CalendarMonthDateRange.tsx @@ -1,4 +1,3 @@ -import React from 'react'; import { CalendarMonth, Title, CalendarMonthInlineProps } from '@patternfly/react-core'; export const CalendarMonthDateRange: React.FunctionComponent = () => { diff --git a/packages/react-core/src/components/CalendarMonth/examples/CalendarMonthSelectableDate.tsx b/packages/react-core/src/components/CalendarMonth/examples/CalendarMonthSelectableDate.tsx index cde7097ffa5..876f2b3dda0 100644 --- a/packages/react-core/src/components/CalendarMonth/examples/CalendarMonthSelectableDate.tsx +++ b/packages/react-core/src/components/CalendarMonth/examples/CalendarMonthSelectableDate.tsx @@ -1,8 +1,8 @@ -import React from 'react'; +import { useState } from 'react'; import { CalendarMonth, Title, CalendarMonthInlineProps } from '@patternfly/react-core'; export const CalendarMonthSelectableDate: React.FunctionComponent = () => { - const [date, setDate] = React.useState(new Date(2020, 10, 24)); + const [date, setDate] = useState(new Date(2020, 10, 24)); const onMonthChange = ( _event: React.MouseEvent | React.ChangeEvent | React.FormEvent | undefined, diff --git a/packages/react-core/src/components/Card/Card.tsx b/packages/react-core/src/components/Card/Card.tsx index 79e282dcc2d..b3e0ad1f024 100644 --- a/packages/react-core/src/components/Card/Card.tsx +++ b/packages/react-core/src/components/Card/Card.tsx @@ -1,4 +1,4 @@ -import * as React from 'react'; +import { createContext, forwardRef } from 'react'; import styles from '@patternfly/react-styles/css/components/Card/card'; import { css } from '@patternfly/react-styles'; import { useOUIAProps, OUIAProps } from '../../helpers'; @@ -11,7 +11,7 @@ export interface CardProps extends React.HTMLProps, OUIAProps { /** Additional classes added to the Card */ className?: string; /** Sets the base component to render. defaults to div */ - component?: keyof JSX.IntrinsicElements; + component?: keyof React.JSX.IntrinsicElements; /** Modifies the card to include compact styling. Should not be used with isLarge. */ isCompact?: boolean; /** Flag indicating that the card is selectable. */ @@ -34,6 +34,8 @@ export interface CardProps extends React.HTMLProps, OUIAProps { isFullHeight?: boolean; /** Modifies the card to include plain styling; this removes border and background */ isPlain?: boolean; + /** Modifies the card to include glass styling when glass theme is enabled */ + isGlass?: boolean; /** Flag indicating if a card is expanded. Modifies the card to be expandable. */ isExpanded?: boolean; /** Card background color variant */ @@ -42,6 +44,8 @@ export interface CardProps extends React.HTMLProps, OUIAProps { ouiaId?: number | string; /** Set the value of data-ouia-safe. Only set to true when the component is in a static state, i.e. no animations are occurring. At all other times, this value must be false. */ ouiaSafe?: boolean; + /** @hide Forwarded ref */ + innerRef?: React.Ref; } interface CardContextProps { @@ -54,7 +58,7 @@ interface CardContextProps { isDisabled: boolean; } -export const CardContext = React.createContext>({ +export const CardContext = createContext>({ cardId: '', isExpanded: false, isClickable: false, @@ -64,7 +68,7 @@ export const CardContext = React.createContext>({ isDisabled: false }); -export const Card: React.FunctionComponent = ({ +const CardBase: React.FunctionComponent = ({ children, id = '', className, @@ -79,10 +83,11 @@ export const Card: React.FunctionComponent = ({ isLarge = false, isFullHeight = false, isPlain = false, + isGlass = false, variant = 'default', ouiaId, ouiaSafe = true, - + innerRef, ...props }: CardProps) => { const Component = component as any; @@ -127,6 +132,7 @@ export const Card: React.FunctionComponent = ({ }} > = ({ isLarge && styles.modifiers.displayLg, isFullHeight && styles.modifiers.fullHeight, isPlain && styles.modifiers.plain, + isGlass && styles.modifiers.glass, variant === 'secondary' && styles.modifiers.secondary, getSelectableModifiers(), isDisabled && styles.modifiers.disabled, @@ -148,4 +155,7 @@ export const Card: React.FunctionComponent = ({ ); }; + +export const Card = forwardRef((props: CardProps, ref: React.Ref) => ); + Card.displayName = 'Card'; diff --git a/packages/react-core/src/components/Card/CardActions.tsx b/packages/react-core/src/components/Card/CardActions.tsx index 2fbe418dc6b..5732439ea0d 100644 --- a/packages/react-core/src/components/Card/CardActions.tsx +++ b/packages/react-core/src/components/Card/CardActions.tsx @@ -1,4 +1,3 @@ -import * as React from 'react'; import { css } from '@patternfly/react-styles'; import styles from '@patternfly/react-styles/css/components/Card/card'; diff --git a/packages/react-core/src/components/Card/CardBody.tsx b/packages/react-core/src/components/Card/CardBody.tsx index cd8af73a8b9..da14d0fe16c 100644 --- a/packages/react-core/src/components/Card/CardBody.tsx +++ b/packages/react-core/src/components/Card/CardBody.tsx @@ -1,7 +1,8 @@ -import * as React from 'react'; import styles from '@patternfly/react-styles/css/components/Card/card'; import { css } from '@patternfly/react-styles'; +import type { JSX } from 'react'; + export interface CardBodyProps extends React.HTMLProps { /** Content rendered inside the Card Body */ children?: React.ReactNode; diff --git a/packages/react-core/src/components/Card/CardExpandableContent.tsx b/packages/react-core/src/components/Card/CardExpandableContent.tsx index 9f9c538ebc9..9def7cebfba 100644 --- a/packages/react-core/src/components/Card/CardExpandableContent.tsx +++ b/packages/react-core/src/components/Card/CardExpandableContent.tsx @@ -1,4 +1,3 @@ -import * as React from 'react'; import styles from '@patternfly/react-styles/css/components/Card/card'; import { css } from '@patternfly/react-styles'; import { CardContext } from './Card'; diff --git a/packages/react-core/src/components/Card/CardFooter.tsx b/packages/react-core/src/components/Card/CardFooter.tsx index cd2314f774a..09078bd8931 100644 --- a/packages/react-core/src/components/Card/CardFooter.tsx +++ b/packages/react-core/src/components/Card/CardFooter.tsx @@ -1,7 +1,8 @@ -import * as React from 'react'; import styles from '@patternfly/react-styles/css/components/Card/card'; import { css } from '@patternfly/react-styles'; +import type { JSX } from 'react'; + export interface CardFooterProps extends React.HTMLProps { /** Content rendered inside the Card Footer */ children?: React.ReactNode; diff --git a/packages/react-core/src/components/Card/CardHeader.tsx b/packages/react-core/src/components/Card/CardHeader.tsx index 1ee98dbee92..dc0cc411511 100644 --- a/packages/react-core/src/components/Card/CardHeader.tsx +++ b/packages/react-core/src/components/Card/CardHeader.tsx @@ -1,4 +1,3 @@ -import * as React from 'react'; import { css } from '@patternfly/react-styles'; import styles from '@patternfly/react-styles/css/components/Card/card'; import { CardContext } from './Card'; @@ -6,9 +5,10 @@ import { CardHeaderMain } from './CardHeaderMain'; import { CardActions } from './CardActions'; import { CardSelectableActions } from './CardSelectableActions'; import { Button } from '../Button'; -import AngleRightIcon from '@patternfly/react-icons/dist/esm/icons/angle-right-icon'; +import RhMicronsCaretDownIcon from '@patternfly/react-icons/dist/esm/icons/rh-microns-caret-down-icon'; import { Radio } from '../Radio'; import { Checkbox } from '../Checkbox'; +import { useSSRSafeId } from '../../helpers'; export interface CardHeaderActionsObject { /** Actions of the card header */ @@ -54,6 +54,8 @@ export interface CardHeaderSelectableActionsObject { * the isSelected prop on the card component instead. */ isChecked?: boolean; + /** Flag indicating the action is hidden */ + isHidden?: boolean; } export interface CardHeaderProps extends React.HTMLProps { @@ -73,6 +75,8 @@ export interface CardHeaderProps extends React.HTMLProps { toggleButtonProps?: any; /** Whether to right-align expandable toggle button */ isToggleRightAligned?: boolean; + /** Flag indicating that header wrapping is enabled */ + hasWrap?: boolean; } export const CardHeader: React.FunctionComponent = ({ @@ -84,9 +88,10 @@ export const CardHeader: React.FunctionComponent = ({ onExpand, toggleButtonProps, isToggleRightAligned, + hasWrap, ...props }: CardHeaderProps) => { - const uniqueId = React.useId(); + const randomId = useSSRSafeId(); return ( @@ -102,7 +107,7 @@ export const CardHeader: React.FunctionComponent = ({ {...toggleButtonProps} icon={ - } /> @@ -133,11 +138,12 @@ export const CardHeader: React.FunctionComponent = ({ const SelectableCardInput = selectableActions?.variant === 'single' ? Radio : Checkbox; const getSelectableProps = () => ({ - className: 'pf-m-standalone', + className: css('pf-m-standalone'), + inputClassName: css(selectableActions?.isHidden && 'pf-v6-screen-reader'), label: <>, 'aria-label': selectableActions.selectableActionAriaLabel, 'aria-labelledby': selectableActions.selectableActionAriaLabelledby, - id: selectableActions.selectableActionId ?? `card-selectable-${uniqueId}`, + id: selectableActions.selectableActionId ?? `card-selectable-${randomId}`, name: selectableActions.name, isDisabled: isCardDisabled, onChange: selectableActions.onChange, @@ -150,7 +156,11 @@ export const CardHeader: React.FunctionComponent = ({ const getClickableProps = () => { const isDisabledLinkCard = isCardDisabled && isClickableLinkCard; const baseProps = { - className: css('pf-v6-c-card__clickable-action', isDisabledLinkCard && styles.modifiers.disabled), + className: css( + 'pf-v6-c-card__clickable-action', + isDisabledLinkCard && styles.modifiers.disabled, + selectableActions?.isHidden && 'pf-v6-screen-reader' + ), id: selectableActions.selectableActionId, 'aria-label': selectableActions.selectableActionAriaLabel, 'aria-labelledby': selectableActions.selectableActionAriaLabelledby, @@ -171,7 +181,12 @@ export const CardHeader: React.FunctionComponent = ({ return (
diff --git a/packages/react-core/src/components/Card/CardHeaderMain.tsx b/packages/react-core/src/components/Card/CardHeaderMain.tsx index 759bb18d47b..e7f4b6d25d8 100644 --- a/packages/react-core/src/components/Card/CardHeaderMain.tsx +++ b/packages/react-core/src/components/Card/CardHeaderMain.tsx @@ -1,4 +1,3 @@ -import * as React from 'react'; import { css } from '@patternfly/react-styles'; import styles from '@patternfly/react-styles/css/components/Card/card'; diff --git a/packages/react-core/src/components/Card/CardSelectableActions.tsx b/packages/react-core/src/components/Card/CardSelectableActions.tsx index 3b86314bdc9..5a2d2d0e8f2 100644 --- a/packages/react-core/src/components/Card/CardSelectableActions.tsx +++ b/packages/react-core/src/components/Card/CardSelectableActions.tsx @@ -1,4 +1,3 @@ -import * as React from 'react'; import { css } from '@patternfly/react-styles'; import styles from '@patternfly/react-styles/css/components/Card/card'; diff --git a/packages/react-core/src/components/Card/CardSubtitle.tsx b/packages/react-core/src/components/Card/CardSubtitle.tsx new file mode 100644 index 00000000000..63e27ac915a --- /dev/null +++ b/packages/react-core/src/components/Card/CardSubtitle.tsx @@ -0,0 +1,20 @@ +import { css } from '@patternfly/react-styles'; +import styles from '@patternfly/react-styles/css/components/Card/card'; + +export interface CardSubtitleProps { + /** Content rendered inside the description. */ + children?: React.ReactNode; + /** Id of the description. */ + id?: string; +} + +export const CardSubtitle: React.FunctionComponent = ({ + children = null, + id = '', + ...props +}: CardSubtitleProps) => ( +
+ {children} +
+); +CardSubtitle.displayName = 'CardSubtitle'; diff --git a/packages/react-core/src/components/Card/CardTitle.tsx b/packages/react-core/src/components/Card/CardTitle.tsx index de4764cf227..17333c150f4 100644 --- a/packages/react-core/src/components/Card/CardTitle.tsx +++ b/packages/react-core/src/components/Card/CardTitle.tsx @@ -1,7 +1,8 @@ -import * as React from 'react'; +import { useContext } from 'react'; import { css } from '@patternfly/react-styles'; import styles from '@patternfly/react-styles/css/components/Card/card'; import { CardContext } from './Card'; +import { CardSubtitle } from './CardSubtitle'; export interface CardTitleProps extends React.HTMLProps { /** Content rendered inside the CardTitle */ @@ -9,24 +10,29 @@ export interface CardTitleProps extends React.HTMLProps { /** Additional classes added to the CardTitle */ className?: string; /** Sets the base component to render. defaults to div */ - component?: keyof JSX.IntrinsicElements; + component?: keyof React.JSX.IntrinsicElements; + /** @beta Subtitle of the card title */ + subtitle?: React.ReactNode; } export const CardTitle: React.FunctionComponent = ({ children, className, component = 'div', + subtitle, ...props }: CardTitleProps) => { - const { cardId } = React.useContext(CardContext); + const { cardId } = useContext(CardContext); const Component = component as any; const titleId = cardId ? `${cardId}-title` : ''; + const subtitleId = cardId ? `${cardId}-subtitle` : ''; return (
{children} + {subtitle && {subtitle}}
); }; diff --git a/packages/react-core/src/components/Card/__tests__/Card.test.tsx b/packages/react-core/src/components/Card/__tests__/Card.test.tsx index beae4f1254f..42ba729d7ab 100644 --- a/packages/react-core/src/components/Card/__tests__/Card.test.tsx +++ b/packages/react-core/src/components/Card/__tests__/Card.test.tsx @@ -1,9 +1,8 @@ -import React from 'react'; - import { render, screen } from '@testing-library/react'; import '@testing-library/jest-dom'; import { Card } from '../Card'; +import { createRef } from 'react'; describe('Card', () => { test('renders with PatternFly Core styles', () => { @@ -33,7 +32,7 @@ describe('Card', () => { test('allows passing in a React Component as the component', () => { const Component = () =>
im a div
; - render(); + render(); expect(screen.getByText('im a div')).toBeInTheDocument(); }); @@ -87,10 +86,25 @@ describe('Card', () => { expect(consoleWarnMock).toHaveBeenCalled(); }); + test('card with isGlass applied', () => { + render(glass card); + expect(screen.getByText('glass card')).toHaveClass('pf-m-glass'); + }); + test('card with variant set to secondary ', () => { render(secondary card); const card = screen.getByText('secondary card'); expect(card).toHaveClass('pf-m-secondary'); }); + + test('ref is added to the root element', () => { + const ref = createRef(); + render( + + card + + ); + expect(ref.current).toBe(screen.getByText('card')); + }); }); diff --git a/packages/react-core/src/components/Card/__tests__/CardBody.test.tsx b/packages/react-core/src/components/Card/__tests__/CardBody.test.tsx index 140f3b25a9e..a1e6478c633 100644 --- a/packages/react-core/src/components/Card/__tests__/CardBody.test.tsx +++ b/packages/react-core/src/components/Card/__tests__/CardBody.test.tsx @@ -1,4 +1,3 @@ -import React from 'react'; import { render, screen } from '@testing-library/react'; import { CardBody } from '../CardBody'; @@ -30,7 +29,7 @@ describe('CardBody', () => { test('allows passing in a React Component as the component', () => { const Component = () =>
im a div
; - render(); + render(); expect(screen.getByText('im a div')).toBeInTheDocument(); }); diff --git a/packages/react-core/src/components/Card/__tests__/CardExpandableContent.test.tsx b/packages/react-core/src/components/Card/__tests__/CardExpandableContent.test.tsx index 72316947730..77b27e573a0 100644 --- a/packages/react-core/src/components/Card/__tests__/CardExpandableContent.test.tsx +++ b/packages/react-core/src/components/Card/__tests__/CardExpandableContent.test.tsx @@ -1,4 +1,3 @@ -import React from 'react'; import { CardContext } from '../Card'; import { CardExpandableContent } from '../CardExpandableContent'; import { render } from '@testing-library/react'; diff --git a/packages/react-core/src/components/Card/__tests__/CardFooter.test.tsx b/packages/react-core/src/components/Card/__tests__/CardFooter.test.tsx index 19c7db7eab2..ed7a55d67c2 100644 --- a/packages/react-core/src/components/Card/__tests__/CardFooter.test.tsx +++ b/packages/react-core/src/components/Card/__tests__/CardFooter.test.tsx @@ -1,4 +1,3 @@ -import React from 'react'; import { render, screen } from '@testing-library/react'; import { CardFooter } from '../CardFooter'; @@ -27,7 +26,7 @@ describe('CardFooter', () => { test('allows passing in a React Component as the component', () => { const Component = () =>
im a div
; - render(); + render(); expect(screen.getByText('im a div')).toBeInTheDocument(); }); }); diff --git a/packages/react-core/src/components/Card/__tests__/CardHeader.test.tsx b/packages/react-core/src/components/Card/__tests__/CardHeader.test.tsx index 996f024b0ec..8a4ac4d38f3 100644 --- a/packages/react-core/src/components/Card/__tests__/CardHeader.test.tsx +++ b/packages/react-core/src/components/Card/__tests__/CardHeader.test.tsx @@ -1,5 +1,6 @@ -import React from 'react'; import { render, screen } from '@testing-library/react'; +import styles from '@patternfly/react-styles/css/components/Card/card'; +import '@testing-library/jest-dom'; import userEvent from '@testing-library/user-event'; import { CardHeader } from '../CardHeader'; import { CardContext } from '../Card'; @@ -14,6 +15,18 @@ describe('CardHeader', () => { const { asFragment } = render(); expect(asFragment()).toMatchSnapshot(); }); + + test(`Should render CardHeader without ${styles.modifiers.wrap} by default`, () => { + render(); + + expect(screen.getByTestId('card-header')).not.toHaveClass(styles.modifiers.wrap); + }); + + test(`Should render CardHeader with ${styles.modifiers.wrap} class when hasWrap is true`, () => { + render(); + + expect(screen.getByTestId('card-header-will-wrap')).toHaveClass(styles.modifiers.wrap); + }); }); // TODO: check if hasNoOffset for actions/selectableActions and className for selectableActions render diff --git a/packages/react-core/src/components/Card/__tests__/CardHeaderMain.test.tsx b/packages/react-core/src/components/Card/__tests__/CardHeaderMain.test.tsx index e72ed722d70..dd393d0d845 100644 --- a/packages/react-core/src/components/Card/__tests__/CardHeaderMain.test.tsx +++ b/packages/react-core/src/components/Card/__tests__/CardHeaderMain.test.tsx @@ -1,4 +1,3 @@ -import React from 'react'; import { render, screen } from '@testing-library/react'; import { CardHeaderMain } from '../CardHeaderMain'; diff --git a/packages/react-core/src/components/Card/__tests__/CardSelectableActions.test.tsx b/packages/react-core/src/components/Card/__tests__/CardSelectableActions.test.tsx index 7d591ac5ddf..3f9798629cf 100644 --- a/packages/react-core/src/components/Card/__tests__/CardSelectableActions.test.tsx +++ b/packages/react-core/src/components/Card/__tests__/CardSelectableActions.test.tsx @@ -1,4 +1,3 @@ -import React from 'react'; import { render, screen } from '@testing-library/react'; import { CardSelectableActions } from '../CardSelectableActions'; diff --git a/packages/react-core/src/components/Card/__tests__/CardSubtitle.test.tsx b/packages/react-core/src/components/Card/__tests__/CardSubtitle.test.tsx new file mode 100644 index 00000000000..1a71e952344 --- /dev/null +++ b/packages/react-core/src/components/Card/__tests__/CardSubtitle.test.tsx @@ -0,0 +1,48 @@ +import { render, screen } from '@testing-library/react'; +import { CardSubtitle } from '../CardSubtitle'; +import styles from '@patternfly/react-styles/css/components/Card/card'; + +test('Renders without children', () => { + render( +
+ +
+ ); + + expect(screen.getByTestId('container').firstChild).toBeVisible(); +}); + +test('Renders with children', () => { + render(Subtitle content); + + expect(screen.getByText('Subtitle content')).toBeInTheDocument(); +}); + +test(`Renders with class ${styles.cardSubtitle} by default`, () => { + render(Subtitle content); + + expect(screen.getByText('Subtitle content')).toHaveClass(styles.cardSubtitle, { exact: true }); +}); + +test('Renders with id when passed', () => { + render(Subtitle content); + + expect(screen.getByText('Subtitle content')).toHaveAttribute('id', 'subtitle-id'); +}); + +test('extra props are spread to the root element', () => { + const testId = 'card-subtitle'; + + render(); + expect(screen.getByTestId(testId)).toBeInTheDocument(); +}); + +test('Matches snapshot without children', () => { + const { asFragment } = render(); + expect(asFragment()).toMatchSnapshot(); +}); + +test('Matches snapshot with children', () => { + const { asFragment } = render(Subtitle content); + expect(asFragment()).toMatchSnapshot(); +}); diff --git a/packages/react-core/src/components/Card/__tests__/CardTitle.test.tsx b/packages/react-core/src/components/Card/__tests__/CardTitle.test.tsx index 0aa55985b51..ff7b10cb055 100644 --- a/packages/react-core/src/components/Card/__tests__/CardTitle.test.tsx +++ b/packages/react-core/src/components/Card/__tests__/CardTitle.test.tsx @@ -1,22 +1,31 @@ -import React from 'react'; import { render, screen } from '@testing-library/react'; import { CardTitle } from '../CardTitle'; -describe('CardTitle', () => { - test('renders with PatternFly Core styles', () => { - const { asFragment } = render(text); - expect(asFragment()).toMatchSnapshot(); - }); +test('Renders with custom class when passed', () => { + render(text); + expect(screen.getByText('text')).toHaveClass('extra-class'); +}); + +test('Does not render with card subtitle by default', () => { + render(text); + + expect(screen.queryByText('text')?.nextElementSibling).not.toBeInTheDocument(); +}); - test('className is added to the root element', () => { - render(text); - expect(screen.getByText('text')).toHaveClass('extra-class'); - }); +test('Renders with card subtitle when subtitle is passed', () => { + render(text); - test('extra props are spread to the root element', () => { - const testId = 'card-header'; + expect(screen.getByText('subtitle content')).toBeInTheDocument(); +}); + +test('extra props are spread to the root element', () => { + const testId = 'card-header'; + + render(); + expect(screen.getByTestId(testId)).toBeInTheDocument(); +}); - render(); - expect(screen.getByTestId(testId)).toBeInTheDocument(); - }); +test('Matches snapshot', () => { + const { asFragment } = render(text); + expect(asFragment()).toMatchSnapshot(); }); diff --git a/packages/react-core/src/components/Card/__tests__/Generated/CardActions.test.tsx b/packages/react-core/src/components/Card/__tests__/Generated/CardActions.test.tsx index 9bd416885cc..5275d6e1a45 100644 --- a/packages/react-core/src/components/Card/__tests__/Generated/CardActions.test.tsx +++ b/packages/react-core/src/components/Card/__tests__/Generated/CardActions.test.tsx @@ -1,7 +1,6 @@ /** * This test was generated */ -import * as React from 'react'; import { render } from '@testing-library/react'; import { CardActions } from '../../CardActions'; // any missing imports can usually be resolved by adding them here diff --git a/packages/react-core/src/components/Card/__tests__/__snapshots__/Card.test.tsx.snap b/packages/react-core/src/components/Card/__tests__/__snapshots__/Card.test.tsx.snap index bfd72f73dd1..cad89cf924a 100644 --- a/packages/react-core/src/components/Card/__tests__/__snapshots__/Card.test.tsx.snap +++ b/packages/react-core/src/components/Card/__tests__/__snapshots__/Card.test.tsx.snap @@ -4,7 +4,7 @@ exports[`Card card with isCompact applied 1`] = `
, + , + + ] + }} + > + This is a longer card title that takes up more space + + This is the card body + +); diff --git a/packages/react-core/src/components/Card/examples/CardOnlyActionsInCardHead.tsx b/packages/react-core/src/components/Card/examples/CardOnlyActionsInCardHead.tsx index ceff2f1e042..823b0450bdf 100644 --- a/packages/react-core/src/components/Card/examples/CardOnlyActionsInCardHead.tsx +++ b/packages/react-core/src/components/Card/examples/CardOnlyActionsInCardHead.tsx @@ -1,4 +1,4 @@ -import React from 'react'; +import { useState } from 'react'; import { Checkbox, Card, @@ -11,11 +11,11 @@ import { MenuToggleElement, Divider } from '@patternfly/react-core'; -import EllipsisVIcon from '@patternfly/react-icons/dist/esm/icons/ellipsis-v-icon'; +import RhUiEllipsisVerticalFillIcon from '@patternfly/react-icons/dist/esm/icons/rh-ui-ellipsis-vertical-fill-icon'; export const CardOnlyActionsInCardHead: React.FunctionComponent = () => { - const [isOpen, setIsOpen] = React.useState(false); - const [isChecked, setIsChecked] = React.useState(false); + const [isOpen, setIsOpen] = useState(false); + const [isChecked, setIsChecked] = useState(false); const onSelect = () => { setIsOpen(!isOpen); @@ -56,9 +56,8 @@ export const CardOnlyActionsInCardHead: React.FunctionComponent = () => { onClick={() => setIsOpen(!isOpen)} variant="plain" aria-label="Card header without title example kebab toggle" - > -
} />); + expect(screen.getByText('Sidebar start')).toBeVisible(); +}); + +test('Renders main content when provided', () => { + render(Main content
} />); + expect(screen.getByText('Main content')).toBeVisible(); +}); + +test('Renders sidebar end content when provided', () => { + render(Sidebar end
} />); + expect(screen.getByText('Sidebar end')).toBeVisible(); +}); + +test('Renders footer content when provided', () => { + render(Footer content
} />); + expect(screen.getByText('Footer content')).toBeVisible(); +}); + +test('Renders header with expanded class when isHeaderExpanded is true', () => { + render(Header
} isHeaderExpanded />); + expect(screen.getByText('Header').parentElement).toHaveClass('pf-m-expanded'); +}); + +test('Renders header without expanded class and with inert when isHeaderExpanded is false', () => { + render(Header
} isHeaderExpanded={false} />); + const headerElement = screen.getByText('Header').parentElement; + expect(headerElement).not.toHaveClass('pf-m-expanded'); + expect(headerElement).toHaveAttribute('inert'); +}); + +test('Renders sidebar start with expanded class when isSidebarStartExpanded is true', () => { + render(Sidebar start
} isSidebarStartExpanded />); + expect(screen.getByText('Sidebar start').parentElement).toHaveClass('pf-m-expanded'); +}); + +test('Renders sidebar start without expanded class and with inert when isSidebarStartExpanded is false', () => { + render(Sidebar start
} isSidebarStartExpanded={false} />); + const sidebarElement = screen.getByText('Sidebar start').parentElement; + expect(sidebarElement).not.toHaveClass('pf-m-expanded'); + expect(sidebarElement).toHaveAttribute('inert'); +}); + +test('Renders sidebar end with expanded class when isSidebarEndExpanded is true', () => { + render(Sidebar end
} isSidebarEndExpanded />); + expect(screen.getByText('Sidebar end').parentElement).toHaveClass('pf-m-expanded'); +}); + +test('Renders sidebar end without expanded class and with inert when isSidebarEndExpanded is false', () => { + render(Sidebar end
} isSidebarEndExpanded={false} />); + const sidebarElement = screen.getByText('Sidebar end').parentElement; + expect(sidebarElement).not.toHaveClass('pf-m-expanded'); + expect(sidebarElement).toHaveAttribute('inert'); +}); + +test('Renders footer with expanded class when isFooterExpanded is true', () => { + render(Footer
} isFooterExpanded />); + expect(screen.getByText('Footer').parentElement).toHaveClass('pf-m-expanded'); +}); + +test('Renders footer without expanded class and with inert when isFooterExpanded is false', () => { + render(Footer
} isFooterExpanded={false} />); + const footerElement = screen.getByText('Footer').parentElement; + expect(footerElement).not.toHaveClass('pf-m-expanded'); + expect(footerElement).toHaveAttribute('inert'); +}); + +test('Renders with drawer when drawerContent is provided', () => { + render(Drawer content
} />); + expect(screen.getByText('Drawer content')).toBeVisible(); +}); + +test('Renders with additional props spread to the component', () => { + render(); + expect(screen.getByTestId('compass')).toHaveAccessibleName('Test label'); +}); + +test('Renders with default expansion states', () => { + render( + Header
} + sidebarStart={
Sidebar start
} + sidebarEnd={
Sidebar end
} + footer={
Footer
} + > + Test + + ); + + expect(screen.getByText('Header').parentElement).toHaveClass('pf-m-expanded'); + expect(screen.getByText('Sidebar start').parentElement).toHaveClass('pf-m-expanded'); + expect(screen.getByText('Sidebar end').parentElement).toHaveClass('pf-m-expanded'); + expect(screen.getByText('Footer').parentElement).toHaveClass('pf-m-expanded'); +}); + +test('Matches the snapshot with basic layout', () => { + const { asFragment } = render( + Header
} + sidebarStart={
Sidebar start
} + main={
Main content
} + sidebarEnd={
Sidebar end
} + footer={
Footer
} + /> + ); + expect(asFragment()).toMatchSnapshot(); +}); + +test('Matches the snapshot with drawer', () => { + const { asFragment } = render( + Drawer content
} + drawerProps={{ isExpanded: true }} + header={
Header
} + sidebarStart={
Sidebar start
} + main={
Main content
} + sidebarEnd={
Sidebar end
} + footer={
Footer
} + /> + ); + expect(asFragment()).toMatchSnapshot(); +}); + +test(`Renders with ${styles.modifiers.docked} class when dock is passed`, () => { + render(Dock content
} data-testid="compass" />); + expect(screen.getByTestId('compass')).toHaveClass(styles.modifiers.docked); +}); + +test(`Does not render with ${styles.modifiers.docked} class when dock is not passed`, () => { + render(); + expect(screen.getByTestId('compass')).not.toHaveClass(styles.modifiers.docked); +}); + +test('Does not render masthead content when dock is not passed', () => { + render(); + expect(screen.queryByText('Masthead content')).not.toBeInTheDocument(); +}); + +test('Renders masthead content when dock is passed', () => { + render(Masthead content
} dock={
Dock content
} />); + expect(screen.getByText('Masthead content')).toBeVisible(); +}); + +test(`Renders dock with ${styles.modifiers.expanded} class when isDockExpanded is true`, () => { + render(); + expect(screen.getByText('Dock content')).toHaveClass(styles.modifiers.expanded); +}); + +test(`Renders dock without ${styles.modifiers.expanded} class when isDockExpanded is false`, () => { + render(); + expect(screen.getByText('Dock content')).not.toHaveClass(styles.modifiers.expanded); +}); + +test(`Renders dock with ${styles.modifiers.textExpanded} class when isDockTextExpanded is true`, () => { + render(); + expect(screen.getByText('Dock content')).toHaveClass(styles.modifiers.textExpanded); +}); + +test(`Renders dock without ${styles.modifiers.textExpanded} class when isDockTextExpanded is false`, () => { + render(); + expect(screen.getByText('Dock content')).not.toHaveClass(styles.modifiers.textExpanded); +}); diff --git a/packages/react-core/src/components/Compass/__tests__/CompassContent.test.tsx b/packages/react-core/src/components/Compass/__tests__/CompassContent.test.tsx new file mode 100644 index 00000000000..1b3cf2eeb0f --- /dev/null +++ b/packages/react-core/src/components/Compass/__tests__/CompassContent.test.tsx @@ -0,0 +1,46 @@ +import { render, screen } from '@testing-library/react'; +import { CompassContent } from '../CompassContent'; +import styles from '@patternfly/react-styles/css/components/Compass/compass'; + +test('Renders with children', () => { + render(Test content); + expect(screen.getByText('Test content')).toBeVisible(); +}); + +test('Renders with custom class name when className prop is provided', () => { + render(Test); + expect(screen.getByText('Test')).toHaveClass('custom-class'); +}); + +test(`Renders with default ${styles.compassContent} class`, () => { + render(Test); + expect(screen.getByText('Test')).toHaveClass(styles.compassContent); +}); + +test('Renders with drawer when drawerContent is provided', () => { + render(Drawer content
}>Test); + expect(screen.getByText('Drawer content')).toBeVisible(); +}); + +test('Renders with additional props spread to the component', () => { + render(Test); + expect(screen.getByText('Test')).toHaveAccessibleName('Test label'); +}); + +test('Matches the snapshot without drawer', () => { + const { asFragment } = render( + +
Test content
+
+ ); + expect(asFragment()).toMatchSnapshot(); +}); + +test('Matches the snapshot with drawer', () => { + const { asFragment } = render( + Drawer content
} drawerProps={{ isExpanded: true }}> +
Test content
+ + ); + expect(asFragment()).toMatchSnapshot(); +}); diff --git a/packages/react-core/src/components/Compass/__tests__/CompassDockMain.test.tsx b/packages/react-core/src/components/Compass/__tests__/CompassDockMain.test.tsx new file mode 100644 index 00000000000..18798a0b020 --- /dev/null +++ b/packages/react-core/src/components/Compass/__tests__/CompassDockMain.test.tsx @@ -0,0 +1,41 @@ +import { render, screen } from '@testing-library/react'; +import { CompassDockMain } from '../CompassDockMain'; +import styles from '@patternfly/react-styles/css/components/Compass/compass'; + +test('Renders without children', () => { + render( +
+ +
+ ); + expect(screen.getByTestId('test-compass-dock-main').firstChild).toBeVisible(); +}); + +test('Renders with children', () => { + render(Test content); + expect(screen.getByText('Test content')).toBeVisible(); +}); + +test('Renders with custom class name when className prop is provided', () => { + render(Test); + expect(screen.getByText('Test')).toHaveClass('custom-class'); +}); + +test(`Renders with default ${styles.compassDockMain} class`, () => { + render(Test); + expect(screen.getByText('Test')).toHaveClass(styles.compassDockMain, { exact: true }); +}); + +test('Renders with additional props spread to the component', () => { + render(Test); + expect(screen.getByText('Test')).toHaveAttribute('id', 'custom-id'); +}); + +test('Matches the snapshot', () => { + const { asFragment } = render( + +
Test content
+
+ ); + expect(asFragment()).toMatchSnapshot(); +}); diff --git a/packages/react-core/src/components/Compass/__tests__/CompassHeader.test.tsx b/packages/react-core/src/components/Compass/__tests__/CompassHeader.test.tsx new file mode 100644 index 00000000000..750f275671d --- /dev/null +++ b/packages/react-core/src/components/Compass/__tests__/CompassHeader.test.tsx @@ -0,0 +1,56 @@ +import { render, screen } from '@testing-library/react'; +import { CompassHeader } from '../CompassHeader'; +import styles from '@patternfly/react-styles/css/components/Compass/compass'; + +test('Renders without children', () => { + render( +
+ +
+ ); + expect(screen.getByTestId('test-header').firstChild).toBeVisible(); +}); + +test('Renders logo content when provided', () => { + render(Logo content
} />); + expect(screen.getByText('Logo content')).toBeVisible(); +}); + +test('Renders nav content when provided', () => { + render(Nav content
} />); + expect(screen.getByText('Nav content')).toBeVisible(); +}); + +test('Renders profile content when provided', () => { + render(Profile content
} />); + expect(screen.getByText('Profile content')).toBeVisible(); +}); + +test('Renders all content when all props are provided', () => { + render(Logo
} nav={
Nav
} profile={
Profile
} />); + expect(screen.getByText('Logo')).toBeVisible(); + expect(screen.getByText('Nav')).toBeVisible(); + expect(screen.getByText('Profile')).toBeVisible(); +}); + +test(`Renders logo with ${styles.compass}__logo class`, () => { + render(Logo
} />); + expect(screen.getByText('Logo').parentElement).toHaveClass(`${styles.compass}__logo`); +}); + +test(`Renders nav with ${styles.compassNav} class`, () => { + render(Nav
} />); + expect(screen.getByText('Nav').parentElement).toHaveClass(styles.compassNav); +}); + +test(`Renders profile with ${styles.compassProfile} class`, () => { + render(Profile
} />); + expect(screen.getByText('Profile').parentElement).toHaveClass(styles.compassProfile); +}); + +test('Matches the snapshot', () => { + const { asFragment } = render( + Logo
} nav={
Nav
} profile={
Profile
} /> + ); + expect(asFragment()).toMatchSnapshot(); +}); diff --git a/packages/react-core/src/components/Compass/__tests__/CompassHero.test.tsx b/packages/react-core/src/components/Compass/__tests__/CompassHero.test.tsx new file mode 100644 index 00000000000..c46f8605e73 --- /dev/null +++ b/packages/react-core/src/components/Compass/__tests__/CompassHero.test.tsx @@ -0,0 +1,38 @@ +import { render, screen } from '@testing-library/react'; +import { CompassHero } from '../CompassHero'; +import styles from '@patternfly/react-styles/css/components/Compass/compass'; + +test('Renders without children', () => { + render( +
+ +
+ ); + expect(screen.getByTestId('test-hero').firstChild).toBeVisible(); +}); + +test('Renders with children', () => { + render(Test content); + expect(screen.getByText('Test content')).toBeVisible(); +}); + +test(`Renders with ${styles.compass}__hero class by defaulty`, () => { + render(Test); + + expect(screen.getByText('Test')).toHaveClass(`${styles.compass}__hero`, { exact: true }); +}); + +test('Renders with custom class name when className prop is provided', () => { + render(Test); + expect(screen.getByText('Test')).toHaveClass('custom-class'); +}); + +test('Renders with additional props spread to the component', () => { + render(Test); + expect(screen.getByText('Test')).toHaveAccessibleName('Test label'); +}); + +test('Matches the snapshot', () => { + const { asFragment } = render(Hero content); + expect(asFragment()).toMatchSnapshot(); +}); diff --git a/packages/react-core/src/components/Compass/__tests__/CompassMainFooter.test.tsx b/packages/react-core/src/components/Compass/__tests__/CompassMainFooter.test.tsx new file mode 100644 index 00000000000..25b955ba77c --- /dev/null +++ b/packages/react-core/src/components/Compass/__tests__/CompassMainFooter.test.tsx @@ -0,0 +1,52 @@ +import { render, screen } from '@testing-library/react'; +import { CompassMainFooter } from '../CompassMainFooter'; +import styles from '@patternfly/react-styles/css/components/Compass/compass'; + +test('Renders without children', () => { + render( +
+ +
+ ); + expect(screen.getByTestId('test-main-footer').firstChild).toBeVisible(); +}); + +test('Renders with children', () => { + render(Custom content); + expect(screen.getByText('Custom content')).toBeVisible(); +}); + +test('Renders with custom class name when className prop is provided', () => { + render(Test); + expect(screen.getByText('Test')).toHaveClass('custom-class'); +}); + +test(`Renders with default ${styles.compassMainFooter} class`, () => { + render(Test); + expect(screen.getByText('Test')).toHaveClass(styles.compassMainFooter); +}); + +test(`Renders with pf-m-expanded class by default`, () => { + render(Test); + expect(screen.getByText('Test')).toHaveClass('pf-m-expanded'); +}); + +test(`Renders with pf-m-expanded class when isExpanded is true`, () => { + render(Test); + expect(screen.getByText('Test')).toHaveClass('pf-m-expanded'); +}); + +test(`Renders without pf-m-expanded class when isExpanded is false`, () => { + render(Test); + expect(screen.getByText('Test')).not.toHaveClass('pf-m-expanded'); +}); + +test('Renders with additional props spread to the component', () => { + render(Test); + expect(screen.getByText('Test')).toHaveAccessibleName('Test label'); +}); + +test('Matches the snapshot', () => { + const { asFragment } = render(Custom children content); + expect(asFragment()).toMatchSnapshot(); +}); diff --git a/packages/react-core/src/components/Compass/__tests__/CompassMainHeader.test.tsx b/packages/react-core/src/components/Compass/__tests__/CompassMainHeader.test.tsx new file mode 100644 index 00000000000..ef2b630edac --- /dev/null +++ b/packages/react-core/src/components/Compass/__tests__/CompassMainHeader.test.tsx @@ -0,0 +1,130 @@ +import { render, screen } from '@testing-library/react'; +import { CompassMainHeader } from '../CompassMainHeader'; +import styles from '@patternfly/react-styles/css/components/Compass/compass'; +import panelStyles from '@patternfly/react-styles/css/components/Panel/panel'; + +test('Renders without children', () => { + render( +
+ +
+ ); + expect(screen.getByTestId('test-main-header').firstChild).toBeVisible(); +}); + +test('Renders with children', () => { + render(Custom content); + expect(screen.getByText('Custom content')).toBeVisible(); +}); + +test('Renders with custom class name when className prop is provided', () => { + render(Test); + expect(screen.getByText('Test')).toHaveClass('custom-class'); +}); + +test(`Renders with default ${styles.compass}__main-header class`, () => { + render(Test); + expect(screen.getByText('Test')).toHaveClass(`${styles.compass}__main-header`); +}); + +test('Renders title when provided', () => { + render(Title content
}>Test); + expect(screen.getByText('Title content')).toBeVisible(); +}); + +test('Renders toolbar when provided', () => { + render(Toolbar content
}>Test); + expect(screen.getByText('Toolbar content')).toBeVisible(); +}); + +test('Renders both title and toolbar when provided', () => { + render( + Title
} toolbar={
Toolbar
}> + Test + + ); + expect(screen.getByText('Title')).toBeVisible(); + expect(screen.getByText('Toolbar')).toBeVisible(); +}); + +test('Ignores children when title is provided', () => { + render(Title
}>Ignored children); + expect(screen.getByText('Title')).toBeVisible(); + expect(screen.queryByText('Ignored children')).not.toBeInTheDocument(); +}); + +test('Ignores children when toolbar is provided', () => { + render(Toolbar
}>Ignored children); + expect(screen.getByText('Toolbar')).toBeVisible(); + expect(screen.queryByText('Ignored children')).not.toBeInTheDocument(); +}); + +test('Ignores children when both title and toolbar are provided', () => { + render( + Title
} toolbar={
Toolbar
}> + Ignored children + + ); + expect(screen.getByText('Title')).toBeVisible(); + expect(screen.getByText('Toolbar')).toBeVisible(); + expect(screen.queryByText('Ignored children')).not.toBeInTheDocument(); +}); + +test('Renders children when neither title nor toolbar are provided', () => { + render(Custom children content); + expect(screen.getByText('Custom children content')).toBeVisible(); +}); + +test('Renders Panel when title is passed', () => { + render(); + + const panel = screen.getByTestId('test-id').firstChild; + expect(panel).toHaveClass(panelStyles.panel); +}); + +test('Renders Panel when toolbar is passed', () => { + render(); + + const panel = screen.getByTestId('test-id').firstChild; + expect(panel).toHaveClass(panelStyles.panel); +}); + +test('Does not render Panel when children are passed', () => { + render( + +
Children content
+
+ ); + + const content = screen.getByTestId('test-id').firstChild; + expect(content).not.toHaveClass(panelStyles.panel); +}); + +test('Passes props to Panel when title and panelProps is passed', () => { + render(); + + const panel = screen.getByTestId('test-id').firstChild; + expect(panel).toHaveClass('panel-class'); +}); + +test('Passes props to Panel when toolbar and panelProps is passed', () => { + render(); + + const panel = screen.getByTestId('test-id').firstChild; + expect(panel).toHaveClass('panel-class'); +}); + +test('Renders with additional props spread to the component', () => { + render(Test); + expect(screen.getByText('Test')).toHaveAttribute('id', 'custom-id'); +}); + +test('Matches the snapshot with both title and toolbar', () => { + const { asFragment } = render(Title
} toolbar={
Toolbar
} />); + expect(asFragment()).toMatchSnapshot(); +}); + +test('Matches the snapshot with children', () => { + const { asFragment } = render(Custom children content); + expect(asFragment()).toMatchSnapshot(); +}); diff --git a/packages/react-core/src/components/Compass/__tests__/CompassMainHeaderContent.test.tsx b/packages/react-core/src/components/Compass/__tests__/CompassMainHeaderContent.test.tsx new file mode 100644 index 00000000000..44475ae7dca --- /dev/null +++ b/packages/react-core/src/components/Compass/__tests__/CompassMainHeaderContent.test.tsx @@ -0,0 +1,28 @@ +import { render, screen } from '@testing-library/react'; +import { CompassMainHeaderContent } from '../CompassMainHeaderContent'; +import styles from '@patternfly/react-styles/css/components/Compass/compass'; + +test('Renders with children', () => { + render(Custom content); + expect(screen.getByText('Custom content')).toBeVisible(); +}); + +test(`Renders with default ${styles.compass}__main-header-content class`, () => { + render(Test); + expect(screen.getByText('Test')).toHaveClass(`${styles.compass}__main-header-content`); +}); + +test('Renders with custom class name when className prop is provided', () => { + render(Test); + expect(screen.getByText('Test')).toHaveClass('custom-class'); +}); + +test('Renders with additional props spread to the component', () => { + render(Test); + expect(screen.getByText('Test')).toHaveAttribute('id', 'custom-id'); +}); + +test('Matches the snapshot', () => { + const { asFragment } = render(Content); + expect(asFragment()).toMatchSnapshot(); +}); diff --git a/packages/react-core/src/components/Compass/__tests__/CompassMainHeaderTitle.test.tsx b/packages/react-core/src/components/Compass/__tests__/CompassMainHeaderTitle.test.tsx new file mode 100644 index 00000000000..9bc10b59b45 --- /dev/null +++ b/packages/react-core/src/components/Compass/__tests__/CompassMainHeaderTitle.test.tsx @@ -0,0 +1,28 @@ +import { render, screen } from '@testing-library/react'; +import { CompassMainHeaderTitle } from '../CompassMainHeaderTitle'; +import styles from '@patternfly/react-styles/css/components/Compass/compass'; + +test('Renders with children', () => { + render(Custom content); + expect(screen.getByText('Custom content')).toBeVisible(); +}); + +test(`Renders with default ${styles.compass}__main-header-title class`, () => { + render(Test); + expect(screen.getByText('Test')).toHaveClass(`${styles.compass}__main-header-title`); +}); + +test('Renders with custom class name when className prop is provided', () => { + render(Test); + expect(screen.getByText('Test')).toHaveClass('custom-class'); +}); + +test('Renders with additional props spread to the component', () => { + render(Test); + expect(screen.getByText('Test')).toHaveAttribute('id', 'custom-id'); +}); + +test('Matches the snapshot', () => { + const { asFragment } = render(Content); + expect(asFragment()).toMatchSnapshot(); +}); diff --git a/packages/react-core/src/components/Compass/__tests__/CompassMainHeaderToolbar.test.tsx b/packages/react-core/src/components/Compass/__tests__/CompassMainHeaderToolbar.test.tsx new file mode 100644 index 00000000000..62ab818f602 --- /dev/null +++ b/packages/react-core/src/components/Compass/__tests__/CompassMainHeaderToolbar.test.tsx @@ -0,0 +1,28 @@ +import { render, screen } from '@testing-library/react'; +import { CompassMainHeaderToolbar } from '../CompassMainHeaderToolbar'; +import styles from '@patternfly/react-styles/css/components/Compass/compass'; + +test('Renders with children', () => { + render(Custom content); + expect(screen.getByText('Custom content')).toBeVisible(); +}); + +test(`Renders with default ${styles.compass}__main-header-toolbar class`, () => { + render(Test); + expect(screen.getByText('Test')).toHaveClass(`${styles.compass}__main-header-toolbar`); +}); + +test('Renders with custom class name when className prop is provided', () => { + render(Test); + expect(screen.getByText('Test')).toHaveClass('custom-class'); +}); + +test('Renders with additional props spread to the component', () => { + render(Test); + expect(screen.getByText('Test')).toHaveAttribute('id', 'custom-id'); +}); + +test('Matches the snapshot', () => { + const { asFragment } = render(Content); + expect(asFragment()).toMatchSnapshot(); +}); diff --git a/packages/react-core/src/components/Compass/__tests__/CompassMessageBar.test.tsx b/packages/react-core/src/components/Compass/__tests__/CompassMessageBar.test.tsx new file mode 100644 index 00000000000..f6f7546e72c --- /dev/null +++ b/packages/react-core/src/components/Compass/__tests__/CompassMessageBar.test.tsx @@ -0,0 +1,41 @@ +import { render, screen } from '@testing-library/react'; +import { CompassMessageBar } from '../CompassMessageBar'; +import styles from '@patternfly/react-styles/css/components/Compass/compass'; + +test('Renders without children', () => { + render( +
+ +
+ ); + expect(screen.getByTestId('test-message-bar').firstChild).toBeVisible(); +}); + +test('Renders with children', () => { + render(Test content); + expect(screen.getByText('Test content')).toBeVisible(); +}); + +test('Renders with custom class name when className prop is provided', () => { + render(Test); + expect(screen.getByText('Test')).toHaveClass('custom-class'); +}); + +test(`Renders with default ${styles.compassMessageBar} class`, () => { + render(Test); + expect(screen.getByText('Test')).toHaveClass(styles.compassMessageBar); +}); + +test('Renders with additional props spread to the component', () => { + render(Test); + expect(screen.getByText('Test')).toHaveAccessibleName('Test label'); +}); + +test('Matches the snapshot', () => { + const { asFragment } = render( + +
Message bar content
+
+ ); + expect(asFragment()).toMatchSnapshot(); +}); diff --git a/packages/react-core/src/components/Compass/__tests__/CompassNavContent.test.tsx b/packages/react-core/src/components/Compass/__tests__/CompassNavContent.test.tsx new file mode 100644 index 00000000000..eb176b5ccae --- /dev/null +++ b/packages/react-core/src/components/Compass/__tests__/CompassNavContent.test.tsx @@ -0,0 +1,37 @@ +import { render, screen } from '@testing-library/react'; +import { CompassNavContent } from '../CompassNavContent'; +import styles from '@patternfly/react-styles/css/components/Compass/compass'; + +test('Renders with children', () => { + render(Test content); + + expect(screen.getByText('Test content')).toBeVisible(); +}); + +test('Renders with custom class name when className prop is provided', () => { + render(Test); + + expect(screen.getByText('Test')).toHaveClass('custom-class'); +}); + +test(`Renders with default ${styles.compassNavContent} class`, () => { + render(Test); + + expect(screen.getByText('Test')).toHaveClass(styles.compassNavContent, { exact: true }); +}); + +test('Renders with additional props spread to the component', () => { + render(Test); + + expect(screen.getByText('Test')).toHaveAccessibleName('Test label'); +}); + +test('Matches the snapshot', () => { + const { asFragment } = render( + +
Nav content wrapper
+
+ ); + + expect(asFragment()).toMatchSnapshot(); +}); diff --git a/packages/react-core/src/components/Compass/__tests__/CompassNavHome.test.tsx b/packages/react-core/src/components/Compass/__tests__/CompassNavHome.test.tsx new file mode 100644 index 00000000000..2f3b8b6fed1 --- /dev/null +++ b/packages/react-core/src/components/Compass/__tests__/CompassNavHome.test.tsx @@ -0,0 +1,89 @@ +import { render, screen } from '@testing-library/react'; +import userEvent from '@testing-library/user-event'; +import { CompassNavHome } from '../CompassNavHome'; +import styles from '@patternfly/react-styles/css/components/Compass/compass'; + +test('Renders with default aria-label', () => { + render(); + + expect(screen.getByRole('button', { name: 'Home' })).toBeVisible(); +}); + +test('Renders with custom aria-label when provided', () => { + render(); + + expect(screen.getByRole('button', { name: 'Custom home' })).toBeVisible(); +}); + +test('Renders with default tooltip content', async () => { + const user = userEvent.setup(); + + render(); + + const button = screen.getByRole('button'); + + await user.hover(button); + + await screen.findByRole('tooltip'); + + expect(screen.getByRole('tooltip')).toHaveTextContent('Home'); +}); + +test('Renders with custom tooltip content when provided', async () => { + const user = userEvent.setup(); + + render(); + + const button = screen.getByRole('button'); + + await user.hover(button); + + await screen.findByRole('tooltip'); + expect(screen.getByRole('tooltip')).toHaveTextContent('Custom tooltip'); +}); + +test('Renders with custom class name when className prop is provided', () => { + const { container } = render(); + + expect(container.firstChild).toHaveClass('custom-class'); +}); + +test(`Renders with default class`, () => { + const { container } = render(); + + expect(container.firstChild).toHaveClass(styles.compassNav + '-home', { exact: true }); +}); + +test('Calls onClick handler when button is clicked', async () => { + const user = userEvent.setup(); + const onClick = jest.fn(); + + render(); + + await user.click(screen.getByRole('button', { name: 'Home' })); + + expect(onClick).toHaveBeenCalledTimes(1); +}); + +test('Renders button with plain variant and circle shape', () => { + render(); + + const button = screen.getByRole('button', { name: 'Home' }); + + expect(button).toHaveClass('pf-m-plain'); + expect(button).toHaveClass('pf-m-circle'); +}); + +test('Matches the snapshot', () => { + const { asFragment } = render(); + + expect(asFragment()).toMatchSnapshot(); +}); + +test('Matches the snapshot with custom props', () => { + const { asFragment } = render( + + ); + + expect(asFragment()).toMatchSnapshot(); +}); diff --git a/packages/react-core/src/components/Compass/__tests__/CompassNavMain.test.tsx b/packages/react-core/src/components/Compass/__tests__/CompassNavMain.test.tsx new file mode 100644 index 00000000000..0242f9ef64c --- /dev/null +++ b/packages/react-core/src/components/Compass/__tests__/CompassNavMain.test.tsx @@ -0,0 +1,37 @@ +import { render, screen } from '@testing-library/react'; +import { CompassNavMain } from '../CompassNavMain'; +import styles from '@patternfly/react-styles/css/components/Compass/compass'; + +test('Renders with children', () => { + render(Test content); + + expect(screen.getByText('Test content')).toBeVisible(); +}); + +test('Renders with custom class name when className prop is provided', () => { + render(Test); + + expect(screen.getByText('Test')).toHaveClass('custom-class'); +}); + +test(`Renders with default ${styles.compassNavMain} class`, () => { + render(Test); + + expect(screen.getByText('Test')).toHaveClass(styles.compassNavMain, { exact: true }); +}); + +test('Renders with additional props spread to the component', () => { + render(Test); + + expect(screen.getByText('Test')).toHaveAccessibleName('Test label'); +}); + +test('Matches the snapshot', () => { + const { asFragment } = render( + +
Main tabs content
+
+ ); + + expect(asFragment()).toMatchSnapshot(); +}); diff --git a/packages/react-core/src/components/Compass/__tests__/CompassNavSearch.test.tsx b/packages/react-core/src/components/Compass/__tests__/CompassNavSearch.test.tsx new file mode 100644 index 00000000000..a32111d6899 --- /dev/null +++ b/packages/react-core/src/components/Compass/__tests__/CompassNavSearch.test.tsx @@ -0,0 +1,87 @@ +import { render, screen } from '@testing-library/react'; +import userEvent from '@testing-library/user-event'; +import { CompassNavSearch } from '../CompassNavSearch'; +import styles from '@patternfly/react-styles/css/components/Compass/compass'; + +test('Renders with default aria-label', () => { + render(); + expect(screen.getByRole('button', { name: 'Search' })).toBeVisible(); +}); + +test('Renders with custom aria-label when provided', () => { + render(); + expect(screen.getByRole('button', { name: 'Custom search' })).toBeVisible(); +}); + +test('Renders with default tooltip content', async () => { + const user = userEvent.setup(); + + render(); + + const button = screen.getByRole('button'); + + await user.hover(button); + + await screen.findByRole('tooltip'); + + expect(screen.getByRole('tooltip')).toHaveTextContent('Search'); +}); + +test('Renders with custom tooltip content when provided', async () => { + const user = userEvent.setup(); + + render(); + + const button = screen.getByRole('button'); + + await user.hover(button); + + await screen.findByRole('tooltip'); + + expect(screen.getByRole('tooltip')).toHaveTextContent('Custom tooltip'); +}); + +test('Renders with custom class name when className prop is provided', () => { + const { container } = render(); + + expect(container.firstChild).toHaveClass('custom-class'); +}); + +test(`Renders with default class`, () => { + const { container } = render(); + + expect(container.firstChild).toHaveClass(styles.compassNav + '-search', { exact: true }); +}); + +test('Calls onClick handler when button is clicked', async () => { + const user = userEvent.setup(); + const onClick = jest.fn(); + + render(); + + await user.click(screen.getByRole('button', { name: 'Search' })); + + expect(onClick).toHaveBeenCalledTimes(1); +}); + +test('Renders button with plain variant and circle shape', () => { + render(); + + const button = screen.getByRole('button', { name: 'Search' }); + + expect(button).toHaveClass('pf-m-plain'); +}); + +test('Matches the snapshot', () => { + const { asFragment } = render(); + + expect(asFragment()).toMatchSnapshot(); +}); + +test('Matches the snapshot with custom props', () => { + const { asFragment } = render( + + ); + + expect(asFragment()).toMatchSnapshot(); +}); diff --git a/packages/react-core/src/components/Compass/__tests__/__snapshots__/Compass.test.tsx.snap b/packages/react-core/src/components/Compass/__tests__/__snapshots__/Compass.test.tsx.snap new file mode 100644 index 00000000000..ceaae419241 --- /dev/null +++ b/packages/react-core/src/components/Compass/__tests__/__snapshots__/Compass.test.tsx.snap @@ -0,0 +1,116 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`Matches the snapshot with basic layout 1`] = ` + +
+
+
+
+ Header +
+
+
+
+ Sidebar start +
+
+
+
+ Main content +
+
+
+
+ Sidebar end +
+
+ +
+
+
+`; + +exports[`Matches the snapshot with drawer 1`] = ` + +
+
+
+
+
+
+
+
+ Header +
+
+
+
+ Sidebar start +
+
+
+
+ Main content +
+
+
+
+ Sidebar end +
+
+ +
+
+
+
+ Drawer content +
+
+
+
+
+`; diff --git a/packages/react-core/src/components/Compass/__tests__/__snapshots__/CompassContent.test.tsx.snap b/packages/react-core/src/components/Compass/__tests__/__snapshots__/CompassContent.test.tsx.snap new file mode 100644 index 00000000000..c0dae790afa --- /dev/null +++ b/packages/react-core/src/components/Compass/__tests__/__snapshots__/CompassContent.test.tsx.snap @@ -0,0 +1,40 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`Matches the snapshot with drawer 1`] = ` + +
+
+
+
+
+ Test content +
+
+
+
+ Drawer content +
+
+
+
+`; + +exports[`Matches the snapshot without drawer 1`] = ` + +
+
+ Test content +
+
+
+`; diff --git a/packages/react-core/src/components/Compass/__tests__/__snapshots__/CompassDockMain.test.tsx.snap b/packages/react-core/src/components/Compass/__tests__/__snapshots__/CompassDockMain.test.tsx.snap new file mode 100644 index 00000000000..b9198688601 --- /dev/null +++ b/packages/react-core/src/components/Compass/__tests__/__snapshots__/CompassDockMain.test.tsx.snap @@ -0,0 +1,13 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`Matches the snapshot 1`] = ` + +
+
+ Test content +
+
+
+`; diff --git a/packages/react-core/src/components/Compass/__tests__/__snapshots__/CompassHeader.test.tsx.snap b/packages/react-core/src/components/Compass/__tests__/__snapshots__/CompassHeader.test.tsx.snap new file mode 100644 index 00000000000..f3e52b6d77d --- /dev/null +++ b/packages/react-core/src/components/Compass/__tests__/__snapshots__/CompassHeader.test.tsx.snap @@ -0,0 +1,27 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`Matches the snapshot 1`] = ` + + +
+
+ Nav +
+
+
+
+ Profile +
+
+
+`; diff --git a/packages/react-core/src/components/Compass/__tests__/__snapshots__/CompassHero.test.tsx.snap b/packages/react-core/src/components/Compass/__tests__/__snapshots__/CompassHero.test.tsx.snap new file mode 100644 index 00000000000..da16b2c6089 --- /dev/null +++ b/packages/react-core/src/components/Compass/__tests__/__snapshots__/CompassHero.test.tsx.snap @@ -0,0 +1,11 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`Matches the snapshot 1`] = ` + +
+ Hero content +
+
+`; diff --git a/packages/react-core/src/components/Compass/__tests__/__snapshots__/CompassMainFooter.test.tsx.snap b/packages/react-core/src/components/Compass/__tests__/__snapshots__/CompassMainFooter.test.tsx.snap new file mode 100644 index 00000000000..160ef4650a2 --- /dev/null +++ b/packages/react-core/src/components/Compass/__tests__/__snapshots__/CompassMainFooter.test.tsx.snap @@ -0,0 +1,11 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`Matches the snapshot 1`] = ` + + + +`; diff --git a/packages/react-core/src/components/Compass/__tests__/__snapshots__/CompassMainHeader.test.tsx.snap b/packages/react-core/src/components/Compass/__tests__/__snapshots__/CompassMainHeader.test.tsx.snap new file mode 100644 index 00000000000..e674266cf33 --- /dev/null +++ b/packages/react-core/src/components/Compass/__tests__/__snapshots__/CompassMainHeader.test.tsx.snap @@ -0,0 +1,50 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`Matches the snapshot with both title and toolbar 1`] = ` + +
+
+
+
+
+
+
+ Title +
+
+
+
+ Toolbar +
+
+
+
+
+
+
+
+`; + +exports[`Matches the snapshot with children 1`] = ` + +
+ Custom children content +
+
+`; diff --git a/packages/react-core/src/components/Compass/__tests__/__snapshots__/CompassMainHeaderContent.test.tsx.snap b/packages/react-core/src/components/Compass/__tests__/__snapshots__/CompassMainHeaderContent.test.tsx.snap new file mode 100644 index 00000000000..c49e1a1d468 --- /dev/null +++ b/packages/react-core/src/components/Compass/__tests__/__snapshots__/CompassMainHeaderContent.test.tsx.snap @@ -0,0 +1,11 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`Matches the snapshot 1`] = ` + +
+ Content +
+
+`; diff --git a/packages/react-core/src/components/Compass/__tests__/__snapshots__/CompassMainHeaderTitle.test.tsx.snap b/packages/react-core/src/components/Compass/__tests__/__snapshots__/CompassMainHeaderTitle.test.tsx.snap new file mode 100644 index 00000000000..15ac7ab71eb --- /dev/null +++ b/packages/react-core/src/components/Compass/__tests__/__snapshots__/CompassMainHeaderTitle.test.tsx.snap @@ -0,0 +1,11 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`Matches the snapshot 1`] = ` + +
+ Content +
+
+`; diff --git a/packages/react-core/src/components/Compass/__tests__/__snapshots__/CompassMainHeaderToolbar.test.tsx.snap b/packages/react-core/src/components/Compass/__tests__/__snapshots__/CompassMainHeaderToolbar.test.tsx.snap new file mode 100644 index 00000000000..79550ac0b48 --- /dev/null +++ b/packages/react-core/src/components/Compass/__tests__/__snapshots__/CompassMainHeaderToolbar.test.tsx.snap @@ -0,0 +1,11 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`Matches the snapshot 1`] = ` + +
+ Content +
+
+`; diff --git a/packages/react-core/src/components/Compass/__tests__/__snapshots__/CompassMessageBar.test.tsx.snap b/packages/react-core/src/components/Compass/__tests__/__snapshots__/CompassMessageBar.test.tsx.snap new file mode 100644 index 00000000000..edde4c73946 --- /dev/null +++ b/packages/react-core/src/components/Compass/__tests__/__snapshots__/CompassMessageBar.test.tsx.snap @@ -0,0 +1,13 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`Matches the snapshot 1`] = ` + +
+
+ Message bar content +
+
+
+`; diff --git a/packages/react-core/src/components/Compass/__tests__/__snapshots__/CompassNavContent.test.tsx.snap b/packages/react-core/src/components/Compass/__tests__/__snapshots__/CompassNavContent.test.tsx.snap new file mode 100644 index 00000000000..df1e9a2ddea --- /dev/null +++ b/packages/react-core/src/components/Compass/__tests__/__snapshots__/CompassNavContent.test.tsx.snap @@ -0,0 +1,13 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`Matches the snapshot 1`] = ` + +
+
+ Nav content wrapper +
+
+
+`; diff --git a/packages/react-core/src/components/Compass/__tests__/__snapshots__/CompassNavHome.test.tsx.snap b/packages/react-core/src/components/Compass/__tests__/__snapshots__/CompassNavHome.test.tsx.snap new file mode 100644 index 00000000000..96703d6ebaa --- /dev/null +++ b/packages/react-core/src/components/Compass/__tests__/__snapshots__/CompassNavHome.test.tsx.snap @@ -0,0 +1,107 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`Matches the snapshot 1`] = ` + +
+ +
+
+`; + +exports[`Matches the snapshot with custom props 1`] = ` + +
+ +
+
+`; diff --git a/packages/react-core/src/components/Compass/__tests__/__snapshots__/CompassNavMain.test.tsx.snap b/packages/react-core/src/components/Compass/__tests__/__snapshots__/CompassNavMain.test.tsx.snap new file mode 100644 index 00000000000..53987fbf559 --- /dev/null +++ b/packages/react-core/src/components/Compass/__tests__/__snapshots__/CompassNavMain.test.tsx.snap @@ -0,0 +1,13 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`Matches the snapshot 1`] = ` + +
+
+ Main tabs content +
+
+
+`; diff --git a/packages/react-core/src/components/Compass/__tests__/__snapshots__/CompassNavSearch.test.tsx.snap b/packages/react-core/src/components/Compass/__tests__/__snapshots__/CompassNavSearch.test.tsx.snap new file mode 100644 index 00000000000..c6e1a8b4953 --- /dev/null +++ b/packages/react-core/src/components/Compass/__tests__/__snapshots__/CompassNavSearch.test.tsx.snap @@ -0,0 +1,93 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`Matches the snapshot 1`] = ` + + + +`; + +exports[`Matches the snapshot with custom props 1`] = ` + + + +`; diff --git a/packages/react-core/src/components/Compass/examples/Compass.md b/packages/react-core/src/components/Compass/examples/Compass.md new file mode 100644 index 00000000000..b83cbc7f18a --- /dev/null +++ b/packages/react-core/src/components/Compass/examples/Compass.md @@ -0,0 +1,74 @@ +--- +id: Compass +cssPrefix: pf-v6-c-compass +section: components +beta: true +propComponents: + [ + 'Compass', + 'CompassHeader', + 'CompassContent', + 'CompassHero', + 'CompassMainHeader', + 'CompassMessageBar', + 'CompassMainFooter' + ] +--- + +import { useRef, useState, useEffect } from 'react'; + +import './compass.css'; + +## Examples + +### Basic + +In a basic Compass layout, content can be passed to the following props to populate different areas of the page: + +- `header`: Content rendered at the top of the page, typically including a `` component that divides the header into 3 areas, with a logo or brand, middle navigation, and profile. +- `sidebarStart`: Content rendered at the horizontal start of the page (by default, the left side). +- `main`: Content rendered in the center of the page, typically including a `` or ``, along with a `` filled with 1 or more `` components. +- `sidebarEnd`: Content rendered at the horizontal end of the page (by default, the right side). +- `footer`: Content rendered at the bottom of the page. + +The background image of `` is set at a global level alongside the theme. You can customize the background image of the `` inside `` by using its `backgroundSrcLight` and `backgroundSrcDark` props, or you may set a gradient using the `gradientLight` and `gradientDark` props. + +```ts isBeta file="CompassBasic.tsx" + +``` + +### With alternate footer + +When `footer` is used, its content will fill the width of the screen. By default, when content inside the footer grows, the height and placement of the start and end sidebars will adjust to allow for the change. To modify this behavior and render footer content without interfering with the sidebars, instead place a `` inside the `main` section. This will render content at the bottom of the page between the 2 sidebars, rather than across the entire bottom of the page. + +```ts file="CompassMainFooterDemo.tsx" + +``` + +### With docked nav + +```ts file="CompassDockLayout.tsx" + +``` + +## Composable structure + +When building a more custom implementation with Compass components, there are some intended or expected structures that must remain present. + +### CompassMainHeader structure + +When using the `children` property in the `` component, there are specific structural patterns that you should follow, as shown this general code structure. + +```noLive + + + + + + {Your custom content goes here, which can include the and/or sub-components} + + + + + +``` diff --git a/packages/react-core/src/components/Compass/examples/CompassBasic.tsx b/packages/react-core/src/components/Compass/examples/CompassBasic.tsx new file mode 100644 index 00000000000..d6ea4b184dd --- /dev/null +++ b/packages/react-core/src/components/Compass/examples/CompassBasic.tsx @@ -0,0 +1,52 @@ +import { + Compass, + CompassHeader, + CompassHero, + CompassContent, + CompassMainHeader, + Panel, + PanelMain, + PanelMainBody, + CompassMainHeaderContent +} from '@patternfly/react-core'; +import './compass.css'; + +export const CompassBasic: React.FunctionComponent = () => { + const headerContent = Logo
} nav={
Nav
} profile={
Profile
} />; + const sidebarStartContent =
Sidebar start
; + // TODO: simplify mainContent to only a div string + const mainContent = ( + <> + +
Hero
+
+ + + + + + +
Content title
+
+
+
+
+
+
Content
+
+ + ); + const sidebarEndContent =
Sidebar end
; + const footerContent =
Footer
; + + return ( + + ); +}; diff --git a/packages/react-core/src/components/Compass/examples/CompassDockLayout.tsx b/packages/react-core/src/components/Compass/examples/CompassDockLayout.tsx new file mode 100644 index 00000000000..09cf87dc5f7 --- /dev/null +++ b/packages/react-core/src/components/Compass/examples/CompassDockLayout.tsx @@ -0,0 +1,31 @@ +import { + Compass, + CompassContent, + CompassMainHeader, + Panel, + PanelMain, + PanelMainBody, + CompassMainHeaderContent +} from '@patternfly/react-core'; +import './compass.css'; + +export const CompassBasic: React.FunctionComponent = () => { + const dockContent =
Content
; + const mainContent = ( + + + + + + +
Content title
+
+
+
+
+
+
Content
+
+ ); + return ; +}; diff --git a/packages/react-core/src/components/Compass/examples/CompassMainFooterDemo.tsx b/packages/react-core/src/components/Compass/examples/CompassMainFooterDemo.tsx new file mode 100644 index 00000000000..4846f6f07aa --- /dev/null +++ b/packages/react-core/src/components/Compass/examples/CompassMainFooterDemo.tsx @@ -0,0 +1,43 @@ +import { + Compass, + CompassHeader, + CompassHero, + CompassContent, + CompassMainHeader, + CompassMainFooter +} from '@patternfly/react-core'; +import './compass.css'; + +export const CompassMainFooterDemo: React.FunctionComponent = () => { + const headerContent = Logo
} nav={
Nav
} profile={
Profile
} />; + const sidebarStartContent =
Sidebar start
; + // TODO: simplify mainContent to only a div string + const mainContent = ( + <> + +
Hero
+
+ + +
Content title
+
+
Content
+
+ +
Footer
+
+ + ); + const sidebarEndContent =
Sidebar end
; + + return ( + + ); +}; diff --git a/packages/react-core/src/components/Compass/examples/compass.css b/packages/react-core/src/components/Compass/examples/compass.css new file mode 100644 index 00000000000..8a1d76248e3 --- /dev/null +++ b/packages/react-core/src/components/Compass/examples/compass.css @@ -0,0 +1,35 @@ +#ws-react-c-compass-basic [class*="pf-v6-c-compass"] { + position: relative; +} + +#ws-react-c-compass-basic [class*="pf-v6-c-compass"]::after { + content: ""; + position: absolute; + inset: 0; + border: var(--pf-t--global--border--width--regular) dashed var(--pf-t--global--border--color--default); + pointer-events: none; +} + +#ws-react-c-compass-with-alternate-footer [class*="pf-v6-c-compass"] { + position: relative; +} + +#ws-react-c-compass-with-alternate-footer [class*="pf-v6-c-compass"]:not([class*="footer"])::after { + content: ""; + position: absolute; + inset: 0; + border: var(--pf-t--global--border--width--regular) dashed var(--pf-t--global--border--color--default); + pointer-events: none; +} + +#ws-react-c-compass-with-docked-nav [class*="pf-v6-c-compass"] { + position: relative; +} + +#ws-react-c-compass-with-docked-nav [class*="pf-v6-c-compass"]:not([class*="footer"])::after { + content: ""; + position: absolute; + inset: 0; + border: var(--pf-t--global--border--width--regular) dashed var(--pf-t--global--border--color--default); + pointer-events: none; +} diff --git a/packages/react-core/src/components/Compass/index.ts b/packages/react-core/src/components/Compass/index.ts new file mode 100644 index 00000000000..c229910c584 --- /dev/null +++ b/packages/react-core/src/components/Compass/index.ts @@ -0,0 +1,15 @@ +export * from './Compass'; +export * from './CompassContent'; +export * from './CompassDockMain'; +export * from './CompassHeader'; +export * from './CompassHero'; +export * from './CompassMainHeader'; +export * from './CompassMainHeaderContent'; +export * from './CompassMainHeaderTitle'; +export * from './CompassMainHeaderToolbar'; +export * from './CompassMainFooter'; +export * from './CompassMessageBar'; +export * from './CompassNavContent'; +export * from './CompassNavHome'; +export * from './CompassNavMain'; +export * from './CompassNavSearch'; diff --git a/packages/react-core/src/components/Content/Content.tsx b/packages/react-core/src/components/Content/Content.tsx index dcb58030156..896f6a040ed 100644 --- a/packages/react-core/src/components/Content/Content.tsx +++ b/packages/react-core/src/components/Content/Content.tsx @@ -1,4 +1,3 @@ -import * as React from 'react'; import { css } from '@patternfly/react-styles'; import styles from '@patternfly/react-styles/css/components/Content/content'; import { useOUIAProps, OUIAProps } from '../../helpers'; @@ -53,6 +52,8 @@ export interface ContentProps extends React.HTMLProps, OUIAProps { isPlainList?: boolean; /** Flag to indicate the link (or all links within the content) has visited styles applied if the browser determines the link has been visited. */ isVisitedLink?: boolean; + /** Flag to indicate the content has editorial styling. This styling increases the font size of body text and small text by one tier, increasing body text to large and small text to the previous body text size. */ + isEditorial?: boolean; /** Value to overwrite the randomly generated data-ouia-component-id. */ ouiaId?: number | string; /** Set the value of data-ouia-safe. Only set to true when the component is in a static state, i.e. no animations are occurring. At all other times, this value must be false. */ @@ -89,6 +90,7 @@ export const Content: React.FunctionComponent = ({ isVisitedLink = false, ouiaId, ouiaSafe = true, + isEditorial = false, ...props }: ContentProps) => { const wrappingComponent = component ?? 'div'; @@ -106,6 +108,7 @@ export const Content: React.FunctionComponent = ({ componentStyles[wrappingComponent], isList && isPlainList && styles.modifiers.plain, isVisitedLink && styles.modifiers.visited, + isEditorial && styles.modifiers.editorial, className )} > diff --git a/packages/react-core/src/components/Content/__tests__/Content.test.tsx b/packages/react-core/src/components/Content/__tests__/Content.test.tsx index 63b922e9c3a..445f7c1b49a 100644 --- a/packages/react-core/src/components/Content/__tests__/Content.test.tsx +++ b/packages/react-core/src/components/Content/__tests__/Content.test.tsx @@ -1,4 +1,3 @@ -import * as React from 'react'; import { render, screen } from '@testing-library/react'; import { Content } from '../Content'; import styles from '@patternfly/react-styles/css/components/Content/content'; @@ -264,6 +263,30 @@ test('Renders with inherited element props spread to the component', () => { expect(screen.getByText('Test')).toHaveAccessibleName('Test label'); }); +test(`Renders without class name ${styles.modifiers.editorial} by default`, () => { + render(Test); + expect(screen.getByText('Test')).not.toHaveClass('pf-m-editorial'); +}); + +test(`Renders with class name ${styles.modifiers.editorial} when isEditorial = true`, () => { + render(Test); + expect(screen.getByText('Test')).toHaveClass('pf-m-editorial'); +}); + +test(`Renders with class name ${styles.modifiers.editorial} when isEditorial = true and component is specified`, () => { + render( + + Test + + ); + expect(screen.getByText('Test')).toHaveClass('pf-m-editorial'); +}); + +test(`Renders without class name ${styles.modifiers.editorial} when isEditorial = false`, () => { + render(Test); + expect(screen.getByText('Test')).not.toHaveClass('pf-m-editorial'); +}); + test('Matches the snapshot', () => { const { asFragment } = render(Test); expect(asFragment()).toMatchSnapshot(); diff --git a/packages/react-core/src/components/Content/examples/Content.md b/packages/react-core/src/components/Content/examples/Content.md index 3f6de645462..db83b5eb615 100644 --- a/packages/react-core/src/components/Content/examples/Content.md +++ b/packages/react-core/src/components/Content/examples/Content.md @@ -2,7 +2,7 @@ id: Content section: components cssPrefix: pf-v6-c-content -propComponents: ['Content'] +propComponents: ['Content', 'ContentVariants'] --- The `` component allows you to establish a block of HTML content and apply simple, built-in styling. `` can be used for any element supported by the `component` property (including `h1` through `h6`, `hr`, `p`, `a`, `small`, `blockquote`, and `pre`). @@ -62,3 +62,11 @@ HTML elements wrapped by `` are styled by the content component. ```ts file="./ContentVisited.tsx" ``` + +### Editorial content + +Editorial styling increases the font size of body text and small text by 1 tier, where body text becomes "lg" and small text becomes "md". To applying editorial styling, use `isEditorial`. + +```ts file="./ContentEditorial.tsx" + +``` diff --git a/packages/react-core/src/components/Content/examples/ContentBody.tsx b/packages/react-core/src/components/Content/examples/ContentBody.tsx index b94e9e2c524..b239985220e 100644 --- a/packages/react-core/src/components/Content/examples/ContentBody.tsx +++ b/packages/react-core/src/components/Content/examples/ContentBody.tsx @@ -1,4 +1,3 @@ -import React from 'react'; import { Content, ContentVariants } from '@patternfly/react-core'; export const ContentBody: React.FunctionComponent = () => ( diff --git a/packages/react-core/src/components/Content/examples/ContentDescriptionList.tsx b/packages/react-core/src/components/Content/examples/ContentDescriptionList.tsx index 7742ca50f94..0199d09df33 100644 --- a/packages/react-core/src/components/Content/examples/ContentDescriptionList.tsx +++ b/packages/react-core/src/components/Content/examples/ContentDescriptionList.tsx @@ -1,4 +1,3 @@ -import React from 'react'; import { Content, ContentVariants } from '@patternfly/react-core'; export const ContentDescriptionList: React.FunctionComponent = () => ( diff --git a/packages/react-core/src/components/Content/examples/ContentEditorial.tsx b/packages/react-core/src/components/Content/examples/ContentEditorial.tsx new file mode 100644 index 00000000000..c1690072ca9 --- /dev/null +++ b/packages/react-core/src/components/Content/examples/ContentEditorial.tsx @@ -0,0 +1,23 @@ +import { Content, ContentVariants } from '@patternfly/react-core'; + +export const ContentEditorial: React.FunctionComponent = () => ( + <> + + Example of editorial content via components + + + Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla accumsan, metus ultrices eleifend gravida, nulla + nunc varius lectus, nec rutrum justo nibh eu lectus. Ut vulputate semper dui. Fusce erat odio, sollicitudin vel + erat vel, interdum mattis neque. Sub works as well! + +
+ +

Example of editorial content via wrapper

+

+ Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla accumsan, metus ultrices eleifend gravida, nulla + nunc varius lectus, nec rutrum justo nibh eu lectus. Ut vulputate semper dui. Fusce erat odio, sollicitudin vel + erat vel, interdum mattis neque. Sub works as well! +

+
+ +); diff --git a/packages/react-core/src/components/Content/examples/ContentHeadings.tsx b/packages/react-core/src/components/Content/examples/ContentHeadings.tsx index f0a6f4b3c0e..4cde33a667e 100644 --- a/packages/react-core/src/components/Content/examples/ContentHeadings.tsx +++ b/packages/react-core/src/components/Content/examples/ContentHeadings.tsx @@ -1,4 +1,3 @@ -import React from 'react'; import { Content, ContentVariants } from '@patternfly/react-core'; export const ContentHeadings: React.FunctionComponent = () => ( diff --git a/packages/react-core/src/components/Content/examples/ContentOrderedList.tsx b/packages/react-core/src/components/Content/examples/ContentOrderedList.tsx index 24dd49c2c5d..bdb4fd73eec 100644 --- a/packages/react-core/src/components/Content/examples/ContentOrderedList.tsx +++ b/packages/react-core/src/components/Content/examples/ContentOrderedList.tsx @@ -1,4 +1,3 @@ -import React from 'react'; import { Content, ContentVariants } from '@patternfly/react-core'; export const ContentOrderedList: React.FunctionComponent = () => ( diff --git a/packages/react-core/src/components/Content/examples/ContentPlainList.tsx b/packages/react-core/src/components/Content/examples/ContentPlainList.tsx index e49e4512868..13433226326 100644 --- a/packages/react-core/src/components/Content/examples/ContentPlainList.tsx +++ b/packages/react-core/src/components/Content/examples/ContentPlainList.tsx @@ -1,4 +1,3 @@ -import React from 'react'; import { Content, ContentVariants } from '@patternfly/react-core'; export const ContentPlainList: React.FunctionComponent = () => ( diff --git a/packages/react-core/src/components/Content/examples/ContentUnorderedList.tsx b/packages/react-core/src/components/Content/examples/ContentUnorderedList.tsx index 356edfe1b0f..d3eade8d88e 100644 --- a/packages/react-core/src/components/Content/examples/ContentUnorderedList.tsx +++ b/packages/react-core/src/components/Content/examples/ContentUnorderedList.tsx @@ -1,4 +1,3 @@ -import React from 'react'; import { Content, ContentVariants } from '@patternfly/react-core'; export const ContentUnorderedList: React.FunctionComponent = () => ( diff --git a/packages/react-core/src/components/Content/examples/ContentVisited.tsx b/packages/react-core/src/components/Content/examples/ContentVisited.tsx index 56fe72aa1b1..82ac85ee812 100644 --- a/packages/react-core/src/components/Content/examples/ContentVisited.tsx +++ b/packages/react-core/src/components/Content/examples/ContentVisited.tsx @@ -1,4 +1,3 @@ -import React from 'react'; import { Content, ContentVariants } from '@patternfly/react-core'; export const ContentVisited: React.FunctionComponent = () => ( diff --git a/packages/react-core/src/components/Content/examples/ContentWrapper.tsx b/packages/react-core/src/components/Content/examples/ContentWrapper.tsx index e8ed09652c2..8e4be41b78a 100644 --- a/packages/react-core/src/components/Content/examples/ContentWrapper.tsx +++ b/packages/react-core/src/components/Content/examples/ContentWrapper.tsx @@ -1,4 +1,3 @@ -import React from 'react'; import { Content, ContentVariants } from '@patternfly/react-core'; export const ContentWrapper: React.FunctionComponent = () => ( diff --git a/packages/react-core/src/components/DataList/DataList.tsx b/packages/react-core/src/components/DataList/DataList.tsx index cc9857baba4..d9063b875ba 100644 --- a/packages/react-core/src/components/DataList/DataList.tsx +++ b/packages/react-core/src/components/DataList/DataList.tsx @@ -1,4 +1,4 @@ -import * as React from 'react'; +import { createContext, forwardRef } from 'react'; import { css } from '@patternfly/react-styles'; import styles from '@patternfly/react-styles/css/components/DataList/data-list'; @@ -19,26 +19,30 @@ export enum DataListWrapModifier { } export interface DataListProps extends React.HTMLProps { - /** Content rendered inside the DataList list */ + /** Content rendered inside the data list list */ children?: React.ReactNode; - /** Additional classes added to the DataList list */ + /** Additional classes added to the data list list */ className?: string; - /** Adds accessible text to the DataList list */ + /** Adds accessible text to the data list list */ 'aria-label': string; - /** Optional callback to make DataList selectable, fired when DataListItem selected */ + /** Optional callback to make data list selectable, fired when data list item selected */ onSelectDataListItem?: (event: React.MouseEvent | React.KeyboardEvent, id: string) => void; - /** Id of DataList item currently selected */ + /** Id of data list item currently selected */ selectedDataListItemId?: string; - /** Flag indicating if DataList should have compact styling */ + /** Flag indicating if data list should have compact styling */ isCompact?: boolean; + /** @beta Flag indicating if data list should have plain styling with a transparent background */ + isPlain?: boolean; + /** @beta Flag to prevent the data list from automatically applying plain styling when glass theme is enabled. */ + isNoPlainOnGlass?: boolean; /** Specifies the grid breakpoints */ gridBreakpoint?: 'none' | 'always' | 'sm' | 'md' | 'lg' | 'xl' | '2xl'; - /** Determines which wrapping modifier to apply to the DataList */ + /** Determines which wrapping modifier to apply to the data list */ wrapModifier?: DataListWrapModifier | 'nowrap' | 'truncate' | 'breakWord'; /** Object that causes the data list to render hidden inputs which improve selectable item a11y */ onSelectableRowChange?: (event: React.FormEvent, id: string) => void; - /** @hide custom ref of the DataList */ - innerRef?: React.RefObject; + /** @hide custom ref of the data list */ + innerRef?: React.RefObject; } interface DataListContextProps { @@ -48,7 +52,7 @@ interface DataListContextProps { onSelectableRowChange?: (event: React.FormEvent, id: string) => void; } -export const DataListContext = React.createContext>({ +export const DataListContext = createContext>({ isSelectable: false }); @@ -59,6 +63,8 @@ export const DataListBase: React.FunctionComponent = ({ onSelectDataListItem, selectedDataListItemId = '', isCompact = false, + isPlain = false, + isNoPlainOnGlass = false, gridBreakpoint = 'md', wrapModifier = null, onSelectableRowChange, @@ -84,6 +90,8 @@ export const DataListBase: React.FunctionComponent = ({ className={css( styles.dataList, isCompact && styles.modifiers.compact, + isPlain && styles.modifiers.plain, + isNoPlainOnGlass && styles.modifiers.noPlainOnGlass, gridBreakpointClasses[gridBreakpoint], wrapModifier && styles.modifiers[wrapModifier], className @@ -102,7 +110,7 @@ export const DataListBase: React.FunctionComponent = ({ DataListBase.displayName = 'DataListBase'; -export const DataList = React.forwardRef((props: DataListProps, ref: React.Ref) => ( +export const DataList = forwardRef((props: DataListProps, ref: React.Ref) => ( } {...props} /> )); diff --git a/packages/react-core/src/components/DataList/DataListAction.tsx b/packages/react-core/src/components/DataList/DataListAction.tsx index 2c3085e859d..dab1e06dc73 100644 --- a/packages/react-core/src/components/DataList/DataListAction.tsx +++ b/packages/react-core/src/components/DataList/DataListAction.tsx @@ -1,18 +1,17 @@ -import * as React from 'react'; import { css } from '@patternfly/react-styles'; import styles from '@patternfly/react-styles/css/components/DataList/data-list'; import { formatBreakpointMods } from '../../helpers/util'; export interface DataListActionProps extends Omit, 'children'> { - /** Content rendered as DataList Action (e.g ); diff --git a/packages/react-core/src/components/DataList/DataListItem.tsx b/packages/react-core/src/components/DataList/DataListItem.tsx index 98032ba43b4..702f4ad9dc4 100644 --- a/packages/react-core/src/components/DataList/DataListItem.tsx +++ b/packages/react-core/src/components/DataList/DataListItem.tsx @@ -1,6 +1,7 @@ -import * as React from 'react'; +import { Children, Component, cloneElement, isValidElement } from 'react'; import { css } from '@patternfly/react-styles'; import styles from '@patternfly/react-styles/css/components/DataList/data-list'; +import menuStyles from '@patternfly/react-styles/css/components/Menu/menu'; import { DataListContext } from './DataList'; import { KeyTypes } from '../../helpers/constants'; @@ -11,7 +12,7 @@ export interface DataListItemProps extends Omit, children: React.ReactNode; /** Additional classes added to the DataList item should be either or */ className?: string; - /** Adds accessible text to the DataList item */ + /** Adds an accessible name to the selectable input if one is rendered */ 'aria-labelledby': string; /** Unique id for the DataList item */ id?: string; @@ -24,7 +25,7 @@ export interface DataListItemChildProps { rowid: string; } -class DataListItem extends React.Component { +class DataListItem extends Component { static displayName = 'DataListItem'; static defaultProps: DataListItemProps = { isExpanded: false, @@ -65,6 +66,17 @@ class DataListItem extends React.Component { const onKeyDown = (event: React.KeyboardEvent) => { if ([KeyTypes.Enter, KeyTypes.Space].includes(event.key)) { + const target: any = event.target as HTMLElement; + + if ( + target.closest(`.${menuStyles.menuItem}`) || + target.parentNode.classList.contains(styles.dataListItemAction) || + target.parentNode.classList.contains(styles.dataListItemControl) + ) { + // check other event handlers are not present. + return; + } + event.preventDefault(); updateSelectedDataListItem(event, id); } @@ -86,9 +98,7 @@ class DataListItem extends React.Component { selectedDataListItemId && isSelected && styles.modifiers.selected, className )} - aria-labelledby={ariaLabelledBy} {...(isSelectable && { tabIndex: 0, onClick: selectDataListItem, onKeyDown })} - {...(isSelectable && isSelected && { 'aria-selected': true })} {...props} > {onSelectableRowChange && ( @@ -101,11 +111,11 @@ class DataListItem extends React.Component { {...selectableInputAriaProps} /> )} - {React.Children.map( + {Children.map( children, (child) => - React.isValidElement(child) && - React.cloneElement(child as React.ReactElement, { + isValidElement(child) && + cloneElement(child as React.ReactElement, { rowid: ariaLabelledBy }) )} diff --git a/packages/react-core/src/components/DataList/DataListItemCells.tsx b/packages/react-core/src/components/DataList/DataListItemCells.tsx index 822eb2a7223..458739f5135 100644 --- a/packages/react-core/src/components/DataList/DataListItemCells.tsx +++ b/packages/react-core/src/components/DataList/DataListItemCells.tsx @@ -1,9 +1,8 @@ -import * as React from 'react'; import { css } from '@patternfly/react-styles'; import styles from '@patternfly/react-styles/css/components/DataList/data-list'; export interface DataListItemCellsProps extends React.HTMLProps { - /** Additional classes added to the DataList item Content Wrapper. Children should be one ore more nodes */ + /** Additional classes added to the data list item content wrapper. Children should be one or more nodes */ className?: string; /** Array of nodes that are rendered one after the other. */ dataListCells?: React.ReactNode; diff --git a/packages/react-core/src/components/DataList/DataListItemRow.tsx b/packages/react-core/src/components/DataList/DataListItemRow.tsx index bc216d07877..39e27829a00 100644 --- a/packages/react-core/src/components/DataList/DataListItemRow.tsx +++ b/packages/react-core/src/components/DataList/DataListItemRow.tsx @@ -1,4 +1,4 @@ -import * as React from 'react'; +import { Children, cloneElement, isValidElement } from 'react'; import { css } from '@patternfly/react-styles'; import styles from '@patternfly/react-styles/css/components/DataList/data-list'; import { DataListWrapModifier } from './DataList'; @@ -22,11 +22,11 @@ export const DataListItemRow: React.FunctionComponent = ({ ...props }: DataListItemRowProps) => (
- {React.Children.map( + {Children.map( children, (child) => - React.isValidElement(child) && - React.cloneElement(child as React.ReactElement, { + isValidElement(child) && + cloneElement(child as React.ReactElement, { rowid }) )} diff --git a/packages/react-core/src/components/DataList/DataListText.tsx b/packages/react-core/src/components/DataList/DataListText.tsx index 69341f792ea..795db78a857 100644 --- a/packages/react-core/src/components/DataList/DataListText.tsx +++ b/packages/react-core/src/components/DataList/DataListText.tsx @@ -1,4 +1,4 @@ -import * as React from 'react'; +import { useState } from 'react'; import { css } from '@patternfly/react-styles'; import styles from '@patternfly/react-styles/css/components/DataList/data-list'; import { Tooltip } from '../Tooltip'; @@ -30,7 +30,7 @@ export const DataListText: React.FunctionComponent = ({ }: DataListTextProps) => { const Component = component as any; - const [tooltip, setTooltip] = React.useState(''); + const [tooltip, setTooltip] = useState(''); const onMouseEnter = (event: any) => { if (event.target.offsetWidth < event.target.scrollWidth) { setTooltip(tooltipProp || event.target.innerHTML); diff --git a/packages/react-core/src/components/DataList/DataListToggle.tsx b/packages/react-core/src/components/DataList/DataListToggle.tsx index 71fda10f908..3b3d31f9e0e 100644 --- a/packages/react-core/src/components/DataList/DataListToggle.tsx +++ b/packages/react-core/src/components/DataList/DataListToggle.tsx @@ -1,21 +1,20 @@ -import * as React from 'react'; import { css } from '@patternfly/react-styles'; -import AngleRightIcon from '@patternfly/react-icons/dist/esm/icons/angle-right-icon'; +import RhMicronsCaretDownIcon from '@patternfly/react-icons/dist/esm/icons/rh-microns-caret-down-icon'; import styles from '@patternfly/react-styles/css/components/DataList/data-list'; import { Button, ButtonProps, ButtonVariant } from '../Button'; export interface DataListToggleProps extends React.HTMLProps { - /** Additional classes added to the DataList cell */ + /** Additional classes added to the data list cell */ className?: string; - /** Flag to show if the expanded content of the DataList item is visible */ + /** Flag to show if the expanded content of the data list item is visible */ isExpanded?: boolean; - /** Identify the DataList toggle number */ + /** Identify the data list toggle number */ id: string; /** Id for the row */ rowid?: string; - /** Adds accessible text to the DataList toggle */ + /** Adds accessible text to the data list toggle */ 'aria-labelledby'?: string; - /** Adds accessible text to the DataList toggle */ + /** Adds accessible text to the data list toggle */ 'aria-label'?: string; /** Allows users of some screen readers to shift focus to the controlled element. Should be used when the controlled contents are not adjacent to the toggle that controls them. */ 'aria-controls'?: string; @@ -45,7 +44,7 @@ export const DataListToggle: React.FunctionComponent = ({ {...buttonProps} icon={
- +
} /> diff --git a/packages/react-core/src/components/DataList/__tests__/DataList.test.tsx b/packages/react-core/src/components/DataList/__tests__/DataList.test.tsx index f28b8cd6f2c..0a906791717 100644 --- a/packages/react-core/src/components/DataList/__tests__/DataList.test.tsx +++ b/packages/react-core/src/components/DataList/__tests__/DataList.test.tsx @@ -1,5 +1,4 @@ -import React from 'react'; - +import '@testing-library/jest-dom'; import { render, screen } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; @@ -40,7 +39,7 @@ test(`Renders ${styles.modifiers.compact} when isCompact = true`, () => { }); ['nowrap', 'truncate', 'breakWord'].forEach((wrap) => { - test(`Renders with class ${styles.modifiers[wrap]} when wrapModifier = ${wrap} is pased`, () => { + test(`Renders with class ${styles.modifiers[wrap]} when wrapModifier = ${wrap} is passed`, () => { render(); expect(screen.getByLabelText('list')).toHaveClass(styles.modifiers[wrap]); }); @@ -57,7 +56,7 @@ const gridBreakpointClasses = { }; ['none', 'always', 'sm', 'md', 'lg', 'xl', '2xl'].forEach((oneBreakpoint) => { - test(`Has breakpoint - ${oneBreakpoint} when gridBreakpoint is pased`, () => { + test(`Has breakpoint - ${oneBreakpoint} when gridBreakpoint is passed`, () => { render(); expect(screen.getByLabelText('list')).toHaveClass(gridBreakpointClasses[oneBreakpoint]); }); @@ -73,6 +72,24 @@ test('Renders custom class when passed', () => { expect(screen.getByLabelText('list')).toHaveClass('data-list-custom'); }); +test(`Renders with class ${styles.modifiers.plain} when isPlain is true`, () => { + render(); + + expect(screen.getByLabelText('list')).toHaveClass(styles.modifiers.plain); +}); + +test(`Renders with ${styles.modifiers.noPlainOnGlass} when isNoPlainOnGlass is true`, () => { + render(); + expect(screen.getByLabelText('list')).toHaveClass(styles.modifiers.noPlainOnGlass); +}); + +test(`Renders with both ${styles.modifiers.plain} and ${styles.modifiers.noPlainOnGlass} when isPlain and isNoPlainOnGlass are true`, () => { + render(); + const list = screen.getByLabelText('list'); + expect(list).toHaveClass(styles.modifiers.plain); + expect(list).toHaveClass(styles.modifiers.noPlainOnGlass); +}); + test('Renders with a hidden input to improve a11y when onSelectableRowChange is passed', () => { render( {}}> diff --git a/packages/react-core/src/components/DataList/__tests__/DataListAction.test.tsx b/packages/react-core/src/components/DataList/__tests__/DataListAction.test.tsx index 38745263caa..c6dbaf99c9c 100644 --- a/packages/react-core/src/components/DataList/__tests__/DataListAction.test.tsx +++ b/packages/react-core/src/components/DataList/__tests__/DataListAction.test.tsx @@ -1,5 +1,6 @@ -import React from 'react'; import { render, screen } from '@testing-library/react'; +import '@testing-library/jest-dom'; + import { DataListAction } from '../DataListAction'; import styles from '@patternfly/react-styles/css/components/DataList/data-list'; @@ -15,38 +16,35 @@ test('Renders to match snapshot', () => { test(`Renders with default class ${styles.dataListItemAction}`, () => { render( - + test ); - expect(screen.getByText('test')).toHaveClass(styles.dataListItemAction, { exact: true }); + expect(screen.getByTestId('actions')).toHaveClass(styles.dataListItemAction, { exact: true }); }); test(`Renders with custom class when className is passed`, () => { render( - + test ); - expect(screen.getByText('test')).toHaveClass('test-class'); + expect(screen.getByTestId('actions')).toHaveClass('test-class'); }); test(`Renders with spread props`, () => { render( - - test - - ); - expect(screen.getByText('test')).toHaveAttribute('dir', 'rtl'); -}); - -test(`Renders with class ${styles.dataListAction} when isPlainButtonAction = true`, () => { - render( - + test ); - expect(screen.getByText('test')).toHaveClass(styles.dataListAction); + expect(screen.getByTestId('actions')).toHaveAttribute('dir', 'rtl'); }); ['hidden', 'visible'].forEach((vis) => { @@ -58,18 +56,19 @@ test(`Renders with class ${styles.dataListAction} when isPlainButtonAction = tru aria-labelledby="check-action-item2 check-action-action2" id="check-action-action2" aria-label="Actions" + data-testid="actions" > test ); if (visMod === 'hidden') { - expect(screen.getByText('test')).toHaveClass(styles.modifiers[`${visMod}`]); + expect(screen.getByTestId('actions')).toHaveClass(styles.modifiers[`${visMod}`]); } - expect(screen.getByText('test')).toHaveClass(styles.modifiers[`${visMod}OnSm`]); - expect(screen.getByText('test')).toHaveClass(styles.modifiers[`${visMod}OnMd`]); - expect(screen.getByText('test')).toHaveClass(styles.modifiers[`${visMod}OnLg`]); - expect(screen.getByText('test')).toHaveClass(styles.modifiers[`${visMod}OnXl`]); - expect(screen.getByText('test')).toHaveClass(styles.modifiers[`${visMod}On_2xl`]); + expect(screen.getByTestId('actions')).toHaveClass(styles.modifiers[`${visMod}OnSm`]); + expect(screen.getByTestId('actions')).toHaveClass(styles.modifiers[`${visMod}OnMd`]); + expect(screen.getByTestId('actions')).toHaveClass(styles.modifiers[`${visMod}OnLg`]); + expect(screen.getByTestId('actions')).toHaveClass(styles.modifiers[`${visMod}OnXl`]); + expect(screen.getByTestId('actions')).toHaveClass(styles.modifiers[`${visMod}On_2xl`]); }); }); diff --git a/packages/react-core/src/components/DataList/__tests__/DataListCell.test.tsx b/packages/react-core/src/components/DataList/__tests__/DataListCell.test.tsx index 6e55ada2648..36a55cbc3e6 100644 --- a/packages/react-core/src/components/DataList/__tests__/DataListCell.test.tsx +++ b/packages/react-core/src/components/DataList/__tests__/DataListCell.test.tsx @@ -1,4 +1,3 @@ -import React from 'react'; import { render, screen } from '@testing-library/react'; import { DataListCell } from '../DataListCell'; diff --git a/packages/react-core/src/components/DataList/__tests__/DataListCheck.test.tsx b/packages/react-core/src/components/DataList/__tests__/DataListCheck.test.tsx index fa1424c746f..eff217f7f22 100644 --- a/packages/react-core/src/components/DataList/__tests__/DataListCheck.test.tsx +++ b/packages/react-core/src/components/DataList/__tests__/DataListCheck.test.tsx @@ -1,4 +1,4 @@ -import * as React from 'react'; +import { useState } from 'react'; import { render, screen } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; import { DataListCheck } from '../DataListCheck'; @@ -13,9 +13,11 @@ it('does not throw a "A component is changing an uncontrolled input of type chec const user = userEvent.setup(); const ControlledDataListCheck = () => { - const [checked, setChecked] = React.useState(false); + const [checked, setChecked] = useState(false); - return setChecked(!checked)} aria-labelledby={'string'} />; + return ( + setChecked(!checked)} aria-labelledby={'string'} /> + ); }; render(); diff --git a/packages/react-core/src/components/DataList/__tests__/DataListContent.test.tsx b/packages/react-core/src/components/DataList/__tests__/DataListContent.test.tsx index 912bb48f0de..63506fb6184 100644 --- a/packages/react-core/src/components/DataList/__tests__/DataListContent.test.tsx +++ b/packages/react-core/src/components/DataList/__tests__/DataListContent.test.tsx @@ -1,4 +1,3 @@ -import React from 'react'; import { render, screen } from '@testing-library/react'; import { DataListContent } from '../DataListContent'; diff --git a/packages/react-core/src/components/DataList/__tests__/DataListItem.test.tsx b/packages/react-core/src/components/DataList/__tests__/DataListItem.test.tsx index 54f358c8e83..19b0fb2d5da 100644 --- a/packages/react-core/src/components/DataList/__tests__/DataListItem.test.tsx +++ b/packages/react-core/src/components/DataList/__tests__/DataListItem.test.tsx @@ -1,4 +1,3 @@ -import React from 'react'; import { render, screen } from '@testing-library/react'; import { DataListItem } from '../DataListItem'; diff --git a/packages/react-core/src/components/DataList/__tests__/DataListItemCells.test.tsx b/packages/react-core/src/components/DataList/__tests__/DataListItemCells.test.tsx index e8419f2b361..c8d756b1985 100644 --- a/packages/react-core/src/components/DataList/__tests__/DataListItemCells.test.tsx +++ b/packages/react-core/src/components/DataList/__tests__/DataListItemCells.test.tsx @@ -1,4 +1,3 @@ -import React from 'react'; import { render, screen } from '@testing-library/react'; import { DataListItemCells } from '../DataListItemCells'; diff --git a/packages/react-core/src/components/DataList/__tests__/DataListItemRow.test.tsx b/packages/react-core/src/components/DataList/__tests__/DataListItemRow.test.tsx index 74ec2e6fafc..e86ec190661 100644 --- a/packages/react-core/src/components/DataList/__tests__/DataListItemRow.test.tsx +++ b/packages/react-core/src/components/DataList/__tests__/DataListItemRow.test.tsx @@ -1,4 +1,3 @@ -import React from 'react'; import { render, screen } from '@testing-library/react'; import { DataListItemRow } from '../DataListItemRow'; @@ -33,7 +32,7 @@ test(`Renders with spread props`, () => { }); ['nowrap', 'truncate', 'breakWord'].forEach((wrap) => { - test(`Renders with class ${styles.modifiers[wrap]} when wrapModifier = ${wrap} is pased`, () => { + test(`Renders with class ${styles.modifiers[wrap]} when wrapModifier = ${wrap} is passed`, () => { render( test diff --git a/packages/react-core/src/components/DataList/__tests__/DataListToggle.test.tsx b/packages/react-core/src/components/DataList/__tests__/DataListToggle.test.tsx index 8f7f8b4cd9b..af677b320b3 100644 --- a/packages/react-core/src/components/DataList/__tests__/DataListToggle.test.tsx +++ b/packages/react-core/src/components/DataList/__tests__/DataListToggle.test.tsx @@ -1,4 +1,3 @@ -import React from 'react'; import { render, screen } from '@testing-library/react'; import { DataListToggle } from '../DataListToggle'; diff --git a/packages/react-core/src/components/DataList/__tests__/Generated/DataListAction.test.tsx b/packages/react-core/src/components/DataList/__tests__/Generated/DataListAction.test.tsx index 2f07cb48c8d..d6af1889bfe 100644 --- a/packages/react-core/src/components/DataList/__tests__/Generated/DataListAction.test.tsx +++ b/packages/react-core/src/components/DataList/__tests__/Generated/DataListAction.test.tsx @@ -1,7 +1,6 @@ /** * This test was generated */ -import * as React from 'react'; import { render } from '@testing-library/react'; import { DataListAction } from '../../DataListAction'; // any missing imports can usually be resolved by adding them here diff --git a/packages/react-core/src/components/DataList/__tests__/Generated/DataListCell.test.tsx b/packages/react-core/src/components/DataList/__tests__/Generated/DataListCell.test.tsx index 8ef64961e43..9325da25c76 100644 --- a/packages/react-core/src/components/DataList/__tests__/Generated/DataListCell.test.tsx +++ b/packages/react-core/src/components/DataList/__tests__/Generated/DataListCell.test.tsx @@ -1,7 +1,6 @@ /** * This test was generated */ -import * as React from 'react'; import { render } from '@testing-library/react'; import { DataListCell } from '../../DataListCell'; // any missing imports can usually be resolved by adding them here diff --git a/packages/react-core/src/components/DataList/__tests__/Generated/DataListCheck.test.tsx b/packages/react-core/src/components/DataList/__tests__/Generated/DataListCheck.test.tsx index 0b6b5e1adff..81c1612e8b3 100644 --- a/packages/react-core/src/components/DataList/__tests__/Generated/DataListCheck.test.tsx +++ b/packages/react-core/src/components/DataList/__tests__/Generated/DataListCheck.test.tsx @@ -1,7 +1,6 @@ /** * This test was generated */ -import * as React from 'react'; import { render } from '@testing-library/react'; import { DataListCheck } from '../../DataListCheck'; // any missing imports can usually be resolved by adding them here @@ -10,11 +9,12 @@ import {} from '../..'; it('DataListCheck should match snapshot (auto-generated)', () => { const { asFragment } = render( , checked: boolean) => {}} aria-labelledby={'string'} /> diff --git a/packages/react-core/src/components/DataList/__tests__/Generated/DataListContent.test.tsx b/packages/react-core/src/components/DataList/__tests__/Generated/DataListContent.test.tsx index 96d79ef0645..d56ee15d68e 100644 --- a/packages/react-core/src/components/DataList/__tests__/Generated/DataListContent.test.tsx +++ b/packages/react-core/src/components/DataList/__tests__/Generated/DataListContent.test.tsx @@ -1,7 +1,6 @@ /** * This test was generated */ -import * as React from 'react'; import { render } from '@testing-library/react'; import { DataListContent } from '../../DataListContent'; // any missing imports can usually be resolved by adding them here diff --git a/packages/react-core/src/components/DataList/__tests__/Generated/DataListItem.test.tsx b/packages/react-core/src/components/DataList/__tests__/Generated/DataListItem.test.tsx index 1e18e943867..8ce3d07a96a 100644 --- a/packages/react-core/src/components/DataList/__tests__/Generated/DataListItem.test.tsx +++ b/packages/react-core/src/components/DataList/__tests__/Generated/DataListItem.test.tsx @@ -1,7 +1,6 @@ /** * This test was generated */ -import * as React from 'react'; import { render } from '@testing-library/react'; import { DataListItem } from '../../DataListItem'; // any missing imports can usually be resolved by adding them here diff --git a/packages/react-core/src/components/DataList/__tests__/Generated/DataListItemCells.test.tsx b/packages/react-core/src/components/DataList/__tests__/Generated/DataListItemCells.test.tsx index 1f71eed7cc1..67438001e56 100644 --- a/packages/react-core/src/components/DataList/__tests__/Generated/DataListItemCells.test.tsx +++ b/packages/react-core/src/components/DataList/__tests__/Generated/DataListItemCells.test.tsx @@ -1,7 +1,6 @@ /** * This test was generated */ -import * as React from 'react'; import { render } from '@testing-library/react'; import { DataListItemCells } from '../../DataListItemCells'; // any missing imports can usually be resolved by adding them here diff --git a/packages/react-core/src/components/DataList/__tests__/Generated/DataListItemRow.test.tsx b/packages/react-core/src/components/DataList/__tests__/Generated/DataListItemRow.test.tsx index acd0768a0bb..6179c72efde 100644 --- a/packages/react-core/src/components/DataList/__tests__/Generated/DataListItemRow.test.tsx +++ b/packages/react-core/src/components/DataList/__tests__/Generated/DataListItemRow.test.tsx @@ -1,7 +1,6 @@ /** * This test was generated */ -import * as React from 'react'; import { render } from '@testing-library/react'; import { DataListItemRow } from '../../DataListItemRow'; // any missing imports can usually be resolved by adding them here diff --git a/packages/react-core/src/components/DataList/__tests__/Generated/DataListToggle.test.tsx b/packages/react-core/src/components/DataList/__tests__/Generated/DataListToggle.test.tsx index 9e1b0e3407a..e6fff7d3fbf 100644 --- a/packages/react-core/src/components/DataList/__tests__/Generated/DataListToggle.test.tsx +++ b/packages/react-core/src/components/DataList/__tests__/Generated/DataListToggle.test.tsx @@ -1,7 +1,6 @@ /** * This test was generated */ -import * as React from 'react'; import { render } from '@testing-library/react'; import { DataListToggle } from '../../DataListToggle'; // any missing imports can usually be resolved by adding them here diff --git a/packages/react-core/src/components/DataList/__tests__/Generated/__snapshots__/DataListCheck.test.tsx.snap b/packages/react-core/src/components/DataList/__tests__/Generated/__snapshots__/DataListCheck.test.tsx.snap index b85f93f8e38..111df143cec 100644 --- a/packages/react-core/src/components/DataList/__tests__/Generated/__snapshots__/DataListCheck.test.tsx.snap +++ b/packages/react-core/src/components/DataList/__tests__/Generated/__snapshots__/DataListCheck.test.tsx.snap @@ -8,11 +8,21 @@ exports[`DataListCheck should match snapshot (auto-generated) 1`] = `
- +
diff --git a/packages/react-core/src/components/DataList/__tests__/Generated/__snapshots__/DataListItem.test.tsx.snap b/packages/react-core/src/components/DataList/__tests__/Generated/__snapshots__/DataListItem.test.tsx.snap index 3aad0404653..02554c4686b 100644 --- a/packages/react-core/src/components/DataList/__tests__/Generated/__snapshots__/DataListItem.test.tsx.snap +++ b/packages/react-core/src/components/DataList/__tests__/Generated/__snapshots__/DataListItem.test.tsx.snap @@ -3,7 +3,6 @@ exports[`DataListItem should match snapshot (auto-generated) 1`] = `
  • diff --git a/packages/react-core/src/components/DataList/__tests__/Generated/__snapshots__/DataListToggle.test.tsx.snap b/packages/react-core/src/components/DataList/__tests__/Generated/__snapshots__/DataListToggle.test.tsx.snap index 641bc0433de..da7429404bb 100644 --- a/packages/react-core/src/components/DataList/__tests__/Generated/__snapshots__/DataListToggle.test.tsx.snap +++ b/packages/react-core/src/components/DataList/__tests__/Generated/__snapshots__/DataListToggle.test.tsx.snap @@ -11,11 +11,10 @@ exports[`DataListToggle should match snapshot (auto-generated) 1`] = ` >
  • diff --git a/packages/react-core/src/components/DataList/__tests__/__snapshots__/DataListItem.test.tsx.snap b/packages/react-core/src/components/DataList/__tests__/__snapshots__/DataListItem.test.tsx.snap index 4e4ed5918ff..3ecc65cd56d 100644 --- a/packages/react-core/src/components/DataList/__tests__/__snapshots__/DataListItem.test.tsx.snap +++ b/packages/react-core/src/components/DataList/__tests__/__snapshots__/DataListItem.test.tsx.snap @@ -3,7 +3,6 @@ exports[`Renders to match snapshot 1`] = `
  • diff --git a/packages/react-core/src/components/DataList/__tests__/__snapshots__/DataListToggle.test.tsx.snap b/packages/react-core/src/components/DataList/__tests__/__snapshots__/DataListToggle.test.tsx.snap index 053d0d56f17..3030121ed4f 100644 --- a/packages/react-core/src/components/DataList/__tests__/__snapshots__/DataListToggle.test.tsx.snap +++ b/packages/react-core/src/components/DataList/__tests__/__snapshots__/DataListToggle.test.tsx.snap @@ -10,12 +10,11 @@ exports[`Renders to match snapshot 1`] = ` >
  • diff --git a/packages/react-core/src/components/DataList/examples/DataList.md b/packages/react-core/src/components/DataList/examples/DataList.md index 8a25af028c6..b052086122c 100644 --- a/packages/react-core/src/components/DataList/examples/DataList.md +++ b/packages/react-core/src/components/DataList/examples/DataList.md @@ -1,7 +1,7 @@ --- id: Data list section: components -cssPrefix: pf-v5-c-data-list +cssPrefix: pf-v6-c-data-list propComponents: [ 'DataList', @@ -18,12 +18,13 @@ propComponents: ] --- -import CodeBranchIcon from '@patternfly/react-icons/dist/esm/icons/code-branch-icon'; -import AngleDownIcon from '@patternfly/react-icons/dist/esm/icons/angle-down-icon'; -import AngleRightIcon from '@patternfly/react-icons/dist/esm/icons/angle-right-icon'; -import EllipsisVIcon from '@patternfly/react-icons/dist/esm/icons/ellipsis-v-icon'; +import { Fragment, useState } from 'react'; +import RhUiBranchFillIcon from '@patternfly/react-icons/dist/esm/icons/rh-ui-branch-fill-icon'; +import RhMicronsCaretDownIcon from '@patternfly/react-icons/dist/esm/icons/rh-microns-caret-down-icon'; +import RhMicronsCaretRightIcon from '@patternfly/react-icons/dist/esm/icons/rh-microns-caret-right-icon'; +import RhUiEllipsisVerticalFillIcon from '@patternfly/react-icons/dist/esm/icons/rh-ui-ellipsis-vertical-fill-icon'; import { css } from '@patternfly/react-styles'; -import { DragDrop, Draggable, Droppable } from '@patternfly/react-core/deprecated'; +import { DragDropSort, DragDropContainer, Droppable as NewDroppable } from '@patternfly/react-drag-drop'; ## Examples @@ -39,6 +40,12 @@ import { DragDrop, Draggable, Droppable } from '@patternfly/react-core/deprecate ``` +### Plain + +```ts file="./DataListPlain.tsx" + +``` + ### Checkboxes, actions and additional cells ```ts file="./DataListCheckboxes.tsx" @@ -83,11 +90,23 @@ import { DragDrop, Draggable, Droppable } from '@patternfly/react-core/deprecate ### Draggable -Note: There is a new recommended drag and drop implementation with full keyboard functionality, which replaces this implementation. To adhere to our new recommendations, refer to the [drag and drop demos](/components/drag-and-drop/react-demos). +To enable drag and drop, wrap the `` component with ``, define the `variant` property as "DataList", and pass both the sortable items and `onDrop` callback to ``. `` will create the component's usual children internally based on the items property, so children should not be passed to the wrapped component. + +Full drag and drop details can be found on the [drag and drop](/components/drag-and-drop) component page. + +```ts file="../../../../../react-drag-drop/src/components/DragDrop/examples/DataListDraggable.tsx" + +``` + +### Draggable with multiple drop zones + +To enable multiple drop zones, and create the desired amount of `` components within a ``. + +Each `` should define the `wrapper` property as the component that acts as the drop zone, ``, and the `items` property of their respective draggable items as an array of `` data. `` should be passed the `onDrop`, `onContainerMove`, and `onCancel` callbacks to handle items being dropped, items moving between droppable containers, and what happens if the drag is cancelled respectively. `` should also be given a `Record` representing all sortable drop zones' items. Both components should define the `variant` property as "DataList". -Previously, draggable data lists had their own API for the [drag and drop component](/components/drag-and-drop), which wasn't flexible enough to allow custom styling for items as they are dragged. To address this disparity, ``, ``, and `` components were added to replace our now deprecated HTML5-based API. Keyboard and screen reader accessibility for the `` component is still in development. +Full drag and drop details can be found on the [drag and drop](/components/drag-and-drop) component page. -```ts isDeprecated file="./DataListDraggable.tsx" +```ts file="../../../../../react-drag-drop/src/components/DragDrop/examples/DragDropContainerDataList.tsx" ``` diff --git a/packages/react-core/src/components/DataList/examples/DataListActions.tsx b/packages/react-core/src/components/DataList/examples/DataListActions.tsx index 68b5d53f1ec..7094808cc2c 100644 --- a/packages/react-core/src/components/DataList/examples/DataListActions.tsx +++ b/packages/react-core/src/components/DataList/examples/DataListActions.tsx @@ -1,4 +1,4 @@ -import React from 'react'; +import { Fragment, useState } from 'react'; import { Button, DataList, @@ -13,11 +13,11 @@ import { MenuToggle, MenuToggleElement } from '@patternfly/react-core'; -import EllipsisVIcon from '@patternfly/react-icons/dist/esm/icons/ellipsis-v-icon'; +import RhUiEllipsisVerticalFillIcon from '@patternfly/react-icons/dist/esm/icons/rh-ui-ellipsis-vertical-fill-icon'; export const DataListActions: React.FunctionComponent = () => { - const [isOpen, setIsOpen] = React.useState(false); - const [isDeleted, setIsDeleted] = React.useState(false); + const [isOpen, setIsOpen] = useState(false); + const [isDeleted, setIsDeleted] = useState(false); const onToggle = () => { setIsOpen(!isOpen); @@ -28,7 +28,7 @@ export const DataListActions: React.FunctionComponent = () => { }; return ( - + {!isDeleted && ( @@ -75,7 +75,6 @@ export const DataListActions: React.FunctionComponent = () => { aria-labelledby="multi-actions-item1 multi-actions-action1" id="multi-actions-action1" aria-label="Actions" - isPlainButtonAction > { onClick={onToggle} variant="plain" aria-label="Data list with actions example kebab toggle" - > - - + ); }; diff --git a/packages/react-core/src/components/DataList/examples/DataListBasic.tsx b/packages/react-core/src/components/DataList/examples/DataListBasic.tsx index 984511aa480..e4af45501e9 100644 --- a/packages/react-core/src/components/DataList/examples/DataListBasic.tsx +++ b/packages/react-core/src/components/DataList/examples/DataListBasic.tsx @@ -1,4 +1,3 @@ -import React from 'react'; import { DataList, DataListItem, DataListItemRow, DataListItemCells, DataListCell } from '@patternfly/react-core'; export const DataListBasic: React.FunctionComponent = () => ( diff --git a/packages/react-core/src/components/DataList/examples/DataListCheckboxes.tsx b/packages/react-core/src/components/DataList/examples/DataListCheckboxes.tsx index 8f3ca384ddd..a0ba52cc57d 100644 --- a/packages/react-core/src/components/DataList/examples/DataListCheckboxes.tsx +++ b/packages/react-core/src/components/DataList/examples/DataListCheckboxes.tsx @@ -1,4 +1,4 @@ -import React from 'react'; +import { useState } from 'react'; import { Button, DataList, @@ -14,12 +14,12 @@ import { MenuToggle, MenuToggleElement } from '@patternfly/react-core'; -import EllipsisVIcon from '@patternfly/react-icons/dist/esm/icons/ellipsis-v-icon'; +import RhUiEllipsisVerticalFillIcon from '@patternfly/react-icons/dist/esm/icons/rh-ui-ellipsis-vertical-fill-icon'; export const DataListCheckboxes: React.FunctionComponent = () => { - const [isOpen1, setIsOpen1] = React.useState(false); - const [isOpen2, setIsOpen2] = React.useState(false); - const [isOpen3, setIsOpen3] = React.useState(false); + const [isOpen1, setIsOpen1] = useState(false); + const [isOpen2, setIsOpen2] = useState(false); + const [isOpen3, setIsOpen3] = useState(false); const onToggle1 = () => { setIsOpen1(!isOpen1); @@ -48,7 +48,7 @@ export const DataListCheckboxes: React.FunctionComponent = () => { - + @@ -73,7 +73,6 @@ export const DataListCheckboxes: React.FunctionComponent = () => { aria-labelledby="check-action-item1 check-action-action1" id="check-action-action1" aria-label="Actions" - isPlainButtonAction > { onClick={onToggle1} variant="plain" aria-label="Data list with checkboxes, actions and additional cells example kebab toggle 1" - > - - + @@ -129,7 +127,6 @@ export const DataListCheckboxes: React.FunctionComponent = () => { aria-labelledby="check-action-item2 check-action-action2" id="check-action-action2" aria-label="Actions" - isPlainButtonAction > { onClick={onToggle2} variant="plain" aria-label="Data list with checkboxes, actions and additional cells example kebab toggle 2" - > - - + @@ -194,7 +190,6 @@ export const DataListCheckboxes: React.FunctionComponent = () => { aria-labelledby="check-action-item3 check-action-action3" id="check-action-action3" aria-label="Actions" - isPlainButtonAction > { onClick={onToggle3} variant="plain" aria-label="Data list with checkboxes, actions and additional cells example kebab toggle 3" - > - - + ); }; diff --git a/packages/react-core/src/components/DataList/examples/DataListCompact.tsx b/packages/react-core/src/components/DataList/examples/DataListCompact.tsx index 6232f30015b..23644d59371 100644 --- a/packages/react-core/src/components/DataList/examples/DataListCompact.tsx +++ b/packages/react-core/src/components/DataList/examples/DataListCompact.tsx @@ -1,4 +1,3 @@ -import React from 'react'; import { DataList, DataListItem, DataListItemRow, DataListItemCells, DataListCell } from '@patternfly/react-core'; export const DataListCompact: React.FunctionComponent = () => ( diff --git a/packages/react-core/src/components/DataList/examples/DataListControllingText.tsx b/packages/react-core/src/components/DataList/examples/DataListControllingText.tsx index c8ced89d5fb..01d5adc3b73 100644 --- a/packages/react-core/src/components/DataList/examples/DataListControllingText.tsx +++ b/packages/react-core/src/components/DataList/examples/DataListControllingText.tsx @@ -1,4 +1,3 @@ -import React from 'react'; import { DataList, DataListItem, diff --git a/packages/react-core/src/components/DataList/examples/DataListDraggable.tsx b/packages/react-core/src/components/DataList/examples/DataListDraggable.tsx deleted file mode 100644 index b74f77246b3..00000000000 --- a/packages/react-core/src/components/DataList/examples/DataListDraggable.tsx +++ /dev/null @@ -1,103 +0,0 @@ -import React from 'react'; -import { - DataList, - DataListItem, - DataListCell, - DataListItemRow, - DataListCheck, - DataListControl, - DataListDragButton, - DataListItemCells, - getUniqueId -} from '@patternfly/react-core'; -import { DragDrop, Draggable, Droppable } from '@patternfly/react-core/deprecated'; - -interface ItemType { - id: string; - content: string; -} - -const getItems = (count: number) => - Array.from({ length: count }, (_, idx) => idx).map((idx) => ({ - id: `draggable-item-${idx}`, - content: `item ${idx} `.repeat(idx === 4 ? 20 : 1) - })); - -const reorder = (list: ItemType[], startIndex: number, endIndex: number) => { - const result = list; - const [removed] = result.splice(startIndex, 1); - result.splice(endIndex, 0, removed); - return result; -}; - -export const DataListDraggable: React.FunctionComponent = () => { - const [items, setItems] = React.useState(getItems(10)); - const [liveText, setLiveText] = React.useState(''); - - function onDrag(source) { - setLiveText(`Started dragging ${items[source.index].content}`); - // Return true to allow drag - return true; - } - - function onDragMove(source, dest) { - const newText = dest ? `Move ${items[source.index].content} to ${items[dest.index].content}` : 'Invalid drop zone'; - if (newText !== liveText) { - setLiveText(newText); - } - } - - function onDrop(source, dest) { - if (dest) { - const newItems = reorder(items, source.index, dest.index); - setItems(newItems); - - setLiveText('Dragging finished.'); - return true; // Signal that this is a valid drop and not to animate the item returning home. - } else { - setLiveText('Dragging cancelled. List unchanged.'); - } - } - - const uniqueId = getUniqueId(); - - return ( - - - - {items.map(({ id, content }) => ( - - - - - - - - - {content} - - ]} - /> - - - - ))} - - -
    - {liveText} -
    -
    - Press space or enter to begin dragging, and use the arrow keys to navigate up or down. Press enter to confirm - the drag, or any other key to cancel the drag operation. -
    -
    - ); -}; diff --git a/packages/react-core/src/components/DataList/examples/DataListExpandable.tsx b/packages/react-core/src/components/DataList/examples/DataListExpandable.tsx index 19a4564f57b..677e1e7b9a8 100644 --- a/packages/react-core/src/components/DataList/examples/DataListExpandable.tsx +++ b/packages/react-core/src/components/DataList/examples/DataListExpandable.tsx @@ -1,4 +1,4 @@ -import React from 'react'; +import { Fragment, useState } from 'react'; import { DataList, DataListItem, @@ -14,14 +14,14 @@ import { MenuToggle, MenuToggleElement } from '@patternfly/react-core'; -import EllipsisVIcon from '@patternfly/react-icons/dist/esm/icons/ellipsis-v-icon'; -import CodeBranchIcon from '@patternfly/react-icons/dist/esm/icons/code-branch-icon'; +import RhUiEllipsisVerticalFillIcon from '@patternfly/react-icons/dist/esm/icons/rh-ui-ellipsis-vertical-fill-icon'; +import RhUiBranchFillIcon from '@patternfly/react-icons/dist/esm/icons/rh-ui-branch-fill-icon'; export const DataListExpandable: React.FunctionComponent = () => { - const [isOpen1, setIsOpen1] = React.useState(false); - const [isOpen2, setIsOpen2] = React.useState(false); - const [isOpen3, setIsOpen3] = React.useState(false); - const [expanded, setExpanded] = React.useState(['ex-toggle1', 'ex-toggle3']); + const [isOpen1, setIsOpen1] = useState(false); + const [isOpen2, setIsOpen2] = useState(false); + const [isOpen3, setIsOpen3] = useState(false); + const [expanded, setExpanded] = useState(['ex-toggle1', 'ex-toggle3']); const onToggle1 = () => { setIsOpen1(!isOpen1); @@ -53,7 +53,7 @@ export const DataListExpandable: React.FunctionComponent = () => { setExpanded(newExpanded); }; return ( - + @@ -66,7 +66,7 @@ export const DataListExpandable: React.FunctionComponent = () => { - + ,
    Primary content
    @@ -81,12 +81,7 @@ export const DataListExpandable: React.FunctionComponent = () => {
    ]} /> - + { onClick={onToggle1} variant="plain" aria-label="Data list exapndable example kebaby toggle 1" - > -
    -
    + ); }; diff --git a/packages/react-core/src/components/DataList/examples/DataListMixedExpandable.tsx b/packages/react-core/src/components/DataList/examples/DataListMixedExpandable.tsx index 7f6a33c6b9b..b7cfc5f0d18 100644 --- a/packages/react-core/src/components/DataList/examples/DataListMixedExpandable.tsx +++ b/packages/react-core/src/components/DataList/examples/DataListMixedExpandable.tsx @@ -1,4 +1,4 @@ -import React from 'react'; +import { Fragment, useState } from 'react'; import { DataList, DataListItem, @@ -14,14 +14,14 @@ import { MenuToggle, MenuToggleElement } from '@patternfly/react-core'; -import EllipsisVIcon from '@patternfly/react-icons/dist/esm/icons/ellipsis-v-icon'; -import CodeBranchIcon from '@patternfly/react-icons/dist/esm/icons/code-branch-icon'; +import RhUiEllipsisVerticalFillIcon from '@patternfly/react-icons/dist/esm/icons/rh-ui-ellipsis-vertical-fill-icon'; +import RhUiBranchFillIcon from '@patternfly/react-icons/dist/esm/icons/rh-ui-branch-fill-icon'; export const DataListMixedExpandable: React.FunctionComponent = () => { - const [isOpen1, setIsOpen1] = React.useState(false); - const [isOpen2, setIsOpen2] = React.useState(false); - const [isOpen3, setIsOpen3] = React.useState(false); - const [expanded, setExpanded] = React.useState(['m-ex-toggle1', 'm-ex-toggle3']); + const [isOpen1, setIsOpen1] = useState(false); + const [isOpen2, setIsOpen2] = useState(false); + const [isOpen3, setIsOpen3] = useState(false); + const [expanded, setExpanded] = useState(['m-ex-toggle1', 'm-ex-toggle3']); const onToggle1 = () => { setIsOpen1(!isOpen1); @@ -55,7 +55,7 @@ export const DataListMixedExpandable: React.FunctionComponent = () => { }; return ( - + @@ -68,7 +68,7 @@ export const DataListMixedExpandable: React.FunctionComponent = () => { - + ,
    Primary content
    @@ -83,12 +83,7 @@ export const DataListMixedExpandable: React.FunctionComponent = () => {
    ]} /> - + { onClick={onToggle1} variant="plain" aria-label="Data list mixed expandable example kebab toggle 1" - > -
    -
    + ); }; diff --git a/packages/react-core/src/components/DataList/examples/DataListPlain.tsx b/packages/react-core/src/components/DataList/examples/DataListPlain.tsx new file mode 100644 index 00000000000..af0b9f9618d --- /dev/null +++ b/packages/react-core/src/components/DataList/examples/DataListPlain.tsx @@ -0,0 +1,32 @@ +import { DataList, DataListItem, DataListItemRow, DataListItemCells, DataListCell } from '@patternfly/react-core'; + +export const DataListPlain: React.FunctionComponent = () => ( + + + + + Primary content + , + Secondary content + ]} + /> + + + + + + Secondary content (pf-m-no-fill) + , + + Secondary content (pf-m-align-right pf-m-no-fill) + + ]} + /> + + + +); diff --git a/packages/react-core/src/components/DataList/examples/DataListSmGridBreakpoint.tsx b/packages/react-core/src/components/DataList/examples/DataListSmGridBreakpoint.tsx index 55d0023dd8c..9beb45d5788 100644 --- a/packages/react-core/src/components/DataList/examples/DataListSmGridBreakpoint.tsx +++ b/packages/react-core/src/components/DataList/examples/DataListSmGridBreakpoint.tsx @@ -1,4 +1,3 @@ -import React from 'react'; import { DataList, DataListItem, DataListItemRow, DataListItemCells, DataListCell } from '@patternfly/react-core'; export const DataListSmGridBreakpoint: React.FunctionComponent = () => ( diff --git a/packages/react-core/src/components/DataList/examples/DataListWidthModifiers.tsx b/packages/react-core/src/components/DataList/examples/DataListWidthModifiers.tsx index 47c316c761e..703a7433eaf 100644 --- a/packages/react-core/src/components/DataList/examples/DataListWidthModifiers.tsx +++ b/packages/react-core/src/components/DataList/examples/DataListWidthModifiers.tsx @@ -1,4 +1,4 @@ -import React from 'react'; +import { useState } from 'react'; import { Content, DataList, @@ -16,12 +16,12 @@ import { MenuToggle, MenuToggleElement } from '@patternfly/react-core'; -import EllipsisVIcon from '@patternfly/react-icons/dist/esm/icons/ellipsis-v-icon'; +import RhUiEllipsisVerticalFillIcon from '@patternfly/react-icons/dist/esm/icons/rh-ui-ellipsis-vertical-fill-icon'; export const DataListWidthModifiers: React.FunctionComponent = () => { - const [show, setShow] = React.useState(true); - const [isOpen1, setIsOpen1] = React.useState(false); - const [isOpen2, setIsOpen2] = React.useState(false); + const [show, setShow] = useState(true); + const [isOpen1, setIsOpen1] = useState(false); + const [isOpen2, setIsOpen2] = useState(false); const onToggle1 = () => { setIsOpen1(!isOpen1); @@ -48,7 +48,7 @@ export const DataListWidthModifiers: React.FunctionComponent = () => { - + @@ -75,7 +75,7 @@ export const DataListWidthModifiers: React.FunctionComponent = () => { - + @@ -92,7 +92,6 @@ export const DataListWidthModifiers: React.FunctionComponent = () => { aria-labelledby="width-ex2-item1 width-ex2-action1" id="width-ex2-action1" aria-label="Actions" - isPlainButtonAction > { onClick={onToggle1} variant="plain" aria-label="Data list width modifiers example kebab toggle 1" - > -
    - + ); }; diff --git a/packages/react-core/src/components/DatePicker/examples/DatePickerControlledCalendar.tsx b/packages/react-core/src/components/DatePicker/examples/DatePickerControlledCalendar.tsx index 89291a358c7..b7f7805fbf3 100644 --- a/packages/react-core/src/components/DatePicker/examples/DatePickerControlledCalendar.tsx +++ b/packages/react-core/src/components/DatePicker/examples/DatePickerControlledCalendar.tsx @@ -1,19 +1,19 @@ -import React from 'react'; +import { Fragment, useRef } from 'react'; import { Button, DatePicker } from '@patternfly/react-core'; export const DatePickerControlledCalendar: React.FunctionComponent = () => { - const dateRef = React.useRef(null); + const dateRef = useRef(null); const onClick = () => { if (dateRef.current) { dateRef.current.toggleCalendar(); } }; return ( - +

    -
    + ); }; diff --git a/packages/react-core/src/components/DatePicker/examples/DatePickerControlledRequired.tsx b/packages/react-core/src/components/DatePicker/examples/DatePickerControlledRequired.tsx index 4ba5bf302da..dc66819a833 100644 --- a/packages/react-core/src/components/DatePicker/examples/DatePickerControlledRequired.tsx +++ b/packages/react-core/src/components/DatePicker/examples/DatePickerControlledRequired.tsx @@ -1,11 +1,11 @@ -import React from 'react'; +import { Fragment, useState } from 'react'; import { Button, DatePicker, Flex, FlexItem } from '@patternfly/react-core'; export const DatePickerControlled: React.FunctionComponent = () => { const initialValue = '2020-03-17'; - const [value, setValue] = React.useState(initialValue); + const [value, setValue] = useState(initialValue); return ( - + { - + ); }; diff --git a/packages/react-core/src/components/DatePicker/examples/DatePickerFrench.tsx b/packages/react-core/src/components/DatePicker/examples/DatePickerFrench.tsx index 1dc033ecb19..3006e3b235a 100644 --- a/packages/react-core/src/components/DatePicker/examples/DatePickerFrench.tsx +++ b/packages/react-core/src/components/DatePicker/examples/DatePickerFrench.tsx @@ -1,4 +1,3 @@ -import React from 'react'; import { DatePicker, Weekday } from '@patternfly/react-core'; export const DatePickerFrench: React.FunctionComponent = () => { diff --git a/packages/react-core/src/components/DatePicker/examples/DatePickerHelperText.tsx b/packages/react-core/src/components/DatePicker/examples/DatePickerHelperText.tsx index 854b922c1e2..55c280074fd 100644 --- a/packages/react-core/src/components/DatePicker/examples/DatePickerHelperText.tsx +++ b/packages/react-core/src/components/DatePicker/examples/DatePickerHelperText.tsx @@ -1,4 +1,3 @@ -import React from 'react'; import { DatePicker, HelperText, HelperTextItem } from '@patternfly/react-core'; export const DatePickerHelperText: React.FunctionComponent = () => ( diff --git a/packages/react-core/src/components/DatePicker/examples/DatePickerMinMax.tsx b/packages/react-core/src/components/DatePicker/examples/DatePickerMinMax.tsx index 1253f5bab56..74f565bc37a 100644 --- a/packages/react-core/src/components/DatePicker/examples/DatePickerMinMax.tsx +++ b/packages/react-core/src/components/DatePicker/examples/DatePickerMinMax.tsx @@ -1,4 +1,3 @@ -import React from 'react'; import { DatePicker } from '@patternfly/react-core'; export const DatePickerMinMax: React.FunctionComponent = () => { diff --git a/packages/react-core/src/components/DatePicker/examples/DatePickerRequired.tsx b/packages/react-core/src/components/DatePicker/examples/DatePickerRequired.tsx index fbeb0f1febb..8571cd817d4 100644 --- a/packages/react-core/src/components/DatePicker/examples/DatePickerRequired.tsx +++ b/packages/react-core/src/components/DatePicker/examples/DatePickerRequired.tsx @@ -1,4 +1,3 @@ -import React from 'react'; import { DatePicker } from '@patternfly/react-core'; export const DatePickerRequired: React.FunctionComponent = () => ( diff --git a/packages/react-core/src/components/DescriptionList/DescriptionList.tsx b/packages/react-core/src/components/DescriptionList/DescriptionList.tsx index 5296f58db60..1e957c597e9 100644 --- a/packages/react-core/src/components/DescriptionList/DescriptionList.tsx +++ b/packages/react-core/src/components/DescriptionList/DescriptionList.tsx @@ -1,15 +1,10 @@ -import * as React from 'react'; import { css } from '@patternfly/react-styles'; import styles from '@patternfly/react-styles/css/components/DescriptionList/description-list'; import { formatBreakpointMods } from '../../helpers'; import cssGridTemplateColumnsMin from '@patternfly/react-tokens/dist/esm/c_description_list_GridTemplateColumns_min'; -// import cssTermWidth from '@patternfly/react-tokens/dist/esm/c_description_list__term_width'; +import cssTermWidth from '@patternfly/react-tokens/dist/esm/c_description_list__term_width'; import cssHorizontalTermWidth from '@patternfly/react-tokens/dist/esm/c_description_list_m_horizontal__term_width'; -const cssTermWidth = { - name: '--pf-v5-c-description-list__term-width' -}; - export interface BreakpointModifiers { default?: string; md?: string; diff --git a/packages/react-core/src/components/DescriptionList/DescriptionListDescription.tsx b/packages/react-core/src/components/DescriptionList/DescriptionListDescription.tsx index 205c0ea3268..cb37fdf71c6 100644 --- a/packages/react-core/src/components/DescriptionList/DescriptionListDescription.tsx +++ b/packages/react-core/src/components/DescriptionList/DescriptionListDescription.tsx @@ -1,4 +1,3 @@ -import * as React from 'react'; import styles from '@patternfly/react-styles/css/components/DescriptionList/description-list'; import { css } from '@patternfly/react-styles'; diff --git a/packages/react-core/src/components/DescriptionList/DescriptionListGroup.tsx b/packages/react-core/src/components/DescriptionList/DescriptionListGroup.tsx index 3828d225654..1d4b54a3529 100644 --- a/packages/react-core/src/components/DescriptionList/DescriptionListGroup.tsx +++ b/packages/react-core/src/components/DescriptionList/DescriptionListGroup.tsx @@ -1,4 +1,3 @@ -import * as React from 'react'; import styles from '@patternfly/react-styles/css/components/DescriptionList/description-list'; import { css } from '@patternfly/react-styles'; diff --git a/packages/react-core/src/components/DescriptionList/DescriptionListTerm.tsx b/packages/react-core/src/components/DescriptionList/DescriptionListTerm.tsx index 459edee63ce..3536e485dd8 100644 --- a/packages/react-core/src/components/DescriptionList/DescriptionListTerm.tsx +++ b/packages/react-core/src/components/DescriptionList/DescriptionListTerm.tsx @@ -1,4 +1,3 @@ -import * as React from 'react'; import styles from '@patternfly/react-styles/css/components/DescriptionList/description-list'; import { css } from '@patternfly/react-styles'; diff --git a/packages/react-core/src/components/DescriptionList/DescriptionListTermHelpText.tsx b/packages/react-core/src/components/DescriptionList/DescriptionListTermHelpText.tsx index cf273a9d504..2a21d37b9a2 100644 --- a/packages/react-core/src/components/DescriptionList/DescriptionListTermHelpText.tsx +++ b/packages/react-core/src/components/DescriptionList/DescriptionListTermHelpText.tsx @@ -1,4 +1,3 @@ -import * as React from 'react'; import styles from '@patternfly/react-styles/css/components/DescriptionList/description-list'; import { css } from '@patternfly/react-styles'; diff --git a/packages/react-core/src/components/DescriptionList/DescriptionListTermHelpTextButton.tsx b/packages/react-core/src/components/DescriptionList/DescriptionListTermHelpTextButton.tsx index cff5753ad72..6950498d2e9 100644 --- a/packages/react-core/src/components/DescriptionList/DescriptionListTermHelpTextButton.tsx +++ b/packages/react-core/src/components/DescriptionList/DescriptionListTermHelpTextButton.tsx @@ -1,4 +1,4 @@ -import * as React from 'react'; +import { createRef } from 'react'; import styles from '@patternfly/react-styles/css/components/DescriptionList/description-list'; import { css } from '@patternfly/react-styles'; @@ -13,15 +13,33 @@ export const DescriptionListTermHelpTextButton: React.FunctionComponent ( - - {children} - -); +}: DescriptionListTermHelpTextButtonProps) => { + const helpTextRef = createRef(); + + const handleKeys = (event: React.KeyboardEvent) => { + if (!helpTextRef.current || helpTextRef.current !== (event.target as HTMLElement)) { + return; + } + + const key = event.key; + if (key === 'Enter' || key === ' ') { + event.preventDefault(); + helpTextRef.current.click(); + } + }; + + return ( + handleKeys(event)} + {...props} + > + {children} + + ); +}; DescriptionListTermHelpTextButton.displayName = 'DescriptionListTermHelpTextButton'; diff --git a/packages/react-core/src/components/DescriptionList/__tests__/DescriptionList.test.tsx b/packages/react-core/src/components/DescriptionList/__tests__/DescriptionList.test.tsx index 02e2177a173..7b344c1b739 100644 --- a/packages/react-core/src/components/DescriptionList/__tests__/DescriptionList.test.tsx +++ b/packages/react-core/src/components/DescriptionList/__tests__/DescriptionList.test.tsx @@ -1,4 +1,3 @@ -import React from 'react'; import { render, screen } from '@testing-library/react'; import { DescriptionList } from '../DescriptionList'; @@ -124,21 +123,21 @@ test(`Renders style when isHorizontal and horizontalTermWidthModifier is set`, ( }} /> ); - expect(screen.getByLabelText('list')).toHaveStyle({ - '--pf-v6-c-description-list--m-horizontal__term--width': '12ch', - '--pf-v6-c-description-list--m-horizontal__term--width-on-sm': '15ch', - '--pf-v6-c-description-list--m-horizontal__term--width-on-md': '20ch', - '--pf-v6-c-description-list--m-horizontal__term--width-on-lg': '28ch', - '--pf-v6-c-description-list--m-horizontal__term--width-on-xl': '30ch', - '--pf-v6-c-description-list--m-horizontal__term--width-on-2xl': '35ch' - }); + const listStyles = {}; + listStyles[`--${styles.descriptionList}--m-horizontal__term--width`] = '12ch'; + listStyles[`--${styles.descriptionList}--m-horizontal__term--width-on-sm`] = '15ch'; + listStyles[`--${styles.descriptionList}--m-horizontal__term--width-on-md`] = '20ch'; + listStyles[`--${styles.descriptionList}--m-horizontal__term--width-on-lg`] = '28ch'; + listStyles[`--${styles.descriptionList}--m-horizontal__term--width-on-xl`] = '30ch'; + listStyles[`--${styles.descriptionList}--m-horizontal__term--width-on-2xl`] = '35ch'; + expect(screen.getByLabelText('list')).toHaveStyle(listStyles); }); -test.skip(`Renders style when termWidth is set`, () => { +test(`Renders style when termWidth is set`, () => { render(); - expect(screen.getByLabelText('list')).toHaveStyle({ - '--pf-v5-c-description-list__term--width': '30px' - }); + const listStyles = {}; + listStyles[`--${styles.descriptionList}__term--width`] = '30px'; + expect(screen.getByLabelText('list')).toHaveStyle(listStyles); }); test(`Renders style when isAutoFit and horizontalTermWidthModifier is set`, () => { @@ -149,8 +148,10 @@ test(`Renders style when isAutoFit and horizontalTermWidthModifier is set`, () = autoFitMinModifier={{ default: '50px', sm: '50px', md: '100px', lg: '150px', xl: '200px', '2xl': '300px' }} /> ); + const listStyles = {}; + expect(screen.getByLabelText('list')).toHaveAttribute( 'style', - '--pf-v6-c-description-list--GridTemplateColumns--min: 50px; --pf-v6-c-description-list--GridTemplateColumns--min-on-sm: 50px; --pf-v6-c-description-list--GridTemplateColumns--min-on-md: 100px; --pf-v6-c-description-list--GridTemplateColumns--min-on-lg: 150px; --pf-v6-c-description-list--GridTemplateColumns--min-on-xl: 200px; --pf-v6-c-description-list--GridTemplateColumns--min-on-2xl: 300px;' + `--${styles.descriptionList}--GridTemplateColumns--min: 50px; --${styles.descriptionList}--GridTemplateColumns--min-on-sm: 50px; --${styles.descriptionList}--GridTemplateColumns--min-on-md: 100px; --${styles.descriptionList}--GridTemplateColumns--min-on-lg: 150px; --${styles.descriptionList}--GridTemplateColumns--min-on-xl: 200px; --${styles.descriptionList}--GridTemplateColumns--min-on-2xl: 300px;` ); }); diff --git a/packages/react-core/src/components/DescriptionList/__tests__/DescriptionListDescription.test.tsx b/packages/react-core/src/components/DescriptionList/__tests__/DescriptionListDescription.test.tsx index 65367307167..e18009a2604 100644 --- a/packages/react-core/src/components/DescriptionList/__tests__/DescriptionListDescription.test.tsx +++ b/packages/react-core/src/components/DescriptionList/__tests__/DescriptionListDescription.test.tsx @@ -1,4 +1,3 @@ -import React from 'react'; import { render, screen } from '@testing-library/react'; import { DescriptionListDescription } from '../DescriptionListDescription'; diff --git a/packages/react-core/src/components/DescriptionList/__tests__/DescriptionListGroup.test.tsx b/packages/react-core/src/components/DescriptionList/__tests__/DescriptionListGroup.test.tsx index 53e84b545ff..18e07ca68b9 100644 --- a/packages/react-core/src/components/DescriptionList/__tests__/DescriptionListGroup.test.tsx +++ b/packages/react-core/src/components/DescriptionList/__tests__/DescriptionListGroup.test.tsx @@ -1,4 +1,3 @@ -import React from 'react'; import { render, screen } from '@testing-library/react'; import { DescriptionListGroup } from '../DescriptionListGroup'; diff --git a/packages/react-core/src/components/DescriptionList/__tests__/DescriptionListHelpTextButton.test.tsx b/packages/react-core/src/components/DescriptionList/__tests__/DescriptionListHelpTextButton.test.tsx index bb49c585450..120279c6fda 100644 --- a/packages/react-core/src/components/DescriptionList/__tests__/DescriptionListHelpTextButton.test.tsx +++ b/packages/react-core/src/components/DescriptionList/__tests__/DescriptionListHelpTextButton.test.tsx @@ -1,4 +1,3 @@ -import React from 'react'; import { render, screen } from '@testing-library/react'; import { DescriptionListTermHelpTextButton } from '../DescriptionListTermHelpTextButton'; diff --git a/packages/react-core/src/components/DescriptionList/__tests__/DescriptionListTerm.test.tsx b/packages/react-core/src/components/DescriptionList/__tests__/DescriptionListTerm.test.tsx index 840db5199ea..173ba1bf4c0 100644 --- a/packages/react-core/src/components/DescriptionList/__tests__/DescriptionListTerm.test.tsx +++ b/packages/react-core/src/components/DescriptionList/__tests__/DescriptionListTerm.test.tsx @@ -1,4 +1,3 @@ -import React from 'react'; import { render, screen } from '@testing-library/react'; import { DescriptionListTerm } from '../DescriptionListTerm'; diff --git a/packages/react-core/src/components/DescriptionList/__tests__/DescriptionListTermHelpText.test.tsx b/packages/react-core/src/components/DescriptionList/__tests__/DescriptionListTermHelpText.test.tsx index 1bd9779d379..27acbaf3d93 100644 --- a/packages/react-core/src/components/DescriptionList/__tests__/DescriptionListTermHelpText.test.tsx +++ b/packages/react-core/src/components/DescriptionList/__tests__/DescriptionListTermHelpText.test.tsx @@ -1,4 +1,3 @@ -import React from 'react'; import { render, screen } from '@testing-library/react'; import { DescriptionListTermHelpText } from '../DescriptionListTermHelpText'; diff --git a/packages/react-core/src/components/DescriptionList/examples/DescriptionList.md b/packages/react-core/src/components/DescriptionList/examples/DescriptionList.md index 2ee797d10a4..c867f452e13 100644 --- a/packages/react-core/src/components/DescriptionList/examples/DescriptionList.md +++ b/packages/react-core/src/components/DescriptionList/examples/DescriptionList.md @@ -1,7 +1,7 @@ --- id: 'Description list' section: components -cssPrefix: 'pf-v5-c-description-list' +cssPrefix: 'pf-v6-c-description-list' propComponents: [ 'DescriptionList', @@ -15,13 +15,14 @@ propComponents: ] --- +import { useState } from 'react'; import { Button, DescriptionList, DescriptionListTerm, DescriptionListDescription, DescriptionListGroup, DescriptionListTermHelpText, DescriptionListTermHelpTextButton, Popover, Checkbox, Card } from '@patternfly/react-core'; -import PlusCircleIcon from '@patternfly/react-icons/dist/esm/icons/plus-circle-icon'; +import RhUiAddCircleFillIcon from '@patternfly/react-icons/dist/esm/icons/rh-ui-add-circle-fill-icon'; import CubeIcon from '@patternfly/react-icons/dist/esm/icons/cube-icon'; import BookIcon from '@patternfly/react-icons/dist/esm/icons/book-icon'; import KeyIcon from '@patternfly/react-icons/dist/esm/icons/key-icon'; -import GlobeIcon from '@patternfly/react-icons/dist/esm/icons/globe-icon'; -import FlagIcon from '@patternfly/react-icons/dist/esm/icons/flag-icon'; +import RhUiFlagFillIcon from '@patternfly/react-icons/dist/esm/icons/rh-ui-flag-fill-icon'; +import RhUiLanguageFillIcon from '@patternfly/react-icons/dist/esm/icons/rh-ui-language-fill-icon'; ## Examples diff --git a/packages/react-core/src/components/DescriptionList/examples/DescriptionListAutoFitBasic.tsx b/packages/react-core/src/components/DescriptionList/examples/DescriptionListAutoFitBasic.tsx index 350ce0c3244..bfd0fda2a9b 100644 --- a/packages/react-core/src/components/DescriptionList/examples/DescriptionListAutoFitBasic.tsx +++ b/packages/react-core/src/components/DescriptionList/examples/DescriptionListAutoFitBasic.tsx @@ -1,4 +1,3 @@ -import React from 'react'; import { Button, DescriptionList, @@ -6,10 +5,10 @@ import { DescriptionListGroup, DescriptionListDescription } from '@patternfly/react-core'; -import PlusCircleIcon from '@patternfly/react-icons/dist/esm/icons/plus-circle-icon'; +import RhUiAddCircleFillIcon from '@patternfly/react-icons/dist/esm/icons/rh-ui-add-circle-fill-icon'; export const DescriptionListAutoFitBasic: React.FunctionComponent = () => ( - + Name example @@ -27,7 +26,7 @@ export const DescriptionListAutoFitBasic: React.FunctionComponent = () => ( Pod selector - diff --git a/packages/react-core/src/components/DescriptionList/examples/DescriptionListAutoFitMinWidthModified.tsx b/packages/react-core/src/components/DescriptionList/examples/DescriptionListAutoFitMinWidthModified.tsx index a9a7f930f60..d5d975f0594 100644 --- a/packages/react-core/src/components/DescriptionList/examples/DescriptionListAutoFitMinWidthModified.tsx +++ b/packages/react-core/src/components/DescriptionList/examples/DescriptionListAutoFitMinWidthModified.tsx @@ -1,4 +1,3 @@ -import React from 'react'; import { Button, DescriptionList, @@ -6,10 +5,14 @@ import { DescriptionListGroup, DescriptionListDescription } from '@patternfly/react-core'; -import PlusCircleIcon from '@patternfly/react-icons/dist/esm/icons/plus-circle-icon'; +import RhUiAddCircleFillIcon from '@patternfly/react-icons/dist/esm/icons/rh-ui-add-circle-fill-icon'; export const DescriptionListAutoFitMinWidthModified: React.FunctionComponent = () => ( - + Name example @@ -27,7 +30,7 @@ export const DescriptionListAutoFitMinWidthModified: React.FunctionComponent = ( Pod selector - diff --git a/packages/react-core/src/components/DescriptionList/examples/DescriptionListAutoFitMinWidthResponsive.tsx b/packages/react-core/src/components/DescriptionList/examples/DescriptionListAutoFitMinWidthResponsive.tsx index c6a6baf0967..90102a75d18 100644 --- a/packages/react-core/src/components/DescriptionList/examples/DescriptionListAutoFitMinWidthResponsive.tsx +++ b/packages/react-core/src/components/DescriptionList/examples/DescriptionListAutoFitMinWidthResponsive.tsx @@ -1,4 +1,3 @@ -import React from 'react'; import { Button, DescriptionList, @@ -6,10 +5,14 @@ import { DescriptionListGroup, DescriptionListDescription } from '@patternfly/react-core'; -import PlusCircleIcon from '@patternfly/react-icons/dist/esm/icons/plus-circle-icon'; +import RhUiAddCircleFillIcon from '@patternfly/react-icons/dist/esm/icons/rh-ui-add-circle-fill-icon'; export const DescriptionListAutoFitMinWidthResponsive: React.FunctionComponent = () => ( - + Name example @@ -27,7 +30,7 @@ export const DescriptionListAutoFitMinWidthResponsive: React.FunctionComponent = Pod selector - diff --git a/packages/react-core/src/components/DescriptionList/examples/DescriptionListBasic.tsx b/packages/react-core/src/components/DescriptionList/examples/DescriptionListBasic.tsx index 2e757d7c134..a23519f6478 100644 --- a/packages/react-core/src/components/DescriptionList/examples/DescriptionListBasic.tsx +++ b/packages/react-core/src/components/DescriptionList/examples/DescriptionListBasic.tsx @@ -1,4 +1,3 @@ -import React from 'react'; import { Button, DescriptionList, @@ -6,10 +5,10 @@ import { DescriptionListGroup, DescriptionListDescription } from '@patternfly/react-core'; -import PlusCircleIcon from '@patternfly/react-icons/dist/esm/icons/plus-circle-icon'; +import RhUiAddCircleFillIcon from '@patternfly/react-icons/dist/esm/icons/rh-ui-add-circle-fill-icon'; export const DescriptionListBasic: React.FunctionComponent = () => ( - + Name Example @@ -27,7 +26,7 @@ export const DescriptionListBasic: React.FunctionComponent = () => ( Pod selector - diff --git a/packages/react-core/src/components/DescriptionList/examples/DescriptionListColumnFill.tsx b/packages/react-core/src/components/DescriptionList/examples/DescriptionListColumnFill.tsx index 4130504079d..041942713d2 100644 --- a/packages/react-core/src/components/DescriptionList/examples/DescriptionListColumnFill.tsx +++ b/packages/react-core/src/components/DescriptionList/examples/DescriptionListColumnFill.tsx @@ -1,4 +1,3 @@ -import React from 'react'; import { Button, DescriptionList, @@ -6,10 +5,10 @@ import { DescriptionListGroup, DescriptionListDescription } from '@patternfly/react-core'; -import PlusCircleIcon from '@patternfly/react-icons/dist/esm/icons/plus-circle-icon'; +import RhUiAddCircleFillIcon from '@patternfly/react-icons/dist/esm/icons/rh-ui-add-circle-fill-icon'; export const DescriptionListColumnFill: React.FunctionComponent = () => ( - + Name @@ -29,7 +28,7 @@ export const DescriptionListColumnFill: React.FunctionComponent = () => ( Pod selector - diff --git a/packages/react-core/src/components/DescriptionList/examples/DescriptionListCompact.tsx b/packages/react-core/src/components/DescriptionList/examples/DescriptionListCompact.tsx index b88b87a1dce..dcd0a6a1d45 100644 --- a/packages/react-core/src/components/DescriptionList/examples/DescriptionListCompact.tsx +++ b/packages/react-core/src/components/DescriptionList/examples/DescriptionListCompact.tsx @@ -1,4 +1,3 @@ -import React from 'react'; import { Button, DescriptionList, @@ -6,10 +5,10 @@ import { DescriptionListGroup, DescriptionListDescription } from '@patternfly/react-core'; -import PlusCircleIcon from '@patternfly/react-icons/dist/esm/icons/plus-circle-icon'; +import RhUiAddCircleFillIcon from '@patternfly/react-icons/dist/esm/icons/rh-ui-add-circle-fill-icon'; export const DescriptionListCompact: React.FunctionComponent = () => ( - + Name Example @@ -27,7 +26,7 @@ export const DescriptionListCompact: React.FunctionComponent = () => ( Pod selector - diff --git a/packages/react-core/src/components/DescriptionList/examples/DescriptionListCompactHorizontal.tsx b/packages/react-core/src/components/DescriptionList/examples/DescriptionListCompactHorizontal.tsx index 9f830d4dc11..7d2781b1dc4 100644 --- a/packages/react-core/src/components/DescriptionList/examples/DescriptionListCompactHorizontal.tsx +++ b/packages/react-core/src/components/DescriptionList/examples/DescriptionListCompactHorizontal.tsx @@ -1,4 +1,3 @@ -import React from 'react'; import { Button, DescriptionList, @@ -6,10 +5,10 @@ import { DescriptionListGroup, DescriptionListDescription } from '@patternfly/react-core'; -import PlusCircleIcon from '@patternfly/react-icons/dist/esm/icons/plus-circle-icon'; +import RhUiAddCircleFillIcon from '@patternfly/react-icons/dist/esm/icons/rh-ui-add-circle-fill-icon'; export const DescriptionListCompactHorizontal: React.FunctionComponent = () => ( - + Name Example @@ -27,7 +26,7 @@ export const DescriptionListCompactHorizontal: React.FunctionComponent = () => ( Pod selector - diff --git a/packages/react-core/src/components/DescriptionList/examples/DescriptionListDefaultAutoColumn.tsx b/packages/react-core/src/components/DescriptionList/examples/DescriptionListDefaultAutoColumn.tsx index faafefab01b..f9ccbdd4366 100644 --- a/packages/react-core/src/components/DescriptionList/examples/DescriptionListDefaultAutoColumn.tsx +++ b/packages/react-core/src/components/DescriptionList/examples/DescriptionListDefaultAutoColumn.tsx @@ -1,4 +1,3 @@ -import React from 'react'; import { Button, DescriptionList, @@ -6,10 +5,10 @@ import { DescriptionListGroup, DescriptionListDescription } from '@patternfly/react-core'; -import PlusCircleIcon from '@patternfly/react-icons/dist/esm/icons/plus-circle-icon'; +import RhUiAddCircleFillIcon from '@patternfly/react-icons/dist/esm/icons/rh-ui-add-circle-fill-icon'; export const DescriptionListDefaultAutoColumn: React.FunctionComponent = () => ( - + Name Example @@ -27,7 +26,7 @@ export const DescriptionListDefaultAutoColumn: React.FunctionComponent = () => ( Pod selector - diff --git a/packages/react-core/src/components/DescriptionList/examples/DescriptionListDefaultInlineGrid.tsx b/packages/react-core/src/components/DescriptionList/examples/DescriptionListDefaultInlineGrid.tsx index f7efc50cf19..463a7abd294 100644 --- a/packages/react-core/src/components/DescriptionList/examples/DescriptionListDefaultInlineGrid.tsx +++ b/packages/react-core/src/components/DescriptionList/examples/DescriptionListDefaultInlineGrid.tsx @@ -1,4 +1,3 @@ -import React from 'react'; import { Button, DescriptionList, @@ -6,10 +5,10 @@ import { DescriptionListGroup, DescriptionListDescription } from '@patternfly/react-core'; -import PlusCircleIcon from '@patternfly/react-icons/dist/esm/icons/plus-circle-icon'; +import RhUiAddCircleFillIcon from '@patternfly/react-icons/dist/esm/icons/rh-ui-add-circle-fill-icon'; export const DescriptionListDefaultInlineGrid: React.FunctionComponent = () => ( - + Name Example @@ -27,7 +26,7 @@ export const DescriptionListDefaultInlineGrid: React.FunctionComponent = () => ( Pod selector - diff --git a/packages/react-core/src/components/DescriptionList/examples/DescriptionListDefaultResponsiveColumns.tsx b/packages/react-core/src/components/DescriptionList/examples/DescriptionListDefaultResponsiveColumns.tsx index 62831bc0a1b..6c6060a734a 100644 --- a/packages/react-core/src/components/DescriptionList/examples/DescriptionListDefaultResponsiveColumns.tsx +++ b/packages/react-core/src/components/DescriptionList/examples/DescriptionListDefaultResponsiveColumns.tsx @@ -1,4 +1,3 @@ -import React from 'react'; import { Button, DescriptionList, @@ -6,10 +5,10 @@ import { DescriptionListGroup, DescriptionListDescription } from '@patternfly/react-core'; -import PlusCircleIcon from '@patternfly/react-icons/dist/esm/icons/plus-circle-icon'; +import RhUiAddCircleFillIcon from '@patternfly/react-icons/dist/esm/icons/rh-ui-add-circle-fill-icon'; export const DescriptionListDefaultResponsiveColumns: React.FunctionComponent = () => ( - + Name Example @@ -27,7 +26,7 @@ export const DescriptionListDefaultResponsiveColumns: React.FunctionComponent = Pod selector - diff --git a/packages/react-core/src/components/DescriptionList/examples/DescriptionListDefaultThreeColLg.tsx b/packages/react-core/src/components/DescriptionList/examples/DescriptionListDefaultThreeColLg.tsx index 06e60b06979..13cfdded80f 100644 --- a/packages/react-core/src/components/DescriptionList/examples/DescriptionListDefaultThreeColLg.tsx +++ b/packages/react-core/src/components/DescriptionList/examples/DescriptionListDefaultThreeColLg.tsx @@ -1,4 +1,3 @@ -import React from 'react'; import { Button, DescriptionList, @@ -6,10 +5,10 @@ import { DescriptionListGroup, DescriptionListDescription } from '@patternfly/react-core'; -import PlusCircleIcon from '@patternfly/react-icons/dist/esm/icons/plus-circle-icon'; +import RhUiAddCircleFillIcon from '@patternfly/react-icons/dist/esm/icons/rh-ui-add-circle-fill-icon'; export const DescriptionListDefaultThreeColLg: React.FunctionComponent = () => ( - + Name Example @@ -27,7 +26,7 @@ export const DescriptionListDefaultThreeColLg: React.FunctionComponent = () => ( Pod selector - diff --git a/packages/react-core/src/components/DescriptionList/examples/DescriptionListDefaultTwoCol.tsx b/packages/react-core/src/components/DescriptionList/examples/DescriptionListDefaultTwoCol.tsx index a06a0d48aac..cc57b073d37 100644 --- a/packages/react-core/src/components/DescriptionList/examples/DescriptionListDefaultTwoCol.tsx +++ b/packages/react-core/src/components/DescriptionList/examples/DescriptionListDefaultTwoCol.tsx @@ -1,4 +1,3 @@ -import React from 'react'; import { Button, DescriptionList, @@ -6,13 +5,14 @@ import { DescriptionListGroup, DescriptionListDescription } from '@patternfly/react-core'; -import PlusCircleIcon from '@patternfly/react-icons/dist/esm/icons/plus-circle-icon'; +import RhUiAddCircleFillIcon from '@patternfly/react-icons/dist/esm/icons/rh-ui-add-circle-fill-icon'; export const DescriptionListDefaultTwoCol: React.FunctionComponent = () => ( Name @@ -31,7 +31,7 @@ export const DescriptionListDefaultTwoCol: React.FunctionComponent = () => ( Pod selector - diff --git a/packages/react-core/src/components/DescriptionList/examples/DescriptionListDisplaySizeAndCardHorizontalTermWidth.tsx b/packages/react-core/src/components/DescriptionList/examples/DescriptionListDisplaySizeAndCardHorizontalTermWidth.tsx index 0c9a0ca430b..eedfa6ad336 100644 --- a/packages/react-core/src/components/DescriptionList/examples/DescriptionListDisplaySizeAndCardHorizontalTermWidth.tsx +++ b/packages/react-core/src/components/DescriptionList/examples/DescriptionListDisplaySizeAndCardHorizontalTermWidth.tsx @@ -1,9 +1,14 @@ -import React from 'react'; import { Button, DescriptionList, DescriptionListTerm, DescriptionListDescription, Card } from '@patternfly/react-core'; -import PlusCircleIcon from '@patternfly/react-icons/dist/esm/icons/plus-circle-icon'; +import RhUiAddCircleFillIcon from '@patternfly/react-icons/dist/esm/icons/rh-ui-add-circle-fill-icon'; export const DescriptionListDisplaySizeAndCardHorizontalTermWidth: React.FunctionComponent = () => ( - + Name Example @@ -21,7 +26,7 @@ export const DescriptionListDisplaySizeAndCardHorizontalTermWidth: React.Functio Pod selector - diff --git a/packages/react-core/src/components/DescriptionList/examples/DescriptionListDisplaySizeAndCardThreeColumn.tsx b/packages/react-core/src/components/DescriptionList/examples/DescriptionListDisplaySizeAndCardThreeColumn.tsx index a54c675e8e0..da2685ff06b 100644 --- a/packages/react-core/src/components/DescriptionList/examples/DescriptionListDisplaySizeAndCardThreeColumn.tsx +++ b/packages/react-core/src/components/DescriptionList/examples/DescriptionListDisplaySizeAndCardThreeColumn.tsx @@ -1,9 +1,12 @@ -import React from 'react'; import { Button, DescriptionList, DescriptionListTerm, DescriptionListDescription, Card } from '@patternfly/react-core'; -import PlusCircleIcon from '@patternfly/react-icons/dist/esm/icons/plus-circle-icon'; +import RhUiAddCircleFillIcon from '@patternfly/react-icons/dist/esm/icons/rh-ui-add-circle-fill-icon'; export const DescriptionListDisplayLgAndCardThreeColumn: React.FunctionComponent = () => ( - + Name Example @@ -21,7 +24,7 @@ export const DescriptionListDisplayLgAndCardThreeColumn: React.FunctionComponent Pod selector - diff --git a/packages/react-core/src/components/DescriptionList/examples/DescriptionListFluidHorizontal.tsx b/packages/react-core/src/components/DescriptionList/examples/DescriptionListFluidHorizontal.tsx index 152d4142490..e3e6c97325c 100644 --- a/packages/react-core/src/components/DescriptionList/examples/DescriptionListFluidHorizontal.tsx +++ b/packages/react-core/src/components/DescriptionList/examples/DescriptionListFluidHorizontal.tsx @@ -1,4 +1,3 @@ -import React from 'react'; import { Button, DescriptionList, @@ -6,10 +5,10 @@ import { DescriptionListGroup, DescriptionListDescription } from '@patternfly/react-core'; -import PlusCircleIcon from '@patternfly/react-icons/dist/esm/icons/plus-circle-icon'; +import RhUiAddCircleFillIcon from '@patternfly/react-icons/dist/esm/icons/rh-ui-add-circle-fill-icon'; export const DescriptionListFluidHorizontal: React.FunctionComponent = () => ( - + Name Example @@ -27,7 +26,7 @@ export const DescriptionListFluidHorizontal: React.FunctionComponent = () => ( Pod selector - diff --git a/packages/react-core/src/components/DescriptionList/examples/DescriptionListHorizontal.tsx b/packages/react-core/src/components/DescriptionList/examples/DescriptionListHorizontal.tsx index 9ef28e516af..c36d0170b2b 100644 --- a/packages/react-core/src/components/DescriptionList/examples/DescriptionListHorizontal.tsx +++ b/packages/react-core/src/components/DescriptionList/examples/DescriptionListHorizontal.tsx @@ -1,4 +1,3 @@ -import React from 'react'; import { Button, DescriptionList, @@ -6,10 +5,10 @@ import { DescriptionListGroup, DescriptionListDescription } from '@patternfly/react-core'; -import PlusCircleIcon from '@patternfly/react-icons/dist/esm/icons/plus-circle-icon'; +import RhUiAddCircleFillIcon from '@patternfly/react-icons/dist/esm/icons/rh-ui-add-circle-fill-icon'; export const DescriptionListHorizontal: React.FunctionComponent = () => ( - + Name Example @@ -27,7 +26,7 @@ export const DescriptionListHorizontal: React.FunctionComponent = () => ( Pod selector - diff --git a/packages/react-core/src/components/DescriptionList/examples/DescriptionListHorizontalAutoColumn.tsx b/packages/react-core/src/components/DescriptionList/examples/DescriptionListHorizontalAutoColumn.tsx index 28c76e77467..12699d16a82 100644 --- a/packages/react-core/src/components/DescriptionList/examples/DescriptionListHorizontalAutoColumn.tsx +++ b/packages/react-core/src/components/DescriptionList/examples/DescriptionListHorizontalAutoColumn.tsx @@ -1,4 +1,3 @@ -import React from 'react'; import { Button, DescriptionList, @@ -6,10 +5,15 @@ import { DescriptionListGroup, DescriptionListDescription } from '@patternfly/react-core'; -import PlusCircleIcon from '@patternfly/react-icons/dist/esm/icons/plus-circle-icon'; +import RhUiAddCircleFillIcon from '@patternfly/react-icons/dist/esm/icons/rh-ui-add-circle-fill-icon'; export const DescriptionListHorizontalAutoColumn: React.FunctionComponent = () => ( - + Name Example @@ -27,7 +31,7 @@ export const DescriptionListHorizontalAutoColumn: React.FunctionComponent = () = Pod selector - diff --git a/packages/react-core/src/components/DescriptionList/examples/DescriptionListHorizontalCustomTermWidth.tsx b/packages/react-core/src/components/DescriptionList/examples/DescriptionListHorizontalCustomTermWidth.tsx index 888cc033939..e3308dd6d59 100644 --- a/packages/react-core/src/components/DescriptionList/examples/DescriptionListHorizontalCustomTermWidth.tsx +++ b/packages/react-core/src/components/DescriptionList/examples/DescriptionListHorizontalCustomTermWidth.tsx @@ -1,4 +1,3 @@ -import React from 'react'; import { Button, DescriptionList, @@ -6,7 +5,7 @@ import { DescriptionListGroup, DescriptionListDescription } from '@patternfly/react-core'; -import PlusCircleIcon from '@patternfly/react-icons/dist/esm/icons/plus-circle-icon'; +import RhUiAddCircleFillIcon from '@patternfly/react-icons/dist/esm/icons/rh-ui-add-circle-fill-icon'; export const DescriptionListHorizontalCustomTermWidth: React.FunctionComponent = () => ( Name longer than the default term width @@ -37,7 +37,7 @@ export const DescriptionListHorizontalCustomTermWidth: React.FunctionComponent = Pod selector - diff --git a/packages/react-core/src/components/DescriptionList/examples/DescriptionListHorizontalResponsiveColumns.tsx b/packages/react-core/src/components/DescriptionList/examples/DescriptionListHorizontalResponsiveColumns.tsx index 22f77d4cabd..be578e313a3 100644 --- a/packages/react-core/src/components/DescriptionList/examples/DescriptionListHorizontalResponsiveColumns.tsx +++ b/packages/react-core/src/components/DescriptionList/examples/DescriptionListHorizontalResponsiveColumns.tsx @@ -1,4 +1,3 @@ -import React from 'react'; import { Button, DescriptionList, @@ -6,10 +5,10 @@ import { DescriptionListGroup, DescriptionListDescription } from '@patternfly/react-core'; -import PlusCircleIcon from '@patternfly/react-icons/dist/esm/icons/plus-circle-icon'; +import RhUiAddCircleFillIcon from '@patternfly/react-icons/dist/esm/icons/rh-ui-add-circle-fill-icon'; export const DescriptionListHorizontalResponsiveColumns: React.FunctionComponent = () => ( - + Name Example @@ -27,7 +26,7 @@ export const DescriptionListHorizontalResponsiveColumns: React.FunctionComponent Pod selector - diff --git a/packages/react-core/src/components/DescriptionList/examples/DescriptionListHorizontalThreeColLg.tsx b/packages/react-core/src/components/DescriptionList/examples/DescriptionListHorizontalThreeColLg.tsx index a582b4dfaca..20a6585dcab 100644 --- a/packages/react-core/src/components/DescriptionList/examples/DescriptionListHorizontalThreeColLg.tsx +++ b/packages/react-core/src/components/DescriptionList/examples/DescriptionListHorizontalThreeColLg.tsx @@ -1,4 +1,3 @@ -import React from 'react'; import { Button, DescriptionList, @@ -6,10 +5,10 @@ import { DescriptionListGroup, DescriptionListDescription } from '@patternfly/react-core'; -import PlusCircleIcon from '@patternfly/react-icons/dist/esm/icons/plus-circle-icon'; +import RhUiAddCircleFillIcon from '@patternfly/react-icons/dist/esm/icons/rh-ui-add-circle-fill-icon'; export const DescriptionListHorizontalThreeColLg: React.FunctionComponent = () => ( - + Name Example @@ -27,7 +26,7 @@ export const DescriptionListHorizontalThreeColLg: React.FunctionComponent = () = Pod selector - diff --git a/packages/react-core/src/components/DescriptionList/examples/DescriptionListHorizontalTwoCol.tsx b/packages/react-core/src/components/DescriptionList/examples/DescriptionListHorizontalTwoCol.tsx index 3e43bf50592..9276f1002c0 100644 --- a/packages/react-core/src/components/DescriptionList/examples/DescriptionListHorizontalTwoCol.tsx +++ b/packages/react-core/src/components/DescriptionList/examples/DescriptionListHorizontalTwoCol.tsx @@ -1,4 +1,3 @@ -import React from 'react'; import { Button, DescriptionList, @@ -6,10 +5,10 @@ import { DescriptionListGroup, DescriptionListDescription } from '@patternfly/react-core'; -import PlusCircleIcon from '@patternfly/react-icons/dist/esm/icons/plus-circle-icon'; +import RhUiAddCircleFillIcon from '@patternfly/react-icons/dist/esm/icons/rh-ui-add-circle-fill-icon'; export const DescriptionListHorizontalTwoCol: React.FunctionComponent = () => ( - + Name Example @@ -27,7 +26,7 @@ export const DescriptionListHorizontalTwoCol: React.FunctionComponent = () => ( Pod selector - diff --git a/packages/react-core/src/components/DescriptionList/examples/DescriptionListIconsOnTerms.tsx b/packages/react-core/src/components/DescriptionList/examples/DescriptionListIconsOnTerms.tsx index 98d896285f9..4dd55fdbe76 100644 --- a/packages/react-core/src/components/DescriptionList/examples/DescriptionListIconsOnTerms.tsx +++ b/packages/react-core/src/components/DescriptionList/examples/DescriptionListIconsOnTerms.tsx @@ -1,4 +1,3 @@ -import React from 'react'; import { Button, DescriptionList, @@ -6,15 +5,15 @@ import { DescriptionListGroup, DescriptionListDescription } from '@patternfly/react-core'; -import PlusCircleIcon from '@patternfly/react-icons/dist/esm/icons/plus-circle-icon'; +import RhUiAddCircleFillIcon from '@patternfly/react-icons/dist/esm/icons/rh-ui-add-circle-fill-icon'; import CubeIcon from '@patternfly/react-icons/dist/esm/icons/cube-icon'; import BookIcon from '@patternfly/react-icons/dist/esm/icons/book-icon'; import KeyIcon from '@patternfly/react-icons/dist/esm/icons/key-icon'; -import GlobeIcon from '@patternfly/react-icons/dist/esm/icons/globe-icon'; -import FlagIcon from '@patternfly/react-icons/dist/esm/icons/flag-icon'; +import RhUiFlagFillIcon from '@patternfly/react-icons/dist/esm/icons/rh-ui-flag-fill-icon'; +import RhUiLanguageFillIcon from '@patternfly/react-icons/dist/esm/icons/rh-ui-language-fill-icon'; export const DescriptionListIconsOnTerms: React.FunctionComponent = () => ( - + }>Name Example @@ -30,15 +29,15 @@ export const DescriptionListIconsOnTerms: React.FunctionComponent = () => ( example - }>Pod selector + }>Pod selector - - }>Annotation + }>Annotation 2 Annotations diff --git a/packages/react-core/src/components/DescriptionList/examples/DescriptionListResponsiveHoriVertGroup.tsx b/packages/react-core/src/components/DescriptionList/examples/DescriptionListResponsiveHoriVertGroup.tsx index e60d592fdf9..a57caab2179 100644 --- a/packages/react-core/src/components/DescriptionList/examples/DescriptionListResponsiveHoriVertGroup.tsx +++ b/packages/react-core/src/components/DescriptionList/examples/DescriptionListResponsiveHoriVertGroup.tsx @@ -1,4 +1,3 @@ -import React from 'react'; import { Button, DescriptionList, @@ -6,7 +5,7 @@ import { DescriptionListGroup, DescriptionListDescription } from '@patternfly/react-core'; -import PlusCircleIcon from '@patternfly/react-icons/dist/esm/icons/plus-circle-icon'; +import RhUiAddCircleFillIcon from '@patternfly/react-icons/dist/esm/icons/rh-ui-add-circle-fill-icon'; export const DescriptionListResponsiveHoriVertGroup: React.FunctionComponent = () => ( Name @@ -35,7 +35,7 @@ export const DescriptionListResponsiveHoriVertGroup: React.FunctionComponent = ( Pod selector - diff --git a/packages/react-core/src/components/DescriptionList/examples/DescriptionListWithCard.tsx b/packages/react-core/src/components/DescriptionList/examples/DescriptionListWithCard.tsx index 5e7a0c0ba80..57bba6e38ad 100644 --- a/packages/react-core/src/components/DescriptionList/examples/DescriptionListWithCard.tsx +++ b/packages/react-core/src/components/DescriptionList/examples/DescriptionListWithCard.tsx @@ -1,4 +1,4 @@ -import React from 'react'; +import { useState } from 'react'; import { Button, DescriptionList, @@ -7,11 +7,11 @@ import { Card, Checkbox } from '@patternfly/react-core'; -import PlusCircleIcon from '@patternfly/react-icons/dist/esm/icons/plus-circle-icon'; +import RhUiAddCircleFillIcon from '@patternfly/react-icons/dist/esm/icons/rh-ui-add-circle-fill-icon'; export const DescriptionListWithCard: React.FunctionComponent = () => { - const [isChecked, setIsChecked] = React.useState(false); - const [isSelectable, setSelectable] = React.useState(false); + const [isChecked, setIsChecked] = useState(false); + const [isSelectable, setSelectable] = useState(false); const toggleSelectable = (checked: boolean) => { setSelectable(checked ? true : false); @@ -29,7 +29,7 @@ export const DescriptionListWithCard: React.FunctionComponent = () => { name="toggle-isSelectable" />
    - + Name Example @@ -47,7 +47,7 @@ export const DescriptionListWithCard: React.FunctionComponent = () => { Pod selector - diff --git a/packages/react-core/src/components/DescriptionList/examples/DescriptionListWithLargeDisplaySize.tsx b/packages/react-core/src/components/DescriptionList/examples/DescriptionListWithLargeDisplaySize.tsx index dc673735d57..2c36dfa4adb 100644 --- a/packages/react-core/src/components/DescriptionList/examples/DescriptionListWithLargeDisplaySize.tsx +++ b/packages/react-core/src/components/DescriptionList/examples/DescriptionListWithLargeDisplaySize.tsx @@ -1,4 +1,4 @@ -import React from 'react'; +import { useState } from 'react'; import { Button, DescriptionList, @@ -7,11 +7,11 @@ import { DescriptionListDescription, Checkbox } from '@patternfly/react-core'; -import PlusCircleIcon from '@patternfly/react-icons/dist/esm/icons/plus-circle-icon'; +import RhUiAddCircleFillIcon from '@patternfly/react-icons/dist/esm/icons/rh-ui-add-circle-fill-icon'; export const DescriptionListWithLargeDisplaySize: React.FunctionComponent = () => { - const [isChecked, setIsChecked] = React.useState(false); - const [displaySize, setDisplaySize] = React.useState<'lg' | '2xl'>('lg'); + const [isChecked, setIsChecked] = useState(false); + const [displaySize, setDisplaySize] = useState<'lg' | '2xl'>('lg'); const toggleDisplaySize = (checked: boolean) => { setDisplaySize(checked ? '2xl' : 'lg'); @@ -30,7 +30,7 @@ export const DescriptionListWithLargeDisplaySize: React.FunctionComponent = () = name="toggle-display-size" />
    - + Name Example @@ -48,7 +48,7 @@ export const DescriptionListWithLargeDisplaySize: React.FunctionComponent = () = Pod selector - diff --git a/packages/react-core/src/components/DescriptionList/examples/DescriptionListWithLargeDisplaySizeAndCard.tsx b/packages/react-core/src/components/DescriptionList/examples/DescriptionListWithLargeDisplaySizeAndCard.tsx index 1d44868ae6e..2a25a652870 100644 --- a/packages/react-core/src/components/DescriptionList/examples/DescriptionListWithLargeDisplaySizeAndCard.tsx +++ b/packages/react-core/src/components/DescriptionList/examples/DescriptionListWithLargeDisplaySizeAndCard.tsx @@ -1,4 +1,4 @@ -import React from 'react'; +import { useState } from 'react'; import { Button, DescriptionList, @@ -7,11 +7,11 @@ import { Card, Checkbox } from '@patternfly/react-core'; -import PlusCircleIcon from '@patternfly/react-icons/dist/esm/icons/plus-circle-icon'; +import RhUiAddCircleFillIcon from '@patternfly/react-icons/dist/esm/icons/rh-ui-add-circle-fill-icon'; export const DescriptionListWithLargeDisplaySizeAndCard: React.FunctionComponent = () => { - const [isChecked, setIsChecked] = React.useState(false); - const [displaySize, setDisplaySize] = React.useState<'lg' | '2xl'>('lg'); + const [isChecked, setIsChecked] = useState(false); + const [displaySize, setDisplaySize] = useState<'lg' | '2xl'>('lg'); const toggleDisplaySize = (checked: boolean) => { setDisplaySize(checked ? '2xl' : 'lg'); @@ -30,7 +30,11 @@ export const DescriptionListWithLargeDisplaySizeAndCard: React.FunctionComponent name="toggle-display-size-with-card" />
    - + Name Example @@ -48,7 +52,7 @@ export const DescriptionListWithLargeDisplaySizeAndCard: React.FunctionComponent Pod selector - diff --git a/packages/react-core/src/components/DescriptionList/examples/DescriptionListWithTermHelpText.tsx b/packages/react-core/src/components/DescriptionList/examples/DescriptionListWithTermHelpText.tsx index 297995a4a2d..a5e8c1f7f1a 100644 --- a/packages/react-core/src/components/DescriptionList/examples/DescriptionListWithTermHelpText.tsx +++ b/packages/react-core/src/components/DescriptionList/examples/DescriptionListWithTermHelpText.tsx @@ -1,4 +1,3 @@ -import React from 'react'; import { Button, DescriptionList, @@ -8,10 +7,10 @@ import { DescriptionListTermHelpTextButton, Popover } from '@patternfly/react-core'; -import PlusCircleIcon from '@patternfly/react-icons/dist/esm/icons/plus-circle-icon'; +import RhUiAddCircleFillIcon from '@patternfly/react-icons/dist/esm/icons/rh-ui-add-circle-fill-icon'; export const DescriptionListWithTermHelpText: React.FunctionComponent = () => ( - + Name
    } bodyContent={
    Additional name info
    }> @@ -45,7 +44,7 @@ export const DescriptionListWithTermHelpText: React.FunctionComponent = () => ( - diff --git a/packages/react-core/src/components/Divider/Divider.tsx b/packages/react-core/src/components/Divider/Divider.tsx index 35ccaba4555..ed5ac8342be 100644 --- a/packages/react-core/src/components/Divider/Divider.tsx +++ b/packages/react-core/src/components/Divider/Divider.tsx @@ -1,4 +1,3 @@ -import * as React from 'react'; import { css } from '@patternfly/react-styles'; import styles from '@patternfly/react-styles/css/components/Divider/divider'; import { formatBreakpointMods } from '../../helpers/util'; @@ -32,6 +31,8 @@ export interface DividerProps extends React.HTMLProps { xl?: 'vertical' | 'horizontal'; '2xl'?: 'vertical' | 'horizontal'; }; + /** The ARIA role of the divider when the component property has a value other than "hr". */ + role?: 'separator' | 'presentation'; } export const Divider: React.FunctionComponent = ({ @@ -39,6 +40,7 @@ export const Divider: React.FunctionComponent = ({ component = DividerVariant.hr, inset, orientation, + role = 'separator', ...props }: DividerProps) => { const Component: any = component; @@ -51,7 +53,7 @@ export const Divider: React.FunctionComponent = ({ formatBreakpointMods(orientation, styles), className )} - {...(component !== 'hr' && { role: 'separator' })} + {...(component !== 'hr' && { role })} {...props} /> ); diff --git a/packages/react-core/src/components/Divider/__tests__/Divider.test.tsx b/packages/react-core/src/components/Divider/__tests__/Divider.test.tsx index 53192ed63a4..f6a7dbb3c99 100644 --- a/packages/react-core/src/components/Divider/__tests__/Divider.test.tsx +++ b/packages/react-core/src/components/Divider/__tests__/Divider.test.tsx @@ -1,4 +1,3 @@ -import * as React from 'react'; import { render, screen } from '@testing-library/react'; import { Divider } from '../Divider'; import styles from '@patternfly/react-styles/css/components/Divider/divider'; @@ -92,6 +91,16 @@ test(`Test all insets`, () => { }); }); +test('Does not render with value passed to role by default', () => { + render(); + expect(screen.queryByRole('presentation')).not.toBeInTheDocument(); +}); + +test('Renders with value passed to role when component is not "hr"', () => { + render(); + expect(screen.getByRole('presentation')).toBeInTheDocument(); +}); + test('Matches the snapshot', () => { const { asFragment } = render(); expect(asFragment()).toMatchSnapshot(); diff --git a/packages/react-core/src/components/Divider/examples/Divider.md b/packages/react-core/src/components/Divider/examples/Divider.md index 1f5aed2416d..a8d039c69e7 100644 --- a/packages/react-core/src/components/Divider/examples/Divider.md +++ b/packages/react-core/src/components/Divider/examples/Divider.md @@ -1,7 +1,7 @@ --- id: Divider section: components -cssPrefix: pf-v5-c-divider +cssPrefix: pf-v6-c-divider propComponents: ['Divider'] --- diff --git a/packages/react-core/src/components/Divider/examples/DividerInsetMedium.tsx b/packages/react-core/src/components/Divider/examples/DividerInsetMedium.tsx index 281c786b590..23ac7a522fd 100644 --- a/packages/react-core/src/components/Divider/examples/DividerInsetMedium.tsx +++ b/packages/react-core/src/components/Divider/examples/DividerInsetMedium.tsx @@ -1,4 +1,3 @@ -import React from 'react'; import { Divider } from '@patternfly/react-core'; export const DividerInsetMedium: React.FunctionComponent = () => ; diff --git a/packages/react-core/src/components/Divider/examples/DividerInsetVariousBreakpoints.tsx b/packages/react-core/src/components/Divider/examples/DividerInsetVariousBreakpoints.tsx index 20f43d5dedc..32a706ec99b 100644 --- a/packages/react-core/src/components/Divider/examples/DividerInsetVariousBreakpoints.tsx +++ b/packages/react-core/src/components/Divider/examples/DividerInsetVariousBreakpoints.tsx @@ -1,4 +1,3 @@ -import React from 'react'; import { Divider } from '@patternfly/react-core'; export const DividerInsetVariousBreakpoints: React.FunctionComponent = () => ( diff --git a/packages/react-core/src/components/Divider/examples/DividerOrientationVariousBreakpoints.tsx b/packages/react-core/src/components/Divider/examples/DividerOrientationVariousBreakpoints.tsx index b182293baaf..da3b18a8337 100644 --- a/packages/react-core/src/components/Divider/examples/DividerOrientationVariousBreakpoints.tsx +++ b/packages/react-core/src/components/Divider/examples/DividerOrientationVariousBreakpoints.tsx @@ -1,4 +1,3 @@ -import React from 'react'; import { Divider, Flex, FlexItem } from '@patternfly/react-core'; export const DividerOrientationVariousBreakpoints: React.FunctionComponent = () => ( diff --git a/packages/react-core/src/components/Divider/examples/DividerUsingDiv.tsx b/packages/react-core/src/components/Divider/examples/DividerUsingDiv.tsx index fc16716c5f7..2db47de38eb 100644 --- a/packages/react-core/src/components/Divider/examples/DividerUsingDiv.tsx +++ b/packages/react-core/src/components/Divider/examples/DividerUsingDiv.tsx @@ -1,4 +1,3 @@ -import React from 'react'; import { Divider } from '@patternfly/react-core'; export const DividerUsingDiv: React.FunctionComponent = () => ; diff --git a/packages/react-core/src/components/Divider/examples/DividerUsingHr.tsx b/packages/react-core/src/components/Divider/examples/DividerUsingHr.tsx index 8ca86bcdee6..90b2418a27b 100644 --- a/packages/react-core/src/components/Divider/examples/DividerUsingHr.tsx +++ b/packages/react-core/src/components/Divider/examples/DividerUsingHr.tsx @@ -1,4 +1,3 @@ -import React from 'react'; import { Divider } from '@patternfly/react-core'; export const DividerUsingHr: React.FunctionComponent = () => ; diff --git a/packages/react-core/src/components/Divider/examples/DividerUsingLi.tsx b/packages/react-core/src/components/Divider/examples/DividerUsingLi.tsx index f8e0c4269ea..0d6e4584f65 100644 --- a/packages/react-core/src/components/Divider/examples/DividerUsingLi.tsx +++ b/packages/react-core/src/components/Divider/examples/DividerUsingLi.tsx @@ -1,4 +1,3 @@ -import React from 'react'; import { Divider } from '@patternfly/react-core'; export const DividerUsingLi: React.FunctionComponent = () => ( diff --git a/packages/react-core/src/components/Divider/examples/DividerVerticalFlex.tsx b/packages/react-core/src/components/Divider/examples/DividerVerticalFlex.tsx index 57054866cde..47a40933628 100644 --- a/packages/react-core/src/components/Divider/examples/DividerVerticalFlex.tsx +++ b/packages/react-core/src/components/Divider/examples/DividerVerticalFlex.tsx @@ -1,4 +1,3 @@ -import React from 'react'; import { Divider, Flex, FlexItem } from '@patternfly/react-core'; export const DividerVerticalFlex: React.FunctionComponent = () => ( diff --git a/packages/react-core/src/components/Divider/examples/DividerVerticalFlexInsetSmall.tsx b/packages/react-core/src/components/Divider/examples/DividerVerticalFlexInsetSmall.tsx index 95e93d151c1..0ad28729feb 100644 --- a/packages/react-core/src/components/Divider/examples/DividerVerticalFlexInsetSmall.tsx +++ b/packages/react-core/src/components/Divider/examples/DividerVerticalFlexInsetSmall.tsx @@ -1,4 +1,3 @@ -import React from 'react'; import { Divider, Flex, FlexItem } from '@patternfly/react-core'; export const DividerVerticalFlexInsetSmall: React.FunctionComponent = () => ( diff --git a/packages/react-core/src/components/Divider/examples/DividerVerticalFlexInsetVariousBreakpoints.tsx b/packages/react-core/src/components/Divider/examples/DividerVerticalFlexInsetVariousBreakpoints.tsx index c47a605b781..7f1c67baca9 100644 --- a/packages/react-core/src/components/Divider/examples/DividerVerticalFlexInsetVariousBreakpoints.tsx +++ b/packages/react-core/src/components/Divider/examples/DividerVerticalFlexInsetVariousBreakpoints.tsx @@ -1,4 +1,3 @@ -import React from 'react'; import { Divider, Flex, FlexItem } from '@patternfly/react-core'; export const DividerVerticalFlexInsetVariousBreakpoints: React.FunctionComponent = () => ( diff --git a/packages/react-core/src/components/Drawer/Drawer.tsx b/packages/react-core/src/components/Drawer/Drawer.tsx index 1f634fd87ac..eaa6c58dfcd 100644 --- a/packages/react-core/src/components/Drawer/Drawer.tsx +++ b/packages/react-core/src/components/Drawer/Drawer.tsx @@ -1,10 +1,13 @@ -import * as React from 'react'; +import { createContext, useRef } from 'react'; import styles from '@patternfly/react-styles/css/components/Drawer/drawer'; import { css } from '@patternfly/react-styles'; export enum DrawerColorVariant { default = 'default', secondary = 'secondary', + /** + * @deprecated `DrawerColorVariant.noBackground` is deprecated. Use the `isPlain` prop on `DrawerPanelContent` and the `DrawerSection`instead. + */ noBackground = 'no-background' } @@ -17,6 +20,8 @@ export interface DrawerProps extends React.HTMLProps { isExpanded?: boolean; /** Indicates if the content element and panel element are displayed side by side. */ isInline?: boolean; + /** @beta Indicates if the drawer will have pill styles */ + isPill?: boolean; /** Indicates if the drawer will always show both content and panel. */ isStatic?: boolean; /** Position of the drawer panel. left and right are deprecated, use start and end instead. */ @@ -30,12 +35,12 @@ export interface DrawerContextProps { isStatic: boolean; onExpand?: (event: KeyboardEvent | React.MouseEvent | React.TransitionEvent) => void; position?: string; - drawerRef?: React.RefObject; - drawerContentRef?: React.RefObject; + drawerRef?: React.RefObject; + drawerContentRef?: React.RefObject; isInline: boolean; } -export const DrawerContext = React.createContext>({ +export const DrawerContext = createContext>({ isExpanded: false, isStatic: false, onExpand: () => {}, @@ -50,13 +55,14 @@ export const Drawer: React.FunctionComponent = ({ children, isExpanded = false, isInline = false, + isPill = false, isStatic = false, position = 'end', onExpand = () => {}, ...props }: DrawerProps) => { - const drawerRef = React.useRef(); - const drawerContentRef = React.useRef(); + const drawerRef = useRef(undefined); + const drawerContentRef = useRef(undefined); return ( @@ -65,6 +71,7 @@ export const Drawer: React.FunctionComponent = ({ styles.drawer, isExpanded && styles.modifiers.expanded, isInline && styles.modifiers.inline, + isPill && styles.modifiers.pill, isStatic && styles.modifiers.static, (position === 'left' || position === 'start') && styles.modifiers.panelLeft, position === 'bottom' && styles.modifiers.panelBottom, diff --git a/packages/react-core/src/components/Drawer/DrawerActions.tsx b/packages/react-core/src/components/Drawer/DrawerActions.tsx index 85321d7c0ee..97d4367861c 100644 --- a/packages/react-core/src/components/Drawer/DrawerActions.tsx +++ b/packages/react-core/src/components/Drawer/DrawerActions.tsx @@ -1,4 +1,3 @@ -import * as React from 'react'; import styles from '@patternfly/react-styles/css/components/Drawer/drawer'; import { css } from '@patternfly/react-styles'; diff --git a/packages/react-core/src/components/Drawer/DrawerCloseButton.tsx b/packages/react-core/src/components/Drawer/DrawerCloseButton.tsx index fc6fff86dc6..cbab0ae4ac3 100644 --- a/packages/react-core/src/components/Drawer/DrawerCloseButton.tsx +++ b/packages/react-core/src/components/Drawer/DrawerCloseButton.tsx @@ -1,8 +1,7 @@ -import * as React from 'react'; import styles from '@patternfly/react-styles/css/components/Drawer/drawer'; import { css } from '@patternfly/react-styles'; import { Button } from '../Button'; -import TimesIcon from '@patternfly/react-icons/dist/esm/icons/times-icon'; +import RhMicronsCloseIcon from '@patternfly/react-icons/dist/esm/icons/rh-microns-close-icon'; export interface DrawerCloseButtonProps extends React.HTMLProps { /** Additional classes added to the drawer close button outer
    . */ @@ -20,7 +19,7 @@ export const DrawerCloseButton: React.FunctionComponent ...props }: DrawerCloseButtonProps) => (
    -
    ); DrawerCloseButton.displayName = 'DrawerCloseButton'; diff --git a/packages/react-core/src/components/Drawer/DrawerContent.tsx b/packages/react-core/src/components/Drawer/DrawerContent.tsx index 4dda7972892..a489316842d 100644 --- a/packages/react-core/src/components/Drawer/DrawerContent.tsx +++ b/packages/react-core/src/components/Drawer/DrawerContent.tsx @@ -1,4 +1,4 @@ -import * as React from 'react'; +import { useContext } from 'react'; import styles from '@patternfly/react-styles/css/components/Drawer/drawer'; import { css } from '@patternfly/react-styles'; import { DrawerMain } from './DrawerMain'; @@ -28,7 +28,7 @@ export const DrawerContent: React.FunctionComponent = ({ colorVariant = DrawerContentColorVariant.default, ...props }: DrawerContentProps) => { - const { drawerContentRef } = React.useContext(DrawerContext); + const { drawerContentRef } = useContext(DrawerContext); return ( diff --git a/packages/react-core/src/components/Drawer/DrawerContentBody.tsx b/packages/react-core/src/components/Drawer/DrawerContentBody.tsx index b5d32fdba39..a522457b4a2 100644 --- a/packages/react-core/src/components/Drawer/DrawerContentBody.tsx +++ b/packages/react-core/src/components/Drawer/DrawerContentBody.tsx @@ -1,4 +1,3 @@ -import * as React from 'react'; import styles from '@patternfly/react-styles/css/components/Drawer/drawer'; import { css } from '@patternfly/react-styles'; diff --git a/packages/react-core/src/components/Drawer/DrawerHead.tsx b/packages/react-core/src/components/Drawer/DrawerHead.tsx index 16b634b0419..703531699ea 100644 --- a/packages/react-core/src/components/Drawer/DrawerHead.tsx +++ b/packages/react-core/src/components/Drawer/DrawerHead.tsx @@ -1,4 +1,3 @@ -import * as React from 'react'; import styles from '@patternfly/react-styles/css/components/Drawer/drawer'; import { css } from '@patternfly/react-styles'; diff --git a/packages/react-core/src/components/Drawer/DrawerMain.tsx b/packages/react-core/src/components/Drawer/DrawerMain.tsx index 095046a7302..1cda6baddab 100644 --- a/packages/react-core/src/components/Drawer/DrawerMain.tsx +++ b/packages/react-core/src/components/Drawer/DrawerMain.tsx @@ -1,4 +1,3 @@ -import * as React from 'react'; import styles from '@patternfly/react-styles/css/components/Drawer/drawer'; import { css } from '@patternfly/react-styles'; diff --git a/packages/react-core/src/components/Drawer/DrawerPanelBody.tsx b/packages/react-core/src/components/Drawer/DrawerPanelBody.tsx index b23ccca102f..9b6ca99e73e 100644 --- a/packages/react-core/src/components/Drawer/DrawerPanelBody.tsx +++ b/packages/react-core/src/components/Drawer/DrawerPanelBody.tsx @@ -1,4 +1,3 @@ -import * as React from 'react'; import styles from '@patternfly/react-styles/css/components/Drawer/drawer'; import { css } from '@patternfly/react-styles'; diff --git a/packages/react-core/src/components/Drawer/DrawerPanelContent.tsx b/packages/react-core/src/components/Drawer/DrawerPanelContent.tsx index 20b06d6640c..2933af16965 100644 --- a/packages/react-core/src/components/Drawer/DrawerPanelContent.tsx +++ b/packages/react-core/src/components/Drawer/DrawerPanelContent.tsx @@ -1,9 +1,9 @@ -import * as React from 'react'; +import { Fragment, useCallback, useContext, useEffect, useRef, useState } from 'react'; import styles from '@patternfly/react-styles/css/components/Drawer/drawer'; import { css } from '@patternfly/react-styles'; import { DrawerColorVariant, DrawerContext } from './Drawer'; import { formatBreakpointMods, getLanguageDirection } from '../../helpers/util'; -import { GenerateId } from '../../helpers/GenerateId/GenerateId'; +import { useSSRSafeId } from '../../helpers'; import { FocusTrap } from '../../helpers/FocusTrap/FocusTrap'; import cssPanelMdFlexBasis from '@patternfly/react-tokens/dist/esm/c_drawer__panel_md_FlexBasis'; import cssPanelMdFlexBasisMin from '@patternfly/react-tokens/dist/esm/c_drawer__panel_md_FlexBasis_min'; @@ -35,6 +35,14 @@ export interface DrawerPanelContentProps extends Omit void; /** The minimum size of a drawer. */ @@ -47,14 +55,17 @@ export interface DrawerPanelContentProps extends Omit { - const panel = React.useRef(); - const splitterRef = React.useRef(); - const [separatorValue, setSeparatorValue] = React.useState(0); - const { position, isExpanded, isStatic, onExpand, drawerRef, drawerContentRef, isInline } = - React.useContext(DrawerContext); + const panelId = useSSRSafeId('pf-drawer-panel-'); + const panel = useRef(undefined); + const splitterRef = useRef(undefined); + const [separatorValue, setSeparatorValue] = useState(0); + const { position, isExpanded, isStatic, onExpand, drawerRef, drawerContentRef, isInline } = useContext(DrawerContext); const hidden = isStatic ? false : !isExpanded; - const [isExpandedInternal, setIsExpandedInternal] = React.useState(!hidden); - const [isFocusTrapActive, setIsFocusTrapActive] = React.useState(false); - const previouslyFocusedElement = React.useRef(null); + const [isExpandedInternal, setIsExpandedInternal] = useState(!hidden); + const [isFocusTrapActive, setIsFocusTrapActive] = useState(false); + const [shouldCollapseSpace, setShouldCollapseSpace] = useState(hidden); + const previouslyFocusedElement = useRef(null); let currWidth: number = 0; let panelRect: DOMRect; let end: number; @@ -102,9 +119,10 @@ export const DrawerPanelContent: React.FunctionComponent { + useEffect(() => { if (!isStatic && isExpanded) { setIsExpandedInternal(isExpanded); + setShouldCollapseSpace(false); } }, [isStatic, isExpanded]); @@ -258,10 +276,10 @@ export const DrawerPanelContent: React.FunctionComponent { const isRTL = getLanguageDirection(panel.current) === 'rtl'; @@ -327,98 +345,102 @@ export const DrawerPanelContent: React.FunctionComponent panel.current, + onActivate: () => { + if (previouslyFocusedElement.current !== document.activeElement) { + previouslyFocusedElement.current = document.activeElement; + } + }, + onDeactivate: () => { + previouslyFocusedElement.current && + previouslyFocusedElement.current.focus && + previouslyFocusedElement.current.focus(); + }, + clickOutsideDeactivates: true, + returnFocusOnDeactivate: false, + // FocusTrap's initialFocus can accept false as a value to prevent initial focus. + // We want to prevent this in case false is ever passed in. + initialFocus: focusTrap?.elementToFocusOnExpand || undefined, + escapeDeactivates: false + } + }; + return ( - - {(panelId) => { - const focusTrapProps = { - tabIndex: -1, - 'aria-modal': true, - role: 'dialog', - active: isFocusTrapActive, - 'aria-labelledby': focusTrap?.['aria-labelledby'] || id || panelId, - focusTrapOptions: { - fallbackFocus: () => panel.current, - onActivate: () => { - if (previouslyFocusedElement.current !== document.activeElement) { - previouslyFocusedElement.current = document.activeElement; - } - }, - onDeactivate: () => { - previouslyFocusedElement.current && - previouslyFocusedElement.current.focus && - previouslyFocusedElement.current.focus(); - }, - clickOutsideDeactivates: true, - returnFocusOnDeactivate: false, - // FocusTrap's initialFocus can accept false as a value to prevent initial focus. - // We want to prevent this in case false is ever passed in. - initialFocus: focusTrap?.elementToFocusOnExpand || undefined, - escapeDeactivates: false + { + if ((ev.target as HTMLElement) === panel.current) { + if (!hidden && ev.nativeEvent.propertyName === 'transform') { + onExpand(ev); } - }; - - return ( - { - if ((ev.target as HTMLElement) === panel.current) { - if (!hidden && ev.nativeEvent.propertyName === 'transform') { - onExpand(ev); - } - setIsExpandedInternal(!hidden); - if (isValidFocusTrap && ev.nativeEvent.propertyName === 'transform') { - setIsFocusTrapActive((prevIsFocusTrapActive) => !prevIsFocusTrapActive); - } - } - }} - hidden={hidden} - {...((defaultSize || minSize || maxSize) && { - style: boundaryCssVars as React.CSSProperties - })} - {...props} - ref={panel} - > - {isExpandedInternal && ( - - {isResizable && ( - -
    -
    -
    -
    {children}
    -
    - )} - {!isResizable && children} -
    - )} -
    - ); + setIsExpandedInternal(!hidden); + // We also need to collapse the space when the panel is hidden to prevent automation from scrolling to it + if (hidden && ev.nativeEvent.propertyName === 'transform') { + setShouldCollapseSpace(true); + } + if (isValidFocusTrap && ev.nativeEvent.propertyName === 'transform') { + setIsFocusTrapActive((prevIsFocusTrapActive) => !prevIsFocusTrapActive); + } + } + }} + hidden={hidden} + style={{ + ...((defaultSize || minSize || maxSize) && boundaryCssVars), + ...style }} -
    + {...(shouldCollapseSpace && { inert: '' })} + {...props} + ref={panel} + > + {isExpandedInternal && ( + + {isResizable && ( + +
    +
    +
    +
    {children}
    +
    + )} + {!isResizable && children} +
    + )} + ); }; DrawerPanelContent.displayName = 'DrawerPanelContent'; diff --git a/packages/react-core/src/components/Drawer/DrawerPanelDescription.tsx b/packages/react-core/src/components/Drawer/DrawerPanelDescription.tsx index ac066f09b0a..7d044777f8d 100644 --- a/packages/react-core/src/components/Drawer/DrawerPanelDescription.tsx +++ b/packages/react-core/src/components/Drawer/DrawerPanelDescription.tsx @@ -1,4 +1,3 @@ -import * as React from 'react'; import styles from '@patternfly/react-styles/css/components/Drawer/drawer'; import { css } from '@patternfly/react-styles'; diff --git a/packages/react-core/src/components/Drawer/DrawerSection.tsx b/packages/react-core/src/components/Drawer/DrawerSection.tsx index 95e0a0662f6..941fa3fa862 100644 --- a/packages/react-core/src/components/Drawer/DrawerSection.tsx +++ b/packages/react-core/src/components/Drawer/DrawerSection.tsx @@ -1,4 +1,3 @@ -import * as React from 'react'; import styles from '@patternfly/react-styles/css/components/Drawer/drawer'; import { css } from '@patternfly/react-styles'; import { DrawerColorVariant } from './Drawer'; @@ -8,19 +7,26 @@ export interface DrawerSectionProps extends React.HTMLProps { className?: string; /** Content to be rendered in the drawer section. */ children?: React.ReactNode; - /** Color variant of the background of the drawer Section */ + /** + * Color variant of the background of the drawer section. + * The `no-background` value is deprecated; use the `isPlain` prop instead. + */ colorVariant?: DrawerColorVariant | 'no-background' | 'default' | 'secondary'; + /** @beta Flag indicating that the drawer section should use plain styles. */ + isPlain?: boolean; } export const DrawerSection: React.FunctionComponent = ({ className = '', children, colorVariant = DrawerColorVariant.default, + isPlain = false, ...props }: DrawerSectionProps) => (
    { }); test('Resizeable DrawerPanelContent can be wrapped in a context without causing an error', async () => { - const TestContext = React.createContext({}); + const TestContext = createContext({}); const consoleError = jest.spyOn(console, 'error').mockImplementation(); @@ -162,3 +163,27 @@ test('Resizeable DrawerPanelContent can be wrapped in a context without causing expect(consoleError).not.toHaveBeenCalled(); }); + +test(`Renders with ${styles.modifiers.pill} class when specified`, () => { + const panelContent = ( + + + drawer-panel + + + + + drawer-panel + + ); + + render( + + + Drawer content text + + + ); + + expect(screen.getByTestId('drawer')).toHaveClass(styles.modifiers.pill); +}); diff --git a/packages/react-core/src/components/Drawer/__tests__/DrawerPanelContent.test.tsx b/packages/react-core/src/components/Drawer/__tests__/DrawerPanelContent.test.tsx index b1cd0fe850e..ba0b0cec4c4 100644 --- a/packages/react-core/src/components/Drawer/__tests__/DrawerPanelContent.test.tsx +++ b/packages/react-core/src/components/Drawer/__tests__/DrawerPanelContent.test.tsx @@ -1,4 +1,3 @@ -import React from 'react'; import { render, screen } from '@testing-library/react'; import { DrawerPanelContent } from '../DrawerPanelContent'; import { Drawer } from '../Drawer'; @@ -14,7 +13,7 @@ test(`Renders with only class ${styles.drawerPanel} by default`, () => { expect(screen.getByText('Drawer panel content')).toHaveClass(styles.drawerPanel, { exact: true }); }); -test(`Renders with class ${styles.modifiers.noBackground} when colorVariant="no-background"`, () => { +test(`Renders with class ${styles.modifiers.noBackground} when deprecated colorVariant="no-background" is used`, () => { render( Drawer panel content @@ -122,3 +121,100 @@ test('Renders with role="dialog" when focusTrap.enabled is true', () => { expect(screen.getByRole('dialog')).toBeInTheDocument(); }); + +test('Does not render with inert when drawer is expanded', () => { + render( + + Drawer panel content + + ); + + expect(screen.getByTestId('drawer-content')).not.toHaveAttribute('inert'); +}); + +test('Renders with inert when drawer is collapsed', () => { + render( + + Drawer panel content + + ); + + expect(screen.getByTestId('drawer-content')).toHaveAttribute('inert'); +}); + +test('Applies style prop as expected', () => { + render( + + Drawer panel content + + ); + + const panelContent = screen.getByText('Drawer panel content'); + expect(panelContent).toHaveStyle({ backgroundColor: 'red', padding: '20px' }); +}); + +test('Style prop overrides boundaryCssVars', () => { + render( + + + Drawer panel content + + + ); + + const panelContent = screen.getByText('Drawer panel content'); + expect(panelContent).toHaveStyle({ + '--pf-v6-c-drawer__panel--md--FlexBasis': '300px', + '--pf-v6-c-drawer__panel--md--FlexBasis--min': '150px', + '--pf-v6-c-drawer__panel--md--FlexBasis--max': '500px' + }); +}); + +test(`Renders with class 'pf-m-no-glass' when hasNoGlass is true`, () => { + render( + + Drawer panel content + + ); + + expect(screen.getByText('Drawer panel content')).toHaveClass('pf-m-no-glass'); +}); + +test(`Renders with class ${styles.modifiers.glass} when isGlass is true`, () => { + render( + + Drawer panel content + + ); + + expect(screen.getByText('Drawer panel content')).toHaveClass(styles.modifiers.glass); +}); + +test(`Renders with class ${styles.modifiers.plain} when isPlain is true`, () => { + render( + + Drawer panel content + + ); + + expect(screen.getByText('Drawer panel content')).toHaveClass(styles.modifiers.plain); +}); + +test(`Renders with class ${styles.modifiers.noPlainOnGlass} when isNoPlainOnGlass is true`, () => { + render( + + Drawer panel content + + ); + + expect(screen.getByText('Drawer panel content')).toHaveClass(styles.modifiers.noPlainOnGlass); +}); diff --git a/packages/react-core/src/components/Drawer/__tests__/DrawerPanelDescription.tsx b/packages/react-core/src/components/Drawer/__tests__/DrawerPanelDescription.tsx index 439a575177c..bee9ac5818c 100644 --- a/packages/react-core/src/components/Drawer/__tests__/DrawerPanelDescription.tsx +++ b/packages/react-core/src/components/Drawer/__tests__/DrawerPanelDescription.tsx @@ -1,4 +1,3 @@ -import React from 'react'; import { render, screen } from '@testing-library/react'; import { DrawerPanelDescription } from '../DrawerPanelDescription'; import styles from '@patternfly/react-styles/css/components/Drawer/drawer'; diff --git a/packages/react-core/src/components/Drawer/__tests__/DrawerSection.test.tsx b/packages/react-core/src/components/Drawer/__tests__/DrawerSection.test.tsx new file mode 100644 index 00000000000..e080cb25a8c --- /dev/null +++ b/packages/react-core/src/components/Drawer/__tests__/DrawerSection.test.tsx @@ -0,0 +1,37 @@ +import { render, screen } from '@testing-library/react'; +import { DrawerColorVariant } from '../Drawer'; +import { DrawerSection } from '../DrawerSection'; +import styles from '@patternfly/react-styles/css/components/Drawer/drawer'; + +test(`Renders with only class ${styles.drawerSection} by default`, () => { + render(Section content); + + expect(screen.getByText('Section content')).toHaveClass(styles.drawerSection, { exact: true }); +}); + +test(`Applies ${styles.drawerSection} and ${styles.modifiers.plain} when isPlain is true`, () => { + render(Section content); + + const section = screen.getByText('Section content'); + expect(section).toHaveClass(styles.drawerSection); + expect(section).toHaveClass(styles.modifiers.plain); +}); + +test(`Does not apply ${styles.modifiers.plain} when isPlain is false`, () => { + render(Section content); + + expect(screen.getByText('Section content')).not.toHaveClass(styles.modifiers.plain); +}); + +test(`Applies plain and secondary modifiers together when isPlain and colorVariant are set`, () => { + render( + + Section content + + ); + + const section = screen.getByText('Section content'); + expect(section).toHaveClass(styles.drawerSection); + expect(section).toHaveClass(styles.modifiers.plain); + expect(section).toHaveClass(styles.modifiers.secondary); +}); diff --git a/packages/react-core/src/components/Drawer/__tests__/Generated/DrawerContent.test.tsx b/packages/react-core/src/components/Drawer/__tests__/Generated/DrawerContent.test.tsx index a4f332fc05e..3ce691d8284 100644 --- a/packages/react-core/src/components/Drawer/__tests__/Generated/DrawerContent.test.tsx +++ b/packages/react-core/src/components/Drawer/__tests__/Generated/DrawerContent.test.tsx @@ -1,7 +1,6 @@ /** * This test was generated */ -import * as React from 'react'; import { render } from '@testing-library/react'; import { DrawerContent } from '../../DrawerContent'; // any missing imports can usually be resolved by adding them here diff --git a/packages/react-core/src/components/Drawer/__tests__/Generated/DrawerPanelContent.test.tsx b/packages/react-core/src/components/Drawer/__tests__/Generated/DrawerPanelContent.test.tsx index ed8676d0943..34c66959937 100644 --- a/packages/react-core/src/components/Drawer/__tests__/Generated/DrawerPanelContent.test.tsx +++ b/packages/react-core/src/components/Drawer/__tests__/Generated/DrawerPanelContent.test.tsx @@ -1,7 +1,6 @@ /** * This test was generated */ -import * as React from 'react'; import { render } from '@testing-library/react'; import { DrawerPanelContent } from '../../DrawerPanelContent'; // any missing imports can usually be resolved by adding them here diff --git a/packages/react-core/src/components/Drawer/__tests__/Generated/__snapshots__/DrawerPanelContent.test.tsx.snap b/packages/react-core/src/components/Drawer/__tests__/Generated/__snapshots__/DrawerPanelContent.test.tsx.snap index b17ab76a1e7..9c0d67ba622 100644 --- a/packages/react-core/src/components/Drawer/__tests__/Generated/__snapshots__/DrawerPanelContent.test.tsx.snap +++ b/packages/react-core/src/components/Drawer/__tests__/Generated/__snapshots__/DrawerPanelContent.test.tsx.snap @@ -5,7 +5,8 @@ exports[`DrawerPanelContent should match snapshot (auto-generated) 1`] = `
    @@ -310,7 +308,8 @@ exports[`Drawer isExpanded = false and isInline = true and isStatic = false 1`]
    @@ -336,7 +335,7 @@ exports[`Drawer isExpanded = true and isInline = false and isStatic = false 1`]
    @@ -54,6 +54,6 @@ export const DrawerAdditionalSectionAboveContent: React.FunctionComponent = () = {drawerContent} - + ); }; diff --git a/packages/react-core/src/components/Drawer/examples/DrawerBasic.tsx b/packages/react-core/src/components/Drawer/examples/DrawerBasic.tsx index efef6b45d34..803d1d92aab 100644 --- a/packages/react-core/src/components/Drawer/examples/DrawerBasic.tsx +++ b/packages/react-core/src/components/Drawer/examples/DrawerBasic.tsx @@ -1,4 +1,4 @@ -import React from 'react'; +import { Fragment, useRef, useState } from 'react'; import { Drawer, DrawerPanelContent, @@ -13,8 +13,8 @@ import { } from '@patternfly/react-core'; export const DrawerBasic: React.FunctionComponent = () => { - const [isExpanded, setIsExpanded] = React.useState(false); - const drawerRef = React.useRef(); + const [isExpanded, setIsExpanded] = useState(false); + const drawerRef = useRef(null); const onExpand = () => { drawerRef.current && drawerRef.current.focus(); @@ -47,7 +47,7 @@ export const DrawerBasic: React.FunctionComponent = () => { 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Phasellus pretium est a porttitor vehicula. Quisque vel commodo urna. Morbi mattis rutrum ante, id vehicula ex accumsan ut. Morbi viverra, eros vel porttitor facilisis, eros purus aliquet erat,nec lobortis felis elit pulvinar sem. Vivamus vulputate, risus eget commodo eleifend, eros nibh porta quam, vitae lacinia leo libero at magna. Maecenas aliquam sagittis orci, et posuere nisi ultrices sit amet. Aliquam ex odio, malesuada sed posuere quis, pellentesque at mauris. Phasellus venenatis massa ex, eget pulvinar libero auctor pretium. Aliquam erat volutpat. Duis euismod justo in quam ullamcorper, in commodo massa vulputate.'; return ( - + @@ -56,6 +56,6 @@ export const DrawerBasic: React.FunctionComponent = () => { {drawerContent} - + ); }; diff --git a/packages/react-core/src/components/Drawer/examples/DrawerBasicInline.tsx b/packages/react-core/src/components/Drawer/examples/DrawerBasicInline.tsx index 8a07bd09bc8..2df988d7740 100644 --- a/packages/react-core/src/components/Drawer/examples/DrawerBasicInline.tsx +++ b/packages/react-core/src/components/Drawer/examples/DrawerBasicInline.tsx @@ -1,4 +1,4 @@ -import React from 'react'; +import { Fragment, useRef, useState } from 'react'; import { Drawer, DrawerPanelContent, @@ -11,8 +11,8 @@ import { } from '@patternfly/react-core'; export const DrawerBasicInline: React.FunctionComponent = () => { - const [isExpanded, setIsExpanded] = React.useState(false); - const drawerRef = React.useRef(); + const [isExpanded, setIsExpanded] = useState(false); + const drawerRef = useRef(null); const onExpand = () => { drawerRef.current && drawerRef.current.focus(); @@ -43,7 +43,7 @@ export const DrawerBasicInline: React.FunctionComponent = () => { 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Phasellus pretium est a porttitor vehicula. Quisque vel commodo urna. Morbi mattis rutrum ante, id vehicula ex accumsan ut. Morbi viverra, eros vel porttitor facilisis, eros purus aliquet erat,nec lobortis felis elit pulvinar sem. Vivamus vulputate, risus eget commodo eleifend, eros nibh porta quam, vitae lacinia leo libero at magna. Maecenas aliquam sagittis orci, et posuere nisi ultrices sit amet. Aliquam ex odio, malesuada sed posuere quis, pellentesque at mauris. Phasellus venenatis massa ex, eget pulvinar libero auctor pretium. Aliquam erat volutpat. Duis euismod justo in quam ullamcorper, in commodo massa vulputate.'; return ( - + @@ -52,6 +52,6 @@ export const DrawerBasicInline: React.FunctionComponent = () => { {drawerContent} - + ); }; diff --git a/packages/react-core/src/components/Drawer/examples/DrawerBasicPill.tsx b/packages/react-core/src/components/Drawer/examples/DrawerBasicPill.tsx new file mode 100644 index 00000000000..fdea78cbfe7 --- /dev/null +++ b/packages/react-core/src/components/Drawer/examples/DrawerBasicPill.tsx @@ -0,0 +1,57 @@ +import { Fragment, useRef, useState } from 'react'; +import { + Drawer, + DrawerPanelContent, + DrawerContent, + DrawerContentBody, + DrawerHead, + DrawerActions, + DrawerCloseButton, + Button +} from '@patternfly/react-core'; + +export const DrawerBasicPill: React.FunctionComponent = () => { + const [isExpanded, setIsExpanded] = useState(false); + const drawerRef = useRef(null); + + const onExpand = () => { + drawerRef.current && drawerRef.current.focus(); + }; + + const onClick = () => { + setIsExpanded(!isExpanded); + }; + + const onCloseClick = () => { + setIsExpanded(false); + }; + + const panelContent = ( + + + + Drawer panel header + + + + + + + ); + + const drawerContent = + 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Phasellus pretium est a porttitor vehicula. Quisque vel commodo urna. Morbi mattis rutrum ante, id vehicula ex accumsan ut. Morbi viverra, eros vel porttitor facilisis, eros purus aliquet erat,nec lobortis felis elit pulvinar sem. Vivamus vulputate, risus eget commodo eleifend, eros nibh porta quam, vitae lacinia leo libero at magna. Maecenas aliquam sagittis orci, et posuere nisi ultrices sit amet. Aliquam ex odio, malesuada sed posuere quis, pellentesque at mauris. Phasellus venenatis massa ex, eget pulvinar libero auctor pretium. Aliquam erat volutpat. Duis euismod justo in quam ullamcorper, in commodo massa vulputate.'; + + return ( + + + + + {drawerContent} + + + + ); +}; diff --git a/packages/react-core/src/components/Drawer/examples/DrawerBreakpoint.tsx b/packages/react-core/src/components/Drawer/examples/DrawerBreakpoint.tsx index 0e40c38f7f1..0401fa35331 100644 --- a/packages/react-core/src/components/Drawer/examples/DrawerBreakpoint.tsx +++ b/packages/react-core/src/components/Drawer/examples/DrawerBreakpoint.tsx @@ -1,4 +1,4 @@ -import React from 'react'; +import { Fragment, useRef, useState } from 'react'; import { Drawer, DrawerPanelContent, @@ -11,8 +11,8 @@ import { } from '@patternfly/react-core'; export const DrawerBreakpoint: React.FunctionComponent = () => { - const [isExpanded, setIsExpanded] = React.useState(false); - const drawerRef = React.useRef(); + const [isExpanded, setIsExpanded] = useState(false); + const drawerRef = useRef(null); const onExpand = () => { drawerRef.current && drawerRef.current.focus(); @@ -43,7 +43,7 @@ export const DrawerBreakpoint: React.FunctionComponent = () => { 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Phasellus pretium est a porttitor vehicula. Quisque vel commodo urna. Morbi mattis rutrum ante, id vehicula ex accumsan ut. Morbi viverra, eros vel porttitor facilisis, eros purus aliquet erat,nec lobortis felis elit pulvinar sem. Vivamus vulputate, risus eget commodo eleifend, eros nibh porta quam, vitae lacinia leo libero at magna. Maecenas aliquam sagittis orci, et posuere nisi ultrices sit amet. Aliquam ex odio, malesuada sed posuere quis, pellentesque at mauris. Phasellus venenatis massa ex, eget pulvinar libero auctor pretium. Aliquam erat volutpat. Duis euismod justo in quam ullamcorper, in commodo massa vulputate.'; return ( - + @@ -52,6 +52,6 @@ export const DrawerBreakpoint: React.FunctionComponent = () => { {drawerContent} - + ); }; diff --git a/packages/react-core/src/components/Drawer/examples/DrawerFocusTrap.tsx b/packages/react-core/src/components/Drawer/examples/DrawerFocusTrap.tsx index e8fde64ed44..5f5f44422e7 100644 --- a/packages/react-core/src/components/Drawer/examples/DrawerFocusTrap.tsx +++ b/packages/react-core/src/components/Drawer/examples/DrawerFocusTrap.tsx @@ -1,4 +1,4 @@ -import React from 'react'; +import { Fragment, useState } from 'react'; import { Drawer, DrawerPanelContent, @@ -11,7 +11,7 @@ import { } from '@patternfly/react-core'; export const DrawerFocusTrap: React.FunctionComponent = () => { - const [isExpanded, setIsExpanded] = React.useState(false); + const [isExpanded, setIsExpanded] = useState(false); const onClick = () => { setIsExpanded(!isExpanded); @@ -44,7 +44,7 @@ export const DrawerFocusTrap: React.FunctionComponent = () => { 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Phasellus pretium est a porttitor vehicula. Quisque vel commodo urna. Morbi mattis rutrum ante, id vehicula ex accumsan ut. Morbi viverra, eros vel porttitor facilisis, eros purus aliquet erat,nec lobortis felis elit pulvinar sem. Vivamus vulputate, risus eget commodo eleifend, eros nibh porta quam, vitae lacinia leo libero at magna. Maecenas aliquam sagittis orci, et posuere nisi ultrices sit amet. Aliquam ex odio, malesuada sed posuere quis, pellentesque at mauris. Phasellus venenatis massa ex, eget pulvinar libero auctor pretium. Aliquam erat volutpat. Duis euismod justo in quam ullamcorper, in commodo massa vulputate.'; return ( - + @@ -53,6 +53,6 @@ export const DrawerFocusTrap: React.FunctionComponent = () => { {drawerContent} - + ); }; diff --git a/packages/react-core/src/components/Drawer/examples/DrawerInlinePanelEnd.tsx b/packages/react-core/src/components/Drawer/examples/DrawerInlinePanelEnd.tsx index 7918cb22e6f..071cd9a3244 100644 --- a/packages/react-core/src/components/Drawer/examples/DrawerInlinePanelEnd.tsx +++ b/packages/react-core/src/components/Drawer/examples/DrawerInlinePanelEnd.tsx @@ -1,4 +1,4 @@ -import React from 'react'; +import { Fragment, useRef, useState } from 'react'; import { Drawer, DrawerPanelContent, @@ -11,8 +11,8 @@ import { } from '@patternfly/react-core'; export const DrawerInlinePanelEnd: React.FunctionComponent = () => { - const [isExpanded, setIsExpanded] = React.useState(false); - const drawerRef = React.useRef(); + const [isExpanded, setIsExpanded] = useState(false); + const drawerRef = useRef(null); const onExpand = () => { drawerRef.current && drawerRef.current.focus(); @@ -43,7 +43,7 @@ export const DrawerInlinePanelEnd: React.FunctionComponent = () => { 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Phasellus pretium est a porttitor vehicula. Quisque vel commodo urna. Morbi mattis rutrum ante, id vehicula ex accumsan ut. Morbi viverra, eros vel porttitor facilisis, eros purus aliquet erat,nec lobortis felis elit pulvinar sem. Vivamus vulputate, risus eget commodo eleifend, eros nibh porta quam, vitae lacinia leo libero at magna. Maecenas aliquam sagittis orci, et posuere nisi ultrices sit amet. Aliquam ex odio, malesuada sed posuere quis, pellentesque at mauris. Phasellus venenatis massa ex, eget pulvinar libero auctor pretium. Aliquam erat volutpat. Duis euismod justo in quam ullamcorper, in commodo massa vulputate.'; return ( - + @@ -52,6 +52,6 @@ export const DrawerInlinePanelEnd: React.FunctionComponent = () => { {drawerContent} - + ); }; diff --git a/packages/react-core/src/components/Drawer/examples/DrawerInlinePanelStart.tsx b/packages/react-core/src/components/Drawer/examples/DrawerInlinePanelStart.tsx index 323fece2207..ffe46a2b9e1 100644 --- a/packages/react-core/src/components/Drawer/examples/DrawerInlinePanelStart.tsx +++ b/packages/react-core/src/components/Drawer/examples/DrawerInlinePanelStart.tsx @@ -1,4 +1,4 @@ -import React from 'react'; +import { Fragment, useRef, useState } from 'react'; import { Drawer, DrawerPanelContent, @@ -11,8 +11,8 @@ import { } from '@patternfly/react-core'; export const DrawerInlinePanelStart: React.FunctionComponent = () => { - const [isExpanded, setIsExpanded] = React.useState(false); - const drawerRef = React.useRef(); + const [isExpanded, setIsExpanded] = useState(false); + const drawerRef = useRef(null); const onExpand = () => { drawerRef.current && drawerRef.current.focus(); @@ -43,7 +43,7 @@ export const DrawerInlinePanelStart: React.FunctionComponent = () => { 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Phasellus pretium est a porttitor vehicula. Quisque vel commodo urna. Morbi mattis rutrum ante, id vehicula ex accumsan ut. Morbi viverra, eros vel porttitor facilisis, eros purus aliquet erat,nec lobortis felis elit pulvinar sem. Vivamus vulputate, risus eget commodo eleifend, eros nibh porta quam, vitae lacinia leo libero at magna. Maecenas aliquam sagittis orci, et posuere nisi ultrices sit amet. Aliquam ex odio, malesuada sed posuere quis, pellentesque at mauris. Phasellus venenatis massa ex, eget pulvinar libero auctor pretium. Aliquam erat volutpat. Duis euismod justo in quam ullamcorper, in commodo massa vulputate.'; return ( - + @@ -52,6 +52,6 @@ export const DrawerInlinePanelStart: React.FunctionComponent = () => { {drawerContent} - + ); }; diff --git a/packages/react-core/src/components/Drawer/examples/DrawerModifiedContentPadding.tsx b/packages/react-core/src/components/Drawer/examples/DrawerModifiedContentPadding.tsx index fa18a03298a..9a06d057e3f 100644 --- a/packages/react-core/src/components/Drawer/examples/DrawerModifiedContentPadding.tsx +++ b/packages/react-core/src/components/Drawer/examples/DrawerModifiedContentPadding.tsx @@ -1,4 +1,4 @@ -import React from 'react'; +import { Fragment, useRef, useState } from 'react'; import { Drawer, DrawerPanelContent, @@ -11,8 +11,8 @@ import { } from '@patternfly/react-core'; export const DrawerModifiedContentPadding: React.FunctionComponent = () => { - const [isExpanded, setIsExpanded] = React.useState(false); - const drawerRef = React.useRef(); + const [isExpanded, setIsExpanded] = useState(false); + const drawerRef = useRef(null); const onExpand = () => { drawerRef.current && drawerRef.current.focus(); @@ -43,7 +43,7 @@ export const DrawerModifiedContentPadding: React.FunctionComponent = () => { 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Phasellus pretium est a porttitor vehicula. Quisque vel commodo urna. Morbi mattis rutrum ante, id vehicula ex accumsan ut. Morbi viverra, eros vel porttitor facilisis, eros purus aliquet erat,nec lobortis felis elit pulvinar sem. Vivamus vulputate, risus eget commodo eleifend, eros nibh porta quam, vitae lacinia leo libero at magna. Maecenas aliquam sagittis orci, et posuere nisi ultrices sit amet. Aliquam ex odio, malesuada sed posuere quis, pellentesque at mauris. Phasellus venenatis massa ex, eget pulvinar libero auctor pretium. Aliquam erat volutpat. Duis euismod justo in quam ullamcorper, in commodo massa vulputate.'; return ( - + @@ -54,6 +54,6 @@ export const DrawerModifiedContentPadding: React.FunctionComponent = () => { - + ); }; diff --git a/packages/react-core/src/components/Drawer/examples/DrawerModifiedPanelPadding.tsx b/packages/react-core/src/components/Drawer/examples/DrawerModifiedPanelPadding.tsx index 4e738e747ab..afabeb0f9df 100644 --- a/packages/react-core/src/components/Drawer/examples/DrawerModifiedPanelPadding.tsx +++ b/packages/react-core/src/components/Drawer/examples/DrawerModifiedPanelPadding.tsx @@ -1,4 +1,4 @@ -import React from 'react'; +import { Fragment, useRef, useState } from 'react'; import { Drawer, DrawerPanelContent, @@ -11,8 +11,8 @@ import { } from '@patternfly/react-core'; export const DrawerModifiedPanelPadding: React.FunctionComponent = () => { - const [isExpanded, setIsExpanded] = React.useState(false); - const drawerRef = React.useRef(); + const [isExpanded, setIsExpanded] = useState(false); + const drawerRef = useRef(null); const onExpand = () => { drawerRef.current && drawerRef.current.focus(); @@ -43,7 +43,7 @@ export const DrawerModifiedPanelPadding: React.FunctionComponent = () => { 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Phasellus pretium est a porttitor vehicula. Quisque vel commodo urna. Morbi mattis rutrum ante, id vehicula ex accumsan ut. Morbi viverra, eros vel porttitor facilisis, eros purus aliquet erat,nec lobortis felis elit pulvinar sem. Vivamus vulputate, risus eget commodo eleifend, eros nibh porta quam, vitae lacinia leo libero at magna. Maecenas aliquam sagittis orci, et posuere nisi ultrices sit amet. Aliquam ex odio, malesuada sed posuere quis, pellentesque at mauris. Phasellus venenatis massa ex, eget pulvinar libero auctor pretium. Aliquam erat volutpat. Duis euismod justo in quam ullamcorper, in commodo massa vulputate.'; return ( - + @@ -52,6 +52,6 @@ export const DrawerModifiedPanelPadding: React.FunctionComponent = () => { {drawerContent} - + ); }; diff --git a/packages/react-core/src/components/Drawer/examples/DrawerPanelBottom.tsx b/packages/react-core/src/components/Drawer/examples/DrawerPanelBottom.tsx index 27755809295..1b765555597 100644 --- a/packages/react-core/src/components/Drawer/examples/DrawerPanelBottom.tsx +++ b/packages/react-core/src/components/Drawer/examples/DrawerPanelBottom.tsx @@ -1,4 +1,4 @@ -import React from 'react'; +import { Fragment, useRef, useState } from 'react'; import { Drawer, DrawerPanelContent, @@ -11,8 +11,8 @@ import { } from '@patternfly/react-core'; export const DrawerPanelBottom: React.FunctionComponent = () => { - const [isExpanded, setIsExpanded] = React.useState(false); - const drawerRef = React.useRef(); + const [isExpanded, setIsExpanded] = useState(false); + const drawerRef = useRef(null); const onExpand = () => { drawerRef.current && drawerRef.current.focus(); @@ -43,7 +43,7 @@ export const DrawerPanelBottom: React.FunctionComponent = () => { 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Phasellus pretium est a porttitor vehicula. Quisque vel commodo urna. Morbi mattis rutrum ante, id vehicula ex accumsan ut. Morbi viverra, eros vel porttitor facilisis, eros purus aliquet erat,nec lobortis felis elit pulvinar sem. Vivamus vulputate, risus eget commodo eleifend, eros nibh porta quam, vitae lacinia leo libero at magna. Maecenas aliquam sagittis orci, et posuere nisi ultrices sit amet. Aliquam ex odio, malesuada sed posuere quis, pellentesque at mauris. Phasellus venenatis massa ex, eget pulvinar libero auctor pretium. Aliquam erat volutpat. Duis euismod justo in quam ullamcorper, in commodo massa vulputate.'; return ( - + @@ -54,6 +54,6 @@ export const DrawerPanelBottom: React.FunctionComponent = () => {
    - + ); }; diff --git a/packages/react-core/src/components/Drawer/examples/DrawerPanelEnd.tsx b/packages/react-core/src/components/Drawer/examples/DrawerPanelEnd.tsx index ed903b7564c..6c3460ace2f 100644 --- a/packages/react-core/src/components/Drawer/examples/DrawerPanelEnd.tsx +++ b/packages/react-core/src/components/Drawer/examples/DrawerPanelEnd.tsx @@ -1,4 +1,4 @@ -import React from 'react'; +import { Fragment, useRef, useState } from 'react'; import { Drawer, DrawerPanelContent, @@ -11,8 +11,8 @@ import { } from '@patternfly/react-core'; export const DrawerPanelEnd: React.FunctionComponent = () => { - const [isExpanded, setIsExpanded] = React.useState(false); - const drawerRef = React.useRef(); + const [isExpanded, setIsExpanded] = useState(false); + const drawerRef = useRef(null); const onExpand = () => { drawerRef.current && drawerRef.current.focus(); @@ -43,7 +43,7 @@ export const DrawerPanelEnd: React.FunctionComponent = () => { 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Phasellus pretium est a porttitor vehicula. Quisque vel commodo urna. Morbi mattis rutrum ante, id vehicula ex accumsan ut. Morbi viverra, eros vel porttitor facilisis, eros purus aliquet erat,nec lobortis felis elit pulvinar sem. Vivamus vulputate, risus eget commodo eleifend, eros nibh porta quam, vitae lacinia leo libero at magna. Maecenas aliquam sagittis orci, et posuere nisi ultrices sit amet. Aliquam ex odio, malesuada sed posuere quis, pellentesque at mauris. Phasellus venenatis massa ex, eget pulvinar libero auctor pretium. Aliquam erat volutpat. Duis euismod justo in quam ullamcorper, in commodo massa vulputate.'; return ( - + @@ -52,6 +52,6 @@ export const DrawerPanelEnd: React.FunctionComponent = () => { {drawerContent} - + ); }; diff --git a/packages/react-core/src/components/Drawer/examples/DrawerPanelStart.tsx b/packages/react-core/src/components/Drawer/examples/DrawerPanelStart.tsx index b53b36dd3fc..a1acde0be10 100644 --- a/packages/react-core/src/components/Drawer/examples/DrawerPanelStart.tsx +++ b/packages/react-core/src/components/Drawer/examples/DrawerPanelStart.tsx @@ -1,4 +1,4 @@ -import React from 'react'; +import { Fragment, useRef, useState } from 'react'; import { Drawer, DrawerPanelContent, @@ -11,8 +11,8 @@ import { } from '@patternfly/react-core'; export const DrawerPanelStart: React.FunctionComponent = () => { - const [isExpanded, setIsExpanded] = React.useState(false); - const drawerRef = React.useRef(); + const [isExpanded, setIsExpanded] = useState(false); + const drawerRef = useRef(null); const onExpand = () => { drawerRef.current && drawerRef.current.focus(); @@ -43,7 +43,7 @@ export const DrawerPanelStart: React.FunctionComponent = () => { 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Phasellus pretium est a porttitor vehicula. Quisque vel commodo urna. Morbi mattis rutrum ante, id vehicula ex accumsan ut. Morbi viverra, eros vel porttitor facilisis, eros purus aliquet erat,nec lobortis felis elit pulvinar sem. Vivamus vulputate, risus eget commodo eleifend, eros nibh porta quam, vitae lacinia leo libero at magna. Maecenas aliquam sagittis orci, et posuere nisi ultrices sit amet. Aliquam ex odio, malesuada sed posuere quis, pellentesque at mauris. Phasellus venenatis massa ex, eget pulvinar libero auctor pretium. Aliquam erat volutpat. Duis euismod justo in quam ullamcorper, in commodo massa vulputate.'; return ( - + @@ -52,6 +52,6 @@ export const DrawerPanelStart: React.FunctionComponent = () => { {drawerContent} - + ); }; diff --git a/packages/react-core/src/components/Drawer/examples/DrawerPillInline.tsx b/packages/react-core/src/components/Drawer/examples/DrawerPillInline.tsx new file mode 100644 index 00000000000..16ae9532739 --- /dev/null +++ b/packages/react-core/src/components/Drawer/examples/DrawerPillInline.tsx @@ -0,0 +1,57 @@ +import { Fragment, useRef, useState } from 'react'; +import { + Drawer, + DrawerPanelContent, + DrawerContent, + DrawerContentBody, + DrawerHead, + DrawerActions, + DrawerCloseButton, + Button +} from '@patternfly/react-core'; + +export const DrawerBasicPill: React.FunctionComponent = () => { + const [isExpanded, setIsExpanded] = useState(false); + const drawerRef = useRef(null); + + const onExpand = () => { + drawerRef.current && drawerRef.current.focus(); + }; + + const onClick = () => { + setIsExpanded(!isExpanded); + }; + + const onCloseClick = () => { + setIsExpanded(false); + }; + + const panelContent = ( + + + + Drawer panel header + + + + + + + ); + + const drawerContent = + 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Phasellus pretium est a porttitor vehicula. Quisque vel commodo urna. Morbi mattis rutrum ante, id vehicula ex accumsan ut. Morbi viverra, eros vel porttitor facilisis, eros purus aliquet erat,nec lobortis felis elit pulvinar sem. Vivamus vulputate, risus eget commodo eleifend, eros nibh porta quam, vitae lacinia leo libero at magna. Maecenas aliquam sagittis orci, et posuere nisi ultrices sit amet. Aliquam ex odio, malesuada sed posuere quis, pellentesque at mauris. Phasellus venenatis massa ex, eget pulvinar libero auctor pretium. Aliquam erat volutpat. Duis euismod justo in quam ullamcorper, in commodo massa vulputate.'; + + return ( + + + + + {drawerContent} + + + + ); +}; diff --git a/packages/react-core/src/components/Drawer/examples/DrawerResizableAtEnd.tsx b/packages/react-core/src/components/Drawer/examples/DrawerResizableAtEnd.tsx index 59bd56bef16..939fcf4a441 100644 --- a/packages/react-core/src/components/Drawer/examples/DrawerResizableAtEnd.tsx +++ b/packages/react-core/src/components/Drawer/examples/DrawerResizableAtEnd.tsx @@ -1,4 +1,4 @@ -import React from 'react'; +import { Fragment, useRef, useState } from 'react'; import { Drawer, DrawerPanelContent, @@ -11,8 +11,8 @@ import { } from '@patternfly/react-core'; export const DrawerResizableAtEnd: React.FunctionComponent = () => { - const [isExpanded, setIsExpanded] = React.useState(false); - const drawerRef = React.useRef(); + const [isExpanded, setIsExpanded] = useState(false); + const drawerRef = useRef(null); const onExpand = () => { drawerRef.current && drawerRef.current.focus(); @@ -48,7 +48,7 @@ export const DrawerResizableAtEnd: React.FunctionComponent = () => { 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Phasellus pretium est a porttitor vehicula. Quisque vel commodo urna. Morbi mattis rutrum ante, id vehicula ex accumsan ut. Morbi viverra, eros vel porttitor facilisis, eros purus aliquet erat,nec lobortis felis elit pulvinar sem. Vivamus vulputate, risus eget commodo eleifend, eros nibh porta quam, vitae lacinia leo libero at magna. Maecenas aliquam sagittis orci, et posuere nisi ultrices sit amet. Aliquam ex odio, malesuada sed posuere quis, pellentesque at mauris. Phasellus venenatis massa ex, eget pulvinar libero auctor pretium. Aliquam erat volutpat. Duis euismod justo in quam ullamcorper, in commodo massa vulputate.'; return ( - + @@ -57,6 +57,6 @@ export const DrawerResizableAtEnd: React.FunctionComponent = () => { {drawerContent} - + ); }; diff --git a/packages/react-core/src/components/Drawer/examples/DrawerResizableAtStart.tsx b/packages/react-core/src/components/Drawer/examples/DrawerResizableAtStart.tsx index 799aac35007..32e56665aa0 100644 --- a/packages/react-core/src/components/Drawer/examples/DrawerResizableAtStart.tsx +++ b/packages/react-core/src/components/Drawer/examples/DrawerResizableAtStart.tsx @@ -1,4 +1,4 @@ -import React from 'react'; +import { Fragment, useRef, useState } from 'react'; import { Drawer, DrawerPanelContent, @@ -11,8 +11,8 @@ import { } from '@patternfly/react-core'; export const DrawerResizableAtStart: React.FunctionComponent = () => { - const [isExpanded, setIsExpanded] = React.useState(false); - const drawerRef = React.useRef(); + const [isExpanded, setIsExpanded] = useState(false); + const drawerRef = useRef(null); const onExpand = () => { drawerRef.current && drawerRef.current.focus(); @@ -43,7 +43,7 @@ export const DrawerResizableAtStart: React.FunctionComponent = () => { 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Phasellus pretium est a porttitor vehicula. Quisque vel commodo urna. Morbi mattis rutrum ante, id vehicula ex accumsan ut. Morbi viverra, eros vel porttitor facilisis, eros purus aliquet erat,nec lobortis felis elit pulvinar sem. Vivamus vulputate, risus eget commodo eleifend, eros nibh porta quam, vitae lacinia leo libero at magna. Maecenas aliquam sagittis orci, et posuere nisi ultrices sit amet. Aliquam ex odio, malesuada sed posuere quis, pellentesque at mauris. Phasellus venenatis massa ex, eget pulvinar libero auctor pretium. Aliquam erat volutpat. Duis euismod justo in quam ullamcorper, in commodo massa vulputate.'; return ( - + @@ -52,6 +52,6 @@ export const DrawerResizableAtStart: React.FunctionComponent = () => { {drawerContent} - + ); }; diff --git a/packages/react-core/src/components/Drawer/examples/DrawerResizableOnBottom.tsx b/packages/react-core/src/components/Drawer/examples/DrawerResizableOnBottom.tsx index 9dc60ebe612..ecce2daa1ca 100644 --- a/packages/react-core/src/components/Drawer/examples/DrawerResizableOnBottom.tsx +++ b/packages/react-core/src/components/Drawer/examples/DrawerResizableOnBottom.tsx @@ -1,4 +1,4 @@ -import React from 'react'; +import { Fragment, useRef, useState } from 'react'; import { Drawer, DrawerPanelContent, @@ -11,8 +11,8 @@ import { } from '@patternfly/react-core'; export const DrawerResizableOnBottom: React.FunctionComponent = () => { - const [isExpanded, setIsExpanded] = React.useState(false); - const drawerRef = React.useRef(); + const [isExpanded, setIsExpanded] = useState(false); + const drawerRef = useRef(null); const onExpand = () => { drawerRef.current && drawerRef.current.focus(); @@ -42,7 +42,7 @@ export const DrawerResizableOnBottom: React.FunctionComponent = () => { 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Phasellus pretium est a porttitor vehicula. Quisque vel commodo urna. Morbi mattis rutrum ante, id vehicula ex accumsan ut. Morbi viverra, eros vel porttitor facilisis, eros purus aliquet erat,nec lobortis felis elit pulvinar sem. Vivamus vulputate, risus eget commodo eleifend, eros nibh porta quam, vitae lacinia leo libero at magna. Maecenas aliquam sagittis orci, et posuere nisi ultrices sit amet. Aliquam ex odio, malesuada sed posuere quis, pellentesque at mauris. Phasellus venenatis massa ex, eget pulvinar libero auctor pretium. Aliquam erat volutpat. Duis euismod justo in quam ullamcorper, in commodo massa vulputate.'; return ( - + @@ -53,6 +53,6 @@ export const DrawerResizableOnBottom: React.FunctionComponent = () => {
    - + ); }; diff --git a/packages/react-core/src/components/Drawer/examples/DrawerResizableOnInline.tsx b/packages/react-core/src/components/Drawer/examples/DrawerResizableOnInline.tsx index 4dfa95573b4..16299b6db8e 100644 --- a/packages/react-core/src/components/Drawer/examples/DrawerResizableOnInline.tsx +++ b/packages/react-core/src/components/Drawer/examples/DrawerResizableOnInline.tsx @@ -1,4 +1,4 @@ -import React from 'react'; +import { Fragment, useRef, useState } from 'react'; import { Drawer, DrawerPanelContent, @@ -11,8 +11,8 @@ import { } from '@patternfly/react-core'; export const DrawerResizableOnInline: React.FunctionComponent = () => { - const [isExpanded, setIsExpanded] = React.useState(false); - const drawerRef = React.useRef(); + const [isExpanded, setIsExpanded] = useState(false); + const drawerRef = useRef(null); const onExpand = () => { drawerRef.current && drawerRef.current.focus(); @@ -42,7 +42,7 @@ export const DrawerResizableOnInline: React.FunctionComponent = () => { 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Phasellus pretium est a porttitor vehicula. Quisque vel commodo urna. Morbi mattis rutrum ante, id vehicula ex accumsan ut. Morbi viverra, eros vel porttitor facilisis, eros purus aliquet erat,nec lobortis felis elit pulvinar sem. Vivamus vulputate, risus eget commodo eleifend, eros nibh porta quam, vitae lacinia leo libero at magna. Maecenas aliquam sagittis orci, et posuere nisi ultrices sit amet. Aliquam ex odio, malesuada sed posuere quis, pellentesque at mauris. Phasellus venenatis massa ex, eget pulvinar libero auctor pretium. Aliquam erat volutpat. Duis euismod justo in quam ullamcorper, in commodo massa vulputate.'; return ( - + @@ -51,6 +51,6 @@ export const DrawerResizableOnInline: React.FunctionComponent = () => { {drawerContent} - + ); }; diff --git a/packages/react-core/src/components/Drawer/examples/DrawerSecondaryBackground.tsx b/packages/react-core/src/components/Drawer/examples/DrawerSecondaryBackground.tsx index 3ad6042666b..485dff0dcbf 100644 --- a/packages/react-core/src/components/Drawer/examples/DrawerSecondaryBackground.tsx +++ b/packages/react-core/src/components/Drawer/examples/DrawerSecondaryBackground.tsx @@ -1,4 +1,4 @@ -import React from 'react'; +import { Fragment, useRef, useState } from 'react'; import { Checkbox, Drawer, @@ -15,12 +15,12 @@ import { } from '@patternfly/react-core'; export const DrawerSecondaryBackground: React.FunctionComponent = () => { - const [isExpanded, setIsExpanded] = React.useState(false); - const [panelSecondary, setPanelSecondary] = React.useState(true); - const [contentSecondary, setContentSecondary] = React.useState(false); - const [sectionSecondary, setSectionSecondary] = React.useState(false); + const [isExpanded, setIsExpanded] = useState(false); + const [panelSecondary, setPanelSecondary] = useState(true); + const [contentSecondary, setContentSecondary] = useState(false); + const [sectionSecondary, setSectionSecondary] = useState(false); - const drawerRef = React.useRef(null); + const drawerRef = useRef(null); const onExpand = () => { drawerRef.current && drawerRef.current.focus(); @@ -63,7 +63,7 @@ export const DrawerSecondaryBackground: React.FunctionComponent = () => { 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Phasellus pretium est a porttitor vehicula. Quisque vel commodo urna. Morbi mattis rutrum ante, id vehicula ex accumsan ut. Morbi viverra, eros vel porttitor facilisis, eros purus aliquet erat,nec lobortis felis elit pulvinar sem. Vivamus vulputate, risus eget commodo eleifend, eros nibh porta quam, vitae lacinia leo libero at magna. Maecenas aliquam sagittis orci, et posuere nisi ultrices sit amet. Aliquam ex odio, malesuada sed posuere quis, pellentesque at mauris. Phasellus venenatis massa ex, eget pulvinar libero auctor pretium. Aliquam erat volutpat. Duis euismod justo in quam ullamcorper, in commodo massa vulputate.'; return ( - + { {drawerContent} - + ); }; diff --git a/packages/react-core/src/components/Drawer/examples/DrawerStackedContentBodyElements.tsx b/packages/react-core/src/components/Drawer/examples/DrawerStackedContentBodyElements.tsx index 8dc8424c97f..c4f55ddb862 100644 --- a/packages/react-core/src/components/Drawer/examples/DrawerStackedContentBodyElements.tsx +++ b/packages/react-core/src/components/Drawer/examples/DrawerStackedContentBodyElements.tsx @@ -1,4 +1,4 @@ -import React from 'react'; +import { Fragment, useRef, useState } from 'react'; import { Drawer, DrawerPanelContent, @@ -13,8 +13,8 @@ import { } from '@patternfly/react-core'; export const DrawerStackedContentBodyElements: React.FunctionComponent = () => { - const [isExpanded, setIsExpanded] = React.useState(false); - const drawerRef = React.useRef(); + const [isExpanded, setIsExpanded] = useState(false); + const drawerRef = useRef(undefined); const onExpand = () => { drawerRef.current && drawerRef.current.focus(); @@ -44,7 +44,7 @@ export const DrawerStackedContentBodyElements: React.FunctionComponent = () => { ); return ( - + @@ -55,6 +55,6 @@ export const DrawerStackedContentBodyElements: React.FunctionComponent = () => { content-body - + ); }; diff --git a/packages/react-core/src/components/Drawer/examples/DrawerStatic.tsx b/packages/react-core/src/components/Drawer/examples/DrawerStatic.tsx index 3a59dd71935..2f5229223cc 100644 --- a/packages/react-core/src/components/Drawer/examples/DrawerStatic.tsx +++ b/packages/react-core/src/components/Drawer/examples/DrawerStatic.tsx @@ -1,4 +1,4 @@ -import React from 'react'; +import { Fragment, useRef, useState } from 'react'; import { Drawer, DrawerPanelContent, @@ -12,8 +12,8 @@ import { import accessibility from '@patternfly/react-styles/css/utilities/Accessibility/accessibility'; export const DrawerStatic: React.FunctionComponent = () => { - const [isExpanded, setIsExpanded] = React.useState(false); - const drawerRef = React.useRef(); + const [isExpanded, setIsExpanded] = useState(false); + const drawerRef = useRef(null); const onExpand = () => { drawerRef.current && drawerRef.current.focus(); @@ -44,7 +44,7 @@ export const DrawerStatic: React.FunctionComponent = () => { 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Phasellus pretium est a porttitor vehicula. Quisque vel commodo urna. Morbi mattis rutrum ante, id vehicula ex accumsan ut. Morbi viverra, eros vel porttitor facilisis, eros purus aliquet erat,nec lobortis felis elit pulvinar sem. Vivamus vulputate, risus eget commodo eleifend, eros nibh porta quam, vitae lacinia leo libero at magna. Maecenas aliquam sagittis orci, et posuere nisi ultrices sit amet. Aliquam ex odio, malesuada sed posuere quis, pellentesque at mauris. Phasellus venenatis massa ex, eget pulvinar libero auctor pretium. Aliquam erat volutpat. Duis euismod justo in quam ullamcorper, in commodo massa vulputate.'; return ( - + @@ -53,6 +53,6 @@ export const DrawerStatic: React.FunctionComponent = () => { {drawerContent} - + ); }; diff --git a/packages/react-core/src/components/Dropdown/Dropdown.tsx b/packages/react-core/src/components/Dropdown/Dropdown.tsx index 30a54d545ce..80219aebdc3 100644 --- a/packages/react-core/src/components/Dropdown/Dropdown.tsx +++ b/packages/react-core/src/components/Dropdown/Dropdown.tsx @@ -1,33 +1,18 @@ -import React from 'react'; +import { forwardRef, useEffect, useRef } from 'react'; import { css } from '@patternfly/react-styles'; import { Menu, MenuContent, MenuProps } from '../Menu'; -import { Popper } from '../../helpers/Popper/Popper'; -import { useOUIAProps, OUIAProps } from '../../helpers'; - -export interface DropdownPopperProps { - /** Vertical direction of the popper. If enableFlip is set to true, this will set the initial direction before the popper flips. */ - direction?: 'up' | 'down'; - /** Horizontal position of the popper */ - position?: 'right' | 'left' | 'center' | 'start' | 'end'; - /** Custom width of the popper. If the value is "trigger", it will set the width to the dropdown toggle's width */ - width?: string | 'trigger'; - /** Minimum width of the popper. If the value is "trigger", it will set the min width to the dropdown toggle's width */ - minWidth?: string | 'trigger'; - /** Maximum width of the popper. If the value is "trigger", it will set the max width to the dropdown toggle's width */ - maxWidth?: string | 'trigger'; - /** Enable to flip the popper when it reaches the boundary */ - enableFlip?: boolean; - /** The container to append the popper to. Defaults to document.body. */ - appendTo?: HTMLElement | (() => HTMLElement) | 'inline'; - /** Flag to prevent the popper from overflowing its container and becoming partially obscured. */ - preventOverflow?: boolean; -} +import { Popper, PopperOptions } from '../../helpers/Popper/Popper'; +import type { DropdownItemProps } from './DropdownItem'; +import { useOUIAProps, OUIAProps, onToggleArrowKeydownDefault } from '../../helpers'; + +/** @deprecated Use PopperOptions instead */ +export type DropdownPopperProps = PopperOptions; export interface DropdownToggleProps { /** Dropdown toggle node. */ toggleNode: React.ReactNode; /** Reference to the toggle. */ - toggleRef?: React.RefObject; + toggleRef?: React.RefObject; } /** @@ -45,12 +30,14 @@ export interface DropdownProps extends MenuProps, OUIAProps { /** Flag indicating the toggle should be focused after a selection. If this use case is too restrictive, the optional toggleRef property with a node toggle may be used to control focus. */ shouldFocusToggleOnSelect?: boolean; /** Function callback called when user selects item. */ - onSelect?: (event?: React.MouseEvent, value?: string | number) => void; + onSelect?: (event?: React.MouseEvent, value?: DropdownItemProps['value']) => void; /** Callback to allow the dropdown component to change the open state of the menu. - * Triggered by clicking outside of the menu, or by pressing any keys specificed in onOpenChangeKeys. */ + * Triggered by clicking outside of the menu, or by pressing any keys specified in onOpenChangeKeys. */ onOpenChange?: (isOpen: boolean) => void; /** Keys that trigger onOpenChange, defaults to tab and escape. It is highly recommended to include Escape in the array, while Tab may be omitted if the menu contains non-menu items that are focusable. */ onOpenChangeKeys?: string[]; + /** Callback to override the toggle keydown behavior. By default, when the toggle has focus and the menu is open, pressing the up/down arrow keys will focus a valid non-disabled menu item - the first item for the down arrow key and last item for the up arrow key. */ + onToggleKeydown?: (event: KeyboardEvent) => void; /** Indicates if the menu should be without the outer box-shadow. */ isPlain?: boolean; /** Indicates if the menu should be scrollable. */ @@ -61,16 +48,26 @@ export interface DropdownProps extends MenuProps, OUIAProps { ouiaId?: number | string; /** Set the value of data-ouia-safe. Only set to true when the component is in a static state, i.e. no animations are occurring. At all other times, this value must be false. */ ouiaSafe?: boolean; + /** When applied, wraps dropdown in a container with a data-ouia-component-id.*/ + containerOuiaId?: number | string; + /** Set the value of data-ouia-safe for the container when containerOuiaId is applied. Only set to true when the component is in a static state, i.e. no animations are occurring. At all other times, this value must be false. */ + containerOuiaSafe?: boolean; + /** Sets the base component to render for the container. Defaults to */ + containerComponent?: React.ReactNode; /** z-index of the dropdown menu */ zIndex?: number; /** Additional properties to pass to the Popper */ - popperProps?: DropdownPopperProps; + popperProps?: PopperOptions; /** Height of the dropdown menu */ menuHeight?: string; /** Maximum height of dropdown menu */ maxMenuHeight?: string; /** @beta Flag indicating the first menu item should be focused after opening the dropdown. */ shouldFocusFirstItemOnOpen?: boolean; + /** Flag indicating if scroll on focus of the first menu item should occur. */ + shouldPreventScrollOnItemFocus?: boolean; + /** Time in ms to wait before firing the toggles' focus event. Defaults to 0 */ + focusTimeoutDelay?: number; } const DropdownBase: React.FunctionComponent = ({ @@ -81,6 +78,7 @@ const DropdownBase: React.FunctionComponent = ({ toggle, shouldFocusToggleOnSelect = false, onOpenChange, + onToggleKeydown, isPlain, isScrollable, innerRef, @@ -91,36 +89,43 @@ const DropdownBase: React.FunctionComponent = ({ onOpenChangeKeys = ['Escape', 'Tab'], menuHeight, maxMenuHeight, - shouldFocusFirstItemOnOpen = true, + shouldFocusFirstItemOnOpen = false, + shouldPreventScrollOnItemFocus = true, + focusTimeoutDelay = 0, + containerOuiaId, + containerOuiaSafe = true, + containerComponent = 'span', ...props }: DropdownProps) => { - const localMenuRef = React.useRef(); - const localToggleRef = React.useRef(); + const localMenuRef = useRef(undefined); + const localToggleRef = useRef(undefined); const ouiaProps = useOUIAProps(Dropdown.displayName, ouiaId, ouiaSafe); + const ContainerComponent = containerComponent as any; + const containerOuiaProps = useOUIAProps('Dropdown container', containerOuiaId, containerOuiaSafe); - const menuRef = (innerRef as React.RefObject) || localMenuRef; + const menuRef = (innerRef as React.RefObject) || localMenuRef; const toggleRef = typeof toggle === 'function' || (typeof toggle !== 'function' && !toggle.toggleRef) ? localToggleRef - : (toggle?.toggleRef as React.RefObject); + : (toggle?.toggleRef as React.RefObject); - const prevIsOpen = React.useRef(isOpen); - React.useEffect(() => { + const prevIsOpen = useRef(isOpen); + useEffect(() => { // menu was opened, focus on first menu item if (prevIsOpen.current === false && isOpen === true && shouldFocusFirstItemOnOpen) { setTimeout(() => { const firstElement = menuRef?.current?.querySelector( 'li button:not(:disabled),li input:not(:disabled),li a:not([aria-disabled="true"])' ); - firstElement && (firstElement as HTMLElement).focus(); - }, 0); + firstElement && (firstElement as HTMLElement).focus({ preventScroll: shouldPreventScrollOnItemFocus }); + }, focusTimeoutDelay); } prevIsOpen.current = isOpen; // eslint-disable-next-line react-hooks/exhaustive-deps }, [isOpen]); - React.useEffect(() => { + useEffect(() => { const handleMenuKeys = (event: KeyboardEvent) => { // Close the menu on tab or escape if onOpenChange is provided if ( @@ -133,6 +138,14 @@ const DropdownBase: React.FunctionComponent = ({ toggleRef.current?.focus(); } } + + if (toggleRef.current?.contains(event.target as Node)) { + if (onToggleKeydown) { + onToggleKeydown(event); + } else if (isOpen) { + onToggleArrowKeydownDefault(event, menuRef); + } + } }; const handleClick = (event: MouseEvent) => { @@ -151,7 +164,17 @@ const DropdownBase: React.FunctionComponent = ({ window.removeEventListener('keydown', handleMenuKeys); window.removeEventListener('click', handleClick); }; - }, [isOpen, menuRef, toggleRef, onOpenChange, onOpenChangeKeys]); + }, [ + isOpen, + menuRef, + toggleRef, + onOpenChange, + onOpenChangeKeys, + onToggleKeydown, + shouldPreventScrollOnItemFocus, + shouldFocusFirstItemOnOpen, + focusTimeoutDelay + ]); const scrollable = maxMenuHeight !== undefined || menuHeight !== undefined || isScrollable; @@ -161,7 +184,7 @@ const DropdownBase: React.FunctionComponent = ({ ref={menuRef} onSelect={(event, value) => { onSelect && onSelect(event, value); - shouldFocusToggleOnSelect && toggleRef.current.focus(); + shouldFocusToggleOnSelect && toggleRef.current?.focus(); }} isPlain={isPlain} isScrollable={scrollable} @@ -173,7 +196,8 @@ const DropdownBase: React.FunctionComponent = ({ ); - return ( + + const popper = ( = ({ {...popperProps} /> ); + + return containerOuiaId ? {popper} : popper; }; -export const Dropdown = React.forwardRef((props: DropdownProps, ref: React.Ref) => ( +export const Dropdown = forwardRef((props: DropdownProps, ref: React.Ref) => ( )); Dropdown.displayName = 'Dropdown'; diff --git a/packages/react-core/src/components/Dropdown/DropdownGroup.tsx b/packages/react-core/src/components/Dropdown/DropdownGroup.tsx index 721e6216071..17aef30c5c2 100644 --- a/packages/react-core/src/components/Dropdown/DropdownGroup.tsx +++ b/packages/react-core/src/components/Dropdown/DropdownGroup.tsx @@ -1,4 +1,3 @@ -import React from 'react'; import { css } from '@patternfly/react-styles'; import { MenuGroupProps, MenuGroup } from '../Menu'; @@ -11,7 +10,7 @@ export interface DropdownGroupProps extends Omit { /** Classes applied to root element of dropdown group */ className?: string; /** Label of the dropdown group */ - label?: string; + label?: React.ReactNode; } export const DropdownGroup: React.FunctionComponent = ({ diff --git a/packages/react-core/src/components/Dropdown/DropdownItem.tsx b/packages/react-core/src/components/Dropdown/DropdownItem.tsx index d6cf6e127c1..0c973f45e9e 100644 --- a/packages/react-core/src/components/Dropdown/DropdownItem.tsx +++ b/packages/react-core/src/components/Dropdown/DropdownItem.tsx @@ -1,4 +1,4 @@ -import React from 'react'; +import { forwardRef } from 'react'; import { css } from '@patternfly/react-styles'; import { MenuItemProps, MenuItem } from '../Menu'; import { TooltipProps } from '../Tooltip'; @@ -65,7 +65,7 @@ const DropdownItemBase: React.FunctionComponent = ({ ); }; -export const DropdownItem = React.forwardRef( +export const DropdownItem = forwardRef( (props: DropdownItemProps, ref: React.Ref) => ( ) diff --git a/packages/react-core/src/components/Dropdown/DropdownList.tsx b/packages/react-core/src/components/Dropdown/DropdownList.tsx index e591d1ae3f0..8f9b8fac4f0 100644 --- a/packages/react-core/src/components/Dropdown/DropdownList.tsx +++ b/packages/react-core/src/components/Dropdown/DropdownList.tsx @@ -1,4 +1,3 @@ -import React from 'react'; import { css } from '@patternfly/react-styles'; import { MenuListProps, MenuList } from '../Menu'; diff --git a/packages/react-core/src/components/Dropdown/__tests__/Dropdown.test.tsx b/packages/react-core/src/components/Dropdown/__tests__/Dropdown.test.tsx index 09951f3ee11..b8b78399fe5 100644 --- a/packages/react-core/src/components/Dropdown/__tests__/Dropdown.test.tsx +++ b/packages/react-core/src/components/Dropdown/__tests__/Dropdown.test.tsx @@ -1,4 +1,3 @@ -import React from 'react'; import { Dropdown } from '../../Dropdown'; import { render, screen } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; @@ -202,6 +201,32 @@ test('onOpenChange is called when passed and user presses esc key', async () => expect(onOpenChange).toBeCalledTimes(1); }); +test('applies containerOuiaId to parent element', () => { + render( + toggle(toggleRef)}> + {dropdownChildren} + + ); + + const dropdownToggle = screen.getByRole('button', { name: 'Dropdown' }); + const dropdownParent = dropdownToggle?.parentNode?.parentNode; + expect(dropdownParent).toHaveAttribute('data-ouia-component-id', 'test-dropdown'); + expect(dropdownParent).toHaveAttribute('data-ouia-component-type', 'PF6/Dropdown container'); + expect(dropdownParent?.tagName).toBe('SPAN'); +}); + +test('Renders with custom container element when containerComponent is passed', () => { + render( + toggle(toggleRef)}> + {dropdownChildren} + + ); + + const dropdownToggle = screen.getByRole('button', { name: 'Dropdown' }); + const dropdownParent = dropdownToggle?.parentNode?.parentNode; + expect(dropdownParent?.tagName).toBe('DIV'); +}); + test('match snapshot', () => { const { asFragment } = render( Dropdown Group children
    ; diff --git a/packages/react-core/src/components/Dropdown/__tests__/DropdownItem.test.tsx b/packages/react-core/src/components/Dropdown/__tests__/DropdownItem.test.tsx index a016915e514..e70b5ca8667 100644 --- a/packages/react-core/src/components/Dropdown/__tests__/DropdownItem.test.tsx +++ b/packages/react-core/src/components/Dropdown/__tests__/DropdownItem.test.tsx @@ -1,7 +1,5 @@ import { DropdownItem } from '../../Dropdown'; import { render, screen } from '@testing-library/react'; -import React from 'react'; - jest.mock('../../Menu'); const dropdownItemChildren =
    Dropdown Item children
    ; diff --git a/packages/react-core/src/components/Dropdown/__tests__/DropdownList.test.tsx b/packages/react-core/src/components/Dropdown/__tests__/DropdownList.test.tsx index ba9a61ee650..be2cdf8316a 100644 --- a/packages/react-core/src/components/Dropdown/__tests__/DropdownList.test.tsx +++ b/packages/react-core/src/components/Dropdown/__tests__/DropdownList.test.tsx @@ -1,7 +1,5 @@ import { DropdownList } from '../../Dropdown'; import { render, screen } from '@testing-library/react'; -import React from 'react'; - jest.mock('../../Menu'); const dropdownListChildren =
    Dropdown List children
    ; diff --git a/packages/react-core/src/components/Dropdown/examples/Dropdown.md b/packages/react-core/src/components/Dropdown/examples/Dropdown.md index f7efe1bff52..d0b8a472153 100644 --- a/packages/react-core/src/components/Dropdown/examples/Dropdown.md +++ b/packages/react-core/src/components/Dropdown/examples/Dropdown.md @@ -2,7 +2,7 @@ id: Dropdown section: components subsection: menus -cssPrefix: pf-v5-c-menu +cssPrefix: pf-v6-c-menu propComponents: [ 'Dropdown', @@ -11,12 +11,13 @@ propComponents: 'DropdownList', 'MenuToggle', 'DropdownToggleProps', - 'DropdownPopperProps', - 'TooltipProps' + 'TooltipProps', + 'PopperOptions' ] --- -import EllipsisVIcon from '@patternfly/react-icons/dist/esm/icons/ellipsis-v-icon'; +import { useState, useRef } from 'react'; +import RhUiEllipsisVerticalFillIcon from '@patternfly/react-icons/dist/esm/icons/rh-ui-ellipsis-vertical-fill-icon'; ## Examples @@ -62,3 +63,15 @@ To provide users with more context about a ``, pass a short messag ```ts file="./DropdownWithDescriptions.tsx" ``` + +### Split toggle with checkbox + +To combine a checkbox or other control with a dropdown menu, use a split button. + +A `` can be rendered as a split button via `splitButtonItems`. Elements to be displayed before the dropdown toggle button (like the ``) must be included in the `splitButtonItems`. + +If the dropdown menu closes upon selection, you will need to manually shift focus back to the toggle element after a user selects an item from the menu. + +```ts file="./DropdownWithSplit.tsx" + +``` diff --git a/packages/react-core/src/components/Dropdown/examples/DropdownBasic.tsx b/packages/react-core/src/components/Dropdown/examples/DropdownBasic.tsx index d5948281fe2..846a846a0b4 100644 --- a/packages/react-core/src/components/Dropdown/examples/DropdownBasic.tsx +++ b/packages/react-core/src/components/Dropdown/examples/DropdownBasic.tsx @@ -1,8 +1,8 @@ -import React from 'react'; +import { useState } from 'react'; import { Dropdown, DropdownItem, DropdownList, Divider, MenuToggle, MenuToggleElement } from '@patternfly/react-core'; export const DropdownBasic: React.FunctionComponent = () => { - const [isOpen, setIsOpen] = React.useState(false); + const [isOpen, setIsOpen] = useState(false); const onToggleClick = () => { setIsOpen(!isOpen); diff --git a/packages/react-core/src/components/Dropdown/examples/DropdownWithDescriptions.tsx b/packages/react-core/src/components/Dropdown/examples/DropdownWithDescriptions.tsx index 751dccbf546..2cd8eb484a0 100644 --- a/packages/react-core/src/components/Dropdown/examples/DropdownWithDescriptions.tsx +++ b/packages/react-core/src/components/Dropdown/examples/DropdownWithDescriptions.tsx @@ -1,8 +1,8 @@ -import React from 'react'; +import { useState } from 'react'; import { Dropdown, DropdownItem, DropdownList, MenuToggle, MenuToggleElement } from '@patternfly/react-core'; export const DropdownWithDescriptions: React.FunctionComponent = () => { - const [isOpen, setIsOpen] = React.useState(false); + const [isOpen, setIsOpen] = useState(false); const onToggleClick = () => { setIsOpen(!isOpen); diff --git a/packages/react-core/src/components/Dropdown/examples/DropdownWithGroups.tsx b/packages/react-core/src/components/Dropdown/examples/DropdownWithGroups.tsx index 5664eb5a8f3..7a68605eda1 100644 --- a/packages/react-core/src/components/Dropdown/examples/DropdownWithGroups.tsx +++ b/packages/react-core/src/components/Dropdown/examples/DropdownWithGroups.tsx @@ -1,4 +1,4 @@ -import React from 'react'; +import { useState } from 'react'; import { Dropdown, DropdownGroup, @@ -10,7 +10,7 @@ import { } from '@patternfly/react-core'; export const DropdownWithGroups: React.FunctionComponent = () => { - const [isOpen, setIsOpen] = React.useState(false); + const [isOpen, setIsOpen] = useState(false); const onToggleClick = () => { setIsOpen(!isOpen); diff --git a/packages/react-core/src/components/Dropdown/examples/DropdownWithKebabToggle.tsx b/packages/react-core/src/components/Dropdown/examples/DropdownWithKebabToggle.tsx index 759a4b8c8a6..6673220f376 100644 --- a/packages/react-core/src/components/Dropdown/examples/DropdownWithKebabToggle.tsx +++ b/packages/react-core/src/components/Dropdown/examples/DropdownWithKebabToggle.tsx @@ -1,9 +1,9 @@ -import React from 'react'; +import { useState } from 'react'; import { Dropdown, DropdownItem, DropdownList, Divider, MenuToggle, MenuToggleElement } from '@patternfly/react-core'; -import EllipsisVIcon from '@patternfly/react-icons/dist/esm/icons/ellipsis-v-icon'; +import RhUiEllipsisVerticalFillIcon from '@patternfly/react-icons/dist/esm/icons/rh-ui-ellipsis-vertical-fill-icon'; export const DropdownWithKebab: React.FunctionComponent = () => { - const [isOpen, setIsOpen] = React.useState(false); + const [isOpen, setIsOpen] = useState(false); const onToggleClick = () => { setIsOpen(!isOpen); @@ -27,9 +27,8 @@ export const DropdownWithKebab: React.FunctionComponent = () => { variant="plain" onClick={onToggleClick} isExpanded={isOpen} - > - - + icon={} + /> )} shouldFocusToggleOnSelect > diff --git a/packages/react-core/src/components/Dropdown/examples/DropdownWithSplit.tsx b/packages/react-core/src/components/Dropdown/examples/DropdownWithSplit.tsx new file mode 100644 index 00000000000..140a99510cd --- /dev/null +++ b/packages/react-core/src/components/Dropdown/examples/DropdownWithSplit.tsx @@ -0,0 +1,97 @@ +import { + Dropdown, + MenuToggle, + MenuToggleCheckbox, + DropdownItem, + DropdownList, + Divider, + MenuToggleElement +} from '@patternfly/react-core'; +import { useRef, useState } from 'react'; + +export const DropdownSplitButtonText: React.FunctionComponent = () => { + const [isOpen, setIsOpen] = useState(false); + const toggleRef = useRef(null); + + const onFocus = () => { + if (!toggleRef.current) { + return; + } + + const toggleButton = toggleRef.current.querySelector('button[aria-expanded]'); + toggleButton?.focus(); + }; + + const onSelect = () => { + setIsOpen(false); + onFocus(); + }; + + const onToggleClick = () => { + setIsOpen(!isOpen); + }; + + return ( + setIsOpen(isOpen)} + toggle={(toggleRefCallback: React.Ref) => ( + { + // Handle both callback ref and useRef + if (typeof toggleRefCallback === 'function') { + toggleRefCallback(node); + } else if (toggleRefCallback) { + (toggleRefCallback as React.MutableRefObject).current = node; + } + (toggleRef as React.MutableRefObject).current = node; + }} + splitButtonItems={[ + + ]} + aria-label="Dropdown with checkbox split button" + onClick={onToggleClick} + isExpanded={isOpen} + /> + )} + isOpen={isOpen} + > + + + Action + + ev.preventDefault()} + > + Link + + + Disabled Action + + + Disabled Link + + + Aria-disabled Link + + + + Separated Action + + ev.preventDefault()}> + Separated Link + + + + ); +}; diff --git a/packages/react-core/src/components/DualListSelector/DualListSelector.tsx b/packages/react-core/src/components/DualListSelector/DualListSelector.tsx index 2663f3fc74e..1c21c05f3f4 100644 --- a/packages/react-core/src/components/DualListSelector/DualListSelector.tsx +++ b/packages/react-core/src/components/DualListSelector/DualListSelector.tsx @@ -1,8 +1,8 @@ -import * as React from 'react'; import styles from '@patternfly/react-styles/css/components/DualListSelector/dual-list-selector'; import { css } from '@patternfly/react-styles'; -import { GenerateId, PickOptional } from '../../helpers'; +import { useSSRSafeId } from '../../helpers'; import { DualListSelectorContext } from './DualListSelectorContext'; +import { useHasAnimations } from '../../helpers'; /** Acts as a container for all other DualListSelector sub-components when using a * composable dual list selector. @@ -17,34 +17,34 @@ export interface DualListSelectorProps { isTree?: boolean; /** Content to be rendered in the dual list selector. */ children?: React.ReactNode; + /** Flag indicating whether a tree dual list selector has animations. This will always render + * nested dual list selector items rather than dynamically rendering them. This prop will be removed in + * the next breaking change release in favor of defaulting to always-rendered items. + */ + hasAnimations?: boolean; } -class DualListSelector extends React.Component { - static displayName = 'DualListSelector'; - static defaultProps: PickOptional = { - children: '', - isTree: false - }; +export const DualListSelector: React.FunctionComponent = ({ + className, + children, + id, + isTree = false, + hasAnimations: hasAnimationsProp, + ...props +}: DualListSelectorProps) => { + const hasAnimations = useHasAnimations(hasAnimationsProp); + const randomId = useSSRSafeId(); - constructor(props: DualListSelectorProps) { - super(props); - } - - render() { - const { className, children, id, isTree, ...props } = this.props; - - return ( - - - {(randomId) => ( -
    - {children} -
    - )} -
    -
    - ); - } -} - -export { DualListSelector }; + return ( + +
    + {children} +
    +
    + ); +}; +DualListSelector.displayName = 'DualListSelector'; diff --git a/packages/react-core/src/components/DualListSelector/DualListSelectorContext.ts b/packages/react-core/src/components/DualListSelector/DualListSelectorContext.ts index 3eccc9a0dc6..9ace87d2817 100644 --- a/packages/react-core/src/components/DualListSelector/DualListSelectorContext.ts +++ b/packages/react-core/src/components/DualListSelector/DualListSelectorContext.ts @@ -1,10 +1,10 @@ -import * as React from 'react'; - -export const DualListSelectorContext = React.createContext<{ +import { createContext } from 'react'; +export const DualListSelectorContext = createContext<{ isTree?: boolean; -}>({ isTree: false }); + hasAnimations?: boolean; +}>({ isTree: false, hasAnimations: false }); -export const DualListSelectorListContext = React.createContext<{ +export const DualListSelectorListContext = createContext<{ setFocusedOption?: (id: string) => void; isTree?: boolean; ariaLabelledBy?: string; @@ -16,6 +16,6 @@ export const DualListSelectorListContext = React.createContext<{ isDisabled?: boolean; }>({}); -export const DualListSelectorPaneContext = React.createContext<{ +export const DualListSelectorPaneContext = createContext<{ isChosen: boolean; }>({ isChosen: false }); diff --git a/packages/react-core/src/components/DualListSelector/DualListSelectorControl.tsx b/packages/react-core/src/components/DualListSelector/DualListSelectorControl.tsx index 94c90eafb46..1781fa3d664 100644 --- a/packages/react-core/src/components/DualListSelector/DualListSelectorControl.tsx +++ b/packages/react-core/src/components/DualListSelector/DualListSelectorControl.tsx @@ -1,4 +1,4 @@ -import * as React from 'react'; +import { forwardRef, useRef } from 'react'; import { css } from '@patternfly/react-styles'; import { Button, ButtonVariant } from '../Button'; import { Tooltip } from '../Tooltip'; @@ -41,7 +41,7 @@ export const DualListSelectorControlBase: React.FunctionComponent { - const privateRef = React.useRef(null); + const privateRef = useRef(null); const ref = innerRef || privateRef; return (
    @@ -63,7 +63,7 @@ export const DualListSelectorControlBase: React.FunctionComponent) => ( +export const DualListSelectorControl = forwardRef((props: DualListSelectorControlProps, ref: React.Ref) => ( )); diff --git a/packages/react-core/src/components/DualListSelector/DualListSelectorControlsWrapper.tsx b/packages/react-core/src/components/DualListSelector/DualListSelectorControlsWrapper.tsx index ee36d662a0c..3f9fcba50d7 100644 --- a/packages/react-core/src/components/DualListSelector/DualListSelectorControlsWrapper.tsx +++ b/packages/react-core/src/components/DualListSelector/DualListSelectorControlsWrapper.tsx @@ -1,4 +1,4 @@ -import * as React from 'react'; +import { forwardRef, useEffect, useRef } from 'react'; import styles from '@patternfly/react-styles/css/components/DualListSelector/dual-list-selector'; import { css } from '@patternfly/react-styles'; import { handleArrows } from '../../helpers'; @@ -11,7 +11,7 @@ export interface DualListSelectorControlsWrapperProps extends React.HTMLProps; + innerRef?: React.RefObject; /** Accessible label for the dual list selector controls wrapper. */ 'aria-label'?: string; } @@ -23,7 +23,7 @@ export const DualListSelectorControlsWrapperBase: React.FunctionComponent { - const ref = React.useRef(null); + const ref = useRef(null); const wrapperRef = innerRef || ref; // Adds keyboard navigation to the dynamically built dual list selector controls. Works when controls are dynamically built // as well as when they are passed in via children. @@ -55,7 +55,7 @@ export const DualListSelectorControlsWrapperBase: React.FunctionComponent { + useEffect(() => { window.addEventListener('keydown', handleKeys); return () => { window.removeEventListener('keydown', handleKeys); @@ -78,7 +78,7 @@ export const DualListSelectorControlsWrapperBase: React.FunctionComponent) => ( } role="group" {...props} /> ) diff --git a/packages/react-core/src/components/DualListSelector/DualListSelectorList.tsx b/packages/react-core/src/components/DualListSelector/DualListSelectorList.tsx index c339870ade3..96287bdc7b8 100644 --- a/packages/react-core/src/components/DualListSelector/DualListSelectorList.tsx +++ b/packages/react-core/src/components/DualListSelector/DualListSelectorList.tsx @@ -1,7 +1,7 @@ +import { forwardRef, useContext } from 'react'; import { css } from '@patternfly/react-styles'; import styles from '@patternfly/react-styles/css/components/DualListSelector/dual-list-selector'; import { DualListSelectorListItem } from './DualListSelectorListItem'; -import * as React from 'react'; import { DualListSelectorListContext } from './DualListSelectorContext'; /** Acts as the container for DualListSelectorListItem sub-components. */ @@ -10,7 +10,7 @@ export interface DualListSelectorListProps extends React.HTMLProps; + innerRef?: React.RefObject; } export const DualListSelectorListBase: React.FunctionComponent = ({ @@ -19,7 +19,7 @@ export const DualListSelectorListBase: React.FunctionComponent { const { isTree, ariaLabelledBy, focusedOption, displayOption, selectedOptions, id, options, isDisabled } = - React.useContext(DualListSelectorListContext); + useContext(DualListSelectorListContext); const hasOptions = () => options.length !== 0 || (children !== undefined && (children as React.ReactNode[]).length !== 0); @@ -60,10 +60,8 @@ export const DualListSelectorListBase: React.FunctionComponent) => ( - } {...props} /> - ) -); +export const DualListSelectorList = forwardRef((props: DualListSelectorListProps, ref: React.Ref) => ( + } {...props} /> +)); DualListSelectorList.displayName = 'DualListSelectorList'; diff --git a/packages/react-core/src/components/DualListSelector/DualListSelectorListItem.tsx b/packages/react-core/src/components/DualListSelector/DualListSelectorListItem.tsx index 28ecdffe7fa..38ec88ceb05 100644 --- a/packages/react-core/src/components/DualListSelector/DualListSelectorListItem.tsx +++ b/packages/react-core/src/components/DualListSelector/DualListSelectorListItem.tsx @@ -1,8 +1,8 @@ -import * as React from 'react'; +import { forwardRef, useContext, useRef } from 'react'; import styles from '@patternfly/react-styles/css/components/DualListSelector/dual-list-selector'; import { css } from '@patternfly/react-styles'; -import { getUniqueId } from '../../helpers'; -import GripVerticalIcon from '@patternfly/react-icons/dist/esm/icons/grip-vertical-icon'; +import { useSSRSafeId } from '../../helpers'; +import RhUiGripVerticalFillIcon from '@patternfly/react-icons/dist/esm/icons/rh-ui-grip-vertical-fill-icon'; import { Button, ButtonVariant } from '../Button'; import { DualListSelectorListContext } from './DualListSelectorContext'; @@ -24,7 +24,7 @@ export interface DualListSelectorListItemProps extends React.HTMLProps; + innerRef?: React.RefObject; /** Flag indicating this item is draggable for reordering. */ isDraggable?: boolean; /** Accessible label for the draggable button on draggable list items. */ @@ -38,7 +38,7 @@ export const DualListSelectorListItemBase: React.FunctionComponent { - const privateRef = React.useRef(null); + const generatedId = useSSRSafeId('dual-list-selector-list-item'); + const id = idProp ?? generatedId; + const privateRef = useRef(null); const ref = innerRef || privateRef; - const { setFocusedOption } = React.useContext(DualListSelectorListContext); + const { setFocusedOption } = useContext(DualListSelectorListContext); return (
  • } + icon={} />
  • )} @@ -99,7 +101,7 @@ export const DualListSelectorListItemBase: React.FunctionComponent) => ( } {...props} /> ) diff --git a/packages/react-core/src/components/DualListSelector/DualListSelectorListWrapper.tsx b/packages/react-core/src/components/DualListSelector/DualListSelectorListWrapper.tsx index a284f4f02f6..e4f8bcb73f5 100644 --- a/packages/react-core/src/components/DualListSelector/DualListSelectorListWrapper.tsx +++ b/packages/react-core/src/components/DualListSelector/DualListSelectorListWrapper.tsx @@ -1,7 +1,7 @@ -import * as React from 'react'; +import { forwardRef, useContext, useEffect, useRef, useState } from 'react'; import styles from '@patternfly/react-styles/css/components/DualListSelector/dual-list-selector'; import { css } from '@patternfly/react-styles'; -import { getUniqueId, handleArrows } from '../../helpers'; +import { handleArrows, useSSRSafeId } from '../../helpers'; import { DualListSelectorList } from './DualListSelectorList'; import { DualListSelectorContext, DualListSelectorListContext } from './DualListSelectorContext'; @@ -15,7 +15,7 @@ export interface DualListSelectorListWrapperProps extends React.HTMLProps; + innerRef?: React.RefObject; /** @hide Options to list in the pane. */ options?: React.ReactNode[]; /** @hide Options currently selected in the pane. */ @@ -34,14 +34,16 @@ export const DualListSelectorListWrapperBase: React.FunctionComponent { - const [focusedOption, setFocusedOption] = React.useState(''); - const ref = React.useRef(null); + const generatedId = useSSRSafeId('dual-list-selector-list'); + const id = idProp ?? generatedId; + const [focusedOption, setFocusedOption] = useState(''); + const ref = useRef(null); const menuRef = innerRef || ref; - const { isTree } = React.useContext(DualListSelectorContext); + const { isTree } = useContext(DualListSelectorContext); // Sets up keyboard focus handling for the dual list selector menu child of the pane. const handleKeys = (event: KeyboardEvent) => { @@ -56,14 +58,17 @@ export const DualListSelectorListWrapperBase: React.FunctionComponent input` - ) - ) as Element[]) + ? ( + Array.from( + menuRef.current.querySelectorAll( + `.${styles.dualListSelectorItemToggle}, .${styles.dualListSelectorItemCheck} > input` + ) + ) as Element[] + ).filter((item) => !item.closest(`.${styles.dualListSelectorList}[inert]`)) : (Array.from(menuRef.current.getElementsByTagName('LI')) as Element[]).filter( (el) => !el.classList.contains('pf-m-disabled') ); + const activeElement = document.activeElement; handleArrows( event, @@ -85,7 +90,7 @@ export const DualListSelectorListWrapperBase: React.FunctionComponent { + useEffect(() => { window.addEventListener('keydown', handleKeys); return () => { window.removeEventListener('keydown', handleKeys); @@ -115,7 +120,7 @@ export const DualListSelectorListWrapperBase: React.FunctionComponent) => ( } {...props} /> ) diff --git a/packages/react-core/src/components/DualListSelector/DualListSelectorPane.tsx b/packages/react-core/src/components/DualListSelector/DualListSelectorPane.tsx index 8011cee0a5d..c7b9a8f98a6 100644 --- a/packages/react-core/src/components/DualListSelector/DualListSelectorPane.tsx +++ b/packages/react-core/src/components/DualListSelector/DualListSelectorPane.tsx @@ -1,7 +1,6 @@ -import * as React from 'react'; import styles from '@patternfly/react-styles/css/components/DualListSelector/dual-list-selector'; import { css } from '@patternfly/react-styles'; -import { getUniqueId } from '../../helpers'; +import { useSSRSafeId } from '../../helpers'; import { DualListSelectorListWrapper } from './DualListSelectorListWrapper'; import { DualListSelectorPaneContext } from './DualListSelectorContext'; import { SearchInput } from '../SearchInput'; @@ -45,50 +44,54 @@ export const DualListSelectorPane: React.FunctionComponent ( -
    - {title && ( -
    -
    -
    {title}
    +}: DualListSelectorPaneProps) => { + const generatedId = useSSRSafeId('dual-list-selector-pane'); + const id = idProp ?? generatedId; + return ( +
    + {title && ( +
    +
    +
    {title}
    +
    +
    + )} + {(actions || searchInput) && ( +
    + {searchInput && ( +
    + {searchInput ? searchInput : } +
    + )} + {actions &&
    {actions}
    }
    -
    - )} - {(actions || searchInput) && ( -
    - {searchInput && ( -
    - {searchInput ? searchInput : } + )} + {status && ( +
    +
    + {status}
    - )} - {actions &&
    {actions}
    } -
    - )} - {status && ( -
    -
    - {status}
    -
    - )} - - - {children} - - -
    -); + )} + + + {children} + + +
    + ); +}; DualListSelectorPane.displayName = 'DualListSelectorPane'; diff --git a/packages/react-core/src/components/DualListSelector/DualListSelectorTree.tsx b/packages/react-core/src/components/DualListSelector/DualListSelectorTree.tsx index 8fb28a289b9..e2a8bf57031 100644 --- a/packages/react-core/src/components/DualListSelector/DualListSelectorTree.tsx +++ b/packages/react-core/src/components/DualListSelector/DualListSelectorTree.tsx @@ -1,6 +1,7 @@ -import * as React from 'react'; +import { useContext } from 'react'; import { css } from '@patternfly/react-styles'; import styles from '@patternfly/react-styles/css/components/DualListSelector/dual-list-selector'; +import { DualListSelectorContext } from './DualListSelectorContext'; import { DualListSelectorTreeItem } from './DualListSelectorTreeItem'; export interface DualListSelectorTreeItemData { @@ -69,11 +70,13 @@ export const DualListSelectorTree: React.FunctionComponent { + const { hasAnimations } = useContext(DualListSelectorContext); const dataToRender = typeof data === 'function' ? data() : data; const tree = dataToRender.map((item) => ( { /** Content rendered inside the dual list selector. */ @@ -38,6 +39,11 @@ export interface DualListSelectorTreeItemProps extends React.HTMLProps = ({ @@ -53,18 +59,29 @@ const DualListSelectorTreeItemBase: React.FunctionComponent { - const ref = React.useRef(null); - const [isExpanded, setIsExpanded] = React.useState(defaultExpanded || false); - const { setFocusedOption } = React.useContext(DualListSelectorListContext); + const ref = useRef(null); + const [isExpanded, setIsExpanded] = useState(defaultExpanded || false); + const { setFocusedOption } = useContext(DualListSelectorListContext); + const hasAnimations = useHasAnimations(hasAnimationsProp); - React.useEffect(() => { + useEffect(() => { setIsExpanded(defaultExpanded); }, [defaultExpanded]); + const clonedChildren = Children.map( + children, + (child) => + isValidElement(child) && + cloneElement(child as React.ReactElement, { + inert: isExpanded ? undefined : '' + }) + ); + return (
  • - +
  • )} @@ -138,7 +155,9 @@ const DualListSelectorTreeItemBase: React.FunctionComponent elem && (elem.indeterminate = isChecked === null)} + ref={(elem) => { + elem && (elem.indeterminate = isChecked === null); + }} checked={isChecked || false} tabIndex={-1} {...checkProps} @@ -148,18 +167,18 @@ const DualListSelectorTreeItemBase: React.FunctionComponent{text} {hasBadge && children && ( - {flattenTree((children as React.ReactElement).props.data).length} + {flattenTree((children as React.ReactElement).props.data).length} )}
    - {isExpanded && children} + {(isExpanded || hasAnimations) && clonedChildren} ); }; -export const DualListSelectorTreeItem = React.memo(DualListSelectorTreeItemBase, (prevProps, nextProps) => { +export const DualListSelectorTreeItem = memo(DualListSelectorTreeItemBase, (prevProps, nextProps) => { if (!nextProps.useMemo) { return false; } diff --git a/packages/react-core/src/components/DualListSelector/__tests__/DualListSelector.test.tsx b/packages/react-core/src/components/DualListSelector/__tests__/DualListSelector.test.tsx index 373aa0e993d..3d3601fe8a1 100644 --- a/packages/react-core/src/components/DualListSelector/__tests__/DualListSelector.test.tsx +++ b/packages/react-core/src/components/DualListSelector/__tests__/DualListSelector.test.tsx @@ -1,8 +1,65 @@ -import { render } from '@testing-library/react'; +import { render, screen } from '@testing-library/react'; +import styles from '@patternfly/react-styles/css/components/DualListSelector/dual-list-selector'; +import { DualListSelector } from '../DualListSelector'; import { DualListSelectorPane } from '../DualListSelectorPane'; import { SearchInput } from '../../SearchInput'; -import React from 'react'; +import { AnimationsProvider } from '../../../helpers/AnimationsProvider'; +// The following tests can be removed as part of https://github.com/patternfly/patternfly-react/issues/11838 +describe('Opt-in animations', () => { + test(`Does not render with class ${styles.modifiers.animateExpand} by default`, () => { + render(); + + expect(screen.getByTestId('test-id')).not.toHaveClass(styles.modifiers.animateExpand); + }); + + test(`Does not render with class ${styles.modifiers.animateExpand} when hasAnimations is true and isTree is false`, () => { + render(); + + expect(screen.getByTestId('test-id')).not.toHaveClass(styles.modifiers.animateExpand); + }); + + test(`Does not render with class ${styles.modifiers.animateExpand} by default when isTree is true`, () => { + render(); + + expect(screen.getByTestId('test-id')).not.toHaveClass(styles.modifiers.animateExpand); + }); + + test(`Renders with class ${styles.modifiers.animateExpand} when both isTree and hasAnimations are true`, () => { + render(); + + expect(screen.getByTestId('test-id')).toHaveClass(styles.modifiers.animateExpand); + }); + + // Animation context tests + test('respects AnimationsProvider context when no local hasAnimations prop', () => { + render( + + + + ); + + expect(screen.getByTestId('test-id')).toHaveClass(styles.modifiers.animateExpand); + }); + + test('local hasAnimations prop takes precedence over context', () => { + render( + + + + ); + + expect(screen.getByTestId('test-id')).not.toHaveClass(styles.modifiers.animateExpand); + }); + + test('works without AnimationsProvider (backward compatibility)', () => { + render(); + + expect(screen.getByTestId('test-id')).not.toHaveClass(styles.modifiers.animateExpand); + }); +}); + +// Following tests should be moved to a separate DualListSelectorPane test file describe('DualListSelector', () => { test('basic', () => { const { asFragment } = render(); diff --git a/packages/react-core/src/components/DualListSelector/__tests__/DualListSelectorTreeItem.test.tsx b/packages/react-core/src/components/DualListSelector/__tests__/DualListSelectorTreeItem.test.tsx new file mode 100644 index 00000000000..87ec2df53da --- /dev/null +++ b/packages/react-core/src/components/DualListSelector/__tests__/DualListSelectorTreeItem.test.tsx @@ -0,0 +1,55 @@ +import { render, screen } from '@testing-library/react'; +import styles from '@patternfly/react-styles/css/components/DualListSelector/dual-list-selector'; +import { DualListSelectorTreeItem } from '../DualListSelectorTreeItem'; + +// The following tests checking for children to not be/to be rendered will need to be refactored +// as part of https://github.com/patternfly/patternfly-react/issues/11838 +test('Does not render children by default', () => { + render( + +
    Children content
    +
    + ); + + expect(screen.queryByText('Children content')).not.toBeInTheDocument(); +}); + +test('Renders children when defaultExpanded is true', () => { + render( + +
    Children content
    +
    + ); + + expect(screen.getByText('Children content')).toBeVisible(); +}); + +test('Renders children when hasAnimations is true', () => { + render( + +
    Children content
    +
    + ); + + expect(screen.getByText('Children content')).toBeVisible(); +}); + +test('Renders children with inert attribute by default when hasAnimations is true', () => { + render( + +
    Children content
    +
    + ); + + expect(screen.getByText('Children content')).toHaveAttribute('inert', ''); +}); + +test('Does not render children with inert attribute when hasAnimations and defaultExpanded are true', () => { + render( + +
    Children content
    +
    + ); + + expect(screen.getByText('Children content')).not.toHaveAttribute('inert'); +}); diff --git a/packages/react-core/src/components/DualListSelector/__tests__/__snapshots__/DualListSelector.test.tsx.snap b/packages/react-core/src/components/DualListSelector/__tests__/__snapshots__/DualListSelector.test.tsx.snap index 63dab5eee9e..f9529ee933f 100644 --- a/packages/react-core/src/components/DualListSelector/__tests__/__snapshots__/DualListSelector.test.tsx.snap +++ b/packages/react-core/src/components/DualListSelector/__tests__/__snapshots__/DualListSelector.test.tsx.snap @@ -90,12 +90,24 @@ exports[`DualListSelector with search inputs 1`] = ` fill="currentColor" height="1em" role="img" - viewBox="0 0 512 512" width="1em" > - + + + + + + ` component with ``, define the `variant` property as "DualListSelectorList", and pass both the sortable items and `onDrop` callback to ``. `` will create the component's usual children internally based on the items property, so children inside the `` should not be passed to the wrapped component. -- wrap the `DualListSelectorPane` in a `DragDrop` component -- wrap the `DualListSelectorList` in a `Droppable` component -- wrap the `DualListSelectorListItem` components in a `Draggable` component -- define an `onDrop` callback which reorders the sortable options. - - The `onDrop` function provides the starting location and destination location for a dragged item. It should return - true to enable the 'drop' animation in the new location and false to enable the 'drop' animation back to the item's - old position. - - define an `onDrag` callback which ensures that the drag event will not cross hairs with the `onOptionSelect` click - event set on the option. Note: the `ignoreNextOptionSelect` state value is used to prevent selection while dragging. +Full drag and drop details can be found on the [drag and drop](/components/drag-and-drop) component page. -Note: Keyboard accessibility and screen reader accessibility for the `DragDrop` component are still in development. +```ts file="../../../../../react-drag-drop/src/components/DragDrop/examples/DualListSelectorDraggable.tsx" -```ts file="DualListSelectorDragDrop.tsx" +``` + +### Draggable with multiple drop zones + +To enable multiple drop zones, wrap the `` component with ``, and create the desired amount of `` components within ``. `` components should be located where `` usually would go for each pane to be made draggable. + +Each `` should define the `wrapper` property as the component that acts as the drop zone, ``, and the `items` property of their respective draggable items as an array of `` data. `` should be passed the `onDrop`, `onContainerMove`, and `onCancel` callbacks to handle items being dropped, items moving between droppable containers, and what happens if the drag is cancelled respectively. `` should also be given a `Record` representing all sortable drop zones' items. Both components should define the `variant` property as "DualListSelectorList". + +Full drag and drop details can be found on the [drag and drop](/components/drag-and-drop) component page. + +```ts file="../../../../../react-drag-drop/src/components/DragDrop/examples/DragDropContainerDualListSelector.tsx" ``` diff --git a/packages/react-core/src/components/DualListSelector/examples/DualListSelectorBasic.tsx b/packages/react-core/src/components/DualListSelector/examples/DualListSelectorBasic.tsx index ec14a043dc2..f4ccc948759 100644 --- a/packages/react-core/src/components/DualListSelector/examples/DualListSelectorBasic.tsx +++ b/packages/react-core/src/components/DualListSelector/examples/DualListSelectorBasic.tsx @@ -1,4 +1,4 @@ -import React from 'react'; +import { useState } from 'react'; import { DualListSelector, DualListSelectorPane, @@ -7,7 +7,7 @@ import { DualListSelectorControlsWrapper, DualListSelectorControl } from '@patternfly/react-core'; -import AngleDoubleLeftIcon from '@patternfly/react-icons/dist/esm/icons/angle-double-left-icon'; +import RhMicronsDoubleCaretLeftIcon from '@patternfly/react-icons/dist/esm/icons/rh-microns-double-caret-left-icon'; import AngleLeftIcon from '@patternfly/react-icons/dist/esm/icons/angle-left-icon'; import AngleDoubleRightIcon from '@patternfly/react-icons/dist/esm/icons/angle-double-right-icon'; import AngleRightIcon from '@patternfly/react-icons/dist/esm/icons/angle-right-icon'; @@ -19,13 +19,13 @@ interface Option { } export const DualListSelectorBasic: React.FunctionComponent = () => { - const [availableOptions, setAvailableOptions] = React.useState([ + const [availableOptions, setAvailableOptions] = useState([ { text: 'Option 1', selected: false, isVisible: true }, { text: 'Option 2', selected: false, isVisible: true }, { text: 'Option 3', selected: false, isVisible: true }, { text: 'Option 4', selected: false, isVisible: true } ]); - const [chosenOptions, setChosenOptions] = React.useState([]); + const [chosenOptions, setChosenOptions] = useState([]); // callback for moving selected options between lists const moveSelected = (fromAvailable: boolean) => { @@ -117,7 +117,7 @@ export const DualListSelectorBasic: React.FunctionComponent = () => { isDisabled={chosenOptions.length === 0} onClick={() => moveAll(false)} aria-label="Remove all" - icon={} + icon={} /> moveSelected(false)} diff --git a/packages/react-core/src/components/DualListSelector/examples/DualListSelectorBasicSearch.tsx b/packages/react-core/src/components/DualListSelector/examples/DualListSelectorBasicSearch.tsx index e395b2bc8bc..c5d6b1af9a9 100644 --- a/packages/react-core/src/components/DualListSelector/examples/DualListSelectorBasicSearch.tsx +++ b/packages/react-core/src/components/DualListSelector/examples/DualListSelectorBasicSearch.tsx @@ -1,4 +1,4 @@ -import React from 'react'; +import { useState } from 'react'; import { Button, DualListSelector, @@ -14,7 +14,7 @@ import { EmptyStateBody, EmptyStateActions } from '@patternfly/react-core'; -import AngleDoubleLeftIcon from '@patternfly/react-icons/dist/esm/icons/angle-double-left-icon'; +import RhMicronsDoubleCaretLeftIcon from '@patternfly/react-icons/dist/esm/icons/rh-microns-double-caret-left-icon'; import AngleLeftIcon from '@patternfly/react-icons/dist/esm/icons/angle-left-icon'; import AngleDoubleRightIcon from '@patternfly/react-icons/dist/esm/icons/angle-double-right-icon'; import AngleRightIcon from '@patternfly/react-icons/dist/esm/icons/angle-right-icon'; @@ -27,16 +27,16 @@ interface Option { } export const DualListSelectorSearch: React.FunctionComponent = () => { - const [availableOptions, setAvailableOptions] = React.useState([ + const [availableOptions, setAvailableOptions] = useState([ { text: 'Option 1', selected: false, isVisible: true }, { text: 'Option 2', selected: false, isVisible: true }, { text: 'Option 3', selected: false, isVisible: true }, { text: 'Option 4', selected: false, isVisible: true } ]); - const [chosenOptions, setChosenOptions] = React.useState([]); - const [availableFilter, setAvailableFilter] = React.useState(''); - const [chosenFilter, setChosenFilter] = React.useState(''); + const [chosenOptions, setChosenOptions] = useState([]); + const [availableFilter, setAvailableFilter] = useState(''); + const [chosenFilter, setChosenFilter] = useState(''); // callback for moving selected options between lists const moveSelected = (fromAvailable: boolean) => { @@ -102,6 +102,7 @@ export const DualListSelectorSearch: React.FunctionComponent = () => { value={isAvailable ? availableFilter : chosenFilter} onChange={(_event, value) => onFilterChange(value, isAvailable)} onClear={() => onFilterChange('', isAvailable)} + aria-label={isAvailable ? 'Search available options' : 'Search chosen options'} /> ); @@ -164,7 +165,7 @@ export const DualListSelectorSearch: React.FunctionComponent = () => { isDisabled={chosenOptions.length === 0} onClick={() => moveAll(false)} aria-label="Remove all" - icon={} + icon={} /> moveSelected(false)} diff --git a/packages/react-core/src/components/DualListSelector/examples/DualListSelectorBasicTooltips.tsx b/packages/react-core/src/components/DualListSelector/examples/DualListSelectorBasicTooltips.tsx index aac0b2f9c45..39377a8f0dd 100644 --- a/packages/react-core/src/components/DualListSelector/examples/DualListSelectorBasicTooltips.tsx +++ b/packages/react-core/src/components/DualListSelector/examples/DualListSelectorBasicTooltips.tsx @@ -1,4 +1,4 @@ -import React from 'react'; +import { useState } from 'react'; import { DualListSelector, DualListSelectorPane, @@ -7,7 +7,7 @@ import { DualListSelectorControlsWrapper, DualListSelectorControl } from '@patternfly/react-core'; -import AngleDoubleLeftIcon from '@patternfly/react-icons/dist/esm/icons/angle-double-left-icon'; +import RhMicronsDoubleCaretLeftIcon from '@patternfly/react-icons/dist/esm/icons/rh-microns-double-caret-left-icon'; import AngleLeftIcon from '@patternfly/react-icons/dist/esm/icons/angle-left-icon'; import AngleDoubleRightIcon from '@patternfly/react-icons/dist/esm/icons/angle-double-right-icon'; import AngleRightIcon from '@patternfly/react-icons/dist/esm/icons/angle-right-icon'; @@ -19,13 +19,13 @@ interface Option { } export const DualListSelectorBasic: React.FunctionComponent = () => { - const [availableOptions, setAvailableOptions] = React.useState([ + const [availableOptions, setAvailableOptions] = useState([ { text: 'Option 1', selected: false, isVisible: true }, { text: 'Option 2', selected: false, isVisible: true }, { text: 'Option 3', selected: false, isVisible: true }, { text: 'Option 4', selected: false, isVisible: true } ]); - const [chosenOptions, setChosenOptions] = React.useState([]); + const [chosenOptions, setChosenOptions] = useState([]); // callback for moving selected options between lists const moveSelected = (fromAvailable: boolean) => { @@ -123,7 +123,7 @@ export const DualListSelectorBasic: React.FunctionComponent = () => { aria-label="Remove all" tooltipContent="Remove all" tooltipProps={{ position: 'left', 'aria-live': 'off' }} - icon={} + icon={} /> moveSelected(false)} diff --git a/packages/react-core/src/components/DualListSelector/examples/DualListSelectorComplexOptionsActions.tsx b/packages/react-core/src/components/DualListSelector/examples/DualListSelectorComplexOptionsActions.tsx index 81b66c9197e..5480a8fa90a 100644 --- a/packages/react-core/src/components/DualListSelector/examples/DualListSelectorComplexOptionsActions.tsx +++ b/packages/react-core/src/components/DualListSelector/examples/DualListSelectorComplexOptionsActions.tsx @@ -1,4 +1,4 @@ -import React from 'react'; +import { Fragment, useState } from 'react'; import { Button, ButtonVariant, @@ -21,13 +21,13 @@ import { MenuToggle, MenuToggleElement } from '@patternfly/react-core'; -import AngleDoubleLeftIcon from '@patternfly/react-icons/dist/esm/icons/angle-double-left-icon'; +import RhMicronsDoubleCaretLeftIcon from '@patternfly/react-icons/dist/esm/icons/rh-microns-double-caret-left-icon'; import AngleLeftIcon from '@patternfly/react-icons/dist/esm/icons/angle-left-icon'; import AngleDoubleRightIcon from '@patternfly/react-icons/dist/esm/icons/angle-double-right-icon'; import AngleRightIcon from '@patternfly/react-icons/dist/esm/icons/angle-right-icon'; -import PficonSortCommonAscIcon from '@patternfly/react-icons/dist/esm/icons/pficon-sort-common-asc-icon'; +import RhMicronsSortDownSmallToLargeIcon from '@patternfly/react-icons/dist/esm/icons/rh-microns-sort-down-small-to-large-icon'; import SearchIcon from '@patternfly/react-icons/dist/esm/icons/search-icon'; -import EllipsisVIcon from '@patternfly/react-icons/dist/esm/icons/ellipsis-v-icon'; +import RhUiEllipsisVerticalFillIcon from '@patternfly/react-icons/dist/esm/icons/rh-ui-ellipsis-vertical-fill-icon'; interface Option { text: string; @@ -36,19 +36,19 @@ interface Option { } export const DualListSelectorComplexOptionsActionsNext: React.FunctionComponent = () => { - const [availableOptions, setAvailableOptions] = React.useState([ + const [availableOptions, setAvailableOptions] = useState([ { text: 'Option 1', selected: false, isVisible: true }, { text: 'Option 2', selected: false, isVisible: true }, { text: 'Option 3', selected: false, isVisible: true }, { text: 'Option 4', selected: false, isVisible: true } ]); - const [chosenOptions, setChosenOptions] = React.useState([]); - const [isAvailableKebabOpen, setIsAvailableKebabOpen] = React.useState(false); - const [isChosenKebabOpen, setIsChosenKebabOpen] = React.useState(false); - const [availableFilter, setAvailableFilter] = React.useState(''); - const [chosenFilter, setChosenFilter] = React.useState(''); - const [isDisabled, setIsDisabled] = React.useState(false); + const [chosenOptions, setChosenOptions] = useState([]); + const [isAvailableKebabOpen, setIsAvailableKebabOpen] = useState(false); + const [isChosenKebabOpen, setIsChosenKebabOpen] = useState(false); + const [availableFilter, setAvailableFilter] = useState(''); + const [chosenFilter, setChosenFilter] = useState(''); + const [isDisabled, setIsDisabled] = useState(false); // callback for moving selected options between lists const moveSelected = (fromAvailable: boolean) => { @@ -115,6 +115,7 @@ export const DualListSelectorComplexOptionsActionsNext: React.FunctionComponent onChange={(_event, value) => onFilterChange(value, isAvailable)} onClear={() => onFilterChange('', isAvailable)} isDisabled={isDisabled} + aria-label={isAvailable ? 'Search available options' : 'Search chosen options'} /> ); @@ -154,7 +155,7 @@ export const DualListSelectorComplexOptionsActionsNext: React.FunctionComponent aria-label="Sort Available" key="availableSortButton" isDisabled={isDisabled} - icon={} + icon={} />, ) => ( @@ -166,9 +167,8 @@ export const DualListSelectorComplexOptionsActionsNext: React.FunctionComponent variant="plain" id="complex-available-toggle" aria-label="Complex actions example available kebab toggle" - > -
    diff --git a/packages/react-core/src/components/EmptyState/__tests__/__snapshots__/EmptyState.test.tsx.snap b/packages/react-core/src/components/EmptyState/__tests__/__snapshots__/EmptyState.test.tsx.snap index 9523427e3e7..68a1da19621 100644 --- a/packages/react-core/src/components/EmptyState/__tests__/__snapshots__/EmptyState.test.tsx.snap +++ b/packages/react-core/src/components/EmptyState/__tests__/__snapshots__/EmptyState.test.tsx.snap @@ -40,11 +40,11 @@ exports[`EmptyState Header with icon 1`] = ` fill="currentColor" height="1em" role="img" - viewBox="0 0 448 512" + viewBox="0 0 32 32" width="1em" >
    @@ -94,9 +94,8 @@ exports[`EmptyState Main 1`] = ` class="pf-v6-c-empty-state__actions" > -
    - ); + const computedToggleContent = + typeof toggleContent === 'function' ? toggleContent(propOrStateIsExpanded) : toggleContent; + const ToggleWrapper = toggleWrapper as any; return ( -
    + {(genContentId) => ( + + {(genToggleId) => { + const uniqueContentId = contentId || genContentId; + const uniqueToggleId = toggleId || genToggleId; + + const expandableToggle = !isDetached && ( + + + + ); + + return ( +
    + {variant === ExpandableSectionVariant.default && expandableToggle} + + {variant === ExpandableSectionVariant.truncate && this.state.hasToggle && expandableToggle} +
    + ); + }} +
    )} - {...props} - > - {variant === ExpandableSectionVariant.default && expandableToggle} - - {variant === ExpandableSectionVariant.truncate && this.state.hasToggle && expandableToggle} -
    + ); } } diff --git a/packages/react-core/src/components/ExpandableSection/ExpandableSectionToggle.tsx b/packages/react-core/src/components/ExpandableSection/ExpandableSectionToggle.tsx index 490ac2b5615..2d06651d986 100644 --- a/packages/react-core/src/components/ExpandableSection/ExpandableSectionToggle.tsx +++ b/packages/react-core/src/components/ExpandableSection/ExpandableSectionToggle.tsx @@ -1,14 +1,13 @@ -import * as React from 'react'; import styles from '@patternfly/react-styles/css/components/ExpandableSection/expandable-section'; import { css } from '@patternfly/react-styles'; -import AngleRightIcon from '@patternfly/react-icons/dist/esm/icons/angle-right-icon'; +import RhMicronsCaretDownIcon from '@patternfly/react-icons/dist/esm/icons/rh-microns-caret-down-icon'; import { Button } from '../Button'; /** Acts as the toggle sub-component when the main expandable section component has the isDetached * property passed in. Allows for more custom control over the expandable section's toggle. */ -export interface ExpandableSectionToggleProps extends React.HTMLProps { +export interface ExpandableSectionToggleProps extends Omit, 'onToggle'> { /** Content rendered inside the expandable toggle. */ children?: React.ReactNode; /** Additional classes added to the expandable toggle. */ @@ -29,6 +28,17 @@ export interface ExpandableSectionToggleProps extends React.HTMLProps void; + /** Flag indicating that the expandable section and expandable toggle are detached from one another. */ + isDetached?: boolean; + /** Accessible name via human readable string for the expandable section toggle. */ + toggleAriaLabel?: string; + /** Accessible name via space delimtted list of IDs for the expandable section toggle. */ + toggleAriaLabelledBy?: string; + /** The HTML element to use for the toggle wrapper. Can be 'div' (default) or any heading level. + * When using heading elements, the button will be rendered inside the heading for proper semantics. + * This is useful when the toggle text should function as a heading in the document structure. + */ + toggleWrapper?: 'div' | 'h1' | 'h2' | 'h3' | 'h4' | 'h5' | 'h6'; } export const ExpandableSectionToggle: React.FunctionComponent = ({ @@ -40,42 +50,53 @@ export const ExpandableSectionToggle: React.FunctionComponent ( -
    -
    - +}: ExpandableSectionToggleProps) => { + const ToggleWrapper = toggleWrapper as any; + + return ( +
    + + +
    -
    -); + ); +}; ExpandableSectionToggle.displayName = 'ExpandableSectionToggle'; diff --git a/packages/react-core/src/components/ExpandableSection/__tests__/ExpandableSection.test.tsx b/packages/react-core/src/components/ExpandableSection/__tests__/ExpandableSection.test.tsx index 2392923267c..06d16370775 100644 --- a/packages/react-core/src/components/ExpandableSection/__tests__/ExpandableSection.test.tsx +++ b/packages/react-core/src/components/ExpandableSection/__tests__/ExpandableSection.test.tsx @@ -1,10 +1,9 @@ -import * as React from 'react'; - import { render, screen } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; import { ExpandableSection, ExpandableSectionVariant } from '../ExpandableSection'; -import { ExpandableSectionToggle } from '../ExpandableSectionToggle'; +import styles from '@patternfly/react-styles/css/components/ExpandableSection/expandable-section'; +import RhUiNotificationFillIcon from '@patternfly/react-icons/dist/esm/icons/rh-ui-notification-fill-icon'; const props = { contentId: 'content-id', toggleId: 'toggle-id' }; @@ -23,7 +22,7 @@ test('Renders ExpandableSection expanded', () => { expect(asFragment()).toMatchSnapshot(); }); -test('ExpandableSection onToggle called', async () => { +test('Calls onToggle when clicked', async () => { const mockfn = jest.fn(); const user = userEvent.setup(); @@ -33,6 +32,21 @@ test('ExpandableSection onToggle called', async () => { expect(mockfn.mock.calls).toHaveLength(1); }); +test('Does not call onToggle when not clicked', async () => { + const mockfn = jest.fn(); + const user = userEvent.setup(); + + render( + <> + test + + + ); + + await user.click(screen.getByRole('button', { name: 'Test clicker' })); + expect(mockfn).not.toHaveBeenCalled(); +}); + test('Renders Uncontrolled ExpandableSection', () => { const { asFragment } = render( @@ -43,20 +57,6 @@ test('Renders Uncontrolled ExpandableSection', () => { expect(asFragment()).toMatchSnapshot(); }); -test('Detached ExpandableSection renders successfully', () => { - const { asFragment } = render( - - - test - - - Toggle text - - - ); - expect(asFragment()).toMatchSnapshot(); -}); - test('Disclosure ExpandableSection', () => { const { asFragment } = render( @@ -76,22 +76,22 @@ test('Renders ExpandableSection indented', () => { expect(asFragment()).toMatchSnapshot(); }); -test('Does not render with pf-m-truncate class when variant is not passed', () => { +test(`Does not render with ${styles.modifiers.truncate} class when variant is not passed`, () => { render(test); - expect(screen.getByText('test').parentElement).not.toHaveClass('pf-m-truncate'); + expect(screen.getByText('test').parentElement).not.toHaveClass(styles.modifiers.truncate); }); -test('Does not render with pf-m-truncate class when variant is not truncate', () => { +test(`Does not render with ${styles.modifiers.truncate} class when variant is not truncate`, () => { render(test); - expect(screen.getByText('test').parentElement).not.toHaveClass('pf-m-truncate'); + expect(screen.getByText('test').parentElement).not.toHaveClass(styles.modifiers.truncate); }); -test('Renders with pf-m-truncate class when variant is truncate', () => { +test(`Renders with ${styles.modifiers.truncate} class when variant is truncate`, () => { render(test); - expect(screen.getByText('test').parentElement).toHaveClass('pf-m-truncate'); + expect(screen.getByText('test').parentElement).toHaveClass(styles.modifiers.truncate); }); test('Renders with value passed to contentId', () => { @@ -130,3 +130,179 @@ test('Renders with ARIA attributes when contentId and toggleId are passed', () = expect(wrapper).toContainHTML('aria-labelledby="toggle-id"'); expect(wrapper).toContainHTML('aria-controls="content-id"'); }); + +test(`Does not render with classes ${styles.modifiers.expandTop} nor ${styles.modifiers.expandBottom} by default`, () => { + render(Test content); + + expect(screen.getByText('Test content').parentElement).not.toHaveClass('pf-m-expand-top'); + expect(screen.getByText('Test content').parentElement).not.toHaveClass('pf-m-expand-bottom'); +}); + +test(`Does not render with classes ${styles.modifiers.expandTop} nor ${styles.modifiers.expandBottom} when only isDetached is true`, () => { + render(Test content); + + expect(screen.getByText('Test content').parentElement).not.toHaveClass('pf-m-expand-top'); + expect(screen.getByText('Test content').parentElement).not.toHaveClass('pf-m-expand-bottom'); +}); + +test(`Does not render with class ${styles.modifiers.expandTop} when direction="up" and isDetached is false`, () => { + render(Test content); + + expect(screen.getByText('Test content').parentElement).not.toHaveClass('pf-m-expand-top'); +}); + +test(`Does not render with class ${styles.modifiers.expandBottom} when direction="down" and isDetached is false`, () => { + render(Test content); + + expect(screen.getByText('Test content').parentElement).not.toHaveClass('pf-m-expand-bottom'); +}); + +test(`Renders with class ${styles.modifiers.expandTop} when isDetached is true and direction="up"`, () => { + render( + + Test content + + ); + + expect(screen.getByText('Test content').parentElement).toHaveClass('pf-m-expand-top'); +}); + +test(`Renders with class ${styles.modifiers.expandBottom} when isDetached is true and direction="down"`, () => { + render( + + Test content + + ); + + expect(screen.getByText('Test content').parentElement).toHaveClass('pf-m-expand-bottom'); +}); + +test('Does not render with class pf-m-detached when isDetached is true and direction is not passed', () => { + render(Test content); + + expect(screen.getByText('Test content').parentElement).not.toHaveClass('pf-m-detached'); +}); + +test('Renders with class pf-m-detached when isDetached is true and direction is passed', () => { + render( + + Test content + + ); + + expect(screen.getByText('Test content').parentElement).toHaveClass('pf-m-detached'); +}); + +test('Renders with aria-label when toggleAriaLabel is passed', () => { + render(); + + expect(screen.getByRole('button')).toHaveAccessibleName('Test label'); +}); + +test('Renders with aria-labelledby when toggleAriaLabelledBy is passed', () => { + render( + <> +
    Test label
    + + + ); + + expect(screen.getByRole('button')).toHaveAccessibleName('Test label'); +}); + +test('Renders toggleContent as a function in uncontrolled mode (collapsed)', () => { + render( + (isExpanded ? 'Hide details' : 'Show details')}> + Test content + + ); + + expect(screen.getByRole('button', { name: 'Show details' })).toBeInTheDocument(); +}); + +test('Renders toggleContent as a function in uncontrolled mode (expanded after click)', async () => { + const user = userEvent.setup(); + + render( + (isExpanded ? 'Hide details' : 'Show details')}> + Test content + + ); + + const button = screen.getByRole('button', { name: 'Show details' }); + await user.click(button); + + expect(screen.getByRole('button', { name: 'Hide details' })).toBeInTheDocument(); +}); + +test('Renders toggleContent as a function in controlled mode', () => { + render( + (isExpanded ? 'Collapse' : 'Expand')}> + Test content + + ); + + expect(screen.getByRole('button', { name: 'Collapse' })).toBeInTheDocument(); +}); + +test('Renders with default div wrapper when toggleWrapper is not specified', () => { + render(Test content); + + const toggle = screen.getByRole('button').parentElement; + expect(toggle?.tagName).toBe('DIV'); +}); + +test('Renders with h2 wrapper when toggleWrapper="h2"', () => { + render( + + Test content + + ); + + expect(screen.getByRole('heading', { level: 2 })).toBeInTheDocument(); +}); + +test('Renders with div wrapper when toggleWrapper="div"', () => { + render( + + Test content + + ); + + const toggle = screen.getByRole('button').parentElement; + expect(toggle?.tagName).toBe('DIV'); +}); + +test('Can render custom toggle icon', () => { + render( + }> + Test content + + ); + + expect(screen.getByTestId('bell-icon')).toBeInTheDocument(); +}); + +test('Does not render toggle icon when hasToggleIcon is false', () => { + render(Test content); + + const button = screen.getByRole('button'); + expect(button.querySelector('.pf-v6-c-expandable-section__toggle-icon')).not.toBeInTheDocument(); +}); + +test('Does not render custom toggle icon when hasToggleIcon is false', () => { + render( + } hasToggleIcon={false}> + Test content + + ); + + expect(screen.queryByTestId('bell-icon')).not.toBeInTheDocument(); +}); + +test('Renders toggle icon by default when hasToggleIcon is true', () => { + render(Test content); + + const button = screen.getByRole('button'); + expect(button.querySelector('.pf-v6-c-expandable-section__toggle-icon')).toBeInTheDocument(); +}); diff --git a/packages/react-core/src/components/ExpandableSection/__tests__/ExpandableSectionToggle.test.tsx b/packages/react-core/src/components/ExpandableSection/__tests__/ExpandableSectionToggle.test.tsx new file mode 100644 index 00000000000..9757132e6fa --- /dev/null +++ b/packages/react-core/src/components/ExpandableSection/__tests__/ExpandableSectionToggle.test.tsx @@ -0,0 +1,77 @@ +import { render, screen } from '@testing-library/react'; +import userEvent from '@testing-library/user-event'; +import { ExpandableSectionToggle } from '../ExpandableSectionToggle'; +import styles from '@patternfly/react-styles/css/components/ExpandableSection/expandable-section'; + +test('Renders without children', () => { + render(); + + expect(screen.getByRole('button')).toBeInTheDocument(); +}); + +test('Renders with children', () => { + render(Toggle test); + + expect(screen.getByRole('button')).toHaveTextContent('Toggle test'); +}); + +test('Does not render with class pf-m-detached by default', () => { + render(Toggle test); + + expect(screen.getByTestId('test-id')).not.toHaveClass('pf-m-detached'); +}); + +test('Renders with class pf-m-detached when isDetached is true', () => { + render( + + Toggle test + + ); + + expect(screen.getByTestId('test-id')).toHaveClass('pf-m-detached'); +}); + +test('Renders with aria-label when toggleAriaLabel is passed', () => { + render(); + + expect(screen.getByRole('button')).toHaveAccessibleName('Test label'); +}); + +test('Renders with aria-labelledby when toggleAriaLabelledBy is passed', () => { + render( + <> +
    Test label
    + + + ); + + expect(screen.getByRole('button')).toHaveAccessibleName('Test label'); +}); + +test('Renders with default div wrapper when toggleWrapper is not specified', () => { + render(Toggle test); + + const toggle = screen.getByRole('button').parentElement; + expect(toggle?.tagName).toBe('DIV'); +}); + +test('Renders with h2 wrapper when toggleWrapper="h2"', () => { + render( + + Toggle test + + ); + + expect(screen.getByRole('heading', { level: 2 })).toBeInTheDocument(); +}); + +test('Renders with div wrapper when toggleWrapper="div"', () => { + render( + + Toggle test + + ); + + const toggle = screen.getByRole('button').parentElement; + expect(toggle?.tagName).toBe('DIV'); +}); diff --git a/packages/react-core/src/components/ExpandableSection/__tests__/__snapshots__/ExpandableSection.test.tsx.snap b/packages/react-core/src/components/ExpandableSection/__tests__/__snapshots__/ExpandableSection.test.tsx.snap index cdd66fa178c..9129caa2247 100644 --- a/packages/react-core/src/components/ExpandableSection/__tests__/__snapshots__/ExpandableSection.test.tsx.snap +++ b/packages/react-core/src/components/ExpandableSection/__tests__/__snapshots__/ExpandableSection.test.tsx.snap @@ -1,68 +1,5 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`Detached ExpandableSection renders successfully 1`] = ` - -
    -
    - test -
    -
    -
    -
    - -
    -
    -
    -`; - exports[`Disclosure ExpandableSection 1`] = `
    - } - onToggle={onToggle} - isExpanded={isExpanded} - > - This content is visible only when the component is expanded. -
    + + +

    Custom Toggle Content

    +

    You can use custom content such as icons and badges in the toggle:

    + + You can also use icons + + or badges + 4 + ! +
    + } + onToggle={onToggle} + isExpanded={isExpanded} + > + This content is visible only when the component is expanded. + + + + +

    Accessibility Note

    +

    + Important: If you need the toggle text to function as a heading in the document structure, do + NOT put heading elements (h1-h6) inside the toggleContent prop, as this creates invalid HTML + structure. Instead, use the toggleWrapper prop. +

    +
    + ); }; diff --git a/packages/react-core/src/components/ExpandableSection/examples/ExpandableSectionDetached.tsx b/packages/react-core/src/components/ExpandableSection/examples/ExpandableSectionDetached.tsx index bcba03935c2..c3b7be561b8 100644 --- a/packages/react-core/src/components/ExpandableSection/examples/ExpandableSectionDetached.tsx +++ b/packages/react-core/src/components/ExpandableSection/examples/ExpandableSectionDetached.tsx @@ -1,8 +1,8 @@ -import React from 'react'; +import { useState } from 'react'; import { ExpandableSection, ExpandableSectionToggle, Stack, StackItem } from '@patternfly/react-core'; export const ExpandableSectionDetached: React.FunctionComponent = () => { - const [isExpanded, setIsExpanded] = React.useState(false); + const [isExpanded, setIsExpanded] = useState(false); const onToggle = (isExpanded: boolean) => { setIsExpanded(isExpanded); @@ -13,7 +13,7 @@ export const ExpandableSectionDetached: React.FunctionComponent = () => { return ( - + This content is visible only when the component is expanded. @@ -25,7 +25,7 @@ export const ExpandableSectionDetached: React.FunctionComponent = () => { contentId={contentId} direction="up" > - {isExpanded ? 'Show less' : 'Show more'} + {isExpanded ? 'Show less detached example content' : 'Show more detached example content'} diff --git a/packages/react-core/src/components/ExpandableSection/examples/ExpandableSectionDisclosure.tsx b/packages/react-core/src/components/ExpandableSection/examples/ExpandableSectionDisclosure.tsx index 9aca30644eb..13c866ce6a2 100644 --- a/packages/react-core/src/components/ExpandableSection/examples/ExpandableSectionDisclosure.tsx +++ b/packages/react-core/src/components/ExpandableSection/examples/ExpandableSectionDisclosure.tsx @@ -1,8 +1,8 @@ -import React from 'react'; +import { useState } from 'react'; import { ExpandableSection } from '@patternfly/react-core'; export const ExpandableSectionDisclosure: React.FunctionComponent = () => { - const [isExpanded, setIsExpanded] = React.useState(false); + const [isExpanded, setIsExpanded] = useState(false); const onToggle = (_event: React.MouseEvent, isExpanded: boolean) => { setIsExpanded(isExpanded); @@ -10,7 +10,9 @@ export const ExpandableSectionDisclosure: React.FunctionComponent = () => { return ( { - const [isExpanded, setIsExpanded] = React.useState(true); - const [isDisplayLgChecked, setIsDisplayLgChecked] = React.useState(false); + const [isExpanded, setIsExpanded] = useState(true); + const [isDisplayLgChecked, setIsDisplayLgChecked] = useState(false); const onToggle = (_event: React.MouseEvent, isExpanded: boolean) => { setIsExpanded(isExpanded); @@ -21,7 +21,7 @@ export const ExpandableSectionIndented: React.FunctionComponent = () => { />
    { - const [isExpanded, setIsExpanded] = React.useState(false); + const [isExpanded, setIsExpanded] = useState(false); const onToggle = (_event: React.MouseEvent, isExpanded: boolean) => { setIsExpanded(isExpanded); @@ -11,7 +11,7 @@ export const ExpandableSectionTruncateExpansion: React.FunctionComponent = () => return ( diff --git a/packages/react-core/src/components/ExpandableSection/examples/ExpandableSectionUncontrolled.tsx b/packages/react-core/src/components/ExpandableSection/examples/ExpandableSectionUncontrolled.tsx index 627940fc6d6..660de9eb1f8 100644 --- a/packages/react-core/src/components/ExpandableSection/examples/ExpandableSectionUncontrolled.tsx +++ b/packages/react-core/src/components/ExpandableSection/examples/ExpandableSectionUncontrolled.tsx @@ -1,8 +1,7 @@ -import React from 'react'; import { ExpandableSection } from '@patternfly/react-core'; export const ExpandableSectionUncontrolled: React.FunctionComponent = () => ( - + This content is visible only when the component is expanded. ); diff --git a/packages/react-core/src/components/ExpandableSection/examples/ExpandableSectionUncontrolledDynamicToggleFunction.tsx b/packages/react-core/src/components/ExpandableSection/examples/ExpandableSectionUncontrolledDynamicToggleFunction.tsx new file mode 100644 index 00000000000..614329918f8 --- /dev/null +++ b/packages/react-core/src/components/ExpandableSection/examples/ExpandableSectionUncontrolledDynamicToggleFunction.tsx @@ -0,0 +1,13 @@ +import { ExpandableSection } from '@patternfly/react-core'; + +export const ExpandableSectionUncontrolledDynamicToggleFunction: React.FunctionComponent = () => ( + + isExpanded + ? 'Show less uncontrolled dynamic toggle example content' + : 'Show more uncontrolled dynamic toggle example content' + } + > + This content is visible only when the component is expanded. + +); diff --git a/packages/react-core/src/components/ExpandableSection/examples/ExpandableSectionUncontrolledDynamicToggleText.tsx b/packages/react-core/src/components/ExpandableSection/examples/ExpandableSectionUncontrolledDynamicToggleText.tsx index 0883285a878..6dbb40f197b 100644 --- a/packages/react-core/src/components/ExpandableSection/examples/ExpandableSectionUncontrolledDynamicToggleText.tsx +++ b/packages/react-core/src/components/ExpandableSection/examples/ExpandableSectionUncontrolledDynamicToggleText.tsx @@ -1,8 +1,10 @@ -import React from 'react'; import { ExpandableSection } from '@patternfly/react-core'; export const ExpandableSectionUncontrolledDynamicToggle: React.FunctionComponent = () => ( - + This content is visible only when the component is expanded. ); diff --git a/packages/react-core/src/components/ExpandableSection/examples/ExpandableSectionWithHeading.tsx b/packages/react-core/src/components/ExpandableSection/examples/ExpandableSectionWithHeading.tsx new file mode 100644 index 00000000000..f2af80222fe --- /dev/null +++ b/packages/react-core/src/components/ExpandableSection/examples/ExpandableSectionWithHeading.tsx @@ -0,0 +1,89 @@ +import { useState, MouseEvent } from 'react'; +import { ExpandableSection, ExpandableSectionToggle, Stack, StackItem } from '@patternfly/react-core'; +import RhUiCheckCircleFillIcon from '@patternfly/react-icons/dist/esm/icons/rh-ui-check-circle-fill-icon'; + +export const ExpandableSectionWithHeading = () => { + const [isExpanded1, setIsExpanded1] = useState(false); + const [isExpanded2, setIsExpanded2] = useState(false); + const [isExpandedDetached, setIsExpandedDetached] = useState(false); + + const onToggle1 = (_event: MouseEvent, isExpanded: boolean) => { + setIsExpanded1(isExpanded); + }; + + const onToggle2 = (_event: MouseEvent, isExpanded: boolean) => { + setIsExpanded2(isExpanded); + }; + + const onToggleDetached = (isExpanded: boolean) => { + setIsExpandedDetached(isExpanded); + }; + + return ( + + +

    Document with Expandable Sections

    +

    This demonstrates how to use expandable sections with proper heading semantics.

    + + {/* Using toggleWrapper prop for proper heading semantics */} + +

    + This content is visible only when the component is expanded. The toggle text above functions as a proper + heading in the document structure, which is important for screen readers and other assistive technologies. +

    +

    + When using the toggleWrapper prop with heading elements (h1-h6), the button is rendered inside + the heading element, maintaining proper semantic structure. +

    +
    +
    + + +

    Detached Variant with Heading

    +

    You can also use the detached variant with heading semantics:

    + + + Detached Toggle with Heading + + + +

    This is detached content that can be positioned anywhere in the DOM.

    +
    +
    + + +

    Custom Content with Heading

    +

    You can also use custom content within heading wrappers:

    + + + Custom Heading Content with Icon + + } + onToggle={onToggle2} + isExpanded={isExpanded2} + > +

    This expandable section uses custom content with an icon inside a heading wrapper.

    +
    +
    +
    + ); +}; diff --git a/packages/react-core/src/components/FileUpload/FileUpload.tsx b/packages/react-core/src/components/FileUpload/FileUpload.tsx index ce4c8e04f33..7317bb31141 100644 --- a/packages/react-core/src/components/FileUpload/FileUpload.tsx +++ b/packages/react-core/src/components/FileUpload/FileUpload.tsx @@ -1,15 +1,13 @@ -import * as React from 'react'; -import { DropzoneInputProps, DropzoneOptions, FileRejection, useDropzone } from 'react-dropzone'; +import { DropzoneInputProps, DropzoneOptions, FileRejection, useDropzone, ErrorCode } from 'react-dropzone'; import { FileUploadField, FileUploadFieldProps } from './FileUploadField'; import { readFile, fileReaderType } from '../../helpers/fileUtils'; import { DropEvent } from '../../helpers/typeUtils'; import { fromEvent } from 'file-selector'; -export interface FileUploadProps - extends Omit< - FileUploadFieldProps, - 'children' | 'onBrowseButtonClick' | 'onClearButtonClick' | 'isDragActive' | 'containerRef' - > { +export interface FileUploadProps extends Omit< + FileUploadFieldProps, + 'children' | 'onBrowseButtonClick' | 'onClearButtonClick' | 'isDragActive' | 'containerRef' +> { /** Flag to allow editing of a text file's contents after it is selected from disk. */ allowEditingUploadedText?: boolean; /** Aria-label for the text area. */ @@ -84,6 +82,8 @@ export interface FileUploadProps onTextChange?: (event: React.ChangeEvent, text: string) => void; } +export { ErrorCode as DropzoneErrorCode }; // FileInvalidType, FileTooLarge, FileTooSmall, TooManyFiles + export const FileUpload: React.FunctionComponent = ({ id, type, @@ -177,6 +177,7 @@ export const FileUpload: React.FunctionComponent = ({ {children} diff --git a/packages/react-core/src/components/FileUpload/FileUploadField.tsx b/packages/react-core/src/components/FileUpload/FileUploadField.tsx index 1523c496b44..8be75a1b95f 100644 --- a/packages/react-core/src/components/FileUpload/FileUploadField.tsx +++ b/packages/react-core/src/components/FileUpload/FileUploadField.tsx @@ -1,4 +1,3 @@ -import * as React from 'react'; import styles from '@patternfly/react-styles/css/components/FileUpload/file-upload'; import { css } from '@patternfly/react-styles'; import { InputGroup, InputGroupItem } from '../InputGroup'; @@ -43,6 +42,8 @@ export interface FileUploadFieldProps extends Omit = ({ browseButtonText = 'Browse...', browseButtonAriaDescribedby, clearButtonText = 'Clear', + isBrowseButtonDisabled = false, isClearButtonDisabled = !filename && !value, containerRef = null as React.Ref, allowEditingUploadedText = false, @@ -153,7 +155,7 @@ export const FileUploadField: React.FunctionComponent = ({
    -
    - {!hideDefaultPreview && type === fileReaderType.text && ( -