diff --git a/.storybook/stories/forms/forms-input-group.stories.ts b/.storybook/stories/forms/forms-input-group.stories.ts new file mode 100644 index 0000000000..ed864abcb2 --- /dev/null +++ b/.storybook/stories/forms/forms-input-group.stories.ts @@ -0,0 +1,195 @@ +/* + * Copyright (c) 2016-2024 Broadcom. All Rights Reserved. + * The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. + * This software is released under MIT license. + * The full license information can be found in LICENSE in the root directory of this project. + */ + +import { ChangeDetectorRef, Component, Input } from '@angular/core'; +import { FormControl, FormGroup } from '@angular/forms'; +import { ClrFormLayout, ClrFormsModule, ClrLayoutModule } from '@clr/angular'; +import { argsToTemplate, moduleMetadata, StoryObj } from '@storybook/angular'; + +import { CommonModules } from '../../helpers/common'; + +@Component({ + selector: 'forms-input-group', + template: ` +
+ + + + + Helper Subtext + State Subtext + State Subtext + + + + + + Helper Subtext + State Subtext + State Subtext + + + + + + + Helper Subtext + State Subtext + State Subtext + + + + +
$
+
.00
+ Helper Subtext + State Subtext + State Subtext +
+ + + +
+ +
+ Helper Subtext + State Subtext + State Subtext +
+
+ `, +}) +class FormsStoryComponent { + _isDisabled = false; + _isSuccess = false; + _isError = false; + + form = new FormGroup({ + text: new FormControl(), + }); + + @Input() clrLayout = ClrFormLayout.HORIZONTAL; + + constructor(private changeDetectorRef: ChangeDetectorRef) {} + + @Input() + get isDisabled() { + return this._isDisabled; + } + set isDisabled(value: boolean) { + this._isDisabled = value; + this.setControlsState(); + } + + @Input() + get isError() { + return this._isError; + } + set isError(value: boolean) { + this._isError = value; + this.setControlsState(); + } + + @Input() + get isSuccess() { + return this._isSuccess; + } + set isSuccess(value: boolean) { + this._isSuccess = value; + this.setControlsState(); + } + + setControlsState() { + this.form.enable(); + Object.keys(this.form.controls).forEach(control => { + if (this._isDisabled) { + this.form.get(control)?.disable(); + } else { + if (this._isError && !this._isSuccess) { + this.form.get(control).setErrors({ required: true }); + this.form.get(control).markAsTouched(); + this.form.get(control).markAsDirty(); + } else if (this._isSuccess) { + this.form.get(control).setErrors(null); + this.form.get(control).markAsTouched(); + } + } + }); + this.form.updateValueAndValidity(); + this.changeDetectorRef.detectChanges(); + } +} + +export default { + title: 'Forms/Input Group', + component: FormsStoryComponent, + decorators: [ + moduleMetadata({ + declarations: [FormsStoryComponent], + imports: [...CommonModules, ClrLayoutModule, ClrFormsModule], + }), + ], + argTypes: { + getProviderFromContainer: { control: { disable: true }, table: { disable: true } }, + triggerValidation: { control: { disable: true }, table: { disable: true } }, + clrLayout: { control: 'radio', options: Object.values(ClrFormLayout).filter(value => typeof value === 'string') }, + }, + args: { + clrLayout: ClrFormLayout.HORIZONTAL, + isDisabled: false, + isError: false, + isSuccess: false, + }, + render: (args: FormsStoryComponent) => ({ + props: { + ...args, + }, + template: ` + + `, + }), +}; + +type Story = StoryObj; + +export const InputStates: Story = {}; + +export const VerticalInputStates: Story = { + args: { clrLayout: ClrFormLayout.VERTICAL }, +}; + +export const CompactInputStates: Story = { + args: { clrLayout: ClrFormLayout.COMPACT }, +}; + +export const DisabledStates: Story = { + args: { isDisabled: true }, +}; + +export const ErrorStates: Story = { + args: { isError: true }, +}; +export const VerticalErrorStates: Story = { + args: { isError: true, clrLayout: ClrFormLayout.VERTICAL }, +}; +export const CompactErrorStates: Story = { + args: { isError: true, clrLayout: ClrFormLayout.COMPACT }, +}; + +export const SuccessStates: Story = { + args: { isSuccess: true }, +}; +export const VerticalSuccessStates: Story = { + args: { isSuccess: true, clrLayout: ClrFormLayout.VERTICAL }, +}; +export const CompactSuccessStates: Story = { + args: { isSuccess: true, clrLayout: ClrFormLayout.COMPACT }, +}; diff --git a/projects/angular/clarity.api.md b/projects/angular/clarity.api.md index 4ef3dac9a9..9326bce254 100644 --- a/projects/angular/clarity.api.md +++ b/projects/angular/clarity.api.md @@ -2635,7 +2635,7 @@ export class ClrInput extends WrappedFormControl { // @public (undocumented) export class ClrInputContainer extends ClrAbstractContainer { // (undocumented) - static ɵcmp: i0.ɵɵComponentDeclaration; + static ɵcmp: i0.ɵɵComponentDeclaration; // (undocumented) static ɵfac: i0.ɵɵFactoryDeclaration; } diff --git a/projects/angular/src/forms/input/input-container.ts b/projects/angular/src/forms/input/input-container.ts index c5cab0f98c..abb43d9f8d 100644 --- a/projects/angular/src/forms/input/input-container.ts +++ b/projects/angular/src/forms/input/input-container.ts @@ -20,7 +20,11 @@ import { NgControlService } from '../common/providers/ng-control.service';
- +
+ + + +
.clr-input-group { max-width: 100%; width: 100%; - padding-right: mixins.baselinePx(10); & > .clr-input { width: calc(100% - tokens.$cds-global-space-9);