# Project Architecture

This document describes where things live in the Tangible UI codebase.

---

## File Structure

```
src/
├── components/           # React components (co-located)
│   ├── Button/
│   │   ├── Button.tsx
│   │   ├── Button.stories.ts
│   │   ├── styles.scss
│   │   └── index.ts
│   ├── Card/
│   ├── Chip/
│   ├── ...
│   └── index.ts          # Main barrel export
│
├── icons/                # SVG icon registry
│   ├── registry.ts       # Maps category/name → component
│   ├── system/           # Core UI icons
│   ├── cred/             # TangibleCred icons
│   ├── reaction/         # Emoji-style reactions
│   └── player/           # Media player icons
│
├── styles/
│   ├── system/           # Design tokens
│   │   ├── _colors.scss
│   │   ├── _spacing.scss
│   │   ├── _typography.scss
│   │   └── ...
│   ├── components/       # Style bundling (imports from co-located styles)
│   │   ├── _bundle.scss
│   │   └── input/        # CSS-only inputs (no React component)
│   ├── utilities/        # Layout helpers (flex, grid, spacing)
│   └── index.scss        # Main entry point
│
└── stories/              # Storybook documentation (MDX)
    ├── Welcome.mdx
    ├── Colors.mdx
    ├── Spacing.mdx
    └── ...
```

---

## Component Co-location

Each component lives in its own folder with everything it needs:

| File | Purpose |
| - | - |
| `Component.tsx` | React component |
| `styles.scss` | Component styles (SCSS) |
| `Component.stories.tsx` | Storybook stories |
| `index.ts` | Barrel export |

This keeps related code together and makes it easy to find everything about a component in one place.

### Why Co-location?

- **Discoverability**: Open folder, see everything
- **Refactoring**: Move/rename folder, done
- **Ownership**: Clear boundaries between components
- **No hunting**: Styles aren't in a separate tree

---

## Import Patterns

### Consuming components

```tsx
// From the main barrel (recommended)
import { Button, Card, Icon } from '@tangible/ui';

// Direct import (also fine)
import { Button } from '@tangible/ui/components/Button';
```

### Within the codebase

```tsx
// Same folder
import { Button } from './Button';

// Sibling component
import { Icon } from '../Icon';

// Icons registry
import { iconRegistry } from '../../icons/registry';
```

---

## Styles Architecture

### Token System

All design tokens use CSS custom properties with `tui-` prefix:

```css
--tui-spacing-md
--tui-color-primary-base
--tui-typography-size-lg
--tui-radius-md
```

Tokens are defined in `src/styles/system/` and emitted to `.tui-interface`.

### Component Styles

Component styles are written in SCSS and use the token system:

```scss
@use "../../styles/system" as sys;

@mixin styles() {
  :where(.#{sys.$prefix}interface) .#{sys.$prefix}button {
    padding: var(--#{sys.$prefix}spacing-sm);
    // ...
  }
}
```

### CSS Layers

Styles are organized into CSS layers for cascade control:

```css
@layer defaults, components, utilities;
```

- **defaults**: Resets and base styles
- **components**: Component styles
- **utilities**: Layout helpers (can override components)

---

## Build Outputs

```
publish/
├── index.js          # React components (ESM)
├── index.d.ts        # TypeScript declarations
├── styles/
│   └── all.css       # All styles bundled
└── ...
```

### CSS-only Usage

For PHP-rendered HTML, include the CSS and use classes directly:

```html
<link rel="stylesheet" href="@tangible/ui/styles/all.css">

<div class="tui-interface">
  <button class="tui-button is-theme-primary">Click me</button>
</div>
```

---

## Adding a New Component

1. Create folder: `src/components/NewComponent/`
2. Add files:
   - `NewComponent.tsx` — React component
   - `styles.scss` — Styles with `@mixin styles()`
   - `NewComponent.stories.tsx` — Storybook stories
   - `index.ts` — Export component and types
3. Register styles in `src/styles/components/_bundle.scss`
4. Export from `src/components/index.ts`

---

## Key Conventions

| Convention | Example |
| - | - |
| Component file | `Button.tsx` (PascalCase) |
| Styles file | `styles.scss` (always this name) |
| Stories file | `Button.stories.tsx` |
| CSS class | `tui-button` (kebab-case) |
| CSS element | `tui-button__icon` (BEM-ish) |
| CSS modifier | `is-theme-primary`, `is-size-sm` |
| CSS state | `is-disabled`, `is-active` |
| Token | `--tui-spacing-md` |

See [Naming](https://storybook-tangible-ui.pages.dev/docs/system-naming.md) for full class naming conventions.

---

Interactive version: https://storybook-tangible-ui.pages.dev/?path=/docs/system-architecture--docs
