Skip to content

Commit 39fcb55

Browse files
aklkvdidoo
andauthored
fix(components): LinkToExternal retake (#2867)
Co-authored-by: Cristiano Rastelli <cristiano.rastelli@hashicorp.com>
1 parent 15e4bf6 commit 39fcb55

File tree

8 files changed

+94
-7
lines changed

8 files changed

+94
-7
lines changed

.changeset/tall-rings-act.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@hashicorp/design-system-components': patch
3+
---
4+
5+
Introduce the `hds-resolve-link-to-component` utility to correctly resolve the LinkTo component when `@isRouteExternal` is set on `HdsBreadcrumbItem` or `HdsInteractive`. Consumers are now required to install `ember-engines` when `@isRouteExternal` is `true`.

packages/components/package.json

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,14 @@
118118
"typescript-eslint": "^8.29.0",
119119
"webpack": "^5.97.1"
120120
},
121+
"peerDependencies": {
122+
"ember-engines": ">= 0.11.0"
123+
},
124+
"peerDependenciesMeta": {
125+
"ember-engines": {
126+
"optional": true
127+
}
128+
},
121129
"ember": {
122130
"edition": "octane"
123131
},

packages/components/src/components/hds/breadcrumb/item.hbs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
</div>
1515
{{else}}
1616
{{#if @isRouteExternal}}
17-
<LinkToExternal
17+
<this.linkToExternal
1818
class="hds-breadcrumb__link"
1919
@current-when={{@current-when}}
2020
@models={{hds-link-to-models @model @models}}
@@ -28,7 +28,7 @@
2828
</div>
2929
{{/if}}
3030
<span class="hds-breadcrumb__text">{{@text}}</span>
31-
</LinkToExternal>
31+
</this.linkToExternal>
3232
{{else}}
3333
<LinkTo
3434
class="hds-breadcrumb__link"

packages/components/src/components/hds/breadcrumb/item.ts

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,16 @@
44
*/
55

66
import Component from '@glimmer/component';
7+
import { tracked } from '@glimmer/tracking';
78
import { htmlSafe } from '@ember/template';
89
import { assert } from '@ember/debug';
10+
11+
import { hdsResolveLinkToExternal } from '../../../utils/hds-resolve-link-to-external.ts';
12+
13+
import type Owner from '@ember/owner';
14+
import type { LinkTo } from '@ember/routing';
915
import type { SafeString } from '@ember/template';
10-
import type { HdsIconSignature } from '../icon';
16+
import type { HdsIconSignature } from '../icon/index';
1117

1218
export interface HdsBreadcrumbItemSignature {
1319
Args: {
@@ -27,6 +33,23 @@ export interface HdsBreadcrumbItemSignature {
2733
}
2834

2935
export default class HdsBreadcrumbItem extends Component<HdsBreadcrumbItemSignature> {
36+
@tracked linkToExternal: LinkTo | null = null;
37+
38+
constructor(owner: Owner, args: HdsBreadcrumbItemSignature['Args']) {
39+
super(owner, args);
40+
41+
// we want to avoid resolving the component if it's not needed
42+
if (args.isRouteExternal) {
43+
void this.resolveLinkToExternal();
44+
}
45+
}
46+
47+
async resolveLinkToExternal() {
48+
this.linkToExternal = await hdsResolveLinkToExternal(
49+
this.args.isRouteExternal
50+
);
51+
}
52+
3053
/**
3154
* @param maxWidth
3255
* @type {string}

packages/components/src/components/hds/interactive/index.hbs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,14 @@
33
{{! NOTICE: we can't support the direct use of the "href" HTML attribute via ...attributes in the <a> elements, because we need to rely on the "@href" Ember argument to differentiate between different types of generated output }}
44
{{~#if @route~}}
55
{{~#if this.isRouteExternal~}}
6-
<LinkToExternal
6+
<this.linkToExternal
77
@current-when={{@current-when}}
88
@models={{hds-link-to-models @model @models}}
99
@query={{hds-link-to-query @query}}
1010
@replace={{@replace}}
1111
@route={{@route}}
1212
...attributes
13-
>{{yield}}</LinkToExternal>
13+
>{{yield}}</this.linkToExternal>
1414
{{~else~}}
1515
<LinkTo
1616
@current-when={{@current-when}}

packages/components/src/components/hds/interactive/index.ts

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,14 @@
44
*/
55

66
import Component from '@glimmer/component';
7+
import { tracked } from '@glimmer/tracking';
78
import { action } from '@ember/object';
89

10+
import { hdsResolveLinkToExternal } from '../../../utils/hds-resolve-link-to-external.ts';
11+
12+
import type Owner from '@ember/owner';
13+
import type { LinkTo } from '@ember/routing';
14+
915
export interface HdsInteractiveSignature {
1016
Args: {
1117
href?: string;
@@ -27,6 +33,22 @@ export interface HdsInteractiveSignature {
2733
}
2834

2935
export default class HdsInteractive extends Component<HdsInteractiveSignature> {
36+
@tracked linkToExternal: LinkTo | null = null;
37+
38+
constructor(owner: Owner, args: HdsInteractiveSignature['Args']) {
39+
super(owner, args);
40+
41+
// we want to avoid resolving the component if it's not needed
42+
if (args.isRouteExternal) {
43+
void this.resolveLinkToExternal();
44+
}
45+
}
46+
47+
async resolveLinkToExternal() {
48+
this.linkToExternal = await hdsResolveLinkToExternal(
49+
this.args.isRouteExternal
50+
);
51+
}
3052
/**
3153
* Determines if a @href value is "external" (it adds target="_blank" rel="noopener noreferrer")
3254
*
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
import { LinkTo } from '@ember/routing';
2+
import { assert } from '@ember/debug';
3+
4+
/**
5+
* Resolves the correct component to use for the `LinkTo`.
6+
*
7+
* @param isRouteExternal - If true, will return the `LinkToExternal` component. If `ember-engines` is not installed, an assertion will be thrown.
8+
* @returns A promise resolving to the correct component to use for the `LinkTo`.
9+
*/
10+
export async function hdsResolveLinkToExternal(
11+
isRouteExternal?: boolean
12+
): Promise<typeof LinkTo> {
13+
if (isRouteExternal) {
14+
try {
15+
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
16+
const mod = await import(
17+
// @ts-expect-error: we list this as optional peer dependency
18+
'ember-engines/components/link-to-external-component'
19+
);
20+
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
21+
return mod.default as typeof LinkTo;
22+
} catch {
23+
assert(
24+
`@isRouteExternal is only available when using the "ember-engines" addon. Please install it to use this feature.`,
25+
false
26+
);
27+
}
28+
}
29+
30+
return LinkTo;
31+
}

packages/components/unpublished-development-types/global.d.ts

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
import '@glint/environment-ember-loose';
22
import '@glint/environment-ember-template-imports';
33

4-
import { LinkTo } from '@ember/routing';
54
import { Portal, PortalTarget } from 'ember-stargate';
65

76
import type HdsComponentsRegistry from '../src/template-registry';
@@ -25,7 +24,6 @@ declare module '@glint/environment-ember-loose/registry' {
2524
RenderModifiersRegistry,
2625
EmbroiderUtilRegistry /*, other addon registries */ {
2726
// local entries
28-
LinkToExternal: typeof LinkTo;
2927
Portal: typeof Portal;
3028
PortalTarget: typeof PortalTarget;
3129
'sort-by': HelperLike<{

0 commit comments

Comments
 (0)