Skip to content

Commit

Permalink
feat: support Angular RouterLink
Browse files Browse the repository at this point in the history
  • Loading branch information
jeripeierSBB committed Jan 21, 2025
1 parent 71aef5f commit 4ad86a2
Show file tree
Hide file tree
Showing 17 changed files with 77 additions and 28 deletions.
4 changes: 2 additions & 2 deletions src/angular/breadcrumb/breadcrumb/breadcrumb.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { Directive, ElementRef, inject, Input, NgZone } from '@angular/core';
import { booleanAttribute } from '@sbb-esta/lyne-angular/core';
import { booleanAttribute, SbbRouterLinkSupportMixin } from '@sbb-esta/lyne-angular/core';
import type { SbbBreadcrumbElement } from '@sbb-esta/lyne-elements/breadcrumb/breadcrumb.js';
import { LinkTargetType } from '@sbb-esta/lyne-elements/core/base-elements.js';

Expand All @@ -8,7 +8,7 @@ import '@sbb-esta/lyne-elements/breadcrumb/breadcrumb.js';
@Directive({
selector: 'sbb-breadcrumb',
})
export class SbbBreadcrumb {
export class SbbBreadcrumb extends SbbRouterLinkSupportMixin(class {}) {
#element: ElementRef<SbbBreadcrumbElement> = inject(ElementRef<SbbBreadcrumbElement>);
#ngZone: NgZone = inject(NgZone);

Expand Down
4 changes: 2 additions & 2 deletions src/angular/button/accent-button-link/accent-button-link.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { Directive, ElementRef, inject, Input, NgZone } from '@angular/core';
import { booleanAttribute } from '@sbb-esta/lyne-angular/core';
import { booleanAttribute, SbbRouterLinkSupportMixin } from '@sbb-esta/lyne-angular/core';
import type { SbbAccentButtonLinkElement } from '@sbb-esta/lyne-elements/button/accent-button-link.js';
import { SbbButtonSize } from '@sbb-esta/lyne-elements/button.js';
import { LinkTargetType } from '@sbb-esta/lyne-elements/core/base-elements.js';
Expand All @@ -9,7 +9,7 @@ import '@sbb-esta/lyne-elements/button/accent-button-link.js';
@Directive({
selector: 'sbb-accent-button-link',
})
export class SbbAccentButtonLink {
export class SbbAccentButtonLink extends SbbRouterLinkSupportMixin(class {}) {
#element: ElementRef<SbbAccentButtonLinkElement> = inject(ElementRef<SbbAccentButtonLinkElement>);
#ngZone: NgZone = inject(NgZone);

Expand Down
4 changes: 2 additions & 2 deletions src/angular/button/button-link/button-link.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { Directive, ElementRef, inject, Input, NgZone } from '@angular/core';
import { booleanAttribute } from '@sbb-esta/lyne-angular/core';
import { booleanAttribute, SbbRouterLinkSupportMixin } from '@sbb-esta/lyne-angular/core';
import type { SbbButtonLinkElement } from '@sbb-esta/lyne-elements/button/button-link.js';
import { SbbButtonSize } from '@sbb-esta/lyne-elements/button.js';
import { LinkTargetType } from '@sbb-esta/lyne-elements/core/base-elements.js';
Expand All @@ -9,7 +9,7 @@ import '@sbb-esta/lyne-elements/button/button-link.js';
@Directive({
selector: 'sbb-button-link',
})
export class SbbButtonLink {
export class SbbButtonLink extends SbbRouterLinkSupportMixin(class {}) {
#element: ElementRef<SbbButtonLinkElement> = inject(ElementRef<SbbButtonLinkElement>);
#ngZone: NgZone = inject(NgZone);

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { Directive, ElementRef, inject, Input, NgZone } from '@angular/core';
import { booleanAttribute } from '@sbb-esta/lyne-angular/core';
import { booleanAttribute, SbbRouterLinkSupportMixin } from '@sbb-esta/lyne-angular/core';
import type { SbbSecondaryButtonLinkElement } from '@sbb-esta/lyne-elements/button/secondary-button-link.js';
import { SbbButtonSize } from '@sbb-esta/lyne-elements/button.js';
import { LinkTargetType } from '@sbb-esta/lyne-elements/core/base-elements.js';
Expand All @@ -9,7 +9,7 @@ import '@sbb-esta/lyne-elements/button/secondary-button-link.js';
@Directive({
selector: 'sbb-secondary-button-link',
})
export class SbbSecondaryButtonLink {
export class SbbSecondaryButtonLink extends SbbRouterLinkSupportMixin(class {}) {
#element: ElementRef<SbbSecondaryButtonLinkElement> = inject(
ElementRef<SbbSecondaryButtonLinkElement>,
);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { Directive, ElementRef, inject, Input, NgZone } from '@angular/core';
import { booleanAttribute } from '@sbb-esta/lyne-angular/core';
import { booleanAttribute, SbbRouterLinkSupportMixin } from '@sbb-esta/lyne-angular/core';
import type { SbbTransparentButtonLinkElement } from '@sbb-esta/lyne-elements/button/transparent-button-link.js';
import { SbbButtonSize } from '@sbb-esta/lyne-elements/button.js';
import { LinkTargetType } from '@sbb-esta/lyne-elements/core/base-elements.js';
Expand All @@ -9,7 +9,7 @@ import '@sbb-esta/lyne-elements/button/transparent-button-link.js';
@Directive({
selector: 'sbb-transparent-button-link',
})
export class SbbTransparentButtonLink {
export class SbbTransparentButtonLink extends SbbRouterLinkSupportMixin(class {}) {
#element: ElementRef<SbbTransparentButtonLinkElement> = inject(
ElementRef<SbbTransparentButtonLinkElement>,
);
Expand Down
4 changes: 2 additions & 2 deletions src/angular/card/card-link/card-link.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { Directive, ElementRef, inject, Input, NgZone } from '@angular/core';
import { booleanAttribute } from '@sbb-esta/lyne-angular/core';
import { booleanAttribute, SbbRouterLinkSupportMixin } from '@sbb-esta/lyne-angular/core';
import type { SbbCardLinkElement } from '@sbb-esta/lyne-elements/card/card-link.js';
import { LinkTargetType } from '@sbb-esta/lyne-elements/core/base-elements.js';

Expand All @@ -8,7 +8,7 @@ import '@sbb-esta/lyne-elements/card/card-link.js';
@Directive({
selector: 'sbb-card-link',
})
export class SbbCardLink {
export class SbbCardLink extends SbbRouterLinkSupportMixin(class {}) {
#element: ElementRef<SbbCardLinkElement> = inject(ElementRef<SbbCardLinkElement>);
#ngZone: NgZone = inject(NgZone);

Expand Down
1 change: 1 addition & 0 deletions src/angular/core/index.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
export * from './attribute-transform';
export * from './control-value-accessor-mixin';
export * from './router-link-support-mixin';
45 changes: 45 additions & 0 deletions src/angular/core/router-link-support-mixin.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import { inject } from '@angular/core';
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
import { NavigationEnd, Router, RouterLink } from '@angular/router';
import { AbstractConstructor } from '@sbb-esta/lyne-elements/core/mixins.js';

/**
* Patches the behavior of the Angular RouterLink.
* With this patch the RouterLink recognizes the web component links
* as native links and processes them correctly.
* TODO: Check whether there is support of Angular for that case:
* - https://github.com/angular/angular/pull/59567
* - https://github.com/angular/angular/issues/28345
*/
export const SbbRouterLinkSupportMixin = <T extends AbstractConstructor>(
superclass: T,
): AbstractConstructor & T => {
abstract class SbbRouterLink extends superclass {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
constructor(...args: any[]) {
super(...args);

const routerLink = inject(RouterLink, { optional: true }) as unknown as {
isAnchorElement: boolean;
updateHref: () => void;
setTabIndexIfNotOnNativeEl: (newTabIndex: string | null) => void;
};

if (!routerLink) {
return;
}

routerLink.setTabIndexIfNotOnNativeEl(null);
routerLink.isAnchorElement = true;

inject(Router)
.events.pipe(takeUntilDestroyed())
.subscribe((s) => {
if (s instanceof NavigationEnd) {
routerLink.updateHref();
}
});
}
}
return SbbRouterLink as unknown as AbstractConstructor & T;
};
4 changes: 2 additions & 2 deletions src/angular/header/header-link/header-link.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { Directive, ElementRef, inject, Input, NgZone } from '@angular/core';
import { booleanAttribute } from '@sbb-esta/lyne-angular/core';
import { booleanAttribute, SbbRouterLinkSupportMixin } from '@sbb-esta/lyne-angular/core';
import { LinkTargetType } from '@sbb-esta/lyne-elements/core/base-elements.js';
import { SbbHorizontalFrom } from '@sbb-esta/lyne-elements/core/interfaces.js';
import type { SbbHeaderLinkElement } from '@sbb-esta/lyne-elements/header/header-link.js';
Expand All @@ -8,7 +8,7 @@ import '@sbb-esta/lyne-elements/header/header-link.js';
@Directive({
selector: 'sbb-header-link',
})
export class SbbHeaderLink {
export class SbbHeaderLink extends SbbRouterLinkSupportMixin(class {}) {
#element: ElementRef<SbbHeaderLinkElement> = inject(ElementRef<SbbHeaderLinkElement>);
#ngZone: NgZone = inject(NgZone);

Expand Down
5 changes: 3 additions & 2 deletions src/angular/link/block-link/block-link.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,16 @@
import { Directive, ElementRef, inject, Input, NgZone } from '@angular/core';
import { booleanAttribute } from '@sbb-esta/lyne-angular/core';
import { booleanAttribute, SbbRouterLinkSupportMixin } from '@sbb-esta/lyne-angular/core';
import { LinkTargetType } from '@sbb-esta/lyne-elements/core/base-elements.js';
import { SbbIconPlacement } from '@sbb-esta/lyne-elements/core/interfaces.js';
import type { SbbBlockLinkElement } from '@sbb-esta/lyne-elements/link/block-link.js';
import { SbbLinkSize } from '@sbb-esta/lyne-elements/link.js';

import '@sbb-esta/lyne-elements/link/block-link.js';

@Directive({
selector: 'sbb-block-link',
})
export class SbbBlockLink {
export class SbbBlockLink extends SbbRouterLinkSupportMixin(class {}) {
#element: ElementRef<SbbBlockLinkElement> = inject(ElementRef<SbbBlockLinkElement>);
#ngZone: NgZone = inject(NgZone);

Expand Down
4 changes: 2 additions & 2 deletions src/angular/link/link/link.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { Directive, ElementRef, inject, Input, NgZone } from '@angular/core';
import { booleanAttribute } from '@sbb-esta/lyne-angular/core';
import { booleanAttribute, SbbRouterLinkSupportMixin } from '@sbb-esta/lyne-angular/core';
import { LinkTargetType } from '@sbb-esta/lyne-elements/core/base-elements.js';
import type { SbbLinkElement } from '@sbb-esta/lyne-elements/link/link.js';
import { SbbLinkSize } from '@sbb-esta/lyne-elements/link.js';
Expand All @@ -8,7 +8,7 @@ import '@sbb-esta/lyne-elements/link/link.js';
@Directive({
selector: 'sbb-link',
})
export class SbbLink {
export class SbbLink extends SbbRouterLinkSupportMixin(class {}) {
#element: ElementRef<SbbLinkElement> = inject(ElementRef<SbbLinkElement>);
#ngZone: NgZone = inject(NgZone);

Expand Down
4 changes: 2 additions & 2 deletions src/angular/menu/menu-link/menu-link.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
import { Directive, ElementRef, inject, Input, NgZone } from '@angular/core';
import { booleanAttribute } from '@sbb-esta/lyne-angular/core';
import { booleanAttribute, SbbRouterLinkSupportMixin } from '@sbb-esta/lyne-angular/core';
import { LinkTargetType } from '@sbb-esta/lyne-elements/core/base-elements.js';
import type { SbbMenuLinkElement } from '@sbb-esta/lyne-elements/menu/menu-link.js';
import '@sbb-esta/lyne-elements/menu/menu-link.js';

@Directive({
selector: 'sbb-menu-link',
})
export class SbbMenuLink {
export class SbbMenuLink extends SbbRouterLinkSupportMixin(class {}) {
#element: ElementRef<SbbMenuLinkElement> = inject(ElementRef<SbbMenuLinkElement>);
#ngZone: NgZone = inject(NgZone);

Expand Down
4 changes: 2 additions & 2 deletions src/angular/navigation/navigation-link/navigation-link.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { Directive, ElementRef, inject, Input, NgZone } from '@angular/core';
import { booleanAttribute } from '@sbb-esta/lyne-angular/core';
import { booleanAttribute, SbbRouterLinkSupportMixin } from '@sbb-esta/lyne-angular/core';
import { LinkTargetType } from '@sbb-esta/lyne-elements/core/base-elements.js';
import type { SbbNavigationLinkElement } from '@sbb-esta/lyne-elements/navigation/navigation-link.js';
import { SbbNavigationMarkerElement } from '@sbb-esta/lyne-elements/navigation/navigation-marker.js';
Expand All @@ -10,7 +10,7 @@ import '@sbb-esta/lyne-elements/navigation/navigation-link.js';
@Directive({
selector: 'sbb-navigation-link',
})
export class SbbNavigationLink {
export class SbbNavigationLink extends SbbRouterLinkSupportMixin(class {}) {
#element: ElementRef<SbbNavigationLinkElement> = inject(ElementRef<SbbNavigationLinkElement>);
#ngZone: NgZone = inject(NgZone);

Expand Down
4 changes: 2 additions & 2 deletions src/angular/teaser-hero/teaser-hero.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
import { Directive, ElementRef, inject, Input, NgZone } from '@angular/core';
import { booleanAttribute } from '@sbb-esta/lyne-angular/core';
import { booleanAttribute, SbbRouterLinkSupportMixin } from '@sbb-esta/lyne-angular/core';
import { LinkTargetType } from '@sbb-esta/lyne-elements/core/base-elements.js';
import type { SbbTeaserHeroElement } from '@sbb-esta/lyne-elements/teaser-hero.js';
import '@sbb-esta/lyne-elements/teaser-hero.js';

@Directive({
selector: 'sbb-teaser-hero',
})
export class SbbTeaserHero {
export class SbbTeaserHero extends SbbRouterLinkSupportMixin(class {}) {
#element: ElementRef<SbbTeaserHeroElement> = inject(ElementRef<SbbTeaserHeroElement>);
#ngZone: NgZone = inject(NgZone);

Expand Down
4 changes: 2 additions & 2 deletions src/angular/teaser-product/teaser-product/teaser-product.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
import { Directive, ElementRef, inject, Input, NgZone } from '@angular/core';
import { booleanAttribute } from '@sbb-esta/lyne-angular/core';
import { booleanAttribute, SbbRouterLinkSupportMixin } from '@sbb-esta/lyne-angular/core';
import { LinkTargetType } from '@sbb-esta/lyne-elements/core/base-elements.js';
import type { SbbTeaserProductElement } from '@sbb-esta/lyne-elements/teaser-product/teaser-product.js';
import '@sbb-esta/lyne-elements/teaser-product/teaser-product.js';

@Directive({
selector: 'sbb-teaser-product',
})
export class SbbTeaserProduct {
export class SbbTeaserProduct extends SbbRouterLinkSupportMixin(class {}) {
#element: ElementRef<SbbTeaserProductElement> = inject(ElementRef<SbbTeaserProductElement>);
#ngZone: NgZone = inject(NgZone);

Expand Down
4 changes: 2 additions & 2 deletions src/angular/teaser/teaser.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { Directive, ElementRef, inject, Input, NgZone } from '@angular/core';
import { booleanAttribute } from '@sbb-esta/lyne-angular/core';
import { booleanAttribute, SbbRouterLinkSupportMixin } from '@sbb-esta/lyne-angular/core';
import { LinkTargetType } from '@sbb-esta/lyne-elements/core/base-elements.js';
import type { SbbTeaserElement } from '@sbb-esta/lyne-elements/teaser.js';
import { SbbTitleLevel } from '@sbb-esta/lyne-elements/title.js';
Expand All @@ -8,7 +8,7 @@ import '@sbb-esta/lyne-elements/teaser.js';
@Directive({
selector: 'sbb-teaser',
})
export class SbbTeaser {
export class SbbTeaser extends SbbRouterLinkSupportMixin(class {}) {
#element: ElementRef<SbbTeaserElement> = inject(ElementRef<SbbTeaserElement>);
#ngZone: NgZone = inject(NgZone);

Expand Down
2 changes: 2 additions & 0 deletions src/showcase/styles.scss
Original file line number Diff line number Diff line change
@@ -1 +1,3 @@
@import '@sbb-esta/lyne-elements/standard-theme.css';

/* You can add global styles to this file, and also import other style files */

0 comments on commit 4ad86a2

Please sign in to comment.