diff --git a/.babelrc.js b/.babelrc.js index b10eab046b..e7a3c19095 100644 --- a/.babelrc.js +++ b/.babelrc.js @@ -23,6 +23,7 @@ const options = { [ '@babel/env', { + bugfixes: true, loose: true, modules, targets, diff --git a/.browserslistrc b/.browserslistrc new file mode 100644 index 0000000000..55ae8fde69 --- /dev/null +++ b/.browserslistrc @@ -0,0 +1,6 @@ +> 0.3% +last 2 versions +Firefox ESR +not dead +not Android <5 +maintained node versions \ No newline at end of file diff --git a/.eslintignore b/.eslintignore deleted file mode 100644 index de85163be2..0000000000 --- a/.eslintignore +++ /dev/null @@ -1,5 +0,0 @@ -/webpack.* -/old_examples -lib -dist -esm diff --git a/.eslintrc b/.eslintrc deleted file mode 100644 index edb3cedcb3..0000000000 --- a/.eslintrc +++ /dev/null @@ -1,48 +0,0 @@ -{ - "extends": [ - "eslint:recommended", - "plugin:react/recommended", - "plugin:import/recommended", - "plugin:jsx-a11y/recommended", - "plugin:prettier/recommended" - ], - "parser": "@babel/eslint-parser", - "parserOptions": { - "requireConfigFile": false - }, - "settings": { - "react": { - "version": "detect" - } - }, - "env": { - "browser": true, - "node": true - }, - "rules": { - "jsx-a11y/no-static-element-interactions": "off", - "import/no-extraneous-dependencies": [ - "error", - { - "devDependencies": [ - "**/__tests__/**/*", - "examples/src/**/*.js", - "rollup.config.js", - "webpack.config.js" - ], - "optionalDependencies": false - } - ], - "no-unused-vars": ["error", { "ignoreRestSiblings": true }], - "no-console": "error", - "react/prop-types": "off" - }, - "overrides": [ - { - "files":["**/*-test.js"], - "env": { - "jest": true - } - } - ] -} diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index d656328146..7ca465ec37 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -1,4 +1,3 @@ - name: CI on: @@ -8,8 +7,7 @@ on: - renovate/** pull_request: -env: - NODE_VERSION: 16 +permissions: {} jobs: tests: @@ -17,150 +15,82 @@ jobs: runs-on: ubuntu-latest steps: - - name: Checkout - uses: actions/checkout@v3 + - name: Checkout + uses: actions/checkout@v5 - - name: Setup Node.js - uses: actions/setup-node@v3 - with: - node-version: ${{ env.NODE_VERSION }} + - name: Install pnpm + uses: pnpm/action-setup@v4 - - name: Cache node_modules - uses: actions/cache@v3 - id: cache-nodemodules - with: - path: node_modules - key: ${{ runner.os }}-${{ env.NODE_VERSION }}-nodemodules-${{ hashFiles('**/yarn.lock') }} + - name: Setup Node.js + uses: actions/setup-node@v6 + with: + node-version: 'lts/*' + cache: 'pnpm' - - name: Install dependencies - if: steps.cache-nodemodules.outputs.cache-hit != 'true' - run: yarn install --frozen-lockfile --non-interactive + - name: Install dependencies + run: pnpm install --frozen-lockfile - - name: Unit tests - run: yarn test --ci --coverage + - name: Unit tests + run: pnpm test --coverage - - name: Upload coverage to Codecov - uses: codecov/codecov-action@v3 + - name: Upload coverage + continue-on-error: true + uses: coverallsapp/github-action@v2 lint: name: Lint runs-on: ubuntu-latest steps: - - name: Checkout - uses: actions/checkout@v3 - - - name: Setup Node.js - uses: actions/setup-node@v3 - with: - node-version: ${{ env.NODE_VERSION }} - - - name: Cache node_modules - uses: actions/cache@v3 - id: cache-nodemodules - with: - path: node_modules - key: ${{ runner.os }}-${{ env.NODE_VERSION }}-nodemodules-${{ hashFiles('**/yarn.lock') }} - - - name: Install dependencies - if: steps.cache-nodemodules.outputs.cache-hit != 'true' - run: yarn install --frozen-lockfile --non-interactive - - - name: Lint - run: yarn lint - - website: - name: Test build website - if: github.ref != 'refs/heads/main' - runs-on: ubuntu-latest - - steps: - - name: Checkout - uses: actions/checkout@v3 + - name: Checkout + uses: actions/checkout@v5 - - name: Setup Node.js - uses: actions/setup-node@v3 - with: - node-version: ${{ env.NODE_VERSION }} + - name: Install pnpm + uses: pnpm/action-setup@v4 - - name: Cache node_modules - uses: actions/cache@v3 - id: cache-nodemodules - with: - path: node_modules - key: ${{ runner.os }}-${{ env.NODE_VERSION }}-nodemodules-${{ hashFiles('**/yarn.lock') }} + - name: Setup Node.js + uses: actions/setup-node@v6 + with: + node-version: 'lts/*' + cache: 'pnpm' - - name: Install dependencies - if: steps.cache-nodemodules.outputs.cache-hit != 'true' - run: yarn install --frozen-lockfile --non-interactive + - name: Install dependencies + run: pnpm install --frozen-lockfile - - name: Build website - run: yarn website + - name: Lint + run: pnpm lint release: needs: [tests, lint] if: github.ref == 'refs/heads/main' name: Release runs-on: ubuntu-latest + permissions: + contents: write # to be able to publish a GitHub release + issues: write # to be able to comment on released issues + pull-requests: write # to be able to comment on released pull requests + id-token: write # to enable use of OIDC for npm provenance steps: - name: Checkout - uses: actions/checkout@v3 + uses: actions/checkout@v5 with: fetch-depth: 0 - - name: Setup Node.js - uses: actions/setup-node@v3 - with: - node-version: ${{ env.NODE_VERSION }} + - name: Install pnpm + uses: pnpm/action-setup@v4 - - name: Cache node_modules - uses: actions/cache@v3 - id: cache-nodemodules + - name: Setup Node.js + uses: actions/setup-node@v6 with: - path: node_modules - key: ${{ runner.os }}-${{ env.NODE_VERSION }}-nodemodules-${{ hashFiles('**/yarn.lock') }} + node-version: 'lts/*' + cache: 'pnpm' - name: Install dependencies - if: steps.cache-nodemodules.outputs.cache-hit != 'true' - run: yarn install --frozen-lockfile --non-interactive + run: pnpm install --frozen-lockfile - name: Release - run: npx semantic-release --branches main + run: pnpm dlx semantic-release --branches main env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} NPM_TOKEN: ${{ secrets.NPM_TOKEN }} - - deploy: - name: Deploy website - needs: [tests, lint] - if: github.ref == 'refs/heads/main' - runs-on: ubuntu-latest - steps: - - name: Checkout - uses: actions/checkout@v3 - - - name: Setup Node.js - uses: actions/setup-node@v3 - with: - node-version: ${{ env.NODE_VERSION }} - - - name: Cache node_modules - uses: actions/cache@v3 - id: cache-nodemodules - with: - path: node_modules - key: ${{ runner.os }}-${{ env.NODE_VERSION }}-nodemodules-${{ hashFiles('**/yarn.lock') }} - - - name: Install dependencies - if: steps.cache-nodemodules.outputs.cache-hit != 'true' - run: yarn install --frozen-lockfile --non-interactive - - - name: Build - run: yarn website - - - name: Deploy - uses: JamesIves/github-pages-deploy-action@v4 - with: - branch: gh-pages - folder: examples/dist diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index 66027a737e..b990d573ed 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -24,6 +24,7 @@ jobs: analyze: name: Analyze runs-on: ubuntu-latest + if: "!startsWith(github.head_ref, 'renovate/')" strategy: fail-fast: false @@ -35,11 +36,11 @@ jobs: steps: - name: Checkout repository - uses: actions/checkout@v3 + uses: actions/checkout@v5 # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL - uses: github/codeql-action/init@v2 + uses: github/codeql-action/init@v4 with: languages: ${{ matrix.language }} # If you wish to specify custom queries, you can do so here or in a config file. @@ -50,7 +51,7 @@ jobs: # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). # If this step fails, then you should remove it and run the build manually (see below) - name: Autobuild - uses: github/codeql-action/autobuild@v2 + uses: github/codeql-action/autobuild@v4 # ℹ️ Command-line programs to run using the OS shell. # 📚 https://git.io/JvXDl @@ -64,4 +65,4 @@ jobs: # make release - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@v2 + uses: github/codeql-action/analyze@v4 diff --git a/.github/workflows/lock.yml b/.github/workflows/lock.yml index 38f8e928af..28cc5d68c0 100644 --- a/.github/workflows/lock.yml +++ b/.github/workflows/lock.yml @@ -8,6 +8,7 @@ on: permissions: issues: write pull-requests: write + discussions: write concurrency: group: lock @@ -16,6 +17,6 @@ jobs: action: runs-on: ubuntu-latest steps: - - uses: dessant/lock-threads@v3 + - uses: dessant/lock-threads@v5 with: - log-output: true \ No newline at end of file + log-output: true diff --git a/.github/workflows/ossar-analysis.yml b/.github/workflows/ossar-analysis.yml index 39153f2ed2..0df7d97112 100644 --- a/.github/workflows/ossar-analysis.yml +++ b/.github/workflows/ossar-analysis.yml @@ -4,7 +4,7 @@ name: OSSAR on: - push: + push: branches: - main - renovate/** @@ -15,11 +15,12 @@ jobs: # OSSAR runs on windows-latest. # ubuntu-latest and macos-latest support coming soon runs-on: windows-latest + if: "!startsWith(github.head_ref, 'renovate/')" steps: # Checkout your code repository to scan - name: Checkout repository - uses: actions/checkout@v3 + uses: actions/checkout@v5 with: # We must fetch at least the immediate parents so that if this is # a pull request then we can checkout the head. @@ -47,6 +48,6 @@ jobs: # Upload results to the Security tab - name: Upload OSSAR results - uses: github/codeql-action/upload-sarif@v2 + uses: github/codeql-action/upload-sarif@v4 with: sarif_file: ${{ steps.ossar.outputs.sarifFile }} diff --git a/.github/workflows/pkg-size-report.yml b/.github/workflows/pkg-size-report.yml index a195d11037..8c3a209704 100644 --- a/.github/workflows/pkg-size-report.yml +++ b/.github/workflows/pkg-size-report.yml @@ -2,10 +2,10 @@ name: Package size report on: pull_request: - branches: [ main, next ] + branches: [main, next] -env: - NODE_VERSION: 16 +permissions: + pull-requests: write jobs: pkg-size-report: @@ -13,29 +13,25 @@ jobs: runs-on: ubuntu-latest steps: - - name: Checkout - uses: actions/checkout@v3 - - - name: Setup Node.js - uses: actions/setup-node@v3 - with: - node-version: ${{ env.NODE_VERSION }} - - - name: Cache node_modules - uses: actions/cache@v3 - id: cache-nodemodules - with: - path: node_modules - key: ${{ runner.os }}-${{ env.NODE_VERSION }}-nodemodules-${{ hashFiles('**/yarn.lock') }} - - - name: Install dependencies - if: steps.cache-nodemodules.outputs.cache-hit != 'true' - run: yarn install --frozen-lockfile --non-interactive - - - name: Package size report - uses: pkg-size/action@v1 - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - with: - hide-files: '*.{js,css}.map' - display-size: uncompressed, gzip + - name: Checkout + uses: actions/checkout@v5 + + - name: Install pnpm + uses: pnpm/action-setup@v4 + + - name: Setup Node.js + uses: actions/setup-node@v6 + with: + node-version: 'lts/*' + cache: 'pnpm' + + - name: Install dependencies + run: pnpm install --frozen-lockfile + + - name: Package size report + uses: pkg-size/action@v1 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + hide-files: '*.{js,css}.map' + display-size: uncompressed, gzip diff --git a/.github/workflows/website.yml b/.github/workflows/website.yml new file mode 100644 index 0000000000..79afef6e47 --- /dev/null +++ b/.github/workflows/website.yml @@ -0,0 +1,66 @@ +name: Website + +on: + push: + branches: + - main + - renovate/** + pull_request: + +permissions: {} + +jobs: + website: + name: Test + if: "github.ref != 'refs/heads/main' && !startsWith(github.head_ref, 'renovate/')" + runs-on: ubuntu-latest + + steps: + - name: Checkout + uses: actions/checkout@v5 + + - name: Install pnpm + uses: pnpm/action-setup@v4 + + - name: Setup Node.js + uses: actions/setup-node@v6 + with: + node-version: 'lts/*' + cache: 'pnpm' + + - name: Install dependencies + run: pnpm install --frozen-lockfile + + - name: Build website + run: pnpm run --sequential '/website:.*/' + + deploy: + name: Deploy + if: github.ref == 'refs/heads/main' + runs-on: ubuntu-latest + permissions: + contents: write + steps: + - name: Checkout + uses: actions/checkout@v5 + + - name: Install pnpm + uses: pnpm/action-setup@v4 + + - name: Setup Node.js + uses: actions/setup-node@v6 + with: + node-version: 'lts/*' + cache: 'pnpm' + + - name: Install dependencies + run: pnpm install --frozen-lockfile + + - name: Build + run: pnpm run --sequential '/website:.*/' + + - name: Deploy + uses: JamesIves/github-pages-deploy-action@v4 + with: + branch: gh-pages + folder: examples/dist diff --git a/.gitignore b/.gitignore index 8c4e7b6f3a..ae3adbfdc5 100644 --- a/.gitignore +++ b/.gitignore @@ -1,8 +1,7 @@ build/ coverage/ +examples/dist/ node_modules/ npm-debug.log lib/ -dist/ esm/ -yarn-error.log diff --git a/.gitpod.yml b/.gitpod.yml index 22304ace94..c9fa969d57 100644 --- a/.gitpod.yml +++ b/.gitpod.yml @@ -1,6 +1,6 @@ tasks: - - init: yarn install && yarn run build + - init: pnpm install && pnpm run build vscode: extensions: diff --git a/README.md b/README.md index 992e84b67f..4f9a3b53ec 100644 --- a/README.md +++ b/README.md @@ -1,11 +1,11 @@ -# react-tabs [![npm version](https://img.shields.io/npm/v/react-tabs.svg)](https://www.npmjs.com/package/react-tabs) [![codecov](https://codecov.io/gh/reactjs/react-tabs/branch/main/graph/badge.svg?token=XnEVrthAub)](https://codecov.io/gh/reactjs/react-tabs) +# react-tabs [![npm version](https://img.shields.io/npm/v/react-tabs.svg)](https://www.npmjs.com/package/react-tabs) [![Coverage Status](https://coveralls.io/repos/github/reactjs/react-tabs/badge.svg?branch=main)](https://coveralls.io/github/reactjs/react-tabs?branch=main) An accessible and easy tab component for ReactJS. https://reactcommunity.org/react-tabs/ -> Version 5 of `react-tabs` needs react version 18 or newer -> +> Version 5 or newer of `react-tabs` needs react version 18 or newer +> > Version 4 of `react-tabs` needs react version 16.8 or newer

react-tabs was tested on real mobile devices and browsers with
@@ -25,17 +25,6 @@ or npm install --save react-tabs ``` -You can also use react-tabs directly as UMD build in an HTML document by adding - -```html - - diff --git a/old_examples/conditional/app.js b/old_examples/conditional/app.js deleted file mode 100644 index ebcb560072..0000000000 --- a/old_examples/conditional/app.js +++ /dev/null @@ -1,56 +0,0 @@ -import React from 'react'; -import { render } from 'react-dom'; -import { Tab, Tabs, TabList, TabPanel } from '../../src/index'; -import '../../style/react-tabs.css'; - -class App extends React.Component { - constructor(props) { - super(props); - - this.state = { - showA: true, - showB: true, - showC: true, - }; - } - - handleCheckClicked = (e) => { - this.setState({ - [e.target.name]: e.target.checked, - }); - } - - render() { - return ( -

-

-
-
-
-

- - - {this.state.showA && Tab A} - {this.state.showB && Tab B} - {this.state.showC && Tab C} - - {this.state.showA && This is tab A} - {this.state.showB && This is tab B} - {this.state.showC && This is tab C} - -
- ); - } -} - -render(, document.getElementById('example')); - diff --git a/old_examples/conditional/index.html b/old_examples/conditional/index.html deleted file mode 100644 index 6b412bd6e9..0000000000 --- a/old_examples/conditional/index.html +++ /dev/null @@ -1,8 +0,0 @@ - - -React Tabs - -
- - - diff --git a/old_examples/dyno/app.js b/old_examples/dyno/app.js deleted file mode 100644 index c60eba5b96..0000000000 --- a/old_examples/dyno/app.js +++ /dev/null @@ -1,96 +0,0 @@ -import React from 'react'; -import { render } from 'react-dom'; -import Modal from 'react-modal'; -import { Tab, Tabs, TabList, TabPanel } from '../../src/index'; -import '../../style/react-tabs.css'; - -Modal.setAppElement(document.getElementById('example')); - -class App extends React.Component { - constructor(props) { - super(props); - - this.state = { - isModalOpen: false, - selectedIndex: -1, - tabs: [ - { label: 'Foo', content: 'This is foo' }, - { label: 'Bar', content: 'This is bar' }, - { label: 'Baz', content: 'This is baz' }, - { label: 'Zap', content: 'This is zap' }, - ], - }; - } - - openModal = () => { - this.setState({ - isModalOpen: true, - }); - } - - closeModal = () => { - this.setState({ - isModalOpen: false, - }); - } - - addTab = () => { - const label = this.refs.label.value; - const content = this.refs.content.value; - - this.setState({ - tabs: [ - ...this.state.tabs, - { label, content }, - ], - selectedIndex: this.state.tabs.length, - }); - this.closeModal(); - } - - removeTab = (index) => { - this.setState({ - tabs: this.state.tabs.filter((tab, i) => i !== index), - selectedIndex: Math.max(this.state.selectedIndex - 1, 0), - }); - } - - render() { - return ( -
-

- -

- this.setState({ selectedIndex })} - > - - {this.state.tabs.map((tab, i) => ( - - {tab.label} this.removeTab(i)}>✕ - - ))} - - {this.state.tabs.map((tab, i) => {tab.content})} - - -

Add a Tab

-
-

-
-