insomni-plot 0.1.0-alpha.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (242) hide show
  1. package/LICENSE.md +674 -0
  2. package/README.md +81 -0
  3. package/dist/core.d.mts +340 -0
  4. package/dist/core.mjs +1047 -0
  5. package/dist/index.d.mts +3426 -0
  6. package/dist/index.mjs +12762 -0
  7. package/dist/interactions-DEFL_F4E.mjs +5395 -0
  8. package/dist/range-presets-CzECsu3V.d.mts +1523 -0
  9. package/package.json +34 -0
  10. package/src/annotations.d.ts +121 -0
  11. package/src/annotations.ts +438 -0
  12. package/src/axis.d.ts +184 -0
  13. package/src/axis.test.ts +131 -0
  14. package/src/axis.ts +765 -0
  15. package/src/colorbar.d.ts +69 -0
  16. package/src/colorbar.ts +294 -0
  17. package/src/colors.d.ts +57 -0
  18. package/src/colors.test.ts +28 -0
  19. package/src/colors.ts +486 -0
  20. package/src/core.ts +299 -0
  21. package/src/format.d.ts +54 -0
  22. package/src/format.ts +138 -0
  23. package/src/grammar/accessibility.d.ts +147 -0
  24. package/src/grammar/accessibility.test.ts +199 -0
  25. package/src/grammar/accessibility.ts +443 -0
  26. package/src/grammar/aes.d.ts +35 -0
  27. package/src/grammar/aes.test.ts +75 -0
  28. package/src/grammar/aes.ts +120 -0
  29. package/src/grammar/annotations.d.ts +86 -0
  30. package/src/grammar/annotations.test.ts +68 -0
  31. package/src/grammar/annotations.ts +336 -0
  32. package/src/grammar/attach-brush.d.ts +44 -0
  33. package/src/grammar/attach-brush.test.ts +214 -0
  34. package/src/grammar/attach-brush.ts +111 -0
  35. package/src/grammar/attach-presets.d.ts +33 -0
  36. package/src/grammar/attach-presets.test.ts +106 -0
  37. package/src/grammar/attach-presets.ts +215 -0
  38. package/src/grammar/chart.d.ts +952 -0
  39. package/src/grammar/chart.test.ts +118 -0
  40. package/src/grammar/chart.ts +1172 -0
  41. package/src/grammar/color-utils.d.ts +29 -0
  42. package/src/grammar/color-utils.test.ts +53 -0
  43. package/src/grammar/color-utils.ts +66 -0
  44. package/src/grammar/constants.d.ts +45 -0
  45. package/src/grammar/constants.ts +61 -0
  46. package/src/grammar/coord.d.ts +183 -0
  47. package/src/grammar/coord.test.ts +355 -0
  48. package/src/grammar/coord.ts +619 -0
  49. package/src/grammar/data/pivot.d.ts +57 -0
  50. package/src/grammar/data/pivot.ts +107 -0
  51. package/src/grammar/emphasis-driver.d.ts +69 -0
  52. package/src/grammar/emphasis-driver.test.ts +199 -0
  53. package/src/grammar/emphasis-driver.ts +205 -0
  54. package/src/grammar/equality.d.ts +3 -0
  55. package/src/grammar/equality.ts +40 -0
  56. package/src/grammar/facet.d.ts +63 -0
  57. package/src/grammar/facet.test.ts +60 -0
  58. package/src/grammar/facet.ts +175 -0
  59. package/src/grammar/geoms/_categorical.d.ts +94 -0
  60. package/src/grammar/geoms/_categorical.ts +0 -0
  61. package/src/grammar/geoms/_distribution.d.ts +52 -0
  62. package/src/grammar/geoms/_distribution.ts +125 -0
  63. package/src/grammar/geoms/_mark.d.ts +69 -0
  64. package/src/grammar/geoms/_mark.ts +136 -0
  65. package/src/grammar/geoms/_shape.d.ts +41 -0
  66. package/src/grammar/geoms/_shape.ts +74 -0
  67. package/src/grammar/geoms/aggregate.d.ts +95 -0
  68. package/src/grammar/geoms/aggregate.test.ts +554 -0
  69. package/src/grammar/geoms/aggregate.ts +840 -0
  70. package/src/grammar/geoms/area.d.ts +32 -0
  71. package/src/grammar/geoms/area.test.ts +165 -0
  72. package/src/grammar/geoms/area.ts +578 -0
  73. package/src/grammar/geoms/band.d.ts +27 -0
  74. package/src/grammar/geoms/band.test.ts +57 -0
  75. package/src/grammar/geoms/band.ts +126 -0
  76. package/src/grammar/geoms/bar.d.ts +56 -0
  77. package/src/grammar/geoms/bar.test.ts +367 -0
  78. package/src/grammar/geoms/bar.ts +1054 -0
  79. package/src/grammar/geoms/boxplot.d.ts +129 -0
  80. package/src/grammar/geoms/boxplot.test.ts +299 -0
  81. package/src/grammar/geoms/boxplot.ts +834 -0
  82. package/src/grammar/geoms/connected-scatter.d.ts +27 -0
  83. package/src/grammar/geoms/connected-scatter.test.ts +157 -0
  84. package/src/grammar/geoms/connected-scatter.ts +63 -0
  85. package/src/grammar/geoms/emphasis.d.ts +76 -0
  86. package/src/grammar/geoms/emphasis.test.ts +135 -0
  87. package/src/grammar/geoms/emphasis.ts +162 -0
  88. package/src/grammar/geoms/histogram.d.ts +75 -0
  89. package/src/grammar/geoms/histogram.test.ts +262 -0
  90. package/src/grammar/geoms/histogram.ts +740 -0
  91. package/src/grammar/geoms/index.d.ts +20 -0
  92. package/src/grammar/geoms/index.ts +77 -0
  93. package/src/grammar/geoms/interval.d.ts +31 -0
  94. package/src/grammar/geoms/interval.test.ts +154 -0
  95. package/src/grammar/geoms/interval.ts +342 -0
  96. package/src/grammar/geoms/line.d.ts +38 -0
  97. package/src/grammar/geoms/line.test.ts +247 -0
  98. package/src/grammar/geoms/line.ts +659 -0
  99. package/src/grammar/geoms/point.d.ts +57 -0
  100. package/src/grammar/geoms/point.test.ts +163 -0
  101. package/src/grammar/geoms/point.ts +545 -0
  102. package/src/grammar/geoms/polar.test.ts +216 -0
  103. package/src/grammar/geoms/ribbon.d.ts +21 -0
  104. package/src/grammar/geoms/ribbon.test.ts +170 -0
  105. package/src/grammar/geoms/ribbon.ts +87 -0
  106. package/src/grammar/geoms/ridgeline.d.ts +89 -0
  107. package/src/grammar/geoms/ridgeline.test.ts +247 -0
  108. package/src/grammar/geoms/ridgeline.ts +1164 -0
  109. package/src/grammar/geoms/rolling.d.ts +43 -0
  110. package/src/grammar/geoms/rolling.test.ts +217 -0
  111. package/src/grammar/geoms/rolling.ts +387 -0
  112. package/src/grammar/geoms/rug.d.ts +28 -0
  113. package/src/grammar/geoms/rug.test.ts +126 -0
  114. package/src/grammar/geoms/rug.ts +214 -0
  115. package/src/grammar/geoms/rule.d.ts +23 -0
  116. package/src/grammar/geoms/rule.test.ts +69 -0
  117. package/src/grammar/geoms/rule.ts +212 -0
  118. package/src/grammar/geoms/smooth.d.ts +54 -0
  119. package/src/grammar/geoms/smooth.test.ts +78 -0
  120. package/src/grammar/geoms/smooth.ts +337 -0
  121. package/src/grammar/geoms/text.d.ts +29 -0
  122. package/src/grammar/geoms/text.test.ts +64 -0
  123. package/src/grammar/geoms/text.ts +234 -0
  124. package/src/grammar/geoms/tile.d.ts +61 -0
  125. package/src/grammar/geoms/tile.test.ts +157 -0
  126. package/src/grammar/geoms/tile.ts +621 -0
  127. package/src/grammar/geoms/types.d.ts +319 -0
  128. package/src/grammar/geoms/types.ts +362 -0
  129. package/src/grammar/geoms/violin.d.ts +85 -0
  130. package/src/grammar/geoms/violin.test.ts +187 -0
  131. package/src/grammar/geoms/violin.ts +672 -0
  132. package/src/grammar/index.d.ts +22 -0
  133. package/src/grammar/index.ts +269 -0
  134. package/src/grammar/interactions/_disposable.d.ts +5 -0
  135. package/src/grammar/interactions/_disposable.ts +23 -0
  136. package/src/grammar/interactions/_z.d.ts +4 -0
  137. package/src/grammar/interactions/_z.ts +16 -0
  138. package/src/grammar/interactions/brush-selection.test.ts +262 -0
  139. package/src/grammar/interactions/brush.d.ts +63 -0
  140. package/src/grammar/interactions/brush.test.ts +483 -0
  141. package/src/grammar/interactions/brush.ts +452 -0
  142. package/src/grammar/interactions/crosshair.d.ts +19 -0
  143. package/src/grammar/interactions/crosshair.test.ts +127 -0
  144. package/src/grammar/interactions/crosshair.ts +76 -0
  145. package/src/grammar/interactions/hit-layer.d.ts +64 -0
  146. package/src/grammar/interactions/hit-layer.ts +246 -0
  147. package/src/grammar/interactions/legend.d.ts +19 -0
  148. package/src/grammar/interactions/legend.ts +101 -0
  149. package/src/grammar/interactions/menu.d.ts +93 -0
  150. package/src/grammar/interactions/menu.test.ts +373 -0
  151. package/src/grammar/interactions/menu.ts +342 -0
  152. package/src/grammar/interactions/selection.d.ts +25 -0
  153. package/src/grammar/interactions/selection.test.ts +289 -0
  154. package/src/grammar/interactions/selection.ts +142 -0
  155. package/src/grammar/interactions/series-readout.d.ts +91 -0
  156. package/src/grammar/interactions/series-readout.test.ts +668 -0
  157. package/src/grammar/interactions/series-readout.ts +422 -0
  158. package/src/grammar/interactions/series-snap.d.ts +70 -0
  159. package/src/grammar/interactions/series-snap.test.ts +214 -0
  160. package/src/grammar/interactions/series-snap.ts +218 -0
  161. package/src/grammar/interactions/tooltip-axis.test.ts +176 -0
  162. package/src/grammar/interactions/tooltip-touch.browser.test.ts +49 -0
  163. package/src/grammar/interactions/tooltip-touch.test.ts +161 -0
  164. package/src/grammar/interactions/tooltip.d.ts +140 -0
  165. package/src/grammar/interactions/tooltip.test.ts +406 -0
  166. package/src/grammar/interactions/tooltip.ts +622 -0
  167. package/src/grammar/interactions/transitions.d.ts +34 -0
  168. package/src/grammar/interactions/transitions.test.ts +172 -0
  169. package/src/grammar/interactions/transitions.ts +160 -0
  170. package/src/grammar/layout.d.ts +68 -0
  171. package/src/grammar/layout.ts +186 -0
  172. package/src/grammar/legend-merge.test.ts +332 -0
  173. package/src/grammar/mount.d.ts +78 -0
  174. package/src/grammar/mount.test.ts +479 -0
  175. package/src/grammar/mount.ts +2112 -0
  176. package/src/grammar/palettes.d.ts +54 -0
  177. package/src/grammar/palettes.test.ts +80 -0
  178. package/src/grammar/palettes.ts +167 -0
  179. package/src/grammar/pan-zoom.test.ts +398 -0
  180. package/src/grammar/phylo.d.ts +65 -0
  181. package/src/grammar/phylo.test.ts +59 -0
  182. package/src/grammar/phylo.ts +112 -0
  183. package/src/grammar/pipeline.auto-ticks.test.ts +40 -0
  184. package/src/grammar/pipeline.d.ts +158 -0
  185. package/src/grammar/pipeline.test.ts +463 -0
  186. package/src/grammar/pipeline.ts +1233 -0
  187. package/src/grammar/profiling.d.ts +8 -0
  188. package/src/grammar/profiling.ts +24 -0
  189. package/src/grammar/scales.d.ts +188 -0
  190. package/src/grammar/scales.test.ts +181 -0
  191. package/src/grammar/scales.ts +800 -0
  192. package/src/grammar/svg.d.ts +3 -0
  193. package/src/grammar/svg.ts +39 -0
  194. package/src/grammar/theme.d.ts +261 -0
  195. package/src/grammar/theme.test.ts +105 -0
  196. package/src/grammar/theme.ts +490 -0
  197. package/src/heatmap/cpu.ts +109 -0
  198. package/src/heatmap/gpu.ts +565 -0
  199. package/src/heatmap/types.ts +177 -0
  200. package/src/heatmap.browser.test.ts +308 -0
  201. package/src/heatmap.test.ts +320 -0
  202. package/src/heatmap.ts +123 -0
  203. package/src/index.d.ts +1 -0
  204. package/src/index.ts +8 -0
  205. package/src/interactions.d.ts +48 -0
  206. package/src/interactions.test.ts +226 -0
  207. package/src/interactions.ts +394 -0
  208. package/src/layout/box.d.ts +48 -0
  209. package/src/layout/box.test.ts +107 -0
  210. package/src/layout/box.ts +143 -0
  211. package/src/legend.d.ts +115 -0
  212. package/src/legend.ts +422 -0
  213. package/src/marks/curve.d.ts +43 -0
  214. package/src/marks/curve.ts +244 -0
  215. package/src/marks/stack.d.ts +53 -0
  216. package/src/marks/stack.ts +184 -0
  217. package/src/marks.d.ts +273 -0
  218. package/src/marks.test.ts +541 -0
  219. package/src/marks.ts +1292 -0
  220. package/src/navigator.test.ts +174 -0
  221. package/src/navigator.ts +393 -0
  222. package/src/range-presets.d.ts +113 -0
  223. package/src/range-presets.test.ts +345 -0
  224. package/src/range-presets.ts +349 -0
  225. package/src/scales.d.ts +98 -0
  226. package/src/scales.test.ts +103 -0
  227. package/src/scales.ts +695 -0
  228. package/src/stats/index.d.ts +200 -0
  229. package/src/stats/index.test.ts +349 -0
  230. package/src/stats/index.ts +740 -0
  231. package/src/stats/regression.d.ts +38 -0
  232. package/src/stats/regression.test.ts +56 -0
  233. package/src/stats/regression.ts +396 -0
  234. package/src/stats/rolling-window.d.ts +55 -0
  235. package/src/stats/rolling-window.test.ts +237 -0
  236. package/src/stats/rolling-window.ts +256 -0
  237. package/src/test-setup.ts +19 -0
  238. package/src/viewport/axis-state.d.ts +72 -0
  239. package/src/viewport/axis-state.ts +476 -0
  240. package/src/viewport.d.ts +170 -0
  241. package/src/viewport.test.ts +363 -0
  242. package/src/viewport.ts +510 -0
@@ -0,0 +1,161 @@
1
+ // Tests for P1-A: touch-tap (onPress) wiring in tooltip and series-readout.
2
+ //
3
+ // These are unit tests — no GPU, no canvas. They verify:
4
+ // 1. onPress calls commit() immediately (no settle delay)
5
+ // 2. onHoverEnter still goes through the settle debounce unchanged
6
+ // 3. onPress fires the onHover callback (so hoverSignal in mount gets the hit)
7
+ // 4. series-readout's onPress updates cursorX
8
+
9
+ import { createInvalidator, type GlyphAtlas, type TooltipBounds } from "insomni";
10
+ import { describe, expect, test, vi } from "vite-plus/test";
11
+
12
+ import type { CompiledHitTest, HoveredHit } from "../geoms/types.ts";
13
+ import { themeDefault } from "../theme.ts";
14
+ import { createGrammarTooltip } from "./tooltip.ts";
15
+ import type { GrammarHitLayer, HitEventContext, HitLayerSubscriber } from "./hit-layer.ts";
16
+
17
+ // ---------------------------------------------------------------------------
18
+ // Helpers
19
+ // ---------------------------------------------------------------------------
20
+
21
+ interface Row {
22
+ name: string;
23
+ v: number;
24
+ }
25
+
26
+ function makeHit(data: readonly Row[], indices: number[]): CompiledHitTest<Row> {
27
+ return {
28
+ geomKind: "point",
29
+ positions: Float32Array.from(indices.flatMap((_, i) => [i * 10, 50])),
30
+ dataIndex: Int32Array.from(indices),
31
+ pickRadius: 5,
32
+ channels: {},
33
+ data,
34
+ };
35
+ }
36
+
37
+ function makePointer(x: number, y: number): HitEventContext["pointer"] {
38
+ return { x, y } as HitEventContext["pointer"];
39
+ }
40
+
41
+ /**
42
+ * Harness that exposes both onHoverEnter and onPress so tests can fire them
43
+ * directly, plus an optional settleDelay for debounce verification.
44
+ */
45
+ function harness(opts?: { settleDelay?: number }) {
46
+ const data: Row[] = [
47
+ { name: "A", v: 1 },
48
+ { name: "B", v: 2 },
49
+ ];
50
+ let sub: HitLayerSubscriber | null = null;
51
+ const hitLayer = {
52
+ subscribe(s: HitLayerSubscriber) {
53
+ sub = s;
54
+ return () => {
55
+ sub = null;
56
+ };
57
+ },
58
+ } as unknown as GrammarHitLayer;
59
+
60
+ const ctxFor = (idx: number): HitEventContext => ({
61
+ hit: { geomKind: "point", dataIndex: idx, data, x: idx * 10, y: 50 } as HoveredHit,
62
+ compiled: makeHit(data, [idx]) as CompiledHitTest<unknown>,
63
+ hitIndex: 0,
64
+ pointer: makePointer(idx * 10, 50),
65
+ });
66
+
67
+ const onHover = vi.fn();
68
+ const tip = createGrammarTooltip(
69
+ {
70
+ hitLayer,
71
+ hudLayer: () => ({}) as never,
72
+ atlas: () => undefined as GlyphAtlas | undefined,
73
+ theme: () => themeDefault,
74
+ bounds: (): TooltipBounds => ({ x: 0, y: 0, width: 500, height: 500 }),
75
+ invalidator: createInvalidator(),
76
+ },
77
+ { settleDelay: opts?.settleDelay, onHover },
78
+ );
79
+
80
+ return {
81
+ tip,
82
+ onHover,
83
+ enter: (idx: number) => sub!.onHoverEnter!(ctxFor(idx)),
84
+ press: (idx: number) => sub!.onPress!(ctxFor(idx)),
85
+ leave: () => sub!.onHoverLeave!(ctxFor(0)),
86
+ };
87
+ }
88
+
89
+ // ---------------------------------------------------------------------------
90
+ // onPress bypasses settle
91
+ // ---------------------------------------------------------------------------
92
+
93
+ describe("createGrammarTooltip — onPress touch-tap path", () => {
94
+ test("onPress commits immediately even with a non-zero settleDelay", () => {
95
+ // With settleDelay=200ms, onHoverEnter would need step() to elapse before
96
+ // committing. onPress must commit synchronously.
97
+ const h = harness({ settleDelay: 200 });
98
+ h.press(0);
99
+ // onHover should have been fired immediately — no step() needed.
100
+ expect(h.onHover).toHaveBeenCalledTimes(1);
101
+ expect(h.onHover.mock.calls[0]![0]).toMatchObject({ dataIndex: 0 });
102
+ });
103
+
104
+ test("onPress fires onHover with the hit object", () => {
105
+ const h = harness({ settleDelay: 100 });
106
+ h.press(1);
107
+ const hit = h.onHover.mock.calls[0]![0] as HoveredHit;
108
+ expect(hit.dataIndex).toBe(1);
109
+ expect(hit.x).toBe(10); // idx=1 → x=10
110
+ expect(hit.y).toBe(50);
111
+ });
112
+
113
+ test("onHoverEnter fires onHover immediately (crosshair) but defers tooltip show until settle", () => {
114
+ const h = harness({ settleDelay: 100 });
115
+ h.enter(0);
116
+ // onHover fires immediately for crosshair/hoverSignal.
117
+ expect(h.onHover).toHaveBeenCalledTimes(1);
118
+ expect(h.onHover.mock.calls[0]![0]).toMatchObject({ dataIndex: 0 });
119
+ // Mid-window: tooltip show still deferred; no extra onHover.
120
+ h.tip.step(0.05);
121
+ expect(h.onHover).toHaveBeenCalledTimes(1);
122
+ // Past the window: settle commits tooltip show without re-firing onHover.
123
+ h.tip.step(0.06);
124
+ expect(h.onHover).toHaveBeenCalledTimes(1);
125
+ });
126
+
127
+ test("onPress while a hover settle is pending clears pending and commits immediately — no stale settle fires", () => {
128
+ const h = harness({ settleDelay: 100 });
129
+ // Start a hover but don't let it settle.
130
+ h.enter(0);
131
+ // onHover fires immediately for crosshair (call 1, dataIndex 0).
132
+ expect(h.onHover).toHaveBeenCalledTimes(1);
133
+ expect(h.onHover.mock.calls[0]![0]).toMatchObject({ dataIndex: 0 });
134
+ h.tip.step(0.05);
135
+ expect(h.onHover).toHaveBeenCalledTimes(1);
136
+ // Touch tap arrives before hover settles — should commit index 1 right away.
137
+ h.press(1);
138
+ // onPress fires commit which calls onHover (call 2, dataIndex 1).
139
+ expect(h.onHover).toHaveBeenCalledTimes(2);
140
+ expect(h.onHover.mock.calls[1]![0]).toMatchObject({ dataIndex: 1 });
141
+ // Step well past the settle window — the old pending was cleared by
142
+ // onPress, so no stale settle should fire.
143
+ h.tip.step(1.0);
144
+ expect(h.onHover).toHaveBeenCalledTimes(2);
145
+ });
146
+
147
+ test("onPress with settleDelay=0 also commits immediately", () => {
148
+ const h = harness({ settleDelay: 0 });
149
+ h.press(0);
150
+ expect(h.onHover).toHaveBeenCalledTimes(1);
151
+ });
152
+
153
+ test("onPress clears stale pending even when no previous enter was settling", () => {
154
+ // Verify the fix is idempotent — clearing null pending is safe.
155
+ const h = harness({ settleDelay: 100 });
156
+ h.press(0);
157
+ expect(h.onHover).toHaveBeenCalledTimes(1);
158
+ h.tip.step(1.0);
159
+ expect(h.onHover).toHaveBeenCalledTimes(1);
160
+ });
161
+ });
@@ -0,0 +1,140 @@
1
+ import { type GlyphAtlas, type Invalidator, type Layer, type TooltipBounds, type TooltipContent } from "insomni";
2
+ import type { AxisTooltipContentResolver, TooltipContentResolver, TooltipContentResult } from "../chart.ts";
3
+ import type { CompiledHitTest, HoveredHit, ScaleBundle } from "../geoms/types.ts";
4
+ import { type SnapGroup, type SnapResult } from "./series-snap.ts";
5
+ import type { Theme } from "../theme.ts";
6
+ import type { GrammarHitLayer } from "./hit-layer.ts";
7
+ export interface GrammarTooltipOptions {
8
+ /** Hover-intent delay before showing (ms). Default from theme.motion.tooltip.showDelay. */
9
+ showDelay?: number;
10
+ /** Linger before hiding (ms). Default from theme.motion.tooltip.hideDelay. */
11
+ hideDelay?: number;
12
+ /** Fade duration (ms). 0 disables. Default from theme.motion.tooltip.fadeMs. */
13
+ fadeMs?: number;
14
+ /**
15
+ * Hover-intent settle (ms). Coalesces rapid enter/leave/switch events so the
16
+ * tooltip only commits a show/hide once the cursor holds a target this long —
17
+ * sweeping across a dense mark grid or through gaps no longer fires an overlay
18
+ * re-render per cell. 0 disables (commit immediately).
19
+ * Default from theme.motion.tooltip.settleDelay.
20
+ */
21
+ settleDelay?: number;
22
+ /** Override placement. Default "top". */
23
+ placement?: "top" | "bottom" | "left" | "right" | "auto";
24
+ /**
25
+ * Consumer-supplied content resolver. Returning a string / shorthand
26
+ * overrides the auto-built channel rows; returning null / undefined falls
27
+ * back to the default builder.
28
+ */
29
+ content?: TooltipContentResolver;
30
+ /**
31
+ * Optional secondary observer fired alongside the tooltip's own show/hide.
32
+ * Receives the active `HoveredHit` (geom kind, data array reference, data
33
+ * index, snapped position) on enter, and `null` on leave. Used by the
34
+ * grammar crosshair to track hit positions, and by the mount to publish
35
+ * `hovered` as a public signal.
36
+ *
37
+ * Also fires on touch-tap (`onPress`) since that path calls `commit` which
38
+ * calls this callback, bypassing the settle debounce.
39
+ */
40
+ onHover?(info: HoveredHit | null): void;
41
+ /**
42
+ * Trigger model. Default `"item"` (one box per hovered mark — unchanged).
43
+ * `"axis"` = floating unified readout snapping to the nearest data column.
44
+ */
45
+ trigger?: "item" | "axis";
46
+ /** Snap axis for `trigger:"axis"`. Default `"x"`. */
47
+ axis?: "x" | "y";
48
+ /** Axis-mode content hook (replaces the auto rows when it returns a shorthand). */
49
+ axisContent?: AxisTooltipContentResolver;
50
+ /** Format the snapped column value (title) in axis mode. */
51
+ axisTitleFormat?: (v: unknown) => string;
52
+ /** Format each auto-built row's value in axis mode. */
53
+ axisValueFormat?: (v: unknown) => string;
54
+ }
55
+ export interface GrammarTooltipDeps {
56
+ hitLayer: GrammarHitLayer;
57
+ hudLayer: () => Layer;
58
+ atlas: () => GlyphAtlas | undefined;
59
+ theme: () => Theme;
60
+ bounds: () => TooltipBounds;
61
+ invalidator: Invalidator;
62
+ /**
63
+ * Optional: current cursor position in element-local CSS px. When provided,
64
+ * the tooltip anchor follows the cursor every frame while visible — no need
65
+ * to wait for a cell-transition enter event.
66
+ */
67
+ pointerPos?: () => {
68
+ x: number;
69
+ y: number;
70
+ } | null;
71
+ /** Latest resolved scales (axis-mode swatch resolution). Optional. */
72
+ scales?: () => ScaleBundle | null;
73
+ /**
74
+ * Axis-mode pointer source: a full-frame interaction node registered by the
75
+ * mount. The tooltip subscribes for cursor tracking when `trigger:"axis"`.
76
+ * Returns an unregister fn.
77
+ */
78
+ onAxisPointer?: (handlers: {
79
+ move(p: {
80
+ x: number;
81
+ y: number;
82
+ }): void;
83
+ leave(): void;
84
+ }) => () => void;
85
+ }
86
+ export interface GrammarTooltip {
87
+ /** Tick opacity + delay timers. */
88
+ step(dt: number): void;
89
+ /** Draw into the hud layer. */
90
+ draw(): void;
91
+ dispose(): void;
92
+ /** Push fresh compiled hit-tests (axis mode only; item mode ignores). */
93
+ syncHits?<T>(hits: readonly CompiledHitTest<T>[]): void;
94
+ }
95
+ /**
96
+ * Best-effort default formatter. Numbers go through `Intl.NumberFormat` with
97
+ * adaptive precision; Dates through ISO; booleans/strings stringify.
98
+ */
99
+ export declare function defaultFormat(value: unknown): string;
100
+ /**
101
+ * Normalize a consumer-supplied resolver result into the canvas tooltip's
102
+ * `TooltipContent` shape. Returns null if the result is null/undefined so the
103
+ * caller can fall through to the default builder.
104
+ *
105
+ * - `string` → single value-only row.
106
+ * - `{ title, rows }` shorthand → rows mapped through the default formatter
107
+ * (strings pass through) with accent → row color via theme.
108
+ *
109
+ * Exported for tests and for reuse by alternative tooltip hosts.
110
+ */
111
+ export declare function normalizeTooltipContent(result: TooltipContentResult | null | undefined, theme: Theme): TooltipContent | null;
112
+ /**
113
+ * Resolve final tooltip content for a hit: run the consumer resolver if any,
114
+ * normalize the result, and fall back to the default channel-driven content
115
+ * when the resolver returns null/undefined.
116
+ */
117
+ export declare function resolveTooltipContent<T>(hit: CompiledHitTest<T>, hitIndex: number, theme: Theme, resolver?: TooltipContentResolver): TooltipContent;
118
+ /**
119
+ * Build the axis-mode tooltip content from a snap result. Pure (no GPU / no
120
+ * closure state) so it is unit-testable. For `axis:"x"` each auto row's value
121
+ * is the series Y; for `axis:"y"` it is the series X. When `axisContent`
122
+ * returns a shorthand it REPLACES the auto rows (normalized through the theme).
123
+ */
124
+ export declare function buildAxisTooltipContent(args: {
125
+ result: SnapResult;
126
+ axis: "x" | "y";
127
+ scales: ScaleBundle | null;
128
+ theme: Theme;
129
+ titleFormat: (v: unknown) => string;
130
+ valueFormat: (v: unknown) => string;
131
+ axisContent?: AxisTooltipContentResolver;
132
+ }): TooltipContent;
133
+ /** Project a snap group's picked hit to a `HoveredHit` (for crosshair snap). */
134
+ export declare function hoveredHitFromGroup(g: SnapGroup): HoveredHit;
135
+ export declare function createGrammarTooltip(deps: GrammarTooltipDeps, opts?: GrammarTooltipOptions): GrammarTooltip;
136
+ /** @internal — exposed for unit tests only. */
137
+ export declare const __test__: {
138
+ buildAxisTooltipContent: typeof buildAxisTooltipContent;
139
+ hoveredHitFromGroup: typeof hoveredHitFromGroup;
140
+ };