UIP Core API

This document consolidates all internal technical details. Use the higher-level user guide at Core Concepts for consumer-facing information. This file targets authors extending or integrating deeply with UI Playground.


Table of Contents

  1. Architecture Overview
  2. Event Surface
  3. UIPRoot
  4. UIPPlugin Base
  5. State Model (UIPStateModel)
  6. Snippet Representation
  7. Persistent State (UIPStateStorage)
  8. Preview Integration Notes
  9. Attribute Mutation API
  10. Lifecycle Timeline
  11. Extensibility & Best Practices
  12. Performance Considerations
  13. Theme & Direction Handling
  14. Glossary

Architecture Overview

<uip-root>
 ├─ Template/script snippet holders (uip-snippet, uip-snippet-js, uip-snippet-note)
 ├─ UIPPreview (required) ← listens to uip:change, snippet switches
 ├─ Plugins (UIPPlugin descendants: editor, settings, list, etc.)
 │    └─ Read model via root.model
 │    └─ Mutate state via setHtml / setJS / changeAttribute / reset
 └─ UIPStateModel (html, js, note, snippet registry, change queue)
       └─ Emits internal events: uip:model:change / uip:model:snippet:change
       └─ Normalization & rendering preprocessors
       └─ Optional UIPStateStorage persistence

Flow summary:

  1. Plugin triggers a mutation on UIPStateModel.
  2. Model batches changes (microtask) and fires uip:model:change.
  3. UIPRoot wraps it into UIPChangeEventuip:change.
  4. Preview & other plugins react; preview may inline-render or iframe-refresh.
  5. Storage saves updated html/js/note if enabled.

Event Surface

Public Event Dispatcher Payload Purpose
uip:root:ready UIPRoot none Root initialized, initial snippet applied.
uip:change UIPRoot UIPChangeEvent Batched state change (html/js/note).
uip:snippet:change UIPRoot { detail: UIPStateModel } Active snippet changed.
uip:theme:change UIPRoot { detail: boolean } dark-theme toggled.
uip:dirchange UIPPreview none dir attribute updated on preview.

Internal (do not rely externally unless extending core):

UIPChangeEvent convenience API:


UIPRoot

Responsibilities:

Attributes:

Attribute Type Meaning
dark-theme boolean Dark UI theme state. Emits uip:theme:change.
store-key string Enables persistence storage namespace.
ready boolean (readonly) Set true after initial snippet applied.

Getters / Properties:

Lifecycle key points:

  1. Connect → optionally construct storage.
  2. Assign model.snippets.
  3. Apply current snippet (anchor > active > index 0).
  4. Mark ready and dispatch uip:root:ready.
  5. Scroll into view if anchor-based activation.
  6. Disconnect → clear model snippets.

UIPPlugin

Abstract base for all plugins.

Key features:

Attributes:

Attr Default Purpose
label '' Human-readable label, mirrored to aria-label.
root ::parent(uip-root) Traversal query to resolve nearest root.

Overridable hooks: standard CustomElement lifecycle plus attribute changes.

Recommended event subscription pattern:

@listen({event: 'uip:change', target: (that: MyPlugin) => that.$root})
_onChange(e: UIPChangeEvent) { /* react */ }

Guidelines:


UIPStateModel

State container for: current html/js/note, snippet registry, and batched change metadata.

Public getters:

Getter Type Notes
html string Current normalized HTML inner markup.
js string Current normalized JS.
note string Current normalized note content.
snippets UIPSnippetItem[] All snippet wrappers.
activeSnippet UIPSnippetItem? Active snippet wrapper.
anchorSnippet UIPSnippetItem? Snippet resolved by URL hash.

Mutation API:

Method Purpose
setHtml(markup, modifier, force?) Update current HTML (optional full refresh flag).
setJS(js, modifier) Update JS (forces preview rebuild when isolated).
setNote(text, modifier) Update note.
changeAttribute(cfg) Batch attribute updates across selected nodes.
getAttribute(selector, attr) Collect attribute values from live HTML mirror.
reset(source, modifier) Reset html or js to original snippet content.
applySnippet(snippet, modifier) Switch active snippet; fires snippet change event.
applyCurrentSnippet(modifier) Helper to choose resolved active snippet.
isHTMLChanged() / isJSChanged() Compare current edited vs original snippet.

Batching: _changes array collects metadata; dispatchChange (microtask) flushes once per tick.

Change attribution: modifier object allows plugins to ignore self-generated updates (e.isOnlyModifier(this)).

Normalization:


Snippet Representation

A snippet comprises:

Snippet attributes:

Attr Meaning
label Display name.
active Preferred initial active snippet if no anchor.
anchor Deep link slug (#hash).
uip-snippet-js ID of JS source holder.
uip-snippet-note ID of note holder.
uip-isolated Forces iframe rendering.
isolated-template Named template key for iframe HTML wrapper.
uip-js-readonly Disables JS editing (auto true if not isolated).

UIPSnippetItem exposes memoized getters: html, js, note, isolated, isolatedTemplate, label, anchor, active (get/set), isJsReadonly.

Activation priority: URL hash > element with active > first snippet.


Persistent State (UIPStateStorage)

Optional layer keyed by combination of store-key + original snippet HTML to avoid collisions after snippet content updates.

Key characteristics:

Aspect Description
Storage bucket localStorage['uip-editor-storage'] JSON map
Entry schema { ts, snippets } where snippets holds serialized { js, html, note }
Expiration 12 hours (entry dropped on access if stale)
Load trigger uip:model:snippet:change
Save trigger uip:model:change

Public methods: loadState(), saveState(), resetState(source).

Reset flow invalidates entry then calls model.reset(source, this).


Resetting the State

Use the reset plugin (<uip-reset>) or remove persisted state (store-key) to revert edited HTML/JS back to the original snippet source.


Preview Integration

Preview listens to uip:change and renders HTML either inline or via iframe for isolated snippets.

Isolated mode distinctions:

For user-focused behaviors (attributes & usage) see ../preview/README.md.


Attribute Mutation API

changeAttribute(cfg: ChangeAttrConfig) enables structured modifications within the current HTML mirror without reparsing full markup.

ChangeAttrConfig:

{
  target: string;          // CSS selector
  attribute: string;       // Attribute to set/toggle
  modifier: object;        // Initiator (plugin instance)
} & (
  { value: string | boolean } | { transform: (current: string | null) => string | boolean | null }
);

Semantics:


Lifecycle Timeline

  1. DOM Construction: Snippet templates and plugin elements appended inside <uip-root>.
  2. Root Connected: Storage (optional) created; snippet collector runs.
  3. Initial Snippet Apply: Model populated, events batched → uip:root:ready.
  4. User Interaction: Plugins mutate model; preview & others update.
  5. Snippet Switch: applySnippet sets html/js/note and triggers refresh logic.
  6. Disconnect: Root clears snippet registry (preventing stale mutations).

Extensibility & Best Practices

Goal Recommendation
Add new tool panel Extend UIPPlugin or existing panel abstraction; subscribe to uip:change.
Apply style variants Use root-level theme class toggles; avoid inline style mutations of preview DOM.
Track self vs external changes Use e.isOnlyModifier(this) on uip:change.
Complex multi-step edits Chain model mutations sequentially; rely on microtask batching.
Undo/redo Maintain external stack keyed off UIPChangeEvent.changes.
Large snippet sets Lazy inject snippet templates before they are needed; then re-run snippet assignment if dynamic.

Avoid:


Performance Considerations


Theme & Direction Handling

Concern Mechanism
Dark mode Toggle dark-theme attribute on <uip-root> → event consumers can react (uip:theme:change).
Text direction Set dir on <uip-preview> (mirrors to inner container) → uip:dirchange.

Plugins should prefer CSS variables / contextual classes over inline style rewrites for theme adjustments.


Glossary

Term Meaning
Snippet Self-contained example (HTML + optional JS + note).
Isolated Snippet Snippet rendered inside an iframe sandbox.
Modifier Object passed to model mutation APIs to identify change origin.
Force Refresh A change requiring full iframe rebuild (e.g., snippet switch).
Storage Key User-provided namespace enabling persistence.

Migration Notes

All previous per-topic markdown files now redirect here. External links will continue working via legacy anchors. For the user-facing overview see ../README.md.


Return to the User Overview or inspect the Preview User Guide.