Skip to content

Commit

Permalink
fix: support inert value with boolean type for react 19 (#4039)
Browse files Browse the repository at this point in the history
  • Loading branch information
wingkwong authored Nov 13, 2024
1 parent a0af4c9 commit 5339b25
Show file tree
Hide file tree
Showing 5 changed files with 42 additions and 8 deletions.
7 changes: 7 additions & 0 deletions .changeset/moody-rabbits-shop.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
"@nextui-org/calendar": patch
"@nextui-org/tabs": patch
"@nextui-org/shared-utils": patch
---

support inert value with boolean type for react 19 (#4038)
5 changes: 2 additions & 3 deletions packages/components/calendar/src/calendar-month.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import {HTMLNextUIProps} from "@nextui-org/system";
import {useLocale} from "@react-aria/i18n";
import {useCalendarGrid} from "@react-aria/calendar";
import {m} from "framer-motion";
import {dataAttr} from "@nextui-org/shared-utils";
import {dataAttr, getInertValue} from "@nextui-org/shared-utils";

import {CalendarCell} from "./calendar-cell";
import {slideVariants} from "./calendar-transitions";
Expand Down Expand Up @@ -40,9 +40,8 @@ export function CalendarMonth(props: CalendarMonthProps) {
className={slots?.gridBodyRow({class: classNames?.gridBodyRow})}
data-slot="grid-body-row"
// makes the browser ignore the element and its children when tabbing
// TODO: invert inert when switching to React 19 (ref: https://github.com/facebook/react/issues/17157)
// @ts-ignore
inert={isHeaderExpanded ? "" : undefined}
inert={getInertValue(!!isHeaderExpanded)}
>
{state
.getDatesInWeek(weekIndex, startDate)
Expand Down
4 changes: 2 additions & 2 deletions packages/components/calendar/src/calendar-picker.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import type {CalendarPickerProps} from "./use-calendar-picker";

import {HTMLNextUIProps} from "@nextui-org/system";
import {useCallback} from "react";
import {getInertValue} from "@nextui-org/shared-utils";

import {CalendarPickerItem} from "./calendar-picker-item";
import {useCalendarPicker} from "./use-calendar-picker";
Expand Down Expand Up @@ -66,9 +67,8 @@ export function CalendarPicker(props: CalendarPickerProps) {
})}
data-slot="picker-wrapper"
// makes the browser ignore the element and its children when tabbing
// TODO: invert inert when switching to React 19 (ref: https://github.com/facebook/react/issues/17157)
// @ts-ignore
inert={isHeaderExpanded ? undefined : ""}
inert={getInertValue(!isHeaderExpanded)}
>
<div
ref={highlightRef}
Expand Down
5 changes: 2 additions & 3 deletions packages/components/tabs/src/tab-panel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import type {AriaTabPanelProps} from "@react-aria/tabs";
import {Key} from "@react-types/shared";
import {forwardRef, HTMLNextUIProps} from "@nextui-org/system";
import {useDOMRef} from "@nextui-org/react-utils";
import {clsx} from "@nextui-org/shared-utils";
import {clsx, getInertValue} from "@nextui-org/shared-utils";
import {mergeProps} from "@react-aria/utils";
import {useTabPanel} from "@react-aria/tabs";
import {useFocusRing} from "@react-aria/focus";
Expand Down Expand Up @@ -70,9 +70,8 @@ const TabPanel = forwardRef<"div", TabPanelProps>((props, ref) => {
data-focus-visible={isFocusVisible}
data-inert={!isSelected ? "true" : undefined}
// makes the browser ignore the element and its children when tabbing
// TODO: invert inert when switching to React 19 (ref: https://github.com/facebook/react/issues/17157)
// @ts-ignore
inert={!isSelected ? "" : undefined}
inert={getInertValue(!isSelected)}
{...(isSelected && mergeProps(tabPanelProps, focusProps, otherProps))}
className={slots.panel?.({class: tabPanelStyles})}
data-slot="panel"
Expand Down
29 changes: 29 additions & 0 deletions packages/utilities/shared-utils/src/functions.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import React from "react";

type Args<T extends Function> = T extends (...args: infer R) => any ? R : never;

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

return res;
};

/**
* Checks if the current React version is 19.x.x
*
* @returns {boolean} - Returns `true` if the React major version is 19, otherwise returns `false`.
*/
export const isReact19 = (): boolean => {
return React.version.split(".")[0] === "19";
};

/**
* Returns an appropriate value for the `inert` attribute based on the React version.
*
* In React 19, the attribute `inert` is a boolean. In versions prior to 19, the attribute
* behaves differently: setting `inert=""` will make it `true`, and `inert=undefined` will make it `false`.
*
* @param {boolean} v - The desired boolean state for the `inert` attribute.
* @returns {boolean | string | undefined} - Depending on the React version:
* - Returns `boolean` if React version is 19 (the input value `v` directly).
* - Returns `string` (empty string) if `v` is `true` in older React versions.
* - Returns `undefined` if `v` is `false` in older React versions.
*
* @see {@link https://github.com/facebook/react/issues/17157} for more details on the behavior in older React versions.
*/
export const getInertValue = (v: boolean): boolean | string | undefined => {
return isReact19() ? v : v ? "" : undefined;
};

0 comments on commit 5339b25

Please sign in to comment.