Skip to content

Commit

Permalink
chore(): sync with main
Browse files Browse the repository at this point in the history
chore(): sync with main
  • Loading branch information
liamdebeasi authored Mar 7, 2023
2 parents 98975ec + c290bea commit 998b920
Show file tree
Hide file tree
Showing 13 changed files with 126 additions and 47 deletions.
6 changes: 5 additions & 1 deletion .github/CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ Please see our [Contributor Code of Conduct](./CODE_OF_CONDUCT.md) for informati
#### Modifying Components

1. Navigate to the `src/components/` directory and open the `icon` component to modify.
2. Make any changes to the icon component and then [preview-changes](#preview-component-changes).
2. Make any changes to the icon component and then [preview the changes](#preview-component-changes).


#### Preview Component Changes
Expand All @@ -64,6 +64,10 @@ TODO -->
3. Please fill out the Pull Request template to the best of your ability and include any issues that are related.


## Updating Documentation

The documentation site for Ionicons is located in the [ionicons-site](https://github.com/ionic-team/ionicons-site) repository.

## License

By contributing your code to the ionic-team/ionicons GitHub Repository, you agree to license your contribution under the MIT license.
45 changes: 45 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,51 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.

## [6.1.3](https://github.com/ionic-team/ionicons/compare/v6.1.2...v6.1.3) (2023-02-09)


### Bug Fixes

* DomParser usage in SSR ([#1180](https://github.com/ionic-team/ionicons/issues/1180)) ([8c412f6](https://github.com/ionic-team/ionicons/commit/8c412f67486d6cc9725de63f0c15b6c6cd8d47ce)), closes [#1179](https://github.com/ionic-team/ionicons/issues/1179)





## [6.1.2](https://github.com/ionic-team/ionicons/compare/v6.1.1...v6.1.2) (2023-02-08)


### Bug Fixes

* **icon:** load base64 data urls ([#1172](https://github.com/ionic-team/ionicons/issues/1172)) ([72f0936](https://github.com/ionic-team/ionicons/commit/72f09369de76b00697437f54d919782307843a87))
* **icon:** md and ios properties are reactive ([#1174](https://github.com/ionic-team/ionicons/issues/1174)) ([65bcbb4](https://github.com/ionic-team/ionicons/commit/65bcbb477734e33901a6f0c650d3f1f2c3084fca)), closes [#802](https://github.com/ionic-team/ionicons/issues/802)





## [6.1.1](https://github.com/ionic-team/ionicons/compare/v6.1.0...v6.1.1) (2023-01-18)


### Bug Fixes

* **icon:** remove <title> during build step ([#1169](https://github.com/ionic-team/ionicons/issues/1169)) ([93b4fa4](https://github.com/ionic-team/ionicons/commit/93b4fa449b0a072b24ef920fe73e1cb04d6f9b43)), closes [#1168](https://github.com/ionic-team/ionicons/issues/1168)





## [6.1.1](https://github.com/ionic-team/ionicons/compare/v6.1.0...v6.1.1) (2023-01-18)


### Bug Fixes

* **icon:** remove <title> during build step ([#1169](https://github.com/ionic-team/ionicons/issues/1169)) ([93b4fa4](https://github.com/ionic-team/ionicons/commit/93b4fa449b0a072b24ef920fe73e1cb04d6f9b43)), closes [#1168](https://github.com/ionic-team/ionicons/issues/1168)





# [6.1.0](https://github.com/ionic-team/ionicons/compare/v6.0.4...v6.1.0) (2023-01-17)


Expand Down
2 changes: 1 addition & 1 deletion lerna.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,5 @@
"packages": [
"./"
],
"version": "6.1.0"
"version": "6.1.3"
}
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "ionicons",
"version": "6.1.0",
"version": "6.1.3",
"description": "Premium icons for Ionic.",
"files": [
"components/",
Expand Down
25 changes: 4 additions & 21 deletions src/components/icon/icon.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,6 @@ import { Build, Component, Element, Host, Prop, State, Watch, h } from '@stencil
import { getSvgContent, ioniconContent } from './request';
import { getName, getUrl, inheritAttributes, isRTL } from './utils';

let parser: DOMParser;

@Component({
tag: 'ion-icon',
assetsDirs: ['svg'],
Expand Down Expand Up @@ -81,7 +79,7 @@ export class Icon {
* @default true
*/
@Prop() sanitize = true;

componentWillLoad() {
this.inheritedAttributes = inheritAttributes(this.el, ['aria-label']);
}
Expand Down Expand Up @@ -127,29 +125,16 @@ export class Icon {
@Watch('name')
@Watch('src')
@Watch('icon')
@Watch('ios')
@Watch('md')
loadIcon() {
if (Build.isBrowser && this.isVisible) {
if (!parser) {
/**
* Create an instance of the DOM parser. This creates a single
* parser instance for the entire app, which is more efficient.
*/
parser = new DOMParser();
}
const url = getUrl(this);

if (url) {
if (ioniconContent.has(url)) {
// sync if it's already loaded
this.svgContent = ioniconContent.get(url);
} else if (url.startsWith('data:')) {
const doc = parser.parseFromString(url, 'text/html');
const svgEl = doc.body.querySelector('svg');
if (svgEl !== null) {
this.svgContent = svgEl.outerHTML;
} else {
this.svgContent = '';
}
} else {
// async if it hasn't been loaded
getSvgContent(url, this.sanitize).then(() => (this.svgContent = ioniconContent.get(url)));
Expand All @@ -165,9 +150,7 @@ export class Icon {
const mode = this.mode || 'md';
const flipRtl =
this.flipRtl ||
(iconName &&
(iconName.indexOf('arrow') > -1 || iconName.indexOf('chevron') > -1) &&
this.flipRtl !== false);
(iconName && (iconName.indexOf('arrow') > -1 || iconName.indexOf('chevron') > -1) && this.flipRtl !== false);

return (
<Host
Expand Down
50 changes: 36 additions & 14 deletions src/components/icon/request.ts
Original file line number Diff line number Diff line change
@@ -1,29 +1,51 @@
import { validateContent } from './validate';
import { isEncodedDataUrl, isSvgDataUrl, validateContent } from './validate';

export const ioniconContent = new Map<string, string>();
const requests = new Map<string, Promise<any>>();

let parser: DOMParser;

export const getSvgContent = (url: string, sanitize: boolean) => {
// see if we already have a request for this url
let req = requests.get(url);

if (!req) {
if (typeof fetch !== 'undefined' && typeof document !== 'undefined') {
// we don't already have a request
req = fetch(url).then((rsp) => {
if (rsp.ok) {
return rsp.text().then((svgContent) => {
if (svgContent && sanitize !== false) {
svgContent = validateContent(svgContent);
}
ioniconContent.set(url, svgContent || '');
});
/**
* If the url is a data url of an svg, then try to parse it
* with the DOMParser. This works with content security policies enabled.
*/
if (isSvgDataUrl(url) && isEncodedDataUrl(url)) {
if (!parser) {
/**
* Create an instance of the DOM parser. This creates a single
* parser instance for the entire app, which is more efficient.
*/
parser = new DOMParser();
}
const doc = parser.parseFromString(url, 'text/html');
const svg = doc.querySelector('svg');
if (svg) {
ioniconContent.set(url, svg.outerHTML);
}
ioniconContent.set(url, '');
});
return Promise.resolve();
} else {
// we don't already have a request
req = fetch(url).then((rsp) => {
if (rsp.ok) {
return rsp.text().then((svgContent) => {
if (svgContent && sanitize !== false) {
svgContent = validateContent(svgContent);
}
ioniconContent.set(url, svgContent || '');
});
}
ioniconContent.set(url, '');
});
// cache for the same requests
requests.set(url, req);
}

// cache for the same requests
requests.set(url, req);
} else {
// set to empty for ssr scenarios and resolve promise
ioniconContent.set(url, '');
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
32 changes: 25 additions & 7 deletions src/components/icon/test/validate.spec.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { isValid } from '../validate';
import { isEncodedDataUrl, isSvgDataUrl, isValid } from '../validate';


describe('isValid', () => {
Expand All @@ -24,9 +24,11 @@ describe('isValid', () => {
});

it('invalid child SCRIPT elm', () => {
const el = { nodeType: 1, nodeName: 'svg', attributes: [], childNodes: [
{ nodeType: 1, nodeName: 'SCRIPT', attributes: [], childNodes: [] }
] } as any;
const el = {
nodeType: 1, nodeName: 'svg', attributes: [], childNodes: [
{ nodeType: 1, nodeName: 'SCRIPT', attributes: [], childNodes: [] }
]
} as any;
expect(isValid(el)).toBe(false);
});

Expand All @@ -41,9 +43,11 @@ describe('isValid', () => {
});

it('is valid SVG elm', () => {
const el = { nodeType: 1, nodeName: 'SVG', attributes: [], childNodes: [
{ nodeType: 1, nodeName: 'line', attributes: [], childNodes: [] }
] } as any;
const el = {
nodeType: 1, nodeName: 'SVG', attributes: [], childNodes: [
{ nodeType: 1, nodeName: 'line', attributes: [], childNodes: [] }
]
} as any;
expect(isValid(el)).toBe(true);
});

Expand All @@ -53,3 +57,17 @@ describe('isValid', () => {
});

});

it('isSvgDataUrl', () => {
expect(isSvgDataUrl('data:image/svg+xml;base64,xxx')).toBe(true);
expect(isSvgDataUrl('data:image/svg+xml;utf8,<svg></svg>')).toBe(true);
expect(isSvgDataUrl('https://example.com/icon.svg')).toBe(false);
expect(isSvgDataUrl('http://example.com/icon.svg')).toBe(false);
});

it('isEncodedDataUrl', () => {
expect(isEncodedDataUrl('data:image/svg+xml;base64,xxx')).toBe(false);
expect(isEncodedDataUrl('data:image/svg+xml;utf8,<svg></svg>')).toBe(true);
expect(isEncodedDataUrl('https://example.com/icon.svg')).toBe(false);
expect(isEncodedDataUrl('http://example.com/icon.svg')).toBe(false);
});
3 changes: 3 additions & 0 deletions src/components/icon/validate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,3 +48,6 @@ export const isValid = (elm: HTMLElement) => {
}
return true;
};

export const isSvgDataUrl = (url: string) => url.startsWith('data:image/svg+xml');
export const isEncodedDataUrl = (url: string) => url.indexOf(';utf8,') !== -1;
4 changes: 4 additions & 0 deletions src/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,10 @@ <h2>Sanitized (shouldn't show)</h2>
<h2>Not Sanitized (should show)</h2>
<ion-icon sanitize="false" src="./assets/no-sanitize.svg"></ion-icon>

<h2>Base64 url</h2>
<ion-icon
src="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyNCIgaGVpZ2h0PSIyNCIgdmlld0JveD0iMCAwIDI0IDI0Ij48cGF0aCBmaWxsPSJub25lIiBkPSJNMCAwaDI0djI0SDBWMHoiLz48cGF0aCBkPSJNMjAgMkg0Yy0xLjEgMC0yIC45LTIgMnYxOGw0LTRoMTRjMS4xIDAgMi0uOSAyLTJWNGMwLTEuMS0uOS0yLTItMnptMCAxNEg2bC0yIDJWNGgxNnYxMnoiLz48L3N2Zz4="></ion-icon>

<p>
<a href="./cheatsheet.html">Cheatsheet</a>
</p>
Expand Down

0 comments on commit 998b920

Please sign in to comment.