From 300f67a2c9c0b991265a55a2ae81e577e0b3dd8f Mon Sep 17 00:00:00 2001 From: Lukas Matta Date: Thu, 21 May 2026 18:18:01 +0200 Subject: [PATCH 1/6] feat(button): Add native type --- .../src/app/api-data/cps-button.json | 8 +++++ .../cps-button/cps-button.component.html | 2 +- .../cps-button/cps-button.component.spec.ts | 31 +++++++++++++++++++ .../cps-button/cps-button.component.ts | 6 ++++ 4 files changed, 46 insertions(+), 1 deletion(-) diff --git a/projects/composition/src/app/api-data/cps-button.json b/projects/composition/src/app/api-data/cps-button.json index 90853e0e..ccfd635f 100644 --- a/projects/composition/src/app/api-data/cps-button.json +++ b/projects/composition/src/app/api-data/cps-button.json @@ -37,6 +37,14 @@ "default": "solid", "description": "Type of the button in terms of appearance, it can be 'solid' or 'outlined' or 'borderless'." }, + { + "name": "nativeType", + "optional": false, + "readonly": false, + "type": "'button' | 'submit' | 'reset'", + "default": "button", + "description": "Native HTML button type attribute, it can be 'button', 'submit' or 'reset'." + }, { "name": "label", "optional": false, diff --git a/projects/cps-ui-kit/src/lib/components/cps-button/cps-button.component.html b/projects/cps-ui-kit/src/lib/components/cps-button/cps-button.component.html index 671273a7..bbfb0140 100644 --- a/projects/cps-ui-kit/src/lib/components/cps-button/cps-button.component.html +++ b/projects/cps-ui-kit/src/lib/components/cps-button/cps-button.component.html @@ -1,6 +1,6 @@
+ +
+ +
+ + + +
+ @if (nativeSubmitMessage) { +
{{ nativeSubmitMessage }}
+ } +
+
+ (this.isLoading = false), 2000); } + onNativePlainClick() { + this.nativeSubmitMessage = 'Plain button clicked (no form action).'; + } + + onNativeSubmit(event: Event) { + event.preventDefault(); + if (this.nativeForm.invalid) { + this.nativeSubmitMessage = 'Form is invalid.'; + return; + } + this.nativeSubmitMessage = `Form submitted with name: "${this.nativeForm.value.name}"`; + } + + onNativeReset() { + this.nativeForm.reset(); + this.nativeSubmitMessage = ''; + } + readonly examples = buttonExamples; } diff --git a/projects/composition/src/app/pages/button-page/button-page.examples.ts b/projects/composition/src/app/pages/button-page/button-page.examples.ts index aea25ab9..23aa0bf2 100644 --- a/projects/composition/src/app/pages/button-page/button-page.examples.ts +++ b/projects/composition/src/app/pages/button-page/button-page.examples.ts @@ -92,6 +92,65 @@ export const buttonExamples: Record = { ` }, + nativeTypes: { + html: ` +
+ +
+ + + +
+ @if (nativeSubmitMessage) { +
{{ nativeSubmitMessage }}
+ } +
`, + ts: ` +private readonly fb = inject(FormBuilder); + +componentData = ComponentData; +isLoading = false; + +nativeForm = this.fb.nonNullable.group({ + name: ['', Validators.required] +}); + +nativeSubmitMessage = ''; + +onNativePlainClick() { + this.nativeSubmitMessage = 'Plain button clicked (no form action).'; +} + +onNativeSubmit(event: Event) { + event.preventDefault(); + if (this.nativeForm.invalid) { + this.nativeSubmitMessage = 'Form is invalid.'; + return; + } + this.nativeSubmitMessage = "Form submitted with name: " + this.nativeForm.value.name; +} + +onNativeReset() { + this.nativeForm.reset(); + this.nativeSubmitMessage = ''; +}` + }, + misc: { html: ` From 2f0231378b790a567483c030c22dbb29f7bb473b Mon Sep 17 00:00:00 2001 From: Lukas Matta Date: Fri, 29 May 2026 16:14:18 +0200 Subject: [PATCH 4/6] Add tests to cover null/undefined handling --- .../cps-button/cps-button.component.spec.ts | 14 ++++++++++++++ .../components/cps-button/cps-button.component.ts | 2 +- 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/projects/cps-ui-kit/src/lib/components/cps-button/cps-button.component.spec.ts b/projects/cps-ui-kit/src/lib/components/cps-button/cps-button.component.spec.ts index 8bd235e1..3fb60307 100644 --- a/projects/cps-ui-kit/src/lib/components/cps-button/cps-button.component.spec.ts +++ b/projects/cps-ui-kit/src/lib/components/cps-button/cps-button.component.spec.ts @@ -280,6 +280,20 @@ describe('CpsButtonComponent', () => { const button = fixture.nativeElement.querySelector('button'); expect(button.getAttribute('type')).toBe('submit'); }); + + it('should fall back to "button" native type if nativeType set to null', () => { + fixture.componentRef.setInput('nativeType', null); + fixture.detectChanges(); + const button = fixture.nativeElement.querySelector('button'); + expect(button.getAttribute('type')).toBe('button'); + }); + + it('should fall back to "button" native type if nativeType set to undefined', () => { + fixture.componentRef.setInput('nativeType', undefined); + fixture.detectChanges(); + const button = fixture.nativeElement.querySelector('button'); + expect(button.getAttribute('type')).toBe('button'); + }); }); describe('aria-label', () => { diff --git a/projects/cps-ui-kit/src/lib/components/cps-button/cps-button.component.ts b/projects/cps-ui-kit/src/lib/components/cps-button/cps-button.component.ts index 4efcdd8a..148158ac 100644 --- a/projects/cps-ui-kit/src/lib/components/cps-button/cps-button.component.ts +++ b/projects/cps-ui-kit/src/lib/components/cps-button/cps-button.component.ts @@ -152,7 +152,7 @@ export class CpsButtonComponent implements OnInit, OnChanges { logMissingAriaLabelError('CpsButtonComponent', this.label, this.ariaLabel); if ( - changes['nativeType]'] && + changes.nativeType && !['button', 'submit', 'reset'].includes(this.nativeType) ) { console.warn( From 246d10f7e18b82ae863952a2f26fb65bfe5fa310 Mon Sep 17 00:00:00 2001 From: Lukas Matta Date: Fri, 29 May 2026 16:21:54 +0200 Subject: [PATCH 5/6] Check console.warn + invalid string values for nativeType --- .../cps-button/cps-button.component.spec.ts | 23 +++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/projects/cps-ui-kit/src/lib/components/cps-button/cps-button.component.spec.ts b/projects/cps-ui-kit/src/lib/components/cps-button/cps-button.component.spec.ts index 3fb60307..62969c9a 100644 --- a/projects/cps-ui-kit/src/lib/components/cps-button/cps-button.component.spec.ts +++ b/projects/cps-ui-kit/src/lib/components/cps-button/cps-button.component.spec.ts @@ -294,6 +294,29 @@ describe('CpsButtonComponent', () => { const button = fixture.nativeElement.querySelector('button'); expect(button.getAttribute('type')).toBe('button'); }); + + it('should fall back to "button" and warn if nativeType is an invalid string', () => { + const warnSpy = jest.spyOn(console, 'warn').mockImplementation(() => {}); + fixture.componentRef.setInput('nativeType', 'invalid-type'); + fixture.detectChanges(); + const button = fixture.nativeElement.querySelector('button'); + expect(button.getAttribute('type')).toBe('button'); + expect(component.nativeType).toBe('button'); + expect(warnSpy).toHaveBeenCalledWith( + expect.stringContaining('Invalid nativeType value') + ); + warnSpy.mockRestore(); + }); + + it('should not warn for valid nativeType values', () => { + const warnSpy = jest.spyOn(console, 'warn').mockImplementation(() => {}); + fixture.componentRef.setInput('nativeType', 'submit'); + fixture.detectChanges(); + fixture.componentRef.setInput('nativeType', 'reset'); + fixture.detectChanges(); + expect(warnSpy).not.toHaveBeenCalled(); + warnSpy.mockRestore(); + }); }); describe('aria-label', () => { From 5cd93791ac4c88453275d968a9b235fd331ab132 Mon Sep 17 00:00:00 2001 From: Lukas Matta Date: Fri, 29 May 2026 16:54:20 +0200 Subject: [PATCH 6/6] Fix layout shift --- .../src/app/pages/button-page/button-page.component.html | 6 +++--- .../src/app/pages/button-page/button-page.component.scss | 1 + 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/projects/composition/src/app/pages/button-page/button-page.component.html b/projects/composition/src/app/pages/button-page/button-page.component.html index 920bee29..df51c30e 100644 --- a/projects/composition/src/app/pages/button-page/button-page.component.html +++ b/projects/composition/src/app/pages/button-page/button-page.component.html @@ -347,9 +347,9 @@ type="borderless" color="surprise"> - @if (nativeSubmitMessage) { -
{{ nativeSubmitMessage }}
- } +
+ {{ nativeSubmitMessage }} +
diff --git a/projects/composition/src/app/pages/button-page/button-page.component.scss b/projects/composition/src/app/pages/button-page/button-page.component.scss index 4619d0b6..e45d93fd 100644 --- a/projects/composition/src/app/pages/button-page/button-page.component.scss +++ b/projects/composition/src/app/pages/button-page/button-page.component.scss @@ -37,5 +37,6 @@ &__message { color: var(--cps-color-depth); font-style: italic; + min-height: 1.5em; } }