Are you an LLM? Read llms.txt for a summary of the docs, or llms-full.txt for the full context.
Skip to content

@enc-protocol/emulator -- SDK API Reference

React phone-frame renderer for the UI Kit. Renders resolved UI trees as interactive previews.

Install

npm config set @enc-protocol:registry https://npm-registry.ocrybit.workers.dev/
npm install @enc-protocol/emulator

Peer dependencies: react >= 19, react-dom >= 19

import { RenderNode } from '@enc-protocol/emulator/tree-renderer'
import * as Chrome from '@enc-protocol/emulator/chrome'
import { PostCard, Tabs, EmptyState } from '@enc-protocol/emulator/common'

Table of Contents

  1. tree-renderer.tsx -- React Tree Renderer
  2. chrome.tsx -- Host Shell Components
  3. common.tsx -- Cross-App Primitives
  4. dm.tsx -- DM-Specific Components
  5. registry.ts -- Component Registry
  6. Package Entry (index.ts)

1. tree-renderer.tsx -- React Tree Renderer

Source: sdk-emulator/tree-renderer.tsx

The core renderer that turns UI Kit trees into interactive React DOM. It recursively walks a JSON tree and dispatches each node to the appropriate atom, component, or directory renderer.


RenderNode

The top-level dispatcher component. Determines node type and delegates.

Props:
PropTypeDefaultDescription
nodeanyrequiredTree node (atom, component, or dir)
pathstring''Data-path for action routing
onAction(path: string, value?: string) => voidoptionalAction callback (only on root node)
Behavior:
  1. If onAction is provided, wraps content in an ActionCtx.Provider so all descendants can access the action callback via React context.
  2. Checks node type in order:
    • isComponent(node): Has component property -> RenderComponent
    • hasFiles(node): Has ./ children -> RenderDir
    • isAtom(node): Has atom or typed type -> RenderAtom
    • Otherwise: renders [unknown] error text.
Action Routing:

Every rendered element gets a data-path attribute. When a user interacts with an element, the onAction callback is called with the element's data-path (and optionally an input value). The host app translates these paths into state transitions via applyAction.

Example:
import { RenderNode } from '@enc-protocol/emulator'
 
function MyApp({ tree, onAction }) {
  return <RenderNode node={tree} path="root" onAction={onAction} />
}

Internal: RenderAtom

Renders leaf nodes (atoms). Not exported directly.

Supported Atom Types:

str (text)

Renders as text. If style has primary: true, renders as a Button. Supports grow, size, color, weight, mono, pad style properties.

Data PropDescription
valueText content to display
labelAlternative text (buttons)

media (avatar)

Renders as a gradient circle with first-letter monogram. Clickable.

Data PropDescription
srcName/key for monogram
nameFallback for src
sizeCircle size (px)

input (text input)

Renders as a text input field. Supports text, file, and textarea types.

Data PropDescription
valueCurrent value
placeholderPlaceholder text
type'text' (default), 'file', 'textarea'
  • text: Standard pill-shaped input. Fires onAction(path, value) on change, onAction(path + '$submit') on Enter.
  • file: File picker display. Shows hash or placeholder.
  • textarea: Multiline display (read-only in current impl).

select (single choice)

Renders as a horizontal row of selectable chips.

Data PropDescription
selectedCurrently selected item
valueAlternative for selected
optionsArray of option strings (or comma-separated string)

Fires onAction(path + '$select#x27; + item_key) on chip click.

multiselect (multiple choice)

Same as select but multiple items can be highlighted.

Data PropDescription
selectedArray of selected items
optionsArray of option strings

bool (toggle)

Renders as a sliding toggle switch (44x24px).

Data PropDescription
valuetrue/'true' for on

Fires onAction(path, String(!current)) on click.

slider (range)

Renders as a horizontal bar with min/max labels and current value.

Data PropDescription
valueCurrent value
minMinimum (0)
maxMaximum (100)

arr (string array)

Renders as a row of teal chips, one per array element.

Data PropDescription
valueArray or comma-separated string

null (spacer/divider)

Renders as empty space or a 1px separator line.

Style PropDescription
heightFixed height (px)
lineIf true, render as line
growIf true, flex-grow

Internal: RenderComponent

Renders component nodes. Dispatches by node.component name.

Supported Components:

header

Renders via DMHeader. Shows title, optional subtitle, optional back button.

Data PropDescription
titleHeader title text
subtitleOptional subtitle
backShow back button

tabs

Renders as a horizontal tab bar with accent-colored active indicator. Supports badge counts (numbers in parentheses after label).

Data PropDescription
itemsArray of tab label strings
activeCurrently active tab label

Fires onAction(path + '$select#x27; + tab_key) on tab click. Tab key = lowercase, spaces to underscores, badge stripped.

bar / compose_bar

Horizontal flex row: growing input + primary button.

Data PropDescription
valueCurrent input value
placeholderInput placeholder
buttonButton label (default "Send")

Fires:

  • onAction(path + '$input', value) on input change
  • onAction(path + '$submit') on button click or Enter

card / list_item

Renders differently based on data shape:

  • With body: PostCard (avatar + title + body text)
  • Without body: ListItem (title + subtitle + avatar + trailing)
Data PropDescription
titlePrimary text
subtitleSecondary text
bodyBody content
mediaAvatar name/key
avatarAlternative to media
trailingTrailing text (time)
outgoingBoolean outgoing flag

post_card

Always renders as a PostCard (regardless of data shape).

field / form_field

Label text above a rectangle-variant input.

Data PropDescription
labelField label text
placeholderInput placeholder

message_bubble

Single chat bubble.

Data PropDescription
bodyMessage text
outgoingAlignment flag

empty_state

Centered message text in muted color.

Data PropDescription
messageDisplay text

connect_gate

Full-page connect wallet CTA: avatar, title, subtitle, primary button.

Data PropDescription
app_nameApp name in text

Fires onAction(path + '$connect') on button click.

error_view

Error state: danger-colored title, message, retry button.

Data PropDescription
messageError message
retry_labelRetry button text

card_list

Dynamic list of card items. The most complex component. Each item is rendered based on its shape:

  1. Full-width button (accept only, no title/subtitle): Primary button. Fires path + '$accept#x27; + idx.

  2. Post card (has body): Avatar + title + body + optional engagement bar (likes/replies). Fires:

    • path + '$avatar#x27; + idx on avatar click
    • path + '#x27; + idx on body click
    • path + '$like#x27; + idx on like click
  3. KV detail row (no media/trailing/accept, has subtitle): Label above, monospace value below.

  4. App catalog row (accept + media + subtitle, no reject): ListItem with action button. Fires path + '$accept#x27; + idx.

  5. Stat row with link (accept, no reject): Title left, accent link right. Fires path + '$accept#x27; + idx.

  6. Accept/reject row (both accept and reject): ListItem with two buttons. Fires path + '$accept#x27; + idx or path + '$reject#x27; + idx.

  7. Standard list item (fallback): Clickable ListItem. Fires path + '#x27; + idx.

Data PropDescription
itemsArray of item objects

bubble_list

Dynamic list of chat bubbles. Messages are reversed (newest at bottom). Author names are colored (cycling through 6 colors for group chats).

Data PropDescription
messagesArray of message objects

Message object fields: body, outgoing, author, tx_amount, txid.

field_list

Dynamic list of form fields. Each field maintains local React state (controlled input). Uses FieldInput internal component.

Data PropDescription
fieldsArray of field objects

Field object: { label, placeholder, value, key }. If key is set, fires onAction(path + '$key#x27; + key, value) on change.

Default (unknown component)

If a component name matches a COMPONENTS catalog entry with a tree definition, it is rendered recursively:

  1. Bind data via bindTree.
  2. Apply styles via applyStyles.
  3. Pass parent data to child components (card_list gets items, bubble_list gets messages, bar gets placeholder/button/value, tabs gets items/active, header gets title/subtitle/back).

If no match: renders [component:name] error text.


Internal: RenderDir

Renders directory (container) nodes. Pure flexbox layout.

Style PropCSS Mapping
axis'h' -> row, 'v' -> column
gapgap (px)
padpadding (px, or [t,r,b,l])
alignalignItems (start/center/end/stretch)
justifyjustifyContent (start/center/end/between)
scrolloverflowY: 'auto'
growflex: 1; minHeight: 0

Children are rendered via RenderNode with $-separated path segments.


Exported: applyStyles(node, styles, path?) -> any

Duplicated from tree-utils.ts (same implementation). Merges style map into tree nodes. See tree-utils.ts documentation for details.

Exported: validateTree(node, path?) -> string[]

Duplicated from tree-utils.ts. See tree-utils.ts documentation.


2. chrome.tsx -- Host Shell Components

Source: sdk-emulator/chrome.tsx

Chrome components render the host shell around apps -- top bar, wallet connection, phone frame. These are distinct from app-scoped components.


PhoneFrame

iPhone-shaped chrome container (390x844 max). Includes system status bar (time, signal, battery), content area, and bottom system bar with optional home button.

Props:
PropTypeDefaultDescription
childrenReact.ReactNoderequiredContent to render inside
onHome() => voidundefinedHome button click handler
Renders:
  • Top system bar: 9:41 time, dynamic island notch, signal/wifi/battery icons.
  • Content area: {children} in a flex column.
  • Bottom system bar: Home button (if onHome provided) or swipe indicator.

data-testid: phone-frame

Example:
<PhoneFrame onHome={() => navigateHome()}>
  <MyAppContent />
</PhoneFrame>

TopBarContainer

Fixed top bar layout (50px height, flex row).

Props:
PropTypeDescription
childrenReact.ReactNodeBar contents

Renders: Fixed-position bar at top with border-bottom, centered items.


Branding

ENC logo monogram (gradient circle with "E") + "ENC" label.

Props: None.


Spacer

Flex-1 filler for flex rows.

Props: None.


ConnectButton

Connect/Disconnect pill button.

Props:
PropTypeDescription
connectedbooleanConnection state
onClick() => voidClick handler
Renders:
  • Connected: Red-tinted "Disconnect" pill.
  • Disconnected: Green gradient "Connect" pill.

PubkeyChip

Small monogram circle + truncated pubkey (first 8 chars). Click to copy.

Props:
PropTypeDescription
pubKeystringFull public key hex
onCopy(text: string) => voidCalled after copy with full key

Renders: Rounded pill with gradient circle + monospace truncated key. Copies full pubkey to clipboard on click (both navigator.clipboard and fallback execCommand).


CopyToast

Green confirmation pill, fixed at top center. Auto-dismissing (parent controls visibility).

Props:
PropTypeDescription
messagestringToast text

Renders: Fixed-position green pill with shadow at top: 60px.


WalletChooserModal

Full wallet connection modal. Supports extension, passkey, and dev account options.

Props:
PropTypeDescription
onClose() => voidBackdrop click handler
extensionAvailablebooleanShow extension option
onExtensionConnect() => voidExtension connect handler
accountsWalletAccount[]Dev accounts to show
onAccountClick(a: WalletAccount) => voidAccount selection handler
passkeysWalletPasskey[]Existing passkeys to show
onPasskeyClick(p: WalletPasskey) => voidPasskey selection handler
passkeySupportedbooleanShow passkey options
onUseExistingPasskey() => void (optional)Use existing passkey handler
onCreatePasskey() => voidCreate new passkey handler
onCreateDevAccount() => voidCreate dev account handler
Supporting Types:
interface WalletAccount {
  pubHex: string
  name: string
}
 
interface WalletPasskey {
  credentialId: string
  pubHex: string
  name: string
}

Renders: Centered modal dialog (320px wide, max 80vh scroll) with:

  • Header: "Connect Wallet" + description
  • Extension button (if available, accent-bordered)
  • Account buttons (gradient-circle monogram + name + truncated key)
  • Passkey buttons (purple-themed)
  • "Use Existing Passkey" button (if onUseExistingPasskey provided)
  • "Create Passkey (secure)" button (purple gradient)
  • "+ Dev Account (insecure)" button (green gradient)

Backdrop click dismisses. Modal click stops propagation.


QRCodeButton

Top-bar QR icon that opens a modal with a scannable QR code.

Props:
PropTypeDescription
urlstringURL to encode in QR
qrSrcstringQR code image source URL

Renders: Small icon button (22x22). On click, opens a modal showing:

  • "Scan to open on phone" header
  • QR code image (260x260 on white background)
  • URL text (monospace, word-break)
  • "Copy URL" button

ConnectPrompt

Full-page "Connect Wallet" CTA shown when app is opened without wallet.

Props:
PropTypeDescription
appNamestringApp name to display
onBack() => voidBack button handler
onConnect() => voidConnect button handler
Renders:
  • Header bar with back arrow + app name
  • Centered content: wallet icon, "Connect Wallet" heading, description text, green gradient "Connect Wallet" button

DetectingExtensionScreen

Full-screen loading state while detecting ENC extension.

Props: None.

Renders: Centered spinner + "Detecting ENC Extension..." text.


ExtensionInstallScreen

Full-page extension install guide with dev mode fallback.

Props:
PropTypeDescription
installStatusstringStatus message after download
onInstall() => voidDownload button handler
onCopyChromeExtensionsUrl() => voidCopy chrome://extensions handler
onDevMode() => voidDev mode button handler
onRetry() => voidRetry detection handler
Renders:
  • Shield icon
  • "ENC Extension Required" heading
  • Install instructions
  • "Download Extension" button
  • Install status + "Copy chrome://extensions" (if installStatus set)
  • Developer mode instructions
  • "Dev Mode (local keys)" button (purple)
  • "Retry Detection" button (muted)

ExtensionUpdateButton

Yellow pill in top bar indicating extension needs update.

Props:
PropTypeDescription
currentVersion`stringnull`
expectedVersionstringRequired version
onClick() => voidClick handler

Renders: Warning-colored pill: "Update Extension (old -> expected)".


HomeGrid

4-column app launcher tile grid.

Props:
PropTypeDescription
itemsHomeGridItem[]Apps to display
onOpen(name: string) => voidApp open handler
HomeGridItem:
interface HomeGridItem {
  name: string
  iconUrl: string
}
Renders:
  • "ENC Emulator" heading
  • "N apps loaded" subtitle
  • 4-column CSS grid of icon tiles (48x48 images with labels)

3. common.tsx -- Cross-App Primitives

Source: sdk-emulator/common.tsx

Stage-2 axioms used by 2+ unrelated apps. This file must NOT reference any app by name.


PageScaffold

Outer flex container for any app page. Owns text color, font, background.

Props:
PropTypeDefaultDescription
background'default' 'chat' 'transparent''default'Background mode
childrenReact.ReactNoderequiredPage content
Background modes:
  • 'default': Inherits from parent (undefined background)
  • 'chat': TG.chatBg (#0e0e1a)
  • 'transparent': Explicit transparent

ScrollBody

Flex-1 body container with optional scroll.

Props:
PropTypeDefaultDescription
scrollbooleanundefinedEnable overflow scroll
childrenReact.ReactNoderequiredBody content
Modes:
  • No scroll: flex: 1; minHeight: 0; display: flex; flexDirection: column
  • Scroll: flex: 1; overflowY: auto

FixedItem

Layout wrapper that prevents flex shrinking. Used to pin tabs/bars.

Props:
PropTypeDescription
childrenReact.ReactNodeWrapped content

Renders: div with flexShrink: 0.


Stack

Vertical flex layout container.

Props:
PropTypeDefaultDescription
gapnumber0Gap between children
paddingnumber or [number, number]undefinedPadding (px)
align'start' 'center' 'end' 'stretch'undefinedCross-axis alignment
onClick() => voidundefinedClick handler
childrenReact.ReactNoderequiredContent

When onClick is set, adds cursor pointer and bottom border.


Row

Horizontal flex layout container.

Props:
PropTypeDefaultDescription
gapnumber0Gap between children
paddingnumber or [number, number]undefinedPadding (px)
align'start' 'center' 'end' 'stretch''center'Cross-axis alignment
wrapbooleanundefinedEnable flex wrap
childrenReact.ReactNoderequiredContent

Text

Typography axiom. Renders a styled text div.

Props:
PropTypeDefaultDescription
valuestringrequiredText content
size'sm' 'md' 'lg' 'xl''md'Font size
color'primary' 'secondary' 'accent' 'danger' 'warning''primary'Color token
weight'regular' 'medium' 'bold''regular'Font weight
align'left' 'center' 'right''left'Text alignment
paddingnumber or [number, number]undefinedPadding
monobooleanundefinedMonospace font
onClick() => voidundefinedClick handler

Size Mapping: sm=12, md=14, lg=16, xl=18. Weight Mapping: regular=400, medium=600, bold=700. Returns null if value is null or empty string. Mono mode: Uses 'SF Mono', monospace with word-break: break-all.


Input

Text input axiom.

Props:
PropTypeDefaultDescription
valuestringrequiredCurrent value
placeholderstringoptionalPlaceholder text
onChange(v: string) => voidoptionalChange handler
onSubmit() => voidoptionalEnter key handler
disabledbooleanoptionalDisable input
variant'pill' or 'rectangle''pill'Border radius style

Radius: pill=20, rectangle=12. Enter key triggers onSubmit. Style: width: 100%; flex: 1 1 auto; minWidth: 0.


Button

Push-button axiom.

Props:
PropTypeDefaultDescription
labelstringrequiredButton text
onClick() => voidoptionalClick handler
primarybooleanundefinedPrimary style
disabledbooleanundefinedDisable button
fullWidthbooleanundefinedwidth: 100%

Primary style: accent background, black text. Default style: semi-transparent white background, primary text. Disabled: 50% opacity, not-allowed cursor.


Banner

Clickable callout box with colored border.

Props:
PropTypeDefaultDescription
titlestringrequiredBanner title
subtitlestringoptionalBanner description
kind'info' 'warning' 'danger' 'success''info'Color scheme
onClick() => voidoptionalClick handler
Color schemes:
  • info: accent (teal)
  • warning: warning (orange)
  • danger: danger (red)
  • success: accent (teal, stronger)

If onClick is set, renders as a button element.


Divider

Visual separator (1px line).

Props:
PropTypeDefaultDescription
spacingnumber0Vertical margin (px)

Avatar

Gradient circle with first-letter monogram.

Props:
PropTypeDefaultDescription
namestringrequiredName for monogram
sizenumber50Circle diameter (px)

Monogram: First character (using Array.from for proper Unicode/emoji handling). ASCII letters are uppercased; emoji/non-ASCII rendered as-is. Font size: Math.round(size * 0.36).


Tabs

Bottom navigation tab bar.

Props:
PropTypeDescription
tabsArray<{ key: string; label: string }>Tab definitions
activestringActive tab key
onChange(key: string) => voidTab change handler

Renders: Horizontal flex row with role="tablist". Each tab is a button with role="tab" and aria-selected. Active tab has accent-colored top border.


ListItem

Generic list row with leading/content/trailing slots.

Props:
PropTypeDescription
titlestringPrimary text
subtitlestringSecondary text (optional)
leadingReact.ReactNodeLeft slot (avatar/icon)
trailingReact.ReactNodeRight slot (time/badge)
monobooleanMonospace title font
onClick() => voidClick handler

PostCard

X/Twitter-style timeline post.

Props:
PropTypeDescription
authorstringDisplay name or handle
authorPubstringOptional pub for fallback
bodystringPost content
timestampnumberUnix timestamp (for relative time)
outgoingbooleanAccent color for own posts
onClick() => voidClick handler

Renders: 40px avatar circle + author name + relative time + body text. If body starts with {, attempts JSON parse and joins string values.


MessageBubble

Chat message bubble (Telegram-style).

Props:
PropTypeDescription
outgoingbooleanAlignment + color
bodystringMessage text
timestampnumberOptional timestamp (HH
)
tx_hashstringOptional transaction hash
amount`stringnumber`
tokenstringOptional token name (default ETH)

Outgoing: Right-aligned, green background, checkmark. Incoming: Left-aligned, dark purple background. Transaction: Gradient background, accent border, amount header, truncated tx hash footer.


ComposeBar

Input + submit button pinned to bottom.

Props:
PropTypeDefaultDescription
draftstringrequiredCurrent draft text
onChange(v: string) => voidrequiredText change handler
onSubmit() => voidrequiredSubmit handler
placeholderstring'Message'Input placeholder
buttonLabelstringundefinedButton text (null = send icon)
disabledbooleanundefinedDisable input + button
pendingMessagestringundefinedShow warning instead of input

Submit guard: Only submits if draft.trim() is non-empty. Pending mode: Shows warning icon + message, hides input.


LoadingSpinner

Animated spinning circle.

Props:
PropTypeDefaultDescription
sizenumber24Spinner diameter
messagestringundefinedText below spinner

EmptyState

Centered muted text for empty lists.

Props:
PropTypeDescription
messagestringDisplay text

ErrorState

Error display with optional retry button.

Props:
PropTypeDefaultDescription
messagestringrequiredError message
retryLabelstring'Retry'Retry button text
onRetry() => voidoptionalRetry handler

AppErrorBoundary

React error boundary that catches render crashes.

Props:
PropTypeDescription
appNamestringApp name for error msg
childrenReact.ReactNodeContent to protect

On error: Renders ErrorState with "<appName> crashed: <message>". Retry button resets the boundary (re-mounts children).


Header

Generic page header with optional back button and trailing slot.

Props:
PropTypeDescription
titlestringHeader title
subtitlestringOptional subtitle
showBackbooleanShow back arrow
onBack() => voidBack handler
trailingReact.ReactNodeRight-side slot

FormField

Label + input combination.

Props:
PropTypeDescription
labelstringField label
placeholderstringInput placeholder
valuestringCurrent value
onChange(v: string) => voidChange handler
monobooleanMonospace input font

IconButton

Compact circular action button.

Props:
PropTypeDefaultDescription
iconReact.ReactNoderequiredIcon content
onClick() => voidoptionalClick handler
sizenumber36Button diameter
variant'default' 'accent' 'danger''default'Color scheme

StatusView

Unified loading/error/empty state.

Props:
PropTypeDescription
type'loading' 'error' 'empty'State type
messagestringDisplay message
actionstringOptional button text
onAction() => voidButton handler

Timestamp

Relative time display.

Props:
PropTypeDefaultDescription
valuenumberrequiredUnix timestamp
size'sm' or 'md''sm'Font size

Output: Ns, Nm, Nh, Nd relative format.


ChatListContainer

Flex-grow scrollable container for chat message lists.

Props:
PropTypeDefaultDescription
reversebooleanundefinedColumn-reverse mode
childrenReact.ReactNoderequiredChat bubbles

Reverse mode: flex-direction: column-reverse; padding: 8px 10px.


4. dm.tsx -- DM-Specific Components

Source: sdk-emulator/dm.tsx

Stage-1 axioms specific to the DM app, plus re-exports of promoted Stage-2 components.


DMHeader

DM-specific page header with optional avatar.

Props:
PropTypeDescription
titlestringHeader title
subtitlestringOptional subtitle
showBackbooleanShow back arrow
onBack() => voidBack handler
showAvatarbooleanShow contact avatar
avatarLetterstringLetter for avatar monogram
trailingReact.ReactNodeRight-side slot

Same visual layout as Header but with optional inline avatar circle (32x32, gradient background).


EnvelopeBadge

Envelope icon with notification count. Used in header trailing slot.

Props:
PropTypeDescription
countnumberNumber of message requests
onClick() => voidClick handler

Active state (count > 0): Red background, red icon stroke, count text. Inactive: Transparent background, secondary icon stroke.

aria-label: "N message request(s)" or "No message requests".


ContactRow

DM contact list item with state indicators.

Props:
PropTypeDescription
namestringDisplay name
pubstringPublic key
state'FRIEND' 'PENDING' 'BLOCKED'Contact state
previewstringLast message preview
outgoingbooleanLast msg was outgoing
timestampnumberLast message time
onClick() => voidClick handler

PENDING state: Shows warning-colored "Awaiting acceptance" text. Outgoing: Prefixes preview with checkmark. data-pub: Set to pub for testing.


MessageBubble (re-export)

Re-exported from common.tsx for backward compatibility. Same component and props as common.MessageBubble.


ChatInputBar

DM-specific chat input bar.

Props:
PropTypeDescription
draftstringCurrent draft
onChange(v: string) => voidText change handler
onSend() => voidSend handler
disabledbooleanDisable input
pendingMessagestringWarning text instead of input

Similar to ComposeBar but with circular send icon button (no label variant). Only sends if draft.trim() is non-empty.


EmptyChat

Centered empty chat state with contact avatar.

Props:
PropTypeDescription
namestringContact name

Renders: 60px gradient avatar, name, "End-to-end encrypted" label.


LookupResultCard

Found-user card with inline invite form.

Props:
PropTypeDescription
namestringFound user's name
enclaveIdstringEnclave ID (truncated)
draftstringGreeting message draft
onChange(v: string) => voidDraft change handler
onSend() => voidInvite send handler

Renders: Accent-bordered card with avatar + name + truncated ID + "Found" badge. Below: input ("Say hello...") + "Invite" button.


PublishBanner

Warning banner prompting user to publish profile to registry.

Props:
PropTypeDescription
onPublish() => voidPublish handler
publishingbooleanLoading state

Renders: Warning-themed banner with "Profile not in registry" title, explanation, and "Publish" button (shows "..." when publishing).


DMSetupPage

Profile setup form for first-time DM users.

Props:
PropTypeDescription
initialNamestringPre-filled name
onContinue(name: string) => voidContinue with name
onChange(name: string) => voidName change handler

Renders: Large avatar (80px), "Your Profile" heading, description, centered text input, "Continue" button. Uses local React state for the name field. Only calls onContinue if name is trimmed non-empty.


InviteRow

Message request row with accept/dismiss buttons.

Props:
PropTypeDescription
fromPubstringSender's public key
messagestringInvitation message
onAccept() => voidAccept handler
onDismiss() => voidDismiss handler

Renders: Truncated monospace pubkey, message text, Accept (accent) and Dismiss (muted) buttons.


DMPageScaffold

DM-specific page wrapper.

Props:
PropTypeDefaultDescription
chatBgbooleanundefinedUse chat background
childrenReact.ReactNoderequiredPage content

DMPageBody

DM page body container (flex-1, column, min-height 0).

Props:
PropTypeDescription
childrenReact.ReactNodeBody content

5. registry.ts -- Component Registry

Source: sdk-emulator/registry.ts

The protocol surface for manifest-driven rendering. Every visible primitive that an app's manifest can reference MUST be registered here.


REGISTRY_VERSION

const REGISTRY_VERSION = '0.1.0'

Bumped on incompatible changes (prop removal, axiom rename). Additive changes (new axiom, new optional prop) keep the same version.


ComponentSpec Interface

interface ComponentSpec {
  /** React component implementing the axiom */
  Component: React.ComponentType<any>
 
  /** Manifest-prop -> component-prop mapping.
   *  'expr':    evaluated from state/bindings
   *  'action':  wired as callback function
   *  'literal': passed as-is from manifest */
  props: Record<string, 'expr' | 'action' | 'literal'>
 
  /** Optional auto-wired props from runtime */
  wireAuto?: Array<'onBack' | 'lookupName' | 'lookupEnclave' | 'runtime'>
 
  /** If set, children are rendered and passed under this prop name */
  childrenSlot?: string
}

REGISTRY Object

Complete registry of all components. Organized by category:

Common (Stage-2) Axioms

KeyComponentProps (type)
PageScaffoldPageScaffoldbackground(literal)
ScrollBodyScrollBodyscroll(literal)
AvatarAvatarname(expr), size(literal)
EmptyStateEmptyStatemessage(expr)
ComposeBarComposeBardraft(expr), onChange(action), onSubmit(action), placeholder(literal), buttonLabel(literal), disabled(expr), pendingMessage(expr)
TabsTabstabs(literal), active(expr), onChange(action)
PostCardPostCardauthor(expr), authorPub(expr), body(expr), timestamp(expr), outgoing(expr), onClick(action)
StackStackgap(literal), padding(literal), align(literal). childrenSlot='children'
RowRowgap(literal), padding(literal), align(literal), wrap(literal). childrenSlot='children'
TextTextvalue(expr), size(literal), color(literal), weight(literal), align(literal), padding(literal), mono(literal)
InputInputvalue(expr), placeholder(literal), onChange(action), onSubmit(action), disabled(expr), variant(literal)
ButtonButtonlabel(expr), onClick(action), primary(literal), disabled(expr), fullWidth(literal)
BannerBannertitle(expr), subtitle(expr), kind(literal), onClick(action)
LoadingSpinnerLoadingSpinnersize(literal), message(expr)
ErrorStateErrorStatemessage(expr), retryLabel(literal), onRetry(action)

Lowercase Aliases

For backward compatibility with existing manifests: stack, row, text, label, button, banner, divider, timestamp.

Generic Patterns

KeyComponentProps (type)
HeaderHeadertitle(expr), subtitle(expr), showBack(literal), onBack(action), trailing(literal)
ListItemListItemtitle(expr), subtitle(expr), mono(literal), onClick(action)
FormFieldFormFieldlabel(literal), placeholder(literal), value(expr), onChange(action), mono(literal)
IconButtonIconButtononClick(action), size(literal), variant(literal)
StatusViewStatusViewtype(literal), message(expr), action(literal), onAction(action)
DividerDividerspacing(literal)
TimestampTimestampvalue(expr), size(literal)

DM (Stage-1) Axioms

KeyComponentProps (type)
DMHeaderDMHeadertitle(expr), subtitle(expr), showBack(literal), onBack(action), showAvatar(literal), avatarLetter(expr), trailing(literal)
EnvelopeBadgeEnvelopeBadgecount(expr), onClick(action)
ContactRowContactRowname(expr), pub(expr), state(expr), preview(expr), outgoing(expr), timestamp(expr), onClick(action)
MessageBubbleMessageBubbleoutgoing(expr), body(expr), timestamp(expr), tx_hash(expr), amount(expr), token(expr)
ChatInputBarChatInputBardraft(expr), onChange(action), onSend(action), disabled(expr), pendingMessage(expr)
EmptyChatEmptyChatname(expr)
LookupResultCardLookupResultCardname(expr), enclaveId(expr), draft(expr), onChange(action), onSend(action)
PublishBannerPublishBanneronPublish(action), publishing(expr)
DMSetupPageDMSetupPageinitialName(expr), onContinue(action), onChange(action)
InviteRowInviteRowfromPub(expr), message(expr), onAccept(action), onDismiss(action)

Re-exports from registry.ts

export * as DM from './dm'
export { TG } from './theme'

6. Package Entry (index.ts)

Source: sdk-emulator/index.ts

export * from './common'           // All common components
export * from './dm'               // All DM components
export * as Chrome from './chrome' // Chrome components under namespace
export { TG, type PaletteKey } from '../sdk-ui-kit/theme'
export { REGISTRY, REGISTRY_VERSION, type ComponentSpec } from './registry'

Chrome components are namespaced (Chrome.PhoneFrame, Chrome.ConnectButton, etc.) to avoid naming conflicts with app-level components.