diff --git a/.changeset/smart-eagles-hope.md b/.changeset/smart-eagles-hope.md new file mode 100644 index 0000000000..c52f634ba0 --- /dev/null +++ b/.changeset/smart-eagles-hope.md @@ -0,0 +1,5 @@ +--- +"@heroui/shared-utils": patch +--- + +Tabs with prop destroyInactiveTabPanel error in nextjs15(#4344) diff --git a/packages/utilities/shared-utils/README.md b/packages/utilities/shared-utils/README.md index e884386580..a7864320b6 100644 --- a/packages/utilities/shared-utils/README.md +++ b/packages/utilities/shared-utils/README.md @@ -1,4 +1,4 @@ -# @heroui/system +# @heroui/shared-utils A Quick description of the component @@ -7,9 +7,9 @@ A Quick description of the component ## Installation ```sh -yarn add @heroui/system +yarn add @heroui/shared-utils # or -npm i @heroui/system +npm i @heroui/shared-utils ``` ## Contribution @@ -18,6 +18,16 @@ Yes please! See the [contributing guidelines](https://github.com/heroui-inc/heroui/blob/master/CONTRIBUTING.md) for details. +## File structure + +``` +src/ +├── common/ # Common utilities for all React versions +└── demi/ # Demi utilities for different React versions + ├── react18/ + └── react19/ +``` + ## License This project is licensed under the terms of the diff --git a/packages/utilities/shared-utils/package.json b/packages/utilities/shared-utils/package.json index 173832eee8..c4cf629d1f 100644 --- a/packages/utilities/shared-utils/package.json +++ b/packages/utilities/shared-utils/package.json @@ -11,7 +11,8 @@ "main": "src/index.ts", "sideEffects": false, "files": [ - "dist" + "dist", + "scripts" ], "publishConfig": { "access": "public" @@ -25,13 +26,15 @@ "url": "https://github.com/heroui-inc/heroui/issues" }, "scripts": { + "postinstall": "node -e \"try{require('./scripts/postinstall.js')}catch(e){}\"", "build": "tsup src --dts", "dev": "pnpm build:fast --watch", "clean": "rimraf dist .turbo", "typecheck": "tsc --noEmit", "build:fast": "tsup src", "prepack": "clean-package", - "postpack": "clean-package restore" + "postpack": "clean-package restore", + "postbuild": "npm run postinstall" }, "devDependencies": { "clean-package": "2.2.0" @@ -43,6 +46,8 @@ "format": [ "cjs", "esm" - ] + ], + "splitting": false, + "entry": ["src/demi/react18", "src/demi/react19"] } -} \ No newline at end of file +} diff --git a/packages/utilities/shared-utils/scripts/postinstall.js b/packages/utilities/shared-utils/scripts/postinstall.js new file mode 100644 index 0000000000..d1e19df28d --- /dev/null +++ b/packages/utilities/shared-utils/scripts/postinstall.js @@ -0,0 +1,41 @@ +const path = require('path') +const fs = require('fs') + +function tryRequirePkg(pkg) { + try { + return require(pkg); + } catch (e) { + return null; + } +} + +function copyDemiDir(dir) { + const src = path.join(__dirname, '..', 'dist', 'demi', dir) + const dest = path.join(__dirname, '..', 'dist') + + fs.cpSync(src, dest, { recursive: true }) +} + +function modifyDts(path) { + const dts = fs.readFileSync(path, 'utf8') + const modifiedDts = dts.replace(/\.\.\/\.\.\/common/g, './common') + + fs.writeFileSync(path, modifiedDts, 'utf8') +} + +function postinstall() { + const nextjs = tryRequirePkg('next/package.json') + const react = tryRequirePkg('react/package.json') + const nextjsVersion = Number((nextjs?.version || '').split('.')[0]) + const reactVersion = Number((react?.version || '').split('.')[0]) + + if (reactVersion === 18 && nextjsVersion < 15) { + copyDemiDir('react18') + } else { + copyDemiDir('react19') + } + + modifyDts(path.join(__dirname, '..', 'dist', 'index.d.ts')) +} + +postinstall(); diff --git a/packages/utilities/shared-utils/src/assertion.ts b/packages/utilities/shared-utils/src/common/assertion.ts similarity index 100% rename from packages/utilities/shared-utils/src/assertion.ts rename to packages/utilities/shared-utils/src/common/assertion.ts diff --git a/packages/utilities/shared-utils/src/clsx.ts b/packages/utilities/shared-utils/src/common/clsx.ts similarity index 100% rename from packages/utilities/shared-utils/src/clsx.ts rename to packages/utilities/shared-utils/src/common/clsx.ts diff --git a/packages/utilities/shared-utils/src/console.ts b/packages/utilities/shared-utils/src/common/console.ts similarity index 100% rename from packages/utilities/shared-utils/src/console.ts rename to packages/utilities/shared-utils/src/common/console.ts diff --git a/packages/utilities/shared-utils/src/dates.ts b/packages/utilities/shared-utils/src/common/dates.ts similarity index 100% rename from packages/utilities/shared-utils/src/dates.ts rename to packages/utilities/shared-utils/src/common/dates.ts diff --git a/packages/utilities/shared-utils/src/dimensions.ts b/packages/utilities/shared-utils/src/common/dimensions.ts similarity index 100% rename from packages/utilities/shared-utils/src/dimensions.ts rename to packages/utilities/shared-utils/src/common/dimensions.ts diff --git a/packages/utilities/shared-utils/src/functions.ts b/packages/utilities/shared-utils/src/common/functions.ts similarity index 90% rename from packages/utilities/shared-utils/src/functions.ts rename to packages/utilities/shared-utils/src/common/functions.ts index bdbcec3db4..2eece226c6 100644 --- a/packages/utilities/shared-utils/src/functions.ts +++ b/packages/utilities/shared-utils/src/common/functions.ts @@ -1,5 +1,3 @@ -import React from "react"; - type Args = T extends (...args: infer R) => any ? R : never; type AnyFunction = (...args: T[]) => any; @@ -391,30 +389,3 @@ 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; -}; diff --git a/packages/utilities/shared-utils/src/common/index.ts b/packages/utilities/shared-utils/src/common/index.ts new file mode 100644 index 0000000000..eec14e1c31 --- /dev/null +++ b/packages/utilities/shared-utils/src/common/index.ts @@ -0,0 +1,11 @@ +export * from "./assertion"; +export * from "./clsx"; +export * from "./object"; +export * from "./text"; +export * from "./dimensions"; +export * from "./functions"; +export * from "./numbers"; +export * from "./console"; +export * from "./types"; +export * from "./dates"; +export * from "./regex"; diff --git a/packages/utilities/shared-utils/src/numbers.ts b/packages/utilities/shared-utils/src/common/numbers.ts similarity index 100% rename from packages/utilities/shared-utils/src/numbers.ts rename to packages/utilities/shared-utils/src/common/numbers.ts diff --git a/packages/utilities/shared-utils/src/object.ts b/packages/utilities/shared-utils/src/common/object.ts similarity index 100% rename from packages/utilities/shared-utils/src/object.ts rename to packages/utilities/shared-utils/src/common/object.ts diff --git a/packages/utilities/shared-utils/src/regex.ts b/packages/utilities/shared-utils/src/common/regex.ts similarity index 100% rename from packages/utilities/shared-utils/src/regex.ts rename to packages/utilities/shared-utils/src/common/regex.ts diff --git a/packages/utilities/shared-utils/src/text.ts b/packages/utilities/shared-utils/src/common/text.ts similarity index 100% rename from packages/utilities/shared-utils/src/text.ts rename to packages/utilities/shared-utils/src/common/text.ts diff --git a/packages/utilities/shared-utils/src/types.ts b/packages/utilities/shared-utils/src/common/types.ts similarity index 100% rename from packages/utilities/shared-utils/src/types.ts rename to packages/utilities/shared-utils/src/common/types.ts diff --git a/packages/utilities/shared-utils/src/demi/react18/getInertValue.ts b/packages/utilities/shared-utils/src/demi/react18/getInertValue.ts new file mode 100644 index 0000000000..6350003e57 --- /dev/null +++ b/packages/utilities/shared-utils/src/demi/react18/getInertValue.ts @@ -0,0 +1,17 @@ +/** + * 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 v ? "" : undefined; +}; diff --git a/packages/utilities/shared-utils/src/demi/react18/index.ts b/packages/utilities/shared-utils/src/demi/react18/index.ts new file mode 100644 index 0000000000..a7b20e28e0 --- /dev/null +++ b/packages/utilities/shared-utils/src/demi/react18/index.ts @@ -0,0 +1,3 @@ +export * from "./getInertValue"; + +export * from "../../common"; diff --git a/packages/utilities/shared-utils/src/demi/react19/getInertValue.ts b/packages/utilities/shared-utils/src/demi/react19/getInertValue.ts new file mode 100644 index 0000000000..80703a4a89 --- /dev/null +++ b/packages/utilities/shared-utils/src/demi/react19/getInertValue.ts @@ -0,0 +1,17 @@ +/** + * 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 v; +}; diff --git a/packages/utilities/shared-utils/src/demi/react19/index.ts b/packages/utilities/shared-utils/src/demi/react19/index.ts new file mode 100644 index 0000000000..a7b20e28e0 --- /dev/null +++ b/packages/utilities/shared-utils/src/demi/react19/index.ts @@ -0,0 +1,3 @@ +export * from "./getInertValue"; + +export * from "../../common"; diff --git a/packages/utilities/shared-utils/src/index.ts b/packages/utilities/shared-utils/src/index.ts index eec14e1c31..c2647d2579 100644 --- a/packages/utilities/shared-utils/src/index.ts +++ b/packages/utilities/shared-utils/src/index.ts @@ -1,11 +1,5 @@ -export * from "./assertion"; -export * from "./clsx"; -export * from "./object"; -export * from "./text"; -export * from "./dimensions"; -export * from "./functions"; -export * from "./numbers"; -export * from "./console"; -export * from "./types"; -export * from "./dates"; -export * from "./regex"; +/** + * For Development + */ +export * from "./common"; +export * from "./demi/react18";