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 <eric.fennis@gmail.com>
This commit is contained in:
Karsa
2026-07-23 11:29:24 +02:00
committed by GitHub
parent 87ec1a0587
commit 138ce8e748
3 changed files with 176 additions and 14 deletions

View File

@@ -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: 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 ### Directly as LucideIconData
::: sandpack {template=angular showTabs=false editorHeight=400 editorWidthPercentage=60 dependencies="@lucide/angular,@lucide/lab"} ::: sandpack {template=angular showTabs=false editorHeight=400 editorWidthPercentage=60 dependencies="@lucide/angular,@lucide/lab"}

View File

@@ -43,13 +43,124 @@ describe('LucideDynamicIcon', () => {
const supportedShapesIcon: LucideIconData = { const supportedShapesIcon: LucideIconData = {
name: 'supported-shapes', name: 'supported-shapes',
node: [ node: [
['path', { d: 'm1 1 2 2', fill: 'currentColor', key: 'path-key' }], [
['line', { x1: 1, x2: 2, y1: 3, y2: 4, key: 'line-key' }], 'path',
['polygon', { points: '1 1 2 2 3 1', key: 'polygon-key' }], {
['polyline', { points: '1 1 2 2 3 1', key: 'polyline-key' }], class: 'path-class',
['circle', { cx: 12, cy: 12, r: 8, fill: 'currentColor', key: 'circle-key' }], d: 'm1 1 2 2',
['ellipse', { cx: 12, cy: 12, rx: 8, ry: 4, key: 'ellipse-key' }], id: 'path-id',
['rect', { x: 1, y: 2, width: 3, height: 4, rx: 5, ry: 6, key: 'rect-key' }], 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() { function createComponent() {
@@ -88,13 +199,13 @@ describe('LucideDynamicIcon', () => {
fixture.detectChanges(); fixture.detectChanges();
const children = getRenderedChildren(); const children = getRenderedChildren();
expect(children.map((child) => child.outerHTML)).toEqual([ expect(children.map((child) => child.outerHTML)).toEqual([
'<path d="m1 1 2 2" fill="currentColor"></path>', '<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"></path>',
'<line x1="1" x2="2" y1="3" y2="4"></line>', '<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"></line>',
'<polygon points="1 1 2 2 3 1"></polygon>', '<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"></polygon>',
'<polyline points="1 1 2 2 3 1"></polyline>', '<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"></polyline>',
'<circle cx="12" cy="12" r="8" fill="currentColor"></circle>', '<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"></circle>',
'<ellipse cx="12" cy="12" rx="8" ry="4"></ellipse>', '<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"></ellipse>',
'<rect x="1" y="2" width="3" height="4" rx="5" ry="6"></rect>', '<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"></rect>',
]); ]);
}); });

View File

@@ -11,13 +11,26 @@ export const lucideIconTemplate = `@if (title(); as titleValue) {
@switch (child[0]) { @switch (child[0]) {
@case ('path') { @case ('path') {
<svg:path <svg:path
[attr.class]="attrs['class']"
[attr.d]="attrs['d']" [attr.d]="attrs['d']"
[attr.id]="attrs['id']"
[attr.opacity]="attrs['opacity']"
[attr.stroke]="attrs['stroke']"
[attr.stroke-opacity]="attrs['stroke-opacity']"
[attr.fill]="attrs['fill']" [attr.fill]="attrs['fill']"
[attr.fill-opacity]="attrs['fill-opacity']"
[attr.vector-effect]="attrs['vector-effect']" [attr.vector-effect]="attrs['vector-effect']"
/> />
} }
@case ('line') { @case ('line') {
<svg:line <svg:line
[attr.class]="attrs['class']"
[attr.id]="attrs['id']"
[attr.opacity]="attrs['opacity']"
[attr.stroke]="attrs['stroke']"
[attr.stroke-opacity]="attrs['stroke-opacity']"
[attr.fill]="attrs['fill']"
[attr.fill-opacity]="attrs['fill-opacity']"
[attr.x1]="attrs['x1']" [attr.x1]="attrs['x1']"
[attr.x2]="attrs['x2']" [attr.x2]="attrs['x2']"
[attr.y1]="attrs['y1']" [attr.y1]="attrs['y1']"
@@ -27,42 +40,76 @@ export const lucideIconTemplate = `@if (title(); as titleValue) {
} }
@case ('polygon') { @case ('polygon') {
<svg:polygon <svg:polygon
[attr.class]="attrs['class']"
[attr.id]="attrs['id']"
[attr.opacity]="attrs['opacity']"
[attr.stroke]="attrs['stroke']"
[attr.stroke-opacity]="attrs['stroke-opacity']"
[attr.fill]="attrs['fill']"
[attr.fill-opacity]="attrs['fill-opacity']"
[attr.points]="attrs['points']" [attr.points]="attrs['points']"
[attr.vector-effect]="attrs['vector-effect']" [attr.vector-effect]="attrs['vector-effect']"
/> />
} }
@case ('polyline') { @case ('polyline') {
<svg:polyline <svg:polyline
[attr.class]="attrs['class']"
[attr.id]="attrs['id']"
[attr.opacity]="attrs['opacity']"
[attr.stroke]="attrs['stroke']"
[attr.stroke-opacity]="attrs['stroke-opacity']"
[attr.fill]="attrs['fill']"
[attr.fill-opacity]="attrs['fill-opacity']"
[attr.points]="attrs['points']" [attr.points]="attrs['points']"
[attr.vector-effect]="attrs['vector-effect']" [attr.vector-effect]="attrs['vector-effect']"
/> />
} }
@case ('circle') { @case ('circle') {
<svg:circle <svg:circle
[attr.class]="attrs['class']"
[attr.cx]="attrs['cx']" [attr.cx]="attrs['cx']"
[attr.cy]="attrs['cy']" [attr.cy]="attrs['cy']"
[attr.id]="attrs['id']"
[attr.opacity]="attrs['opacity']"
[attr.r]="attrs['r']" [attr.r]="attrs['r']"
[attr.stroke]="attrs['stroke']"
[attr.stroke-opacity]="attrs['stroke-opacity']"
[attr.fill]="attrs['fill']" [attr.fill]="attrs['fill']"
[attr.fill-opacity]="attrs['fill-opacity']"
[attr.vector-effect]="attrs['vector-effect']" [attr.vector-effect]="attrs['vector-effect']"
/> />
} }
@case ('ellipse') { @case ('ellipse') {
<svg:ellipse <svg:ellipse
[attr.class]="attrs['class']"
[attr.cx]="attrs['cx']" [attr.cx]="attrs['cx']"
[attr.cy]="attrs['cy']" [attr.cy]="attrs['cy']"
[attr.id]="attrs['id']"
[attr.opacity]="attrs['opacity']"
[attr.rx]="attrs['rx']" [attr.rx]="attrs['rx']"
[attr.ry]="attrs['ry']" [attr.ry]="attrs['ry']"
[attr.stroke]="attrs['stroke']"
[attr.stroke-opacity]="attrs['stroke-opacity']"
[attr.fill]="attrs['fill']"
[attr.fill-opacity]="attrs['fill-opacity']"
[attr.vector-effect]="attrs['vector-effect']" [attr.vector-effect]="attrs['vector-effect']"
/> />
} }
@case ('rect') { @case ('rect') {
<svg:rect <svg:rect
[attr.class]="attrs['class']"
[attr.x]="attrs['x']" [attr.x]="attrs['x']"
[attr.y]="attrs['y']" [attr.y]="attrs['y']"
[attr.id]="attrs['id']"
[attr.opacity]="attrs['opacity']"
[attr.width]="attrs['width']" [attr.width]="attrs['width']"
[attr.height]="attrs['height']" [attr.height]="attrs['height']"
[attr.rx]="attrs['rx']" [attr.rx]="attrs['rx']"
[attr.ry]="attrs['ry']" [attr.ry]="attrs['ry']"
[attr.stroke]="attrs['stroke']"
[attr.stroke-opacity]="attrs['stroke-opacity']"
[attr.fill]="attrs['fill']"
[attr.fill-opacity]="attrs['fill-opacity']"
[attr.vector-effect]="attrs['vector-effect']" [attr.vector-effect]="attrs['vector-effect']"
/> />
} }