# WebContainer

> Embebe una webview nativa (HTML/JS) dentro de la UI — vía la interfaz IWebView, dependiente de plataforma.

Source: https://crossfly.dev/es/docs/ui/widgets/webcontainer — CrossFly documentation. Full docs as one file: https://crossfly.dev/llms-full.txt

# WebContainer

`WebContainer` es un widget que **embebe una webview nativa** (contenido HTML/JavaScript) dentro de tu UI CrossFly. Es un *wrapper* fino: no dibuja nada propio — delega todo a la `IWebView` que la plataforma provee vía `PlatformUtils.instance.createWebView()`. Sirve para mostrar una página, un formulario HTML o un panel web como si fuera un componente común de la pantalla.

> ⚠️ **Honestidad sobre disponibilidad:** `WebContainer` **solo funciona donde existe una `IWebView` nativa** (Android, iOS, Desktop). **No hay implementación concreta de `IWebView` en esta base de código ni en el destino Web/TeaVM** — `createWebView()` retorna `null` en plataformas sin soporte, y el constructor de `WebContainer` entonces lanza `UnsupportedOperationException`. En un build Web/WebGL, prefiere abrir una página externa (`view(url)`) en vez de embeber una webview.

> 🔴 · **Paquete:** `dev.crossfly.ui` · **Extiende:** `Component` (implementa `Runnable`) · **Delega a:** `IWebView`

## Cuándo usar
- Mostrar contenido web (HTML/JS) **dentro** de la app, en una plataforma con webview nativa (Android/iOS/Desktop).
- Integrar un formulario HTML y capturar el envío vía `setFormSubmitListener`.

## Cuándo NO usar
- Para contenido estático simple (texto/imagen) → usa los widgets nativos ([`chartview`](/docs/ui/widgets/chartview), labels, imágenes) en vez de cargar una página.

## Apariencia
`WebContainer` no pinta píxeles propios: la webview nativa del sistema se superpone al área del componente. La visibilidad se coordina automáticamente en `onPaint` — la webview aparece solo cuando la ventana padre está al frente (`isTopMost()`) y desaparece en caso contrario.

## Ejemplo completo (copiar, pegar y ejecutar)
`WebContainer` solo funciona donde hay una `IWebView` nativa. El ejemplo detecta el soporte con `PlatformUtils.instance.createWebView() != null` **antes** de crear el container (evitando el `UnsupportedOperationException` del constructor) y, sin soporte (ej.: destino Web/TeaVM), degrada abriendo la página externamente con `view(url)`.

```java
package com.exemplo;

import dev.crossfly.PlatformUtils;

import dev.crossfly.ui.*;
import dev.crossfly.ui.layout.*;

/** Pantalla principal ejecutable. Apunta el launcher (classname) y corre: gradlew :lwjgl3:run */
public class MainWindow extends Window
{
   @Override
   public void onShow() throws Exception
   {
      super.onShow();
      setLayout(new VerticalLayout());

      String url = "https://example.com";

      // Solo crea el WebContainer si la plataforma provee una IWebView nativa.
      if (PlatformUtils.instance.createWebView() != null)
      {
         WebContainer browser = new WebContainer();
         browser.show(url);
         add(LAY_FILL, browser);
      }
      else
      {
         // Destino Web/TeaVM (sin webview embebida): abre la página externamente.
         add(LAY_AUTO, new Label("Sem webview nativa — abrindo externamente…"));
         PlatformUtils.instance.view(url);
      }
   }
}
```

> Los fragmentos siguientes muestran **solo el núcleo** (lo que va dentro de `onShow()`). Para ejecutarlos, colócalos en el esqueleto `MainWindow` de arriba.

## Uso básico
```java
WebContainer browser = new WebContainer();   // puede lanzar UnsupportedOperationException
browser.show("https://example.com");
container.add(LAY_FILL, browser);
```

## Constructores
| Constructor | Descripción |
|---|---|
| `WebContainer()` | Obtiene la webview nativa vía `PlatformUtils.instance.createWebView()` e inicia invisible. **Lanza `UnsupportedOperationException`** si la plataforma no provee una `IWebView`. |

## Propiedades y personalización
| Método | Tipo | Qué hace |
|---|---|---|
| `show(String url)` | `void` | Carga y muestra la URL en la webview. |
| `hide()` | `void` | Oculta la webview manteniendo el estado de la página. |
| `setVisible(boolean)` | `void` | `true` = `show(null)` (mantiene URL/estado actual); `false` = `hide()`. |
| `isVisible()` | `boolean` | Si la webview está visible. |
| `evaluateJavaScript(String script)` | `void` | Ejecuta JavaScript en la página. |
| `setFormSubmitListener(IWebView.FormSubmitListener)` | `void` | Registra callback para captura de envíos de formulario HTML. |

> La `IWebView` exige que las operaciones ocurran en el *render thread* (paint thread). Vuelve a él con `Component.onUI(...)` si estás llamando `show`/`evaluateJavaScript` desde otro thread.

## Callbacks y eventos
| Callback | Cuándo se dispara |
|---|---|
| `IWebView.FormSubmitListener` (vía `setFormSubmitListener`) | Al enviar un formulario HTML dentro de la página embebida. |

> `WebContainer` **no usa** `onAction`/`onClick` — la interacción ocurre dentro de la página web. El único gancho de app es el listener de submit de formulario.

## Estados
- **visible / oculto**: gestionado por `show`/`hide`/`setVisible` y, automáticamente, por la posición de la ventana (la webview desaparece cuando la ventana padre no está al frente).
- **removido**: en `onRemove`, se llama a `view.removeView()` y la `IWebView` **no puede reutilizarse** — para volver a mostrar, crea un nuevo `WebContainer`.

### Formulario HTML con captura de envío (plataforma con webview)
```java
WebContainer form = new WebContainer();
form.setFormSubmitListener(dados -> processarEnvio(dados));  // IWebView.FormSubmitListener
form.show("https://meuservico/formulario.html");
container.add(LAY_FILL, form);
```

### Degradación segura en el destino Web
```java
// En el build Web/TeaVM, createWebView() devuelve null y el constructor lanza.
try {
   WebContainer c = new WebContainer();
   c.show("https://example.com");
   container.add(LAY_FILL, c);
} catch (UnsupportedOperationException e) {
   // Sin webview embebida: abre la página externamente.
   PlatformUtils.instance.view("https://example.com");
}
```

## Buenas prácticas
- Encapsula la creación en un `try/catch` de `UnsupportedOperationException` para degradar bien en el destino Web.

## Errores comunes
- **Crear `WebContainer` en plataforma sin soporte**: lanza `UnsupportedOperationException`. Trátalo o detéctalo antes.
- **Reutilizar tras `onRemove`**: la `IWebView` fue descartada (`removeView()`); crea una nueva instancia.
- **Esperar embeber web en el destino Web/TeaVM**: no hay implementación; embeber webview ≠ ser una app web. Usa `view(url)`.

## Ver también
- Guía del área: [`ui/`](/docs/ui) · Recetas: [`cookbook/`](/docs/cookbook)
- Concepto (plataformas, threading de UI): [`concepts/`](/docs/concepts)
- Componentes relacionados: [`locationview`](/docs/ui/widgets/locationview)
