feat: Add more base component to UI

This commit is contained in:
deytenit committed 2026-02-01 16:24:45 +03:00
1 parent ca20310460
commit df2abc06f2
116 files changed
+10379 -3473

No files matched your search

+10 -12
View File
@@ -19,10 +19,10 @@ describe('shared/helpers/cn/cn', () => {
// Test with actual conditional values (simulating real usage)
const activeCondition = Math.random() > -1; // Always true but not constant
const inactiveCondition = Math.random() < -1; // Always false but not constant
expect(cn('p-4', activeCondition && 'bg-red-500')).toBe('p-4 bg-red-500');
expect(cn('p-4', inactiveCondition && 'bg-red-500')).toBe('p-4');
// Test null and undefined conditions
const nullCondition: string | null = null;
const undefinedCondition: string | undefined = undefined;
@@ -36,7 +36,9 @@ describe('shared/helpers/cn/cn', () => {
});
it('handles array inputs', () => {
expect(cn(['flex', 'items-center'], 'justify-between')).toBe('flex items-center justify-between');
expect(cn(['flex', 'items-center'], 'justify-between')).toBe(
'flex items-center justify-between'
);
expect(cn(['p-4', null, 'bg-red-500'])).toBe('p-4 bg-red-500');
});
@@ -50,11 +52,11 @@ describe('shared/helpers/cn/cn', () => {
const getIsActive = (): boolean => true;
const getPrimaryVariant = (): 'primary' | 'secondary' => 'primary';
const getSecondaryVariant = (): 'primary' | 'secondary' => 'secondary';
const isActive = getIsActive();
const primaryVariant = getPrimaryVariant();
const secondaryVariant = getSecondaryVariant();
// Test primary variant
expect(
cn(
@@ -84,12 +86,8 @@ describe('shared/helpers/cn/cn', () => {
});
it('properly handles spacing and responsive classes', () => {
expect(
cn('p-2 p-4', 'sm:p-6', 'md:p-8')
).toBe('p-4 sm:p-6 md:p-8');
expect(
cn('m-2', 'mx-4', 'ml-6')
).toBe('m-2 mx-4 ml-6');
expect(cn('p-2 p-4', 'sm:p-6', 'md:p-8')).toBe('p-4 sm:p-6 md:p-8');
expect(cn('m-2', 'mx-4', 'ml-6')).toBe('m-2 mx-4 ml-6');
});
});
+3 -3
View File
@@ -3,13 +3,13 @@ import { twMerge } from 'tailwind-merge';
/**
* Combines and merges CSS class names using clsx and tailwind-merge.
*
*
* This utility function combines the power of clsx for conditional class handling
* with tailwind-merge for proper Tailwind CSS class deduplication and conflict resolution.
*
*
* @param inputs - Class values to combine (strings, objects, arrays, etc.)
* @returns Merged class string with conflicts resolved
*
*
* @example
* ```typescript
* cn('px-4 py-2', 'bg-blue-500') // 'px-4 py-2 bg-blue-500'
+1 -1
View File
@@ -2,4 +2,4 @@
* Shared helper utilities for common functionality.
*/
export { cn } from './cn/cn';
export { cn } from './cn/cn';
+1 -1
View File
@@ -1,3 +1,3 @@
export * from './types';
export * from './functions';
export * from './react';
export * from './react';
+5 -5
View File
@@ -2,9 +2,9 @@ import type React from 'react';
/**
* Safely casts a React ref to a specific type.
* This is a controlled escape hatch for situations where TypeScript's
* This is a controlled escape hatch for situations where TypeScript's
* built-in Ref types are too restrictive (e.g., in generic forwardRef components).
*
*
* @param ref - The ref to cast
* @returns The casted ref
* @example
@@ -13,7 +13,7 @@ import type React from 'react';
* ```
*/
// eslint-disable-next-line @typescript-eslint/no-explicit-any
export function castRef<T>(ref: React.ForwardedRef<any>): React.ForwardedRef<T> {
export function castRef<T>(ref: React.ForwardedRef<any>): React.RefObject<T> {
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
return ref as React.ForwardedRef<T>;
}
return ref as unknown as React.RefObject<T>;
}
@@ -6,7 +6,7 @@ describe('react/genericMemo', () => {
it('should memoize a component', () => {
const Component = ({ name }: { name: string }) => <div>{name}</div>;
const Memoized = genericMemo(Component);
expect(Memoized).toBeDefined();
// In React, memo returns a special object with type: component
expect((Memoized as any).type).toBe(Component);
@@ -2,7 +2,7 @@ import React from 'react';
/**
* A type-safe version of React.memo that preserves generic types.
*
*
* @param component - The component to memoize
* @returns The memoized component
* @example
@@ -13,4 +13,4 @@ import React from 'react';
export function genericMemo<T>(component: T): T {
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions, @typescript-eslint/no-explicit-any
return React.memo(component as any) as any as T;
}
}
+2 -1
View File
@@ -7,4 +7,5 @@ import type React from 'react';
* Common props for any React element.
* Useful for forwarding props to dynamic components.
*/
export type ReactElementProps = React.HTMLAttributes<HTMLElement> & React.AllHTMLAttributes<HTMLElement>;
export type ReactElementProps = React.HTMLAttributes<HTMLElement> &
React.AllHTMLAttributes<HTMLElement>;
+1 -1
View File
@@ -1,6 +1,6 @@
/**
* Props interface for components that accept a className prop.
*
*
* @example
* ```typescript
* interface ButtonProps extends ClassNameProps {
+1 -1
View File
@@ -1,6 +1,6 @@
/**
* Props interface for components that accept a test ID prop for React Testing Library.
*
*
* @example
* ```typescript
* interface ButtonProps extends TestIdProps {