@countermeasure-platform/web-components
v1.3.9
Published
Shared web components for CounterMeasure applications - consolidates common frontend functionality across projects.
Readme
Install
npm install @countermeasure-platform/web-components --registry=https://npm.pkg.github.comConfigure 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
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:
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:
<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
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
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.
document.documentElement.dataset.theme = 'dark' // dark | light | monokai | glass
document.documentElement.dataset.accent = 'cyan' // cyan | violet | rose | emeraldDark 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:
// 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:
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:
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
# 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 previewReleases
Releases are fully automated via conventional commits. See docs/RELEASING.md for the complete runbook.
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 → 0.2.0) |
| fix: / perf: | patch (0.1.0 → 0.1.1) |
| BREAKING CHANGE / feat!: | major (0.1.0 → 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 withdestroy() - 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(core repo)crates/countermeasure-web(core repo)apps/ui(tenant-ui) — usesCodeVieweron the detection detail page for syntax-highlighted rule display
TypeScript
Strict TypeScript 6.0+ configuration:
strict: truenoUncheckedIndexedAccess: trueexactOptionalPropertyTypes: truemoduleResolution: "bundler"jsx: "react-jsx"
Documentation
| Document | Description | | ------------------------------------ | ------------------------------------------------- | | Architecture | Component map, design decisions, directory layout | | Releasing | Release runbook — automated and manual flows | | Changelog | Version history | | Contributing | Contribution workflow, code style, testing | | Security | Vulnerability reporting policy |
License
CounterMeasure Security Proprietary License. See LICENSE.
