# Events and listeners

AsukaDesigner v1 includes runtime listeners that can be enabled, disabled, and configured depending on the integration.

This guide explains the role of listeners, how to inspect their state, and how they relate to movement, snapping, constraints, and other runtime behaviors.

## Why listeners exist

Listeners are used to keep editor behavior modular.

Instead of hard-wiring every behavior permanently, the runtime can activate or deactivate focused behavior groups such as:

- snapping
- rotation snapping
- center snapping
- object constraints
- click handling
- bounding-box updates
- state synchronization helpers

This makes it easier to adapt the editor to different products and permissions.

## Public listener API

The public controls live under `designer.util.listeners`.

```ts
const designer = createAsukaDesigner('#app');

const listeners = designer.util.listeners;
```

### Inspect enabled listeners

```ts
listeners.getEnabled();
listeners.isEnabled('objectSnapping');
```

### Enable or disable a listener

```ts
listeners.setEnabled('objectSnapping', true);
listeners.setEnabled('rotationSnapping', false);
```

### Update several listeners at once

```ts
listeners.setMany({
  objectSnapping: true,
  rotationSnapping: true,
  centerSnapping: true,
});
```

### Read and update listener settings

```ts
listeners.getSettings();

listeners.setSettings({
  snappingThreshold: 5,
  snappingRelease: 10,
});
```

## Snapping

Snapping is one of the most important listener-driven behaviors in the editor.

The Fabric-only snapping extension is exposed through `designer.engine.canvas2d`.

```ts
designer.engine.canvas2d?.setSnapping({
  enabled: true,
  threshold: 5,
  release: 10,
  priority: 'zones-first',
});

const snapping = designer.engine.canvas2d?.getSnapping();
```

### Typical snapping goals

Snapping can help users align objects against:

- other objects
- drawing zone boundaries
- drawing zone centers
- canvas centers
- horizontal and vertical guides

### Current project note

The current project history includes fixes for a visual edge case where snapping guides might remain visible or reappear after `mouse:up` when motion continues with an elastic or inertia-like effect.

That behavior should be tested in integrations that customize movement behavior.

## Constraints and movement

Listeners often work together with constraint logic.

Typical responsibilities include:

- keeping an object within a drawing zone or allowed boundary
- updating the object border color depending on whether it is inside or outside the allowed zone
- restoring a previous position when the object exits the allowed area
- normalizing transform behavior after drag, scale, or rotation

These behaviors are especially relevant when your integration relies on strict printable areas.

## Object interaction

Listener-driven behaviors also affect object interaction patterns such as:

- selection changes
- object hover previews
- layer previews
- click-to-open contextual tools
- movement synchronization with UI elements

Examples include:

- contextual selection menu updates based on the selected object type
- layer hover previews on the canvas
- hiding and restoring object-linked menus while a transform is in progress

## Permissions and listeners

Listeners can be adapted to integration mode and permissions.

For example, a production-facing integration may disable some editing-related listeners, while a more advanced editor build may keep them enabled.

Common strategies include:

- enabling richer listener sets in development mode
- disabling destructive or advanced manipulation flows in restricted modes
- adapting movement and snapping rules based on role-specific permissions

## Example: tune snapping during initialization

```ts
const designer = createAsukaDesigner('#app', {
  listeners: {
    objectSnapping: true,
    rotationSnapping: true,
    centerSnapping: true,
  },
});

designer.engine.canvas2d?.setSnapping({
  enabled: true,
  threshold: 6,
  release: 10,
  priority: 'zones-first',
});
```

## Example: temporarily disable snapping

```ts
const restore = designer.engine.canvas2d?.getSnapping();

if (restore) designer.engine.canvas2d?.setSnapping({
  ...restore,
  enabled: false,
});

// ...perform a specific flow...

if (restore) designer.engine.canvas2d?.setSnapping(restore);
```

## Example: disable advanced listeners for a lightweight experience

```ts
designer.util.listeners.setMany({
  objectSnapping: false,
  rotationSnapping: false,
  centerSnapping: false,
});
```

## Best practices

- Keep snapping enabled when layout precision matters.
- Test listener combinations with text, shapes, images, and grouped SVG objects.
- Debounce heavy side effects when listening to broad state changes.
- Use permissions and mode configuration to decide which listeners should be active.
- Validate guide cleanup behavior after `mouse:up` in custom movement flows.
- Treat listeners as part of the runtime product design, not only as implementation details.

## Related APIs

Listener flows often work together with:

- `designer.engine.areas?.create(...)`
- `designer.engine.areas?.select(id)`
- `designer.layout.selectionMenu.open()`
- `designer.layout.selectionMenu.goTo(id)`
- `designer.engine.objects.reorder(...)`
- `designer.util.state.exportFull()`

## Next step

Continue with the [Examples guide](./examples.md).

## See also

- [Guides index](./index.md)
- [API overview](./api-overview.md)
- [State and persistence](./state-and-persistence.md)
- [Examples](./examples.md)
