From a2f3d210a94a2eeb04f8f6a3ab4fcafe0ad6f3b1 Mon Sep 17 00:00:00 2001 From: OZGCloud <ozgcloud@mgm-tp.com> Date: Fri, 6 Sep 2024 16:23:58 +0200 Subject: [PATCH] OZG-6237 Add heading component --- alfa-client/libs/design-system/src/index.ts | 1 + .../src/lib/heading/heading.component.spec.ts | 75 +++++++++++++++++++ .../src/lib/heading/heading.component.ts | 40 ++++++++++ .../src/lib/heading/heading.stories.ts | 35 +++++++++ 4 files changed, 151 insertions(+) create mode 100644 alfa-client/libs/design-system/src/lib/heading/heading.component.spec.ts create mode 100644 alfa-client/libs/design-system/src/lib/heading/heading.component.ts create mode 100644 alfa-client/libs/design-system/src/lib/heading/heading.stories.ts diff --git a/alfa-client/libs/design-system/src/index.ts b/alfa-client/libs/design-system/src/index.ts index 8adc00f2d8..79c0844756 100644 --- a/alfa-client/libs/design-system/src/index.ts +++ b/alfa-client/libs/design-system/src/index.ts @@ -10,6 +10,7 @@ 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'; export * from './lib/form/textarea/textarea.component'; +export * from './lib/heading/heading.component'; export * from './lib/icons/admin-logo-icon/admin-logo-icon.component'; export * from './lib/icons/attachment-icon/attachment-icon.component'; export * from './lib/icons/bescheid-generate-icon/bescheid-generate-icon.component'; diff --git a/alfa-client/libs/design-system/src/lib/heading/heading.component.spec.ts b/alfa-client/libs/design-system/src/lib/heading/heading.component.spec.ts new file mode 100644 index 0000000000..50a934b9fe --- /dev/null +++ b/alfa-client/libs/design-system/src/lib/heading/heading.component.spec.ts @@ -0,0 +1,75 @@ +import { getElementFromFixture } from '@alfa-client/test-utils'; +import { ComponentFixture, TestBed } from '@angular/core/testing'; +import { getDataTestIdOf } from 'libs/tech-shared/test/data-test'; +import { HeadingComponent } from './heading.component'; + +describe('HeadingComponent', () => { + let component: HeadingComponent; + let fixture: ComponentFixture<HeadingComponent>; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + imports: [HeadingComponent], + }).compileComponents(); + + fixture = TestBed.createComponent(HeadingComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); + + describe('input', () => { + describe('text', () => { + it('should set text as inner HTML', () => { + component.text = 'test'; + fixture.detectChanges(); + + const heading: HTMLElement = getElementFromFixture( + fixture, + getDataTestIdOf('heading-test'), + ); + + expect(heading.innerHTML).toContain('test'); + }); + }); + + describe('level', () => { + it('should set aria level', () => { + component.level = '2'; + component.text = 'test'; + fixture.detectChanges(); + + const heading: HTMLElement = getElementFromFixture( + fixture, + getDataTestIdOf('heading-test'), + ); + + expect(heading.getAttribute('aria-level')).toBe('2'); + }); + }); + + describe('class', () => { + it('should get classes for level', () => { + component.headingVariants = jest.fn(); + component.level = '2'; + + fixture.detectChanges(); + + expect(component.headingVariants).toHaveBeenCalledWith({ level: '2' }); + }); + + it('should merge classes', () => { + component.twMerge = jest.fn(); + component.headingVariants = jest.fn().mockReturnValue('test-class-2'); + component.class = 'test-class-1'; + + fixture.detectChanges(); + + expect(component.twMerge).toHaveBeenCalledWith('test-class-1', 'test-class-2'); + }); + }); + }); +}); diff --git a/alfa-client/libs/design-system/src/lib/heading/heading.component.ts b/alfa-client/libs/design-system/src/lib/heading/heading.component.ts new file mode 100644 index 0000000000..d958e24a13 --- /dev/null +++ b/alfa-client/libs/design-system/src/lib/heading/heading.component.ts @@ -0,0 +1,40 @@ +import { TechSharedModule } from '@alfa-client/tech-shared'; +import { NgClass } from '@angular/common'; +import { Component, Input } from '@angular/core'; +import { VariantProps, cva } from 'class-variance-authority'; +import { twMerge } from 'tailwind-merge'; + +export const headingVariants = cva('font-medium', { + variants: { + level: { + '1': 'text-3xl pb-6', + '2': 'text-2xl py-4', + }, + }, + defaultVariants: { + level: '1', + }, +}); +type HeadingVariants = VariantProps<typeof headingVariants>; + +@Component({ + selector: 'ods-heading', + standalone: true, + imports: [NgClass, TechSharedModule], + template: `<div + role="heading" + [attr.aria-level]="level" + [ngClass]="twMerge(class, headingVariants({ level }))" + [attr.data-test-id]="'heading-' + text | convertForDataTest" + > + {{ text }} + </div>`, +}) +export class HeadingComponent { + @Input({ required: true }) text!: string; + @Input() level: HeadingVariants['level'] = '1'; + @Input() class: string = ''; + + headingVariants = headingVariants; + twMerge = twMerge; +} diff --git a/alfa-client/libs/design-system/src/lib/heading/heading.stories.ts b/alfa-client/libs/design-system/src/lib/heading/heading.stories.ts new file mode 100644 index 0000000000..f38efcb047 --- /dev/null +++ b/alfa-client/libs/design-system/src/lib/heading/heading.stories.ts @@ -0,0 +1,35 @@ +import { moduleMetadata, type Meta, type StoryObj } from '@storybook/angular'; +import { HeadingComponent } from './heading.component'; + +const meta: Meta<HeadingComponent> = { + title: 'Heading', + component: HeadingComponent, + excludeStories: /.*Data$/, + tags: ['autodocs'], + decorators: [ + moduleMetadata({ + imports: [HeadingComponent], + }), + ], +}; + +export default meta; +type Story = StoryObj<HeadingComponent>; + +export const Default: Story = { + args: { + level: '1', + text: 'This is awesome heading!', + class: '', + }, + argTypes: { + level: { + description: 'Level of heading element', + control: 'select', + options: ['1', '2'], + table: { defaultValue: { summary: '1' } }, + }, + text: { description: 'Heading text' }, + class: { description: 'Style class for element' }, + }, +}; -- GitLab