Selkie.git | docs/api/ | Selkie--Layout--Split.md


NAME
====

Selkie::Layout::Split - Two-pane layout with a divider

SYNOPSIS
========

```raku
use Selkie::Layout::Split;
use Selkie::Sizing;

my $split = Selkie::Layout::Split.new(
    orientation => 'horizontal',   # left | right
    ratio       => 0.3,            # 30% | 70%
    sizing      => Sizing.flex,
);
$split.set-first($sidebar);
$split.set-second($main);
```

DESCRIPTION
===========

Split divides its area into exactly two panes with a one-cell divider between them. The `ratio` attribute controls the split — `0.3` means the first pane takes 30% of the space, the second gets the rest (minus one cell for the divider).

Two orientations:

  * `'horizontal'` — left and right panes, divided by a vertical bar

  * `'vertical'` — top and bottom panes, divided by a horizontal bar

Unlike VBox/HBox which take a list of children, Split takes exactly two content widgets via `set-first` and `set-second`. Each assignment destroys the previous occupant of that slot — use a container widget (like another VBox) on each side if you need more than one widget per pane.

EXAMPLES
========

Sidebar + main content
----------------------

A classic two-pane layout with a 25/75 split:

```raku
my $split = Selkie::Layout::Split.new(
    orientation => 'horizontal',
    ratio       => 0.25,
    sizing      => Sizing.flex,
);
$split.set-first($sidebar-list);
$split.set-second($detail-view);
```

Editor + preview (vertical split)
---------------------------------

Top half is the editor, bottom half is the live preview:

```raku
my $split = Selkie::Layout::Split.new(
    orientation => 'vertical',
    ratio       => 0.5,
    sizing      => Sizing.flex,
);
$split.set-first($editor);
$split.set-second($preview);
```

Multiple widgets per pane
-------------------------

Wrap each side in its own layout:

```raku
my $left = Selkie::Layout::VBox.new(sizing => Sizing.flex);
$left.add($search-input);     # fixed(1)
$left.add($result-list);      # flex

$split.set-first($left);
$split.set-second($details);
```

SEE ALSO
========

  * [Selkie::Layout::VBox](Selkie--Layout--VBox.md), [Selkie::Layout::HBox](Selkie--Layout--HBox.md) — N-child stacked layouts

  * [Selkie::Theme](Selkie--Theme.md) — `divider` slot controls divider appearance

### has Rat $.ratio

The fraction of space given to the first pane. `0.5` is an even split; `0.3` gives 30% to the first pane, 70% to the second. Can be changed at runtime — just mark the Split dirty and re-layout.

### has Str $.orientation

Either `'horizontal'` (left+right panes, vertical divider) or `'vertical'` (top+bottom panes, horizontal divider).

### has Selkie::Widget $.first

The first (left or top) pane's widget. Set via `set-first`.

### has Selkie::Widget $.second

The second (right or bottom) pane's widget. Set via `set-second`.

### method set-first

```raku
method set-first(
    Selkie::Widget $w
) returns Selkie::Widget
```

Install a widget in the first pane. The previous occupant (if any) is destroyed. Returns the new widget for chaining.

### method set-second

```raku
method set-second(
    Selkie::Widget $w
) returns Selkie::Widget
```

Install a widget in the second pane. The previous occupant is destroyed. Returns the new widget for chaining.

### method handle-resize

```raku
method handle-resize(
    Int $rows where { ... },
    Int $cols where { ... }
) returns Mu
```

Re-layout the two panes and the divider when the parent resizes. The split ratio is honoured exactly — first pane gets `floor(total * ratio)`, the divider takes 1 cell, the second gets the remainder. Idempotent on no-size-change calls.

### method compute-split-sizes

```raku
method compute-split-sizes(
    Int $total where { ... },
    Rat $ratio
) returns Hash
```

Pure-math helper that computes the split allocation for a given total length and ratio. Returns a Hash with `first`, `divider`, `second` keys — all UInt, all guaranteed non-negative. Exposed at class scope so the boundary math is unit-testable without needing a notcurses context. Used by `!layout-split`.

### method children

```raku
method children() returns List
```

Expose the panes as `children` so that Container-level cascade helpers (notably `!unsubscribe-tree`) reach them. Split stores its panes in `$!first` / `$!second` rather than the inherited `@!children` array, so without this override the cascade walks an empty list and leaks subscriptions / bookkeeping for anything inside a pane.

### method focusable-descendants

```raku
method focusable-descendants() returns Seq
```

Focusable descendants in stable left-to-right (or top-to-bottom) order — Tab cycles through everything in the first pane, then everything in the second pane. Omits the divider (which is chrome).

### method destroy

```raku
method destroy() returns Mu
```

Destroy both panes, the divider plane, and the split's own plane.