# Link

- Entry point: `@koobiq/components/link`
- Page: https://koobiq.io/en/components/link/overview

## Overview

`KbqLink` is a component that connects web pages or acts as a lighter alternative to a button.

**Example: Link** (`link-overview`)

```ts link-overview-example.ts
import { ChangeDetectionStrategy, Component } from '@angular/core';
import { KbqLink } from '@koobiq/components/link';

@Component({
    selector: 'link-overview-example',
    imports: [KbqLink],
    template: `
        <a kbqLink href="https://koobiq.io/en/components/link" target="_blank">Scan report</a>
    `,
    styles: `
        :host {
            display: flex;
            align-items: center;
            justify-content: center;
            min-height: 160px;
        }
    `,
    changeDetection: ChangeDetectionStrategy.OnPush
})
export class LinkOverviewExample {}
```

### Size

The `size` attribute sets the size of the link, its typography and the gaps to its icons.

**Example: Link size** (`link-size`)

```ts link-size-example.ts
import { ChangeDetectionStrategy, Component, model } from '@angular/core';
import { FormsModule } from '@angular/forms';
import { KbqButtonToggleModule } from '@koobiq/components/button-toggle';
import { KbqDefaultSizes } from '@koobiq/components/core';
import { KbqLink } from '@koobiq/components/link';

@Component({
    selector: 'link-size-example',
    imports: [KbqLink, KbqButtonToggleModule, FormsModule],
    template: `
        <kbq-button-toggle-group [(ngModel)]="size">
            <kbq-button-toggle value="compact">Compact</kbq-button-toggle>
            <kbq-button-toggle value="normal">Normal</kbq-button-toggle>
            <kbq-button-toggle value="big">Big</kbq-button-toggle>
        </kbq-button-toggle-group>

        <div class="example-stage">
            <a kbqLink href="https://koobiq.io/en/components/link" target="_blank" [size]="size()">Scan report</a>
        </div>
    `,
    styles: `
        :host {
            display: flex;
            flex-direction: column;
            align-items: center;
        }

        .example-stage {
            display: flex;
            align-items: center;
            min-height: 160px;
        }
    `,
    changeDetection: ChangeDetectionStrategy.OnPush
})
export class LinkSizeExample {
    readonly size = model<KbqDefaultSizes>('normal');
}
```

### Underline

The `underline` attribute sets when the link text is underlined. By default a link is always underlined, and a pseudo link only on hover.

**Example: Link underline** (`link-underline`)

```ts link-underline-example.ts
import { ChangeDetectionStrategy, Component, model } from '@angular/core';
import { FormsModule } from '@angular/forms';
import { KbqButtonToggleModule } from '@koobiq/components/button-toggle';
import { KbqLink, KbqLinkUnderline } from '@koobiq/components/link';

@Component({
    selector: 'link-underline-example',
    imports: [KbqLink, KbqButtonToggleModule, FormsModule],
    template: `
        <kbq-button-toggle-group [(ngModel)]="underline">
            <kbq-button-toggle value="always">Always</kbq-button-toggle>
            <kbq-button-toggle value="hover">Hover</kbq-button-toggle>
            <kbq-button-toggle value="none">None</kbq-button-toggle>
        </kbq-button-toggle-group>

        <div class="example-stage">
            <a kbqLink href="https://koobiq.io/en/components/link" target="_blank" [underline]="underline()">
                Scan report
            </a>
        </div>
    `,
    styles: `
        :host {
            display: flex;
            flex-direction: column;
            align-items: center;
        }

        .example-stage {
            display: flex;
            align-items: center;
            min-height: 160px;
        }
    `,
    changeDetection: ChangeDetectionStrategy.OnPush
})
export class LinkUnderlineExample {
    readonly underline = model<KbqLinkUnderline>('always');
}
```

### Disabled

The `disabled` attribute makes the link inactive. It keeps its address, but cannot be followed.

**Example: Link disabled** (`link-disabled`)

```ts link-disabled-example.ts
import { ChangeDetectionStrategy, Component, model } from '@angular/core';
import { FormsModule } from '@angular/forms';
import { KbqLink } from '@koobiq/components/link';
import { KbqToggleModule } from '@koobiq/components/toggle';

@Component({
    selector: 'link-disabled-example',
    imports: [KbqLink, KbqToggleModule, FormsModule],
    template: `
        <kbq-toggle [(ngModel)]="disabled">Disabled</kbq-toggle>

        <div class="example-stage">
            <a kbqLink href="https://koobiq.io/en/components/link" target="_blank" [disabled]="disabled()">
                Scan report
            </a>
        </div>
    `,
    styles: `
        :host {
            display: flex;
            flex-direction: column;
            align-items: center;
        }

        .example-stage {
            display: flex;
            align-items: center;
            min-height: 160px;
        }
    `,
    changeDetection: ChangeDetectionStrategy.OnPush
})
export class LinkDisabledExample {
    readonly disabled = model(true);
}
```

### Visited

The `useVisited` attribute colors visited links. It is useful on collection pages, such as article roundups and reading lists, where the color marks reading progress.

**Example: Link visited** (`link-visited`)

```ts link-visited-example.ts
import { ChangeDetectionStrategy, Component } from '@angular/core';
import { KbqLink } from '@koobiq/components/link';

@Component({
    selector: 'link-visited-example',
    imports: [KbqLink],
    template: `
        <a kbqLink href="https://koobiq.io/en/components/link" target="_blank" useVisited>Scan report</a>
    `,
    styles: `
        :host {
            display: flex;
            align-items: center;
            justify-content: center;
            min-height: 160px;
        }
    `,
    changeDetection: ChangeDetectionStrategy.OnPush
})
export class LinkVisitedExample {}
```

### Pseudo link

A pseudo link looks like a link, but acts as a button, performing an action without leaving the page. Use it for an action inside text.

**Example: Link pseudo** (`link-pseudo`)

```ts link-pseudo-example.ts
import { ChangeDetectionStrategy, Component } from '@angular/core';
import { KbqLink } from '@koobiq/components/link';

@Component({
    selector: 'link-pseudo-example',
    imports: [KbqLink],
    template: `
        <span kbqLink>Scan report</span>
    `,
    styles: `
        :host {
            display: flex;
            align-items: center;
            justify-content: center;
            min-height: 160px;
        }
    `,
    changeDetection: ChangeDetectionStrategy.OnPush
})
export class LinkPseudoExample {}
```

### Content

#### Icon

Mark an icon before the text with `kbqLinkPrefix` and an icon after the text with `kbqLinkSuffix`. The icon is within the click area, but is not underlined.

**Example: Link icons** (`link-icons`)

```ts link-icons-example.ts
import { ChangeDetectionStrategy, Component } from '@angular/core';
import { KbqIconModule } from '@koobiq/components/icon';
import { KbqLink, KbqLinkPrefix, KbqLinkSuffix } from '@koobiq/components/link';

@Component({
    selector: 'link-icons-example',
    imports: [KbqLink, KbqLinkPrefix, KbqLinkSuffix, KbqIconModule],
    template: `
        <a kbqLink href="https://koobiq.io/en/components/link" target="_blank">
            <i kbqLinkPrefix kbq-icon="kbq-clock_16"></i>
            Scan history
        </a>

        <a kbqLink href="https://koobiq.io/en/components/link" target="_blank">
            Scan report
            <i kbqLinkSuffix kbq-icon="kbq-file-text-o_16"></i>
        </a>
    `,
    styles: `
        :host {
            display: flex;
            align-items: center;
            justify-content: center;
            gap: var(--kbq-size-xxl);
            min-height: 160px;
        }
    `,
    changeDetection: ChangeDetectionStrategy.OnPush
})
export class LinkIconsExample {}
```

#### Multi-line link

A long link wraps like plain text, and every line is underlined.

**Example: Link multi-line** (`link-multi-line`)

```ts link-multi-line-example.ts
import { ChangeDetectionStrategy, Component } from '@angular/core';
import { KbqIconModule } from '@koobiq/components/icon';
import { KbqLink, KbqLinkPrefix } from '@koobiq/components/link';

@Component({
    selector: 'link-multi-line-example',
    imports: [KbqLink, KbqLinkPrefix, KbqIconModule],
    template: `
        <p class="example-text">
            I fully agree
            <a kbqLink external href="https://koobiq.io/en/components/link" target="_blank">
                <i kbqLinkPrefix kbq-icon="kbq-scroll-o_16"></i>
                with the terms of the license agreement
            </a>
        </p>
    `,
    styles: `
        :host {
            display: flex;
            align-items: center;
            justify-content: center;
            min-height: 160px;
        }

        .example-text {
            width: 200px;
            margin: 0;
        }
    `,
    changeDetection: ChangeDetectionStrategy.OnPush
})
export class LinkMultiLineExample {}
```

#### Link in text

Put the preposition that belongs to the link inside it. Put the period that ends the sentence in an element with `kbqLinkSuffix`, so that it takes the link color, but is not underlined.

**Example: Link in text** (`link-in-text`)

```ts link-in-text-example.ts
import { ChangeDetectionStrategy, Component } from '@angular/core';
import { KbqLink, KbqLinkSuffix } from '@koobiq/components/link';

@Component({
    selector: 'link-in-text-example',
    imports: [KbqLink, KbqLinkSuffix],
    template: `
        <p class="example-text">
            Learn more
            <a kbqLink href="https://koobiq.io/en/components/link" target="_blank">
                about scan reports
                <span kbqLinkSuffix>.</span>
            </a>
        </p>
    `,
    styles: `
        :host {
            display: flex;
            align-items: center;
            justify-content: center;
            min-height: 160px;
        }

        .example-text {
            margin: 0;
        }
    `,
    changeDetection: ChangeDetectionStrategy.OnPush
})
export class LinkInTextExample {}
```

### Destination

#### New tab and external pages

The `external` attribute adds the icon to a link to an external page or to a link that opens in a new tab. It does not open the page in a separate tab itself, so add the `target="_blank"` attribute for that.

**Example: Link external** (`link-external`)

```ts link-external-example.ts
import { ChangeDetectionStrategy, Component } from '@angular/core';
import { KbqLink } from '@koobiq/components/link';

@Component({
    selector: 'link-external-example',
    imports: [KbqLink],
    template: `
        <a kbqLink external href="https://www.cvedetails.com/cve/CVE-2019-1020010/" target="_blank">CVE-2019-1020010</a>
    `,
    styles: `
        :host {
            display: flex;
            align-items: center;
            justify-content: center;
            gap: var(--kbq-size-xxl);
            min-height: 160px;
        }
    `,
    changeDetection: ChangeDetectionStrategy.OnPush
})
export class LinkExternalExample {}
```

#### External application

When a link opens another application, name the application in the link text. Instead of the icon, the application logo can be shown with `kbqLinkSuffix`.

**Example: Link application** (`link-application`)

```ts link-application-example.ts
import { NgOptimizedImage } from '@angular/common';
import { ChangeDetectionStrategy, Component } from '@angular/core';
import { KbqLink, KbqLinkSuffix } from '@koobiq/components/link';

@Component({
    selector: 'link-application-example',
    imports: [KbqLink, KbqLinkSuffix, NgOptimizedImage],
    template: `
        <a kbqLink href="https://koobiq.io/en/components/link" target="_blank">
            Scan report in AI Desktop
            <img
                kbqLinkSuffix
                class="example-app-icon"
                ngSrc="https://koobiq.io/assets/images/favicons/icon.svg"
                width="16"
                height="16"
                alt=""
            />
        </a>

        <a kbqLink external href="https://koobiq.io/en/components/link" target="_blank">Scan report in AI Desktop</a>
    `,
    styles: `
        :host {
            display: flex;
            align-items: center;
            justify-content: center;
            gap: var(--kbq-size-xxl);
            min-height: 160px;
        }

        .example-app-icon {
            vertical-align: text-bottom;
        }
    `,
    changeDetection: ChangeDetectionStrategy.OnPush
})
export class LinkApplicationExample {}
```

### Printing

The `print` attribute adds the link address after its text when the page is printed, without the protocol and `www.`. To print something else, pass the text to the attribute.

**Example: Link print** (`link-print`)

```ts link-print-example.ts
import { ChangeDetectionStrategy, Component } from '@angular/core';
import { KbqLink } from '@koobiq/components/link';

@Component({
    selector: 'link-print-example',
    imports: [KbqLink],
    template: `
        <a kbqLink print href="https://www.cvedetails.com/cve/CVE-2019-1020010/" target="_blank">CVE-2019-1020010</a>
    `,
    styles: `
        :host {
            display: flex;
            align-items: center;
            justify-content: center;
            min-height: 160px;
        }
    `,
    changeDetection: ChangeDetectionStrategy.OnPush
})
export class LinkPrintExample {}
```

### Default settings

`kbqLinkOptionsProvider` sets the link defaults for the whole application or for one component. A value set on the link itself takes precedence.

```ts
bootstrapApplication(AppComponent, {
    providers: [kbqLinkOptionsProvider({ size: 'compact', useVisited: true })]
});
```

### Keyboard

| Key       | Action              |
| --------- | ------------------- |
| ⏎         | Follow the link     |
| Space \ ⏎ | Press a pseudo link |

### Recommendations

- Open links in the same tab by default.
- For an action inside text, use a pseudo link. For interactivity outside text, use a [ghost button](https://koobiq.io/en/components/button.md), whose click area is larger.
- For the primary action in a [modal dialog](https://koobiq.io/en/components/modal.md), use a [button](https://koobiq.io/en/components/button.md).
- A link should not lead to the page it is on. You click, the page loads, and you are where you started. The exception is a page with refreshable content, where the link duplicates the refresh.
- A link should work like a link, not only look like one. Use the `<a>` tag, so that the address can be copied and the page opened in a new tab from the context menu.
- The link text answers "what? where?". A pseudo link is worded like a button.

## API

### Components

#### KbqLink (component)

Link of the design system. Applied to an `<a>` with a `href`, so that the browser keeps treating it as a
link, or to any other element, which makes it a pseudo link that acts as a button. The component renders the
text between the `kbqLinkPrefix` and `kbqLinkSuffix` content, and only the text is underlined.

```ts
@Component({ selector: '[kbqLink]', exportAs: 'kbqLink' })
class KbqLink {
    readonly disabled = input<boolean>(false);
    readonly pseudo = input<boolean>(false);
    readonly external = input<boolean>(false);
    readonly underline = input<KbqLinkUnderline>();
    readonly size = input<KbqDefaultSizes>(this.options.size);
    readonly useVisited = input<boolean>(this.options.useVisited);
    readonly print = input<string | null>();
    focus(): void;
    getHostElement(): HTMLElement;
}
```

- `[disabled]`: `boolean` — Whether the link is disabled.
- `[pseudo]`: `boolean` — Whether an `<a>` is a pseudo link: a control without a `href` that looks like a link. Any other element is
  a pseudo link anyway. A pseudo link gets the `button` role and is activated with Enter and Space, unless
  the element is a `<button>` or a `<label>`, declares a role of its own in the template, or is taken out of
  the tab order with a negative `tabIndex`. A key that another directive on the element has already handled,
  as `kbqDropdownTriggerFor` does, is left to it.
- `[external]`: `boolean` — Whether the link leads outside the product. Adds the external link icon after the text. It does not set
  `target`: bind `target="_blank"` as well to open the page in a new tab.
- `[underline]`: `KbqLinkUnderline` — When the text is underlined. Defaults to the app-wide `KBQ_LINK_OPTIONS`, and without one there to
  `always` for a link and `hover` for a pseudo link.
- `[size]`: `KbqDefaultSizes` — Size of the link: its typography and the gaps to its icons. Defaults to the app-wide
  `KBQ_LINK_OPTIONS`.
- `[useVisited]`: `boolean` — Whether a visited link is styled differently. Defaults to the app-wide `KBQ_LINK_OPTIONS`.
- `[print]`: `string | null` — What to print after the link text when the page is printed. An empty string, which a valueless `print`
  attribute is, prints the `href` without its protocol and `www.`; any other string is printed as is. Unbound
  or `null`, nothing is printed.
- `focus()`: `void` — Focuses the link.
- `getHostElement()`: `HTMLElement` — The element the link is applied to.

### Directives

#### KbqLinkPrefix (directive)

Marks content to be projected before the text of a link, such as a leading icon.

```ts
@Directive({ selector: '[kbqLinkPrefix]' })
class KbqLinkPrefix {}
```

#### KbqLinkSuffix (directive)

Marks content to be projected after the text of a link: a trailing icon, or the punctuation that ends a
sentence, which takes the link color without the underline. It wraps to the next line together with the last
word only.

```ts
@Directive({ selector: '[kbqLinkSuffix]' })
class KbqLinkSuffix {}
```

### Functions

#### kbqLinkOptionsProvider (function)

Overrides the default link options within the given injector scope: the whole application from
`bootstrapApplication`, or one subtree from the `providers` of a component or a route.

```ts
function kbqLinkOptionsProvider(
    options: Partial<KbqLinkOptions>
): Provider;
```

### Types

#### KbqLinkOptions (type)

Settings a whole application shares, rather than something a single link decides: how big links are, when
they are underlined and whether visited ones stand out. Where a link leads and how it behaves stay on the
link itself.

```ts
type KbqLinkOptions = {
    size: KbqDefaultSizes;
    underline?: KbqLinkUnderline;
    useVisited: boolean;
};
```

- `size`: `KbqDefaultSizes` — Size of a link: its typography and the gaps to its icons.
- `underline?`: `KbqLinkUnderline` — When the text of a link and of a pseudo link is underlined. Unset, a link is always underlined and a pseudo
  link only on hover.
- `useVisited`: `boolean` — Whether a visited link is styled differently.

#### KbqLinkUnderline (type)

When the text of a link is underlined: always, only while the pointer is over the link, or never.

```ts
type KbqLinkUnderline = 'always' | 'hover' | 'none';
```

### Constants

#### KBQ_LINK_OPTIONS (const)

Injection token holding the current `KbqLinkOptions`.

```ts
const KBQ_LINK_OPTIONS: InjectionToken<KbqLinkOptions>;
```

## Examples

### Link with caption

A caption under the link is placed in an element with `kbqLinkSuffix`.

**Example: Link with caption** (`link-with-caption`)

```ts link-with-caption-example.ts
import { ChangeDetectionStrategy, Component } from '@angular/core';
import { KbqLink, KbqLinkSuffix } from '@koobiq/components/link';

@Component({
    selector: 'link-with-caption-example',
    imports: [KbqLink, KbqLinkSuffix],
    template: `
        <a kbqLink external href="https://koobiq.io/en/components/link" target="_blank">
            Scan report
            <span class="example-link-caption" kbqLinkSuffix>task/koobiq.io</span>
        </a>
    `,
    styles: `
        :host {
            display: flex;
            align-items: center;
            justify-content: center;
            min-height: 160px;
        }

        .example-link-caption {
            display: flex;
            color: var(--kbq-foreground-contrast-secondary);
        }
    `,
    changeDetection: ChangeDetectionStrategy.OnPush
})
export class LinkWithCaptionExample {}
```
