@gooddata/sdk-ui-vis-commons 11.33.0-alpha.4 → 11.33.0-alpha.7

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,5 @@
1
+ /**
2
+ * @internal
3
+ */
4
+ export declare function markdownToHtml(markdown: string): string;
5
+ //# sourceMappingURL=markdownToHtml.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"markdownToHtml.d.ts","sourceRoot":"","sources":["../../src/customTooltip/markdownToHtml.ts"],"names":[],"mappings":"AAsHA;;GAEG;AACH,wBAAgB,cAAc,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAuBvD"}
@@ -0,0 +1,191 @@
1
+ // (C) 2026 GoodData Corporation
2
+ /**
3
+ * Lightweight Markdown-to-HTML converter for tooltip rendering.
4
+ *
5
+ * Supports the subset of Markdown needed for tooltips:
6
+ * - Headings (# through ####)
7
+ * - Bold (**text** or __text__)
8
+ * - Italic (*text* or _text_)
9
+ * - Unordered lists (- item or * item)
10
+ * - Ordered lists (1. item)
11
+ * - Images (![alt](url))
12
+ * - Links ([text](url)) — rendered as plain styled text (not clickable in tooltips)
13
+ * - Horizontal rules (--- or ***)
14
+ * - Line breaks
15
+ * - Backslash escapes (\*, \_, \[, \!, etc.) — render the metachar as literal text.
16
+ * Used by reference resolution to keep data values that contain markdown
17
+ * syntax from being reinterpreted as formatting.
18
+ *
19
+ * Does NOT support: tables, code blocks, blockquotes, nested lists, HTML passthrough.
20
+ * For full Markdown fidelity, a library like `marked` should be used instead.
21
+ *
22
+ * IMPORTANT: When changing the supported syntax here, also update the @alpha TSDoc
23
+ * on `ICustomTooltipConfig.content` in ./types.ts so the SDK documentation matches reality.
24
+ */
25
+ function escapeHtml(text) {
26
+ return text.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;");
27
+ }
28
+ function isSafeUrl(url) {
29
+ return /^https?:\/\//i.test(url) || /^data:image\//i.test(url);
30
+ }
31
+ // URL pattern allowing one level of balanced parens, e.g.
32
+ // https://en.wikipedia.org/wiki/Page_(name)
33
+ const URL_PATTERN = "(?:[^()\\s]|\\([^)]*\\))+";
34
+ const IMAGE_REGEX = new RegExp(`!\\[([^\\]]*)\\]\\((${URL_PATTERN})\\)`, "g");
35
+ const LINK_REGEX = new RegExp(`\\[([^\\]]+)\\]\\((${URL_PATTERN})\\)`, "g");
36
+ // Italic content must have non-whitespace at both inner boundaries. This keeps
37
+ // arithmetic-style text (e.g. `5 * 3 * 2`) from being misread as italics.
38
+ const ITALIC_ASTERISK_REGEX = /\*([^\s*][^*]*[^\s*]|[^\s*])\*/g;
39
+ const ITALIC_UNDERSCORE_REGEX = /(?<!\w)_([^\s_][^_]*[^\s_]|[^\s_])_(?!\w)/g;
40
+ function processInlineMarkdown(text) {
41
+ let result = escapeHtml(text);
42
+ // Inline style as fallback since the tooltip renders outside the normal DOM tree.
43
+ result = result.replace(IMAGE_REGEX, (_match, alt, url) => {
44
+ if (!isSafeUrl(url)) {
45
+ return `${alt}`;
46
+ }
47
+ return `<img src="${url}" alt="${alt}" style="max-width: 100%; display: block; margin: 4px 0;" />`;
48
+ });
49
+ // Render as styled text — links are intentionally not clickable inside tooltips.
50
+ result = result.replace(LINK_REGEX, (_match, linkText) => {
51
+ return `<span class="gd-viz-tooltip-custom-link">${linkText}</span>`;
52
+ });
53
+ // Bold-italic: ***text*** — must run before bold and italic so the triple
54
+ // asterisks are consumed as a unit instead of being split across patterns.
55
+ result = result.replace(/\*\*\*(.+?)\*\*\*/g, "<strong><em>$1</em></strong>");
56
+ result = result.replace(/\*\*(.+?)\*\*/g, "<strong>$1</strong>");
57
+ result = result.replace(/__(.+?)__/g, "<strong>$1</strong>");
58
+ result = result.replace(ITALIC_ASTERISK_REGEX, "<em>$1</em>");
59
+ result = result.replace(ITALIC_UNDERSCORE_REGEX, "<em>$1</em>");
60
+ return result;
61
+ }
62
+ // Backslash-escape protection: replace `\X` with a per-parse sentinel that
63
+ // survives all block- and inline-level matching, then restore it to the literal
64
+ // char at the end. The generated prefix is chosen so it does not already appear
65
+ // in the input, which prevents user-supplied sentinel-shaped text from being
66
+ // restored into raw HTML after escaping.
67
+ const ESCAPABLE_METACHARS = /\\([\\*_`\[\]()!#~+\-])/g;
68
+ const SENTINEL_PREFIX = "\u0001E";
69
+ function escapeRegExp(value) {
70
+ return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
71
+ }
72
+ function createSentinelPrefix(markdown) {
73
+ let index = 0;
74
+ let prefix;
75
+ do {
76
+ prefix = `${SENTINEL_PREFIX}${index}:`;
77
+ index += 1;
78
+ } while (markdown.includes(prefix));
79
+ return prefix;
80
+ }
81
+ function protectEscapes(markdown) {
82
+ const sentinelPrefix = createSentinelPrefix(markdown);
83
+ const escapeSentinelRe = new RegExp(`${escapeRegExp(sentinelPrefix)}([0-9a-f]+);`, "g");
84
+ return {
85
+ markdown: markdown.replace(ESCAPABLE_METACHARS, (_, char) => `${sentinelPrefix}${char.charCodeAt(0).toString(16)};`),
86
+ restore: (html) =>
87
+ // None of the escapable chars are HTML-special (`<`, `>`, `&`, `"`),
88
+ // so a raw substitution is safe — no re-escaping needed.
89
+ html.replace(escapeSentinelRe, (_, code) => String.fromCharCode(parseInt(code, 16))),
90
+ };
91
+ }
92
+ // LRU cache: tooltip formatter is invoked on every Highcharts mousemove,
93
+ // so the same resolved content is parsed many times per second. Caching
94
+ // turns repeated calls into O(1) lookups.
95
+ const CACHE_LIMIT = 200;
96
+ const cache = new Map();
97
+ /**
98
+ * @internal
99
+ */
100
+ export function markdownToHtml(markdown) {
101
+ if (!markdown) {
102
+ return "";
103
+ }
104
+ const cached = cache.get(markdown);
105
+ if (cached !== undefined) {
106
+ // Touch: re-insert so it becomes most-recently-used.
107
+ cache.delete(markdown);
108
+ cache.set(markdown, cached);
109
+ return cached;
110
+ }
111
+ const protectedEscapes = protectEscapes(markdown);
112
+ const html = protectedEscapes.restore(parseMarkdown(protectedEscapes.markdown));
113
+ cache.set(markdown, html);
114
+ if (cache.size > CACHE_LIMIT) {
115
+ const oldest = cache.keys().next().value;
116
+ if (oldest !== undefined) {
117
+ cache.delete(oldest);
118
+ }
119
+ }
120
+ return html;
121
+ }
122
+ function parseMarkdown(markdown) {
123
+ const lines = markdown.split("\n");
124
+ const htmlParts = [];
125
+ let inUnorderedList = false;
126
+ let inOrderedList = false;
127
+ const closeList = () => {
128
+ if (inUnorderedList) {
129
+ htmlParts.push("</ul>");
130
+ inUnorderedList = false;
131
+ }
132
+ if (inOrderedList) {
133
+ htmlParts.push("</ol>");
134
+ inOrderedList = false;
135
+ }
136
+ };
137
+ for (const line of lines) {
138
+ const trimmed = line.trim();
139
+ if (!trimmed) {
140
+ closeList();
141
+ continue;
142
+ }
143
+ // Horizontal rule: --- or *** or ___
144
+ if (/^(-{3,}|\*{3,}|_{3,})$/.test(trimmed)) {
145
+ closeList();
146
+ htmlParts.push("<hr/>");
147
+ continue;
148
+ }
149
+ // Headings: # through ####
150
+ const headingMatch = trimmed.match(/^(#{1,4})\s+(.+)$/);
151
+ if (headingMatch) {
152
+ closeList();
153
+ const level = headingMatch[1].length;
154
+ const content = processInlineMarkdown(headingMatch[2]);
155
+ htmlParts.push(`<h${level}>${content}</h${level}>`);
156
+ continue;
157
+ }
158
+ // Unordered list: - item or * item
159
+ const ulMatch = trimmed.match(/^[-*]\s+(.+)$/);
160
+ if (ulMatch) {
161
+ if (inOrderedList) {
162
+ closeList();
163
+ }
164
+ if (!inUnorderedList) {
165
+ htmlParts.push("<ul>");
166
+ inUnorderedList = true;
167
+ }
168
+ htmlParts.push(`<li>${processInlineMarkdown(ulMatch[1])}</li>`);
169
+ continue;
170
+ }
171
+ // Ordered list: 1. item
172
+ const olMatch = trimmed.match(/^\d+\.\s+(.+)$/);
173
+ if (olMatch) {
174
+ if (inUnorderedList) {
175
+ closeList();
176
+ }
177
+ if (!inOrderedList) {
178
+ htmlParts.push("<ol>");
179
+ inOrderedList = true;
180
+ }
181
+ htmlParts.push(`<li>${processInlineMarkdown(olMatch[1])}</li>`);
182
+ continue;
183
+ }
184
+ // Regular paragraph
185
+ closeList();
186
+ htmlParts.push(`<p>${processInlineMarkdown(trimmed)}</p>`);
187
+ }
188
+ closeList();
189
+ return htmlParts.join("");
190
+ }
191
+ //# sourceMappingURL=markdownToHtml.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"markdownToHtml.js","sourceRoot":"","sources":["../../src/customTooltip/markdownToHtml.ts"],"names":[],"mappings":"AAAA,gCAAgC;AAEhC;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAEH,SAAS,UAAU,CAAC,IAAY,EAAU;IACtC,OAAO,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC;AAAA,CAC1G;AAED,SAAS,SAAS,CAAC,GAAW,EAAW;IACrC,OAAO,eAAe,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,gBAAgB,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AAAA,CAClE;AAED,0DAA0D;AAC1D,4CAA4C;AAC5C,MAAM,WAAW,GAAG,2BAA2B,CAAC;AAChD,MAAM,WAAW,GAAG,IAAI,MAAM,CAAC,uBAAuB,WAAW,MAAM,EAAE,GAAG,CAAC,CAAC;AAC9E,MAAM,UAAU,GAAG,IAAI,MAAM,CAAC,sBAAsB,WAAW,MAAM,EAAE,GAAG,CAAC,CAAC;AAE5E,+EAA+E;AAC/E,0EAA0E;AAC1E,MAAM,qBAAqB,GAAG,iCAAiC,CAAC;AAChE,MAAM,uBAAuB,GAAG,4CAA4C,CAAC;AAE7E,SAAS,qBAAqB,CAAC,IAAY,EAAU;IACjD,IAAI,MAAM,GAAG,UAAU,CAAC,IAAI,CAAC,CAAC;IAE9B,kFAAkF;IAClF,MAAM,GAAG,MAAM,CAAC,OAAO,CAAC,WAAW,EAAE,CAAC,MAAM,EAAE,GAAG,EAAE,GAAG,EAAE,EAAE,CAAC;QACvD,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,EAAE,CAAC;YAClB,OAAO,GAAG,GAAG,EAAE,CAAC;QACpB,CAAC;QACD,OAAO,aAAa,GAAG,UAAU,GAAG,8DAA8D,CAAC;IAAA,CACtG,CAAC,CAAC;IAEH,mFAAiF;IACjF,MAAM,GAAG,MAAM,CAAC,OAAO,CAAC,UAAU,EAAE,CAAC,MAAM,EAAE,QAAQ,EAAE,EAAE,CAAC;QACtD,OAAO,4CAA4C,QAAQ,SAAS,CAAC;IAAA,CACxE,CAAC,CAAC;IAEH,4EAA0E;IAC1E,2EAA2E;IAC3E,MAAM,GAAG,MAAM,CAAC,OAAO,CAAC,oBAAoB,EAAE,8BAA8B,CAAC,CAAC;IAE9E,MAAM,GAAG,MAAM,CAAC,OAAO,CAAC,gBAAgB,EAAE,qBAAqB,CAAC,CAAC;IACjE,MAAM,GAAG,MAAM,CAAC,OAAO,CAAC,YAAY,EAAE,qBAAqB,CAAC,CAAC;IAE7D,MAAM,GAAG,MAAM,CAAC,OAAO,CAAC,qBAAqB,EAAE,aAAa,CAAC,CAAC;IAC9D,MAAM,GAAG,MAAM,CAAC,OAAO,CAAC,uBAAuB,EAAE,aAAa,CAAC,CAAC;IAEhE,OAAO,MAAM,CAAC;AAAA,CACjB;AAED,2EAA2E;AAC3E,gFAAgF;AAChF,gFAAgF;AAChF,6EAA6E;AAC7E,yCAAyC;AACzC,MAAM,mBAAmB,GAAG,0BAA0B,CAAC;AACvD,MAAM,eAAe,GAAG,SAAS,CAAC;AAElC,SAAS,YAAY,CAAC,KAAa,EAAU;IACzC,OAAO,KAAK,CAAC,OAAO,CAAC,qBAAqB,EAAE,MAAM,CAAC,CAAC;AAAA,CACvD;AAED,SAAS,oBAAoB,CAAC,QAAgB,EAAU;IACpD,IAAI,KAAK,GAAG,CAAC,CAAC;IACd,IAAI,MAAc,CAAC;IACnB,GAAG,CAAC;QACA,MAAM,GAAG,GAAG,eAAe,GAAG,KAAK,GAAG,CAAC;QACvC,KAAK,IAAI,CAAC,CAAC;IACf,CAAC,QAAQ,QAAQ,CAAC,QAAQ,CAAC,MAAM,CAAC,EAAE;IACpC,OAAO,MAAM,CAAC;AAAA,CACjB;AAED,SAAS,cAAc,CAAC,QAAgB,EAA2D;IAC/F,MAAM,cAAc,GAAG,oBAAoB,CAAC,QAAQ,CAAC,CAAC;IACtD,MAAM,gBAAgB,GAAG,IAAI,MAAM,CAAC,GAAG,YAAY,CAAC,cAAc,CAAC,cAAc,EAAE,GAAG,CAAC,CAAC;IAExF,OAAO;QACH,QAAQ,EAAE,QAAQ,CAAC,OAAO,CACtB,mBAAmB,EACnB,CAAC,CAAC,EAAE,IAAY,EAAE,EAAE,CAAC,GAAG,cAAc,GAAG,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,GAAG,CAC9E;QACD,OAAO,EAAE,CAAC,IAAY,EAAE,EAAE;QACtB,qEAAqE;QACrE,2DAAyD;QACzD,IAAI,CAAC,OAAO,CAAC,gBAAgB,EAAE,CAAC,CAAC,EAAE,IAAY,EAAE,EAAE,CAAC,MAAM,CAAC,YAAY,CAAC,QAAQ,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,CAAC;KACnG,CAAC;AAAA,CACL;AAED,yEAAyE;AACzE,wEAAwE;AACxE,0CAA0C;AAC1C,MAAM,WAAW,GAAG,GAAG,CAAC;AACxB,MAAM,KAAK,GAAG,IAAI,GAAG,EAAkB,CAAC;AAExC;;GAEG;AACH,MAAM,UAAU,cAAc,CAAC,QAAgB,EAAU;IACrD,IAAI,CAAC,QAAQ,EAAE,CAAC;QACZ,OAAO,EAAE,CAAC;IACd,CAAC;IAED,MAAM,MAAM,GAAG,KAAK,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;IACnC,IAAI,MAAM,KAAK,SAAS,EAAE,CAAC;QACvB,qDAAqD;QACrD,KAAK,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;QACvB,KAAK,CAAC,GAAG,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC;QAC5B,OAAO,MAAM,CAAC;IAClB,CAAC;IAED,MAAM,gBAAgB,GAAG,cAAc,CAAC,QAAQ,CAAC,CAAC;IAClD,MAAM,IAAI,GAAG,gBAAgB,CAAC,OAAO,CAAC,aAAa,CAAC,gBAAgB,CAAC,QAAQ,CAAC,CAAC,CAAC;IAChF,KAAK,CAAC,GAAG,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAC;IAC1B,IAAI,KAAK,CAAC,IAAI,GAAG,WAAW,EAAE,CAAC;QAC3B,MAAM,MAAM,GAAG,KAAK,CAAC,IAAI,EAAE,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC;QACzC,IAAI,MAAM,KAAK,SAAS,EAAE,CAAC;YACvB,KAAK,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;QACzB,CAAC;IACL,CAAC;IACD,OAAO,IAAI,CAAC;AAAA,CACf;AAED,SAAS,aAAa,CAAC,QAAgB,EAAU;IAC7C,MAAM,KAAK,GAAG,QAAQ,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IACnC,MAAM,SAAS,GAAa,EAAE,CAAC;IAC/B,IAAI,eAAe,GAAG,KAAK,CAAC;IAC5B,IAAI,aAAa,GAAG,KAAK,CAAC;IAE1B,MAAM,SAAS,GAAG,GAAG,EAAE,CAAC;QACpB,IAAI,eAAe,EAAE,CAAC;YAClB,SAAS,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;YACxB,eAAe,GAAG,KAAK,CAAC;QAC5B,CAAC;QACD,IAAI,aAAa,EAAE,CAAC;YAChB,SAAS,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;YACxB,aAAa,GAAG,KAAK,CAAC;QAC1B,CAAC;IAAA,CACJ,CAAC;IAEF,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACvB,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,EAAE,CAAC;QAE5B,IAAI,CAAC,OAAO,EAAE,CAAC;YACX,SAAS,EAAE,CAAC;YACZ,SAAS;QACb,CAAC;QAED,qCAAqC;QACrC,IAAI,wBAAwB,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC;YACzC,SAAS,EAAE,CAAC;YACZ,SAAS,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;YACxB,SAAS;QACb,CAAC;QAED,2BAA2B;QAC3B,MAAM,YAAY,GAAG,OAAO,CAAC,KAAK,CAAC,mBAAmB,CAAC,CAAC;QACxD,IAAI,YAAY,EAAE,CAAC;YACf,SAAS,EAAE,CAAC;YACZ,MAAM,KAAK,GAAG,YAAY,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC;YACrC,MAAM,OAAO,GAAG,qBAAqB,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,CAAC;YACvD,SAAS,CAAC,IAAI,CAAC,KAAK,KAAK,IAAI,OAAO,MAAM,KAAK,GAAG,CAAC,CAAC;YACpD,SAAS;QACb,CAAC;QAED,mCAAmC;QACnC,MAAM,OAAO,GAAG,OAAO,CAAC,KAAK,CAAC,eAAe,CAAC,CAAC;QAC/C,IAAI,OAAO,EAAE,CAAC;YACV,IAAI,aAAa,EAAE,CAAC;gBAChB,SAAS,EAAE,CAAC;YAChB,CAAC;YACD,IAAI,CAAC,eAAe,EAAE,CAAC;gBACnB,SAAS,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;gBACvB,eAAe,GAAG,IAAI,CAAC;YAC3B,CAAC;YACD,SAAS,CAAC,IAAI,CAAC,OAAO,qBAAqB,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC;YAChE,SAAS;QACb,CAAC;QAED,wBAAwB;QACxB,MAAM,OAAO,GAAG,OAAO,CAAC,KAAK,CAAC,gBAAgB,CAAC,CAAC;QAChD,IAAI,OAAO,EAAE,CAAC;YACV,IAAI,eAAe,EAAE,CAAC;gBAClB,SAAS,EAAE,CAAC;YAChB,CAAC;YACD,IAAI,CAAC,aAAa,EAAE,CAAC;gBACjB,SAAS,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;gBACvB,aAAa,GAAG,IAAI,CAAC;YACzB,CAAC;YACD,SAAS,CAAC,IAAI,CAAC,OAAO,qBAAqB,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC;YAChE,SAAS;QACb,CAAC;QAED,oBAAoB;QACpB,SAAS,EAAE,CAAC;QACZ,SAAS,CAAC,IAAI,CAAC,MAAM,qBAAqB,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;IAC/D,CAAC;IAED,SAAS,EAAE,CAAC;IAEZ,OAAO,SAAS,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;AAAA,CAC7B"}
@@ -0,0 +1,12 @@
1
+ import { type IMeasure } from "@gooddata/sdk-model";
2
+ /**
3
+ * Returns the LDM identifier the measure ultimately resolves to.
4
+ *
5
+ * - Simple measures: the identifier of the underlying catalog metric
6
+ * - Derived measures (PoP, previous period): follows the chain to the master
7
+ * - Arithmetic measures (and anything without an identifier ref): undefined
8
+ *
9
+ * @internal
10
+ */
11
+ export declare function resolveMeasureLdmIdentifier(measure: IMeasure, allMeasures: IMeasure[]): string | undefined;
12
+ //# sourceMappingURL=measureLdmIdentifier.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"measureLdmIdentifier.d.ts","sourceRoot":"","sources":["../../src/customTooltip/measureLdmIdentifier.ts"],"names":[],"mappings":"AAEA,OAAO,EACH,KAAK,QAAQ,EAMhB,MAAM,qBAAqB,CAAC;AAE7B;;;;;;;;GAQG;AACH,wBAAgB,2BAA2B,CAAC,OAAO,EAAE,QAAQ,EAAE,WAAW,EAAE,QAAQ,EAAE,GAAG,MAAM,GAAG,SAAS,CAa1G"}
@@ -0,0 +1,24 @@
1
+ // (C) 2026 GoodData Corporation
2
+ import { isIdentifierRef, isSimpleMeasure, measureItem, measureLocalId, measureMasterIdentifier, } from "@gooddata/sdk-model";
3
+ /**
4
+ * Returns the LDM identifier the measure ultimately resolves to.
5
+ *
6
+ * - Simple measures: the identifier of the underlying catalog metric
7
+ * - Derived measures (PoP, previous period): follows the chain to the master
8
+ * - Arithmetic measures (and anything without an identifier ref): undefined
9
+ *
10
+ * @internal
11
+ */
12
+ export function resolveMeasureLdmIdentifier(measure, allMeasures) {
13
+ if (isSimpleMeasure(measure)) {
14
+ const ref = measureItem(measure);
15
+ return ref && isIdentifierRef(ref) ? ref.identifier : undefined;
16
+ }
17
+ const masterLocalId = measureMasterIdentifier(measure);
18
+ if (!masterLocalId) {
19
+ return undefined;
20
+ }
21
+ const masterMeasure = allMeasures.find((m) => measureLocalId(m) === masterLocalId);
22
+ return masterMeasure ? resolveMeasureLdmIdentifier(masterMeasure, allMeasures) : undefined;
23
+ }
24
+ //# sourceMappingURL=measureLdmIdentifier.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"measureLdmIdentifier.js","sourceRoot":"","sources":["../../src/customTooltip/measureLdmIdentifier.ts"],"names":[],"mappings":"AAAA,gCAAgC;AAEhC,OAAO,EAEH,eAAe,EACf,eAAe,EACf,WAAW,EACX,cAAc,EACd,uBAAuB,GAC1B,MAAM,qBAAqB,CAAC;AAE7B;;;;;;;;GAQG;AACH,MAAM,UAAU,2BAA2B,CAAC,OAAiB,EAAE,WAAuB,EAAsB;IACxG,IAAI,eAAe,CAAC,OAAO,CAAC,EAAE,CAAC;QAC3B,MAAM,GAAG,GAAG,WAAW,CAAC,OAAO,CAAC,CAAC;QACjC,OAAO,GAAG,IAAI,eAAe,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC,CAAC,SAAS,CAAC;IACpE,CAAC;IAED,MAAM,aAAa,GAAG,uBAAuB,CAAC,OAAO,CAAC,CAAC;IACvD,IAAI,CAAC,aAAa,EAAE,CAAC;QACjB,OAAO,SAAS,CAAC;IACrB,CAAC;IAED,MAAM,aAAa,GAAG,WAAW,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,cAAc,CAAC,CAAC,CAAC,KAAK,aAAa,CAAC,CAAC;IACnF,OAAO,aAAa,CAAC,CAAC,CAAC,2BAA2B,CAAC,aAAa,EAAE,WAAW,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;AAAA,CAC9F"}
@@ -0,0 +1,20 @@
1
+ import { type IResolvedReferenceValues } from "./types.js";
2
+ /**
3
+ * Substitutes `{metric/id}` and `{label/id}` references in markdown content
4
+ * with resolved values from the lookup table.
5
+ *
6
+ * Substituted values come from data and may contain markdown metacharacters
7
+ * (e.g., `*`, `_`, `[`). They are backslash-escaped so the downstream
8
+ * markdown-to-HTML conversion renders them as literal text rather than as
9
+ * unintended formatting. `markdownToHtml` understands the backslash escapes.
10
+ *
11
+ * @param content - Markdown content with reference placeholders
12
+ * @param values - Lookup of `metric/id` and `label/id` keys to formatted values.
13
+ * Keys must use a lowercase prefix; LDM identifiers are case-sensitive.
14
+ * @param fallbackText - Localized text shown when a reference is recognized
15
+ * but no value is available (unknown identifier, point with no value, etc.).
16
+ *
17
+ * @internal
18
+ */
19
+ export declare function resolveReferences(content: string, values: IResolvedReferenceValues, fallbackText: string): string;
20
+ //# sourceMappingURL=referenceResolver.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"referenceResolver.d.ts","sourceRoot":"","sources":["../../src/customTooltip/referenceResolver.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,KAAK,wBAAwB,EAAE,MAAM,YAAY,CAAC;AAa3D;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,iBAAiB,CAC7B,OAAO,EAAE,MAAM,EACf,MAAM,EAAE,wBAAwB,EAChC,YAAY,EAAE,MAAM,GACrB,MAAM,CAYR"}
@@ -0,0 +1,41 @@
1
+ // (C) 2026 GoodData Corporation
2
+ import { REFERENCE_REGEX_MATCH } from "@gooddata/sdk-ui-kit";
3
+ // Markdown metacharacters that, if present in a substituted value, would be
4
+ // reinterpreted as formatting by `markdownToHtml`. Backslash-escape them so the
5
+ // parser treats them as literal text. The set covers every char that can start
6
+ // or end a markdown construct supported by our parser: emphasis, link/image
7
+ // brackets, parens, headings, lists, and horizontal rules.
8
+ const MARKDOWN_METACHARS = /[\\*_`\[\]()!#~+\-]/g;
9
+ function escapeMarkdownMetachars(value) {
10
+ return value.replace(MARKDOWN_METACHARS, "\\$&");
11
+ }
12
+ /**
13
+ * Substitutes `{metric/id}` and `{label/id}` references in markdown content
14
+ * with resolved values from the lookup table.
15
+ *
16
+ * Substituted values come from data and may contain markdown metacharacters
17
+ * (e.g., `*`, `_`, `[`). They are backslash-escaped so the downstream
18
+ * markdown-to-HTML conversion renders them as literal text rather than as
19
+ * unintended formatting. `markdownToHtml` understands the backslash escapes.
20
+ *
21
+ * @param content - Markdown content with reference placeholders
22
+ * @param values - Lookup of `metric/id` and `label/id` keys to formatted values.
23
+ * Keys must use a lowercase prefix; LDM identifiers are case-sensitive.
24
+ * @param fallbackText - Localized text shown when a reference is recognized
25
+ * but no value is available (unknown identifier, point with no value, etc.).
26
+ *
27
+ * @internal
28
+ */
29
+ export function resolveReferences(content, values, fallbackText) {
30
+ if (!content) {
31
+ return "";
32
+ }
33
+ return content.replace(REFERENCE_REGEX_MATCH, (_fullMatch, _wrapped, _key, prefix, identifier) => {
34
+ // The regex matches the prefix case-insensitively; storage uses
35
+ // lowercase prefixes so users can write either `{metric/foo}` or
36
+ // `{Metric/foo}`. LDM identifiers stay as-is — they are case-sensitive.
37
+ const value = values[`${prefix.toLowerCase()}/${identifier}`];
38
+ return escapeMarkdownMetachars(value === undefined ? fallbackText : value);
39
+ });
40
+ }
41
+ //# sourceMappingURL=referenceResolver.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"referenceResolver.js","sourceRoot":"","sources":["../../src/customTooltip/referenceResolver.ts"],"names":[],"mappings":"AAAA,gCAAgC;AAEhC,OAAO,EAAE,qBAAqB,EAAE,MAAM,sBAAsB,CAAC;AAI7D,4EAA4E;AAC5E,gFAAgF;AAChF,+EAA+E;AAC/E,4EAA4E;AAC5E,2DAA2D;AAC3D,MAAM,kBAAkB,GAAG,sBAAsB,CAAC;AAElD,SAAS,uBAAuB,CAAC,KAAa,EAAU;IACpD,OAAO,KAAK,CAAC,OAAO,CAAC,kBAAkB,EAAE,MAAM,CAAC,CAAC;AAAA,CACpD;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,UAAU,iBAAiB,CAC7B,OAAe,EACf,MAAgC,EAChC,YAAoB,EACd;IACN,IAAI,CAAC,OAAO,EAAE,CAAC;QACX,OAAO,EAAE,CAAC;IACd,CAAC;IAED,OAAO,OAAO,CAAC,OAAO,CAAC,qBAAqB,EAAE,CAAC,UAAU,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,EAAE,UAAU,EAAE,EAAE,CAAC;QAC9F,gEAAgE;QAChE,iEAAiE;QACjE,0EAAwE;QACxE,MAAM,KAAK,GAAG,MAAM,CAAC,GAAG,MAAM,CAAC,WAAW,EAAE,IAAI,UAAU,EAAE,CAAC,CAAC;QAC9D,OAAO,uBAAuB,CAAC,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC;IAAA,CAC9E,CAAC,CAAC;AAAA,CACN"}
@@ -0,0 +1,61 @@
1
+ /**
2
+ * Placement of the custom tooltip section relative to the default tooltip content.
3
+ *
4
+ * @alpha
5
+ */
6
+ export type CustomTooltipPlacement = "above" | "below" | "replace";
7
+ /**
8
+ * Custom tooltip configuration.
9
+ *
10
+ * @remarks
11
+ * Allows users to define a custom section in the visualization tooltip using Markdown
12
+ * with metric/attribute references that resolve dynamically per hovered data point.
13
+ *
14
+ * @alpha
15
+ */
16
+ export interface ICustomTooltipConfig {
17
+ /**
18
+ * Whether the custom tooltip is enabled.
19
+ */
20
+ enabled?: boolean;
21
+ /**
22
+ * Markdown content for the custom tooltip section.
23
+ *
24
+ * @remarks
25
+ * Supports a subset of Markdown:
26
+ *
27
+ * - Headings: `#` through `####`
28
+ * - Bold (`**text**`), italic (`*text*`)
29
+ * - Unordered lists (`- item`) and ordered lists (`1. item`) — not nested
30
+ * - Images (`![alt](url)`) — `https:`, `http:`, and `data:image/...` URLs only
31
+ * - Links (`[text](url)`) — rendered as styled text, NOT clickable inside tooltips
32
+ * - Horizontal rules (`---`)
33
+ * - Backslash escapes (`\*`, `\_`, `\[`, `\!`, etc.) to render a metacharacter
34
+ * as literal text instead of formatting
35
+ *
36
+ * Not supported: tables, code blocks, blockquotes, nested lists, raw HTML.
37
+ *
38
+ * Also accepts metric/attribute references (\{metric/id\}, \{label/id\})
39
+ * that resolve dynamically per hovered data point. Resolved values are
40
+ * automatically backslash-escaped, so data containing markdown metacharacters
41
+ * renders as literal text — no manual escaping is required.
42
+ *
43
+ * @see https://www.gooddata.com/docs/cloud/create-visualizations/custom-tooltips/
44
+ */
45
+ content?: string;
46
+ /**
47
+ * Where to place the custom section relative to the default tooltip content.
48
+ *
49
+ * @defaultValue "above"
50
+ */
51
+ placement?: CustomTooltipPlacement;
52
+ }
53
+ /**
54
+ * Lookup of resolved reference values keyed by `metric/id` or `label/id`.
55
+ *
56
+ * @internal
57
+ */
58
+ export interface IResolvedReferenceValues {
59
+ [referenceKey: string]: string | undefined;
60
+ }
61
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/customTooltip/types.ts"],"names":[],"mappings":"AAEA;;;;GAIG;AACH,MAAM,MAAM,sBAAsB,GAAG,OAAO,GAAG,OAAO,GAAG,SAAS,CAAC;AAEnE;;;;;;;;GAQG;AACH,MAAM,WAAW,oBAAoB;IACjC;;OAEG;IACH,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB;;;;;;;;;;;;;;;;;;;;;;;OAuBG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB;;;;OAIG;IACH,SAAS,CAAC,EAAE,sBAAsB,CAAC;CACtC;AAED;;;;GAIG;AACH,MAAM,WAAW,wBAAwB;IACrC,CAAC,YAAY,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAAC;CAC9C"}
@@ -0,0 +1,3 @@
1
+ // (C) 2026 GoodData Corporation
2
+ export {};
3
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/customTooltip/types.ts"],"names":[],"mappings":"AAAA,gCAAgC"}
package/esm/index.d.ts CHANGED
@@ -28,4 +28,8 @@ export { getHeadlineResponsiveClassName } from "./utils/headlineResponsiveClassN
28
28
  export { getLegendDetails, type ILegendDetails, type ILegendDetailOptions, } from "./legend/PopUpLegend/helpers.js";
29
29
  export { PATTERN_FILLS, getPatternFillByIndex, getPatternFillByName, getPatternFill, type IPatternFill, type PatternFillName, type IChartFillConfig, } from "./coloring/patternFills.js";
30
30
  export { PatternFill, type IPatternFillProps } from "./coloring/PatternFill.js";
31
+ export { type ICustomTooltipConfig, type CustomTooltipPlacement, type IResolvedReferenceValues, } from "./customTooltip/types.js";
32
+ export { markdownToHtml } from "./customTooltip/markdownToHtml.js";
33
+ export { resolveReferences } from "./customTooltip/referenceResolver.js";
34
+ export { resolveMeasureLdmIdentifier } from "./customTooltip/measureLdmIdentifier.js";
31
35
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAIA;;;;;;;;GAQG;AAEH,OAAO,EAAE,sBAAsB,EAAE,MAAM,yBAAyB,CAAC;AACjE,OAAO,EACH,aAAa,EACb,KAAK,cAAc,EACnB,KAAK,iCAAiC,EACtC,2BAA2B,EAC3B,kBAAkB,GACrB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EACH,cAAc,EACd,mBAAmB,EACnB,wBAAwB,EACxB,yBAAyB,EACzB,eAAe,EACf,sBAAsB,EACtB,YAAY,EACZ,mBAAmB,EACnB,eAAe,EACf,mBAAmB,EACnB,iBAAiB,EACjB,oBAAoB,EACpB,UAAU,EACV,cAAc,EACd,eAAe,EACf,kBAAkB,EAClB,gBAAgB,GACnB,MAAM,qBAAqB,CAAC;AAE7B,YAAY,EACR,aAAa,EACb,aAAa,EACb,qBAAqB,EACrB,cAAc,GACjB,MAAM,qBAAqB,CAAC;AAE7B,OAAO,EAAE,MAAM,EAAE,KAAK,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAE/D,OAAO,EAAE,YAAY,EAAE,KAAK,kBAAkB,EAAE,MAAM,0BAA0B,CAAC;AAEjF,OAAO,EAAE,WAAW,EAAE,KAAK,iBAAiB,EAAE,MAAM,qCAAqC,CAAC;AAE1F,OAAO,EAAE,WAAW,EAAE,KAAK,iBAAiB,EAAE,MAAM,yBAAyB,CAAC;AAE9E,OAAO,EAAE,aAAa,EAAE,KAAK,mBAAmB,EAAE,MAAM,2BAA2B,CAAC;AAEpF,OAAO,EAAE,WAAW,EAAE,KAAK,iBAAiB,EAAE,MAAM,yBAAyB,CAAC;AAE9E,OAAO,EAAE,MAAM,EAAE,KAAK,YAAY,EAAE,KAAK,sBAAsB,EAAE,MAAM,oBAAoB,CAAC;AAE5F,OAAO,EAAE,kBAAkB,EAAE,KAAK,wBAAwB,EAAE,MAAM,qCAAqC,CAAC;AAExG,OAAO,EAAE,iBAAiB,EAAE,eAAe,EAAE,sBAAsB,EAAE,MAAM,qBAAqB,CAAC;AAEjG,OAAO,EACH,KAAK,YAAY,EACjB,KAAK,gBAAgB,EACrB,KAAK,sBAAsB,EAC3B,KAAK,mBAAmB,EACxB,KAAK,kBAAkB,EACvB,KAAK,cAAc,EACnB,KAAK,0BAA0B,EAC/B,KAAK,MAAM,EACX,KAAK,qBAAqB,EAC1B,KAAK,yBAAyB,EAC9B,KAAK,gBAAgB,EACrB,KAAK,WAAW,EAChB,KAAK,YAAY,EACjB,KAAK,cAAc,EACnB,KAAK,kBAAkB,EACvB,KAAK,iBAAiB,EACtB,KAAK,oBAAoB,EACzB,KAAK,wBAAwB,EAC7B,qBAAqB,EACrB,cAAc,EACd,wBAAwB,EACxB,aAAa,EACb,kBAAkB,EAClB,qBAAqB,EACrB,yBAAyB,EACzB,qBAAqB,EACrB,gBAAgB,EAChB,YAAY,GACf,MAAM,mBAAmB,CAAC;AAE3B,OAAO,EAAE,mBAAmB,EAAE,MAAM,gCAAgC,CAAC;AACrE,OAAO,EAAE,sBAAsB,EAAE,MAAM,mCAAmC,CAAC;AAE3E,OAAO,EAAE,sBAAsB,EAAE,+BAA+B,EAAE,MAAM,kCAAkC,CAAC;AAC3G,OAAO,EAAE,8BAA8B,EAAE,MAAM,wCAAwC,CAAC;AAExF,OAAO,EACH,gBAAgB,EAChB,KAAK,cAAc,EACnB,KAAK,oBAAoB,GAC5B,MAAM,iCAAiC,CAAC;AAEzC,OAAO,EACH,aAAa,EACb,qBAAqB,EACrB,oBAAoB,EACpB,cAAc,EACd,KAAK,YAAY,EACjB,KAAK,eAAe,EACpB,KAAK,gBAAgB,GACxB,MAAM,4BAA4B,CAAC;AACpC,OAAO,EAAE,WAAW,EAAE,KAAK,iBAAiB,EAAE,MAAM,2BAA2B,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
package/esm/index.js CHANGED
@@ -29,4 +29,7 @@ export { getHeadlineResponsiveClassName } from "./utils/headlineResponsiveClassN
29
29
  export { getLegendDetails, } from "./legend/PopUpLegend/helpers.js";
30
30
  export { PATTERN_FILLS, getPatternFillByIndex, getPatternFillByName, getPatternFill, } from "./coloring/patternFills.js";
31
31
  export { PatternFill } from "./coloring/PatternFill.js";
32
+ export { markdownToHtml } from "./customTooltip/markdownToHtml.js";
33
+ export { resolveReferences } from "./customTooltip/referenceResolver.js";
34
+ export { resolveMeasureLdmIdentifier } from "./customTooltip/measureLdmIdentifier.js";
32
35
  //# sourceMappingURL=index.js.map
package/esm/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,qCAAqC;AAErC,oDAAoD;AAEpD;;;;;;;;GAQG;AAEH,OAAO,EAAE,sBAAsB,EAAE,MAAM,yBAAyB,CAAC;AACjE,OAAO,EACH,aAAa,EAGb,2BAA2B,EAC3B,kBAAkB,GACrB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EACH,cAAc,EACd,mBAAmB,EACnB,wBAAwB,EACxB,yBAAyB,EACzB,eAAe,EACf,sBAAsB,EACtB,YAAY,EACZ,mBAAmB,EACnB,eAAe,EACf,mBAAmB,EACnB,iBAAiB,EACjB,oBAAoB,EACpB,UAAU,EACV,cAAc,EACd,eAAe,EACf,kBAAkB,EAClB,gBAAgB,GACnB,MAAM,qBAAqB,CAAC;AAS7B,OAAO,EAAE,MAAM,EAAqB,MAAM,oBAAoB,CAAC;AAE/D,OAAO,EAAE,YAAY,EAA2B,MAAM,0BAA0B,CAAC;AAEjF,OAAO,EAAE,WAAW,EAA0B,MAAM,qCAAqC,CAAC;AAE1F,OAAO,EAAE,WAAW,EAA0B,MAAM,yBAAyB,CAAC;AAE9E,OAAO,EAAE,aAAa,EAA4B,MAAM,2BAA2B,CAAC;AAEpF,OAAO,EAAE,WAAW,EAA0B,MAAM,yBAAyB,CAAC;AAE9E,OAAO,EAAE,MAAM,EAAkD,MAAM,oBAAoB,CAAC;AAE5F,OAAO,EAAE,kBAAkB,EAAiC,MAAM,qCAAqC,CAAC;AAExG,OAAO,EAAE,iBAAiB,EAAE,eAAe,EAAE,sBAAsB,EAAE,MAAM,qBAAqB,CAAC;AAEjG,OAAO,EAmBH,qBAAqB,EACrB,cAAc,EACd,wBAAwB,EACxB,aAAa,EACb,kBAAkB,EAClB,qBAAqB,EACrB,yBAAyB,EACzB,qBAAqB,EACrB,gBAAgB,EAChB,YAAY,GACf,MAAM,mBAAmB,CAAC;AAE3B,OAAO,EAAE,mBAAmB,EAAE,MAAM,gCAAgC,CAAC;AACrE,OAAO,EAAE,sBAAsB,EAAE,MAAM,mCAAmC,CAAC;AAE3E,OAAO,EAAE,sBAAsB,EAAE,+BAA+B,EAAE,MAAM,kCAAkC,CAAC;AAC3G,OAAO,EAAE,8BAA8B,EAAE,MAAM,wCAAwC,CAAC;AAExF,OAAO,EACH,gBAAgB,GAGnB,MAAM,iCAAiC,CAAC;AAEzC,OAAO,EACH,aAAa,EACb,qBAAqB,EACrB,oBAAoB,EACpB,cAAc,GAIjB,MAAM,4BAA4B,CAAC;AACpC,OAAO,EAAE,WAAW,EAA0B,MAAM,2BAA2B,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,qCAAqC;AAErC,oDAAoD;AAEpD;;;;;;;;GAQG;AAEH,OAAO,EAAE,sBAAsB,EAAE,MAAM,yBAAyB,CAAC;AACjE,OAAO,EACH,aAAa,EAGb,2BAA2B,EAC3B,kBAAkB,GACrB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EACH,cAAc,EACd,mBAAmB,EACnB,wBAAwB,EACxB,yBAAyB,EACzB,eAAe,EACf,sBAAsB,EACtB,YAAY,EACZ,mBAAmB,EACnB,eAAe,EACf,mBAAmB,EACnB,iBAAiB,EACjB,oBAAoB,EACpB,UAAU,EACV,cAAc,EACd,eAAe,EACf,kBAAkB,EAClB,gBAAgB,GACnB,MAAM,qBAAqB,CAAC;AAS7B,OAAO,EAAE,MAAM,EAAqB,MAAM,oBAAoB,CAAC;AAE/D,OAAO,EAAE,YAAY,EAA2B,MAAM,0BAA0B,CAAC;AAEjF,OAAO,EAAE,WAAW,EAA0B,MAAM,qCAAqC,CAAC;AAE1F,OAAO,EAAE,WAAW,EAA0B,MAAM,yBAAyB,CAAC;AAE9E,OAAO,EAAE,aAAa,EAA4B,MAAM,2BAA2B,CAAC;AAEpF,OAAO,EAAE,WAAW,EAA0B,MAAM,yBAAyB,CAAC;AAE9E,OAAO,EAAE,MAAM,EAAkD,MAAM,oBAAoB,CAAC;AAE5F,OAAO,EAAE,kBAAkB,EAAiC,MAAM,qCAAqC,CAAC;AAExG,OAAO,EAAE,iBAAiB,EAAE,eAAe,EAAE,sBAAsB,EAAE,MAAM,qBAAqB,CAAC;AAEjG,OAAO,EAmBH,qBAAqB,EACrB,cAAc,EACd,wBAAwB,EACxB,aAAa,EACb,kBAAkB,EAClB,qBAAqB,EACrB,yBAAyB,EACzB,qBAAqB,EACrB,gBAAgB,EAChB,YAAY,GACf,MAAM,mBAAmB,CAAC;AAE3B,OAAO,EAAE,mBAAmB,EAAE,MAAM,gCAAgC,CAAC;AACrE,OAAO,EAAE,sBAAsB,EAAE,MAAM,mCAAmC,CAAC;AAE3E,OAAO,EAAE,sBAAsB,EAAE,+BAA+B,EAAE,MAAM,kCAAkC,CAAC;AAC3G,OAAO,EAAE,8BAA8B,EAAE,MAAM,wCAAwC,CAAC;AAExF,OAAO,EACH,gBAAgB,GAGnB,MAAM,iCAAiC,CAAC;AAEzC,OAAO,EACH,aAAa,EACb,qBAAqB,EACrB,oBAAoB,EACpB,cAAc,GAIjB,MAAM,4BAA4B,CAAC;AACpC,OAAO,EAAE,WAAW,EAA0B,MAAM,2BAA2B,CAAC;AAOhF,OAAO,EAAE,cAAc,EAAE,MAAM,mCAAmC,CAAC;AACnE,OAAO,EAAE,iBAAiB,EAAE,MAAM,sCAAsC,CAAC;AACzE,OAAO,EAAE,2BAA2B,EAAE,MAAM,yCAAyC,CAAC"}
@@ -18,6 +18,7 @@ import { IColorPaletteItem } from '@gooddata/sdk-model';
18
18
  import { IDataView } from '@gooddata/sdk-backend-spi';
19
19
  import { IHeaderPredicate } from '@gooddata/sdk-ui';
20
20
  import { IMappingHeader } from '@gooddata/sdk-ui';
21
+ import { IMeasure } from '@gooddata/sdk-model';
21
22
  import { IRgbColorValue } from '@gooddata/sdk-model';
22
23
  import { ITheme } from '@gooddata/sdk-model';
23
24
  import { JSX } from 'react/jsx-runtime';
@@ -83,6 +84,13 @@ export declare const ColorUtils: {
83
84
  getColorMappingPredicate: typeof getColorMappingPredicate;
84
85
  };
85
86
 
87
+ /**
88
+ * Placement of the custom tooltip section relative to the default tooltip content.
89
+ *
90
+ * @alpha
91
+ */
92
+ export declare type CustomTooltipPlacement = "above" | "below" | "replace";
93
+
86
94
  /**
87
95
  * @internal
88
96
  */
@@ -334,6 +342,53 @@ export declare interface ICreateColorAssignmentReturnValue {
334
342
  outputColorAssignment?: IColorAssignment[];
335
343
  }
336
344
 
345
+ /**
346
+ * Custom tooltip configuration.
347
+ *
348
+ * @remarks
349
+ * Allows users to define a custom section in the visualization tooltip using Markdown
350
+ * with metric/attribute references that resolve dynamically per hovered data point.
351
+ *
352
+ * @alpha
353
+ */
354
+ export declare interface ICustomTooltipConfig {
355
+ /**
356
+ * Whether the custom tooltip is enabled.
357
+ */
358
+ enabled?: boolean;
359
+ /**
360
+ * Markdown content for the custom tooltip section.
361
+ *
362
+ * @remarks
363
+ * Supports a subset of Markdown:
364
+ *
365
+ * - Headings: `#` through `####`
366
+ * - Bold (`**text**`), italic (`*text*`)
367
+ * - Unordered lists (`- item`) and ordered lists (`1. item`) — not nested
368
+ * - Images (`![alt](url)`) — `https:`, `http:`, and `data:image/...` URLs only
369
+ * - Links (`[text](url)`) — rendered as styled text, NOT clickable inside tooltips
370
+ * - Horizontal rules (`---`)
371
+ * - Backslash escapes (`\*`, `\_`, `\[`, `\!`, etc.) to render a metacharacter
372
+ * as literal text instead of formatting
373
+ *
374
+ * Not supported: tables, code blocks, blockquotes, nested lists, raw HTML.
375
+ *
376
+ * Also accepts metric/attribute references (\{metric/id\}, \{label/id\})
377
+ * that resolve dynamically per hovered data point. Resolved values are
378
+ * automatically backslash-escaped, so data containing markdown metacharacters
379
+ * renders as literal text — no manual escaping is required.
380
+ *
381
+ * @see https://www.gooddata.com/docs/cloud/create-visualizations/custom-tooltips/
382
+ */
383
+ content?: string;
384
+ /**
385
+ * Where to place the custom section relative to the default tooltip content.
386
+ *
387
+ * @defaultValue "above"
388
+ */
389
+ placement?: CustomTooltipPlacement;
390
+ }
391
+
337
392
  /**
338
393
  * @internal
339
394
  */
@@ -556,6 +611,15 @@ export declare interface IRange {
556
611
  to: number;
557
612
  }
558
613
 
614
+ /**
615
+ * Lookup of resolved reference values keyed by `metric/id` or `label/id`.
616
+ *
617
+ * @internal
618
+ */
619
+ export declare interface IResolvedReferenceValues {
620
+ [referenceKey: string]: string | undefined;
621
+ }
622
+
559
623
  /**
560
624
  * @internal
561
625
  */
@@ -685,6 +749,11 @@ export declare const LegendPosition: {
685
749
  [name: string]: PositionType;
686
750
  };
687
751
 
752
+ /**
753
+ * @internal
754
+ */
755
+ export declare function markdownToHtml(markdown: string): string;
756
+
688
757
  /**
689
758
  * @internal
690
759
  */
@@ -747,6 +816,36 @@ export declare function PopUpLegend({ name, maxRows, enableBorderRadius, series,
747
816
  */
748
817
  export declare type PositionType = "left" | "right" | "top" | "bottom" | "auto";
749
818
 
819
+ /**
820
+ * Returns the LDM identifier the measure ultimately resolves to.
821
+ *
822
+ * - Simple measures: the identifier of the underlying catalog metric
823
+ * - Derived measures (PoP, previous period): follows the chain to the master
824
+ * - Arithmetic measures (and anything without an identifier ref): undefined
825
+ *
826
+ * @internal
827
+ */
828
+ export declare function resolveMeasureLdmIdentifier(measure: IMeasure, allMeasures: IMeasure[]): string | undefined;
829
+
830
+ /**
831
+ * Substitutes `{metric/id}` and `{label/id}` references in markdown content
832
+ * with resolved values from the lookup table.
833
+ *
834
+ * Substituted values come from data and may contain markdown metacharacters
835
+ * (e.g., `*`, `_`, `[`). They are backslash-escaped so the downstream
836
+ * markdown-to-HTML conversion renders them as literal text rather than as
837
+ * unintended formatting. `markdownToHtml` understands the backslash escapes.
838
+ *
839
+ * @param content - Markdown content with reference placeholders
840
+ * @param values - Lookup of `metric/id` and `label/id` keys to formatted values.
841
+ * Keys must use a lowercase prefix; LDM identifiers are case-sensitive.
842
+ * @param fallbackText - Localized text shown when a reference is recognized
843
+ * but no value is available (unknown identifier, point with no value, etc.).
844
+ *
845
+ * @internal
846
+ */
847
+ export declare function resolveReferences(content: string, values: IResolvedReferenceValues, fallbackText: string): string;
848
+
750
849
  /**
751
850
  * @internal
752
851
  * Check if Kpi's and Headlines should display pagination according to widget height.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gooddata/sdk-ui-vis-commons",
3
- "version": "11.33.0-alpha.4",
3
+ "version": "11.33.0-alpha.7",
4
4
  "description": "GoodData.UI SDK - common functionality for different types of visualizations",
5
5
  "license": "MIT",
6
6
  "author": "GoodData Corporation",
@@ -36,11 +36,11 @@
36
36
  "react-intl": "7.1.11",
37
37
  "react-measure": "^2.5.2",
38
38
  "tslib": "2.8.1",
39
- "@gooddata/sdk-backend-spi": "11.33.0-alpha.4",
40
- "@gooddata/sdk-model": "11.33.0-alpha.4",
41
- "@gooddata/sdk-ui": "11.33.0-alpha.4",
42
- "@gooddata/sdk-ui-kit": "11.33.0-alpha.4",
43
- "@gooddata/sdk-ui-theme-provider": "11.33.0-alpha.4"
39
+ "@gooddata/sdk-backend-spi": "11.33.0-alpha.7",
40
+ "@gooddata/sdk-model": "11.33.0-alpha.7",
41
+ "@gooddata/sdk-ui": "11.33.0-alpha.7",
42
+ "@gooddata/sdk-ui-kit": "11.33.0-alpha.7",
43
+ "@gooddata/sdk-ui-theme-provider": "11.33.0-alpha.7"
44
44
  },
45
45
  "devDependencies": {
46
46
  "@microsoft/api-documenter": "^7.17.0",
@@ -81,11 +81,11 @@
81
81
  "typescript": "5.9.3",
82
82
  "vitest": "4.1.0",
83
83
  "vitest-dom": "0.1.1",
84
- "@gooddata/eslint-config": "11.33.0-alpha.4",
85
- "@gooddata/oxlint-config": "11.33.0-alpha.4",
86
- "@gooddata/reference-workspace": "11.33.0-alpha.4",
87
- "@gooddata/sdk-backend-mockingbird": "11.33.0-alpha.4",
88
- "@gooddata/stylelint-config": "11.33.0-alpha.4"
84
+ "@gooddata/eslint-config": "11.33.0-alpha.7",
85
+ "@gooddata/oxlint-config": "11.33.0-alpha.7",
86
+ "@gooddata/sdk-backend-mockingbird": "11.33.0-alpha.7",
87
+ "@gooddata/reference-workspace": "11.33.0-alpha.7",
88
+ "@gooddata/stylelint-config": "11.33.0-alpha.7"
89
89
  },
90
90
  "peerDependencies": {
91
91
  "react": "^18.0.0 || ^19.0.0",
@@ -0,0 +1,65 @@
1
+ // (C) 2026 GoodData Corporation
2
+
3
+ // Styles for the custom tooltip section rendered inside .gd-viz-tooltip
4
+ // containers across chart families (Highcharts, geo, etc.).
5
+
6
+ .gd-viz-tooltip-custom-section {
7
+ font-size: 13px;
8
+ line-height: 1.4;
9
+ text-align: left;
10
+ white-space: normal;
11
+ word-wrap: break-word;
12
+ min-width: 200px;
13
+
14
+ h1,
15
+ h2,
16
+ h3,
17
+ h4 {
18
+ margin: 0 0 2px;
19
+ font-weight: 700;
20
+ color: var(--gd-chart-tooltip-valueColor);
21
+ font-size: 14px;
22
+ line-height: 1.3;
23
+ }
24
+
25
+ p {
26
+ margin: 0 0 1px;
27
+ }
28
+
29
+ strong {
30
+ font-weight: 700;
31
+ color: var(--gd-chart-tooltip-valueColor);
32
+ }
33
+
34
+ ul,
35
+ ol {
36
+ margin: 2px 0;
37
+ padding-left: 18px;
38
+ }
39
+
40
+ li {
41
+ margin-bottom: 1px;
42
+ }
43
+
44
+ hr {
45
+ border: 0;
46
+ border-top: 1px solid var(--gd-palette-complementary-3);
47
+ margin: 4px 0;
48
+ }
49
+
50
+ img {
51
+ max-width: 100%;
52
+ display: block;
53
+ margin: 4px 0;
54
+ }
55
+
56
+ .gd-viz-tooltip-custom-link {
57
+ text-decoration: underline;
58
+ color: var(--gd-chart-tooltip-labelColor-from-theme);
59
+ }
60
+ }
61
+
62
+ .gd-viz-tooltip-custom-separator {
63
+ border-top: 1px solid var(--gd-palette-complementary-3);
64
+ margin: 8px 0;
65
+ }