Skip to content

Declarations ​

The APIs on this page are imported from @makoojs/core. inject(), injectEach(), and listen() only create declaration objects; they don't access the DOM, register, or start anything. Declarations are validated and run only after they are passed to core.apply().

inject() ​

Declares a component: mounts a framework component into an element of the host page.

ts
function inject<TComponent = unknown, TProps = unknown>(
  input: MakooComponentInput<TComponent, TProps>
): MakooComponentDeclaration<TComponent, TProps>;
ts
import { inject, listen } from '@makoojs/core';
import Toolbar from './Toolbar.vue';

const toolbar = inject({
  name: 'toolbar',
  injectAt: '#header',
  adapter: 'vue',
  component: Toolbar,
  props: { compact: true },
  timeout: 30000,
  reinject: true,
  listeners: [
    listen({ name: 'search-submit', listenAt: '#search', type: 'submit', callback: onSubmit })
  ]
});

MakooComponentInput ​

FieldTypeDefaultDescription
namestringRequiredInjection name, unique among the top-level injections of the same Core instance
injectAtstringRequiredCSS selector of the mount target
adapterstringRequiredName of a registered adapter, such as 'vue' or 'react'
componentTComponentRequiredThe framework component to mount
propsTPropsundefinedProps passed as-is to the root component
timeoutnumber15000Wait budget for each search for the mount target, in milliseconds
reinjectbooleanfalseWhether to search and mount again after the mount target or component container becomes invalid; also determines whether attached listeners can recover locally
listenersArray of listen() declarations[]Attached listeners, started and stopped together with the component

Field Constraints ​

  • Attached listener names are unique within the owning component and may match top-level injection names.
  • Attached listeners can't set reinject; they use the component's reinject.

When an attached listener sets reinject, apply() throws MAKOO_DECLARATION_INVALID; duplicate attached listener names throw MAKOO_INJECTION_NAME_CONFLICT.

Mount Position ​

Core uses the first element matching injectAt as the mount target, appends a div at its end as the component container, and mounts the component in that container. When the component stops, Core unmounts the component and removes the container, without touching the mount target's original content.

Makoo doesn't copy or freeze props. Vue shallow-copies root props, so for the component to see outside changes, pass a reactive() or ref() as a property of props, for example props: { state }.

injectEach() ​

Declares an Each Injection: mounts the same framework component on every element matching injectAt, including elements that match later.

ts
function injectEach<TComponent = unknown, TProps = unknown>(
  input: MakooComponentEachInput<TComponent, TProps>
): MakooComponentEachDeclaration<TComponent, TProps>;
ts
import { injectEach } from '@makoojs/core';
import Badge from './Badge.vue';

const badges = injectEach({
  name: 'badges',
  injectAt: '.comment .author',
  adapter: 'vue',
  component: Badge,
  props: { compact: true }
});

MakooComponentEachInput ​

FieldTypeDefaultDescription
namestringRequiredInjection name, unique among the top-level injections of the same Core instance
injectAtstringRequiredCSS selector; every matching element gets its own Child Injection
adapterstringRequiredName of a registered adapter, such as 'vue' or 'react'
componentTComponentRequiredThe framework component to mount on each element
propsTPropsundefinedProps passed as-is to every mounted component; all of them receive the same object

injectEach() has no timeout, reinject, or listeners.

Matching and Mounting ​

  • On start, every current match is mounted in document order. While running, elements that start matching later are mounted too, until the Each Injection is stopped or removed.
  • There is no wait timeout: when nothing matches, the status stays collecting instead of failing.
  • Each element gets its own component container at its end, exactly like inject(). An element is mounted at most once per run.
  • A Child Injection that is stopped, removed, or fails is not remounted on the same element until the Each Injection is stopped and started again. When its element leaves the page, the Child ends with failed; if that element or a new matching element is inserted later, a new Child is mounted.
  • A Child Injection's failure doesn't affect the Each Injection or other Children.

To control the Children, see injection() and Each Injection Status.

listen() ​

Declares a host listener: binds a native event on an element of the host page.

ts
function listen(input: MakooListenerInput): MakooListenerDeclaration;
ts
import { listen } from '@makoojs/core';

const escape = listen({
  name: 'escape',
  listenAt: 'body',
  type: 'keydown',
  capture: true,
  callback(event) {
    if (event instanceof KeyboardEvent && event.key === 'Escape') console.log('Escape');
  }
});

Putting the return value directly into apply() makes it a standalone listener; putting it into inject()'s listeners makes it an attached listener.

MakooListenerInput ​

FieldTypeDefaultDescription
namestringRequiredInjection name; attached listeners only need to be unique within the owning component
listenAtstringRequiredCSS selector of the listener target
typestringRequiredEvent type, such as 'click'
callback(this: Element, event: Event) => unknownRequiredEvent handler
capturebooleanfalseWhether to fire in the capture phase
timeoutnumber15000Wait budget for each search for the listener target, in milliseconds
reinjectbooleanfalseWhether to search and bind again after the listener target becomes invalid; only standalone listeners can set it

Event Handler ​

  • The listener is bound to the first element matching listenAt. this is that element, and event is the native event object.
  • When the callback throws synchronously or returns a rejected Promise, Core prints a MAKOO_LISTENER_CALLBACK_FAILED error and the listener stays bound. Standalone listeners also write this error to lastError.
  • The listener target can only be read through this when the callback is a regular function; with arrow functions, use event.currentTarget.

Declaration Types ​

ts
type MakooComponentDeclaration<TComponent = unknown, TProps = unknown> = Readonly<
  MakooComponentInput<TComponent, TProps> & { kind: 'component' }
>;

type MakooComponentEachDeclaration<TComponent = unknown, TProps = unknown> = Readonly<
  MakooComponentEachInput<TComponent, TProps> & { kind: 'component-each' }
>;

type MakooListenerDeclaration = Readonly<MakooListenerInput & { kind: 'listener' }>;

MakooInjectionDeclaration ​

The element type of the array accepted by apply():

ts
type MakooInjectionDeclaration =
  | MakooListenerDeclaration
  | MakooComponentDeclaration
  | MakooComponentEachDeclaration;

Declarations are fixed at apply() time; modifying the original object afterwards doesn't affect registered injections. To change selectors, timeouts, or other settings, remove() first and then apply() the new declaration.