From 5339b2571e6d73ca6efe2acd34d88669419db9f7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D5=A1=D3=84=D5=A1?= Date: Thu, 14 Nov 2024 03:30:17 +0800 Subject: [PATCH] fix: support inert value with boolean type for react 19 (#4039) --- .changeset/moody-rabbits-shop.md | 7 +++++ .../calendar/src/calendar-month.tsx | 5 ++-- .../calendar/src/calendar-picker.tsx | 4 +-- packages/components/tabs/src/tab-panel.tsx | 5 ++-- .../utilities/shared-utils/src/functions.ts | 29 +++++++++++++++++++ 5 files changed, 42 insertions(+), 8 deletions(-) create mode 100644 .changeset/moody-rabbits-shop.md diff --git a/.changeset/moody-rabbits-shop.md b/.changeset/moody-rabbits-shop.md new file mode 100644 index 0000000000..8fec710f2e --- /dev/null +++ b/.changeset/moody-rabbits-shop.md @@ -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) diff --git a/packages/components/calendar/src/calendar-month.tsx b/packages/components/calendar/src/calendar-month.tsx index e17fca20d9..8972f10bd6 100644 --- a/packages/components/calendar/src/calendar-month.tsx +++ b/packages/components/calendar/src/calendar-month.tsx @@ -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"; @@ -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) diff --git a/packages/components/calendar/src/calendar-picker.tsx b/packages/components/calendar/src/calendar-picker.tsx index 76e4cf07e5..c75194aa2a 100644 --- a/packages/components/calendar/src/calendar-picker.tsx +++ b/packages/components/calendar/src/calendar-picker.tsx @@ -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"; @@ -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)} >
((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" diff --git a/packages/utilities/shared-utils/src/functions.ts b/packages/utilities/shared-utils/src/functions.ts index 2eece226c6..bdbcec3db4 100644 --- a/packages/utilities/shared-utils/src/functions.ts +++ b/packages/utilities/shared-utils/src/functions.ts @@ -1,3 +1,5 @@ +import React from "react"; + type Args = T extends (...args: infer R) => any ? R : never; type AnyFunction = (...args: T[]) => any; @@ -389,3 +391,30 @@ export const intersectionBy = (...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; +};