semiotic 3.4.1 → 3.5.0

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.
Files changed (164) hide show
  1. package/CLAUDE.md +114 -9
  2. package/README.md +45 -4
  3. package/ai/behaviorContracts.cjs +311 -0
  4. package/ai/chartSuggestions.cjs +291 -0
  5. package/ai/cli.js +255 -30
  6. package/ai/componentMetadata.cjs +107 -0
  7. package/ai/dist/mcp-server.js +907 -227
  8. package/ai/schema.json +3954 -2537
  9. package/ai/system-prompt.md +23 -4
  10. package/dist/components/LinkedCharts.d.ts +5 -1
  11. package/dist/components/Tooltip/Tooltip.d.ts +1 -1
  12. package/dist/components/charts/custom/NetworkCustomChart.d.ts +64 -0
  13. package/dist/components/charts/custom/OrdinalCustomChart.d.ts +71 -0
  14. package/dist/components/charts/custom/XYCustomChart.d.ts +59 -0
  15. package/dist/components/charts/geo/ChoroplethMap.d.ts +93 -2
  16. package/dist/components/charts/geo/DistanceCartogram.d.ts +51 -4
  17. package/dist/components/charts/geo/FlowMap.d.ts +55 -0
  18. package/dist/components/charts/geo/ProportionalSymbolMap.d.ts +53 -0
  19. package/dist/components/charts/index.d.ts +6 -0
  20. package/dist/components/charts/network/ChordDiagram.d.ts +34 -2
  21. package/dist/components/charts/network/CirclePack.d.ts +36 -1
  22. package/dist/components/charts/network/ForceDirectedGraph.d.ts +130 -2
  23. package/dist/components/charts/network/OrbitDiagram.d.ts +37 -0
  24. package/dist/components/charts/network/SankeyDiagram.d.ts +51 -2
  25. package/dist/components/charts/network/TreeDiagram.d.ts +37 -2
  26. package/dist/components/charts/network/Treemap.d.ts +36 -2
  27. package/dist/components/charts/ordinal/BarChart.d.ts +111 -1
  28. package/dist/components/charts/ordinal/BoxPlot.d.ts +31 -0
  29. package/dist/components/charts/ordinal/DonutChart.d.ts +36 -0
  30. package/dist/components/charts/ordinal/DotPlot.d.ts +31 -0
  31. package/dist/components/charts/ordinal/FunnelChart.d.ts +40 -0
  32. package/dist/components/charts/ordinal/GaugeChart.d.ts +45 -0
  33. package/dist/components/charts/ordinal/GroupedBarChart.d.ts +38 -0
  34. package/dist/components/charts/ordinal/Histogram.d.ts +95 -0
  35. package/dist/components/charts/ordinal/LikertChart.d.ts +42 -0
  36. package/dist/components/charts/ordinal/PieChart.d.ts +90 -1
  37. package/dist/components/charts/ordinal/RidgelinePlot.d.ts +27 -0
  38. package/dist/components/charts/ordinal/StackedBarChart.d.ts +38 -0
  39. package/dist/components/charts/ordinal/SwarmPlot.d.ts +36 -0
  40. package/dist/components/charts/ordinal/SwimlaneChart.d.ts +60 -0
  41. package/dist/components/charts/ordinal/ViolinPlot.d.ts +32 -0
  42. package/dist/components/charts/realtime/RealtimeHeatmap.d.ts +22 -4
  43. package/dist/components/charts/realtime/RealtimeHistogram.d.ts +5 -2
  44. package/dist/components/charts/realtime/RealtimeLineChart.d.ts +24 -3
  45. package/dist/components/charts/realtime/RealtimeSwarmChart.d.ts +12 -0
  46. package/dist/components/charts/realtime/RealtimeWaterfallChart.d.ts +14 -0
  47. package/dist/components/charts/realtime/defaultRealtimeTooltip.d.ts +43 -0
  48. package/dist/components/charts/realtime/resolveWindowSize.d.ts +26 -0
  49. package/dist/components/charts/shared/chartSpecs.d.ts +91 -0
  50. package/dist/components/charts/shared/colorPalettes.d.ts +62 -0
  51. package/dist/components/charts/shared/colorUtils.d.ts +9 -10
  52. package/dist/components/charts/shared/numberFormat.d.ts +58 -0
  53. package/dist/components/charts/shared/sparseArray.d.ts +27 -0
  54. package/dist/components/charts/shared/streamPropsHelpers.d.ts +113 -0
  55. package/dist/components/charts/shared/timeFormat.d.ts +60 -0
  56. package/dist/components/charts/shared/useChartSetup.d.ts +8 -0
  57. package/dist/components/charts/shared/useCustomChartSetup.d.ts +84 -0
  58. package/dist/components/charts/shared/useFrameImperativeHandle.d.ts +28 -0
  59. package/dist/components/charts/shared/useOrdinalStreaming.d.ts +6 -19
  60. package/dist/components/charts/shared/useStreamingLegend.d.ts +27 -11
  61. package/dist/components/charts/shared/validateProps.d.ts +2 -2
  62. package/dist/components/charts/shared/validationMap.d.ts +2 -1
  63. package/dist/components/charts/shared/withChartWrapper.d.ts +13 -4
  64. package/dist/components/charts/xy/AreaChart.d.ts +30 -1
  65. package/dist/components/charts/xy/CandlestickChart.d.ts +33 -6
  66. package/dist/components/charts/xy/ConnectedScatterplot.d.ts +24 -0
  67. package/dist/components/charts/xy/MinimapChart.d.ts +51 -0
  68. package/dist/components/charts/xy/MultiAxisLineChart.d.ts +27 -0
  69. package/dist/components/charts/xy/QuadrantChart.d.ts +21 -0
  70. package/dist/components/charts/xy/Scatterplot.d.ts +34 -2
  71. package/dist/components/charts/xy/ScatterplotMatrix.d.ts +16 -0
  72. package/dist/components/charts/xy/StackedAreaChart.d.ts +49 -1
  73. package/dist/components/export/selectionSerializer.d.ts +1 -1
  74. package/dist/components/realtime/types.d.ts +7 -9
  75. package/dist/components/recipes/bullet.d.ts +86 -0
  76. package/dist/components/recipes/calendar.d.ts +43 -0
  77. package/dist/components/recipes/dagre.d.ts +56 -0
  78. package/dist/components/recipes/flextree.d.ts +55 -0
  79. package/dist/components/recipes/marimekko.d.ts +55 -0
  80. package/dist/components/recipes/parallelCoordinates.d.ts +97 -0
  81. package/dist/components/recipes/recipeUtils.d.ts +27 -0
  82. package/dist/components/recipes/waffle.d.ts +46 -0
  83. package/dist/components/semiotic-ai.d.ts +4 -0
  84. package/dist/components/semiotic-network.d.ts +3 -0
  85. package/dist/components/semiotic-ordinal.d.ts +3 -0
  86. package/dist/components/semiotic-recipes.d.ts +24 -0
  87. package/dist/components/semiotic-xy.d.ts +3 -0
  88. package/dist/components/semiotic.d.ts +2 -2
  89. package/dist/components/server/renderToStaticSVG.d.ts +8 -2
  90. package/dist/components/server/serverChartConfigs.d.ts +47 -1
  91. package/dist/components/server/staticAnnotations.d.ts +6 -0
  92. package/dist/components/store/ObservationStore.d.ts +1 -3
  93. package/dist/components/store/SelectionStore.d.ts +2 -4
  94. package/dist/components/store/ThemeStore.d.ts +4 -4
  95. package/dist/components/store/TooltipStore.d.ts +5 -3
  96. package/dist/components/store/createStore.d.ts +4 -2
  97. package/dist/components/store/useSelection.d.ts +7 -4
  98. package/dist/components/stream/CanvasHitTester.d.ts +10 -8
  99. package/dist/components/stream/DataSourceAdapter.d.ts +9 -0
  100. package/dist/components/stream/GeoPipelineStore.d.ts +9 -0
  101. package/dist/components/stream/GeoTileRenderer.d.ts +14 -0
  102. package/dist/components/stream/NetworkPipelineStore.d.ts +25 -0
  103. package/dist/components/stream/NetworkSVGOverlay.d.ts +18 -12
  104. package/dist/components/stream/OrdinalPipelineStore.d.ts +12 -0
  105. package/dist/components/stream/PipelineStore.d.ts +51 -0
  106. package/dist/components/stream/SVGOverlay.d.ts +12 -0
  107. package/dist/components/stream/SceneGraph.d.ts +15 -1
  108. package/dist/components/stream/SceneToSVG.d.ts +1 -1
  109. package/dist/components/stream/categoryDomain.d.ts +4 -0
  110. package/dist/components/stream/composeOverlays.d.ts +15 -0
  111. package/dist/components/stream/customLayout.d.ts +76 -0
  112. package/dist/components/stream/customLayoutPalette.d.ts +29 -0
  113. package/dist/components/stream/geoTypes.d.ts +33 -8
  114. package/dist/components/stream/hoverUtils.d.ts +4 -10
  115. package/dist/components/stream/keyboardNav.d.ts +18 -6
  116. package/dist/components/stream/networkCustomLayout.d.ts +67 -0
  117. package/dist/components/stream/networkTypes.d.ts +87 -21
  118. package/dist/components/stream/ordinalCustomLayout.d.ts +84 -0
  119. package/dist/components/stream/ordinalTypes.d.ts +47 -13
  120. package/dist/components/stream/renderers/barFunnelCanvasRenderer.d.ts +9 -1
  121. package/dist/components/stream/renderers/canvasRenderHelpers.d.ts +92 -0
  122. package/dist/components/stream/sampleCurvePath.d.ts +9 -0
  123. package/dist/components/stream/types.d.ts +57 -10
  124. package/dist/components/stream/useHydration.d.ts +89 -0
  125. package/dist/components/stream/useStableShallow.d.ts +1 -0
  126. package/dist/components/stream/xySceneBuilders/types.d.ts +4 -0
  127. package/dist/geo.min.js +2 -1
  128. package/dist/geo.module.min.js +2 -1
  129. package/dist/network.min.js +2 -1
  130. package/dist/network.module.min.js +2 -1
  131. package/dist/ordinal.min.js +2 -1
  132. package/dist/ordinal.module.min.js +2 -1
  133. package/dist/realtime.min.js +2 -1
  134. package/dist/realtime.module.min.js +2 -1
  135. package/dist/semiotic-ai.d.ts +69 -65
  136. package/dist/semiotic-ai.min.js +2 -1
  137. package/dist/semiotic-ai.module.min.js +2 -1
  138. package/dist/semiotic-data.d.ts +4 -4
  139. package/dist/semiotic-geo.d.ts +15 -15
  140. package/dist/semiotic-network.d.ts +19 -16
  141. package/dist/semiotic-ordinal.d.ts +31 -28
  142. package/dist/semiotic-realtime.d.ts +17 -17
  143. package/dist/semiotic-recipes.d.ts +24 -0
  144. package/dist/semiotic-recipes.min.js +1 -0
  145. package/dist/semiotic-recipes.module.min.js +1 -0
  146. package/dist/semiotic-server.d.ts +6 -6
  147. package/dist/semiotic-statisticalOverlays-C3DsOgr_.js +1 -0
  148. package/dist/semiotic-themes.d.ts +3 -3
  149. package/dist/semiotic-themes.min.js +2 -1
  150. package/dist/semiotic-themes.module.min.js +2 -1
  151. package/dist/semiotic-utils.d.ts +23 -23
  152. package/dist/semiotic-utils.min.js +2 -1
  153. package/dist/semiotic-utils.module.min.js +2 -1
  154. package/dist/semiotic-xy.d.ts +27 -24
  155. package/dist/semiotic.d.ts +63 -63
  156. package/dist/semiotic.min.js +2 -1
  157. package/dist/semiotic.module.min.js +2 -1
  158. package/dist/server.min.js +1 -1
  159. package/dist/server.module.min.js +1 -1
  160. package/dist/test-utils/canvasMock.d.ts +34 -5
  161. package/dist/xy.min.js +2 -1
  162. package/dist/xy.module.min.js +2 -1
  163. package/package.json +40 -20
  164. package/dist/semiotic-statisticalOverlays-Ckd_jM8z.js +0 -1
@@ -0,0 +1,84 @@
1
+ import type { ReactNode } from "react";
2
+ import type { ScaleBand, ScaleLinear } from "d3-scale";
3
+ import type { Datum } from "../charts/shared/datumTypes";
4
+ import type { MarginType } from "../types/marginType";
5
+ import type { OrdinalSceneNode, OrdinalScales } from "./ordinalTypes";
6
+ import type { ThemeSemanticColors } from "./types";
7
+ /**
8
+ * customLayout escape hatch for `StreamOrdinalFrame`.
9
+ *
10
+ * Mirrors the XY `CustomLayout` and network `NetworkCustomLayout` patterns.
11
+ * Reach for it when the catalog (bar, swarm, pie, box, ...) doesn't fit:
12
+ * marimekko, parallel coordinates, bullet charts, fan charts, slope graphs
13
+ * and similar are all natural ordinal customLayouts.
14
+ *
15
+ * The frame still owns hit testing, transitions, decay, theme cascade,
16
+ * and SSR — the layout owns geometry only. Emit standard scene nodes
17
+ * (`rect`, `point`, `wedge`, `boxplot`, `violin`, `connector`, `trapezoid`)
18
+ * and the frame handles the rest.
19
+ */
20
+ export type OrdinalCustomLayout<C extends object = Record<string, unknown>> = (ctx: OrdinalLayoutContext<C>) => OrdinalLayoutResult;
21
+ export interface OrdinalLayoutContext<C extends object = Record<string, unknown>> {
22
+ /** Buffered, post-filter data the frame is currently drawing. */
23
+ data: Datum[];
24
+ /**
25
+ * Frame-built scales. `o` is the band scale over categories
26
+ * (insertion-ordered by default; flip via `oSort`). `r` is the linear
27
+ * value scale. Their domains/ranges respect `oExtent`/`rExtent` if you
28
+ * passed them on the chart.
29
+ */
30
+ scales: {
31
+ o: ScaleBand<string>;
32
+ r: ScaleLinear<number, number>;
33
+ projection: OrdinalScales["projection"];
34
+ };
35
+ /**
36
+ * Plot-area geometry. The canvas/SVG group is already translated by
37
+ * the frame, so scene-node coordinates are *plot-local* — but the
38
+ * origin depends on `scales.projection`:
39
+ *
40
+ * - `vertical` / `horizontal`: origin is the **top-left** of the
41
+ * plot rect. `plot = { x: 0, y: 0, width, height }`.
42
+ * - `radial`: origin is the **center** of the plot rect. The frame
43
+ * translates the context to `(margin.left + width/2, margin.top
44
+ * + height/2)` so radial layouts emit coordinates around 0,0.
45
+ * `plot = { x: -width/2, y: -height/2, width, height }` — the
46
+ * top-left of the visible plot rect lives at `(plot.x, plot.y)`
47
+ * in your coord space.
48
+ *
49
+ * In both cases `plot.width` and `plot.height` describe the plot rect.
50
+ * Read `margin` if you need the outer canvas size.
51
+ */
52
+ dimensions: {
53
+ width: number;
54
+ height: number;
55
+ margin: MarginType;
56
+ plot: {
57
+ x: number;
58
+ y: number;
59
+ width: number;
60
+ height: number;
61
+ };
62
+ };
63
+ /** Theme-resolved semantic + categorical colors. */
64
+ theme: {
65
+ semantic: ThemeSemanticColors;
66
+ categorical: string[];
67
+ };
68
+ /**
69
+ * Resolves a stable color for a given key (typically a category
70
+ * label) from the frame's categorical palette. Palette precedence:
71
+ * explicit `colorScheme` (array or named d3 scheme like `"tableau10"`)
72
+ * → theme categorical → fallback. The same key always returns the
73
+ * same color for the lifetime of this store.
74
+ */
75
+ resolveColor: (key: string) => string;
76
+ /** User-supplied config blob threaded through `layoutConfig`. */
77
+ config: C;
78
+ }
79
+ export interface OrdinalLayoutResult {
80
+ /** Scene nodes to render. Get hit testing, transitions, decay, SSR for free. */
81
+ nodes?: OrdinalSceneNode[];
82
+ /** SVG overlays composited above the canvas (labels, axis lines, annotations). */
83
+ overlays?: ReactNode;
84
+ }
@@ -1,11 +1,11 @@
1
1
  import type { ReactNode } from "react";
2
2
  import type { ScaleLinear, ScaleBand } from "d3-scale";
3
3
  import type { WindowMode, HoverAnnotationConfig, HoverData, AnnotationContext } from "../realtime/types";
4
- import type { Style, DecayConfig, PulseConfig, TransitionConfig, StalenessConfig, ThemeSemanticColors } from "./types";
4
+ import type { Style, SceneDatum, DecayConfig, PulseConfig, TransitionConfig, StalenessConfig, ThemeSemanticColors } from "./types";
5
5
  import type { AnimateProp } from "./pipelineTransitionUtils";
6
6
  import type { LegendGroup } from "../types/legendTypes";
7
7
  import type { Datum } from "../charts/shared/datumTypes";
8
- export type OrdinalChartType = "bar" | "clusterbar" | "point" | "swarm" | "pie" | "donut" | "boxplot" | "violin" | "histogram" | "ridgeline" | "timeline" | "funnel" | "bar-funnel" | "swimlane";
8
+ export type OrdinalChartType = "bar" | "clusterbar" | "point" | "swarm" | "pie" | "donut" | "boxplot" | "violin" | "histogram" | "ridgeline" | "timeline" | "funnel" | "bar-funnel" | "swimlane" | "custom";
9
9
  export interface OrdinalScales {
10
10
  o: ScaleBand<string>;
11
11
  r: ScaleLinear<number, number>;
@@ -24,7 +24,7 @@ export interface WedgeSceneNode {
24
24
  /** Corner radius for rounded wedge arcs (d3-shape arc.cornerRadius) */
25
25
  cornerRadius?: number;
26
26
  style: Style;
27
- datum: any;
27
+ datum: SceneDatum;
28
28
  category?: string;
29
29
  _pulseIntensity?: number;
30
30
  _pulseColor?: string;
@@ -50,13 +50,13 @@ export interface BoxplotSceneNode {
50
50
  maxPos: number;
51
51
  stats: DistributionStats;
52
52
  style: Style;
53
- datum: any;
53
+ datum: Datum;
54
54
  category?: string;
55
55
  outliers?: {
56
56
  px: number;
57
57
  py: number;
58
58
  value: number;
59
- datum: any;
59
+ datum: Datum;
60
60
  }[];
61
61
  _pulseIntensity?: number;
62
62
  _pulseColor?: string;
@@ -98,7 +98,7 @@ export interface ViolinSceneNode {
98
98
  /** Pre-computed distribution statistics for tooltips */
99
99
  stats?: DistributionStats;
100
100
  style: Style;
101
- datum: any;
101
+ datum: Datum;
102
102
  category?: string;
103
103
  _pulseIntensity?: number;
104
104
  _pulseColor?: string;
@@ -113,7 +113,7 @@ export interface ConnectorSceneNode {
113
113
  x2: number;
114
114
  y2: number;
115
115
  style: Style;
116
- datum: any;
116
+ datum: Datum;
117
117
  group?: string;
118
118
  _pulseIntensity?: number;
119
119
  _pulseColor?: string;
@@ -126,7 +126,7 @@ export interface TrapezoidSceneNode {
126
126
  /** Four corners: [top-left, top-right, bottom-right, bottom-left] */
127
127
  points: [number, number][];
128
128
  style: Style;
129
- datum: any;
129
+ datum: Datum;
130
130
  category?: string;
131
131
  _pulseIntensity?: number;
132
132
  _pulseColor?: string;
@@ -187,6 +187,14 @@ export interface OrdinalPipelineConfig {
187
187
  color: string;
188
188
  }>;
189
189
  };
190
+ /** Swimlane "track" fill — a rect drawn behind each lane spanning the
191
+ * full value-axis range, sized to the lane's bandwidth. Used to make
192
+ * budget/progress lanes read as filled vs. empty. Pass a color (CSS
193
+ * var supported) or `{ color, opacity }`. Honored by `chartType="swimlane"` only. */
194
+ trackFill?: string | {
195
+ color: string;
196
+ opacity?: number;
197
+ };
190
198
  /** When true, adds padding below the 0 baseline. When false (default), bars are flush with the axis line. */
191
199
  baselinePadding?: boolean;
192
200
  innerRadius?: number;
@@ -205,9 +213,9 @@ export interface OrdinalPipelineConfig {
205
213
  oSort?: ((a: string, b: string) => number) | boolean | "asc" | "desc" | "auto";
206
214
  connectorAccessor?: string | ((d: Datum) => string);
207
215
  connectorStyle?: Style | ((d: Datum) => Style);
208
- dynamicColumnWidth?: string | ((data: any[]) => number);
209
- pieceStyle?: (d: any, category?: string) => Style;
210
- summaryStyle?: (d: any, category?: string) => Style;
216
+ dynamicColumnWidth?: string | ((data: Datum[]) => number);
217
+ pieceStyle?: (d: Datum, category?: string) => Style;
218
+ summaryStyle?: (d: Datum, category?: string) => Style;
211
219
  colorScheme?: string | string[];
212
220
  themeCategorical?: string[];
213
221
  /** Theme-resolved semantic role colors — default fallback before hardcoded hex. See `ThemeSemanticColors` in ./types. */
@@ -225,6 +233,15 @@ export interface OrdinalPipelineConfig {
225
233
  /** Whether to animate elements on first render (bars grow from baseline, wedges sweep in) */
226
234
  introAnimation?: boolean;
227
235
  staleness?: StalenessConfig;
236
+ /** When provided, replaces chart-type dispatch in scene building.
237
+ * Receives an OrdinalLayoutContext (scales, dimensions, theme,
238
+ * resolveColor) and returns scene nodes plus optional overlays. */
239
+ customLayout?: import("./ordinalCustomLayout").OrdinalCustomLayout;
240
+ /** User-supplied config blob threaded through to OrdinalLayoutContext.config. */
241
+ layoutConfig?: object;
242
+ /** Resolved margin — passed through so OrdinalLayoutContext.dimensions.margin
243
+ * reflects what the frame actually used. */
244
+ layoutMargin?: import("../types/marginType").MarginType;
228
245
  }
229
246
  export interface StreamOrdinalFrameProps<T = Datum> {
230
247
  chartType: OrdinalChartType;
@@ -266,6 +283,11 @@ export interface StreamOrdinalFrameProps<T = Datum> {
266
283
  color: string;
267
284
  }>;
268
285
  };
286
+ /** Swimlane "track" fill — see OrdinalPipelineConfig.trackFill */
287
+ trackFill?: string | {
288
+ color: string;
289
+ opacity?: number;
290
+ };
269
291
  baselinePadding?: boolean;
270
292
  innerRadius?: number;
271
293
  cornerRadius?: number;
@@ -293,8 +315,8 @@ export interface StreamOrdinalFrameProps<T = Datum> {
293
315
  rTickValues?: number[];
294
316
  /** Align first tick label to start and last tick label to end. Default false. */
295
317
  tickLabelEdgeAlign?: boolean;
296
- pieceStyle?: (d: any, category?: string) => Style;
297
- summaryStyle?: (d: any, category?: string) => Style;
318
+ pieceStyle?: (d: Datum, category?: string) => Style;
319
+ summaryStyle?: (d: Datum, category?: string) => Style;
298
320
  colorScheme?: string | string[];
299
321
  barColors?: Record<string, string>;
300
322
  showAxes?: boolean;
@@ -336,6 +358,10 @@ export interface StreamOrdinalFrameProps<T = Datum> {
336
358
  legendHighlightedCategory?: string | null;
337
359
  legendIsolatedCategories?: Set<string>;
338
360
  legendPosition?: "right" | "left" | "top" | "bottom";
361
+ /** Accessor used to report the current legend category domain in push mode. */
362
+ legendCategoryAccessor?: string | ((d: T) => string);
363
+ /** Fires when the current legend category domain changes after scene rebuilds. */
364
+ onCategoriesChange?: (categories: string[]) => void;
339
365
  backgroundGraphics?: ReactNode;
340
366
  foregroundGraphics?: ReactNode;
341
367
  title?: string | ReactNode;
@@ -364,6 +390,14 @@ export interface StreamOrdinalFrameProps<T = Datum> {
364
390
  description?: string;
365
391
  /** Accessible summary rendered as a screen-reader-only note */
366
392
  summary?: string;
393
+ /** Replaces ordinal scene dispatch with a user-supplied function.
394
+ * Receives an OrdinalLayoutContext (scales, dimensions, theme,
395
+ * resolveColor), returns scene nodes + optional overlays. See
396
+ * `semiotic/recipes` for reference layouts (marimekko, parallel
397
+ * coordinates, bullet). */
398
+ customLayout?: import("./ordinalCustomLayout").OrdinalCustomLayout;
399
+ /** User-supplied config blob threaded through to OrdinalLayoutContext.config. */
400
+ layoutConfig?: object;
367
401
  }
368
402
  export interface StreamOrdinalFrameHandle<T = Datum> {
369
403
  push(datum: T): void;
@@ -7,6 +7,14 @@ export declare const barFunnelHatchRenderer: (ctx: CanvasRenderingContext2D, nod
7
7
  * - Bold percentage (of first step)
8
8
  * - Raw value below it
9
9
  *
10
- * Labels appear on a white rounded-rect background (matching the reference images).
10
+ * Light/dark mode is decided per-frame from the luminance of the
11
+ * resolved `--semiotic-text` value: if body text is light, we're in
12
+ * dark mode and pair a dark surface with light text; otherwise light
13
+ * mode (white surface, dark text). Pairing the background to whatever
14
+ * text color the consumer's theme actually emits is more robust than
15
+ * sourcing both from independent CSS variables — many sites set
16
+ * `--semiotic-text` and `--semiotic-bg` without setting
17
+ * `--semiotic-tooltip-bg`, which would otherwise leave the label box
18
+ * stuck on its fallback regardless of theme.
11
19
  */
12
20
  export declare const barFunnelLabelRenderer: (ctx: CanvasRenderingContext2D, nodes: OrdinalSceneNode[], _scales: OrdinalScales, _layout: OrdinalLayout) => void;
@@ -0,0 +1,92 @@
1
+ /**
2
+ * Shared canvas-rendering primitives used by `bar`/`area`/`line`/`point`
3
+ * renderers (and any future mark renderer that paints a fill, a stroke,
4
+ * or a linear gradient).
5
+ *
6
+ * These are extractions, not abstractions: every function in this module
7
+ * was inline-duplicated across two or more renderers in byte-identical
8
+ * (or near-identical) form. Centralizing them eliminates drift at the
9
+ * "what does the canvas seam look like for a stream renderer" boundary
10
+ * and keeps each renderer focused on its mark-specific path tracing.
11
+ *
12
+ * Anything genuinely chart-shape-specific — `buildBarGradient`'s
13
+ * tip-vs-base coordinate computation from `node.roundedEdge`, the
14
+ * area's strip-decay path, the line's threshold-color crossing logic —
15
+ * stays in the renderer that owns the mark. The helpers here are the
16
+ * mechanical bits that recur regardless of the shape being painted.
17
+ */
18
+ import type { CurveType } from "../types";
19
+ import type { CurveFactory } from "d3-shape";
20
+ /**
21
+ * Structural shapes for the gradient configs the helpers accept. Kept
22
+ * local rather than exported from `types.ts` because today's scene-node
23
+ * interfaces (`AreaSceneNode`, `RectSceneNode`, `LineSceneNode`) declare
24
+ * the same shapes inline. TS structural typing means a caller passing
25
+ * `node.fillGradient` satisfies these types without an explicit cast.
26
+ */
27
+ type ColorStop = {
28
+ offset: number;
29
+ color: string;
30
+ };
31
+ export type ColorStopGradient = {
32
+ colorStops: ColorStop[];
33
+ };
34
+ export type OpacityGradient = {
35
+ topOpacity: number;
36
+ bottomOpacity: number;
37
+ };
38
+ export type FillGradient = ColorStopGradient | OpacityGradient;
39
+ /**
40
+ * Map a `CurveType` string to a d3-shape curve factory. Returns `null`
41
+ * for `"linear"` and `undefined` so callers can branch on a single
42
+ * "use linear fallback" sentinel instead of a separate has-curve check.
43
+ *
44
+ * Identical implementations previously lived in `areaCanvasRenderer.ts`
45
+ * and `lineCanvasRenderer.ts` — every new curve token had to be added
46
+ * to both switches in lockstep.
47
+ */
48
+ export declare function resolveCurveFactory(curve: CurveType | undefined): CurveFactory | null;
49
+ /**
50
+ * Resolve a node's `style.fill` (or `style.stroke`) to something the
51
+ * canvas can accept as `fillStyle` / `strokeStyle`:
52
+ *
53
+ * - Strings go through `resolveCSSColor` so `var(...)` references
54
+ * resolve via the canvas DOM ancestor's computed style. Without
55
+ * this, canvas silently rejects CSS-variable strings and falls
56
+ * back to `#000000`.
57
+ * - `CanvasPattern` values pass through untouched.
58
+ * - `null` / `undefined` returns the caller-provided fallback.
59
+ *
60
+ * The previous inline form was
61
+ * `(typeof X === "string" ? resolveCSSColor(ctx, X) : X) || fallback`,
62
+ * repeated once per renderer per fill/stroke site.
63
+ */
64
+ export declare function resolveCanvasFill(ctx: CanvasRenderingContext2D, fill: string | CanvasPattern | null | undefined, fallback: string): string | CanvasPattern;
65
+ /**
66
+ * Build a linear gradient from a `FillGradient` config. Returns `null`
67
+ * when the gradient cannot be constructed (fewer than two valid color
68
+ * stops in the `colorStops` form, or a non-finite opacity in the
69
+ * `topOpacity` form).
70
+ *
71
+ * The renderer is responsible for choosing the gradient axis (a bar
72
+ * runs tip→base along its value axis; an area runs minTop→maxBottom
73
+ * vertically). The opacity-form path color-normalizes through the
74
+ * canvas via `parseCanvasColor` so named colors (`steelblue`), hsl(),
75
+ * etc. all produce gradients that match the mark's actual fill.
76
+ *
77
+ * Replaces `buildBarGradient` (bar) and the inline gradient block in
78
+ * `areaCanvasRenderer` — both implemented the same two-shape switch
79
+ * with the same offset-clamping and the same parseCanvasColor flow.
80
+ */
81
+ export declare function buildLinearFillGradient(ctx: CanvasRenderingContext2D, fillGradient: FillGradient, baseFill: string, x0: number, y0: number, x1: number, y1: number): CanvasGradient | null;
82
+ /**
83
+ * Build a linear gradient from a `ColorStopGradient` (the stroke-side
84
+ * shape — only the `colorStops` form, no opacity variant). Returns
85
+ * `null` when there aren't enough valid stops to render a gradient.
86
+ *
87
+ * Caller picks the axis. Identical patterns previously lived inline in
88
+ * `areaCanvasRenderer`'s top-stroke branch and `lineCanvasRenderer`'s
89
+ * stroke branch.
90
+ */
91
+ export declare function buildColorStopGradient(ctx: CanvasRenderingContext2D, strokeGradient: ColorStopGradient, x0: number, y0: number, x1: number, y1: number): CanvasGradient | null;
92
+ export {};
@@ -0,0 +1,9 @@
1
+ import type { CurveFactory } from "d3-shape";
2
+ /**
3
+ * Sample a d3-shape curve through `points` into a dense polyline.
4
+ *
5
+ * Returns the same `points` array unchanged when `curveFactory` is
6
+ * null — caller should treat that as the linear case (no resampling
7
+ * needed).
8
+ */
9
+ export declare function sampleCurvePath(points: ReadonlyArray<readonly [number, number]>, curveFactory: CurveFactory | null, samplesPerSegment?: number): [number, number][];
@@ -1,8 +1,12 @@
1
1
  import type { ReactNode } from "react";
2
2
  import type { ScaleLinear } from "d3-scale";
3
3
  import type { AnimateProp } from "./pipelineTransitionUtils";
4
+ import type { LegendGroup, GradientLegendConfig } from "../types/legendTypes";
4
5
  import type { ArrowOfTime, WindowMode, LineStyle, BarStyle, WaterfallStyle, SwarmStyle, HoverAnnotationConfig, HoverData, AnnotationContext, AnnotationAnchorMode } from "../realtime/types";
5
6
  import type { Datum } from "../charts/shared/datumTypes";
7
+ export type SceneDatum = Datum | null;
8
+ export type SeriesDatum = Datum[] | null;
9
+ export type AxisTickFormat = ((d: number, index?: number, allTicks?: number[]) => string) | ((d: string, index?: number, allTicks?: number[]) => string) | ((d: Date, index?: number, allTicks?: number[]) => string);
6
10
  export interface ThemeSemanticColors {
7
11
  primary?: string;
8
12
  secondary?: string;
@@ -70,7 +74,7 @@ export interface MarginalGraphicsConfig {
70
74
  left?: MarginalConfig | MarginalType;
71
75
  right?: MarginalConfig | MarginalType;
72
76
  }
73
- export type StreamChartType = "line" | "area" | "stackedarea" | "mixed" | "scatter" | "bubble" | "heatmap" | "bar" | "swarm" | "waterfall" | "candlestick";
77
+ export type StreamChartType = "line" | "area" | "stackedarea" | "mixed" | "scatter" | "bubble" | "heatmap" | "bar" | "swarm" | "waterfall" | "candlestick" | "custom";
74
78
  export type RuntimeMode = "bounded" | "streaming";
75
79
  export interface Style {
76
80
  stroke?: string;
@@ -100,7 +104,7 @@ export interface LineSceneNode {
100
104
  /** Threshold-based color segments */
101
105
  colorThresholds?: LineColorThreshold[];
102
106
  style: Style;
103
- datum: any;
107
+ datum: SeriesDatum;
104
108
  group?: string;
105
109
  /** Horizontal gradient for the line stroke */
106
110
  strokeGradient?: {
@@ -131,8 +135,16 @@ export interface AreaSceneNode {
131
135
  topPath: [number, number][];
132
136
  bottomPath: [number, number][];
133
137
  style: Style;
134
- datum: any;
138
+ datum: SeriesDatum;
135
139
  group?: string;
140
+ /** Clip the area to this rect (in plot-relative pixels). Used by horizon
141
+ * charts to band a single series into N slices. */
142
+ clipRect?: {
143
+ x: number;
144
+ y: number;
145
+ width: number;
146
+ height: number;
147
+ };
136
148
  /** Gradient fill: opacity-based (topOpacity/bottomOpacity) or multi-color (colorStops) */
137
149
  fillGradient?: {
138
150
  topOpacity: number;
@@ -183,7 +195,7 @@ export interface PointSceneNode {
183
195
  y: number;
184
196
  r: number;
185
197
  style: Style;
186
- datum: any;
198
+ datum: SceneDatum;
187
199
  /** Optional unique identifier for point-anchored annotations */
188
200
  pointId?: string;
189
201
  /** Pulse glow intensity 0–1 (set by PipelineStore when pulse is active) */
@@ -227,7 +239,7 @@ export interface RectSceneNode {
227
239
  }>;
228
240
  };
229
241
  style: Style;
230
- datum: any;
242
+ datum: SceneDatum;
231
243
  group?: string;
232
244
  _pulseIntensity?: number;
233
245
  _pulseColor?: string;
@@ -249,7 +261,7 @@ export interface HeatcellSceneNode {
249
261
  w: number;
250
262
  h: number;
251
263
  fill: string;
252
- datum: any;
264
+ datum: SceneDatum;
253
265
  /** Optional style object (used for decay/transition opacity on heatmap cells) */
254
266
  style?: Style;
255
267
  /** Numeric cell value (for canvas text rendering when showValues is enabled) */
@@ -286,7 +298,7 @@ export interface CandlestickSceneNode {
286
298
  isUp: boolean;
287
299
  /** Range/dumbbell mode — no body, endpoint dots instead */
288
300
  isRange?: boolean;
289
- datum: any;
301
+ datum: SceneDatum;
290
302
  /** Optional style object (used during transition opacity animations) */
291
303
  style?: Style;
292
304
  _pulseIntensity?: number;
@@ -360,6 +372,27 @@ export interface StreamXYFrameProps<T = Datum> {
360
372
  lineDataAccessor?: string;
361
373
  curve?: CurveType;
362
374
  normalize?: boolean;
375
+ /**
376
+ * Stacked area baseline. Only consulted by stackedarea chartType.
377
+ * - "zero" (default): standard stack from y=0
378
+ * - "wiggle": Byron–Wattenberg streamgraph offset (minimizes wiggle)
379
+ * - "silhouette": center the stack symmetrically around y=0
380
+ *
381
+ * Mutually exclusive with `normalize`: when `normalize` is `true`, the
382
+ * stack is forced to a `"zero"` baseline (any other value is ignored)
383
+ * because normalization assumes a fixed `[0, 1]` y-domain.
384
+ */
385
+ baseline?: "zero" | "wiggle" | "silhouette";
386
+ /**
387
+ * Stack order — controls which series sits at the top, middle, or bottom.
388
+ * - "key" (default): alphabetical by group key
389
+ * - "insideOut": largest-total series in the middle, smaller alternating
390
+ * above/below. Combined with `baseline: "wiggle"` or `"silhouette"`,
391
+ * produces the canonical streamgraph look where a "central anchor"
392
+ * layer sits across y=0 and other layers stack outward.
393
+ * - "asc" / "desc": by total ascending / descending
394
+ */
395
+ stackOrder?: "key" | "insideOut" | "asc" | "desc";
363
396
  /**
364
397
  * Accessor returning a symmetric uncertainty offset per datum.
365
398
  * When set, an uncertainty band is drawn ± this offset from the line.
@@ -446,7 +479,7 @@ export interface StreamXYFrameProps<T = Datum> {
446
479
  orient: "left" | "right" | "top" | "bottom";
447
480
  label?: string;
448
481
  ticks?: number;
449
- tickFormat?: (d: any, index?: number, allTicks?: number[]) => string;
482
+ tickFormat?: AxisTickFormat;
450
483
  baseline?: boolean | "under";
451
484
  jaggedBase?: boolean;
452
485
  }>;
@@ -489,9 +522,9 @@ export interface StreamXYFrameProps<T = Datum> {
489
522
  svgAnnotationRules?: (annotation: Datum, index: number, context: AnnotationContext) => ReactNode;
490
523
  showGrid?: boolean;
491
524
  legend?: ReactNode | {
492
- legendGroups: any[];
525
+ legendGroups: LegendGroup[];
493
526
  } | {
494
- gradient: import("../types/legendTypes").GradientLegendConfig;
527
+ gradient: GradientLegendConfig;
495
528
  };
496
529
  legendHoverBehavior?: (item: {
497
530
  label: string;
@@ -502,6 +535,10 @@ export interface StreamXYFrameProps<T = Datum> {
502
535
  legendHighlightedCategory?: string | null;
503
536
  legendIsolatedCategories?: Set<string>;
504
537
  legendPosition?: "right" | "left" | "top" | "bottom";
538
+ /** Accessor used to report the current legend category domain in push mode. */
539
+ legendCategoryAccessor?: string | ((d: T) => string);
540
+ /** Fires when the current legend category domain changes after scene rebuilds. */
541
+ onCategoriesChange?: (categories: string[]) => void;
505
542
  /** SVG elements rendered behind the canvas (in pixel space) */
506
543
  backgroundGraphics?: ReactNode;
507
544
  /** SVG elements rendered on top of everything (in SVG overlay) */
@@ -546,6 +583,16 @@ export interface StreamXYFrameProps<T = Datum> {
546
583
  linkedCrosshairName?: string;
547
584
  /** Source chart ID — crosshair is suppressed on the source chart to avoid double rendering */
548
585
  linkedCrosshairSourceId?: string;
586
+ /** Replaces chart-type scene dispatch with a user-supplied layout function.
587
+ * Receives a LayoutContext (scales, dimensions, theme, resolveColor) and
588
+ * returns SceneNode[] + optional overlays. See `semiotic/recipes` for
589
+ * reference layouts (waffle, calendar, horizon). */
590
+ customLayout?: import("./customLayout").CustomLayout;
591
+ /** User-supplied config blob threaded through to LayoutContext.config.
592
+ * Typed as `object` so caller-defined interfaces (without an index
593
+ * signature) flow through without casts; layouts narrow via their
594
+ * own `CustomLayout<TConfig>` parameterization. */
595
+ layoutConfig?: object;
549
596
  }
550
597
  export interface StreamXYFrameHandle<T = Datum> {
551
598
  push(datum: T): void;
@@ -0,0 +1,89 @@
1
+ import type { MutableRefObject, RefObject } from "react";
2
+ /**
3
+ * Returns `false` on the server (no effect fires there) and during the
4
+ * first client render after hydration; `true` from the first
5
+ * post-commit re-render onward.
6
+ */
7
+ export declare function useHydration(): boolean;
8
+ /**
9
+ * Returns `true` when this component instance was mounted via SSR
10
+ * hydration (i.e. there was server-rendered HTML to hydrate from), and
11
+ * `false` when it was mounted via pure client-side rendering (no SSR).
12
+ *
13
+ * The trick: `useSyncExternalStore`'s `getServerSnapshot` callback is
14
+ * called *only* during hydration of server-rendered content — never
15
+ * during a fresh CSR mount. Returning different values from the two
16
+ * snapshots lets us read the hydration mode on the very first render,
17
+ * then we capture it into a ref so it survives later renders.
18
+ *
19
+ * Stream Frames use this to decide whether to skip the intro animation
20
+ * on the canvas's first paint: when SSR has already shown the chart in
21
+ * its final state, re-animating from blank when the canvas takes over
22
+ * looks like a regression. CSR mounts keep their intro animation
23
+ * because the SVG branch's output never actually paints (it's
24
+ * overwritten by the canvas branch within the same paint frame, before
25
+ * the browser commits a frame).
26
+ */
27
+ export declare function useWasHydratingFromSSR(): boolean;
28
+ /**
29
+ * Shared post-hydration lifecycle for every Stream Frame.
30
+ *
31
+ * Three things happen on every commit-after-hydration:
32
+ *
33
+ * 1. If we just rehydrated from SSR, cancel the intro animation that
34
+ * the SVG-branch's `computeScene` installed (the server already
35
+ * painted the chart in its final state — re-animating from blank
36
+ * on the canvas takeover is a visual regression).
37
+ * 2. Mark the scene dirty so the canvas-paint pipeline rebuilds.
38
+ * 3. **Paint the canvas synchronously** via `renderFnRef.current()`.
39
+ *
40
+ * Step 3 is the timing-critical bit. The hook fires inside an
41
+ * isomorphic layout effect — `useLayoutEffect` on the client (runs
42
+ * synchronously after commit but before the browser paints),
43
+ * `useEffect` on the server (no-op, since SSR doesn't paint). If we
44
+ * deferred the paint to a `requestAnimationFrame` (the standard
45
+ * `scheduleRender()` route), the rAF callback wouldn't fire until
46
+ * the *next* frame — meaning the browser would paint *frame N* with
47
+ * the canvas in DOM but blank, then *frame N+1* with the canvas
48
+ * actually drawn. Synchronous paint inside the layout effect makes
49
+ * frame N's paint already include the canvas content; no flash.
50
+ *
51
+ * Each frame supplies its own `cleanup` for unmount work that's
52
+ * frame-specific (XY/Ordinal clear the streaming adapter; Geo clears
53
+ * its tile cache; Network has no extra cleanup).
54
+ */
55
+ export interface HydrationLifecycleOptions {
56
+ hydrated: boolean;
57
+ wasHydratingFromSSR: boolean;
58
+ /**
59
+ * Ref to the frame's pipeline store. The store optionally implements
60
+ * `cancelIntroAnimation()`; the hook calls it when the SVG → canvas
61
+ * swap fires after SSR rehydration. (Currently every shipped store
62
+ * implements the method, but the optional shape lets a custom store
63
+ * opt out.)
64
+ */
65
+ storeRef: RefObject<{
66
+ cancelIntroAnimation?: () => void;
67
+ } | null>;
68
+ /**
69
+ * Mutable dirty flag the renderer reads on its next paint. The hook
70
+ * sets it to true on every commit so the post-hydration paint
71
+ * rebuilds the scene from scratch.
72
+ */
73
+ dirtyRef: MutableRefObject<boolean>;
74
+ /**
75
+ * Ref to the frame's render closure (assigned by `useFrame` /
76
+ * the frame body). The hook calls this synchronously to paint
77
+ * within the same frame as the SVG → canvas swap commit, avoiding
78
+ * the one-frame blank-canvas flicker that an rAF-deferred paint
79
+ * would produce.
80
+ */
81
+ renderFnRef: MutableRefObject<() => void>;
82
+ /**
83
+ * Optional unmount cleanup. Frame-specific work the hook can't
84
+ * generalize — e.g. clearing the streaming `DataSourceAdapter`
85
+ * (XY/Ordinal) or the geo tile cache.
86
+ */
87
+ cleanup?: () => void;
88
+ }
89
+ export declare function useHydrationLifecycle(opts: HydrationLifecycleOptions): void;
@@ -0,0 +1 @@
1
+ export declare function useStableShallow<T>(value: T): T;
@@ -46,6 +46,10 @@ export interface XYSceneConfig {
46
46
  curve?: CurveType;
47
47
  colorScheme?: string | string[];
48
48
  normalize?: boolean;
49
+ /** Stacked area baseline. "zero" (default), "wiggle" (streamgraph), "silhouette" (centered). */
50
+ baseline?: "zero" | "wiggle" | "silhouette";
51
+ /** Stack order — see PipelineConfig.stackOrder. */
52
+ stackOrder?: "key" | "insideOut" | "asc" | "desc";
49
53
  gradientFill?: boolean | {
50
54
  topOpacity?: number;
51
55
  bottomOpacity?: number;