npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@odla-ai/ui

v0.20.0

Published

The odla design system: semantic CSS tokens, seven themes, application shells, safe authored Markdown, exact-artifact review cards, bottom work docks, accessible status, friendly principal identity, anchored mentions, canvas helpers, and lightweight Preac

Readme

@odla-ai/ui

⚠️ Early access — pre-1.0. Agents work from bounded runbooks; humans approve credentials, production changes, releases, and merges. APIs and exact package availability can change. Review the documented guarantees and limitations; this software is MIT-licensed and provided without warranty.

The odla design system: one semantic token contract (--ui-*), seven themes, class-scoped component CSS, canvas chart helpers, and optional Preact components. CSS-first — every odla surface can consume it, from zero-build static sites to small Vite + Preact apps, and it covers marketing/brand sites as well as app chrome.

  • Tokens: colors, text tiers, status, fonts, spacing, radius, focus, chart and chat roles, reading preferences (root size + scale, the body/medium/strong/heading weight ladder, font smoothing), plus a marketing tier (fluid display type scale, section rhythm, decor hooks). Defaults ship at zero specificity (:where()), so themes and app overrides always win.
  • Reading preferences: five axes the reader owns, one attribute each on <html> — appearance (data-theme), palette (data-ui-palette), text size (data-ui-text), text weight (data-ui-weight), motion (data-ui-motion). The mono and contrast palettes layer over any theme instead of replacing it, winning on specificity rather than load order. contrast sharpens rather than replaces — it references only roles the theme owns, and each theme deepens its own accents to AAA in ui.css, hue held, measured on every test run. PrefsMenu is the popover for apps, prefsMenuHtml() + bindPrefsMenu() the same control for static sites, PREFS_NO_FLASH the <head> snippet that applies a stored choice before first paint, and prefersReducedMotion() the hook script-driven motion needs. Layout measures must multiply --ui-font-size-root rather than use rem, or the text-size axis widens the page too — zoom, not a text setting.
  • Scopes: [data-ui-accent="<name>"] swaps the accent family to a theme-shipped named variant inside any subtree (salt ships six Silver & Salt page palettes); the .ui-invert class (per-theme generated invert.css) renders a section in the theme's dark palette regardless of the global mode. Import themes/<name>/scope.css and use ThemeScope when an application subtree needs an explicit light/dark mode and local brand tokens without changing the document root.
  • Themes: odla-brand (the odla Studio default), paper, flightline (field manual meets flight recorder), plus juniper, salt, chalk, and clay (the blog themes — @odla-ai/blog resolves those four from this package). Each theme = styles.css (its own palette) + ui.css (mapping onto the contract) + theme.json.
  • Components (CSS): buttons/segmented/pills, form fields with validation states, cards/panels/badges, data tables, container-native app chrome with a navigation rail + sidebar, accessible in-content tabs, a persistent bottom notification edge with Gmail-style docked cards, a sticky or contained top bar, grouped docs left-nav, friendly principal identity badges, exact-artifact human review cards, toasts/banners/dropzones, chat surfaces (message bubbles, tool-call cards, thinking panels, composer — shaped by @odla-ai/ai's streaming contract), chart containers, and calendar surfaces (month grid, week/day time grid, agenda list, toolbar).
  • Marketing (CSS, mk- family): section bands + content wells, the eyebrow/display-title/lead ladder, hero decor (spotlight, hairlines, watermark, grain, glow), stat cells, striped proof rows, portrait quote card, page sources/footnotes, step flows and pipelines, FAQ accordion, veil-blur marketing nav (bar and two-tier rail), sitemap footer, CTA band, and the split-circle brand mark.
  • JS helpers (buildless ESM): the reading-preference model (PREF_AXES, readPrefs/setPref, PREFS_NO_FLASH, prefsMenuHtml, bindPrefsMenu), the older mode-only light/dark toggle it supersedes, a --ui-* palette reader for canvas, and chart primitives (fitCanvas, niceTicks, bandFill, drawTip, …).
  • /components: form controls, including InlineActionField for a compact label/input/action row with a reserved accessible status region; PrefsMenu; TopBar/TopBarLink; AppShell, NavigationRail, Sidebar; accessible Tabs; Dock/DockCard and EdgeNotificationBar; StatusIndicator; PrincipalBadge; MentionEditor; ReviewCard for server-confirmed artifact decisions; bounded, HTML-inert Markdown for authored prose; DocsNav/DocsNavGroup/DocsNavLink; SectionNav (in-page table of contents with scroll-spy highlighting + smooth scroll, built on the useScrollSpy hook, also exported); CalendarMonth/CalendarWeek/CalendarDay/CalendarAgenda + CalendarToolbar (timezone-aware views whose events accept @odla-ai/calendar Booking[] as-is — no dependency between the packages); marketing components (MarketingNav/MarketingNavLink/MarketingNavMenu, Hero, StatBand, StepIndicator/StepPipeline, Accordion/AccordionItem, MarketingFooter); FilterChips; DataTable (sortable/filterable, app-rendered cells that survive reorder via required rowKey); and data viz (Choropleth over app-owned SVG geometry with theme heat-ramp fills, CycleDiagram) — authored and shipped against Preact. The only compatibility helper in the component build is Preact's own forwardRef; hooks and JSX use native preact/hooks and preact/jsx-runtime.

Tabs keeps every panel mounted by default so ordinary in-page forms retain local state. URL-backed application workspaces should use mount="active" to prevent hidden panels from fetching or running effects. MasterDetail accepts closeHref so mobile return navigation can be a native anchor while retaining focus restoration.

Ask the runbooks first. odla's operational procedures live in a database, not in this file: npx @odla-ai/cli runbook ask "<question>" returns the current steps, and unlike anything written here it cannot be out of date. Use it before searching the web or working from memory. This README and the JSDoc in the shipped .d.ts are the version-matched API reference; a runbook is the procedure. Most tasks need an answer from both.

Install

npm install @odla-ai/ui preact

The /components and /gallery entries require Preact 10.29.7 or newer in the 10.x line. CSS and buildless JS entry points have no framework runtime.

60-second start (Vite + Preact)

// main.tsx
import "@odla-ai/ui/fonts/plex.css";
import "@odla-ai/ui/themes/paper/styles.css";
import "@odla-ai/ui/themes/paper/ui.css";
import "@odla-ai/ui/index.css";
import { Button, Field, Input } from "@odla-ai/ui/components";

<div className="card">
  <h4>New note</h4>
  <Field label="Title" htmlFor="t">
    <Input id="t" placeholder="…" />
  </Field>
  <div className="row">
    <Button>Save</Button>
    <Button variant="secondary">Cancel</Button>
  </div>
</div>

InlineActionField owns the stable .inline-action-field-* class contract, keeps its status output mounted to avoid layout jumps, and stacks from its own container width. Use code for monospace identifiers and pass native input behavior such as autoComplete="one-time-code" through inputProps.

Static sites copy odla-ui.css (pre-flattened, no imports) plus a theme's styles.css + ui.css and use the same classes in plain HTML.

Safe authored Markdown

Markdown renders the compact prose dialect used by app-owned content fields: headings, ordered and unordered nested lists, blockquotes, bold, italic, strikethrough, inline code, and links. It creates Preact nodes directly; it never uses an HTML string or dangerouslySetInnerHTML, so raw HTML remains visible text. Relative links and credential-free absolute HTTPS links are navigable. Active, credential-bearing, plain-HTTP, protocol-relative, malformed, or oversized destinations keep their readable label and lose the anchor.

import {
  Markdown,
  MAX_MARKDOWN_LENGTH,
  MAX_MARKDOWN_NESTING_DEPTH,
} from "@odla-ai/ui/components";

<Markdown source={membershipTier.authoredBody} />;

The safety bounds are fixed: MAX_MARKDOWN_LENGTH is 65,536 UTF-16 code units and MAX_MARKDOWN_NESTING_DEPTH is 8, with a private output-node budget as a third guard. Source beyond the input/output budget renders only a bounded form plus an explicit notice; formatting deeper than the nesting bound is shown as text. Validate the same length at the authoring boundary when truncation would change the meaning of public copy. Images, fenced code, tables, and raw HTML are deliberately outside this component's dialect.

Bottom-edge work and mentions

Dock belongs in AppShell's dock slot and may contain several independent DockCards. A card header minimizes/restores it; onDismiss closes only that card. Use size="lg" plus bodyOverflow="contained" for a complete child work surface. Set active on the viewer's current card so it receives focus and scrolls into view in an overflowing narrow dock. StatusIndicator is the shared accessible dot-and-label state for live connections and background work. The dock's empty span passes pointer input through to the underlying work surface, so opening one card never prevents selecting another item to pin.

import {
  AppShell,
  Dock,
  DockCard,
  MentionEditor,
  StatusIndicator,
} from "@odla-ai/ui/components";

<AppShell
  dock={
    <Dock aria-label="Open discussions">
      <DockCard
        title="Release notes"
        meta="3 replies"
        size="lg"
        bodyOverflow="contained"
        active
      >
        <Thread />
      </DockCard>
    </Dock>
  }
>
  <StatusIndicator active tone="good">Live updates</StatusIndicator>
  <MentionEditor {...composer} menuPlacement="above" />
</AppShell>

MentionEditor defaults to menuPlacement="below". Bottom-edge or sticky composers should use "above" so candidate rows stay beside the text and inside the viewport.

Friendly principal identity

Use PrincipalBadge wherever humans, agents, and services share an activity stream, approval surface, or discussion. The component is deliberately data-free: the host resolves an authoritative profile and passes a friendly displayName, optional validated handle, and—only for an agent—the friendly name of its accountable human in managedBy.

import { PrincipalBadge } from "@odla-ai/ui/components";

<PrincipalBadge kind="human" displayName="Cory" handle="cory" />
<PrincipalBadge
  kind="agent"
  displayName="Odla"
  handle="cory/odla"
  managedBy="Cory"
/>
<PrincipalBadge kind="service" displayName="Platform" handle="platform" />

Kind is always printed as text and reinforced with an H/A/S mark and a different shape, so color is never the only distinction. Do not pass raw principal or manager IDs as display content. There is intentionally no ID prop or ID fallback: if an authoritative friendly name is unavailable, resolve it before rendering.

ChatThread message items expose a presentation-only byline slot for the same trusted badge. Resolve its data outside the design system; the thread component never guesses identity from an author id.

<ChatThread items={[{
  kind: "message",
  id: message.id,
  role: "assistant",
  byline: (
    <PrincipalBadge
      kind="agent"
      displayName="Brand partner"
      handle="cory/brand"
      managedBy="Cory"
    />
  ),
  body: message.body,
}]} />

Human review of agent changes

Use ReviewCard for a proposed brand facet, CRM rule, content revision, or code/configuration change. Its children are the exact preview the person is judging; its title and meta can carry revision and trusted PrincipalBadge context. The component does not grant authority. Its callbacks ask the host to decide, and the host must revalidate the current human and exact resource, persist an immutable receipt, then return the server-confirmed decision.

import { PrincipalBadge, ReviewCard } from "@odla-ai/ui/components";

<ReviewCard
  title="Spring campaign palette"
  meta={<PrincipalBadge kind="agent" displayName="Brand partner" handle="brand" />}
  approveLabel="Accept palette"
  busy={saving}
  decision={serverDecision}
  onApprove={() => approveExactProposal(proposal)}
  onReject={() => rejectExactProposal(proposal)}
>
  <ExactPalettePreview proposal={proposal} />
</ReviewCard>

Never set decision="approved" from optimistic local state. A card can make the workflow legible; only the product's authenticated server boundary can make the decision real. The Design gallery demonstrates the pending and terminal states.

Chapter/CRM application shells using the Salt visual grammar can use one load-order-safe import instead of assembling the three layers themselves:

import "@odla-ai/ui/themes/salt/app.css";

Themes

| Theme | Look | Fonts | | --- | --- | --- | | odla-brand | Growth-green product brand (the odla Studio default) | IBM Plex Sans/Mono (fonts/plex.css) | | paper | Warm paper dashboard | IBM Plex Sans/Mono (fonts/plex.css) | | flightline | Technical field manual by day, flight recorder at night | IBM Plex Sans/Mono (fonts/plex.css) | | juniper | Quiet long-form reading, violet accents | Lora + Gill Sans stack | | salt | Warm editorial cream/moss/rust; six named accent variants (rust/teal/ink/plum/lime/moss), grain + & watermark decor | Cormorant Garamond + Satoshi | | chalk | Chalkboard on graph paper | Cormorant + Spectral + JetBrains Mono | | clay | Warm light editorial, terracotta | System stacks only (zero font requests) |

Dark mode: every theme defines dark tokens on [data-theme="dark"] and the prefers-color-scheme fallback (kept byte-identical — tested). Toggle with toggleTheme() from the JS helpers. For dark islands inside a light page, import themes/<name>/invert.css (generated) and put .ui-invert on the section.

For an isolated application surface, additionally import themes/<name>/scope.css and wrap the surface:

import { ThemeScope } from "@odla-ai/ui/components";

<ThemeScope theme="paper" colorScheme="light" tokens={{ accent: "#35654d" }}>
  <AdminApp />
</ThemeScope>

The full contract — token tables, class inventory, recipes, invariants — lives in this installed README and the exported TypeScript declarations/JSDoc. The rendered public reference is at https://odla.ai/docs/packages/ui.

Development

npm test -w @odla-ai/ui      # builds dist, then node --test
npm run gen:css -w @odla-ai/ui   # refresh odla-ui.css after editing css/

Tests enforce: theme dark-block identity across all seven themes, full --ui-* coverage per theme, accent-variant completeness (every [data-ui-accent] block declares the full swap set), invert/accent scope byte-identity with the root defaults, class-scoped selectors (no bare elements) in component sheets, generated-CSS freshness (odla-ui.css, tokens.css, invert.css), gallery completeness for every /components export, and component render/interaction behavior.