@opendata-ai/openchart-core 6.10.0 → 6.12.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.
- package/dist/index.d.ts +89 -12
- package/dist/index.js +16 -5
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/src/layout/__tests__/chrome.test.ts +15 -0
- package/src/layout/chrome.ts +6 -4
- package/src/types/__tests__/gradient.test.ts +95 -0
- package/src/types/index.ts +6 -0
- package/src/types/layout.ts +17 -8
- package/src/types/spec.ts +93 -2
package/package.json
CHANGED
|
@@ -190,4 +190,19 @@ describe('computeChrome', () => {
|
|
|
190
190
|
expect(result.title).toBeDefined();
|
|
191
191
|
// Just verify it runs without error; exact values depend on measure fn
|
|
192
192
|
});
|
|
193
|
+
|
|
194
|
+
it('returns zero bottom height when watermark is false and no bottom chrome', () => {
|
|
195
|
+
const chrome: Chrome = { title: 'Title' };
|
|
196
|
+
const result = computeChrome(chrome, theme, 600, undefined, 'full', undefined, false);
|
|
197
|
+
expect(result.bottomHeight).toBe(0);
|
|
198
|
+
});
|
|
199
|
+
|
|
200
|
+
it('does not reserve brand width for bottom text when watermark is false', () => {
|
|
201
|
+
const chrome: Chrome = { source: 'Source: World Bank' };
|
|
202
|
+
const withWatermark = computeChrome(chrome, theme, 600, undefined, 'full', undefined, true);
|
|
203
|
+
const withoutWatermark = computeChrome(chrome, theme, 600, undefined, 'full', undefined, false);
|
|
204
|
+
|
|
205
|
+
// Without watermark, source text gets full width (not reduced by BRAND_RESERVE_WIDTH)
|
|
206
|
+
expect(withoutWatermark.source!.maxWidth).toBeGreaterThan(withWatermark.source!.maxWidth);
|
|
207
|
+
});
|
|
193
208
|
});
|
package/src/layout/chrome.ts
CHANGED
|
@@ -148,6 +148,7 @@ export function computeChrome(
|
|
|
148
148
|
measureText?: MeasureTextFn,
|
|
149
149
|
chromeMode: ChromeMode = 'full',
|
|
150
150
|
padding?: number,
|
|
151
|
+
watermark: boolean = true,
|
|
151
152
|
): ResolvedChrome {
|
|
152
153
|
if (!chrome || chromeMode === 'hidden') {
|
|
153
154
|
// Brand watermark is also skipped at cramped sizes (height < 200px triggers
|
|
@@ -217,7 +218,7 @@ export function computeChrome(
|
|
|
217
218
|
// renders for wide-enough charts. Reserve space so it doesn't overflow.
|
|
218
219
|
if (chromeMode === 'compact') {
|
|
219
220
|
let compactBottom = 0;
|
|
220
|
-
if (width >= BRAND_MIN_WIDTH) {
|
|
221
|
+
if (watermark && width >= BRAND_MIN_WIDTH) {
|
|
221
222
|
const brandHeight = estimateTextHeight(BRAND_FONT_SIZE, 1);
|
|
222
223
|
compactBottom = theme.spacing.chartToFooter + brandHeight + pad;
|
|
223
224
|
}
|
|
@@ -230,7 +231,8 @@ export function computeChrome(
|
|
|
230
231
|
|
|
231
232
|
// Bottom elements: source, byline, footer
|
|
232
233
|
// Reserve space on the right for the brand watermark so text doesn't overlap it
|
|
233
|
-
const
|
|
234
|
+
const shouldReserveBrandWidth = watermark && width >= BRAND_MIN_WIDTH;
|
|
235
|
+
const bottomMaxWidth = maxWidth - (shouldReserveBrandWidth ? BRAND_RESERVE_WIDTH : 0);
|
|
234
236
|
const bottomElements: Partial<Pick<ResolvedChrome, 'source' | 'byline' | 'footer'>> = {};
|
|
235
237
|
let bottomHeight = 0;
|
|
236
238
|
|
|
@@ -300,7 +302,7 @@ export function computeChrome(
|
|
|
300
302
|
// Ensure bottom height accommodates the brand watermark, which renders
|
|
301
303
|
// at the same Y as the first bottom chrome item but is taller (20px font
|
|
302
304
|
// vs 12px source). Without this, the brand overflows the SVG viewBox.
|
|
303
|
-
if (width >= BRAND_MIN_WIDTH) {
|
|
305
|
+
if (watermark && width >= BRAND_MIN_WIDTH) {
|
|
304
306
|
const brandHeight = estimateTextHeight(BRAND_FONT_SIZE, 1);
|
|
305
307
|
// firstItemY is chartToFooter (the Y offset of the first bottom item).
|
|
306
308
|
// The brand needs brandHeight below that point; bottom chrome content
|
|
@@ -313,7 +315,7 @@ export function computeChrome(
|
|
|
313
315
|
|
|
314
316
|
// Add bottom padding
|
|
315
317
|
bottomHeight += pad;
|
|
316
|
-
} else if (width >= BRAND_MIN_WIDTH) {
|
|
318
|
+
} else if (watermark && width >= BRAND_MIN_WIDTH) {
|
|
317
319
|
// No bottom chrome items, but brand watermark still renders.
|
|
318
320
|
// Reserve space: chartToFooter gap + brand text height + padding.
|
|
319
321
|
const brandHeight = estimateTextHeight(BRAND_FONT_SIZE, 1);
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import { describe, expect, it } from 'vitest';
|
|
2
|
+
import type { GradientDef } from '../spec';
|
|
3
|
+
import { getRepresentativeColor, isGradientDef } from '../spec';
|
|
4
|
+
|
|
5
|
+
describe('isGradientDef', () => {
|
|
6
|
+
it('returns true for a valid linear gradient', () => {
|
|
7
|
+
expect(
|
|
8
|
+
isGradientDef({
|
|
9
|
+
gradient: 'linear',
|
|
10
|
+
stops: [
|
|
11
|
+
{ offset: 0, color: '#f00' },
|
|
12
|
+
{ offset: 1, color: '#00f' },
|
|
13
|
+
],
|
|
14
|
+
}),
|
|
15
|
+
).toBe(true);
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
it('returns true for a valid radial gradient', () => {
|
|
19
|
+
expect(
|
|
20
|
+
isGradientDef({
|
|
21
|
+
gradient: 'radial',
|
|
22
|
+
stops: [{ offset: 0, color: '#f00' }],
|
|
23
|
+
}),
|
|
24
|
+
).toBe(true);
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
it('returns false for a plain string', () => {
|
|
28
|
+
expect(isGradientDef('#ff0000')).toBe(false);
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
it('returns false for null', () => {
|
|
32
|
+
expect(isGradientDef(null)).toBe(false);
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
it('returns false for undefined', () => {
|
|
36
|
+
expect(isGradientDef(undefined)).toBe(false);
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
it('returns false for an object without gradient property', () => {
|
|
40
|
+
expect(isGradientDef({ stops: [] })).toBe(false);
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
it('returns false for an object without stops', () => {
|
|
44
|
+
expect(isGradientDef({ gradient: 'linear' })).toBe(false);
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
it('returns false for an object with invalid gradient type', () => {
|
|
48
|
+
expect(isGradientDef({ gradient: 'mesh', stops: [] })).toBe(false);
|
|
49
|
+
});
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
describe('getRepresentativeColor', () => {
|
|
53
|
+
it('returns the string directly when given a string', () => {
|
|
54
|
+
expect(getRepresentativeColor('#1b7fa3')).toBe('#1b7fa3');
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
it('returns the last stop color for a linear gradient', () => {
|
|
58
|
+
const grad: GradientDef = {
|
|
59
|
+
gradient: 'linear',
|
|
60
|
+
stops: [
|
|
61
|
+
{ offset: 0, color: '#f00' },
|
|
62
|
+
{ offset: 0.5, color: '#0f0' },
|
|
63
|
+
{ offset: 1, color: '#00f' },
|
|
64
|
+
],
|
|
65
|
+
};
|
|
66
|
+
expect(getRepresentativeColor(grad)).toBe('#00f');
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
it('returns the last stop color for a radial gradient', () => {
|
|
70
|
+
const grad: GradientDef = {
|
|
71
|
+
gradient: 'radial',
|
|
72
|
+
stops: [
|
|
73
|
+
{ offset: 0, color: '#fff' },
|
|
74
|
+
{ offset: 1, color: '#000' },
|
|
75
|
+
],
|
|
76
|
+
};
|
|
77
|
+
expect(getRepresentativeColor(grad)).toBe('#000');
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
it('returns #000000 for a gradient with empty stops array', () => {
|
|
81
|
+
const grad: GradientDef = {
|
|
82
|
+
gradient: 'linear',
|
|
83
|
+
stops: [],
|
|
84
|
+
};
|
|
85
|
+
expect(getRepresentativeColor(grad)).toBe('#000000');
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
it('returns the single stop color for a gradient with one stop', () => {
|
|
89
|
+
const grad: GradientDef = {
|
|
90
|
+
gradient: 'radial',
|
|
91
|
+
stops: [{ offset: 0, color: '#abc' }],
|
|
92
|
+
};
|
|
93
|
+
expect(getRepresentativeColor(grad)).toBe('#abc');
|
|
94
|
+
});
|
|
95
|
+
});
|
package/src/types/index.ts
CHANGED
|
@@ -114,6 +114,8 @@ export type {
|
|
|
114
114
|
FieldType,
|
|
115
115
|
FilterPredicate,
|
|
116
116
|
FilterTransform,
|
|
117
|
+
GradientDef,
|
|
118
|
+
GradientStop,
|
|
117
119
|
GraphEdge,
|
|
118
120
|
GraphEncoding,
|
|
119
121
|
GraphEncodingChannel,
|
|
@@ -125,12 +127,14 @@ export type {
|
|
|
125
127
|
LabelDensity,
|
|
126
128
|
LayerSpec,
|
|
127
129
|
LegendConfig,
|
|
130
|
+
LinearGradient,
|
|
128
131
|
LogicalAnd,
|
|
129
132
|
LogicalNot,
|
|
130
133
|
LogicalOr,
|
|
131
134
|
MarkDef,
|
|
132
135
|
MarkType,
|
|
133
136
|
NodeOverride,
|
|
137
|
+
RadialGradient,
|
|
134
138
|
RangeAnnotation,
|
|
135
139
|
RefLineAnnotation,
|
|
136
140
|
ResolveConfig,
|
|
@@ -155,9 +159,11 @@ export type {
|
|
|
155
159
|
} from './spec';
|
|
156
160
|
export {
|
|
157
161
|
CHART_TYPES,
|
|
162
|
+
getRepresentativeColor,
|
|
158
163
|
isChartSpec,
|
|
159
164
|
isConditionalDef,
|
|
160
165
|
isEncodingChannel,
|
|
166
|
+
isGradientDef,
|
|
161
167
|
isGraphSpec,
|
|
162
168
|
isLayerSpec,
|
|
163
169
|
isRangeAnnotation,
|
package/src/types/layout.ts
CHANGED
|
@@ -9,6 +9,7 @@
|
|
|
9
9
|
* fully resolved with computed positions, colors, and dimensions.
|
|
10
10
|
*/
|
|
11
11
|
|
|
12
|
+
import type { GradientDef } from './spec';
|
|
12
13
|
import type { ResolvedTheme } from './theme';
|
|
13
14
|
|
|
14
15
|
// ---------------------------------------------------------------------------
|
|
@@ -235,8 +236,8 @@ export interface AreaMark {
|
|
|
235
236
|
path: string;
|
|
236
237
|
/** SVG path string for just the top boundary (for stroking the data line only). */
|
|
237
238
|
topPath: string;
|
|
238
|
-
/** Fill color. */
|
|
239
|
-
fill: string;
|
|
239
|
+
/** Fill color or gradient. */
|
|
240
|
+
fill: string | GradientDef;
|
|
240
241
|
/** Fill opacity. */
|
|
241
242
|
fillOpacity: number;
|
|
242
243
|
/** Optional stroke for the top boundary. */
|
|
@@ -277,8 +278,8 @@ export interface RectMark {
|
|
|
277
278
|
width: number;
|
|
278
279
|
/** Height. */
|
|
279
280
|
height: number;
|
|
280
|
-
/** Fill color. */
|
|
281
|
-
fill: string;
|
|
281
|
+
/** Fill color or gradient. */
|
|
282
|
+
fill: string | GradientDef;
|
|
282
283
|
/** Stroke color. */
|
|
283
284
|
stroke?: string;
|
|
284
285
|
/** Stroke width. */
|
|
@@ -321,8 +322,8 @@ export interface ArcMark {
|
|
|
321
322
|
startAngle: number;
|
|
322
323
|
/** End angle in radians. */
|
|
323
324
|
endAngle: number;
|
|
324
|
-
/** Fill color. */
|
|
325
|
-
fill: string;
|
|
325
|
+
/** Fill color or gradient. */
|
|
326
|
+
fill: string | GradientDef;
|
|
326
327
|
/** Stroke color (usually white for slice separation). */
|
|
327
328
|
stroke: string;
|
|
328
329
|
/** Stroke width. */
|
|
@@ -349,8 +350,8 @@ export interface PointMark {
|
|
|
349
350
|
cy: number;
|
|
350
351
|
/** Radius in pixels. */
|
|
351
352
|
r: number;
|
|
352
|
-
/** Fill color. */
|
|
353
|
-
fill: string;
|
|
353
|
+
/** Fill color or gradient. */
|
|
354
|
+
fill: string | GradientDef;
|
|
354
355
|
/** Stroke color. */
|
|
355
356
|
stroke: string;
|
|
356
357
|
/** Stroke width. */
|
|
@@ -666,6 +667,8 @@ export interface ChartLayout {
|
|
|
666
667
|
dimensions: { width: number; height: number };
|
|
667
668
|
/** Resolved animation config. Present only when animation is enabled. */
|
|
668
669
|
animation?: ResolvedAnimation;
|
|
670
|
+
/** Whether the tryOpenData.ai watermark is enabled. */
|
|
671
|
+
watermark: boolean;
|
|
669
672
|
}
|
|
670
673
|
|
|
671
674
|
// ---------------------------------------------------------------------------
|
|
@@ -842,6 +845,8 @@ export interface TableLayout {
|
|
|
842
845
|
theme: ResolvedTheme;
|
|
843
846
|
/** Resolved animation config. Present only when animation is enabled. */
|
|
844
847
|
animation?: ResolvedAnimation;
|
|
848
|
+
/** Whether the tryOpenData.ai watermark is enabled. */
|
|
849
|
+
watermark: boolean;
|
|
845
850
|
}
|
|
846
851
|
|
|
847
852
|
// ---------------------------------------------------------------------------
|
|
@@ -1019,6 +1024,8 @@ export interface SankeyLayout {
|
|
|
1019
1024
|
dimensions: { width: number; height: number };
|
|
1020
1025
|
/** Resolved animation config. Present only when animation is enabled. */
|
|
1021
1026
|
animation?: ResolvedAnimation;
|
|
1027
|
+
/** Whether the tryOpenData.ai watermark is enabled. */
|
|
1028
|
+
watermark: boolean;
|
|
1022
1029
|
}
|
|
1023
1030
|
|
|
1024
1031
|
// ---------------------------------------------------------------------------
|
|
@@ -1053,6 +1060,8 @@ export interface CompileOptions {
|
|
|
1053
1060
|
* before calling compile. The engine always receives a resolved boolean.
|
|
1054
1061
|
*/
|
|
1055
1062
|
darkMode?: boolean;
|
|
1063
|
+
/** Whether to show the tryOpenData.ai watermark. Defaults to true. */
|
|
1064
|
+
watermark?: boolean;
|
|
1056
1065
|
/**
|
|
1057
1066
|
* Real text measurement function provided by the adapter.
|
|
1058
1067
|
* Uses a hidden canvas or DOM element for accurate text dimensions.
|
package/src/types/spec.ts
CHANGED
|
@@ -48,6 +48,87 @@ export type MarkType =
|
|
|
48
48
|
/** @deprecated Use MarkType instead. Kept for internal migration references. */
|
|
49
49
|
export type ChartType = MarkType;
|
|
50
50
|
|
|
51
|
+
// ---------------------------------------------------------------------------
|
|
52
|
+
// Gradient definitions (Vega-aligned)
|
|
53
|
+
// ---------------------------------------------------------------------------
|
|
54
|
+
|
|
55
|
+
/** A single color stop in a gradient definition. */
|
|
56
|
+
export interface GradientStop {
|
|
57
|
+
/** Position along the gradient, 0 to 1. */
|
|
58
|
+
offset: number;
|
|
59
|
+
/** CSS color string at this stop. */
|
|
60
|
+
color: string;
|
|
61
|
+
/** Opacity at this stop, 0 to 1. Maps to SVG stop-opacity. */
|
|
62
|
+
opacity?: number;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Linear gradient definition.
|
|
67
|
+
* Coordinates are in [0,1] normalized space relative to the mark's bounding box
|
|
68
|
+
* (maps to SVG gradientUnits="objectBoundingBox").
|
|
69
|
+
*/
|
|
70
|
+
export interface LinearGradient {
|
|
71
|
+
gradient: 'linear';
|
|
72
|
+
/** Color stops from start to end. */
|
|
73
|
+
stops: GradientStop[];
|
|
74
|
+
/** Start x coordinate (0-1). Default: 0. */
|
|
75
|
+
x1?: number;
|
|
76
|
+
/** Start y coordinate (0-1). Default: 0. */
|
|
77
|
+
y1?: number;
|
|
78
|
+
/** End x coordinate (0-1). Default: 0. */
|
|
79
|
+
x2?: number;
|
|
80
|
+
/** End y coordinate (0-1). Default: 1 (top-to-bottom). */
|
|
81
|
+
y2?: number;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* Radial gradient definition.
|
|
86
|
+
* Coordinates are in [0,1] normalized space relative to the mark's bounding box.
|
|
87
|
+
*/
|
|
88
|
+
export interface RadialGradient {
|
|
89
|
+
gradient: 'radial';
|
|
90
|
+
/** Color stops from inner to outer. */
|
|
91
|
+
stops: GradientStop[];
|
|
92
|
+
/** Inner circle center x (0-1). Default: 0.5. */
|
|
93
|
+
x1?: number;
|
|
94
|
+
/** Inner circle center y (0-1). Default: 0.5. */
|
|
95
|
+
y1?: number;
|
|
96
|
+
/** Inner circle radius (0-1). Default: 0. */
|
|
97
|
+
r1?: number;
|
|
98
|
+
/** Outer circle center x (0-1). Default: 0.5. */
|
|
99
|
+
x2?: number;
|
|
100
|
+
/** Outer circle center y (0-1). Default: 0.5. */
|
|
101
|
+
y2?: number;
|
|
102
|
+
/** Outer circle radius (0-1). Default: 0.5. */
|
|
103
|
+
r2?: number;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
/** A gradient definition, either linear or radial. */
|
|
107
|
+
export type GradientDef = LinearGradient | RadialGradient;
|
|
108
|
+
|
|
109
|
+
/** Type guard: check if a value is a GradientDef object. */
|
|
110
|
+
export function isGradientDef(value: unknown): value is GradientDef {
|
|
111
|
+
return (
|
|
112
|
+
typeof value === 'object' &&
|
|
113
|
+
value !== null &&
|
|
114
|
+
'gradient' in value &&
|
|
115
|
+
'stops' in value &&
|
|
116
|
+
((value as GradientDef).gradient === 'linear' || (value as GradientDef).gradient === 'radial')
|
|
117
|
+
);
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
/**
|
|
121
|
+
* Extract a single representative color from a fill value.
|
|
122
|
+
* Returns the fill directly if it's a string, or the last stop color
|
|
123
|
+
* if it's a gradient. Used by tooltips, labels, legends, and voronoi
|
|
124
|
+
* overlays that need a flat color.
|
|
125
|
+
*/
|
|
126
|
+
export function getRepresentativeColor(fill: string | GradientDef): string {
|
|
127
|
+
if (typeof fill === 'string') return fill;
|
|
128
|
+
const stops = fill.stops;
|
|
129
|
+
return stops.length > 0 ? stops[stops.length - 1].color : '#000000';
|
|
130
|
+
}
|
|
131
|
+
|
|
51
132
|
// ---------------------------------------------------------------------------
|
|
52
133
|
// Mark definition (Vega-Lite aligned)
|
|
53
134
|
// ---------------------------------------------------------------------------
|
|
@@ -94,8 +175,8 @@ export interface MarkDef {
|
|
|
94
175
|
filled?: boolean;
|
|
95
176
|
/** Default opacity (0-1). */
|
|
96
177
|
opacity?: number;
|
|
97
|
-
/** Default fill color. */
|
|
98
|
-
fill?: string;
|
|
178
|
+
/** Default fill color or gradient. */
|
|
179
|
+
fill?: string | GradientDef;
|
|
99
180
|
/** Default stroke color. */
|
|
100
181
|
stroke?: string;
|
|
101
182
|
/** Default stroke width. */
|
|
@@ -723,6 +804,8 @@ export interface ChartSpec {
|
|
|
723
804
|
theme?: ThemeConfig;
|
|
724
805
|
/** Dark mode behavior. Defaults to "off". */
|
|
725
806
|
darkMode?: DarkMode;
|
|
807
|
+
/** Whether to show the tryOpenData.ai watermark. Defaults to true. */
|
|
808
|
+
watermark?: boolean;
|
|
726
809
|
/** Series names to hide from rendering. Hidden series remain in the legend but are visually dimmed. */
|
|
727
810
|
hiddenSeries?: string[];
|
|
728
811
|
/** Per-series visual overrides, keyed by series name (the color field value). */
|
|
@@ -763,6 +846,8 @@ export interface TableSpec {
|
|
|
763
846
|
theme?: ThemeConfig;
|
|
764
847
|
/** Dark mode behavior. */
|
|
765
848
|
darkMode?: DarkMode;
|
|
849
|
+
/** Whether to show the tryOpenData.ai watermark. Defaults to true. */
|
|
850
|
+
watermark?: boolean;
|
|
766
851
|
/** Enable client-side search/filter. */
|
|
767
852
|
search?: boolean;
|
|
768
853
|
/** Pagination configuration. True for defaults, or an object with pageSize. */
|
|
@@ -830,6 +915,8 @@ export interface GraphSpec {
|
|
|
830
915
|
theme?: ThemeConfig;
|
|
831
916
|
/** Dark mode behavior. */
|
|
832
917
|
darkMode?: DarkMode;
|
|
918
|
+
/** Whether to show the tryOpenData.ai watermark. Defaults to true. */
|
|
919
|
+
watermark?: boolean;
|
|
833
920
|
}
|
|
834
921
|
|
|
835
922
|
// ---------------------------------------------------------------------------
|
|
@@ -883,6 +970,8 @@ export interface LayerSpec {
|
|
|
883
970
|
theme?: ThemeConfig;
|
|
884
971
|
/** Dark mode behavior. Defaults to "off". */
|
|
885
972
|
darkMode?: DarkMode;
|
|
973
|
+
/** Whether to show the tryOpenData.ai watermark. Defaults to true. */
|
|
974
|
+
watermark?: boolean;
|
|
886
975
|
/** Resolution strategy for shared scales/axes/legends. */
|
|
887
976
|
resolve?: ResolveConfig;
|
|
888
977
|
/** Hidden series names. */
|
|
@@ -949,6 +1038,8 @@ export interface SankeySpec {
|
|
|
949
1038
|
theme?: ThemeConfig;
|
|
950
1039
|
/** Dark mode behavior. Defaults to "off". */
|
|
951
1040
|
darkMode?: DarkMode;
|
|
1041
|
+
/** Whether to show the tryOpenData.ai watermark. Defaults to true. */
|
|
1042
|
+
watermark?: boolean;
|
|
952
1043
|
/** Animation configuration for entrance animations. */
|
|
953
1044
|
animation?: AnimationSpec;
|
|
954
1045
|
/**
|