Skip to content

Commit

Permalink
Merge pull request #156 from czeckd/update-to-ng18
Browse files Browse the repository at this point in the history
Update to ng18
  • Loading branch information
czeckd authored Jun 19, 2024
2 parents 26a64b5 + bef42a6 commit 63e65a8
Show file tree
Hide file tree
Showing 11 changed files with 241 additions and 268 deletions.
2 changes: 1 addition & 1 deletion LICENSE
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
The MIT License (MIT)

Copyright (c) 2023 David Czeck.
Copyright (c) 2024 David Czeck.

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
Expand Down
17 changes: 14 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
Angular SVG Icon
=========

The **angular-svg-icon** is an Angular 17 service and component that provides a
The **angular-svg-icon** is an Angular 18 service and component that provides a
means to inline SVG files to allow for them to be easily styled by CSS and code.

The service provides an icon registery that loads and caches a SVG indexed by
Expand All @@ -18,7 +18,17 @@ This [demo](https://czeckd.github.io/angular-svg-icon/) shows this module in act
```
$ npm i angular-svg-icon --save
```

## Versions

The latest version of the package is for Angular 18.

:grey_exclamation: **BREAKING CHANGE**: as of [email protected], the package was converted to use
`inject` and `signal` from `@common/core` for improved performance. Thus method calls that are inputs
should be avoided. Inputs are now signal inputs.

**Note on earlier versions of Angular:**
- For Angular 17, use [email protected]
- For Angular 16, use [email protected]
- For Angular 15, use [email protected]
- For Angular 14, use [email protected]
Expand Down Expand Up @@ -67,7 +77,7 @@ import { SvgIconComponent, provideAngularSvgIcon } from 'angular-svg-icon';
export class AppModule {}
```

**BREAKING CHANGE**: as of [email protected], an explicit call to `forRoot()`
:grey_exclamation: **BREAKING CHANGE**: as of [email protected], an explicit call to `forRoot()`
must be made on the module's import.

### Child Modules
Expand Down Expand Up @@ -323,5 +333,6 @@ MIT


## Author
- David Czeck [@czeckd](https://github.com/czeckd)
- David Czeck [@czeckd](https://github.com/czeckd) and
[community contributors](https://github.com/czeckd/angular-svg-icon/graphs/contributors). Thank you!

36 changes: 19 additions & 17 deletions angular.json
Original file line number Diff line number Diff line change
Expand Up @@ -48,9 +48,7 @@
"src/styles.scss"
],
"scripts": [],
"extractLicenses": false,
"sourceMap": true,
"optimization": false
"extractLicenses": false
},
"configurations": {
"production": {
Expand All @@ -60,10 +58,7 @@
"with": "src/environments/environment.prod.ts"
}
],
"optimization": true,
"outputHashing": "all",
"sourceMap": false,
"extractLicenses": true,
"budgets": [
{
"type": "initial",
Expand All @@ -75,19 +70,26 @@
"maximumWarning": "6kb"
}
]
}
}
},
"development": {
"optimization": false,
"extractLicenses": false,
"sourceMap": true
}
},
"defaultConfiguration": "production"
},
"serve": {
"builder": "@angular-devkit/build-angular:dev-server",
"options": {
"buildTarget": "svg-icon:build"
},
"configurations": {
"production": {
"buildTarget": "svg-icon:build:production"
}
}
},
"development": {
"buildTarget": "svg-icon:build:development"
}
},
"defaultConfiguration": "development"
},
"extract-i18n": {
"builder": "@angular-devkit/build-angular:extract-i18n",
Expand All @@ -99,7 +101,7 @@
"builder": "@angular-devkit/build-angular:karma",
"options": {
"main": "src/test.ts",
"polyfills": "src/polyfills.ts",
"polyfills": ["src/polyfills.ts"],
"tsConfig": "tsconfig.spec.json",
"karmaConfig": "karma.conf.js",
"assets": [
Expand Down Expand Up @@ -137,13 +139,13 @@
"options": {
"tsConfig": "projects/angular-svg-icon/tsconfig.lib.json",
"project": "projects/angular-svg-icon/ng-package.json"
}
, "configurations": {
},
"configurations": {
"production": {
"tsConfig": "projects/angular-svg-icon/tsconfig.lib.prod.json"
}
}
},
},
"test": {
"builder": "@angular-devkit/build-angular:karma",
"options": {
Expand Down
33 changes: 17 additions & 16 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "svg-icon",
"description": "Angular 17 component and service for inlining SVGs allowing them to be easily styled with CSS.",
"version": "17.0.0",
"description": "Angular 18 component and service for inlining SVGs allowing them to be easily styled with CSS.",
"version": "18.0.0",
"repository": {
"type": "git",
"url": "https://github.com/czeckd/angular-svg-icon.git"
Expand All @@ -15,7 +15,7 @@
],
"scripts": {
"ng": "ng",
"start": "ng serve --configuration production",
"start": "ng serve",
"build": "ng build --configuration production",
"dist": "ng build --configuration production angular-svg-icon && cp README.md LICENSE ./dist/angular-svg-icon/",
"test": "ng test --source-map=false angular-svg-icon",
Expand All @@ -25,31 +25,32 @@
},
"private": true,
"dependencies": {
"@angular/animations": "^17.0.2",
"@angular/common": "^17.0.2",
"@angular/compiler": "^17.0.2",
"@angular/core": "^17.0.2",
"@angular/forms": "^17.0.2",
"@angular/platform-browser": "^17.0.2",
"@angular/platform-browser-dynamic": "^17.0.2",
"@angular/router": "^17.0.2",
"@angular/animations": "^18.0.2",
"@angular/common": "^18.0.2",
"@angular/compiler": "^18.0.2",
"@angular/core": "^18.0.2",
"@angular/forms": "^18.0.2",
"@angular/platform-browser": "^18.0.2",
"@angular/platform-browser-dynamic": "^18.0.2",
"@angular/router": "^18.0.2",
"rxjs": "~6.6.3",
"tslib": "^2.3.1",
"zone.js": "~0.14.2"
},
"devDependencies": {
"@angular-devkit/build-angular": "^17.0.0",
"@angular/cli": "^17.0.0",
"@angular/compiler-cli": "^17.0.2",
"@angular-devkit/build-angular": "^18.0.3",
"@angular/cli": "^18.0.3",
"@angular/compiler-cli": "^18.0.2",
"@types/jasmine": "~4.0.0",
"@types/node": "^12.11.1",
"jasmine-core": "~4.1.0",
"karma": "~6.3.0",
"karma-chrome-launcher": "~3.1.0",
"karma-coverage": "~2.2.0",
"karma-coverage-istanbul-reporter": "^3.0.3",
"karma-jasmine": "~5.0.0",
"karma-jasmine-html-reporter": "~1.7.0",
"ng-packagr": "^17.0.0",
"typescript": "~5.2.2"
"ng-packagr": "^18.0.0",
"typescript": "~5.4.5"
}
}
8 changes: 4 additions & 4 deletions projects/angular-svg-icon/package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "angular-svg-icon",
"description": "Angular 17 component and service for inlining SVGs allowing them to be easily styled with CSS.",
"version": "17.0.0",
"description": "Angular 18 component and service for inlining SVGs allowing them to be easily styled with CSS.",
"version": "18.0.0",
"repository": {
"type": "git",
"url": "https://github.com/czeckd/angular-svg-icon.git"
Expand All @@ -14,8 +14,8 @@
"icon"
],
"peerDependencies": {
"@angular/core": ">=17.0.0",
"@angular/common": ">=17.0.0",
"@angular/core": ">=18.0.0",
"@angular/common": ">=18.0.0",
"rxjs": ">=6.6.3"
},
"dependencies": {
Expand Down
34 changes: 15 additions & 19 deletions projects/angular-svg-icon/src/lib/svg-icon-registry.service.spec.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
import { Inject, Optional, PLATFORM_ID } from '@angular/core';
import { TestBed, getTestBed } from '@angular/core/testing';
import { TestBed } from '@angular/core/testing';
import { DOCUMENT } from '@angular/common';

import { of } from 'rxjs';

import { SvgLoader } from './svg-loader';
import { SvgIconRegistryService } from './svg-icon-registry.service';
import { SERVER_URL, SvgIconRegistryService } from './svg-icon-registry.service';

describe('SvgIconRegistryService', () => {
let service: SvgIconRegistryService;
Expand All @@ -18,75 +17,72 @@ describe('SvgIconRegistryService', () => {
beforeEach(() => {
TestBed.configureTestingModule({
providers: [
{ provide: SvgLoader, userValue: mockSvgLoader },
{ provide: PLATFORM_ID, useValue: 'browser' }
{ provide: SvgLoader, useValue: mockSvgLoader },
{ provide: SERVER_URL, useValue: serverUrl },
SvgIconRegistryService
]
});

service = TestBed.inject(SvgIconRegistryService);
document = TestBed.inject(DOCUMENT);

});

it ('should add svg that does not exist', () => {
service = new SvgIconRegistryService(mockSvgLoader, PLATFORM_ID, serverUrl, document);
const div = document.createElement('DIV');
div.innerHTML = SVG;
const svg = div.querySelector('svg') as SVGElement;

service.addSvg('svg', SVG);

service.getSvgByName('svg').subscribe(data => {
service.getSvgByName('svg')?.subscribe(data => {
expect(data).toEqual(svg);
});

});

it ('should load svg by url', () => {
service = new SvgIconRegistryService(mockSvgLoader, PLATFORM_ID, serverUrl, document);
const div = document.createElement('DIV');
div.innerHTML = SVG;
const svg = div.querySelector('svg') as SVGElement;
mockSvgLoader.getSvg.and.returnValue(of(SVG));

service.loadSvg('http://svg').subscribe(data => {
service.loadSvg('http://svg')?.subscribe(data => {
expect(data).toEqual(svg);
});
});

it ('should load svg only once', () => {
service = new SvgIconRegistryService(mockSvgLoader, PLATFORM_ID, serverUrl, document);
mockSvgLoader.getSvg.and.returnValue(of(SVG));
mockSvgLoader.getSvg.calls.reset();

service.loadSvg('svg').subscribe(data => {});
service.loadSvg('svg').subscribe(data => {});
service.loadSvg('svg')?.subscribe(data => {});
service.loadSvg('svg')?.subscribe(data => {});

expect(mockSvgLoader.getSvg).toHaveBeenCalledTimes(1);
});

it ('should load svg by url and assign name', () => {
service = new SvgIconRegistryService(mockSvgLoader, PLATFORM_ID, serverUrl, document);
const div = document.createElement('DIV');
div.innerHTML = SVG;
const svg = div.querySelector('svg') as SVGElement;
mockSvgLoader.getSvg.and.returnValue(of(SVG));

service.loadSvg('svg', 'sample').subscribe(data => {});
service.loadSvg('svg', 'sample')?.subscribe(data => {});

service.getSvgByName('sample').subscribe(data => {
service.getSvgByName(serverUrl + 'svg')?.subscribe(data => {
expect(data).toEqual(svg);
});
});

it ('should remove svg', () => {
service = new SvgIconRegistryService(mockSvgLoader, PLATFORM_ID, serverUrl, document);
service.addSvg('svg', SVG);

service.unloadSvg('svg');

service.getSvgByName('svg').subscribe(data => {
}, err => {
expect(err).toBe(`No svg with name 'svg' has been loaded`);
service.getSvgByName('svg')?.subscribe({
error: (err) =>
expect(err).toBe(`No svg with name 'svg' has been loaded`)
});
});

Expand Down
26 changes: 7 additions & 19 deletions projects/angular-svg-icon/src/lib/svg-icon-registry.service.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Inject, Injectable, InjectionToken, Optional, PLATFORM_ID, SkipSelf } from '@angular/core';
import { Injectable, InjectionToken, Optional, SkipSelf, inject } from '@angular/core';

import { Observable, of as observableOf, throwError as observableThrowError } from 'rxjs';
import { catchError, finalize, map, share, tap } from 'rxjs/operators';
Expand All @@ -9,19 +9,13 @@ export const SERVER_URL = new InjectionToken<string>('SERVER_URL');

@Injectable()
export class SvgIconRegistryService {
private loader = inject(SvgLoader);
protected serverUrl = inject< string | undefined>(SERVER_URL, {optional: true});
private document = inject(DOCUMENT);

private document: Document;
private iconsByUrl = new Map<string, SVGElement>();
private iconsLoadingByUrl = new Map<string, Observable<SVGElement>>();

constructor(
private loader: SvgLoader,
@Inject(PLATFORM_ID) private platformId: Object,
@Optional() @Inject(SERVER_URL) protected serverUrl: string | undefined,
@Optional() @Inject(DOCUMENT) private _document: any) {
this.document = this._document;
}

/** Add a SVG to the registry by passing a name and the SVG. */
addSvg(name: string, data: string) {
if (!this.iconsByUrl.has(name)) {
Expand Down Expand Up @@ -86,18 +80,12 @@ export class SvgIconRegistryService {
}

export function SVG_ICON_REGISTRY_PROVIDER_FACTORY(
parentRegistry: SvgIconRegistryService,
loader: SvgLoader,
platformId: object,
serverUrl?: string,
document?: any) {
return parentRegistry || new SvgIconRegistryService(loader, platformId, serverUrl, document);
parentRegistry: SvgIconRegistryService) {
return parentRegistry || new SvgIconRegistryService();
}

export const SVG_ICON_REGISTRY_PROVIDER = {
provide: SvgIconRegistryService,
deps: [ [new Optional(), new SkipSelf(), SvgIconRegistryService], SvgLoader, [PLATFORM_ID as InjectionToken<any>],
[new Optional(), SERVER_URL as InjectionToken<string>], [new Optional(), DOCUMENT as InjectionToken<any>]
],
deps: [ [new Optional(), new SkipSelf(), SvgIconRegistryService] ],
useFactory: SVG_ICON_REGISTRY_PROVIDER_FACTORY
};
Loading

0 comments on commit 63e65a8

Please sign in to comment.