@reflow-js/templates 0.1.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/README.md +23 -0
- package/mfe/application.json +17 -0
- package/mfe/jest.config.js +7 -0
- package/mfe/package.json +18 -0
- package/mfe/public/index.html +21 -0
- package/mfe/reflow.config.json +35 -0
- package/mfe/src/index.ts +18 -0
- package/mfe/src/style.css +13 -0
- package/mfe/src/welcome-component.test.ts +38 -0
- package/mfe/src/welcome-component.ts +52 -0
- package/mfe/tsconfig.json +16 -0
- package/mfe-angular/README.md +14 -0
- package/mfe-angular/public/index.html +21 -0
- package/mfe-angular/reflow.config.json +23 -0
- package/mfe-angular/src/app.component.html +3 -0
- package/mfe-angular/src/components/welcome.component.ts +283 -0
- package/mfe-angular/src/index.ts +44 -0
- package/mfe-angular/src/styles.css +25 -0
- package/mfe-angular/tsconfig.json +16 -0
- package/mfe-react/README.md +0 -0
- package/mfe-react/application.json +5 -0
- package/mfe-react/public/index.html +22 -0
- package/mfe-react/reflow.config.json +34 -0
- package/mfe-react/src/App.tsx +21 -0
- package/mfe-react/src/components/welcome/welcome.component.tsx +74 -0
- package/mfe-react/src/components/welcome/welcome.style.css +224 -0
- package/mfe-react/src/index.css +25 -0
- package/mfe-react/src/index.tsx +39 -0
- package/mfe-react/tsconfig.json +19 -0
- package/mfe-react-tailwind/README.md +0 -0
- package/mfe-react-tailwind/application.json +5 -0
- package/mfe-react-tailwind/postcss.config.js +6 -0
- package/mfe-react-tailwind/public/index.html +22 -0
- package/mfe-react-tailwind/reflow.config.json +34 -0
- package/mfe-react-tailwind/src/App.tsx +21 -0
- package/mfe-react-tailwind/src/components/welcome/welcome.component.tsx +74 -0
- package/mfe-react-tailwind/src/components/welcome/welcome.style.css +224 -0
- package/mfe-react-tailwind/src/index.css +29 -0
- package/mfe-react-tailwind/src/index.tsx +39 -0
- package/mfe-react-tailwind/tailwind.config.js +11 -0
- package/mfe-react-tailwind/tsconfig.json +19 -0
- package/mfe-vue/README.md +14 -0
- package/mfe-vue/public/application.json +7 -0
- package/mfe-vue/public/index.html +21 -0
- package/mfe-vue/reflow.config.json +23 -0
- package/mfe-vue/src/App.vue +16 -0
- package/mfe-vue/src/components/Welcome.vue +307 -0
- package/mfe-vue/src/index.css +5 -0
- package/mfe-vue/src/index.ts +16 -0
- package/mfe-vue/tsconfig.json +14 -0
- package/package.json +23 -0
|
@@ -0,0 +1,224 @@
|
|
|
1
|
+
/* welcome.style.css
|
|
2
|
+
* Estilos nativos del componente — encapsulados por Shadow DOM
|
|
3
|
+
* cuando se usa Reflow.define() con { shadow: true }
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
/* ── Brand tokens (React Blue) ── */
|
|
7
|
+
:host {
|
|
8
|
+
--rf-blue: #0EA5E9;
|
|
9
|
+
--rf-dark: #222A2D;
|
|
10
|
+
--rf-light: #E6E7E8;
|
|
11
|
+
--rf-surface: #2A3438;
|
|
12
|
+
--rf-border: rgba(14, 165, 233, 0.18);
|
|
13
|
+
--rf-muted: rgba(230, 231, 232, 0.45);
|
|
14
|
+
|
|
15
|
+
display: flex;
|
|
16
|
+
justify-content: center;
|
|
17
|
+
align-items: center;
|
|
18
|
+
width: 100%;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/* ── Card shell ── */
|
|
22
|
+
.rf-card {
|
|
23
|
+
position: relative;
|
|
24
|
+
width: 100%;
|
|
25
|
+
max-width: 440px;
|
|
26
|
+
border-radius: 1.25rem;
|
|
27
|
+
background: var(--rf-surface);
|
|
28
|
+
border: 1px solid var(--rf-border);
|
|
29
|
+
box-shadow:
|
|
30
|
+
0 0 0 1px rgba(14,165,233,0.06),
|
|
31
|
+
0 24px 64px rgba(0,0,0,0.55),
|
|
32
|
+
0 4px 16px rgba(0,0,0,0.35);
|
|
33
|
+
overflow: hidden;
|
|
34
|
+
font-family: -apple-system, BlinkMacSystemFont, 'Inter', 'Segoe UI', system-ui, sans-serif;
|
|
35
|
+
transition: transform 0.25s ease, box-shadow 0.25s ease;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
.rf-card:hover {
|
|
39
|
+
transform: translateY(-3px);
|
|
40
|
+
box-shadow:
|
|
41
|
+
0 0 0 1px rgba(14,165,233,0.14),
|
|
42
|
+
0 32px 80px rgba(0,0,0,0.6),
|
|
43
|
+
0 8px 24px rgba(14,165,233,0.12);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/* ambient blue glow */
|
|
47
|
+
.rf-glow {
|
|
48
|
+
position: absolute;
|
|
49
|
+
top: -60px; left: 50%;
|
|
50
|
+
transform: translateX(-50%);
|
|
51
|
+
width: 260px; height: 120px;
|
|
52
|
+
background: radial-gradient(ellipse, rgba(14,165,233,0.18) 0%, transparent 70%);
|
|
53
|
+
pointer-events: none;
|
|
54
|
+
z-index: 0;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/* top accent line */
|
|
58
|
+
.rf-card__top-bar {
|
|
59
|
+
height: 3px;
|
|
60
|
+
background: linear-gradient(90deg, transparent 0%, var(--rf-blue) 40%, #06B6D4 60%, transparent 100%);
|
|
61
|
+
position: relative;
|
|
62
|
+
z-index: 1;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
.rf-card__inner {
|
|
66
|
+
position: relative;
|
|
67
|
+
z-index: 1;
|
|
68
|
+
padding: 2rem 2rem 1.75rem;
|
|
69
|
+
display: flex;
|
|
70
|
+
flex-direction: column;
|
|
71
|
+
gap: 0;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/* ── Header row ── */
|
|
75
|
+
.rf-card__header {
|
|
76
|
+
display: flex;
|
|
77
|
+
align-items: center;
|
|
78
|
+
gap: 0.75rem;
|
|
79
|
+
margin-bottom: 1.5rem;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
.rf-icon-wrap {
|
|
83
|
+
width: 42px; height: 42px;
|
|
84
|
+
border-radius: 0.75rem;
|
|
85
|
+
display: flex;
|
|
86
|
+
align-items: center;
|
|
87
|
+
justify-content: center;
|
|
88
|
+
flex-shrink: 0;
|
|
89
|
+
font-size: 1.75rem;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
.rf-badge {
|
|
93
|
+
font-size: 0.7rem;
|
|
94
|
+
font-weight: 700;
|
|
95
|
+
letter-spacing: 0.08em;
|
|
96
|
+
text-transform: uppercase;
|
|
97
|
+
color: var(--rf-blue);
|
|
98
|
+
background: rgba(14,165,233,0.10);
|
|
99
|
+
border: 1px solid rgba(14,165,233,0.20);
|
|
100
|
+
padding: 0.22rem 0.7rem;
|
|
101
|
+
border-radius: 999px;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
/* ── Typography ── */
|
|
105
|
+
.rf-card__title {
|
|
106
|
+
margin: 0 0 0.6rem;
|
|
107
|
+
font-size: 1.5rem;
|
|
108
|
+
font-weight: 800;
|
|
109
|
+
color: var(--rf-light);
|
|
110
|
+
letter-spacing: -0.03em;
|
|
111
|
+
line-height: 1.2;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
.rf-card__desc {
|
|
115
|
+
margin: 0;
|
|
116
|
+
font-size: 0.875rem;
|
|
117
|
+
color: var(--rf-muted);
|
|
118
|
+
line-height: 1.7;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
/* ── Divider ── */
|
|
122
|
+
.rf-divider {
|
|
123
|
+
height: 1px;
|
|
124
|
+
background: linear-gradient(90deg, transparent, rgba(230,231,232,0.10), transparent);
|
|
125
|
+
margin: 1.5rem 0;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
/* ── Greeting ── */
|
|
129
|
+
.rf-greeting {
|
|
130
|
+
display: flex;
|
|
131
|
+
align-items: center;
|
|
132
|
+
gap: 0.75rem;
|
|
133
|
+
margin-bottom: 1.75rem;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
.rf-avatar {
|
|
137
|
+
width: 36px; height: 36px;
|
|
138
|
+
border-radius: 50%;
|
|
139
|
+
background: linear-gradient(135deg, var(--rf-blue), #06B6D4);
|
|
140
|
+
color: #fff;
|
|
141
|
+
font-size: 0.875rem;
|
|
142
|
+
font-weight: 800;
|
|
143
|
+
display: flex;
|
|
144
|
+
align-items: center;
|
|
145
|
+
justify-content: center;
|
|
146
|
+
flex-shrink: 0;
|
|
147
|
+
box-shadow: 0 2px 8px rgba(14,165,233,0.40);
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
.rf-greeting__text { font-size: 0.9rem; color: var(--rf-muted); }
|
|
151
|
+
.rf-greeting__name { color: var(--rf-light); font-weight: 700; }
|
|
152
|
+
|
|
153
|
+
/* ── Buttons ── */
|
|
154
|
+
.rf-actions {
|
|
155
|
+
display: flex;
|
|
156
|
+
gap: 0.75rem;
|
|
157
|
+
margin-bottom: 1.75rem;
|
|
158
|
+
flex-wrap: wrap;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
.rf-btn {
|
|
162
|
+
display: inline-flex;
|
|
163
|
+
align-items: center;
|
|
164
|
+
gap: 0.45rem;
|
|
165
|
+
padding: 0.6rem 1.25rem;
|
|
166
|
+
border-radius: 0.65rem;
|
|
167
|
+
font-size: 0.85rem;
|
|
168
|
+
font-weight: 600;
|
|
169
|
+
cursor: pointer;
|
|
170
|
+
border: none;
|
|
171
|
+
transition: transform 0.18s ease, box-shadow 0.18s ease, background 0.18s ease;
|
|
172
|
+
letter-spacing: 0.01em;
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
.rf-btn__ico { width: 14px; height: 14px; flex-shrink: 0; }
|
|
176
|
+
|
|
177
|
+
.rf-btn--primary {
|
|
178
|
+
background: var(--rf-blue);
|
|
179
|
+
color: #fff;
|
|
180
|
+
box-shadow: 0 4px 16px rgba(14,165,233,0.40);
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
.rf-btn--primary:hover {
|
|
184
|
+
background: #0284C7;
|
|
185
|
+
transform: translateY(-2px);
|
|
186
|
+
box-shadow: 0 8px 24px rgba(14,165,233,0.50);
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
.rf-btn--primary:active { transform: translateY(0); }
|
|
190
|
+
|
|
191
|
+
.rf-btn--ghost {
|
|
192
|
+
background: rgba(230,231,232,0.06);
|
|
193
|
+
color: var(--rf-light);
|
|
194
|
+
border: 1px solid rgba(230,231,232,0.14);
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
.rf-btn--ghost:hover {
|
|
198
|
+
background: rgba(230,231,232,0.10);
|
|
199
|
+
border-color: rgba(230,231,232,0.24);
|
|
200
|
+
transform: translateY(-2px);
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
.rf-btn--ghost:active { transform: translateY(0); }
|
|
204
|
+
|
|
205
|
+
/* ── Chips ── */
|
|
206
|
+
.rf-chips {
|
|
207
|
+
display: flex;
|
|
208
|
+
gap: 0.5rem;
|
|
209
|
+
flex-wrap: wrap;
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
.rf-chip {
|
|
213
|
+
display: inline-block;
|
|
214
|
+
padding: 0.18rem 0.6rem;
|
|
215
|
+
border-radius: 999px;
|
|
216
|
+
font-size: 0.68rem;
|
|
217
|
+
font-weight: 600;
|
|
218
|
+
letter-spacing: 0.05em;
|
|
219
|
+
text-transform: uppercase;
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
.rf-chip--blue { background: rgba(14,165,233,0.12); color: var(--rf-blue); border: 1px solid rgba(14,165,233,0.25); }
|
|
223
|
+
.rf-chip--muted { background: rgba(230,231,232,0.07); color: var(--rf-muted); border: 1px solid rgba(230,231,232,0.12); }
|
|
224
|
+
.rf-chip--outline { background: transparent; color: rgba(230,231,232,0.35); border: 1px solid rgba(230,231,232,0.12); }
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
@tailwind base;
|
|
2
|
+
@tailwind components;
|
|
3
|
+
@tailwind utilities;
|
|
4
|
+
|
|
5
|
+
/* ── React brand: #222A2D / #0EA5E9 / #E6E7E8 ── */
|
|
6
|
+
*, *::before, *::after { box-sizing: border-box; }
|
|
7
|
+
|
|
8
|
+
html, body {
|
|
9
|
+
height: 100%;
|
|
10
|
+
margin: 0;
|
|
11
|
+
padding: 0;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
body {
|
|
15
|
+
min-height: 100vh;
|
|
16
|
+
display: flex;
|
|
17
|
+
align-items: center;
|
|
18
|
+
justify-content: center;
|
|
19
|
+
padding: 2rem 1rem;
|
|
20
|
+
font-family: -apple-system, BlinkMacSystemFont, 'Inter', 'Segoe UI', system-ui, sans-serif;
|
|
21
|
+
color: #E6E7E8;
|
|
22
|
+
/* Dark background with blue ambient glow */
|
|
23
|
+
background-color: #222A2D;
|
|
24
|
+
background-image:
|
|
25
|
+
radial-gradient(ellipse 600px 400px at 15% 60%, rgba(14,165,233,0.08) 0%, transparent 70%),
|
|
26
|
+
radial-gradient(ellipse 500px 300px at 85% 25%, rgba(6,182,212,0.06) 0%, transparent 65%),
|
|
27
|
+
radial-gradient(ellipse 800px 600px at 50% 100%, rgba(34,42,45,0.8) 0%, transparent 80%);
|
|
28
|
+
background-attachment: fixed;
|
|
29
|
+
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import * as ReactDOM from 'react-dom/client';
|
|
3
|
+
// @ts-ignore
|
|
4
|
+
import { Reflow } from '@reflow-js/core';
|
|
5
|
+
// @ts-ignore
|
|
6
|
+
import { Welcome } from './components/welcome/welcome.component';
|
|
7
|
+
import './index.css';
|
|
8
|
+
|
|
9
|
+
declare global {
|
|
10
|
+
namespace JSX {
|
|
11
|
+
interface IntrinsicElements {
|
|
12
|
+
'welcome-card': any; // Usamos el tag definido en el registry del MFE
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
// Inicializa Reflow inyectando las dependencias de React
|
|
18
|
+
// Esto evita múltiples instancias de React entre host y MFEs
|
|
19
|
+
Reflow.init({
|
|
20
|
+
propertiesFile: 'application.json',
|
|
21
|
+
react: React,
|
|
22
|
+
reactDom: ReactDOM,
|
|
23
|
+
}).then(() => {
|
|
24
|
+
console.log('[Reflow] ✅ Inicializado correctamente');
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Reflow.define() convierte un componente React en un Custom Element.
|
|
28
|
+
*
|
|
29
|
+
* Firma: Reflow.define(tagName, Component, defaultProps, options)
|
|
30
|
+
*
|
|
31
|
+
* options.shadow: true → Shadow DOM activo → estilos encapsulados
|
|
32
|
+
* Las props se pueden pasar como atributos HTML: <welcome-card title="Hola">
|
|
33
|
+
*/
|
|
34
|
+
Reflow.define('welcome-card', Welcome, { name: 'User' }, { shadow: true });
|
|
35
|
+
|
|
36
|
+
console.log('[Reflow] 🧩 welcome-card registrado como Web Component');
|
|
37
|
+
}).catch((e: any) => {
|
|
38
|
+
console.error('[Reflow] ❌ Error en inicialización', e);
|
|
39
|
+
});
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"target": "ESNext",
|
|
4
|
+
"lib": ["DOM", "DOM.Iterable", "ESNext"],
|
|
5
|
+
"allowJs": true,
|
|
6
|
+
"skipLibCheck": true,
|
|
7
|
+
"esModuleInterop": true,
|
|
8
|
+
"allowSyntheticDefaultImports": true,
|
|
9
|
+
"strict": true,
|
|
10
|
+
"forceConsistentCasingInFileNames": true,
|
|
11
|
+
"module": "ESNext",
|
|
12
|
+
"moduleResolution": "Node",
|
|
13
|
+
"resolveJsonModule": true,
|
|
14
|
+
"isolatedModules": true,
|
|
15
|
+
"noEmit": true,
|
|
16
|
+
"jsx": "react-jsx"
|
|
17
|
+
},
|
|
18
|
+
"include": ["src"]
|
|
19
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
# Plantilla Vue MFE + Reflow-js
|
|
2
|
+
|
|
3
|
+
Esta plantilla muestra cómo consumir un Web Component generado por Reflow-js en una aplicación Vue.
|
|
4
|
+
|
|
5
|
+
## Uso básico
|
|
6
|
+
|
|
7
|
+
1. Asegúrate de que el bundle de tu microfrontend (MFE) de Reflow-js esté disponible y cargado en tu `index.html` (por ejemplo, vía `<script src="/dist/mi-mfe/registry/registry.js"></script>`).
|
|
8
|
+
2. Usa el Web Component directamente en tus templates Vue:
|
|
9
|
+
|
|
10
|
+
```html
|
|
11
|
+
<welcome-card title="¡Hola desde Vue!" description="Este componente es un Web Component generado por Reflow-js." />
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
No necesitas wrappers ni librerías adicionales. Los eventos y propiedades funcionan como atributos estándar de HTML.
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="es">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8" />
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
6
|
+
<title>Vue MFE + Reflow-js</title>
|
|
7
|
+
<!-- Ejemplo: cargar el script con src apuntando al registry.js generado -->
|
|
8
|
+
</head>
|
|
9
|
+
<body>
|
|
10
|
+
<!--
|
|
11
|
+
Reflow registra 'welcome-card' en src/index.ts:
|
|
12
|
+
Reflow.define('welcome-card', Welcome, defaultProps, { shadow: true, framework: 'vue' })
|
|
13
|
+
Las props se pasan como atributos HTML.
|
|
14
|
+
-->
|
|
15
|
+
<welcome-card
|
|
16
|
+
title="{{name}} corriendo"
|
|
17
|
+
description="Componente Vue encapsulado con Shadow DOM por Reflow-js."
|
|
18
|
+
name="Developer">
|
|
19
|
+
</welcome-card>
|
|
20
|
+
</body>
|
|
21
|
+
</html>
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "{{name}}",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"buildEngine": "webpack",
|
|
5
|
+
"bundler": {
|
|
6
|
+
"input": "src/index.ts",
|
|
7
|
+
"output": "dist",
|
|
8
|
+
"format": "umd",
|
|
9
|
+
"minify": false,
|
|
10
|
+
"sourcemap": true
|
|
11
|
+
},
|
|
12
|
+
"components": {
|
|
13
|
+
"srcDir": "src/components",
|
|
14
|
+
"outDir": "dist/components",
|
|
15
|
+
"prefix": "mfe",
|
|
16
|
+
"registry": "dist/registry/registry.js"
|
|
17
|
+
},
|
|
18
|
+
"dev": {
|
|
19
|
+
"port": 3003,
|
|
20
|
+
"hotReload": true,
|
|
21
|
+
"open": true
|
|
22
|
+
}
|
|
23
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div>
|
|
3
|
+
<h1>Vue MFE + Reflow-js</h1>
|
|
4
|
+
<welcome-card title="¡Hola desde Vue!" description="Este componente es un Web Component generado por Reflow-js." />
|
|
5
|
+
</div>
|
|
6
|
+
</template>
|
|
7
|
+
|
|
8
|
+
<script>
|
|
9
|
+
export default {
|
|
10
|
+
name: 'App',
|
|
11
|
+
mounted() {
|
|
12
|
+
// Asegúrate de que el bundle de tu MFE esté cargado antes de usar el componente
|
|
13
|
+
// Ejemplo: usando tag script con src="/dist/mi-mfe/registry/registry.js"
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
</script>
|