@itwin/core-react 5.33.3 → 5.34.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/CHANGELOG.md CHANGED
@@ -1,5 +1,11 @@
1
1
  # Change Log - @itwin/core-react
2
2
 
3
+ ## 5.34.0
4
+
5
+ ### Patch Changes
6
+
7
+ - fc74775: Fixed the fetching of SVG icons via the legacy/deprecated `webSvg:` scheme.
8
+
3
9
  ## 5.33.3
4
10
 
5
11
  ## 5.33.2
@@ -1 +1 @@
1
- {"version":3,"file":"IconWebComponent.d.ts","sourceRoot":"","sources":["../../../src/core-react/utils/IconWebComponent.ts"],"names":[],"mappings":"AAIA;;GAEG;AA4FH;;GAEG;AACH,qBAAa,gBAAiB,SAAQ,WAAW;IAClC,iBAAiB;YAKhB,OAAO;CAetB;AAED,gBAAgB;AAChB,wBAAgB,wBAAwB,SAGvC"}
1
+ {"version":3,"file":"IconWebComponent.d.ts","sourceRoot":"","sources":["../../../src/core-react/utils/IconWebComponent.ts"],"names":[],"mappings":"AAIA;;GAEG;AAsGH;;GAEG;AACH,qBAAa,gBAAiB,SAAQ,WAAW;IAClC,iBAAiB;YAKhB,OAAO;CAetB;AAED,gBAAgB;AAChB,wBAAgB,wBAAwB,SAGvC"}
@@ -17,6 +17,18 @@ import { reuseOrCreatePromise } from "./reuseOrCreatePromise.js";
17
17
  * only do the fetch once, and have all icon use the same result)
18
18
  */
19
19
  const cache = new Map();
20
+ function sanitizeSvg(rawSvg) {
21
+ const sanitized = DOMPurify.sanitize(rawSvg, {
22
+ USE_PROFILES: { svg: true, svgFilters: true },
23
+ RETURN_DOM: true,
24
+ });
25
+ if (!(sanitized instanceof HTMLElement))
26
+ return undefined;
27
+ const svg = sanitized.firstElementChild;
28
+ if (!svg || svg.nodeName.toLowerCase() !== "svg")
29
+ return undefined;
30
+ return svg;
31
+ }
20
32
  /**
21
33
  * Parse 'data:' uri to retrieve the Svg component within it.
22
34
  * @param src data:image/svg+xml;base64 or data:image/svg+xml
@@ -40,13 +52,11 @@ function parseSvgFromDataUri(src, element) {
40
52
  // `,` is valid character in data when not in base64, rebuild the data correctly
41
53
  rawSvg = decodeURIComponent(dataUriParts.slice(1).join(","));
42
54
  }
43
- const sanitizedSvg = DOMPurify.sanitize(rawSvg);
44
- const parsedSvg = new window.DOMParser().parseFromString(sanitizedSvg, "text/xml");
45
- const errorNode = parsedSvg.querySelector("parsererror");
46
- if (errorNode || "svg" !== parsedSvg.documentElement.nodeName.toLowerCase()) {
55
+ const svg = sanitizeSvg(rawSvg);
56
+ if (!svg) {
47
57
  throw new UiError(UiCore.loggerCategory(element), "Unable to load icon.");
48
58
  }
49
- return parsedSvg.documentElement;
59
+ return svg;
50
60
  }
51
61
  /**
52
62
  * Fetch the src from the network and return the SVG element.
@@ -61,12 +71,15 @@ async function fetchSvg(src, element) {
61
71
  if (!response || !response.ok) {
62
72
  throw new UiError(UiCore.loggerCategory(element), "Unable to load icon.");
63
73
  }
64
- const str = await response.text();
65
- if (str === undefined) {
74
+ const rawSvg = await response.text();
75
+ if (rawSvg === undefined) {
76
+ throw new UiError(UiCore.loggerCategory(element), "Unable to load icon.");
77
+ }
78
+ const svg = sanitizeSvg(rawSvg);
79
+ if (!svg) {
66
80
  throw new UiError(UiCore.loggerCategory(element), "Unable to load icon.");
67
81
  }
68
- const data = new window.DOMParser().parseFromString(str, "text/xml");
69
- return data.documentElement;
82
+ return svg;
70
83
  }
71
84
  /**
72
85
  * Get the svg (fetch and parse for url, or decode and parse for data: url)
@@ -1 +1 @@
1
- {"version":3,"file":"IconWebComponent.js","sourceRoot":"","sources":["../../../src/core-react/utils/IconWebComponent.ts"],"names":[],"mappings":"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","sourcesContent":["/*---------------------------------------------------------------------------------------------\n * Copyright (c) Bentley Systems, Incorporated. All rights reserved.\n * See LICENSE.md in the project root for license terms and full copyright notice.\n *--------------------------------------------------------------------------------------------*/\n/** @packageDocumentation\n * @module Utilities\n */\n\nimport { UiError } from \"@itwin/appui-abstract\";\nimport { Logger } from \"@itwin/core-bentley\";\nimport { UiCore } from \"../UiCore.js\";\nimport DOMPurify from \"dompurify\";\nimport { reuseOrCreatePromise } from \"./reuseOrCreatePromise.js\";\n\n/* eslint-disable @typescript-eslint/no-deprecated */\n\n/**\n * \"getSvg\" list\n * (if multiple icon require the same thing,\n * only do the fetch once, and have all icon use the same result)\n */\nconst cache = new Map<string, Promise<any>>();\n\n/**\n * Parse 'data:' uri to retrieve the Svg component within it.\n * @param src data:image/svg+xml;base64 or data:image/svg+xml\n * @param element Element for logging purpose.\n * @returns HTMLElement (svg)\n */\nfunction parseSvgFromDataUri(src: string, element: any) {\n const dataUriParts = src.split(\",\");\n\n if (\n (dataUriParts.length !== 2 &&\n \"data:image/svg+xml;base64\" === dataUriParts[0]) ||\n (\"data:image/svg+xml;base64\" !== dataUriParts[0] &&\n \"data:image/svg+xml\" !== dataUriParts[0])\n ) {\n Logger.logError(UiCore.loggerCategory(element), \"Unable to load icon.\");\n return;\n }\n\n let rawSvg = \"\";\n if (\"data:image/svg+xml;base64\" === dataUriParts[0]) {\n rawSvg = window.atob(dataUriParts[1]);\n } else {\n // `,` is valid character in data when not in base64, rebuild the data correctly\n rawSvg = decodeURIComponent(dataUriParts.slice(1).join(\",\"));\n }\n\n const sanitizedSvg = DOMPurify.sanitize(rawSvg);\n\n const parsedSvg = new window.DOMParser().parseFromString(\n sanitizedSvg,\n \"text/xml\"\n );\n const errorNode = parsedSvg.querySelector(\"parsererror\");\n if (errorNode || \"svg\" !== parsedSvg.documentElement.nodeName.toLowerCase()) {\n throw new UiError(UiCore.loggerCategory(element), \"Unable to load icon.\");\n }\n\n return parsedSvg.documentElement;\n}\n\n/**\n * Fetch the src from the network and return the SVG element.\n * @param src URL representing a .svg file\n * @param element Element for logging purpose\n * @returns HTMLElement (svg)\n */\nasync function fetchSvg(src: string, element: any) {\n const response = await fetch(src).catch((_error) => {\n Logger.logError(UiCore.loggerCategory(element), \"Unable to load icon.\");\n });\n if (!response || !response.ok) {\n throw new UiError(UiCore.loggerCategory(element), \"Unable to load icon.\");\n }\n const str = await response.text();\n if (str === undefined) {\n throw new UiError(UiCore.loggerCategory(element), \"Unable to load icon.\");\n }\n const data = new window.DOMParser().parseFromString(str, \"text/xml\");\n return data.documentElement;\n}\n\n/**\n * Get the svg (fetch and parse for url, or decode and parse for data: url)\n * @param src URL of the content to download/parse\n * @param element Element for logging purpose.\n * @returns HTMLElement (svg)\n */\nasync function getSvg(src: string, element: any) {\n if (src.startsWith(\"data:\")) {\n return parseSvgFromDataUri(src, element);\n }\n return fetchSvg(src, element);\n}\n\n/** IconWebComponent loads icon from an svg path\n * @internal\n */\nexport class IconWebComponent extends HTMLElement {\n public async connectedCallback() {\n await this.loadSvg();\n this.dispatchEvent(new CustomEvent(\"load\"));\n }\n\n private async loadSvg() {\n // if svg was already appended don't request it again\n if (this.childNodes.length) return;\n const src = this.getAttribute(\"src\") || \"\";\n if (!src) return;\n\n const svg = await reuseOrCreatePromise(\n src,\n async () => getSvg(src, this),\n cache\n );\n if (svg && !this.childNodes.length) {\n this.append(svg.cloneNode(true));\n }\n }\n}\n\n/** @internal */\nexport function registerIconWebComponent() {\n if (window.customElements.get(\"svg-loader\") === undefined)\n window.customElements.define(\"svg-loader\", IconWebComponent);\n}\n"]}
1
+ {"version":3,"file":"IconWebComponent.js","sourceRoot":"","sources":["../../../src/core-react/utils/IconWebComponent.ts"],"names":[],"mappings":"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","sourcesContent":["/*---------------------------------------------------------------------------------------------\n * Copyright (c) Bentley Systems, Incorporated. All rights reserved.\n * See LICENSE.md in the project root for license terms and full copyright notice.\n *--------------------------------------------------------------------------------------------*/\n/** @packageDocumentation\n * @module Utilities\n */\n\nimport { UiError } from \"@itwin/appui-abstract\";\nimport { Logger } from \"@itwin/core-bentley\";\nimport { UiCore } from \"../UiCore.js\";\nimport DOMPurify from \"dompurify\";\nimport { reuseOrCreatePromise } from \"./reuseOrCreatePromise.js\";\n\n/* eslint-disable @typescript-eslint/no-deprecated */\n\n/**\n * \"getSvg\" list\n * (if multiple icon require the same thing,\n * only do the fetch once, and have all icon use the same result)\n */\nconst cache = new Map<string, Promise<any>>();\n\nfunction sanitizeSvg(rawSvg: string): Element | undefined {\n const sanitized = DOMPurify.sanitize(rawSvg, {\n USE_PROFILES: { svg: true, svgFilters: true },\n RETURN_DOM: true,\n });\n if (!(sanitized instanceof HTMLElement)) return undefined;\n\n const svg = sanitized.firstElementChild;\n if (!svg || svg.nodeName.toLowerCase() !== \"svg\") return undefined;\n return svg;\n}\n\n/**\n * Parse 'data:' uri to retrieve the Svg component within it.\n * @param src data:image/svg+xml;base64 or data:image/svg+xml\n * @param element Element for logging purpose.\n * @returns HTMLElement (svg)\n */\nfunction parseSvgFromDataUri(src: string, element: any) {\n const dataUriParts = src.split(\",\");\n\n if (\n (dataUriParts.length !== 2 &&\n \"data:image/svg+xml;base64\" === dataUriParts[0]) ||\n (\"data:image/svg+xml;base64\" !== dataUriParts[0] &&\n \"data:image/svg+xml\" !== dataUriParts[0])\n ) {\n Logger.logError(UiCore.loggerCategory(element), \"Unable to load icon.\");\n return;\n }\n\n let rawSvg = \"\";\n if (\"data:image/svg+xml;base64\" === dataUriParts[0]) {\n rawSvg = window.atob(dataUriParts[1]);\n } else {\n // `,` is valid character in data when not in base64, rebuild the data correctly\n rawSvg = decodeURIComponent(dataUriParts.slice(1).join(\",\"));\n }\n\n const svg = sanitizeSvg(rawSvg);\n if (!svg) {\n throw new UiError(UiCore.loggerCategory(element), \"Unable to load icon.\");\n }\n\n return svg;\n}\n\n/**\n * Fetch the src from the network and return the SVG element.\n * @param src URL representing a .svg file\n * @param element Element for logging purpose\n * @returns HTMLElement (svg)\n */\nasync function fetchSvg(src: string, element: any) {\n const response = await fetch(src).catch((_error) => {\n Logger.logError(UiCore.loggerCategory(element), \"Unable to load icon.\");\n });\n if (!response || !response.ok) {\n throw new UiError(UiCore.loggerCategory(element), \"Unable to load icon.\");\n }\n const rawSvg = await response.text();\n if (rawSvg === undefined) {\n throw new UiError(UiCore.loggerCategory(element), \"Unable to load icon.\");\n }\n\n const svg = sanitizeSvg(rawSvg);\n if (!svg) {\n throw new UiError(UiCore.loggerCategory(element), \"Unable to load icon.\");\n }\n return svg;\n}\n\n/**\n * Get the svg (fetch and parse for url, or decode and parse for data: url)\n * @param src URL of the content to download/parse\n * @param element Element for logging purpose.\n * @returns HTMLElement (svg)\n */\nasync function getSvg(src: string, element: any) {\n if (src.startsWith(\"data:\")) {\n return parseSvgFromDataUri(src, element);\n }\n return fetchSvg(src, element);\n}\n\n/** IconWebComponent loads icon from an svg path\n * @internal\n */\nexport class IconWebComponent extends HTMLElement {\n public async connectedCallback() {\n await this.loadSvg();\n this.dispatchEvent(new CustomEvent(\"load\"));\n }\n\n private async loadSvg() {\n // if svg was already appended don't request it again\n if (this.childNodes.length) return;\n const src = this.getAttribute(\"src\") || \"\";\n if (!src) return;\n\n const svg = await reuseOrCreatePromise(\n src,\n async () => getSvg(src, this),\n cache\n );\n if (svg && !this.childNodes.length) {\n this.append(svg.cloneNode(true));\n }\n }\n}\n\n/** @internal */\nexport function registerIconWebComponent() {\n if (window.customElements.get(\"svg-loader\") === undefined)\n window.customElements.define(\"svg-loader\", IconWebComponent);\n}\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@itwin/core-react",
3
- "version": "5.33.3",
3
+ "version": "5.34.0",
4
4
  "description": "A react component library of iTwin.js UI general purpose components",
5
5
  "type": "module",
6
6
  "types": "./lib/core-react.d.ts",