From 8f280f1022b56bed307b73124a9e7fa0e1b62fae Mon Sep 17 00:00:00 2001 From: Giampaolo Bellavite Date: Sat, 2 May 2026 11:42:38 +0200 Subject: [PATCH] fix: support React 19 in v8 --- .github/scripts/smoke-v8-release.mjs | 235 ++++++++++++++++++ .github/scripts/verify-npm-version.mjs | 18 ++ .github/workflows/package.yml | 41 +-- .github/workflows/release.yml | 71 ++++++ CHANGELOG.md | 6 + README.md | 2 + package.json | 6 +- src/DayPicker.tsx | 4 +- src/components/Button/Button.tsx | 3 +- src/components/Caption/Caption.tsx | 6 +- .../CaptionDropdowns/CaptionDropdowns.tsx | 4 +- src/components/CaptionLabel/CaptionLabel.tsx | 4 +- .../CaptionNavigation/CaptionNavigation.tsx | 4 +- src/components/Day/Day.tsx | 3 +- src/components/DayContent/DayContent.tsx | 4 +- src/components/Dropdown/Dropdown.tsx | 5 +- src/components/Footer/Footer.tsx | 4 +- src/components/Head/Head.tsx | 4 +- src/components/HeadRow/HeadRow.tsx | 4 +- src/components/IconDropdown/IconDropdown.tsx | 4 +- src/components/IconLeft/IconLeft.tsx | 4 +- src/components/IconRight/IconRight.tsx | 4 +- src/components/Months/Months.tsx | 4 +- .../MonthsDropdown/MonthsDropdown.tsx | 4 +- src/components/Navigation/Navigation.tsx | 4 +- src/components/Root/Root.tsx | 3 +- src/components/Row/Row.tsx | 4 +- src/components/Table/Table.tsx | 4 +- src/components/WeekNumber/WeekNumber.tsx | 4 +- .../YearsDropdown/YearsDropdown.tsx | 4 +- src/contexts/DayPicker/DayPickerContext.tsx | 5 +- src/contexts/Focus/FocusContext.tsx | 5 +- src/contexts/Modifiers/ModifiersContext.tsx | 5 +- src/contexts/Navigation/NavigationContext.tsx | 5 +- src/contexts/RootProvider.tsx | 4 +- .../SelectMultipleContext.test.ts | 2 +- .../SelectMultiple/SelectMultipleContext.tsx | 7 +- .../SelectRange/SelectRangeContext.test.ts | 2 +- .../SelectRange/SelectRangeContext.tsx | 7 +- .../SelectSingle/SelectSingleContext.test.ts | 2 +- .../SelectSingle/SelectSingleContext.tsx | 7 +- .../useControlledValue.test.ts | 2 +- .../useDayEventHandlers.tsx | 2 +- src/hooks/useDayRender/useDayRender.tsx | 3 +- src/hooks/useDayRender/utils/getDayStyle.ts | 2 +- src/hooks/useInput/useInput.ts | 6 +- src/types/DayPickerBase.ts | 30 +-- src/types/EventHandlers.ts | 2 +- src/types/Formatters.ts | 2 +- src/types/Modifiers.ts | 2 +- src/types/Styles.ts | 2 +- test/render/customRender.tsx | 2 +- test/render/renderDayPickerHook.tsx | 4 +- 53 files changed, 458 insertions(+), 123 deletions(-) create mode 100644 .github/scripts/smoke-v8-release.mjs create mode 100644 .github/scripts/verify-npm-version.mjs create mode 100644 .github/workflows/release.yml diff --git a/.github/scripts/smoke-v8-release.mjs b/.github/scripts/smoke-v8-release.mjs new file mode 100644 index 0000000000..f361569f2a --- /dev/null +++ b/.github/scripts/smoke-v8-release.mjs @@ -0,0 +1,235 @@ +/* eslint-env node */ +import { execFileSync } from 'node:child_process'; +import { copyFileSync, mkdirSync, mkdtempSync, writeFileSync } from 'node:fs'; +import { tmpdir } from 'node:os'; +import { join } from 'node:path'; + +const command = process.argv[2]; + +if (!command) { + throw new Error('Expected a smoke test command.'); +} + +const env = { + ...process.env, + NPM_CONFIG_CACHE: + process.env.NPM_CONFIG_CACHE || join(tmpdir(), 'rdp-v8-npm-cache') +}; + +function run(binary, args, cwd) { + execFileSync(binary, args, { cwd, env, stdio: 'inherit' }); +} + +function packTarball() { + const destination = + process.env.RUNNER_TEMP || mkdtempSync(join(tmpdir(), 'rdp-pack-')); + const filename = execFileSync( + 'npm', + ['pack', '--pack-destination', destination, '--silent'], + { encoding: 'utf8' } + ) + .trim() + .split('\n') + .pop(); + + return join(destination, filename); +} + +function createConsumer(tarball) { + const directory = mkdtempSync(join(tmpdir(), 'rdp-consumer-')); + + copyFileSync(tarball, join(directory, 'react-day-picker.tgz')); + writeFileSync( + join(directory, 'package.json'), + `${JSON.stringify({ private: true, type: 'commonjs' }, null, 2)}\n` + ); + + return directory; +} + +function installConsumer(directory, dependencies) { + run( + 'npm', + ['install', '--ignore-scripts', './react-day-picker.tgz', ...dependencies], + directory + ); +} + +function writeTypescriptConfig(directory) { + writeFileSync( + join(directory, 'tsconfig.json'), + `${JSON.stringify( + { + compilerOptions: { + strict: true, + jsx: 'react-jsx', + module: 'NodeNext', + moduleResolution: 'NodeNext', + target: 'ES2022', + skipLibCheck: false, + noEmit: true + }, + include: ['src'] + }, + null, + 2 + )}\n` + ); +} + +function writeTypescriptFixture(directory, options) { + mkdirSync(join(directory, 'src')); + + const multiplePicker = options.includeMultiple + ? ` +export function MultiplePicker() { + const [selected, setSelected] = useState(); + return ; +} +` + : ''; + + const customDayContentPicker = options.includeCustomDayContent + ? ` +export function CustomDayContentPicker() { + return ( + {props.date.getDate()}; + } + }} + /> + ); +} +` + : ''; + + writeFileSync( + join(directory, 'src/index.tsx'), + `import { createRef, useState } from "react"; +import { DayPicker, type ButtonProps, type DateRange } from "react-day-picker"; +import "react-day-picker/dist/style.css"; + +const buttonRef = createRef(); +const buttonProps: ButtonProps = { ref: buttonRef, type: "button" }; +void buttonProps; + +export function SinglePicker() { + const [selected, setSelected] = useState(); + return ; +} +${multiplePicker} +export function RangePicker() { + const [selected, setSelected] = useState(); + return ; +} +${customDayContentPicker}` + ); +} + +function runTypescriptSmoke(tarball, options) { + const directory = createConsumer(tarball); + + installConsumer(directory, [ + `react@${options.react}`, + `react-dom@${options.react}`, + `date-fns@${options.dateFns}`, + 'typescript@^5', + `@types/react@${options.reactTypes}`, + `@types/react-dom@${options.reactDomTypes}` + ]); + + writeTypescriptConfig(directory); + writeTypescriptFixture(directory, options); + run('npx', ['tsc', '--noEmit'], directory); +} + +function writeRuntimeFixture(directory) { + writeFileSync( + join(directory, 'smoke.mjs'), + `import { createRequire } from "node:module"; + +const require = createRequire(import.meta.url); +const { JSDOM } = require("jsdom"); + +const dom = new JSDOM('
'); +globalThis.window = dom.window; +globalThis.document = dom.window.document; +globalThis.HTMLElement = dom.window.HTMLElement; +globalThis.Node = dom.window.Node; +Object.defineProperty(globalThis, "navigator", { + value: dom.window.navigator, + configurable: true +}); + +const React = require("react"); +const { flushSync } = require("react-dom"); +const { createRoot } = require("react-dom/client"); +const { DayPicker } = require("react-day-picker"); + +const container = document.getElementById("root"); +const root = createRoot(container); + +flushSync(() => { + root.render(React.createElement(DayPicker, { month: new Date(2024, 0, 1) })); +}); + +if (!container.querySelector(".rdp")) { + throw new Error("DayPicker did not render its root element."); +} + +root.unmount(); +` + ); +} + +function runRuntimeSmoke(tarball, options) { + const directory = createConsumer(tarball); + + installConsumer(directory, [ + `react@${options.react}`, + `react-dom@${options.react}`, + `date-fns@${options.dateFns}`, + 'jsdom@^24.1.3' + ]); + + writeRuntimeFixture(directory); + run('node', ['smoke.mjs'], directory); +} + +const tarball = packTarball(); + +switch (command) { + case 'react19-runtime': + runRuntimeSmoke(tarball, { react: '19', dateFns: '3' }); + runRuntimeSmoke(tarball, { react: '19', dateFns: '2' }); + break; + + case 'react19-types': + runTypescriptSmoke(tarball, { + react: '19', + reactTypes: '19', + reactDomTypes: '19', + dateFns: '3', + includeMultiple: false, + includeCustomDayContent: false + }); + break; + + case 'react18-types': + for (const dateFns of ['2', '3']) { + runTypescriptSmoke(tarball, { + react: '18', + reactTypes: '18', + reactDomTypes: '18', + dateFns, + includeMultiple: true, + includeCustomDayContent: true + }); + } + break; + + default: + throw new Error(`Unknown smoke test command: ${command}`); +} diff --git a/.github/scripts/verify-npm-version.mjs b/.github/scripts/verify-npm-version.mjs new file mode 100644 index 0000000000..a306ba5533 --- /dev/null +++ b/.github/scripts/verify-npm-version.mjs @@ -0,0 +1,18 @@ +/* eslint-env node */ +import { execFileSync } from 'node:child_process'; + +const minimum = [11, 5, 1]; +const version = execFileSync('npm', ['--version'], { + encoding: 'utf8' +}).trim(); +const current = version.split('.').map(Number); + +for (let index = 0; index < minimum.length; index += 1) { + if (current[index] > minimum[index]) { + process.exit(0); + } + + if (current[index] < minimum[index]) { + throw new Error(`npm ${version} does not satisfy >=11.5.1`); + } +} diff --git a/.github/workflows/package.yml b/.github/workflows/package.yml index 7af356c65d..ebdab1cf34 100644 --- a/.github/workflows/package.yml +++ b/.github/workflows/package.yml @@ -1,29 +1,17 @@ name: react-day-picker on: - release: - types: [published] pull_request: branches: - main + - maintenance/v8 push: branches: - main + - maintenance/v8 workflow_dispatch: - inputs: - publish: - description: Publish on npm - required: false - default: false - type: boolean jobs: - # print-env: - # runs-on: ubuntu-latest - # steps: - # - run: | - # echo "publish=${{ github.event.inputs.publish || false }}" - typecheck: runs-on: ubuntu-latest steps: @@ -84,28 +72,3 @@ jobs: with: name: rdp-dist path: dist - - publish-on-npm: - runs-on: ubuntu-latest - needs: [build, test] - if: ${{ github.event_name == 'release' || github.event.inputs.publish }} - permissions: - id-token: write - steps: - - uses: actions/checkout@v4 - - uses: pnpm/action-setup@v3 - with: - version: 8.6.2 - - uses: actions/setup-node@v4 - with: - node-version: 18.16 - registry-url: https://registry.npmjs.org/ - always-auth: false - - uses: actions/download-artifact@v4 - with: - name: rdp-dist - path: dist - - run: echo "//:8080/:_authToken=$NODE_AUTH_TOKEN" > ~/.npmrc - - run: npm publish --provenance - env: - NODE_AUTH_TOKEN: ${{ secrets.npm_token }} diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 0000000000..1c9b933449 --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,71 @@ +name: react-day-picker v8 release + +on: + release: + types: [published] + +permissions: + contents: read + +jobs: + validate: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: pnpm/action-setup@v3 + with: + version: 8.6.2 + - uses: actions/setup-node@v4 + with: + node-version: 24 + cache: pnpm + - run: pnpm install --frozen-lockfile + - run: pnpm typecheck + - run: pnpm test + - run: pnpm build + - name: Verify npm trusted publishing support + run: node .github/scripts/verify-npm-version.mjs + - name: Smoke test React 19 consumer installs + run: node .github/scripts/smoke-v8-release.mjs react19-runtime + - name: Smoke test React 19 TypeScript declarations + run: node .github/scripts/smoke-v8-release.mjs react19-types + - name: Smoke test React 18 TypeScript declarations + run: node .github/scripts/smoke-v8-release.mjs react18-types + + publish: + needs: validate + runs-on: ubuntu-latest + permissions: + contents: read + id-token: write + steps: + - uses: actions/checkout@v4 + - uses: pnpm/action-setup@v3 + with: + version: 8.6.2 + - uses: actions/setup-node@v4 + with: + node-version: 24 + registry-url: https://registry.npmjs.org/ + - name: Block prerelease publishing + env: + RELEASE_PRERELEASE: ${{ github.event.release.prerelease }} + run: | + if [ "$RELEASE_PRERELEASE" = "true" ]; then + echo "Prerelease GitHub Releases cannot publish stable v8 packages." >&2 + exit 1 + fi + - name: Verify release tag matches package version + env: + RELEASE_TAG: ${{ github.event.release.tag_name }} + run: | + expected_tag="v$(node -p "require('./package.json').version")" + if [ "$RELEASE_TAG" != "$expected_tag" ]; then + echo "Release tag $RELEASE_TAG does not match package version $expected_tag." >&2 + exit 1 + fi + - run: pnpm install --frozen-lockfile + - run: pnpm build + - name: Verify npm trusted publishing support + run: node .github/scripts/verify-npm-version.mjs + - run: npm publish --tag legacy-v8 diff --git a/CHANGELOG.md b/CHANGELOG.md index a0ff3e7855..135a8a8bde 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,9 @@ # Changelog +## v8.10.2 + +_Release date: 2026-05-02_ + +- Expand React peer dependency support to include React 19. This release has no runtime or API changes. + Full release notes at https://github.com/gpbl/react-day-picker/releases diff --git a/README.md b/README.md index e1a45be696..d482c5c132 100644 --- a/README.md +++ b/README.md @@ -30,6 +30,8 @@ pnpm install react-day-picker date-fns # using pnpm yarn add react-day-picker date-fns # using yarn ``` +DayPicker v8 supports React 16.8, 17, 18, and 19, with date-fns 2 or 3. + npm version npm downloads Min gzipped size ## Example diff --git a/package.json b/package.json index 8dc71d0cc3..ec40948479 100644 --- a/package.json +++ b/package.json @@ -1,13 +1,13 @@ { "name": "react-day-picker", - "version": "8.10.1", + "version": "8.10.2", "description": "Customizable Date Picker for React", "author": "Giampaolo Bellavite ", "homepage": "http://react-day-picker.js.org", "license": "MIT", "repository": { "type": "git", - "url": "https://github.com/gpbl/react-day-picker" + "url": "git+https://github.com/gpbl/react-day-picker.git" }, "bugs": { "url": "https://github.com/gpbl/react-day-picker/issues" @@ -81,7 +81,7 @@ }, "peerDependencies": { "date-fns": "^2.28.0 || ^3.0.0", - "react": "^16.8.0 || ^17.0.0 || ^18.0.0" + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" }, "funding": { "type": "individual", diff --git a/src/DayPicker.tsx b/src/DayPicker.tsx index b4133eaadd..4371a9a758 100644 --- a/src/DayPicker.tsx +++ b/src/DayPicker.tsx @@ -1,3 +1,5 @@ +import type { ReactElement } from 'react'; + import { DayPickerDefaultProps } from 'types/DayPickerDefault'; import { DayPickerMultipleProps } from 'types/DayPickerMultiple'; import { DayPickerRangeProps } from 'types/DayPickerRange'; @@ -105,7 +107,7 @@ export function DayPicker( | DayPickerSingleProps | DayPickerMultipleProps | DayPickerRangeProps -): JSX.Element { +): ReactElement { return ( diff --git a/src/components/Button/Button.tsx b/src/components/Button/Button.tsx index 325a3122de..cd96624b2b 100644 --- a/src/components/Button/Button.tsx +++ b/src/components/Button/Button.tsx @@ -1,9 +1,10 @@ import { forwardRef } from 'react'; +import type { ComponentPropsWithRef } from 'react'; import { useDayPicker } from 'contexts/DayPicker'; /** The props for the {@link Button} component. */ -export type ButtonProps = JSX.IntrinsicElements['button']; +export type ButtonProps = ComponentPropsWithRef<'button'>; /** Render a button HTML element applying the reset class name. */ export const Button = forwardRef( diff --git a/src/components/Caption/Caption.tsx b/src/components/Caption/Caption.tsx index 18b6274665..9d51ece0dc 100644 --- a/src/components/Caption/Caption.tsx +++ b/src/components/Caption/Caption.tsx @@ -1,3 +1,5 @@ +import type { ReactElement } from 'react'; + import { CaptionDropdowns } from 'components/CaptionDropdowns'; import { CaptionLabel } from 'components/CaptionLabel'; import { CaptionNavigation } from 'components/CaptionNavigation'; @@ -26,13 +28,13 @@ export type CaptionLayout = 'dropdown' | 'buttons' | 'dropdown-buttons'; * Render the caption of a month. The caption has a different layout when * setting the {@link DayPickerBase.captionLayout} prop. */ -export function Caption(props: CaptionProps): JSX.Element { +export function Caption(props: CaptionProps): ReactElement { const { classNames, disableNavigation, styles, captionLayout, components } = useDayPicker(); const CaptionLabelComponent = components?.CaptionLabel ?? CaptionLabel; - let caption: JSX.Element; + let caption: ReactElement; if (disableNavigation) { caption = ( diff --git a/src/components/CaptionDropdowns/CaptionDropdowns.tsx b/src/components/CaptionDropdowns/CaptionDropdowns.tsx index 073f2852f2..8996fb2d2f 100644 --- a/src/components/CaptionDropdowns/CaptionDropdowns.tsx +++ b/src/components/CaptionDropdowns/CaptionDropdowns.tsx @@ -1,3 +1,5 @@ +import type { ReactElement } from 'react'; + import { addMonths } from 'date-fns'; import { CaptionProps } from 'components/Caption/Caption'; @@ -11,7 +13,7 @@ import { MonthChangeEventHandler } from 'types/EventHandlers'; /** * Render a caption with the dropdowns to navigate between months and years. */ -export function CaptionDropdowns(props: CaptionProps): JSX.Element { +export function CaptionDropdowns(props: CaptionProps): ReactElement { const { classNames, styles, components } = useDayPicker(); const { goToMonth } = useNavigation(); diff --git a/src/components/CaptionLabel/CaptionLabel.tsx b/src/components/CaptionLabel/CaptionLabel.tsx index 86eb995afe..9004250a86 100644 --- a/src/components/CaptionLabel/CaptionLabel.tsx +++ b/src/components/CaptionLabel/CaptionLabel.tsx @@ -1,3 +1,5 @@ +import type { ReactElement } from 'react'; + import { useDayPicker } from 'contexts/DayPicker'; /** The props for the {@link CaptionLabel} component. */ @@ -11,7 +13,7 @@ export interface CaptionLabelProps { } /** Render the caption for the displayed month. This component is used when `captionLayout="buttons"`. */ -export function CaptionLabel(props: CaptionLabelProps): JSX.Element { +export function CaptionLabel(props: CaptionLabelProps): ReactElement { const { locale, classNames, diff --git a/src/components/CaptionNavigation/CaptionNavigation.tsx b/src/components/CaptionNavigation/CaptionNavigation.tsx index 5412a89cfc..fbf36af2d8 100644 --- a/src/components/CaptionNavigation/CaptionNavigation.tsx +++ b/src/components/CaptionNavigation/CaptionNavigation.tsx @@ -1,4 +1,4 @@ -import { MouseEventHandler } from 'react'; +import type { MouseEventHandler, ReactElement } from 'react'; import { isSameMonth } from 'date-fns'; @@ -10,7 +10,7 @@ import { useNavigation } from 'contexts/Navigation'; /** * Render a caption with a button-based navigation. */ -export function CaptionNavigation(props: CaptionProps): JSX.Element { +export function CaptionNavigation(props: CaptionProps): ReactElement { const { numberOfMonths } = useDayPicker(); const { previousMonth, nextMonth, goToMonth, displayMonths } = useNavigation(); diff --git a/src/components/Day/Day.tsx b/src/components/Day/Day.tsx index ee9e953787..8b908a4075 100644 --- a/src/components/Day/Day.tsx +++ b/src/components/Day/Day.tsx @@ -1,4 +1,5 @@ import { useRef } from 'react'; +import type { ReactElement } from 'react'; import { useDayRender } from 'hooks/useDayRender'; @@ -16,7 +17,7 @@ export interface DayProps { * The content of a day cell – as a button or span element according to its * modifiers. */ -export function Day(props: DayProps): JSX.Element { +export function Day(props: DayProps): ReactElement { const buttonRef = useRef(null); const dayRender = useDayRender(props.date, props.displayMonth, buttonRef); diff --git a/src/components/DayContent/DayContent.tsx b/src/components/DayContent/DayContent.tsx index afa729a34a..285a157d39 100644 --- a/src/components/DayContent/DayContent.tsx +++ b/src/components/DayContent/DayContent.tsx @@ -1,3 +1,5 @@ +import type { ReactElement } from 'react'; + import { useDayPicker } from 'contexts/DayPicker'; import { ActiveModifiers } from 'types/Modifiers'; @@ -12,7 +14,7 @@ export interface DayContentProps { } /** Render the content of the day cell. */ -export function DayContent(props: DayContentProps): JSX.Element { +export function DayContent(props: DayContentProps): ReactElement { const { locale, formatters: { formatDay } diff --git a/src/components/Dropdown/Dropdown.tsx b/src/components/Dropdown/Dropdown.tsx index c0e92432fa..4a189eac02 100644 --- a/src/components/Dropdown/Dropdown.tsx +++ b/src/components/Dropdown/Dropdown.tsx @@ -1,6 +1,7 @@ -import { +import type { ChangeEventHandler, CSSProperties, + ReactElement, ReactNode, SelectHTMLAttributes } from 'react'; @@ -27,7 +28,7 @@ export interface DropdownProps { * Render a styled select component – displaying a caption and a custom * drop-down icon. */ -export function Dropdown(props: DropdownProps): JSX.Element { +export function Dropdown(props: DropdownProps): ReactElement { const { onChange, value, children, caption, className, style } = props; const dayPicker = useDayPicker(); diff --git a/src/components/Footer/Footer.tsx b/src/components/Footer/Footer.tsx index 4e5446b192..db45e1d14e 100644 --- a/src/components/Footer/Footer.tsx +++ b/src/components/Footer/Footer.tsx @@ -1,3 +1,5 @@ +import type { ReactElement } from 'react'; + import { useDayPicker } from 'contexts/DayPicker'; export interface FooterProps { @@ -6,7 +8,7 @@ export interface FooterProps { } /** Render the Footer component (empty as default).*/ // eslint-disable-next-line @typescript-eslint/no-unused-vars -export function Footer(props: FooterProps): JSX.Element { +export function Footer(props: FooterProps): ReactElement { const { footer, styles, diff --git a/src/components/Head/Head.tsx b/src/components/Head/Head.tsx index 972c5dbfe8..8511730b6a 100644 --- a/src/components/Head/Head.tsx +++ b/src/components/Head/Head.tsx @@ -1,8 +1,10 @@ +import type { ReactElement } from 'react'; + import { HeadRow } from 'components/HeadRow'; import { useDayPicker } from 'contexts/DayPicker'; /** Render the table head. */ -export function Head(): JSX.Element { +export function Head(): ReactElement { const { classNames, styles, components } = useDayPicker(); const HeadRowComponent = components?.HeadRow ?? HeadRow; return ( diff --git a/src/components/HeadRow/HeadRow.tsx b/src/components/HeadRow/HeadRow.tsx index 6c4b9d0adf..141a0040e5 100644 --- a/src/components/HeadRow/HeadRow.tsx +++ b/src/components/HeadRow/HeadRow.tsx @@ -1,3 +1,5 @@ +import type { ReactElement } from 'react'; + import { useDayPicker } from 'contexts/DayPicker'; import { getWeekdays } from './utils'; @@ -5,7 +7,7 @@ import { getWeekdays } from './utils'; /** * Render the HeadRow component - i.e. the table head row with the weekday names. */ -export function HeadRow(): JSX.Element { +export function HeadRow(): ReactElement { const { classNames, styles, diff --git a/src/components/IconDropdown/IconDropdown.tsx b/src/components/IconDropdown/IconDropdown.tsx index a2ed253a26..451d794b4f 100644 --- a/src/components/IconDropdown/IconDropdown.tsx +++ b/src/components/IconDropdown/IconDropdown.tsx @@ -1,9 +1,11 @@ +import type { ReactElement } from 'react'; + import { StyledComponent } from 'types/Styles'; /** * Render the icon in the styled drop-down. */ -export function IconDropdown(props: StyledComponent): JSX.Element { +export function IconDropdown(props: StyledComponent): ReactElement { return ( ( export type FocusProviderProps = { children: ReactNode }; /** The provider for the {@link FocusContext}. */ -export function FocusProvider(props: FocusProviderProps): JSX.Element { +export function FocusProvider(props: FocusProviderProps): ReactElement { const navigation = useNavigation(); const modifiers = useModifiers(); diff --git a/src/contexts/Modifiers/ModifiersContext.tsx b/src/contexts/Modifiers/ModifiersContext.tsx index d5496c54dd..4ae665c2af 100644 --- a/src/contexts/Modifiers/ModifiersContext.tsx +++ b/src/contexts/Modifiers/ModifiersContext.tsx @@ -1,4 +1,5 @@ -import { createContext, useContext, ReactNode } from 'react'; +import { createContext, useContext } from 'react'; +import type { ReactElement, ReactNode } from 'react'; import { useDayPicker } from 'contexts/DayPicker'; import { useSelectMultiple } from 'contexts/SelectMultiple'; @@ -14,7 +15,7 @@ export const ModifiersContext = createContext(undefined); export type ModifiersProviderProps = { children: ReactNode }; /** Provide the value for the {@link ModifiersContext}. */ -export function ModifiersProvider(props: ModifiersProviderProps): JSX.Element { +export function ModifiersProvider(props: ModifiersProviderProps): ReactElement { const dayPicker = useDayPicker(); const selectMultiple = useSelectMultiple(); const selectRange = useSelectRange(); diff --git a/src/contexts/Navigation/NavigationContext.tsx b/src/contexts/Navigation/NavigationContext.tsx index 0f4cb065fe..d0d8417c81 100644 --- a/src/contexts/Navigation/NavigationContext.tsx +++ b/src/contexts/Navigation/NavigationContext.tsx @@ -1,4 +1,5 @@ -import { createContext, ReactNode, useContext } from 'react'; +import { createContext, useContext } from 'react'; +import type { ReactElement, ReactNode } from 'react'; import { addMonths, isBefore, isSameMonth } from 'date-fns'; @@ -37,7 +38,7 @@ export const NavigationContext = createContext< /** Provides the values for the {@link NavigationContext}. */ export function NavigationProvider(props: { children?: ReactNode; -}): JSX.Element { +}): ReactElement { const dayPicker = useDayPicker(); const [currentMonth, goToMonth] = useNavigationState(); diff --git a/src/contexts/RootProvider.tsx b/src/contexts/RootProvider.tsx index 1a625dc952..58cc182b84 100644 --- a/src/contexts/RootProvider.tsx +++ b/src/contexts/RootProvider.tsx @@ -1,4 +1,4 @@ -import { ReactNode } from 'react'; +import type { ReactElement, ReactNode } from 'react'; import { ModifiersProvider } from 'contexts/Modifiers/ModifiersContext'; @@ -25,7 +25,7 @@ export type RootContext = RootContextProps & { }; /** Provide the value for all the context providers. */ -export function RootProvider(props: RootContext): JSX.Element { +export function RootProvider(props: RootContext): ReactElement { const { children, ...initialProps } = props; return ( diff --git a/src/contexts/SelectMultiple/SelectMultipleContext.test.ts b/src/contexts/SelectMultiple/SelectMultipleContext.test.ts index 3457f264b5..1556623249 100644 --- a/src/contexts/SelectMultiple/SelectMultipleContext.test.ts +++ b/src/contexts/SelectMultiple/SelectMultipleContext.test.ts @@ -1,4 +1,4 @@ -import { MouseEvent } from 'react'; +import type { MouseEvent } from 'react'; import { addDays, addMonths } from 'date-fns'; import { DayPickerProps } from 'DayPicker'; diff --git a/src/contexts/SelectMultiple/SelectMultipleContext.tsx b/src/contexts/SelectMultiple/SelectMultipleContext.tsx index 8c48757794..56f879f905 100644 --- a/src/contexts/SelectMultiple/SelectMultipleContext.tsx +++ b/src/contexts/SelectMultiple/SelectMultipleContext.tsx @@ -1,4 +1,5 @@ -import { createContext, ReactNode, useContext } from 'react'; +import { createContext, useContext } from 'react'; +import type { ReactElement, ReactNode } from 'react'; import { isSameDay } from 'date-fns'; @@ -44,7 +45,7 @@ export type SelectMultipleProviderProps = { /** Provides the values for the {@link SelectMultipleContext}. */ export function SelectMultipleProvider( props: SelectMultipleProviderProps -): JSX.Element { +): ReactElement { if (!isDayPickerMultiple(props.initialProps)) { const emptyContextValue: SelectMultipleContextValue = { selected: undefined, @@ -75,7 +76,7 @@ export interface SelectMultipleProviderInternalProps { export function SelectMultipleProviderInternal({ initialProps, children -}: SelectMultipleProviderInternalProps): JSX.Element { +}: SelectMultipleProviderInternalProps): ReactElement { const { selected, min, max } = initialProps; const onDayClick: DayClickEventHandler = (day, activeModifiers, e) => { diff --git a/src/contexts/SelectRange/SelectRangeContext.test.ts b/src/contexts/SelectRange/SelectRangeContext.test.ts index bd8000c7ad..a79094988e 100644 --- a/src/contexts/SelectRange/SelectRangeContext.test.ts +++ b/src/contexts/SelectRange/SelectRangeContext.test.ts @@ -1,4 +1,4 @@ -import { MouseEvent } from 'react'; +import type { MouseEvent } from 'react'; import { addDays, diff --git a/src/contexts/SelectRange/SelectRangeContext.tsx b/src/contexts/SelectRange/SelectRangeContext.tsx index cb171fb1e1..92c5425cd7 100644 --- a/src/contexts/SelectRange/SelectRangeContext.tsx +++ b/src/contexts/SelectRange/SelectRangeContext.tsx @@ -1,4 +1,5 @@ -import { createContext, ReactNode, useContext } from 'react'; +import { createContext, useContext } from 'react'; +import type { ReactElement, ReactNode } from 'react'; import { addDays, @@ -52,7 +53,7 @@ export interface SelectRangeProviderProps { /** Provides the values for the {@link SelectRangeProvider}. */ export function SelectRangeProvider( props: SelectRangeProviderProps -): JSX.Element { +): ReactElement { if (!isDayPickerRange(props.initialProps)) { const emptyContextValue: SelectRangeContextValue = { selected: undefined, @@ -86,7 +87,7 @@ export interface SelectRangeProviderInternalProps { export function SelectRangeProviderInternal({ initialProps, children -}: SelectRangeProviderInternalProps): JSX.Element { +}: SelectRangeProviderInternalProps): ReactElement { const { selected } = initialProps; const { from: selectedFrom, to: selectedTo } = selected || {}; const min = initialProps.min; diff --git a/src/contexts/SelectSingle/SelectSingleContext.test.ts b/src/contexts/SelectSingle/SelectSingleContext.test.ts index 30fb546492..5954573d96 100644 --- a/src/contexts/SelectSingle/SelectSingleContext.test.ts +++ b/src/contexts/SelectSingle/SelectSingleContext.test.ts @@ -1,4 +1,4 @@ -import { MouseEvent } from 'react'; +import type { MouseEvent } from 'react'; import { DayPickerProps } from 'DayPicker'; diff --git a/src/contexts/SelectSingle/SelectSingleContext.tsx b/src/contexts/SelectSingle/SelectSingleContext.tsx index d4b4f0d4db..f48e227e3d 100644 --- a/src/contexts/SelectSingle/SelectSingleContext.tsx +++ b/src/contexts/SelectSingle/SelectSingleContext.tsx @@ -1,4 +1,5 @@ -import { createContext, ReactNode, useContext } from 'react'; +import { createContext, useContext } from 'react'; +import type { ReactElement, ReactNode } from 'react'; import { DayPickerBase } from 'types/DayPickerBase'; import { DayPickerSingleProps, isDayPickerSingle } from 'types/DayPickerSingle'; @@ -30,7 +31,7 @@ export interface SelectSingleProviderProps { /** Provides the values for the {@link SelectSingleProvider}. */ export function SelectSingleProvider( props: SelectSingleProviderProps -): JSX.Element { +): ReactElement { if (!isDayPickerSingle(props.initialProps)) { const emptyContextValue: SelectSingleContextValue = { selected: undefined @@ -58,7 +59,7 @@ export interface SelectSingleProviderInternal { export function SelectSingleProviderInternal({ initialProps, children -}: SelectSingleProviderInternal): JSX.Element { +}: SelectSingleProviderInternal): ReactElement { const onDayClick: DayClickEventHandler = (day, activeModifiers, e) => { initialProps.onDayClick?.(day, activeModifiers, e); diff --git a/src/hooks/useControlledValue/useControlledValue.test.ts b/src/hooks/useControlledValue/useControlledValue.test.ts index 96b361115e..9a6e3f45b9 100644 --- a/src/hooks/useControlledValue/useControlledValue.test.ts +++ b/src/hooks/useControlledValue/useControlledValue.test.ts @@ -1,4 +1,4 @@ -import { act } from 'react-dom/test-utils'; +import { act } from '@testing-library/react'; import { renderDayPickerHook } from 'test/render'; diff --git a/src/hooks/useDayEventHandlers/useDayEventHandlers.tsx b/src/hooks/useDayEventHandlers/useDayEventHandlers.tsx index 935dcc1844..22306dfaae 100644 --- a/src/hooks/useDayEventHandlers/useDayEventHandlers.tsx +++ b/src/hooks/useDayEventHandlers/useDayEventHandlers.tsx @@ -1,4 +1,4 @@ -import { +import type { FocusEventHandler, HTMLProps, KeyboardEventHandler, diff --git a/src/hooks/useDayRender/useDayRender.tsx b/src/hooks/useDayRender/useDayRender.tsx index 5646a71239..701fa582de 100644 --- a/src/hooks/useDayRender/useDayRender.tsx +++ b/src/hooks/useDayRender/useDayRender.tsx @@ -1,4 +1,5 @@ -import { RefObject, useEffect } from 'react'; +import { useEffect } from 'react'; +import type { RefObject } from 'react'; import { isSameDay } from 'date-fns'; diff --git a/src/hooks/useDayRender/utils/getDayStyle.ts b/src/hooks/useDayRender/utils/getDayStyle.ts index 58858dafef..532d0ea8f6 100644 --- a/src/hooks/useDayRender/utils/getDayStyle.ts +++ b/src/hooks/useDayRender/utils/getDayStyle.ts @@ -1,4 +1,4 @@ -import { CSSProperties } from 'react'; +import type { CSSProperties } from 'react'; import { DayPickerContextValue } from 'contexts/DayPicker'; import { ActiveModifiers } from 'types/Modifiers'; diff --git a/src/hooks/useInput/useInput.ts b/src/hooks/useInput/useInput.ts index 7cfa71bd00..f200dd022b 100644 --- a/src/hooks/useInput/useInput.ts +++ b/src/hooks/useInput/useInput.ts @@ -1,8 +1,8 @@ -import { +import { useState } from 'react'; +import type { ChangeEventHandler, FocusEventHandler, - InputHTMLAttributes, - useState + InputHTMLAttributes } from 'react'; import { differenceInCalendarDays, format as _format, parse } from 'date-fns'; diff --git a/src/types/DayPickerBase.ts b/src/types/DayPickerBase.ts index e49aa1c768..49b39da4df 100644 --- a/src/types/DayPickerBase.ts +++ b/src/types/DayPickerBase.ts @@ -1,4 +1,4 @@ -import { CSSProperties, ReactNode } from 'react'; +import type { CSSProperties, ReactElement, ReactNode } from 'react'; import { Locale } from 'date-fns'; @@ -386,9 +386,9 @@ export interface DayPickerBase { */ export interface CustomComponents { /** The component for the caption element. */ - Caption?: (props: CaptionProps) => JSX.Element | null; + Caption?: (props: CaptionProps) => ReactElement | null; /** The component for the caption element. */ - CaptionLabel?: (props: CaptionLabelProps) => JSX.Element | null; + CaptionLabel?: (props: CaptionLabelProps) => ReactElement | null; /** * The component for the day element. * @@ -400,27 +400,27 @@ export interface CustomComponents { * - a `div` or a `span` element, when the day is not interactive * */ - Day?: (props: DayProps) => JSX.Element | null; + Day?: (props: DayProps) => ReactElement | null; /** The component for the content of the day element. */ - DayContent?: (props: DayContentProps) => JSX.Element | null; + DayContent?: (props: DayContentProps) => ReactElement | null; /** The component for the drop-down elements. */ - Dropdown?: (props: DropdownProps) => JSX.Element | null; + Dropdown?: (props: DropdownProps) => ReactElement | null; /** The component for the table footer. */ - Footer?: (props: FooterProps) => JSX.Element | null; + Footer?: (props: FooterProps) => ReactElement | null; /** The component for the table’s head. */ - Head?: () => JSX.Element | null; + Head?: () => ReactElement | null; /** The component for the table’s head row. */ - HeadRow?: () => JSX.Element | null; + HeadRow?: () => ReactElement | null; /** The component for the small icon in the drop-downs. */ - IconDropdown?: (props: StyledComponent) => JSX.Element | null; + IconDropdown?: (props: StyledComponent) => ReactElement | null; /** The arrow right icon (used for the Navigation buttons). */ - IconRight?: (props: StyledComponent) => JSX.Element | null; + IconRight?: (props: StyledComponent) => ReactElement | null; /** The arrow left icon (used for the Navigation buttons). */ - IconLeft?: (props: StyledComponent) => JSX.Element | null; + IconLeft?: (props: StyledComponent) => ReactElement | null; /** The component wrapping the month grids. */ - Months?: (props: MonthsProps) => JSX.Element | null; + Months?: (props: MonthsProps) => ReactElement | null; /** The component for the table rows. */ - Row?: (props: RowProps) => JSX.Element | null; + Row?: (props: RowProps) => ReactElement | null; /** The component for the week number in the table rows. */ - WeekNumber?: (props: WeekNumberProps) => JSX.Element | null; + WeekNumber?: (props: WeekNumberProps) => ReactElement | null; } diff --git a/src/types/EventHandlers.ts b/src/types/EventHandlers.ts index a5a1c764b6..53f3b92d2d 100644 --- a/src/types/EventHandlers.ts +++ b/src/types/EventHandlers.ts @@ -1,4 +1,4 @@ -import { +import type { FocusEvent, KeyboardEvent, MouseEvent, diff --git a/src/types/Formatters.ts b/src/types/Formatters.ts index e68cda1bf3..5fe59733b3 100644 --- a/src/types/Formatters.ts +++ b/src/types/Formatters.ts @@ -1,4 +1,4 @@ -import { ReactNode } from 'react'; +import type { ReactNode } from 'react'; import { Locale } from 'date-fns'; diff --git a/src/types/Modifiers.ts b/src/types/Modifiers.ts index 201df9a4cb..288f5e0da5 100644 --- a/src/types/Modifiers.ts +++ b/src/types/Modifiers.ts @@ -1,4 +1,4 @@ -import { CSSProperties } from 'react'; +import type { CSSProperties } from 'react'; import { Matcher } from './Matchers'; diff --git a/src/types/Styles.ts b/src/types/Styles.ts index a7d432b223..4e6e28a87e 100644 --- a/src/types/Styles.ts +++ b/src/types/Styles.ts @@ -1,4 +1,4 @@ -import { CSSProperties, ReactNode } from 'react'; +import type { CSSProperties, ReactNode } from 'react'; /** The style (either via class names or via in-line styles) of an element. */ export type StyledElement = { diff --git a/test/render/customRender.tsx b/test/render/customRender.tsx index e1f0d1d367..aca793bf1c 100644 --- a/test/render/customRender.tsx +++ b/test/render/customRender.tsx @@ -1,4 +1,4 @@ -import { ReactElement } from 'react'; +import type { ReactElement } from 'react'; import { render } from '@testing-library/react'; import { DayPickerProps } from 'DayPicker'; diff --git a/test/render/renderDayPickerHook.tsx b/test/render/renderDayPickerHook.tsx index 165859f27e..89fe5b852a 100644 --- a/test/render/renderDayPickerHook.tsx +++ b/test/render/renderDayPickerHook.tsx @@ -1,3 +1,5 @@ +import type { ReactElement } from 'react'; + import { render } from '@testing-library/react'; import { DayPickerProps } from 'DayPicker'; @@ -32,7 +34,7 @@ export function renderDayPickerHook( } ): RenderHookResult { const returnVal = { current: undefined as TResult }; - function Test(): JSX.Element { + function Test(): ReactElement { const hookResult: TResult = hook(); returnVal.current = hookResult; return <>;