# FilterModel

> Headless filtering model for search-as-you-type option lists such as a command palette.

```ts
import { FilterModel } from "@sdxc/ui/behaviors";
```

Owns the query, the matched option set, and the active match for a
filterable list, dispatching `"change"` whenever any of the three moves, so
a DOM adapter stays a thin layer forwarding input and reading state back.

## Signature

```ts
new FilterModel(init?: FilterModel.Init)
```

## Parameters

| Parameter | Type | Description |
| --- | --- | --- |
| `init?` | `FilterModel.Init` | Initial options, query, and match override. |

## Properties

| Property | Type | Description |
| --- | --- | --- |
| `query` | `string` | Current query string filtering the option set. |
| `options` | `readonly FilterModel.Option[]` | Full option set the model filters over, in the order last provided. |
| `matches` | `readonly FilterModel.Option[]` | Options whose value or keywords currently match the query, in their original order. |
| `activeId` | `string \| null` | Id of the currently active match, or `null` when nothing is active. |
| `activeOption` | `FilterModel.Option \| null` | The active match's full option, or `null` when nothing is active. |
| `isEmpty` | `boolean` | `true` when the current query has no matches. |

## Methods

| Method | Description |
| --- | --- |
| `setOptions(options: Iterable<FilterModel.Option>): void` | Replaces the option set and recomputes matches against the current query, keeping the active option while it still matches and falling back to the first match otherwise. Always dispatches `"change"`. |
| `setQuery(query: string): void` | Updates the query and recomputes matches, keeping the active option while it still matches and falling back to the first match otherwise. A no-op when `query` equals the current query. |
| `isMatch(id: string): boolean` | Reports whether an option id is part of the current matched set. |
| `setActive(id: string \| null): void` | Sets the active option explicitly. An `id` outside the current matches is ignored, so the active option always stays a visible match. Dispatches `"change"` only when the active id actually changes. |
| `moveNext(): void` | Moves activation to the match after the current one, wrapping to the first match after the last. Activates the first match when nothing is currently active. |
| `movePrevious(): void` | Moves activation to the match before the current one, wrapping to the last match before the first. Activates the last match when nothing is currently active. |
| `moveFirst(): void` | Activates the first match, or clears activation when there are no matches. |
| `moveLast(): void` | Activates the last match, or clears activation when there are no matches. |

## Used with it

The events, constants and types its module publishes, each imported from `@sdxc/ui/behaviors` too.

### FilterModel.Option

One filterable option. `id` is the stable key a consumer uses to
correlate a rendered item with matched/active state; `value` and
`keywords` are the text compared against the query.

#### Members

| Member | Type | Description |
| --- | --- | --- |
| `id` | `string` | Stable identifier correlated with a rendered item. |
| `value` | `string` | Primary text compared against the query. |
| `keywords?` | `readonly string[]` | Additional search terms folded into matching alongside `value`. |

### FilterModel.Init

Construction options accepted by FilterModel.

#### Members

| Member | Type | Description |
| --- | --- | --- |
| `options?` | `Iterable<Option>` | Initial option set the model filters over. Defaults to none. |
| `query?` | `string` | Initial query string. Defaults to an empty string. |
| `match?` | `(option: Option, query: string) => boolean` | Overrides the default case-insensitive substring match against `value` and `keywords`. |

### FilterModel.EventMap

Events dispatched by FilterModel as its state changes.

#### Members

| Member | Type | Description |
| --- | --- | --- |
| `change` | `Event` | Dispatched whenever the query, the matched set, or the active option changes. |
