wu-framework 1.2.0 → 2.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.
Files changed (154) hide show
  1. package/README.md +99 -18
  2. package/dist/adapters/alpine/index.js +2 -0
  3. package/dist/adapters/alpine/index.js.map +1 -0
  4. package/dist/adapters/angular/index.js +2 -0
  5. package/dist/adapters/angular/index.js.map +1 -0
  6. package/dist/adapters/htmx/index.js +2 -0
  7. package/dist/adapters/htmx/index.js.map +1 -0
  8. package/dist/adapters/index.js +2 -0
  9. package/dist/adapters/index.js.map +1 -0
  10. package/dist/adapters/lit/index.js +44 -0
  11. package/dist/adapters/lit/index.js.map +1 -0
  12. package/dist/adapters/preact/index.js +2 -0
  13. package/dist/adapters/preact/index.js.map +1 -0
  14. package/dist/adapters/qwik/index.js +2 -0
  15. package/dist/adapters/qwik/index.js.map +1 -0
  16. package/dist/adapters/react/index.js +2 -0
  17. package/dist/adapters/react/index.js.map +1 -0
  18. package/dist/adapters/shared.js +2 -0
  19. package/dist/adapters/shared.js.map +1 -0
  20. package/dist/adapters/solid/index.js +2 -0
  21. package/dist/adapters/solid/index.js.map +1 -0
  22. package/dist/adapters/stencil/index.js +2 -0
  23. package/dist/adapters/stencil/index.js.map +1 -0
  24. package/dist/adapters/stimulus/index.js +2 -0
  25. package/dist/adapters/stimulus/index.js.map +1 -0
  26. package/dist/adapters/svelte/index.js +2 -0
  27. package/dist/adapters/svelte/index.js.map +1 -0
  28. package/dist/adapters/vanilla/index.js +2 -0
  29. package/dist/adapters/vanilla/index.js.map +1 -0
  30. package/dist/adapters/vue/index.js +2 -0
  31. package/dist/adapters/vue/index.js.map +1 -0
  32. package/dist/ai/wu-ai.js +2 -0
  33. package/dist/ai/wu-ai.js.map +1 -0
  34. package/dist/core/wu-mcp-bridge.js +2 -0
  35. package/dist/core/wu-mcp-bridge.js.map +1 -0
  36. package/{src → dist}/index.d.ts +445 -317
  37. package/dist/wu-ai-browser-primitives-BDKXJlwc.js +2 -0
  38. package/dist/wu-ai-browser-primitives-BDKXJlwc.js.map +1 -0
  39. package/dist/wu-framework.cjs.js +3 -0
  40. package/dist/wu-framework.cjs.js.map +1 -0
  41. package/dist/wu-framework.dev.js +9175 -0
  42. package/dist/wu-framework.dev.js.map +1 -0
  43. package/dist/wu-framework.esm.js +3 -0
  44. package/dist/wu-framework.esm.js.map +1 -0
  45. package/dist/wu-framework.umd.js +3 -0
  46. package/dist/wu-framework.umd.js.map +1 -0
  47. package/dist/wu-html-parser.js +2 -0
  48. package/dist/wu-html-parser.js.map +1 -0
  49. package/dist/wu-iframe-sandbox.js +2 -0
  50. package/dist/wu-iframe-sandbox.js.map +1 -0
  51. package/dist/wu-logger-fJfUHBGA.js +2 -0
  52. package/dist/wu-logger-fJfUHBGA.js.map +1 -0
  53. package/dist/wu-script-executor.js +2 -0
  54. package/dist/wu-script-executor.js.map +1 -0
  55. package/package.json +43 -34
  56. package/src/adapters/alpine/index.js +0 -231
  57. package/src/adapters/alpine.js +0 -3
  58. package/src/adapters/angular/ai.js +0 -30
  59. package/src/adapters/angular/index.js +0 -932
  60. package/src/adapters/angular.js +0 -3
  61. package/src/adapters/htmx/index.js +0 -242
  62. package/src/adapters/htmx.js +0 -3
  63. package/src/adapters/index.js +0 -225
  64. package/src/adapters/lit/ai.js +0 -20
  65. package/src/adapters/lit/index.js +0 -721
  66. package/src/adapters/lit.js +0 -3
  67. package/src/adapters/preact/ai.js +0 -33
  68. package/src/adapters/preact/index.js +0 -661
  69. package/src/adapters/preact.js +0 -3
  70. package/src/adapters/qwik/index.js +0 -108
  71. package/src/adapters/qwik.js +0 -3
  72. package/src/adapters/react/ai.js +0 -135
  73. package/src/adapters/react/index.js +0 -695
  74. package/src/adapters/react.js +0 -3
  75. package/src/adapters/shared.js +0 -64
  76. package/src/adapters/solid/ai.js +0 -32
  77. package/src/adapters/solid/index.js +0 -586
  78. package/src/adapters/solid.js +0 -3
  79. package/src/adapters/stencil/index.js +0 -228
  80. package/src/adapters/stencil.js +0 -3
  81. package/src/adapters/stimulus/index.js +0 -255
  82. package/src/adapters/stimulus.js +0 -3
  83. package/src/adapters/svelte/ai.js +0 -31
  84. package/src/adapters/svelte/index.js +0 -798
  85. package/src/adapters/svelte.js +0 -3
  86. package/src/adapters/vanilla/ai.js +0 -30
  87. package/src/adapters/vanilla/index.js +0 -785
  88. package/src/adapters/vanilla.js +0 -3
  89. package/src/adapters/vue/ai.js +0 -52
  90. package/src/adapters/vue/index.js +0 -618
  91. package/src/adapters/vue.js +0 -3
  92. package/src/ai/wu-ai-actions.js +0 -261
  93. package/src/ai/wu-ai-agent.js +0 -546
  94. package/src/ai/wu-ai-browser-primitives.js +0 -354
  95. package/src/ai/wu-ai-browser.js +0 -380
  96. package/src/ai/wu-ai-context.js +0 -332
  97. package/src/ai/wu-ai-conversation.js +0 -613
  98. package/src/ai/wu-ai-orchestrate.js +0 -1021
  99. package/src/ai/wu-ai-permissions.js +0 -381
  100. package/src/ai/wu-ai-provider.js +0 -700
  101. package/src/ai/wu-ai-schema.js +0 -225
  102. package/src/ai/wu-ai-triggers.js +0 -396
  103. package/src/ai/wu-ai.js +0 -804
  104. package/src/core/wu-app.js +0 -236
  105. package/src/core/wu-cache.js +0 -498
  106. package/src/core/wu-core.js +0 -1412
  107. package/src/core/wu-error-boundary.js +0 -396
  108. package/src/core/wu-event-bus.js +0 -390
  109. package/src/core/wu-hooks.js +0 -350
  110. package/src/core/wu-html-parser.js +0 -199
  111. package/src/core/wu-iframe-sandbox.js +0 -328
  112. package/src/core/wu-loader.js +0 -385
  113. package/src/core/wu-logger.js +0 -143
  114. package/src/core/wu-manifest.js +0 -533
  115. package/src/core/wu-mcp-bridge.js +0 -432
  116. package/src/core/wu-overrides.js +0 -510
  117. package/src/core/wu-performance.js +0 -228
  118. package/src/core/wu-plugin.js +0 -401
  119. package/src/core/wu-prefetch.js +0 -414
  120. package/src/core/wu-proxy-sandbox.js +0 -477
  121. package/src/core/wu-sandbox.js +0 -779
  122. package/src/core/wu-script-executor.js +0 -161
  123. package/src/core/wu-snapshot-sandbox.js +0 -227
  124. package/src/core/wu-store.js +0 -307
  125. package/src/core/wu-strategies.js +0 -256
  126. package/src/core/wu-style-bridge.js +0 -477
  127. package/src/index.js +0 -234
  128. package/src/utils/dependency-resolver.js +0 -328
  129. /package/{src → dist}/adapters/alpine/index.d.ts +0 -0
  130. /package/{src → dist}/adapters/alpine.d.ts +0 -0
  131. /package/{src → dist}/adapters/angular/index.d.ts +0 -0
  132. /package/{src → dist}/adapters/angular.d.ts +0 -0
  133. /package/{src → dist}/adapters/htmx/index.d.ts +0 -0
  134. /package/{src → dist}/adapters/htmx.d.ts +0 -0
  135. /package/{src → dist}/adapters/lit/index.d.ts +0 -0
  136. /package/{src → dist}/adapters/lit.d.ts +0 -0
  137. /package/{src → dist}/adapters/preact/index.d.ts +0 -0
  138. /package/{src → dist}/adapters/preact.d.ts +0 -0
  139. /package/{src → dist}/adapters/qwik/index.d.ts +0 -0
  140. /package/{src → dist}/adapters/qwik.d.ts +0 -0
  141. /package/{src → dist}/adapters/react/index.d.ts +0 -0
  142. /package/{src → dist}/adapters/react.d.ts +0 -0
  143. /package/{src → dist}/adapters/solid/index.d.ts +0 -0
  144. /package/{src → dist}/adapters/solid.d.ts +0 -0
  145. /package/{src → dist}/adapters/stencil/index.d.ts +0 -0
  146. /package/{src → dist}/adapters/stencil.d.ts +0 -0
  147. /package/{src → dist}/adapters/stimulus/index.d.ts +0 -0
  148. /package/{src → dist}/adapters/stimulus.d.ts +0 -0
  149. /package/{src → dist}/adapters/svelte/index.d.ts +0 -0
  150. /package/{src → dist}/adapters/svelte.d.ts +0 -0
  151. /package/{src → dist}/adapters/vanilla/index.d.ts +0 -0
  152. /package/{src → dist}/adapters/vanilla.d.ts +0 -0
  153. /package/{src → dist}/adapters/vue/index.d.ts +0 -0
  154. /package/{src → dist}/adapters/vue.d.ts +0 -0
@@ -1,785 +0,0 @@
1
- /**
2
- * 🚀 WU-FRAMEWORK VANILLA JS ADAPTER
3
- *
4
- * El adapter más simple - Para JavaScript puro sin frameworks.
5
- * Ideal para microfrontends ligeros o legacy code.
6
- *
7
- * @example
8
- * // Microfrontend (main.js)
9
- * import { wuVanilla } from 'wu-framework/adapters/vanilla';
10
- *
11
- * wuVanilla.register('my-app', {
12
- * render: (container) => {
13
- * container.innerHTML = '<h1>Hello World</h1>';
14
- * }
15
- * });
16
- *
17
- * @example
18
- * // Con clase
19
- * class MyApp {
20
- * constructor(container) {
21
- * this.container = container;
22
- * }
23
- * render() {
24
- * this.container.innerHTML = '<h1>My App</h1>';
25
- * }
26
- * destroy() {
27
- * this.container.innerHTML = '';
28
- * }
29
- * }
30
- *
31
- * wuVanilla.registerClass('my-app', MyApp);
32
- */
33
-
34
- // Estado global del adapter
35
- const adapterState = {
36
- apps: new Map(),
37
- instances: new Map()
38
- };
39
-
40
- /**
41
- * Obtiene la instancia de Wu Framework
42
- */
43
- function getWuInstance() {
44
- if (typeof window === 'undefined') return null;
45
-
46
- return window.wu
47
- || window.parent?.wu
48
- || window.top?.wu
49
- || null;
50
- }
51
-
52
- /**
53
- * Espera a que Wu Framework esté disponible
54
- */
55
- function waitForWu(timeout = 5000) {
56
- return new Promise((resolve, reject) => {
57
- const wu = getWuInstance();
58
- if (wu) {
59
- resolve(wu);
60
- return;
61
- }
62
-
63
- const startTime = Date.now();
64
-
65
- const handleWuReady = () => {
66
- cleanup();
67
- resolve(getWuInstance());
68
- };
69
-
70
- window.addEventListener('wu:ready', handleWuReady);
71
- window.addEventListener('wu:app:ready', handleWuReady);
72
-
73
- const checkInterval = setInterval(() => {
74
- const wu = getWuInstance();
75
- if (wu) {
76
- cleanup();
77
- resolve(wu);
78
- return;
79
- }
80
-
81
- if (Date.now() - startTime > timeout) {
82
- cleanup();
83
- reject(new Error(`Wu Framework not found after ${timeout}ms`));
84
- }
85
- }, 200);
86
-
87
- function cleanup() {
88
- clearInterval(checkInterval);
89
- window.removeEventListener('wu:ready', handleWuReady);
90
- window.removeEventListener('wu:app:ready', handleWuReady);
91
- }
92
- });
93
- }
94
-
95
- /**
96
- * Registra una app Vanilla JS como microfrontend
97
- *
98
- * @param {string} appName - Nombre único del microfrontend
99
- * @param {Object} config - Configuración de la app
100
- * @param {Function} config.render - Función para renderizar (recibe container)
101
- * @param {Function} [config.destroy] - Función para limpiar (recibe container)
102
- * @param {Function} [config.init] - Función de inicialización (recibe container)
103
- * @param {Object} [config.state] - Estado inicial
104
- * @param {Object} options - Opciones adicionales
105
- *
106
- * @example
107
- * wuVanilla.register('counter', {
108
- * state: { count: 0 },
109
- * init: (container) => {
110
- * console.log('Initializing...');
111
- * },
112
- * render: (container, state) => {
113
- * container.innerHTML = `
114
- * <div>
115
- * <h1>Count: ${state.count}</h1>
116
- * <button id="increment">+</button>
117
- * </div>
118
- * `;
119
- * container.querySelector('#increment').onclick = () => {
120
- * state.count++;
121
- * // Re-render
122
- * };
123
- * },
124
- * destroy: (container) => {
125
- * container.innerHTML = '';
126
- * }
127
- * });
128
- */
129
- async function register(appName, config, options = {}) {
130
- const {
131
- render,
132
- destroy = null,
133
- init = null,
134
- state = {}
135
- } = config;
136
-
137
- const {
138
- onMount = null,
139
- onUnmount = null,
140
- standalone = true,
141
- standaloneContainer = '#app'
142
- } = options;
143
-
144
- if (!render || typeof render !== 'function') {
145
- throw new Error(`[WuVanilla] render function is required for ${appName}`);
146
- }
147
-
148
- // Estado local de la app
149
- const appState = { ...state };
150
-
151
- // Función de mount
152
- const mountApp = (container) => {
153
- if (!container) {
154
- console.error(`[WuVanilla] Mount failed for ${appName}: container is null`);
155
- return;
156
- }
157
-
158
- // Evitar doble mount
159
- if (adapterState.apps.has(appName)) {
160
- console.warn(`[WuVanilla] ${appName} already mounted, unmounting first`);
161
- unmountApp();
162
- }
163
-
164
- try {
165
- // Limpiar container
166
- container.innerHTML = '';
167
-
168
- // Ejecutar init si existe
169
- if (init && typeof init === 'function') {
170
- init(container, appState);
171
- }
172
-
173
- // Renderizar
174
- render(container, appState);
175
-
176
- // Guardar referencia
177
- adapterState.apps.set(appName, {
178
- container,
179
- config,
180
- state: appState
181
- });
182
-
183
- console.log(`[WuVanilla] ✅ ${appName} mounted successfully`);
184
-
185
- if (onMount) {
186
- onMount(container, appState);
187
- }
188
- } catch (error) {
189
- console.error(`[WuVanilla] Mount error for ${appName}:`, error);
190
- throw error;
191
- }
192
- };
193
-
194
- // Función de unmount
195
- const unmountApp = (container) => {
196
- const appData = adapterState.apps.get(appName);
197
-
198
- if (appData) {
199
- try {
200
- if (onUnmount) {
201
- onUnmount(appData.container, appData.state);
202
- }
203
-
204
- // Ejecutar destroy si existe
205
- if (destroy && typeof destroy === 'function') {
206
- destroy(appData.container, appData.state);
207
- } else {
208
- // Cleanup por defecto
209
- appData.container.innerHTML = '';
210
- }
211
-
212
- adapterState.apps.delete(appName);
213
-
214
- console.log(`[WuVanilla] ✅ ${appName} unmounted successfully`);
215
- } catch (error) {
216
- console.error(`[WuVanilla] Unmount error for ${appName}:`, error);
217
- }
218
- }
219
-
220
- if (container) {
221
- container.innerHTML = '';
222
- }
223
- };
224
-
225
- // Intentar registrar con Wu Framework
226
- try {
227
- const wu = await waitForWu(3000);
228
-
229
- wu.define(appName, {
230
- mount: mountApp,
231
- unmount: unmountApp
232
- });
233
-
234
- console.log(`[WuVanilla] ✅ ${appName} registered with Wu Framework`);
235
- return true;
236
-
237
- } catch (error) {
238
- console.warn(`[WuVanilla] Wu Framework not available for ${appName}`);
239
-
240
- if (standalone) {
241
- const containerElement = document.querySelector(standaloneContainer);
242
-
243
- if (containerElement) {
244
- console.log(`[WuVanilla] Running ${appName} in standalone mode`);
245
- mountApp(containerElement);
246
- return true;
247
- }
248
- }
249
-
250
- return false;
251
- }
252
- }
253
-
254
- /**
255
- * Registra una clase como microfrontend
256
- *
257
- * @param {string} appName - Nombre único del microfrontend
258
- * @param {Function} AppClass - Clase con constructor(container) y métodos render/destroy
259
- * @param {Object} options - Opciones adicionales
260
- *
261
- * @example
262
- * class TodoApp {
263
- * constructor(container) {
264
- * this.container = container;
265
- * this.todos = [];
266
- * }
267
- *
268
- * render() {
269
- * this.container.innerHTML = `
270
- * <ul>${this.todos.map(t => `<li>${t}</li>`).join('')}</ul>
271
- * `;
272
- * }
273
- *
274
- * addTodo(text) {
275
- * this.todos.push(text);
276
- * this.render();
277
- * }
278
- *
279
- * destroy() {
280
- * this.container.innerHTML = '';
281
- * this.todos = [];
282
- * }
283
- * }
284
- *
285
- * wuVanilla.registerClass('todo-app', TodoApp);
286
- */
287
- async function registerClass(appName, AppClass, options = {}) {
288
- const {
289
- constructorArgs = [],
290
- onMount = null,
291
- onUnmount = null,
292
- standalone = true,
293
- standaloneContainer = '#app'
294
- } = options;
295
-
296
- // Función de mount
297
- const mountApp = (container) => {
298
- if (!container) {
299
- console.error(`[WuVanilla] Mount failed for ${appName}: container is null`);
300
- return;
301
- }
302
-
303
- // Evitar doble mount
304
- if (adapterState.instances.has(appName)) {
305
- console.warn(`[WuVanilla] ${appName} already mounted, unmounting first`);
306
- unmountApp();
307
- }
308
-
309
- try {
310
- container.innerHTML = '';
311
-
312
- // Crear instancia de la clase
313
- const instance = new AppClass(container, ...constructorArgs);
314
-
315
- // Llamar render si existe
316
- if (instance.render && typeof instance.render === 'function') {
317
- instance.render();
318
- }
319
-
320
- // Guardar instancia
321
- adapterState.instances.set(appName, {
322
- instance,
323
- container
324
- });
325
-
326
- console.log(`[WuVanilla] ✅ ${appName} (class) mounted successfully`);
327
-
328
- if (onMount) {
329
- onMount(container, instance);
330
- }
331
- } catch (error) {
332
- console.error(`[WuVanilla] Mount error for ${appName}:`, error);
333
- throw error;
334
- }
335
- };
336
-
337
- // Función de unmount
338
- const unmountApp = (container) => {
339
- const appData = adapterState.instances.get(appName);
340
-
341
- if (appData) {
342
- try {
343
- if (onUnmount) {
344
- onUnmount(appData.container, appData.instance);
345
- }
346
-
347
- // Llamar destroy si existe
348
- if (appData.instance.destroy && typeof appData.instance.destroy === 'function') {
349
- appData.instance.destroy();
350
- } else {
351
- appData.container.innerHTML = '';
352
- }
353
-
354
- adapterState.instances.delete(appName);
355
-
356
- console.log(`[WuVanilla] ✅ ${appName} (class) unmounted successfully`);
357
- } catch (error) {
358
- console.error(`[WuVanilla] Unmount error for ${appName}:`, error);
359
- }
360
- }
361
-
362
- if (container) {
363
- container.innerHTML = '';
364
- }
365
- };
366
-
367
- // Intentar registrar con Wu Framework
368
- try {
369
- const wu = await waitForWu(3000);
370
-
371
- wu.define(appName, {
372
- mount: mountApp,
373
- unmount: unmountApp
374
- });
375
-
376
- console.log(`[WuVanilla] ✅ ${appName} (class) registered with Wu Framework`);
377
- return true;
378
-
379
- } catch (error) {
380
- console.warn(`[WuVanilla] Wu Framework not available for ${appName}`);
381
-
382
- if (standalone) {
383
- const containerElement = document.querySelector(standaloneContainer);
384
-
385
- if (containerElement) {
386
- console.log(`[WuVanilla] Running ${appName} in standalone mode`);
387
- mountApp(containerElement);
388
- return true;
389
- }
390
- }
391
-
392
- return false;
393
- }
394
- }
395
-
396
- /**
397
- * Registra un template HTML como microfrontend
398
- *
399
- * @param {string} appName - Nombre único del microfrontend
400
- * @param {string|Function} template - HTML string o función que retorna HTML
401
- * @param {Object} options - Opciones adicionales
402
- *
403
- * @example
404
- * // Template estático
405
- * wuVanilla.registerTemplate('header', '<header><h1>My Header</h1></header>');
406
- *
407
- * // Template dinámico
408
- * wuVanilla.registerTemplate('greeting', (data) => `<h1>Hello ${data.name}!</h1>`, {
409
- * data: { name: 'World' }
410
- * });
411
- */
412
- async function registerTemplate(appName, template, options = {}) {
413
- const {
414
- data = {},
415
- scripts = [],
416
- styles = [],
417
- onMount = null,
418
- onUnmount = null,
419
- standalone = true,
420
- standaloneContainer = '#app'
421
- } = options;
422
-
423
- const mountApp = (container) => {
424
- if (!container) {
425
- console.error(`[WuVanilla] Mount failed for ${appName}: container is null`);
426
- return;
427
- }
428
-
429
- try {
430
- container.innerHTML = '';
431
-
432
- // Inyectar estilos
433
- if (styles.length > 0) {
434
- const styleEl = document.createElement('style');
435
- styleEl.textContent = styles.join('\n');
436
- styleEl.setAttribute('data-wu-app', appName);
437
- container.appendChild(styleEl);
438
- }
439
-
440
- // Crear wrapper
441
- const wrapper = document.createElement('div');
442
- wrapper.setAttribute('data-wu-template', appName);
443
-
444
- // Renderizar template
445
- if (typeof template === 'function') {
446
- wrapper.innerHTML = template(data);
447
- } else {
448
- wrapper.innerHTML = template;
449
- }
450
-
451
- container.appendChild(wrapper);
452
-
453
- // Ejecutar scripts
454
- scripts.forEach(scriptFn => {
455
- if (typeof scriptFn === 'function') {
456
- scriptFn(container, data);
457
- }
458
- });
459
-
460
- adapterState.apps.set(appName, { container, template, data });
461
-
462
- console.log(`[WuVanilla] ✅ ${appName} (template) mounted successfully`);
463
-
464
- if (onMount) {
465
- onMount(container, data);
466
- }
467
- } catch (error) {
468
- console.error(`[WuVanilla] Mount error for ${appName}:`, error);
469
- throw error;
470
- }
471
- };
472
-
473
- const unmountApp = (container) => {
474
- const appData = adapterState.apps.get(appName);
475
-
476
- if (appData) {
477
- if (onUnmount) {
478
- onUnmount(appData.container, appData.data);
479
- }
480
-
481
- appData.container.innerHTML = '';
482
- adapterState.apps.delete(appName);
483
-
484
- console.log(`[WuVanilla] ✅ ${appName} (template) unmounted successfully`);
485
- }
486
-
487
- if (container) {
488
- container.innerHTML = '';
489
- }
490
- };
491
-
492
- try {
493
- const wu = await waitForWu(3000);
494
-
495
- wu.define(appName, {
496
- mount: mountApp,
497
- unmount: unmountApp
498
- });
499
-
500
- console.log(`[WuVanilla] ✅ ${appName} (template) registered with Wu Framework`);
501
- return true;
502
-
503
- } catch (error) {
504
- console.warn(`[WuVanilla] Wu Framework not available for ${appName}`);
505
-
506
- if (standalone) {
507
- const containerElement = document.querySelector(standaloneContainer);
508
- if (containerElement) {
509
- console.log(`[WuVanilla] Running ${appName} in standalone mode`);
510
- mountApp(containerElement);
511
- return true;
512
- }
513
- }
514
-
515
- return false;
516
- }
517
- }
518
-
519
- /**
520
- * Helper para crear un componente reactivo simple
521
- *
522
- * @param {Object} config - Configuración del componente
523
- * @returns {Object} Componente con métodos de estado
524
- *
525
- * @example
526
- * const Counter = wuVanilla.createComponent({
527
- * state: { count: 0 },
528
- * template: (state) => `
529
- * <div>
530
- * <h1>Count: ${state.count}</h1>
531
- * <button data-action="increment">+</button>
532
- * <button data-action="decrement">-</button>
533
- * </div>
534
- * `,
535
- * actions: {
536
- * increment: (state) => ({ count: state.count + 1 }),
537
- * decrement: (state) => ({ count: state.count - 1 })
538
- * }
539
- * });
540
- *
541
- * wuVanilla.register('counter', Counter);
542
- */
543
- function createComponent(config) {
544
- const { state: initialState = {}, template, actions = {}, onInit, onDestroy } = config;
545
-
546
- let currentState = { ...initialState };
547
- let container = null;
548
- let mounted = false;
549
-
550
- const setState = (newState) => {
551
- currentState = { ...currentState, ...newState };
552
- if (mounted && container) {
553
- render(container, currentState);
554
- }
555
- };
556
-
557
- const render = (cont, state) => {
558
- const html = template(state);
559
-
560
- // Preservar focus si es posible
561
- const activeId = document.activeElement?.id;
562
-
563
- cont.innerHTML = html;
564
-
565
- // Restaurar focus
566
- if (activeId) {
567
- const el = cont.querySelector(`#${activeId}`);
568
- if (el) el.focus();
569
- }
570
-
571
- // Bind actions
572
- cont.querySelectorAll('[data-action]').forEach(el => {
573
- const actionName = el.getAttribute('data-action');
574
- if (actions[actionName]) {
575
- el.addEventListener('click', () => {
576
- const result = actions[actionName](currentState, el);
577
- if (result) {
578
- setState(result);
579
- }
580
- });
581
- }
582
- });
583
- };
584
-
585
- return {
586
- state: currentState,
587
-
588
- init: (cont) => {
589
- container = cont;
590
- if (onInit) onInit(cont, currentState);
591
- },
592
-
593
- render: (cont, state) => {
594
- container = cont;
595
- currentState = state || currentState;
596
- mounted = true;
597
- render(cont, currentState);
598
- },
599
-
600
- destroy: (cont) => {
601
- if (onDestroy) onDestroy(cont, currentState);
602
- mounted = false;
603
- container = null;
604
- cont.innerHTML = '';
605
- },
606
-
607
- // Exponer setState para uso externo
608
- setState,
609
- getState: () => currentState
610
- };
611
- }
612
-
613
- /**
614
- * Helper para usar eventos de Wu Framework
615
- */
616
- function useWuEvents() {
617
- const subscriptions = [];
618
-
619
- return {
620
- emit: (event, data, options) => {
621
- const wu = getWuInstance();
622
- if (wu?.eventBus) {
623
- wu.eventBus.emit(event, data, options);
624
- }
625
- },
626
-
627
- on: (event, callback) => {
628
- const wu = getWuInstance();
629
- if (wu?.eventBus) {
630
- const unsubscribe = wu.eventBus.on(event, callback);
631
- subscriptions.push(unsubscribe);
632
- return unsubscribe;
633
- }
634
- return () => {};
635
- },
636
-
637
- once: (event, callback) => {
638
- const wu = getWuInstance();
639
- if (wu?.eventBus) {
640
- return wu.eventBus.once(event, callback);
641
- }
642
- return () => {};
643
- },
644
-
645
- off: (event, callback) => {
646
- const wu = getWuInstance();
647
- if (wu?.eventBus) {
648
- wu.eventBus.off(event, callback);
649
- }
650
- },
651
-
652
- cleanup: () => {
653
- subscriptions.forEach(unsub => unsub());
654
- subscriptions.length = 0;
655
- }
656
- };
657
- }
658
-
659
- /**
660
- * Helper para usar el Store de Wu Framework
661
- */
662
- function useWuStore(namespace = '') {
663
- return {
664
- get: (path = '') => {
665
- const wu = getWuInstance();
666
- if (wu?.store) {
667
- const fullPath = namespace ? (path ? `${namespace}.${path}` : namespace) : path;
668
- return wu.store.get(fullPath);
669
- }
670
- return null;
671
- },
672
-
673
- set: (path, value) => {
674
- const wu = getWuInstance();
675
- if (wu?.store) {
676
- const fullPath = namespace ? `${namespace}.${path}` : path;
677
- wu.store.set(fullPath, value);
678
- }
679
- },
680
-
681
- onChange: (pattern, callback) => {
682
- const wu = getWuInstance();
683
- if (wu?.store) {
684
- const fullPattern = namespace ? `${namespace}.${pattern}` : pattern;
685
- return wu.store.on(fullPattern, callback);
686
- }
687
- return () => {};
688
- }
689
- };
690
- }
691
-
692
- /**
693
- * Crea un WuSlot en JavaScript puro
694
- */
695
- function createWuSlot(target, props) {
696
- const { name, url, fallbackText = null, onLoad = null, onError = null } = props;
697
-
698
- const container = document.createElement('div');
699
- container.className = 'wu-slot';
700
- container.style.cssText = 'min-height: 100px; position: relative;';
701
- container.setAttribute('data-wu-app', name);
702
- container.setAttribute('data-wu-url', url);
703
-
704
- // Loading state
705
- container.innerHTML = `
706
- <div style="display: flex; align-items: center; justify-content: center; padding: 2rem; color: #666;">
707
- ${fallbackText || `Loading ${name}...`}
708
- </div>
709
- `;
710
-
711
- target.appendChild(container);
712
-
713
- let appInstance = null;
714
-
715
- const mount = async () => {
716
- try {
717
- const wu = getWuInstance();
718
- if (!wu) throw new Error('Wu Framework not initialized');
719
-
720
- const containerId = `wu-slot-${name}-${Date.now()}`;
721
- const innerContainer = document.createElement('div');
722
- innerContainer.id = containerId;
723
- innerContainer.style.cssText = 'width: 100%; height: 100%;';
724
-
725
- container.innerHTML = '';
726
- container.appendChild(innerContainer);
727
-
728
- const app = wu.app(name, {
729
- url,
730
- container: `#${containerId}`,
731
- autoInit: true
732
- });
733
-
734
- appInstance = app;
735
- await app.mount();
736
-
737
- if (onLoad) onLoad({ name, url });
738
-
739
- } catch (err) {
740
- container.innerHTML = `
741
- <div style="padding: 1rem; border: 1px solid #f5c6cb; border-radius: 4px; background: #f8d7da; color: #721c24;">
742
- <strong>Error loading ${name}</strong>
743
- <p style="margin: 0.5rem 0 0 0;">${err.message}</p>
744
- </div>
745
- `;
746
- if (onError) onError(err);
747
- }
748
- };
749
-
750
- const destroy = async () => {
751
- if (appInstance) {
752
- try {
753
- await appInstance.unmount();
754
- } catch (e) {}
755
- appInstance = null;
756
- }
757
- container.remove();
758
- };
759
-
760
- mount();
761
-
762
- return { container, destroy };
763
- }
764
-
765
- // ============================================
766
- // AI INTEGRATION
767
- // ============================================
768
- export { useWuAI } from './ai.js';
769
- import { useWuAI } from './ai.js';
770
-
771
- // API pública del adapter
772
- export const wuVanilla = {
773
- register,
774
- registerClass,
775
- registerTemplate,
776
- createComponent,
777
- createWuSlot,
778
- useWuEvents,
779
- useWuStore,
780
- useWuAI,
781
- getWuInstance,
782
- waitForWu
783
- };
784
-
785
- export default wuVanilla;