From cd75caaa1e844d8386eab1dbff4d5790cfbabc8a Mon Sep 17 00:00:00 2001 From: Stefan Cameron Date: Thu, 12 Dec 2024 10:10:58 -0600 Subject: [PATCH] Fix v11.0.0 types that removed the default export (#1406) * Fix v11.0.0 types that removed the default export Fixes #1396 My original intent was to remove the default export (a breaking change) as part of the major 11.0.0 release but I totally flopped on that by not also actually providing the named export in the code. Now that the major release ship has sailed, this change fixes the types by reinstating the default export in the typings but marking it deprecated, while also providing the new named export alternative as the way forward. * Props no longer extend from AllHTMLAttributes --- .changeset/brown-buttons-do.md | 5 ++ README.md | 19 +++---- demo/js/demo-animated-dialog.js | 2 +- demo/js/demo-animated-trigger.js | 2 +- demo/js/demo-autofocus.js | 2 +- demo/js/demo-containerelements-childless.js | 2 +- demo/js/demo-containerelements.js | 2 +- demo/js/demo-defaults.js | 2 +- demo/js/demo-ffne.js | 2 +- demo/js/demo-iframe.js | 2 +- demo/js/demo-setReturnFocus.js | 2 +- demo/js/demo-special-element.js | 2 +- demo/js/demo-with-shadow-dom.js | 2 +- index.d.ts | 58 ++++++++++++++++++--- src/focus-trap-react.js | 4 ++ test/focus-trap-react.test.js | 2 +- 16 files changed, 79 insertions(+), 31 deletions(-) create mode 100644 .changeset/brown-buttons-do.md diff --git a/.changeset/brown-buttons-do.md b/.changeset/brown-buttons-do.md new file mode 100644 index 00000000..6967d36b --- /dev/null +++ b/.changeset/brown-buttons-do.md @@ -0,0 +1,5 @@ +--- +'focus-trap-react': patch +--- + +Fix missing default export in typings; props no longer extend `React.AllHTMLAttributes` to allow things like `className` (those extra props have always been ignored anyway); deprecate default export; add named export in code ([#1396](https://github.com/focus-trap/focus-trap-react/issues/1396)) diff --git a/README.md b/README.md index 9ab51bed..71cb83c4 100644 --- a/README.md +++ b/README.md @@ -84,10 +84,9 @@ You can read further code examples in `demo/` (it's very simple), and [see how i Here's one more simple example: ```jsx -const React = require('react'); -const ReactDOM = require('react-dom'); // React 16-17 -const { createRoot } = require('react-dom/client'); // React 18 -const FocusTrap = require('focus-trap-react'); +import React from 'react'; +import { createRoot } from 'react-dom/client'; +import { FocusTrap } from 'focus-trap-react'; class Demo extends React.Component { constructor(props) { @@ -150,7 +149,6 @@ class Demo extends React.Component { } } -ReactDOM.render(, document.getElementById('root')); // React 16-17 createRoot(document.getElementById('root')).render(); // React 18 ``` @@ -192,14 +190,13 @@ The result can be that (depending on how you render the trap) in Strict Mode, th Example: ```jsx -const React = require('react'); -const { createRoot } = require('react-dom/client'); -const propTypes = require('prop-types'); -const FocusTrap = require('../../dist/focus-trap-react'); +import { forwardRef, Component } from 'react'; +import { createRoot } from 'react-dom/client'; +import { FocusTrap } from 'focus-trap-react'; const container = document.getElementById('demo-function-child'); -const TrapChild = React.forwardRef(function ({ onDeactivate }, ref) { +const TrapChild = forwardRef(function ({ onDeactivate }, ref) { return (

@@ -223,7 +220,7 @@ TrapChild.propTypes = { onDeactivate: propTypes.func, }; -class DemoFunctionChild extends React.Component { +class DemoFunctionChild extends Component { constructor(props) { super(props); diff --git a/demo/js/demo-animated-dialog.js b/demo/js/demo-animated-dialog.js index cce27178..0bb39b61 100644 --- a/demo/js/demo-animated-dialog.js +++ b/demo/js/demo-animated-dialog.js @@ -1,7 +1,7 @@ const { useState } = require('react'); const React = require('react'); const { createRoot } = require('react-dom/client'); -const FocusTrap = require('../../dist/focus-trap-react'); +const { FocusTrap } = require('../../dist/focus-trap-react'); const container = document.getElementById('demo-animated-dialog'); diff --git a/demo/js/demo-animated-trigger.js b/demo/js/demo-animated-trigger.js index b36f185f..2a431008 100644 --- a/demo/js/demo-animated-trigger.js +++ b/demo/js/demo-animated-trigger.js @@ -1,7 +1,7 @@ const { useState } = require('react'); const React = require('react'); const { createRoot } = require('react-dom/client'); -const FocusTrap = require('../../dist/focus-trap-react'); +const { FocusTrap } = require('../../dist/focus-trap-react'); const container = document.getElementById('demo-animated-trigger'); diff --git a/demo/js/demo-autofocus.js b/demo/js/demo-autofocus.js index eea7d652..861563c8 100644 --- a/demo/js/demo-autofocus.js +++ b/demo/js/demo-autofocus.js @@ -1,6 +1,6 @@ const React = require('react'); const { createRoot } = require('react-dom/client'); -const FocusTrap = require('../../dist/focus-trap-react'); +const { FocusTrap } = require('../../dist/focus-trap-react'); const container = document.getElementById('demo-autofocus'); diff --git a/demo/js/demo-containerelements-childless.js b/demo/js/demo-containerelements-childless.js index 5c245742..8ffd3e6e 100644 --- a/demo/js/demo-containerelements-childless.js +++ b/demo/js/demo-containerelements-childless.js @@ -1,6 +1,6 @@ const React = require('react'); const { createRoot } = require('react-dom/client'); -const FocusTrap = require('../../dist/focus-trap-react'); +const { FocusTrap } = require('../../dist/focus-trap-react'); const container = document.getElementById('demo-containerelements-childless'); diff --git a/demo/js/demo-containerelements.js b/demo/js/demo-containerelements.js index 8532baf7..ad718755 100644 --- a/demo/js/demo-containerelements.js +++ b/demo/js/demo-containerelements.js @@ -1,6 +1,6 @@ const React = require('react'); const { createRoot } = require('react-dom/client'); -const FocusTrap = require('../../dist/focus-trap-react'); +const { FocusTrap } = require('../../dist/focus-trap-react'); const container = document.getElementById('demo-containerelements'); diff --git a/demo/js/demo-defaults.js b/demo/js/demo-defaults.js index be5dd634..876dfabf 100644 --- a/demo/js/demo-defaults.js +++ b/demo/js/demo-defaults.js @@ -1,6 +1,6 @@ const React = require('react'); const { createRoot } = require('react-dom/client'); -const FocusTrap = require('../../dist/focus-trap-react'); +const { FocusTrap } = require('../../dist/focus-trap-react'); const container = document.getElementById('demo-defaults'); diff --git a/demo/js/demo-ffne.js b/demo/js/demo-ffne.js index 2973695c..a30587c1 100644 --- a/demo/js/demo-ffne.js +++ b/demo/js/demo-ffne.js @@ -1,6 +1,6 @@ const React = require('react'); const { createRoot } = require('react-dom/client'); -const FocusTrap = require('../../dist/focus-trap-react'); +const { FocusTrap } = require('../../dist/focus-trap-react'); const container = document.getElementById('demo-ffne'); diff --git a/demo/js/demo-iframe.js b/demo/js/demo-iframe.js index 3e9ebd3f..4d538cf2 100644 --- a/demo/js/demo-iframe.js +++ b/demo/js/demo-iframe.js @@ -2,7 +2,7 @@ const React = require('react'); const ReactDOM = require('react-dom'); const { createRoot } = require('react-dom/client'); const PropTypes = require('prop-types'); -const FocusTrap = require('../../dist/focus-trap-react'); +const { FocusTrap } = require('../../dist/focus-trap-react'); const { useRef, useState, useEffect } = React; const container = document.getElementById('demo-iframe'); diff --git a/demo/js/demo-setReturnFocus.js b/demo/js/demo-setReturnFocus.js index 1f56c09d..c9848f51 100644 --- a/demo/js/demo-setReturnFocus.js +++ b/demo/js/demo-setReturnFocus.js @@ -1,7 +1,7 @@ const { useState, useMemo } = require('react'); const React = require('react'); const { createRoot } = require('react-dom/client'); -const FocusTrap = require('../../dist/focus-trap-react'); +const { FocusTrap } = require('../../dist/focus-trap-react'); const container = document.getElementById('demo-setReturnFocus'); diff --git a/demo/js/demo-special-element.js b/demo/js/demo-special-element.js index f2f53cff..9de863bb 100644 --- a/demo/js/demo-special-element.js +++ b/demo/js/demo-special-element.js @@ -1,6 +1,6 @@ const React = require('react'); const { createRoot } = require('react-dom/client'); -const FocusTrap = require('../../dist/focus-trap-react'); +const { FocusTrap } = require('../../dist/focus-trap-react'); const container = document.getElementById('demo-special-element'); diff --git a/demo/js/demo-with-shadow-dom.js b/demo/js/demo-with-shadow-dom.js index 98d36160..df2cf425 100644 --- a/demo/js/demo-with-shadow-dom.js +++ b/demo/js/demo-with-shadow-dom.js @@ -1,6 +1,6 @@ const React = require('react'); const { createRoot } = require('react-dom/client'); -const FocusTrap = require('../../dist/focus-trap-react'); +const { FocusTrap } = require('../../dist/focus-trap-react'); const createShadow = function (hostEl, isOpen) { const containerEl = document.createElement('div'); diff --git a/index.d.ts b/index.d.ts index 6afe9355..81e09d5b 100644 --- a/index.d.ts +++ b/index.d.ts @@ -1,14 +1,56 @@ import { Options as FocusTrapOptions } from 'focus-trap'; import * as React from 'react'; +export interface FocusTrapProps { + /** + * __Single container child__ for the trap. Use `containerElements` instead + * if you need a trap with multiple containers. + */ + children?: React.ReactNode; + + /** + * By default, the trap will be active when it mounts, so it's activated by + * mounting, and deactivated by unmounting. Use this prop to control when + * it's active while it's mounted, or if it's initially inactive. + */ + active?: boolean; + + /** + * To pause or unpause the trap while it's `active`. Primarily for use when + * you need to manage multiple traps in the same view. When paused, the trap + * retains its various event listeners, but ignores all events. + */ + paused?: boolean; + + /** + * See Focus-trap's [createOptions](https://github.com/focus-trap/focus-trap?tab=readme-ov-file#createoptions) + * for more details on available options. + */ + focusTrapOptions?: FocusTrapOptions; + + /** + * If specified, these elements will be used as the boundaries for the + * trap, __instead of the child__ specified in `children` (though + * `children` will still be rendered). + */ + containerElements?: Array; +} + +export declare class FocusTrap extends React.Component { } + +/** + * Default export of the FocusTrap component. + * @deprecated 🔺 Use the named import `{ FocusTrap }` instead. + * @description 🔺 The default export will be removed in a future release. Migrate to the named + * import `{ FocusTrap }` today to ensure future compatibility. + */ declare namespace FocusTrap { - export interface Props extends React.AllHTMLAttributes { - children?: React.ReactNode; - active?: boolean; - paused?: boolean; - focusTrapOptions?: FocusTrapOptions; - containerElements?: Array; - } + export type Props = FocusTrapProps; } -export declare class FocusTrap extends React.Component { } +/** + * @deprecated 🔺 Use the named import `{ FocusTrap }` instead. + * @description 🔺 The default export will be removed in a future release. Migrate to the named + * import `{ FocusTrap }` today to ensure future compatibility. + */ +export default FocusTrap; diff --git a/src/focus-trap-react.js b/src/focus-trap-react.js index 971c918b..12da5192 100644 --- a/src/focus-trap-react.js +++ b/src/focus-trap-react.js @@ -425,4 +425,8 @@ FocusTrap.defaultProps = { _createFocusTrap: createFocusTrap, }; +// 🔺 DEPRECATED: default export module.exports = FocusTrap; + +// named export +module.exports.FocusTrap = FocusTrap; diff --git a/test/focus-trap-react.test.js b/test/focus-trap-react.test.js index 408a371b..2f0bcc10 100644 --- a/test/focus-trap-react.test.js +++ b/test/focus-trap-react.test.js @@ -6,7 +6,7 @@ const { waitFor, } = require('@testing-library/react'); const { default: userEvent } = require('@testing-library/user-event'); -const FocusTrap = require('../src/focus-trap-react'); +const { FocusTrap } = require('../src/focus-trap-react'); const getTestFocusTrapOptions = function (focusTrapOptions) { const { tabbableOptions, ...rest } = focusTrapOptions || {};