npm.io
0.0.0-anvil2-kits-poc-20260717210733 • Published 3d ago

@servicetitan/anvil2-ai-kit

Licence
UNLICENSED
Version
0.0.0-anvil2-kits-poc-20260717210733
Deps
12
Size
1.1 MB
Vulns
0
Weekly
0

@servicetitan/anvil2-ai-kit

Anvil2 AI component kit. Ships as ESM with type declarations.

Install

pnpm add @servicetitan/anvil2-ai-kit

Peer requirements: react@>=18 <20, react-dom@>=18 <20.

Runtime dependency: @servicetitan/anvil2 (overlap primitives — Button, Text, Checkbox, Card, Dialog, Link, Menu — are not re-exported from this package).

Usage

import { Button } from "@servicetitan/anvil2";
import { AiKitTheme } from "@servicetitan/anvil2-ai-kit";
import { SvgPencil } from "@servicetitan/anvil2-ai-kit/icons";
import "@servicetitan/anvil2-ai-kit/styles.css";
import "@servicetitan/anvil2/dist/index.css"; // if your bundler needs an explicit CSS entry

<AiKitTheme>
  {/* Overlap primitives (Button, Text, Card, …) come from @servicetitan/anvil2 */}
  <Button appearance="primary" onClick={handleSave}>Save</Button>
  <Button appearance="secondary" icon={{ before: SvgPencil }} onClick={handleEdit}>
    Edit
  </Button>
</AiKitTheme>

Always import the CSS bundle once at your app's entry point so vanilla-extract styles are loaded.

Icons ship as individual components under the ./icons subpath — IconPencil, IconChevronDown, etc. Each accepts the same locked prop surface (size, color, label, className, style, ref). The allowlist (Lucide-backed and custom Carto SVGs alike) is owned by VizD and curated inside the kit; consumers can't extend it from outside, and direct lucide-react imports outside this module are intentionally out of bounds.

Fonts

Carto components render in Inter (body) and Sofia Pro (headings). For the fastest first paint, add Inter <link> tags to your app shell <head> and ensure @servicetitan/anvil-fonts is loaded for Sofia Pro so the fetches start during HTML parse, before any Carto JS runs:

<link rel="preconnect" href="https://fonts.googleapis.com" crossorigin />
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
<link
  rel="stylesheet"
  href="https://fonts.googleapis.com/css?family=Inter:400,400i,500,500i,700,700i&display=optional"
/>
import "@servicetitan/anvil-fonts/dist/css/anvil-fonts.css";

The kit also injects Inter links and imports anvil-fonts at module load as a runtime safety net — but the shell pattern is strictly preferable: fonts arrive before paint instead of after. See .storybook/preview-head.html for the canonical reference.

Source layout

Component code lives in src/components/<Component>/. Each component is a sibling group: <Component>.tsx (render only), <Component>.css.ts (vanilla-extract recipe), types.ts (props + variant unions), <Component>.test.tsx, and stories/<Component>.stories.tsx. Icons follow a slightly different shape — they ship from src/icons/ via factory functions; see src/icons/custom/README.md for the custom-icon workflow.

Common tasks (build, test, typecheck, typedoc, storybook) run from the repo root via pnpm build:anvil2-ai-kit, pnpm test:anvil2-ai-kit, etc. See the root package.json for the full list.

Local testing

Vitest is split into two projects (see vitest.config.ts):

  • unit — jsdom, runs every *.test.tsx. This is what pnpm test and CI's Test job run.
  • storybook — real Chromium via @vitest/browser-playwright, runs every *.stories.tsx through @storybook/addon-vitest. This is what the Run tests button in the Storybook UI and pnpm test-storybook use locally. CI does not run this project — Chromatic catches play-function regressions in the cloud.

The storybook project needs Playwright's Chromium binary installed locally — it lives outside node_modules at ~/Library/Caches/ms-playwright/ (macOS) or ~/.cache/ms-playwright/ (Linux), ~150 MB. Run once per machine:

pnpm --filter @servicetitan/anvil2-ai-kit exec playwright install chromium

You only need this if you (a) click Run tests in the Storybook UI or (b) run pnpm test-storybook locally. Browsing stories with pnpm storybook and running unit tests with pnpm test do not need it.

Storybook

pnpm storybook:anvil2-ai-kit

Stories render in light DOM by default under AnvilProvider + AiKitTheme (light). Anvil2 component CSS and Core tokens come from the live @servicetitan/anvil2 package (lib-inject-css + AnvilProvider) — not from vendored monolith bundles.

The Storybook toolbar has a Shadow toggle that wraps the story in an open shadow root (data-mfe-name="test-mfe") for optional isolation checks. It is not a fidelity environment for hover/focus testing — non-bubbling DOM events (pointerenter, mouseenter) can't cross shadow boundaries. See src/internal/storybook/Shadow/Shadow.tsx; develop hover-driven components in Fragment mode.

Monolith CSS snapshot (not loaded in preview)

Outdated monolith host CSS is not linked from preview-head.html (it fights live Anvil2 after the hard-cut). A snapshot may still be refreshed into public/monolith-css/ for later clash-testing work:

pnpm refresh-monolith-css:anvil2-ai-kit

That script still downloads CDN bundles / builds local anvil2+design-system snapshots into public/monolith-css/, and regenerates the font-only preview-head.html. No monolith checkout is required.