mirror of
https://github.com/bitwarden/browser.git
synced 2025-01-04 18:37:45 +01:00
[CL-46] Dialogs (#3237)
This commit is contained in:
parent
e7220644d1
commit
762fac062f
2
.github/workflows/chromatic.yml
vendored
2
.github/workflows/chromatic.yml
vendored
@ -39,4 +39,4 @@ jobs:
|
|||||||
projectToken: ${{ secrets.CHROMATIC_PROJECT_TOKEN }}
|
projectToken: ${{ secrets.CHROMATIC_PROJECT_TOKEN }}
|
||||||
exitOnceUploaded: true
|
exitOnceUploaded: true
|
||||||
onlyChanged: true
|
onlyChanged: true
|
||||||
externals: "[\"components/**/*.scss\", \"components/tailwind.config*.js\"]"
|
externals: "[\"libs/components/**/*.scss\", \"libs/components/tailwind.config*.js\"]"
|
||||||
|
18
libs/components/src/dialog/dialog-close.directive.ts
Normal file
18
libs/components/src/dialog/dialog-close.directive.ts
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
import { DialogRef } from "@angular/cdk/dialog";
|
||||||
|
import { Directive, Input, Optional } from "@angular/core";
|
||||||
|
|
||||||
|
@Directive({
|
||||||
|
selector: "[bitDialogClose]",
|
||||||
|
host: {
|
||||||
|
"(click)": "close()",
|
||||||
|
},
|
||||||
|
})
|
||||||
|
export class DialogCloseDirective {
|
||||||
|
@Input("bit-dialog-close") dialogResult: any;
|
||||||
|
|
||||||
|
constructor(@Optional() public dialogRef: DialogRef<any>) {}
|
||||||
|
|
||||||
|
close() {
|
||||||
|
this.dialogRef.close(this.dialogResult);
|
||||||
|
}
|
||||||
|
}
|
78
libs/components/src/dialog/dialog-service.stories.ts
Normal file
78
libs/components/src/dialog/dialog-service.stories.ts
Normal file
@ -0,0 +1,78 @@
|
|||||||
|
import { DialogModule, DialogRef, DIALOG_DATA } from "@angular/cdk/dialog";
|
||||||
|
import { Component, Inject } from "@angular/core";
|
||||||
|
import { Meta, moduleMetadata, Story } from "@storybook/angular";
|
||||||
|
|
||||||
|
import { ButtonModule } from "../button";
|
||||||
|
|
||||||
|
import { DialogCloseDirective } from "./dialog-close.directive";
|
||||||
|
import { DialogService } from "./dialog.service";
|
||||||
|
import { DialogComponent } from "./dialog/dialog.component";
|
||||||
|
|
||||||
|
interface Animal {
|
||||||
|
animal: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: "app-story-dialog",
|
||||||
|
template: `<button bitButton (click)="openDialog()">Open Dialog</button>`,
|
||||||
|
})
|
||||||
|
class StoryDialogComponent {
|
||||||
|
constructor(public dialogService: DialogService) {}
|
||||||
|
|
||||||
|
openDialog() {
|
||||||
|
this.dialogService.open(StoryDialogContentComponent, {
|
||||||
|
data: {
|
||||||
|
animal: "panda",
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: "story-dialog-content",
|
||||||
|
template: `
|
||||||
|
<bit-dialog [dialogSize]="large">
|
||||||
|
<span bit-dialog-title>Dialog Title</span>
|
||||||
|
<span bit-dialog-content>
|
||||||
|
Dialog body text goes here.
|
||||||
|
<br />
|
||||||
|
Animal: {{ animal }}
|
||||||
|
</span>
|
||||||
|
<div bit-dialog-footer class="tw-flex tw-flex-row tw-gap-2">
|
||||||
|
<button bitButton buttonType="primary" (click)="dialogRef.close()">Save</button>
|
||||||
|
<button bitButton buttonType="secondary" bitDialogClose>Cancel</button>
|
||||||
|
</div>
|
||||||
|
</bit-dialog>
|
||||||
|
`,
|
||||||
|
})
|
||||||
|
class StoryDialogContentComponent {
|
||||||
|
constructor(public dialogRef: DialogRef, @Inject(DIALOG_DATA) private data: Animal) {}
|
||||||
|
|
||||||
|
get animal() {
|
||||||
|
return this.data?.animal;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default {
|
||||||
|
title: "Component Library/Dialogs/Service",
|
||||||
|
component: StoryDialogComponent,
|
||||||
|
decorators: [
|
||||||
|
moduleMetadata({
|
||||||
|
declarations: [DialogComponent, StoryDialogContentComponent, DialogCloseDirective],
|
||||||
|
imports: [ButtonModule, DialogModule],
|
||||||
|
providers: [DialogService],
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
parameters: {
|
||||||
|
design: {
|
||||||
|
type: "figma",
|
||||||
|
url: "https://www.figma.com/file/Zt3YSeb6E6lebAffrNLa0h/Tailwind-Component-Library",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
} as Meta;
|
||||||
|
|
||||||
|
const Template: Story<StoryDialogComponent> = (args: StoryDialogComponent) => ({
|
||||||
|
props: args,
|
||||||
|
});
|
||||||
|
|
||||||
|
export const Default = Template.bind({});
|
16
libs/components/src/dialog/dialog.module.ts
Normal file
16
libs/components/src/dialog/dialog.module.ts
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
import { DialogModule as CdkDialogModule } from "@angular/cdk/dialog";
|
||||||
|
import { CommonModule } from "@angular/common";
|
||||||
|
import { NgModule } from "@angular/core";
|
||||||
|
|
||||||
|
import { DialogCloseDirective } from "./dialog-close.directive";
|
||||||
|
import { DialogService } from "./dialog.service";
|
||||||
|
import { DialogComponent } from "./dialog/dialog.component";
|
||||||
|
import { SimpleDialogComponent } from "./simple-dialog/simple-dialog.component";
|
||||||
|
|
||||||
|
@NgModule({
|
||||||
|
imports: [CommonModule, CdkDialogModule],
|
||||||
|
declarations: [DialogCloseDirective, DialogComponent, SimpleDialogComponent],
|
||||||
|
exports: [CdkDialogModule, DialogComponent, SimpleDialogComponent],
|
||||||
|
providers: [DialogService],
|
||||||
|
})
|
||||||
|
export class DialogModule {}
|
18
libs/components/src/dialog/dialog.service.ts
Normal file
18
libs/components/src/dialog/dialog.service.ts
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
import { Dialog, DialogConfig, DialogRef } from "@angular/cdk/dialog";
|
||||||
|
import { ComponentType } from "@angular/cdk/overlay";
|
||||||
|
import { Injectable, TemplateRef } from "@angular/core";
|
||||||
|
|
||||||
|
@Injectable()
|
||||||
|
export class DialogService extends Dialog {
|
||||||
|
override open<R = unknown, D = unknown, C = unknown>(
|
||||||
|
componentOrTemplateRef: ComponentType<C> | TemplateRef<C>,
|
||||||
|
config?: DialogConfig<D, DialogRef<R, C>>
|
||||||
|
): DialogRef<R, C> {
|
||||||
|
config = {
|
||||||
|
backdropClass: ["tw-fixed", "tw-bg-black", "tw-bg-opacity-30", "tw-inset-0", "tw-z-40"],
|
||||||
|
...config,
|
||||||
|
};
|
||||||
|
|
||||||
|
return super.open(componentOrTemplateRef, config);
|
||||||
|
}
|
||||||
|
}
|
@ -6,20 +6,20 @@
|
|||||||
class="tw-flex tw-gap-4 tw-border-0 tw-border-b tw-border-solid tw-border-secondary-300 tw-p-4"
|
class="tw-flex tw-gap-4 tw-border-0 tw-border-b tw-border-solid tw-border-secondary-300 tw-p-4"
|
||||||
>
|
>
|
||||||
<h2 class="tw-mb-0 tw-grow tw-text-lg tw-uppercase">
|
<h2 class="tw-mb-0 tw-grow tw-text-lg tw-uppercase">
|
||||||
<ng-content select="[bit-modal-title]"></ng-content>
|
<ng-content select="[bit-dialog-title]"></ng-content>
|
||||||
</h2>
|
</h2>
|
||||||
<button class="tw-border-0 tw-bg-transparent tw-p-0">
|
<button class="tw-border-0 tw-bg-transparent tw-p-0" bitDialogClose>
|
||||||
<i class="bwi bwi-close tw-text-xs tw-font-bold tw-text-main" aria-hidden="true"></i>
|
<i class="bwi bwi-close tw-text-xs tw-font-bold tw-text-main" aria-hidden="true"></i>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="tw-overflow-y-auto tw-p-4 tw-pb-8">
|
<div class="tw-overflow-y-auto tw-p-4 tw-pb-8">
|
||||||
<ng-content select="[bit-modal-content]"></ng-content>
|
<ng-content select="[bit-dialog-content]"></ng-content>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div
|
<div
|
||||||
class="tw-border-0 tw-border-t tw-border-solid tw-border-secondary-300 tw-bg-background-alt tw-p-4"
|
class="tw-border-0 tw-border-t tw-border-solid tw-border-secondary-300 tw-bg-background-alt tw-p-4"
|
||||||
>
|
>
|
||||||
<ng-content select="[bit-modal-footer]"></ng-content>
|
<ng-content select="[bit-dialog-footer]"></ng-content>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
23
libs/components/src/dialog/dialog/dialog.component.ts
Normal file
23
libs/components/src/dialog/dialog/dialog.component.ts
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
import { Component, Input } from "@angular/core";
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: "bit-dialog",
|
||||||
|
templateUrl: "./dialog.component.html",
|
||||||
|
})
|
||||||
|
export class DialogComponent {
|
||||||
|
@Input() dialogSize: "small" | "default" | "large" = "default";
|
||||||
|
|
||||||
|
get width() {
|
||||||
|
switch (this.dialogSize) {
|
||||||
|
case "small": {
|
||||||
|
return "tw-w-96";
|
||||||
|
}
|
||||||
|
case "large": {
|
||||||
|
return "tw-w-75vw";
|
||||||
|
}
|
||||||
|
default: {
|
||||||
|
return "tw-w-50vw";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
81
libs/components/src/dialog/dialog/dialog.stories.ts
Normal file
81
libs/components/src/dialog/dialog/dialog.stories.ts
Normal file
@ -0,0 +1,81 @@
|
|||||||
|
import { Meta, moduleMetadata, Story } from "@storybook/angular";
|
||||||
|
|
||||||
|
import { ButtonModule } from "../../button";
|
||||||
|
|
||||||
|
import { DialogComponent } from "./dialog.component";
|
||||||
|
|
||||||
|
export default {
|
||||||
|
title: "Component Library/Dialogs/Dialog",
|
||||||
|
component: DialogComponent,
|
||||||
|
decorators: [
|
||||||
|
moduleMetadata({
|
||||||
|
imports: [ButtonModule],
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
args: {
|
||||||
|
dialogSize: "small",
|
||||||
|
},
|
||||||
|
parameters: {
|
||||||
|
design: {
|
||||||
|
type: "figma",
|
||||||
|
url: "https://www.figma.com/file/Zt3YSeb6E6lebAffrNLa0h/Tailwind-Component-Library",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
} as Meta;
|
||||||
|
|
||||||
|
const Template: Story<DialogComponent> = (args: DialogComponent) => ({
|
||||||
|
props: args,
|
||||||
|
template: `
|
||||||
|
<bit-dialog [dialogSize]="dialogSize">
|
||||||
|
<span bit-dialog-title>{{title}}</span>
|
||||||
|
<span bit-dialog-content>Dialog body text goes here.</span>
|
||||||
|
<div bit-dialog-footer class="tw-flex tw-flex-row tw-gap-2">
|
||||||
|
<button bitButton buttonType="primary">Save</button>
|
||||||
|
<button bitButton buttonType="secondary">Cancel</button>
|
||||||
|
</div>
|
||||||
|
</bit-dialog>
|
||||||
|
`,
|
||||||
|
});
|
||||||
|
|
||||||
|
export const Default = Template.bind({});
|
||||||
|
Default.args = {
|
||||||
|
dialogSize: "default",
|
||||||
|
title: "Default",
|
||||||
|
};
|
||||||
|
|
||||||
|
export const Small = Template.bind({});
|
||||||
|
Small.args = {
|
||||||
|
dialogSize: "small",
|
||||||
|
title: "Small",
|
||||||
|
};
|
||||||
|
|
||||||
|
export const Large = Template.bind({});
|
||||||
|
Large.args = {
|
||||||
|
dialogSize: "large",
|
||||||
|
title: "Large",
|
||||||
|
};
|
||||||
|
|
||||||
|
const TemplateScrolling: Story<DialogComponent> = (args: DialogComponent) => ({
|
||||||
|
props: args,
|
||||||
|
template: `
|
||||||
|
<bit-dialog [dialogSize]="dialogSize">
|
||||||
|
<span bit-dialog-title>Scrolling Example</span>
|
||||||
|
<span bit-dialog-content>
|
||||||
|
Dialog body text goes here.<br>
|
||||||
|
<ng-container *ngFor="let _ of [].constructor(100)">
|
||||||
|
repeating lines of characters <br>
|
||||||
|
</ng-container>
|
||||||
|
end of sequence!
|
||||||
|
</span>
|
||||||
|
<div bit-dialog-footer class="tw-flex tw-flex-row tw-gap-2">
|
||||||
|
<button bitButton buttonType="primary">Save</button>
|
||||||
|
<button bitButton buttonType="secondary">Cancel</button>
|
||||||
|
</div>
|
||||||
|
</bit-dialog>
|
||||||
|
`,
|
||||||
|
});
|
||||||
|
|
||||||
|
export const ScrollingContent = TemplateScrolling.bind({});
|
||||||
|
ScrollingContent.args = {
|
||||||
|
dialogSize: "small",
|
||||||
|
};
|
2
libs/components/src/dialog/index.ts
Normal file
2
libs/components/src/dialog/index.ts
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
export * from "./dialog.module";
|
||||||
|
export * from "./dialog.service";
|
@ -2,18 +2,18 @@
|
|||||||
class="tw-my-4 tw-flex tw-max-h-screen tw-max-w-sm tw-flex-col tw-overflow-hidden tw-rounded tw-border tw-border-solid tw-border-secondary-300 tw-bg-text-contrast tw-text-main"
|
class="tw-my-4 tw-flex tw-max-h-screen tw-max-w-sm tw-flex-col tw-overflow-hidden tw-rounded tw-border tw-border-solid tw-border-secondary-300 tw-bg-text-contrast tw-text-main"
|
||||||
>
|
>
|
||||||
<div class="tw-flex tw-flex-col tw-items-center tw-gap-2 tw-px-4 tw-pt-4 tw-text-center">
|
<div class="tw-flex tw-flex-col tw-items-center tw-gap-2 tw-px-4 tw-pt-4 tw-text-center">
|
||||||
<ng-content *ngIf="hasIcon; else elseBlock" select="[bit-modal-icon]"></ng-content>
|
<ng-content *ngIf="hasIcon; else elseBlock" select="[bit-dialog-icon]"></ng-content>
|
||||||
<ng-template #elseBlock>
|
<ng-template #elseBlock>
|
||||||
<i class="bwi bwi-exclamation-triangle tw-text-3xl tw-text-warning" aria-hidden="true"></i>
|
<i class="bwi bwi-exclamation-triangle tw-text-3xl tw-text-warning" aria-hidden="true"></i>
|
||||||
</ng-template>
|
</ng-template>
|
||||||
<h2 class="tw-mb-0 tw-text-base tw-font-semibold">
|
<h2 class="tw-mb-0 tw-text-base tw-font-semibold">
|
||||||
<ng-content select="[bit-modal-title]"></ng-content>
|
<ng-content select="[bit-dialog-title]"></ng-content>
|
||||||
</h2>
|
</h2>
|
||||||
</div>
|
</div>
|
||||||
<div class="tw-overflow-y-auto tw-px-4 tw-pt-2 tw-pb-4 tw-text-center tw-text-base">
|
<div class="tw-overflow-y-auto tw-px-4 tw-pt-2 tw-pb-4 tw-text-center tw-text-base">
|
||||||
<ng-content select="[bit-modal-content]"></ng-content>
|
<ng-content select="[bit-dialog-content]"></ng-content>
|
||||||
</div>
|
</div>
|
||||||
<div class="tw-border-0 tw-border-t tw-border-solid tw-border-secondary-300 tw-p-4">
|
<div class="tw-border-0 tw-border-t tw-border-solid tw-border-secondary-300 tw-p-4">
|
||||||
<ng-content select="[bit-modal-footer]"></ng-content>
|
<ng-content select="[bit-dialog-footer]"></ng-content>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
@ -1,13 +1,13 @@
|
|||||||
import { Component, ContentChild, Directive } from "@angular/core";
|
import { Component, ContentChild, Directive } from "@angular/core";
|
||||||
|
|
||||||
@Directive({ selector: "[bit-modal-icon]" })
|
@Directive({ selector: "[bit-dialog-icon]" })
|
||||||
export class IconDirective {}
|
export class IconDirective {}
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: "bit-simple-modal",
|
selector: "bit-simple-dialog",
|
||||||
templateUrl: "./modal-simple.component.html",
|
templateUrl: "./simple-dialog.component.html",
|
||||||
})
|
})
|
||||||
export class ModalSimpleComponent {
|
export class SimpleDialogComponent {
|
||||||
@ContentChild(IconDirective) icon!: IconDirective;
|
@ContentChild(IconDirective) icon!: IconDirective;
|
||||||
|
|
||||||
get hasIcon() {
|
get hasIcon() {
|
@ -0,0 +1,81 @@
|
|||||||
|
import { Meta, moduleMetadata, Story } from "@storybook/angular";
|
||||||
|
|
||||||
|
import { ButtonModule } from "../../button";
|
||||||
|
|
||||||
|
import { IconDirective, SimpleDialogComponent } from "./simple-dialog.component";
|
||||||
|
|
||||||
|
export default {
|
||||||
|
title: "Component Library/Dialogs/Simple Dialog",
|
||||||
|
component: SimpleDialogComponent,
|
||||||
|
decorators: [
|
||||||
|
moduleMetadata({
|
||||||
|
imports: [ButtonModule],
|
||||||
|
declarations: [IconDirective],
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
parameters: {
|
||||||
|
design: {
|
||||||
|
type: "figma",
|
||||||
|
url: "https://www.figma.com/file/Zt3YSeb6E6lebAffrNLa0h/Tailwind-Component-Library",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
} as Meta;
|
||||||
|
|
||||||
|
const Template: Story<SimpleDialogComponent> = (args: SimpleDialogComponent) => ({
|
||||||
|
props: args,
|
||||||
|
template: `
|
||||||
|
<bit-simple-dialog>
|
||||||
|
<span bit-dialog-title>Alert Dialog</span>
|
||||||
|
<span bit-dialog-content>Message Content</span>
|
||||||
|
<div bit-dialog-footer class="tw-flex tw-flex-row tw-gap-2">
|
||||||
|
<button bitButton buttonType="primary">Yes</button>
|
||||||
|
<button bitButton buttonType="secondary">No</button>
|
||||||
|
</div>
|
||||||
|
</bit-simple-dialog>
|
||||||
|
`,
|
||||||
|
});
|
||||||
|
|
||||||
|
export const Default = Template.bind({});
|
||||||
|
|
||||||
|
const TemplateWithIcon: Story<SimpleDialogComponent> = (args: SimpleDialogComponent) => ({
|
||||||
|
props: args,
|
||||||
|
template: `
|
||||||
|
<bit-simple-dialog>
|
||||||
|
<i bit-dialog-icon class="bwi bwi-star tw-text-3xl tw-text-success" aria-hidden="true"></i>
|
||||||
|
<span bit-dialog-title>Premium Subscription Available</span>
|
||||||
|
<span bit-dialog-content> Message Content</span>
|
||||||
|
<div bit-dialog-footer class="tw-flex tw-flex-row tw-gap-2">
|
||||||
|
<button bitButton buttonType="primary">Yes</button>
|
||||||
|
<button bitButton buttonType="secondary">No</button>
|
||||||
|
</div>
|
||||||
|
</bit-simple-dialog>
|
||||||
|
`,
|
||||||
|
});
|
||||||
|
|
||||||
|
export const CustomIcon = TemplateWithIcon.bind({});
|
||||||
|
|
||||||
|
const TemplateScroll: Story<SimpleDialogComponent> = (args: SimpleDialogComponent) => ({
|
||||||
|
props: args,
|
||||||
|
template: `
|
||||||
|
<bit-simple-dialog>
|
||||||
|
<span bit-dialog-title>Alert Dialog</span>
|
||||||
|
<span bit-dialog-content>
|
||||||
|
Message Content
|
||||||
|
Message text goes here.<br>
|
||||||
|
<ng-container *ngFor="let _ of [].constructor(100)">
|
||||||
|
repeating lines of characters <br>
|
||||||
|
</ng-container>
|
||||||
|
end of sequence!
|
||||||
|
</span>
|
||||||
|
<div bit-dialog-footer class="tw-flex tw-flex-row tw-gap-2">
|
||||||
|
<button bitButton buttonType="primary">Yes</button>
|
||||||
|
<button bitButton buttonType="secondary">No</button>
|
||||||
|
</div>
|
||||||
|
</bit-simple-dialog>
|
||||||
|
`,
|
||||||
|
});
|
||||||
|
|
||||||
|
export const ScrollingContent = TemplateScroll.bind({});
|
||||||
|
ScrollingContent.args = {
|
||||||
|
useDefaultIcon: true,
|
||||||
|
};
|
@ -5,7 +5,7 @@ export * from "./callout";
|
|||||||
export * from "./form-field";
|
export * from "./form-field";
|
||||||
export * from "./icon";
|
export * from "./icon";
|
||||||
export * from "./menu";
|
export * from "./menu";
|
||||||
export * from "./modal";
|
export * from "./dialog";
|
||||||
export * from "./submit-button";
|
export * from "./submit-button";
|
||||||
export * from "./tabs";
|
export * from "./tabs";
|
||||||
export * from "./toggle-group";
|
export * from "./toggle-group";
|
||||||
|
@ -1,3 +0,0 @@
|
|||||||
export * from "./modal.component";
|
|
||||||
export * from "./modal-simple.component";
|
|
||||||
export * from "./modal.module";
|
|
@ -1,85 +0,0 @@
|
|||||||
import { Meta, moduleMetadata, Story } from "@storybook/angular";
|
|
||||||
|
|
||||||
import { ButtonModule } from "../button";
|
|
||||||
|
|
||||||
import { IconDirective, ModalSimpleComponent } from "./modal-simple.component";
|
|
||||||
|
|
||||||
export default {
|
|
||||||
title: "Component Library/Modals/Simple Modal",
|
|
||||||
component: ModalSimpleComponent,
|
|
||||||
decorators: [
|
|
||||||
moduleMetadata({
|
|
||||||
imports: [ButtonModule],
|
|
||||||
declarations: [IconDirective],
|
|
||||||
}),
|
|
||||||
],
|
|
||||||
parameters: {
|
|
||||||
design: {
|
|
||||||
type: "figma",
|
|
||||||
url: "https://www.figma.com/file/Zt3YSeb6E6lebAffrNLa0h/Tailwind-Component-Library",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
} as Meta;
|
|
||||||
|
|
||||||
const Template: Story<ModalSimpleComponent> = (args: ModalSimpleComponent) => ({
|
|
||||||
props: args,
|
|
||||||
template: `
|
|
||||||
<bit-simple-modal>
|
|
||||||
<span bit-modal-title> Alert Modal
|
|
||||||
</span>
|
|
||||||
<span bit-modal-content> Message Content
|
|
||||||
</span>
|
|
||||||
<div bit-modal-footer class="tw-flex tw-flex-row tw-gap-2">
|
|
||||||
<button bitButton buttonType="primary"> Yes </button>
|
|
||||||
<button bitButton buttonType="secondary"> No </button>
|
|
||||||
</div>
|
|
||||||
</bit-simple-modal>
|
|
||||||
`,
|
|
||||||
});
|
|
||||||
|
|
||||||
export const Default = Template.bind({});
|
|
||||||
|
|
||||||
const TemplateWithIcon: Story<ModalSimpleComponent> = (args: ModalSimpleComponent) => ({
|
|
||||||
props: args,
|
|
||||||
template: `
|
|
||||||
<bit-simple-modal>
|
|
||||||
<i bit-modal-icon class="bwi bwi-star tw-text-3xl tw-text-success" aria-hidden="true"></i>
|
|
||||||
<span bit-modal-title> Premium Subscription Available
|
|
||||||
</span>
|
|
||||||
<span bit-modal-content> Message Content
|
|
||||||
</span>
|
|
||||||
<div bit-modal-footer class="tw-flex tw-flex-row tw-gap-2">
|
|
||||||
<button bitButton buttonType="primary"> Yes </button>
|
|
||||||
<button bitButton buttonType="secondary"> No </button>
|
|
||||||
</div>
|
|
||||||
</bit-simple-modal>
|
|
||||||
`,
|
|
||||||
});
|
|
||||||
|
|
||||||
export const CustomIcon = TemplateWithIcon.bind({});
|
|
||||||
|
|
||||||
const TemplateScroll: Story<ModalSimpleComponent> = (args: ModalSimpleComponent) => ({
|
|
||||||
props: args,
|
|
||||||
template: `
|
|
||||||
<bit-simple-modal>
|
|
||||||
<span bit-modal-title> Alert Modal
|
|
||||||
</span>
|
|
||||||
<span bit-modal-content> Message Content
|
|
||||||
Message text goes here.<br>
|
|
||||||
<ng-container *ngFor="let _ of [].constructor(100)">
|
|
||||||
repeating lines of characters <br>
|
|
||||||
</ng-container>
|
|
||||||
end of sequence!
|
|
||||||
</span>
|
|
||||||
<div bit-modal-footer class="tw-flex tw-flex-row tw-gap-2">
|
|
||||||
<button bitButton buttonType="primary"> Yes </button>
|
|
||||||
<button bitButton buttonType="secondary"> No </button>
|
|
||||||
</div>
|
|
||||||
</bit-simple-modal>
|
|
||||||
`,
|
|
||||||
});
|
|
||||||
|
|
||||||
export const ScrollingContent = TemplateScroll.bind({});
|
|
||||||
ScrollingContent.args = {
|
|
||||||
useDefaultIcon: true,
|
|
||||||
};
|
|
@ -1,23 +0,0 @@
|
|||||||
import { Component, Input } from "@angular/core";
|
|
||||||
|
|
||||||
@Component({
|
|
||||||
selector: "bit-modal",
|
|
||||||
templateUrl: "./modal.component.html",
|
|
||||||
})
|
|
||||||
export class ModalComponent {
|
|
||||||
@Input() modalSize: "small" | "default" | "large";
|
|
||||||
|
|
||||||
get width() {
|
|
||||||
switch (this.modalSize) {
|
|
||||||
case "small": {
|
|
||||||
return "tw-max-w-xs";
|
|
||||||
}
|
|
||||||
case "large": {
|
|
||||||
return "tw-max-w-4xl";
|
|
||||||
}
|
|
||||||
default: {
|
|
||||||
return "tw-max-w-xl";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,12 +0,0 @@
|
|||||||
import { CommonModule } from "@angular/common";
|
|
||||||
import { NgModule } from "@angular/core";
|
|
||||||
|
|
||||||
import { ModalSimpleComponent } from "./modal-simple.component";
|
|
||||||
import { ModalComponent } from "./modal.component";
|
|
||||||
|
|
||||||
@NgModule({
|
|
||||||
imports: [CommonModule],
|
|
||||||
exports: [ModalComponent, ModalSimpleComponent],
|
|
||||||
declarations: [ModalComponent, ModalSimpleComponent],
|
|
||||||
})
|
|
||||||
export class ModalModule {}
|
|
@ -1,80 +0,0 @@
|
|||||||
import { Meta, moduleMetadata, Story } from "@storybook/angular";
|
|
||||||
|
|
||||||
import { ButtonModule } from "../button";
|
|
||||||
|
|
||||||
import { ModalComponent } from "./modal.component";
|
|
||||||
|
|
||||||
export default {
|
|
||||||
title: "Component Library/Modals/Modal",
|
|
||||||
component: ModalComponent,
|
|
||||||
decorators: [
|
|
||||||
moduleMetadata({
|
|
||||||
imports: [ButtonModule],
|
|
||||||
}),
|
|
||||||
],
|
|
||||||
args: {
|
|
||||||
modalSize: "small",
|
|
||||||
},
|
|
||||||
parameters: {
|
|
||||||
design: {
|
|
||||||
type: "figma",
|
|
||||||
url: "https://www.figma.com/file/Zt3YSeb6E6lebAffrNLa0h/Tailwind-Component-Library",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
} as Meta;
|
|
||||||
|
|
||||||
const Template: Story<ModalComponent> = (args: ModalComponent) => ({
|
|
||||||
props: args,
|
|
||||||
template: `
|
|
||||||
<bit-modal [modalSize]="modalSize">
|
|
||||||
<span bit-modal-title> Modal Title </span>
|
|
||||||
<span bit-modal-content>
|
|
||||||
Modal body text goes here.
|
|
||||||
</span>
|
|
||||||
<div bit-modal-footer class="tw-flex tw-flex-row tw-gap-2">
|
|
||||||
<button bitButton buttonType="primary"> Save </button>
|
|
||||||
<button bitButton buttonType="secondary"> Cancel </button>
|
|
||||||
</div>
|
|
||||||
</bit-modal>
|
|
||||||
`,
|
|
||||||
});
|
|
||||||
|
|
||||||
export const Default = Template.bind({});
|
|
||||||
Default.args = {
|
|
||||||
modalSize: "default",
|
|
||||||
};
|
|
||||||
|
|
||||||
export const Small = Template.bind({});
|
|
||||||
Small.args = {
|
|
||||||
modalSize: "small",
|
|
||||||
};
|
|
||||||
|
|
||||||
export const Large = Template.bind({});
|
|
||||||
Large.args = {
|
|
||||||
modalSize: "large",
|
|
||||||
};
|
|
||||||
|
|
||||||
const TemplateScrolling: Story<ModalComponent> = (args: ModalComponent) => ({
|
|
||||||
props: args,
|
|
||||||
template: `
|
|
||||||
<bit-modal [modalSize]="modalSize">
|
|
||||||
<span bit-modal-title> Modal Title </span>
|
|
||||||
<span bit-modal-content>
|
|
||||||
Modal body text goes here.<br>
|
|
||||||
<ng-container *ngFor="let _ of [].constructor(100)">
|
|
||||||
repeating lines of characters <br>
|
|
||||||
</ng-container>
|
|
||||||
end of sequence!
|
|
||||||
</span>
|
|
||||||
<div bit-modal-footer class="tw-flex tw-flex-row tw-gap-2">
|
|
||||||
<button bitButton buttonType="primary"> Save </button>
|
|
||||||
<button bitButton buttonType="secondary"> Cancel </button>
|
|
||||||
</div>
|
|
||||||
</bit-modal>
|
|
||||||
`,
|
|
||||||
});
|
|
||||||
|
|
||||||
export const ScrollingContent = TemplateScrolling.bind({});
|
|
||||||
ScrollingContent.args = {
|
|
||||||
modalSize: "small",
|
|
||||||
};
|
|
@ -10,6 +10,7 @@ module.exports = {
|
|||||||
colors: {
|
colors: {
|
||||||
transparent: colors.transparent,
|
transparent: colors.transparent,
|
||||||
current: colors.current,
|
current: colors.current,
|
||||||
|
black: colors.black,
|
||||||
primary: {
|
primary: {
|
||||||
300: "var(--color-primary-300)",
|
300: "var(--color-primary-300)",
|
||||||
500: "var(--color-primary-500)",
|
500: "var(--color-primary-500)",
|
||||||
@ -68,6 +69,12 @@ module.exports = {
|
|||||||
DEFAULT: theme("colors.background"),
|
DEFAULT: theme("colors.background"),
|
||||||
...theme("colors"),
|
...theme("colors"),
|
||||||
}),
|
}),
|
||||||
|
extend: {
|
||||||
|
width: {
|
||||||
|
"50vw": "50vw",
|
||||||
|
"75vw": "75vw",
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
plugins: [],
|
plugins: [],
|
||||||
};
|
};
|
||||||
|
Loading…
Reference in New Issue
Block a user