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
If you are looking to use a slot exposed by another aspect, head to the using Aspect dependencies section.
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[]>;
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; } }
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 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; } }
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.
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; } }
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; } }
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; } }
Remember to support the weight
key in your slot type to prior to using this method.
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; } }