diff --git a/packages/components/inline-edit/__screenshots__/01-dark.png b/packages/components/inline-edit/__screenshots__/01-dark.png index 4b7df1a52..77813ecbb 100644 Binary files a/packages/components/inline-edit/__screenshots__/01-dark.png and b/packages/components/inline-edit/__screenshots__/01-dark.png differ diff --git a/packages/components/inline-edit/__screenshots__/01-light.png b/packages/components/inline-edit/__screenshots__/01-light.png index cf2bdcb65..dc2a8b4c9 100644 Binary files a/packages/components/inline-edit/__screenshots__/01-light.png and b/packages/components/inline-edit/__screenshots__/01-light.png differ diff --git a/packages/components/inline-edit/__screenshots__/07-dark.png b/packages/components/inline-edit/__screenshots__/07-dark.png new file mode 100644 index 000000000..4e5d37946 Binary files /dev/null and b/packages/components/inline-edit/__screenshots__/07-dark.png differ diff --git a/packages/components/inline-edit/__screenshots__/07-light.png b/packages/components/inline-edit/__screenshots__/07-light.png new file mode 100644 index 000000000..71804e221 Binary files /dev/null and b/packages/components/inline-edit/__screenshots__/07-light.png differ diff --git a/packages/components/inline-edit/e2e.playwright-spec.ts b/packages/components/inline-edit/e2e.playwright-spec.ts index 76f94fb5b..fcacf3fbc 100644 --- a/packages/components/inline-edit/e2e.playwright-spec.ts +++ b/packages/components/inline-edit/e2e.playwright-spec.ts @@ -64,6 +64,27 @@ test.describe('KbqInlineEdit', () => { }); }); + test.describe('E2eInlineEditActionButtons', () => { + const getContainer = (page: Page) => page.getByTestId('e2eInlineEditActionButtonsContainer'); + const openEdit = (page: Page) => page.getByTestId('e2eInlineEditActionButtonsOpen').click(); + const getSaveButton = (page: Page) => + page.locator('.kbq-inline-edit__action-buttons .kbq-inline-edit__action-button').first().locator('button'); + + test('invalid state on save attempt', async ({ page }) => { + await page.goto('/E2eInlineEditActionButtons'); + + await openEdit(page); + await page.getByRole('textbox').clear(); + await getSaveButton(page).click(); + + const screenshotTarget = getContainer(page); + + await expect(screenshotTarget).toHaveScreenshot('07-light.png'); + await e2eEnableDarkTheme(page); + await expect(screenshotTarget).toHaveScreenshot('07-dark.png'); + }); + }); + test.describe('E2eInlineEditMenuButton', () => { const getComponent = (page: Page) => page.getByTestId('e2eInlineEditMenuButton'); const getContainer = (page: Page) => page.getByTestId('e2eInlineEditMenuButtonContainer'); diff --git a/packages/components/inline-edit/e2e.ts b/packages/components/inline-edit/e2e.ts index 4723c1c5c..8f1f5f4e4 100644 --- a/packages/components/inline-edit/e2e.ts +++ b/packages/components/inline-edit/e2e.ts @@ -1,11 +1,12 @@ import { NgTemplateOutlet } from '@angular/common'; import { ChangeDetectionStrategy, Component, viewChildren } from '@angular/core'; -import { FormsModule } from '@angular/forms'; +import { FormControl, FormsModule, ReactiveFormsModule, Validators } from '@angular/forms'; import { KbqButtonModule } from '@koobiq/components/button'; import { kbqInjectNativeElement } from '@koobiq/components/core'; import { KbqDropdownModule } from '@koobiq/components/dropdown'; import { KbqIconModule } from '@koobiq/components/icon'; import { KbqInputModule } from '@koobiq/components/input'; +import { KbqTextareaModule } from '@koobiq/components/textarea'; import { KbqInlineEdit } from './inline-edit'; import { KbqInlineEditModule } from './module'; @@ -212,3 +213,41 @@ export class E2eInlineEditTruncation {} } }) export class E2eInlineEditMenuButton {} + +@Component({ + selector: 'e2e-inline-edit-action-buttons', + imports: [ + ReactiveFormsModule, + KbqInlineEditModule, + KbqTextareaModule, + KbqButtonModule + ], + template: ` + + +
+ +
{{ control.value || 'empty' }}
+ +
+ @if (textareaInlineEdit.modeAsReadonly() === 'edit') { + + + + } +
+
+
+ `, + changeDetection: ChangeDetectionStrategy.OnPush, + host: { + class: 'layout-margin-top-l layout-column layout-gap-m', + style: 'max-width: 400px', + 'data-testid': 'e2eInlineEditActionButtons' + } +}) +export class E2eInlineEditActionButtons { + readonly control = new FormControl('Initial value', Validators.required); +} diff --git a/packages/components/inline-edit/inline-edit.html b/packages/components/inline-edit/inline-edit.html index f6027d28b..f9589ab2b 100644 --- a/packages/components/inline-edit/inline-edit.html +++ b/packages/components/inline-edit/inline-edit.html @@ -50,12 +50,17 @@ @if (showActions()) {
- - +
+ +
+ +
+ +
} diff --git a/packages/components/inline-edit/inline-edit.scss b/packages/components/inline-edit/inline-edit.scss index cfdf93df8..852956e2e 100644 --- a/packages/components/inline-edit/inline-edit.scss +++ b/packages/components/inline-edit/inline-edit.scss @@ -176,10 +176,6 @@ .kbq-inline-edit__panel { width: 100%; - .kbq-inline-edit__control-container { - border-radius: var(--kbq-size-border-radius); - } - .kbq-inline-edit__action-buttons { position: absolute; left: calc(-1 * var(--kbq-inline-edit-padding-horizontal)); @@ -190,7 +186,9 @@ } .kbq-inline-edit__control-container, - .kbq-inline-edit__action-buttons > .kbq-button-icon { + .kbq-inline-edit__action-button { box-shadow: var(--kbq-shadow-popup); + background-color: var(--kbq-background-bg); + border-radius: var(--kbq-size-border-radius); } } diff --git a/packages/components/inline-edit/inline-edit.spec.ts b/packages/components/inline-edit/inline-edit.spec.ts index 37a5e430d..3605fd3d9 100644 --- a/packages/components/inline-edit/inline-edit.spec.ts +++ b/packages/components/inline-edit/inline-edit.spec.ts @@ -14,6 +14,7 @@ import { TAB } from '@koobiq/components/core'; import { KbqDropdownModule } from '@koobiq/components/dropdown'; +import { KbqFormFieldModule } from '@koobiq/components/form-field'; import { KbqIconModule } from '@koobiq/components/icon'; import { KbqInputModule } from '@koobiq/components/input'; import { KbqSelectModule } from '@koobiq/components/select'; @@ -37,6 +38,7 @@ const componentCssClasses = { panel: '.kbq-inline-edit__panel', focusContainer: '.kbq-inline-edit', terminalButtons: '.kbq-inline-edit__action-buttons', + terminalButtonItem: '.kbq-inline-edit__action-button', menuMask: '.kbq-inline-edit__menu-mask', menu: '.kbq-inline-edit__menu', overlay: '.cdk-overlay-pane', @@ -176,9 +178,9 @@ describe('KbqInlineEdit', () => { inlineEditDebugElement.nativeElement.click(); fixture.detectChanges(); - const saveButtonHTMLElement = document.querySelector( - `${componentCssClasses.panel} ${componentCssClasses.terminalButtons}` - )!.firstElementChild as HTMLButtonElement | null; + const saveButtonHTMLElement = document + .querySelector(`${componentCssClasses.panel} ${componentCssClasses.terminalButtons}`)! + .querySelector('button') as HTMLButtonElement | null; saveButtonHTMLElement?.click(); @@ -213,9 +215,9 @@ describe('KbqInlineEdit', () => { inlineEditDebugElement.nativeElement.click(); fixture.detectChanges(); - const cancelButtonHTMLElement = document.querySelector( - `${componentCssClasses.panel} ${componentCssClasses.terminalButtons}` - )!.lastElementChild as HTMLButtonElement | null; + const cancelButtonHTMLElement = document + .querySelector(`${componentCssClasses.panel} ${componentCssClasses.terminalButtons}`)! + .querySelectorAll('button')[1] as HTMLButtonElement | null; cancelButtonHTMLElement?.click(); @@ -251,9 +253,9 @@ describe('KbqInlineEdit', () => { fixture.detectChanges(); await fixture.whenStable(); - const cancelButtonHTMLElement = document.querySelector( - `${componentCssClasses.panel} ${componentCssClasses.terminalButtons}` - )!.lastElementChild as HTMLButtonElement | null; + const cancelButtonHTMLElement = document + .querySelector(`${componentCssClasses.panel} ${componentCssClasses.terminalButtons}`)! + .querySelectorAll('button')[1] as HTMLButtonElement | null; const control = getOverlayElement()!.querySelector('input'); @@ -333,9 +335,9 @@ describe('KbqInlineEdit', () => { componentInstance.control.updateValueAndValidity(); fixture.detectChanges(); - const saveButtonHTMLElement = document.querySelector( - `${componentCssClasses.panel} ${componentCssClasses.terminalButtons}` - )!.firstElementChild as HTMLButtonElement | null; + const saveButtonHTMLElement = document + .querySelector(`${componentCssClasses.panel} ${componentCssClasses.terminalButtons}`)! + .querySelector('button') as HTMLButtonElement | null; saveButtonHTMLElement?.click(); @@ -404,9 +406,9 @@ describe('KbqInlineEdit', () => { fixture.detectChanges(); await fixture.whenStable(); - const saveButton = document.querySelector( - `${componentCssClasses.panel} ${componentCssClasses.terminalButtons}` - )!.firstElementChild as HTMLButtonElement; + const saveButton = document + .querySelector(`${componentCssClasses.panel} ${componentCssClasses.terminalButtons}`)! + .querySelector('button') as HTMLButtonElement; saveButton.click(); @@ -430,9 +432,9 @@ describe('KbqInlineEdit', () => { componentInstance.form.controls.firstName.updateValueAndValidity(); fixture.detectChanges(); - const saveButton = document.querySelector( - `${componentCssClasses.panel} ${componentCssClasses.terminalButtons}` - )!.firstElementChild as HTMLButtonElement; + const saveButton = document + .querySelector(`${componentCssClasses.panel} ${componentCssClasses.terminalButtons}`)! + .querySelector('button') as HTMLButtonElement; saveButton.click(); @@ -456,9 +458,9 @@ describe('KbqInlineEdit', () => { componentInstance.form.controls.lastName.updateValueAndValidity(); fixture.detectChanges(); - const saveButton = document.querySelector( - `${componentCssClasses.panel} ${componentCssClasses.terminalButtons}` - )!.firstElementChild as HTMLButtonElement; + const saveButton = document + .querySelector(`${componentCssClasses.panel} ${componentCssClasses.terminalButtons}`)! + .querySelector('button') as HTMLButtonElement; saveButton.click(); @@ -485,9 +487,9 @@ describe('KbqInlineEdit', () => { inputs[1].dispatchEvent(new Event('input')); fixture.detectChanges(); - const cancelButton = document.querySelector( - `${componentCssClasses.panel} ${componentCssClasses.terminalButtons}` - )!.lastElementChild as HTMLButtonElement; + const cancelButton = document + .querySelector(`${componentCssClasses.panel} ${componentCssClasses.terminalButtons}`)! + .querySelectorAll('button')[1] as HTMLButtonElement; cancelButton.click(); @@ -570,10 +572,16 @@ describe('KbqInlineEdit', () => { }; const clickSave = () => { - ( - document.querySelector(`${componentCssClasses.panel} ${componentCssClasses.terminalButtons}`)! - .firstElementChild as HTMLButtonElement - ).click(); + const terminalButtonList = document.querySelectorAll( + `${componentCssClasses.panel} ${componentCssClasses.terminalButtonItem}` + ); + + const saveButton = terminalButtonList.length && terminalButtonList[0].firstElementChild; + + expect(saveButton).toBeTruthy(); + expect(saveButton instanceof HTMLButtonElement).toBeTruthy(); + + (saveButton as HTMLButtonElement).click(); }; it('should not show tooltip when empty string is passed and control is invalid', () => { @@ -962,7 +970,7 @@ export class TestWithSelect extends BaseTestComponent { @Component({ selector: 'name', - imports: [ReactiveFormsModule, KbqInlineEditModule, KbqTextareaModule], + imports: [ReactiveFormsModule, KbqFormFieldModule, KbqInlineEditModule, KbqTextareaModule], template: `
{{ control.value }}
diff --git a/packages/e2e/routes.ts b/packages/e2e/routes.ts index e7ac63428..3811a76e1 100644 --- a/packages/e2e/routes.ts +++ b/packages/e2e/routes.ts @@ -33,7 +33,12 @@ import { E2eFileUploadDropzone, E2eFileUploadStateAndStyle } from '../components import { E2eFilterBarStates } from '../components/filter-bar/e2e'; import { E2eFormFieldGroup, E2eFormFieldset } from '../components/form-field/e2e'; import { E2eIconStateAndStyle, E2eIconSvg } from '../components/icon/e2e'; -import { E2eInlineEditMenuButton, E2eInlineEditStates, E2eInlineEditTruncation } from '../components/inline-edit/e2e'; +import { + E2eInlineEditActionButtons, + E2eInlineEditMenuButton, + E2eInlineEditStates, + E2eInlineEditTruncation +} from '../components/inline-edit/e2e'; import { E2eInputStateAndStyle } from '../components/input/e2e'; import { E2eLinkStates, E2eLinkWithCaption } from '../components/link/e2e'; import { E2eListStates } from '../components/list/e2e'; @@ -213,6 +218,7 @@ const components = [ E2eInlineEditStates, E2eInlineEditMenuButton, E2eInlineEditTruncation, + E2eInlineEditActionButtons, E2eFormHorizontal, E2eTypographyStyles, E2eTreeTwoLineNode,