libraryPackage manifestv14.0.6

lib.design-system

Design tokens and theming primitives

@lssm-tech/lib.design-system
Source, release and verification context

Source snapshot bcc79fcc · Declared package version 14.0.6. This page combines the checked-in package guide and manifest; commands and runtime behavior were not executed in this review.

Package source ↗ Manifest ↗
webreact-nativeservernodebrowser
EXPLORE THE PACKAGE

See where this package fits.

Follow a declared connection, inspect an import, then open the source guide when you need the detail.

THIS PACKAGElib.design-systemplatform

Arrows point from a package to its direct dependency. Each count is derived from the captured manifests.

25 declarations · first 6 shownSELECT TO INSPECT

@lssm-tech/lib.design-system

@lssm-tech/lib.design-system provides higher-level design-system components, tokens, platform adapters, renderers, and composed layouts used across web, native, marketing, legal, agent, and application surfaces.

Website: https://contractspec.io

Native routing hosts support Expo Router ~57.0.11, including the workspace-tested 57.0.20 patch. This remains an optional native peer.

Installation

bun add @lssm-tech/lib.design-system

or

npm install @lssm-tech/lib.design-system

What belongs here

This package owns the higher-level design-system layer:

  • Theme tokens and token bridging.
  • Platform helpers and responsive hooks.
  • Renderers and form-contract integration.
  • Higher-level atoms, molecules, organisms, templates, and visualization components.
  • Registry metadata and shadcn-style component registry support.

Use this package when you want the composed design-system layer. Do not use it when a lower-level primitive from ui-kit or ui-kit-web is enough.

Core workflows

Import a higher-level design-system component

ts
import { AppLayout, Button, HeroSection } from "@lssm-tech/lib.design-system";

Work with tokens and platform helpers

ts
import {
  createTranslationResolver,
  defaultTokens,
  mapTokensForPlatform,
  resolvePlatformTheme,
  resolveThemeRefTokens,
  withPlatformUI,
} from "@lssm-tech/lib.design-system";

const nativeTokens = mapTokensForPlatform("native", defaultTokens);
const ui = withPlatformUI({
  tokens: defaultTokens,
  platform: "web",
});

Focused public subpaths are available when consumers do not need the full root barrel:

ts
import { themeSpecToTailwindPreset } from "@lssm-tech/lib.design-system/theme";
import { Select } from "@lssm-tech/lib.design-system/controls";
import { FormDialog } from "@lssm-tech/lib.design-system/forms";
import { HStack } from "@lssm-tech/lib.design-system/layout";
import { inputValue } from "@lssm-tech/lib.design-system/primitives";

Associate labels with controls

Use FieldLabel htmlFor="control-id" with a matching control id when the label and control are siblings. htmlFor may be omitted when exactly one labelable control is nested inside FieldLabel; native implicit label association is preserved for compatibility with composed control rows.

Choose layout primitives intentionally

Product surfaces should import shared layout primitives from @lssm-tech/lib.design-system/layout and make direction explicit:

  • Use VStack for vertical composition: page sections, card bodies, forms, lists, panels, and other columnar content.
  • Use HStack for horizontal composition: toolbars, chip rows, inline metrics, action rows, and label/value pairs.
  • Use Box only for neutral semantic wrappers, single-child surfaces, or explicit non-stack layout such as true grid, absolute positioning, or measured custom layout.

Do not use Box to express normal flex stack layout. Replace Box className="flex flex-col gap-4" with VStack gap="md" and replace Box className="flex flex-row items-center justify-between" with HStack align="center" justify="between". Prefer stack props over hiding gap, items-*, justify-*, flex-row, or flex-col in className.

Compatibility note: lower-level Box primitives are neutral by default. Legacy row/gap/center layout is available only through the temporary legacyBoxLayout bridge while owned callsites migrate. New design-system code must not introduce that bridge. Changes to Box, HStack, VStack, or the shared gap/align/justify/wrap contract must update the package docs and paired .changeset/*.release.yaml evidence.

Compose adaptive planning surfaces

Use AdaptiveToolbar for explicit presentation choices and reversible personalization actions. Use TimeRibbon for chronological, status-aware work items; it requires semantic item labels and preserves a readable list at narrow widths. ResponsiveInspector provides the matching desktop panel/mobile bottom inspector without owning selection or action authority. AdaptivePanel, Stepper, and StatusBadge provide explanation, setup-progress, and lifecycle-state primitives.

AdaptivePanel is the shared viewport-overlay boundary for drawers, sheets, centered dialogs, and fullscreen tasks. Its default adaptive mode preserves the familiar detail flow (mobile drawer, desktop sheet); intent="task" selects fullscreen on mobile and a dialog on desktop, while intent="immersive" stays fullscreen. mobileMode and desktopMode can override either side of the breakpoint. Keep anchored or nested preview flows on PreviewPanel and destructive confirmations on AlertDialog.

tsx
import { AdaptivePanel } from "@lssm-tech/lib.design-system/components/overlays/AdaptivePanel";

<AdaptivePanel
  open={open}
  onOpenChange={setOpen}
  intent="task"
  title="Edit customer"
>
  {form}
</AdaptivePanel>;

These components are presentation primitives. Consumers must resolve authority, policy, lifecycle state, and tenant scope before rendering them; density or layout personalization must never expose an action or surface that RoleMorph hides. Motion remains reduced-motion-safe and all copy stays consumer-owned so typed locale catalogs can supply en/fr/es text.

Editorial radius tokens

The ContractSpec editorial theme publishes an additive radius taxonomy from the contracts source of truth: scale keys xs/sm/md/lg/xl/full/default and semantic aliases control/card/panel/overlay/pill. Existing design-system RadiusTokens (sm/md/lg/xl/full) remain supported; resolved ThemeSpec radii also flow through the generic bridge as --ds-radius-* variables and Tailwind borderRadius entries.

Use smaller radii (xs/sm) for dense indicators, compact chips, and more precise or assertive affordances. Use md/control for standard controls. Use lg/card, default/panel, and xl/overlay for progressively softer editorial surfaces and lower-pressure reading contexts. Reserve full/pill for avatars, status dots, and explicit capsule forms.

Personalization and RoleMorph may later choose radius profiles by persona, tone, or density, but this pass is documentation-only: no runtime persona radius switching or action-boundary changes are implemented.

Motion, elevation, and density tokens

defaultTokens includes motion (durations in ms + easing as cubic-bezier control-point tuples), structured elevation (a web box-shadow string plus a React Native shadow object), and density (compact/comfortable spacing/size multipliers). They flow tokens.ts → web CSS vars (--ds-motion-* / --ds-elevation-* / --ds-density-*, surfaced as Tailwind transitionDuration / transitionTimingFunction / boxShadow utilities) → the native tokenBridge (which maps the RN shadow branch and keeps easing as numeric tuples — a CSS string is never pushed into RN style). dsBaseVariants tone and density variants are token-backed.

Animation is reduced-motion-first. Use the useMotion hook (@lssm-tech/lib.design-system/platform/useMotion, native: platform/useMotion.native); it returns a transition config gated by useReducedMotion, collapsing to an instant, no-displacement transition when the OS/user prefers reduced motion. Native skeletons (SkeletonBlock / SkeletonCircle / SkeletonList) animate via reanimated and fall back to a static view under reduced motion. Animation libraries are declared as split-by-lane peers — framer-motion (web, resolves via ui-kit-web) and optional react-native-reanimated / -gesture-handler / -svg (native).

Compose full-page marketing surfaces

Marketing page foundations live in the design system so product bundles can own story/content while sharing page structure. Use MarketingLandingPage for a typed section sequence, MarketingHero / MarketingCtaBand / MarketingProseSection / MarketingIconGridSection for reusable sections, MarketingPricingCalculator / MarketingPricingTable / MarketingFaqSection / MarketingTestimonialSection plus MarketingLeadCapture, MarketingFeatureTabs, MarketingTimeline, MarketingTrustBadges, MarketingVideo, and MarketingAnnouncementBar for rich prop-driven marketing blocks, and MarketingCtaRow / MarketingProofStrip for molecule-level pieces.

tsx
import { MarketingLandingPage } from "@lssm-tech/lib.design-system";

<MarketingLandingPage
  sections={[
    { kind: "hero", id: "hero", title: "CompanyOS", ctas: [] },
    { kind: "ctaBand", id: "final", title: "Start" },
  ]}
/>;

The section union is intentionally closed to the first-pass marketing taxonomy; content mapping, icon lookup, and product-specific copy remain in the consuming bundle/app. Static tone/alignment variants are supported, but no runtime personalization or bundle imports belong in design-system marketing components.

Reuse form configuration surfaces

Form configuration chrome is centralized under @lssm-tech/lib.design-system/forms:

tsx
import {
  FormConfigMenuBar,
  FormConfigPanel,
  FormConfigShell,
} from "@lssm-tech/lib.design-system/forms";

Use FormConfigShell when a screen needs a shared category menu plus adaptive panel. Use FormConfigMenuBar or FormConfigPanel directly only when a host already owns one side of the layout. The category and entry objects are display metadata; callers own the active category state and any submit/apply behavior. The default menu label, panel title, panel description and empty state come from the designSystem.organisms.formConfig.* catalog keys (en/fr/es) for the active locale, also when the mounted LocaleProvider runtime does not carry the design-system catalog; pass ariaLabel, title, description or emptyState to override them.

FormConfig components do not persist preferences, drafts, credentials, or form submissions. Product, example, and docs surfaces such as the form-showcase proof should reuse these exports instead of forking local configuration shells, and must keep storage or governed mutation behavior in the host/runtime layer.

Compose contract-driven entity workspaces

EntityWorkspace is the public entity-surface façade for DataView-backed product flows. It keeps DataViewSpec as the canonical contract input and delegates list/grid/table rendering to DataViewRenderer, while adding neutral workspace chrome for result counts, search/filter framing, metric cards, card/row/detail-action open-detail semantics, AdaptivePanel detail/edit shells, RichReference-aware field values, visible RoleMorph summaries, and personalization chips.

tsx
import { EntityWorkspace } from "@lssm-tech/lib.design-system";
// or the focused subpath:
import { EntityActionBar } from "@lssm-tech/lib.design-system/components/entity-workspace";

<EntityWorkspace
  spec={agentDataViewSpec}
  items={agents}
  selectedItem={selectedAgent}
  selectedItemId={selectedAgent?.id ?? null}
  selectedIds={selectedAgentIds}
  getItemId={(agent) => agent.id}
  preferences={{ viewMode: "list", density: "compact", dataDepth: "summary" }}
  adaptiveModel={{
    layout: "master-detail",
    hiddenFields: ["internalNotes"],
    summary: "Manager-safe projection",
  }}
  actionStates={{}}
  search={search}
  filters={{}}
  sort={null}
  pagination={undefined}
  metrics={[{ key: "allowed", label: "Allowed", value: 12, tone: "success" }]}
  showMetrics={true}
  evidence={[]}
  onOpenDetail={({ itemId, interaction }) => {
    // `interaction.action === "opened"` and includes the DataView key/version.
    console.log(itemId, interaction);
  }}
  onNavigateToDetailPage={({ detailPageHref }) => {
    if (detailPageHref) router.push(detailPageHref);
  }}
  buildDetailPageLink={({ itemId }) => `/entities/${itemId}`}
  detailPageActionLabel="Open full page"
  onSelectedItemChange={setSelectedAgent}
  onSelectedIdsChange={setSelectedAgentIds}
  onAction={handleAgentAction}
  renderAction={renderAgentAction}
  renderFormSlot={null}
  onSearchChange={setSearch}
  onFilterChange={setFilters}
  onPageChange={setPage}
  viewMode="list"
  onViewModeChange={setViewMode}
  density="compact"
  onDensityChange={setDensity}
  dataDepth="summary"
  onDataDepthChange={setDataDepth}
  onSortChange={setSort}
  headerActions={null}
  toolbarActions={null}
  renderResultCard={undefined}
  renderFieldValue={undefined}
  getFieldClassName={undefined}
  getFieldLabelClassName={undefined}
  renderDetail={undefined}
  detailOpen={Boolean(selectedAgent)}
  onDetailOpenChange={setDetailOpen}
  editOpen={false}
  onEditOpenChange={setEditOpen}
  loading={false}
  emptyState="No agents yet"
  noResultsState="No agent selected"
/>;

Use the default querySource="local" when the workspace receives an in-memory collection and should apply DataView search/filter/sort controls itself. Use querySource="remote" when items already came from spec.source.primary (for example agent.list with cursor pagination); the workspace still renders the same controls and emits host callbacks, but it does not re-apply search, filters, or sort locally. This prevents double filtering when a server or governed DataView query source has already projected the result set.

These surfaces are QueryState-aware and remain I/O-free: they accept the canonical QueryState (from @lssm-tech/lib.contracts-spec-core/query) and render loading / error / offline / stale / empty / conflict / retry states, but never fetch. Hosts wire useContractQuery (from @lssm-tech/lib.contracts-runtime-client-react, over the contracts-runtime-core engine) and pass the returned QueryState straight in with zero adapter.

When onNavigateToDetailPage is provided, the workspace renders a standard "Open full page" detail-panel action. Hosts can pair it with buildDetailPageLink to keep route construction standardized while still owning the actual router call, such as Expo Router or React Navigation.

The focused subpath exports the workspace and neutral primitives: EntityWorkspace, EntityResultsToolbar, EntityResultCard, EntityResultRow, EntityDetailPanel, EntityEditPanel, EntityFieldValue, EntityActionBar, EntityMetricStrip, and EntityEvidenceBlock. The neutral metric and evidence primitives are backed by ThemeSpec component token hooks and compose design-system StatCard, Text, and card primitives instead of domain-specific AgentFleet surfaces. Every public component is covered by the native parity matrix at src/components/entity-workspace/native-parity.ts; public entries must be platform-safe shared or have paired .tsx / .native.tsx implementations. "Native later" is not an accepted public status.

Run the focused gate with:

bash
bun test src/components/entity-workspace/EntityWorkspace.test.tsx src/components/entity-workspace/native-parity.test.ts

Resolve contract-backed themes

ts
import { ThemeRegistry } from "@lssm-tech/lib.design-catalog/themes";
import { resolvePlatformTheme } from "@lssm-tech/lib.design-system";

const registry = new ThemeRegistry([themeSpec]);

const webTokens = resolvePlatformTheme(
  registry,
  { key: "design.brand", version: "1.0.0" },
  "web",
  { targets: ["tenant:acme"] }
);

Translate ThemeSpec into Tailwind tokens

Use the Tailwind bridge when a ThemeSpec should drive CSS variables and utility names without requiring a generated file:

ts
import {
  resolveThemeModeTokens,
  themeSpecToCssVariables,
  themeSpecToTailwindCss,
  themeSpecToTailwindPreset,
} from "@lssm-tech/lib.design-system";

const tokens = resolveThemeModeTokens(themeSpec, "light", {
  targets: ["tenant:acme"],
});

export default themeSpecToTailwindPreset(tokens);

const variables = themeSpecToCssVariables(themeSpec, {
  targets: ["tenant:acme"],
});

const cssText = themeSpecToTailwindCss(variables, {
  includeCustomVariant: true,
});

The bridge emits stable variables such as --ds-color-primary, --ds-radius-md, and --ds-space-sm, plus Tailwind v4 @theme inline aliases like --color-primary: var(--ds-color-primary). Color values are passed through unchanged, so OKLCH tokens such as oklch(0.72 0.11 221.19) can be authored directly in ThemeSpec.

Compose rich-reference layouts (replaces legacy CodeBlock / DiffBlock / object-reference)

BREAKING (S-8): the legacy CodeBlock, DiffBlock, and object-reference components were deleted from this package without a shim phase. Composition now flows through <RichRef> / <PreviewPanel> / <RichBlock> from @lssm-tech/lib.ui-kit-web (web) or @lssm-tech/lib.ui-kit (native), combined with per-kind layouts shipped from this package under components/rich-reference/layouts/{kind}.

Each of the six built-in RichReference kinds — database-record, object, link, file, media, and code-symbol — has a paired Preview (inline trigger) and Panel (expanded body) layout that consumes the canonical RichReference<TPayload> shape and routes redacted fields through a uniform (redacted) indicator (DenialAwareValue).

tsx
import {
  builtInRichReferenceLayouts,
  getRichReferenceLayout,
} from "@lssm-tech/lib.design-system";
import { RichRef } from "@lssm-tech/lib.ui-kit-web/rich-ref";

function GovernedReference({ kindId, refId }: { kindId: ReferenceKindId; refId: ReferenceInstanceId }) {
  const layout = getRichReferenceLayout(builtInRichReferenceLayouts, kindId);
  if (!layout) return null;
  return (
    <RichRef
      kindId={kindId}
      refId={refId}
      renderPreview={({ reference }) => <layout.Preview reference={reference} />}
      renderPanel={({ reference }) => <layout.Panel reference={reference} />}
    />
  );
}

Apps that ship custom kinds merge them into the registry at the composition root via registerRichReferenceLayouts({...}). Code-symbol layouts respect the DiffHighlightTokenizer contract from @lssm-tech/lib.ui-kit-core; the real Shiki/WASM implementation lives in @lssm-tech/lib.ui-kit-web and a plain-text equivalent lives in @lssm-tech/lib.ui-kit (Hermes is WASM-incompatible).

To open a resolved reference's details in a sheet, on web or React Native, use RichReferenceSheet. It presents the kind's Panel (the object layout for kinds without one) inside AdaptivePanel with the detail intent: a bottom sheet on narrow viewports and on phones, a side sheet from the breakpoint up, and the gesture-dismissable native sheet on React Native. The title defaults to the reference label, or its id when the label is absent or redacted, and a hidden reference renders nothing. Drive open from your own control to use the same code on both platforms; resolveRichReferenceSheetTitle gives that control a label that never shows a denial token.

tsx
import {
  Button,
  RichReferenceSheet,
  resolveRichReferenceSheetTitle,
} from "@lssm-tech/lib.design-system";

function ReferenceDetails({ reference }: { reference: RichReference }) {
  const [open, setOpen] = React.useState(false);
  return (
    <>
      <Button variant="ghost" onPress={() => setOpen(true)}>
        {resolveRichReferenceSheetTitle(reference)}
      </Button>
      <RichReferenceSheet
        reference={reference}
        open={open}
        onOpenChange={setOpen}
      />
    </>
  );
}

The trigger prop is the shorter web form: it renders through asChild, so pass an element that forwards props and ref, such as Button, not a bare Preview layout. React Native wraps trigger in its own pressable, so a pressable Button there would swallow the press.

Provide translations to contract-driven renderers

tsx
import {
  createTranslationResolver,
  DesignSystemTranslationProvider,
} from "@lssm-tech/lib.design-system";

const resolver = createTranslationResolver({
  registry: translationRegistry,
  locale: "fr",
  specKeys: ["design-system.form", "design-system.data-view"],
});

<DesignSystemTranslationProvider resolver={resolver}>
  {children}
</DesignSystemTranslationProvider>;

Provide contract-backed themes to controls

tsx
import {
  DesignSystemThemeProvider,
  Input,
  Select,
} from "@lssm-tech/lib.design-system";

<DesignSystemThemeProvider
  theme={themeSpec}
  targets={["tenant:acme"]}
  mode="dark"
  applyCssVariables
>
  <Input
    componentKey="Input"
    themeVariant="default"
    placeholderI18n="form.customerName.placeholder"
  />
  <Select
    componentKey="Select"
    options={[{ labelI18n: "status.draft", value: "draft" }]}
  />
  <Select
    componentKey="Select"
    groups={[
      {
        labelI18n: "status.lifecycle",
        options: [{ labelI18n: "status.draft", value: "draft" }],
      },
      {
        labelI18n: "status.release",
        options: [{ labelI18n: "status.published", value: "published" }],
      },
    ]}
  />
</DesignSystemThemeProvider>;

When both options and groups are provided to Select, grouped options are used and the flat options list is ignored.

Hydrate the selected design without a flash

For server-rendered web apps, pass cssVariablesStrategy="stylesheet" to DesignSystemThemeProvider together with the server designHydration payload. The provider then always renders the [data-design-pack] wrapper and an inline stylesheet holding the pack's light and dark variables (dark applies under a .dark ancestor or wrapper class). The markup does not depend on the resolved colour mode, so the selected design paints on first render without a hydration mismatch. createDesignPackStylesheet drops unsafe keys and values. The default inline strategy keeps the previous mount-gated behaviour.

Use form controls from the design-system boundary

The root barrel exposes themed and translation-aware controls for product surfaces: Button, Input, Textarea, Select, NativeSelect, Autocomplete, Combobox, Checkbox, RadioGroup, Switch, DatePicker, TimePicker, DateTimePicker, DateRangePicker, Field*, InputGroup, InputOTP, LoadingButton, plus Box, HStack, and VStack.

Field* includes semantic FieldSet, FieldLegend, FieldGroup, FieldContent, FieldLabel, FieldDescription, FieldError, and FieldSeparator wrappers so contract-driven forms can preserve accessible legend, description, invalid, and grouped-control structure.

The Autocomplete control renders through the shared combobox primitive on web and keeps native rendering aligned for query, selected options, loading, error, and empty states. FormSpec renderers pass resolver-backed async state through these props without requiring product surfaces to know the underlying transport.

Use neutral primitive helpers

Use @lssm-tech/lib.design-system/primitives for design-system-neutral helpers shared by web and native controls, such as themed primitive hooks, translated placeholder helpers, and safe inputValue / optionValue event normalization. The root barrel re-exports this surface for compatibility, while the focused subpath keeps lower-level control code from depending on a full component import.

Compose application shells

Use the shell subpath for app frames that need sidebar navigation, topbar breadcrumbs, command search, account actions, and a right-side page outline. The same typed shell contract has web and native entrypoints.

CompanyOsShellTemplate accepts one contextSwitcher plus contextPlacement="topbar" | "sidebar-footer"; AppShell.sidebarFooter also surfaces inside mobile navigation. Its account-menu model remains compatible with flat action items and additively supports submenus, radio groups, and separators. Pass only server-authorized persona preview choices and the real user role; active preview is disclosed by the template banner. components/templates/CompanyOsShellTemplate/preference-menu-items builds the density, guidance and pace account-menu entries from { dims, setDim }: createPreferenceMenuItems (cycling actions) and createPreferenceRadioGroups (radio groups over PREFERENCE_DIMENSION_VALUES from lib.personalization; unknown values are ignored).

tsx
import { AppShell } from "@lssm-tech/lib.design-system/shell";

<AppShell
  brand={null}
  logo={null}
  title="Workspace"
  homeHref="/"
  commands={[
    {
      heading: "Actions",
      items: [{ id: "new-project", label: "New project" }],
    },
  ]}
  notifications={null}
  navigation={[
    {
      title: "Main",
      items: [
        {
          label: "Projects",
          href: "/projects",
          children: [{ label: "Active", href: "/projects/active" }],
        },
      ],
    },
  ]}
  notifications={undefined}
  breadcrumbs={[{ href: "/", label: "Home" }, { label: "Projects" }]}
  pageOutline={[
    { id: "summary", label: "Summary" },
    { id: "details", label: "Details", level: 2 },
    { id: "audit", label: "Audit trail", level: 3 },
  ]}
  activeHref="/projects"
  activeOutlineId="summary"
  userMenu={null}
  topbarStart={null}
  topbarContext={<WorkspaceSwitcher />}
  topbarEnd={null}
  aiPanel={null}
  onNavigate={(item) => {
    if (item.href) router.push(item.href);
  }}
>
  {children}
</AppShell>;

On desktop web, AppShell renders a 240px collapsible sidebar with a 72px icon rail, a 64px sticky topbar, content region, and optional floating PageOutline. The outline does not reserve a right-side content column: it reduces to a slim rail while inactive and expands on hover or keyboard focus, keeping wide page content centered. The desktop topbar is inset beside the sidebar and includes a sidebar toggle. The topbarContext slot remains in shell chrome at every web breakpoint so an authoritative context or workspace control never shifts page content or disappears during navigation. Primary sidebar destinations retain at least a 44px interactive target in expanded and collapsed layouts; the top-bar trigger is the single supported sidebar-collapse control. On small web screens, the first four authorized destinations move into a persistent, safe-area-aware bottom dock and the remaining navigation stays reachable from the localized “More” dialog. AppShell hides the page outline to preserve layout stability. On native, AppShell is an Expo Router NativeTabs layout adapter intended for an Expo Router layout boundary such as app/_layout.tsx. Native primary navigation is rendered through Expo's alpha expo-router/unstable-native-tabs system tab bar, while overflow navigation, actions, user content, and page outline stay reachable from a header menu button that opens a sheet (rendered only when such overflow content exists). children render outside the NativeTabs navigator as an overlay/utility slot for source compatibility; routed tab screens remain owned by Expo Router. The tab bar is themed from design-system tokens: active label and icon use the primary color and inactive items use mutedForeground, with background, indicator, ripple, and badge colors resolved from the active theme (falling back to default tokens when no DesignSystemThemeProvider is mounted). Primary native tab triggers render a governed native-safe tab icon when a host supplies nativeIcon (sf SF Symbol on iOS, md Material icon or drawable on Android) and fall back to label and string/number badge only when no icon is provided; the platform-agnostic ReactNode icon remains for overflow/menu navigation. Native tab route inference is deliberately narrow: use / for the index tab and single-segment hrefs such as /settings for route names. Missing, empty, external, nested, dynamic, duplicate, or denied/disabled primary tab hrefs throw developer errors instead of falling back to custom tabs.

AppShell also accepts a prop-driven notifications center for in-app notifications. Hosts provide structural items, unreadCount, loading/empty state, and callbacks such as onSelect, onMarkRead, and onMarkAllRead; the design-system shell renders the web topbar trigger and a native header bell button (with an unread-count badge) that opens the notifications sheet, without importing or owning any notification runtime package. On web, the notification panel closes when users select an item, press the close button, click outside the panel, press Escape, or click the notification trigger again.

Shell navigation and command items may carry optional policy metadata plus a policyBehavior of hide, disable, or show-with-lock. Use filterShellNavigationForPolicy() / annotateShellCommandsDecisions() with decisions produced by your application runtime; AppShell only adapts affordances and does not fetch permissions or enforce backend access.

Render forms on mobile through the shared renderer

Use the focused shared renderer subpath when rendering FormSpec contracts in Expo or React Native apps:

tsx
import { formRenderer } from "@lssm-tech/lib.design-system/renderers";

The shared FormSpec renderer includes a first-class phone field implementation that displays country flags, parses international input with libphonenumber-js, and keeps single-input or split country/national controls linked. Contracts can configure behavior through a phone field's input, output, country, and display options; host apps can set package-wide defaults by passing phone overrides to createFormRenderer.

Expo apps must keep the presentation Metro aliases enabled so design-system imports of @lssm-tech/lib.ui-kit-web/ui/* are remapped to @lssm-tech/lib.ui-kit/ui/* at bundle time:

js
const {
  withPresentationMetroAliases,
} = require("@lssm-tech/lib.presentation-runtime-core");

module.exports = withPresentationMetroAliases(config, { monorepoRoot });

Render the canonical account grid

The canonical data-table example lives in @lssm-tech/example.data-grid-showcase†. Its composed lane uses DataTable, DataTableToolbar, and DataViewTable from this package:

tsx
import {
  Button,
  DataTable,
  DataTableToolbar,
  DataViewTable,
} from '@lssm-tech/lib.design-system';
import { useContractTable } from '@lssm-tech/lib.presentation-runtime-react';

import { DataGridShowcaseDataView } from '@lssm-tech/example.data-grid-showcase/contracts/data-grid-showcase.data-view';
import { SHOWCASE_ROWS } from '@lssm-tech/example.data-grid-showcase/ui/data-grid-showcase.data';
import { useShowcaseColumns } from '@lssm-tech/example.data-grid-showcase/ui/data-grid-showcase.columns';
import {
  ExpandedRowContent,
} from '@lssm-tech/example.data-grid-showcase/ui/data-grid-showcase.parts';

export function AccountHealthTable() {
  const columns = useShowcaseColumns();

  const controller = useContractTable({
    data: SHOWCASE_ROWS,
    columns,
    selectionMode: 'multiple',
    initialState: {
      sorting: [{ id: 'arr', desc: true }],
      pagination: { pageIndex: 0, pageSize: 4 },
      columnVisibility: { notes: false },
      columnPinning: { left: ['account'], right: [] },
    },
    renderExpandedContent: (row) => <ExpandedRowContent row={row} />,
    getCanExpand: () => true,
  });

  return (
    <>
      <DataTable
        controller={controller}
        title="Account health"
        description="Composed table surface for the canonical account grid."
        headerActions={<Button variant="outline">Reset</Button>}
        toolbar={
          <DataTableToolbar
            controller={controller}
            searchPlaceholder="Search accounts"
            actionsStart={
              <Button variant="outline" size="sm">
                Risk Only
              </Button>
            }
          />
        }
        loading={false}
        emptyState={<div>No rows available.</div>}
        footer={\`Page \${controller.pageIndex + 1} of \${controller.pageCount}\`}
      />

      <DataViewTable
        spec={DataGridShowcaseDataView}
        items={SHOWCASE_ROWS}
      />
    </>
  );
}

DataTable remains the composed card/container surface. DataTableToolbar is the recommended ergonomic layer for search, chips, selection summary, and hidden-column recovery without widening the primitive table API. DataView-driven tables also honor field and column overflow hints from DataViewSpec: column hints override field hints, markdown wraps by default, compact scalar formats truncate, expand adds detail to the row expansion surface, and hideColumn starts hidden when column visibility is enabled. Collection DataViewSpec contracts can also declare view.collection defaults for list/grid/table mode switching, toolbar controls, query page size, and density. They can also declare collection.dataDepth and field-level visibility.minDataDepth so one spec can project summary, standard, detailed, or exhaustive fields. DataViewRenderer uses those defaults for web and native renderers while keeping caller props authoritative through viewMode, density, dataDepth, onViewModeChange, onDensityChange, and onDataDepthChange. Personalization integrations should resolve preferences in the host app and pass ordinary renderer props; the design system intentionally does not import @lssm-tech/lib.personalization.

Compose CommunicationOS presentational primitives

Use the focused communication subpath when CommunicationOS screens need neutral presentational blocks without pulling in example fixtures or module workflow state:

tsx
import {
  ActionCandidateList,
  CommunicationWorkQueue,
  ReplyDraftReviewPanel,
} from "@lssm-tech/lib.design-system/components/communication-os";

These blocks are UI-only: callers provide work items, source evidence, policy decisions, handoff packets, and action candidates. Workflow behavior and rich screen composition live in @lssm-tech/module.communication-os/ui; deterministic sample data lives in example packages such as @lssm-tech/example.communication-os and @lssm-tech/example.messaging-app.

API map

Theme and platform

  • defaultTokens and token interfaces from ./theme/tokens
  • mapTokensForPlatform from ./theme/tokenBridge
  • resolveThemeSpecTokens, resolveThemeRefTokens, and resolvePlatformTheme from ./theme/contracts
  • resolveThemeModeTokens, themeSpecToCssVariables, themeSpecToTailwindTheme, themeSpecToTailwindPreset, and themeSpecToTailwindCss
  • DesignSystemThemeProvider, useDesignSystemTheme, and useComponentTheme
  • theme variants
  • withPlatformUI
  • useColorScheme
  • useReducedMotion
  • useResponsive

Renderers and hooks

  • renderer exports from ./renderers
  • form-contract renderer support, including readonly, email, password, autocomplete, address, phone, date, time, datetime, semantic FormSpec groups, grid layout hints, progressive FormSpec sections/steps, mobile-safe FormSpec column helper output, and text/textarea/email input groups
  • translation-aware rendering through DesignSystemTranslationProvider and createTranslationResolver
  • theme-aware form controls, neutral primitive helpers, and stack primitives that consume ThemeSpec component variant props
  • hooks such as useListUrlState, including scoped list filters where locked constraints are excluded from user-editable URL state
  • DataViewRenderer filter chips for scoped DataView filters, including disabled locked chips on web and native surfaces
  • navigation-related shared types

Component composition layers

  • atoms
  • forms
  • legal
  • marketing
  • molecules
  • organisms
  • templates
  • visualization
  • agent and approval components

The root barrel is the primary API and already groups these exports in one place.

Contract-driven Storybook catalog

The optional ./storybook catalog covers fifteen canonical public component families in Editorial light/mobile and Executive Ledger dark/desktop modes. ./storybook-bindings owns the real eight-surface product fixtures used by the design-catalog matrix, while ./storybook-preview installs ThemeSpec and locale providers plus semantic styling.

ts
import { designSystemStorybookCatalog } from '@lssm-tech/lib.design-system/storybook';

export default {
	catalogs: [designSystemStorybookCatalog],
};

The catalog is web-only. Native components remain qualified by the paired native test lanes. New public component families must update the coverage manifest before release. Each family lists representative published subpaths, so deleting an export without a coverage disposition fails the catalog test. Run bun run storybook:generate to refresh the committed embedded-catalog manifest and bun run storybook:check to enforce deterministic drift checks.

Public surface

The root barrel at src/index.ts is the main public API for this package.

The export map is broad, but it is centralized:

  • . for backward-compatible root imports across theme, platform, renderers, controls, and composed components
  • ./theme for ThemeSpec runtime, platform token mapping, and Tailwind bridge helpers
  • ./controls for themed and translated controls
  • ./forms for form controls, layouts, and ZodForm
  • ./layout For Box, HStack, and VStack
  • ./primitives for themed primitive hooks, translated value helpers, and input/option value normalization
  • ./renderers for focused renderer imports such as formRenderer
  • hooks and shared types

The package also ships registry metadata and build support:

  • components.json
  • registry/registry.json
  • bun run registry:build

Operational semantics and gotchas

  • Token names and token shapes are compatibility surface.
  • mapTokensForPlatform() deliberately returns different token shapes for web and native, and can now map resolved contract-backed tokens.
  • withPlatformUI() is a lightweight adapter, not a full runtime framework.
  • DesignSystemThemeProvider resolves ThemeSpec / ThemeRef tokens, scoped overrides, and component variant default props. Explicit caller props win over theme defaults.
  • The root barrel is broad and therefore high-blast-radius.
  • This package depends on both ui-kit and ui-kit-web.
  • The package includes legal, marketing, agent, app-shell, and visualization compositions, not just low-level primitives.

When not to use this package

  • Do not use it for tiny low-level utilities.
  • Do not use it for router-agnostic links.
  • Do not use it when a single lower-level primitive from ui-kit or ui-kit-web is enough.
  • @lssm-tech/lib.ui-kit
  • @lssm-tech/lib.ui-kit-web
  • @lssm-tech/lib.ui-kit-core
  • @lssm-tech/lib.ui-link

Local commands

  • bun run lint:check
  • bun run typecheck
  • bun run test

Render governed rich code and diffs

Code-symbol and diff rendering flows through the per-kind rich-reference layouts (components/rich-reference/layouts/code-symbol) and the DiffHighlightTokenizer contract from @lssm-tech/lib.ui-kit-core. Web apps get Shiki dual-theme highlighting via @lssm-tech/lib.ui-kit-web/rich-block/diff/highlight; native apps get a plain-text equivalent via @lssm-tech/lib.ui-kit/rich-block/diff/highlight (Hermes cannot execute Shiki/WASM).

Server surfaces redact sensitive payload fields before passing RichReference<TPayload> to the client. The per-kind layouts render the canonical denial-token wire form through DenialAwareValue; the design-system does not decide authorization by itself.

Graph & Timeline Primitives

@lssm-tech/lib.design-system routes graph, timeline, and timeline-graph data views through DataViewRenderer. The switch has been updated to handle three new kinds:

  • "graph" → DataViewRendererGraph (P3/W3.2 stub; renders emptyState until real renderer lands)
  • "timeline" → DataViewRendererTimeline
  • "timeline-graph" → DataViewRendererTimelineGraph

Product code should always use DataViewRenderer — the sub-renderers are internal:

ts
import { DataViewRenderer } from "@lssm-tech/lib.design-system";

<DataViewRenderer spec={voiceOpsOperatingGraphView} items={[]} />

See AGENTS.md for layer placement and import rules.

Marketing page foundation

@lssm-tech/lib.design-system owns the generic marketing page primitives used by full-page landing surfaces:

  • MarketingCtaRow, MarketingBadge, and MarketingProofStatStrip for atoms/molecules.
  • MarketingHeroSection, MarketingProseSection, MarketingIconGridSection, MarketingSummarySection, and MarketingCtaBand for reusable sections.
  • MarketingPricingCalculator, MarketingPricingTable, MarketingFaqSection, and MarketingTestimonialSection for prop-driven pricing, FAQ, and social-proof blocks. Pricing logic, formatting, copy, analytics callbacks, FAQ JSON-LD, and product-specific content stay in the consuming bundle/app.
  • MarketingLeadCapture, MarketingFeatureTabs, MarketingTimeline, MarketingTrustBadges, MarketingVideo, and MarketingAnnouncementBar for generic lead capture, use-case tabs, process, trust/compliance, media, and campaign banner surfaces. Forms, media embeds, analytics, validation, and provider logic stay caller-owned. MarketingFeatureTabs is a client component; import its focused subpath in RSC-sensitive apps when you want the client boundary to stay explicit.
  • MarketingLandingPage plus the MarketingPageSection discriminated union for ordered, typed page composition.
  • MarketingContractLandingPage, MarketingContractDescriptorPage, MarketingContractBoundary and adaptMarketingPageContractToSections / adaptMarketingPageContractToDescriptors render marketing page contracts. Their props are structural (MarketingPageContractLike, MarketingSiteContractLike and the section, card, CTA and binding parts): they name only the fields the renderers read, so a growth marketing site contract (@lssm-tech/lib.growth-spec/marketing) passes as-is without the design system depending on the growth domain. A section kind the renderers do not know renders as prose instead of failing. A section whose disclosure link has no label gets the designSystem.organisms.marketingContract.disclosureCta catalog label ("Learn more") in the optional locale the two components and mappers accept (default en).

Product bundles keep copy, icon mapping, and content-model conversion. The design system must not import bundle, app, or personalization runtime modules.

Data-view enum filter labels, options and active chips now resolve through the scoped translation context on web and native. Cleared filters do not produce undefined chips; semantic filter keys/values and legacy removal payloads are preserved.

Action feedback imports the theme-independent toast entrypoint, so collection renderers do not require the optional next-themes peer merely to load.

MarkdownRenderer now renders block nodes directly inside its neutral container rather than nesting headings and paragraphs inside a paragraph, preventing invalid HTML and hydration warnings.

Standalone declaration exports keep their existing public subpath names. The shared builder preserves their original declaration suffix and copies checked source declarations into dist, without overwriting emitted implementation types.

The web Box/stack/list/Text wrappers forward to their canonical UIkit-web themed implementations. DesignSystemThemeProvider continues resolving ThemeSpec, modes, scopes and overrides, then binds resolved component variants to those wrappers. The conditional ./theme/component-theme-bridge self-import selects a web provider or a native pass-through; native primitives continue using the existing DesignSystem context without loading the web bridge. Run bun run typecheck:surface-primitives for strict frozen prop compatibility and the focused theme/interaction fixture.

Canonical builds retain the intentional published export map (exports.rewrite: false). New production roots must be declared in the existing build entries and manifest together; generation must not silently rename or drop supported aliases or platform conditions. Full artifact verification checks every advertised target, including native aliases. Test fixtures remain in source verification while excluded from production entry discovery.

Entity-workspace web and native public types use the canonical Core DataView spec and field declarations. Marketing contract composition takes structural props, so the package no longer depends on the @lssm-tech/lib.contracts-spec compatibility facade.

Declared capabilities.

Lib Design System

Design tokens and theming primitives

Use it to

  • Adopt design tokens and theming primitives

Requires

  • TypeScript

Choose another boundary when

  • The @lssm-tech/lib.design-system package constraints do not match the target runtime or platform.

@lssm-tech/lib.design-system

@lssm-tech/lib.design-system/adaptive

@lssm-tech/lib.design-system/adaptive/adapter

@lssm-tech/lib.design-system/adaptive/CanonicalProjectionProvider

@lssm-tech/lib.design-system/adaptive/useCanonicalProjection

@lssm-tech/lib.design-system/components/agent/AgentMonitor

@lssm-tech/lib.design-system/components/agent/ApprovalQueue

@lssm-tech/lib.design-system/components/agent/ApprovalQueue.native

@lssm-tech/lib.design-system/components/atoms/ActionButtons

@lssm-tech/lib.design-system/components/atoms/AutocompleteCombobox

@lssm-tech/lib.design-system/components/atoms/AutocompleteCombobox/AutocompleteCombobox

@lssm-tech/lib.design-system/components/atoms/AutocompleteCombobox/useAutocompleteCombobox

Imports and export paths.

571 entries

These are package-manifest entry points. Named symbols listed above come from the capability catalogue; this is not an exhaustive TypeScript symbol reference.

571 imports · showing 35

Dependencies and related packages.

Runtime dependencies 25
@hookform/resolvers
5.9.1
class-variance-authority
catalog:ui
clsx
catalog:ui
country-flag-icons
^1.6.20
libphonenumber-js
^1.13.13
lucide-react
catalog:ui
react-hook-form
^7.86.0
tailwind-merge
catalog:ui
tailwindcss-animate
catalog:ui
zod
catalog:
Peer dependencies 19
@fontsource/atkinson-hyperlegible
5.3.0
@fontsource/bricolage-grotesque
5.3.0
@fontsource/fraunces
5.3.0
@fontsource/ibm-plex-mono
5.3.0
@fontsource/ibm-plex-sans
5.3.0
@fontsource/newsreader
5.3.0
@fontsource/unbounded
5.3.0
expo-router
~57.0.11
framer-motion
^13.2.0
next
catalog:
posthog-react-native
^4.68.0
react
catalog:
react-dom
catalog:
react-native
catalog:native
react-native-css
catalog:native
react-native-gesture-handler
>=2.0.0
react-native-reanimated
>=3.0.0
react-native-safe-area-context
~5.7.0
react-native-svg
>=15.0.0
Development dependencies 18
@types/node
catalog:types
@types/react-dom
^19.2.5
axe-core
catalog:testing
expo-router
~57.0.20
happy-dom
catalog:testing
next
catalog:
postcss
catalog:build
postcss-load-config
^6.0.1
posthog-react-native
^4.74.2
react
catalog:
react-dom
catalog:
react-native
catalog:native
react-native-css
catalog:native
react-native-safe-area-context
~5.7.0
tailwindcss
catalog:build
typescript
catalog:

Package scripts.

Commands declared by this package. Review its setup requirements before running them; no command here was executed by this review.

publish:pkgbun publish --tolerate-republish --ignore-scripts --verbose
publish:pkg:canarybun publish:pkg --tag canary
buildbun run build:bundle && bun run build:types
build:bundlecontractspec-bun-build transpile && node scripts/copy-web-stubs-to-native.mjs
build:typescontractspec-bun-build types
devcontractspec-bun-build dev
registry:buildbun run scripts/build-registry.ts
storybook:generatebun run scripts/storybook-catalog.ts
storybook:checkbun run scripts/storybook-catalog.ts --check
testbun test src --pass-with-no-tests
test:build-artifactsnode scripts/check-generated-js.mjs
lintbun run lint:fix
lint:fixnode ../../../../scripts/biome.cjs check --write --unsafe --only=nursery/useSortedClasses . && node ../../../../scripts/biome.cjs check --write .
lint:checknode ../../../../scripts/biome.cjs check .
prebuildcontractspec-bun-build prebuild
typechecktsgo --noEmit -p tsconfig.build.json
typecheck:surface-primitivestsgo --noEmit --project tsconfig.surface-primitives.json
Your view

Make room for your context.

Shape the presentation around this moment. You can change it whenever you need.

Your context

The different parts of you

Choose a starting point

A useful mix of context, visuals and gentle guidance.

Tune each dimension
Each dimension can change independently. Product permissions and available actions stay unchanged.

Support the way you begin and return

Tune your support

Reading comfort

Choose your language

Interface language changes text only. Markets, prices and workflows keep their own settings.

Translation coverage

Original source

Navigation151
Graph616
Categories378
Portfolio833
Examples2,035
Source preview1,542

More translations will be added as content is reviewed.

This preference is saved on this browser.

Search the website

Useful starting points

No results. Try a shorter phrase, an operation name or another search area.

A LITTLE ROOM TO EXPLORE

Find something to explore.

Open a closer look on this page, try a different perspective, or follow the detail into its own page.

How previews and controls work
01

Look before you leave

Hover a link or focus it with Tab to see a preview. Clicking the original link or pressing Enter always opens its destination.

02

Stay with the context

Move into the preview to explore its sections. Use Alt + ↓ from a focused link to enter it with the keyboard. Escape closes it.

03

Open the possibilities

Disclosure rows, perspective choices and highlighted controls reveal more. Your view changes reading comfort and the context you explore.

A separate button for a closer look

Show small preview buttons beside links where there is room. Tap the eye to inspect, or tap the link to go straight there. This choice stays in this tab.

No browsing history is collected. Reduced motion follows your device and Your view.