@cascivo/charts 0.4.1 → 0.5.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -3,7 +3,7 @@
3
3
  <div align="center">
4
4
  <a href="https://cascivo.com"><img src="https://cascivo.com/favicon.svg" width="72" height="72" alt="cascivo logo"></a>
5
5
  <h1>@cascivo/charts</h1>
6
- <p><strong>Chart components built from scratch — scales, shapes, and signal-driven rendering, zero dependencies</strong></p>
6
+ <p><strong>Chart components built from scratch — scales, shapes, and signal-driven rendering, zero dependencies. Colors come from @cascivo/themes; components from @cascivo/react. Docs offline: npx @cascivo/docs</strong></p>
7
7
 
8
8
  [![npm](https://img.shields.io/npm/v/%40cascivo%2Fcharts?style=flat-square&color=0079bf)](https://www.npmjs.com/package/@cascivo/charts)
9
9
  [![downloads](https://img.shields.io/npm/dm/%40cascivo%2Fcharts?style=flat-square&color=0079bf)](https://www.npmjs.com/package/@cascivo/charts)
@@ -18,6 +18,8 @@
18
18
 
19
19
  Accessible, signal-driven chart library for cascivo — AreaChart, BarChart, LineChart, Sparkline, Heatmap, and more. All charts are keyboard-navigable with `aria-live` tooltips. CVD-safe palettes (Okabe-Ito, oklch) verified in CI across all 12 themes.
20
20
 
21
+ > **Docs offline?** The full cascivo reference ships as an npm package — `npx -y @cascivo/docs`, no website needed.
22
+
21
23
  ## Install
22
24
 
23
25
  ```sh
@@ -49,6 +51,24 @@ export function Traffic() {
49
51
  Charts are CSS-token-themed: drop them inside any element carrying a `data-theme` (or import a
50
52
  theme stylesheet) and they pick up the same palette, radii, and typography as the rest of cascivo.
51
53
 
54
+ ### Sizing — responsive by default
55
+
56
+ **Omit `width`** and the chart fills and tracks its container (a `ResizeObserver`
57
+ watches the slot), so a chart drops cleanly into a responsive `Card` or grid cell with
58
+ no measuring on your part. `height` defaults to `300` (px); set it to change the aspect.
59
+
60
+ Pass an explicit `width` only for a fixed-size export — and even then it is **clamped to
61
+ the container** (`max-inline-size: 100%`), so an over-wide `width` scales down instead of
62
+ overflowing and clipping data. To size another element to match a chart, or to build a
63
+ custom chart, use the exported `useChartSize()` hook.
64
+
65
+ ```tsx
66
+ <Card>
67
+ <LineChart data={data} /> {/* fills the card, resizes with it */}
68
+ </Card>
69
+ <LineChart data={data} height={160} /> {/* shorter, still full-width */}
70
+ ```
71
+
52
72
  > **Vite SSR (TanStack Start, Remix, vite-ssr, workerd)?** Like the rest of cascivo, the
53
73
  > chart CSS ships as side-effect imports a bare server loader can't resolve — mark
54
74
  > `ssr: { noExternal: [/^@cascivo\//] }` (the pattern already covers `@cascivo/charts`) and
package/dist/charts.css CHANGED
@@ -1,2 +1,2 @@
1
- @layer cascivo.component{._frame_1doa7_2{inline-size:100%;position:relative}@media (prefers-reduced-motion:no-preference){._frame_1doa7_2>svg{animation:_cascivo-chart-in_1doa7_1 var(--cascivo-chart-anim-dur,.32s) var(--cascivo-chart-anim-ease,ease-out) both}@keyframes _cascivo-chart-in_1doa7_1{0%{opacity:0;transform:translateY(4px)}to{opacity:1;transform:translateY(0)}}._frame_1doa7_2 svg :is(path,rect,circle,line)[data-series],._frame_1doa7_2 svg path[data-link],._frame_1doa7_2 svg path[data-depth],._frame_1doa7_2 svg rect[data-day]{transition-property:var(--cascivo-chart-anim-props,opacity, fill, fill-opacity);transition-duration:var(--cascivo-chart-anim-dur,.24s);transition-timing-function:var(--cascivo-chart-anim-ease,ease)}._frame_1doa7_2[data-no-anim]>svg{animation:none}._frame_1doa7_2[data-no-anim] svg :is(path,rect,circle,line)[data-series],._frame_1doa7_2[data-no-anim] svg path[data-link],._frame_1doa7_2[data-no-anim] svg path[data-depth],._frame_1doa7_2[data-no-anim] svg rect[data-day]{transition:none}}._fallback_1doa7_53{clip-path:inset(50%);white-space:nowrap;block-size:1px;inline-size:1px;position:absolute;inset-inline-start:-9999px;overflow:hidden}._legend_zczeh_2{gap:var(--cascivo-space-2);padding-block:var(--cascivo-space-2);flex-wrap:wrap;display:flex}._item_zczeh_9{align-items:center;gap:var(--cascivo-space-1);padding:var(--cascivo-space-1) var(--cascivo-space-2);border:1px solid var(--cascivo-color-border);border-radius:var(--cascivo-radius-sm);cursor:pointer;font-size:var(--cascivo-font-size-sm);color:var(--cascivo-color-text);transition:opacity var(--cascivo-duration-150,.15s) ease;background:0 0;display:flex}._item_zczeh_9[data-state=off]{opacity:.4}._swatch_zczeh_27{border-radius:2px;flex-shrink:0;block-size:12px;inline-size:12px;display:inline-block}}
1
+ @layer cascivo.component{._frame_1xxqo_2{inline-size:100%;position:relative}._frame_1xxqo_2>svg{block-size:auto;max-inline-size:100%}@media (prefers-reduced-motion:no-preference){._frame_1xxqo_2>svg{animation:_cascivo-chart-in_1xxqo_1 var(--cascivo-chart-anim-dur,.32s) var(--cascivo-chart-anim-ease,ease-out) both}@keyframes _cascivo-chart-in_1xxqo_1{0%{opacity:0;transform:translateY(4px)}to{opacity:1;transform:translateY(0)}}._frame_1xxqo_2 svg :is(path,rect,circle,line)[data-series],._frame_1xxqo_2 svg path[data-link],._frame_1xxqo_2 svg path[data-depth],._frame_1xxqo_2 svg rect[data-day]{transition-property:var(--cascivo-chart-anim-props,opacity, fill, fill-opacity);transition-duration:var(--cascivo-chart-anim-dur,.24s);transition-timing-function:var(--cascivo-chart-anim-ease,ease)}._frame_1xxqo_2[data-no-anim]>svg{animation:none}._frame_1xxqo_2[data-no-anim] svg :is(path,rect,circle,line)[data-series],._frame_1xxqo_2[data-no-anim] svg path[data-link],._frame_1xxqo_2[data-no-anim] svg path[data-depth],._frame_1xxqo_2[data-no-anim] svg rect[data-day]{transition:none}}._fallback_1xxqo_62{clip-path:inset(50%);white-space:nowrap;block-size:1px;inline-size:1px;position:absolute;inset-inline-start:-9999px;overflow:hidden}._legend_zczeh_2{gap:var(--cascivo-space-2);padding-block:var(--cascivo-space-2);flex-wrap:wrap;display:flex}._item_zczeh_9{align-items:center;gap:var(--cascivo-space-1);padding:var(--cascivo-space-1) var(--cascivo-space-2);border:1px solid var(--cascivo-color-border);border-radius:var(--cascivo-radius-sm);cursor:pointer;font-size:var(--cascivo-font-size-sm);color:var(--cascivo-color-text);transition:opacity var(--cascivo-duration-150,.15s) ease;background:0 0;display:flex}._item_zczeh_9[data-state=off]{opacity:.4}._swatch_zczeh_27{border-radius:2px;flex-shrink:0;block-size:12px;inline-size:12px;display:inline-block}}
2
2
  /*$vite$:1*/
package/dist/index.d.ts CHANGED
@@ -765,7 +765,15 @@ interface ZoomConfig {
765
765
  interface ChartFrameProps {
766
766
  title: string;
767
767
  description?: string | undefined;
768
+ /**
769
+ * Fixed SVG width in px. **Omit it (the default) for a responsive chart** — the
770
+ * frame fills and tracks its container's width via `ResizeObserver`. Set a fixed
771
+ * width only for a fixed-size export or thumbnail; even then it is clamped to the
772
+ * container (`max-inline-size: 100%`) so it can never overflow its card.
773
+ */
768
774
  width?: number | undefined;
775
+ /** SVG height in px. Defaults to 300 (48 in `plain` mode). Unlike `width`, height
776
+ * does not track the container — set it to change the chart's aspect. */
769
777
  height?: number | undefined;
770
778
  fallback?: ReactNode;
771
779
  children: (size: {
@@ -847,6 +855,20 @@ interface ChartSize {
847
855
  width: number;
848
856
  height: number;
849
857
  }
858
+ /**
859
+ * Measure a container and track its size in signals. **Every cascivo chart already
860
+ * uses this internally** — charts are responsive by default and fill their
861
+ * container, so you do NOT need this to make a chart responsive (just omit the
862
+ * chart's `width`). Reach for it only to size *another* element to match a chart,
863
+ * or to build a custom chart on the same measurement primitive.
864
+ *
865
+ * Returns `{ ref, width, height }`: spread `ref` onto the element to measure; read
866
+ * `width.value` / `height.value` (they update on resize via a `ResizeObserver`,
867
+ * deferred one frame to avoid the "ResizeObserver loop" warning). Under SSR (no
868
+ * `ResizeObserver`) it falls back to a single `getBoundingClientRect()` read, so
869
+ * the first paint has a sensible size. `defaultWidth` seeds the signal only until
870
+ * the first real measurement lands.
871
+ */
850
872
  declare function useChartSize(defaultWidth?: number, defaultHeight?: number): {
851
873
  ref: React.RefObject<HTMLDivElement | null>;
852
874
  width: import('@preact/signals-react').Signal<number>;
@@ -865,6 +887,19 @@ declare const PLAIN_MARGINS: {
865
887
  readonly bottom: 2;
866
888
  readonly left: 2;
867
889
  };
890
+ /**
891
+ * Left margin sized to the widest left-axis label so wide ticks (e.g. `40,000`)
892
+ * aren't clipped past the SVG's `0` origin. The default 36px only fits ~4 glyphs;
893
+ * a 6-glyph thousands label needs ~45px. `plain` charts keep their tiny margin.
894
+ */
895
+ declare function leftMarginForLabels(leftAxisLabels: readonly string[], plain: boolean | undefined): number;
896
+ /**
897
+ * Stride for a crowded categorical (band) axis: render every Nth label so they stop
898
+ * colliding (e.g. 14 `Jul 1`…`Jul 14` dates in a narrow chart). Returns `undefined`
899
+ * when every label fits — callers pass that straight to `Axis.labelEvery` (all shown).
900
+ * An explicit `xLabelEvery` from the caller always overrides this.
901
+ */
902
+ declare function autoLabelStride(labels: readonly string[], axisLength: number): number | undefined;
868
903
  /**
869
904
  * Pure index-window math shared by the DataZoom slider and the in-plot wheel/drag
870
905
  * zoom-pan. A "window" is an inclusive `[startIndex, endIndex]` over a series of
@@ -1272,7 +1307,12 @@ interface AreaChartProps<Datum = {
1272
1307
  y: number;
1273
1308
  }> {
1274
1309
  series: readonly AreaChartSeries<Datum>[];
1275
- x: (d: Datum) => number;
1310
+ /**
1311
+ * X-value accessor. Return a `number` for a numeric axis, or a `Date` for a
1312
+ * time axis — when the values are Dates the chart uses a time scale and formats
1313
+ * ticks as dates (parity with `LineChart`). One x-domain per chart.
1314
+ */
1315
+ x: (d: Datum) => number | Date;
1276
1316
  /**
1277
1317
  * Y-value accessor, applied to **every** series' data unless a series provides
1278
1318
  * its own `y`. There is one x-domain per chart, so `x` is chart-level only; to
@@ -2089,4 +2129,4 @@ declare function Gauge({
2089
2129
  className,
2090
2130
  plain
2091
2131
  }: GaugeProps): import("react").JSX.Element;
2092
- export { AggOp, AggregateSpec, AngleBand, Annotation, AnnotationContext, AnnotationScale, AreaChart, AreaChartProps, AreaChartSeries, AreaDecimateOptions, Axis, AxisProps, BandScale, BarChart, BarChartProps, BarChartSeries, Bin, BoundStream, BoxStats, Boxplot, BoxplotProps, BoxplotSeries, Brush, BrushProps, BubbleChart, BubbleChartProps, BubbleDatum, BubbleSeries, Bullet, BulletProps, Calendar, CalendarDatum, CalendarProps, Candlestick, CandlestickDatum, CandlestickProps, CanvasLayer, CanvasLayerProps, CanvasPaint, CanvasSize, CategoryDatum, CategoryMapping, ChartDefs, ChartDefsProps, ChartFrame, ChartFrameProps, ChartSize, ComboChart, ComboChartBar, ComboChartPoint, ComboChartProps, Curve, DEFAULT_MARGINS, DataLabel, DataLabelProps, DataZoom, DataZoomProps, DecimateMethod, DecimateOptions, DefSeries, EncodeMapping, EncodedResult, EncodedSeries, FillKind, Funnel, FunnelProps, FunnelStage, Gauge, GaugeProps, GaugeThreshold, Glyph, GlyphProps, GlyphShape, GridLines, GridLinesProps, Heatmap, HeatmapDatum, HeatmapProps, HierNode, Histogram, HistogramBin, HistogramProps, Kpi, KpiProps, LabelOptions, LaidLink, LaidNode, Legend, LegendProps, LegendSeries, LineChart, LineChartProps, LineChartSeries, LinearScale, LogScale, Meter, MeterProps, MeterThresholds, PLAIN_MARGINS, PartitionedNode, PatternKind, PieChart, PieChartDatum, PieChartProps, Point, Polar, PolarDatum, PolarProps, Pt, Radar, RadarProps, RadarSeries, RadialBar, RadialBarDatum, RadialBarProps, RampKind, Rect, RegressionResult, RegressionType, ResolvedLabelOptions, Row, Sankey, SankeyLayout, SankeyLink, SankeyNode, SankeyOptions, SankeyProps, ScatterChart, ScatterChartProps, ScatterChartSeries, ScatterDatum, Sparkline, SparklineProps, StackedRow, StackedSegment, Stream, StreamDecimate, StreamOffset, StreamProps, StreamSeries, StreamSeriesOptions, StreamSource, Sunburst, SunburstProps, SyncGroup, Text, TextProps, TimeScale, Toolbox, ToolboxOptions, ToolboxProps, Treemap, TreemapDatum, TreemapNode, TreemapProps, TreemapRect, Vec, VisualChannel, VisualMap, VisualMapOptions, VisualMapProps, VisualMode, VisualResult, ZoomConfig, _syncGroupCount, aggregate, angleBand, annotationSummary, arcPath, areaPath, bandScale, bin, binValues, bindStream, boxStats, cellPath, decimate$1 as decimate, divergingRamp, download, encode, encodeCategory, extent, fillFor, filter, getSyncGroup, glyphPath, gradientId, isZoomed, linePath, linearScale, linkPath, logScale, lttb, mapVisual, maxDepth, minmax, nearestIndex, niceTicks, panWindow, partition, patternId, pieceIndex, polarPoint, quantize, radiusScale, rampLightness, rampOf, rampStops, regression, releaseSyncGroup, renderAnnotation, renderAnnotations, resolveColor, resolveLabels, sankeyLayout, sequentialRamp, serializeSvg, sort, splitDefined, sqrtScale, squarify, stackSeries, streamExtent, streamLayout, sumValue, svgToPngBlob, timeScale, toStackedSeries, useChartSize, useStreamSeries, visualVisible, voronoiCells, voronoiFind, wrapText, zoomWindow };
2132
+ export { AggOp, AggregateSpec, AngleBand, Annotation, AnnotationContext, AnnotationScale, AreaChart, AreaChartProps, AreaChartSeries, AreaDecimateOptions, Axis, AxisProps, BandScale, BarChart, BarChartProps, BarChartSeries, Bin, BoundStream, BoxStats, Boxplot, BoxplotProps, BoxplotSeries, Brush, BrushProps, BubbleChart, BubbleChartProps, BubbleDatum, BubbleSeries, Bullet, BulletProps, Calendar, CalendarDatum, CalendarProps, Candlestick, CandlestickDatum, CandlestickProps, CanvasLayer, CanvasLayerProps, CanvasPaint, CanvasSize, CategoryDatum, CategoryMapping, ChartDefs, ChartDefsProps, ChartFrame, ChartFrameProps, ChartSize, ComboChart, ComboChartBar, ComboChartPoint, ComboChartProps, Curve, DEFAULT_MARGINS, DataLabel, DataLabelProps, DataZoom, DataZoomProps, DecimateMethod, DecimateOptions, DefSeries, EncodeMapping, EncodedResult, EncodedSeries, FillKind, Funnel, FunnelProps, FunnelStage, Gauge, GaugeProps, GaugeThreshold, Glyph, GlyphProps, GlyphShape, GridLines, GridLinesProps, Heatmap, HeatmapDatum, HeatmapProps, HierNode, Histogram, HistogramBin, HistogramProps, Kpi, KpiProps, LabelOptions, LaidLink, LaidNode, Legend, LegendProps, LegendSeries, LineChart, LineChartProps, LineChartSeries, LinearScale, LogScale, Meter, MeterProps, MeterThresholds, PLAIN_MARGINS, PartitionedNode, PatternKind, PieChart, PieChartDatum, PieChartProps, Point, Polar, PolarDatum, PolarProps, Pt, Radar, RadarProps, RadarSeries, RadialBar, RadialBarDatum, RadialBarProps, RampKind, Rect, RegressionResult, RegressionType, ResolvedLabelOptions, Row, Sankey, SankeyLayout, SankeyLink, SankeyNode, SankeyOptions, SankeyProps, ScatterChart, ScatterChartProps, ScatterChartSeries, ScatterDatum, Sparkline, SparklineProps, StackedRow, StackedSegment, Stream, StreamDecimate, StreamOffset, StreamProps, StreamSeries, StreamSeriesOptions, StreamSource, Sunburst, SunburstProps, SyncGroup, Text, TextProps, TimeScale, Toolbox, ToolboxOptions, ToolboxProps, Treemap, TreemapDatum, TreemapNode, TreemapProps, TreemapRect, Vec, VisualChannel, VisualMap, VisualMapOptions, VisualMapProps, VisualMode, VisualResult, ZoomConfig, _syncGroupCount, aggregate, angleBand, annotationSummary, arcPath, areaPath, autoLabelStride, bandScale, bin, binValues, bindStream, boxStats, cellPath, decimate$1 as decimate, divergingRamp, download, encode, encodeCategory, extent, fillFor, filter, getSyncGroup, glyphPath, gradientId, isZoomed, leftMarginForLabels, linePath, linearScale, linkPath, logScale, lttb, mapVisual, maxDepth, minmax, nearestIndex, niceTicks, panWindow, partition, patternId, pieceIndex, polarPoint, quantize, radiusScale, rampLightness, rampOf, rampStops, regression, releaseSyncGroup, renderAnnotation, renderAnnotations, resolveColor, resolveLabels, sankeyLayout, sequentialRamp, serializeSvg, sort, splitDefined, sqrtScale, squarify, stackSeries, streamExtent, streamLayout, sumValue, svgToPngBlob, timeScale, toStackedSeries, useChartSize, useStreamSeries, visualVisible, voronoiCells, voronoiFind, wrapText, zoomWindow };