Skip to content

Commit 1e33313

Browse files
authored
feat: allow passing in only icon SVG data to addIcons (#1256)
1 parent 45c04dd commit 1e33313

File tree

2 files changed

+97
-3
lines changed

2 files changed

+97
-3
lines changed

src/components/icon/test/utils.spec.ts

Lines changed: 69 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { Icon } from '../icon';
2-
import { getName, getSrc, getUrl } from '../utils';
2+
import { addIcons, getIconMap, getName, getSrc, getUrl } from '../utils';
33

44

55
describe('getUrl', () => {
@@ -82,3 +82,71 @@ describe('getName', () => {
8282
});
8383

8484
});
85+
86+
describe('addIcons', () => {
87+
it('should add an svg to the icon cache', () => {
88+
const testData = 'stubbed data';
89+
90+
expect(getIconMap().get('logo-ionic')).toEqual(undefined);
91+
92+
addIcons({ 'logo-ionic': 'stubbed data' });
93+
94+
expect(getIconMap().get('logo-ionic')).toEqual(testData);
95+
});
96+
97+
it('should add kebab and camel case names to the icon cache', () => {
98+
const logoIonitron = 'stubbed data';
99+
100+
expect(getIconMap().get('logo-ionitron')).toEqual(undefined);
101+
expect(getIconMap().get('logoIonitron')).toEqual(undefined);
102+
103+
addIcons({ logoIonitron });
104+
105+
expect(getIconMap().get('logo-ionitron')).toEqual(logoIonitron);
106+
expect(getIconMap().get('logoIonitron')).toEqual(logoIonitron);
107+
});
108+
109+
it('should map to a name that does not match the svg', () => {
110+
const logoIonitron = 'stubbed data';
111+
112+
expect(getIconMap().get('my-fun-icon')).toEqual(undefined);
113+
114+
addIcons({ 'my-fun-icon': logoIonitron });
115+
116+
expect(getIconMap().get('my-fun-icon')).toEqual(logoIonitron);
117+
});
118+
119+
it('should map to an explicit camel case name', () => {
120+
const logoIonitron = 'stubbed data';
121+
122+
expect(getIconMap().get('myCoolIcon')).toEqual(undefined);
123+
124+
addIcons({ 'myCoolIcon': logoIonitron });
125+
126+
expect(getIconMap().get('myCoolIcon')).toEqual(logoIonitron);
127+
});
128+
129+
it('should not overwrite icons', () => {
130+
const logoA = 'logo a';
131+
const logoB = 'logo b';
132+
133+
expect(getIconMap().get('logo-a')).toEqual(undefined);
134+
135+
addIcons({ 'logo-a': logoB, logoA });
136+
137+
expect(getIconMap().get('logo-a')).toEqual(logoB);
138+
expect(getIconMap().get('logoA')).toEqual(logoA);
139+
});
140+
141+
it('passing kebab case key should not generate a camel case key', () => {
142+
const logoIonitron = 'stubbed data';
143+
144+
expect(getIconMap().get('kebab-key')).toEqual(undefined);
145+
expect(getIconMap().get('kebabKey')).toEqual(undefined);
146+
147+
addIcons({ 'kebab-key': logoIonitron });
148+
149+
expect(getIconMap().get('kebab-key')).toEqual(logoIonitron);
150+
expect(getIconMap().get('kebabKey')).toEqual(undefined);
151+
});
152+
});

src/components/icon/utils.ts

Lines changed: 28 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,10 +18,36 @@ export const getIconMap = (): Map<string, string> => {
1818
};
1919

2020
export const addIcons = (icons: { [name: string]: string; }) => {
21-
const map = getIconMap();
22-
Object.keys(icons).forEach(name => map.set(name, icons[name]));
21+
Object.keys(icons).forEach(name => {
22+
addToIconMap(name, icons[name]);
23+
24+
/**
25+
* Developers can also pass in the SVG object directly
26+
* and Ionicons can map the object to a kebab case name.
27+
* Example: addIcons({ addCircleOutline });
28+
* This will create an "addCircleOutline" entry and
29+
* an "add-circle-outline" entry.
30+
* Usage: <ion-icon name="add-circle-outline"></ion-icon>
31+
* Using name="addCircleOutline" is valid too, but the
32+
* kebab case naming is preferred.
33+
*/
34+
const toKebabCase = name.replace(/([a-z0-9]|(?=[A-Z]))([A-Z])/g, "$1-$2").toLowerCase();
35+
if (name !== toKebabCase) {
36+
addToIconMap(toKebabCase, icons[name]);
37+
}
38+
});
2339
};
2440

41+
const addToIconMap = (name: string, data: any) => {
42+
const map = getIconMap();
43+
44+
if (map.get(name) === undefined) {
45+
map.set(name, data);
46+
} else {
47+
console.warn(`[Ionicons Warning]: Multiple icons were mapped to name "${name}". Ensure that multiple icons are not mapped to the same icon name.`)
48+
}
49+
}
50+
2551

2652
export const getUrl = (i: Icon) => {
2753
let url = getSrc(i.src);

0 commit comments

Comments
 (0)