Skip to content

Commit

Permalink
feat: allow passing in only icon SVG data to addIcons (#1256)
Browse files Browse the repository at this point in the history
  • Loading branch information
liamdebeasi authored Aug 22, 2023
1 parent 45c04dd commit 1e33313
Show file tree
Hide file tree
Showing 2 changed files with 97 additions and 3 deletions.
70 changes: 69 additions & 1 deletion src/components/icon/test/utils.spec.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { Icon } from '../icon';
import { getName, getSrc, getUrl } from '../utils';
import { addIcons, getIconMap, getName, getSrc, getUrl } from '../utils';


describe('getUrl', () => {
Expand Down Expand Up @@ -82,3 +82,71 @@ describe('getName', () => {
});

});

describe('addIcons', () => {
it('should add an svg to the icon cache', () => {
const testData = 'stubbed data';

expect(getIconMap().get('logo-ionic')).toEqual(undefined);

addIcons({ 'logo-ionic': 'stubbed data' });

expect(getIconMap().get('logo-ionic')).toEqual(testData);
});

it('should add kebab and camel case names to the icon cache', () => {
const logoIonitron = 'stubbed data';

expect(getIconMap().get('logo-ionitron')).toEqual(undefined);
expect(getIconMap().get('logoIonitron')).toEqual(undefined);

addIcons({ logoIonitron });

expect(getIconMap().get('logo-ionitron')).toEqual(logoIonitron);
expect(getIconMap().get('logoIonitron')).toEqual(logoIonitron);
});

it('should map to a name that does not match the svg', () => {
const logoIonitron = 'stubbed data';

expect(getIconMap().get('my-fun-icon')).toEqual(undefined);

addIcons({ 'my-fun-icon': logoIonitron });

expect(getIconMap().get('my-fun-icon')).toEqual(logoIonitron);
});

it('should map to an explicit camel case name', () => {
const logoIonitron = 'stubbed data';

expect(getIconMap().get('myCoolIcon')).toEqual(undefined);

addIcons({ 'myCoolIcon': logoIonitron });

expect(getIconMap().get('myCoolIcon')).toEqual(logoIonitron);
});

it('should not overwrite icons', () => {
const logoA = 'logo a';
const logoB = 'logo b';

expect(getIconMap().get('logo-a')).toEqual(undefined);

addIcons({ 'logo-a': logoB, logoA });

expect(getIconMap().get('logo-a')).toEqual(logoB);
expect(getIconMap().get('logoA')).toEqual(logoA);
});

it('passing kebab case key should not generate a camel case key', () => {
const logoIonitron = 'stubbed data';

expect(getIconMap().get('kebab-key')).toEqual(undefined);
expect(getIconMap().get('kebabKey')).toEqual(undefined);

addIcons({ 'kebab-key': logoIonitron });

expect(getIconMap().get('kebab-key')).toEqual(logoIonitron);
expect(getIconMap().get('kebabKey')).toEqual(undefined);
});
});
30 changes: 28 additions & 2 deletions src/components/icon/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,36 @@ export const getIconMap = (): Map<string, string> => {
};

export const addIcons = (icons: { [name: string]: string; }) => {
const map = getIconMap();
Object.keys(icons).forEach(name => map.set(name, icons[name]));
Object.keys(icons).forEach(name => {
addToIconMap(name, icons[name]);

/**
* Developers can also pass in the SVG object directly
* and Ionicons can map the object to a kebab case name.
* Example: addIcons({ addCircleOutline });
* This will create an "addCircleOutline" entry and
* an "add-circle-outline" entry.
* Usage: <ion-icon name="add-circle-outline"></ion-icon>
* Using name="addCircleOutline" is valid too, but the
* kebab case naming is preferred.
*/
const toKebabCase = name.replace(/([a-z0-9]|(?=[A-Z]))([A-Z])/g, "$1-$2").toLowerCase();
if (name !== toKebabCase) {
addToIconMap(toKebabCase, icons[name]);
}
});
};

const addToIconMap = (name: string, data: any) => {
const map = getIconMap();

if (map.get(name) === undefined) {
map.set(name, data);
} else {
console.warn(`[Ionicons Warning]: Multiple icons were mapped to name "${name}". Ensure that multiple icons are not mapped to the same icon name.`)
}
}


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

0 comments on commit 1e33313

Please sign in to comment.