Skip to content

Commit

Permalink
feat(design): add sidebar service (#3014)
Browse files Browse the repository at this point in the history
  • Loading branch information
griest024 authored Aug 22, 2024
1 parent d2567fa commit 35eda07
Show file tree
Hide file tree
Showing 4 changed files with 130 additions and 0 deletions.
2 changes: 2 additions & 0 deletions libs/design/sidebar/src/public_api.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
export { DaffSidebarModule } from './sidebar.module';
export * from './service/registration.type';
export * from './service/sidebar.service';
export * from './sidebar-viewport/sidebar-viewport.component';
export * from './sidebar/sidebar.component';
export * from './sidebar-header/sidebar-header.component';
Expand Down
12 changes: 12 additions & 0 deletions libs/design/sidebar/src/service/registration.type.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { Type } from '@angular/core';

/**
* Represents a registration of a sidebar.
* A collection of sidebar components is associated with an ID which can be passed to {@link DaffSidebarService#open}.
*/
export interface DaffSidebarRegistration {
id: string;
header?: Type<unknown>;
body?: Type<unknown>;
footer?: Type<unknown>;
}
63 changes: 63 additions & 0 deletions libs/design/sidebar/src/service/sidebar.service.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
import { Injectable } from '@angular/core';
import { TestBed } from '@angular/core/testing';
import { take } from 'rxjs';

import { DaffSidebarService } from './sidebar.service';

@Injectable({
providedIn: 'root',
})
class TestService extends DaffSidebarService {
constructor() {
super('defaultId');
}
}

describe('@daffodil/design/sidebar | DaffSidebarService', () => {
let service: TestService;

beforeEach(() => {
service = TestBed.inject(TestService);
});

it('should init id to the default ID', (done) => {
service.id$.pipe(
take(1),
).subscribe((id) => {
expect(id).toEqual('defaultId');
done();
});
});

describe('open', () => {
let id: string;

beforeEach(() => {
id = 'id';
service.open(id);
});

it('should set the ID', (done) => {
service.id$.pipe(
take(1),
).subscribe((v) => {
expect(v).toEqual(id);
done();
});
});

it('should set isOpen to true', () => {
expect(service.isOpen()).toBeTrue();
});
});

describe('close', () => {
beforeEach(() => {
service.close();
});

it('should set isOpen to false', () => {
expect(service.isOpen()).toBeFalse();
});
});
});
53 changes: 53 additions & 0 deletions libs/design/sidebar/src/service/sidebar.service.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import {
Signal,
signal,
} from '@angular/core';
import {
BehaviorSubject,
Observable,
} from 'rxjs';

import { DaffSidebarRegistration } from './registration.type';

/**
* A service that stores the open state and ID of the currently opened sidebar.
*
* A default sidebar ID can be passed to the constructor that will be the initial value of `$id`.
*/
export abstract class DaffSidebarService {
protected _id$: BehaviorSubject<DaffSidebarRegistration['id']>;
protected _open = signal(false);

readonly id$: Observable<DaffSidebarRegistration['id']>;

get isOpen(): Signal<boolean> {
return this._open.asReadonly();
}

constructor(
defaultId: DaffSidebarRegistration['id'] = null,
) {
this._id$ = new BehaviorSubject<DaffSidebarRegistration['id']>(defaultId);

this.id$ = this._id$.asObservable();
}

/**
* Opens the specified sidebar.
*
* @param id The optional sidebar ID. If omitted the most recently passed opened sidebar ID will persist (or the default if none was passed).
*/
open(id?: DaffSidebarRegistration['id']) {
if (id) {
this._id$.next(id);
}
this._open.set(true);
};

/**
* Closes the sidebar. Does not clear the ID.
*/
close() {
this._open.set(false);
}
}

0 comments on commit 35eda07

Please sign in to comment.