Integration Slots

Slots are used to open room for other Aspects to plugin into your Aspect functionallity. Slots are declared in your provider and then exposed by the Aspect API.

Slots can be automatically generated upon creation of an aspect, use the following command to generate an Aspect with the needed slots:

bit create aspect people
CopiedCopy

If you are looking to use a slot exposed by another aspect, head to the using Aspect dependencies section.

Create the Slot types

Create a file to create the Slot type you are accepting and its Slot registry. This example shows a badge.ts file in an Aspect declering it:

import type { SlotRegistry } from '@bitdev/harmony.harmony';

export interface Badge {
  /**
   * name of the badge.
   */
  name: string;

  /**
   * component to render as a badge.
   */
  component: ComponentType;
};

// define the slot registry type. 
export type BadgeSlot = SlotRegistry<Badge[]>;
CopiedCopy

Declare the slot

Obtain a slot registry of your type by declaring it in the slot in the provider function:

import type { Badge, BadgeSlot } from './badge.js';

export class PeopleBrowser {
  constructor(
    private badgeSlot: BadgeSlot
  ) {}

  // declare the slot in the provider to get a slot instance.
  static async provider(deps, config, [badgeSlot]: [BadgeSlot]) {
    const people = new PeopleBrowser(badgeSlot);
    return people;
  }
}
CopiedCopy

The example above demonstrating declaring the slot in the Browser runtime. Slots and their values are specific to a each runtime and slot values are not shared.

Expose the slot API

Expose an API for plugging in new values to your slot registry, by adding methods to your aspect runtime. Common APIs to expose are register, list or get

import type { Badge, BadgeSlot } from './badge.js';

export class PeopleBrowser {
  constructor(
    private badgeSlot: BadgeSlot
  ) {}

  /** 
   * API for aspects to plugin their user badge.
   */
  registerUserBadge(badges: Badge[]) {
    this.badgeSlot.register(badges); // an API for registering new values to the slot.
    return this; // returning `this` is useful for chaining, but no required.
  }

  /**
   * list all badges plugged-in by other aspects.
   */
  listBadges() {
    return this.badgeSlot.flatValues(); // provide access to registered slot values. can be private as needed.
  }

  static async provider(deps, config, [badgeSlot]: [BadgeSlot]) {
    const people = new PeopleBrowser(badgeSlot);
    return people;
  }
}
CopiedCopy

Using the Slot Registry

The slot registry to store and map values registered to the slot by aspects. They are keyed by the Aspect ID and includes their corresponding values.

Slots are storing values in Map which you can access through the registry map API directly.

Register values to Aspect slots

Expose an API allowing Aspects to register to your slot:

import type { Badge, BadgeSlot } from './badge.js';

export class PeopleBrowser {
  constructor(
    private badgeSlot: BadgeSlot
  ) {}

  /** 
   * API for aspects to plugin their user badge.
   */
  registerUserBadge(badges: Badge[]) {
    this.badgeSlot.register(badges); // an API for registering new values to the slot.
    return this; // returning `this` is useful for chaining, but no required.
  }

  static async provider(deps, config, [badgeSlot]: [BadgeSlot]) {
    const people = new PeopleBrowser(badgeSlot);
    return people;
  }
}
CopiedCopy

List slot values

Use the values() or flatValues() to list all values registerd to your slot. flatValues is needed when an array was used in the slot type.

import type { Badge, BadgeSlot } from './badge.js';

export class PeopleBrowser {
  constructor(
    private badgeSlot: BadgeSlot
  ) {}

  /**
   * list all badges plugged-in by other aspects.
   */
  listBadges() {
    return this.badgeSlot.flatValues();
  }

  static async provider(deps, config, [badgeSlot]: [BadgeSlot]) {
    const people = new PeopleBrowser(badgeSlot);
    return people;
  }
}
CopiedCopy

Sort values by weight

A common problem is sorting slot values. A common way to do this is using a weight property on your slot type. If you did you can use the slot registery to list and sort the values:

import type { Badge, BadgeSlot } from './badge.js';

export class PeopleBrowser {
  constructor(
    private badgeSlot: BadgeSlot
  ) {}

  /**
   * list all badges by their weight. 
   */
  listBadges() {
    return this.badgeSlot.sortByWeight();
  }

  static async provider(deps, config, [badgeSlot]: [BadgeSlot]) {
    const people = new PeopleBrowser(badgeSlot);
    return people;
  }
}
CopiedCopy

Remember to support the weight key in your slot type to prior to using this method.

Access items using a name of a custom key

You can access an item in slots even when registering an array of them using custom keys. By default, the name key is used to search for the requested item.

import type { Badge, BadgeSlot } from './badge.js';

export class PeopleBrowser {
  constructor(
    private badgeSlot: BadgeSlot
  ) {}

  /**
   * list all badges by their weight. 
   */
  listBadges(name: string) {
    return this.badgeSlot.getByName(name);
  }

  static async provider(deps, config, [badgeSlot]: [BadgeSlot]) {
    const people = new PeopleBrowser(badgeSlot);
    return people;
  }
}
CopiedCopy