npm package: @mypolis.eu/action-controller
Description: `@mypolis.eu/action-controller` is a lightweight TypeScript library that brings declarative event handling to your web components. It allows you to connect DOM events to methods on LitElement-based controllers using simple HTML data-action attributes.
Author: Guilherme Rosado
Latest version: 4.1.0

# @mypolis.eu/action-controller

`@mypolis.eu/action-controller` is a lightweight TypeScript library that brings
declarative event handling to your web components. It allows you to connect DOM
events to methods on LitElement-based controllers using simple HTML data-action
attributes.

## Features

- **Declarative Event Handling**: Define actions directly in your HTML using
  data-action attributes.

- **LitElement Based**: Controllers are extensions of LitElement, allowing you
  to use all Lit features like reactive properties and efficient rendering.

- **Automatic Registration**: Easily register your controller classes as custom
  elements.

- **Dynamic Content Ready**: Uses a MutationObserver to automatically bind
  actions to new elements added to the DOM and clean up when they are removed.

- **Scoped Actions**: Actions are scoped to the controller that defines them,
  ensuring clean component encapsulation.

- **DOM Query Helpers**: Includes query and queryAll utilities for accessing
  elements within your controller's scope, often used with data-target
  attributes.

## Installation

You'll also need to install lit as it's a peer dependency.

```bash
npm install @mypolis.eu/action-controller lit

# or

yarn add @mypolis.eu/action-controller lit

# or

pnpm add @mypolis.eu/action-controller lit
```

## Core Concepts

### Controllers

Controllers are custom elements that extend the Controller class (which itself
extends LitElement). They encapsulate the behavior and state related to a piece
of UI. The Controller base class handles the setup of action listeners.

### Actions

Actions link DOM events on elements within a controller's template to methods
on that controller instance. They are defined using the data-action attribute.

**Syntax**: `data-action="eventType->controllerTagName#methodName eventType2->controllerTagName#methodName2 ..."`

- **eventType**: The name of the DOM event (e.g., click, input, custom-event).

- **controllerTagName**: The tag name of the controller custom element (e.g.,
  my-greeter). This must match the tag name of the controller component where the
  data-action attribute is placed.

- **methodName**: The name of the method to call on the controller instance.

### Registration

Controllers are registered as custom elements using the `@customElement`
decorator from `lit/decorators.js`. This decorator requires you to explicitly
provide the custom element's tag name (e.g.,
`@customElement("my-example-controller")`).

### Targets

"Targets" are specific elements within a controller's view that you might want
to reference directly in your controller's logic. You can identify these
elements using data-target attributes (or any other selector) and access them
using the query and queryAll helper functions.

## Usage

// dialog-trigger.ts

```typescript
import {customElement} from "lit/decorators.js";
import {Controller, target} from "@mypolis.eu/action-controller";
import type {SlDialog} from "@shoelace-style/shoelace";

@customElement("dialog-trigger")
export class DialogTrigger extends Controller {
	@target dialog!: SlDialog;

	open() {
		this.dialog.show();
	}

	close() {
		this.dialog.hide();
	}
}
```

// index.html

```html
<dialog-trigger>
	<sl-dialog
		data-error="default"
		data-target="dialog-trigger.dialog"
	>
		<header>
			<h4>Algo Correu Mal</h4>
			<sl-button
				size="small"
				title="Cancelar"
				data-action="click->dialog-trigger#close"
				circle
			>
				<sl-icon
					library="lucide"
					name="x"
				></sl-icon>
			</sl-button>
		</header>
		<div>
			<p>
				Lamentamos, mas ocorreu um erro inesperado. Por favor, tente novamente dentro de momentos. Se a situação
				persistir, não hesite em contactar o nosso suporte.
			</p>
		</div>
		<button
			data-action="click->dialog-trigger#close"
			style="width: 100%"
		>
			Fechar
		</button>
	</sl-dialog>
</dialog-trigger>
```