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:
::: 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"}

View File

@@ -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([
'<path d="m1 1 2 2" fill="currentColor"></path>',
'<line x1="1" x2="2" y1="3" y2="4"></line>',
'<polygon points="1 1 2 2 3 1"></polygon>',
'<polyline points="1 1 2 2 3 1"></polyline>',
'<circle cx="12" cy="12" r="8" fill="currentColor"></circle>',
'<ellipse cx="12" cy="12" rx="8" ry="4"></ellipse>',
'<rect x="1" y="2" width="3" height="4" rx="5" ry="6"></rect>',
'<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 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 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 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 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 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 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]) {
@case ('path') {
<svg:path
[attr.class]="attrs['class']"
[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-opacity]="attrs['fill-opacity']"
[attr.vector-effect]="attrs['vector-effect']"
/>
}
@case ('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.x2]="attrs['x2']"
[attr.y1]="attrs['y1']"
@@ -27,42 +40,76 @@ export const lucideIconTemplate = `@if (title(); as titleValue) {
}
@case ('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.vector-effect]="attrs['vector-effect']"
/>
}
@case ('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.vector-effect]="attrs['vector-effect']"
/>
}
@case ('circle') {
<svg:circle
[attr.class]="attrs['class']"
[attr.cx]="attrs['cx']"
[attr.cy]="attrs['cy']"
[attr.id]="attrs['id']"
[attr.opacity]="attrs['opacity']"
[attr.r]="attrs['r']"
[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']"
/>
}
@case ('ellipse') {
<svg:ellipse
[attr.class]="attrs['class']"
[attr.cx]="attrs['cx']"
[attr.cy]="attrs['cy']"
[attr.id]="attrs['id']"
[attr.opacity]="attrs['opacity']"
[attr.rx]="attrs['rx']"
[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']"
/>
}
@case ('rect') {
<svg:rect
[attr.class]="attrs['class']"
[attr.x]="attrs['x']"
[attr.y]="attrs['y']"
[attr.id]="attrs['id']"
[attr.opacity]="attrs['opacity']"
[attr.width]="attrs['width']"
[attr.height]="attrs['height']"
[attr.rx]="attrs['rx']"
[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']"
/>
}