From 50493ab6f7956eaaca2b27a391eb9a16dc329ced Mon Sep 17 00:00:00 2001 From: Oscar Hinton Date: Tue, 21 Nov 2023 04:59:03 +0100 Subject: [PATCH] [PM-2195] Adjust radio groups margin (#5410) * Adjust radio groups margin * Move hint margin to input field * Tweak field spacing * Add story for hint, and fix hint display * Fix label ssue * Revert input margin * Re-add margin to hint * Change font weight * Fix required placement * Add support for required * Change margin of radio group * Remove unnecessary div * Fix long inputs cutting off * Fix radio story * Remove newline --------- Co-authored-by: Will Martin --- .../src/checkbox/checkbox.component.ts | 1 + .../src/checkbox/checkbox.stories.ts | 46 +++++++++++- .../form-control/form-control.component.html | 10 +-- .../form-control/form-control.component.ts | 24 ++++-- .../src/form-control/hint.component.ts | 2 +- .../radio-button/radio-button.component.html | 4 +- .../radio-button/radio-button.component.ts | 8 ++ .../src/radio-button/radio-button.module.ts | 3 +- .../src/radio-button/radio-button.stories.ts | 75 +++++++++++++++++-- .../radio-button/radio-group.component.html | 8 +- .../src/radio-button/radio-group.component.ts | 9 ++- .../src/radio-button/radio-input.component.ts | 1 + 12 files changed, 168 insertions(+), 23 deletions(-) diff --git a/libs/components/src/checkbox/checkbox.component.ts b/libs/components/src/checkbox/checkbox.component.ts index 5e1e17a5ca..82113b68c5 100644 --- a/libs/components/src/checkbox/checkbox.component.ts +++ b/libs/components/src/checkbox/checkbox.component.ts @@ -25,6 +25,7 @@ export class CheckboxComponent implements BitFormControlAbstraction { "tw-w-3.5", "tw-mr-1.5", "tw-bottom-[-1px]", // Fix checkbox looking off-center + "tw-flex-none", // Flexbox fix for bit-form-control "before:tw-content-['']", "before:tw-block", diff --git a/libs/components/src/checkbox/checkbox.stories.ts b/libs/components/src/checkbox/checkbox.stories.ts index 11ef32eac7..86b682240d 100644 --- a/libs/components/src/checkbox/checkbox.stories.ts +++ b/libs/components/src/checkbox/checkbox.stories.ts @@ -1,5 +1,12 @@ import { Component, Input } from "@angular/core"; -import { FormsModule, ReactiveFormsModule, FormBuilder, Validators } from "@angular/forms"; +import { + FormsModule, + ReactiveFormsModule, + FormBuilder, + Validators, + FormGroup, + FormControl, +} from "@angular/forms"; import { Meta, StoryObj, moduleMetadata } from "@storybook/angular"; import { I18nService } from "@bitwarden/common/src/platform/abstractions/i18n.service"; @@ -15,7 +22,8 @@ const template = ` Click me - `; + +`; @Component({ selector: "app-example", @@ -89,6 +97,40 @@ export const Default: Story = { }, }; +export const Hint: Story = { + render: (args) => ({ + props: { + formObj: new FormGroup({ + checkbox: new FormControl(false), + }), + }, + template: ` +
+ + + Really long value that never ends. + + Lorem ipsum dolor sit amet, consectetur adipiscing elit. Curabitur iaculis consequat enim vitae elementum. + Ut non odio est. Duis eu nisi ultrices, porttitor lorem eget, ornare libero. Fusce ex ante, consequat ac + sem et, euismod placerat tellus. + + +
+ `, + }), + parameters: { + docs: { + source: { + code: template, + }, + }, + }, + args: { + checked: false, + disabled: false, + }, +}; + export const Custom: Story = { render: (args) => ({ props: args, diff --git a/libs/components/src/form-control/form-control.component.html b/libs/components/src/form-control/form-control.component.html index 9e31bc9ec4..91bba1719d 100644 --- a/libs/components/src/form-control/form-control.component.html +++ b/libs/components/src/form-control/form-control.component.html @@ -1,13 +1,13 @@ -
- -
{{ displayError }}
diff --git a/libs/components/src/form-control/form-control.component.ts b/libs/components/src/form-control/form-control.component.ts index 934622a4a2..b61dee709c 100644 --- a/libs/components/src/form-control/form-control.component.ts +++ b/libs/components/src/form-control/form-control.component.ts @@ -20,22 +20,36 @@ export class FormControlComponent { this._inline = coerceBooleanProperty(value); } + private _disableMargin = false; + @Input() set disableMargin(value: boolean | "") { + this._disableMargin = coerceBooleanProperty(value); + } + get disableMargin() { + return this._disableMargin; + } + @ContentChild(BitFormControlAbstraction) protected formControl: BitFormControlAbstraction; @HostBinding("class") get classes() { - return ["tw-mb-6"].concat(this.inline ? ["tw-inline-block", "tw-mr-4"] : ["tw-block"]); + return [] + .concat(this.inline ? ["tw-inline-block", "tw-mr-4"] : ["tw-block"]) + .concat(this.disableMargin ? [] : ["tw-mb-6"]); } constructor(private i18nService: I18nService) {} protected get labelClasses() { - return ["tw-transition", "tw-select-none", "tw-mb-0"].concat( - this.formControl.disabled ? "tw-cursor-auto" : "tw-cursor-pointer" - ); + return [ + "tw-transition", + "tw-select-none", + "tw-mb-0", + "tw-inline-flex", + "tw-items-baseline", + ].concat(this.formControl.disabled ? "tw-cursor-auto" : "tw-cursor-pointer"); } protected get labelContentClasses() { - return ["tw-font-semibold"].concat( + return ["tw-inline-flex", "tw-flex-col", "tw-font-semibold"].concat( this.formControl.disabled ? "tw-text-muted" : "tw-text-main" ); } diff --git a/libs/components/src/form-control/hint.component.ts b/libs/components/src/form-control/hint.component.ts index 59d01a89da..e5b285c018 100644 --- a/libs/components/src/form-control/hint.component.ts +++ b/libs/components/src/form-control/hint.component.ts @@ -6,7 +6,7 @@ let nextId = 0; @Directive({ selector: "bit-hint", host: { - class: "tw-text-muted tw-inline-block tw-mt-1", + class: "tw-text-muted tw-font-normal tw-inline-block tw-mt-1", }, }) export class BitHintComponent { diff --git a/libs/components/src/radio-button/radio-button.component.html b/libs/components/src/radio-button/radio-button.component.html index 0d45559653..04ed6189a5 100644 --- a/libs/components/src/radio-button/radio-button.component.html +++ b/libs/components/src/radio-button/radio-button.component.html @@ -1,15 +1,15 @@ - + + diff --git a/libs/components/src/radio-button/radio-button.component.ts b/libs/components/src/radio-button/radio-button.component.ts index 8da02488d4..967718f407 100644 --- a/libs/components/src/radio-button/radio-button.component.ts +++ b/libs/components/src/radio-button/radio-button.component.ts @@ -10,6 +10,10 @@ let nextId = 0; }) export class RadioButtonComponent { @HostBinding("attr.id") @Input() id = `bit-radio-button-${nextId++}`; + @HostBinding("class") get classList() { + return [this.block ? "tw-block" : "tw-inline-block", "tw-mb-2"]; + } + @Input() value: unknown; @Input() disabled = false; @@ -31,6 +35,10 @@ export class RadioButtonComponent { return this.groupComponent.disabled; } + get block() { + return this.groupComponent.block; + } + protected onInputChange() { this.groupComponent.onInputChange(this.value); } diff --git a/libs/components/src/radio-button/radio-button.module.ts b/libs/components/src/radio-button/radio-button.module.ts index 11b5bc3732..21fd942704 100644 --- a/libs/components/src/radio-button/radio-button.module.ts +++ b/libs/components/src/radio-button/radio-button.module.ts @@ -2,13 +2,14 @@ import { CommonModule } from "@angular/common"; import { NgModule } from "@angular/core"; import { FormControlModule } from "../form-control"; +import { SharedModule } from "../shared"; import { RadioButtonComponent } from "./radio-button.component"; import { RadioGroupComponent } from "./radio-group.component"; import { RadioInputComponent } from "./radio-input.component"; @NgModule({ - imports: [CommonModule, FormControlModule], + imports: [CommonModule, SharedModule, FormControlModule], declarations: [RadioInputComponent, RadioButtonComponent, RadioGroupComponent], exports: [FormControlModule, RadioInputComponent, RadioButtonComponent, RadioGroupComponent], }) diff --git a/libs/components/src/radio-button/radio-button.stories.ts b/libs/components/src/radio-button/radio-button.stories.ts index da9d9d6b2a..f9b0079936 100644 --- a/libs/components/src/radio-button/radio-button.stories.ts +++ b/libs/components/src/radio-button/radio-button.stories.ts @@ -1,5 +1,5 @@ import { FormsModule, ReactiveFormsModule, FormControl, FormGroup } from "@angular/forms"; -import { Meta, StoryObj, moduleMetadata } from "@storybook/angular"; +import { Meta, moduleMetadata, StoryObj } from "@storybook/angular"; import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; @@ -67,6 +67,37 @@ export const Inline: Story = { }), }; +export const InlineHint: Story = { + render: () => ({ + props: { + formObj: new FormGroup({ + radio: new FormControl(0), + }), + }, + template: ` +
+ + Group of radio buttons + + + First + + + + Second + + + + Third + + + This is a hint for the radio group + +
+ `, + }), +}; + export const Block: Story = { render: () => ({ props: { @@ -76,20 +107,20 @@ export const Block: Story = { }, template: `
- + Group of radio buttons - + First This is a hint for the first option - + Second This is a hint for the second option - + Third This is a hint for the third option @@ -98,3 +129,37 @@ export const Block: Story = { `, }), }; + +export const BlockHint: Story = { + render: () => ({ + props: { + formObj: new FormGroup({ + radio: new FormControl(0), + }), + }, + template: ` + + + Group of radio buttons + + + First + This is a hint for the first option + + + + Second + This is a hint for the second option + + + + Third + This is a hint for the third option + + + This is a hint for the radio group + + + `, + }), +}; diff --git a/libs/components/src/radio-button/radio-group.component.html b/libs/components/src/radio-button/radio-group.component.html index 2931020b2b..128a723d46 100644 --- a/libs/components/src/radio-button/radio-group.component.html +++ b/libs/components/src/radio-button/radio-group.component.html @@ -2,6 +2,7 @@
+ ({{ "required" | i18n }})
@@ -11,4 +12,9 @@ - + +
+ +
+ +
diff --git a/libs/components/src/radio-button/radio-group.component.ts b/libs/components/src/radio-button/radio-group.component.ts index 4b88230394..6a93ee07a6 100644 --- a/libs/components/src/radio-button/radio-group.component.ts +++ b/libs/components/src/radio-button/radio-group.component.ts @@ -1,5 +1,5 @@ import { Component, ContentChild, HostBinding, Input, Optional, Self } from "@angular/core"; -import { ControlValueAccessor, NgControl } from "@angular/forms"; +import { ControlValueAccessor, NgControl, Validators } from "@angular/forms"; import { BitLabel } from "../form-control/label.directive"; @@ -21,8 +21,11 @@ export class RadioGroupComponent implements ControlValueAccessor { this._name = value; } + @Input() block = false; + @HostBinding("attr.role") role = "radiogroup"; @HostBinding("attr.id") @Input() id = `bit-radio-group-${nextId++}`; + @HostBinding("class") classList = ["tw-block", "tw-mb-4"]; @ContentChild(BitLabel) protected label: BitLabel; @@ -32,6 +35,10 @@ export class RadioGroupComponent implements ControlValueAccessor { } } + get required() { + return this.ngControl?.control?.hasValidator(Validators.required) ?? false; + } + // ControlValueAccessor onChange: (value: unknown) => void; onTouched: () => void; diff --git a/libs/components/src/radio-button/radio-input.component.ts b/libs/components/src/radio-button/radio-input.component.ts index bc767add6e..8b36cbf5ed 100644 --- a/libs/components/src/radio-button/radio-input.component.ts +++ b/libs/components/src/radio-button/radio-input.component.ts @@ -29,6 +29,7 @@ export class RadioInputComponent implements BitFormControlAbstraction { "tw-h-3.5", "tw-mr-1.5", "tw-bottom-[-1px]", // Fix checkbox looking off-center + "tw-flex-none", // Flexbox fix for bit-form-control "hover:tw-border-2", "[&>label:hover]:tw-border-2",