1
0
mirror of https://github.com/bitwarden/browser synced 2025-12-18 09:13:33 +00:00

[CL-38] Follow Angular styleguide naming convention, simplify hostbinding logic (#787)

This commit is contained in:
Oscar Hinton
2022-06-02 11:16:59 +02:00
committed by GitHub
parent 78d2f957d5
commit 2b647df001
17 changed files with 92 additions and 113 deletions

View File

@@ -1,4 +1,4 @@
import { Directive, ElementRef, HostBinding, Input, OnChanges, OnInit } from "@angular/core"; import { Directive, ElementRef, HostBinding, Input } from "@angular/core";
type BadgeTypes = "primary" | "secondary" | "success" | "danger" | "warning" | "info"; type BadgeTypes = "primary" | "secondary" | "success" | "danger" | "warning" | "info";
@@ -21,28 +21,10 @@ const hoverStyles: Record<BadgeTypes, string[]> = {
}; };
@Directive({ @Directive({
selector: "span[bit-badge], a[bit-badge], button[bit-badge]", selector: "span[bitBadge], a[bitBadge], button[bitBadge]",
}) })
export class BadgeComponent implements OnInit, OnChanges { export class BadgeDirective {
@HostBinding("class") @Input("class") classList = ""; @HostBinding("class") get classList() {
@Input() badgeType: BadgeTypes = "primary";
private isSpan = false;
constructor(private el: ElementRef<Element>) {
this.isSpan = el?.nativeElement?.nodeName == "SPAN";
}
ngOnInit(): void {
this.classList = this.classes.join(" ");
}
ngOnChanges() {
this.ngOnInit();
}
get classes() {
return [ return [
"tw-inline-block", "tw-inline-block",
"tw-py-1", "tw-py-1",
@@ -63,6 +45,14 @@ export class BadgeComponent implements OnInit, OnChanges {
"focus:tw-ring-primary-700", "focus:tw-ring-primary-700",
] ]
.concat(styles[this.badgeType]) .concat(styles[this.badgeType])
.concat(this.isSpan ? [] : hoverStyles[this.badgeType]); .concat(this.hasHoverEffects ? hoverStyles[this.badgeType] : []);
}
@Input() badgeType: BadgeTypes = "primary";
private hasHoverEffects = false;
constructor(el: ElementRef<Element>) {
this.hasHoverEffects = el?.nativeElement?.nodeName != "SPAN";
} }
} }

View File

@@ -1,11 +1,11 @@
import { CommonModule } from "@angular/common"; import { CommonModule } from "@angular/common";
import { NgModule } from "@angular/core"; import { NgModule } from "@angular/core";
import { BadgeComponent } from "./badge.component"; import { BadgeDirective } from "./badge.directive";
@NgModule({ @NgModule({
imports: [CommonModule], imports: [CommonModule],
exports: [BadgeComponent], exports: [BadgeDirective],
declarations: [BadgeComponent], declarations: [BadgeDirective],
}) })
export class BadgeModule {} export class BadgeModule {}

View File

@@ -1,12 +1,12 @@
import { Meta, Story } from "@storybook/angular"; import { Meta, Story } from "@storybook/angular";
import { BadgeComponent } from "./badge.component"; import { BadgeDirective } from "./badge.directive";
export default { export default {
title: "Jslib/Badge", title: "Jslib/Badge",
component: BadgeComponent, component: BadgeDirective,
args: { args: {
type: "primary", badgeType: "primary",
}, },
parameters: { parameters: {
design: { design: {
@@ -16,14 +16,14 @@ export default {
}, },
} as Meta; } as Meta;
const Template: Story<BadgeComponent> = (args: BadgeComponent) => ({ const Template: Story<BadgeDirective> = (args: BadgeDirective) => ({
props: args, props: args,
template: ` template: `
<span class="tw-text-main">Span </span><span bit-badge [badgeType]="type">Badge</span> <span class="tw-text-main">Span </span><span bitBadge [badgeType]="badgeType">Badge</span>
<br><br> <br><br>
<span class="tw-text-main">Link </span><a href="#" bit-badge [badgeType]="type">Badge</a> <span class="tw-text-main">Link </span><a href="#" bitBadge [badgeType]="badgeType">Badge</a>
<br><br> <br><br>
<span class="tw-text-main">Button </span><button bit-badge [badgeType]="type">Badge</button> <span class="tw-text-main">Button </span><button bitBadge [badgeType]="badgeType">Badge</button>
`, `,
}); });
@@ -32,25 +32,25 @@ Primary.args = {};
export const Secondary = Template.bind({}); export const Secondary = Template.bind({});
Secondary.args = { Secondary.args = {
type: "secondary", badgeType: "secondary",
}; };
export const Success = Template.bind({}); export const Success = Template.bind({});
Success.args = { Success.args = {
type: "success", badgeType: "success",
}; };
export const Danger = Template.bind({}); export const Danger = Template.bind({});
Danger.args = { Danger.args = {
type: "danger", badgeType: "danger",
}; };
export const Warning = Template.bind({}); export const Warning = Template.bind({});
Warning.args = { Warning.args = {
type: "warning", badgeType: "warning",
}; };
export const Info = Template.bind({}); export const Info = Template.bind({});
Info.args = { Info.args = {
type: "info", badgeType: "info",
}; };

View File

@@ -1,2 +1,2 @@
export * from "./badge.component"; export * from "./badge.directive";
export * from "./badge.module"; export * from "./badge.module";

View File

@@ -67,8 +67,8 @@ describe("Button", () => {
@Component({ @Component({
selector: "test-app", selector: "test-app",
template: ` template: `
<button type="button" bit-button [buttonType]="buttonType" [block]="block">Button</button> <button type="button" bitButton [buttonType]="buttonType" [block]="block">Button</button>
<a href="#" bit-button [buttonType]="buttonType" [block]="block"> Link </a> <a href="#" bitButton [buttonType]="buttonType" [block]="block"> Link </a>
`, `,
}) })
class TestApp { class TestApp {

View File

@@ -1,8 +1,8 @@
import { Input, HostBinding, OnChanges, Directive, OnInit } from "@angular/core"; import { Input, HostBinding, Directive } from "@angular/core";
export type ButtonTypes = "primary" | "secondary" | "danger"; export type ButtonTypes = "primary" | "secondary" | "danger";
const buttonStyles: Record<ButtonTypes, string> = { const buttonStyles: Record<ButtonTypes, string[]> = {
primary: [ primary: [
"tw-border-primary-500", "tw-border-primary-500",
"tw-bg-primary-500", "tw-bg-primary-500",
@@ -11,7 +11,7 @@ const buttonStyles: Record<ButtonTypes, string> = {
"hover:tw-border-primary-700", "hover:tw-border-primary-700",
"focus:tw-bg-primary-700", "focus:tw-bg-primary-700",
"focus:tw-border-primary-700", "focus:tw-border-primary-700",
].join(" "), ],
secondary: [ secondary: [
"tw-bg-transparent", "tw-bg-transparent",
"tw-border-text-muted", "tw-border-text-muted",
@@ -22,7 +22,7 @@ const buttonStyles: Record<ButtonTypes, string> = {
"focus:tw-bg-secondary-500", "focus:tw-bg-secondary-500",
"focus:tw-border-secondary-500", "focus:tw-border-secondary-500",
"focus:!tw-text-contrast", "focus:!tw-text-contrast",
].join(" "), ],
danger: [ danger: [
"tw-bg-transparent", "tw-bg-transparent",
"tw-border-danger-500", "tw-border-danger-500",
@@ -33,30 +33,14 @@ const buttonStyles: Record<ButtonTypes, string> = {
"focus:tw-bg-danger-500", "focus:tw-bg-danger-500",
"focus:tw-border-danger-500", "focus:tw-border-danger-500",
"focus:!tw-text-contrast", "focus:!tw-text-contrast",
].join(" "), ],
}; };
@Directive({ @Directive({
selector: "button[bit-button], a[bit-button]", selector: "button[bitButton], a[bitButton]",
}) })
export class ButtonComponent implements OnInit, OnChanges { export class ButtonDirective {
@HostBinding("class") @Input() classList = ""; @HostBinding("class") get classList() {
@Input()
buttonType: ButtonTypes = "secondary";
@Input()
block = false;
ngOnInit(): void {
this.classList = this.classes.join(" ");
}
ngOnChanges() {
this.ngOnInit();
}
get classes(): string[] {
return [ return [
"tw-font-semibold", "tw-font-semibold",
"tw-py-1.5", "tw-py-1.5",
@@ -75,8 +59,14 @@ export class ButtonComponent implements OnInit, OnChanges {
"focus:tw-ring-offset-2", "focus:tw-ring-offset-2",
"focus:tw-ring-primary-700", "focus:tw-ring-primary-700",
"focus:tw-z-10", "focus:tw-z-10",
this.block ? "tw-w-full tw-block" : "tw-inline-block", ]
buttonStyles[this.buttonType ?? "secondary"], .concat(this.block ? ["tw-w-full", "tw-block"] : ["tw-inline-block"])
]; .concat(buttonStyles[this.buttonType] ?? []);
} }
@Input()
buttonType: ButtonTypes = "secondary";
@Input()
block = false;
} }

View File

@@ -1,11 +1,11 @@
import { CommonModule } from "@angular/common"; import { CommonModule } from "@angular/common";
import { NgModule } from "@angular/core"; import { NgModule } from "@angular/core";
import { ButtonComponent } from "./button.component"; import { ButtonDirective } from "./button.directive";
@NgModule({ @NgModule({
imports: [CommonModule], imports: [CommonModule],
exports: [ButtonComponent], exports: [ButtonDirective],
declarations: [ButtonComponent], declarations: [ButtonDirective],
}) })
export class ButtonModule {} export class ButtonModule {}

View File

@@ -1,10 +1,10 @@
import { Meta, Story } from "@storybook/angular"; import { Meta, Story } from "@storybook/angular";
import { ButtonComponent } from "./button.component"; import { ButtonDirective } from "./button.directive";
export default { export default {
title: "Jslib/Button", title: "Jslib/Button",
component: ButtonComponent, component: ButtonDirective,
args: { args: {
buttonType: "primary", buttonType: "primary",
}, },
@@ -16,11 +16,11 @@ export default {
}, },
} as Meta; } as Meta;
const Template: Story<ButtonComponent> = (args: ButtonComponent) => ({ const Template: Story<ButtonDirective> = (args: ButtonDirective) => ({
props: args, props: args,
template: ` template: `
<button bit-button [buttonType]="buttonType" [block]="block">Button</button> <button bitButton [buttonType]="buttonType" [block]="block">Button</button>
<a bit-button [buttonType]="buttonType" [block]="block" href="#" class="tw-ml-2">Link</a> <a bitButton [buttonType]="buttonType" [block]="block" href="#" class="tw-ml-2">Link</a>
`, `,
}); });
@@ -42,9 +42,9 @@ Danger.args = {
const DisabledTemplate: Story = (args) => ({ const DisabledTemplate: Story = (args) => ({
props: args, props: args,
template: ` template: `
<button bit-button disabled buttonType="primary" class="tw-mr-2">Primary</button> <button bitButton disabled buttonType="primary" class="tw-mr-2">Primary</button>
<button bit-button disabled buttonType="secondary" class="tw-mr-2">Secondary</button> <button bitButton disabled buttonType="secondary" class="tw-mr-2">Secondary</button>
<button bit-button disabled buttonType="danger" class="tw-mr-2">Danger</button> <button bitButton disabled buttonType="danger" class="tw-mr-2">Danger</button>
`, `,
}); });

View File

@@ -1,2 +1,2 @@
export * from "./button.component"; export * from "./button.directive";
export * from "./button.module"; export * from "./button.module";

View File

@@ -68,7 +68,7 @@ const Template: Story<BitFormFieldComponent> = (args: BitFormFieldComponent) =>
<input bitInput formControlName="email" /> <input bitInput formControlName="email" />
</bit-form-field> </bit-form-field>
<button type="submit" bit-button buttonType="primary">Submit</button> <button type="submit" bitButton buttonType="primary">Submit</button>
<bit-error-summary [formGroup]="formObj"></bit-error-summary> <bit-error-summary [formGroup]="formObj"></bit-error-summary>
</form> </form>
`, `,

View File

@@ -87,7 +87,7 @@ const Template: Story<BitFormFieldComponent> = (args: BitFormFieldComponent) =>
<input bitInput formControlName="email" /> <input bitInput formControlName="email" />
</bit-form-field> </bit-form-field>
<button type="submit" bit-button buttonType="primary">Submit</button> <button type="submit" bitButton buttonType="primary">Submit</button>
</form> </form>
`, `,
}); });
@@ -167,12 +167,12 @@ const ButtonGroupTemplate: Story<BitFormFieldComponent> = (args: BitFormFieldCom
<bit-form-field> <bit-form-field>
<bit-label>Label</bit-label> <bit-label>Label</bit-label>
<input bitInput placeholder="Placeholder" /> <input bitInput placeholder="Placeholder" />
<button bitPrefix bit-button>Button</button> <button bitPrefix bitButton>Button</button>
<button bitPrefix bit-button>Button</button> <button bitPrefix bitButton>Button</button>
<button bitSuffix bit-button> <button bitSuffix bitButton>
<i aria-hidden="true" class="bwi bwi-lg bwi-eye"></i> <i aria-hidden="true" class="bwi bwi-lg bwi-eye"></i>
</button> </button>
<button bitSuffix bit-button> <button bitSuffix bitButton>
<i aria-hidden="true" class="bwi bwi-lg bwi-clone"></i> <i aria-hidden="true" class="bwi bwi-lg bwi-clone"></i>
</button> </button>
</bit-form-field> </bit-form-field>

View File

@@ -1,5 +1,5 @@
export * from "./menu.module"; export * from "./menu.module";
export * from "./menu.component"; export * from "./menu.component";
export * from "./menu-trigger-for.directive"; export * from "./menu-trigger-for.directive";
export * from "./menu-item.component"; export * from "./menu-item.directive";
export * from "./menu-divider.component"; export * from "./menu-divider.component";

View File

@@ -1,11 +1,10 @@
import { FocusableOption } from "@angular/cdk/a11y"; import { FocusableOption } from "@angular/cdk/a11y";
import { Component, ElementRef, HostBinding } from "@angular/core"; import { Directive, ElementRef, HostBinding } from "@angular/core";
@Component({ @Directive({
selector: "[bit-menu-item]", selector: "[bitMenuItem]",
template: `<ng-content></ng-content>`,
}) })
export class MenuItemComponent implements FocusableOption { export class MenuItemDirective implements FocusableOption {
@HostBinding("class") classList = [ @HostBinding("class") classList = [
"tw-block", "tw-block",
"tw-py-1", "tw-py-1",
@@ -25,7 +24,7 @@ export class MenuItemComponent implements FocusableOption {
"focus:tw-ring-primary-700", "focus:tw-ring-primary-700",
"active:!tw-ring-0", "active:!tw-ring-0",
"active:!tw-ring-offset-0", "active:!tw-ring-offset-0",
].join(" "); ];
@HostBinding("attr.role") role = "menuitem"; @HostBinding("attr.role") role = "menuitem";
@HostBinding("tabIndex") tabIndex = "-1"; @HostBinding("tabIndex") tabIndex = "-1";

View File

@@ -69,8 +69,8 @@ describe("Menu", () => {
<button type="button" [bitMenuTriggerFor]="testMenu" class="testclass">Open menu</button> <button type="button" [bitMenuTriggerFor]="testMenu" class="testclass">Open menu</button>
<bit-menu #testMenu> <bit-menu #testMenu>
<a id="item1" bit-menu-item>Item 1</a> <a id="item1" bitMenuItem>Item 1</a>
<a id="item2" bit-menu-item>Item 2</a> <a id="item2" bitMenuItem>Item 2</a>
</bit-menu> </bit-menu>
`, `,
}) })

View File

@@ -10,7 +10,7 @@ import {
AfterContentInit, AfterContentInit,
} from "@angular/core"; } from "@angular/core";
import { MenuItemComponent } from "./menu-item.component"; import { MenuItemDirective } from "./menu-item.directive";
@Component({ @Component({
selector: "bit-menu", selector: "bit-menu",
@@ -20,9 +20,9 @@ import { MenuItemComponent } from "./menu-item.component";
export class MenuComponent implements AfterContentInit { export class MenuComponent implements AfterContentInit {
@ViewChild(TemplateRef) templateRef: TemplateRef<any>; @ViewChild(TemplateRef) templateRef: TemplateRef<any>;
@Output() closed = new EventEmitter<void>(); @Output() closed = new EventEmitter<void>();
@ContentChildren(MenuItemComponent, { descendants: true }) @ContentChildren(MenuItemDirective, { descendants: true })
menuItems: QueryList<MenuItemComponent>; menuItems: QueryList<MenuItemDirective>;
keyManager: FocusKeyManager<MenuItemComponent>; keyManager: FocusKeyManager<MenuItemDirective>;
ngAfterContentInit() { ngAfterContentInit() {
this.keyManager = new FocusKeyManager(this.menuItems).withWrap(); this.keyManager = new FocusKeyManager(this.menuItems).withWrap();

View File

@@ -3,13 +3,13 @@ import { CommonModule } from "@angular/common";
import { NgModule } from "@angular/core"; import { NgModule } from "@angular/core";
import { MenuDividerComponent } from "./menu-divider.component"; import { MenuDividerComponent } from "./menu-divider.component";
import { MenuItemComponent } from "./menu-item.component"; import { MenuItemDirective } from "./menu-item.directive";
import { MenuTriggerForDirective } from "./menu-trigger-for.directive"; import { MenuTriggerForDirective } from "./menu-trigger-for.directive";
import { MenuComponent } from "./menu.component"; import { MenuComponent } from "./menu.component";
@NgModule({ @NgModule({
imports: [CommonModule, OverlayModule], imports: [CommonModule, OverlayModule],
declarations: [MenuComponent, MenuTriggerForDirective, MenuItemComponent, MenuDividerComponent], declarations: [MenuComponent, MenuTriggerForDirective, MenuItemDirective, MenuDividerComponent],
exports: [MenuComponent, MenuTriggerForDirective, MenuItemComponent, MenuDividerComponent], exports: [MenuComponent, MenuTriggerForDirective, MenuItemDirective, MenuDividerComponent],
}) })
export class MenuModule {} export class MenuModule {}

View File

@@ -4,7 +4,7 @@ import { Meta, moduleMetadata, Story } from "@storybook/angular";
import { ButtonModule } from "../button/button.module"; import { ButtonModule } from "../button/button.module";
import { MenuDividerComponent } from "./menu-divider.component"; import { MenuDividerComponent } from "./menu-divider.component";
import { MenuItemComponent } from "./menu-item.component"; import { MenuItemDirective } from "./menu-item.directive";
import { MenuTriggerForDirective } from "./menu-trigger-for.directive"; import { MenuTriggerForDirective } from "./menu-trigger-for.directive";
import { MenuComponent } from "./menu.component"; import { MenuComponent } from "./menu.component";
@@ -16,7 +16,7 @@ export default {
declarations: [ declarations: [
MenuTriggerForDirective, MenuTriggerForDirective,
MenuComponent, MenuComponent,
MenuItemComponent, MenuItemDirective,
MenuDividerComponent, MenuDividerComponent,
], ],
imports: [OverlayModule, ButtonModule], imports: [OverlayModule, ButtonModule],
@@ -34,11 +34,11 @@ const Template: Story<MenuTriggerForDirective> = (args: MenuTriggerForDirective)
props: args, props: args,
template: ` template: `
<bit-menu #myMenu="menuComponent"> <bit-menu #myMenu="menuComponent">
<a href="#" bit-menu-item>Anchor link</a> <a href="#" bitMenuItem>Anchor link</a>
<a href="#" bit-menu-item>Another link</a> <a href="#" bitMenuItem>Another link</a>
<button type="button" bit-menu-item>Button</button> <button type="button" bitMenuItem>Button</button>
<bit-menu-divider></bit-menu-divider> <bit-menu-divider></bit-menu-divider>
<button type="button" bit-menu-item>Button after divider</button> <button type="button" bitMenuItem>Button after divider</button>
</bit-menu> </bit-menu>
<div class="tw-h-40"> <div class="tw-h-40">
@@ -53,15 +53,15 @@ const TemplateWithButton: Story<MenuTriggerForDirective> = (args: MenuTriggerFor
props: args, props: args,
template: ` template: `
<div class="tw-h-40"> <div class="tw-h-40">
<button bit-button [buttonType]="secondary" [bitMenuTriggerFor]="myMenu">Open menu</button> <button bitButton buttonType="secondary" [bitMenuTriggerFor]="myMenu">Open menu</button>
</div> </div>
<bit-menu #myMenu> <bit-menu #myMenu>
<a href="#" bit-menu-item>Anchor link</a> <a href="#" bitMenuItem>Anchor link</a>
<a href="#" bit-menu-item>Another link</a> <a href="#" bitMenuItem>Another link</a>
<button type="button" bit-menu-item>Button</button> <button type="button" bitMenuItem>Button</button>
<bit-menu-divider></bit-menu-divider> <bit-menu-divider></bit-menu-divider>
<button type="button" bit-menu-item>Button after divider</button> <button type="button" bitMenuItem>Button after divider</button>
</bit-menu>`, </bit-menu>`,
}); });