<p align="center">
  <picture>
    <source media="(prefers-color-scheme: dark)" srcset="data/countermeasure.svg" />
    <source media="(prefers-color-scheme: light)" srcset="data/countermeasure-2.svg" />
    <img src="data/countermeasure-2.svg" alt="CounterMeasure" width="400" />
  </picture>
</p>

<p align="center">
  <a href="https://www.typescriptlang.org"><img src="https://img.shields.io/badge/TypeScript-6.0+-blue.svg" alt="TypeScript" /></a>
  <a href="https://react.dev"><img src="https://img.shields.io/badge/React-19-blue.svg" alt="React" /></a>
  <a href="LICENSE"><img src="https://img.shields.io/badge/license-proprietary-orange.svg" alt="License" /></a>
  <a href="https://github.com/countermeasure-platform/web-components/actions/workflows/ci.yml"><img src="https://github.com/countermeasure-platform/web-components/actions/workflows/ci.yml/badge.svg" alt="CI" /></a>
  <a href="https://app.codacy.com/gh/countermeasure-platform/web-components/dashboard?utm_source=gh&amp;utm_medium=referral&amp;utm_content=&amp;utm_campaign=Badge_grade"><img src="https://app.codacy.com/project/badge/Grade/f54db9297f80488bbbd1304c7dd933f4" alt="Codacy Grade" /></a>
  <a href="https://app.codacy.com/gh/countermeasure-platform/web-components/dashboard?utm_source=gh&amp;utm_medium=referral&amp;utm_content=&amp;utm_campaign=Badge_coverage"><img src="https://app.codacy.com/project/badge/Coverage/f54db9297f80488bbbd1304c7dd933f4" alt="Codacy Coverage" /></a>
</p>

<p align="center">
  Shared web component library for CounterMeasure applications.<br />
  Dual-implementation: vanilla TypeScript classes <strong>and</strong> React components.<br />
  Design system primitives, auth flows, layout shells, charts, editors, and security visualizations.
</p>

---

## Install

```bash
npm install @countermeasure-platform/web-components --registry=https://npm.pkg.github.com
```

Configure your `.npmrc` for the `@countermeasure-platform` scope:

```
@countermeasure-platform:registry=https://npm.pkg.github.com
//npm.pkg.github.com/:_authToken=${GITHUB_TOKEN}
```

## Usage

### Vanilla TypeScript

```typescript
import { Button } from '@countermeasure-platform/web-components/primitives/button'
import { DataTable } from '@countermeasure-platform/web-components/components/data-table'
import { PageHeader } from '@countermeasure-platform/web-components/layout/page-header'
import { MitreMatrix } from '@countermeasure-platform/web-components/security/mitre-matrix'
```

### Native Product Chrome

Rust-native and other non-React product surfaces should use the vanilla chrome
helpers instead of mounting a React app for shared navigation. The core `/app`
preset ships the Threat Library visual treatment with a CounterMeasure Core
topbar identity:

```typescript
import '@countermeasure-platform/web-components/styles/layout.css'
import '@countermeasure-platform/web-components/styles/sidebar.css'
import { mountCoreAppChromeFromDom } from '@countermeasure-platform/web-components/layout/core-app-chrome'

mountCoreAppChromeFromDom({
  root: document,
  preserveTopbarActions: true,
})
```

Server-rendered pages provide placeholders and keep legacy markup as a fallback:

```html
<div data-core-app-sidebar data-base-path="/app" data-pathname="/app"></div>
<div
  data-core-app-topbar
  data-base-path="/app"
  data-pathname="/app"
  data-product="CounterMeasure Core"
  data-current="Platform Overview"
></div>
```

### React

```tsx
import { Button } from '@countermeasure-platform/web-components/react'
import { DataTable } from '@countermeasure-platform/web-components/react'
import { Calendar } from '@countermeasure-platform/web-components/react'
import { PageHeader } from '@countermeasure-platform/web-components/react/layout'
```

Every module is individually importable via the package exports map — only the code you use gets bundled.

### Styles, Themes, And Accents

```ts
import '@countermeasure-platform/web-components/styles'
```

The default style entry imports canonical design-system tokens and fonts. Use `@countermeasure-platform/web-components/styles/no-fonts.css` when fonts are self-hosted or blocked by policy.

```ts
document.documentElement.dataset.theme = 'dark' // dark | light | monokai | glass
document.documentElement.dataset.accent = 'cyan' // cyan | violet | rose | emerald
```

Dark is the default theme in `1.0.0`; set `data-theme="light"` explicitly for light-first apps.

## Adopting in a Tailwind v4 / shadcn app

The library's React primitives default to a glass / glow visual tone that
relies on the CounterMeasure design tokens. To use the same primitives in
a shadcn-style Tailwind v4 host app, load the compat stylesheet and pass
`tone="shadcn"` to `Button`, `Card`, and `Badge`:

```tsx
// Once, alongside your shadcn theme stylesheet
import '@countermeasure-platform/web-components/styles/shadcn-compat.css'

import { Button, Card, Badge } from '@countermeasure-platform/web-components/react'

export function Example() {
  return (
    <Card tone="shadcn" className="p-4">
      <Button tone="shadcn" variant="default">
        Run
      </Button>
      <Badge tone="shadcn" variant="status-running">
        running
      </Badge>
    </Card>
  )
}
```

The compat stylesheet maps `--primary`, `--card`, `--foreground`,
`--muted-foreground`, `--border`, `--destructive`, `--accent` (and the
matching `*-foreground` pairs) onto the shadcn `--color-*` token names
that Tailwind v4's `@theme` block expects. Host-app overrides still win
because the bridge sits in `@layer base`.

The `Badge` `variant="status-queued|running|completed|failed|cancelled"`
palette is wired through both tones for run-status pills.

### Toasts (shadcn-style `useToast`)

For host apps that want the React-idiomatic `useToast()` API the shadcn
ecosystem ships, mount `<ToastProvider>` once and call `toast()` inside any
descendant. The visuals reuse the library's `<Toast>` primitive so the
look-and-feel stays consistent across surfaces:

```tsx
import {
  ToastProvider,
  useToast,
} from '@countermeasure-platform/web-components/services/toast-react'

function Root({ children }: { children: React.ReactNode }) {
  return (
    <ToastProvider duration={5000} swipeDirection="right">
      {children}
    </ToastProvider>
  )
}

function SaveButton() {
  const { toast, dismiss, toasts } = useToast()
  return (
    <button
      onClick={() => {
        const t = toast({ title: 'Saved', description: 'OK', variant: 'success' })
        // t.dismiss(), t.update({ title: "Saving…" })
      }}
    >
      Save ({toasts.length} active)
    </button>
  )
}
```

Variants accepted: `'default' | 'destructive' | 'success' | 'info' | 'warning'`.
`'destructive'` is treated as an alias of `'error'` so consumers migrating
from local shadcn-flavoured hooks keep working without code churn.

### `Alert` variant migration (v0.2 → v0.4)

The `Alert` primitive's variant set is now
`'info' | 'success' | 'warning' | 'error'`. Older v0.2.0 call-sites that
pass `variant="destructive"` (or the literal `variant="default"`) are
auto-mapped to `'error'` / `'info'` and emit a one-time `console.warn` in
non-production builds. To clean up call-sites, run a quick codemod:

```bash
find src -type f \( -name '*.tsx' -o -name '*.ts' \) \
  -exec sed -i 's/variant="destructive"/variant="error"/g' {} +
```

The `Button` component still accepts `variant="destructive"` — the codemod
is scoped to `Alert` call-sites by intent. Search-and-replace tools should
prefer the AST-aware path on shared utility files.

## Modules

| Module               | Description                                                                                                                                                           |
| -------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **primitives**       | Base UI controls — button, input, select, checkbox, radio, switch, slider, toggle, label, spinner, skeleton                                                           |
| **components**       | Composite UI — data-table, tree-view, tabs, split-pane, modal, toast, search, command-palette, pagination                                                             |
| **display**          | Read-only visuals — alert, avatar, badge, card, code-block, code-viewer, markdown-viewer, progress, tooltip, stat-card                                                |
| **navigation**       | Nav patterns — breadcrumb, menubar, dropdown-menu, navigation-menu, stepper, drawer                                                                                   |
| **overlays**         | Modals and panels — alert-dialog, sheet, carousel                                                                                                                     |
| **form**             | Form controls — calendar, date-picker, tag-input, color-picker, cron-editor                                                                                           |
| **charts**           | Data visualization — line, bar, area, pie, sparkline, gauge, heatmap, treemap, scatter, radar, waterfall, sankey, funnel, candlestick                                 |
| **visualization**    | Domain visuals — timeline, flow-diagram, network-graph, map, file-tree, terminal, kanban, mermaid-diagram, rule-editor                                                |
| **security**         | Security-specific — cvss-badge, vulnerability-card, attack-path, mitre-matrix, detection-status                                                                       |
| **editors**          | Code editing — code-editor, log-viewer, json-viewer, yaml-editor, diff-viewer, FluxL/YARAL/YARA language support                                                      |
| **layout**           | App shell — layout primitives for page structure                                                                                                                      |
| **sidebar**          | Sidebar navigation component                                                                                                                                          |
| **app-switcher**     | Multi-app navigation switcher                                                                                                                                         |
| **auth**             | Authentication UI flows                                                                                                                                               |
| **passkey**          | WebAuthn/passkey components                                                                                                                                           |
| **consent**          | Cookie/privacy consent UI                                                                                                                                             |
| **appearance**       | Theme and appearance controls                                                                                                                                         |
| **icons**            | Icon set                                                                                                                                                              |
| **crypto**           | Client-side crypto utilities (AES-256-GCM, RSA-OAEP, PBKDF2)                                                                                                          |
| **services**         | Shared services — API client (with CSRF support), SSE, keybindings, router, storage                                                                                   |
| **utils**            | Utilities — a11y helpers, keyboard navigation, date, sorting, selection, validation, sanitization, touch gestures                                                     |
| **styles**           | CSS tokens, layout styles, and utility classes                                                                                                                        |
| **react/primitives** | React primitives — code-viewer (CodeMirror 6 read-only viewer with syntax highlighting for YARA, YARAL, FluxL, SQL, YAML, JSON, Python, JS/TS, Rust, Markdown, Shell) |
| **react**            | React-specific wrappers, theme toggle, brand, topology, threat visuals                                                                                                |

## Auth Token Storage

`createAuthManager()` supports pluggable token storage via `tokenStorage`.
Prefer server-managed HttpOnly/Secure/SameSite cookies or `createMemoryTokenStorage()` for production flows.
The default `localStorage` storage remains available for compatibility and development, but it increases the impact of any XSS in a host app.

## Map Tile Privacy

`ThreatMap` uses OpenStreetMap tiles by default.
Sensitive deployments should pass a first-party/proxied `tileUrl`, or set `allowExternalTiles: false` to disable default third-party tile requests.

## Development

```bash
# Install dependencies
npm ci

# Build the library
npm run build

# Run all checks (typecheck + lint + format)
npm run check

# Run unit tests
npm test

# Run unit tests with coverage
npm run test:coverage

# Run linter
npm run lint

# Type check
npm run typecheck

# Format code
npm run format

# Check formatting without writing
npm run format:check

# Run Playwright e2e tests
npx playwright test

# Preview components in browser
npm run preview
```

## Releases

Releases are fully automated via conventional commits. See [docs/RELEASING.md](docs/RELEASING.md) for the complete runbook.

```mermaid
flowchart LR
    PR["PR merged to main"] --> CI["CI workflow"]
    CI -->|success| Release["Release workflow"]
    Release -->|on completion| Publish["Publish workflow"]
    Publish --> GPR["GitHub Packages"]
```

| Commit prefix                | Version bump                   |
| ---------------------------- | ------------------------------ |
| `feat:`                      | **minor** (0.1.0 &rarr; 0.2.0) |
| `fix:` / `perf:`             | **patch** (0.1.0 &rarr; 0.1.1) |
| `BREAKING CHANGE` / `feat!:` | **major** (0.1.0 &rarr; 1.0.0) |

## Architecture

This library provides two parallel implementations:

- **Vanilla TypeScript** — Imperative class-based API (`new Button(config)`), direct DOM manipulation, BEM CSS classes (`cmm-*`), manual lifecycle with `destroy()`
- **React** — Declarative functional components using Radix UI primitives, Tailwind CSS with CVA, hooks-based state

Both share:

- Design tokens (`src/styles/tokens.css`)
- Shared utilities (`src/utils/` — date, sorting, selection, a11y, keyboard, sanitization)
- Services (`src/services/` — API client, SSE, keybindings, router)
- Chart engine (canvas-based vanilla, React wraps it)
- Editor engine (CodeMirror 6, shared across both)

## Consumers

This library is consumed by:

- [`packages/threat-library`](https://github.com/countermeasure-platform/core) (core repo)
- [`crates/countermeasure-web`](https://github.com/countermeasure-platform/core) (core repo)
- [`apps/ui`](https://github.com/countermeasure-platform/countermeasure) (tenant-ui) — uses `CodeViewer` on the detection detail page for syntax-highlighted rule display

## TypeScript

Strict TypeScript 6.0+ configuration:

- `strict: true`
- `noUncheckedIndexedAccess: true`
- `exactOptionalPropertyTypes: true`
- `moduleResolution: "bundler"`
- `jsx: "react-jsx"`

## Documentation

| Document                             | Description                                       |
| ------------------------------------ | ------------------------------------------------- |
| [Architecture](docs/ARCHITECTURE.md) | Component map, design decisions, directory layout |
| [Releasing](docs/RELEASING.md)       | Release runbook — automated and manual flows      |
| [Changelog](docs/CHANGELOG.md)       | Version history                                   |
| [Contributing](CONTRIBUTING.md)      | Contribution workflow, code style, testing        |
| [Security](SECURITY.md)              | Vulnerability reporting policy                    |

## License

CounterMeasure Security Proprietary License. See [LICENSE](LICENSE).
