# Splitter

- Entry point: `@koobiq/components/splitter`
- NgModule: `KbqSplitterModule`
- Page: https://koobiq.io/en/components/splitter/overview

## Overview

Splitter resizes neighboring panels by dragging the separator.

Only panels placed directly inside `kbq-splitter`, without a wrapper element, participate in the layout.

**Example: Splitter overview** (`splitter-overview`)

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

@Component({
    selector: 'splitter-overview-example',
    imports: [KbqSplitter, KbqSplitterPanel],
    template: `
        <kbq-splitter class="example-splitter">
            <kbq-splitter-panel minSize="100">
                <div class="example-splitter-panel-content">Panel 1</div>
            </kbq-splitter-panel>
            <kbq-splitter-panel minSize="100">
                <div class="example-splitter-panel-content">Panel 2</div>
            </kbq-splitter-panel>
        </kbq-splitter>
    `,
    styles: `
        :host {
            display: block;
            padding: var(--kbq-size-l);
        }

        .example-splitter {
            height: 200px;
            border: 1px solid var(--kbq-line-contrast-less);
            border-radius: var(--kbq-size-border-radius);
        }

        .example-splitter-panel-content {
            flex: 1;
            align-content: center;
            text-align: center;
            user-select: none;
            white-space: nowrap;
            overflow: hidden;
            text-overflow: ellipsis;
            color: var(--kbq-foreground-contrast-secondary);
        }
    `,
    changeDetection: ChangeDetectionStrategy.OnPush
})
export class SplitterOverviewExample {}
```

### Appearance

The `appearance` input sets how the separator is drawn:

| Variant       | Description                                                                            |
| ------------- | -------------------------------------------------------------------------------------- |
| `divider`     | Dividing line. Used by default                                                         |
| `transparent` | Invisible separator. Use it when panels differ by background or have their own borders |
| `handle`      | Drag handle at the center of the boundary                                              |

`kbqSplitterOptionsProvider` sets the default appearance for the whole application or for one injector.

**Example: Splitter appearance** (`splitter-appearance`)

```ts splitter-appearance-example.ts
import { ChangeDetectionStrategy, Component, model } from '@angular/core';
import { FormsModule } from '@angular/forms';
import { KbqButtonToggleModule } from '@koobiq/components/button-toggle';
import { KbqSplitter, KbqSplitterAppearance, KbqSplitterPanel } from '@koobiq/components/splitter';

@Component({
    selector: 'splitter-appearance-example',
    imports: [KbqSplitter, KbqSplitterPanel, KbqButtonToggleModule, FormsModule],
    template: `
        <kbq-button-toggle-group class="example-toggle-group" [(ngModel)]="appearance">
            @for (appearance of appearances; track appearance) {
                <kbq-button-toggle [value]="appearance">{{ appearance }}</kbq-button-toggle>
            }
        </kbq-button-toggle-group>

        <kbq-splitter class="example-splitter" [appearance]="appearance()">
            <kbq-splitter-panel minSize="125">
                <div class="example-splitter-panel-content layout-margin-right-s">Panel 1</div>
            </kbq-splitter-panel>
            <kbq-splitter-panel minSize="125">
                <div class="example-splitter-panel-content layout-margin-left-s">Panel 2</div>
            </kbq-splitter-panel>
        </kbq-splitter>
    `,
    styles: `
        :host {
            display: flex;
            flex-direction: column;
            gap: var(--kbq-size-l);
            padding: var(--kbq-size-l);
        }

        .example-toggle-group {
            align-self: center;
        }

        .example-splitter {
            height: 200px;
        }

        .example-splitter-panel-content {
            flex: 1;
            align-content: center;
            text-align: center;
            user-select: none;
            white-space: nowrap;
            overflow: hidden;
            text-overflow: ellipsis;
            color: var(--kbq-foreground-contrast-secondary);
            background-color: var(--kbq-background-bg-secondary);
            border-radius: var(--kbq-size-border-radius);
        }
    `,
    changeDetection: ChangeDetectionStrategy.OnPush
})
export class SplitterAppearanceExample {
    protected readonly appearances: KbqSplitterAppearance[] = ['divider', 'transparent', 'handle'];
    protected readonly appearance = model<KbqSplitterAppearance>('handle');
}
```

### Orientation

The `orientation` input sets the layout direction: `horizontal` places panels in a row, `vertical` in a column.

**Example: Splitter orientation** (`splitter-orientation`)

```ts splitter-orientation-example.ts
import { ChangeDetectionStrategy, Component, model } from '@angular/core';
import { FormsModule } from '@angular/forms';
import { KbqButtonToggleModule } from '@koobiq/components/button-toggle';
import { KbqSplitter, KbqSplitterOrientation, KbqSplitterPanel } from '@koobiq/components/splitter';

@Component({
    selector: 'splitter-orientation-example',
    imports: [KbqSplitter, KbqSplitterPanel, KbqButtonToggleModule, FormsModule],
    template: `
        <kbq-button-toggle-group class="example-toggle-group" [(ngModel)]="orientation">
            @for (orientation of orientations; track orientation) {
                <kbq-button-toggle [value]="orientation">{{ orientation }}</kbq-button-toggle>
            }
        </kbq-button-toggle-group>

        <kbq-splitter class="example-splitter" [orientation]="orientation()">
            <kbq-splitter-panel minSize="70">
                <div class="example-splitter-panel-content">Panel 1</div>
            </kbq-splitter-panel>
            <kbq-splitter-panel minSize="70">
                <div class="example-splitter-panel-content">Panel 2</div>
            </kbq-splitter-panel>
        </kbq-splitter>
    `,
    styles: `
        :host {
            display: flex;
            flex-direction: column;
            gap: var(--kbq-size-l);
            padding: var(--kbq-size-l);
        }

        .example-toggle-group {
            align-self: center;
        }

        .example-splitter {
            height: 300px;
            border: 1px solid var(--kbq-line-contrast-less);
            border-radius: var(--kbq-size-border-radius);
        }

        .example-splitter-panel-content {
            flex: 1;
            align-content: center;
            text-align: center;
            user-select: none;
            white-space: nowrap;
            overflow: hidden;
            text-overflow: ellipsis;
            color: var(--kbq-foreground-contrast-secondary);
        }
    `,
    changeDetection: ChangeDetectionStrategy.OnPush
})
export class SplitterOrientationExample {
    protected readonly orientations: KbqSplitterOrientation[] = ['horizontal', 'vertical'];
    protected readonly orientation = model<KbqSplitterOrientation>('vertical');
}
```

### Disabling

The `disabled` input forbids resizing: the separators stop reacting to the pointer and the keyboard, leave the tab order and show the plain cursor.

**Example: Splitter disabled** (`splitter-disabled`)

```ts splitter-disabled-example.ts
import { ChangeDetectionStrategy, Component, signal } from '@angular/core';
import { KbqSplitter, KbqSplitterPanel } from '@koobiq/components/splitter';
import { KbqToggleModule } from '@koobiq/components/toggle';

@Component({
    selector: 'splitter-disabled-example',
    imports: [KbqSplitter, KbqSplitterPanel, KbqToggleModule],
    template: `
        <kbq-toggle [checked]="disabled()" (change)="disabled.set($event.checked)">disabled</kbq-toggle>

        <kbq-splitter class="example-splitter" [disabled]="disabled()">
            <kbq-splitter-panel minSize="100">
                <div class="example-splitter-panel-content">Panel 1</div>
            </kbq-splitter-panel>
            <kbq-splitter-panel minSize="100">
                <div class="example-splitter-panel-content">Panel 2</div>
            </kbq-splitter-panel>
        </kbq-splitter>
    `,
    styles: `
        :host {
            display: flex;
            flex-direction: column;
            gap: var(--kbq-size-l);
            padding: var(--kbq-size-l);
        }

        kbq-toggle {
            align-self: center;
        }

        .example-splitter {
            height: 200px;
            border: 1px solid var(--kbq-line-contrast-less);
            border-radius: var(--kbq-size-border-radius);
        }

        .example-splitter-panel-content {
            flex: 1;
            align-content: center;
            text-align: center;
            user-select: none;
            white-space: nowrap;
            overflow: hidden;
            text-overflow: ellipsis;
            color: var(--kbq-foreground-contrast-secondary);
        }
    `,
    changeDetection: ChangeDetectionStrategy.OnPush
})
export class SplitterDisabledExample {
    protected readonly disabled = signal(true);
}
```

### Size and constraints

Three inputs set the size of a panel:

| Input     | Description                                                   |
| --------- | ------------------------------------------------------------- |
| `size`    | Initial size. Panels without `size` share the remaining space |
| `minSize` | Smallest size the panel can be reduced to                     |
| `maxSize` | Largest size the panel can be expanded to                     |

A value can be a number of pixels (`240`), a pixel string (`'240px'`), or a share of the splitter (`'30%'`). Units can be mixed within one splitter. Other units, such as `rem` or `vw`, are not supported: such a value is ignored, and a warning is logged in development mode.

When a neighboring panel reaches its constraint, the separator keeps moving: the panels after it give up space, so the next separator moves too.

**Example: Splitter constraints** (`splitter-constraints`)

```ts splitter-constraints-example.ts
import { ChangeDetectionStrategy, Component } from '@angular/core';
import { KbqSplitter, KbqSplitterPanel } from '@koobiq/components/splitter';

@Component({
    selector: 'splitter-constraints-example',
    imports: [KbqSplitter, KbqSplitterPanel],
    template: `
        <kbq-splitter class="example-splitter" appearance="transparent">
            <kbq-splitter-panel minSize="125">
                <div class="example-splitter-panel-content layout-margin-right-s">
                    Panel 1
                    <small>min: 125px</small>
                </div>
            </kbq-splitter-panel>
            <kbq-splitter-panel size="30%" minSize="25%" maxSize="40%">
                <div class="example-splitter-panel-content layout-margin-left-s layout-margin-right-s">
                    Panel 2
                    <small>size: 30%</small>
                    <small>min: 25%, max: 40%</small>
                </div>
            </kbq-splitter-panel>
            <kbq-splitter-panel minSize="125">
                <div class="example-splitter-panel-content layout-margin-left-s">
                    Panel 3
                    <small>min: 125px</small>
                </div>
            </kbq-splitter-panel>
        </kbq-splitter>
    `,
    styles: `
        :host {
            display: block;
            padding: var(--kbq-size-l);
        }

        .example-splitter {
            height: 200px;
        }

        .example-splitter-panel-content {
            flex: 1;
            display: flex;
            flex-direction: column;
            align-content: center;
            justify-content: center;
            text-align: center;
            user-select: none;
            white-space: nowrap;
            overflow: hidden;
            text-overflow: ellipsis;
            color: var(--kbq-foreground-contrast-secondary);
            background-color: var(--kbq-background-bg-secondary);
            border-radius: var(--kbq-size-border-radius);
        }
    `,
    changeDetection: ChangeDetectionStrategy.OnPush
})
export class SplitterConstraintsExample {}
```

### Snapping

The `snapSizes` input sets the sizes a panel snaps to. If either panel beside a separator has `snapSizes`, the `minSize` and `maxSize` of both panels also become snap points. The separator follows the pointer during a drag. The panel snaps after the drag ends.

The `snapTolerance` input sets the distance from a snap point at which a panel snaps to it. The default is 32 pixels and is set by `kbqSplitterOptionsProvider`.

**Example: Splitter snap** (`splitter-snap`)

```ts splitter-snap-example.ts
import { ChangeDetectionStrategy, Component } from '@angular/core';
import { KbqSplitter, KbqSplitterPanel } from '@koobiq/components/splitter';

@Component({
    selector: 'splitter-snap-example',
    imports: [KbqSplitter, KbqSplitterPanel],
    template: `
        <kbq-splitter class="example-splitter">
            <kbq-splitter-panel>
                <div class="example-splitter-panel-content">Panel 1</div>
            </kbq-splitter-panel>
            <kbq-splitter-panel minSize="200" maxSize="500" snapTolerance="100" [snapSizes]="[300, 400]">
                <div class="example-splitter-panel-content">
                    Panel 2
                    <small>snap: 300px, 400px</small>
                    <small>tolerance: 100px</small>
                </div>
            </kbq-splitter-panel>
        </kbq-splitter>
    `,
    styles: `
        :host {
            display: block;
            padding: var(--kbq-size-l);
        }

        .example-splitter {
            height: 200px;
            border: 1px solid var(--kbq-line-contrast-less);
            border-radius: var(--kbq-size-border-radius);
        }

        .example-splitter-panel-content {
            display: flex;
            flex-direction: column;
            flex: 1;
            justify-content: center;
            align-content: center;
            text-align: center;
            user-select: none;
            white-space: nowrap;
            overflow: hidden;
            text-overflow: ellipsis;
            color: var(--kbq-foreground-contrast-secondary);
        }
    `,
    changeDetection: ChangeDetectionStrategy.OnPush
})
export class SplitterSnapExample {}
```

### Collapsed panel

The `collapsible` input lets a panel be collapsed by dragging, and `collapsedSize` sets the width of the collapsed strip. Such a panel has no sizes in between: a drag stops at `minSize`, and pulling further collapses it.

When `collapsedSize` is zero, the panel is completely hidden and no separator remains to restore it. The panel can be expanded through the `[(collapsed)]` two-way binding, for example with a button or keyboard shortcut.

**Example: Splitter collapsible panel** (`splitter-collapsible`)

```ts splitter-collapsible-example.ts
import { ChangeDetectionStrategy, Component, model } from '@angular/core';
import { FormsModule } from '@angular/forms';
import { KbqSplitter, KbqSplitterPanel } from '@koobiq/components/splitter';
import { KbqToggleModule } from '@koobiq/components/toggle';

@Component({
    selector: 'splitter-collapsible-example',
    imports: [KbqSplitter, KbqSplitterPanel, KbqToggleModule, FormsModule],
    template: `
        <kbq-toggle [(ngModel)]="sidebarCollapsed">Sidebar collapsed</kbq-toggle>
        <kbq-toggle [(ngModel)]="terminalCollapsed">Terminal collapsed</kbq-toggle>

        <kbq-splitter class="example-splitter layout-margin-top-l">
            <kbq-splitter-panel minSize="125" size="150" maxSize="200" collapsible [(collapsed)]="sidebarCollapsed">
                <div class="example-splitter-panel-content">
                    Sidebar
                    @if (!sidebarCollapsed()) {
                        <small>Drag left to collapse</small>
                    }
                </div>
            </kbq-splitter-panel>
            <kbq-splitter-panel>
                <kbq-splitter class="example-splitter-nested" orientation="vertical">
                    <kbq-splitter-panel minSize="100">
                        <div class="example-splitter-panel-content">Editor</div>
                    </kbq-splitter-panel>
                    <kbq-splitter-panel
                        size="100"
                        minSize="75"
                        collapsible
                        collapsedSize="30"
                        [(collapsed)]="terminalCollapsed"
                    >
                        <div class="example-splitter-panel-content">
                            Terminal
                            @if (!terminalCollapsed()) {
                                <small>Drag bottom to collapse</small>
                            }
                        </div>
                    </kbq-splitter-panel>
                </kbq-splitter>
            </kbq-splitter-panel>
        </kbq-splitter>
    `,
    styles: `
        :host {
            display: flex;
            flex-direction: column;
            padding: var(--kbq-size-l);
        }

        .example-splitter {
            height: 300px;
            border: 1px solid var(--kbq-line-contrast-less);
            border-radius: var(--kbq-size-border-radius);
        }

        .example-splitter-panel-content {
            display: flex;
            flex-direction: column;
            flex: 1;
            justify-content: center;
            align-content: center;
            text-align: center;
            user-select: none;
            white-space: nowrap;
            overflow: hidden;
            text-overflow: ellipsis;
            color: var(--kbq-foreground-contrast-secondary);
        }

        .example-splitter-nested {
            flex: 1;
        }
    `,
    changeDetection: ChangeDetectionStrategy.OnPush
})
export class SplitterCollapsibleExample {
    protected readonly terminalCollapsed = model(false);
    protected readonly sidebarCollapsed = model(false);
}
```

### Nested areas

One of the panels can hold nested resizable areas.

**Example: Splitter nested** (`splitter-nested`)

```ts splitter-nested-example.ts
import { ChangeDetectionStrategy, Component } from '@angular/core';
import { KbqSplitter, KbqSplitterPanel } from '@koobiq/components/splitter';

@Component({
    selector: 'splitter-nested-example',
    imports: [KbqSplitter, KbqSplitterPanel],
    template: `
        <kbq-splitter class="example-splitter">
            <kbq-splitter-panel maxSize="200">
                <div class="example-splitter-panel-content">Sidebar</div>
            </kbq-splitter-panel>
            <kbq-splitter-panel>
                <kbq-splitter class="example-splitter-nested" orientation="vertical">
                    <kbq-splitter-panel minSize="100">
                        <kbq-splitter class="example-splitter-nested">
                            <kbq-splitter-panel minSize="100">
                                <div class="example-splitter-panel-content">Editor 1</div>
                            </kbq-splitter-panel>
                            <kbq-splitter-panel minSize="100">
                                <div class="example-splitter-panel-content">Editor 2</div>
                            </kbq-splitter-panel>
                        </kbq-splitter>
                    </kbq-splitter-panel>
                    <kbq-splitter-panel size="50">
                        <div class="example-splitter-panel-content">Terminal</div>
                    </kbq-splitter-panel>
                </kbq-splitter>
            </kbq-splitter-panel>
        </kbq-splitter>
    `,
    styles: `
        :host {
            display: flex;
            flex-direction: column;
            padding: var(--kbq-size-l);
        }

        .example-splitter {
            height: 300px;
            border: 1px solid var(--kbq-line-contrast-less);
            border-radius: var(--kbq-size-border-radius);
        }

        .example-splitter-panel-content {
            flex: 1;
            align-content: center;
            text-align: center;
            user-select: none;
            white-space: nowrap;
            overflow: hidden;
            text-overflow: ellipsis;
            color: var(--kbq-foreground-contrast-secondary);
        }

        .example-splitter-nested {
            flex: 1;
        }
    `,
    changeDetection: ChangeDetectionStrategy.OnPush
})
export class SplitterNestedExample {}
```

### Keyboard interaction

The separator is placed in the tab order between the content of neighboring panels.

| Key                      | Behavior                                                                                                         |
| ------------------------ | ---------------------------------------------------------------------------------------------------------------- |
| Left Arrow \ Right Arrow | Moves a vertical separator in the direction of the arrow.                                                        |
| Up Arrow \ Down Arrow    | Moves a horizontal separator in the direction of the arrow.                                                      |
| Home                     | Sets the smallest available size of the panel. A panel already at its minimum collapses, when it is collapsible. |
| End                      | Sets the largest available size of the panel, squeezing the neighboring panels when needed.                      |
| Enter                    | Collapses and expands the panel, when `collapsible` is set.                                                      |
| F6 \ Shift + F6          | Moves focus to the next or the previous panel.                                                                   |
| Double-click             | Resets the sizes to the ones the panels declare. A second double-click sets the panel to its minimum size.       |

## API

### Components

#### KbqSplitter (component)

Splits an area into panels the user can resize by dragging the separators between them.

Panels must be direct children of the splitter — a wrapper element around them hides them from the group.

```html
<kbq-splitter>
    <kbq-splitter-panel [minSize]="100">…</kbq-splitter-panel>
    <kbq-splitter-panel>…</kbq-splitter-panel>
</kbq-splitter>
```

```ts
@Component({ selector: 'kbq-splitter', exportAs: 'kbqSplitter' })
class KbqSplitter implements KbqSplitterGroup {
    readonly orientation = input<KbqSplitterOrientation>('horizontal');
    readonly appearance = input<KbqSplitterAppearance>(
        this.options.appearance
    );
    readonly disabled = input<boolean>(false);
    readonly layout = model<number[] | null>(null);
}
```

- `[orientation]`: `KbqSplitterOrientation` — Direction the panels are laid out in.
- `[appearance]`: `KbqSplitterAppearance` — How the separators are drawn. Defaults to the app-wide `KBQ_SPLITTER_OPTIONS`.
- `[disabled]`: `boolean` — Whether the panels can be resized at all.
- `[(layout)]`: `number[] | null` — Sizes of the panels as percentages of the splitter, in panel order.

  Two-way and, while `null`, derived from what the panels declare — so a host reads it to persist a
  layout, writes it to restore one, and shares the same signal between two splitters to keep their panels
  the same width. Setting it back to `null` returns the panels to their declared sizes.

#### KbqSplitterPanel (component)

A resizable region of a `KbqSplitter`.

Every panel but the last renders the separator that follows it, so the separator sits between the two
panels it resizes in the tab order as well as on screen.

```ts
@Component({ selector: 'kbq-splitter-panel', exportAs: 'kbqSplitterPanel' })
class KbqSplitterPanel implements KbqSplitterPanelRef {
    readonly id = input<string>(
        inject(_IdGenerator).getId('kbq-splitter-panel-')
    );
    readonly size = input<KbqSplitterSize | undefined>();
    readonly minSize = input<KbqSplitterSize | undefined>();
    readonly maxSize = input<KbqSplitterSize | undefined>();
    readonly snapSizes = input<readonly KbqSplitterSize[]>([]);
    readonly snapTolerance = input<number>(this.options.snapTolerance);
    readonly collapsible = input<boolean>(false);
    readonly collapsedSize = input<KbqSplitterSize>(0);
    readonly collapsed = model<boolean>(false);
    readonly separatorAriaLabel = input<string | undefined>();
}
```

- `[id]`: `string` — Identifies the panel to the `aria-controls` of its own separator, and gives a host something to point
  `aria-labelledby` or a fragment link at. Generated when omitted.
- `[size]`: `KbqSplitterSize | undefined` — Size the panel starts at, in pixels (`240`, `'240px'`) or as a share of the splitter (`'30%'`).
  Panels that leave it unset share whatever the sized ones did not claim.
- `[minSize]`: `KbqSplitterSize | undefined` — Smallest size the panel may be dragged to. Defaults to `0`.
- `[maxSize]`: `KbqSplitterSize | undefined` — Largest size the panel may be dragged to. Unbounded when omitted.
- `[snapSizes]`: `readonly KbqSplitterSize[]` — Sizes a drag is pulled onto when it is released near one. `minSize` and `maxSize` become snap points too
  as soon as either panel around a separator declares any snap size.

  The layout the panels start at settles onto them as well, so a splitter is never handed to the user
  sitting between two of its own snap points.
- `[snapTolerance]`: `number` — How close to one of this panel's `snapSizes` a drag has to be released for it to be pulled in, in
  pixels. Raise it to make the snap points reach further — past half the gap between two of them the panel
  can only ever land on a snap size.

  Defaults to the app-wide `KBQ_SPLITTER_OPTIONS`.
- `[collapsible]`: `boolean` — Whether dragging the panel past half of its `minSize` collapses it to `collapsedSize` instead of
  stopping at the minimum.
- `[collapsedSize]`: `KbqSplitterSize` — Size the panel takes while collapsed. `0` — the default — hides it completely.
- `[(collapsed)]`: `boolean` — Whether the panel is collapsed. Two-way, so a host can collapse and restore the panel itself — which is
  the only way back for a panel whose `collapsedSize` is `0` and which therefore has no separator to grab.
- `[separatorAriaLabel]`: `string | undefined` — Accessible name of the separator that follows the panel; falls back to the localized default.

### Functions

#### kbqSplitterOptionsProvider (function)

Overrides the default splitter 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 kbqSplitterOptionsProvider(
    options: Partial<KbqSplitterOptions>
): Provider;
```

#### resizeSplitterSizesAt (function)

Moves the boundary that follows `index` by `delta` pixels and returns the new sizes.

The panels on one side of the boundary take the delta and the ones on the other side give it up, each walking
outwards from the boundary: a panel sitting at its limit hands the remainder to the next one instead of
stopping the drag. Walking outwards on the taking side too is what keeps a boundary reachable when the panel
right beside it is pinned — otherwise a neighbour at its maximum would freeze a boundary that the panels
further out could still move, and the drag would do nothing at all.

```ts
function resizeSplitterSizesAt(
    sizes: readonly number[],
    index: number,
    delta: number,
    min: readonly number[],
    max: readonly number[]
): number[];
```

### Types

#### KbqSplitterAppearance (type)

How a splitter draws its separators.

- `divider` — a line between the panels, the default.
- `transparent` — nothing until the pointer reaches the separator, which then gives itself away by the cursor.
- `handle` — a grip centred on the boundary.

```ts
type KbqSplitterAppearance = 'divider' | 'transparent' | 'handle';
```

#### KbqSplitterOptions (type)

Settings a whole application shares, rather than something a single splitter decides.

Only what a product picks once belongs here: how its separators look, and how far a snap size reaches. The
sizes and limits of the panels are a property of one layout and stay on the panels themselves.

```ts
type KbqSplitterOptions = {
    appearance: KbqSplitterAppearance;
    snapTolerance: number;
};
```

- `appearance`: `KbqSplitterAppearance` — How the separators are drawn.
- `snapTolerance`: `number` — How close to a snap size a drag has to be released for it to be pulled in, in pixels.

#### KbqSplitterOrientation (type)

Direction the panels of a splitter are laid out in.

```ts
type KbqSplitterOrientation = 'horizontal' | 'vertical';
```

#### KbqSplitterSize (type)

Size of a splitter panel: a number of pixels, a `<number>px` string, or a `<number>%` share of the
splitter's own size along the resize axis. A size in any other unit is ignored.

```ts
type KbqSplitterSize = number | string;
```

#### KbqSplitterSnapPoint (type)

A size a drag is pulled onto, with the distance the release has to be within for the pull to happen.

```ts
type KbqSplitterSnapPoint = {
    size: number;
    tolerance: number;
};
```

### Constants

#### KBQ_SPLITTER_OPTIONS (const)

Injection token holding the current `KbqSplitterOptions`.

```ts
const KBQ_SPLITTER_OPTIONS: InjectionToken<KbqSplitterOptions>;
```
