# Progress spinner

- Entry point: `@koobiq/components/progress-spinner`
- NgModule: `KbqProgressSpinnerModule`
- Page: https://koobiq.io/en/components/progress-spinner/overview

## Overview

`<kbq-progress-spinner>` is a component that displays a progress indicator as a spinner.

### Simple progress spinner

A `<kbq-progress-spinner>` element can be used on its own to create a sector progress with koobiq theme

```html
<kbq-progress-spinner></kbq-progress-spinner>
```

**Example: Basic progress spinner** (`progress-spinner-overview`)

```ts progress-spinner-overview-example.ts
import { afterNextRender, ChangeDetectionStrategy, Component, OnDestroy, signal } from '@angular/core';
import { KbqProgressSpinnerModule } from '@koobiq/components/progress-spinner';

const DELAY: number = 300;
const STEP: number = 4;
const MAX_PERCENT: number = 100;

@Component({
    selector: 'progress-spinner-overview-example',
    imports: [KbqProgressSpinnerModule],
    template: `
        <small [style.width.px]="40">{{ percent() }}%</small>
        <kbq-progress-spinner [value]="percent()" />
    `,
    changeDetection: ChangeDetectionStrategy.OnPush,
    host: {
        class: 'layout-margin-5xl layout-align-center-center layout-row'
    }
})
export class ProgressSpinnerOverviewExample implements OnDestroy {
    readonly percent = signal(0);
    private intervalId: ReturnType<typeof setInterval>;

    constructor() {
        afterNextRender(() => {
            this.intervalId = setInterval(
                () => this.percent.update((value) => (value + STEP) % (MAX_PERCENT + STEP)),
                DELAY
            );
        });
    }

    ngOnDestroy() {
        clearInterval(this.intervalId);
    }
}
```

### Props

#### value

Displaying sector filling progress depends on this property\
The range of value is \[0, 100]\
Default: 0

This will fill 30% of the sector

```html
<kbq-progress-spinner [value]="30"></kbq-progress-spinner>
```

#### mode

Enum ('determinate', 'indeterminate')\
Default: 'determinate'

To show indeterminate progress

```html
<kbq-progress-spinner [mode]="'indeterminate'"></kbq-progress-spinner>
```

Or for determinate progress

```html
<kbq-progress-spinner [mode]="'determinate'" [value]="30"></kbq-progress-spinner>
```

**Example: Progress spinner indeterminate** (`progress-spinner-indeterminate`)

```ts progress-spinner-indeterminate-example.ts
import { ChangeDetectionStrategy, Component } from '@angular/core';
import { KbqProgressSpinnerModule } from '@koobiq/components/progress-spinner';

@Component({
    selector: 'progress-spinner-indeterminate-example',
    imports: [KbqProgressSpinnerModule],
    template: `
        <kbq-progress-spinner class="layout-margin-right-s" size="big" mode="indeterminate" />
        <kbq-progress-spinner class="layout-margin-right-s" size="big" color="contrast" mode="indeterminate" />
        <kbq-progress-spinner size="big" color="contrast-fade" mode="indeterminate" />
    `,
    changeDetection: ChangeDetectionStrategy.OnPush,
    host: {
        class: 'layout-margin-5xl layout-align-center-center layout-row'
    }
})
export class ProgressSpinnerIndeterminateExample {}
```

## API

### Components

#### KbqProgressSpinner (component)

Component that reports the progress of an ongoing operation.

```ts
@Component({ selector: 'kbq-progress-spinner' })
class KbqProgressSpinner extends KbqColorDirective {
    readonly id = input<string>(
        inject(_IdGenerator).getId('kbq-progress-spinner-')
    );
    readonly value = input<number>(0);
    readonly mode = input<ProgressSpinnerMode>('determinate');
    readonly size = input<ProgressSpinnerSize>('compact');
    readonly color = input<T | null | undefined>();
    get colorClassName(): string;
    setDefaultColor(color: T): void;
}
```

- `[id]`: `string` — Unique id of the spinner.
- `[value]`: `number` — Progress of the operation, in percent. Clamped to `[0, 100]` and only rendered in `determinate` mode.

  Anything that is not a number reads as `0`: the value feeds a `stroke-dashoffset` percentage, and a
  bare `numberAttribute` would turn a null binding into `NaN%`, which is not a length at all. The
  transform is typed rather than taking `unknown`, so `[value]="progress$ | async"` and `value="40"`
  keep type-checking while an object or an array stays a template type error.
- `[mode]`: `ProgressSpinnerMode` — Whether the spinner reports `value` or spins indefinitely.
- `[size]`: `ProgressSpinnerSize` — Size of the spinner.
- `[color]`: `T | null | undefined` — Color of the component. A value set in code holds until the input changes, and the default color is used
  while both are unset or falsy.
- `colorClassName`: `string` — current class name of color
- `setDefaultColor()`: `void` — this color will be used as a default value. For example [color]="'' | false | undefined | null".

### Directives

#### KbqProgressSpinnerCaption (directive)

Directive that marks the caption of a progress spinner.

```ts
@Directive({ selector: '[kbq-progress-spinner-caption]' })
class KbqProgressSpinnerCaption {}
```

#### KbqProgressSpinnerText (directive)

Directive that marks the text of a progress spinner.

```ts
@Directive({ selector: '[kbq-progress-spinner-text]' })
class KbqProgressSpinnerText {}
```

### Types

#### ProgressSpinnerMode (type)

Whether the spinner reports a known progress value or spins indefinitely.

```ts
type ProgressSpinnerMode = 'determinate' | 'indeterminate';
```

#### ProgressSpinnerSize (type)

Sizes supported by the progress spinner.

```ts
type ProgressSpinnerSize = Exclude<KbqDefaultSizes, 'normal'>;
```
