semiotic 3.4.2 → 3.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.
Files changed (163) 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 +113 -1
  28. package/dist/components/charts/ordinal/BoxPlot.d.ts +33 -0
  29. package/dist/components/charts/ordinal/DonutChart.d.ts +36 -0
  30. package/dist/components/charts/ordinal/DotPlot.d.ts +33 -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 +40 -0
  34. package/dist/components/charts/ordinal/Histogram.d.ts +97 -0
  35. package/dist/components/charts/ordinal/LikertChart.d.ts +44 -0
  36. package/dist/components/charts/ordinal/PieChart.d.ts +90 -1
  37. package/dist/components/charts/ordinal/RidgelinePlot.d.ts +29 -0
  38. package/dist/components/charts/ordinal/StackedBarChart.d.ts +40 -0
  39. package/dist/components/charts/ordinal/SwarmPlot.d.ts +38 -0
  40. package/dist/components/charts/ordinal/SwimlaneChart.d.ts +62 -0
  41. package/dist/components/charts/ordinal/ViolinPlot.d.ts +34 -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 +67 -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 +44 -1
  65. package/dist/components/charts/xy/BubbleChart.d.ts +4 -0
  66. package/dist/components/charts/xy/CandlestickChart.d.ts +37 -6
  67. package/dist/components/charts/xy/ConnectedScatterplot.d.ts +28 -0
  68. package/dist/components/charts/xy/Heatmap.d.ts +4 -0
  69. package/dist/components/charts/xy/LineChart.d.ts +12 -0
  70. package/dist/components/charts/xy/MinimapChart.d.ts +58 -0
  71. package/dist/components/charts/xy/MultiAxisLineChart.d.ts +27 -0
  72. package/dist/components/charts/xy/QuadrantChart.d.ts +21 -0
  73. package/dist/components/charts/xy/Scatterplot.d.ts +38 -2
  74. package/dist/components/charts/xy/ScatterplotMatrix.d.ts +16 -0
  75. package/dist/components/charts/xy/StackedAreaChart.d.ts +61 -1
  76. package/dist/components/realtime/types.d.ts +2 -4
  77. package/dist/components/recipes/bullet.d.ts +86 -0
  78. package/dist/components/recipes/calendar.d.ts +43 -0
  79. package/dist/components/recipes/dagre.d.ts +56 -0
  80. package/dist/components/recipes/flextree.d.ts +55 -0
  81. package/dist/components/recipes/marimekko.d.ts +55 -0
  82. package/dist/components/recipes/parallelCoordinates.d.ts +97 -0
  83. package/dist/components/recipes/recipeUtils.d.ts +27 -0
  84. package/dist/components/recipes/waffle.d.ts +46 -0
  85. package/dist/components/semiotic-ai.d.ts +4 -0
  86. package/dist/components/semiotic-network.d.ts +3 -0
  87. package/dist/components/semiotic-ordinal.d.ts +3 -0
  88. package/dist/components/semiotic-recipes.d.ts +24 -0
  89. package/dist/components/semiotic-xy.d.ts +3 -0
  90. package/dist/components/semiotic.d.ts +2 -2
  91. package/dist/components/server/renderToStaticSVG.d.ts +8 -2
  92. package/dist/components/server/serverChartConfigs.d.ts +47 -1
  93. package/dist/components/server/staticAnnotations.d.ts +6 -0
  94. package/dist/components/store/ObservationStore.d.ts +1 -3
  95. package/dist/components/store/SelectionStore.d.ts +1 -3
  96. package/dist/components/store/ThemeStore.d.ts +4 -4
  97. package/dist/components/store/TooltipStore.d.ts +1 -3
  98. package/dist/components/store/createStore.d.ts +4 -2
  99. package/dist/components/stream/CanvasHitTester.d.ts +10 -8
  100. package/dist/components/stream/DataSourceAdapter.d.ts +9 -0
  101. package/dist/components/stream/GeoPipelineStore.d.ts +9 -0
  102. package/dist/components/stream/GeoTileRenderer.d.ts +14 -0
  103. package/dist/components/stream/NetworkPipelineStore.d.ts +25 -0
  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 +13 -0
  114. package/dist/components/stream/hoverUtils.d.ts +4 -10
  115. package/dist/components/stream/networkCustomLayout.d.ts +67 -0
  116. package/dist/components/stream/networkTypes.d.ts +45 -0
  117. package/dist/components/stream/ordinalCustomLayout.d.ts +84 -0
  118. package/dist/components/stream/ordinalTypes.d.ts +35 -1
  119. package/dist/components/stream/renderers/barFunnelCanvasRenderer.d.ts +9 -1
  120. package/dist/components/stream/renderers/canvasRenderHelpers.d.ts +92 -0
  121. package/dist/components/stream/sampleCurvePath.d.ts +9 -0
  122. package/dist/components/stream/types.d.ts +44 -1
  123. package/dist/components/stream/useHydration.d.ts +89 -0
  124. package/dist/components/stream/useStableShallow.d.ts +1 -0
  125. package/dist/components/stream/xySceneBuilders/types.d.ts +4 -0
  126. package/dist/geo.min.js +2 -1
  127. package/dist/geo.module.min.js +2 -1
  128. package/dist/network.min.js +2 -1
  129. package/dist/network.module.min.js +2 -1
  130. package/dist/ordinal.min.js +2 -1
  131. package/dist/ordinal.module.min.js +2 -1
  132. package/dist/realtime.min.js +2 -1
  133. package/dist/realtime.module.min.js +2 -1
  134. package/dist/semiotic-ai.d.ts +69 -65
  135. package/dist/semiotic-ai.min.js +2 -1
  136. package/dist/semiotic-ai.module.min.js +2 -1
  137. package/dist/semiotic-data.d.ts +4 -4
  138. package/dist/semiotic-geo.d.ts +15 -15
  139. package/dist/semiotic-network.d.ts +19 -16
  140. package/dist/semiotic-ordinal.d.ts +31 -28
  141. package/dist/semiotic-realtime.d.ts +17 -17
  142. package/dist/semiotic-recipes.d.ts +24 -0
  143. package/dist/semiotic-recipes.min.js +1 -0
  144. package/dist/semiotic-recipes.module.min.js +1 -0
  145. package/dist/semiotic-server.d.ts +6 -6
  146. package/dist/semiotic-statisticalOverlays-C3DsOgr_.js +1 -0
  147. package/dist/semiotic-themes.d.ts +3 -3
  148. package/dist/semiotic-themes.min.js +2 -1
  149. package/dist/semiotic-themes.module.min.js +2 -1
  150. package/dist/semiotic-utils.d.ts +23 -23
  151. package/dist/semiotic-utils.min.js +2 -1
  152. package/dist/semiotic-utils.module.min.js +2 -1
  153. package/dist/semiotic-xy.d.ts +27 -24
  154. package/dist/semiotic.d.ts +63 -63
  155. package/dist/semiotic.min.js +2 -1
  156. package/dist/semiotic.module.min.js +2 -1
  157. package/dist/server.min.js +1 -1
  158. package/dist/server.module.min.js +1 -1
  159. package/dist/test-utils/canvasMock.d.ts +34 -5
  160. package/dist/xy.min.js +2 -1
  161. package/dist/xy.module.min.js +2 -1
  162. package/package.json +38 -17
  163. package/dist/semiotic-statisticalOverlays-Ckd_jM8z.js +0 -1
@@ -4,10 +4,24 @@ export declare function buildLineNode(data: Datum[], scales: StreamScales, xGet:
4
4
  export declare function buildAreaNode(data: Datum[], scales: StreamScales, xGet: (d: Datum) => number, yGet: (d: Datum) => number, baselineY: number, style: Style, group?: string, y0Get?: (d: Datum) => number): AreaSceneNode;
5
5
  /** Per-group-per-x stacked top values, keyed by group then x */
6
6
  export type StackedTops = Map<string, Map<number, number>>;
7
+ export type StackBaseline = "zero" | "wiggle" | "silhouette";
8
+ /**
9
+ * Compute per-x stack baseline offsets. Shared between scene rendering
10
+ * (`buildStackedAreaNodes`) and extent computation (`PipelineStore`) so
11
+ * both see the same y-bounds — without this, the wiggle offset's
12
+ * accumulated drift can exceed `±total/2` and clip against a too-small
13
+ * y-domain.
14
+ *
15
+ * Inputs:
16
+ * xValues — sorted unique x values
17
+ * groupKeys — group keys in stacking order (same order both callers use)
18
+ * valueAt — (groupKey, x) → group's value at x (0 if absent)
19
+ */
20
+ export declare function computeStackOffsets(xValues: number[], groupKeys: string[], valueAt: (groupKey: string, x: number) => number, baseline: StackBaseline): Map<number, number>;
7
21
  export declare function buildStackedAreaNodes(groups: {
8
22
  key: string;
9
23
  data: Datum[];
10
- }[], scales: StreamScales, xGet: (d: Datum) => number, yGet: (d: Datum) => number, styleFn: (group: string, sampleDatum?: Datum) => Style, normalize?: boolean, curve?: CurveType): {
24
+ }[], scales: StreamScales, xGet: (d: Datum) => number, yGet: (d: Datum) => number, styleFn: (group: string, sampleDatum?: Datum) => Style, normalize?: boolean, curve?: CurveType, baseline?: StackBaseline): {
11
25
  nodes: AreaSceneNode[];
12
26
  stackedTops: StackedTops;
13
27
  };
@@ -9,7 +9,7 @@ import type { SceneNode } from "./types";
9
9
  import type { NetworkSceneNode, NetworkSceneEdge, NetworkLabel } from "./networkTypes";
10
10
  import type { OrdinalSceneNode } from "./ordinalTypes";
11
11
  import type { GeoSceneNode } from "./geoTypes";
12
- export declare function xySceneNodeToSVG(node: SceneNode, i: number): React.ReactNode;
12
+ export declare function xySceneNodeToSVG(node: SceneNode, i: number, idPrefix?: string): React.ReactNode;
13
13
  export declare function networkSceneNodeToSVG(node: NetworkSceneNode, i: number): React.ReactNode;
14
14
  export declare function networkSceneEdgeToSVG(edge: NetworkSceneEdge, i: number): React.ReactNode;
15
15
  export declare function networkLabelToSVG(label: NetworkLabel, i: number): React.ReactNode;
@@ -0,0 +1,4 @@
1
+ import type { Datum } from "../charts/shared/datumTypes";
2
+ export type CategoryDomainAccessor<T = Datum> = string | ((d: T) => unknown);
3
+ export declare function extractCategoryDomain<T extends Datum>(data: T[], accessor: CategoryDomainAccessor<T> | undefined): string[];
4
+ export declare function sameCategoryDomain(a: readonly string[], b: readonly string[]): boolean;
@@ -0,0 +1,15 @@
1
+ import * as React from "react";
2
+ /**
3
+ * Compose a stack of overlay ReactNodes into a single fragment, dropping
4
+ * null/undefined sources. Each frame paints its `resolvedForeground`
5
+ * (axes, legends, annotations, react overlay) and may layer additional
6
+ * sources on top — currently `customLayoutOverlays` from recipe-managed
7
+ * chrome, with brush UIs and recipe-owned legends planned. Centralising
8
+ * the merge here keeps SSR and client branches in sync and gives future
9
+ * overlay sources one obvious place to plug in.
10
+ *
11
+ * Returns the single non-null source as-is when only one is present
12
+ * (avoids an unnecessary fragment); returns `null` when every source is
13
+ * absent so callers can skip the overlay subtree entirely.
14
+ */
15
+ export declare function composeOverlays(...sources: Array<React.ReactNode | null | undefined>): React.ReactNode;
@@ -0,0 +1,76 @@
1
+ import type { ReactNode } from "react";
2
+ import type { Datum } from "../charts/shared/datumTypes";
3
+ import type { MarginType } from "../types/marginType";
4
+ import type { SceneNode, StreamScales, Style, ThemeSemanticColors } from "./types";
5
+ /**
6
+ * customLayout — escape hatch for bespoke chart geometry.
7
+ *
8
+ * A customLayout function receives the same context the built-in scene
9
+ * builders use (scales, theme, resolvers, dimensions) and returns scene
10
+ * nodes. The frame still owns hit testing, transitions, decay, theme
11
+ * cascade, and SSR — the layout owns geometry only.
12
+ *
13
+ * Surface is intentionally narrow. Resist adding fields until a real
14
+ * recipe demands them.
15
+ */
16
+ export type CustomLayout<C extends object = Record<string, unknown>> = (ctx: LayoutContext<C>) => LayoutResult;
17
+ /**
18
+ * Context handed to every customLayout invocation. Six fields:
19
+ * data, scales, dimensions, theme, resolveColor, config.
20
+ *
21
+ * `resolveColor` is the contract that makes user layouts theme-aware —
22
+ * always prefer it over hardcoded color literals. `--doctor` flags
23
+ * layouts that emit nodes with literal hex/rgb fills.
24
+ */
25
+ export interface LayoutContext<C extends object = Record<string, unknown>> {
26
+ /** Buffered, post-filter data the frame is currently drawing. */
27
+ data: Datum[];
28
+ /** Scales constructed by the frame from the resolved x/y domains. */
29
+ scales: StreamScales;
30
+ /**
31
+ * Plot-area geometry. All scene-node coordinates are plot-relative —
32
+ * the canvas/SVG group already lives inside `margin.left`/`margin.top`,
33
+ * so `width`/`height` describe the plot rect (same as `plot.width`/
34
+ * `plot.height`). Read `margin` if you need the outer canvas size.
35
+ */
36
+ dimensions: {
37
+ width: number;
38
+ height: number;
39
+ margin: MarginType;
40
+ plot: {
41
+ x: number;
42
+ y: number;
43
+ width: number;
44
+ height: number;
45
+ };
46
+ };
47
+ /** Theme-resolved semantic colors + categorical palette. */
48
+ theme: {
49
+ semantic: ThemeSemanticColors;
50
+ categorical: string[];
51
+ };
52
+ /**
53
+ * Resolves a color for a given group/category, honoring
54
+ * CategoryColorProvider → colorScheme → theme cascade. Always prefer
55
+ * this over hardcoded literals.
56
+ */
57
+ resolveColor: (group: string, datum?: Datum) => string;
58
+ /** User-supplied config blob threaded through `layoutConfig`. */
59
+ config: C;
60
+ }
61
+ export interface LayoutResult {
62
+ /** Scene nodes to render. Get hit testing, transitions, decay, SSR for free. */
63
+ nodes?: SceneNode[];
64
+ /** SVG overlays composited above the canvas (labels, annotations). */
65
+ overlays?: ReactNode;
66
+ }
67
+ /**
68
+ * Note on extents: customLayout v1 does not return extents. Layouts that
69
+ * need to drive axis domains (e.g. horizon banding a continuous series)
70
+ * should pass `xExtent` / `yExtent` props on the chart — those flow into
71
+ * scale construction *before* the layout runs, so the layout sees correct
72
+ * scales. Layouts that don't use scales (waffle, calendar, treemap) can
73
+ * ignore extents entirely.
74
+ */
75
+ /** Convenience helper: build a Style object that defers fill/stroke to the theme. */
76
+ export declare function themedStyle(color: string, overrides?: Style): Style;
@@ -0,0 +1,29 @@
1
+ import { STREAMING_PALETTE } from "../charts/shared/colorUtils";
2
+ import { schemeCategory10 } from "../charts/shared/colorPalettes";
3
+ /**
4
+ * Shared palette resolution for the network and ordinal customLayout
5
+ * escape hatches. XY's customLayout uses `PipelineStore.resolveGroupColor`
6
+ * (richer cascade with CategoryColorProvider integration) so it doesn't
7
+ * call this helper.
8
+ *
9
+ * Precedence:
10
+ * 1. Explicit `colorScheme` array — used as-is.
11
+ * 2. Named scheme string (e.g. "tableau10") — looked up in
12
+ * `COLOR_SCHEMES`. Unknown names fall through.
13
+ * 3. Theme categorical (when non-empty).
14
+ * 4. The provided fallback palette.
15
+ *
16
+ * @param colorScheme `colorScheme` from the chart's pipeline config
17
+ * @param themeCategorical `themeCategorical` from theme resolution
18
+ * @param fallback Palette to use when nothing else matches.
19
+ * Network passes `schemeCategory10`; ordinal passes
20
+ * `STREAMING_PALETTE`. Caller's choice.
21
+ */
22
+ export declare function resolveCustomLayoutPalette(colorScheme: string | string[] | undefined, themeCategorical: string[] | undefined, fallback: readonly string[]): readonly string[];
23
+ /**
24
+ * Build a stable hash → palette index resolver. Used by the network and
25
+ * ordinal customLayout contexts so the same key always returns the same
26
+ * color for the lifetime of the closure.
27
+ */
28
+ export declare function buildResolveColor(palette: readonly string[]): (key: string) => string;
29
+ export { schemeCategory10, STREAMING_PALETTE };
@@ -155,6 +155,15 @@ export interface StreamGeoFrameProps<T = Datum> {
155
155
  };
156
156
  lineStyle?: Style | ((d: Datum, group?: string) => Style);
157
157
  colorScheme?: string | string[];
158
+ /**
159
+ * Categorical color field. For ChoroplethMap reads from area `properties`
160
+ * (or top-level fallback); for ProportionalSymbolMap reads from each point.
161
+ * Server-side legend auto-build groups by this field when `showLegend` is
162
+ * set and no explicit `legend` prop is provided. The function form accepts
163
+ * either the point datum `T` or a GeoJSON Feature so choropleth callers can
164
+ * write `(f) => f.properties.region` without a cast.
165
+ */
166
+ colorBy?: string | ((d: T | GeoJSON.Feature) => string);
158
167
  enableHover?: boolean;
159
168
  hoverAnnotation?: boolean | HoverAnnotationConfig;
160
169
  tooltipContent?: (d: HoverData) => ReactNode;
@@ -186,6 +195,10 @@ export interface StreamGeoFrameProps<T = Datum> {
186
195
  }) => void;
187
196
  legendHighlightedCategory?: string | null;
188
197
  legendIsolatedCategories?: Set<string>;
198
+ /** Accessor used to report the current legend category domain in push mode. */
199
+ legendCategoryAccessor?: string | ((d: T) => string);
200
+ /** Fires when the current legend category domain changes after scene rebuilds. */
201
+ onCategoriesChange?: (categories: string[]) => void;
189
202
  showAxes?: boolean;
190
203
  /** Render a visually-hidden data table from the scene graph for screen readers */
191
204
  accessibleTable?: boolean;
@@ -1,4 +1,3 @@
1
- import type { Datum } from "../charts/shared/datumTypes";
2
1
  /**
3
2
  * Shared hover data utilities for stream frames.
4
3
  *
@@ -20,16 +19,11 @@ export interface HoverPointerCoords {
20
19
  clientX: number;
21
20
  clientY: number;
22
21
  }
23
- /**
24
- * Spread raw datum properties onto HoverData if it's a non-null,
25
- * non-array object. Class instances (Date, etc.) are included —
26
- * this matches the historical behavior where all datum fields are
27
- * accessible directly on the hover object (d.fieldName).
28
- */
29
- export declare function spreadDatum(rawDatum: any): Datum;
30
22
  /**
31
23
  * Build a HoverData object from a raw datum and pixel coordinates.
32
- * Spreads plain-object datum properties for backwards compatibility
33
- * (consumers can access d.fieldName directly in addition to d.data.fieldName).
24
+ * The raw datum is preserved as `hover.data` for tooltip / callback
25
+ * consumers; pixel coordinates land on `x` / `y`. Anything else
26
+ * relevant to a specific frame family — `category`, `stats`,
27
+ * `nodeOrEdge`, `xValue`, etc. — is layered in via `extra`.
34
28
  */
35
29
  export declare function buildHoverData(rawDatum: any, x: number, y: number, extra?: Partial<HoverData>): HoverData;
@@ -0,0 +1,67 @@
1
+ import type { ReactNode } from "react";
2
+ import type { NetworkSceneNode, NetworkSceneEdge, NetworkLabel, RealtimeNode, RealtimeEdge } from "./networkTypes";
3
+ import type { ThemeSemanticColors } from "./types";
4
+ /**
5
+ * customLayout escape hatch for `StreamNetworkFrame`.
6
+ *
7
+ * A network layout is a pure function: given raw nodes/edges plus the
8
+ * frame's dimensions/theme, return positioned scene primitives — circles,
9
+ * rects, lines, beziers — and optional labels/overlays. The frame still
10
+ * owns hit testing, decay, accessibility, and SSR.
11
+ *
12
+ * Mirrors the XY `CustomLayout` pattern. Reach for it when the catalog
13
+ * (force, sankey, chord, tree, treemap, circle-pack, orbit) doesn't fit
14
+ * — e.g. `d3-flextree`, `dagre`, custom radial layouts.
15
+ */
16
+ export type NetworkCustomLayout<C extends object = Record<string, unknown>> = (ctx: NetworkLayoutContext<C>) => NetworkLayoutResult;
17
+ export interface NetworkLayoutContext<C extends object = Record<string, unknown>> {
18
+ /** Raw nodes from the data prop / push API. May or may not have positions. */
19
+ nodes: RealtimeNode[];
20
+ /** Raw edges. Source/target may be id strings or node references. */
21
+ edges: RealtimeEdge[];
22
+ /**
23
+ * Plot-area geometry. All scene-node coordinates are plot-relative —
24
+ * the canvas/SVG group already lives inside `margin.left`/`margin.top`.
25
+ */
26
+ dimensions: {
27
+ width: number;
28
+ height: number;
29
+ plot: {
30
+ x: number;
31
+ y: number;
32
+ width: number;
33
+ height: number;
34
+ };
35
+ };
36
+ /** Theme-resolved semantic + categorical colors. */
37
+ theme: {
38
+ semantic: ThemeSemanticColors;
39
+ categorical: string[];
40
+ };
41
+ /**
42
+ * Resolves a stable color for a given key (typically a node id or
43
+ * category) by hashing into the frame-resolved categorical palette.
44
+ * The palette comes from `colorScheme` (array or named d3 scheme like
45
+ * `"tableau10"` / `"set3"`), then the active theme's `categorical`,
46
+ * then a fallback. The same key always returns the same color for the
47
+ * lifetime of this store.
48
+ *
49
+ * Note: this does *not* honor `CategoryColorProvider` — network charts
50
+ * don't currently thread that into the pipeline. If you need
51
+ * cross-chart category color sync, pass a matching `colorScheme` to
52
+ * each chart instead.
53
+ */
54
+ resolveColor: (key: string) => string;
55
+ /** User-supplied config blob threaded through `layoutConfig`. */
56
+ config: C;
57
+ }
58
+ export interface NetworkLayoutResult {
59
+ /** Positioned scene primitives. Circles, rects, or arcs. */
60
+ sceneNodes?: NetworkSceneNode[];
61
+ /** Positioned edges. Lines, beziers, ribbons, or curved. */
62
+ sceneEdges?: NetworkSceneEdge[];
63
+ /** Optional labels placed at arbitrary plot-relative positions. */
64
+ labels?: NetworkLabel[];
65
+ /** SVG overlays composited above the canvas. */
66
+ overlays?: ReactNode;
67
+ }
@@ -40,6 +40,29 @@ export interface RealtimeNode {
40
40
  _pulseIntensity?: number;
41
41
  _pulseColor?: string;
42
42
  _pulseGlowRadius?: number;
43
+ /**
44
+ * @internal Hierarchy-layout-only extension fields. Set by
45
+ * `hierarchyLayoutPlugin` / `orbitLayoutPlugin` during layout and
46
+ * read by `hierarchySceneBuilders`. Typed `unknown` because the d3
47
+ * `HierarchyNode` shape is layout-specific (rectangular, circular,
48
+ * point) — consumers narrow with the structural fields they need.
49
+ */
50
+ __hierarchyNode?: unknown;
51
+ /** @internal Circle-pack layout radius. Set by `hierarchyLayoutPlugin`. */
52
+ __radius?: number;
53
+ /**
54
+ * @internal Chord-layout extension. Carries the start/end angles
55
+ * for the arc segment representing this node, computed by
56
+ * `chordLayoutPlugin` and read by its `buildScene`. Concretely
57
+ * typed (unlike `__hierarchyNode`) because chord is the only
58
+ * layout that writes this field, so the shape is fixed — no
59
+ * narrowing-at-read needed. `__` prefix matches the convention
60
+ * used by `__hierarchyNode` / `__radius` on this same interface.
61
+ */
62
+ __arcData?: {
63
+ startAngle: number;
64
+ endAngle: number;
65
+ };
43
66
  }
44
67
  export interface RealtimeEdge {
45
68
  source: RealtimeNode | string;
@@ -69,6 +92,17 @@ export interface RealtimeEdge {
69
92
  /** @internal Circular sankey layout fields */
70
93
  _circularWidth?: number;
71
94
  _circularStub?: boolean;
95
+ /**
96
+ * @internal Chord-layout extension. Carries the d3-chord-generated
97
+ * source/target arc spans for this edge, set by `chordLayoutPlugin`
98
+ * during `computeLayout` and read by its `buildScene`. Typed
99
+ * `unknown` because the d3 `Chord` interface lives in `d3-chord`
100
+ * and importing the type here would couple `networkTypes` to that
101
+ * dep — consumers narrow at the read site. `__` prefix matches the
102
+ * `_circularWidth` / `_circularStub` internal-field convention on
103
+ * this same interface.
104
+ */
105
+ __chordData?: unknown;
72
106
  }
73
107
  export interface BezierPoint {
74
108
  x: number;
@@ -402,6 +436,11 @@ export interface NetworkPipelineConfig {
402
436
  x: number;
403
437
  y: number;
404
438
  }>;
439
+ /** When provided, replaces both layout dispatch and scene building.
440
+ * Receives raw nodes/edges and returns positioned scene primitives. */
441
+ customNetworkLayout?: import("./networkCustomLayout").NetworkCustomLayout;
442
+ /** User-supplied config blob threaded through to NetworkLayoutContext.config. */
443
+ layoutConfig?: object;
405
444
  }
406
445
  export interface StreamNetworkFrameProps<T = Datum> {
407
446
  chartType: NetworkChartType;
@@ -507,6 +546,12 @@ export interface StreamNetworkFrameProps<T = Datum> {
507
546
  description?: string;
508
547
  /** Accessible summary rendered as a screen-reader-only note */
509
548
  summary?: string;
549
+ /** Replaces network layout + scene dispatch with a user-supplied function.
550
+ * Receives raw nodes/edges + dimensions/theme, returns positioned scene
551
+ * primitives. See `semiotic/recipes` for reference layouts (flextree, dagre). */
552
+ customNetworkLayout?: import("./networkCustomLayout").NetworkCustomLayout;
553
+ /** User-supplied config blob threaded through to NetworkLayoutContext.config. */
554
+ layoutConfig?: object;
510
555
  }
511
556
  export interface StreamNetworkFrameHandle {
512
557
  push(edge: EdgePush): void;
@@ -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
+ }
@@ -5,7 +5,7 @@ import type { Style, SceneDatum, DecayConfig, PulseConfig, TransitionConfig, Sta
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>;
@@ -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;
@@ -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;
@@ -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][];