# @xsolla/xui-core

Design system foundation providing theming, context, design tokens, and shared utilities for the XUI toolkit.

## Installation

```bash
npm install @xsolla/xui-core
```

## Usage

```tsx
import { XUIProvider, useDesignSystem } from '@xsolla/xui-core';

function App() {
  return (
    <XUIProvider initialMode="dark">
      <MyApp />
    </XUIProvider>
  );
}

function MyComponent() {
  const { theme, mode, setMode } = useDesignSystem();
  return <div style={{ color: theme.colors.content.primary }}>Hello</div>;
}
```

Per-component theme overrides with `useResolvedTheme`:

```tsx
import { useResolvedTheme, ThemeOverrideProps } from '@xsolla/xui-core';

type MyWidgetProps = ThemeOverrideProps & { label: string };

function MyWidget({ label, themeMode, themeProductContext }: MyWidgetProps) {
  const { theme, mode } = useResolvedTheme({ themeMode, themeProductContext });
  return <div style={{ color: theme.colors.content.primary }}>{label}</div>;
}

// Usage — override theme per-instance without nesting providers
<MyWidget label="Global theme" />
<MyWidget label="Light override" themeMode="light" />
```

## Available Theme Modes

| Mode | Theme |
|------|-------|
| `"dark"` | Pentagram Dark (default) |
| `"light"` | Pentagram Light |
| `"ltg-dark"` | LTG Dark |
| `"blueprints"` | Blueprints |

## Per-Component Overrides

Every component accepts `themeMode` and `themeProductContext` props to override the global provider:

```tsx
<Button themeMode="light" themeProductContext="b2c">Override Both</Button>
```

For custom components, use `useResolvedTheme` instead of `useDesignSystem`.

## Responsive Typography

By default, `XUIProvider` injects CSS custom properties (`--xui-font-size-*`, `--xui-lh-*`) with `@media` queries so text scales between mobile and desktop breakpoints. Pass `responsive={false}` to disable this — all components will use the fixed common/desktop values instead.

```tsx
// Default — responsive scaling via CSS vars + @media
<XUIProvider>
  <App />
</XUIProvider>

// Opt-out — fixed sizes, no @media queries injected
<XUIProvider responsive={false}>
  <App />
</XUIProvider>
```

The `responsive` flag is also available from `useDesignSystem()` if a component needs to branch on it:

```tsx
const { responsive } = useDesignSystem();
```

## Exports

- `XUIProvider` — Root context provider; accepts `initialMode` (see theme modes above) and `responsive` (opt-out of responsive typography, defaults to `true`)
- `useDesignSystem` — Hook returning `{ theme, mode, setMode, responsive }`; falls back to dark theme if no provider
- `useResolvedTheme` — Hook returning resolved theme with per-component overrides applied; same return shape as `useDesignSystem`
- `ThemeOverrideProps` — Type: `{ themeMode?: ThemeMode; themeProductContext?: ProductContext }`
- `themeConfig` — Function returning the full theme object for a given `ThemeMode`
- `useId` — Stable unique ID hook; polyfills `React.useId` for React < 18
- `ModalIdContext` — Context holding the current modal's ID for portal-based components
- `useModalId` — Hook returning the current modal ID, or `null` if outside a modal
- `breakpoints` — Responsive breakpoints: `{ mobile: 0, desktop: 768 }`
- `responsiveTypographyScale` — Raw responsive font-size and line-height data (13 steps × 2 device modes: common/mobile)
- `SCALE_STEPS` — Array of all scale step identifiers
- `generateTypographyCSS` — Returns the full CSS string for responsive typography custom properties
- `cssVar` — Helper to get CSS variable references: `cssVar.fontSize("350")` → `"var(--xui-font-size-350)"`
- `TypographyStyleLoader` — Component that injects responsive typography CSS (rendered automatically by `XUIProvider`)
- `FontLoader` — Component that injects the `@font-face` declarations for XUI fonts
- `fontFacesCSS` — Raw `@font-face` CSS string (for SSR or manual injection)
- `ThemeMode` — Type: `"dark"` | `"light"` | `"ltg-dark"` | `"blueprints"`
- `ThemeColors` — Type of the colour token object
- `ProductContext` — Type of the `themeProductContext` prop: `"b2c"` | `"b2b"`
- `colors` — Raw colour tokens for all themes
- `spacing` — Spacing scale (`xs`, `s`, `m`, `l`, `xl`)
- `radius` — Border-radius tokens (button, card, input, tag, avatar variants)
- `shadow` — Shadow tokens
- `fonts` — Font-family definitions
- `isWeb` / `isNative` / `isIOS` / `isAndroid` — Platform detection booleans

## Per-Component Theme Override

Every component accepts optional `themeMode` and `themeProductContext` props to override the global theme on a per-instance basis, without nesting additional providers.

`useResolvedTheme` is the hook that powers this. It accepts an optional overrides object and returns the same `{ theme, mode, productContext }` shape as `useDesignSystem`:

```tsx
import { useResolvedTheme, ThemeOverrideProps } from '@xsolla/xui-core';
import { Box, Text } from '@xsolla/xui-primitives';

type CardProps = ThemeOverrideProps & { title: string };

export const Card = ({ title, themeMode, themeProductContext }: CardProps) => {
  const { theme } = useResolvedTheme({ themeMode, themeProductContext });

  return (
    <Box backgroundColor={theme.colors.surface.primary}>
      <Text color={theme.colors.content.primary}>{title}</Text>
    </Box>
  );
};
```

```tsx
// Consumer usage
<XUIProvider initialMode="dark">
  <Card title="Dark card" />
  <Card title="Light card" themeMode="light" />
  <Card title="B2C card" themeMode="light" themeProductContext="b2c" />
</XUIProvider>
```

When no overrides are passed, `useResolvedTheme` returns the global theme object by reference — zero overhead compared to `useDesignSystem`.
