# @regna-verkt/ui

Embeddable React widgets: financial data, ownership records, and news for companies across Sweden, Norway, Finland, Denmark, the United Kingdom, and the United States.

> **v0.x — pre-stable.** Pin tightly. Minor bumps may include breaking changes until v1.0.

## Installation

```bash
npm install @regna-verkt/ui
```

Peer dependencies: `react ^18 || ^19`, `react-dom ^18 || ^19`.

## Quick start

The customer-facing data widgets (`CompanyCard`, `FinancialsTable`, `NewsFeed`, `OwnershipChart`, `HealthScore`, `CompanyValuation`, `SimilarCompanies`, `ChatBot`, `FloatingChatBot`) take `publishableKey` + `companyId` directly:

```tsx
import { CompanyCard, FinancialsTable } from '@regna-verkt/ui'
import '@regna-verkt/ui/theme.css'

export function App() {
  const publishableKey = 'rk_public_...' // from regnaverkt.com/dashboard/keys/
  return (
    <>
      <CompanyCard publishableKey={publishableKey} companyId="5591234567" />
      <FinancialsTable publishableKey={publishableKey} companyId="5591234567" />
    </>
  )
}
```

The chart / financial-summary components (`CompanyOverview`, `FinancialChart`, etc.) compose with `<RegnaProvider>` for shared theme / tier / render-mode, then take typed data props directly:

```tsx
import { RegnaProvider, FinancialChart, type AnnualFinancials } from '@regna-verkt/ui'
import '@regna-verkt/ui/theme.css'

export function App({ data }: { data: AnnualFinancials[] }) {
  return (
    <RegnaProvider publishableKey="rk_public_..." theme="light">
      <FinancialChart data={data} />
    </RegnaProvider>
  )
}
```

Get a publishable key from the [Regna dashboard](https://regnaverkt.com/dashboard/keys/). Publishable keys (`rk_public_*`) are browser-safe — they're bound to a domain allowlist on the server, so leaking them off your domain doesn't burn quota.

## Local development

The production API rejects `http://localhost` and `http://127.0.0.1` origins (no exception for unverified hosts). Two ways to develop against it from your laptop:

- **For prototyping or Storybook**: pass `publishableKey="demo-key"` and the server short-circuits to mock data (Option 1 below). No account needed; works from any origin.
- **For real data**: expose your dev server over a reverse tunnel and add the tunnel's public hostname to your publishable key's allowlist (Option 2). Requires a real `rk_public_*` key.

In every example below, `5173` is the dev-server port (Vite default). Substitute your own (`3000` for Next.js / CRA, `6006` for Storybook, `4321` for Astro, etc.).

### Option 1: prototype with the `demo-key` sentinel

```tsx
<CompanyCard publishableKey="demo-key" companyId="5591234567" />
```

The server recognises the literal string `"demo-key"` and returns demo data. Use this for Storybook, design-tool exports, and any flow where mock data is fine.

### Option 2: tunnel your dev server (real account, real data)

Run a reverse tunnel so your dev server is reachable on a public HTTPS hostname, then add that hostname to your publishable key's allowlist.

**ngrok** (no account needed for the free tier):

```bash
# Terminal 1: your dev server.
npm run dev    # serves http://localhost:5173

# Terminal 2:
ngrok http 5173
# -> Forwarding  https://abc123.ngrok-free.app -> http://localhost:5173
```

Then on [regnaverkt.com/dashboard/keys/](https://regnaverkt.com/dashboard/keys/) add `abc123.ngrok-free.app` to the allowlist of your `rk_public_*` key. Open the ngrok URL in your browser (not `localhost:5173`) and the widgets will fetch through fine.

The free ngrok tier rotates the subdomain on every restart; update the allowlist or upgrade to a static domain (paid).

**Cloudflare Tunnel** (free, no account required for quick tunnels):

```bash
cloudflared tunnel --url http://localhost:5173
```

Returns an ephemeral `https://<random>.trycloudflare.com` URL. If you already have a Cloudflare-managed zone, you can also wire a stable custom subdomain. Stable across restarts when you do; set it once in the allowlist and forget.

**localtunnel** (zero install, npx):

```bash
npx localtunnel --port 5173
```

Random `*.loca.lt` subdomain.

**Tailscale Funnel** (if you are already on Tailscale):

```bash
tailscale serve / http://localhost:5173
tailscale funnel 443 on
```

Stable `*.ts.net` URL.

### Why not just `localhost` in the allowlist?

The dashboard's allowlist validator requires a public DNS pattern (each entry must be a hostname with at least one dot, optionally prefixed by `*.` for subdomain wildcards). The bare string `localhost` is rejected at create time. Even if it were accepted, the production API does not honor `http://localhost` origins on prod, so the request would still fail at auth time.

The tunnel option above sidesteps both checks. The widgets always make HTTPS requests from a real domain that is in your allowlist - same code path you will ship to prod.

## Documentation

- **Live demo** — [demo.regnaverkt.com](https://demo.regnaverkt.com) — every component rendered against real data
- **Storybook** — [storybook.regnaverkt.com](https://storybook.regnaverkt.com) — props, variants, copy-pasteable code
- **API docs** — [regnaverkt.com/api/docs/](https://regnaverkt.com/api/docs/) — the underlying REST surface

## What's in the package

| Surface | What it is | Import |
|---------|-----------|--------|
| **React widgets** | `CompanyCard`, `FinancialsTable`, `NewsFeed`, `OwnershipChart`, `HealthScore`, `CompanyValuation`, `SimilarCompanies`, `ChatBot`, `FloatingChatBot` | `import { CompanyCard } from '@regna-verkt/ui'` |
| **Charts & summaries** | `CompanyOverview`, `FinancialSummary`, `FinancialChart`, `BalanceSheet`, `PeerComparison`, `ChangeFeed`, `PriceHero`, `OrderBook`, `KeyStats`, `EventsCalendar`, `RecentTrades`, `PriceChart`, `CandlestickChart`, `FinancialAreaChart`, `WaterfallChart`, `FinancialRadarChart`, `BudgetVsActuals`, `PricingSimulator`, `InactiveTombstone` | `import { FinancialChart } from '@regna-verkt/ui'` |
| **Provider** | `RegnaProvider`, `useRegnaContext`, `useRegnaClient`, `useRegnaRenderMode` | `import { RegnaProvider } from '@regna-verkt/ui'` |
| **Hooks** | `useCompany`, `useFinancials`, `useChangelog`, `usePeers` | `import { useCompany } from '@regna-verkt/ui'` |
| **Theme** | Single global stylesheet | `import '@regna-verkt/ui/theme.css'` |
| **i18n** | Swedish, English, Norwegian | `import { LocaleProvider } from '@regna-verkt/ui'` |
| **Key guards** | Client-side `rk_public_*` / `rk_secret_*` enforcement | `import { detectKeyKind, assertClientSafeKey } from '@regna-verkt/ui'` |

The data widgets accept a `locale` prop directly (`locale="sv"` etc.). Chart components read `locale` from `<RegnaProvider>` context — wrapping data widgets in `<LocaleProvider>` has no effect; pass them `locale` instead.

## Integration modes

Three ways to keep keys out of your browser bundle:

1. **Publishable key** (default) — `rk_public_*` with a domain allowlist; safe to ship in JS.
2. **Session token** — exchange an `rk_secret_*` for a 15-min scoped JWT (for the `<ChatBot />` endpoint).
3. **Proxy mode** — `<RegnaProvider proxyBaseUrl={...}>` routes calls through a customer-owned proxy that injects the secret server-side.

For proxy reference implementations (Cloudflare Workers, Vercel Edge, Node/Express) and a deeper comparison of the three modes, email [support@regnaverkt.com](mailto:support@regnaverkt.com).

## TypeScript

Types ship with the package — no `@types/*` install required.

## Non-React hosts

`@regna-verkt/ui` is React-only. To embed in a non-React page, mount a small React island:

```ts
import { createRoot } from 'react-dom/client'
import { CompanyCard } from '@regna-verkt/ui'
import '@regna-verkt/ui/theme.css'

createRoot(document.querySelector('#regna-card')!).render(
  <CompanyCard publishableKey="rk_public_..." companyId="5591234567" />
)
```

## Migrating from `@regna-verkt/widgets` or `@regna-verkt/elements`

Swap the package name to `@regna-verkt/ui`; previous exports are available under the same names. For the full diff, email [support@regnaverkt.com](mailto:support@regnaverkt.com).

## Support

Email [support@regnaverkt.com](mailto:support@regnaverkt.com) for bug reports, feature requests, integration help, and security disclosures.

## License

[MIT](https://opensource.org/licenses/MIT).
