mirror of
https://github.com/bitwarden/browser
synced 2025-12-12 22:33:35 +00:00
Move to libs
This commit is contained in:
77
libs/components/src/button/button.directive.spec.ts
Normal file
77
libs/components/src/button/button.directive.spec.ts
Normal file
@@ -0,0 +1,77 @@
|
||||
import { Component, DebugElement } from "@angular/core";
|
||||
import { ComponentFixture, TestBed, waitForAsync } from "@angular/core/testing";
|
||||
import { By } from "@angular/platform-browser";
|
||||
|
||||
import { ButtonModule } from "./index";
|
||||
|
||||
describe("Button", () => {
|
||||
let fixture: ComponentFixture<TestApp>;
|
||||
let testAppComponent: TestApp;
|
||||
let buttonDebugElement: DebugElement;
|
||||
let linkDebugElement: DebugElement;
|
||||
|
||||
beforeEach(
|
||||
waitForAsync(() => {
|
||||
TestBed.configureTestingModule({
|
||||
imports: [ButtonModule],
|
||||
declarations: [TestApp],
|
||||
});
|
||||
|
||||
TestBed.compileComponents();
|
||||
fixture = TestBed.createComponent(TestApp);
|
||||
testAppComponent = fixture.debugElement.componentInstance;
|
||||
buttonDebugElement = fixture.debugElement.query(By.css("button"));
|
||||
linkDebugElement = fixture.debugElement.query(By.css("a"));
|
||||
})
|
||||
);
|
||||
|
||||
it("should apply classes based on type", () => {
|
||||
testAppComponent.buttonType = "primary";
|
||||
fixture.detectChanges();
|
||||
expect(buttonDebugElement.nativeElement.classList.contains("tw-bg-primary-500")).toBe(true);
|
||||
expect(linkDebugElement.nativeElement.classList.contains("tw-bg-primary-500")).toBe(true);
|
||||
|
||||
testAppComponent.buttonType = "secondary";
|
||||
fixture.detectChanges();
|
||||
expect(buttonDebugElement.nativeElement.classList.contains("tw-border-text-muted")).toBe(true);
|
||||
expect(linkDebugElement.nativeElement.classList.contains("tw-border-text-muted")).toBe(true);
|
||||
|
||||
testAppComponent.buttonType = "danger";
|
||||
fixture.detectChanges();
|
||||
expect(buttonDebugElement.nativeElement.classList.contains("tw-border-danger-500")).toBe(true);
|
||||
expect(linkDebugElement.nativeElement.classList.contains("tw-border-danger-500")).toBe(true);
|
||||
|
||||
testAppComponent.buttonType = null;
|
||||
fixture.detectChanges();
|
||||
expect(buttonDebugElement.nativeElement.classList.contains("tw-border-text-muted")).toBe(true);
|
||||
expect(linkDebugElement.nativeElement.classList.contains("tw-border-text-muted")).toBe(true);
|
||||
});
|
||||
|
||||
it("should apply block when true and inline-block when false", () => {
|
||||
testAppComponent.block = true;
|
||||
fixture.detectChanges();
|
||||
expect(buttonDebugElement.nativeElement.classList.contains("tw-block")).toBe(true);
|
||||
expect(linkDebugElement.nativeElement.classList.contains("tw-block")).toBe(true);
|
||||
expect(buttonDebugElement.nativeElement.classList.contains("tw-inline-block")).toBe(false);
|
||||
expect(linkDebugElement.nativeElement.classList.contains("tw-inline-block")).toBe(false);
|
||||
|
||||
testAppComponent.block = false;
|
||||
fixture.detectChanges();
|
||||
expect(buttonDebugElement.nativeElement.classList.contains("tw-inline-block")).toBe(true);
|
||||
expect(linkDebugElement.nativeElement.classList.contains("tw-inline-block")).toBe(true);
|
||||
expect(buttonDebugElement.nativeElement.classList.contains("tw-block")).toBe(false);
|
||||
expect(linkDebugElement.nativeElement.classList.contains("tw-block")).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
@Component({
|
||||
selector: "test-app",
|
||||
template: `
|
||||
<button type="button" bitButton [buttonType]="buttonType" [block]="block">Button</button>
|
||||
<a href="#" bitButton [buttonType]="buttonType" [block]="block"> Link </a>
|
||||
`,
|
||||
})
|
||||
class TestApp {
|
||||
buttonType: string;
|
||||
block: boolean;
|
||||
}
|
||||
72
libs/components/src/button/button.directive.ts
Normal file
72
libs/components/src/button/button.directive.ts
Normal file
@@ -0,0 +1,72 @@
|
||||
import { Input, HostBinding, Directive } from "@angular/core";
|
||||
|
||||
export type ButtonTypes = "primary" | "secondary" | "danger";
|
||||
|
||||
const buttonStyles: Record<ButtonTypes, string[]> = {
|
||||
primary: [
|
||||
"tw-border-primary-500",
|
||||
"tw-bg-primary-500",
|
||||
"!tw-text-contrast",
|
||||
"hover:tw-bg-primary-700",
|
||||
"hover:tw-border-primary-700",
|
||||
"focus:tw-bg-primary-700",
|
||||
"focus:tw-border-primary-700",
|
||||
],
|
||||
secondary: [
|
||||
"tw-bg-transparent",
|
||||
"tw-border-text-muted",
|
||||
"!tw-text-muted",
|
||||
"hover:tw-bg-secondary-500",
|
||||
"hover:tw-border-secondary-500",
|
||||
"hover:!tw-text-contrast",
|
||||
"focus:tw-bg-secondary-500",
|
||||
"focus:tw-border-secondary-500",
|
||||
"focus:!tw-text-contrast",
|
||||
],
|
||||
danger: [
|
||||
"tw-bg-transparent",
|
||||
"tw-border-danger-500",
|
||||
"!tw-text-danger",
|
||||
"hover:tw-bg-danger-500",
|
||||
"hover:tw-border-danger-500",
|
||||
"hover:!tw-text-contrast",
|
||||
"focus:tw-bg-danger-500",
|
||||
"focus:tw-border-danger-500",
|
||||
"focus:!tw-text-contrast",
|
||||
],
|
||||
};
|
||||
|
||||
@Directive({
|
||||
selector: "button[bitButton], a[bitButton]",
|
||||
})
|
||||
export class ButtonDirective {
|
||||
@HostBinding("class") get classList() {
|
||||
return [
|
||||
"tw-font-semibold",
|
||||
"tw-py-1.5",
|
||||
"tw-px-3",
|
||||
"tw-rounded",
|
||||
"tw-transition",
|
||||
"tw-border",
|
||||
"tw-border-solid",
|
||||
"tw-text-center",
|
||||
"hover:tw-no-underline",
|
||||
"disabled:tw-bg-secondary-100",
|
||||
"disabled:tw-border-secondary-100",
|
||||
"disabled:!tw-text-main",
|
||||
"focus:tw-outline-none",
|
||||
"focus:tw-ring",
|
||||
"focus:tw-ring-offset-2",
|
||||
"focus:tw-ring-primary-700",
|
||||
"focus:tw-z-10",
|
||||
]
|
||||
.concat(this.block ? ["tw-w-full", "tw-block"] : ["tw-inline-block"])
|
||||
.concat(buttonStyles[this.buttonType] ?? []);
|
||||
}
|
||||
|
||||
@Input()
|
||||
buttonType: ButtonTypes = "secondary";
|
||||
|
||||
@Input()
|
||||
block = false;
|
||||
}
|
||||
11
libs/components/src/button/button.module.ts
Normal file
11
libs/components/src/button/button.module.ts
Normal file
@@ -0,0 +1,11 @@
|
||||
import { CommonModule } from "@angular/common";
|
||||
import { NgModule } from "@angular/core";
|
||||
|
||||
import { ButtonDirective } from "./button.directive";
|
||||
|
||||
@NgModule({
|
||||
imports: [CommonModule],
|
||||
exports: [ButtonDirective],
|
||||
declarations: [ButtonDirective],
|
||||
})
|
||||
export class ButtonModule {}
|
||||
54
libs/components/src/button/button.stories.ts
Normal file
54
libs/components/src/button/button.stories.ts
Normal file
@@ -0,0 +1,54 @@
|
||||
import { Meta, Story } from "@storybook/angular";
|
||||
|
||||
import { ButtonDirective } from "./button.directive";
|
||||
|
||||
export default {
|
||||
title: "Jslib/Button",
|
||||
component: ButtonDirective,
|
||||
args: {
|
||||
buttonType: "primary",
|
||||
},
|
||||
parameters: {
|
||||
design: {
|
||||
type: "figma",
|
||||
url: "https://www.figma.com/file/f32LSg3jaegICkMu7rPARm/Tailwind-Component-Library-Update?node-id=1881%3A16733",
|
||||
},
|
||||
},
|
||||
} as Meta;
|
||||
|
||||
const Template: Story<ButtonDirective> = (args: ButtonDirective) => ({
|
||||
props: args,
|
||||
template: `
|
||||
<button bitButton [buttonType]="buttonType" [block]="block">Button</button>
|
||||
<a bitButton [buttonType]="buttonType" [block]="block" href="#" class="tw-ml-2">Link</a>
|
||||
`,
|
||||
});
|
||||
|
||||
export const Primary = Template.bind({});
|
||||
Primary.args = {
|
||||
buttonType: "primary",
|
||||
};
|
||||
|
||||
export const Secondary = Template.bind({});
|
||||
Secondary.args = {
|
||||
buttonType: "secondary",
|
||||
};
|
||||
|
||||
export const Danger = Template.bind({});
|
||||
Danger.args = {
|
||||
buttonType: "danger",
|
||||
};
|
||||
|
||||
const DisabledTemplate: Story = (args) => ({
|
||||
props: args,
|
||||
template: `
|
||||
<button bitButton disabled buttonType="primary" class="tw-mr-2">Primary</button>
|
||||
<button bitButton disabled buttonType="secondary" class="tw-mr-2">Secondary</button>
|
||||
<button bitButton disabled buttonType="danger" class="tw-mr-2">Danger</button>
|
||||
`,
|
||||
});
|
||||
|
||||
export const Disabled = DisabledTemplate.bind({});
|
||||
Disabled.args = {
|
||||
size: "small",
|
||||
};
|
||||
2
libs/components/src/button/index.ts
Normal file
2
libs/components/src/button/index.ts
Normal file
@@ -0,0 +1,2 @@
|
||||
export * from "./button.directive";
|
||||
export * from "./button.module";
|
||||
Reference in New Issue
Block a user