Skip to content

Latest commit

 

History

History

README.md

@stainless-code/angular-layers

Layers

Modals are just async functions you forgot to await.

The Angular adapter for Layers — open any layer from anywhere and await a typed result. State coordination, not UI ownership: Layers owns the stack/keys/transitions/await contract; you own rendering, focus, portals, and a11y.

bundle size

Experimental — the API may change between minor releases. Pin your version.

Install

bun add @stainless-code/angular-layers

Peer: @angular/core (>=17.0.0)

Taste

import { Component, ViewContainerRef, inject } from "@angular/core";
import {
  injectLayer,
  layerOptions,
  provideLayerClient,
  renderStack,
  type LayerComponentProps,
} from "@stainless-code/angular-layers";

@Component({
  selector: "confirm-dialog",
  template: `
    <div role="dialog">
      <h2>{{ payload.title }}</h2>
      <button type="button" (click)="call.end(true)">Yes</button>
      <button type="button" (click)="call.end(false)">No</button>
    </div>
  `,
})
class ConfirmDialogComponent {
  call!: LayerComponentProps<{ title: string }, boolean>["call"];
  payload!: { title: string };
}

export const confirm = layerOptions({
  stack: "confirm",
  key: ["confirm", "remove"],
  component: ConfirmDialogComponent,
});

@Component({
  selector: "app-root",
  standalone: true,
  providers: [provideLayerClient()],
  template: `<ng-container #outlet />`,
})
export class AppComponent {
  private vcr = inject(ViewContainerRef);
  constructor() {
    renderStack(this.vcr, "confirm");
  }
}

@Component({
  selector: "remove-btn",
  standalone: true,
  template: `<button type="button" (click)="remove()">Remove</button>`,
})
export class RemoveButtonComponent {
  private readonly c = injectLayer(confirm);

  async remove() {
    const ok = await this.c.open({
      title: "Remove?",
      message: "Sure?",
    });
    if (ok) deleteItem();
  }
}

Docs

Source on GitHub