[CL-63] Color password component (#4018)

This commit is contained in:
Thomas Rittson 2022-11-18 07:33:54 +10:00 committed by GitHub
parent a57424df75
commit dc84a54928
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 144 additions and 0 deletions

View File

@ -0,0 +1,79 @@
import { Component, HostBinding, Input } from "@angular/core";
import { Utils } from "@bitwarden/common/misc/utils";
enum CharacterType {
Letter,
Emoji,
Special,
Number,
}
@Component({
selector: "bit-color-password",
template: `<div
*ngFor="let character of passwordArray; index as i"
[class]="getCharacterClass(character)"
>
<span>{{ character }}</span>
<span *ngIf="showCount" class="tw-whitespace-nowrap tw-text-xs tw-leading-5 tw-text-main">{{
i + 1
}}</span>
</div>`,
})
export class ColorPasswordComponent {
@Input() private password: string = null;
@Input() showCount = false;
characterStyles: Record<CharacterType, string[]> = {
[CharacterType.Emoji]: [],
[CharacterType.Letter]: ["tw-text-main"],
[CharacterType.Special]: ["tw-text-danger"],
[CharacterType.Number]: ["tw-text-primary-500"],
};
@HostBinding("class")
get classList() {
return ["tw-min-w-0", "tw-whitespace-pre-wrap", "tw-break-all"];
}
get passwordArray() {
// Convert to an array to handle cases that strings have special characters, i.e.: emoji.
return Array.from(this.password);
}
getCharacterClass(character: string) {
const charType = this.getCharacterType(character);
const charClass = this.characterStyles[charType].concat("tw-inline-flex");
if (this.showCount) {
return charClass.concat([
"tw-inline-flex",
"tw-flex-col",
"tw-items-center",
"tw-w-7",
"tw-py-1",
"odd:tw-bg-secondary-100",
]);
}
return charClass;
}
private getCharacterType(character: string): CharacterType {
if (character.match(Utils.regexpEmojiPresentation)) {
return CharacterType.Emoji;
}
if (character.match(/\d/)) {
return CharacterType.Number;
}
const specials = ["&", "<", ">", " "];
if (specials.includes(character) || character.match(/[^\w ]/)) {
return CharacterType.Special;
}
return CharacterType.Letter;
}
}

View File

@ -0,0 +1,11 @@
import { CommonModule } from "@angular/common";
import { NgModule } from "@angular/core";
import { ColorPasswordComponent } from "./color-password.component";
@NgModule({
imports: [CommonModule],
exports: [ColorPasswordComponent],
declarations: [ColorPasswordComponent],
})
export class ColorPasswordModule {}

View File

@ -0,0 +1,52 @@
import { Meta, Story } from "@storybook/angular";
import { ColorPasswordComponent } from "./color-password.component";
const examplePassword = "Wq$Jk😀7jDX#rS5Sdi!z";
export default {
title: "Component Library/Color Password",
component: ColorPasswordComponent,
args: {
password: examplePassword,
showCount: false,
},
parameters: {
design: {
type: "figma",
url: "https://www.figma.com/file/6fvTDa3zfvgWdizLQ7nSTP/Numbered-Password",
},
},
} as Meta;
const Template: Story<ColorPasswordComponent> = (args: ColorPasswordComponent) => ({
props: args,
template: `
<bit-color-password class="tw-text-base" [password]="password" [showCount]="showCount"></bit-color-password>
`,
});
const WrappedTemplate: Story<ColorPasswordComponent> = (args: ColorPasswordComponent) => ({
props: args,
template: `
<div class="tw-max-w-32">
<bit-color-password class="tw-text-base" [password]="password" [showCount]="showCount"></bit-color-password>
</div>
`,
});
export const ColorPassword = Template.bind({});
export const WrappedColorPassword = WrappedTemplate.bind({});
export const ColorPasswordCount = Template.bind({});
ColorPasswordCount.args = {
password: examplePassword,
showCount: true,
};
export const WrappedColorPasswordCount = WrappedTemplate.bind({});
WrappedColorPasswordCount.args = {
password: examplePassword,
showCount: true,
};

View File

@ -0,0 +1 @@
export * from "./color-password.module";

View File

@ -14,4 +14,5 @@ export * from "./multi-select";
export * from "./tabs";
export * from "./table";
export * from "./toggle-group";
export * from "./color-password";
export * from "./utils/i18n-mock.service";