Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
64 changes: 64 additions & 0 deletions libs/core/src/components.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1352,6 +1352,38 @@ export namespace Components {
* @example <pds-link href="https://example.com" target="_blank">Opens in new tab</pds-link>
*/
"target"?: '_blank' | '_self' | '_parent' | '_top';
/**
* Enables or disables Turbo Drive for this link. Maps to the `data-turbo` attribute on the inner anchor element.
*/
"turbo"?: string;
/**
* Controls the Turbo visit action type. Maps to the `data-turbo-action` attribute on the inner anchor element.
*/
"turboAction"?: 'advance' | 'replace';
/**
* Displays a confirmation dialog before navigating. Maps to the `data-turbo-confirm` attribute on the inner anchor element.
*/
"turboConfirm"?: string;
/**
* Specifies the Turbo Frame to target for navigation. Maps to the `data-turbo-frame` attribute on the inner anchor element.
*/
"turboFrame"?: string;
/**
* Changes the HTTP method for the link request. Maps to the `data-turbo-method` attribute on the inner anchor element.
*/
"turboMethod"?: 'get' | 'post' | 'put' | 'patch' | 'delete';
/**
* Controls link prefetching on hover. Maps to the `data-turbo-prefetch` attribute on the inner anchor element.
*/
"turboPrefetch"?: string;
/**
* Eagerly preloads the link's destination into cache. Maps to the `data-turbo-preload` attribute on the inner anchor element.
*/
"turboPreload"?: string;
/**
* Accepts Turbo Stream responses for GET requests. Maps to the `data-turbo-stream` attribute on the inner anchor element.
*/
"turboStream"?: string;
/**
* Sets the link variant styles.
* @defaultValue inline
Expand Down Expand Up @@ -4472,6 +4504,38 @@ declare namespace LocalJSX {
* @example <pds-link href="https://example.com" target="_blank">Opens in new tab</pds-link>
*/
"target"?: '_blank' | '_self' | '_parent' | '_top';
/**
* Enables or disables Turbo Drive for this link. Maps to the `data-turbo` attribute on the inner anchor element.
*/
"turbo"?: string;
/**
* Controls the Turbo visit action type. Maps to the `data-turbo-action` attribute on the inner anchor element.
*/
"turboAction"?: 'advance' | 'replace';
/**
* Displays a confirmation dialog before navigating. Maps to the `data-turbo-confirm` attribute on the inner anchor element.
*/
"turboConfirm"?: string;
/**
* Specifies the Turbo Frame to target for navigation. Maps to the `data-turbo-frame` attribute on the inner anchor element.
*/
"turboFrame"?: string;
/**
* Changes the HTTP method for the link request. Maps to the `data-turbo-method` attribute on the inner anchor element.
*/
"turboMethod"?: 'get' | 'post' | 'put' | 'patch' | 'delete';
/**
* Controls link prefetching on hover. Maps to the `data-turbo-prefetch` attribute on the inner anchor element.
*/
"turboPrefetch"?: string;
/**
* Eagerly preloads the link's destination into cache. Maps to the `data-turbo-preload` attribute on the inner anchor element.
*/
"turboPreload"?: string;
/**
* Accepts Turbo Stream responses for GET requests. Maps to the `data-turbo-stream` attribute on the inner anchor element.
*/
"turboStream"?: string;
/**
* Sets the link variant styles.
* @defaultValue inline
Expand Down
56 changes: 56 additions & 0 deletions libs/core/src/components/pds-link/pds-link.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,54 @@ export class PdsLink {
*/
@Prop() href!: string;

/**
* Enables or disables Turbo Drive for this link.
* Maps to the `data-turbo` attribute on the inner anchor element.
*/
@Prop() turbo?: string;

/**
* Specifies the Turbo Frame to target for navigation.
* Maps to the `data-turbo-frame` attribute on the inner anchor element.
*/
@Prop() turboFrame?: string;

/**
* Controls the Turbo visit action type.
* Maps to the `data-turbo-action` attribute on the inner anchor element.
*/
@Prop() turboAction?: 'advance' | 'replace';

/**
* Changes the HTTP method for the link request.
* Maps to the `data-turbo-method` attribute on the inner anchor element.
*/
@Prop() turboMethod?: 'get' | 'post' | 'put' | 'patch' | 'delete';

/**
* Displays a confirmation dialog before navigating.
* Maps to the `data-turbo-confirm` attribute on the inner anchor element.
*/
@Prop() turboConfirm?: string;

/**
* Accepts Turbo Stream responses for GET requests.
* Maps to the `data-turbo-stream` attribute on the inner anchor element.
*/
@Prop() turboStream?: string;

/**
* Controls link prefetching on hover.
* Maps to the `data-turbo-prefetch` attribute on the inner anchor element.
*/
@Prop() turboPrefetch?: string;

/**
* Eagerly preloads the link's destination into cache.
* Maps to the `data-turbo-preload` attribute on the inner anchor element.
*/
@Prop() turboPreload?: string;

private classNames() {
const classNames = ['pds-link'];

Expand Down Expand Up @@ -105,6 +153,14 @@ export class PdsLink {
target={targetValue}
rel={relValue}
style={this.setLinkStyles()}
data-turbo={this.turbo || undefined}
data-turbo-frame={this.turboFrame || undefined}
data-turbo-action={this.turboAction || undefined}
data-turbo-method={this.turboMethod || undefined}
data-turbo-confirm={this.turboConfirm || undefined}
data-turbo-stream={this.turboStream || undefined}
data-turbo-prefetch={this.turboPrefetch || undefined}
data-turbo-preload={this.turboPreload || undefined}
>
<slot>{this.href}</slot>
{showExternalIcon &&
Expand Down
28 changes: 18 additions & 10 deletions libs/core/src/components/pds-link/readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,16 +7,24 @@ Link is mainly used as navigational element and usually appear within or directl

## Properties

| Property | Attribute | Description | Type | Default |
| ------------------- | -------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------- | ----------- |
| `color` | `color` | Sets the link color. | `string` | `undefined` |
| `componentId` | `component-id` | A unique identifier used for the underlying component `id` attribute. | `string` | `undefined` |
| `download` | `download` | Prompts the user to save the linked URL instead of navigating to it. It can be used without a value to download with the default filename, or with a string value to suggest a specific filename for the download. | `string` | `undefined` |
| `external` | `external` | <span style="color:red">**[DEPRECATED]**</span> Consider using the `target` prop for more control. This prop will be maintained for backward compatibility.<br/><br/>Determines whether the link should open in a new tab. | `boolean` | `false` |
| `fontSize` | `font-size` | The font size of the link's text. | `"lg" \| "md" \| "sm"` | `'lg'` |
| `href` _(required)_ | `href` | The hyperlink's destination URL. If no text is provided in the custom slot, the href will be used. | `string` | `undefined` |
| `target` | `target` | Specifies where to open the linked document. | `"_blank" \| "_parent" \| "_self" \| "_top"` | `undefined` |
| `variant` | `variant` | Sets the link variant styles. | `"inline" \| "plain"` | `'inline'` |
| Property | Attribute | Description | Type | Default |
| ------------------- | ---------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------- | ----------- |
| `color` | `color` | Sets the link color. | `string` | `undefined` |
| `componentId` | `component-id` | A unique identifier used for the underlying component `id` attribute. | `string` | `undefined` |
| `download` | `download` | Prompts the user to save the linked URL instead of navigating to it. It can be used without a value to download with the default filename, or with a string value to suggest a specific filename for the download. | `string` | `undefined` |
| `external` | `external` | <span style="color:red">**[DEPRECATED]**</span> Consider using the `target` prop for more control. This prop will be maintained for backward compatibility.<br/><br/>Determines whether the link should open in a new tab. | `boolean` | `false` |
| `fontSize` | `font-size` | The font size of the link's text. | `"lg" \| "md" \| "sm"` | `'lg'` |
| `href` _(required)_ | `href` | The hyperlink's destination URL. If no text is provided in the custom slot, the href will be used. | `string` | `undefined` |
| `target` | `target` | Specifies where to open the linked document. | `"_blank" \| "_parent" \| "_self" \| "_top"` | `undefined` |
| `turbo` | `turbo` | Enables or disables Turbo Drive for this link. Maps to the `data-turbo` attribute on the inner anchor element. | `string` | `undefined` |
| `turboAction` | `turbo-action` | Controls the Turbo visit action type. Maps to the `data-turbo-action` attribute on the inner anchor element. | `"advance" \| "replace"` | `undefined` |
| `turboConfirm` | `turbo-confirm` | Displays a confirmation dialog before navigating. Maps to the `data-turbo-confirm` attribute on the inner anchor element. | `string` | `undefined` |
| `turboFrame` | `turbo-frame` | Specifies the Turbo Frame to target for navigation. Maps to the `data-turbo-frame` attribute on the inner anchor element. | `string` | `undefined` |
| `turboMethod` | `turbo-method` | Changes the HTTP method for the link request. Maps to the `data-turbo-method` attribute on the inner anchor element. | `"delete" \| "get" \| "patch" \| "post" \| "put"` | `undefined` |
| `turboPrefetch` | `turbo-prefetch` | Controls link prefetching on hover. Maps to the `data-turbo-prefetch` attribute on the inner anchor element. | `string` | `undefined` |
| `turboPreload` | `turbo-preload` | Eagerly preloads the link's destination into cache. Maps to the `data-turbo-preload` attribute on the inner anchor element. | `string` | `undefined` |
| `turboStream` | `turbo-stream` | Accepts Turbo Stream responses for GET requests. Maps to the `data-turbo-stream` attribute on the inner anchor element. | `string` | `undefined` |
| `variant` | `variant` | Sets the link variant styles. | `"inline" \| "plain"` | `'inline'` |


## Slots
Expand Down
111 changes: 111 additions & 0 deletions libs/core/src/components/pds-link/test/pds-link.spec.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -118,4 +118,115 @@ describe('pds-link', () => {
const anchor = root?.shadowRoot?.querySelector('a');
expect(anchor?.getAttribute('download')).toBe('my-file.pdf');
});

describe('turbo props', () => {
it('renders data-turbo on the inner anchor', async () => {
const { root } = await newSpecPage({
components: [PdsLink],
html: `<pds-link href="/page" turbo="true">Page</pds-link>`,
});

const anchor = root?.shadowRoot?.querySelector('a');
expect(anchor?.getAttribute('data-turbo')).toBe('true');
});

it('renders data-turbo-frame on the inner anchor', async () => {
const { root } = await newSpecPage({
components: [PdsLink],
html: `<pds-link href="/page" turbo-frame="admin-content">Page</pds-link>`,
});

const anchor = root?.shadowRoot?.querySelector('a');
expect(anchor?.getAttribute('data-turbo-frame')).toBe('admin-content');
});

it('renders data-turbo-action on the inner anchor', async () => {
const { root } = await newSpecPage({
components: [PdsLink],
html: `<pds-link href="/page" turbo-action="replace">Page</pds-link>`,
});

const anchor = root?.shadowRoot?.querySelector('a');
expect(anchor?.getAttribute('data-turbo-action')).toBe('replace');
});

it('renders data-turbo-method on the inner anchor', async () => {
const { root } = await newSpecPage({
components: [PdsLink],
html: `<pds-link href="/page" turbo-method="delete">Delete</pds-link>`,
});

const anchor = root?.shadowRoot?.querySelector('a');
expect(anchor?.getAttribute('data-turbo-method')).toBe('delete');
});

it('renders data-turbo-confirm on the inner anchor', async () => {
const { root } = await newSpecPage({
components: [PdsLink],
html: `<pds-link href="/page" turbo-confirm="Are you sure?">Delete</pds-link>`,
});

const anchor = root?.shadowRoot?.querySelector('a');
expect(anchor?.getAttribute('data-turbo-confirm')).toBe('Are you sure?');
});

it('renders data-turbo-stream on the inner anchor', async () => {
const { root } = await newSpecPage({
components: [PdsLink],
html: `<pds-link href="/page" turbo-stream="true">Page</pds-link>`,
});

const anchor = root?.shadowRoot?.querySelector('a');
expect(anchor?.getAttribute('data-turbo-stream')).toBe('true');
});

it('renders data-turbo-prefetch on the inner anchor', async () => {
const { root } = await newSpecPage({
components: [PdsLink],
html: `<pds-link href="/page" turbo-prefetch="false">Page</pds-link>`,
});

const anchor = root?.shadowRoot?.querySelector('a');
expect(anchor?.getAttribute('data-turbo-prefetch')).toBe('false');
});

it('renders data-turbo-preload on the inner anchor', async () => {
const { root } = await newSpecPage({
components: [PdsLink],
html: `<pds-link href="/page" turbo-preload="true">Page</pds-link>`,
});

const anchor = root?.shadowRoot?.querySelector('a');
expect(anchor?.getAttribute('data-turbo-preload')).toBe('true');
});

it('omits turbo data attributes when props are not set', async () => {
const { root } = await newSpecPage({
components: [PdsLink],
html: `<pds-link href="/page">Page</pds-link>`,
});

const anchor = root?.shadowRoot?.querySelector('a');
expect(anchor?.hasAttribute('data-turbo')).toBe(false);
expect(anchor?.hasAttribute('data-turbo-frame')).toBe(false);
expect(anchor?.hasAttribute('data-turbo-action')).toBe(false);
expect(anchor?.hasAttribute('data-turbo-method')).toBe(false);
expect(anchor?.hasAttribute('data-turbo-confirm')).toBe(false);
expect(anchor?.hasAttribute('data-turbo-stream')).toBe(false);
expect(anchor?.hasAttribute('data-turbo-prefetch')).toBe(false);
expect(anchor?.hasAttribute('data-turbo-preload')).toBe(false);
});

it('renders multiple turbo attributes together', async () => {
const { root } = await newSpecPage({
components: [PdsLink],
html: `<pds-link href="/page" turbo="true" turbo-frame="content" turbo-action="advance">Page</pds-link>`,
});

const anchor = root?.shadowRoot?.querySelector('a');
expect(anchor?.getAttribute('data-turbo')).toBe('true');
expect(anchor?.getAttribute('data-turbo-frame')).toBe('content');
expect(anchor?.getAttribute('data-turbo-action')).toBe('advance');
});
});
});
Loading