# Toolkit API

The toolkit is a crucial object provided to each mod during its initialization, enabling seamless interaction with Vellum’s core system. It’s passed as the first argument to a mod’s `init` function and offers methods to dispatch actions and bind functionality to custom classes. This document explains the toolkit’s core methods, provides practical examples, and demonstrates how it empowers mods to integrate with Vellum.

For a broader understanding of mods, see [Understanding Mods](./mods.md). For details on the action system, check out [Action System](./actions.md).

---

## Toolkit Overview

The toolkit is created via `createToolkit` in `src/utils/toolkit.mjs` and provides the following properties and methods:

- **`element`**: The `HTMLElement` (Vellum instance) associated with the toolkit.
- **`dispatchAction(action)`**: Dispatches an action to Vellum’s event system.
- **`bindToClass(targetClass)`**: Binds the toolkit to a custom class for easier access.

These tools allow mods to communicate with Vellum and other mods, manipulate layouts, and extend functionality dynamically.

---

## Core Methods

### `element`
- **Description**: A reference to the Vellum custom element (`<vellum-app>`), giving mods direct access to its DOM context.
- **Use Case**: Useful for inspecting the Vellum instance or attaching event listeners directly.
- **Example**:
  ```javascript
  export async function init(toolkit) {
    console.log('Vellum element:', toolkit.element);
    // Outputs the <vellum-app> element
  }
  ```

### `dispatchAction(action)`
- **Description**: Dispatches a custom action to Vellum, triggering registered handlers. Actions are objects with a `type` (string) and optional `detail` (object).
- **Use Case**: Commonly used to register actions, update layouts, or communicate with other mods.
- **Example from `app-counter.mjs`**:
  ```javascript
  export async function init(toolkit) {
    let count = 0;
    const renderCounter = () => html`<div>Count: ${count}</div>`;

    toolkit.dispatchAction({
      type: 'app:register',
      detail: {
        id: 'counter',
        name: 'Counter',
        content: renderCounter,
      },
    });
  }
  ```
  Here, the `app-counter` mod registers itself with the `app-manager` mod by dispatching an `'app:register'` action.

- **Another Example from `mod-help.mjs`**:
  ```javascript
  export async function init(toolkit) {
    const toggleHelp = (detail) => {
      if (detail.open) {
        toolkit.dispatchAction({
          type: 'layout:content:append',
          detail: { content: html`<div>Help content</div>`, id: 'help-panel' },
        });
      }
    };

    toolkit.dispatchAction({
      type: 'action:register',
      detail: { actionType: 'help:toggle', handler: toggleHelp, modName: 'mod-help' },
    });
  }
  ```
  This shows registering a handler for `'help:toggle'` and appending content to the layout when triggered.

### `bindToClass(targetClass)`
- **Description**: Creates a subclass of `targetClass` that automatically includes the toolkit as a property (default: `.$toolkit`), unless disabled with `toolkitProp = false`.
- **Use Case**: Simplifies toolkit access in custom web components or classes within a mod.
- **Example**:
  ```javascript
  export async function init(toolkit) {
    class MyComponent {
      constructor() {
        this.name = 'My Component';
      }
      logAction() {
        this['.$toolkit'].dispatchAction({ type: 'log', detail: { message: this.name } });
      }
    }

    const BoundComponent = toolkit.bindToClass(MyComponent);
    const instance = new BoundComponent();
    instance.logAction(); // Dispatches action using toolkit
  }
  ```
  Here, `bindToClass` ensures the toolkit is available as `this['.$toolkit']` in the `MyComponent` instance.

- **Custom Property Example**:
  ```javascript
  const toolkit = createToolkit(element, 'customToolkit');
  const BoundClass = toolkit.bindToClass(MyComponent);
  const instance = new BoundClass();
  instance.customToolkit.dispatchAction({ type: 'test' });
  ```
  This uses a custom property name instead of the default `.$toolkit`.

---

## Dispatching Actions

The `dispatchAction` method is the primary way mods interact with Vellum. Here’s a practical example from `mod-app-manager.mjs`:

```javascript
export function init(toolkit) {
  const registerApp = (detail) => {
    toolkit.dispatchAction({
      type: 'layout:content:append',
      detail: {
        content: html`<button>${detail.name}</button>`,
        id: `app-btn-${detail.id}`,
      },
    });
  };

  toolkit.dispatchAction({
    type: 'action:register',
    detail: { actionType: 'app:register', modName: 'mod-app-manager', handler: registerApp },
  });
}
```

- **Explanation**: The mod registers a handler for `'app:register'` and uses `dispatchAction` to append a button to the layout when an app registers.

See [Action System](./actions.md) for more on creating and handling actions.

---

## Binding to Classes

The `bindToClass` method is particularly useful for mods that define custom elements or complex logic. Here’s how it might be used:

```javascript
export async function init(toolkit) {
  class CounterElement {
    constructor() {
      this.count = 0;
    }
    increment() {
      this.count++;
      this['.$toolkit'].dispatchAction({
        type: 'layout:content:append',
        detail: { content: `Count: ${this.count}`, id: 'counter' },
      });
    }
  }

  const EnhancedCounter = toolkit.bindToClass(CounterElement);
  const counter = new EnhancedCounter();
  counter.increment(); // Updates layout with new count
}
```

- **Note**: If `toolkitProp` is set to `false`, the original class is returned unchanged:
  ```javascript
  const toolkit = createToolkit(element, false);
  const UnboundClass = toolkit.bindToClass(CounterElement);
  const instance = new UnboundClass();
  console.log(instance['.$toolkit']); // undefined
  ```

---

## Accessing the Host Element

The `element` property lets mods interact with Vellum’s DOM directly:

```javascript
export async function init(toolkit) {
  const vellumElement = toolkit.element;
  vellumElement.addEventListener('click', () => {
    toolkit.dispatchAction({ type: 'click:detected', detail: { time: Date.now() } });
  });
}
```

This attaches a click listener to `<vellum-app>`, dispatching an action on click.

---

## Next Steps
- **Learn More**: Explore how the toolkit integrates with actions in [Action System](./actions.md).
- **See Examples**: Check out [Examples and Tutorials](./examples/) for real-world usage.
- **Technical Details**: Refer to the [API Reference](./api-reference.md) for `createToolkit` specifics.