@1urso/generic-editor
v0.1.80
Published
<div align="center"> <a href="https://bearry.app"> <img src="https://cdn.bearry.app/images/logo_png.png" alt="Bearry - Streaming Tools" height="100"> </a> <br /> <br />
Readme
Generic Editor
A powerful, framework-agnostic, and 100% customizable React library for creating dynamic layouts, template generation, and visual editing. Designed to be the design engine within your application (Web, Electron, Tauri, Next.js, etc.).
This library is the core engine behind the visual editors found in Bearry - Streaming Tools.
📚 Table of Contents
- Installation and Configuration
- User Guide (Visual Interface)
- Developer Guide (Integration)
- API Reference
Installation and Configuration
1. Install the package
npm install @1urso/generic-editor
# or
yarn add @1urso/generic-editor2. Install Peer Dependencies
The editor uses modern libraries to ensure performance and accessibility. You need to install them in your project:
npm install @radix-ui/themes @radix-ui/react-icons react-resizable-panels re-resizable framer-motion @dnd-kit/core3. Import Styles
In your application entry file (e.g., main.tsx, App.tsx, or layout.tsx in Next.js), import the editor's CSS (required for the context menu) and Radix UI:
import "@1urso/generic-editor/dist/generic-editor.css"; // Essential for the editor to work
import "@radix-ui/themes/styles.css";User Guide (Visual Interface)
This section describes the features available to the end user who will use the editor on your platform.
Grouping and Layers Panel
- Group Elements:
- Select multiple elements and use the context menu option Agrupar Seleção.
- Groups act as a bounding box; moving the group moves all children.
- Clicking a child selects its parent group for consistent interactions.
- Rename Layers:
- Right-click any element or group and choose Renomear....
- Layers Panel (Left Sidebar):
- Shows a tree of Groups and their children.
- Drag any element in the list onto a Group to add it.
- Drop an element onto the “Soltar aqui para remover do grupo” area to ungroup it.
- Collapse/expand groups to focus on what matters.
Vínculos de Estilo (Cores por Variável)
- O que é: vincule propriedades de estilo (cor do texto, cor de fundo, cor da borda) diretamente a variáveis de dados, sem precisar de regras condicionais.
- Como usar:
- Abra Configurações Avançadas do elemento.
- Na seção Vínculos de Estilo (Data Binding), escolha uma variável para cada propriedade desejada.
- Propriedades suportadas:
color,backgroundColor,borderColor.
- Formato dos valores:
- Aceita cores CSS válidas:
#RRGGBB,#RRGGBBAA(convertido parargba), nomes CSS (red,blue),rgb(),rgba().
- Aceita cores CSS válidas:
- Exemplo (JSON):
Se{ "type": "text", "content": "Preço: {{price}}", "x": 50, "y": 50, "width": 200, "height": 40, "styleBindings": { "color": "priceColor", "backgroundColor": "tagBg" } }data = { "price": 10, "priceColor": "#FF0000", "tagBg": "rgba(0,0,0,0.1)" }, o texto será renderizado comcolor: #FF0000ebackgroundColor: rgba(0,0,0,0.1).
Basic Manipulation
The editor offers an experience similar to design tools like Canva or Figma:
- Add Elements: Use the sidebar (or buttons you implement) to drag or click and add Texts, Images, or Boxes.
- Move: Click and drag any element to reposition it.
- Resize: Click on the element to select it. Pull the handles (blue squares) on the edges or corners to change the size.
- Rotate: When selecting an element, a circular handle will appear above it. Click and drag to rotate freely.
- Delete: Select an element and press the
Deletekey or use the context menu.
Context Menu and Styling
Right-click on any element to open the advanced options menu.
General Options (All Elements)
- Duplicate: Creates an exact copy of the element next to the original.
- Remove: Deletes the element.
- Layers:
- Bring to front: Places the element above all others.
- Send to back: Places the element behind all others.
- Background Color: Changes the background color of the element (includes transparent).
- Borders:
- Radius: From 0px (square) to 50% (circle/oval).
- Thickness: Adds a solid border from 1px to 4px.
Advanced Settings (Formatting and Conditions)
Right-click and select Advanced Settings to access powerful data formatting and conditional styling options.
Data Formatting:
- Type: Choose between Text (Default), Boolean (True/False), Date, or Number/Currency.
- Boolean: Define custom labels for true/false values (e.g., "Active" / "Inactive").
- Date: Custom date patterns (e.g., "DD/MM/YYYY HH:mm").
- Number: Format as Decimal, Currency (with symbol), or Percentage.
Conditional Formatting:
- Define rules to change the element's style based on data values.
- Example: If
priceis greater than100, set text color tored. - Action: Choose between applying styles (Color, Bold, Background, etc.) or Hiding the Element completely.
- Supports multiple rules with operators like Equals, Not Equals, Contains, Greater Than, Less Than, Truthy, and Falsy.
Settings and Test Data
At the top of the left sidebar, the Settings button (gear icon) allows you to simulate how the layout will look with real data.
- List Configuration Tab:
- Sort Property: Defines which field will be used to sort the list (e.g.,
price,name). - Order: Ascending or Descending.
- Newest Position: Defines where the newest item appears ('top' or 'bottom').
- Scroll Behavior: Defines the scroll direction ('down' - default, or 'up' - chat-like).
- Container Height: Defines the fixed height of the list container in pixels. If the content exceeds this height, a vertical scrollbar will appear automatically.
- Sort Property: Defines which field will be used to sort the list (e.g.,
Working with Text and Fonts
When right-clicking on a Text element:
- Edit Text: Opens a window to type content. This is where you insert variables (e.g., Customer Name) by clicking on the available buttons.
- Font: Select from various web-safe fonts (Arial, Helvetica, etc.) and popular Google Fonts (Roboto, Open Sans, Montserrat).
- Import Google Font: Allows you to type the name of any Google Fonts font (e.g., "Pacifico") and the editor will automatically load it.
- Size: Adjust from 12px to 64px.
- Text Color: Pre-defined color palette.
- Weight: Normal or Bold.
- Alignment: Left, Center, or Right.
- Vertical Alignment: Top, Center, or Bottom.
Working with Images
When right-clicking on an Image element:
- Change Image:
- Upload: Upload an image from your computer.
- URL: Paste a direct link to an image from the web.
- Fit (Object Fit):
- Fit (Contain): The entire image is shown inside the box, maintaining proportions (may leave white space).
- Stretch (Fill): The image fills the entire box, potentially being cropped or distorted depending on the aspect ratio.
- Bind Data: Connects the image to a dynamic variable (e.g., Product Photo).
Export and Import
- Export: Saves the full layout (elements, list settings, mock data, canvas height).
- Import: Loads a previously exported JSON to restore the editor state.
- Images are serialized as Base64 inside the layout to avoid external dependencies.
Preview and Simulation
- Preview Panel: See a live rendering of your layout.
- Simulation Mode (Lists): Visualize entry animations and list behavior for incoming items.
- Animations: Configure entry animations (fade, slide, zoom, etc.) for list items.
Developer Guide (Integration)
Initialization and Props
To start the editor, you must provide the layout configuration which dictates what data (variables) will be available to the user.
import { EditorContent } from "@1urso/generic-editor";
const config = {
isList: false, // Single mode (e.g., ID Card) or List (e.g., Catalog)
name: "Employee ID Card",
props: [
// Define the variables that will appear in the "Insert Variable" button
{ name: "Full Name", dataName: "nome" },
{ name: "Role", dataName: "cargo" },
{ name: "Profile Picture", dataName: "fotoUrl" },
],
};
function App() {
return (
<div style={{ height: "100vh", width: "100%" }}>
<EditorContent
layout={config}
onSave={(json) => saveToBackend(json)}
theme="light" // Optional: 'light' or 'dark'
/>
</div>
);
}Data Binding and Variables
The editor uses an interpolation system based on double braces {{key}}.
- Insertion: The user does not need to type
{{...}}manually. In the text edit window, they will see buttons (badges) with friendly names (e.g., "Full Name"). Clicking them inserts the{{nome}}code. - Rendering:
- If
data = { nome: "Maria" }, the text "Hello {{nome}}" becomes "Hello Maria". - If the variable does not exist in the data, the editor keeps the original text
{{nome}}or displays empty, depending on the configuration.
- If
Modes: Single Item vs. List
The isList property drastically changes how the editor and HTML generator behave.
isList: false (Single Mode)
- Usage: Certificates, ID Cards, Banners, Covers.
- Data: Expects a Single Object
{ nome: 'John', cargo: 'Dev' }. - Canvas: Shows a single page/art.
isList: true (List Mode)
- Usage: Price Lists, Catalogs, Shelf Labels, Reports.
- Data: Expects an Array of Objects
[{ nome: 'A' }, { nome: 'B' }]. - Canvas:
- The user designs the "Template Item".
- The editor repeats this model vertically for each item in the mock data array.
- Allows visualization of how the list behaves with multiple items.
- Height Limit: Elements are constrained within the defined item height (canvas height).
JSON Structure
The output of onSave is a JSON ready to be stored.
{
"isList": false,
"elements": [
{
"id": "uuid-v4",
"type": "text", // 'text' | 'image' | 'box'
"content": "Name: {{nome}}",
"x": 50,
"y": 100,
"width": 200,
"height": 40,
"rotation": 0,
"style": {
"color": "#000000",
"fontSize": "16px",
"fontFamily": "Roboto",
"textAlign": "center"
},
"dataBinding": "nome", // Optional, used for direct binding
"formatting": {
"type": "text" // 'text' | 'boolean' | 'date' | 'number'
// Extra fields based on type:
// trueLabel, falseLabel (boolean)
// dateFormat (date)
// numberFormat, currencySymbol, decimalPlaces (number)
},
"conditions": [
{
"id": "rule-1",
"property": "price",
"operator": "greaterThan",
"value": "100",
"style": { "color": "red", "fontWeight": "bold" }
}
]
}
],
"listSettings": {
"sortProp": "nome",
"sortOrder": "asc",
"newestPosition": "bottom",
"scrollDirection": "down",
"containerHeight": 400 // Optional: Limits the list height (scrollable)
}
}Generating HTML (Backend/Print)
To generate the final result (for printing, saving as PDF, or sending via email), use the generateHTML function. It runs in any JS environment (Node, Browser, etc.).
import { generateHTML } from "@1urso/generic-editor";
// 1. Load layout and data
const layout = JSON.parse(db.getLayout());
const dados = db.getFuncionarios(); // Array or Object
// 2. Generate HTML
const htmlString = generateHTML(layout.elements, dados, {
isList: layout.isList, // Important to pass the correct mode
listSettings: layout.listSettings,
canvasHeight: layout.canvasHeight, // Optional: Force item height
});
// 3. Inject where needed
document.getElementById("preview").innerHTML = htmlString;Dynamic List Updates (Real-time)
When generating HTML for lists (isList: true), the editor automatically injects a smart script that enables real-time updates without regenerating the entire HTML.
This is perfect for OBS Overlays, Chat Widgets, or Live Feeds.
How to use:
- Generate the initial HTML using
generateHTML. - Load the HTML in your view (Browser, WebView, OBS).
- Call
window.addItem(data)whenever you have new data.
// Example: Adding a new item via WebSocket or Event
const newItem = {
name: "New Subscriber",
message: "Hello World!",
avatar: "https://...",
};
// This function is automatically available in the generated HTML
if (window.addItem) {
window.addItem(newItem);
}The injected script automatically handles:
- Rendering: Uses the exact same layout configuration from the JSON.
- Animation: Smooth slide-in animation for new items.
- Positioning: Respects 'Newest on Top' or 'Bottom' settings.
- Scrolling: Auto-scrolls to the newest item if configured.
Templates
Use templates to let your system provide ready-to-use layouts and let the editor apply them.
Enable
const templates = [
{ id: 'classic', name: 'Clássico', state: savedJsonClassic },
{ id: 'card', name: 'Cartão', state: savedJsonCard },
];
const [activeTemplateId, setActiveTemplateId] = useState('classic');
<EditorContent
layout={editorLayout}
templates={templates}
activeTemplateId={activeTemplateId}
onTemplateChange={setActiveTemplateId}
/>Send
Provide templates from your backend or local store. The state field accepts:
- Full saved JSON (with
elements,listSettings,canvasHeight, etc.) - A simple array of elements
{
"templates": [
{
"id": "classic",
"name": "Clássico",
"description": "Layout simples com nome e mensagem.",
"state": {
"elements": [{ "type": "text", "content": "{{displayName}}", "x": 20, "y": 20, "width": 240, "height": 40 }]
}
}
]
}Use
- When
activeTemplateIdchanges, the editor applies the template state to the canvas. - If you omit
activeTemplateIdandonTemplateChange, the editor applies the template the user selects locally.
API Reference
Component <EditorContent />
| Property | Type | Required | Default | Description |
| -------------- | ------------------------ | -------- | ------- | --------------------------------------------- |
| layout | ILayout | Yes | - | Initial configuration of variables and mode. |
| initialState | any | No | null | JSON state to load a saved layout. |
| onSave | (json: string) => void | No | - | Callback triggered when clicking Save button. |
| mockData | any[] | No | [] | Data for immediate preview during editing. |
TypeScript Types
ILayout
interface ILayout {
name: string; // Layout name (metadata)
isList?: boolean; // Defines default behavior (List or Single)
props: IProp[]; // List of available variables
}IProp
interface IProp {
name: string; // Visible label (e.g., "Product Price")
dataName: string; // Object key (e.g., "product_price")
}EditorProps
| Prop | Type | Required | Description |
| -------------- | ------------------------ | -------- | ------------------------------------- |
| layout | ILayout | Yes | Initial configuration and metadata. |
| onSave | (json: string) => void | No | Callback triggered on save. |
| initialState | any | No | Previously saved state (parsed JSON). |
| theme | 'light' \| 'dark' | No | Interface theme (default: 'light'). |
| templates | ITemplate[] | No | Lista de templates fornecidos pelo sistema. |
| activeTemplateId | string | No | Template ativo controlado externamente. |
| onTemplateChange | (id: string) => void | No | Callback para o sistema trocar template. |
