- ..
- index.ts23 KB
- package.json170 B
- readme.md3.3 KB
- tsconfig.json125 B
readme.md
@ace/split-tabs
Renderless split-pane and tab state for Ace. The package owns layout math: tabs, panes, grid lines, resize bounds, min-size constraints, and saved state shape. Rendering, labels, icons, storage, tooltips, and drag UI belong to the consuming app.
Model
import * as Split from "@ace/split-tabs";
let state = Split.initial("session");
let api = Split.create(state, { min: tab => tab === "session" ? 450 : 350 });
Tabis a string id.Panestores a grid area, ordered tab ids, and the active tab.Statestoresrows,cols,panes,tabs, focused pane, and id counters.Config.minis optional and returns the minimum pane size in pixels.
Rendering
let view = api.view({ width, height, flat });
let css = Split.style(view);
root.style.gridTemplateColumns = css.gridTemplateColumns;
root.style.gridTemplateRows = css.gridTemplateRows;
for (let pane of view.panes) {
element.style.gridArea = Split.place(pane);
}
for (let handle of Split.handles(view)) {
handleElement.style.gridArea = Split.place(handle);
}
view(data)returns the render state for a container size, projecting ratios inside min-size limits when possible.flat: truecollapses all panes into one tab strip without changing saved state.style(state)returns CSS grid templates with named lines.place(pane | handle)returns a CSSgrid-area.handles(state)returns resize handles for visible shared grid lines.
Mutations
All mutations return false when nothing changed.
api.open({ tab: "notes" });
api.open({ to: { pane: "pane-1", side: "right" }, fit });
api.move({ tab: "notes", to: { pane: "pane-2" }, fit });
api.move({ tab: "notes", to: { pane: "pane-2", before: "logs" }, fit });
api.move({ tab: "notes", to: { pane: "pane-2", side: "bottom" }, fit });
api.select({ tab: "notes" });
api.focus({ pane: "pane-2" });
api.close({ tab: "notes" });
api.resize({ axis: "col", line: "C1", ratio: 0.5, size: width });
opencreates a tab, optionally into a pane or split.movereorders, moves between panes, or creates a split.selectactivates a tab and focuses its host pane.focuschanges the focused pane.closeremoves a tab and compacts empty panes.resizemoves a named grid line within min-size bounds.
Persistence
let json = JSON.stringify(Split.save(api.get()));
let state = Split.restore(JSON.parse(json));
savereturns a versioned data object suitable for storage or transfer.restoreturns saved data back into state. It also accepts rawStatefor migration from unversioned data.
Constraints
let fit = { width, height, min };
let allowed = Split.can(state, {
...fit,
move: { tab: "notes", to: { pane: "pane-2", side: "right" } },
});
let bounds = Split.bounds(state, {
axis: "col",
line: "C1",
ratio: 0.5,
size: width,
min,
});
canchecks whether anopenormovewould fit.fitschecks whether a layout can fit a container after projection.boundsreturns min/max resize ratios for a line.constrainprojects a layout back inside min-size limits.collapsereturns a one-pane tabbed layout.
Store
let unsubscribe = api.subscribe(render);
let state = api.get();
The store is synchronous and framework-neutral. During pointer resize, update DOM
directly with Split.style(next) and call api.resize once on pointer up.