Skip to content

Commit 5339b25

Browse files
authored
fix: support inert value with boolean type for react 19 (#4039)
1 parent a0af4c9 commit 5339b25

File tree

5 files changed

+42
-8
lines changed

5 files changed

+42
-8
lines changed

.changeset/moody-rabbits-shop.md

+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
---
2+
"@nextui-org/calendar": patch
3+
"@nextui-org/tabs": patch
4+
"@nextui-org/shared-utils": patch
5+
---
6+
7+
support inert value with boolean type for react 19 (#4038)

packages/components/calendar/src/calendar-month.tsx

+2-3
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import {HTMLNextUIProps} from "@nextui-org/system";
44
import {useLocale} from "@react-aria/i18n";
55
import {useCalendarGrid} from "@react-aria/calendar";
66
import {m} from "framer-motion";
7-
import {dataAttr} from "@nextui-org/shared-utils";
7+
import {dataAttr, getInertValue} from "@nextui-org/shared-utils";
88

99
import {CalendarCell} from "./calendar-cell";
1010
import {slideVariants} from "./calendar-transitions";
@@ -40,9 +40,8 @@ export function CalendarMonth(props: CalendarMonthProps) {
4040
className={slots?.gridBodyRow({class: classNames?.gridBodyRow})}
4141
data-slot="grid-body-row"
4242
// makes the browser ignore the element and its children when tabbing
43-
// TODO: invert inert when switching to React 19 (ref: https://github.com/facebook/react/issues/17157)
4443
// @ts-ignore
45-
inert={isHeaderExpanded ? "" : undefined}
44+
inert={getInertValue(!!isHeaderExpanded)}
4645
>
4746
{state
4847
.getDatesInWeek(weekIndex, startDate)

packages/components/calendar/src/calendar-picker.tsx

+2-2
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import type {CalendarPickerProps} from "./use-calendar-picker";
22

33
import {HTMLNextUIProps} from "@nextui-org/system";
44
import {useCallback} from "react";
5+
import {getInertValue} from "@nextui-org/shared-utils";
56

67
import {CalendarPickerItem} from "./calendar-picker-item";
78
import {useCalendarPicker} from "./use-calendar-picker";
@@ -66,9 +67,8 @@ export function CalendarPicker(props: CalendarPickerProps) {
6667
})}
6768
data-slot="picker-wrapper"
6869
// makes the browser ignore the element and its children when tabbing
69-
// TODO: invert inert when switching to React 19 (ref: https://github.com/facebook/react/issues/17157)
7070
// @ts-ignore
71-
inert={isHeaderExpanded ? undefined : ""}
71+
inert={getInertValue(!isHeaderExpanded)}
7272
>
7373
<div
7474
ref={highlightRef}

packages/components/tabs/src/tab-panel.tsx

+2-3
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import type {AriaTabPanelProps} from "@react-aria/tabs";
33
import {Key} from "@react-types/shared";
44
import {forwardRef, HTMLNextUIProps} from "@nextui-org/system";
55
import {useDOMRef} from "@nextui-org/react-utils";
6-
import {clsx} from "@nextui-org/shared-utils";
6+
import {clsx, getInertValue} from "@nextui-org/shared-utils";
77
import {mergeProps} from "@react-aria/utils";
88
import {useTabPanel} from "@react-aria/tabs";
99
import {useFocusRing} from "@react-aria/focus";
@@ -70,9 +70,8 @@ const TabPanel = forwardRef<"div", TabPanelProps>((props, ref) => {
7070
data-focus-visible={isFocusVisible}
7171
data-inert={!isSelected ? "true" : undefined}
7272
// makes the browser ignore the element and its children when tabbing
73-
// TODO: invert inert when switching to React 19 (ref: https://github.com/facebook/react/issues/17157)
7473
// @ts-ignore
75-
inert={!isSelected ? "" : undefined}
74+
inert={getInertValue(!isSelected)}
7675
{...(isSelected && mergeProps(tabPanelProps, focusProps, otherProps))}
7776
className={slots.panel?.({class: tabPanelStyles})}
7877
data-slot="panel"

packages/utilities/shared-utils/src/functions.ts

+29
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
import React from "react";
2+
13
type Args<T extends Function> = T extends (...args: infer R) => any ? R : never;
24

35
type AnyFunction<T = any> = (...args: T[]) => any;
@@ -389,3 +391,30 @@ export const intersectionBy = <T>(...args: [...arrays: T[][], iteratee: Iteratee
389391

390392
return res;
391393
};
394+
395+
/**
396+
* Checks if the current React version is 19.x.x
397+
*
398+
* @returns {boolean} - Returns `true` if the React major version is 19, otherwise returns `false`.
399+
*/
400+
export const isReact19 = (): boolean => {
401+
return React.version.split(".")[0] === "19";
402+
};
403+
404+
/**
405+
* Returns an appropriate value for the `inert` attribute based on the React version.
406+
*
407+
* In React 19, the attribute `inert` is a boolean. In versions prior to 19, the attribute
408+
* behaves differently: setting `inert=""` will make it `true`, and `inert=undefined` will make it `false`.
409+
*
410+
* @param {boolean} v - The desired boolean state for the `inert` attribute.
411+
* @returns {boolean | string | undefined} - Depending on the React version:
412+
* - Returns `boolean` if React version is 19 (the input value `v` directly).
413+
* - Returns `string` (empty string) if `v` is `true` in older React versions.
414+
* - Returns `undefined` if `v` is `false` in older React versions.
415+
*
416+
* @see {@link https://github.com/facebook/react/issues/17157} for more details on the behavior in older React versions.
417+
*/
418+
export const getInertValue = (v: boolean): boolean | string | undefined => {
419+
return isReact19() ? v : v ? "" : undefined;
420+
};

0 commit comments

Comments
 (0)