From 138ce8e748546d190432ee11fe11c417c57fd11a Mon Sep 17 00:00:00 2001 From: Karsa Date: Thu, 23 Jul 2026 11:29:24 +0200 Subject: [PATCH] fix(packages/angular): add more supported attributes for SVG nodes (#4570) * fix(packages/angular): add more supported attributes for SVG nodes * fix(packages/angular): use original matcher syntax instead of toMatchInlineSnapshot matcher --------- Co-authored-by: Eric Fennis --- .../guide/angular/advanced/with-lucide-lab.md | 4 + .../angular/src/lucide-dynamic-icon.spec.ts | 139 ++++++++++++++++-- packages/angular/src/lucide-icon-template.ts | 47 ++++++ 3 files changed, 176 insertions(+), 14 deletions(-) diff --git a/docs/guide/angular/advanced/with-lucide-lab.md b/docs/guide/angular/advanced/with-lucide-lab.md index 0f4106a2a..c5b612002 100644 --- a/docs/guide/angular/advanced/with-lucide-lab.md +++ b/docs/guide/angular/advanced/with-lucide-lab.md @@ -12,6 +12,10 @@ import Sandpack from '~/.vitepress/theme/components/editors/SandpackAngular.vue' While they aren't provided as standalone components, they can be still be passed to the `LucideIcon` component the same way as official icons: +::: info Limitation +Only custom icons that follow Lucide's [code conventions](../../../contribute/icon-design-guide.md#code-conventions) are supported. +::: + ### Directly as LucideIconData ::: sandpack {template=angular showTabs=false editorHeight=400 editorWidthPercentage=60 dependencies="@lucide/angular,@lucide/lab"} diff --git a/packages/angular/src/lucide-dynamic-icon.spec.ts b/packages/angular/src/lucide-dynamic-icon.spec.ts index bd9e1fbb8..6dc0be2f3 100644 --- a/packages/angular/src/lucide-dynamic-icon.spec.ts +++ b/packages/angular/src/lucide-dynamic-icon.spec.ts @@ -43,13 +43,124 @@ describe('LucideDynamicIcon', () => { const supportedShapesIcon: LucideIconData = { name: 'supported-shapes', node: [ - ['path', { d: 'm1 1 2 2', fill: 'currentColor', key: 'path-key' }], - ['line', { x1: 1, x2: 2, y1: 3, y2: 4, key: 'line-key' }], - ['polygon', { points: '1 1 2 2 3 1', key: 'polygon-key' }], - ['polyline', { points: '1 1 2 2 3 1', key: 'polyline-key' }], - ['circle', { cx: 12, cy: 12, r: 8, fill: 'currentColor', key: 'circle-key' }], - ['ellipse', { cx: 12, cy: 12, rx: 8, ry: 4, key: 'ellipse-key' }], - ['rect', { x: 1, y: 2, width: 3, height: 4, rx: 5, ry: 6, key: 'rect-key' }], + [ + 'path', + { + class: 'path-class', + d: 'm1 1 2 2', + id: 'path-id', + opacity: '0.7', + stroke: 'red', + 'stroke-opacity': '0.5', + fill: 'blue', + 'fill-opacity': '0.3', + 'vector-effect': 'non-scaling-stroke', + key: 'path-key', + }, + ], + [ + 'line', + { + class: 'line-class', + id: 'line-id', + opacity: '0.7', + stroke: 'red', + 'stroke-opacity': '0.5', + fill: 'blue', + 'fill-opacity': '0.3', + x1: 1, + x2: 2, + y1: 3, + y2: 4, + 'vector-effect': 'non-scaling-stroke', + key: 'line-key', + }, + ], + [ + 'polygon', + { + class: 'polygon-class', + id: 'polygon-id', + opacity: '0.7', + stroke: 'red', + 'stroke-opacity': '0.5', + fill: 'blue', + 'fill-opacity': '0.3', + points: '1 1 2 2 3 1', + 'vector-effect': 'non-scaling-stroke', + key: 'polygon-key', + }, + ], + [ + 'polyline', + { + class: 'polyline-class', + id: 'polyline-id', + opacity: '0.7', + stroke: 'red', + 'stroke-opacity': '0.5', + fill: 'blue', + 'fill-opacity': '0.3', + points: '1 1 2 2 3 1', + 'vector-effect': 'non-scaling-stroke', + key: 'polyline-key', + }, + ], + [ + 'circle', + { + class: 'circle-class', + cx: 12, + cy: 12, + id: 'circle-id', + opacity: '0.7', + r: 8, + stroke: 'red', + 'stroke-opacity': '0.5', + fill: 'blue', + 'fill-opacity': '0.3', + 'vector-effect': 'non-scaling-stroke', + key: 'circle-key', + }, + ], + [ + 'ellipse', + { + class: 'ellipse-class', + cx: 12, + cy: 12, + id: 'ellipse-id', + opacity: '0.7', + rx: 8, + ry: 4, + stroke: 'red', + 'stroke-opacity': '0.5', + fill: 'blue', + 'fill-opacity': '0.3', + 'vector-effect': 'non-scaling-stroke', + key: 'ellipse-key', + }, + ], + [ + 'rect', + { + class: 'rect-class', + x: 1, + y: 2, + id: 'rect-id', + opacity: '0.7', + width: 3, + height: 4, + rx: 5, + ry: 6, + stroke: 'red', + 'stroke-opacity': '0.5', + fill: 'blue', + 'fill-opacity': '0.3', + 'vector-effect': 'non-scaling-stroke', + key: 'rect-key', + }, + ], ], }; function createComponent() { @@ -88,13 +199,13 @@ describe('LucideDynamicIcon', () => { fixture.detectChanges(); const children = getRenderedChildren(); expect(children.map((child) => child.outerHTML)).toEqual([ - '', - '', - '', - '', - '', - '', - '', + '', + '', + '', + '', + '', + '', + '', ]); }); diff --git a/packages/angular/src/lucide-icon-template.ts b/packages/angular/src/lucide-icon-template.ts index 1ae677ecb..ec95dc55f 100644 --- a/packages/angular/src/lucide-icon-template.ts +++ b/packages/angular/src/lucide-icon-template.ts @@ -11,13 +11,26 @@ export const lucideIconTemplate = `@if (title(); as titleValue) { @switch (child[0]) { @case ('path') { } @case ('line') { } @case ('polyline') { } @case ('circle') { } @case ('ellipse') { } @case ('rect') { }