mirror of
https://github.com/nextui-org/nextui.git
synced 2025-12-08 19:26:11 +00:00
Cn utility refactor (#2915)
* refactor(core): cn utility adjusted and moved to the theme package * chore(root): changeset * fix(storybook): stories that used cn
This commit is contained in:
parent
f8b917a208
commit
e3afa4789a
7
.changeset/few-oranges-jam.md
Normal file
7
.changeset/few-oranges-jam.md
Normal file
@ -0,0 +1,7 @@
|
||||
---
|
||||
"@nextui-org/system": patch
|
||||
"@nextui-org/system-rsc": patch
|
||||
"@nextui-org/theme": patch
|
||||
---
|
||||
|
||||
The `cn` utility was moved the `theme` package and updated to support NextUI custom classes.
|
||||
@ -12,7 +12,7 @@ import {
|
||||
import {I18nProvider, useLocale} from "@react-aria/i18n";
|
||||
import {Button, ButtonGroup} from "@nextui-org/button";
|
||||
import {Radio, RadioGroup} from "@nextui-org/radio";
|
||||
import {cn} from "@nextui-org/system";
|
||||
import {cn} from "@nextui-org/theme";
|
||||
|
||||
import {Calendar, CalendarProps, DateValue} from "../src";
|
||||
|
||||
|
||||
@ -16,7 +16,7 @@ import {
|
||||
import {I18nProvider, useLocale} from "@react-aria/i18n";
|
||||
import {Button, ButtonGroup} from "@nextui-org/button";
|
||||
import {Radio, RadioGroup} from "@nextui-org/radio";
|
||||
import {cn} from "@nextui-org/system";
|
||||
import {cn} from "@nextui-org/theme";
|
||||
|
||||
import {RangeCalendar, RangeCalendarProps} from "../src";
|
||||
|
||||
|
||||
@ -16,7 +16,7 @@ import {
|
||||
import {I18nProvider, useDateFormatter, useLocale} from "@react-aria/i18n";
|
||||
import {Button, ButtonGroup} from "@nextui-org/button";
|
||||
import {Radio, RadioGroup} from "@nextui-org/radio";
|
||||
import {cn} from "@nextui-org/system";
|
||||
import {cn} from "@nextui-org/theme";
|
||||
|
||||
import {DatePicker, DatePickerProps} from "../src";
|
||||
|
||||
|
||||
@ -18,7 +18,7 @@ import {DateValue} from "@react-types/datepicker";
|
||||
import {I18nProvider, useDateFormatter, useLocale} from "@react-aria/i18n";
|
||||
import {Button, ButtonGroup} from "@nextui-org/button";
|
||||
import {Radio, RadioGroup} from "@nextui-org/radio";
|
||||
import {cn} from "@nextui-org/system";
|
||||
import {cn} from "@nextui-org/theme";
|
||||
|
||||
import {DateRangePicker, DateRangePickerProps} from "../src";
|
||||
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
import React from "react";
|
||||
import {Meta} from "@storybook/react";
|
||||
import {button, pagination} from "@nextui-org/theme";
|
||||
import {cn} from "@nextui-org/system";
|
||||
import {cn} from "@nextui-org/theme";
|
||||
import {ChevronIcon} from "@nextui-org/shared-icons";
|
||||
|
||||
import {Pagination, PaginationItemRenderProps, PaginationItemType, usePagination} from "../src";
|
||||
|
||||
@ -4,7 +4,7 @@ import {Meta} from "@storybook/react";
|
||||
import {slider} from "@nextui-org/theme";
|
||||
import {InfoIcon, VolumeHighBoldIcon, VolumeLowBoldIcon} from "@nextui-org/shared-icons";
|
||||
import {Tooltip} from "@nextui-org/tooltip";
|
||||
import {cn} from "@nextui-org/system";
|
||||
import {cn} from "@nextui-org/theme";
|
||||
|
||||
import {Slider, SliderProps, SliderValue} from "../src";
|
||||
|
||||
|
||||
@ -35,8 +35,7 @@
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": ">=18",
|
||||
"@nextui-org/theme": ">=2.1.0",
|
||||
"tailwind-variants": ">=0.1.13"
|
||||
"@nextui-org/theme": ">=2.1.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"react": "^18.0.0",
|
||||
|
||||
@ -1,7 +1,8 @@
|
||||
import * as React from "react";
|
||||
import {tv} from "@nextui-org/theme";
|
||||
import clsx from "clsx";
|
||||
|
||||
import {cn, mapPropsVariants} from "./utils";
|
||||
import {mapPropsVariants} from "./utils";
|
||||
|
||||
function getSlots(variants) {
|
||||
return variants
|
||||
@ -65,7 +66,7 @@ function getClassNamesWithProps({
|
||||
|
||||
// if no slots, the result is a string
|
||||
if (!hasSlots) {
|
||||
newProps.className = cn(result, props.className);
|
||||
newProps.className = clsx(result, props.className);
|
||||
}
|
||||
// if has slots, the result is an object with keys as slots functions
|
||||
else {
|
||||
@ -78,7 +79,7 @@ function getClassNamesWithProps({
|
||||
});
|
||||
|
||||
Object.entries(props.classNames ?? {}).forEach(([key, value]) => {
|
||||
classNames[key] = cn(classNames[key], value);
|
||||
classNames[key] = clsx(classNames[key], value);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@ -15,7 +15,6 @@ export type {
|
||||
} from "./types";
|
||||
|
||||
export {
|
||||
cn,
|
||||
forwardRef,
|
||||
toIterator,
|
||||
mapPropsVariants,
|
||||
|
||||
@ -1,7 +1,6 @@
|
||||
import type {As, RightJoinProps, PropsOf, InternalForwardRefRenderFunction} from "./types";
|
||||
|
||||
import * as React from "react";
|
||||
import clsx from "clsx";
|
||||
import {forwardRef as baseForwardRef} from "react";
|
||||
|
||||
export function forwardRef<
|
||||
@ -96,11 +95,6 @@ export const mapPropsVariantsWithCommon = <
|
||||
return [props, variants] as const;
|
||||
};
|
||||
|
||||
/**
|
||||
* Classnames utility
|
||||
*/
|
||||
export const cn = clsx;
|
||||
|
||||
/**
|
||||
* Checks if a component is a NextUI component.
|
||||
* @param component - The component to check.
|
||||
|
||||
@ -4,8 +4,9 @@ import React, {useMemo} from "react";
|
||||
import {SlotsToClasses, tv, type VariantProps} from "@nextui-org/theme";
|
||||
import {filterDOMProps, ReactRef, useDOMRef} from "@nextui-org/react-utils";
|
||||
import {objectToDeps} from "@nextui-org/shared-utils";
|
||||
import clsx from "clsx";
|
||||
|
||||
import {cn, forwardRef, mapPropsVariants} from "../src/utils";
|
||||
import {forwardRef, mapPropsVariants} from "../src/utils";
|
||||
|
||||
const card = tv({
|
||||
slots: {
|
||||
@ -171,7 +172,7 @@ export const Card = forwardRef<"div", CardProps>((originalProps, ref) => {
|
||||
|
||||
const styles = useMemo(() => card({...variantProps}), [objectToDeps(variantProps)]);
|
||||
|
||||
const baseStyles = cn(classNames?.base, className);
|
||||
const baseStyles = clsx(classNames?.base, className);
|
||||
|
||||
const domRef = useDOMRef(ref);
|
||||
|
||||
|
||||
@ -18,7 +18,6 @@ export type {
|
||||
} from "@nextui-org/system-rsc";
|
||||
|
||||
export {
|
||||
cn,
|
||||
forwardRef,
|
||||
toIterator,
|
||||
mapPropsVariants,
|
||||
|
||||
@ -55,7 +55,9 @@
|
||||
"lodash.kebabcase": "^4.1.1",
|
||||
"lodash.mapkeys": "^4.6.0",
|
||||
"lodash.omit": "^4.5.0",
|
||||
"tailwind-variants": "^0.1.20"
|
||||
"clsx": "^1.2.1",
|
||||
"tailwind-variants": "^0.1.20",
|
||||
"tailwind-merge": "^1.14.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"tailwindcss": ">=3.4.0"
|
||||
|
||||
17
packages/core/theme/src/utils/cn.ts
Normal file
17
packages/core/theme/src/utils/cn.ts
Normal file
@ -0,0 +1,17 @@
|
||||
import type {ClassValue} from "clsx";
|
||||
|
||||
import clsx from "clsx";
|
||||
import {extendTailwindMerge} from "tailwind-merge";
|
||||
|
||||
import {twMergeConfig} from "./tw-merge-config";
|
||||
|
||||
/**
|
||||
* We need to extend the tailwind merge to include NextUI's custom classes.
|
||||
*
|
||||
* So we can use classes like `text-small` or `text-default-500` and override them.
|
||||
*/
|
||||
const twMerge = extendTailwindMerge(twMergeConfig);
|
||||
|
||||
export function cn(...inputs: ClassValue[]) {
|
||||
return twMerge(clsx(inputs));
|
||||
}
|
||||
@ -1,3 +1,14 @@
|
||||
export * from "./classes";
|
||||
export * from "./types";
|
||||
export * from "./variants";
|
||||
export {
|
||||
baseStyles,
|
||||
ringClasses,
|
||||
focusVisibleClasses,
|
||||
dataFocusVisibleClasses,
|
||||
groupDataFocusVisibleClasses,
|
||||
translateCenterClasses,
|
||||
absoluteFullClasses,
|
||||
collapseAdjacentVariantBorders,
|
||||
} from "./classes";
|
||||
export type {SlotsToClasses} from "./types";
|
||||
export {colorVariants} from "./variants";
|
||||
export {COMMON_UNITS, twMergeConfig} from "./tw-merge-config";
|
||||
export {cn} from "./cn";
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
import {tv as tvBase, TV} from "tailwind-variants";
|
||||
|
||||
const COMMON_UNITS = ["small", "medium", "large"];
|
||||
import {twMergeConfig} from "./tw-merge-config";
|
||||
|
||||
export const tv: TV = (options, config) =>
|
||||
tvBase(options, {
|
||||
@ -10,16 +10,11 @@ export const tv: TV = (options, config) =>
|
||||
...config?.twMergeConfig,
|
||||
theme: {
|
||||
...config?.twMergeConfig?.theme,
|
||||
opacity: ["disabled"],
|
||||
spacing: ["divider"],
|
||||
borderWidth: COMMON_UNITS,
|
||||
borderRadius: COMMON_UNITS,
|
||||
...twMergeConfig.theme,
|
||||
},
|
||||
classGroups: {
|
||||
...config?.twMergeConfig?.classGroups,
|
||||
shadow: [{shadow: COMMON_UNITS}],
|
||||
"font-size": [{text: ["tiny", ...COMMON_UNITS]}],
|
||||
"bg-image": ["bg-stripe-gradient"],
|
||||
...twMergeConfig.classGroups,
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
16
packages/core/theme/src/utils/tw-merge-config.ts
Normal file
16
packages/core/theme/src/utils/tw-merge-config.ts
Normal file
@ -0,0 +1,16 @@
|
||||
import type {Config} from "tailwind-merge";
|
||||
export const COMMON_UNITS = ["small", "medium", "large"];
|
||||
|
||||
export const twMergeConfig: Partial<Config> = {
|
||||
theme: {
|
||||
opacity: ["disabled"],
|
||||
spacing: ["divider"],
|
||||
borderWidth: COMMON_UNITS,
|
||||
borderRadius: COMMON_UNITS,
|
||||
},
|
||||
classGroups: {
|
||||
shadow: [{shadow: COMMON_UNITS}],
|
||||
"font-size": [{text: ["tiny", ...COMMON_UNITS]}],
|
||||
"bg-image": ["bg-stripe-gradient"],
|
||||
},
|
||||
};
|
||||
6
pnpm-lock.yaml
generated
6
pnpm-lock.yaml
generated
@ -3020,6 +3020,9 @@ importers:
|
||||
|
||||
packages/core/theme:
|
||||
dependencies:
|
||||
clsx:
|
||||
specifier: ^1.2.1
|
||||
version: 1.2.1
|
||||
color:
|
||||
specifier: ^4.2.3
|
||||
version: 4.2.3
|
||||
@ -3047,6 +3050,9 @@ importers:
|
||||
lodash.omit:
|
||||
specifier: ^4.5.0
|
||||
version: 4.5.0
|
||||
tailwind-merge:
|
||||
specifier: ^1.14.0
|
||||
version: 1.14.0
|
||||
tailwind-variants:
|
||||
specifier: ^0.1.20
|
||||
version: 0.1.20(tailwindcss@3.4.3)
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user