[CL-146] Add kitchen sink story (#8310)
This commit is contained in:
parent
f70639d792
commit
0f375c3a0e
|
@ -0,0 +1,176 @@
|
|||
import { Component } from "@angular/core";
|
||||
import { FormBuilder, Validators } from "@angular/forms";
|
||||
|
||||
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
|
||||
|
||||
import { DialogService } from "../../../dialog";
|
||||
import { I18nMockService } from "../../../utils/i18n-mock.service";
|
||||
import { KitchenSinkSharedModule } from "../kitchen-sink-shared.module";
|
||||
|
||||
@Component({
|
||||
standalone: true,
|
||||
selector: "bit-kitchen-sink-form",
|
||||
imports: [KitchenSinkSharedModule],
|
||||
providers: [
|
||||
DialogService,
|
||||
{
|
||||
provide: I18nService,
|
||||
useFactory: () => {
|
||||
return new I18nMockService({
|
||||
close: "Close",
|
||||
checkboxRequired: "Option is required",
|
||||
fieldsNeedAttention: "__$1__ field(s) above need your attention.",
|
||||
inputEmail: "Input is not an email-address.",
|
||||
inputMaxValue: (max) => `Input value must not exceed ${max}.`,
|
||||
inputMinValue: (min) => `Input value must be at least ${min}.`,
|
||||
inputRequired: "Input is required.",
|
||||
multiSelectClearAll: "Clear all",
|
||||
multiSelectLoading: "Retrieving options...",
|
||||
multiSelectNotFound: "No items found",
|
||||
multiSelectPlaceholder: "-- Type to Filter --",
|
||||
required: "required",
|
||||
selectPlaceholder: "-- Select --",
|
||||
toggleVisibility: "Toggle visibility",
|
||||
});
|
||||
},
|
||||
},
|
||||
],
|
||||
template: `
|
||||
<form [formGroup]="formObj" [bitSubmit]="submit">
|
||||
<div class="tw-mb-6">
|
||||
<bit-progress [barWidth]="50"></bit-progress>
|
||||
</div>
|
||||
|
||||
<bit-form-field>
|
||||
<bit-label>Your favorite feature</bit-label>
|
||||
<input bitInput formControlName="favFeature" />
|
||||
</bit-form-field>
|
||||
|
||||
<bit-form-field>
|
||||
<bit-label>Your favorite color</bit-label>
|
||||
<bit-select formControlName="favColor">
|
||||
<bit-option
|
||||
*ngFor="let color of colors"
|
||||
[value]="color.value"
|
||||
[label]="color.name"
|
||||
></bit-option>
|
||||
</bit-select>
|
||||
</bit-form-field>
|
||||
|
||||
<bit-form-field>
|
||||
<bit-label>Your top 3 worst passwords</bit-label>
|
||||
<bit-multi-select formControlName="topWorstPasswords" [baseItems]="worstPasswords">
|
||||
</bit-multi-select>
|
||||
</bit-form-field>
|
||||
|
||||
<bit-form-field>
|
||||
<bit-label>How many passwords do you have?</bit-label>
|
||||
<input bitInput type="number" formControlName="numPasswords" min="0" max="150" />
|
||||
</bit-form-field>
|
||||
|
||||
<bit-form-field>
|
||||
<bit-label>
|
||||
A random password
|
||||
<button
|
||||
bitLink
|
||||
linkType="primary"
|
||||
[bitPopoverTriggerFor]="myPopover"
|
||||
#triggerRef="popoverTrigger"
|
||||
>
|
||||
<i class="bwi bwi-question-circle"></i>
|
||||
</button>
|
||||
</bit-label>
|
||||
<input bitInput type="password" formControlName="password" />
|
||||
<button type="button" bitIconButton bitSuffix bitPasswordInputToggle></button>
|
||||
</bit-form-field>
|
||||
|
||||
<div class="tw-mb-6">
|
||||
<span bitTypography="body1" class="tw-text-main">
|
||||
An example of a strong password:
|
||||
</span>
|
||||
|
||||
<bit-color-password
|
||||
class="tw-text-base"
|
||||
[password]="'Wq$Jk😀7j DX#rS5Sdi!z'"
|
||||
[showCount]="true"
|
||||
></bit-color-password>
|
||||
</div>
|
||||
|
||||
<bit-form-control>
|
||||
<bit-label>Check if you love security</bit-label>
|
||||
<input type="checkbox" bitCheckbox formControlName="loveSecurity" />
|
||||
<bit-hint>Hint: the correct answer is yes!</bit-hint>
|
||||
</bit-form-control>
|
||||
|
||||
<bit-radio-group formControlName="current">
|
||||
<bit-label>Do you currently use Bitwarden?</bit-label>
|
||||
<bit-radio-button value="yes">
|
||||
<bit-label>Yes</bit-label>
|
||||
</bit-radio-button>
|
||||
<bit-radio-button value="no">
|
||||
<bit-label>No</bit-label>
|
||||
</bit-radio-button>
|
||||
</bit-radio-group>
|
||||
|
||||
<button bitButton bitFormButton buttonType="primary" type="submit">Submit</button>
|
||||
<bit-error-summary [formGroup]="formObj"></bit-error-summary>
|
||||
|
||||
<bit-popover [title]="'Password help'" #myPopover>
|
||||
<div>A strong password has the following:</div>
|
||||
<ul class="tw-mt-2 tw-mb-0 tw-pl-4">
|
||||
<li>Letters</li>
|
||||
<li>Numbers</li>
|
||||
<li>Special characters</li>
|
||||
</ul>
|
||||
</bit-popover>
|
||||
</form>
|
||||
`,
|
||||
})
|
||||
export class KitchenSinkForm {
|
||||
constructor(
|
||||
public dialogService: DialogService,
|
||||
public formBuilder: FormBuilder,
|
||||
) {}
|
||||
|
||||
formObj = this.formBuilder.group({
|
||||
favFeature: ["", [Validators.required]],
|
||||
favColor: [undefined as string | undefined, [Validators.required]],
|
||||
topWorstPasswords: [undefined as string | undefined],
|
||||
loveSecurity: [false, [Validators.requiredTrue]],
|
||||
current: ["yes"],
|
||||
numPasswords: [null, [Validators.min(0), Validators.max(150)]],
|
||||
password: ["", [Validators.required]],
|
||||
});
|
||||
|
||||
submit = async () => {
|
||||
await this.dialogService.openSimpleDialog({
|
||||
title: "Confirm",
|
||||
content: "Are you sure you want to submit?",
|
||||
type: "primary",
|
||||
acceptButtonText: "Yes",
|
||||
cancelButtonText: "No",
|
||||
acceptAction: async () => this.acceptDialog(),
|
||||
});
|
||||
};
|
||||
|
||||
acceptDialog() {
|
||||
this.formObj.markAllAsTouched();
|
||||
this.dialogService.closeAll();
|
||||
}
|
||||
|
||||
colors = [
|
||||
{ value: "blue", name: "Blue" },
|
||||
{ value: "white", name: "White" },
|
||||
{ value: "gray", name: "Gray" },
|
||||
];
|
||||
|
||||
worstPasswords = [
|
||||
{ id: "1", listName: "1234", labelName: "1234" },
|
||||
{ id: "2", listName: "admin", labelName: "admin" },
|
||||
{ id: "3", listName: "password", labelName: "password" },
|
||||
{ id: "4", listName: "querty", labelName: "querty" },
|
||||
{ id: "5", listName: "letmein", labelName: "letmein" },
|
||||
{ id: "6", listName: "trustno1", labelName: "trustno1" },
|
||||
{ id: "7", listName: "1qaz2wsx", labelName: "1qaz2wsx" },
|
||||
];
|
||||
}
|
|
@ -0,0 +1,117 @@
|
|||
import { DialogRef } from "@angular/cdk/dialog";
|
||||
import { Component } from "@angular/core";
|
||||
|
||||
import { DialogService } from "../../../dialog";
|
||||
import { KitchenSinkSharedModule } from "../kitchen-sink-shared.module";
|
||||
|
||||
import { KitchenSinkForm } from "./kitchen-sink-form.component";
|
||||
import { KitchenSinkTable } from "./kitchen-sink-table.component";
|
||||
import { KitchenSinkToggleList } from "./kitchen-sink-toggle-list.component";
|
||||
|
||||
@Component({
|
||||
standalone: true,
|
||||
imports: [KitchenSinkSharedModule],
|
||||
template: `
|
||||
<bit-dialog title="Dialog Title" dialogSize="large">
|
||||
<span bitDialogContent> Dialog body text goes here. </span>
|
||||
<ng-container bitDialogFooter>
|
||||
<button bitButton buttonType="primary" (click)="dialogRef.close()">OK</button>
|
||||
<button bitButton buttonType="secondary" bitDialogClose>Cancel</button>
|
||||
</ng-container>
|
||||
</bit-dialog>
|
||||
`,
|
||||
})
|
||||
class KitchenSinkDialog {
|
||||
constructor(public dialogRef: DialogRef) {}
|
||||
}
|
||||
|
||||
@Component({
|
||||
standalone: true,
|
||||
selector: "bit-tab-main",
|
||||
imports: [
|
||||
KitchenSinkSharedModule,
|
||||
KitchenSinkTable,
|
||||
KitchenSinkToggleList,
|
||||
KitchenSinkForm,
|
||||
KitchenSinkDialog,
|
||||
],
|
||||
template: `
|
||||
<bit-banner bannerType="info" class="-tw-m-6 tw-flex tw-flex-col tw-pb-6">
|
||||
Kitchen Sink test zone
|
||||
</bit-banner>
|
||||
|
||||
<p class="tw-mt-4">
|
||||
<bit-breadcrumbs>
|
||||
<bit-breadcrumb *ngFor="let item of navItems" [icon]="item.icon" [route]="[item.route]">
|
||||
{{ item.name }}
|
||||
</bit-breadcrumb>
|
||||
</bit-breadcrumbs>
|
||||
</p>
|
||||
|
||||
<bit-callout type="info" title="About the Kitchen Sink">
|
||||
<p bitTypography="body1">
|
||||
The purpose of this story is to compose together all of our components. When snapshot tests
|
||||
run, we'll be able to spot-check visual changes in a more app-like environment than just the
|
||||
isolated stories. The stories for the Kitchen Sink exist to be tested by the Chromatic UI
|
||||
tests.
|
||||
</p>
|
||||
|
||||
<p bitTypography="body1">
|
||||
NOTE: These stories will treat "Light & Dark" mode as "Light" mode. This is done to avoid a
|
||||
bug with the way that we render the same component twice in the same iframe and how that
|
||||
interacts with the <code>router-outlet</code>.
|
||||
</p>
|
||||
</bit-callout>
|
||||
|
||||
<div class="tw-mb-6 tw-mt-6">
|
||||
<h1 bitTypography="h1" class="tw-text-main">
|
||||
Bitwarden <bit-avatar text="Bit Warden"></bit-avatar>
|
||||
</h1>
|
||||
<a bitLink linkType="primary" href="#">Learn more</a>
|
||||
</div>
|
||||
|
||||
<bit-tab-group label="Main content tabs" class="tw-text-main">
|
||||
<bit-tab label="Evaluation">
|
||||
<bit-section>
|
||||
<h2 bitTypography="h2" class="tw-text-main tw-mb-6">About</h2>
|
||||
<bit-kitchen-sink-table></bit-kitchen-sink-table>
|
||||
|
||||
<button bitButton (click)="openDefaultDialog()">Open Dialog</button>
|
||||
</bit-section>
|
||||
<bit-section>
|
||||
<h2 bitTypography="h2" class="tw-text-main tw-mb-6">Companies using Bitwarden</h2>
|
||||
<bit-kitchen-sink-toggle-list></bit-kitchen-sink-toggle-list>
|
||||
</bit-section>
|
||||
<bit-section>
|
||||
<h2 bitTypography="h2" class="tw-text-main tw-mb-6">Survey</h2>
|
||||
<bit-kitchen-sink-form></bit-kitchen-sink-form>
|
||||
</bit-section>
|
||||
</bit-tab>
|
||||
|
||||
<bit-tab label="Empty tab" data-testid="empty-tab">
|
||||
<bit-section>
|
||||
<bit-no-items class="tw-text-main">
|
||||
<ng-container slot="title">This tab is empty</ng-container>
|
||||
<ng-container slot="description">
|
||||
<p bitTypography="body2">Try searching for what you are looking for:</p>
|
||||
<bit-search></bit-search>
|
||||
<p bitTypography="helper">Note that the search bar is not functional</p>
|
||||
</ng-container>
|
||||
</bit-no-items>
|
||||
</bit-section>
|
||||
</bit-tab>
|
||||
</bit-tab-group>
|
||||
`,
|
||||
})
|
||||
export class KitchenSinkMainComponent {
|
||||
constructor(public dialogService: DialogService) {}
|
||||
|
||||
openDefaultDialog() {
|
||||
this.dialogService.open(KitchenSinkDialog);
|
||||
}
|
||||
|
||||
navItems = [
|
||||
{ icon: "bwi-collection", name: "Password Managers", route: "/" },
|
||||
{ icon: "bwi-collection", name: "Favorites", route: "/" },
|
||||
];
|
||||
}
|
|
@ -0,0 +1,49 @@
|
|||
import { Component } from "@angular/core";
|
||||
|
||||
import { KitchenSinkSharedModule } from "../kitchen-sink-shared.module";
|
||||
|
||||
@Component({
|
||||
standalone: true,
|
||||
selector: "bit-kitchen-sink-table",
|
||||
imports: [KitchenSinkSharedModule],
|
||||
template: `
|
||||
<bit-table>
|
||||
<ng-container header>
|
||||
<tr>
|
||||
<th bitCell>Product</th>
|
||||
<th bitCell>User</th>
|
||||
<th bitCell>Options</th>
|
||||
</tr>
|
||||
</ng-container>
|
||||
<ng-template body>
|
||||
<tr bitRow>
|
||||
<td bitCell>Password Manager</td>
|
||||
<td bitCell>Everyone</td>
|
||||
<td bitCell>
|
||||
<button bitIconButton="bwi-ellipsis-v" [bitMenuTriggerFor]="menu1"></button>
|
||||
<bit-menu #menu1>
|
||||
<a href="#" bitMenuItem>Anchor link</a>
|
||||
<a href="#" bitMenuItem>Another link</a>
|
||||
<bit-menu-divider></bit-menu-divider>
|
||||
<button type="button" bitMenuItem>Button after divider</button>
|
||||
</bit-menu>
|
||||
</td>
|
||||
</tr>
|
||||
<tr bitRow>
|
||||
<td bitCell>Secrets Manager</td>
|
||||
<td bitCell>Developers</td>
|
||||
<td bitCell>
|
||||
<button bitIconButton="bwi-ellipsis-v" [bitMenuTriggerFor]="menu2"></button>
|
||||
<bit-menu #menu2>
|
||||
<a href="#" bitMenuItem>Anchor link</a>
|
||||
<a href="#" bitMenuItem>Another link</a>
|
||||
<bit-menu-divider></bit-menu-divider>
|
||||
<button type="button" bitMenuItem>Button after divider</button>
|
||||
</bit-menu>
|
||||
</td>
|
||||
</tr>
|
||||
</ng-template>
|
||||
</bit-table>
|
||||
`,
|
||||
})
|
||||
export class KitchenSinkTable {}
|
|
@ -0,0 +1,34 @@
|
|||
import { Component } from "@angular/core";
|
||||
|
||||
import { KitchenSinkSharedModule } from "../kitchen-sink-shared.module";
|
||||
|
||||
@Component({
|
||||
standalone: true,
|
||||
selector: "bit-kitchen-sink-toggle-list",
|
||||
imports: [KitchenSinkSharedModule],
|
||||
template: `
|
||||
<div class="tw-mt-6 tw-mb-6">
|
||||
<bit-toggle-group [(selected)]="selectedToggle" aria-label="Company list filter">
|
||||
<bit-toggle value="all"> All <span bitBadge variant="info">3</span> </bit-toggle>
|
||||
|
||||
<bit-toggle value="large"> Enterprise <span bitBadge variant="info">2</span> </bit-toggle>
|
||||
|
||||
<bit-toggle value="small"> Mid-sized <span bitBadge variant="info">1</span> </bit-toggle>
|
||||
</bit-toggle-group>
|
||||
</div>
|
||||
<ul *ngFor="let company of companyList">
|
||||
<li *ngIf="company.size === selectedToggle || selectedToggle === 'all'">
|
||||
{{ company.name }}
|
||||
</li>
|
||||
</ul>
|
||||
`,
|
||||
})
|
||||
export class KitchenSinkToggleList {
|
||||
selectedToggle: "all" | "large" | "small" = "all";
|
||||
|
||||
companyList = [
|
||||
{ name: "A large enterprise company", size: "large" },
|
||||
{ name: "Another enterprise company", size: "large" },
|
||||
{ name: "A smaller company", size: "small" },
|
||||
];
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
export * from "./kitchen-sink.stories";
|
|
@ -0,0 +1,114 @@
|
|||
import { CommonModule } from "@angular/common";
|
||||
import { NgModule } from "@angular/core";
|
||||
import { FormsModule, ReactiveFormsModule } from "@angular/forms";
|
||||
import { RouterModule } from "@angular/router";
|
||||
|
||||
import { AsyncActionsModule } from "../../async-actions";
|
||||
import { AvatarModule } from "../../avatar";
|
||||
import { BadgeModule } from "../../badge";
|
||||
import { BannerModule } from "../../banner";
|
||||
import { BreadcrumbsModule } from "../../breadcrumbs";
|
||||
import { ButtonModule } from "../../button";
|
||||
import { CalloutModule } from "../../callout";
|
||||
import { CheckboxModule } from "../../checkbox";
|
||||
import { ColorPasswordModule } from "../../color-password";
|
||||
import { DialogModule } from "../../dialog";
|
||||
import { FormControlModule } from "../../form-control";
|
||||
import { FormFieldModule } from "../../form-field";
|
||||
import { IconModule } from "../../icon";
|
||||
import { IconButtonModule } from "../../icon-button";
|
||||
import { InputModule } from "../../input";
|
||||
import { LayoutComponent } from "../../layout";
|
||||
import { LinkModule } from "../../link";
|
||||
import { MenuModule } from "../../menu";
|
||||
import { NavigationModule } from "../../navigation";
|
||||
import { NoItemsModule } from "../../no-items";
|
||||
import { PopoverModule } from "../../popover";
|
||||
import { ProgressModule } from "../../progress";
|
||||
import { RadioButtonModule } from "../../radio-button";
|
||||
import { SearchModule } from "../../search";
|
||||
import { SectionComponent } from "../../section";
|
||||
import { SelectModule } from "../../select";
|
||||
import { SharedModule } from "../../shared";
|
||||
import { TableModule } from "../../table";
|
||||
import { TabsModule } from "../../tabs";
|
||||
import { ToggleGroupModule } from "../../toggle-group";
|
||||
import { TypographyModule } from "../../typography";
|
||||
|
||||
@NgModule({
|
||||
imports: [
|
||||
AsyncActionsModule,
|
||||
AvatarModule,
|
||||
BadgeModule,
|
||||
BannerModule,
|
||||
BreadcrumbsModule,
|
||||
ButtonModule,
|
||||
CalloutModule,
|
||||
CheckboxModule,
|
||||
ColorPasswordModule,
|
||||
CommonModule,
|
||||
DialogModule,
|
||||
FormControlModule,
|
||||
FormFieldModule,
|
||||
FormsModule,
|
||||
IconButtonModule,
|
||||
IconModule,
|
||||
InputModule,
|
||||
LayoutComponent,
|
||||
LinkModule,
|
||||
MenuModule,
|
||||
NavigationModule,
|
||||
NoItemsModule,
|
||||
PopoverModule,
|
||||
ProgressModule,
|
||||
RadioButtonModule,
|
||||
ReactiveFormsModule,
|
||||
RouterModule,
|
||||
SearchModule,
|
||||
SectionComponent,
|
||||
SelectModule,
|
||||
SharedModule,
|
||||
TableModule,
|
||||
TabsModule,
|
||||
ToggleGroupModule,
|
||||
TypographyModule,
|
||||
],
|
||||
exports: [
|
||||
AsyncActionsModule,
|
||||
AvatarModule,
|
||||
BadgeModule,
|
||||
BannerModule,
|
||||
BreadcrumbsModule,
|
||||
ButtonModule,
|
||||
CalloutModule,
|
||||
CheckboxModule,
|
||||
ColorPasswordModule,
|
||||
CommonModule,
|
||||
DialogModule,
|
||||
FormControlModule,
|
||||
FormFieldModule,
|
||||
FormsModule,
|
||||
IconButtonModule,
|
||||
IconModule,
|
||||
InputModule,
|
||||
LayoutComponent,
|
||||
LinkModule,
|
||||
MenuModule,
|
||||
NavigationModule,
|
||||
NoItemsModule,
|
||||
PopoverModule,
|
||||
ProgressModule,
|
||||
RadioButtonModule,
|
||||
ReactiveFormsModule,
|
||||
RouterModule,
|
||||
SearchModule,
|
||||
SectionComponent,
|
||||
SelectModule,
|
||||
SharedModule,
|
||||
TableModule,
|
||||
TabsModule,
|
||||
ToggleGroupModule,
|
||||
TypographyModule,
|
||||
],
|
||||
})
|
||||
export class KitchenSinkSharedModule {}
|
|
@ -0,0 +1,15 @@
|
|||
import { Meta, Story } from "@storybook/addon-docs";
|
||||
|
||||
import * as stories from "./kitchen-sink.stories";
|
||||
|
||||
<Meta of={stories} />
|
||||
|
||||
# Kitchen Sink
|
||||
|
||||
The purpose of this story is to compose together all of our components. When snapshot tests run,
|
||||
we'll be able to spot-check visual changes in a more app-like environment than just the isolated
|
||||
stories. The stories for the Kitchen Sink exist to be tested by the Chromatic UI tests.
|
||||
|
||||
NOTE: These stories will treat "Light & Dark" mode as "Light" mode. This is done to avoid a bug with
|
||||
the way that we render the same component twice in the same iframe and how that interacts with the
|
||||
`router-outlet`.
|
|
@ -0,0 +1,172 @@
|
|||
import { importProvidersFrom } from "@angular/core";
|
||||
import { provideNoopAnimations } from "@angular/platform-browser/animations";
|
||||
import { RouterModule } from "@angular/router";
|
||||
import {
|
||||
Meta,
|
||||
StoryObj,
|
||||
applicationConfig,
|
||||
componentWrapperDecorator,
|
||||
moduleMetadata,
|
||||
} from "@storybook/angular";
|
||||
import {
|
||||
userEvent,
|
||||
getAllByRole,
|
||||
getByRole,
|
||||
getByLabelText,
|
||||
fireEvent,
|
||||
} from "@storybook/testing-library";
|
||||
|
||||
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
|
||||
|
||||
import { DialogService } from "../../dialog";
|
||||
import { LayoutComponent } from "../../layout";
|
||||
import { I18nMockService } from "../../utils/i18n-mock.service";
|
||||
|
||||
import { KitchenSinkForm } from "./components/kitchen-sink-form.component";
|
||||
import { KitchenSinkMainComponent } from "./components/kitchen-sink-main.component";
|
||||
import { KitchenSinkTable } from "./components/kitchen-sink-table.component";
|
||||
import { KitchenSinkToggleList } from "./components/kitchen-sink-toggle-list.component";
|
||||
import { KitchenSinkSharedModule } from "./kitchen-sink-shared.module";
|
||||
|
||||
export default {
|
||||
title: "Documentation / Kitchen Sink",
|
||||
component: LayoutComponent,
|
||||
decorators: [
|
||||
componentWrapperDecorator(
|
||||
/**
|
||||
* Applying a CSS transform makes a `position: fixed` element act like it is `position: relative`
|
||||
* https://github.com/storybookjs/storybook/issues/8011#issue-490251969
|
||||
*/
|
||||
(story) => {
|
||||
return /* HTML */ `<div class="tw-scale-100 tw-border-2 tw-border-solid tw-border-[red]">
|
||||
${story}
|
||||
</div>`;
|
||||
},
|
||||
({ globals }) => {
|
||||
/**
|
||||
* avoid a bug with the way that we render the same component twice in the same iframe and how
|
||||
* that interacts with the router-outlet
|
||||
*/
|
||||
const themeOverride = globals["theme"] === "both" ? "light" : globals["theme"];
|
||||
return { theme: themeOverride };
|
||||
},
|
||||
),
|
||||
moduleMetadata({
|
||||
imports: [
|
||||
KitchenSinkSharedModule,
|
||||
KitchenSinkForm,
|
||||
KitchenSinkMainComponent,
|
||||
KitchenSinkTable,
|
||||
KitchenSinkToggleList,
|
||||
],
|
||||
providers: [
|
||||
DialogService,
|
||||
{
|
||||
provide: I18nService,
|
||||
useFactory: () => {
|
||||
return new I18nMockService({
|
||||
close: "Close",
|
||||
search: "Search",
|
||||
skipToContent: "Skip to content",
|
||||
submenu: "submenu",
|
||||
toggleCollapse: "toggle collapse",
|
||||
});
|
||||
},
|
||||
},
|
||||
],
|
||||
}),
|
||||
applicationConfig({
|
||||
providers: [
|
||||
provideNoopAnimations(),
|
||||
importProvidersFrom(
|
||||
RouterModule.forRoot(
|
||||
[
|
||||
{ path: "", redirectTo: "bitwarden", pathMatch: "full" },
|
||||
{ path: "bitwarden", component: KitchenSinkMainComponent },
|
||||
],
|
||||
{ useHash: true },
|
||||
),
|
||||
),
|
||||
],
|
||||
}),
|
||||
],
|
||||
} as Meta;
|
||||
|
||||
type Story = StoryObj<LayoutComponent>;
|
||||
|
||||
export const Default: Story = {
|
||||
render: (args) => {
|
||||
return {
|
||||
props: args,
|
||||
template: /* HTML */ `<bit-layout>
|
||||
<nav slot="sidebar">
|
||||
<bit-nav-group text="Password Managers" icon="bwi-collection" [open]="true">
|
||||
<bit-nav-group text="Favorites" icon="bwi-collection" variant="tree" [open]="true">
|
||||
<bit-nav-item text="Bitwarden" route="bitwarden"></bit-nav-item>
|
||||
<bit-nav-divider></bit-nav-divider>
|
||||
</bit-nav-group>
|
||||
</bit-nav-group>
|
||||
</nav>
|
||||
<router-outlet></router-outlet>
|
||||
</bit-layout>`,
|
||||
};
|
||||
},
|
||||
};
|
||||
|
||||
export const MenuOpen: Story = {
|
||||
...Default,
|
||||
play: async (context) => {
|
||||
const canvas = context.canvasElement;
|
||||
const table = getByRole(canvas, "table");
|
||||
|
||||
const menuButton = getAllByRole(table, "button")[0];
|
||||
await userEvent.click(menuButton);
|
||||
},
|
||||
};
|
||||
|
||||
export const DefaultDialogOpen: Story = {
|
||||
...Default,
|
||||
play: (context) => {
|
||||
const canvas = context.canvasElement;
|
||||
const dialogButton = getByRole(canvas, "button", {
|
||||
name: "Open Dialog",
|
||||
});
|
||||
|
||||
// workaround for userEvent not firing in FF https://github.com/testing-library/user-event/issues/1075
|
||||
fireEvent.click(dialogButton);
|
||||
},
|
||||
};
|
||||
|
||||
export const PopoverOpen: Story = {
|
||||
...Default,
|
||||
play: async (context) => {
|
||||
const canvas = context.canvasElement;
|
||||
const passwordLabelIcon = getByLabelText(canvas, "A random password (required)", {
|
||||
selector: "button",
|
||||
});
|
||||
|
||||
await userEvent.click(passwordLabelIcon);
|
||||
},
|
||||
};
|
||||
|
||||
export const SimpleDialogOpen: Story = {
|
||||
...Default,
|
||||
play: (context) => {
|
||||
const canvas = context.canvasElement;
|
||||
const submitButton = getByRole(canvas, "button", {
|
||||
name: "Submit",
|
||||
});
|
||||
|
||||
// workaround for userEvent not firing in FF https://github.com/testing-library/user-event/issues/1075
|
||||
fireEvent.click(submitButton);
|
||||
},
|
||||
};
|
||||
|
||||
export const EmptyTab: Story = {
|
||||
...Default,
|
||||
play: async (context) => {
|
||||
const canvas = context.canvasElement;
|
||||
const emptyTab = getByRole(canvas, "tab", { name: "Empty tab" });
|
||||
await userEvent.click(emptyTab);
|
||||
},
|
||||
};
|
Loading…
Reference in New Issue