Ephemeral-AI-Lab/mayfly--packages-ui ↗★ 22

@ephemeral-ai/mayfly-ui

Renderer-neutral contracts, builders, and UI contribution services for Mayfly

套件
@ephemeral-ai/mayfly-ui
相容性
待驗證
Cordis 依賴範圍
^4.0.5
版本
0.1.4-rc.2
授權
MIT
最近更新
2026年10月22日

安裝

此插件尚未提供可驗證的 bundle,或相容性檢查未通過。請先閱讀倉庫說明。 閱讀完整 README ↗

@ephemeral-ai/mayfly-ui

Pure, renderer-neutral builders for Mayfly's public UI wire format. The ui namespace recursively clones caller data, then creates deeply frozen MayflyUiNode objects with the same shape a plugin can write by hand. It includes every content leaf, flex and viewport children, row/column stacks, surfaces, scrolling, explicit Markdown and Mermaid nodes, structured charts, controlled patterns, progress, spacers, and dividers. Plain nodes can enter a stack directly; use ui.child only when child layout metadata is needed.

Caller-owned data is isolated. Snapshots already created by this module may be shared across builders and registry updates without cloning their immutable subtrees again. Arbitrary frozen objects do not receive this optimization. Wire data must not contain cycles or accessor properties; getters are rejected without being executed. Registration identity remains fixed even if the caller later changes the original definition.

import { defineMayflyComponent, ui } from '@ephemeral-ai/mayfly-ui'

export const metric = defineMayflyComponent({
  id: '@acme/metric',
  render: props => ui.surface({
    title: props.label,
    child: ui.stack.column([
      ui.child(ui.progress({ value: props.value, max: 100 }), {
        grow: 1,
        when: { minWidth: 40 },
      }),
    ]),
  }),
})

Compose

compose is the one layered shell for visible UI:

import { compose, ui } from '@ephemeral-ai/mayfly-ui'

const surface = compose.panel({
  title: 'Plugins',
  escapeLabel: 'close',
  body: compose.browser({
    list: ui.list({ id: 'plugins', role: 'browse', selectedIds: [], items: [] }),
    detail: ui.text('Select a plugin'),
  }),
})

panel is a command Panel (overlay chrome, editor slot). decisionLane is the one lane for agent requests; decisionStrip is a user-triggered Yes/No lane (y/n, Esc no). tabs, wizard, rail, browser, statusPage, and completionPalette are body-only compositions. tabs is horizontal tabs over arbitrary pages; rail is the vertical equivalent with a column rule. Product command panels are keys-only: no visible Save/Cancel/Close buttons; multi-field forms save with the last field's Enter and Ctrl+S.

defineMayflyComponent records a package-namespaced id, then deeply freezes each rendered node. It is a pure package-level factory, not a runtime registry. Core still validates node kinds, values, depth, quotas, and renderer safety when a plugin contributes the expanded tree.

The root entry is side-effect free. The explicit ./provider entry owns the four Fiber-scoped snapshot registries; handles publish with set() and remove with dispose(). A snapshot is frozen before its revision advances. set() is a data refresh (reason: 'data') or a new instance boundary (reason: 'replace', the only update that may change scope); callbacks do not create acknowledgements — action handlers return structured replies that core admits before a single-use publisher updates the original registration. The package has no dependency on Harness, core, pi-tui, or a terminal runtime.

ui.markdown(source), ui.diagram(source), and ui.chart({ chart, ...data }) preserve only renderer-neutral wire data. Mermaid and chart libraries are core-owned; plugins do not install them or pass library-specific configuration.