# Toggle API

### Global API (`window.Toggles`)

The component exposes a global registry to interact with toggle instances programmatically.

#### `window.Toggles.getAll()`

Returns an array of all initialized `Toggle` class instances on the page.

#### `window.Toggles.findById(id)`

Returns the `Toggle` instance with the matching button ID.

#### `window.Toggles.findByTarget(targetId)`

Returns an array of `Toggle` instances that target the specified element ID.

***

### Instance API (`Toggle`)

Each toggle instance provides properties and methods for state control.

#### Properties

* `id`: The unique ID of the toggle (generated if not present on the button).
* `button`: The HTML button element.
* `target`: The HTML target element (resolved at runtime).
* `isEnabled`: Boolean indicating if the toggle is currently active (supports getter and setter).
* `config`: The parsed configuration object (read-only via `getConfig()`).

#### Methods

* `enable()`: Activates the toggle.
* `disable()`: Deactivates the toggle.
* `toggle()`: Flips the current state.
* `setEnabled(boolean)`: Explicitly sets the state.
* `updateLabelWidth()`: Force recalculation of label widths (if in `alternate` mode).
* `on(eventName, handler)`: Adds an event listener to the **target** element.
* `off(eventName, handler)`: Removes an event listener from the **target** element.
* `getConfig()`: Returns a copy of the parsed configuration from data attributes.

***

### Events

Events are dispatched from the **target element**. They bubble up and are not cancelable.

| Event Name       | Detail                       | Description                           |
| ---------------- | ---------------------------- | ------------------------------------- |
| `toggle:enable`  | `{ id, isEnabled: true }`    | Fired when the toggle is activated.   |
| `toggle:disable` | `{ id, isEnabled: false }`   | Fired when the toggle is deactivated. |
| `toggle:change`  | `{ id, isEnabled: boolean }` | Fired on any state change.            |

***

### Examples

#### Programmatic Toggle Control

```javascript
// Find a toggle by its button ID
const menuToggle = window.Toggles.findById("menu-toggle");

// Open the toggle target
menuToggle.enable();

// Close the toggle target
menuToggle.disable();

// Toggle the current state
menuToggle.toggle();

// Set state explicitly
menuToggle.setEnabled(true);  // Open
menuToggle.setEnabled(false); // Close

// Check current state
if (menuToggle.isEnabled) {
  console.log("Menu is open");
}

// Get all toggle instances
const allToggles = window.Toggles.getAll();
console.log(`Found ${allToggles.length} toggles on the page`);
```

#### Finding Toggles by Target

```javascript
// Find all toggle buttons that control "mobile-menu"
const menuToggles = window.Toggles.findByTarget("mobile-menu");

console.log(`${menuToggles.length} buttons control the mobile menu`);

// Disable all of them (closes the menu)
menuToggles.forEach(toggle => toggle.disable());

// Enable via any of them (opens the menu, all stay synced)
menuToggles[0].enable();
```

#### Event Listeners for State Changes

```javascript
const menuTarget = document.getElementById("mobile-menu");

// Listen for enable (open)
menuTarget.addEventListener("toggle:enable", (e) => {
  console.log(`Toggle ${e.detail.id} opened the menu`);
  
  // Track analytics
  analytics.track("menu_opened");
});

// Listen for disable (close)
menuTarget.addEventListener("toggle:disable", (e) => {
  console.log(`Toggle ${e.detail.id} closed the menu`);
});

// Listen for any state change
menuTarget.addEventListener("toggle:change", (e) => {
  const { id, isEnabled } = e.detail;
  console.log(`Menu is now ${isEnabled ? "open" : "closed"}`);
  
  // Update UI based on state
  document.body.classList.toggle("menu-active", isEnabled);
});
```

#### Using Instance Event Methods

```javascript
const toggle = window.Toggles.findById("menu-toggle");

// Add event listener via instance method (attaches to target element)
function handleChange(e) {
  console.log(`State changed: ${e.detail.isEnabled}`);
}

toggle.on("toggle:change", handleChange);

// Later, remove the listener
toggle.off("toggle:change", handleChange);
```

#### Reading Toggle Configuration

```javascript
const toggle = window.Toggles.findById("menu-toggle");

// Get a copy of the parsed configuration
const config = toggle.getConfig();

console.log(config);
// Output:
// {
//   targetId: "mobile-menu",
//   targetToggledClass: "is-open",
//   freezeScroll: true,
//   labelMode: "alternate",
//   nextFocusId: null,
//   targetIsModal: false
// }

// Access individual config values
if (config.freezeScroll) {
  console.log("This toggle freezes scroll when active");
}
```

#### Close All Open Toggles

```javascript
// Close all active toggles on the page
function closeAllToggles() {
  window.Toggles.getAll()
    .filter(toggle => toggle.isEnabled)
    .forEach(toggle => toggle.disable());
}

// Example: Close all toggles on route change (SPA)
window.addEventListener("popstate", closeAllToggles);

// Example: Close all toggles with Escape (handled automatically, but custom logic)
document.addEventListener("keydown", (e) => {
  if (e.key === "Escape") {
    closeAllToggles();
  }
});
```
