diff --git a/apps/design-land/src/app/form/form.component.html b/apps/design-land/src/app/form/form.component.html
index 3e49be8dd2..201388ae2b 100644
--- a/apps/design-land/src/app/form/form.component.html
+++ b/apps/design-land/src/app/form/form.component.html
@@ -2,8 +2,7 @@
+ [formControl]="form.controls['inputTest1']">
This is a required field >:(
diff --git a/apps/design-land/src/app/input/input.component.html b/apps/design-land/src/app/input/input.component.html
index 9f30c8d256..5f559b4675 100644
--- a/apps/design-land/src/app/input/input.component.html
+++ b/apps/design-land/src/app/input/input.component.html
@@ -1,24 +1,23 @@
Input
-Input is a form control element that can be used in forms.
+The input component allows a native HTML input element to work with the form field component.
-Examples
-
-Basic
-A basic input without using the DaffFormFieldComponent
.
-
-
-
-With DaffFormFieldComponent
-An input using DaffFormField
+Overview
+The input component has the same functionality as a native HTML <input>
element, with additional custom styling and functionality. It can't be used by itself and must be contained within a <daff-form-field>
.
+Basic input with form field
-Disabled
+Disabled input
The input in this example is disabled using the native HTML disabled attribute.
-With Reactive Forms
+Input with error messages
The input in this example uses the ReactiveFormsModule
to display errors.
-
\ No newline at end of file
+
+
+Input with hint
+The input in this example has a hint.
+
+
diff --git a/libs/design/input/examples/src/basic-input/basic-input.component.ts b/libs/design/input/examples/src/basic-input/basic-input.component.ts
index 299731fdda..cea1ce8471 100644
--- a/libs/design/input/examples/src/basic-input/basic-input.component.ts
+++ b/libs/design/input/examples/src/basic-input/basic-input.component.ts
@@ -10,8 +10,9 @@ import { DaffInputModule } from '@daffodil/design';
selector: 'basic-input',
templateUrl: './basic-input.component.html',
changeDetection: ChangeDetectionStrategy.OnPush,
- imports: [DaffInputModule],
+ standalone: true,
+ imports: [
+ DaffInputModule,
+ ],
})
-export class BasicInputComponent {
-
-}
+export class BasicInputComponent { }
diff --git a/libs/design/input/examples/src/examples.ts b/libs/design/input/examples/src/examples.ts
index acee588cb3..22a5c662c4 100644
--- a/libs/design/input/examples/src/examples.ts
+++ b/libs/design/input/examples/src/examples.ts
@@ -1,11 +1,15 @@
import { BasicInputComponent } from './basic-input/basic-input.component';
import { InputDisabledComponent } from './input-disabled/input-disabled.component';
import { InputErrorComponent } from './input-error/input-error.component';
+import { InputHintComponent } from './input-hint/input-hint.component';
import { InputWithFormFieldComponent } from './input-with-form-field/input-with-form-field.component';
+import { PasswordWithFormFieldComponent } from './password-with-form-field/password-with-form-field.component';
export const INPUT_EXAMPLES = [
BasicInputComponent,
InputWithFormFieldComponent,
InputDisabledComponent,
InputErrorComponent,
+ PasswordWithFormFieldComponent,
+ InputHintComponent,
];
diff --git a/libs/design/input/examples/src/input-disabled/input-disabled.component.html b/libs/design/input/examples/src/input-disabled/input-disabled.component.html
index edf6f1b289..21f1998567 100644
--- a/libs/design/input/examples/src/input-disabled/input-disabled.component.html
+++ b/libs/design/input/examples/src/input-disabled/input-disabled.component.html
@@ -1,3 +1,4 @@
-
+ Email
+
\ No newline at end of file
diff --git a/libs/design/input/examples/src/input-disabled/input-disabled.component.ts b/libs/design/input/examples/src/input-disabled/input-disabled.component.ts
index f344bc317f..7dd46a688f 100644
--- a/libs/design/input/examples/src/input-disabled/input-disabled.component.ts
+++ b/libs/design/input/examples/src/input-disabled/input-disabled.component.ts
@@ -2,6 +2,10 @@ import {
ChangeDetectionStrategy,
Component,
} from '@angular/core';
+import {
+ ReactiveFormsModule,
+ UntypedFormControl,
+} from '@angular/forms';
import {
DaffFormFieldModule,
@@ -12,9 +16,19 @@ import {
// eslint-disable-next-line @angular-eslint/component-selector
selector: 'input-disabled',
templateUrl: './input-disabled.component.html',
+ styles: [`
+ daff-form-field {
+ max-width: 320px;
+ }
+ `],
changeDetection: ChangeDetectionStrategy.OnPush,
- imports: [DaffFormFieldModule, DaffInputModule],
+ standalone: true,
+ imports: [
+ ReactiveFormsModule,
+ DaffFormFieldModule,
+ DaffInputModule,
+ ],
})
export class InputDisabledComponent {
-
+ disabled = new UntypedFormControl({ value : '' , disabled: true });
}
diff --git a/libs/design/input/examples/src/input-error/input-error.component.html b/libs/design/input/examples/src/input-error/input-error.component.html
index e8683fad5e..506edf187a 100644
--- a/libs/design/input/examples/src/input-error/input-error.component.html
+++ b/libs/design/input/examples/src/input-error/input-error.component.html
@@ -1,4 +1,11 @@
-
+ Email
+
+ @if (control.errors?.required) {
+ Email is a required field.
+ }
+ @if (control.errors?.email) {
+ Email is not valid.
+ }
Value: {{ control.value }}
\ No newline at end of file
diff --git a/libs/design/input/examples/src/input-error/input-error.component.ts b/libs/design/input/examples/src/input-error/input-error.component.ts
index b659aeea55..966057925c 100644
--- a/libs/design/input/examples/src/input-error/input-error.component.ts
+++ b/libs/design/input/examples/src/input-error/input-error.component.ts
@@ -10,6 +10,7 @@ import {
import {
DaffFormFieldModule,
+ DaffHintComponent,
DaffInputModule,
} from '@daffodil/design';
@@ -17,10 +18,16 @@ import {
// eslint-disable-next-line @angular-eslint/component-selector
selector: 'input-error',
templateUrl: './input-error.component.html',
+ styles: [`
+ daff-form-field {
+ max-width: 320px;
+ }
+ `],
changeDetection: ChangeDetectionStrategy.OnPush,
imports: [
DaffFormFieldModule,
DaffInputModule,
+ DaffHintComponent,
ReactiveFormsModule,
],
})
diff --git a/libs/design/input/examples/src/input-hint/input-hint.component.html b/libs/design/input/examples/src/input-hint/input-hint.component.html
new file mode 100644
index 0000000000..d4fdf9d9a3
--- /dev/null
+++ b/libs/design/input/examples/src/input-hint/input-hint.component.html
@@ -0,0 +1,5 @@
+
+ Email
+
+ Hint goes here.
+
\ No newline at end of file
diff --git a/libs/design/input/examples/src/input-hint/input-hint.component.ts b/libs/design/input/examples/src/input-hint/input-hint.component.ts
new file mode 100644
index 0000000000..a2057dee67
--- /dev/null
+++ b/libs/design/input/examples/src/input-hint/input-hint.component.ts
@@ -0,0 +1,30 @@
+import {
+ ChangeDetectionStrategy,
+ Component,
+} from '@angular/core';
+
+import {
+ DaffFormFieldModule,
+ DaffHintComponent,
+ DaffInputModule,
+} from '@daffodil/design';
+
+@Component({
+ // eslint-disable-next-line @angular-eslint/component-selector
+ selector: 'input-hint',
+ templateUrl: './input-hint.component.html',
+ styles: [`
+ daff-form-field {
+ max-width: 320px;
+ }
+ `],
+ changeDetection: ChangeDetectionStrategy.OnPush,
+ standalone: true,
+ imports: [
+ DaffFormFieldModule,
+ DaffInputModule,
+ DaffHintComponent,
+ ],
+})
+export class InputHintComponent {
+}
diff --git a/libs/design/input/examples/src/input-with-form-field/input-with-form-field.component.html b/libs/design/input/examples/src/input-with-form-field/input-with-form-field.component.html
index 0fb7567fd5..87274b93ea 100644
--- a/libs/design/input/examples/src/input-with-form-field/input-with-form-field.component.html
+++ b/libs/design/input/examples/src/input-with-form-field/input-with-form-field.component.html
@@ -1,3 +1,6 @@
-
-
+
+ First Name
+
+
+
\ No newline at end of file
diff --git a/libs/design/input/examples/src/input-with-form-field/input-with-form-field.component.ts b/libs/design/input/examples/src/input-with-form-field/input-with-form-field.component.ts
index ffc7b9de8e..a81e32d0c5 100644
--- a/libs/design/input/examples/src/input-with-form-field/input-with-form-field.component.ts
+++ b/libs/design/input/examples/src/input-with-form-field/input-with-form-field.component.ts
@@ -2,19 +2,37 @@ import {
ChangeDetectionStrategy,
Component,
} from '@angular/core';
+import { FaIconComponent } from '@fortawesome/angular-fontawesome';
+import {
+ faUser,
+ faCircleXmark,
+} from '@fortawesome/free-solid-svg-icons';
import {
DaffFormFieldModule,
DaffInputModule,
+ DaffPrefixSuffixModule,
} from '@daffodil/design';
@Component({
// eslint-disable-next-line @angular-eslint/component-selector
selector: 'input-with-form-field',
templateUrl: './input-with-form-field.component.html',
+ styles: [`
+ daff-form-field {
+ max-width: 320px;
+ }
+ `],
changeDetection: ChangeDetectionStrategy.OnPush,
- imports: [DaffFormFieldModule, DaffInputModule],
+ standalone: true,
+ imports: [
+ DaffFormFieldModule,
+ DaffInputModule,
+ FaIconComponent,
+ DaffPrefixSuffixModule,
+ ],
})
export class InputWithFormFieldComponent {
-
+ faUser = faUser;
+ faCircleXmark = faCircleXmark;
}
diff --git a/libs/design/scss/theme.scss b/libs/design/scss/theme.scss
index 3e73b43885..d30924a649 100644
--- a/libs/design/scss/theme.scss
+++ b/libs/design/scss/theme.scss
@@ -27,6 +27,7 @@
@use '../button/src/button/underline/underline-theme' as underline-button;
@use '../article/src/article-theme' as article;
@use '../src/atoms/form/error-message/error-message-theme' as error-message;
+@use '../src/atoms/form/hint/hint-theme' as hint;
@use '../src/atoms/form/form-field/form-field/form-field-theme' as form-field;
@use '../src/atoms/form/input/input-theme' as input;
@use '../src/atoms/form/native-select/native-select-theme' as native-select;
@@ -77,6 +78,7 @@
@include underline-button.daff-underline-button-theme($theme);
@include breadcrumb.daff-breadcrumb-theme($theme);
@include error-message.daff-error-message-theme($theme);
+ @include hint.daff-hint-theme($theme);
@include form-field.daff-form-field-theme($theme);
@include input.daff-input-theme($theme);
@include native-select.daff-native-select-theme($theme);
diff --git a/libs/design/src/atoms/form/error-message/error-message.component.scss b/libs/design/src/atoms/form/error-message/error-message.component.scss
index 78fc8391f7..cd9ba709e5 100644
--- a/libs/design/src/atoms/form/error-message/error-message.component.scss
+++ b/libs/design/src/atoms/form/error-message/error-message.component.scss
@@ -3,5 +3,4 @@
:host {
display: block;
font-size: t.$small-font-size;
- margin-top: 5px;
}
diff --git a/libs/design/src/atoms/form/form-field/behaviors/disableable/disableable-interface.ts b/libs/design/src/atoms/form/form-field/behaviors/disableable/disableable-interface.ts
deleted file mode 100644
index 83b59b74b6..0000000000
--- a/libs/design/src/atoms/form/form-field/behaviors/disableable/disableable-interface.ts
+++ /dev/null
@@ -1,9 +0,0 @@
-import { DaffFormFieldControl } from '../../form-field-control';
-
-/**
- * A behavior interface for tracking the disabled state of a form field.
- */
-export interface DaffDisableable {
- _control: DaffFormFieldControl;
- disabled: boolean;
-}
diff --git a/libs/design/src/atoms/form/form-field/behaviors/focusable/focusable-interface.ts b/libs/design/src/atoms/form/form-field/behaviors/focusable/focusable-interface.ts
deleted file mode 100644
index 10dd65e5e8..0000000000
--- a/libs/design/src/atoms/form/form-field/behaviors/focusable/focusable-interface.ts
+++ /dev/null
@@ -1,9 +0,0 @@
-import { DaffFormFieldControl } from '../../form-field-control';
-
-/**
- * A behavior interface for tracking the focused state of a form field.
- */
-export interface DaffFocusable {
- _control: DaffFormFieldControl;
- focused: boolean;
-}
diff --git a/libs/design/src/atoms/form/form-field/form-field-control.ts b/libs/design/src/atoms/form/form-field/form-field-control.ts
index 43581ba7c3..9486140d5b 100644
--- a/libs/design/src/atoms/form/form-field/form-field-control.ts
+++ b/libs/design/src/atoms/form/form-field/form-field-control.ts
@@ -1,4 +1,10 @@
import { NgControl } from '@angular/forms';
+import {
+ BehaviorSubject,
+ Observable,
+} from 'rxjs';
+
+import { DaffFormFieldState } from './form-field-state';
/**
*
@@ -11,12 +17,39 @@ import { NgControl } from '@angular/forms';
* in javascript, they get thrown out by the typescript compiler and cannot
* be used for the necessary dependency injection.
*/
-export abstract class DaffFormFieldControl {
- readonly ngControl: NgControl | null;
-
- readonly controlType?: any;
+export abstract class DaffFormFieldControl {
+ abstract readonly controlType?: any;
- readonly focused: boolean;
+ abstract readonly focused: boolean;
abstract focus(event?: Event): void;
+
+ abstract readonly value: T;
+
+ constructor(public ngControl: NgControl | null) {
+ }
+
+ get state(): DaffFormFieldState {
+ return {
+ focused: this.focused,
+ filled: !!this.value,
+ disabled: this.ngControl?.disabled,
+ error: this.ngControl?.errors && (this.ngControl?.dirty || this.ngControl?.touched),
+ valid: !this.ngControl?.errors && (this.ngControl?.dirty || this.ngControl?.touched),
+ };
+ }
+
+ _stateChanges = new BehaviorSubject({
+ focused: false,
+ filled: false,
+ disabled: false,
+ error: false,
+ valid: true,
+ });
+
+ stateChanges: Observable;
+
+ emitState() {
+ this._stateChanges.next(this.state);
+ }
};
diff --git a/libs/design/src/atoms/form/form-field/form-field-state.ts b/libs/design/src/atoms/form/form-field/form-field-state.ts
new file mode 100644
index 0000000000..53ab81a071
--- /dev/null
+++ b/libs/design/src/atoms/form/form-field/form-field-state.ts
@@ -0,0 +1,7 @@
+export interface DaffFormFieldState {
+ focused: boolean;
+ filled: boolean;
+ disabled: boolean;
+ error: boolean;
+ valid: boolean;
+}
diff --git a/libs/design/src/atoms/form/form-field/form-field.module.ts b/libs/design/src/atoms/form/form-field/form-field.module.ts
index 2b061a3916..15238ff71f 100644
--- a/libs/design/src/atoms/form/form-field/form-field.module.ts
+++ b/libs/design/src/atoms/form/form-field/form-field.module.ts
@@ -1,20 +1,21 @@
import { CommonModule } from '@angular/common';
import { NgModule } from '@angular/core';
-import { FontAwesomeModule } from '@fortawesome/angular-fontawesome';
import { DaffFormFieldComponent } from './form-field/form-field.component';
import { DaffErrorMessageModule } from '../error-message/error-message.module';
+import { DaffFormLabelModule } from '../form-label/form-label.module';
@NgModule({
imports: [
CommonModule,
- FontAwesomeModule,
DaffErrorMessageModule,
+ DaffFormLabelModule,
],
exports: [
DaffFormFieldComponent,
DaffErrorMessageModule,
+ DaffFormLabelModule,
],
declarations: [
DaffFormFieldComponent,
diff --git a/libs/design/src/atoms/form/form-field/form-field/form-field-theme.scss b/libs/design/src/atoms/form/form-field/form-field/form-field-theme.scss
index 4a11e8002a..2bee19605b 100644
--- a/libs/design/src/atoms/form/form-field/form-field/form-field-theme.scss
+++ b/libs/design/src/atoms/form/form-field/form-field/form-field-theme.scss
@@ -6,6 +6,7 @@
$primary: core.daff-map-get($theme, primary);
$secondary: core.daff-map-get($theme, secondary);
$tertiary: core.daff-map-get($theme, tertiary);
+ $critical: core.daff-map-get($theme, critical);
$base: core.daff-map-get($theme, 'core', 'base');
$base-contrast: core.daff-map-get($theme, 'core', 'base-contrast');
$neutral: core.daff-map-get($theme, 'core', 'neutral');
@@ -13,26 +14,34 @@
.daff-form-field {
&__control {
background: $base;
- border: 1px solid theming.daff-illuminate($base, $neutral, 3);
- color: theming.daff-illuminate($base-contrast, $neutral, 4);
+ border: 1px solid theming.daff-illuminate($base, $neutral, 6);
+ color: theming.daff-illuminate($base, $neutral, 6);
- &:focus {
- border: 1px solid $base-contrast;
+ &.daff-focused {
+ border: 1px solid theming.daff-color($primary);
+
+ .daff-form-label {
+ color: theming.daff-color($primary);
+ }
}
&.daff-error {
- border: 1px solid theming.daff-color(theming.$daff-red, 60);
+ border: 1px solid theming.daff-color($critical);
- &:focus {
- border: 1px solid theming.daff-color(theming.$daff-red, 60);
+ .daff-form-label {
+ color: theming.daff-color($critical);
}
}
&.daff-valid {
- > * {
- color: $base-contrast;
- }
+ color: $base-contrast;
}
+
+ &.daff-disabled {
+ background-color: transparent;
+ border: 1px solid theming.daff-illuminate($base, $neutral, 4);
+ color: theming.daff-illuminate($base, $neutral, 4);
+ }
}
}
}
diff --git a/libs/design/src/atoms/form/form-field/form-field/form-field.component.html b/libs/design/src/atoms/form/form-field/form-field/form-field.component.html
index 837e5e0640..7c23b2dc7b 100644
--- a/libs/design/src/atoms/form/form-field/form-field/form-field.component.html
+++ b/libs/design/src/atoms/form/form-field/form-field/form-field.component.html
@@ -1,7 +1,23 @@
-