@data-navigator/bokeh-wrapper 0.2.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.
@@ -0,0 +1,186 @@
1
+ import { NodeObject, Structure, LLMMessage, StructureOptions, RenderingOptions } from 'data-navigator';
2
+
3
+ /**
4
+ * Supported Bokeh chart types for smart defaults.
5
+ * Use 'auto' to let the wrapper infer the type from your data.
6
+ */
7
+ type BokehChartType = 'bar' | 'hbar' | 'scatter' | 'cartesian' | 'line' | 'multiline' | 'crossline' | 'stacked_bar' | 'auto';
8
+ /**
9
+ * Navigation interface mode.
10
+ * - 'text' — text-chat menu only (default, best for broad accessibility)
11
+ * - 'keyboard' — keyboard navigation only (arrow keys, no text chat)
12
+ * - 'both' — both interfaces simultaneously
13
+ */
14
+ type BokehWrapperMode = 'text' | 'keyboard' | 'both';
15
+ type BokehWrapperOptions = {
16
+ /**
17
+ * The element containing the rendered Bokeh plot.
18
+ * The wrapper sets this to `inert` so assistive technologies
19
+ * skip Bokeh's inaccessible canvas/SVG output.
20
+ */
21
+ plotContainer: string | HTMLElement;
22
+ /**
23
+ * The dataset used to generate the chart — plain JSON array of objects.
24
+ */
25
+ data: Record<string, unknown>[];
26
+ /**
27
+ * Chart type for smart defaults. Defaults to 'auto'.
28
+ */
29
+ type?: BokehChartType;
30
+ /**
31
+ * Field name used as the horizontal / category axis.
32
+ */
33
+ xField?: string;
34
+ /**
35
+ * Field name used as the vertical / value axis.
36
+ */
37
+ yField?: string;
38
+ /**
39
+ * Field name used to group data (series, stack layer, etc.).
40
+ */
41
+ groupField?: string;
42
+ /**
43
+ * Override the field used to generate node IDs.
44
+ * By default the wrapper derives IDs from the data.
45
+ */
46
+ idField?: string;
47
+ /**
48
+ * Chart title used as the opening of the accessible chart description
49
+ * announced when a user first enters the navigation structure.
50
+ * If omitted, the description opens with the x and y field names instead.
51
+ * Example: "Fruit counts"
52
+ */
53
+ title?: string;
54
+ /**
55
+ * Override the auto-generated accessible description for the chart's root node.
56
+ * Pass a string for a static description, or a function that receives the
57
+ * wrapper options and returns a string.
58
+ *
59
+ * Single-dimension charts (bar, multiline): the description is set
60
+ * as `semantics.label` on the dimension root node.
61
+ * Multi-dimension charts (stacked_bar, crossline, cartesian): it becomes the `semantics.label`
62
+ * of an injected Level 0 node added via the data-navigator `dimensions.parentOptions.addLevel0` API.
63
+ */
64
+ describeRoot?: string | ((options: BokehWrapperOptions) => string);
65
+ /**
66
+ * Interface mode. Defaults to 'text' (text-chat menu).
67
+ */
68
+ mode?: BokehWrapperMode;
69
+ /**
70
+ * Container element for the text-chat UI.
71
+ * If omitted, the wrapper creates a `<div>` and inserts it
72
+ * immediately after `plotContainer`.
73
+ */
74
+ chatContainer?: string | HTMLElement;
75
+ /**
76
+ * Called every time the user navigates to a new node.
77
+ * Use this to sync Bokeh chart highlights or tooltips.
78
+ */
79
+ onNavigate?: (node: NodeObject) => void;
80
+ /**
81
+ * Called when the user exits the navigation structure.
82
+ */
83
+ onExit?: () => void;
84
+ /**
85
+ * Called when the user types "click" or "select" in text mode.
86
+ * Receives the currently focused node. Use this to programmatically
87
+ * trigger Bokeh hit-testing or selection logic.
88
+ */
89
+ onClick?: (node: NodeObject) => void;
90
+ /**
91
+ * Called when the user types "hover" or "inspect" in text mode.
92
+ * Receives the currently focused node. Use this to programmatically
93
+ * trigger Bokeh hover / tooltip display.
94
+ */
95
+ onHover?: (node: NodeObject) => void;
96
+ /**
97
+ * Optional LLM callback for AI-assisted data Q&A in text mode.
98
+ * Receives a message array and should return a response string.
99
+ */
100
+ llm?: (messages: LLMMessage[]) => Promise<string | null>;
101
+ /**
102
+ * Override the default human-readable labels for navigation commands
103
+ * shown in the text-chat interface (e.g. { left: 'Previous bar' }).
104
+ */
105
+ commandLabels?: Record<string, string>;
106
+ /**
107
+ * Advanced: merge additional options into the generated StructureOptions
108
+ * before calling `data-navigator`'s structure builder.
109
+ */
110
+ structureOptions?: Partial<StructureOptions>;
111
+ /**
112
+ * Advanced: override rendering options used in keyboard mode.
113
+ */
114
+ renderingOptions?: Partial<RenderingOptions>;
115
+ /**
116
+ * Advanced: adds "compressSparseDivisions" to all dimensions of the chart.
117
+ */
118
+ compressSparseDivisions?: boolean;
119
+ };
120
+ type BokehWrapperInstance = {
121
+ /** Remove all DOM nodes added by the wrapper and restore `plotContainer`. */
122
+ destroy: () => void;
123
+ /** Returns the node currently focused in the navigation structure. */
124
+ getCurrentNode: () => NodeObject | null;
125
+ /** The data-navigator Structure, e.g. for use with @data-navigator/inspector. */
126
+ structure: Structure;
127
+ };
128
+
129
+ /**
130
+ * Builds an accessible description for a chart's root node following the pattern:
131
+ * "[title | x and y]. [chart type]. [x axis info]. [y axis info].
132
+ * [grouping info]. [count sentence]."
133
+ *
134
+ * `dimensionCount` controls the count sentence:
135
+ * - 0 or 1 (default): "contains N divisions and M data points" (or just M if equal)
136
+ * - >1: "contains N dimensions and M total data points"
137
+ *
138
+ * For single-dimension charts, the string is set as `node.semantics.label` on the
139
+ * dimension root so data-navigator's defaultDescribeNode announces it when a user
140
+ * enters. For multi-dimension charts it is the label of an injected Level 0 node.
141
+ */
142
+ declare function buildChartDescription(options: BokehWrapperOptions, dimensionCount?: number): string;
143
+ /**
144
+ * Generates a human-readable `semantics.label` for a single node.
145
+ *
146
+ * - Division node (has `data.values` map): "<value>. Contains N data point(s)."
147
+ * - Leaf node (raw datum): "field: value. field: value." (internal _ fields excluded)
148
+ * - Fallback: node id
149
+ *
150
+ * This label is consumed by data-navigator's rendering module (`aria-label`) in
151
+ * keyboard mode, and by textChat's `defaultDescribeNode` when `semantics.label`
152
+ * is present (textChat falls back to its own description when it is absent).
153
+ */
154
+ declare function buildNodeLabel(node: any): string;
155
+ /**
156
+ * Ensures every node in the structure has `semantics.label` set.
157
+ *
158
+ * Required by data-navigator's rendering module for every element it renders
159
+ * in keyboard mode. Also used by textChat's `defaultDescribeNode` — textChat
160
+ * uses the label when present and falls back to its own description when absent.
161
+ *
162
+ * Nodes that already have `semantics.label` (e.g. the dimension root set to the
163
+ * full chart description) are left unchanged.
164
+ */
165
+ declare function prepareNodeSemantics(structure: Structure): void;
166
+
167
+ /**
168
+ * @data-navigator/bokeh-wrapper
169
+ *
170
+ * Adds accessible data navigation to Bokeh charts with minimal setup.
171
+ * Uses the data-navigator text-chat interface by default so that the
172
+ * broadest range of users — including screen reader users, keyboard-only
173
+ * users, and mobile users — can explore your chart.
174
+ */
175
+
176
+ /**
177
+ * Adds accessible data-navigator to a Bokeh chart.
178
+ *
179
+ * Text-chat mode (default) places the accessible UI adjacent to the plot
180
+ * and marks the Bokeh canvas inert so assistive technologies skip it.
181
+ * Keyboard mode places keyboard navigation elements *inside* the plot container
182
+ * and must NOT mark the container inert.
183
+ */
184
+ declare function addDataNavigator(options: BokehWrapperOptions): BokehWrapperInstance;
185
+
186
+ export { type BokehChartType, type BokehWrapperInstance, type BokehWrapperMode, type BokehWrapperOptions, addDataNavigator, buildChartDescription, buildNodeLabel, prepareNodeSemantics };
@@ -0,0 +1,186 @@
1
+ import { NodeObject, Structure, LLMMessage, StructureOptions, RenderingOptions } from 'data-navigator';
2
+
3
+ /**
4
+ * Supported Bokeh chart types for smart defaults.
5
+ * Use 'auto' to let the wrapper infer the type from your data.
6
+ */
7
+ type BokehChartType = 'bar' | 'hbar' | 'scatter' | 'cartesian' | 'line' | 'multiline' | 'crossline' | 'stacked_bar' | 'auto';
8
+ /**
9
+ * Navigation interface mode.
10
+ * - 'text' — text-chat menu only (default, best for broad accessibility)
11
+ * - 'keyboard' — keyboard navigation only (arrow keys, no text chat)
12
+ * - 'both' — both interfaces simultaneously
13
+ */
14
+ type BokehWrapperMode = 'text' | 'keyboard' | 'both';
15
+ type BokehWrapperOptions = {
16
+ /**
17
+ * The element containing the rendered Bokeh plot.
18
+ * The wrapper sets this to `inert` so assistive technologies
19
+ * skip Bokeh's inaccessible canvas/SVG output.
20
+ */
21
+ plotContainer: string | HTMLElement;
22
+ /**
23
+ * The dataset used to generate the chart — plain JSON array of objects.
24
+ */
25
+ data: Record<string, unknown>[];
26
+ /**
27
+ * Chart type for smart defaults. Defaults to 'auto'.
28
+ */
29
+ type?: BokehChartType;
30
+ /**
31
+ * Field name used as the horizontal / category axis.
32
+ */
33
+ xField?: string;
34
+ /**
35
+ * Field name used as the vertical / value axis.
36
+ */
37
+ yField?: string;
38
+ /**
39
+ * Field name used to group data (series, stack layer, etc.).
40
+ */
41
+ groupField?: string;
42
+ /**
43
+ * Override the field used to generate node IDs.
44
+ * By default the wrapper derives IDs from the data.
45
+ */
46
+ idField?: string;
47
+ /**
48
+ * Chart title used as the opening of the accessible chart description
49
+ * announced when a user first enters the navigation structure.
50
+ * If omitted, the description opens with the x and y field names instead.
51
+ * Example: "Fruit counts"
52
+ */
53
+ title?: string;
54
+ /**
55
+ * Override the auto-generated accessible description for the chart's root node.
56
+ * Pass a string for a static description, or a function that receives the
57
+ * wrapper options and returns a string.
58
+ *
59
+ * Single-dimension charts (bar, multiline): the description is set
60
+ * as `semantics.label` on the dimension root node.
61
+ * Multi-dimension charts (stacked_bar, crossline, cartesian): it becomes the `semantics.label`
62
+ * of an injected Level 0 node added via the data-navigator `dimensions.parentOptions.addLevel0` API.
63
+ */
64
+ describeRoot?: string | ((options: BokehWrapperOptions) => string);
65
+ /**
66
+ * Interface mode. Defaults to 'text' (text-chat menu).
67
+ */
68
+ mode?: BokehWrapperMode;
69
+ /**
70
+ * Container element for the text-chat UI.
71
+ * If omitted, the wrapper creates a `<div>` and inserts it
72
+ * immediately after `plotContainer`.
73
+ */
74
+ chatContainer?: string | HTMLElement;
75
+ /**
76
+ * Called every time the user navigates to a new node.
77
+ * Use this to sync Bokeh chart highlights or tooltips.
78
+ */
79
+ onNavigate?: (node: NodeObject) => void;
80
+ /**
81
+ * Called when the user exits the navigation structure.
82
+ */
83
+ onExit?: () => void;
84
+ /**
85
+ * Called when the user types "click" or "select" in text mode.
86
+ * Receives the currently focused node. Use this to programmatically
87
+ * trigger Bokeh hit-testing or selection logic.
88
+ */
89
+ onClick?: (node: NodeObject) => void;
90
+ /**
91
+ * Called when the user types "hover" or "inspect" in text mode.
92
+ * Receives the currently focused node. Use this to programmatically
93
+ * trigger Bokeh hover / tooltip display.
94
+ */
95
+ onHover?: (node: NodeObject) => void;
96
+ /**
97
+ * Optional LLM callback for AI-assisted data Q&A in text mode.
98
+ * Receives a message array and should return a response string.
99
+ */
100
+ llm?: (messages: LLMMessage[]) => Promise<string | null>;
101
+ /**
102
+ * Override the default human-readable labels for navigation commands
103
+ * shown in the text-chat interface (e.g. { left: 'Previous bar' }).
104
+ */
105
+ commandLabels?: Record<string, string>;
106
+ /**
107
+ * Advanced: merge additional options into the generated StructureOptions
108
+ * before calling `data-navigator`'s structure builder.
109
+ */
110
+ structureOptions?: Partial<StructureOptions>;
111
+ /**
112
+ * Advanced: override rendering options used in keyboard mode.
113
+ */
114
+ renderingOptions?: Partial<RenderingOptions>;
115
+ /**
116
+ * Advanced: adds "compressSparseDivisions" to all dimensions of the chart.
117
+ */
118
+ compressSparseDivisions?: boolean;
119
+ };
120
+ type BokehWrapperInstance = {
121
+ /** Remove all DOM nodes added by the wrapper and restore `plotContainer`. */
122
+ destroy: () => void;
123
+ /** Returns the node currently focused in the navigation structure. */
124
+ getCurrentNode: () => NodeObject | null;
125
+ /** The data-navigator Structure, e.g. for use with @data-navigator/inspector. */
126
+ structure: Structure;
127
+ };
128
+
129
+ /**
130
+ * Builds an accessible description for a chart's root node following the pattern:
131
+ * "[title | x and y]. [chart type]. [x axis info]. [y axis info].
132
+ * [grouping info]. [count sentence]."
133
+ *
134
+ * `dimensionCount` controls the count sentence:
135
+ * - 0 or 1 (default): "contains N divisions and M data points" (or just M if equal)
136
+ * - >1: "contains N dimensions and M total data points"
137
+ *
138
+ * For single-dimension charts, the string is set as `node.semantics.label` on the
139
+ * dimension root so data-navigator's defaultDescribeNode announces it when a user
140
+ * enters. For multi-dimension charts it is the label of an injected Level 0 node.
141
+ */
142
+ declare function buildChartDescription(options: BokehWrapperOptions, dimensionCount?: number): string;
143
+ /**
144
+ * Generates a human-readable `semantics.label` for a single node.
145
+ *
146
+ * - Division node (has `data.values` map): "<value>. Contains N data point(s)."
147
+ * - Leaf node (raw datum): "field: value. field: value." (internal _ fields excluded)
148
+ * - Fallback: node id
149
+ *
150
+ * This label is consumed by data-navigator's rendering module (`aria-label`) in
151
+ * keyboard mode, and by textChat's `defaultDescribeNode` when `semantics.label`
152
+ * is present (textChat falls back to its own description when it is absent).
153
+ */
154
+ declare function buildNodeLabel(node: any): string;
155
+ /**
156
+ * Ensures every node in the structure has `semantics.label` set.
157
+ *
158
+ * Required by data-navigator's rendering module for every element it renders
159
+ * in keyboard mode. Also used by textChat's `defaultDescribeNode` — textChat
160
+ * uses the label when present and falls back to its own description when absent.
161
+ *
162
+ * Nodes that already have `semantics.label` (e.g. the dimension root set to the
163
+ * full chart description) are left unchanged.
164
+ */
165
+ declare function prepareNodeSemantics(structure: Structure): void;
166
+
167
+ /**
168
+ * @data-navigator/bokeh-wrapper
169
+ *
170
+ * Adds accessible data navigation to Bokeh charts with minimal setup.
171
+ * Uses the data-navigator text-chat interface by default so that the
172
+ * broadest range of users — including screen reader users, keyboard-only
173
+ * users, and mobile users — can explore your chart.
174
+ */
175
+
176
+ /**
177
+ * Adds accessible data-navigator to a Bokeh chart.
178
+ *
179
+ * Text-chat mode (default) places the accessible UI adjacent to the plot
180
+ * and marks the Bokeh canvas inert so assistive technologies skip it.
181
+ * Keyboard mode places keyboard navigation elements *inside* the plot container
182
+ * and must NOT mark the container inert.
183
+ */
184
+ declare function addDataNavigator(options: BokehWrapperOptions): BokehWrapperInstance;
185
+
186
+ export { type BokehChartType, type BokehWrapperInstance, type BokehWrapperMode, type BokehWrapperOptions, addDataNavigator, buildChartDescription, buildNodeLabel, prepareNodeSemantics };