@itwin/core-react 5.33.2 → 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 +1 @@
|
|
|
1
|
-
{"version":3,"file":"IconWebComponent.d.ts","sourceRoot":"","sources":["../../../src/core-react/utils/IconWebComponent.ts"],"names":[],"mappings":"AAIA;;GAEG;
|
|
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
|
|
44
|
-
|
|
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
|
|
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
|
|
65
|
-
if (
|
|
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
|
-
|
|
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":"AAAA;;;gGAGgG;AAChG;;GAEG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,uBAAuB,CAAC;AAChD,OAAO,EAAE,MAAM,EAAE,MAAM,qBAAqB,CAAC;AAC7C,OAAO,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AACtC,OAAO,SAAS,MAAM,WAAW,CAAC;AAClC,OAAO,EAAE,oBAAoB,EAAE,MAAM,2BAA2B,CAAC;AAEjE,qDAAqD;AAErD;;;;GAIG;AACH,MAAM,KAAK,GAAG,IAAI,GAAG,EAAwB,CAAC;AAE9C;;;;;GAKG;AACH,SAAS,mBAAmB,CAAC,GAAW,EAAE,OAAY;IACpD,MAAM,YAAY,GAAG,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IAEpC,IACE,CAAC,YAAY,CAAC,MAAM,KAAK,CAAC;QACxB,2BAA2B,KAAK,YAAY,CAAC,CAAC,CAAC,CAAC;QAClD,CAAC,2BAA2B,KAAK,YAAY,CAAC,CAAC,CAAC;YAC9C,oBAAoB,KAAK,YAAY,CAAC,CAAC,CAAC,CAAC,EAC3C,CAAC;QACD,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,cAAc,CAAC,OAAO,CAAC,EAAE,sBAAsB,CAAC,CAAC;QACxE,OAAO;IACT,CAAC;IAED,IAAI,MAAM,GAAG,EAAE,CAAC;IAChB,IAAI,2BAA2B,KAAK,YAAY,CAAC,CAAC,CAAC,EAAE,CAAC;QACpD,MAAM,GAAG,MAAM,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,CAAC;IACxC,CAAC;SAAM,CAAC;QACN,gFAAgF;QAChF,MAAM,GAAG,kBAAkB,CAAC,YAAY,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;IAC/D,CAAC;IAED,MAAM,
|
|
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"]}
|