diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 8832dbfec8..63d1a2fcd0 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -37,13 +37,16 @@ jobs: - name: Install Playwright Browsers run: yarn playwright install --with-deps + - name: Run lint + run: yarn lint + - name: Run Tests - run: yarn test --browser.name=${{ env.BROWSER }} --browser.headless + run: yarn test-browser --browser.name=${{ env.BROWSER }} --browser.headless --coverage env: BROWSER: ${{ matrix.browser }} - name: Codecov - uses: codecov/codecov-action@v3 + uses: codecov/codecov-action@v4 - name: Build Project run: yarn build diff --git a/CHANGELOG.md b/CHANGELOG.md index 7686a68176..ddea24e541 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,16 @@ +## [2.10.6](https://github.com/react-bootstrap/react-bootstrap/compare/v2.10.5...v2.10.6) (2024-11-25) + + +### Bug Fixes + +* **AccordionHeader:** apply aria-controls to button ([#6868](https://github.com/react-bootstrap/react-bootstrap/issues/6868)) ([8475119](https://github.com/react-bootstrap/react-bootstrap/commit/8475119a6c8e9606d5e5cc87e19cf91f1670e224)) +* fix ref access in React 19 ([#6869](https://github.com/react-bootstrap/react-bootstrap/issues/6869)) ([2c65f5d](https://github.com/react-bootstrap/react-bootstrap/commit/2c65f5de1a50d28e4c4e6c4c7d0dc332a68e6bd7)) +* **Nav:** remove prop-types-extra import from build ([#6854](https://github.com/react-bootstrap/react-bootstrap/issues/6854)) ([ab81d6b](https://github.com/react-bootstrap/react-bootstrap/commit/ab81d6b1fda1175bc635978a493da49c60db9b25)) + + + + + ## [2.10.5](https://github.com/react-bootstrap/react-bootstrap/compare/v2.10.4...v2.10.5) (2024-09-26) diff --git a/package.json b/package.json index 8727a80de4..432be9dda0 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "react-bootstrap", - "version": "2.10.5", + "version": "2.10.6", "description": "Bootstrap 5 components built with React", "keywords": [ "bootstrap", @@ -60,7 +60,7 @@ "dependencies": { "@babel/runtime": "^7.24.7", "@restart/hooks": "^0.4.9", - "@restart/ui": "^1.6.9", + "@restart/ui": "^1.9.0", "@types/react-transition-group": "^4.4.6", "classnames": "^2.3.2", "dom-helpers": "^5.2.1", @@ -91,13 +91,13 @@ "@types/warning": "^3.0.3", "@typescript-eslint/eslint-plugin": "^7.13.0", "@typescript-eslint/parser": "^7.13.0", - "@vitejs/plugin-react": "^4.3.1", - "@vitest/browser": "^2.0.4", + "@vitejs/plugin-react": "^4.3.2", + "@vitest/browser": "^2.1.3", + "@vitest/coverage-istanbul": "^2.1.3", "babel-loader": "^9.1.3", "babel-plugin-istanbul": "^6.1.1", "chalk": "^4.1.2", "cherry-pick": "^0.5.0", - "codecov": "^3.8.3", "conventional-changelog-cli": "^2.2.2", "cpy-cli": "^3.1.1", "cross-env": "^7.0.3", @@ -121,7 +121,7 @@ "react": "^18.3.1", "react-dom": "^18.3.1", "typescript": "^5.5.4", - "vitest": "^2.0.4", + "vitest": "^2.1.3", "webpack": "^5.93.0" }, "peerDependencies": { diff --git a/src/AccordionHeader.tsx b/src/AccordionHeader.tsx index 7ea47e5a6c..78f8e4e9b0 100644 --- a/src/AccordionHeader.tsx +++ b/src/AccordionHeader.tsx @@ -28,6 +28,7 @@ const AccordionHeader: BsPrefixRefForwardingComponent< { // Need to define the default "as" during prop destructuring to be compatible with styled-components github.com/react-bootstrap/react-bootstrap/issues/3595 as: Component = 'h2', + 'aria-controls': ariaControls, bsPrefix, className, children, @@ -44,7 +45,9 @@ const AccordionHeader: BsPrefixRefForwardingComponent< {...props} className={classNames(className, bsPrefix)} > - {children} + + {children} + ); }, diff --git a/src/Collapse.tsx b/src/Collapse.tsx index eb2ff01aa6..f89abd05aa 100644 --- a/src/Collapse.tsx +++ b/src/Collapse.tsx @@ -10,6 +10,7 @@ import Transition, { EXITING, } from 'react-transition-group/Transition'; import { TransitionCallbacks } from '@restart/ui/types'; +import { getChildRef } from '@restart/ui/utils'; import transitionEndListener from './transitionEndListener'; import createChainedFunction from './createChainedFunction'; import triggerBrowserReflow from './triggerBrowserReflow'; @@ -229,7 +230,7 @@ const Collapse = React.forwardRef, CollapseProps>( onEntered={handleEntered} onExit={handleExit} onExiting={handleExiting} - childRef={(children as any).ref} + childRef={getChildRef(children)} in={inProp} timeout={timeout} mountOnEnter={mountOnEnter} diff --git a/src/Fade.tsx b/src/Fade.tsx index 1595246a56..2153ef8f8f 100644 --- a/src/Fade.tsx +++ b/src/Fade.tsx @@ -8,7 +8,7 @@ import Transition, { ENTERING, } from 'react-transition-group/Transition'; import { TransitionCallbacks } from '@restart/ui/types'; -import { getReactVersion } from '@restart/ui/utils'; +import { getChildRef } from '@restart/ui/utils'; import transitionEndListener from './transitionEndListener'; import triggerBrowserReflow from './triggerBrowserReflow'; import TransitionWrapper from './TransitionWrapper'; @@ -114,16 +114,13 @@ const Fade = React.forwardRef, FadeProps>( [onEnter], ); - const { major } = getReactVersion(); - const childRef = major >= 19 ? (children as any).props.ref : (children as any).ref; - return ( {(status: TransitionStatus, innerProps: Record) => React.cloneElement(children, { diff --git a/src/Nav.tsx b/src/Nav.tsx index be0ae56e58..eb03e9e1c7 100644 --- a/src/Nav.tsx +++ b/src/Nav.tsx @@ -1,7 +1,7 @@ import classNames from 'classnames'; import PropTypes from 'prop-types'; -import all from 'prop-types-extra/lib/all'; +import { all } from 'prop-types-extra'; import * as React from 'react'; import { useContext } from 'react'; import { useUncontrolled } from 'uncontrollable'; diff --git a/src/OffcanvasToggling.tsx b/src/OffcanvasToggling.tsx index 9e0b8ae1ee..10a9449b54 100644 --- a/src/OffcanvasToggling.tsx +++ b/src/OffcanvasToggling.tsx @@ -8,6 +8,7 @@ import Transition, { EXITING, } from 'react-transition-group/Transition'; import { TransitionCallbacks } from '@restart/ui/types'; +import { getChildRef } from '@restart/ui/utils'; import transitionEndListener from './transitionEndListener'; import { BsPrefixOnlyProps } from './helpers'; import TransitionWrapper from './TransitionWrapper'; @@ -113,7 +114,7 @@ const OffcanvasToggling = React.forwardRef< unmountOnExit={unmountOnExit} appear={appear} {...props} - childRef={(children as any).ref} + childRef={getChildRef(children)} > {(status: TransitionStatus, innerProps: Record) => React.cloneElement(children, { diff --git a/src/OverlayTrigger.tsx b/src/OverlayTrigger.tsx index 4c04a3a3b6..82c7ffa6a1 100644 --- a/src/OverlayTrigger.tsx +++ b/src/OverlayTrigger.tsx @@ -6,6 +6,7 @@ import useTimeout from '@restart/hooks/useTimeout'; import warning from 'warning'; import { useUncontrolledProp } from 'uncontrollable'; import useMergedRefs from '@restart/hooks/useMergedRefs'; +import { getChildRef } from '@restart/ui/utils'; import Overlay, { OverlayChildren, OverlayProps } from './Overlay'; import safeFindDOMNode from './safeFindDOMNode'; import { Placement } from './types'; @@ -192,7 +193,7 @@ const OverlayTrigger: React.FC = ({ const triggerNodeRef = useRef(null); const mergedRef = useMergedRefs( triggerNodeRef, - (children as any).ref, + getChildRef(children), ); const timeout = useTimeout(); const hoverStateRef = useRef(''); diff --git a/test/AccordionHeaderSpec.tsx b/test/AccordionHeaderSpec.tsx new file mode 100644 index 0000000000..444e8dbfeb --- /dev/null +++ b/test/AccordionHeaderSpec.tsx @@ -0,0 +1,13 @@ +import { describe, expect, it } from 'vitest'; +import { render, screen } from '@testing-library/react'; +import { AccordionHeader } from '../src'; + +describe('', () => { + it('should apply aria-controls to the button', () => { + render(); + + expect(screen.getByRole('button').getAttribute('aria-controls')).toEqual( + 'test', + ); + }); +}); diff --git a/vitest.config.ts b/vitest.config.ts index bb4ea4990d..b9ea319d8e 100644 --- a/vitest.config.ts +++ b/vitest.config.ts @@ -1,4 +1,4 @@ -import { defineConfig } from 'vitest/config'; +import { coverageConfigDefaults, defineConfig } from 'vitest/config'; import react from '@vitejs/plugin-react'; export default defineConfig({ @@ -14,8 +14,20 @@ export default defineConfig({ enabled: true, name: 'chromium', provider: 'playwright', - // https://playwright.dev - providerOptions: {}, + providerOptions: { + context: { + hasTouch: true, + }, + }, + }, + coverage: { + provider: 'istanbul', + exclude: [ + ...coverageConfigDefaults.exclude, + 'www/**', + 'tools/**', + '**/*.js', + ], }, }, }); diff --git a/www/docs/components/overlays.mdx b/www/docs/components/overlays.mdx index 13cb25fe41..d862c02dbf 100644 --- a/www/docs/components/overlays.mdx +++ b/www/docs/components/overlays.mdx @@ -104,7 +104,7 @@ compliant. Hover over the links below to see tooltips. - + {TooltipInCopy} diff --git a/www/docs/examples/Button/Active.js b/www/docs/examples/Button/Active.js index 99a1671377..2b1bb90d9d 100644 --- a/www/docs/examples/Button/Active.js +++ b/www/docs/examples/Button/Active.js @@ -5,7 +5,7 @@ function ActiveExample() { <> {' '} + diff --git a/www/docs/examples/Button/Disabled.js b/www/docs/examples/Button/Disabled.js index 8c29535f41..479a606a80 100644 --- a/www/docs/examples/Button/Disabled.js +++ b/www/docs/examples/Button/Disabled.js @@ -5,10 +5,10 @@ function DisabledExample() { <> {' '} + {' '} + diff --git a/www/docs/examples/Button/Loading.js b/www/docs/examples/Button/Loading.js index 20577d2cfd..a5c271e995 100644 --- a/www/docs/examples/Button/Loading.js +++ b/www/docs/examples/Button/Loading.js @@ -6,7 +6,9 @@ function LoadingButton() { useEffect(() => { function simulateNetworkRequest() { - return new Promise((resolve) => setTimeout(resolve, 2000)); + return new Promise(resolve => { + setTimeout(resolve, 2000); + }); } if (isLoading) { diff --git a/www/docs/examples/Button/OutlineTypes.js b/www/docs/examples/Button/OutlineTypes.js index b0b61fc967..a33eb49bd7 100644 --- a/www/docs/examples/Button/OutlineTypes.js +++ b/www/docs/examples/Button/OutlineTypes.js @@ -3,13 +3,13 @@ import Button from 'react-bootstrap/Button'; function OutlineTypesExample() { return ( <> - {' '} - {' '} - {' '} - {' '} - {' '} - {' '} - {' '} + + + + + + + ); diff --git a/www/docs/examples/Button/Sizes.js b/www/docs/examples/Button/Sizes.js index 01d4b814d3..01c9150a85 100644 --- a/www/docs/examples/Button/Sizes.js +++ b/www/docs/examples/Button/Sizes.js @@ -3,18 +3,18 @@ import Button from 'react-bootstrap/Button'; function SizesExample() { return ( <> -
+
{' '} +
-
+
{' '} + diff --git a/www/docs/examples/Button/TagTypes.js b/www/docs/examples/Button/TagTypes.js index d1e89e204e..90de9e5ef1 100644 --- a/www/docs/examples/Button/TagTypes.js +++ b/www/docs/examples/Button/TagTypes.js @@ -3,9 +3,9 @@ import Button from 'react-bootstrap/Button'; function TagTypesExample() { return ( <> - {' '} - + {' '} - {' '} - {' '} - {' '} - {' '} - {' '} - {' '} + + + + + + + diff --git a/www/docs/examples/ButtonGroup/Toolbar.js b/www/docs/examples/ButtonGroup/Toolbar.js index 12497f8d88..9540d60444 100644 --- a/www/docs/examples/ButtonGroup/Toolbar.js +++ b/www/docs/examples/ButtonGroup/Toolbar.js @@ -9,9 +9,9 @@ function ToolbarExample() { <> - {' '} - {' '} - {' '} + + + @@ -30,9 +30,9 @@ function ToolbarExample() { aria-label="Toolbar with Button groups" > - {' '} - {' '} - {' '} + + + diff --git a/www/docs/examples/ButtonGroup/ToolbarBasic.js b/www/docs/examples/ButtonGroup/ToolbarBasic.js index b7a5c8ca8d..051a505b22 100644 --- a/www/docs/examples/ButtonGroup/ToolbarBasic.js +++ b/www/docs/examples/ButtonGroup/ToolbarBasic.js @@ -6,11 +6,15 @@ function ToolbarBasicExample() { return ( - {' '} + + + - + + + diff --git a/www/docs/examples/Card/Group.js b/www/docs/examples/Card/Group.js index f462043ff4..64e6f4ad84 100644 --- a/www/docs/examples/Card/Group.js +++ b/www/docs/examples/Card/Group.js @@ -23,7 +23,7 @@ function GroupExample() { Card title This card has supporting text below as a natural lead-in to - additional content.{' '} + additional content. diff --git a/www/docs/examples/Card/WithHeaderAndQuote.js b/www/docs/examples/Card/WithHeaderAndQuote.js index 2f846578ed..4413e6b49d 100644 --- a/www/docs/examples/Card/WithHeaderAndQuote.js +++ b/www/docs/examples/Card/WithHeaderAndQuote.js @@ -7,9 +7,8 @@ function WithHeaderAndQuoteExample() {

- {' '} Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer - posuere erat a ante.{' '} + posuere erat a ante.