@flux-ui/statistics 3.0.0-next.72 → 3.0.0-next.73
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.js +32 -5
- package/dist/index.js.map +1 -1
- package/dist/util/html.d.ts +9 -0
- package/dist/util/index.d.ts +1 -0
- package/package.json +4 -4
- package/src/util/html.ts +25 -0
- package/src/util/icons.ts +3 -1
- package/src/util/index.ts +1 -0
- package/src/util/tooltips/render.ts +7 -5
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Escapes a value for safe interpolation into HTML text content.
|
|
3
|
+
*/
|
|
4
|
+
export declare function escapeHtml(value: unknown): string;
|
|
5
|
+
/**
|
|
6
|
+
* Escapes a value for safe interpolation into a double-quoted HTML attribute
|
|
7
|
+
* or inline style value. Prevents attribute breakout from untrusted input.
|
|
8
|
+
*/
|
|
9
|
+
export declare function escapeAttr(value: unknown): string;
|
package/dist/util/index.d.ts
CHANGED
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@flux-ui/statistics",
|
|
3
3
|
"description": "Statistics components for the Flux UI library.",
|
|
4
|
-
"version": "3.0.0-next.
|
|
4
|
+
"version": "3.0.0-next.73",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
7
7
|
"funding": "https://github.com/sponsors/basmilius",
|
|
@@ -51,9 +51,9 @@
|
|
|
51
51
|
"dependencies": {
|
|
52
52
|
"@basmilius/common": "^3.37.0",
|
|
53
53
|
"@basmilius/utils": "^3.37.0",
|
|
54
|
-
"@flux-ui/components": "3.0.0-next.
|
|
55
|
-
"@flux-ui/internals": "3.0.0-next.
|
|
56
|
-
"@flux-ui/types": "3.0.0-next.
|
|
54
|
+
"@flux-ui/components": "3.0.0-next.73",
|
|
55
|
+
"@flux-ui/internals": "3.0.0-next.73",
|
|
56
|
+
"@flux-ui/types": "3.0.0-next.73",
|
|
57
57
|
"clsx": "^2.1.1"
|
|
58
58
|
},
|
|
59
59
|
"peerDependencies": {
|
package/src/util/html.ts
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
const HTML_ESCAPES: Record<string, string> = {
|
|
2
|
+
'&': '&',
|
|
3
|
+
'<': '<',
|
|
4
|
+
'>': '>',
|
|
5
|
+
'"': '"',
|
|
6
|
+
'\'': '''
|
|
7
|
+
};
|
|
8
|
+
|
|
9
|
+
const HTML_PATTERN = /[&<>"']/g;
|
|
10
|
+
const ATTR_PATTERN = /[&<>"]/g;
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Escapes a value for safe interpolation into HTML text content.
|
|
14
|
+
*/
|
|
15
|
+
export function escapeHtml(value: unknown): string {
|
|
16
|
+
return String(value ?? '').replace(HTML_PATTERN, char => HTML_ESCAPES[char]);
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Escapes a value for safe interpolation into a double-quoted HTML attribute
|
|
21
|
+
* or inline style value. Prevents attribute breakout from untrusted input.
|
|
22
|
+
*/
|
|
23
|
+
export function escapeAttr(value: unknown): string {
|
|
24
|
+
return String(value ?? '').replace(ATTR_PATTERN, char => HTML_ESCAPES[char]);
|
|
25
|
+
}
|
package/src/util/icons.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { iconRegistry } from '@flux-ui/components';
|
|
2
2
|
import type { FluxIconName } from '@flux-ui/types';
|
|
3
|
+
import { escapeAttr } from './html';
|
|
3
4
|
|
|
4
5
|
export function renderIconSvg(name: FluxIconName | undefined, color: string, size: number = 14): string {
|
|
5
6
|
if (!name) {
|
|
@@ -14,7 +15,8 @@ export function renderIconSvg(name: FluxIconName | undefined, color: string, siz
|
|
|
14
15
|
|
|
15
16
|
const [width, height, , , pathData] = icon;
|
|
16
17
|
const paths = Array.isArray(pathData) ? pathData : [pathData];
|
|
17
|
-
const
|
|
18
|
+
const safeColor = escapeAttr(color);
|
|
19
|
+
const pathElements = paths.map(d => `<path d="${escapeAttr(d)}" fill="${safeColor}"/>`).join('');
|
|
18
20
|
|
|
19
21
|
return `<svg viewBox="0 0 ${width} ${height}" width="${size}" height="${size}" focusable="false" aria-hidden="true">${pathElements}</svg>`;
|
|
20
22
|
}
|
package/src/util/index.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { formatNumber } from '@basmilius/utils';
|
|
2
|
+
import { escapeAttr, escapeHtml } from '../html';
|
|
2
3
|
import { renderIconSvg } from '../icons';
|
|
3
4
|
import type { ChartTooltipValueFormatter, SharedTooltipItem, TooltipParam, TooltipStyleClasses, Translator } from './types';
|
|
4
5
|
|
|
@@ -15,7 +16,7 @@ export function renderTooltip(
|
|
|
15
16
|
}
|
|
16
17
|
|
|
17
18
|
const titleHtml = title
|
|
18
|
-
? `<div class="${styles.statisticsChartTooltipTitle}">${title}</div>`
|
|
19
|
+
? `<div class="${styles.statisticsChartTooltipTitle}">${escapeHtml(title)}</div>`
|
|
19
20
|
: '';
|
|
20
21
|
|
|
21
22
|
const hasActive = activeIndex !== -1;
|
|
@@ -25,16 +26,17 @@ export function renderTooltip(
|
|
|
25
26
|
const activeClass = isActive ? ` ${styles.isActive}` : '';
|
|
26
27
|
const translatedName = item.name ? t(String(item.name)) : '';
|
|
27
28
|
|
|
29
|
+
const safeColor = escapeAttr(item.color);
|
|
28
30
|
const marker = item.icon
|
|
29
|
-
? `<div class="${styles.statisticsChartTooltipSeriesIcon}${activeClass}" style="color: ${
|
|
30
|
-
: `<div class="${styles.statisticsChartTooltipSeriesColor}${activeClass}" style="background: ${
|
|
31
|
+
? `<div class="${styles.statisticsChartTooltipSeriesIcon}${activeClass}" style="color: ${safeColor}">${renderIconSvg(item.icon, item.color, 14)}</div>`
|
|
32
|
+
: `<div class="${styles.statisticsChartTooltipSeriesColor}${activeClass}" style="background: ${safeColor}"></div>`;
|
|
31
33
|
|
|
32
34
|
const display = valueFormatter ? valueFormatter(item.value, item) : formatValue(item.value);
|
|
33
35
|
|
|
34
36
|
return `
|
|
35
37
|
${marker}
|
|
36
|
-
<div class="${styles.statisticsChartTooltipSeriesName}${activeClass}">${translatedName}</div>
|
|
37
|
-
<div class="${styles.statisticsChartTooltipSeriesValue}${activeClass}">${display}</div>
|
|
38
|
+
<div class="${styles.statisticsChartTooltipSeriesName}${activeClass}">${escapeHtml(translatedName)}</div>
|
|
39
|
+
<div class="${styles.statisticsChartTooltipSeriesValue}${activeClass}">${escapeHtml(display)}</div>
|
|
38
40
|
`;
|
|
39
41
|
}).join('');
|
|
40
42
|
|