# InfiniteScroll

![Status](https://img.shields.io/badge/status-stable-brightgreen)

Diretiva de scroll infinito que detecta quando o usuário chega ao final de um elemento com scroll e emite o evento `scrolled`. Deve ser aplicada a um elemento com `overflow` e scroll habilitado.

## Quando usar

- Listas longas carregadas de API com paginação progressiva
- Feeds de conteúdo (notícias, posts, cards) com carregamento sob demanda
- Tabelas ou listas com muitos registros onde a paginação clássica é indesejada

## Quando não usar

- Listas curtas onde todos os itens podem ser carregados de uma vez — carregue tudo e exiba diretamente
- Quando o usuário precisa navegar para uma página específica — prefira paginação com controles numéricos

## Instalação

```typescript
import { InfiniteScrollModule } from '@seniorsistemas/angular-components/infinite-scroll';

@NgModule({
    imports: [InfiniteScrollModule],
})
export class MeuModule {}
```

## Uso básico

```html
<div
    sInfiniteScroll
    (scrolled)="carregarMais()"
    style="overflow-y: auto; height: 400px;"
>
    <!-- itens da lista -->
</div>
```

## API

### Inputs

Esta diretiva não possui inputs configuráveis.

### Outputs

| Evento | Tipo | Descrição |
|--------|------|-----------|
| `scrolled` | `EventEmitter<number>` | Emitido quando o usuário atinge o final do elemento com scroll. |

## Exemplos

### Lista com carregamento progressivo

```html
<div
    sInfiniteScroll
    (scrolled)="carregarMais()"
    style="height: 300px; overflow-y: auto;"
>
    @for (item of itens; track item.id) {
        <div>{{ item.nome }}</div>
    }
    @if (carregando) {
        <div>Carregando...</div>
    }
</div>
```

```typescript
carregarMais() {
    if (this.carregando) return;
    this.carregando = true;
    this.api.buscarItens(this.pagina++).subscribe(novosItens => {
        this.itens = [...this.itens, ...novosItens];
        this.carregando = false;
    });
}
```

### Com indicador de fim de lista

```html
<div sInfiniteScroll (scrolled)="carregarMais()" style="height: 300px; overflow-y: auto;">
    @for (item of itens; track item) {
        <div>{{ item }}</div>
    }
    @if (carregando) {
        <div>Carregando...</div>
    }
    @if (!temMais && !carregando) {
        <div>Todos os registros foram carregados.</div>
    }
</div>
```

### Com debounce no callback (recomendado para APIs)

```typescript
import { Subject } from 'rxjs';
import { debounceTime } from 'rxjs/operators';

private scroll$ = new Subject<void>();

ngOnInit() {
    this.scroll$.pipe(debounceTime(300)).subscribe(() => this.buscarProximaPagina());
}

onScrolled() {
    this.scroll$.next();
}
```

```html
<div sInfiniteScroll (scrolled)="onScrolled()" style="height: 400px; overflow-y: auto;">
    <!-- itens -->
</div>
```

## Acessibilidade

- O elemento hospedeiro deve ter altura definida e `overflow-y: auto` ou `overflow-y: scroll`
- A diretiva não possui debounce interno — implemente no callback quando necessário para evitar múltiplas requisições simultâneas
- O evento `scrolled` é disparado quando `scrollTop > scrollHeight - offsetHeight - 2`

## Componentes relacionados

- [`LoadingState`](../loading-state/README.md) — indicador de carregamento a ser exibido durante o scroll
