# Escribir un componente de Flow: un archivo HTML

> Un componente de Flow es un único archivo HTML con una parte Node.js, un formulario de ajustes y un diseño. Construye uno que cambie el texto de un mensaje, conoce las partes del archivo y cómo probarlo.

Framework: flow
Product: Flow (flow@11.1)
Language: es
Content-SHA256: dbb0091ae1048aca717e4e67903083a89a3a7456acbfa84e98b86db69656193f
Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c
Sources: 
Review: not-recorded

Un componente es **un archivo `.html`**. Flow lee el archivo, ejecuta su parte Node.js dentro del flujo y muestra su diseño en el editor. Todos los componentes oficiales de [el repositorio](/en/flow/the-components-repository/) usan este formato, así que puedes leer cualquiera de ellos como ejemplo.

## Un ejemplo: `shout.html`

Recibe un mensaje, convierte el texto a mayúsculas, añade un sufijo y lo envía.

```html
<script total>

	exports.id = 'shout';
	exports.name = 'Shout';
	exports.group = 'Common';
	exports.version = '1';
	exports.icon = 'ti ti-speakerphone';
	exports.author = 'Forge';
	exports.config = { suffix: '!' };
	exports.inputs = [{ id: 'input', name: 'Input' }];
	exports.outputs = [{ id: 'output', name: 'Output' }];

	exports.make = function(instance, config) {

		let count = 0;

		instance.message = function($) {
			count++;
			instance.status({ shouted: count });
			$.data = String($.data).toUpperCase() + config.suffix;
			$.send('output');
		};

	};

</script>

<settings>
	<div class="padding">
		<ui-component name="input" path="?.suffix" config="maxlength:10">Suffix</ui-component>
	</div>
</settings>

<readme>
The component converts the text of a message to upper case and adds a suffix.
</readme>

<body>
	<header>
		<i class="ICON"></i>NAME
	</header>
	<footer>
		<div class="padding">Shouted: <b><ui-bind path="STATUS.shouted" config="text:value||0"></ui-bind></b></div>
	</footer>
</body>
```

## Las partes del archivo

| Parte | Para qué sirve |
|---|---|
| `<script total>` | el código Node.js del componente, ejecutado en el proceso del flujo |
| `<settings>` | el formulario de configuración, con los componentes de la interfaz de usuario (`ui-component`, las rutas que empiezan por `?.` apuntan al `config` del componente) |
| `<readme>` | la ayuda que se muestra en el editor |
| `<body>` | la caja en el diagrama: un `<header>` con los marcadores `ICON` y `NAME`, y opcionalmente un `<footer>` o un cuerpo, donde `<ui-bind path="STATUS.x">` muestra el estado y `CONFIG.x` la configuración |
| `<style>` | el CSS de la caja; `.CLASS` se sustituye por una clase única del componente |
| `<script>` (segundo) | JavaScript opcional del editor, para botones de la caja (puede enviar `{ TYPE: 'trigger', id: ... }` al flujo) |

## Los `exports` de la parte Node.js

| Export | Significado |
|---|---|
| `id`, `name`, `group`, `version`, `icon`, `author` | la identidad del componente y dónde aparece en la lista |
| `config` | la configuración por defecto; el formulario de `<settings>` la edita |
| `inputs`, `outputs` | la lista de conectores `{ id, name }`. Un componente sin `inputs` es una fuente |
| `kind` | opcional: el papel del componente en el catálogo (`trigger`, `action` u `output`) |
| `make(instance, config)` | se llama una vez por cada caja que colocas en el diagrama |

## La `instance`

Dentro de `make` defines el comportamiento asignando funciones a la instancia:

| Función | Se llama cuando |
|---|---|
| `instance.message = function($) {}` | llega un mensaje. `$.data` son los datos, `$.send('output')` los reenvía a los conectores de esa salida, `$.destroy()` lo termina sin enviarlo |
| `instance.configure = function() {}` | cambia la configuración, y una vez al inicio |
| `instance.trigger = function() {}` | el botón del editor o el código lo pide |
| `instance.pause = function(is) {}` | el flujo se pausa o se reanuda |
| `instance.close = function() {}` | se elimina la caja o se detiene el flujo: limpia aquí tus temporizadores |

Y llamas a `instance.send('output', data)` para crear un mensaje propio (como hace `timer`), a `instance.status(object)` para mostrar un estado en la caja (`delay.html` pasa un tiempo en milisegundos como segundo argumento para refrescarlo) y a `instance.throw(error)` para informar de un error.

## Pruébalo

1. Pon `shout.html` en un catálogo y escribe su dirección en el ajuste `components2` (consulta [el repositorio](/en/flow/the-components-repository/)), o importa un flujo que lo contenga en sus `components`.
2. Añade un `timer` y un `print` a su lado en el editor, conéctalos e inicia el flujo.
3. Abre el estado de la caja: el contador crece con cada mensaje.

Para probar un componente sin el editor, el repositorio tiene un pequeño tester, consulta [el repositorio de componentes](/en/flow/the-components-repository/).
