Skip to content
Concepts

Concepts

container-relative layout and pointer ownership

Maosaico arranges React panes inside a measured container. It supports floating frames and optional tiling while leaving pane content, styling, controls, and DOM focus with the host.

MaosaicoRoot owns layout state for one root. Pass its current container size as bounds. Without tiling, panes use floating frames. With tiling, choose layout: "main-left" | "main-top" | "columns" | "rows" | "grid". main-left is the default: the first pane is the main pane and companions stack beside it. main-top puts the main pane above its companions. The preferred mainSize is the main width or height respectively, clamped to pane minima and available space; these layouts expose one draggable divider.

columns, rows, and grid use equal cells and ignore mainSize; they have no main divider. Grid starts near-square by tile count and adapts to the container’s capacity. Equal layouts preserve leading tiles and group overflow in the final cell, showing that group’s most recently focused pane. Minima account for every member of a group, so changing its active tab does not move the cell. If even one minimum cannot fit, a single full-container tab group keeps a pane readable. The caller renders tabs from tabGroups; hidden panes stay mounted.

useMaosaicoItem registers an ID, starting frame, and minimum size. The returned binding provides the current frame, visibility, active state, drag props, and focus, snap, and restore actions. Keep keyed content mounted when a pane is hidden; apply hidden={!visible} so hidden content leaves input and accessibility navigation. Closing a pane means removing it from the mounted list.

MaosaicoLayers renders five isolated sibling overlay roots: chrome, popover, dialog, toast, tooltip. Mount it inside the shell’s positioned container, outside clipped panes. The host loads Stipe’s stylesheet; Maosaico consumes its layer tokens. Overlay roots are pointer-transparent; set pointerEvents: "auto" on their interactive content.

MaosaicoRegion supplies the desktop and windows layers in the host’s positioned work area. It forwards ordinary div attributes and a ref, keeps the host’s positioning styles, and owns isolation and the layer token. Inside MaosaicoLayers, it also registers that region for useLayer. A windows region is inert while the dialog root contains painted content; closing the dialog releases it without remounting windows or desktop content.

useLayer("popover") returns the nearest provider’s portal container. It is null until that root mounts, and during server rendering. Outside a provider it returns document.body, so standalone overlays keep an ordinary portal container. Pass the container to the maintained overlay primitive, or use React DOM’s createPortal. Choosing a layer does not implement positioning, light-dismiss, focus trapping or iframe occlusion.

Place window content in <MaosaicoRegion layer="windows"> and merge the binding’s stackingStyle into each window’s style. Its rank is dense, starting at zero, and follows the layout owner’s focus order. useMaosaicoLayout().stackingStyle ranks divider and snap decorations directly above the windows inside the same region. Arbitrarily many ranks stay below chrome because the windows root owns their stacking context. Each shell’s roots and window order are independent; portaled content stays mounted when other layer roots change.

useMaosaicoLayout provides focus and swap commands, zoom and restore, tile order, tab groups, divider interaction, and pending snap information. Pass a containerRef for edge snapping relative to a positioned workspace, such as a workbench below a toolbar.

@fungi.computer/maosaico/headless exports createMaosaicoState and arrangeTiles without the React renderer. The native TUI shell uses the same focus, grouping, divider and zoom state in terminal cells. Browser bento and window geometry keep their existing entrypoints and rules.

Run pnpm run build, pnpm run pack and pnpm run stranger in this package. The maintained stranger proof installs only package tarballs into a fresh npm consumer, checks the exact shipped files, runs the public runtime fixture and compiles every JavaScript entrypoint with strict NodeNext and no library-check skip. This qualification does not publish npm releases or push a repository split.

See LICENSE for the license and the package manifest for its public repository destination.