# @alfadocs/ui-kit

The AlfaDocs design system — React components, tokens, and translations.

> Released. Breaking changes land in majors and are called out in
> [CHANGELOG.md](./CHANGELOG.md).

## Install

```bash
npm install @alfadocs/ui-kit
```

Requires React 18+ and Node ≥ 22.6.

### Source maps (optional)

The default `@alfadocs/ui-kit` tarball ships without `.map` files to keep
installs small (4.6 MB tarball / 17.3 MB unpacked, against 9.5 MB / 36.8 MB
for the debug build). Browsers only request source maps on demand when
devtools is open, so end-users don't pay this cost regardless.

If you need symbolicated stack traces (Sentry / Rollbar uploads, in-browser
debugging of kit internals), install the `-debug` sibling instead. Both
packages are runtime-identical and version-locked:

```jsonc
// package.json — alias-install so imports still resolve as @alfadocs/ui-kit.
// Pin the exact version you already have installed, not a range: maps from a
// different release point at lines that have moved.
"@alfadocs/ui-kit": "npm:@alfadocs/ui-kit-debug@0.98.1"
```

Or as a separate dev-only dep if your error reporter accepts maps from a
sibling package.

Never commit the alias — it rewrites the lockfile, so `npm ci` would pull the
debug build into production images. See Storybook → "30. Debugging — Source
Maps and the Debug Package" for the full guide.

## Troubleshooting

### `npm install` fails with `ETARGET No matching version found for @alfadocs/ui-kit@<x.y.z>` — even though the version exists on npmjs.org

This almost always means your `~/.npmrc` (or a project-level `.npmrc`) has a
stale `@alfadocs:registry=` line pointing somewhere other than
`https://registry.npmjs.org/`. `@alfadocs/ui-kit` is published exclusively
to public npmjs.org from `0.1.0` onwards; the `@alfadocs` scope on GitHub
Packages only contains legacy `0.0.x` builds and is not maintained.

Earlier `0.1.x` bumps inside the same checkout can mask this — npm reuses
the resolved tarball URL from `package-lock.json` and never re-consults the
scope mapping. The first fresh resolve (a new minor, a clean checkout, a
`rm -rf node_modules`) is when the dead end surfaces.

**Fix.** Open `~/.npmrc` and remove any `@alfadocs:registry=…` line — or
set it to the npm default, which is redundant but harmless:

```
@alfadocs:registry=https://registry.npmjs.org/
```

Then re-run `npm install`.

**One-shot workaround** (if you can't edit your `.npmrc` right now):

```bash
npm install --@alfadocs:registry=https://registry.npmjs.org
```

## Usage

### Tokens

Import the design tokens once at your app root so the CSS custom
properties are available everywhere:

```ts
import '@alfadocs/ui-kit/tokens';
```

This full stylesheet includes all four third-party bridges. For an app that
uses only part of the kit, choose core and add the bridges its components need:

```ts
import '@alfadocs/ui-kit/styles/core.css';
import '@alfadocs/ui-kit/styles/ag-grid.css'; // DataTable
```

| Add after core                             | Components and patterns that need it                                                                                 |
| ------------------------------------------ | -------------------------------------------------------------------------------------------------------------------- |
| `@alfadocs/ui-kit/styles/ag-grid.css`      | `DataTable`, `PatientTable`, `FileManager` (list view), Heatmap's "View as table", and the calendar pattern's sheets |
| `@alfadocs/ui-kit/styles/redactor.css`     | `RichTextEditor` with the host's Redactor runtime, `NotesPanel`, `help-me-write-templates`                           |
| `@alfadocs/ui-kit/styles/fullcalendar.css` | `Calendar`, `CalendarWorkspace` and the calendar patterns                                                            |
| `@alfadocs/ui-kit/styles/apexcharts.css`   | `Chart`, `Sparkline`, and the anamnesis indicators, compare panel and evolution grid                                 |

Anything else that renders one of these components needs the same bridge.

Choose either `tokens` or core plus the required bridges. Core keeps all
tokens, themes, base rules, component utilities and kit font declarations.
Date pickers and booking components need no bridge. Vendor JavaScript and
optional peer dependencies are still installed or supplied as before.
Load core first so it establishes the CSS layer order. If copying built
stylesheets, keep them beside the `fonts/` directory, as with `tokens.css`.

Then apply a theme class on the root element:

```html
<html class="theme-light">
  <!-- or theme-dark, optionally combined with theme-accessible -->
</html>
```

### Components

Each component is also available as its own subpath import for
narrower bundles:

```tsx
import { Button } from '@alfadocs/ui-kit/button';
import { Card } from '@alfadocs/ui-kit/card';

export function Example() {
  return (
    <Card>
      <Card.Body>
        <Button intent="primary">Save</Button>
      </Card.Body>
    </Card>
  );
}
```

Or import everything from the root entry:

```tsx
import { Button, Card } from '@alfadocs/ui-kit';
```

### i18n

The kit ships with `react-i18next` pre-configured and locale bundles
in `dist/locales/`:

```ts
import i18n from '@alfadocs/ui-kit/i18n';
import en from '@alfadocs/ui-kit/locales/en.json';

i18n.addResourceBundle('en', 'ui', en);
```

## Host integration

The kit's dismissable primitives — `Dialog`, `Popover`, `DropdownMenu`,
`Tooltip`, `Select`, `ContextMenu`, `NavigationMenu`, `AlertDialog` —
all build on Radix's `@radix-ui/react-dismissable-layer`, which attaches
a bubble-phase `pointerdown` listener on `document` to detect outside
clicks. Consuming applications **must not** register a capture-phase
`document` (or `body`) listener that calls `event.stopPropagation()` on
`pointerdown` / `mousedown` / `click` — capture-phase consumers run
BEFORE Radix's detector and starve it, leaving overlays stuck open.

```js
// Will break every dismissable primitive in the kit
document.addEventListener('pointerdown', (e) => e.stopPropagation(), true);
```

If a legacy script must intercept pointer events at `document` level
(jQuery plugins, Bootstrap modals, in-house global menu handlers, etc.):

- Scope the listener to a specific container instead of `document` / `body`.
- Drop the `useCapture: true` flag — bubble-phase listeners fire AFTER Radix and don't interfere.
- Drop the `stopPropagation()` call entirely if it isn't load-bearing.

Each dismissable component's Storybook page carries a `WithHostInterference`
story that reproduces the failure mode for diagnosis.

## Peer dependencies

`react`, `react-dom`, `react-i18next`, `i18next`. Tailwind CSS is not
required to consume the kit — components ship pre-styled, and the
tokens stylesheet exposes CSS custom properties you can reference from
your own styles.

## License

[Business Source License 1.1](./LICENSE) — production use is
permitted; offering the Licensed Work, or a substantial portion of it,
as a competing hosted, embedded, or rebranded design-system or
component-library product is not. The Licensed Work converts to the
Apache License 2.0 on the Change Date specified in the LICENSE.

For commercial licensing arrangements outside the BUSL grant, contact
AlfaDocs GmbH.
