@servicetitan/carto-charts-core
v0.2.0
Published
Platform-neutral Carto data-viz layer: the token-driven ECharts theme, the supported chart module set, and the popover controller shared by the web and React Native chart hosts.
Downloads
266
Readme
@servicetitan/carto-charts-core
Platform-neutral data-viz layer for Carto — the piece the web and React Native chart hosts share. It carries no rendering dependency and no DOM: the token-driven ECharts theme, the per-index treatment that a theme can't express, the palettes, the supported module set, and the tooltip helpers.
Status: early release. Grew out of the library-selection spike and its proof-of-concept (ANV-5264).
Most consumers don't import this directly. Render a chart through
@servicetitan/carto-charts-react or -rn and pass variant; reach in here only
when you're styling series yourself.
The variant is two halves
A "variant" is a named Carto palette plus its full treatment — colors, borders,
pattern fills, marker shapes, corner radii. It takes two pieces to apply, because
an ECharts theme can carry per-index color: [] and uniform per-series-type
defaults and nothing else: no per-index borders, symbols, or area patterns.
createCartoChartTheme({ appearance?, variant? })— the half a theme can express: fonts, axis colors, hover states, per-index color. Registered against each host's echarts instance underCARTO_CHART_THEME_NAME.applyWebChartVariant(option, { appearance?, variant? })andapplyNativeChartVariant(...)— a pure, non-mutating transform over the consumer's option that injects the rest: monochrome's borders and decals, line marker shapes at 3+ series, bar corner radius (following orientation and sign), area band separators, and the legend's wrapping and swatch shape.
The hosts call both for you. Consumer-authored styling always wins over anything
injected — per-datum itemStyle beats per-series, which beats the transform,
which beats the theme. That's what keeps per-point treatments (a patterned
forecast bar among solid actuals) expressible in your own option.
Both entry points are currently identical; they're separate so a platform
divergence has a seam to land on, matching prepareWebOption /
prepareNativeOption.
Palettes
ChartVariant is "monochrome" | "categorical" — the palettes that assign a
color per variable index, so they can be applied without knowing what the data
means. Monochrome is the default, matching Anvil's documented default; it has
four designed steps and is scoped to 4 variables or fewer. Categorical is for 5+,
and is also what line charts use at any count.
Semantic is not a variant. A status color is chosen by what a variable means (success/warning/danger/default) and, within a role, by how urgent it is — neither is derivable from a series index. Compose it instead:
chartPalette(appearance, "semantic")— the status hues.chartStepItemStyle(step)— turns a{ fill, stroke, pattern }step into an echartsitemStyle, borders and decals included. Palette-agnostic: it's the same treatment monochrome uses, which is why it isn't named after it.
See either host package's Semantic stories for worked examples, including
Anvil's invoice-aging bar where three of five segments are the same role at
different urgencies.
chartPalette also returns the "monochrome" steps and the "categorical"
hues, if you're styling series by hand rather than via variant.
Also here
cartoChartModules— the supported echarts chart types and components. Both hosts register this exact set plus their own renderer, so an option renders the same on either. Widen it here and both platforms gain the capability together.prepareWebOption/prepareNativeOption— each host's option normalization. Both drop a consumer'stooltip, so a host owns the one in play; web enablesaria, native strips it.chartTooltipTrigger(option)/toChartTooltipPoint(params)— what a host needs to drive echarts' tooltip: which trigger a chart shape requires, and the mapping from echarts' callback params to aChartTooltipPoint.chartTokens(appearance?)/chartTypography(appearance?)— the token → chart-role mapping the theme reads. Exported so a custom theme can build on the same values rather than re-deriving them.
On appearance
A theme is built for an appearance rather than reacting to one. These packages
deliberately don't depend on the kits, so useCartoTheme() is out of reach and
the consumer selects the appearance — the kits' own Chart wrappers fill it in
from CartoTheme.
chartTokens currently resolves to the same values for "light" and "dark",
because carto-tokens' semanticDark is still a copy of semanticLight; it picks
up real dark values the moment the token set differentiates, with no change here.
Two things already differ per appearance: the chart palettes, which are
authored per appearance rather than resolved through carto-tokens, and
chartTypography's directLabel.backgroundColor, which is a raw translucent value
with no semantic token behind it yet.
Consuming it
This package ships no chart specs — consumers author their own option and
render it through a platform host. The DS owns the theme, the treatment and the
supported module set; the consumer owns the data and the chart type. echarts is
a peer dependency, so all three packages resolve to a single echarts version.
Author paint as plain declarative objects rather than reaching for
echarts.graphic.* helpers, so a spec stays portable — importing echarts into a
spec file would tie it to one platform's build.
Build
Bundled with Vite in library mode, emitting ESM and CommonJS plus declarations.
CommonJS is there because carto-charts-rn's own CommonJS build require()s
this package. carto-tokens is a devDependency on purpose: its runtime is compiled
in, so consumers never have to transpile raw TypeScript out of node_modules.
