npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@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

  1. Installation and Configuration
  2. User Guide (Visual Interface)
  3. Developer Guide (Integration)
  4. API Reference

Installation and Configuration

1. Install the package

npm install @1urso/generic-editor
# or
yarn add @1urso/generic-editor

2. 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/core

3. 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 para rgba), nomes CSS (red, blue), rgb(), rgba().
  • Exemplo (JSON):
    {
      "type": "text",
      "content": "Preço: {{price}}",
      "x": 50,
      "y": 50,
      "width": 200,
      "height": 40,
      "styleBindings": {
        "color": "priceColor",
        "backgroundColor": "tagBg"
      }
    }
    Se data = { "price": 10, "priceColor": "#FF0000", "tagBg": "rgba(0,0,0,0.1)" }, o texto será renderizado com color: #FF0000 e backgroundColor: 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 Delete key 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 price is greater than 100, set text color to red.
    • 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.

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}}.

  1. 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.
  2. 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.

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:

  1. Generate the initial HTML using generateHTML.
  2. Load the HTML in your view (Browser, WebView, OBS).
  3. 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 activeTemplateId changes, the editor applies the template state to the canvas.
  • If you omit activeTemplateId and onTemplateChange, 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. |