semiotic 3.7.4 → 3.7.5

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 (135) hide show
  1. package/CLAUDE.md +10 -7
  2. package/README.md +36 -19
  3. package/ai/schema.json +221 -1
  4. package/ai/system-prompt.md +2 -1
  5. package/dist/components/Annotation.d.ts +4 -0
  6. package/dist/components/DataSummaryContext.d.ts +1 -0
  7. package/dist/components/ai/chartCapabilityTypes.d.ts +16 -0
  8. package/dist/components/ai/dataPitfallsBridge.d.ts +101 -0
  9. package/dist/components/ai/dataQualityBridge.d.ts +201 -0
  10. package/dist/components/ai/describeChart.d.ts +2 -0
  11. package/dist/components/ai/generativeChart.d.ts +145 -0
  12. package/dist/components/charts/custom/NetworkCustomChart.d.ts +14 -1
  13. package/dist/components/charts/ordinal/SwarmPlot.d.ts +7 -0
  14. package/dist/components/charts/realtime/RealtimeLineChart.d.ts +21 -0
  15. package/dist/components/charts/realtime/aggregate.d.ts +51 -0
  16. package/dist/components/charts/realtime/eventTime.d.ts +26 -0
  17. package/dist/components/charts/shared/colorPalettes.d.ts +2 -0
  18. package/dist/components/charts/shared/colorUtils.d.ts +1 -12
  19. package/dist/components/charts/shared/minMax.d.ts +3 -0
  20. package/dist/components/charts/shared/radialGeometry.d.ts +0 -18
  21. package/dist/components/charts/shared/smartTooltip.d.ts +27 -0
  22. package/dist/components/charts/shared/statisticalOverlays.d.ts +35 -0
  23. package/dist/components/charts/shared/tooltipUtils.d.ts +2 -0
  24. package/dist/components/charts/shared/useChartSetup.d.ts +1 -1
  25. package/dist/components/charts/shared/useCustomChartSetup.d.ts +1 -1
  26. package/dist/components/charts/shared/validateChartData.d.ts +1 -1
  27. package/dist/components/charts/xy/Scatterplot.d.ts +9 -0
  28. package/dist/components/data/fromArrow.d.ts +54 -0
  29. package/dist/components/data/fromMermaid.d.ts +47 -0
  30. package/dist/components/data/fromObservablePlot.d.ts +69 -0
  31. package/dist/components/data/portability/index.d.ts +14 -0
  32. package/dist/components/data/portability/spec.d.ts +129 -0
  33. package/dist/components/data/portability/vegaLite.d.ts +62 -0
  34. package/dist/components/realtime/ReorderBuffer.d.ts +54 -0
  35. package/dist/components/realtime/RunningStats.d.ts +66 -0
  36. package/dist/components/realtime/WindowAccumulator.d.ts +105 -0
  37. package/dist/components/realtime/parseWindowDuration.d.ts +12 -0
  38. package/dist/components/recipes/customTooltip.d.ts +31 -0
  39. package/dist/components/recipes/gofish.d.ts +207 -0
  40. package/dist/components/recipes/gofishBoba.d.ts +23 -0
  41. package/dist/components/recipes/gofishIR.d.ts +169 -0
  42. package/dist/components/recipes/gofishIRExamples.d.ts +89 -0
  43. package/dist/components/recipes/gofishInterpreter.d.ts +52 -0
  44. package/dist/components/recipes/gofishLambdas.d.ts +145 -0
  45. package/dist/components/recipes/mermaidDag.d.ts +44 -0
  46. package/dist/components/recipes/packedClusterMatrix.d.ts +166 -0
  47. package/dist/components/recipes/recipeChrome.d.ts +100 -0
  48. package/dist/components/recipes/recipeLegend.d.ts +57 -0
  49. package/dist/components/recipes/recipeUtils.d.ts +105 -0
  50. package/dist/components/semiotic-ai.d.ts +6 -0
  51. package/dist/components/semiotic-data.d.ts +2 -0
  52. package/dist/components/semiotic-experimental.d.ts +20 -0
  53. package/dist/components/semiotic-network.d.ts +3 -1
  54. package/dist/components/semiotic-ordinal.d.ts +2 -0
  55. package/dist/components/semiotic-realtime.d.ts +9 -1
  56. package/dist/components/semiotic-recipes.d.ts +18 -1
  57. package/dist/components/semiotic-themes.d.ts +2 -0
  58. package/dist/components/semiotic-xy.d.ts +2 -0
  59. package/dist/components/semiotic.d.ts +4 -0
  60. package/dist/components/store/ObservationStore.d.ts +21 -2
  61. package/dist/components/store/SelectionStore.d.ts +1 -1
  62. package/dist/components/store/ThemeStore.d.ts +1 -1
  63. package/dist/components/store/TooltipStore.d.ts +1 -1
  64. package/dist/components/store/createStore.d.ts +1 -1
  65. package/dist/components/store/designTokens.d.ts +15 -0
  66. package/dist/components/stream/NetworkHtmlMarksLayer.d.ts +44 -0
  67. package/dist/components/stream/NetworkPipelineStore.d.ts +32 -0
  68. package/dist/components/stream/NetworkSVGOverlay.d.ts +12 -0
  69. package/dist/components/stream/OrdinalPipelineStore.d.ts +18 -0
  70. package/dist/components/stream/PipelineStore.d.ts +27 -0
  71. package/dist/components/stream/SceneGraph.d.ts +5 -1
  72. package/dist/components/stream/customLayout.d.ts +20 -0
  73. package/dist/components/stream/customLayoutDiagnostics.d.ts +11 -0
  74. package/dist/components/stream/customLayoutSelection.d.ts +52 -0
  75. package/dist/components/stream/networkCustomLayout.d.ts +66 -1
  76. package/dist/components/stream/networkTypes.d.ts +29 -1
  77. package/dist/components/stream/ordinalCustomLayout.d.ts +17 -1
  78. package/dist/components/stream/ordinalSceneBuilders/types.d.ts +2 -0
  79. package/dist/components/stream/ordinalTypes.d.ts +19 -3
  80. package/dist/components/stream/renderers/networkSymbolRenderer.d.ts +2 -0
  81. package/dist/components/stream/renderers/symbolCanvasRenderer.d.ts +2 -0
  82. package/dist/components/stream/stalenessBands.d.ts +28 -0
  83. package/dist/components/stream/symbolPath.d.ts +24 -0
  84. package/dist/components/stream/types.d.ts +72 -3
  85. package/dist/components/stream/useStalenessCheck.d.ts +6 -1
  86. package/dist/components/stream/xySceneBuilders/pointScene.d.ts +2 -2
  87. package/dist/components/stream/xySceneBuilders/types.d.ts +5 -0
  88. package/dist/geo.min.js +1 -1
  89. package/dist/geo.module.min.js +1 -1
  90. package/dist/network.min.js +1 -1
  91. package/dist/network.module.min.js +1 -1
  92. package/dist/ordinal.min.js +1 -1
  93. package/dist/ordinal.module.min.js +1 -1
  94. package/dist/realtime.min.js +1 -1
  95. package/dist/realtime.module.min.js +1 -1
  96. package/dist/semiotic-ai-semiotic-ai-u954ylUn.js +2 -0
  97. package/dist/semiotic-ai-statisticalOverlays-CU7jW05Q.js +1 -0
  98. package/dist/semiotic-ai.d.ts +6 -0
  99. package/dist/semiotic-ai.min.js +1 -1
  100. package/dist/semiotic-ai.module.min.js +1 -1
  101. package/dist/semiotic-data.d.ts +2 -0
  102. package/dist/semiotic-data.min.js +1 -1
  103. package/dist/semiotic-data.module.min.js +1 -1
  104. package/dist/semiotic-experimental.d.ts +20 -0
  105. package/dist/semiotic-experimental.min.js +1 -0
  106. package/dist/semiotic-experimental.module.min.js +1 -0
  107. package/dist/semiotic-network.d.ts +3 -1
  108. package/dist/semiotic-ordinal.d.ts +2 -0
  109. package/dist/semiotic-realtime.d.ts +9 -1
  110. package/dist/semiotic-recipes.d.ts +18 -1
  111. package/dist/semiotic-recipes.min.js +1 -1
  112. package/dist/semiotic-recipes.module.min.js +1 -1
  113. package/dist/semiotic-semiotic-BmrYbi99.js +2 -0
  114. package/dist/semiotic-statisticalOverlays-IjZw8Lsu.js +1 -0
  115. package/dist/semiotic-themes.d.ts +2 -0
  116. package/dist/semiotic-themes.min.js +1 -1
  117. package/dist/semiotic-themes.module.min.js +1 -1
  118. package/dist/semiotic-utils.min.js +1 -1
  119. package/dist/semiotic-utils.module.min.js +1 -1
  120. package/dist/semiotic-value.min.js +1 -1
  121. package/dist/semiotic-value.module.min.js +1 -1
  122. package/dist/semiotic-xy.d.ts +2 -0
  123. package/dist/semiotic.d.ts +4 -0
  124. package/dist/semiotic.min.js +1 -1
  125. package/dist/semiotic.module.min.js +1 -1
  126. package/dist/server.min.js +1 -1
  127. package/dist/server.module.min.js +1 -1
  128. package/dist/xy-semiotic-xy-Dufu3D0-.js +2 -0
  129. package/dist/xy-statisticalOverlays-3Ni9bRph.js +1 -0
  130. package/dist/xy.min.js +1 -1
  131. package/dist/xy.module.min.js +1 -1
  132. package/package.json +11 -3
  133. package/dist/semiotic-ai-statisticalOverlays-C2PPlmXv.js +0 -1
  134. package/dist/semiotic-statisticalOverlays-C3DsOgr_.js +0 -1
  135. package/dist/xy-statisticalOverlays-C2PPlmXv.js +0 -1
@@ -1,7 +1,8 @@
1
1
  import type { ReactNode } from "react";
2
2
  import type { NetworkSceneNode, NetworkSceneEdge, NetworkLabel, RealtimeNode, RealtimeEdge } from "./networkTypes";
3
- import type { ThemeSemanticColors } from "./types";
3
+ import type { Style, ThemeSemanticColors } from "./types";
4
4
  import type { Datum } from "../charts/shared/datumTypes";
5
+ import type { CustomLayoutSelection } from "./customLayoutSelection";
5
6
  /**
6
7
  * The shared selection state, projected into the custom-layout context.
7
8
  *
@@ -90,6 +91,43 @@ export interface NetworkLayoutContext<C extends object = Record<string, unknown>
90
91
  */
91
92
  selection?: NetworkLayoutSelection | null;
92
93
  }
94
+ /**
95
+ * An HTML/React node positioned in plot space, rendered into a real DOM layer
96
+ * above the canvas (and above the SVG `overlays`) — **not** an SVG
97
+ * `<foreignObject>`.
98
+ *
99
+ * Reach for this over `overlays` when a mark is text-heavy or a rich component
100
+ * (a labelled card, an Axon widget) **and** it dims/animates on interaction.
101
+ * HTML-in-SVG (`<foreignObject>`) gets no compositor layer, so an `opacity`
102
+ * change — the common hover-dim — re-rasterizes the text; on a large graph that
103
+ * stalls the interaction. A real DOM element composites `opacity` / `transform`
104
+ * / `visibility` without re-painting its contents.
105
+ *
106
+ * The framework owns placement: each mark is wrapped in an absolutely-positioned
107
+ * element that tracks the same margin (and any future zoom/pan) transform the
108
+ * canvas and `overlays` receive, so a mark at `(x, y)` lands exactly where a
109
+ * `sceneNode` at `(x, y)` does. The consumer owns the content's appearance.
110
+ *
111
+ * Marks are non-interactive by default (`pointer-events: none`) — pointer events
112
+ * fall through to the canvas, so existing `sceneNodes` hit-testing
113
+ * (`onObservation` / `onClick`) is unaffected. Emit a transparent hit-rect
114
+ * `sceneNode` per mark to keep the canvas authoritative for interaction.
115
+ */
116
+ export interface NetworkHtmlMark {
117
+ /** Stable identity for keying / reconciliation across layout runs. A
118
+ * position-only update repositions without remounting the content. */
119
+ id: string;
120
+ /** Top-left x in plot coordinates — the same space as `sceneNodes`. */
121
+ x: number;
122
+ /** Top-left y in plot coordinates — the same space as `sceneNodes`. */
123
+ y: number;
124
+ /** Wrapper width in plot units. */
125
+ width: number;
126
+ /** Wrapper height in plot units. */
127
+ height: number;
128
+ /** Arbitrary HTML/React rendered inside the positioned wrapper. */
129
+ content: ReactNode;
130
+ }
93
131
  export interface NetworkLayoutResult {
94
132
  /** Positioned scene primitives. Circles, rects, or arcs. */
95
133
  sceneNodes?: NetworkSceneNode[];
@@ -99,4 +137,31 @@ export interface NetworkLayoutResult {
99
137
  labels?: NetworkLabel[];
100
138
  /** SVG overlays composited above the canvas. */
101
139
  overlays?: ReactNode;
140
+ /**
141
+ * HTML/React nodes positioned in plot space, rendered into one real DOM layer
142
+ * above the canvas and SVG `overlays`. Use for rich-text / component marks that
143
+ * dim or animate on hover — they composite `opacity`/`transform` changes
144
+ * instead of re-rasterizing text the way an SVG `<foreignObject>` does. The
145
+ * framework owns positioning + transform so marks stay pixel-aligned with
146
+ * `sceneNodes`. Additive: a layout that omits it renders no extra DOM. See
147
+ * {@link NetworkHtmlMark}.
148
+ */
149
+ htmlMarks?: NetworkHtmlMark[];
150
+ /**
151
+ * **Per-frame restyle of canvas marks, without re-positioning.** When present,
152
+ * a selection/hover change re-applies styles to the existing scene nodes and
153
+ * repaints — it does **not** re-run the layout or rebuild the quadtree. Return
154
+ * a style patch merged onto the node's *base* style (the style it was emitted
155
+ * with); return nothing to leave it unchanged.
156
+ *
157
+ * This is the canvas counterpart to {@link useCustomLayoutSelection} (which
158
+ * restyles `overlays`): compute geometry once in the layout body, and express
159
+ * selection-driven dimming/highlighting here so hover stays O(nodes) paint
160
+ * instead of O(nodes+edges) relayout. Providing it opts the chart into the
161
+ * cheap selection path; omit it and selection changes re-run the layout (the
162
+ * pre-existing behavior).
163
+ */
164
+ restyle?: (node: NetworkSceneNode, selection: CustomLayoutSelection | null) => Partial<Style> | void;
165
+ /** Per-frame restyle of edges — same contract as {@link NetworkLayoutResult.restyle}. */
166
+ restyleEdge?: (edge: NetworkSceneEdge, selection: CustomLayoutSelection | null) => Partial<Style> | void;
102
167
  }
@@ -6,6 +6,7 @@ import type { Style, DecayConfig, PulseConfig, TransitionConfig, StalenessConfig
6
6
  import type { AnimateProp } from "./pipelineTransitionUtils";
7
7
  import type { Datum } from "../charts/shared/datumTypes";
8
8
  import type { AutoPlaceAnnotations } from "../recipes/annotationLayout";
9
+ import type { NetworkSymbolName } from "./symbolPath";
9
10
  export interface TensionConfig {
10
11
  weightChange: number;
11
12
  newEdge: number;
@@ -247,6 +248,33 @@ export interface NetworkArcNode {
247
248
  _pulseColor?: string;
248
249
  _pulseGlowRadius?: number;
249
250
  }
251
+ /**
252
+ * Symbol node — a glyph rendered from a `d3-shape` symbol path (or a custom
253
+ * path). The per-datum shape channel: recipes that encode a categorical field
254
+ * as marker shape (e.g. `packedClusterMatrix`) emit these. Hit-tests as a
255
+ * circle of the symbol's effective radius; renders on canvas and in SVG/SSR.
256
+ */
257
+ export interface NetworkSymbolNode {
258
+ type: "symbol";
259
+ cx: number;
260
+ cy: number;
261
+ /** d3-symbol area in px² — drives the glyph's drawn size. */
262
+ size: number;
263
+ /** Named shape. Ignored when `path` is set. @default "circle" */
264
+ symbolType?: NetworkSymbolName;
265
+ /** Pre-built SVG path string, origin-centered — overrides `symbolType`. */
266
+ path?: string;
267
+ /** Rotation in radians about (cx, cy). */
268
+ rotation?: number;
269
+ style: Style;
270
+ datum: SceneDatum;
271
+ id?: string;
272
+ label?: string;
273
+ depth?: number;
274
+ _pulseIntensity?: number;
275
+ _pulseColor?: string;
276
+ _pulseGlowRadius?: number;
277
+ }
250
278
  /** Line edge — used by force */
251
279
  export interface NetworkLineEdge {
252
280
  type: "line";
@@ -305,7 +333,7 @@ export interface NetworkCurvedEdge {
305
333
  _cachedPath2D?: Path2D;
306
334
  _cachedPath2DSource?: string;
307
335
  }
308
- export type NetworkSceneNode = NetworkCircleNode | NetworkRectNode | NetworkArcNode;
336
+ export type NetworkSceneNode = NetworkCircleNode | NetworkRectNode | NetworkArcNode | NetworkSymbolNode;
309
337
  export type NetworkSceneEdge = NetworkLineEdge | NetworkBezierEdge | NetworkRibbonEdge | NetworkCurvedEdge;
310
338
  /** Label data for the SVG overlay */
311
339
  export interface NetworkLabel {
@@ -3,7 +3,8 @@ import type { ScaleBand, ScaleLinear } from "d3-scale";
3
3
  import type { Datum } from "../charts/shared/datumTypes";
4
4
  import type { MarginType } from "../types/marginType";
5
5
  import type { OrdinalSceneNode, OrdinalScales } from "./ordinalTypes";
6
- import type { ThemeSemanticColors } from "./types";
6
+ import type { Style, ThemeSemanticColors } from "./types";
7
+ import type { CustomLayoutSelection } from "./customLayoutSelection";
7
8
  /**
8
9
  * customLayout escape hatch for `StreamOrdinalFrame`.
9
10
  *
@@ -75,10 +76,25 @@ export interface OrdinalLayoutContext<C extends object = Record<string, unknown>
75
76
  resolveColor: (key: string) => string;
76
77
  /** User-supplied config blob threaded through `layoutConfig`. */
77
78
  config: C;
79
+ /**
80
+ * Shared-selection projection (from `selection` / `linkedHover`). `null` when
81
+ * unwired. For selection-driven styling without a relayout, use
82
+ * {@link OrdinalLayoutResult.restyle} (canvas) / `useCustomLayoutSelection`
83
+ * (overlays) rather than recomputing geometry here.
84
+ */
85
+ selection?: CustomLayoutSelection | null;
78
86
  }
79
87
  export interface OrdinalLayoutResult {
80
88
  /** Scene nodes to render. Get hit testing, transitions, decay, SSR for free. */
81
89
  nodes?: OrdinalSceneNode[];
82
90
  /** SVG overlays composited above the canvas (labels, axis lines, annotations). */
83
91
  overlays?: ReactNode;
92
+ /**
93
+ * **Per-frame restyle of canvas marks, without re-positioning.** When present,
94
+ * a selection/hover change re-applies styles to the existing scene nodes +
95
+ * repaints — no relayout, no quadtree rebuild. Return a style patch merged onto
96
+ * the node's *base* style. Providing it opts into the cheap selection path.
97
+ * Pairs with `useCustomLayoutSelection` for the `overlays`.
98
+ */
99
+ restyle?: (node: OrdinalSceneNode, selection: CustomLayoutSelection | null) => Partial<Style> | void;
84
100
  }
@@ -10,6 +10,8 @@ export interface OrdinalSceneContext {
10
10
  getStack?: (d: Datum) => string;
11
11
  getGroup?: (d: Datum) => string;
12
12
  getColor?: (d: Datum) => string;
13
+ /** Categorical accessor → glyph shape (swarm/dot symbolBy). */
14
+ getSymbol?: (d: Datum) => string;
13
15
  getConnector?: (d: Datum) => string;
14
16
  getO: (d: Datum) => string;
15
17
  multiScales: ScaleLinear<number, number>[];
@@ -2,6 +2,7 @@ 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
4
  import type { AutoPlaceAnnotations } from "../recipes/annotationLayout";
5
+ import type { SymbolName } from "./symbolPath";
5
6
  import type { Style, SceneDatum, DecayConfig, PulseConfig, TransitionConfig, StalenessConfig, ThemeSemanticColors } from "./types";
6
7
  import type { AnimateProp } from "./pipelineTransitionUtils";
7
8
  import type { GradientLegendConfig, LegendGroup, LegendLayout } from "../types/legendTypes";
@@ -162,9 +163,9 @@ export interface TrapezoidSceneNode {
162
163
  _targetOpacity?: number;
163
164
  _transitionKey?: string;
164
165
  }
165
- export type { Style, PointSceneNode, RectSceneNode } from "./types";
166
- import type { PointSceneNode, RectSceneNode } from "./types";
167
- export type OrdinalSceneNode = RectSceneNode | PointSceneNode | WedgeSceneNode | BoxplotSceneNode | ViolinSceneNode | ConnectorSceneNode | TrapezoidSceneNode;
166
+ export type { Style, PointSceneNode, RectSceneNode, SymbolSceneNode } from "./types";
167
+ import type { PointSceneNode, RectSceneNode, SymbolSceneNode } from "./types";
168
+ export type OrdinalSceneNode = RectSceneNode | PointSceneNode | SymbolSceneNode | WedgeSceneNode | BoxplotSceneNode | ViolinSceneNode | ConnectorSceneNode | TrapezoidSceneNode;
168
169
  export interface OrdinalColumn {
169
170
  name: string;
170
171
  x: number;
@@ -193,6 +194,10 @@ export interface OrdinalPipelineConfig {
193
194
  categoryAccessor?: string | ((d: Datum) => string);
194
195
  valueAccessor?: string | ((d: Datum) => number) | Array<string | ((d: Datum) => number)>;
195
196
  colorAccessor?: string | ((d: Datum) => string);
197
+ /** Categorical accessor → glyph shape (swarm/dot). Emits SymbolSceneNodes. */
198
+ symbolAccessor?: string | ((d: Datum) => string);
199
+ /** Explicit `{category → shape}` map; unmapped categories auto-assign. */
200
+ symbolMap?: Record<string, SymbolName>;
196
201
  stackBy?: string | ((d: Datum) => string);
197
202
  groupBy?: string | ((d: Datum) => string);
198
203
  timeAccessor?: string | ((d: Datum) => number);
@@ -275,6 +280,9 @@ export interface OrdinalPipelineConfig {
275
280
  /** Resolved margin — passed through so OrdinalLayoutContext.dimensions.margin
276
281
  * reflects what the frame actually used. */
277
282
  layoutMargin?: import("../types/marginType").MarginType;
283
+ /** Resolved shared selection projected into OrdinalLayoutContext.selection.
284
+ * Owned by a dedicated frame effect (kept off the rebuild path). */
285
+ layoutSelection?: import("./customLayoutSelection").CustomLayoutSelection | null;
278
286
  }
279
287
  export interface StreamOrdinalFrameProps<T = Datum> {
280
288
  chartType: OrdinalChartType;
@@ -285,6 +293,10 @@ export interface StreamOrdinalFrameProps<T = Datum> {
285
293
  /** Value field — the quantitative dimension (replaces rAccessor). Can be array for multiAxis. */
286
294
  valueAccessor?: string | ((d: T) => number) | Array<string | ((d: T) => number)>;
287
295
  colorAccessor?: string | ((d: T) => string);
296
+ /** Categorical accessor → glyph shape (swarm/dot). */
297
+ symbolAccessor?: string | ((d: T) => string);
298
+ /** Explicit `{category → shape}` map for `symbolAccessor`; unmapped auto-assign. */
299
+ symbolMap?: Record<string, SymbolName>;
288
300
  stackBy?: string | ((d: T) => string);
289
301
  groupBy?: string | ((d: T) => string);
290
302
  timeAccessor?: string | ((d: T) => number);
@@ -440,6 +452,10 @@ export interface StreamOrdinalFrameProps<T = Datum> {
440
452
  customLayout?: import("./ordinalCustomLayout").OrdinalCustomLayout;
441
453
  /** User-supplied config blob threaded through to OrdinalLayoutContext.config. */
442
454
  layoutConfig?: object;
455
+ /** Resolved shared selection projected into `OrdinalLayoutContext.selection`.
456
+ * Kept off the rebuild path — restyles (if the layout returned `restyle`) or
457
+ * rebuilds, never re-ingests. */
458
+ layoutSelection?: import("./customLayoutSelection").CustomLayoutSelection | null;
443
459
  }
444
460
  export interface StreamOrdinalFrameHandle<T = Datum> {
445
461
  push(datum: T): void;
@@ -0,0 +1,2 @@
1
+ import type { NetworkSceneNode } from "../networkTypes";
2
+ export declare function networkSymbolRenderer(ctx: CanvasRenderingContext2D, nodes: NetworkSceneNode[]): void;
@@ -0,0 +1,2 @@
1
+ import type { StreamRendererFn } from "./types";
2
+ export declare const symbolCanvasRenderer: StreamRendererFn;
@@ -0,0 +1,28 @@
1
+ import { type LifecycleBand, type LifecycleBandThresholds } from "../realtime/lifecycleBands";
2
+ import type { StalenessConfig } from "./types";
3
+ /**
4
+ * Default canvas alpha per band in graded mode. `fresh` is full; each
5
+ * older band dims further. Override individually via
6
+ * `staleness.graded.opacities`.
7
+ */
8
+ export declare const DEFAULT_STALENESS_BAND_OPACITY: Record<LifecycleBand, number>;
9
+ export interface ResolvedStaleness {
10
+ /** Canvas alpha to apply (1 = no dimming). */
11
+ alpha: number;
12
+ /**
13
+ * Classified band. In graded mode this is the `bandFromAge` result;
14
+ * in binary mode it collapses to `"fresh"` or `"stale"`.
15
+ */
16
+ band: LifecycleBand;
17
+ /** Whether the chart should read as stale (drives the badge). */
18
+ isStale: boolean;
19
+ }
20
+ /**
21
+ * Resolve the dimming + band for a given idle duration. Pure — the
22
+ * render path computes idle from `now - lastIngestTime` each paint and
23
+ * the staleness poll uses the same function to decide when to repaint.
24
+ *
25
+ * `idleMs` of 0 (no data yet) is treated as fresh.
26
+ */
27
+ export declare function resolveStaleness(staleness: StalenessConfig | undefined, idleMs: number): ResolvedStaleness;
28
+ export type { LifecycleBand, LifecycleBandThresholds };
@@ -0,0 +1,24 @@
1
+ /** Named glyph shapes a `symbol` scene node can request. */
2
+ export type NetworkSymbolName = "circle" | "square" | "triangle" | "diamond" | "star" | "cross" | "wye" | "chevron";
3
+ /** Pipeline-neutral alias — the symbol mark is shared by network, XY, and
4
+ * ordinal scenes, so callers outside the network pipeline read this name. */
5
+ export type SymbolName = NetworkSymbolName;
6
+ /** Default shape assignment order when a recipe auto-maps distinct categories. */
7
+ export declare const SYMBOL_SEQUENCE: NetworkSymbolName[];
8
+ /**
9
+ * SVG path `d` string for a glyph, centered at the origin. `size` follows the
10
+ * d3-symbol area convention (px²) for named shapes; the custom `chevron`
11
+ * derives a comparable radius from it. `customPath`, when provided, is returned
12
+ * verbatim (already origin-centered and sized).
13
+ */
14
+ export declare function symbolPathString(symbolType: NetworkSymbolName | string | undefined, size: number, customPath?: string): string;
15
+ /** Effective radius of a glyph with the given d3-symbol `size` (used for hit testing). */
16
+ export declare function symbolRadius(size: number): number;
17
+ /**
18
+ * Maximum extent (circumradius) of a glyph from its center — the radius that
19
+ * actually bounds the drawn shape. For `circle` this equals {@link symbolRadius},
20
+ * but pointy shapes (triangle/star/chevron) reach further for the same area, so
21
+ * collision-packing must use this to avoid visual overlap. Polygonal shapes are
22
+ * measured from their path vertices; `circle` is the area formula.
23
+ */
24
+ export declare function symbolExtent(symbolType: NetworkSymbolName | string | undefined, size: number, customPath?: string): number;
@@ -6,6 +6,7 @@ import type { ArrowOfTime, WindowMode, LineStyle, BarStyle, WaterfallStyle, Swar
6
6
  import type { Datum } from "../charts/shared/datumTypes";
7
7
  import type { CoercibleNumber } from "./accessorUtils";
8
8
  import type { AutoPlaceAnnotations } from "../recipes/annotationLayout";
9
+ import type { SymbolName } from "./symbolPath";
9
10
  export type SceneDatum = Datum | null;
10
11
  export type SeriesDatum = Datum[] | null;
11
12
  export type AxisTickFormat = ((d: number, index?: number, allTicks?: number[]) => string) | ((d: string, index?: number, allTicks?: number[]) => string) | ((d: Date, index?: number, allTicks?: number[]) => string);
@@ -47,14 +48,34 @@ export interface TransitionConfig {
47
48
  easing?: "ease-out" | "linear";
48
49
  }
49
50
  export interface StalenessConfig {
50
- /** ms without data before "stale" (default: 5000) */
51
+ /**
52
+ * ms without data before "stale" (default: 5000). In graded mode this
53
+ * is the base TTL the lifecycle bands are measured against — `aging`
54
+ * begins here, `stale` at 1.5×, `expired` at 3× (overridable).
55
+ */
51
56
  threshold?: number;
52
- /** Canvas alpha when stale (default: 0.5) */
57
+ /** Canvas alpha when stale, binary mode (default: 0.5) */
53
58
  dimOpacity?: number;
54
59
  /** Render LIVE/STALE badge (default: false) */
55
60
  showBadge?: boolean;
56
61
  /** Badge position (default: "top-right") */
57
62
  badgePosition?: "top-left" | "top-right" | "bottom-left" | "bottom-right";
63
+ /**
64
+ * Opt into graded (banded) staleness. Instead of a single live→stale
65
+ * flip at `threshold`, frames that support graded staleness dim
66
+ * progressively through fresh → aging → stale → expired as idle time
67
+ * crosses multiples of `threshold`, sharing one schedule with per-datum
68
+ * decay and annotation freshness. (Currently honored by `StreamXYFrame`,
69
+ * which backs the realtime XY charts; other frames treat it as binary.)
70
+ * `true` uses the default per-band opacities; pass an object to override
71
+ * the band thresholds or opacities.
72
+ */
73
+ graded?: boolean | {
74
+ /** Multiples of `threshold` marking each band edge (see LifecycleBandThresholds). */
75
+ thresholds?: import("../realtime/lifecycleBands").LifecycleBandThresholds;
76
+ /** Per-band canvas alpha override. Missing bands use the defaults. */
77
+ opacities?: Partial<Record<import("../realtime/lifecycleBands").LifecycleBand, number>>;
78
+ };
58
79
  }
59
80
  export type MarginalType = "histogram" | "violin" | "ridgeline" | "boxplot";
60
81
  export interface MarginalConfig {
@@ -96,7 +117,7 @@ export interface Style {
96
117
  /** Internal geo line flag: fade line ends at projection clipping edges. */
97
118
  _edgeFade?: boolean;
98
119
  }
99
- export type SceneNode = LineSceneNode | AreaSceneNode | PointSceneNode | RectSceneNode | HeatcellSceneNode | CandlestickSceneNode;
120
+ export type SceneNode = LineSceneNode | AreaSceneNode | PointSceneNode | SymbolSceneNode | RectSceneNode | HeatcellSceneNode | CandlestickSceneNode;
100
121
  export interface LineColorThreshold {
101
122
  value: number;
102
123
  color: string;
@@ -219,6 +240,46 @@ export interface PointSceneNode {
219
240
  /** Stable identity key for transition tracking */
220
241
  _transitionKey?: string;
221
242
  }
243
+ /**
244
+ * Symbol node — the per-datum **shape channel**, shared with the network and
245
+ * ordinal pipelines. A glyph drawn from a `d3-shape` symbol path (or a custom
246
+ * `path`), painted on canvas and in SVG/SSR via the shared `symbolPath` helpers,
247
+ * and hit-tested + keyboard-navigated as a unit. Emitted by custom XY layouts
248
+ * and by Scatterplot's `symbolBy` encoding. Uses `x`/`y` like its sibling
249
+ * `PointSceneNode` (the network variant uses `cx`/`cy`).
250
+ */
251
+ export interface SymbolSceneNode {
252
+ type: "symbol";
253
+ x: number;
254
+ y: number;
255
+ /** d3-symbol area in px² — drives the glyph's drawn size. */
256
+ size: number;
257
+ /** Named shape. Ignored when `path` is set. @default "circle" */
258
+ symbolType?: SymbolName;
259
+ /** Pre-built SVG path string, origin-centered — overrides `symbolType`. */
260
+ path?: string;
261
+ /** Rotation in radians about (x, y). */
262
+ rotation?: number;
263
+ style: Style;
264
+ datum: SceneDatum;
265
+ /** Optional unique identifier for point-anchored annotations. */
266
+ pointId?: string;
267
+ /** Pulse glow intensity 0–1 (set by PipelineStore when pulse is active). */
268
+ _pulseIntensity?: number;
269
+ /** Pulse glow color. */
270
+ _pulseColor?: string;
271
+ /** Pulse glow radius in px. */
272
+ _pulseGlowRadius?: number;
273
+ /** Animation target fields (set during transitions). */
274
+ _targetX?: number;
275
+ _targetY?: number;
276
+ _targetR?: number;
277
+ _targetOpacity?: number;
278
+ /** Per-datum decay opacity (set by PipelineStore.applyDecay). */
279
+ _decayOpacity?: number;
280
+ /** Stable identity key for transition tracking. */
281
+ _transitionKey?: string;
282
+ }
222
283
  export interface RectSceneNode {
223
284
  type: "rect";
224
285
  x: number;
@@ -467,6 +528,10 @@ export interface StreamXYFrameProps<T = Datum> {
467
528
  yAccessor?: string | ((d: T) => CoercibleNumber);
468
529
  colorAccessor?: string | ((d: T) => string);
469
530
  sizeAccessor?: string | ((d: T) => CoercibleNumber);
531
+ /** Categorical accessor → glyph shape (scatter/bubble). */
532
+ symbolAccessor?: string | ((d: T) => string);
533
+ /** Explicit `{category → shape}` map for `symbolAccessor`; unmapped auto-assign. */
534
+ symbolMap?: Record<string, SymbolName>;
470
535
  groupAccessor?: string | ((d: T) => string);
471
536
  lineDataAccessor?: string;
472
537
  curve?: CurveType;
@@ -712,6 +777,10 @@ export interface StreamXYFrameProps<T = Datum> {
712
777
  * signature) flow through without casts; layouts narrow via their
713
778
  * own `CustomLayout<TConfig>` parameterization. */
714
779
  layoutConfig?: object;
780
+ /** Resolved shared selection projected into `LayoutContext.selection`. Kept off
781
+ * the rebuild path — a change restyles (if the layout returned `restyle`) or
782
+ * rebuilds, never re-ingests. */
783
+ layoutSelection?: import("./customLayoutSelection").CustomLayoutSelection | null;
715
784
  }
716
785
  export interface StreamXYFrameHandle<T = Datum> {
717
786
  push(datum: T): void;
@@ -4,10 +4,15 @@ interface StoreWithIngestTime {
4
4
  }
5
5
  /**
6
6
  * Shared hook that polls a store's `lastIngestTime` on a 1-second interval
7
- * and manages staleness state. When staleness changes it sets
7
+ * and manages staleness state. When the resolved staleness changes it sets
8
8
  * `dirtyRef.current = true` and calls `scheduleRender()` so the canvas
9
9
  * repaints with the appropriate dimming.
10
10
  *
11
+ * Handles both binary staleness (a single live→stale flip) and graded
12
+ * staleness (progressive dimming through fresh → aging → stale → expired):
13
+ * a repaint is scheduled whenever the resolved *band* changes, so the
14
+ * graded ramp advances even though `isStale` may already be true.
15
+ *
11
16
  * Call this hook after `storeRef`, `dirtyRef`, and `scheduleRender` are
12
17
  * declared. The `isStale` / `setIsStale` state must live in the caller
13
18
  * so that the `useState` call order stays unchanged.
@@ -8,6 +8,6 @@ import type { Datum } from "../../charts/shared/datumTypes";
8
8
  * Dependencies: SceneGraph (buildPointNode)
9
9
  * Consumed by: PipelineStore.buildSceneNodes (chartTypes "scatter", "bubble")
10
10
  */
11
- import type { PointSceneNode } from "../types";
11
+ import type { PointSceneNode, SymbolSceneNode } from "../types";
12
12
  import type { XYSceneContext } from "./types";
13
- export declare function buildPointScene(ctx: XYSceneContext, data: Datum[]): PointSceneNode[];
13
+ export declare function buildPointScene(ctx: XYSceneContext, data: Datum[]): (PointSceneNode | SymbolSceneNode)[];
@@ -8,6 +8,7 @@ import type { AreaGradientConfig } from "./areaGradient";
8
8
  * accessing PipelineStore instance fields directly.
9
9
  */
10
10
  import type { StreamScales, Style, CurveType, BarStyle, ThemeSemanticColors } from "../types";
11
+ import type { SymbolName } from "../symbolPath";
11
12
  import type { ResolvedRibbon } from "./ribbonScene";
12
13
  export interface XYSceneContext {
13
14
  scales: StreamScales;
@@ -17,6 +18,8 @@ export interface XYSceneContext {
17
18
  getY0?: (d: Datum) => number | null;
18
19
  getSize?: (d: Datum) => number;
19
20
  getColor?: (d: Datum) => string;
21
+ /** Categorical accessor → glyph shape (scatter/bubble symbolBy). */
22
+ getSymbol?: (d: Datum) => string;
20
23
  getGroup?: (d: Datum) => string;
21
24
  getCategory?: (d: Datum) => string;
22
25
  getPointId?: (d: Datum) => string;
@@ -68,6 +71,8 @@ export interface XYSceneConfig {
68
71
  r?: number;
69
72
  };
70
73
  sizeRange?: [number, number];
74
+ /** Explicit `{category → shape}` map for symbolBy; unmapped auto-assign. */
75
+ symbolMap?: Record<string, SymbolName>;
71
76
  xAccessor?: string | ((d: Datum) => any);
72
77
  yAccessor?: string | ((d: Datum) => any);
73
78
  valueAccessor?: string | ((d: Datum) => any);