diff --git a/alfa-client/apps/demo/src/app/app.component.html b/alfa-client/apps/demo/src/app/app.component.html index 458cfa1ddbe968a75d5f95492bafe385a4bb502d..24f25d365c37301b8ea9dc84a6aa0923372077bb 100644 --- a/alfa-client/apps/demo/src/app/app.component.html +++ b/alfa-client/apps/demo/src/app/app.component.html @@ -15,28 +15,42 @@ </div> <main class="flex-auto bg-background-50 p-6"> <form id="antrag_bescheiden_form" [formGroup]="exampleForm"> - <div class="mb-6"> - <label - for="default-input" - class="mb-2 block text-sm font-medium text-gray-900 dark:text-white" - >Default input</label + <div class="my-4"> + <ods-text-input id="test-input-id1" label="Betreff" placeholder="Betreff hier eingeben" /> + </div> + <div class="my-4"> + <ods-textarea + id="messageText1" + name="messageText1" + ariaLabel="Ihre Nachricht" + rows="10" + placeholder="Nachrichtentext hier eingeben" > - <input - type="text" - id="default-input" - class="block w-full rounded-lg border border-gray-300 bg-background-50 p-2.5 text-base text-text focus:border-blue-500 focus:ring-blue-500" - /> + </ods-textarea> </div> - <div> + <div class="my-4"> <ods-text-input id="test-input-id" label="Betreff" - placeholder="hier muss der Betreff rein" - /> + placeholder="Betreff hier eingeben" + variant="error" + > + <ods-error-message error="Betreff fehlt"></ods-error-message + ></ods-text-input> </div> - <div> - <ods-textarea /> + <div class="my-4"> + <ods-textarea + id="messageText" + name="messageText" + ariaLabel="Ihre Nachricht" + rows="10" + placeholder="Nachrichtentext hier eingeben" + variant="error" + > + <ods-error-message error="Nachrichtentext fehlt"></ods-error-message> + </ods-textarea> </div> + <div class="my-10 flex gap-8"> <ods-radio-button-card label="bewilligt" diff --git a/alfa-client/apps/demo/src/app/app.component.ts b/alfa-client/apps/demo/src/app/app.component.ts index 35c94d3162ac39e8ef00fd349a9a0c2ade313733..0a62c45b2eeeffd23cf57a69b266f92683e467ff 100644 --- a/alfa-client/apps/demo/src/app/app.component.ts +++ b/alfa-client/apps/demo/src/app/app.component.ts @@ -7,6 +7,7 @@ import { AttachmentComponent, ButtonCardComponent, ButtonComponent, + ErrorMessageComponent, FileUploadButtonComponent, IconComponent, RadioButtonCardComponent, @@ -40,6 +41,8 @@ import { CustomStepperComponent } from './components/cdk-demo/custom-stepper.com SpinnerIconComponent, TextareaComponent, TextInputComponent, + TextareaComponent, + ErrorMessageComponent, ], selector: 'app-root', templateUrl: './app.component.html', diff --git a/alfa-client/libs/design-system/src/index.ts b/alfa-client/libs/design-system/src/index.ts index 00e8a89ec69168de4e4c66e0293a146c9cdfe629..1d024028f217117d49f28fa597e57bb9c8d3de49 100644 --- a/alfa-client/libs/design-system/src/index.ts +++ b/alfa-client/libs/design-system/src/index.ts @@ -1,6 +1,7 @@ export * from './lib/attachment/attachment.component'; export * from './lib/button-card/button-card.component'; export * from './lib/button/button.component'; +export * from './lib/form/error-message/error-message.component'; export * from './lib/form/file-upload-button/file-upload-button.component'; export * from './lib/form/radio-button-card/radio-button-card.component'; export * from './lib/form/text-input/text-input.component'; diff --git a/alfa-client/libs/design-system/src/lib/form/error-message/error-message.component.spec.ts b/alfa-client/libs/design-system/src/lib/form/error-message/error-message.component.spec.ts new file mode 100644 index 0000000000000000000000000000000000000000..841f14c8b7ce7b54a913e221b416ba95fc53f422 --- /dev/null +++ b/alfa-client/libs/design-system/src/lib/form/error-message/error-message.component.spec.ts @@ -0,0 +1,21 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; +import { ErrorMessageComponent } from './error-message.component'; + +describe('ErrorMessageComponent', () => { + let component: ErrorMessageComponent; + let fixture: ComponentFixture<ErrorMessageComponent>; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + imports: [ErrorMessageComponent], + }).compileComponents(); + + fixture = TestBed.createComponent(ErrorMessageComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/alfa-client/libs/design-system/src/lib/form/error-message/error-message.component.ts b/alfa-client/libs/design-system/src/lib/form/error-message/error-message.component.ts new file mode 100644 index 0000000000000000000000000000000000000000..14676069eea4d270c58fc711ba9e1720dafef696 --- /dev/null +++ b/alfa-client/libs/design-system/src/lib/form/error-message/error-message.component.ts @@ -0,0 +1,12 @@ +import { CommonModule } from '@angular/common'; +import { Component, Input } from '@angular/core'; + +@Component({ + selector: 'ods-error-message', + standalone: true, + imports: [CommonModule], + template: `<p *ngIf="error" error class="text-error mt-2 text-sm">{{ error }}</p>`, +}) +export class ErrorMessageComponent { + @Input() error: string; +} diff --git a/alfa-client/libs/design-system/src/lib/form/text-input/text-input.component.ts b/alfa-client/libs/design-system/src/lib/form/text-input/text-input.component.ts index 634781aaefeb341fc1b4b2a723969085b5f06abe..3cc78ba8722ceb007b3610349d979f54ec567d0f 100644 --- a/alfa-client/libs/design-system/src/lib/form/text-input/text-input.component.ts +++ b/alfa-client/libs/design-system/src/lib/form/text-input/text-input.component.ts @@ -1,24 +1,44 @@ import { CommonModule } from '@angular/common'; import { Component, Input } from '@angular/core'; +import { VariantProps, cva } from 'class-variance-authority'; + +import { ErrorMessageComponent } from '../error-message/error-message.component'; + +const textInputVariants = cva( + 'block w-full rounded-lg border bg-background-50 p-2.5 text-base text-text focus:border-primary focus:ring-primary', + { + variants: { + variant: { + default: 'border-primary-600/50', + error: 'border-error', + }, + }, + defaultVariants: { + variant: 'default', + }, + }, +); +type TextInputVariants = VariantProps<typeof textInputVariants>; @Component({ selector: 'ods-text-input', standalone: true, - imports: [CommonModule], + imports: [CommonModule, ErrorMessageComponent], template: ` <div> - <label [for]="id" class="block text-sm font-medium leading-6 text-gray-900">{{ + <label [for]="id" class="mb-2 block text-sm font-medium leading-6 text-text">{{ label }}</label> <div class="mt-2"> <input type="text" - name="email" [id]="id" - class="block w-full rounded-lg border border-gray-300 bg-background-50 p-2.5 text-base text-text focus:border-blue-500 focus:ring-blue-500" + [ngClass]="textInputVariants({ variant })" [placeholder]="placeholder" + [autocomplete]="autocomplete" /> </div> + <ng-content select="[error]"></ng-content> </div> `, }) @@ -26,4 +46,9 @@ export class TextInputComponent { @Input({ required: true }) id!: string; @Input() label: string = ''; @Input() placeholder: string = ''; + @Input() error: string; + @Input() autocomplete: string = 'off'; + @Input() variant: TextInputVariants['variant']; + + textInputVariants = textInputVariants; } diff --git a/alfa-client/libs/design-system/src/lib/form/textarea/textarea.component.ts b/alfa-client/libs/design-system/src/lib/form/textarea/textarea.component.ts index 3ec25e20a3281e068323d2fe34d51f86d114d8c4..9969e8e27c31de674ebcf42147ae476a788e6806 100644 --- a/alfa-client/libs/design-system/src/lib/form/textarea/textarea.component.ts +++ b/alfa-client/libs/design-system/src/lib/form/textarea/textarea.component.ts @@ -1,31 +1,54 @@ import { CommonModule } from '@angular/common'; import { Component, Input } from '@angular/core'; +import { ReactiveFormsModule } from '@angular/forms'; +import { VariantProps, cva } from 'class-variance-authority'; + +import { ErrorMessageComponent } from '../error-message/error-message.component'; + +const textareaVariants = cva( + 'block w-full rounded-lg border bg-background-50 p-2.5 text-base text-text focus:border-primary focus:ring-primary', + { + variants: { + variant: { + default: 'border-primary-600/50', + error: 'border-error', + }, + }, + defaultVariants: { + variant: 'default', + }, + }, +); +type TextareaVariants = VariantProps<typeof textareaVariants>; @Component({ selector: 'ods-textarea', standalone: true, - imports: [CommonModule], + imports: [CommonModule, ReactiveFormsModule, ErrorMessageComponent], template: ` <div class="mt-2"> + <label *ngIf="ariaLabel" [for]="name" class="sr-only">{{ ariaLabel }}</label> <textarea - rows="4" - name="comment" - id="comment" - class="block w-full rounded-md border-0 py-1.5 text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 placeholder:text-gray-400 focus:ring-2 focus:ring-inset focus:ring-indigo-600 sm:text-sm sm:leading-6" - ></textarea> - <label for="description" class="sr-only">Description</label> - <textarea - rows="2" - name="description" - id="description" - class="block w-full resize-none border-0 py-0 text-gray-900 placeholder:text-gray-400 focus:ring-0 sm:text-sm sm:leading-6" - placeholder="Write a description..." + [id]="id" + [name]="name" + [rows]="rows" + [ngClass]="textareaVariants({ variant })" + [placeholder]="placeholder" + [autocomplete]="autocomplete" ></textarea> + <ng-content select="[error]"></ng-content> </div> `, }) export class TextareaComponent { - @Input() label!: string; - @Input() placeholder: string = ''; - @Input() value!: string; + @Input({ required: true }) id: string; + @Input({ required: true }) name: string; + @Input({ required: true }) ariaLabel: string; + @Input() placeholder!: string; + @Input() rows: number = 3; + @Input() error!: string; + @Input() autocomplete: string = 'off'; + @Input() variant: TextareaVariants['variant']; + + textareaVariants = textareaVariants; } diff --git a/alfa-client/libs/design-system/src/lib/tailwind-preset/root.css b/alfa-client/libs/design-system/src/lib/tailwind-preset/root.css index ee4388c87e0ea5bb4f717a24b78a1b3b0858f879..1ea5814ba45c6937e509f933e18a55fb36c55cf0 100644 --- a/alfa-client/libs/design-system/src/lib/tailwind-preset/root.css +++ b/alfa-client/libs/design-system/src/lib/tailwind-preset/root.css @@ -6,6 +6,7 @@ :root { --warning: 38 92% 50%; + --color-error: 0 71% 49%; --color-background-secondary: 0 0% 98%; --color-mainbg: 0 0% 100%; @@ -29,6 +30,8 @@ } .dark { + --color-error: 0 71% 49%; + --color-background-secondary: 0 0% 16%; --color-mainbg: 0 0% 14%; --text: 0 0% 100%; diff --git a/alfa-client/libs/design-system/src/lib/tailwind-preset/tailwind.config.js b/alfa-client/libs/design-system/src/lib/tailwind-preset/tailwind.config.js index 1ae7845a8f59331b2875f9f9620a33ad12545871..fa5e338aa989da33abca91ae6dcf894937180615 100644 --- a/alfa-client/libs/design-system/src/lib/tailwind-preset/tailwind.config.js +++ b/alfa-client/libs/design-system/src/lib/tailwind-preset/tailwind.config.js @@ -92,6 +92,7 @@ module.exports = { text: 'hsl(var(--text) / <alpha-value>)', whitetext: 'hsl(var(--color-text-white) / <alpha-value>)', warning: 'hsl(var(--warning))', + error: 'hsl(var(--color-error))', }, }, },