mirror of
https://gitlab.com/openstapps/openstapps.git
synced 2026-01-19 16:13:06 +00:00
refactor: migrate to material symbols icon set
This commit is contained in:
57
src/app/util/ion-icon/icon-match.spec.ts
Normal file
57
src/app/util/ion-icon/icon-match.spec.ts
Normal file
@@ -0,0 +1,57 @@
|
||||
/*
|
||||
* Copyright (C) 2022 StApps
|
||||
* This program is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the Free
|
||||
* Software Foundation, version 3.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
/* eslint-disable unicorn/no-null */
|
||||
|
||||
import {matchPropertyContent, matchTagProperties} from './icon-match';
|
||||
|
||||
describe('matchTagProperties', function () {
|
||||
const regex = matchTagProperties('test');
|
||||
|
||||
it('should match html tag content', function () {
|
||||
expect('<test content></test>'.match(regex)).toEqual([' content']);
|
||||
});
|
||||
|
||||
it('should match all tags', function () {
|
||||
expect(
|
||||
'<test content1></test> <test content2></test>'.match(regex),
|
||||
).toEqual([' content1', ' content2']);
|
||||
});
|
||||
|
||||
it('should not match wrong tags', function () {
|
||||
expect('<no content></no>'.match(regex)).toEqual(null);
|
||||
});
|
||||
});
|
||||
|
||||
describe('matchPropertyContent', function () {
|
||||
const regex = matchPropertyContent(['test1', 'test2']);
|
||||
|
||||
it('should match bare literals', function () {
|
||||
expect(`test1="content" test2="content1"`.match(regex)).toEqual([
|
||||
'content',
|
||||
'content1',
|
||||
]);
|
||||
});
|
||||
|
||||
it('should match angular literals', function () {
|
||||
expect(`[test1]="'content'" [test2]="'content1'"`.match(regex)).toEqual([
|
||||
'content',
|
||||
'content1',
|
||||
]);
|
||||
});
|
||||
|
||||
it('should not match wrong literals', function () {
|
||||
expect(`no="content" [no]="'content'"`.match(regex)).toEqual(null);
|
||||
});
|
||||
});
|
||||
33
src/app/util/ion-icon/icon-match.ts
Normal file
33
src/app/util/ion-icon/icon-match.ts
Normal file
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
* Copyright (C) 2022 StApps
|
||||
* This program is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the Free
|
||||
* Software Foundation, version 3.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
export function matchTagProperties(tag: string) {
|
||||
return new RegExp(`(?<=<${tag})[\\s\\S]*?(?=><\\/${tag}>)`, 'g');
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
export function matchPropertyContent(properties: string[]) {
|
||||
const names = properties.join('|');
|
||||
|
||||
return new RegExp(
|
||||
`((?<=(${names})=")[\\w-]+(?="))|((?<=\\[(${names})]="')[\\w-]+(?='"))`,
|
||||
'g',
|
||||
);
|
||||
}
|
||||
48
src/app/util/ion-icon/icon.component.ts
Normal file
48
src/app/util/ion-icon/icon.component.ts
Normal file
@@ -0,0 +1,48 @@
|
||||
/*
|
||||
* Copyright (C) 2022 StApps
|
||||
* This program is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the Free
|
||||
* Software Foundation, version 3.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import {Component, HostBinding, Input} from '@angular/core';
|
||||
|
||||
@Component({
|
||||
selector: 'stapps-icon',
|
||||
templateUrl: 'icon.html',
|
||||
styleUrls: ['icon.scss'],
|
||||
})
|
||||
export class IconComponent {
|
||||
@HostBinding('style.--size')
|
||||
@Input()
|
||||
size?: number;
|
||||
|
||||
@HostBinding('style.--weight')
|
||||
@Input()
|
||||
weight?: number;
|
||||
|
||||
@HostBinding('style.--grade')
|
||||
@Input()
|
||||
grade?: number;
|
||||
|
||||
@Input()
|
||||
fill: boolean;
|
||||
|
||||
@HostBinding('innerHtml')
|
||||
@Input()
|
||||
name: string;
|
||||
|
||||
@HostBinding('style.--fill') get fillStyle(): number | undefined {
|
||||
return this.fill ? 1 : undefined;
|
||||
}
|
||||
|
||||
@HostBinding('class.material-symbols-rounded') hostClass = true;
|
||||
}
|
||||
15
src/app/util/ion-icon/icon.html
Normal file
15
src/app/util/ion-icon/icon.html
Normal file
@@ -0,0 +1,15 @@
|
||||
<!--
|
||||
~ Copyright (C) 2022 StApps
|
||||
~ This program is free software: you can redistribute it and/or modify it
|
||||
~ under the terms of the GNU General Public License as published by the Free
|
||||
~ Software Foundation, version 3.
|
||||
~
|
||||
~ This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
~ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
~ FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
~ more details.
|
||||
~
|
||||
~ You should have received a copy of the GNU General Public License along with
|
||||
~ this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
-->
|
||||
<ng-content></ng-content>
|
||||
26
src/app/util/ion-icon/icon.scss
Normal file
26
src/app/util/ion-icon/icon.scss
Normal file
@@ -0,0 +1,26 @@
|
||||
/*!
|
||||
* Copyright (C) 2022 StApps
|
||||
* This program is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the Free
|
||||
* Software Foundation, version 3.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
:host {
|
||||
font-variation-settings: 'wght' var(--weight), 'GRAD' var(--grade), 'FILL' var(--fill);
|
||||
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
font-size: inherit;
|
||||
transition: all 0.2s ease-in-out;
|
||||
}
|
||||
24
src/app/util/ion-icon/icon.ts
Normal file
24
src/app/util/ion-icon/icon.ts
Normal file
@@ -0,0 +1,24 @@
|
||||
/*
|
||||
* Copyright (C) 2022 StApps
|
||||
* This program is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the Free
|
||||
* Software Foundation, version 3.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/**
|
||||
* A noop function to aid parsing icon names
|
||||
*/
|
||||
export function SCIcon(
|
||||
strings: TemplateStringsArray,
|
||||
..._keys: string[]
|
||||
): string {
|
||||
return strings.join('');
|
||||
}
|
||||
35
src/app/util/ion-icon/ion-back-button.directive.ts
Normal file
35
src/app/util/ion-icon/ion-back-button.directive.ts
Normal file
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
* Copyright (C) 2022 StApps
|
||||
* This program is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the Free
|
||||
* Software Foundation, version 3.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import {Directive, ElementRef, ViewContainerRef} from '@angular/core';
|
||||
import {SCIcon} from './icon';
|
||||
import {IconReplacer} from './replace-util';
|
||||
|
||||
@Directive({
|
||||
selector: 'ion-back-button',
|
||||
})
|
||||
export class IonBackButtonDirective extends IconReplacer {
|
||||
constructor(element: ElementRef, viewContainerRef: ViewContainerRef) {
|
||||
super(element, viewContainerRef, 'shadow');
|
||||
}
|
||||
|
||||
replace() {
|
||||
this.replaceIcon(this.host.querySelector('.button-inner'), {
|
||||
md: SCIcon`arrow_back`,
|
||||
ios: SCIcon`arrow_back_ios`,
|
||||
size: 24,
|
||||
});
|
||||
}
|
||||
}
|
||||
37
src/app/util/ion-icon/ion-breadcrumb.directive.ts
Normal file
37
src/app/util/ion-icon/ion-breadcrumb.directive.ts
Normal file
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
* Copyright (C) 2022 StApps
|
||||
* This program is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the Free
|
||||
* Software Foundation, version 3.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import {Directive, ElementRef, ViewContainerRef} from '@angular/core';
|
||||
import {SCIcon} from './icon';
|
||||
import {IconReplacer} from './replace-util';
|
||||
|
||||
@Directive({
|
||||
selector: 'ion-breadcrumb',
|
||||
})
|
||||
export class IonBreadcrumbDirective extends IconReplacer {
|
||||
constructor(element: ElementRef, viewContainerRef: ViewContainerRef) {
|
||||
super(element, viewContainerRef, 'shadow');
|
||||
}
|
||||
|
||||
replace() {
|
||||
this.replaceIcon(
|
||||
this.host.querySelector('button[part="collapsed-indicator"]'),
|
||||
{
|
||||
name: SCIcon`more_horiz`,
|
||||
size: 24,
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
133
src/app/util/ion-icon/ion-icon.directive.ts
Normal file
133
src/app/util/ion-icon/ion-icon.directive.ts
Normal file
@@ -0,0 +1,133 @@
|
||||
/*
|
||||
* Copyright (C) 2022 StApps
|
||||
* This program is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the Free
|
||||
* Software Foundation, version 3.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import {
|
||||
ComponentRef,
|
||||
Directive,
|
||||
ElementRef,
|
||||
Host,
|
||||
Input,
|
||||
OnChanges,
|
||||
OnDestroy,
|
||||
OnInit,
|
||||
Optional,
|
||||
Self,
|
||||
ViewContainerRef,
|
||||
} from '@angular/core';
|
||||
import {IconComponent} from './icon.component';
|
||||
import {IonIcon} from '@ionic/angular';
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-empty-function
|
||||
const noop = () => {};
|
||||
const noopProperty = {
|
||||
set: noop,
|
||||
get: noop,
|
||||
};
|
||||
|
||||
@Directive({
|
||||
selector: 'ion-icon',
|
||||
})
|
||||
export class IonIconDirective implements OnInit, OnDestroy, OnChanges {
|
||||
@Input() name: string;
|
||||
|
||||
@Input() md: string;
|
||||
|
||||
@Input() ios: string;
|
||||
|
||||
@Input() fill = false;
|
||||
|
||||
@Input() weight: number;
|
||||
|
||||
@Input() size: number;
|
||||
|
||||
@Input() grade: number;
|
||||
|
||||
private mutationObserver: MutationObserver;
|
||||
|
||||
iconComponent?: ComponentRef<IconComponent>;
|
||||
|
||||
private static get mode(): 'md' | 'ios' {
|
||||
return document.querySelector(':root')?.getAttribute('mode') as
|
||||
| 'md'
|
||||
| 'ios';
|
||||
}
|
||||
|
||||
constructor(
|
||||
private element: ElementRef,
|
||||
private viewContainerRef: ViewContainerRef,
|
||||
@Host() @Self() @Optional() private ionIcon: IonIcon,
|
||||
) {}
|
||||
|
||||
ngOnInit() {
|
||||
this.iconComponent = this.viewContainerRef.createComponent(
|
||||
IconComponent,
|
||||
{},
|
||||
);
|
||||
|
||||
this.element.nativeElement.insertBefore(
|
||||
this.iconComponent.location.nativeElement,
|
||||
this.element.nativeElement.firstChild,
|
||||
);
|
||||
|
||||
this.mutationObserver = new MutationObserver(() => {
|
||||
const inner =
|
||||
this.element.nativeElement.shadowRoot.querySelector('.icon-inner');
|
||||
if (!inner) return;
|
||||
|
||||
inner.insertBefore(document.createElement('slot'), inner.firstChild);
|
||||
});
|
||||
this.mutationObserver.observe(this.element.nativeElement.shadowRoot, {
|
||||
childList: true,
|
||||
});
|
||||
|
||||
this.ngOnChanges();
|
||||
// this will effectively completely disable the ion-icon component
|
||||
for (const name of ['src', 'name', 'icon', 'md', 'ios']) {
|
||||
this.disableProperty(name);
|
||||
}
|
||||
}
|
||||
|
||||
ngOnDestroy() {
|
||||
this.mutationObserver.disconnect();
|
||||
}
|
||||
|
||||
ngOnChanges() {
|
||||
if (!this.iconComponent) return;
|
||||
for (const key of ['name', 'weight', 'fill', 'size', 'grade'] as Array<
|
||||
keyof IconComponent & keyof IonIconDirective
|
||||
>) {
|
||||
// @ts-expect-error type mismatch
|
||||
this.iconComponent.instance[key] = this[key];
|
||||
}
|
||||
|
||||
for (const mode of ['md', 'ios'] as Array<'md' | 'ios'>) {
|
||||
if (this[mode] && IonIconDirective.mode === mode) {
|
||||
this.iconComponent.instance.name = this[mode];
|
||||
}
|
||||
}
|
||||
|
||||
if (this.size) {
|
||||
this.element.nativeElement.style.cssText = `font-size: ${this.size}px;`;
|
||||
}
|
||||
}
|
||||
|
||||
disableProperty(name: string) {
|
||||
Object.defineProperty(
|
||||
Object.getPrototypeOf((this.ionIcon as unknown as {el: HTMLElement}).el),
|
||||
name,
|
||||
noopProperty,
|
||||
);
|
||||
}
|
||||
}
|
||||
38
src/app/util/ion-icon/ion-icon.module.ts
Normal file
38
src/app/util/ion-icon/ion-icon.module.ts
Normal file
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
* Copyright (C) 2022 StApps
|
||||
* This program is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the Free
|
||||
* Software Foundation, version 3.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import {NgModule} from '@angular/core';
|
||||
import {IconComponent} from './icon.component';
|
||||
import {IonIconDirective} from './ion-icon.directive';
|
||||
import {IonBackButtonDirective} from './ion-back-button.directive';
|
||||
import {IonSearchbarDirective} from './ion-searchbar.directive';
|
||||
import {IonBreadcrumbDirective} from './ion-breadcrumb.directive';
|
||||
|
||||
@NgModule({
|
||||
declarations: [
|
||||
IconComponent,
|
||||
IonIconDirective,
|
||||
IonBackButtonDirective,
|
||||
IonSearchbarDirective,
|
||||
IonBreadcrumbDirective,
|
||||
],
|
||||
exports: [
|
||||
IonIconDirective,
|
||||
IonBackButtonDirective,
|
||||
IonSearchbarDirective,
|
||||
IonBreadcrumbDirective,
|
||||
],
|
||||
})
|
||||
export class IonIconModule {}
|
||||
37
src/app/util/ion-icon/ion-searchbar.directive.ts
Normal file
37
src/app/util/ion-icon/ion-searchbar.directive.ts
Normal file
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
* Copyright (C) 2022 StApps
|
||||
* This program is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the Free
|
||||
* Software Foundation, version 3.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
import {Directive, ElementRef, ViewContainerRef} from '@angular/core';
|
||||
import {SCIcon} from './icon';
|
||||
import {IconReplacer} from './replace-util';
|
||||
|
||||
@Directive({
|
||||
selector: 'ion-searchbar',
|
||||
})
|
||||
export class IonSearchbarDirective extends IconReplacer {
|
||||
constructor(element: ElementRef, viewContainerRef: ViewContainerRef) {
|
||||
super(element, viewContainerRef, 'light');
|
||||
}
|
||||
|
||||
replace() {
|
||||
this.replaceIcon(this.host.querySelector('.searchbar-input-container'), {
|
||||
name: SCIcon`search`,
|
||||
size: 24,
|
||||
});
|
||||
this.replaceIcon(this.host.querySelector('.searchbar-clear-button'), {
|
||||
name: SCIcon`close`,
|
||||
size: 24,
|
||||
});
|
||||
}
|
||||
}
|
||||
145
src/app/util/ion-icon/replace-util.ts
Normal file
145
src/app/util/ion-icon/replace-util.ts
Normal file
@@ -0,0 +1,145 @@
|
||||
/*
|
||||
* Copyright (C) 2022 StApps
|
||||
* This program is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the Free
|
||||
* Software Foundation, version 3.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import {
|
||||
ComponentRef,
|
||||
Directive,
|
||||
ElementRef,
|
||||
OnDestroy,
|
||||
OnInit,
|
||||
ViewContainerRef,
|
||||
} from '@angular/core';
|
||||
import {IonIcon} from '@ionic/angular';
|
||||
import {IonIconDirective} from './ion-icon.directive';
|
||||
|
||||
export type IconData = Omit<
|
||||
Partial<IonIconDirective>,
|
||||
| 'ngOnChanges'
|
||||
| 'ngOnInit'
|
||||
| 'viewContainerRef'
|
||||
| 'ngOnDestroy'
|
||||
| 'element'
|
||||
| 'ionIcon'
|
||||
| 'disableProperty'
|
||||
>;
|
||||
|
||||
/**
|
||||
* A utility class to replace ion-icons in other ionic components.
|
||||
*/
|
||||
@Directive()
|
||||
export abstract class IconReplacer implements OnInit, OnDestroy {
|
||||
private mutationObserver: MutationObserver;
|
||||
|
||||
protected slotName = 'sc-icon';
|
||||
|
||||
/**
|
||||
* The host element
|
||||
*
|
||||
* This will be either element.nativeElement.shadowRoot or element.nativeElement
|
||||
* depending on the iconDomLocation
|
||||
*/
|
||||
protected host: HTMLElement;
|
||||
|
||||
/**
|
||||
* @param element The host element
|
||||
* @param viewContainerRef The view container ref
|
||||
* @param iconDomLocation If the icon is placed inside the shadow dom or not
|
||||
* @protected
|
||||
*/
|
||||
protected constructor(
|
||||
private readonly element: ElementRef,
|
||||
private readonly viewContainerRef: ViewContainerRef,
|
||||
private readonly iconDomLocation: 'shadow' | 'light',
|
||||
) {}
|
||||
|
||||
/**
|
||||
* Replace the icons here
|
||||
*/
|
||||
abstract replace(): void;
|
||||
|
||||
/**
|
||||
* If any additional work needs to be done, this
|
||||
* is called during ngOnInit
|
||||
*/
|
||||
init() {
|
||||
// noop
|
||||
}
|
||||
|
||||
/**
|
||||
* If you need to do cleanup, this method is called during ngOnDestroy
|
||||
*/
|
||||
destroy() {
|
||||
// noop
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
this.host =
|
||||
this.iconDomLocation === 'shadow'
|
||||
? this.element.nativeElement.shadowRoot
|
||||
: this.element.nativeElement;
|
||||
|
||||
this.init();
|
||||
|
||||
this.mutationObserver = new MutationObserver(() => this.replace());
|
||||
this.mutationObserver.observe(this.host, {
|
||||
childList: true,
|
||||
});
|
||||
}
|
||||
|
||||
replaceIcon(parent: HTMLElement | null, iconData: IconData) {
|
||||
if (!parent) return;
|
||||
|
||||
const icon = parent.querySelector('ion-icon');
|
||||
if (!icon) return;
|
||||
|
||||
const scIcon = this.createIcon(iconData);
|
||||
// @ts-expect-error can be spread
|
||||
scIcon.location.nativeElement.classList.add(...icon.classList);
|
||||
|
||||
if (this.iconDomLocation === 'shadow') {
|
||||
// shadow dom needs to utilize slotting, to put it outside
|
||||
// the shadow dom, otherwise it won't receive any css data
|
||||
const slot = document.createElement('slot');
|
||||
slot.name = this.slotName;
|
||||
icon.replaceWith(slot);
|
||||
|
||||
scIcon.location.nativeElement.slot = this.slotName;
|
||||
this.element.nativeElement.append(scIcon.location.nativeElement);
|
||||
} else {
|
||||
icon.replaceWith(scIcon.location.nativeElement);
|
||||
}
|
||||
}
|
||||
|
||||
private createIcon(iconData: IconData): ComponentRef<IonIcon> {
|
||||
const ionIcon = this.viewContainerRef.createComponent(IonIcon, {});
|
||||
const iconDirective = new IonIconDirective(
|
||||
ionIcon.location,
|
||||
this.viewContainerRef,
|
||||
ionIcon.instance,
|
||||
);
|
||||
for (const key in iconData) {
|
||||
// @ts-expect-error type mismatch
|
||||
iconDirective[key] = iconData[key];
|
||||
}
|
||||
iconDirective.ngOnInit();
|
||||
|
||||
return ionIcon;
|
||||
}
|
||||
|
||||
ngOnDestroy() {
|
||||
this.mutationObserver.disconnect();
|
||||
this.destroy();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user