diff --git a/apps/browser/src/_locales/en/messages.json b/apps/browser/src/_locales/en/messages.json
index bb2483daf3b..3c46085c3d7 100644
--- a/apps/browser/src/_locales/en/messages.json
+++ b/apps/browser/src/_locales/en/messages.json
@@ -5588,6 +5588,9 @@
"showLess": {
"message": "Show less"
},
+ "next": {
+ "message": "Next"
+ },
"moreBreadcrumbs": {
"message": "More breadcrumbs",
"description": "This is used in the context of a breadcrumb navigation, indicating that there are more items in the breadcrumb trail that are not currently displayed."
diff --git a/apps/desktop/src/locales/en/messages.json b/apps/desktop/src/locales/en/messages.json
index c805096189b..1094a8be26f 100644
--- a/apps/desktop/src/locales/en/messages.json
+++ b/apps/desktop/src/locales/en/messages.json
@@ -4080,5 +4080,8 @@
"moreBreadcrumbs": {
"message": "More breadcrumbs",
"description": "This is used in the context of a breadcrumb navigation, indicating that there are more items in the breadcrumb trail that are not currently displayed."
+ },
+ "next": {
+ "message": "Next"
}
}
diff --git a/libs/vault/src/components/carousel/carousel.component.html b/libs/vault/src/components/carousel/carousel.component.html
index 04c6e559056..778b70e15e2 100644
--- a/libs/vault/src/components/carousel/carousel.component.html
+++ b/libs/vault/src/components/carousel/carousel.component.html
@@ -6,18 +6,40 @@
#container
>
-
-
+
+
+
+
+
+
diff --git a/libs/vault/src/components/carousel/carousel.component.spec.ts b/libs/vault/src/components/carousel/carousel.component.spec.ts
index 1409aea0cb2..ebb38576813 100644
--- a/libs/vault/src/components/carousel/carousel.component.spec.ts
+++ b/libs/vault/src/components/carousel/carousel.component.spec.ts
@@ -2,6 +2,8 @@ import { Component } from "@angular/core";
import { ComponentFixture, TestBed } from "@angular/core/testing";
import { By } from "@angular/platform-browser";
+import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
+
import { VaultCarouselSlideComponent } from "./carousel-slide/carousel-slide.component";
import { VaultCarouselComponent } from "./carousel.component";
@@ -33,6 +35,7 @@ describe("VaultCarouselComponent", () => {
beforeEach(async () => {
await TestBed.configureTestingModule({
imports: [VaultCarouselComponent, VaultCarouselSlideComponent],
+ providers: [{ provide: I18nService, useValue: { t: (key: string) => key } }],
}).compileComponents();
});
@@ -48,7 +51,7 @@ describe("VaultCarouselComponent", () => {
it("shows the active slides content", () => {
// Set the second slide as active
- fixture.debugElement.queryAll(By.css("button"))[1].nativeElement.click();
+ fixture.debugElement.queryAll(By.css("button"))[2].nativeElement.click();
fixture.detectChanges();
const heading = fixture.debugElement.query(By.css("h1")).nativeElement;
@@ -63,10 +66,37 @@ describe("VaultCarouselComponent", () => {
it('emits "slideChange" event when slide changes', () => {
jest.spyOn(component.slideChange, "emit");
- const thirdSlideButton = fixture.debugElement.queryAll(By.css("button"))[2];
+ const thirdSlideButton = fixture.debugElement.queryAll(By.css("button"))[3];
thirdSlideButton.nativeElement.click();
expect(component.slideChange.emit).toHaveBeenCalledWith(2);
});
+
+ it('advances to the next slide when the "next" button is pressed', () => {
+ const middleSlideButton = fixture.debugElement.queryAll(By.css("button"))[2];
+ const nextButton = fixture.debugElement.queryAll(By.css("button"))[4];
+
+ middleSlideButton.nativeElement.click();
+
+ jest.spyOn(component.slideChange, "emit");
+
+ nextButton.nativeElement.click();
+
+ expect(component.slideChange.emit).toHaveBeenCalledWith(2);
+ });
+
+ it('advances to the previous slide when the "back" button is pressed', async () => {
+ const middleSlideButton = fixture.debugElement.queryAll(By.css("button"))[2];
+ const backButton = fixture.debugElement.queryAll(By.css("button"))[0];
+
+ middleSlideButton.nativeElement.click();
+ await new Promise((r) => setTimeout(r, 100)); // Give time for the DOM to update.
+
+ jest.spyOn(component.slideChange, "emit");
+
+ backButton.nativeElement.click();
+
+ expect(component.slideChange.emit).toHaveBeenCalledWith(0);
+ });
});
diff --git a/libs/vault/src/components/carousel/carousel.component.ts b/libs/vault/src/components/carousel/carousel.component.ts
index f2d211697df..fdebbebc33b 100644
--- a/libs/vault/src/components/carousel/carousel.component.ts
+++ b/libs/vault/src/components/carousel/carousel.component.ts
@@ -20,7 +20,9 @@ import {
import { takeUntilDestroyed } from "@angular/core/rxjs-interop";
import { take } from "rxjs";
-import { ButtonModule } from "@bitwarden/components";
+import { JslibModule } from "@bitwarden/angular/jslib.module";
+import { ButtonModule, IconButtonModule } from "@bitwarden/components";
+import { I18nPipe } from "@bitwarden/ui-common";
import { VaultCarouselButtonComponent } from "./carousel-button/carousel-button.component";
import { VaultCarouselContentComponent } from "./carousel-content/carousel-content.component";
@@ -32,9 +34,12 @@ import { VaultCarouselSlideComponent } from "./carousel-slide/carousel-slide.com
imports: [
CdkPortalOutlet,
CommonModule,
+ JslibModule,
+ IconButtonModule,
ButtonModule,
VaultCarouselContentComponent,
VaultCarouselButtonComponent,
+ I18nPipe,
],
})
export class VaultCarouselComponent implements AfterViewInit {
@@ -97,6 +102,18 @@ export class VaultCarouselComponent implements AfterViewInit {
this.slideChange.emit(index);
}
+ protected nextSlide() {
+ if (this.selectedIndex < this.slides.length - 1) {
+ this.selectSlide(this.selectedIndex + 1);
+ }
+ }
+
+ protected prevSlide() {
+ if (this.selectedIndex > 0) {
+ this.selectSlide(this.selectedIndex - 1);
+ }
+ }
+
async ngAfterViewInit() {
this.keyManager = new FocusKeyManager(this.carouselButtons)
.withHorizontalOrientation("ltr")
diff --git a/libs/vault/src/components/carousel/carousel.stories.ts b/libs/vault/src/components/carousel/carousel.stories.ts
index 521a561a19f..1e393779a6a 100644
--- a/libs/vault/src/components/carousel/carousel.stories.ts
+++ b/libs/vault/src/components/carousel/carousel.stories.ts
@@ -1,5 +1,6 @@
import { Meta, moduleMetadata, StoryObj } from "@storybook/angular";
+import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
import { ButtonComponent, TypographyModule } from "@bitwarden/components";
import { VaultCarouselSlideComponent } from "./carousel-slide/carousel-slide.component";
@@ -11,6 +12,7 @@ export default {
decorators: [
moduleMetadata({
imports: [VaultCarouselSlideComponent, TypographyModule, ButtonComponent],
+ providers: [{ provide: I18nService, useValue: { t: (key: string) => key } }],
}),
],
} as Meta;