Skip to content

Commit e525808

Browse files
committed
feat: separate linkActive input
1 parent 71f02e7 commit e525808

File tree

3 files changed

+38
-28
lines changed

3 files changed

+38
-28
lines changed

src/app/app.component.ts

Lines changed: 3 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -7,18 +7,8 @@ import { TanStackRouterDevtoolsComponent } from '../router/router-devtools';
77
imports: [Outlet, TanStackRouterDevtoolsComponent, Link],
88
template: `
99
<h1>Welcome to {{ title }}!</h1>
10-
11-
<a #link="link" link="/" [class.active]="link.isActive()">Home</a> |
12-
<a #aboutLink="link" link="/about" [class.active]="aboutLink.isActive()"
13-
>About</a
14-
>
15-
|
16-
<a
17-
#parentOneLink="link"
18-
[link]="{ to: '/parent/$id', params: { id: '1' } }"
19-
[class.active]="parentOneLink.isActive()"
20-
>Parent 1</a
21-
>
10+
<a link="/" class="chau">Home</a> | <a link="/about">About</a> |
11+
<a [link]="{ to: '/parent/$id', params: { id: '1' } }">Parent 1</a>
2212
<hr />
2313
2414
<outlet />
@@ -33,7 +23,7 @@ import { TanStackRouterDevtoolsComponent } from '../router/router-devtools';
3323
`,
3424
styles: [
3525
`
36-
.active {
26+
a[data-active='true'] {
3727
font-weight: bold;
3828
padding: 0.5rem;
3929
border: 1px solid;

src/app/parent.component.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,12 @@ export const Route = createRoute({
3232
a {
3333
text-decoration: underline;
3434
}
35+
36+
a[data-active='true'] {
37+
font-weight: bold;
38+
padding: 0.5rem;
39+
border: 1px solid red;
40+
}
3541
`,
3642
],
3743
})

src/router/link.ts

Lines changed: 29 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ import { injectRouter } from './router';
2626
'(touchstart)': 'type() === "internal" && handleClick($event)',
2727
'(mouseenter)': 'type() === "internal" && handleMouseEnter($event)',
2828
'(mouseleave)': 'type() === "internal" && handleMouseLeave()',
29+
'[class]': '[isActive() ? activeClass() : ""]',
2930
'[attr.data-active]': 'isActive()',
3031
'[attr.data-type]': 'type()',
3132
'[attr.data-transitioning]':
@@ -41,14 +42,25 @@ export class Link {
4142
alias: 'link',
4243
transform: (
4344
value:
44-
| (Omit<LinkOptions, 'to'> & {
45+
| (Omit<LinkOptions, 'to' | 'activeOptions'> & {
4546
to: NonNullable<LinkOptions['to']>;
4647
})
4748
| NonNullable<LinkOptions['to']>
4849
) => {
4950
return (typeof value === 'object' ? value : { to: value }) as LinkOptions;
5051
},
5152
});
53+
linkActiveOptions = input(
54+
{ class: 'active' },
55+
{
56+
alias: 'linkActive',
57+
transform: (
58+
value: (LinkOptions['activeOptions'] & { class: string }) | string
59+
) => {
60+
return typeof value === 'string' ? { class: value } : value;
61+
},
62+
}
63+
);
5264

5365
router = injectRouter();
5466
hostElement = inject<ElementRef<HTMLAnchorElement>>(ElementRef);
@@ -59,34 +71,34 @@ export class Link {
5971
() => this.router.routerState().location.search
6072
);
6173

62-
private to = computed(() => this.linkOptions().to);
6374
protected disabled = computed(() => this.linkOptions().disabled);
75+
private to = computed(() => this.linkOptions().to);
6476
private userFrom = computed(() => this.linkOptions().from);
6577
private userReloadDocument = computed(
6678
() => this.linkOptions().reloadDocument
6779
);
6880
private userPreload = computed(() => this.linkOptions().preload);
6981
private userPreloadDelay = computed(() => this.linkOptions().preloadDelay);
70-
private exactActiveOptions = computed(
71-
() => this.linkOptions().activeOptions?.exact
72-
);
82+
private exactActiveOptions = computed(() => this.linkActiveOptions().exact);
7383
private includeHashActiveOptions = computed(
74-
() => this.linkOptions().activeOptions?.includeHash
84+
() => this.linkActiveOptions().includeHash
7585
);
7686
private includeSearchActiveOptions = computed(
77-
() => this.linkOptions().activeOptions?.includeSearch
87+
() => this.linkActiveOptions().includeSearch
7888
);
7989
private explicitUndefinedActiveOptions = computed(
80-
() => this.linkOptions().activeOptions?.explicitUndefined
90+
() => this.linkActiveOptions().explicitUndefined
8191
);
92+
protected activeClass = computed(() => this.linkActiveOptions().class);
8293

8394
protected type = computed(() => {
8495
const to = this.to();
8596
try {
8697
new URL(`${to}`);
8798
return 'external';
88-
} catch {}
89-
return 'internal';
99+
} catch {
100+
return 'internal';
101+
}
90102
});
91103

92104
private from = computed(() => {
@@ -200,6 +212,13 @@ export class Link {
200212
this.doPreload();
201213
}
202214
});
215+
216+
effect((onCleanup) => {
217+
const unsub = this.router.subscribe('onResolved', () => {
218+
this.transitioning.set(false);
219+
});
220+
onCleanup(() => unsub());
221+
});
203222
}
204223

205224
protected handleClick(event: MouseEvent) {
@@ -221,11 +240,6 @@ export class Link {
221240
event.preventDefault();
222241
this.transitioning.set(true);
223242

224-
const unsub = this.router.subscribe('onResolved', () => {
225-
unsub();
226-
this.transitioning.set(false);
227-
});
228-
229243
this.router.navigate(this.navigateOptions());
230244
}
231245

0 commit comments

Comments
 (0)