@automattic/charts 0.59.0 → 1.0.1

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/CHANGELOG.md CHANGED
@@ -5,6 +5,22 @@ All notable changes to this project will be documented in this file.
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/)
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
+ ## [1.0.1] - 2026-03-30
9
+ ### Security
10
+ - Sanitize GeoChart HTML tooltip content with DOMPurify. [#47789]
11
+
12
+ ### Changed
13
+ - Bump minimum Node version to 20.11. [#47770]
14
+ - Support all CSS color formats (HSL, HSLA, RGB, RGBA, named colors) in theme colors. [#46349]
15
+ - Update package dependencies. [#47799]
16
+
17
+ ### Fixed
18
+ - ChartLayout: Display SVG as block to avoid unexpected resizing in certain browser environments. [#47802]
19
+
20
+ ## [1.0.0] - 2026-03-24
21
+ ### Changed
22
+ - Internal updates. [#43811]
23
+
8
24
  ## [0.59.0] - 2026-03-23
9
25
  ### Added
10
26
  - ChartLayout: Add component for shared chart and legend layout. [#47554]
@@ -760,6 +776,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
760
776
  - Fixed lints following ESLint rule changes for TS [#40584]
761
777
  - Fixing a bug in Chart storybook data. [#40640]
762
778
 
779
+ [1.0.1]: https://github.com/Automattic/charts/compare/v1.0.0...v1.0.1
780
+ [1.0.0]: https://github.com/Automattic/charts/compare/v0.59.0...v1.0.0
763
781
  [0.59.0]: https://github.com/Automattic/charts/compare/v0.58.0...v0.59.0
764
782
  [0.58.0]: https://github.com/Automattic/charts/compare/v0.57.0...v0.58.0
765
783
  [0.57.0]: https://github.com/Automattic/charts/compare/v0.56.7...v0.57.0
package/dist/index.cjs CHANGED
@@ -993,7 +993,7 @@ var parseRgbString = (rgbString) => {
993
993
  }
994
994
  return parsed.formatHex();
995
995
  };
996
- var normalizeColorToHex = (color, element, resolveCss) => {
996
+ var normalizeColorToHex = (color, element, resolveCss, _depth = 0) => {
997
997
  if (!color || typeof color !== "string") {
998
998
  return "";
999
999
  }
@@ -1010,22 +1010,23 @@ var normalizeColorToHex = (color, element, resolveCss) => {
1010
1010
  if (trimmed.startsWith("--") || trimmed.startsWith("var(")) {
1011
1011
  if (resolveCss) {
1012
1012
  const resolved = resolveCss(color, element);
1013
- if (resolved) {
1014
- return normalizeColorToHex(resolved, element, resolveCss);
1013
+ if (resolved && resolved !== color && _depth < 10) {
1014
+ return normalizeColorToHex(resolved, element, resolveCss, _depth + 1);
1015
1015
  }
1016
1016
  }
1017
1017
  return color;
1018
1018
  }
1019
- if (trimmed.startsWith("hsl(") || trimmed.startsWith("rgb(")) {
1020
- if (trimmed.startsWith("rgba(")) {
1021
- return color;
1022
- }
1023
- const parsed = _d3color.color.call(void 0, trimmed);
1024
- if (parsed) {
1025
- return parsed.formatHex();
1019
+ if (trimmed.startsWith("hsl(") || trimmed.startsWith("hsla(") || trimmed.startsWith("rgb(") || trimmed.startsWith("rgba(")) {
1020
+ const parsed2 = _d3color.color.call(void 0, trimmed);
1021
+ if (parsed2) {
1022
+ return parsed2.formatHex();
1026
1023
  }
1027
1024
  return color;
1028
1025
  }
1026
+ const parsed = _d3color.color.call(void 0, trimmed);
1027
+ if (parsed) {
1028
+ return parsed.formatHex();
1029
+ }
1029
1030
  return color;
1030
1031
  };
1031
1032
  var lightenHexColor = (hex, blend) => {
@@ -1274,17 +1275,10 @@ var GlobalChartsProvider = ({
1274
1275
  if (Array.isArray(colors)) {
1275
1276
  for (const color of colors) {
1276
1277
  if (color && typeof color === "string") {
1277
- let colorValue = color;
1278
- if (color.startsWith("--") || color.startsWith("var(")) {
1279
- const resolved = resolveCssVariable(color, wrapperRef.current);
1280
- if (resolved === null || resolved === "") {
1281
- continue;
1282
- }
1283
- colorValue = resolved;
1284
- }
1285
- if (colorValue.startsWith("#")) {
1286
- resolvedColors.push(colorValue);
1287
- const hslColor = _d3color.hsl.call(void 0, colorValue);
1278
+ const normalizedColor = normalizeColorToHex(color, wrapperRef.current, resolveCssVariable);
1279
+ if (normalizedColor.startsWith("#")) {
1280
+ resolvedColors.push(normalizedColor);
1281
+ const hslColor = _d3color.hsl.call(void 0, normalizedColor);
1288
1282
  if (!isNaN(hslColor.h)) {
1289
1283
  const hslTuple = [hslColor.h, hslColor.s * 100, hslColor.l * 100];
1290
1284
  hues.push(hslTuple[0]);
@@ -2925,7 +2919,7 @@ function paramCase(input, options) {
2925
2919
  return dotCase(input, _tslib.__assign.call(void 0, { delimiter: "-" }, options));
2926
2920
  }
2927
2921
 
2928
- // ../../../node_modules/.pnpm/@wordpress+ui@0.9.0_@types+react@18.3.28_react-dom@18.3.1_react@18.3.1__react@18.3.1_stylelint@16.26.1/node_modules/@wordpress/ui/build-module/stack/stack.mjs
2922
+ // ../../../node_modules/.pnpm/@wordpress+ui@0.9.0_@types+react@18.3.28_react-dom@18.3.1_react@18.3.1__react@18.3.1_stylelint@17.5.0/node_modules/@wordpress/ui/build-module/stack/stack.mjs
2929
2923
  if (typeof document !== "undefined" && process.env.NODE_ENV !== "test" && !document.head.querySelector("style[data-wp-hash='71d20935c2']")) {
2930
2924
  const style = document.createElement("style");
2931
2925
  style.setAttribute("data-wp-hash", "71d20935c2");
@@ -4296,6 +4290,43 @@ ConversionFunnelChartWithProvider.displayName = "ConversionFunnelChart";
4296
4290
 
4297
4291
  var _reactgooglecharts = require('react-google-charts');
4298
4292
 
4293
+ // src/utils/sanitize-html.ts
4294
+ var _dompurify = require('dompurify'); var _dompurify2 = _interopRequireDefault(_dompurify);
4295
+ _dompurify2.default.addHook("afterSanitizeAttributes", (node2) => {
4296
+ if (node2.tagName === "A" && node2.getAttribute("target") === "_blank") {
4297
+ node2.setAttribute("rel", "noopener noreferrer");
4298
+ }
4299
+ });
4300
+ function sanitizeHtml(html) {
4301
+ return _dompurify2.default.sanitize(html, {
4302
+ ALLOWED_TAGS: [
4303
+ "a",
4304
+ "b",
4305
+ "br",
4306
+ "div",
4307
+ "em",
4308
+ "i",
4309
+ "li",
4310
+ "ol",
4311
+ "p",
4312
+ "small",
4313
+ "span",
4314
+ "strong",
4315
+ "sub",
4316
+ "sup",
4317
+ "table",
4318
+ "tbody",
4319
+ "td",
4320
+ "th",
4321
+ "thead",
4322
+ "tr",
4323
+ "u",
4324
+ "ul"
4325
+ ],
4326
+ ALLOWED_ATTR: ["class", "href", "target", "rel"]
4327
+ });
4328
+ }
4329
+
4299
4330
  // src/charts/geo-chart/geo-chart.module.scss
4300
4331
  var geo_chart_module_default = {
4301
4332
  "container": "a8ccharts-JvcqOz"
@@ -4337,7 +4368,40 @@ var GeoChartInternal = ({
4337
4368
  const lightColorHex = lightenHexColor(fullColorHex, 0.8);
4338
4369
  const backgroundColorHex = normalizeColorToHex(backgroundColor, null, resolveCssVariable) || DEFAULT_BACKGROUND_COLOR;
4339
4370
  const defaultFillColorHex = normalizeColorToHex(featureFillColor, null, resolveCssVariable) || DEFAULT_FEATURE_FILL_COLOR;
4340
- const hasHtmlTooltips = _react.useMemo.call(void 0, () => data.length > 0 && data[0].some((col) => typeof col === "object" && col !== null && "role" in col && col.role === "tooltip" && "p" in col && typeof col.p === "object" && col.p !== null && "html" in col.p && col.p.html === true), [data]);
4371
+ const sanitizedData = _react.useMemo.call(void 0, () => {
4372
+ if (data.length === 0) {
4373
+ return {
4374
+ data,
4375
+ hasHtmlTooltips: false
4376
+ };
4377
+ }
4378
+ const htmlTooltipIndices = [];
4379
+ for (let i2 = 0; i2 < data[0].length; i2++) {
4380
+ const col = data[0][i2];
4381
+ if (typeof col === "object" && col !== null && "role" in col && col.role === "tooltip" && "p" in col && typeof col.p === "object" && col.p !== null && "html" in col.p && col.p.html === true) {
4382
+ htmlTooltipIndices.push(i2);
4383
+ }
4384
+ }
4385
+ if (htmlTooltipIndices.length === 0) {
4386
+ return {
4387
+ data,
4388
+ hasHtmlTooltips: false
4389
+ };
4390
+ }
4391
+ const sanitizedRows = data.slice(1).map((row) => {
4392
+ const newRow = [...row];
4393
+ for (const colIndex of htmlTooltipIndices) {
4394
+ if (typeof newRow[colIndex] === "string") {
4395
+ newRow[colIndex] = sanitizeHtml(newRow[colIndex]);
4396
+ }
4397
+ }
4398
+ return newRow;
4399
+ });
4400
+ return {
4401
+ data: [data[0], ...sanitizedRows],
4402
+ hasHtmlTooltips: true
4403
+ };
4404
+ }, [data]);
4341
4405
  const options = _react.useMemo.call(void 0, () => ({
4342
4406
  ...region !== "world" && {
4343
4407
  region
@@ -4353,11 +4417,11 @@ var GeoChartInternal = ({
4353
4417
  defaultColor: defaultFillColorHex,
4354
4418
  tooltip: {
4355
4419
  trigger: "focus",
4356
- isHtml: hasHtmlTooltips
4420
+ isHtml: sanitizedData.hasHtmlTooltips
4357
4421
  },
4358
4422
  legend: "none",
4359
4423
  keepAspectRatio: true
4360
- }), [region, resolution, lightColorHex, fullColorHex, backgroundColorHex, defaultFillColorHex, hasHtmlTooltips]);
4424
+ }), [region, resolution, lightColorHex, fullColorHex, backgroundColorHex, defaultFillColorHex, sanitizedData.hasHtmlTooltips]);
4361
4425
  return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", {
4362
4426
  className: _clsx2.default.call(void 0, "geo-chart", geo_chart_module_default.container, className),
4363
4427
  style: {
@@ -4369,7 +4433,7 @@ var GeoChartInternal = ({
4369
4433
  chartType: "GeoChart",
4370
4434
  width,
4371
4435
  height,
4372
- data,
4436
+ data: sanitizedData.data,
4373
4437
  options,
4374
4438
  loader: loadingPlaceholder
4375
4439
  })