Skip to content

Commit 88a2ede

Browse files
committed
fix: support React 19 in v8
1 parent 9a25636 commit 88a2ede

51 files changed

Lines changed: 385 additions & 123 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.github/workflows/package.yml

Lines changed: 2 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,17 @@
11
name: react-day-picker
22

33
on:
4-
release:
5-
types: [published]
64
pull_request:
75
branches:
86
- main
7+
- maintenance/v8
98
push:
109
branches:
1110
- main
11+
- maintenance/v8
1212
workflow_dispatch:
13-
inputs:
14-
publish:
15-
description: Publish on npm
16-
required: false
17-
default: false
18-
type: boolean
1913

2014
jobs:
21-
# print-env:
22-
# runs-on: ubuntu-latest
23-
# steps:
24-
# - run: |
25-
# echo "publish=${{ github.event.inputs.publish || false }}"
26-
2715
typecheck:
2816
runs-on: ubuntu-latest
2917
steps:
@@ -84,28 +72,3 @@ jobs:
8472
with:
8573
name: rdp-dist
8674
path: dist
87-
88-
publish-on-npm:
89-
runs-on: ubuntu-latest
90-
needs: [build, test]
91-
if: ${{ github.event_name == 'release' || github.event.inputs.publish }}
92-
permissions:
93-
id-token: write
94-
steps:
95-
- uses: actions/checkout@v4
96-
- uses: pnpm/action-setup@v3
97-
with:
98-
version: 8.6.2
99-
- uses: actions/setup-node@v4
100-
with:
101-
node-version: 18.16
102-
registry-url: https://registry.npmjs.org/
103-
always-auth: false
104-
- uses: actions/download-artifact@v4
105-
with:
106-
name: rdp-dist
107-
path: dist
108-
- run: echo "//<npm-registry>:8080/:_authToken=$NODE_AUTH_TOKEN" > ~/.npmrc
109-
- run: npm publish --provenance
110-
env:
111-
NODE_AUTH_TOKEN: ${{ secrets.npm_token }}

.github/workflows/release.yml

Lines changed: 251 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,251 @@
1+
name: react-day-picker v8 release
2+
3+
on:
4+
release:
5+
types: [published]
6+
7+
permissions:
8+
contents: read
9+
id-token: write
10+
11+
jobs:
12+
validate:
13+
runs-on: ubuntu-latest
14+
steps:
15+
- uses: actions/checkout@v4
16+
- uses: pnpm/action-setup@v3
17+
with:
18+
version: 8.6.2
19+
- uses: actions/setup-node@v4
20+
with:
21+
node-version: 24
22+
cache: pnpm
23+
- run: pnpm install --frozen-lockfile
24+
- run: pnpm typecheck
25+
- run: pnpm test
26+
- run: pnpm build
27+
- name: Verify npm trusted publishing support
28+
run: |
29+
npm_version="$(npm --version)"
30+
node -e '
31+
const [major, minor, patch] = process.argv[1].split(".").map(Number);
32+
if (major < 11 || (major === 11 && (minor < 5 || (minor === 5 && patch < 1)))) {
33+
throw new Error(`npm ${process.argv[1]} does not satisfy >=11.5.1`);
34+
}
35+
' "$npm_version"
36+
- name: Smoke test React 19 consumer installs
37+
run: |
38+
set -euo pipefail
39+
40+
tarball="$RUNNER_TEMP/$(npm pack --pack-destination "$RUNNER_TEMP" --silent)"
41+
42+
smoke_react19() {
43+
local date_fns_major="$1"
44+
local smoke_dir
45+
smoke_dir="$(mktemp -d)"
46+
47+
cp "$tarball" "$smoke_dir/react-day-picker.tgz"
48+
cd "$smoke_dir"
49+
50+
npm init -y
51+
npm install --ignore-scripts ./react-day-picker.tgz react@19 react-dom@19 "date-fns@${date_fns_major}" jsdom@^24.1.3
52+
53+
cat > smoke.mjs <<'EOF'
54+
import { createRequire } from "node:module";
55+
56+
const require = createRequire(import.meta.url);
57+
const { JSDOM } = require("jsdom");
58+
59+
const dom = new JSDOM('<div id="root"></div>');
60+
globalThis.window = dom.window;
61+
globalThis.document = dom.window.document;
62+
globalThis.HTMLElement = dom.window.HTMLElement;
63+
globalThis.Node = dom.window.Node;
64+
Object.defineProperty(globalThis, "navigator", {
65+
value: dom.window.navigator,
66+
configurable: true
67+
});
68+
69+
const React = require("react");
70+
const { flushSync } = require("react-dom");
71+
const { createRoot } = require("react-dom/client");
72+
const { DayPicker } = require("react-day-picker");
73+
74+
const container = document.getElementById("root");
75+
const root = createRoot(container);
76+
77+
flushSync(() => {
78+
root.render(React.createElement(DayPicker, { month: new Date(2024, 0, 1) }));
79+
});
80+
81+
if (!container.querySelector(".rdp")) {
82+
throw new Error("DayPicker did not render its root element.");
83+
}
84+
85+
root.unmount();
86+
EOF
87+
88+
node smoke.mjs
89+
}
90+
91+
smoke_react19 3
92+
smoke_react19 2
93+
- name: Smoke test React 19 TypeScript declarations
94+
run: |
95+
set -euo pipefail
96+
97+
tarball="$RUNNER_TEMP/$(npm pack --pack-destination "$RUNNER_TEMP" --silent)"
98+
smoke_dir="$(mktemp -d)"
99+
100+
cp "$tarball" "$smoke_dir/react-day-picker.tgz"
101+
cd "$smoke_dir"
102+
103+
npm init -y
104+
npm install --ignore-scripts ./react-day-picker.tgz react@19 react-dom@19 date-fns@3 typescript@^5 @types/react@19 @types/react-dom@19
105+
106+
cat > tsconfig.json <<'EOF'
107+
{
108+
"compilerOptions": {
109+
"strict": true,
110+
"jsx": "react-jsx",
111+
"module": "NodeNext",
112+
"moduleResolution": "NodeNext",
113+
"target": "ES2022",
114+
"skipLibCheck": false,
115+
"noEmit": true
116+
},
117+
"include": ["src"]
118+
}
119+
EOF
120+
121+
mkdir src
122+
cat > src/index.tsx <<'EOF'
123+
import { createRef, useState } from "react";
124+
import { DayPicker, type ButtonProps, type DateRange } from "react-day-picker";
125+
import "react-day-picker/dist/style.css";
126+
127+
const buttonRef = createRef<HTMLButtonElement>();
128+
const buttonProps: ButtonProps = { ref: buttonRef, type: "button" };
129+
void buttonProps;
130+
131+
export function SinglePicker() {
132+
const [selected, setSelected] = useState<Date>();
133+
return <DayPicker mode="single" selected={selected} onSelect={setSelected} />;
134+
}
135+
136+
export function RangePicker() {
137+
const [selected, setSelected] = useState<DateRange>();
138+
return <DayPicker mode="range" selected={selected} onSelect={setSelected} />;
139+
}
140+
EOF
141+
142+
npx tsc --noEmit
143+
- name: Smoke test React 18 TypeScript declarations
144+
run: |
145+
set -euo pipefail
146+
147+
tarball="$RUNNER_TEMP/$(npm pack --pack-destination "$RUNNER_TEMP" --silent)"
148+
149+
smoke_react18_types() {
150+
local date_fns_major="$1"
151+
local smoke_dir
152+
smoke_dir="$(mktemp -d)"
153+
154+
cp "$tarball" "$smoke_dir/react-day-picker.tgz"
155+
cd "$smoke_dir"
156+
157+
npm init -y
158+
npm install --ignore-scripts ./react-day-picker.tgz react@18 react-dom@18 "date-fns@${date_fns_major}" typescript@^5 @types/react@18 @types/react-dom@18
159+
160+
cat > tsconfig.json <<'EOF'
161+
{
162+
"compilerOptions": {
163+
"strict": true,
164+
"jsx": "react-jsx",
165+
"module": "NodeNext",
166+
"moduleResolution": "NodeNext",
167+
"target": "ES2022",
168+
"skipLibCheck": false,
169+
"noEmit": true
170+
},
171+
"include": ["src"]
172+
}
173+
EOF
174+
175+
mkdir src
176+
cat > src/index.tsx <<'EOF'
177+
import { createRef, useState } from "react";
178+
import { DayPicker, type ButtonProps, type DateRange } from "react-day-picker";
179+
import "react-day-picker/dist/style.css";
180+
181+
const buttonRef = createRef<HTMLButtonElement>();
182+
const buttonProps: ButtonProps = { ref: buttonRef, type: "button" };
183+
void buttonProps;
184+
185+
export function SinglePicker() {
186+
const [selected, setSelected] = useState<Date>();
187+
return <DayPicker mode="single" selected={selected} onSelect={setSelected} />;
188+
}
189+
190+
export function MultiplePicker() {
191+
const [selected, setSelected] = useState<Date[]>();
192+
return <DayPicker mode="multiple" selected={selected} onSelect={setSelected} />;
193+
}
194+
195+
export function RangePicker() {
196+
const [selected, setSelected] = useState<DateRange>();
197+
return <DayPicker mode="range" selected={selected} onSelect={setSelected} />;
198+
}
199+
200+
export function CustomDayContentPicker() {
201+
return (
202+
<DayPicker
203+
components={{
204+
DayContent(props) {
205+
return <span>{props.date.getDate()}</span>;
206+
}
207+
}}
208+
/>
209+
);
210+
}
211+
EOF
212+
213+
npx tsc --noEmit
214+
}
215+
216+
smoke_react18_types 2
217+
smoke_react18_types 3
218+
219+
publish:
220+
needs: validate
221+
runs-on: ubuntu-latest
222+
steps:
223+
- uses: actions/checkout@v4
224+
- uses: pnpm/action-setup@v3
225+
with:
226+
version: 8.6.2
227+
- uses: actions/setup-node@v4
228+
with:
229+
node-version: 24
230+
registry-url: https://registry.npmjs.org/
231+
- name: Verify release tag matches package version
232+
env:
233+
RELEASE_TAG: ${{ github.event.release.tag_name }}
234+
run: |
235+
expected_tag="v$(node -p "require('./package.json').version")"
236+
if [ "$RELEASE_TAG" != "$expected_tag" ]; then
237+
echo "Release tag $RELEASE_TAG does not match package version $expected_tag." >&2
238+
exit 1
239+
fi
240+
- run: pnpm install --frozen-lockfile
241+
- run: pnpm build
242+
- name: Verify npm trusted publishing support
243+
run: |
244+
npm_version="$(npm --version)"
245+
node -e '
246+
const [major, minor, patch] = process.argv[1].split(".").map(Number);
247+
if (major < 11 || (major === 11 && (minor < 5 || (minor === 5 && patch < 1)))) {
248+
throw new Error(`npm ${process.argv[1]} does not satisfy >=11.5.1`);
249+
}
250+
' "$npm_version"
251+
- run: npm publish --tag legacy-v8

CHANGELOG.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,9 @@
11
# Changelog
22

3+
## v8.10.2
4+
5+
_Release date: 2026-05-02_
6+
7+
- Expand React peer dependency support to include React 19. This release has no runtime or API changes.
8+
39
Full release notes at https://github.com/gpbl/react-day-picker/releases

README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,8 @@ pnpm install react-day-picker date-fns # using pnpm
3030
yarn add react-day-picker date-fns # using yarn
3131
```
3232

33+
DayPicker v8 supports React 16.8, 17, 18, and 19, with date-fns 2 or 3.
34+
3335
<a href="https://www.npmjs.com/package/react-day-picker"><img src="https://img.shields.io/npm/v/react-day-picker.svg?style=flat-square" alt="npm version"/></a> <img src="https://img.shields.io/npm/dm/react-day-picker.svg?style=flat-square" alt="npm downloads"/> <img src="https://img.shields.io/bundlephobia/minzip/react-day-picker" alt="Min gzipped size"/>
3436

3537
## Example

package.json

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
11
{
22
"name": "react-day-picker",
3-
"version": "8.10.1",
3+
"version": "8.10.2",
44
"description": "Customizable Date Picker for React",
55
"author": "Giampaolo Bellavite <io@gpbl.dev>",
66
"homepage": "http://react-day-picker.js.org",
77
"license": "MIT",
88
"repository": {
99
"type": "git",
10-
"url": "https://github.com/gpbl/react-day-picker"
10+
"url": "git+https://github.com/gpbl/react-day-picker.git"
1111
},
1212
"bugs": {
1313
"url": "https://github.com/gpbl/react-day-picker/issues"
@@ -81,7 +81,7 @@
8181
},
8282
"peerDependencies": {
8383
"date-fns": "^2.28.0 || ^3.0.0",
84-
"react": "^16.8.0 || ^17.0.0 || ^18.0.0"
84+
"react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0"
8585
},
8686
"funding": {
8787
"type": "individual",

src/DayPicker.tsx

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
import type { ReactElement } from 'react';
2+
13
import { DayPickerDefaultProps } from 'types/DayPickerDefault';
24
import { DayPickerMultipleProps } from 'types/DayPickerMultiple';
35
import { DayPickerRangeProps } from 'types/DayPickerRange';
@@ -105,7 +107,7 @@ export function DayPicker(
105107
| DayPickerSingleProps
106108
| DayPickerMultipleProps
107109
| DayPickerRangeProps
108-
): JSX.Element {
110+
): ReactElement {
109111
return (
110112
<RootProvider {...props}>
111113
<Root initialProps={props} />

src/components/Button/Button.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
11
import { forwardRef } from 'react';
2+
import type { ComponentPropsWithRef } from 'react';
23

34
import { useDayPicker } from 'contexts/DayPicker';
45

56
/** The props for the {@link Button} component. */
6-
export type ButtonProps = JSX.IntrinsicElements['button'];
7+
export type ButtonProps = ComponentPropsWithRef<'button'>;
78

89
/** Render a button HTML element applying the reset class name. */
910
export const Button = forwardRef<HTMLButtonElement, ButtonProps>(

0 commit comments

Comments
 (0)