@supernovaio/prototyping-tooling
v0.9.4
Published
Prototyping Tooling — iframe communication bridge for design-to-code workflows
Keywords
Readme
@supernovaio/prototyping-tooling
Communication bridge for iframe-based design-to-code prototyping workflows. Enables a host (parent window) to control and interact with a client (child iframe) for element selection, design-mode editing, annotations, and live source-code updates.
Installation
npm install @supernovaio/prototyping-toolingEntry Points
| Import path | Side | Description |
|---|---|---|
| @supernovaio/prototyping-tooling/host | Parent | ForgeHost — connects to the iframe, sends commands, receives events |
| @supernovaio/prototyping-tooling/client | Child | ForgeClient — auto-initializes, handles messages, manages overlays |
| @supernovaio/prototyping-tooling/react | Parent | React hooks: useElementSelector, useDesignMode |
| @supernovaio/prototyping-tooling/build | Build | Vite plugin that injects data-forge-id attributes into JSX |
| @supernovaio/prototyping-tooling | Either | Shared types, debug utilities, message constants |
Quick Start
Parent (host) app
import { ForgeHost } from '@supernovaio/prototyping-tooling/host'
const iframe = document.querySelector('iframe')!
const host = new ForgeHost(iframe)
await host.connect()
host.on('element-selected', (selection) => {
console.log('Selected:', selection.componentName, selection.forgeId)
})
host.enableDesignMode(true)Child (client) app
// Importing the client auto-initializes it
import '@supernovaio/prototyping-tooling/client'Vite plugin (child build)
// vite.config.ts
import { supernovaDesignPlugin } from '@supernovaio/prototyping-tooling/build'
export default defineConfig({
plugins: [react(), supernovaDesignPlugin()],
})API Reference
ForgeHost (host)
| Method | Description |
|---|---|
| connect() | Connects to the child iframe. Resolves on CHILD_READY. |
| enableSelectMode(enabled) | Toggles XPath element-picking mode |
| enableDesignMode(enabled) | Toggles design mode (click to select, edit props) |
| enableAnnotationMode(enabled) | Toggles annotation mode (click/drag to annotate) |
| updateElementText(forgeId, text) | Updates text content of a forge element |
| updateProperty(forgeId, prop, value) | Updates any property via Babel AST |
| deselectElement() | Clears the design-mode selection |
| deleteAnnotation(id) | Removes an annotation dot |
| keepAnnotation(id, order) | Confirms and numbers an annotation |
| updateAnnotationOrders(orders) | Bulk-updates annotation order numbers |
| toggleMarkers() | Toggles visibility of annotation marker badges |
| restoreAnnotations(annotations) | Re-sends saved annotations to the child to recreate dots after reconnect |
| registerComponents(components) | Sends component definitions to the child |
| on(event, handler) | Subscribes to events; returns unsubscribe fn |
| getStatus() | Returns 'connecting' \| 'connected' \| 'disconnected' |
| disconnect() | Cleans up listeners and resets state |
Events
| Event | Payload |
|---|---|
| connected | — |
| disconnected | — |
| xpath-selected | xpath: string |
| select-mode-disabled | — |
| design-mode-disabled | — |
| element-selected | ElementSelection |
| annotation-created | AnnotationData |
| annotation-dot-clicked | annotationId, dotX, dotY |
| source-updated | forgeId, source, filePath |
ForgeClient (client)
Singleton that auto-initializes on import. Access via ForgeClient.getInstance().
Accepts an optional ForgeClientOptions with an onError callback for error handling.
The client also exposes a public enableAnnotationMode(enabled) method for console-driven testing (see Console Access).
React Hooks
useElementSelector(host)
Returns { selectMode, connectionStatus, selectedXPath, enableSelectMode, clearXPath }.
useDesignMode(host)
Returns { designMode, selectedElement, enableDesignMode, updateText, updateProperty, deselectElement }.
Annotations
Annotation badges are anchored to their associated elements. When the page scrolls or the window resizes, badges automatically reposition to follow their elements.
Forge ID generation is deterministic — IDs are derived from filePath + line + column, so the same source position always produces the same ID across rebuilds. Elements rendered inside loops (.map()) share the same forge-id; the system disambiguates them using a forgeIdIndex.
Restoring annotations — the parent can call host.restoreAnnotations(annotations) after reconnecting to the child (e.g., after HMR reload) to recreate all annotation dots. The child resolves elements by data-forge-id first, falling back to XPath.
Keyboard Shortcuts
The plugin does not handle keyboard events. The consuming parent application is responsible for binding its own shortcuts and calling the appropriate ForgeHost methods. Example implementation:
useEffect(() => {
const handleKeyDown = (e: KeyboardEvent) => {
// Cmd/Ctrl + Shift + F → toggle annotation mode
if (e.shiftKey && (e.metaKey || e.ctrlKey) && e.key.toLowerCase() === 'f') {
e.preventDefault()
host.enableAnnotationMode(!annotationMode)
}
// Escape → close popup
if (e.key === 'Escape') {
closePopup()
}
// H → toggle annotation markers (skip when typing)
if (e.key.toLowerCase() === 'h' && !e.metaKey && !e.ctrlKey && !e.shiftKey && !e.altKey) {
const tag = (e.target as HTMLElement)?.tagName?.toLowerCase()
if (tag === 'input' || tag === 'textarea') return
host.toggleMarkers()
}
}
window.addEventListener('keydown', handleKeyDown)
return () => window.removeEventListener('keydown', handleKeyDown)
}, [host, annotationMode])Console Access
Both ForgeHost and ForgeClient expose themselves on the window for console-driven testing:
// From the parent page's console:
__forgeHost.enableAnnotationMode(true) // activate annotation mode
__forgeHost.enableAnnotationMode(false) // deactivate
__forgeHost.toggleMarkers() // toggle marker visibility
__forgeHost.restoreAnnotations([...]) // restore saved annotations
// From the child iframe's console (switch iframe context in DevTools):
__forgeClient.enableAnnotationMode(true)
__forgeAnnotations.toggleMarkers()Debug
import { enableDebug } from '@supernovaio/prototyping-tooling'
enableDebug(true) // Turns on timestamped console output
enableDebug(false) // Silences all library loggingArchitecture
src/
├── shared/ Constants, debug, events, messaging
├── client/
│ ├── general/ ForgeClient orchestrator, SourceCodeUpdater, types
│ ├── annotation/ AnnotationOverlay
│ ├── select-mode/ SelectModeController
│ └── design-mode/ DesignModeController
├── host/ ForgeHost, types
├── react/ useElementSelector, useDesignMode
└── build/ Vite plugin (supernovaDesignPlugin)See INTEGRATION.md for a detailed integration guide.
License
MIT
