---
applyTo: "**/*.ts,**/*.tsx"
---

# @cfx-dev/ui-components — TypeScript Utilities

All utilities are imported from `@cfx-dev/ui-components`.

## `ui` Namespace (TypeScript)

Mirror of the SCSS `ui.*` API for use in inline styles and JS logic:

```tsx
import { ui } from '@cfx-dev/ui-components';

// Quant-based sizing
ui.q(4)                              // "calc(var(--quant) * 4)"
ui.q()                               // "var(--quant)"

// Colors
ui.color('accent')                   // "rgba(var(--color-accent), 1)"
ui.color('primary', 700, 0.5)        // "rgba(var(--color-primary-700), 0.5)"
ui.color('bg')                       // "rgba(var(--color-bg), 1)"

// Tokens
ui.offset('normal')                  // "var(--offset-normal)"
ui.fontSize('medium')                // "var(--font-size-medium)"
ui.lineHeight('medium')              // "var(--line-height-medium)"
ui.borderRadius('large')             // "var(--border-radius-large)"
ui.zindex('max')                     // z-index value
ui.spacer('large')                   // "var(--spacer-large)"
ui.spacing('sp400')                  // "var(--spacing-400)"

// Unit helpers
ui.px(16)                            // "16px"
ui.pc(50)                            // "50%"
ui.rem(1.5)                          // "1.5rem"
ui.em(2)                             // "2em"
ui.vh(100)                           // "100vh"
ui.vw(50)                            // "50vw"

// CSS utility classes
ui.cls.fullWidth                     // "util-full-width"
ui.cls.fullHeight                    // "util-full-height"
ui.cls.flexGrow                      // "util-flex-grow"
ui.cls.flexNoShrink                  // "util-flex-no-shrink"
ui.cls.userSelectableText            // "util-text-selectable"

// Responsive style/class generation (used internally by Box, Flex, Text)
ui.getResponsiveStyles('gap', { initial: 2, bp768: 4 })
ui.getResponsiveClassnames('gap', { initial: 2, bp768: 4 })
```

## Type System

```tsx
import type {
  ColorType,              // 'accent' | 'primary' | 'secondary' | ... | 'bg-black'
  OffsetType,             // 'none' | 'hairthin' | ... | 'safezone'
  SpacerType,             // 'xxsmall' | ... | 'xxxxxlarge'
  SpacingType,            // 'sp25' | 'sp100' | ... | 'sp2400'
  MediaQueryType,         // 'initial' | 'bp320' | ... | 'bp2560'
  BorderRadiusType,       // 'none' | 'xsmall' | ... | 'pill'
  ZIndexType,             // 'zero' | 'first' | 'second' | 'max' | 'select' | 'title'
  ResponsiveValueType,    // T | { [breakpoint]: T }
  ResponsiveSizeUnitType, // ResponsiveValueType<SpacingType | SpacerType | number>
  MPProps,                // margin/padding responsive props (m, mt, mr, mb, ml, mx, my, p, pt, pr, pb, pl, px, py)
  OpacityRange,           // 0 | 0.1 | 0.2 | ... | 1
} from '@cfx-dev/ui-components';
```

## Enums

```tsx
import {
  ColorEnum,
  OffsetEnum,
  MediaQueryEnum,
  MediaQueryValuesMap,    // Record<MediaQueryType, number> — breakpoint → pixel value
  BorderRadiusEnum,
  ZIndexEnum,
  TextSizeEnum,
  SpacerEnum,
  SpacingEnum,
} from '@cfx-dev/ui-components';
```

## Utility Functions

### Class Names

```tsx
import { clsx } from '@cfx-dev/ui-components';

// Lightweight class name composer (same API as lukeed/clsx)
clsx('base', isActive && 'active', { disabled: isDisabled })
// → "base active" or "base disabled"
```

### Formatting

```tsx
import { formatDate, formatShortDate, formatLocaleDate } from '@cfx-dev/ui-components';

formatDate('2024-01-15T10:30:00')      // "01/15/2024, 10:30:00 AM"
formatDate('2024-01-15', true)          // "01/15/2024" (no time)
formatShortDate('2024-01-15')           // "January 15, 2024"

import { formatCurrency, FREE_PRICE_TEXT, CURRENCY_MAP } from '@cfx-dev/ui-components';

formatCurrency(1999, 'USD')             // "$19.99"
formatCurrency(0, '')                   // "free"
formatCurrency(500, 'EUR')             // "€5"

import { formatBytes } from '@cfx-dev/ui-components';

formatBytes(1024)                       // "1.00 KB"
formatBytes(1048576)                    // "1.00 MB"
```

### Functional Helpers

```tsx
import { noop, returnTrue, returnFalse, identity, invoke } from '@cfx-dev/ui-components';

// noop — empty function, use as default callback
<Button onClick={onAction || noop} />

// identity — returns its argument unchanged
items.map(identity)

import { debounce, throttle } from '@cfx-dev/ui-components';

const debouncedSearch = debounce(search, 300);
const throttledScroll = throttle(onScroll, 100);
```

### Refs

```tsx
import { mergeRefs } from '@cfx-dev/ui-components';

// Combine multiple refs into one
<div ref={mergeRefs(localRef, forwardedRef)} />
```

### Value Helpers

```tsx
import { getValue } from '@cfx-dev/ui-components';
import type { ValueOrGetter } from '@cfx-dev/ui-components';

// Resolves value-or-function pattern
const result = getValue(propOrGetter);  // calls it if function, returns it otherwise
```

### String Utilities

```tsx
import {
  unicodeCharAt,
  splitByIndices,
  replaceRange,
  normalizeSlashes,
  isTrueString,
  isFalseString,
} from '@cfx-dev/ui-components';
```

### Math Utilities

```tsx
import { clamp, clamp01, minmax } from '@cfx-dev/ui-components';

clamp(value, 0, 100)     // constrain to [0, 100]
clamp01(value)            // constrain to [0, 1]
```

### Color Utility

```tsx
import { getColor } from '@cfx-dev/ui-components';
import type { GetColorProps } from '@cfx-dev/ui-components';

// Generate CSS color string from theme props
getColor({ color: 'accent' })                    // "rgba(var(--color-accent), 1)"
getColor({ color: 'green', opacity: 0.5 })       // "rgba(var(--color-green), 0.5)"
getColor({ color: 'primary', luminance: 700 })    // "rgba(var(--color-primary-700), 1)"
getColor({ colorToken: 'button-text' })           // "var(--color-button-text)"
```

### Link Utilities

```tsx
import { linkify, linkifyWithMD, Linkify, LinkifyWithMD, isExternalUrl } from '@cfx-dev/ui-components';

// Detect and replace URLs in text with React elements
<Linkify>{text}</Linkify>
<LinkifyWithMD>{markdownText}</LinkifyWithMD>

isExternalUrl('https://example.com')   // true
isExternalUrl('/page')                 // false
```

### Enum Check

```tsx
import { isInEnum } from '@cfx-dev/ui-components';

isInEnum('accent', ColorEnum)   // true
isInEnum('unknown', ColorEnum)  // false
```

### Hash

```tsx
import { joaat32 } from '@cfx-dev/ui-components';

joaat32('string-to-hash')   // number hash
```

## Hooks

```tsx
import {
  useInstance,            // Stable instance ref (like useRef but initialized lazily)
  useDynamicRef,          // Ref that always points to latest value
  useGlobalKeyboardEvent, // Register global keydown/keyup listeners
  useKeyboardClose,       // Calls callback on Escape key press
  useWindowResize,        // Window resize listener with debounce
  useOutlet,              // Portal outlet hook — returns component that renders children into a DOM outlet
  usePopoverController,   // Manages popover open/close/toggle state
  useClipboardComponent,  // Copy-to-clipboard with visual feedback state
} from '@cfx-dev/ui-components';
```

### useOutlet

```tsx
const MyOutlet = useOutlet('my-outlet-id');
// Then: <MyOutlet>{children}</MyOutlet>
// Renders children into <div id="my-outlet-id" />
```

### useKeyboardClose

```tsx
useKeyboardClose(() => setIsOpen(false));
// Calls the callback when Escape is pressed
```

## Contexts

### MediaQueryContext

```tsx
import { useMediaQuery, MediaQueryContextProvider } from '@cfx-dev/ui-components';

function MyComponent() {
  const { isMobile, isTablet, isDesktop, isLDesktop, size, qSize } = useMediaQuery();

  if (isMobile) return <MobileLayout />;
  return <DesktopLayout />;
}
```

### AnalyticsContext

```tsx
import { AnalyticsProvider, useAnalytics, useSiteLinkClick } from '@cfx-dev/ui-components';

<AnalyticsProvider value={{ trackEvent: myTracker }}>
  {children}
</AnalyticsProvider>
```

### StoreContext

```tsx
import { createStoreContext } from '@cfx-dev/ui-components';

const [StoreProvider, useStore, useStoreDispatch] = createStoreContext(initialState, reducer);
```

## Truncation

```tsx
import { truncateWithEllipsis } from '@cfx-dev/ui-components';

truncateWithEllipsis('Long text...', 20)   // "Long text..."
```
