@1urso/generic-editor 0.1.0 → 0.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +206 -145
- package/dist/editor/context.d.ts +2 -0
- package/dist/editor/index.d.ts +1 -0
- package/dist/generic-editor.css +1 -1
- package/dist/generic-editor.js +472 -396
- package/dist/generic-editor.umd.cjs +2 -2
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,216 +1,277 @@
|
|
|
1
1
|
# Generic Editor
|
|
2
2
|
|
|
3
|
-
Uma biblioteca React poderosa
|
|
3
|
+
Uma biblioteca React poderosa, agnóstica de framework e **100% personalizável** para criação de layouts dinâmicos, geração de templates e edição visual. Projetada para ser o motor de design dentro da sua aplicação (Web, Electron, Tauri, Next.js, etc.).
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
---
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
- **Data Binding**: Suporte a variáveis dinâmicas (ex: `{{produto.nome}}`) para geração de templates.
|
|
9
|
-
- **Framework Agnostic**: Funciona em qualquer ambiente React.
|
|
10
|
-
- **JSON Based**: Entrada e saída puramente em JSON, facilitando persistência e integração com backends.
|
|
11
|
-
- **Socket Ready**: Projetado para suportar atualizações em tempo real via WebSockets.
|
|
12
|
-
- **Preview em Tempo Real**: Visualização instantânea de como o layout ficará renderizado.
|
|
7
|
+
## 📚 Índice
|
|
13
8
|
|
|
14
|
-
|
|
9
|
+
1. [Instalação e Configuração](#instalação-e-configuração)
|
|
10
|
+
2. [Guia do Usuário (Interface Visual)](#guia-do-usuário-interface-visual)
|
|
11
|
+
- [Manipulação Básica](#manipulação-básica)
|
|
12
|
+
- [Menu de Contexto e Estilização](#menu-de-contexto-e-estilização)
|
|
13
|
+
- [Trabalhando com Textos e Fontes](#trabalhando-com-textos-e-fontes)
|
|
14
|
+
- [Trabalhando com Imagens](#trabalhando-com-imagens)
|
|
15
|
+
3. [Guia do Desenvolvedor (Integração)](#guia-do-desenvolvedor-integração)
|
|
16
|
+
- [Inicialização e Props](#inicialização-e-props)
|
|
17
|
+
- [Data Binding e Variáveis](#data-binding-e-variáveis)
|
|
18
|
+
- [Modos: Item Único vs. Lista](#modos-item-único-vs-lista)
|
|
19
|
+
- [Estrutura do JSON](#estrutura-do-json)
|
|
20
|
+
- [Gerando HTML (Backend/Print)](#gerando-html-backendprint)
|
|
21
|
+
4. [API Reference](#api-reference)
|
|
22
|
+
|
|
23
|
+
---
|
|
24
|
+
|
|
25
|
+
## Instalação e Configuração
|
|
26
|
+
|
|
27
|
+
### 1. Instale o pacote
|
|
15
28
|
|
|
16
29
|
```bash
|
|
17
|
-
npm install generic-editor
|
|
30
|
+
npm install @1urso/generic-editor
|
|
18
31
|
# ou
|
|
19
|
-
yarn add generic-editor
|
|
32
|
+
yarn add @1urso/generic-editor
|
|
20
33
|
```
|
|
21
34
|
|
|
22
|
-
### Peer Dependencies
|
|
35
|
+
### 2. Instale as dependências (Peer Dependencies)
|
|
23
36
|
|
|
24
|
-
|
|
37
|
+
O editor utiliza bibliotecas modernas para garantir performance e acessibilidade. Você precisa instalá-las no seu projeto:
|
|
25
38
|
|
|
26
39
|
```bash
|
|
27
40
|
npm install @radix-ui/themes @radix-ui/react-icons react-resizable-panels re-resizable framer-motion @dnd-kit/core
|
|
28
41
|
```
|
|
29
42
|
|
|
30
|
-
|
|
43
|
+
### 3. Importe os Estilos
|
|
44
|
+
|
|
45
|
+
No arquivo de entrada da sua aplicação (ex: `main.tsx`, `App.tsx` ou `layout.tsx` no Next.js), importe o CSS do Radix UI:
|
|
31
46
|
|
|
32
47
|
```tsx
|
|
33
|
-
import
|
|
48
|
+
import "@radix-ui/themes/styles.css";
|
|
34
49
|
```
|
|
35
50
|
|
|
36
|
-
|
|
51
|
+
---
|
|
52
|
+
|
|
53
|
+
## Guia do Usuário (Interface Visual)
|
|
54
|
+
|
|
55
|
+
Esta seção descreve as funcionalidades disponíveis para o **usuário final** que utilizará o editor na sua plataforma.
|
|
56
|
+
|
|
57
|
+
### Manipulação Básica
|
|
58
|
+
|
|
59
|
+
O editor oferece uma experiência similar a ferramentas de design como Canva ou Figma:
|
|
60
|
+
|
|
61
|
+
- **Adicionar Elementos**: Utilize a barra lateral (ou botões que você implementar) para arrastar ou clicar e adicionar Textos, Imagens ou Caixas.
|
|
62
|
+
- **Mover**: Clique e arraste qualquer elemento para reposicioná-lo.
|
|
63
|
+
- **Redimensionar**: Clique no elemento para selecioná-lo. Puxe as alças (quadrados azuis) nas bordas ou cantos para alterar o tamanho.
|
|
64
|
+
- **Rotacionar**: Ao selecionar um elemento, uma alça circular aparecerá acima dele. Clique e arraste para girar livremente.
|
|
65
|
+
- **Deletar**: Selecione um elemento e pressione a tecla `Delete` ou use o menu de contexto.
|
|
66
|
+
|
|
67
|
+
### Menu de Contexto e Estilização
|
|
68
|
+
|
|
69
|
+
**Clique com o botão direito** em qualquer elemento para abrir o menu de opções avançadas.
|
|
70
|
+
|
|
71
|
+
#### Opções Gerais (Todos os Elementos)
|
|
72
|
+
|
|
73
|
+
- **Duplicar**: Cria uma cópia exata do elemento próximo ao original.
|
|
74
|
+
- **Remover**: Exclui o elemento.
|
|
75
|
+
- **Camadas**:
|
|
76
|
+
- _Trazer para frente_: Coloca o elemento sobre todos os outros.
|
|
77
|
+
- _Enviar para trás_: Coloca o elemento atrás de todos.
|
|
78
|
+
- **Cor de Fundo**: Altera a cor de fundo do elemento (inclui transparente).
|
|
79
|
+
- **Bordas**:
|
|
80
|
+
- _Arredondamento_: De 0px (quadrado) até 50% (círculo/oval).
|
|
81
|
+
- _Espessura_: Adiciona borda sólida de 1px a 4px.
|
|
82
|
+
|
|
83
|
+
### Configurações e Dados de Teste
|
|
84
|
+
|
|
85
|
+
No topo da barra lateral esquerda, o botão **Configurações** (ícone de engrenagem) permite simular como o layout ficará com dados reais.
|
|
37
86
|
|
|
38
|
-
|
|
87
|
+
- **Aba Configuração da Lista**:
|
|
88
|
+
- _Propriedade para Ordenar_: Define qual campo será usado para ordenar a lista (ex: `preco`, `nome`).
|
|
89
|
+
- _Ordem_: Crescente ou Decrescente.
|
|
90
|
+
- **Aba Dados Mockados**:
|
|
91
|
+
- _Dados para Lista_: Um array JSON `[...]` para testar o modo lista.
|
|
92
|
+
- _Dados Únicos_: Um objeto JSON `{...}` para testar o modo único.
|
|
93
|
+
> Edite esses JSONs para ver o layout reagir em tempo real às suas variáveis.
|
|
94
|
+
|
|
95
|
+
### Trabalhando com Textos e Fontes
|
|
96
|
+
|
|
97
|
+
Ao clicar com o botão direito em um elemento de **Texto**:
|
|
98
|
+
|
|
99
|
+
- **Editar Texto**: Abre uma janela para digitar o conteúdo. É aqui que você insere variáveis (ex: Nome do Cliente) clicando nos botões disponíveis.
|
|
100
|
+
- **Fonte**: Selecione entre diversas fontes seguras para web (Arial, Helvetica, etc) e Google Fonts populares (Roboto, Open Sans, Montserrat).
|
|
101
|
+
- _Importar Google Font_: Permite digitar o nome de qualquer fonte do Google Fonts (ex: "Pacifico") e o editor a carregará automaticamente.
|
|
102
|
+
- **Tamanho**: Ajuste de 12px a 64px.
|
|
103
|
+
- **Cor do Texto**: Paleta de cores pré-definida.
|
|
104
|
+
- **Peso**: Normal ou Negrito.
|
|
105
|
+
- **Alinhamento**: Esquerda, Centro ou Direita.
|
|
106
|
+
|
|
107
|
+
### Trabalhando com Imagens
|
|
108
|
+
|
|
109
|
+
Ao clicar com o botão direito em um elemento de **Imagem**:
|
|
110
|
+
|
|
111
|
+
- **Alterar Imagem**:
|
|
112
|
+
- _Upload_: Carregue uma imagem do seu computador.
|
|
113
|
+
- _URL_: Cole um link direto para uma imagem da web.
|
|
114
|
+
- **Ajuste (Object Fit)**:
|
|
115
|
+
- _Ajustar (Contain)_: A imagem inteira é mostrada dentro da caixa, mantendo a proporção (pode sobrar espaço em branco).
|
|
116
|
+
- _Esticar (Fill)_: A imagem preenche toda a caixa, podendo ser cortada ou distorcida dependendo da proporção.
|
|
117
|
+
- **Vincular Dados**: Conecta a imagem a uma variável dinâmica (ex: Foto do Produto).
|
|
118
|
+
|
|
119
|
+
---
|
|
120
|
+
|
|
121
|
+
## Guia do Desenvolvedor (Integração)
|
|
122
|
+
|
|
123
|
+
### Inicialização e Props
|
|
124
|
+
|
|
125
|
+
Para iniciar o editor, você deve fornecer a configuração de `layout` que dita quais dados (variáveis) estarão disponíveis para o usuário.
|
|
39
126
|
|
|
40
127
|
```tsx
|
|
41
|
-
import
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
const handleSave = (jsonState: string) => {
|
|
55
|
-
console.log("Layout salvo:", jsonState);
|
|
56
|
-
// Envie para sua API, salve em arquivo, etc.
|
|
57
|
-
};
|
|
128
|
+
import { EditorContent } from "@1urso/generic-editor";
|
|
129
|
+
|
|
130
|
+
const config = {
|
|
131
|
+
isList: false, // Modo único (ex: Crachá) ou Lista (ex: Catálogo)
|
|
132
|
+
name: "Crachá de Funcionário",
|
|
133
|
+
props: [
|
|
134
|
+
// Define as variáveis que aparecerão no botão "Inserir Variável"
|
|
135
|
+
{ name: "Nome Completo", dataName: "nome" },
|
|
136
|
+
{ name: "Cargo", dataName: "cargo" },
|
|
137
|
+
{ name: "Foto de Perfil", dataName: "fotoUrl" },
|
|
138
|
+
],
|
|
139
|
+
};
|
|
58
140
|
|
|
141
|
+
function App() {
|
|
59
142
|
return (
|
|
60
|
-
<div style={{ height:
|
|
61
|
-
<EditorContent
|
|
62
|
-
layout={
|
|
63
|
-
onSave={
|
|
143
|
+
<div style={{ height: "100vh", width: "100%" }}>
|
|
144
|
+
<EditorContent
|
|
145
|
+
layout={config}
|
|
146
|
+
onSave={(json) => saveToBackend(json)}
|
|
147
|
+
theme="light" // Opcional: 'light' ou 'dark'
|
|
64
148
|
/>
|
|
65
149
|
</div>
|
|
66
150
|
);
|
|
67
|
-
}
|
|
151
|
+
}
|
|
68
152
|
```
|
|
69
153
|
|
|
70
|
-
|
|
154
|
+
### Data Binding e Variáveis
|
|
71
155
|
|
|
72
|
-
|
|
156
|
+
O editor utiliza um sistema de interpolação baseado em chaves duplas `{{chave}}`.
|
|
73
157
|
|
|
74
|
-
|
|
158
|
+
1. **Inserção**: O usuário não precisa digitar `{{...}}` manualmente. Na janela de edição de texto, ele verá botões (badges) com os nomes amigáveis (ex: "Nome Completo"). Ao clicar, o código `{{nome}}` é inserido.
|
|
159
|
+
2. **Renderização**:
|
|
160
|
+
- Se `data = { nome: "Maria" }`, o texto "Olá {{nome}}" vira "Olá Maria".
|
|
161
|
+
- Se a variável não existir nos dados, o editor mantém o texto original `{{nome}}` ou exibe vazio, dependendo da configuração.
|
|
75
162
|
|
|
76
|
-
|
|
77
|
-
|------|------|-------------|-----------|
|
|
78
|
-
| `layout` | `ILayout` | Sim | Configuração das variáveis disponíveis para data-binding. |
|
|
79
|
-
| `initialState` | `any` (JSON string ou Objeto) | Não | Estado inicial do editor. Útil para carregar layouts salvos ou atualizações via socket. |
|
|
80
|
-
| `onSave` | `(json: string) => void` | Não | Callback disparado quando o usuário clica em "Salvar". Retorna o estado completo em JSON. |
|
|
163
|
+
### Modos: Item Único vs. Lista
|
|
81
164
|
|
|
82
|
-
|
|
165
|
+
A propriedade `isList` muda drasticamente como o editor e o gerador de HTML se comportam.
|
|
83
166
|
|
|
84
|
-
#### `
|
|
167
|
+
#### `isList: false` (Modo Único)
|
|
85
168
|
|
|
86
|
-
|
|
169
|
+
- **Uso**: Certificados, Crachás, Banners, Capas.
|
|
170
|
+
- **Dados**: Espera um **Objeto Único** `{ nome: 'João', cargo: 'Dev' }`.
|
|
171
|
+
- **Canvas**: Mostra uma única página/arte.
|
|
87
172
|
|
|
88
|
-
|
|
89
|
-
interface ILayout {
|
|
90
|
-
props: IProp[];
|
|
91
|
-
}
|
|
173
|
+
#### `isList: true` (Modo Lista)
|
|
92
174
|
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
175
|
+
- **Uso**: Listas de Preços, Catálogos, Etiquetas de Gôndola, Relatórios.
|
|
176
|
+
- **Dados**: Espera um **Array de Objetos** `[{ nome: 'A' }, { nome: 'B' }]`.
|
|
177
|
+
- **Canvas**:
|
|
178
|
+
- O usuário desenha o "Item Modelo" (Template).
|
|
179
|
+
- O editor repete esse modelo verticalmente para cada item do array de dados mockados.
|
|
180
|
+
- Permite visualizar como a lista se comporta com múltiplos itens.
|
|
98
181
|
|
|
99
|
-
|
|
182
|
+
### Estrutura do JSON
|
|
100
183
|
|
|
101
|
-
O
|
|
184
|
+
O output do `onSave` é um JSON pronto para ser armazenado.
|
|
102
185
|
|
|
103
186
|
```json
|
|
104
187
|
{
|
|
188
|
+
"isList": false,
|
|
105
189
|
"elements": [
|
|
106
190
|
{
|
|
107
|
-
"id": "uuid-
|
|
108
|
-
"type": "text", //
|
|
109
|
-
"content": "
|
|
191
|
+
"id": "uuid-v4",
|
|
192
|
+
"type": "text", // 'text' | 'image' | 'box'
|
|
193
|
+
"content": "Nome: {{nome}}",
|
|
110
194
|
"x": 50,
|
|
111
195
|
"y": 100,
|
|
112
196
|
"width": 200,
|
|
113
|
-
"height":
|
|
197
|
+
"height": 40,
|
|
114
198
|
"rotation": 0,
|
|
115
|
-
"style": {
|
|
199
|
+
"style": {
|
|
200
|
+
"color": "#000000",
|
|
201
|
+
"fontSize": "16px",
|
|
202
|
+
"fontFamily": "Roboto",
|
|
203
|
+
"textAlign": "center"
|
|
204
|
+
},
|
|
205
|
+
"dataBinding": "nome" // Opcional, usado para vínculo direto
|
|
116
206
|
}
|
|
117
207
|
],
|
|
118
|
-
"listSettings": {
|
|
119
|
-
|
|
120
|
-
|
|
208
|
+
"listSettings": {
|
|
209
|
+
"sortProp": "nome",
|
|
210
|
+
"sortOrder": "asc"
|
|
211
|
+
}
|
|
121
212
|
}
|
|
122
213
|
```
|
|
123
214
|
|
|
124
|
-
|
|
215
|
+
### Gerando HTML (Backend/Print)
|
|
125
216
|
|
|
126
|
-
|
|
217
|
+
Para gerar o resultado final (para imprimir, salvar PDF ou enviar por email), use a função `generateHTML`. Ela roda em qualquer ambiente JS (Node, Browser, etc).
|
|
127
218
|
|
|
128
|
-
|
|
219
|
+
```typescript
|
|
220
|
+
import { generateHTML } from "@1urso/generic-editor";
|
|
129
221
|
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
import { io } from 'socket.io-client';
|
|
222
|
+
// 1. Carregue o layout e os dados
|
|
223
|
+
const layout = JSON.parse(db.getLayout());
|
|
224
|
+
const dados = db.getFuncionarios(); // Array ou Objeto
|
|
134
225
|
|
|
135
|
-
|
|
226
|
+
// 2. Gere o HTML
|
|
227
|
+
const htmlString = generateHTML(layout.elements, dados, {
|
|
228
|
+
isList: layout.isList, // Importante passar o modo correto
|
|
229
|
+
listSettings: layout.listSettings,
|
|
230
|
+
});
|
|
136
231
|
|
|
137
|
-
|
|
138
|
-
|
|
232
|
+
// 3. Injete onde precisar
|
|
233
|
+
document.getElementById("preview").innerHTML = htmlString;
|
|
234
|
+
```
|
|
139
235
|
|
|
140
|
-
|
|
141
|
-
// Escuta atualizações do servidor
|
|
142
|
-
socket.on('layout-update', (data) => {
|
|
143
|
-
setRemoteState(data);
|
|
144
|
-
});
|
|
236
|
+
---
|
|
145
237
|
|
|
146
|
-
|
|
147
|
-
}, []);
|
|
238
|
+
## API Reference
|
|
148
239
|
|
|
149
|
-
|
|
150
|
-
// Envia alterações para o servidor
|
|
151
|
-
socket.emit('save-layout', jsonState);
|
|
152
|
-
};
|
|
240
|
+
### Componente `<EditorContent />`
|
|
153
241
|
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
);
|
|
161
|
-
};
|
|
162
|
-
```
|
|
242
|
+
| Propriedade | Tipo | Obrigatório | Padrão | Descrição |
|
|
243
|
+
| -------------- | ------------------------ | ----------- | ------ | --------------------------------------------- |
|
|
244
|
+
| `layout` | `ILayout` | **Sim** | - | Configuração inicial das variáveis e modo. |
|
|
245
|
+
| `initialState` | `any` | Não | `null` | Estado JSON para carregar um layout salvo. |
|
|
246
|
+
| `onSave` | `(json: string) => void` | Não | - | Callback acionado ao clicar no botão Salvar. |
|
|
247
|
+
| `mockData` | `any[]` | Não | `[]` | Dados para preview imediato durante a edição. |
|
|
163
248
|
|
|
164
|
-
|
|
249
|
+
### Tipos TypeScript
|
|
165
250
|
|
|
166
|
-
|
|
251
|
+
#### `ILayout`
|
|
167
252
|
|
|
168
|
-
|
|
253
|
+
```typescript
|
|
254
|
+
interface ILayout {
|
|
255
|
+
name: string; // Nome do layout (metadado)
|
|
256
|
+
isList?: boolean; // Define o comportamento padrão (Lista ou Único)
|
|
257
|
+
props: IProp[]; // Lista de variáveis disponíveis
|
|
258
|
+
}
|
|
259
|
+
```
|
|
169
260
|
|
|
170
|
-
|
|
171
|
-
// Exemplo Tauri / Electron
|
|
172
|
-
import { writeFile, readTextFile } from '@tauri-apps/api/fs'; // ou 'fs' do Node no Electron
|
|
173
|
-
|
|
174
|
-
const DesktopEditor = () => {
|
|
175
|
-
const [fileContent, setFileContent] = useState(null);
|
|
176
|
-
|
|
177
|
-
useEffect(() => {
|
|
178
|
-
// Carregar arquivo ao abrir
|
|
179
|
-
readTextFile('path/to/layout.json').then(content => {
|
|
180
|
-
setFileContent(content);
|
|
181
|
-
});
|
|
182
|
-
}, []);
|
|
183
|
-
|
|
184
|
-
const handleSave = async (jsonState) => {
|
|
185
|
-
await writeFile({
|
|
186
|
-
path: 'path/to/layout.json',
|
|
187
|
-
contents: jsonState
|
|
188
|
-
});
|
|
189
|
-
alert('Salvo com sucesso no disco!');
|
|
190
|
-
};
|
|
261
|
+
#### `IProp`
|
|
191
262
|
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
/>
|
|
198
|
-
);
|
|
199
|
-
};
|
|
263
|
+
```typescript
|
|
264
|
+
interface IProp {
|
|
265
|
+
name: string; // Rótulo visível (ex: "Preço do Produto")
|
|
266
|
+
dataName: string; // Chave do objeto (ex: "product_price")
|
|
267
|
+
}
|
|
200
268
|
```
|
|
201
269
|
|
|
202
|
-
|
|
270
|
+
#### `EditorProps`
|
|
203
271
|
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
body: jsonState // Envia o JSON completo
|
|
211
|
-
});
|
|
212
|
-
};
|
|
213
|
-
|
|
214
|
-
return <EditorContent layout={...} onSave={handleSave} />;
|
|
215
|
-
};
|
|
216
|
-
```
|
|
272
|
+
| Prop | Tipo | Obrigatório | Descrição |
|
|
273
|
+
| -------------- | ------------------------ | ----------- | ------------------------------------------- |
|
|
274
|
+
| `layout` | `ILayout` | Sim | Configuração inicial e metadados. |
|
|
275
|
+
| `onSave` | `(json: string) => void` | Não | Callback disparado ao salvar. |
|
|
276
|
+
| `initialState` | `any` | Não | Estado salvo anteriormente (JSON parseado). |
|
|
277
|
+
| `theme` | `'light' \| 'dark'` | Não | Tema da interface (padrão: `'light'`). |
|
package/dist/editor/context.d.ts
CHANGED
|
@@ -28,6 +28,7 @@ interface IEditorState {
|
|
|
28
28
|
listSettings: IListSettings;
|
|
29
29
|
availableProps: IProp[];
|
|
30
30
|
availableFonts: string[];
|
|
31
|
+
theme: 'light' | 'dark';
|
|
31
32
|
}
|
|
32
33
|
interface IEditorContext {
|
|
33
34
|
state: IEditorState;
|
|
@@ -44,6 +45,7 @@ export declare const EditorProvider: React.FC<{
|
|
|
44
45
|
children: ReactNode;
|
|
45
46
|
isList?: boolean;
|
|
46
47
|
availableProps?: IProp[];
|
|
48
|
+
theme?: 'light' | 'dark';
|
|
47
49
|
}>;
|
|
48
50
|
export declare const useEditor: () => IEditorContext;
|
|
49
51
|
export {};
|