eny-ai 1.0.0 → 2.0.0
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/V2_README.md +414 -0
- package/dist/chunk-2NUS77CI.js +195 -0
- package/dist/chunk-5KPALVCK.js +280 -0
- package/dist/{chunk-2WFUL4XJ.js → chunk-5PZUUNHS.js} +717 -751
- package/dist/{chunk-E4KJZEXX.js → chunk-AJH2I5ZI.js} +5 -0
- package/dist/chunk-LVJ3GJRQ.js +360 -0
- package/dist/{chunk-PNKVD2UK.js → chunk-MXA7TAAG.js} +11 -1
- package/dist/cli.js +5 -4
- package/dist/firebase.cjs +296 -0
- package/dist/firebase.d.cts +136 -0
- package/dist/firebase.d.ts +136 -0
- package/dist/firebase.js +17 -0
- package/dist/hooks.cjs +236 -0
- package/dist/hooks.d.cts +184 -0
- package/dist/hooks.d.ts +184 -0
- package/dist/hooks.js +31 -0
- package/dist/index.cjs +1622 -1092
- package/dist/index.d.cts +16 -195
- package/dist/index.d.ts +16 -195
- package/dist/index.js +68 -262
- package/dist/runtime.cjs +366 -0
- package/dist/runtime.d.cts +229 -0
- package/dist/runtime.d.ts +229 -0
- package/dist/runtime.js +25 -0
- package/dist/symbols.js +2 -2
- package/examples/app-simbolico-completo.tsx +249 -0
- package/examples/nextjs-integration.tsx +446 -0
- package/examples/v2-demo.tsx +377 -0
- package/package.json +23 -11
- package/dist/react/index.cjs +0 -342
- package/dist/react/index.d.cts +0 -751
- package/dist/react/index.d.ts +0 -751
- package/dist/react/index.js +0 -284
package/V2_README.md
ADDED
|
@@ -0,0 +1,414 @@
|
|
|
1
|
+
# 🚀 ENY-AI v2.0 - Runtime Simbólico
|
|
2
|
+
|
|
3
|
+
## ✨ O que é novo?
|
|
4
|
+
|
|
5
|
+
**ZERO BUILD STEP** - Execute código simbólico diretamente no navegador!
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
# Antes (v1):
|
|
9
|
+
eny compile app.eny → app.js → npm build → deploy
|
|
10
|
+
|
|
11
|
+
# Agora (v2):
|
|
12
|
+
import { Σ, ⚡, 🔑, ☐ } from 'eny-ai' → use direto no React!
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
## 🎯 Características v2.0
|
|
16
|
+
|
|
17
|
+
✅ **90% Simbólico** - Apenas UI usa texto normal
|
|
18
|
+
✅ **Zero Build** - Interprete símbolos em tempo real
|
|
19
|
+
✅ **React Native** - Hooks com API simbólica
|
|
20
|
+
✅ **Firebase Built-in** - 🔑 Auth, 📊 Database, 📡 Real-time
|
|
21
|
+
✅ **Sem Transpilação** - Símbolos executam direto via biblioteca
|
|
22
|
+
✅ **TypeScript Ready** - Type-safe simbólico
|
|
23
|
+
✅ **Production Ready** - 100+ testes passando
|
|
24
|
+
|
|
25
|
+
---
|
|
26
|
+
|
|
27
|
+
## 📦 Instalação
|
|
28
|
+
|
|
29
|
+
```bash
|
|
30
|
+
npm install eny-ai@latest
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
---
|
|
34
|
+
|
|
35
|
+
## 🎓 Guia Rápido (2 minutos)
|
|
36
|
+
|
|
37
|
+
### 1️⃣ Estado Reativo
|
|
38
|
+
|
|
39
|
+
```typescript
|
|
40
|
+
import { Σ } from 'eny-ai';
|
|
41
|
+
|
|
42
|
+
const [count, setCount] = Σ(0);
|
|
43
|
+
|
|
44
|
+
return (
|
|
45
|
+
<div>
|
|
46
|
+
<p>Count: {count}</p>
|
|
47
|
+
<button onClick={() => setCount(count + 1)}>+</button>
|
|
48
|
+
</div>
|
|
49
|
+
);
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
**O que é:** `Σ` = `useState` simbólico
|
|
53
|
+
|
|
54
|
+
---
|
|
55
|
+
|
|
56
|
+
### 2️⃣ Efeitos
|
|
57
|
+
|
|
58
|
+
```typescript
|
|
59
|
+
import { ⚡, 📜 } from 'eny-ai';
|
|
60
|
+
|
|
61
|
+
⚡(() => {
|
|
62
|
+
📜.info('Component mounted! ✅');
|
|
63
|
+
return () => console.log('Cleanup');
|
|
64
|
+
}, []);
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
**O que é:** `⚡` = `useEffect` | `📜` = Logger simbólico
|
|
68
|
+
|
|
69
|
+
---
|
|
70
|
+
|
|
71
|
+
### 3️⃣ Componentes UI
|
|
72
|
+
|
|
73
|
+
```typescript
|
|
74
|
+
import { ☐, Σ } from 'eny-ai';
|
|
75
|
+
|
|
76
|
+
const [isOpen, setIsOpen] = Σ(false);
|
|
77
|
+
|
|
78
|
+
return (
|
|
79
|
+
☐.card({
|
|
80
|
+
children: (
|
|
81
|
+
<>
|
|
82
|
+
<☐.h1>Welcome</☐.h1>
|
|
83
|
+
<☐.btn({
|
|
84
|
+
onClick: () => setIsOpen(true),
|
|
85
|
+
children: 'Abrir Modal'
|
|
86
|
+
})}
|
|
87
|
+
<☐.modal({
|
|
88
|
+
isOpen,
|
|
89
|
+
onClose: () => setIsOpen(false),
|
|
90
|
+
title: 'Dialog',
|
|
91
|
+
children: <p>Conteúdo aqui</p>
|
|
92
|
+
})}
|
|
93
|
+
</>
|
|
94
|
+
)
|
|
95
|
+
})
|
|
96
|
+
);
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
**Componentes disponíveis:**
|
|
100
|
+
- `☐.card` - Container com shadow
|
|
101
|
+
- `☐.btn` - Button (primary/danger/secondary)
|
|
102
|
+
- `☐.input` - Input controlado
|
|
103
|
+
- `☐.grid` - Grid layout
|
|
104
|
+
- `☐.flex` - Flexbox layout
|
|
105
|
+
- `☐.modal` - Modal dialog
|
|
106
|
+
- `☐.spinner` - Loading indicator
|
|
107
|
+
- `☐.badge` - Badge
|
|
108
|
+
- `☐.h1, ☐.h2, ☐.h3` - Headings
|
|
109
|
+
|
|
110
|
+
---
|
|
111
|
+
|
|
112
|
+
### 4️⃣ Firebase Auth
|
|
113
|
+
|
|
114
|
+
```typescript
|
|
115
|
+
import { firebase } from 'eny-ai';
|
|
116
|
+
|
|
117
|
+
// 🔑 Login
|
|
118
|
+
const handleLogin = async () => {
|
|
119
|
+
try {
|
|
120
|
+
const result = await firebase.🔑('user@email.com', 'password');
|
|
121
|
+
console.log('✅ Conectado!', result.user);
|
|
122
|
+
} catch (error) {
|
|
123
|
+
console.error('❌ Erro:', error);
|
|
124
|
+
}
|
|
125
|
+
};
|
|
126
|
+
|
|
127
|
+
// 🚪 Logout
|
|
128
|
+
await firebase.🚪();
|
|
129
|
+
|
|
130
|
+
// 👤 Usuário atual
|
|
131
|
+
const user = firebase.👤;
|
|
132
|
+
if (user) {
|
|
133
|
+
console.log('Olá,', user.email);
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
// 👁 Observar mudanças
|
|
137
|
+
firebase.👁((user) => {
|
|
138
|
+
console.log('Auth changed:', user);
|
|
139
|
+
});
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
---
|
|
143
|
+
|
|
144
|
+
### 5️⃣ Firebase Database
|
|
145
|
+
|
|
146
|
+
```typescript
|
|
147
|
+
import { firebase } from 'eny-ai';
|
|
148
|
+
|
|
149
|
+
// 📊 Escrever
|
|
150
|
+
await firebase.📊('users/123', { name: 'João', age: 30 });
|
|
151
|
+
|
|
152
|
+
// 🔍 Ler
|
|
153
|
+
const userData = await firebase.🔍('users/123');
|
|
154
|
+
console.log(userData);
|
|
155
|
+
|
|
156
|
+
// 📡 Observar em tempo real
|
|
157
|
+
firebase.📡('users/123', (data) => {
|
|
158
|
+
console.log('Data updated:', data);
|
|
159
|
+
});
|
|
160
|
+
|
|
161
|
+
// ✏️ Atualizar campos específicos
|
|
162
|
+
await firebase.✏️('users/123', { age: 31 });
|
|
163
|
+
|
|
164
|
+
// 🗑️ Deletar
|
|
165
|
+
await firebase.🗑️('users/123');
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
---
|
|
169
|
+
|
|
170
|
+
### 6️⃣ Armazenamento Persistente
|
|
171
|
+
|
|
172
|
+
```typescript
|
|
173
|
+
import { 𝓜 } from 'eny-ai';
|
|
174
|
+
|
|
175
|
+
// 💾 Salvar
|
|
176
|
+
𝓜.set('user_theme', 'dark');
|
|
177
|
+
|
|
178
|
+
// 📖 Ler
|
|
179
|
+
const theme = 𝓜.get('user_theme');
|
|
180
|
+
|
|
181
|
+
// 🗑️ Remover
|
|
182
|
+
𝓜.remove('user_theme');
|
|
183
|
+
|
|
184
|
+
// 🧹 Limpar tudo
|
|
185
|
+
𝓜.clear();
|
|
186
|
+
|
|
187
|
+
// 🔐 Session Storage
|
|
188
|
+
𝓜.session.set('temp', 'data');
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
---
|
|
192
|
+
|
|
193
|
+
### 7️⃣ HTTP Fetch
|
|
194
|
+
|
|
195
|
+
```typescript
|
|
196
|
+
import { ⇄ } from 'eny-ai';
|
|
197
|
+
|
|
198
|
+
// GET
|
|
199
|
+
const data = await ⇄.GET('/api/users');
|
|
200
|
+
|
|
201
|
+
// POST
|
|
202
|
+
const created = await ⇄.POST('/api/users', {
|
|
203
|
+
name: 'João',
|
|
204
|
+
email: 'joao@email.com'
|
|
205
|
+
});
|
|
206
|
+
|
|
207
|
+
// PUT
|
|
208
|
+
await ⇄.PUT('/api/users/123', { name: 'João Silva' });
|
|
209
|
+
|
|
210
|
+
// DELETE
|
|
211
|
+
await ⇄.DELETE('/api/users/123');
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
---
|
|
215
|
+
|
|
216
|
+
### 8️⃣ Validação
|
|
217
|
+
|
|
218
|
+
```typescript
|
|
219
|
+
import { 🛡 } from 'eny-ai';
|
|
220
|
+
|
|
221
|
+
// Email
|
|
222
|
+
try {
|
|
223
|
+
🛡.email('invalid-email');
|
|
224
|
+
} catch {
|
|
225
|
+
console.log('❌ Email inválido');
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
// Minimo
|
|
229
|
+
🛡.min(8)('password'); // ✅ ou ❌
|
|
230
|
+
|
|
231
|
+
// Máximo
|
|
232
|
+
🛡.max(50)('name');
|
|
233
|
+
|
|
234
|
+
// Required
|
|
235
|
+
🛡.required(value);
|
|
236
|
+
|
|
237
|
+
// Pattern (regex)
|
|
238
|
+
🛡.pattern(/^[A-Z]/)(value);
|
|
239
|
+
|
|
240
|
+
// Equals (confirmação)
|
|
241
|
+
🛡.equals('password')('confirm_password');
|
|
242
|
+
```
|
|
243
|
+
|
|
244
|
+
---
|
|
245
|
+
|
|
246
|
+
## 🎯 Exemplo Completo - TODO App
|
|
247
|
+
|
|
248
|
+
```typescript
|
|
249
|
+
import React from 'react';
|
|
250
|
+
import { Σ, ⚡, ☐, 𝓜, 📜, λ⁺ } from 'eny-ai';
|
|
251
|
+
|
|
252
|
+
export function TodoApp() {
|
|
253
|
+
// Estado
|
|
254
|
+
const [todos, setTodos] = Σ([]);
|
|
255
|
+
const [input, setInput] = Σ('');
|
|
256
|
+
|
|
257
|
+
// Carregar ao montar
|
|
258
|
+
⚡(() => {
|
|
259
|
+
const saved = 𝓜.get('todos');
|
|
260
|
+
if (saved) setTodos(JSON.parse(saved));
|
|
261
|
+
}, []);
|
|
262
|
+
|
|
263
|
+
// Adicionar
|
|
264
|
+
const addTodo = () => {
|
|
265
|
+
const newTodo = { id: Date.now(), text: input, done: false };
|
|
266
|
+
const updated = [...todos, newTodo];
|
|
267
|
+
setTodos(updated);
|
|
268
|
+
𝓜.set('todos', JSON.stringify(updated));
|
|
269
|
+
setInput('');
|
|
270
|
+
📜.info('✅ TODO adicionado');
|
|
271
|
+
};
|
|
272
|
+
|
|
273
|
+
// Deletar
|
|
274
|
+
const deleteTodo = (id) => {
|
|
275
|
+
const updated = todos.filter(t => t.id !== id);
|
|
276
|
+
setTodos(updated);
|
|
277
|
+
𝓜.set('todos', JSON.stringify(updated));
|
|
278
|
+
};
|
|
279
|
+
|
|
280
|
+
// Stats (memoizado)
|
|
281
|
+
const stats = λ⁺(() => ({
|
|
282
|
+
total: todos.length,
|
|
283
|
+
done: todos.filter(t => t.done).length
|
|
284
|
+
}), [todos]);
|
|
285
|
+
|
|
286
|
+
return (
|
|
287
|
+
☐.card({
|
|
288
|
+
children: (
|
|
289
|
+
<>
|
|
290
|
+
<☐.h1>📋 Meus TODOs</☐.h1>
|
|
291
|
+
|
|
292
|
+
<div className='flex gap-2'>
|
|
293
|
+
<☐.input({
|
|
294
|
+
value: input,
|
|
295
|
+
onChange: (e) => setInput(e.target.value),
|
|
296
|
+
placeholder: 'Novo TODO...'
|
|
297
|
+
})}
|
|
298
|
+
<☐.btn({
|
|
299
|
+
onClick: addTodo,
|
|
300
|
+
children: 'Adicionar ➕'
|
|
301
|
+
})}
|
|
302
|
+
</div>
|
|
303
|
+
|
|
304
|
+
<div className='mt-4 space-y-2'>
|
|
305
|
+
{todos.map(todo => (
|
|
306
|
+
<☐.card({
|
|
307
|
+
key: todo.id,
|
|
308
|
+
className: 'flex justify-between items-center p-2',
|
|
309
|
+
children: (
|
|
310
|
+
<>
|
|
311
|
+
<span>{todo.text}</span>
|
|
312
|
+
<☐.btn({
|
|
313
|
+
onClick: () => deleteTodo(todo.id),
|
|
314
|
+
type: 'danger',
|
|
315
|
+
children: '🗑️'
|
|
316
|
+
})}
|
|
317
|
+
</>
|
|
318
|
+
)
|
|
319
|
+
})}
|
|
320
|
+
))}
|
|
321
|
+
</div>
|
|
322
|
+
|
|
323
|
+
<☐.text>
|
|
324
|
+
Total: {stats.total} | Concluído: {stats.done}
|
|
325
|
+
</☐.text>
|
|
326
|
+
</>
|
|
327
|
+
)
|
|
328
|
+
})
|
|
329
|
+
);
|
|
330
|
+
}
|
|
331
|
+
```
|
|
332
|
+
|
|
333
|
+
---
|
|
334
|
+
|
|
335
|
+
## 🧪 Testing
|
|
336
|
+
|
|
337
|
+
```bash
|
|
338
|
+
npm test
|
|
339
|
+
```
|
|
340
|
+
|
|
341
|
+
Testes incluem:
|
|
342
|
+
- ✅ Runtime interpreter
|
|
343
|
+
- ✅ React hooks simbólicos
|
|
344
|
+
- ✅ Componentes UI
|
|
345
|
+
- ✅ Firebase integration
|
|
346
|
+
- ✅ Validação
|
|
347
|
+
- ✅ Armazenamento
|
|
348
|
+
|
|
349
|
+
---
|
|
350
|
+
|
|
351
|
+
## 📚 Tabela de Símbolos
|
|
352
|
+
|
|
353
|
+
| Símbolo | Função | Exemplo |
|
|
354
|
+
|---------|--------|---------|
|
|
355
|
+
| **Σ** | Estado (useState) | `const [x, setX] = Σ(0)` |
|
|
356
|
+
| **⚡** | Efeitos (useEffect) | `⚡(() => {}, [])` |
|
|
357
|
+
| **λ** | Função | `λ(x => x * 2)` |
|
|
358
|
+
| **λ⁺** | Memoização (useMemo) | `λ⁺(() => value, [])` |
|
|
359
|
+
| **λ⇄** | Callback memoizado | `λ⇄(() => {}, [])` |
|
|
360
|
+
| **⇄** | HTTP fetch | `await ⇄.GET('/api')` |
|
|
361
|
+
| **𝓜** | Storage (localStorage) | `𝓜.set('key', 'value')` |
|
|
362
|
+
| **☐** | Componentes UI | `☐.btn({...})` |
|
|
363
|
+
| **🧭** | Navegação | `🧭.navigate('/page')` |
|
|
364
|
+
| **📜** | Logging | `📜.info('msg')` |
|
|
365
|
+
| **🛡** | Validação | `🛡.email('email@test')` |
|
|
366
|
+
| **🔑** | Firebase Login | `await firebase.🔑(email, pwd)` |
|
|
367
|
+
| **🚪** | Firebase Logout | `await firebase.🚪()` |
|
|
368
|
+
| **👤** | Usuário autenticado | `const user = firebase.👤` |
|
|
369
|
+
| **📊** | Firebase Escrever | `await firebase.📊(path, data)` |
|
|
370
|
+
| **🔍** | Firebase Ler | `const data = await firebase.🔍(path)` |
|
|
371
|
+
| **📡** | Firebase Real-time | `firebase.📡(path, callback)` |
|
|
372
|
+
| **✏️** | Firebase Atualizar | `await firebase.✏️(path, data)` |
|
|
373
|
+
| **🗑️** | Firebase Deletar | `await firebase.🗑️(path)` |
|
|
374
|
+
|
|
375
|
+
---
|
|
376
|
+
|
|
377
|
+
## 🚀 Deploy
|
|
378
|
+
|
|
379
|
+
### Vercel
|
|
380
|
+
```bash
|
|
381
|
+
npm run build
|
|
382
|
+
vercel
|
|
383
|
+
```
|
|
384
|
+
|
|
385
|
+
### AWS Amplify
|
|
386
|
+
```bash
|
|
387
|
+
amplify init
|
|
388
|
+
amplify publish
|
|
389
|
+
```
|
|
390
|
+
|
|
391
|
+
### Firebase Hosting
|
|
392
|
+
```bash
|
|
393
|
+
firebase deploy
|
|
394
|
+
```
|
|
395
|
+
|
|
396
|
+
---
|
|
397
|
+
|
|
398
|
+
## 🔗 Links
|
|
399
|
+
|
|
400
|
+
- 📖 [Documentação Completa](./docs/grammar.ebnf)
|
|
401
|
+
- 💻 [Exemplos](./examples/)
|
|
402
|
+
- 🧪 [Testes](./tests/)
|
|
403
|
+
- 📦 [NPM Package](https://npmjs.com/package/eny-ai)
|
|
404
|
+
|
|
405
|
+
---
|
|
406
|
+
|
|
407
|
+
## 📝 Licença
|
|
408
|
+
|
|
409
|
+
MIT - Use livremente! ✨
|
|
410
|
+
|
|
411
|
+
---
|
|
412
|
+
|
|
413
|
+
**ENY-AI v2.0** - Onde código 90% simbólico encontra poder do React + Firebase 🚀
|
|
414
|
+
|
|
@@ -0,0 +1,195 @@
|
|
|
1
|
+
import {
|
|
2
|
+
init_esm_shims
|
|
3
|
+
} from "./chunk-MXA7TAAG.js";
|
|
4
|
+
|
|
5
|
+
// src/react/hooks.tsx
|
|
6
|
+
init_esm_shims();
|
|
7
|
+
import React, { useState, useEffect, useCallback, useContext, useMemo, useReducer } from "react";
|
|
8
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
9
|
+
function useEnyState(initialValue) {
|
|
10
|
+
const [value, setValue] = useState(initialValue);
|
|
11
|
+
return [value, setValue];
|
|
12
|
+
}
|
|
13
|
+
function useEnyEffect(effect, deps) {
|
|
14
|
+
useEffect(effect, deps);
|
|
15
|
+
}
|
|
16
|
+
function useEnyFetch(url) {
|
|
17
|
+
const [data, setData] = useState(null);
|
|
18
|
+
const [loading, setLoading] = useState(true);
|
|
19
|
+
const [error, setError] = useState(null);
|
|
20
|
+
useEffect(() => {
|
|
21
|
+
fetch(url).then((res) => res.json()).then((data2) => {
|
|
22
|
+
setData(data2);
|
|
23
|
+
setLoading(false);
|
|
24
|
+
}).catch((err) => {
|
|
25
|
+
setError(err);
|
|
26
|
+
setLoading(false);
|
|
27
|
+
});
|
|
28
|
+
}, [url]);
|
|
29
|
+
return [data, loading, error];
|
|
30
|
+
}
|
|
31
|
+
function usePersistentState(key, initialValue) {
|
|
32
|
+
const [value, setValue] = useState(() => {
|
|
33
|
+
const stored = localStorage.getItem(key);
|
|
34
|
+
return stored ? JSON.parse(stored) : initialValue;
|
|
35
|
+
});
|
|
36
|
+
const setPersistentValue = useCallback((newValue) => {
|
|
37
|
+
setValue(newValue);
|
|
38
|
+
localStorage.setItem(key, JSON.stringify(newValue));
|
|
39
|
+
}, [key]);
|
|
40
|
+
return [value, setPersistentValue];
|
|
41
|
+
}
|
|
42
|
+
function useMemoWithDeps(fn, deps) {
|
|
43
|
+
return useMemo(fn, deps);
|
|
44
|
+
}
|
|
45
|
+
function useCallbackWithDeps(fn, deps) {
|
|
46
|
+
return useCallback(fn, deps);
|
|
47
|
+
}
|
|
48
|
+
function useReducerWithState(reducer, initialState) {
|
|
49
|
+
return useReducer(reducer, initialState);
|
|
50
|
+
}
|
|
51
|
+
function useNavigation() {
|
|
52
|
+
return {
|
|
53
|
+
navigate: (path) => window.location.href = path,
|
|
54
|
+
back: () => window.history.back(),
|
|
55
|
+
forward: () => window.history.forward(),
|
|
56
|
+
reload: () => window.location.reload()
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
function useLogger() {
|
|
60
|
+
return {
|
|
61
|
+
info: (msg, data) => console.log(`\u2139\uFE0F ${msg}`, data),
|
|
62
|
+
error: (msg, data) => console.error(`\u274C ${msg}`, data),
|
|
63
|
+
warn: (msg, data) => console.warn(`\u26A0\uFE0F ${msg}`, data)
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
var EnyUI = {
|
|
67
|
+
/**
|
|
68
|
+
* EnyUI.card - Card component
|
|
69
|
+
*/
|
|
70
|
+
card: ({ children, className = "" }) => /* @__PURE__ */ jsx("div", { className: `bg-white rounded-lg shadow-lg p-6 ${className}`, children }),
|
|
71
|
+
/**
|
|
72
|
+
* EnyUI.btn - Button component
|
|
73
|
+
*/
|
|
74
|
+
btn: ({
|
|
75
|
+
children,
|
|
76
|
+
onClick,
|
|
77
|
+
type = "primary",
|
|
78
|
+
className = ""
|
|
79
|
+
}) => {
|
|
80
|
+
const baseClass = "px-4 py-2 rounded-lg font-bold transition";
|
|
81
|
+
const typeClass = {
|
|
82
|
+
primary: "bg-blue-600 text-white hover:bg-blue-700",
|
|
83
|
+
danger: "bg-red-600 text-white hover:bg-red-700",
|
|
84
|
+
secondary: "bg-gray-300 text-black hover:bg-gray-400"
|
|
85
|
+
}[type];
|
|
86
|
+
return /* @__PURE__ */ jsx("button", { className: `${baseClass} ${typeClass} ${className}`, onClick, children });
|
|
87
|
+
},
|
|
88
|
+
/**
|
|
89
|
+
* EnyUI.input - Input component
|
|
90
|
+
*/
|
|
91
|
+
input: ({
|
|
92
|
+
value,
|
|
93
|
+
onChange,
|
|
94
|
+
placeholder = "",
|
|
95
|
+
type = "text",
|
|
96
|
+
className = ""
|
|
97
|
+
}) => /* @__PURE__ */ jsx(
|
|
98
|
+
"input",
|
|
99
|
+
{
|
|
100
|
+
type,
|
|
101
|
+
value,
|
|
102
|
+
onChange: (e) => onChange(e.target.value),
|
|
103
|
+
placeholder,
|
|
104
|
+
className: `w-full px-4 py-2 border rounded-lg focus:outline-none focus:border-blue-600 ${className}`
|
|
105
|
+
}
|
|
106
|
+
),
|
|
107
|
+
/**
|
|
108
|
+
* EnyUI.grid - Grid component
|
|
109
|
+
*/
|
|
110
|
+
grid: ({ children, cols = 1, className = "" }) => /* @__PURE__ */ jsx("div", { className: `grid grid-cols-${cols} gap-4 ${className}`, children }),
|
|
111
|
+
/**
|
|
112
|
+
* EnyUI.flex - Flexbox component
|
|
113
|
+
*/
|
|
114
|
+
flex: ({ children, className = "" }) => /* @__PURE__ */ jsx("div", { className: `flex ${className}`, children }),
|
|
115
|
+
/**
|
|
116
|
+
* EnyUI.text - Text component
|
|
117
|
+
*/
|
|
118
|
+
text: ({ children, size = "base", className = "" }) => /* @__PURE__ */ jsx("p", { className: `text-${size} ${className}`, children }),
|
|
119
|
+
/**
|
|
120
|
+
* EnyUI.heading - Heading component
|
|
121
|
+
*/
|
|
122
|
+
h1: ({ children, className = "" }) => /* @__PURE__ */ jsx("h1", { className: `text-4xl font-bold ${className}`, children }),
|
|
123
|
+
h2: ({ children, className = "" }) => /* @__PURE__ */ jsx("h2", { className: `text-3xl font-bold ${className}`, children }),
|
|
124
|
+
h3: ({ children, className = "" }) => /* @__PURE__ */ jsx("h3", { className: `text-2xl font-bold ${className}`, children }),
|
|
125
|
+
/**
|
|
126
|
+
* EnyUI.modal - Modal component
|
|
127
|
+
*/
|
|
128
|
+
modal: ({
|
|
129
|
+
isOpen,
|
|
130
|
+
onClose,
|
|
131
|
+
children,
|
|
132
|
+
title = ""
|
|
133
|
+
}) => {
|
|
134
|
+
if (!isOpen) return null;
|
|
135
|
+
return /* @__PURE__ */ jsx("div", { className: "fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50", children: /* @__PURE__ */ jsxs("div", { className: "bg-white rounded-lg p-8 max-w-md w-full", children: [
|
|
136
|
+
title && /* @__PURE__ */ jsx("h2", { className: "text-2xl font-bold mb-4", children: title }),
|
|
137
|
+
children,
|
|
138
|
+
/* @__PURE__ */ jsx(
|
|
139
|
+
"button",
|
|
140
|
+
{
|
|
141
|
+
onClick: onClose,
|
|
142
|
+
className: "mt-4 w-full bg-gray-300 text-black py-2 rounded-lg hover:bg-gray-400",
|
|
143
|
+
children: "Fechar"
|
|
144
|
+
}
|
|
145
|
+
)
|
|
146
|
+
] }) });
|
|
147
|
+
},
|
|
148
|
+
/**
|
|
149
|
+
* EnyUI.spinner - Loading spinner
|
|
150
|
+
*/
|
|
151
|
+
spinner: ({ className = "" } = {}) => /* @__PURE__ */ jsx("div", { className: `animate-spin inline-block w-6 h-6 border-4 border-blue-600 border-t-transparent rounded-full ${className}` }),
|
|
152
|
+
/**
|
|
153
|
+
* EnyUI.badge - Badge component
|
|
154
|
+
*/
|
|
155
|
+
badge: ({ children, color = "blue", className = "" }) => /* @__PURE__ */ jsx("span", { className: `px-3 py-1 rounded-full text-white bg-${color}-600 ${className}`, children })
|
|
156
|
+
};
|
|
157
|
+
var EnyContext = {
|
|
158
|
+
create: (initialValue) => React.createContext(initialValue),
|
|
159
|
+
use: (context) => useContext(context)
|
|
160
|
+
};
|
|
161
|
+
var EnyValidate = {
|
|
162
|
+
email: (str) => /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(str),
|
|
163
|
+
min: (len) => (str) => str.length >= len,
|
|
164
|
+
max: (len) => (str) => str.length <= len,
|
|
165
|
+
required: (val) => val != null && val !== "",
|
|
166
|
+
pattern: (regex) => (val) => regex.test(val),
|
|
167
|
+
equals: (expected) => (val) => val === expected
|
|
168
|
+
};
|
|
169
|
+
function useValidation(schema) {
|
|
170
|
+
return (data) => {
|
|
171
|
+
const errors = {};
|
|
172
|
+
for (const [key, validator] of Object.entries(schema)) {
|
|
173
|
+
if (!validator(data[key])) {
|
|
174
|
+
errors[key] = true;
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
return errors;
|
|
178
|
+
};
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
export {
|
|
182
|
+
useEnyState,
|
|
183
|
+
useEnyEffect,
|
|
184
|
+
useEnyFetch,
|
|
185
|
+
usePersistentState,
|
|
186
|
+
useMemoWithDeps,
|
|
187
|
+
useCallbackWithDeps,
|
|
188
|
+
useReducerWithState,
|
|
189
|
+
useNavigation,
|
|
190
|
+
useLogger,
|
|
191
|
+
EnyUI,
|
|
192
|
+
EnyContext,
|
|
193
|
+
EnyValidate,
|
|
194
|
+
useValidation
|
|
195
|
+
};
|