@fungi.computer/maosaico

中文文档
0.1.2发布于 2026/11/09MITTypeScriptES Module近 30 天下载 4771

container-relative layout and pointer ownership

原始使用文档
文档目录11 节
  1. Install or set up
  2. Quick start
  3. Core concepts
  4. Shell layers
  5. API reference
  6. Examples and checks
  7. Limits and errors
  8. Contribute and license
  9. Controlled bento grids
  10. Native hosts
  11. Packed consumer readiness

Maosaico (@fungi.computer/maosaico)

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.

Install or set up

npm install @fungi.computer/maosaico react react-dom

Maosaico needs React 17 or newer as a peer dependency.

The package exports MaosaicoRoot, useMaosaicoItem, useMaosaicoLayout, MaosaicoLayers, useLayer, and usePointerDrag from @fungi.computer/maosaico.

usePointerDrag supplies captured-pointer DOM props for a caller-owned gesture. Its move callback receives incremental pixel deltas; cancellation and unmount release the same capture. An optional third AbortSignal lets the caller cancel a gesture; Escape policy stays with the caller. Grove uses it with the Caps ResizeHandle for its conversation rail, without introducing a tiling root for one sidebar width.

Quick start

This illustrative example registers panes and asks Maosaico to tile them within the supplied bounds:

import { MaosaicoRoot, useMaosaicoItem } from "@fungi.computer/maosaico";

function Pane({ id }: { id: string }) {
  const pane = useMaosaicoItem({
    id,
    frame: { x: 0, y: 0, width: 320, height: 240 },
    minima: { width: 180, height: 120 },
  });

  return (
    <section
      hidden={!pane.visible}
      {...pane.props}
      style={{
        position: "absolute",
        left: pane.frame.x,
        top: pane.frame.y,
        width: pane.frame.width,
        height: pane.frame.height,
      }}
    >
      Pane content stays mounted here.
    </section>
  );
}

function Workspace() {
  return (
    <div style={{ position: "relative", width: 1000, height: 600 }}>
      <MaosaicoRoot bounds={{ width: 1000, height: 600 }} tiling={{ gap: 8 }}>
        <Pane id="chat" />
        <Pane id="files" />
      </MaosaicoRoot>
    </div>
  );
}

This sketch is illustrative; the layout tests exercise the public React boundary and pane registration in test/tiling.test.tsx.

Core concepts

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.

Shell layers

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.

API reference

See the generated API reference and the public exports and types. Implementation details such as state collections remain private.

Examples and checks

The Layouts / Automatic Tiling in the shared workbench demonstrates tiling, tabs, divider resizing, floating panes, zoom, focus, and swapping. Run the workbench from the repository root with:

pnpm workbench:serve

The focused tests cover layout, tiling, pointer contracts, and the public boundary:

pnpm --filter @fungi.computer/maosaico test

The browser proof also mounts 33 windows through the public bindings, checks that chrome receives real pointer clicks before and after raising a window, and consumes Stipe's actual CSS rather than reproducing its numbers.

The browser pointer proof is available separately with pnpm --filter @fungi.computer/maosaico browser:contract; it does not prove a mounted Tourtois App.

Limits and errors

Maosaico stores layout state only for the lifetime of a mounted root. It does not persist frames, provide App identity, own keyboard policy, or move/focus the caller's content. The host provides bounds, minima, controls, theme, and animation. Resize gestures and tiled mode do not offer snap targets.

Bounds, minima, and size preferences are layout measurements and must be finite and nonnegative. Maosaico adapts the MaoMaoLabs core gesture and snap behavior; see LICENSE for its MIT license terms and attribution.

Contribute and license

Build it from the repository root with pnpm --filter @fungi.computer/maosaico build. Maosaico is MIT licensed; see LICENSE.

MaosaicoLayers onDismiss reports host-window blur and focus entering the windows region. Compose it with Caps OverlayRoot subscribeDismiss to retire transient popovers and tooltips together; blocking dialogs and toasts stay live.

Controlled bento grids

arrangeBento reflows caller-owned { id, col, row, w, h } placements into 1, 2 or 4 columns. Spans clamp to the current grid; collisions push occupants down and vertical gaps compact deterministically. IDs are unique within a grid. applyBentoOps accepts move and resize intents without mutating the input. bentoFrames maps accepted cells to container-relative pixel frames. Every accepted move or resize compacts all tiles to an arrangeBento fixpoint; downward moves pass the intersecting occupant. Cells and their extents must fit finite safe integers; duplicate IDs throw. There is no engine product quota on tile count or size.

useMaosaicoBento takes those placements, measured width, columns, rowHeight, gap and an onChange(ops) callback. Optional rowHeights provide measured pixel heights for individual rows; missing rows use rowHeight. Frames and pointer snapping share those row boundaries. Changing measurements cancels an in-flight gesture; equal fresh arrays preserve it. These measurements never change the integer placements. Its previewId names only the live gesture tile. Its frames include the live pointer preview. Spread bind(id, "move") or bind(id, "resize") onto a focusable handle with touchAction: "none". Arrow keys propose one cell; Escape, lost capture, disabling, unmount and host geometry changes cancel a pointer gesture. A completed drop proposes operations through onChange; the host accepts them with applyBentoOps and supplies the new placements.

The host chooses breakpoints and persists its own placements. Reflow does not rewrite storage, and bento does not change MaosaicoRoot window behavior. The controlled bento story composes Caps SectionCard and Button. The browser contract exercises real captured-pointer move, resize, cancellation and keyboard input.

Native hosts

@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.

Packed consumer readiness

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.

版本与发布记录

@fungi.computer/maosaico 共发布 5 个版本,首次发布于 2026/10/15;过去 12 个月发布了 5 个版本。

版本发布日期距今
0.1.2latest2026/11/096 天前
0.1.12026/11/079 天前
0.1.02026/10/2323 天前
0.0.12026/10/151 个月前
0.0.0-stage2026/10/151 个月前

关于 @fungi.computer/maosaico 的常见问题

@fungi.computer/maosaico 是什么?

container-relative layout and pointer ownership

如何安装 @fungi.computer/maosaico?

在项目目录运行 npm install @fungi.computer/maosaico,或使用 pnpm add / yarn add / bun add。它还需要宿主项目提供 peer 依赖:react(>=17)。npm 7 及以上与 pnpm 8 及以上默认会自动安装必需的 peer 依赖,Yarn 需要手动安装。

@fungi.computer/maosaico 支持 TypeScript 吗?

支持。包内自带 TypeScript 类型声明(package.json 声明了 types 入口),安装后即可获得类型提示,无需再安装 @types 包。

@fungi.computer/maosaico 支持 ESM 还是 CommonJS?

以 ES Module 形式发布,推荐使用 import 引入。在 CommonJS 项目中,Node.js 20.19+ / 22.12+ 可以直接 require() 不含顶层 await 的 ES Module,更早的版本需要改用动态 import()。

@fungi.computer/maosaico 可以商用吗?

@fungi.computer/maosaico 使用 MIT 许可。宽松许可:允许商业使用、修改和再分发,通常只需在分发时保留原版权与许可声明。以上为概括,不构成法律意见,请以许可原文为准。

@fungi.computer/maosaico 的下载量有多少?

根据 npm 官方下载统计,@fungi.computer/maosaico 在 2026/10/16 – 2026/11/14 这 30 天内被下载 4,771 次,日均约 159 次。下载量会把 CI 构建、镜像同步和作为其他包依赖的安装一并计入,适合横向比较热度,不能直接等同于使用人数。

@fungi.computer/maosaico 还在维护吗?

最新版本 0.1.2 发布于 2026/11/09(6 天前);至今共发布 5 个版本,其中过去 12 个月发布了 5 个;首次发布于 2026/10/15。发布频率只是参考信号:功能稳定的工具可能很少需要更新,建议结合源码仓库的 issue 和提交记录判断。