@@ -138,6 +138,118 @@ describe("icons", () => {
138138 expect ( result . code ) . toContain ( 'className={cn("icon")}' ) ;
139139 } ) ;
140140
141+ describe ( "default size attributes" , ( ) => {
142+ it ( "should add default width and height of 1em when not specified" , ( ) => {
143+ const code = `
144+ import { Lucide } from "@qds.dev/ui";
145+
146+ function App() {
147+ return <Lucide.Check class="icon" />;
148+ }
149+ ` ;
150+ const result = transform ( code , "test.tsx" ) ;
151+ expect ( result ) . toBeTruthy ( ) ;
152+ expect ( result . code ) . toContain ( 'width="1em"' ) ;
153+ expect ( result . code ) . toContain ( 'height="1em"' ) ;
154+ expect ( result . code ) . toContain ( 'viewBox="0 0 24 24"' ) ;
155+ } ) ;
156+
157+ it ( "should not add default width when width is explicitly provided" , ( ) => {
158+ const code = `
159+ import { Lucide } from "@qds.dev/ui";
160+
161+ function App() {
162+ return <Lucide.Check width={24} />;
163+ }
164+ ` ;
165+ const result = transform ( code , "test.tsx" ) ;
166+ expect ( result ) . toBeTruthy ( ) ;
167+ expect ( result . code ) . toContain ( "width={24}" ) ;
168+ expect ( result . code ) . not . toContain ( 'width="1em"' ) ;
169+ // Should still add default height
170+ expect ( result . code ) . toContain ( 'height="1em"' ) ;
171+ } ) ;
172+
173+ it ( "should not add default height when height is explicitly provided" , ( ) => {
174+ const code = `
175+ import { Lucide } from "@qds.dev/ui";
176+
177+ function App() {
178+ return <Lucide.Check height={24} />;
179+ }
180+ ` ;
181+ const result = transform ( code , "test.tsx" ) ;
182+ expect ( result ) . toBeTruthy ( ) ;
183+ expect ( result . code ) . toContain ( "height={24}" ) ;
184+ expect ( result . code ) . not . toContain ( 'height="1em"' ) ;
185+ // Should still add default width
186+ expect ( result . code ) . toContain ( 'width="1em"' ) ;
187+ } ) ;
188+
189+ it ( "should not add defaults when both width and height are explicitly provided" , ( ) => {
190+ const code = `
191+ import { Lucide } from "@qds.dev/ui";
192+
193+ function App() {
194+ return <Lucide.Check width={24} height={24} />;
195+ }
196+ ` ;
197+ const result = transform ( code , "test.tsx" ) ;
198+ expect ( result ) . toBeTruthy ( ) ;
199+ expect ( result . code ) . toContain ( "width={24}" ) ;
200+ expect ( result . code ) . toContain ( "height={24}" ) ;
201+ expect ( result . code ) . not . toContain ( 'width="1em"' ) ;
202+ expect ( result . code ) . not . toContain ( 'height="1em"' ) ;
203+ } ) ;
204+
205+ it ( "should add default sizes with expression props" , ( ) => {
206+ const code = `
207+ import { Lucide } from "@qds.dev/ui";
208+
209+ function App() {
210+ return <Lucide.Check className="icon" aria-label="Check" />;
211+ }
212+ ` ;
213+ const result = transform ( code , "test.tsx" ) ;
214+ expect ( result ) . toBeTruthy ( ) ;
215+ expect ( result . code ) . toContain ( 'width="1em"' ) ;
216+ expect ( result . code ) . toContain ( 'height="1em"' ) ;
217+ expect ( result . code ) . toContain ( 'className="icon"' ) ;
218+ expect ( result . code ) . toContain ( 'aria-label="Check"' ) ;
219+ } ) ;
220+
221+ it ( "should respect string width values" , ( ) => {
222+ const code = `
223+ import { Lucide } from "@qds.dev/ui";
224+
225+ function App() {
226+ return <Lucide.Check width="2rem" />;
227+ }
228+ ` ;
229+ const result = transform ( code , "test.tsx" ) ;
230+ expect ( result ) . toBeTruthy ( ) ;
231+ expect ( result . code ) . toContain ( 'width="2rem"' ) ;
232+ expect ( result . code ) . not . toContain ( 'width="1em"' ) ;
233+ expect ( result . code ) . toContain ( 'height="1em"' ) ;
234+ } ) ;
235+
236+ it ( "should respect expression width values" , ( ) => {
237+ const code = `
238+ import { Lucide } from "@qds.dev/ui";
239+
240+ function App() {
241+ const iconSize = "2em";
242+ return <Lucide.Check width={iconSize} />;
243+ }
244+ ` ;
245+ const result = transform ( code , "test.tsx" ) ;
246+ expect ( result ) . toBeTruthy ( ) ;
247+ expect ( result . code ) . toContain ( "width={iconSize}" ) ;
248+ expect ( result . code ) . not . toContain ( 'width="1em"' ) ;
249+ expect ( result . code ) . toContain ( 'height="1em"' ) ;
250+ } ) ;
251+ } ) ;
252+
141253 it ( "should convert title prop to children" , ( ) => {
142254 const code = `
143255 import { Lucide } from "@qds.dev/ui";
@@ -149,7 +261,7 @@ describe("icons", () => {
149261 const result = transform ( code , "test.tsx" ) ;
150262 expect ( result ) . toBeTruthy ( ) ;
151263 expect ( result . code ) . toContain (
152- '<svg viewBox="0 0 24 24" dangerouslySetInnerHTML={__qds_i_lucide_check}><title>Checked item</title></svg>'
264+ '<svg width="1em" height="1em" viewBox="0 0 24 24" dangerouslySetInnerHTML={__qds_i_lucide_check}><title>Checked item</title></svg>'
153265 ) ;
154266 } ) ;
155267
@@ -165,7 +277,7 @@ describe("icons", () => {
165277 const result = transform ( code , "test.tsx" ) ;
166278 expect ( result ) . toBeTruthy ( ) ;
167279 expect ( result . code ) . toContain (
168- '<svg viewBox="0 0 24 24" dangerouslySetInnerHTML={__qds_i_lucide_check}><title>{label}</title></svg>'
280+ '<svg width="1em" height="1em" viewBox="0 0 24 24" dangerouslySetInnerHTML={__qds_i_lucide_check}><title>{label}</title></svg>'
169281 ) ;
170282 } ) ;
171283
@@ -184,7 +296,7 @@ describe("icons", () => {
184296 const result = transform ( code , "test.tsx" ) ;
185297 expect ( result ) . toBeTruthy ( ) ;
186298 expect ( result . code ) . toContain (
187- '<svg viewBox="0 0 24 24" dangerouslySetInnerHTML={__qds_i_lucide_check}><title>Checked item</title><desc>Extra a11y</desc></svg>'
299+ '<svg width="1em" height="1em" viewBox="0 0 24 24" dangerouslySetInnerHTML={__qds_i_lucide_check}><title>Checked item</title><desc>Extra a11y</desc></svg>'
188300 ) ;
189301 } ) ;
190302
@@ -199,7 +311,7 @@ describe("icons", () => {
199311 const result = transform ( code , "test.tsx" ) ;
200312 expect ( result ) . toBeTruthy ( ) ;
201313 expect ( result . code ) . toContain (
202- '<svg viewBox="0 0 24 24" dangerouslySetInnerHTML={__qds_i_lucide_check}><desc>This icon indicates completion</desc></svg>'
314+ '<svg width="1em" height="1em" viewBox="0 0 24 24" dangerouslySetInnerHTML={__qds_i_lucide_check}><desc>This icon indicates completion</desc></svg>'
203315 ) ;
204316 } ) ;
205317
@@ -215,7 +327,7 @@ describe("icons", () => {
215327 const result = transform ( code , "test.tsx" ) ;
216328 expect ( result ) . toBeTruthy ( ) ;
217329 expect ( result . code ) . toContain (
218- '<svg viewBox="0 0 24 24" dangerouslySetInnerHTML={__qds_i_lucide_check}><desc>{desc}</desc></svg>'
330+ '<svg width="1em" height="1em" viewBox="0 0 24 24" dangerouslySetInnerHTML={__qds_i_lucide_check}><desc>{desc}</desc></svg>'
219331 ) ;
220332 } ) ;
221333
@@ -230,7 +342,7 @@ describe("icons", () => {
230342 const result = transform ( code , "test.tsx" ) ;
231343 expect ( result ) . toBeTruthy ( ) ;
232344 expect ( result . code ) . toContain (
233- '<svg viewBox="0 0 24 24" dangerouslySetInnerHTML={__qds_i_lucide_check}><title>Check mark</title><desc>Indicates completion</desc></svg>'
345+ '<svg width="1em" height="1em" viewBox="0 0 24 24" dangerouslySetInnerHTML={__qds_i_lucide_check}><title>Check mark</title><desc>Indicates completion</desc></svg>'
234346 ) ;
235347 } ) ;
236348
@@ -247,7 +359,7 @@ describe("icons", () => {
247359 const result = transform ( code , "test.tsx" ) ;
248360 expect ( result ) . toBeTruthy ( ) ;
249361 expect ( result . code ) . toContain (
250- '<svg viewBox="0 0 24 24" dangerouslySetInnerHTML={__qds_i_lucide_check}><title>{iconTitle}</title><desc>{iconDesc}</desc></svg>'
362+ '<svg width="1em" height="1em" viewBox="0 0 24 24" dangerouslySetInnerHTML={__qds_i_lucide_check}><title>{iconTitle}</title><desc>{iconDesc}</desc></svg>'
251363 ) ;
252364 } ) ;
253365
@@ -472,7 +584,7 @@ describe("icons", () => {
472584 const result = transform ( code , "test.tsx" ) ;
473585 expect ( result ) . toBeTruthy ( ) ;
474586 expect ( result . code ) . toContain (
475- '<svg viewBox="0 0 24 24" dangerouslySetInnerHTML={__qds_i_lucide_check}><title>Check</title><desc>Description</desc></svg>'
587+ '<svg width="1em" height="1em" viewBox="0 0 24 24" dangerouslySetInnerHTML={__qds_i_lucide_check}><title>Check</title><desc>Description</desc></svg>'
476588 ) ;
477589 } ) ;
478590
@@ -592,7 +704,7 @@ describe("icons", () => {
592704 "import __qds_i_lucide_check from 'virtual:icons/lucide/check'"
593705 ) ;
594706 expect ( result . code ) . toContain (
595- '<svg width={24} class="text-green-500" viewBox="0 0 24 24" dangerouslySetInnerHTML={__qds_i_lucide_check} />'
707+ '<svg width={24} class="text-green-500" height="1em" viewBox="0 0 24 24" dangerouslySetInnerHTML={__qds_i_lucide_check} />'
596708 ) ;
597709 } ) ;
598710
@@ -610,7 +722,7 @@ describe("icons", () => {
610722 "import __qds_i_lucide_x from 'virtual:icons/lucide/x'"
611723 ) ;
612724 expect ( result . code ) . toContain (
613- '<svg width={24} class="text-red-500" viewBox="0 0 24 24" dangerouslySetInnerHTML={__qds_i_lucide_x} />'
725+ '<svg width={24} class="text-red-500" height="1em" viewBox="0 0 24 24" dangerouslySetInnerHTML={__qds_i_lucide_x} />'
614726 ) ;
615727 } ) ;
616728
@@ -628,7 +740,7 @@ describe("icons", () => {
628740 "import __qds_i_lucide_heart from 'virtual:icons/lucide/heart'"
629741 ) ;
630742 expect ( result . code ) . toContain (
631- '<svg width={24} class="text-red-500 fill-current" viewBox="0 0 24 24" dangerouslySetInnerHTML={__qds_i_lucide_heart} />'
743+ '<svg width={24} class="text-red-500 fill-current" height="1em" viewBox="0 0 24 24" dangerouslySetInnerHTML={__qds_i_lucide_heart} />'
632744 ) ;
633745 } ) ;
634746
@@ -662,16 +774,16 @@ describe("icons", () => {
662774 "import __qds_i_lucide_star from 'virtual:icons/lucide/star'"
663775 ) ;
664776 expect ( result . code ) . toContain (
665- '<svg width={24} class="text-green-500" viewBox="0 0 24 24" dangerouslySetInnerHTML={__qds_i_lucide_check} />'
777+ '<svg width={24} class="text-green-500" height="1em" viewBox="0 0 24 24" dangerouslySetInnerHTML={__qds_i_lucide_check} />'
666778 ) ;
667779 expect ( result . code ) . toContain (
668- '<svg width={24} class="text-red-500" viewBox="0 0 24 24" dangerouslySetInnerHTML={__qds_i_lucide_x} />'
780+ '<svg width={24} class="text-red-500" height="1em" viewBox="0 0 24 24" dangerouslySetInnerHTML={__qds_i_lucide_x} />'
669781 ) ;
670782 expect ( result . code ) . toContain (
671- '<svg width={24} class="text-red-500 fill-current" viewBox="0 0 24 24" dangerouslySetInnerHTML={__qds_i_lucide_heart} />'
783+ '<svg width={24} class="text-red-500 fill-current" height="1em" viewBox="0 0 24 24" dangerouslySetInnerHTML={__qds_i_lucide_heart} />'
672784 ) ;
673785 expect ( result . code ) . toContain (
674- '<svg width={24} class="text-yellow-500" viewBox="0 0 24 24" dangerouslySetInnerHTML={__qds_i_lucide_star} />'
786+ '<svg width={24} class="text-yellow-500" height="1em" viewBox="0 0 24 24" dangerouslySetInnerHTML={__qds_i_lucide_star} />'
675787 ) ;
676788 } ) ;
677789
@@ -689,7 +801,7 @@ describe("icons", () => {
689801 "import __qds_i_heroicons_check_circle from 'virtual:icons/heroicons/check-circle'"
690802 ) ;
691803 expect ( result . code ) . toContain (
692- '<svg width={24} class="text-green-500" viewBox="0 0 24 24" dangerouslySetInnerHTML={__qds_i_heroicons_check_circle} />'
804+ '<svg width={24} class="text-green-500" height="1em" viewBox="0 0 24 24" dangerouslySetInnerHTML={__qds_i_heroicons_check_circle} />'
693805 ) ;
694806 } ) ;
695807
@@ -707,7 +819,7 @@ describe("icons", () => {
707819 "import __qds_i_tabler_check from 'virtual:icons/tabler/check'"
708820 ) ;
709821 expect ( result . code ) . toContain (
710- '<svg width={24} class="text-green-500" viewBox="0 0 24 24" dangerouslySetInnerHTML={__qds_i_tabler_check} />'
822+ '<svg width={24} class="text-green-500" height="1em" viewBox="0 0 24 24" dangerouslySetInnerHTML={__qds_i_tabler_check} />'
711823 ) ;
712824 } ) ;
713825
@@ -729,7 +841,7 @@ describe("icons", () => {
729841 expect ( result . code ) . toContain ( "__qds_i_akaricons_airpods" ) ;
730842
731843 expect ( result . code ) . toContain (
732- '<svg viewBox="0 0 24 24" viewBox="0 0 24 24" dangerouslySetInnerHTML={__qds_i_akaricons_airpods} />'
844+ '<svg viewBox="0 0 24 24" width="1em" height="1em" viewBox="0 0 24 24" dangerouslySetInnerHTML={__qds_i_akaricons_airpods} />'
733845 ) ;
734846
735847 expect ( result . code ) . not . toContain ( "__qds_i_akar-icons_airpods" ) ;
@@ -753,7 +865,7 @@ describe("icons", () => {
753865 expect ( result . code ) . toContain ( "__qds_i_materialsymbols_ac_unit_rounded" ) ;
754866
755867 expect ( result . code ) . toContain (
756- '<svg class="text-blue-500" viewBox="0 0 24 24" dangerouslySetInnerHTML={__qds_i_materialsymbols_ac_unit_rounded} />'
868+ '<svg class="text-blue-500" width="1em" height="1em" viewBox="0 0 24 24" dangerouslySetInnerHTML={__qds_i_materialsymbols_ac_unit_rounded} />'
757869 ) ;
758870
759871 expect ( result . code ) . not . toContain ( "__qds_i_material-symbols_ac-unit-rounded" ) ;
@@ -772,7 +884,7 @@ describe("icons", () => {
772884
773885 // Should include consumer's viewBox and width
774886 expect ( result . code ) . toContain (
775- '<svg viewBox="0 0 32 32" width={32} viewBox="0 0 24 24" dangerouslySetInnerHTML={__qds_i_lucide_check} />'
887+ '<svg viewBox="0 0 32 32" width={32} height="1em" viewBox="0 0 24 24" dangerouslySetInnerHTML={__qds_i_lucide_check} />'
776888 ) ;
777889 } ) ;
778890
@@ -830,28 +942,28 @@ describe("icons", () => {
830942
831943 // Should contain all the transformed icons
832944 expect ( result . code ) . toContain (
833- '<svg width={24} class="text-green-500" viewBox="0 0 24 24" dangerouslySetInnerHTML={__qds_i_lucide_check} />'
945+ '<svg width={24} class="text-green-500" height="1em" viewBox="0 0 24 24" dangerouslySetInnerHTML={__qds_i_lucide_check} />'
834946 ) ;
835947 expect ( result . code ) . toContain (
836- '<svg width={24} class="text-red-500" viewBox="0 0 24 24" dangerouslySetInnerHTML={__qds_i_lucide_x} />'
948+ '<svg width={24} class="text-red-500" height="1em" viewBox="0 0 24 24" dangerouslySetInnerHTML={__qds_i_lucide_x} />'
837949 ) ;
838950 expect ( result . code ) . toContain (
839- '<svg width={24} class="text-red-500 fill-current" viewBox="0 0 24 24" dangerouslySetInnerHTML={__qds_i_lucide_heart} />'
951+ '<svg width={24} class="text-red-500 fill-current" height="1em" viewBox="0 0 24 24" dangerouslySetInnerHTML={__qds_i_lucide_heart} />'
840952 ) ;
841953 expect ( result . code ) . toContain (
842- '<svg width={24} class="text-yellow-500" viewBox="0 0 24 24" dangerouslySetInnerHTML={__qds_i_lucide_star} />'
954+ '<svg width={24} class="text-yellow-500" height="1em" viewBox="0 0 24 24" dangerouslySetInnerHTML={__qds_i_lucide_star} />'
843955 ) ;
844956 expect ( result . code ) . toContain (
845- '<svg width={24} class="text-gray-500" viewBox="0 0 24 24" dangerouslySetInnerHTML={__qds_i_lucide_search} />'
957+ '<svg width={24} class="text-gray-500" height="1em" viewBox="0 0 24 24" dangerouslySetInnerHTML={__qds_i_lucide_search} />'
846958 ) ;
847959 expect ( result . code ) . toContain (
848- '<svg width={24} class="text-green-500" viewBox="0 0 24 24" dangerouslySetInnerHTML={__qds_i_heroicons_check_circle} />'
960+ '<svg width={24} class="text-green-500" height="1em" viewBox="0 0 24 24" dangerouslySetInnerHTML={__qds_i_heroicons_check_circle} />'
849961 ) ;
850962 expect ( result . code ) . toContain (
851- '<svg width={24} class="text-red-500" viewBox="0 0 24 24" dangerouslySetInnerHTML={__qds_i_heroicons_x_circle} />'
963+ '<svg width={24} class="text-red-500" height="1em" viewBox="0 0 24 24" dangerouslySetInnerHTML={__qds_i_heroicons_x_circle} />'
852964 ) ;
853965 expect ( result . code ) . toContain (
854- '<svg width={24} class="text-green-500" viewBox="0 0 24 24" dangerouslySetInnerHTML={__qds_i_tabler_check} />'
966+ '<svg width={24} class="text-green-500" height="1em" viewBox="0 0 24 24" dangerouslySetInnerHTML={__qds_i_tabler_check} />'
855967 ) ;
856968
857969 // Validate JSX syntax using oxc-parser
0 commit comments