# Changelog — @regna-verkt/ui

All notable changes to `@regna-verkt/ui` are documented here.
This package follows [Semantic Versioning](https://semver.org/) starting at v1.0.0.
While in v0.x, **minor bumps may include breaking changes** — pin tightly until v1.0.

> **Note on the missing `0.2.0`.** A `0.2.0` tarball appeared on npm on
> 2026-05-01 from a stray publish off a deleted branch with no matching
> main commit. It does not represent a real release of this codebase
> and has been deprecated on the registry with a redirect-to-`0.2.1`
> message. The `0.x` line skips from `0.1.5` to `0.2.1`.

## 0.2.4 - 2026-05-14

### Changed (metadata only - no code change)

- **README scope** rewritten to reflect the multi-market reality: the
  package now covers listed AND private companies across SE, NO, FI, DK,
  UK, US (previously the description still read "Swedish companies"
  from the pre-v2 codebase). Added a mention of the MCP server surface
  alongside the REST API + React component library.
- **`package.json` `description`** rewritten to match.
- **`package.json` `keywords`** expanded from 8 to 35 entries: added
  country tags (sweden / norway / finland / denmark / united-kingdom /
  united-states / nordic), regulator-source tags (bolagsverket /
  companies-house / brreg / prh / cvr / edgar / ixbrl / 10-k),
  data-shape tags (annual-reports / quarterly-reports / ownership-data /
  fundamental-data / news-feed), audience tags (investing / fintech /
  mcp / ai-agents), and tightened the existing ones. Dropped
  `swedish-companies` (replaced by the more accurate set above).
- **README License link** now points to the canonical MIT licence text
  at <https://opensource.org/licenses/MIT> instead of the local
  `./LICENSE` file (the local file is still there, but the canonical
  link is what npmjs.com readers expect).

No source-code or behavioural change in this release. Re-published to
push the updated README + keywords onto the npmjs.com listing.

## 0.2.3 - 2026-05-14

### Changed

- **recharts upgraded 2.15.4 -> 3.7.0** (PR #433). Major bump of the
  chart library. The public widget surface does not change (component
  props, render output, exported types are identical), so this is a
  patch from the SDK consumer's perspective. Transitive note: if your
  app pins recharts directly, you may want to align with 3.x to avoid
  two copies in the bundle.

### Fixed

- **Tooltip formatter callbacks now accept `value: number | undefined`
  and `name: string | undefined`** across all six chart components
  (PR #449). recharts 3 widened the `Formatter<number, string>` type
  signature; the SDK's chart components used narrowed callbacks that
  broke against `tsc --noEmit`. Patched files: `PriceChart` (two
  formatters), `RadarChart`, `WaterfallChart`, `FinancialChart`,
  `OwnershipChart`, `AreaChart`.

  Behaviour on `undefined` data points (e.g. sparse `connectNulls`
  overlays): the formatter returns an empty string for the value cell
  instead of crashing. `WaterfallChart` returns `[null, null]` to skip
  the row entirely (matches its existing `'base'`-bar behaviour).

### Why this matters

Without #449 the package was not releasable (typecheck red). The fix
unblocks every consumer using recharts 3 in their own tree and prevents
silent runtime breakage if recharts decides to pass `undefined` on
sparse-data overlays in a future minor.

## 0.2.2 - 2026-05-08

### Added

- **localStorage persistence on the widget data cache (issue #260)**.
  The module-level `dedupedRequest` cache from PR #250 now also writes
  resolved values to `localStorage` under the `regna-widgets:v1:*` key
  prefix, so a tab revisit or full page reload reuses the persisted
  envelope instead of refiring every widget endpoint. The cache key is
  fingerprinted by the same `keyParts` array the in-memory layer uses
  (which includes the `publishableKey`), so per-key isolation per OWASP
  A07 stays intact and two providers in the same realm with different
  keys never share results. The persistence layer survives:
  - SSR / no-window environments (silent skip; no throw).
  - `localStorage` quota exceeded (catches `DOMException`, evicts the
    oldest envelope under the regna prefix, retries; gives up
    gracefully if eviction does not free enough space; in-memory cache
    still serves).
  - Errors (a failed fetch does NOT poison `localStorage`; the next
    caller retries against the network).
  - Older browsers / private-mode `localStorage` stubs that throw on
    every operation (sniffed via probe call; treated as no-storage).

  Resolves issue #260: bare-mounted widgets (the `app/` partner-demos
  SPA mounts widgets without `<RegnaProvider>`) now get a real cache.
  PR #252's `<SWRConfig>` approach was reverted in #259 because it only
  installed inside the provider; this layer works for both bare mounts
  and provider-wrapped consumers.

### Why this matters

Live UAT on `https://demo.regnaverkt.com/` previously showed every tab
revisit re-firing every endpoint and `/companies/X/financials` plus
`/companies/X/analysis` doubling on first paint. PR #250's in-flight
dedup collapses the same-paint duplication; this release closes the
across-reload gap. Customer quota usage drops materially without any
SDK consumer code change (cache is automatic).

## 0.2.1 - 2026-05-08

### Removed (breaking - pre-launch surface)

- **`revenueSek` field across the SDK return shapes** - the SDK methods
  that surface revenue rows have been renamed end to end. Specifically,
  `RegnaClient.getFinancials(...)` now returns `AnnualRow` items with
  `revenue: number | null` and `currency: string` (ISO 4217), and
  `RegnaClient.getFeaturedCompanies()` returns items with the same
  `(revenue, currency)` pair, both replacing the previous
  `revenueSek: number | null`. `RegnaClient.getCompany(...)` and
  `RegnaClient.getSimilar(...)` did not carry `revenueSek` and are
  unchanged at the type level. The rename is paired with a schema
  migration on the server side (Django billing migration
  `0025_drop_revenue_sek`) so the per-row currency column is the source
  of truth, no longer hardcoded SEK. Migrate consumer code with:
  `revenueSek` -> `revenue`; emit `currency` next to every revenue
  render.

### Added

- **`PreviewBadge` component and preview-mode awareness on every widget**
  (#267). Widgets that detect `useRegnaRenderMode() === 'preview'` now
  surface a clear `Preview only - no live data` overlay instead of
  silently rendering mock data. Removes a category of "did the demo
  hit prod?" confusion in partner sandbox embeds.
- **`useRegnaClient()` routing** — every widget reads its API client from
  the provider context rather than reaching for the module-level
  singleton, so a downstream Vite consumer can hot-swap the client per
  test or per route (#267).
- **Currency-aware widget formatting** — `FinancialsTable`,
  `CompanyValuation`, `HealthScore`, `OwnershipChart`, `SimilarCompanies`,
  `CompanyCard`, `NewsFeed`, `BalanceSheet`, `WaterfallChart` all read
  `currency` off the row and pick the matching number-format locale
  per ISO 4217. Previously every value was rendered as SEK regardless of
  source country (#270).
- **`format-currency.test.ts` (203 LoC) and `widget-preview-mode.test.tsx`
  / `widget-routing.test.tsx`** test suites covering the additions above.

### Fixed

- **PostHog snippet now consent-gated** (#262) — the snippet only loads
  after the user accepts the `regna_cookie_consent` cookie, addressing
  GDPR consent-before-tracking obligation.
- **PostHog `posthog.init` no longer fires synchronously during render**
  (#258) — moved to a `useEffect`, fixing a hydration race that broke
  the marketing hero on first paint.
- **PostHog assets CDN unblocked and SPA navigation tracked** (#254).
- **Widget API requests deduplicated** so SDK consumers do not burn
  quota on duplicate `getCompany`/`getFinancials` calls in the same
  render pass (#250).
- **Reverted SWR + localStorage cache** (PR #259 reverts #252) - the
  cache layer turned out not to be active in production and added
  surface area without benefit.

### Why this matters

The `revenueSek` rename is the breaking change in this release - it lets
US, NO, FI, DK, GB consumers see real revenue figures in their reporting
currency rather than getting a `null` because the field name implied
Sweden-only data. Pin to `0.2.1` exactly, then bump to a future minor
once the rest of the call-site migration cleans up locally.

## 0.1.5 — 2026-04-28

### Added

- **`@regna-verkt/ui/hooks` subpath export** — the four data hooks
  (`useCompany`, `useFinancials`, `useChangelog`, `usePeers`) are now
  importable from a dedicated subpath in addition to the package root.
  Downstream Vite consumers were hitting

  > [plugin:builtin:vite-resolve] "./hooks" is not exported under the
  > conditions \["module", "browser", "development", "import"\] from
  > package @regna-verkt/ui

  because the `exports` map didn't list the path. The build now emits
  a separate `dist/regna-ui-hooks.{js,cjs}` bundle and `./hooks` is
  wired up in `package.json`. Both spellings work:

  ```ts
  import { useCompany } from '@regna-verkt/ui'
  import { useCompany } from '@regna-verkt/ui/hooks'   // now valid
  ```

### Changed (dev-surface only — not in the published tarball)

- **Storybook story labels** — six stories that still referenced the
  retired "Free Tier" / "Paid Tier" vocabulary were renamed to describe
  the data slice they showcase ("Limited History (2 Years)", "Full
  Period", "No Preview Badge", etc.). The `Limited History (2 Years)`
  stories now slice `mockAnnualFinancials` to two entries so the
  rendered chart matches the label.

## 0.1.4 — 2026-04-27

### Removed (breaking — pre-launch surface)

- **`tier` prop** — every component (19 files) had an unused
  `tier?: Tier` parameter that was already accepted-and-ignored
  (`tier: _tier`). The tier system never went live, so the prop
  added type-surface noise without any runtime effect. Drop it
  from your component callsites; nothing else changes.
- **`Tier` type** — removed from the type barrel. If you typed any
  variable as `Tier` (free / paid), inline the union or drop it.
- **`useRegnaTier()` hook** — removed. Use `useRegnaRenderMode()`
  if you need to branch on `'preview' | 'active' | 'inactive'`.
- **`FREE_TIER_LIMITS` constant** — removed (the free tier itself
  was retired in 0007; the constants weren't gating anything).
- **`apiKey` prop on `<RegnaProvider>`** — the `@deprecated` alias
  for `publishableKey` is gone. Rename `apiKey={…}` to
  `publishableKey={…}` on every callsite.
- **`apiKey` field on the `RegnaConfig` type** — renamed to
  `publishableKey` for consistency with the prop name.

### Why

> "we never launched before" — the tier scaffolding and the
> `apiKey` deprecation alias were both speculative pre-launch
> surface. The `apiKey` JSDoc previously promised "Accepted until
> @regna-verkt/ui v4", but no external consumer ever pinned
> against that promise — the package's first npm publish was
> 0.1.0 on 2026-04-27 (this same day). With zero shipped
> consumers on `apiKey`, removing it now (vs at v4) costs nothing
> and keeps the v0.x surface tight.

This bump strips back to the surface that's actually
load-bearing: `publishableKey`, `RegnaProvider`,
`useRegnaRenderMode`, the components themselves.

The render-mode tests are renamed and rewritten to use
`publishableKey` throughout; the legacy-`apiKey`-with-warn test is
deleted.

## 0.1.3 — 2026-04-27

### Added

- **`devMode` prop on `<RegnaProvider>`** — dev-loop shortcut for the
  regna-api / regna-ui maintainers. `devMode={true}` routes every
  request to `http://localhost:8765/api/v1` (Django runserver default);
  `devMode="https://staging.example/v1"` uses the verbatim URL.
  Resolution: `proxyBaseUrl` (existing prod escape hatch) wins over
  `devMode`, which wins over `baseUrl`. Logs a one-time `console.warn`
  so a build that ships with `devMode` active is loud, not silent.
- **`VITE_REGNA_DEV_MODE=1` env-var shortcut** in `widget-config.ts`
  for the `RegnaClient` functional API path used by the demo and
  Storybook. Defaults to `http://localhost:8765/api/v1` without
  requiring the full `VITE_REGNA_API_URL` URL. Resolution chain
  documented in `app/.env.local.example`.

### Why

- Avoids the publish-and-test loop when iterating on the regna-api
  endpoints — the in-package `RegnaProvider` and the `RegnaClient`
  functional path can both flip to localhost without rebuilding or
  republishing the npm package.

## 0.1.2 — 2026-04-27

### Removed

- **`PoweredByBadge`** — deleted from the package surface, all 17
  component use-sites, the barrel export, the i18n `poweredBy.label`
  string in en/sv/no, the `badgeWrapper` style helper, and the
  render-mode test block. The free tier was retired in 0007 (Basic
  99 kr/mo replaced free), so the badge — which only rendered in
  preview mode — no longer carried product weight. Consumers that
  imported `PoweredByBadge` from the barrel will see a TypeScript /
  bundler error and should drop the import.

## 0.1.1 — 2026-04-27

### Fixed

- **Chart colors missing** — `theme/variables.css` (the `.regna {
  --regna-chart-1..5, --regna-bg, --regna-accent, … }` palette) was
  orphaned from the lib entry, so the published `dist/assets/ui.css`
  shipped with zero `--regna-*` variables. Every chart stroke and card
  background resolved to an empty value, leaving Recharts components
  colorless. Fixed by importing `./theme/variables.css` from
  `src/index.ts` so the global theme is bundled into the CSS chunk via
  the existing `sideEffects: ["**/*.css"]` allowlist.

## 0.1.0 — First publish to npm

### Added

- **First publish** to the public npm registry under the `@regna-verkt` scope.
  Previously the package existed only in source — Eqvor and other consumers
  could not `npm install @regna-verkt/ui` until this release.
- **Unified package surface** — all React components, provider, hooks, key
  guards, i18n, and theme are now exported from a single `@regna-verkt/ui`
  package. Previous `@regna-verkt/widgets` and `@regna-verkt/elements`
  source-only packages have been folded in.
- **20 chart / financial summary components** (from the v1.0 origin):
  CompanyOverview, FinancialSummary, FinancialChart, BalanceSheet, PeerComparison,
  ChangeFeed, PriceHero, OrderBook, KeyStats, EventsCalendar, RecentTrades,
  PriceChart, CandlestickChart, FinancialAreaChart, WaterfallChart,
  FinancialRadarChart, BudgetVsActuals, PricingSimulator, PoweredByBadge,
  InactiveTombstone.
- **9 customer-facing data widgets** (from `@regna-verkt/widgets`):
  CompanyCard, FinancialsTable, NewsFeed, OwnershipChart, HealthScore,
  CompanyValuation, SimilarCompanies, ChatBot, FloatingChatBot.
- **`RegnaProvider`** with `publishableKey` + `theme` + `proxyBaseUrl` props.
  `apiKey` is accepted as a deprecation-warning alias until v4.
- **Key guards** — `detectKeyKind`, `assertClientSafeKey`, `envIsDev` exported
  from the root for callers who want to enforce the publishable/secret split
  in their own code paths.
- **Hooks** — `useCompany`, `useFinancials`, `useChangelog`, `usePeers`.
- **i18n** — `LocaleProvider`, `useLocale`, `translate`, `LOCALES`,
  `DEFAULT_LOCALE`, `formatShortNumber`, `localeNumberFormat` for `'en' | 'sv' | 'no'`.
- **API clients** — `RegnaApiClient` (canonical, used by the Provider) and
  `RegnaClient` (functional API surface from the absorbed widgets package; both
  shipped to avoid breaking existing consumers).
- **Auto-generated API contract types** under the `./generated/api-types`
  surface — re-exported via `export type *` from the root barrel. Regenerate
  with `uv run python -m api.contracts.generate_widget_types`.

### Build & packaging

- Vite single-entry library build (ESM+CJS) externalising `react`,
  `react-dom`, `recharts`.
- Correct `exports` map with `types` first in each conditional, `default`
  fallback, separate `import`/`require` resolution.
- `peerDependencies` for `react` and `react-dom` (^18 || ^19); `recharts`
  in `dependencies` so installers don't need to add it manually, but
  externalised in the bundle so host apps with their own copy don't ship two.
- `sideEffects` allowlist for CSS Modules so the React surface tree-shakes
  cleanly while CSS imports survive.
- Single global stylesheet at `@regna-verkt/ui/theme.css` (~12 KB minified).
- Release pipeline: tag-driven GitHub Actions workflow with `publint`,
  `arethetypeswrong --pack`, and a pack-and-test smoke install as gating
  steps before `npm publish`.

### Removed

- `@regna-verkt/widgets` — folded into this package. Users on the source-only
  v1.0 should migrate import paths to `@regna-verkt/ui`. See
  [`docs/migrate-to-unified-ui-package.md`](../../docs/migrate-to-unified-ui-package.md).
- `@regna-verkt/elements` — folded into this package, then **descoped from
  v0.1**. The Web Components / `<regna-*>` custom-element surface is no
  longer shipped. Non-React embedding is a v3+ direction via a vanilla-JS
  `RegnaWidgets.mount('#node', { … })` API; the current React + Vite-bundle
  path covers the only consumer (Eqvor).
- Duplicate `key-guards.ts` between widgets and regna-ui — single source of
  truth at `provider/key-guards.ts`.

### Migration

If your code imported from `@regna-verkt/widgets`, swap the package name to
`@regna-verkt/ui` — all previous exports are available under the same names.

If your code imported from `@regna-verkt/elements` or referenced `<regna-*>`
custom elements, those are no longer published. Mount a small React island
(`createRoot` + the corresponding component from `@regna-verkt/ui`) instead;
see [`docs/migrate-to-unified-ui-package.md`](../../docs/migrate-to-unified-ui-package.md).
