diff --git a/docs/2-advanced/03-using-icons.md b/docs/2-advanced/03-using-icons.md index 4611dbc878b1..94ea9ae90557 100644 --- a/docs/2-advanced/03-using-icons.md +++ b/docs/2-advanced/03-using-icons.md @@ -110,61 +110,58 @@ After the SVG icons collection is registered, you can use the custom icons every ## Custom SVG icons -In case you need to use a fully custom SVG with multiple SVG elements like `circle` and `rect` instead of only a custom `path`, you can provide a custom renderer and register it for usage in ``. +### with JSX Templates -First, create a template for the icon you need: +In case you need to use a fully custom SVG, that can be used `ui5-icon`, `ui5-button` or any component that offers API to display an icon via icon name, you can provide a custom JSX template, rendering the custom SVG and register it under a custom name. -`BakeryDining.hbs` -```html - - - - - - - - - - - - - + +#### 1. Create JSX template + +First, create a JSX template for the icon you need: + +```tsx +// MyPensilSVGTemplate.tsx +export default function MyPensilSVGTemplate() { + return ( + + + + + + + ) +}; ``` -The `.hbs` file must start exactly with the content `""` or `"`. In that case, a `path` won't be rendered. You can also specify a custom `viewBox` size, as the default one is `0 0 512 512`. +#### 3. Use the Custom Icon Finally, the icon can be used anywhere. ```html - - + + + ``` -Tip: for multi-colored icons, you can specify multiple SVG elements and put a fill/color attribute with a specific value on each element. +**Tip:** for multi-colored icons, you can specify multiple SVG elements and put a fill/color attribute with a specific value on each element. ```html diff --git a/packages/main/src/IconTemplate.tsx b/packages/main/src/IconTemplate.tsx index 67e18b8cc9a9..b4d101487b96 100644 --- a/packages/main/src/IconTemplate.tsx +++ b/packages/main/src/IconTemplate.tsx @@ -1,5 +1,10 @@ import type Icon from "./Icon.js"; +type LegacySVGTemplate = { + strings: string[], + values?: Array +} + export default function IconTemplate(this: Icon) { return ( - {this.customSvg && - - } + {this.customSvg && svgTemplate.call(this, this.customSvg)} {this.pathData.map(path => ( @@ -33,3 +36,29 @@ export default function IconTemplate(this: Icon) { ); } + +function svgTemplate(this: Icon, template: object | LegacySVGTemplate) { + if ((template as LegacySVGTemplate).strings) { + return ; + } + return template; +} + +// Renders legacy (lit) SVG template +function renderLegacySVGTemplate(customTemplate: LegacySVGTemplate): string { + const { strings, values } = customTemplate; + + return strings.map((str: string, i: number) => { + const value = values && values[i]; + + if (typeof value === "string") { + return str + value; + } + + if (typeof value === "object" && value?.strings) { + return str + renderLegacySVGTemplate(value); + } + + return str; + }).join(""); +} diff --git a/packages/main/src/bundle-assets/IconPensilJSXTemplate.tsx b/packages/main/src/bundle-assets/IconPensilJSXTemplate.tsx new file mode 100644 index 000000000000..390243e10c43 --- /dev/null +++ b/packages/main/src/bundle-assets/IconPensilJSXTemplate.tsx @@ -0,0 +1,10 @@ +export default function IconPensilJSXTemplate() { + return ( + + + + + + + ); +} diff --git a/packages/main/src/bundle-assets/IconPensilLitTemplate.ts b/packages/main/src/bundle-assets/IconPensilLitTemplate.ts new file mode 100644 index 000000000000..eaa3c765cf0d --- /dev/null +++ b/packages/main/src/bundle-assets/IconPensilLitTemplate.ts @@ -0,0 +1,13 @@ +import { html, svg } from "@ui5/webcomponents-base/dist/renderer/LitRenderer.js"; + +function block0(this: any) { + return html`${blockSVG1.call(this)}`; +} + +function blockSVG1(this: any) { + return svg``; +} + +export default function IconPensilLitTemplate(this: any) { + return block0.call(this); +} diff --git a/packages/main/src/bundle.esm.ts b/packages/main/src/bundle.esm.ts index 6ff524ca75e5..65880608717e 100644 --- a/packages/main/src/bundle.esm.ts +++ b/packages/main/src/bundle.esm.ts @@ -3,7 +3,7 @@ // eslint-disable-next-line import testAssetsCommon from "./bundle.common.bootstrap.js"; // code that needs to be executed before other modules -import { registerIconLoader } from "@ui5/webcomponents-base/dist/asset-registries/Icons.js"; +import { registerIconLoader, registerIcon } from "@ui5/webcomponents-base/dist/asset-registries/Icons.js"; // SAP Icons import accept, { getPathData } from "@ui5/webcomponents-icons/dist/accept.js"; @@ -128,6 +128,10 @@ import ListItemCustom from "./ListItemCustom.js"; import ListItemGroupHeader from "./ListItemGroupHeader.js"; import ListItemGroup from "./ListItemGroup.js"; +// custom SVG template (Lit or JSX), registered as an icon +import IconPensilJSXTemplate from "./bundle-assets/IconPensilJSXTemplate.js"; +import IconPensilLitTemplate from "./bundle-assets/IconPensilLitTemplate.js"; + const icons = [accept, acceptv4, acceptv5, actor, actorv2, actorv3, icon3d, icon3dv1, icon3dv2]; const testAssets = { @@ -215,6 +219,22 @@ registerIconLoader("my-icons", () => { }]); }); +registerIcon("pencil", { + customTemplate: IconPensilJSXTemplate, + viewBox: "0 0 16 16", + packageName: "custom-svg-icon", + collection: "custom-svg-icons", + pathData: "pencil", +}); + +registerIcon("pencil2", { + customTemplate: IconPensilLitTemplate, + viewBox: "0 0 16 16", + packageName: "custom-svg-icon", + collection: "custom-svg-icons", + pathData: "pencil2", +}); + // @ts-ignore window["sap-ui-webcomponents-bundle"] = testAssets; diff --git a/packages/main/test/pages/Icon_custom.html b/packages/main/test/pages/Icon_custom.html index 1ff10aee6e03..031d9e6c8a83 100644 --- a/packages/main/test/pages/Icon_custom.html +++ b/packages/main/test/pages/Icon_custom.html @@ -12,5 +12,7 @@ home
tnt/actor
my-icons/mark
+ pensil
+ pensil2