Skip to content

Commit eb0663b

Browse files
stramelclaude
andauthored
fix: keep viewBox on the svg wrapper instead of stripping it (#298)
* fix: keep viewBox on the svg wrapper for every icon instance PR #286 made viewBox stripping consistent across repeated instances by removing it everywhere for non-inline rendering. As Chris pointed out, viewBox does more than size the icon: attributes like preserveAspectRatio have no effect without it. Achieve the same consistency by always keeping the viewBox instead. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * fix: anchor use element to the icon's viewBox rect Keeping viewBox on the wrapper alone reintroduces the clipping from #212: a <use> with no x/y/width/height generates its viewport at user-space (0,0) sized to 100% of the wrapper, so icons whose viewBox has a non-zero min-x/min-y render shifted and cropped. Pin the <use> to the symbol's viewBox rect so the reference is an identity placement, and source the symbol's viewBox from the icon data rather than the merged props so a per-instance override no longer leaks onto every other instance of the same icon. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * fix: only anchor the use element for offset-origin icons The generated <use> viewport already defaults to the symbol's viewBox rect when that rect starts at the origin, which covers essentially every icon. Emit x/y/width/height only when the icon's viewBox has a non-zero min-x/min-y, so the common case renders exactly the markup it did before. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * fix: keep the symbol viewBox only where it does work With the wrapper's viewBox restored, a symbol viewBox is redundant for an icon whose own viewBox starts at the origin: a bare <use> already generates a viewport covering the whole wrapper, and the artwork lands on it 1:1. It stays for offset-origin icons, where it is the only way to decouple viewport placement from the artwork's coordinates, since <use> x/y translate the referenced content along with the viewport. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * refactor: trim viewBox comments down to the why Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
1 parent d90facd commit eb0663b

2 files changed

Lines changed: 17 additions & 11 deletions

File tree

.changeset/tame-donuts-shout.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,4 @@
22
"astro-icon": patch
33
---
44

5-
Fix `viewBox` being inconsistently present on `<svg>` elements across repeated uses of the same icon
5+
Fix `viewBox` being inconsistently present on `<svg>` elements across repeated uses of the same icon. The `viewBox` is now always kept on the `<svg>` element, so attributes that depend on it (such as `preserveAspectRatio`) continue to work. Icons whose `viewBox` has a non-zero `min-x`/`min-y` keep a `viewBox` on their shared `<symbol>` and anchor their `<use>` element, so they stay positioned correctly and a per-instance `viewBox` override no longer leaks onto other instances of the same icon.

packages/core/components/Icon.astro

Lines changed: 16 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -128,16 +128,22 @@ if (props.size) {
128128
delete props.size;
129129
}
130130
const renderData = iconToSVG(iconData);
131-
const normalizedProps = {
132-
...(renderData.attributes as Partial<IconifyIconBuildResult["attributes"]>),
133-
...props,
134-
};
131+
const attributes = renderData.attributes as Partial<
132+
IconifyIconBuildResult["attributes"]
133+
>;
134+
const normalizedProps = { ...attributes, ...props };
135135
const normalizedBody = replaceIDs(renderData.body);
136136
137-
const { viewBox } = normalizedProps;
138-
if (!inline) {
139-
delete normalizedProps.viewBox;
140-
}
137+
const [minX, minY, vbWidth, vbHeight] =
138+
attributes.viewBox?.split(/[\s,]+/).map(Number) ?? [];
139+
// Without this the artwork renders offset by its origin and clipped (https://github.com/natemoo-re/astro-icon/issues/212).
140+
const hasOffsetOrigin =
141+
[minX, minY, vbWidth, vbHeight].every(Number.isFinite) &&
142+
(minX !== 0 || minY !== 0);
143+
const symbolViewBox = hasOffsetOrigin ? attributes.viewBox : undefined;
144+
const useRect = hasOffsetOrigin
145+
? { x: minX, y: minY, width: vbWidth, height: vbHeight }
146+
: {};
141147
---
142148

143149
<svg {...normalizedProps} data-icon={name}>
@@ -153,9 +159,9 @@ if (!inline) {
153159
) : (
154160
<Fragment>
155161
{includeSymbol && (
156-
<symbol id={id} viewBox={viewBox} set:html={normalizedBody} />
162+
<symbol id={id} viewBox={symbolViewBox} set:html={normalizedBody} />
157163
)}
158-
<use href={`#${id}`} />
164+
<use href={`#${id}`} {...useRect} />
159165
</Fragment>
160166
)
161167
}

0 commit comments

Comments
 (0)