diff --git a/packages/ui/components.json b/packages/ui/components.json index b5c2f24eff..a6c7c26b0c 100644 --- a/packages/ui/components.json +++ b/packages/ui/components.json @@ -5,7 +5,7 @@ "hooks": "@cherrystudio/ui/hooks", "lib": "@cherrystudio/ui/lib", "ui": "@cherrystudio/ui/components/primitives", - "utils": "@cherrystudio/ui/utils" + "utils": "@cherrystudio/ui/lib/utils" }, "iconLibrary": "lucide", "rsc": false, diff --git a/packages/ui/src/components/composites/Ellipsis/index.tsx b/packages/ui/src/components/composites/Ellipsis/index.tsx index c4c296079c..c5c3a5fd72 100644 --- a/packages/ui/src/components/composites/Ellipsis/index.tsx +++ b/packages/ui/src/components/composites/Ellipsis/index.tsx @@ -1,8 +1,7 @@ // Original: src/renderer/src/components/Ellipsis/index.tsx +import { cn } from '@cherrystudio/ui/lib/utils' import type { HTMLAttributes } from 'react' -import { cn } from '../../../utils' - type Props = { maxLine?: number className?: string diff --git a/packages/ui/src/components/composites/Flex/index.tsx b/packages/ui/src/components/composites/Flex/index.tsx index 522a5574d7..6aa34293e1 100644 --- a/packages/ui/src/components/composites/Flex/index.tsx +++ b/packages/ui/src/components/composites/Flex/index.tsx @@ -1,7 +1,6 @@ +import { cn } from '@cherrystudio/ui/lib/utils' import React from 'react' -import { cn } from '../../../utils' - export interface BoxProps extends React.ComponentProps<'div'> {} export const Box = ({ children, className, ...props }: BoxProps & { children?: React.ReactNode }) => { diff --git a/packages/ui/src/components/composites/Input/input.tsx b/packages/ui/src/components/composites/Input/input.tsx index 80c83fe15e..1d792f2039 100644 --- a/packages/ui/src/components/composites/Input/input.tsx +++ b/packages/ui/src/components/composites/Input/input.tsx @@ -1,4 +1,5 @@ -import { cn, toUndefinedIfNull } from '@cherrystudio/ui/utils' +import { cn } from '@cherrystudio/ui/lib/utils' +import { toUndefinedIfNull } from '@cherrystudio/ui/utils/index' import type { VariantProps } from 'class-variance-authority' import { cva } from 'class-variance-authority' import { Edit2Icon, EyeIcon, EyeOffIcon } from 'lucide-react' diff --git a/packages/ui/src/components/composites/ListItem/index.tsx b/packages/ui/src/components/composites/ListItem/index.tsx index 196fdb2949..327dda27e0 100644 --- a/packages/ui/src/components/composites/ListItem/index.tsx +++ b/packages/ui/src/components/composites/ListItem/index.tsx @@ -1,9 +1,8 @@ // Original path: src/renderer/src/components/ListItem/index.tsx +import { cn } from '@cherrystudio/ui/lib/utils' import { Tooltip } from '@heroui/react' import type { ReactNode } from 'react' -import { cn } from '../../../utils' - interface ListItemProps { active?: boolean icon?: ReactNode diff --git a/packages/ui/src/components/composites/Sortable/ItemRenderer.tsx b/packages/ui/src/components/composites/Sortable/ItemRenderer.tsx index e9e048fd6a..396af9b11b 100644 --- a/packages/ui/src/components/composites/Sortable/ItemRenderer.tsx +++ b/packages/ui/src/components/composites/Sortable/ItemRenderer.tsx @@ -1,10 +1,10 @@ +import { cn } from '@cherrystudio/ui/lib/utils' import type { DraggableSyntheticListeners } from '@dnd-kit/core' import type { Transform } from '@dnd-kit/utilities' import { CSS } from '@dnd-kit/utilities' import React, { useEffect } from 'react' import styled from 'styled-components' -import { cn } from '../../../utils' import type { RenderItemType } from './types' interface ItemRendererProps { diff --git a/packages/ui/src/components/composites/ThinkingEffect/index.tsx b/packages/ui/src/components/composites/ThinkingEffect/index.tsx index 6c542bf3d4..86baad1470 100644 --- a/packages/ui/src/components/composites/ThinkingEffect/index.tsx +++ b/packages/ui/src/components/composites/ThinkingEffect/index.tsx @@ -7,12 +7,12 @@ */ // Original path: src/renderer/src/components/ThinkingEffect.tsx +import { cn } from '@cherrystudio/ui/lib/utils' import { isEqual } from 'lodash' import { ChevronRight, Lightbulb } from 'lucide-react' import { motion } from 'motion/react' import React, { useEffect, useMemo, useState } from 'react' -import { cn } from '../../../utils' import { lightbulbVariants } from './defaultVariants' interface ThinkingEffectProps { diff --git a/packages/ui/src/components/primitives/Avatar/EmojiAvatar.tsx b/packages/ui/src/components/primitives/Avatar/EmojiAvatar.tsx index 7a9ce03e24..e6fef89703 100644 --- a/packages/ui/src/components/primitives/Avatar/EmojiAvatar.tsx +++ b/packages/ui/src/components/primitives/Avatar/EmojiAvatar.tsx @@ -1,7 +1,6 @@ +import { cn } from '@cherrystudio/ui/lib/utils' import React, { memo } from 'react' -import { cn } from '../../../utils' - interface EmojiAvatarProps { children: string size?: number diff --git a/packages/ui/src/components/primitives/Avatar/index.tsx b/packages/ui/src/components/primitives/Avatar/index.tsx index a2ad31bd73..1c5aff9658 100644 --- a/packages/ui/src/components/primitives/Avatar/index.tsx +++ b/packages/ui/src/components/primitives/Avatar/index.tsx @@ -1,7 +1,7 @@ +import { cn } from '@cherrystudio/ui/lib/utils' import type { AvatarProps as HeroUIAvatarProps } from '@heroui/react' import { Avatar as HeroUIAvatar, AvatarGroup as HeroUIAvatarGroup } from '@heroui/react' -import { cn } from '../../../utils' import EmojiAvatar from './EmojiAvatar' export interface AvatarProps extends Omit { diff --git a/packages/ui/src/components/primitives/badge.tsx b/packages/ui/src/components/primitives/badge.tsx index e63b6dde4c..5cb3c8cefe 100644 --- a/packages/ui/src/components/primitives/badge.tsx +++ b/packages/ui/src/components/primitives/badge.tsx @@ -1,4 +1,4 @@ -import { cn } from '@cherrystudio/ui/utils/index' +import { cn } from '@cherrystudio/ui/lib/utils' import { Slot } from '@radix-ui/react-slot' import { cva, type VariantProps } from 'class-variance-authority' import * as React from 'react' diff --git a/packages/ui/src/components/primitives/breadcrumb.tsx b/packages/ui/src/components/primitives/breadcrumb.tsx index 6f9d871409..11c3527eeb 100644 --- a/packages/ui/src/components/primitives/breadcrumb.tsx +++ b/packages/ui/src/components/primitives/breadcrumb.tsx @@ -1,4 +1,4 @@ -import { cn } from '@cherrystudio/ui/utils/index' +import { cn } from '@cherrystudio/ui/lib/utils' import { Slot } from '@radix-ui/react-slot' import { ChevronRight, MoreHorizontal } from 'lucide-react' import * as React from 'react' diff --git a/packages/ui/src/components/primitives/button.tsx b/packages/ui/src/components/primitives/button.tsx index 092d55dd1c..8fb96c9903 100644 --- a/packages/ui/src/components/primitives/button.tsx +++ b/packages/ui/src/components/primitives/button.tsx @@ -1,4 +1,4 @@ -import { cn } from '@cherrystudio/ui/utils/index' +import { cn } from '@cherrystudio/ui/lib/utils' import { Slot } from '@radix-ui/react-slot' import { cva, type VariantProps } from 'class-variance-authority' import { Loader } from 'lucide-react' diff --git a/packages/ui/src/components/primitives/checkbox.tsx b/packages/ui/src/components/primitives/checkbox.tsx index 34f374fec4..dff1f928c2 100644 --- a/packages/ui/src/components/primitives/checkbox.tsx +++ b/packages/ui/src/components/primitives/checkbox.tsx @@ -1,4 +1,4 @@ -import { cn } from '@cherrystudio/ui/utils/index' +import { cn } from '@cherrystudio/ui/lib/utils' import * as CheckboxPrimitive from '@radix-ui/react-checkbox' import { cva, type VariantProps } from 'class-variance-authority' import { CheckIcon } from 'lucide-react' diff --git a/packages/ui/src/components/primitives/combobox.tsx b/packages/ui/src/components/primitives/combobox.tsx index 15afa8c0a8..2e11809351 100644 --- a/packages/ui/src/components/primitives/combobox.tsx +++ b/packages/ui/src/components/primitives/combobox.tsx @@ -10,7 +10,7 @@ import { CommandList } from '@cherrystudio/ui/components/primitives/command' import { Popover, PopoverContent, PopoverTrigger } from '@cherrystudio/ui/components/primitives/popover' -import { cn } from '@cherrystudio/ui/utils/index' +import { cn } from '@cherrystudio/ui/lib/utils' import { cva, type VariantProps } from 'class-variance-authority' import { Check, ChevronDown, X } from 'lucide-react' import * as React from 'react' diff --git a/packages/ui/src/components/primitives/command.tsx b/packages/ui/src/components/primitives/command.tsx index 2d0515d272..76ecf7a1c1 100644 --- a/packages/ui/src/components/primitives/command.tsx +++ b/packages/ui/src/components/primitives/command.tsx @@ -5,7 +5,7 @@ import { DialogHeader, DialogTitle } from '@cherrystudio/ui/components/primitives/dialog' -import { cn } from '@cherrystudio/ui/utils' +import { cn } from '@cherrystudio/ui/lib/utils' import { Command as CommandPrimitive } from 'cmdk' import { SearchIcon } from 'lucide-react' import * as React from 'react' diff --git a/packages/ui/src/components/primitives/dialog.tsx b/packages/ui/src/components/primitives/dialog.tsx index 6b36644bc7..62a063eea4 100644 --- a/packages/ui/src/components/primitives/dialog.tsx +++ b/packages/ui/src/components/primitives/dialog.tsx @@ -1,4 +1,4 @@ -import { cn } from '@cherrystudio/ui/utils/index' +import { cn } from '@cherrystudio/ui/lib/utils' import * as DialogPrimitive from '@radix-ui/react-dialog' import { XIcon } from 'lucide-react' import * as React from 'react' diff --git a/packages/ui/src/components/primitives/input-group.tsx b/packages/ui/src/components/primitives/input-group.tsx index 9c27456b34..0bb9253001 100644 --- a/packages/ui/src/components/primitives/input-group.tsx +++ b/packages/ui/src/components/primitives/input-group.tsx @@ -3,7 +3,7 @@ import type { InputProps } from '@cherrystudio/ui/components/primitives/input' import { Input } from '@cherrystudio/ui/components/primitives/input' import type { TextareaInputProps } from '@cherrystudio/ui/components/primitives/textarea' import * as Textarea from '@cherrystudio/ui/components/primitives/textarea' -import { cn } from '@cherrystudio/ui/utils/index' +import { cn } from '@cherrystudio/ui/lib/utils' import { cva, type VariantProps } from 'class-variance-authority' import * as React from 'react' diff --git a/packages/ui/src/components/primitives/input.tsx b/packages/ui/src/components/primitives/input.tsx index 5a5e29cd5a..cffad36b44 100644 --- a/packages/ui/src/components/primitives/input.tsx +++ b/packages/ui/src/components/primitives/input.tsx @@ -1,4 +1,4 @@ -import { cn } from '@cherrystudio/ui/utils' +import { cn } from '@cherrystudio/ui/lib/utils' import * as React from 'react' interface InputProps extends React.ComponentProps<'input'> {} diff --git a/packages/ui/src/components/primitives/kbd.tsx b/packages/ui/src/components/primitives/kbd.tsx index d1a2268e75..21c4b06b7b 100644 --- a/packages/ui/src/components/primitives/kbd.tsx +++ b/packages/ui/src/components/primitives/kbd.tsx @@ -1,4 +1,4 @@ -import { cn } from '@cherrystudio/ui/utils/index' +import { cn } from '@cherrystudio/ui/lib/utils' function Kbd({ className, ...props }: React.ComponentProps<'kbd'>) { return ( diff --git a/packages/ui/src/components/primitives/pagination.tsx b/packages/ui/src/components/primitives/pagination.tsx index eb675e8bb0..4e5a407c07 100644 --- a/packages/ui/src/components/primitives/pagination.tsx +++ b/packages/ui/src/components/primitives/pagination.tsx @@ -1,6 +1,6 @@ import type { Button } from '@cherrystudio/ui/components/primitives/button' import { buttonVariants } from '@cherrystudio/ui/components/primitives/button' -import { cn } from '@cherrystudio/ui/utils/index' +import { cn } from '@cherrystudio/ui/lib/utils' import { ChevronLeftIcon, ChevronRightIcon, MoreHorizontalIcon } from 'lucide-react' import * as React from 'react' diff --git a/packages/ui/src/components/primitives/popover.tsx b/packages/ui/src/components/primitives/popover.tsx index b52cc7aa4a..805d952b07 100644 --- a/packages/ui/src/components/primitives/popover.tsx +++ b/packages/ui/src/components/primitives/popover.tsx @@ -1,6 +1,6 @@ 'use client' -import { cn } from '@cherrystudio/ui/utils' +import { cn } from '@cherrystudio/ui/lib/utils' import * as PopoverPrimitive from '@radix-ui/react-popover' import * as React from 'react' diff --git a/packages/ui/src/components/primitives/radioGroup.tsx b/packages/ui/src/components/primitives/radioGroup.tsx index 0d4b95b6c9..2dd4ece391 100644 --- a/packages/ui/src/components/primitives/radioGroup.tsx +++ b/packages/ui/src/components/primitives/radioGroup.tsx @@ -1,4 +1,4 @@ -import { cn } from '@cherrystudio/ui/utils/index' +import { cn } from '@cherrystudio/ui/lib/utils' import * as RadioGroupPrimitive from '@radix-ui/react-radio-group' import { cva, type VariantProps } from 'class-variance-authority' import { CircleIcon } from 'lucide-react' diff --git a/packages/ui/src/components/primitives/select.tsx b/packages/ui/src/components/primitives/select.tsx index ec2bac4cba..9b1fa1bba5 100644 --- a/packages/ui/src/components/primitives/select.tsx +++ b/packages/ui/src/components/primitives/select.tsx @@ -1,4 +1,4 @@ -import { cn } from '@cherrystudio/ui/utils/index' +import { cn } from '@cherrystudio/ui/lib/utils' import * as SelectPrimitive from '@radix-ui/react-select' import { cva, type VariantProps } from 'class-variance-authority' import { CheckIcon, ChevronDownIcon, ChevronUpIcon } from 'lucide-react' diff --git a/packages/ui/src/components/primitives/shadcn-io/dropzone/index.tsx b/packages/ui/src/components/primitives/shadcn-io/dropzone/index.tsx index 4892a94244..14ba16a6d0 100644 --- a/packages/ui/src/components/primitives/shadcn-io/dropzone/index.tsx +++ b/packages/ui/src/components/primitives/shadcn-io/dropzone/index.tsx @@ -1,7 +1,7 @@ 'use client' import { Button } from '@cherrystudio/ui/components/primitives/button' -import { cn } from '@cherrystudio/ui/utils/index' +import { cn } from '@cherrystudio/ui/lib/utils' import { UploadIcon } from 'lucide-react' import type { ReactNode } from 'react' import { createContext, use } from 'react' diff --git a/packages/ui/src/components/primitives/switch.tsx b/packages/ui/src/components/primitives/switch.tsx index 7ce2ac5d3c..2e9b2c12eb 100644 --- a/packages/ui/src/components/primitives/switch.tsx +++ b/packages/ui/src/components/primitives/switch.tsx @@ -1,4 +1,4 @@ -import { cn } from '@cherrystudio/ui/utils' +import { cn } from '@cherrystudio/ui/lib/utils' import * as SwitchPrimitive from '@radix-ui/react-switch' import { cva } from 'class-variance-authority' import * as React from 'react' diff --git a/packages/ui/src/components/primitives/tabs.tsx b/packages/ui/src/components/primitives/tabs.tsx index 051de1dfb2..95c8ec90e2 100644 --- a/packages/ui/src/components/primitives/tabs.tsx +++ b/packages/ui/src/components/primitives/tabs.tsx @@ -1,4 +1,4 @@ -import { cn } from '@cherrystudio/ui/utils/index' +import { cn } from '@cherrystudio/ui/lib/utils' import * as TabsPrimitive from '@radix-ui/react-tabs' import { cva } from 'class-variance-authority' import * as React from 'react' diff --git a/packages/ui/src/components/primitives/textarea.tsx b/packages/ui/src/components/primitives/textarea.tsx index 5bc749d7ac..1444e8c9ed 100644 --- a/packages/ui/src/components/primitives/textarea.tsx +++ b/packages/ui/src/components/primitives/textarea.tsx @@ -1,4 +1,4 @@ -import { cn } from '@cherrystudio/ui/utils/index' +import { cn } from '@cherrystudio/ui/lib/utils' import { composeEventHandlers } from '@radix-ui/primitive' import { useCallbackRef } from '@radix-ui/react-use-callback-ref' import { useControllableState } from '@radix-ui/react-use-controllable-state' diff --git a/packages/ui/src/components/primitives/tooltip_new.tsx b/packages/ui/src/components/primitives/tooltip_new.tsx index 430ac262f4..9b1db13e1e 100644 --- a/packages/ui/src/components/primitives/tooltip_new.tsx +++ b/packages/ui/src/components/primitives/tooltip_new.tsx @@ -1,4 +1,4 @@ -import { cn } from '@cherrystudio/ui/utils/index' +import { cn } from '@cherrystudio/ui/lib/utils' import * as TooltipPrimitive from '@radix-ui/react-tooltip' import * as React from 'react' diff --git a/packages/ui/src/lib/utils.ts b/packages/ui/src/lib/utils.ts new file mode 100644 index 0000000000..d477ffd44a --- /dev/null +++ b/packages/ui/src/lib/utils.ts @@ -0,0 +1,23 @@ +/** + * Internal utilities for UI components. + * + * This module is for INTERNAL use only and should NOT be exposed to external consumers. + * External utilities should be placed in `utils/` instead. + * + * @internal + */ + +import { type ClassValue, clsx } from 'clsx' +import { twMerge } from 'tailwind-merge' + +/** + * Merges Tailwind CSS class names with conflict resolution. + * Combines clsx for conditional classes and tailwind-merge for deduplication. + * + * @example + * cn('px-2 py-1', 'px-4') // => 'py-1 px-4' + * cn('text-red-500', isActive && 'text-blue-500') + */ +export function cn(...inputs: ClassValue[]) { + return twMerge(clsx(inputs)) +} diff --git a/packages/ui/src/utils/index.ts b/packages/ui/src/utils/index.ts index 7f0275f99d..573e97be73 100644 --- a/packages/ui/src/utils/index.ts +++ b/packages/ui/src/utils/index.ts @@ -1,13 +1,11 @@ -import { type ClassValue, clsx } from 'clsx' -import { twMerge } from 'tailwind-merge' - /** - * Merge class names with tailwind-merge - * This utility combines clsx and tailwind-merge for optimal class name handling + * Public utility functions for external consumers. + * + * This module is part of the PUBLIC API and can be imported via `@cherrystudio/ui/utils`. + * For internal-only utilities (e.g., Tailwind class merging), use `lib/` instead. + * + * @module utils */ -export function cn(...inputs: ClassValue[]) { - return twMerge(clsx(inputs)) -} /** * Converts `null` to `undefined`, otherwise returns the input value. diff --git a/src/renderer/src/components/Avatar/ModelAvatar.tsx b/src/renderer/src/components/Avatar/ModelAvatar.tsx index 9ce6d87c46..cff23486f7 100644 --- a/src/renderer/src/components/Avatar/ModelAvatar.tsx +++ b/src/renderer/src/components/Avatar/ModelAvatar.tsx @@ -1,7 +1,8 @@ import type { AvatarProps } from '@cherrystudio/ui' -import { Avatar, cn } from '@cherrystudio/ui' +import { Avatar } from '@cherrystudio/ui' import { getModelLogo } from '@renderer/config/models' import type { Model } from '@renderer/types' +import { cn } from '@renderer/utils' import { first } from 'lodash' import type { FC } from 'react' diff --git a/src/renderer/src/components/Buttons/ActionIconButton.tsx b/src/renderer/src/components/Buttons/ActionIconButton.tsx index 221a5eeb30..ec1da45ab8 100644 --- a/src/renderer/src/components/Buttons/ActionIconButton.tsx +++ b/src/renderer/src/components/Buttons/ActionIconButton.tsx @@ -1,4 +1,5 @@ -import { Button, cn } from '@cherrystudio/ui' +import { Button } from '@cherrystudio/ui' +import { cn } from '@renderer/utils' import React, { memo } from 'react' interface ActionIconButtonProps extends Omit, 'ref'> { diff --git a/src/renderer/src/components/ProviderAvatar.tsx b/src/renderer/src/components/ProviderAvatar.tsx index 468941e3f8..dddfdce983 100644 --- a/src/renderer/src/components/ProviderAvatar.tsx +++ b/src/renderer/src/components/ProviderAvatar.tsx @@ -1,7 +1,8 @@ -import { Avatar, cn } from '@cherrystudio/ui' +import { Avatar } from '@cherrystudio/ui' import { PoeLogo } from '@renderer/components/Icons' import { getProviderLogo } from '@renderer/config/providers' import type { Provider } from '@renderer/types' +import { cn } from '@renderer/utils' import { generateColorFromChar, getFirstCharacter, getForegroundColor } from '@renderer/utils' import React from 'react' diff --git a/src/renderer/src/pages/home/Messages/NewTopicButton.tsx b/src/renderer/src/pages/home/Messages/NewTopicButton.tsx index 55696a4e95..1c654967f4 100644 --- a/src/renderer/src/pages/home/Messages/NewTopicButton.tsx +++ b/src/renderer/src/pages/home/Messages/NewTopicButton.tsx @@ -1,8 +1,9 @@ import { FormOutlined } from '@ant-design/icons' -import { Button, cn } from '@cherrystudio/ui' +import { Button } from '@cherrystudio/ui' import { useTheme } from '@renderer/context/ThemeProvider' import { EventEmitter } from '@renderer/services/EventService' import { EVENT_NAMES } from '@renderer/services/EventService' +import { cn } from '@renderer/utils' import { ThemeMode } from '@shared/data/preference/preferenceTypes' import type { FC } from 'react' import { useTranslation } from 'react-i18next' diff --git a/src/renderer/src/pages/home/Tabs/components/AddButton.tsx b/src/renderer/src/pages/home/Tabs/components/AddButton.tsx index 407fa7a271..69a89ff312 100644 --- a/src/renderer/src/pages/home/Tabs/components/AddButton.tsx +++ b/src/renderer/src/pages/home/Tabs/components/AddButton.tsx @@ -1,4 +1,5 @@ -import { Button, cn } from '@cherrystudio/ui' +import { Button } from '@cherrystudio/ui' +import { cn } from '@renderer/utils' import { PlusIcon } from 'lucide-react' const AddButton = ({ children, className, ...props }) => { diff --git a/src/renderer/src/pages/settings/index.tsx b/src/renderer/src/pages/settings/index.tsx index e5c88f83e1..9afe342548 100644 --- a/src/renderer/src/pages/settings/index.tsx +++ b/src/renderer/src/pages/settings/index.tsx @@ -1,4 +1,4 @@ -import { cn } from '@cherrystudio/ui' +import { cn } from '@renderer/utils' import type { ThemeMode } from '@shared/data/preference/preferenceTypes' import { Divider } from 'antd' import Link from 'antd/es/typography/Link'