@ocusell/playground-widget
v0.1.1
Published
Embeddable Rulesetta Playground widget for writing and validating RCP-019 rules
Readme
@ocusell/playground-widget
An embeddable iframe widget that lets users write and validate RCP-019 rules inside your own app. When the user clicks Save, the widget emits a rulesetta:save event via postMessage with the rule payload, which your app can persist in its own database.
Install
npm install @ocusell/playground-widgetThe package ships three independent entrypoints:
| Import path | What it exports |
|---|---|
| @ocusell/playground-widget | Framework-agnostic PlaygroundWidget class |
| @ocusell/playground-widget/vue | usePlaygroundWidget composable + <PlaygroundWidgetComponent> |
| @ocusell/playground-widget/react | <PlaygroundWidget> React component |
Usage
Plain iframe (no JS required)
For static initial state, you can use the iframe directly without any JavaScript:
<iframe
src="https://api.rulesetta.com/play/widget#<base64-encoded-state>"
width="100%"
height="600"
style="border:none"
></iframe>Use @ocusell/playground-link's encodeFragment helper to build the fragment, or set the state dynamically via postMessage after load.
Vanilla JS / TypeScript
import { PlaygroundWidget } from "@ocusell/playground-widget";
const widget = new PlaygroundWidget(document.getElementById("container")!, {
baseUrl: "https://api.rulesetta.com",
initialState: {
expression: "ListPrice > 0",
action: "REJECT",
fieldName: "ListPrice",
},
onSave(state) {
// { expression, action, fieldName }
console.log("Rule saved:", state);
},
height: "600px",
});
// Update state programmatically after load:
widget.setState({ expression: "ListPrice >= 50000" });
// Clean up (removes the iframe and event listeners):
widget.destroy();Vue 3
<script setup lang="ts">
import { PlaygroundWidgetComponent } from "@ocusell/playground-widget/vue";
function onSave(state) {
console.log("Rule saved:", state);
}
</script>
<template>
<PlaygroundWidgetComponent
base-url="https://api.rulesetta.com"
:initial-state="{ expression: 'ListPrice > 0', action: 'REJECT', fieldName: 'ListPrice' }"
height="600px"
@save="onSave"
/>
</template>Or use the composable directly:
import { usePlaygroundWidget } from "@ocusell/playground-widget/vue";
const { containerRef } = usePlaygroundWidget({
baseUrl: "https://api.rulesetta.com",
onSave(state) { console.log(state); },
});React
import { PlaygroundWidget, PlaygroundWidgetHandle } from "@ocusell/playground-widget/react";
import { useRef } from "react";
function RuleEditor() {
const widgetRef = useRef<PlaygroundWidgetHandle>(null);
return (
<PlaygroundWidget
ref={widgetRef}
baseUrl="https://api.rulesetta.com"
initialState={{ expression: "ListPrice > 0", action: "REJECT", fieldName: "ListPrice" }}
height="600px"
onSave={(state) => console.log("Saved:", state)}
/>
);
}postMessage Protocol
The widget communicates with the host via window.postMessage.
Widget → Host
| Message type | Payload | When |
|---|---|---|
| rulesetta:ready | {} | After iframe loads |
| rulesetta:save | { state: { expression, action, fieldName } } | When user clicks Save |
Host → Widget
| Message type | Payload | Effect |
|---|---|---|
| rulesetta:set-state | { state: { expression?, action?, fieldName?, data? } } | Updates editor state |
Publishing
See docs/npm-publishing.md for manual publishing instructions.
