semiotic 3.2.3 → 3.3.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 (64) hide show
  1. package/CLAUDE.md +122 -265
  2. package/README.md +37 -17
  3. package/ai/schema.json +97 -1
  4. package/ai/system-prompt.md +3 -3
  5. package/dist/components/charts/ordinal/BarChart.d.ts +2 -0
  6. package/dist/components/charts/ordinal/DonutChart.d.ts +2 -0
  7. package/dist/components/charts/ordinal/GroupedBarChart.d.ts +4 -0
  8. package/dist/components/charts/ordinal/PieChart.d.ts +2 -0
  9. package/dist/components/charts/ordinal/StackedBarChart.d.ts +4 -0
  10. package/dist/components/charts/ordinal/SwimlaneChart.d.ts +4 -0
  11. package/dist/components/charts/realtime/RealtimeHeatmap.d.ts +2 -0
  12. package/dist/components/charts/realtime/RealtimeHistogram.d.ts +2 -0
  13. package/dist/components/charts/realtime/RealtimeLineChart.d.ts +2 -0
  14. package/dist/components/charts/realtime/RealtimeSwarmChart.d.ts +2 -0
  15. package/dist/components/charts/realtime/RealtimeWaterfallChart.d.ts +2 -0
  16. package/dist/components/charts/shared/hooks.d.ts +2 -1
  17. package/dist/components/charts/shared/types.d.ts +6 -2
  18. package/dist/components/charts/shared/useChartSetup.d.ts +1 -1
  19. package/dist/components/realtime/RingBuffer.d.ts +11 -0
  20. package/dist/components/realtime/types.d.ts +46 -3
  21. package/dist/components/semiotic-server.d.ts +6 -1
  22. package/dist/components/server/animatedGif.d.ts +78 -0
  23. package/dist/components/server/renderToStaticSVG.d.ts +86 -5
  24. package/dist/components/server/serverChartConfigs.d.ts +17 -0
  25. package/dist/components/server/staticAnnotations.d.ts +40 -0
  26. package/dist/components/server/staticLegend.d.ts +39 -0
  27. package/dist/components/server/svgHatchPattern.d.ts +26 -0
  28. package/dist/components/server/themeResolver.d.ts +39 -0
  29. package/dist/components/store/ThemeStore.d.ts +14 -0
  30. package/dist/components/stream/GeoPipelineStore.d.ts +6 -1
  31. package/dist/components/stream/NetworkPipelineStore.d.ts +26 -0
  32. package/dist/components/stream/OrdinalPipelineStore.d.ts +11 -0
  33. package/dist/components/stream/OrdinalSVGOverlay.d.ts +5 -0
  34. package/dist/components/stream/PipelineStore.d.ts +11 -0
  35. package/dist/components/stream/accessorUtils.d.ts +3 -3
  36. package/dist/components/stream/geoTypes.d.ts +6 -4
  37. package/dist/components/stream/hoverUtils.d.ts +22 -0
  38. package/dist/components/stream/networkTypes.d.ts +45 -20
  39. package/dist/components/stream/ordinalTypes.d.ts +40 -3
  40. package/dist/components/stream/pipelineDecay.d.ts +6 -5
  41. package/dist/components/stream/renderers/resolveCSSColor.d.ts +17 -0
  42. package/dist/components/stream/types.d.ts +8 -0
  43. package/dist/geo.min.js +1 -1
  44. package/dist/geo.module.min.js +1 -1
  45. package/dist/network.min.js +1 -1
  46. package/dist/network.module.min.js +1 -1
  47. package/dist/ordinal.min.js +1 -1
  48. package/dist/ordinal.module.min.js +1 -1
  49. package/dist/realtime.min.js +1 -1
  50. package/dist/realtime.module.min.js +1 -1
  51. package/dist/semiotic-ai.min.js +1 -1
  52. package/dist/semiotic-ai.module.min.js +1 -1
  53. package/dist/semiotic-server.d.ts +6 -1
  54. package/dist/semiotic-themes.min.js +1 -1
  55. package/dist/semiotic-themes.module.min.js +1 -1
  56. package/dist/semiotic-utils.min.js +1 -1
  57. package/dist/semiotic-utils.module.min.js +1 -1
  58. package/dist/semiotic.min.js +1 -1
  59. package/dist/semiotic.module.min.js +1 -1
  60. package/dist/server.min.js +1 -1
  61. package/dist/server.module.min.js +1 -1
  62. package/dist/xy.min.js +1 -1
  63. package/dist/xy.module.min.js +1 -1
  64. package/package.json +14 -3
@@ -0,0 +1,39 @@
1
+ /**
2
+ * Static legend rendering for server-side SVG.
3
+ *
4
+ * Builds legend SVG elements from data + colorScheme without React hooks.
5
+ * Used by renderToStaticSVG when showLegend is true.
6
+ */
7
+ import * as React from "react";
8
+ import type { SemioticTheme } from "../store/ThemeStore";
9
+ export interface StaticLegendConfig {
10
+ /** Category labels to show in legend */
11
+ categories: string[];
12
+ /** Color scheme — array of colors or d3-scale-chromatic name */
13
+ colorScheme?: string | string[];
14
+ /** Theme for text/font colors */
15
+ theme: SemioticTheme;
16
+ /** Legend position */
17
+ position?: "right" | "left" | "top" | "bottom";
18
+ /** Chart dimensions for positioning */
19
+ totalWidth: number;
20
+ totalHeight: number;
21
+ /** Chart margins */
22
+ margin: {
23
+ top: number;
24
+ right: number;
25
+ bottom: number;
26
+ left: number;
27
+ };
28
+ /** Title presence (affects top-position offset) */
29
+ hasTitle?: boolean;
30
+ }
31
+ /**
32
+ * Render a static legend as SVG elements.
33
+ * Returns null if no categories to show.
34
+ */
35
+ export declare function renderStaticLegend(config: StaticLegendConfig): React.ReactNode;
36
+ /**
37
+ * Extract unique categories from data using an accessor.
38
+ */
39
+ export declare function extractCategories(data: any[], accessor: string | ((d: any) => string) | undefined): string[];
@@ -0,0 +1,26 @@
1
+ /**
2
+ * SVG hatch pattern for server-side rendering.
3
+ *
4
+ * Creates a <pattern> element that can be referenced via url(#id) fill.
5
+ * The SVG equivalent of createHatchPattern() which produces CanvasPatterns.
6
+ */
7
+ import * as React from "react";
8
+ export interface SVGHatchOptions {
9
+ /** Pattern ID — must be unique within the SVG */
10
+ id: string;
11
+ /** Background color */
12
+ background?: string;
13
+ /** Line color */
14
+ stroke?: string;
15
+ /** Line width @default 1.5 */
16
+ lineWidth?: number;
17
+ /** Spacing between lines @default 6 */
18
+ spacing?: number;
19
+ /** Angle in degrees @default 45 */
20
+ angle?: number;
21
+ }
22
+ /**
23
+ * Create an SVG <pattern> element for diagonal hatch fills.
24
+ * Place inside <defs> and reference with fill="url(#id)".
25
+ */
26
+ export declare function createSVGHatchPattern(options: SVGHatchOptions): React.ReactElement;
@@ -0,0 +1,39 @@
1
+ /**
2
+ * Theme resolution for server-side rendering.
3
+ *
4
+ * Resolves theme presets and partial theme objects to concrete
5
+ * SemioticTheme instances with all color/font values resolved.
6
+ * No CSS custom properties — everything is concrete for inline SVG.
7
+ */
8
+ import type { SemioticTheme } from "../store/ThemeStore";
9
+ export type ThemeInput = string | Partial<SemioticTheme> | undefined;
10
+ /**
11
+ * Resolve a theme input to a full SemioticTheme object.
12
+ *
13
+ * - undefined → LIGHT_THEME
14
+ * - string → named preset ("dark", "tufte", "carbon-dark", etc.)
15
+ * - object with mode → merge onto matching base theme
16
+ * - object without mode → merge onto LIGHT_THEME
17
+ */
18
+ export declare function resolveTheme(theme: ThemeInput): SemioticTheme;
19
+ /**
20
+ * Extract concrete style values from a resolved theme for use in SVG attributes.
21
+ * Returns a flat object of commonly-needed values.
22
+ */
23
+ export declare function themeStyles(theme: SemioticTheme): {
24
+ background: string;
25
+ text: string;
26
+ textSecondary: string;
27
+ grid: string;
28
+ border: string;
29
+ primary: string;
30
+ fontFamily: string;
31
+ titleSize: number;
32
+ labelSize: number;
33
+ tickSize: number;
34
+ categorical: string[];
35
+ annotation: string;
36
+ legendSize: number;
37
+ titleFontSize: number;
38
+ tickFontFamily: string;
39
+ };
@@ -16,12 +16,20 @@ export interface SemioticTheme {
16
16
  selection?: string;
17
17
  /** Opacity for non-selected (dimmed) elements, 0–1 */
18
18
  selectionOpacity?: number;
19
+ /** Default annotation text/marker color. Falls back to `text` if unset. */
20
+ annotation?: string;
19
21
  };
20
22
  typography: {
21
23
  fontFamily: string;
22
24
  titleSize: number;
23
25
  labelSize: number;
24
26
  tickSize: number;
27
+ /** Font size for legend text. Falls back to `labelSize` if unset. */
28
+ legendSize?: number;
29
+ /** Font family for axis tick labels. Use monospace for aligned numerics. Falls back to `fontFamily`. */
30
+ tickFontFamily?: string;
31
+ /** Font size for chart title. Falls back to `titleSize` if unset. */
32
+ titleFontSize?: number;
25
33
  };
26
34
  tooltip?: {
27
35
  background?: string;
@@ -31,6 +39,12 @@ export interface SemioticTheme {
31
39
  shadow?: string;
32
40
  };
33
41
  borderRadius?: string;
42
+ accessibility?: {
43
+ /** Auto-swap to color-blind safe palette when true */
44
+ colorBlindSafe?: boolean;
45
+ /** Enforce minimum 3:1 contrast ratios */
46
+ highContrast?: boolean;
47
+ };
34
48
  }
35
49
  /** Color-blind safe categorical palette (8 colors).
36
50
  * Derived from Wong (2011) "Points of view: Color blindness" — safe for
@@ -39,6 +39,11 @@ export declare class GeoPipelineStore {
39
39
  pushPoint(datum: Record<string, any>): void;
40
40
  /** Push multiple streaming points */
41
41
  pushMany(data: Record<string, any>[]): void;
42
+ /**
43
+ * Remove points by ID. Requires pointIdAccessor to be configured.
44
+ * Returns the removed items.
45
+ */
46
+ removePoint(id: string | string[]): Record<string, any>[];
42
47
  clear(): void;
43
48
  computeScene(layout: StreamLayout): void;
44
49
  private fitProjection;
@@ -70,7 +75,7 @@ export declare class GeoPipelineStore {
70
75
  scale: number;
71
76
  translate: [number, number];
72
77
  };
73
- private getPoints;
78
+ getPoints(): Record<string, any>[];
74
79
  private buildSceneNodes;
75
80
  private applyCartogramTransform;
76
81
  private applyDecay;
@@ -126,5 +126,31 @@ export declare class NetworkPipelineStore {
126
126
  nodes: RealtimeNode[];
127
127
  edges: RealtimeEdge[];
128
128
  };
129
+ /**
130
+ * Update a node's data by ID. Returns the previous data, or null if not found.
131
+ */
132
+ updateNode(id: string, updater: (data: Record<string, any>) => Record<string, any>): Record<string, any> | null;
133
+ /**
134
+ * Update all edges between source and target. Handles parallel edges.
135
+ * Returns array of previous data values (one per updated edge), or empty array.
136
+ */
137
+ updateEdge(sourceId: string, targetId: string, updater: (data: Record<string, any>) => Record<string, any>): Record<string, any>[];
138
+ /**
139
+ * Remove a node by ID. Also removes all edges connected to this node.
140
+ * Returns true if the node was found and removed.
141
+ */
142
+ removeNode(id: string): boolean;
143
+ /**
144
+ * Remove all edges between source and target node IDs.
145
+ * Handles parallel edges (multiple edges between the same pair).
146
+ * Returns true if at least one edge was removed.
147
+ */
148
+ /**
149
+ * Remove edges by source+target IDs, or by edge ID when edgeIdAccessor is configured.
150
+ *
151
+ * - `removeEdge(sourceId, targetId)` — removes all parallel edges between endpoints
152
+ * - `removeEdge(edgeId)` — removes the edge matching edgeIdAccessor (requires config.edgeIdAccessor)
153
+ */
154
+ removeEdge(sourceIdOrEdgeId: string, targetId?: string): boolean;
129
155
  clear(): void;
130
156
  }
@@ -32,6 +32,7 @@ export declare class OrdinalPipelineStore {
32
32
  private getGroup;
33
33
  private getColor;
34
34
  private getConnector;
35
+ private getDataId;
35
36
  /** Discovered categories in insertion order */
36
37
  private categories;
37
38
  /** True once a non-bounded (push) changeset has been ingested */
@@ -77,6 +78,16 @@ export declare class OrdinalPipelineStore {
77
78
  private startTransition;
78
79
  advanceTransition(now: number): boolean;
79
80
  getData(): Record<string, any>[];
81
+ /**
82
+ * Remove data items by ID. Requires dataIdAccessor to be configured.
83
+ * Returns the removed items. Marks the store dirty for scene rebuild.
84
+ */
85
+ remove(id: string | string[]): Record<string, any>[];
86
+ /**
87
+ * Update data items by ID. Requires dataIdAccessor.
88
+ * Returns the previous values. Categories and extents are rebuilt.
89
+ */
90
+ update(id: string | string[], updater: (d: Record<string, any>) => Record<string, any>): Record<string, any>[];
80
91
  clear(): void;
81
92
  get size(): number;
82
93
  getOAccessor(): (d: any) => string;
@@ -21,6 +21,10 @@ interface OrdinalSVGOverlayProps {
21
21
  rLabel?: string;
22
22
  oFormat?: (d: string, index?: number) => string | React.ReactNode;
23
23
  rFormat?: (d: number) => string;
24
+ /** Custom tick values for the value (r) axis */
25
+ rTickValues?: number[];
26
+ /** Align first tick label to start, last to end */
27
+ tickLabelEdgeAlign?: boolean;
24
28
  showGrid?: boolean;
25
29
  title?: string | ReactNode;
26
30
  legend?: ReactNode | {
@@ -63,6 +67,7 @@ interface OrdinalSVGUnderlayProps {
63
67
  showAxes?: boolean;
64
68
  showGrid?: boolean;
65
69
  rFormat?: (d: number) => string;
70
+ rTickValues?: number[];
66
71
  }
67
72
  export declare function OrdinalSVGUnderlay(props: OrdinalSVGUnderlayProps): React.JSX.Element | null;
68
73
  export declare function OrdinalSVGOverlay(props: OrdinalSVGOverlayProps): React.JSX.Element | null;
@@ -197,6 +197,17 @@ export declare class PipelineStore {
197
197
  */
198
198
  private getBufferArray;
199
199
  getData(): Record<string, any>[];
200
+ /**
201
+ * Remove data points by ID. Requires pointIdAccessor to be configured.
202
+ * Returns the removed items. Marks the store dirty for scene rebuild.
203
+ */
204
+ remove(id: string | string[]): Record<string, any>[];
205
+ /**
206
+ * Update data points by ID. Requires pointIdAccessor.
207
+ * The updater receives the current datum and returns the replacement.
208
+ * Returns the previous values. Extents and scene are marked dirty.
209
+ */
210
+ update(id: string | string[], updater: (d: Record<string, any>) => Record<string, any>): Record<string, any>[];
200
211
  /** Returns sorted bin boundary values from the last bar scene build. Persists until clear() or the next bar scene build. */
201
212
  getBinBoundaries(): number[];
202
213
  getExtents(): {
@@ -12,6 +12,6 @@
12
12
  * the variable in the dependency array so the reference changes when behavior changes.
13
13
  */
14
14
  export declare function accessorsEquivalent(a: string | ((...args: any[]) => any) | undefined, b: string | ((...args: any[]) => any) | undefined): boolean;
15
- export declare function resolveAccessor<T>(accessor: string | ((d: T) => number) | undefined, fallback: string): (d: T) => number;
16
- export declare function resolveRawAccessor<T>(accessor: string | ((d: T) => any) | undefined, fallback: string): (d: T) => any;
17
- export declare function resolveStringAccessor<T>(accessor: string | ((d: T) => string) | undefined, fallback?: string): ((d: T) => string) | undefined;
15
+ export declare function resolveAccessor<T extends Record<string, unknown>>(accessor: string | ((d: T) => number) | undefined, fallback: string): (d: T) => number;
16
+ export declare function resolveRawAccessor<T extends Record<string, unknown>>(accessor: string | ((d: T) => unknown) | undefined, fallback: string): (d: T) => unknown;
17
+ export declare function resolveStringAccessor<T extends Record<string, unknown>>(accessor: string | ((d: T) => string) | undefined, fallback?: string): ((d: T) => string) | undefined;
@@ -1,7 +1,7 @@
1
1
  import type { ReactNode } from "react";
2
2
  import type { GeoProjection, GeoPath, GeoPermissibleObjects } from "d3-geo";
3
3
  import type { Style, DecayConfig, PulseConfig, TransitionConfig, StalenessConfig, PointSceneNode, LineSceneNode } from "./types";
4
- import type { HoverAnnotationConfig } from "../realtime/types";
4
+ import type { HoverAnnotationConfig, HoverData } from "../realtime/types";
5
5
  import type { GeoParticleStyle } from "./GeoParticlePool";
6
6
  export type ProjectionProp = GeoProjection | ProjectionName | ProjectionConfig;
7
7
  export type ProjectionName = "mercator" | "equalEarth" | "albersUsa" | "orthographic" | "naturalEarth" | "equirectangular";
@@ -139,9 +139,9 @@ export interface StreamGeoFrameProps<T = Record<string, any>> {
139
139
  colorScheme?: string | string[];
140
140
  enableHover?: boolean;
141
141
  hoverAnnotation?: boolean | HoverAnnotationConfig;
142
- tooltipContent?: (d: any) => ReactNode;
143
- customClickBehavior?: (d: any) => void;
144
- customHoverBehavior?: (d: any) => void;
142
+ tooltipContent?: (d: HoverData) => ReactNode;
143
+ customClickBehavior?: (d: HoverData | null) => void;
144
+ customHoverBehavior?: (d: HoverData | null) => void;
145
145
  annotations?: Record<string, any>[];
146
146
  decay?: DecayConfig;
147
147
  pulse?: PulseConfig;
@@ -171,6 +171,8 @@ export interface StreamGeoFrameProps<T = Record<string, any>> {
171
171
  export interface StreamGeoFrameHandle {
172
172
  push(datum: Record<string, any>): void;
173
173
  pushMany(data: Record<string, any>[]): void;
174
+ /** Remove points by ID. Requires pointIdAccessor. */
175
+ removePoint(id: string | string[]): Record<string, any>[];
174
176
  clear(): void;
175
177
  getProjection(): GeoProjection | null;
176
178
  getGeoPath(): GeoPath<any, GeoPermissibleObjects> | null;
@@ -0,0 +1,22 @@
1
+ /**
2
+ * Shared hover data utilities for stream frames.
3
+ *
4
+ * Centralizes the common HoverData construction pattern used by
5
+ * XY, Ordinal, and Network stream frames for hover and click events.
6
+ * Geo frame and keyboard navigation use variants with additional
7
+ * property flattening that are handled at the call site.
8
+ */
9
+ import type { HoverData } from "../realtime/types";
10
+ /**
11
+ * Spread raw datum properties onto HoverData if it's a non-null,
12
+ * non-array object. Class instances (Date, etc.) are included —
13
+ * this matches the historical behavior where all datum fields are
14
+ * accessible directly on the hover object (d.fieldName).
15
+ */
16
+ export declare function spreadDatum(rawDatum: any): Record<string, any>;
17
+ /**
18
+ * Build a HoverData object from a raw datum and pixel coordinates.
19
+ * Spreads plain-object datum properties for backwards compatibility
20
+ * (consumers can access d.fieldName directly in addition to d.data.fieldName).
21
+ */
22
+ export declare function buildHoverData(rawDatum: any, x: number, y: number, extra?: Partial<HoverData>): HoverData;
@@ -35,6 +35,9 @@ export interface RealtimeNode {
35
35
  createdByFrame?: boolean;
36
36
  sourceLinks?: RealtimeEdge[];
37
37
  targetLinks?: RealtimeEdge[];
38
+ _pulseIntensity?: number;
39
+ _pulseColor?: string;
40
+ _pulseGlowRadius?: number;
38
41
  }
39
42
  export interface RealtimeEdge {
40
43
  source: RealtimeNode | string;
@@ -56,6 +59,12 @@ export interface RealtimeEdge {
56
59
  data?: Record<string, any>;
57
60
  /** Unique key for this edge (supports parallel edges between same node pair) */
58
61
  _edgeKey?: string;
62
+ _pulseIntensity?: number;
63
+ _pulseColor?: string;
64
+ _pulseGlowRadius?: number;
65
+ /** @internal Circular sankey layout fields */
66
+ _circularWidth?: number;
67
+ _circularStub?: boolean;
59
68
  }
60
69
  export interface BezierPoint {
61
70
  x: number;
@@ -159,18 +168,24 @@ export interface NetworkRectNode {
159
168
  _pulseGlowRadius?: number;
160
169
  }
161
170
  /** Arc node — used by chord */
171
+ /** Arc node — used by chord. Angles in canvas convention (0 = 3 o'clock). */
162
172
  export interface NetworkArcNode {
163
173
  type: "arc";
164
174
  cx: number;
165
175
  cy: number;
166
176
  innerR: number;
167
177
  outerR: number;
178
+ /** Start angle in radians, canvas convention (0 = 3 o'clock, positive = clockwise) */
168
179
  startAngle: number;
180
+ /** End angle in radians, canvas convention */
169
181
  endAngle: number;
170
182
  style: Style;
171
183
  datum: any;
172
184
  id?: string;
173
185
  label?: string;
186
+ _pulseIntensity?: number;
187
+ _pulseColor?: string;
188
+ _pulseGlowRadius?: number;
174
189
  }
175
190
  /** Line edge — used by force */
176
191
  export interface NetworkLineEdge {
@@ -200,6 +215,8 @@ export interface NetworkRibbonEdge {
200
215
  pathD: string;
201
216
  style: Style;
202
217
  datum: any;
218
+ _pulseIntensity?: number;
219
+ _pulseColor?: string;
203
220
  }
204
221
  /** Curved edge — used by tree, cluster */
205
222
  export interface NetworkCurvedEdge {
@@ -207,6 +224,8 @@ export interface NetworkCurvedEdge {
207
224
  pathD: string;
208
225
  style: Style;
209
226
  datum: any;
227
+ _pulseIntensity?: number;
228
+ _pulseColor?: string;
210
229
  }
211
230
  export type NetworkSceneNode = NetworkCircleNode | NetworkRectNode | NetworkArcNode;
212
231
  export type NetworkSceneEdge = NetworkLineEdge | NetworkBezierEdge | NetworkRibbonEdge | NetworkCurvedEdge;
@@ -274,8 +293,10 @@ export interface NetworkPipelineConfig {
274
293
  sourceAccessor?: string | ((d: any) => string);
275
294
  targetAccessor?: string | ((d: any) => string);
276
295
  valueAccessor?: string | ((d: any) => number);
296
+ /** Edge ID accessor for removeEdge(edgeId) — enables single-ID edge removal */
297
+ edgeIdAccessor?: string | ((d: any) => string);
277
298
  childrenAccessor?: string | ((d: any) => any[]);
278
- hierarchySum?: (d: any) => number;
299
+ hierarchySum?: string | ((d: any) => number);
279
300
  orientation?: "horizontal" | "vertical";
280
301
  nodeAlign?: "justify" | "left" | "right" | "center";
281
302
  nodePaddingRatio?: number;
@@ -333,6 +354,15 @@ export interface NetworkPipelineConfig {
333
354
  orbitShowRings?: boolean;
334
355
  /** Enable orbit animation. @default true */
335
356
  orbitAnimated?: boolean;
357
+ /** @internal Hierarchy root stashed for tree/treemap/circlepack plugins */
358
+ __hierarchyRoot?: unknown;
359
+ /** @internal Orbit animation state preserved across config updates */
360
+ __orbitState?: unknown;
361
+ /** @internal Previous node positions for warm-start force layout */
362
+ __previousPositions?: Map<string, {
363
+ x: number;
364
+ y: number;
365
+ }>;
336
366
  }
337
367
  export interface StreamNetworkFrameProps<T = Record<string, any>> {
338
368
  chartType: NetworkChartType;
@@ -345,8 +375,10 @@ export interface StreamNetworkFrameProps<T = Record<string, any>> {
345
375
  sourceAccessor?: string | ((d: T) => string);
346
376
  targetAccessor?: string | ((d: T) => string);
347
377
  valueAccessor?: string | ((d: T) => number);
378
+ /** Edge ID accessor for removeEdge(edgeId) single-ID removal */
379
+ edgeIdAccessor?: string | ((d: any) => string);
348
380
  childrenAccessor?: string | ((d: T) => T[]);
349
- hierarchySum?: (d: T) => number;
381
+ hierarchySum?: string | ((d: T) => number);
350
382
  orientation?: "horizontal" | "vertical";
351
383
  nodeAlign?: "justify" | "left" | "right" | "center";
352
384
  nodePaddingRatio?: number;
@@ -388,24 +420,9 @@ export interface StreamNetworkFrameProps<T = Record<string, any>> {
388
420
  className?: string;
389
421
  background?: string;
390
422
  enableHover?: boolean;
391
- tooltipContent?: (d: {
392
- type: "node" | "edge";
393
- data: any;
394
- x: number;
395
- y: number;
396
- }) => ReactNode;
397
- customHoverBehavior?: (d: {
398
- type: "node" | "edge";
399
- data: any;
400
- x: number;
401
- y: number;
402
- } | null) => void;
403
- customClickBehavior?: (d: {
404
- type: "node" | "edge";
405
- data: any;
406
- x: number;
407
- y: number;
408
- } | null) => void;
423
+ tooltipContent?: (d: HoverData) => ReactNode;
424
+ customHoverBehavior?: (d: HoverData | null) => void;
425
+ customClickBehavior?: (d: HoverData | null) => void;
409
426
  /** Observation callback — emits hover/click events to the ObservationStore and this callback */
410
427
  onObservation?: OnObservationCallback;
411
428
  /** Chart instance identifier for observation filtering */
@@ -450,6 +467,14 @@ export interface StreamNetworkFrameProps<T = Record<string, any>> {
450
467
  export interface StreamNetworkFrameHandle {
451
468
  push(edge: EdgePush): void;
452
469
  pushMany(edges: EdgePush[]): void;
470
+ /** Remove a node by ID. Also removes connected edges. */
471
+ removeNode(id: string): boolean;
472
+ /** Remove edges by source+target, or by edge ID when edgeIdAccessor is configured. */
473
+ removeEdge(sourceIdOrEdgeId: string, targetId?: string): boolean;
474
+ /** Update a node's data by ID. Returns previous data. */
475
+ updateNode(id: string, updater: (data: Record<string, any>) => Record<string, any>): Record<string, any> | null;
476
+ /** Update all edges between source+target. Returns array of previous data. */
477
+ updateEdge(sourceId: string, targetId: string, updater: (data: Record<string, any>) => Record<string, any>): Record<string, any>[];
453
478
  clear(): void;
454
479
  getTopology(): {
455
480
  nodes: RealtimeNode[];
@@ -15,17 +15,20 @@ export interface WedgeSceneNode {
15
15
  cy: number;
16
16
  innerRadius: number;
17
17
  outerRadius: number;
18
+ /** Start angle in radians, canvas convention (0 = 3 o'clock, positive = clockwise) */
18
19
  startAngle: number;
20
+ /** End angle in radians, canvas convention */
19
21
  endAngle: number;
22
+ /** Corner radius for rounded wedge arcs (d3-shape arc.cornerRadius) */
23
+ cornerRadius?: number;
20
24
  style: Style;
21
25
  datum: any;
22
26
  category?: string;
23
- /** Pulse intensity 0–1 (set when aggregated category value changes) */
24
27
  _pulseIntensity?: number;
25
- /** Pulse color */
26
28
  _pulseColor?: string;
27
- /** Animation target opacity (set during enter/exit transitions) */
29
+ _pulseGlowRadius?: number;
28
30
  _targetOpacity?: number;
31
+ _transitionKey?: string;
29
32
  }
30
33
  export interface BoxplotSceneNode {
31
34
  type: "boxplot";
@@ -51,7 +54,11 @@ export interface BoxplotSceneNode {
51
54
  value: number;
52
55
  datum: any;
53
56
  }[];
57
+ _pulseIntensity?: number;
58
+ _pulseColor?: string;
59
+ _pulseGlowRadius?: number;
54
60
  _targetOpacity?: number;
61
+ _transitionKey?: string;
55
62
  }
56
63
  export interface DistributionStats {
57
64
  n: number;
@@ -89,7 +96,11 @@ export interface ViolinSceneNode {
89
96
  style: Style;
90
97
  datum: any;
91
98
  category?: string;
99
+ _pulseIntensity?: number;
100
+ _pulseColor?: string;
101
+ _pulseGlowRadius?: number;
92
102
  _targetOpacity?: number;
103
+ _transitionKey?: string;
93
104
  }
94
105
  export interface ConnectorSceneNode {
95
106
  type: "connector";
@@ -100,7 +111,11 @@ export interface ConnectorSceneNode {
100
111
  style: Style;
101
112
  datum: any;
102
113
  group?: string;
114
+ _pulseIntensity?: number;
115
+ _pulseColor?: string;
116
+ _pulseGlowRadius?: number;
103
117
  _targetOpacity?: number;
118
+ _transitionKey?: string;
104
119
  }
105
120
  export interface TrapezoidSceneNode {
106
121
  type: "trapezoid";
@@ -109,7 +124,11 @@ export interface TrapezoidSceneNode {
109
124
  style: Style;
110
125
  datum: any;
111
126
  category?: string;
127
+ _pulseIntensity?: number;
128
+ _pulseColor?: string;
129
+ _pulseGlowRadius?: number;
112
130
  _targetOpacity?: number;
131
+ _transitionKey?: string;
113
132
  }
114
133
  export type { Style, PointSceneNode, RectSceneNode } from "./types";
115
134
  import type { PointSceneNode, RectSceneNode } from "./types";
@@ -146,9 +165,13 @@ export interface OrdinalPipelineConfig {
146
165
  rExtent?: [number?, number?];
147
166
  oExtent?: string[];
148
167
  barPadding?: number;
168
+ /** Rounded top corner radius for bar charts. Only the end away from the baseline is rounded. For stacked bars, only the topmost segment gets rounded. */
169
+ roundedTop?: number;
149
170
  /** When true, adds padding below the 0 baseline. When false (default), bars are flush with the axis line. */
150
171
  baselinePadding?: boolean;
151
172
  innerRadius?: number;
173
+ /** Corner radius for rounded wedge arcs (pie/donut) */
174
+ cornerRadius?: number;
152
175
  normalize?: boolean;
153
176
  startAngle?: number;
154
177
  /** Total arc sweep in degrees (default 360 = full circle). Used by GaugeChart for partial arcs. */
@@ -167,6 +190,8 @@ export interface OrdinalPipelineConfig {
167
190
  summaryStyle?: (d: any, category?: string) => Style;
168
191
  colorScheme?: string | string[];
169
192
  barColors?: Record<string, string>;
193
+ /** ID accessor for remove() — extracts a unique identifier from each datum */
194
+ dataIdAccessor?: string | ((d: any) => string);
170
195
  decay?: DecayConfig;
171
196
  pulse?: PulseConfig;
172
197
  transition?: TransitionConfig;
@@ -196,8 +221,10 @@ export interface StreamOrdinalFrameProps<T = Record<string, any>> {
196
221
  left?: number;
197
222
  };
198
223
  barPadding?: number;
224
+ roundedTop?: number;
199
225
  baselinePadding?: boolean;
200
226
  innerRadius?: number;
227
+ cornerRadius?: number;
201
228
  normalize?: boolean;
202
229
  startAngle?: number;
203
230
  sweepAngle?: number;
@@ -217,6 +244,12 @@ export interface StreamOrdinalFrameProps<T = Record<string, any>> {
217
244
  windowSize?: number;
218
245
  connectorAccessor?: string | ((d: T) => string);
219
246
  connectorStyle?: Style | ((d: any) => Style);
247
+ /** ID accessor for remove()/update() — extracts a unique identifier from each datum */
248
+ dataIdAccessor?: string | ((d: any) => string);
249
+ /** Custom tick values for the value (r) axis. Overrides the default d3 ticks. */
250
+ rTickValues?: number[];
251
+ /** Align first tick label to start and last tick label to end. Default false. */
252
+ tickLabelEdgeAlign?: boolean;
220
253
  pieceStyle?: (d: any, category?: string) => Style;
221
254
  summaryStyle?: (d: any, category?: string) => Style;
222
255
  colorScheme?: string | string[];
@@ -276,6 +309,10 @@ export interface StreamOrdinalFrameProps<T = Record<string, any>> {
276
309
  export interface StreamOrdinalFrameHandle<T = Record<string, any>> {
277
310
  push(datum: T): void;
278
311
  pushMany(data: T[]): void;
312
+ /** Remove data items by ID. Requires dataIdAccessor. */
313
+ remove(id: string | string[]): T[];
314
+ /** Update data items by ID in place. Requires dataIdAccessor. Returns previous values. */
315
+ update(id: string | string[], updater: (d: T) => T): T[];
279
316
  clear(): void;
280
317
  getData(): T[];
281
318
  getScales(): OrdinalScales | null;
@@ -1,11 +1,12 @@
1
1
  /**
2
- * Decay encoding for XY pipeline scene nodes.
2
+ * Shared decay encoding utilities for all pipeline stores.
3
3
  *
4
- * Applies age-based opacity fade to scene nodes linear, exponential, or step.
5
- * Per-vertex decay for line/area nodes, uniform for discrete nodes (point, rect, etc.).
4
+ * `computeDecayOpacity()` core algorithm used by all four pipeline stores
5
+ * (XY, Ordinal, Network, Geo) to compute age-based opacity.
6
6
  *
7
- * Dependencies: types (SceneNode, DecayConfig)
8
- * Consumed by: PipelineStore.computeScene (after scene build, before transitions)
7
+ * `applyDecay()` XY-specific application that handles per-vertex decay
8
+ * for line/area nodes. Other stores call `computeDecayOpacity()` directly
9
+ * with their own node iteration logic.
9
10
  */
10
11
  import type { SceneNode, DecayConfig } from "./types";
11
12
  /**
@@ -0,0 +1,17 @@
1
+ /**
2
+ * Resolve a CSS custom property value to a concrete color string.
3
+ *
4
+ * If the input is a `var(--name)` or `var(--name, fallback)` string,
5
+ * reads the computed value from the canvas element. Otherwise returns
6
+ * the input unchanged.
7
+ *
8
+ * Per-canvas cache avoids repeated getComputedStyle calls within a single
9
+ * paint cycle. The cache is cleared on theme changes via clearCSSColorCache(),
10
+ * which each Stream Frame calls in its theme-change useEffect.
11
+ */
12
+ export declare function resolveCSSColor(ctx: CanvasRenderingContext2D, value: string | undefined): string | undefined;
13
+ /**
14
+ * Clear the per-canvas CSS variable cache. Called by Stream Frames
15
+ * when the theme changes so the next paint reads fresh computed values.
16
+ */
17
+ export declare function clearCSSColorCache(canvas: HTMLCanvasElement): void;
@@ -187,6 +187,10 @@ export interface RectSceneNode {
187
187
  y: number;
188
188
  w: number;
189
189
  h: number;
190
+ /** Rounded corner radius on the end away from the baseline */
191
+ roundedTop?: number;
192
+ /** Which edge to round: "top"/"bottom" (vertical), "right"/"left" (horizontal) */
193
+ roundedEdge?: "top" | "bottom" | "right" | "left";
190
194
  style: Style;
191
195
  datum: any;
192
196
  group?: string;
@@ -491,6 +495,10 @@ export interface StreamXYFrameProps<T = Record<string, any>> {
491
495
  export interface StreamXYFrameHandle<T = Record<string, any>> {
492
496
  push(datum: T): void;
493
497
  pushMany(data: T[]): void;
498
+ /** Remove data points by ID. Requires pointIdAccessor. */
499
+ remove(id: string | string[]): T[];
500
+ /** Update data points by ID in place. Requires pointIdAccessor. Returns previous values. */
501
+ update(id: string | string[], updater: (d: T) => T): T[];
494
502
  clear(): void;
495
503
  getData(): T[];
496
504
  getScales(): StreamScales | null;