-
Notifications
You must be signed in to change notification settings - Fork 23
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #460 from christophercr/feature/viewbox-directive
feat(stark-ui): implement SvgViewBox directive to enable resizing of Angular Material's mat-icon directive
- Loading branch information
Showing
10 changed files
with
246 additions
and
5 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1,2 @@ | ||
export * from "./modules/app-logo"; | ||
export * from "./modules/svg-view-box"; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
export * from "./svg-view-box/svg-view-box.module"; | ||
export * from "./svg-view-box/directives"; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
export * from "./directives/svg-view-box.directive"; |
123 changes: 123 additions & 0 deletions
123
packages/stark-ui/src/modules/svg-view-box/directives/svg-view-box.directive.spec.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,123 @@ | ||
/*tslint:disable:completed-docs*/ | ||
import { ComponentFixture, fakeAsync, TestBed } from "@angular/core/testing"; | ||
import { StarkSvgViewBoxDirective } from "./svg-view-box.directive"; | ||
import { Component, DebugElement, NO_ERRORS_SCHEMA } from "@angular/core"; | ||
import { By } from "@angular/platform-browser"; | ||
|
||
describe("SvgViewBoxDirective", () => { | ||
@Component({ | ||
selector: "test-component", | ||
template: getTemplate("starkSvgViewBox") | ||
}) | ||
class TestComponent {} | ||
|
||
let fixture: ComponentFixture<TestComponent>; | ||
|
||
function getTemplate(svgViewBoxDirective: string, viewBoxAttribute?: string): string { | ||
return ( | ||
"<div " + | ||
svgViewBoxDirective + | ||
"><svg xmlns='http://www.w3.org/2000/svg' " + | ||
viewBoxAttribute + | ||
">" + | ||
"<text font-size='8' font-family='serif' y='6'><![CDATA[dummy icon]]></text>" + | ||
"</svg></div>" | ||
); | ||
} | ||
|
||
function initializeComponentFixture(): void { | ||
fixture = TestBed.createComponent(TestComponent); | ||
// trigger initial data binding | ||
fixture.detectChanges(); | ||
} | ||
|
||
beforeEach(() => { | ||
TestBed.configureTestingModule({ | ||
declarations: [StarkSvgViewBoxDirective, TestComponent], | ||
schemas: [NO_ERRORS_SCHEMA] | ||
}); | ||
}); | ||
|
||
describe("when viewBox value is not defined", () => { | ||
beforeEach( | ||
fakeAsync(() => { | ||
// compile template and css | ||
return TestBed.compileComponents(); | ||
}) | ||
); | ||
|
||
beforeEach(() => { | ||
initializeComponentFixture(); | ||
}); | ||
|
||
it("should add the default values to the viewBox attribute of the svg element", () => { | ||
expect(fixture).toBeDefined(); | ||
const parentElement: DebugElement = fixture.debugElement.query(By.directive(StarkSvgViewBoxDirective)); | ||
expect(parentElement).toBeDefined(); | ||
const svgElement: SVGElement = parentElement.nativeElement.querySelector("svg"); | ||
expect(svgElement).toBeDefined(); | ||
expect(svgElement.hasAttribute("viewBox")).toBe(true); | ||
expect(svgElement.getAttribute("viewBox")).toBe("0 0 24 24"); | ||
}); | ||
}); | ||
|
||
describe("when viewBox value is given", () => { | ||
const viewBoxValue: number = 48; | ||
|
||
// overriding the components's template | ||
beforeEach( | ||
fakeAsync(() => { | ||
const newTemplate: string = getTemplate("starkSvgViewBox='" + viewBoxValue + "'"); | ||
|
||
TestBed.overrideTemplate(TestComponent, newTemplate); | ||
|
||
// compile template and css | ||
return TestBed.compileComponents(); | ||
}) | ||
); | ||
|
||
beforeEach(() => { | ||
initializeComponentFixture(); | ||
}); | ||
|
||
it("should add the provided value as the width and height of the viewBox attribute of the svg element", () => { | ||
expect(fixture).toBeDefined(); | ||
const parentElement: DebugElement = fixture.debugElement.query(By.directive(StarkSvgViewBoxDirective)); | ||
expect(parentElement).toBeDefined(); | ||
const svgElement: SVGElement = parentElement.nativeElement.querySelector("svg"); | ||
expect(svgElement).toBeDefined(); | ||
expect(svgElement.hasAttribute("viewBox")).toBe(true); | ||
expect(svgElement.getAttribute("viewBox")).toBe(`0 0 ${viewBoxValue} ${viewBoxValue}`); | ||
}); | ||
}); | ||
|
||
describe("when SVG has already the viewBox attribute", () => { | ||
const viewBoxAttribute: string = "0 0 12 12"; | ||
|
||
// overriding the components's template | ||
beforeEach( | ||
fakeAsync(() => { | ||
const newTemplate: string = getTemplate("starkSvgViewBox", "viewBox='" + viewBoxAttribute + "'"); | ||
|
||
TestBed.overrideTemplate(TestComponent, newTemplate); | ||
|
||
// compile template and css | ||
return TestBed.compileComponents(); | ||
}) | ||
); | ||
|
||
beforeEach(() => { | ||
initializeComponentFixture(); | ||
}); | ||
|
||
it("should keep the viewBox attribute as is", () => { | ||
expect(fixture).toBeDefined(); | ||
const parentElement: DebugElement = fixture.debugElement.query(By.directive(StarkSvgViewBoxDirective)); | ||
expect(parentElement).toBeDefined(); | ||
const svgElement: SVGElement = parentElement.nativeElement.querySelector("svg"); | ||
expect(svgElement).toBeDefined(); | ||
expect(svgElement.hasAttribute("viewBox")).toBe(true); | ||
expect(svgElement.getAttribute("viewBox")).toBe(viewBoxAttribute); | ||
}); | ||
}); | ||
}); |
60 changes: 60 additions & 0 deletions
60
packages/stark-ui/src/modules/svg-view-box/directives/svg-view-box.directive.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,60 @@ | ||
import { AfterViewChecked, Directive, ElementRef, Input, Renderer2 } from "@angular/core"; | ||
|
||
/** | ||
* Name of the directive | ||
*/ | ||
const directiveName: string = "[starkSvgViewBox]"; | ||
|
||
@Directive({ | ||
selector: directiveName | ||
}) | ||
/** | ||
* Directive to add the 'viewBox' attribute to an SVG element. | ||
* Specially useful to fix the issue with the Angular Material's MatIcon directive which prevents the icons from | ||
* being re-sized via CSS due to the 'viewBox' property not being added to the SVG element. | ||
* @link https://github.com/angular/material2/issues/4422 | ||
* @link https://github.com/angular/material2/issues/5488 | ||
*/ | ||
export class StarkSvgViewBoxDirective implements AfterViewChecked { | ||
/** | ||
* Width and height to be set to the 'viewBox' attribute of the SVG element. | ||
*/ | ||
/* tslint:disable:no-input-rename */ | ||
@Input("starkSvgViewBox") private viewBoxSize: number; | ||
|
||
/** | ||
* Default value for the width and height of the 'viewBox' attribute if it is not given as an input. | ||
*/ | ||
private defaultViewBoxSize: number = 24; | ||
|
||
/** | ||
* SVG element to which the viewBox attribute should be added. | ||
*/ | ||
private svgIcon?: SVGElement; | ||
|
||
/** | ||
* Class constructor | ||
* @param element - Reference to the DOM element where this directive is applied to. | ||
* @param renderer - Angular Renderer wrapper for DOM manipulations. | ||
*/ | ||
public constructor(public element: ElementRef<HTMLElement>, public renderer: Renderer2) {} | ||
|
||
/** | ||
* Directive lifecycle hook | ||
*/ | ||
public ngAfterViewChecked(): void { | ||
// the svg icon inside the <mat-icon> is only present at this point | ||
// ensure that this should be set only once since the ngAfterViewChecked is triggered continuously | ||
if (!this.svgIcon) { | ||
this.svgIcon = this.element.nativeElement.querySelector("svg") || undefined; | ||
this.viewBoxSize = this.viewBoxSize || this.defaultViewBoxSize; | ||
|
||
// set the "viewBox" attribute only if the SVG element doesn't have any defined | ||
if (this.svgIcon && !this.svgIcon.hasAttribute("viewBox")) { | ||
// viewBox value: the points "seen" in the SVG drawing area. Four values separated by white space or commas. (min x, min y, width, height) | ||
const viewBoxValue: string = `0 0 ${this.viewBoxSize} ${this.viewBoxSize}`; | ||
this.renderer.setAttribute(this.svgIcon, "viewBox", viewBoxValue); | ||
} | ||
} | ||
} | ||
} |
8 changes: 8 additions & 0 deletions
8
packages/stark-ui/src/modules/svg-view-box/svg-view-box.module.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
import { NgModule } from "@angular/core"; | ||
import { StarkSvgViewBoxDirective } from "./directives"; | ||
|
||
@NgModule({ | ||
declarations: [StarkSvgViewBoxDirective], | ||
exports: [StarkSvgViewBoxDirective] | ||
}) | ||
export class StarkSvgViewBoxModule {} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters