diff --git a/docs/BREAKING_CHANGES.v3.md b/docs/BREAKING_CHANGES.v3.md
index 5cbe824359..05b261a5dc 100644
--- a/docs/BREAKING_CHANGES.v3.md
+++ b/docs/BREAKING_CHANGES.v3.md
@@ -23,6 +23,18 @@ The following components have been removed:
- Visually, the tooltip has been replaced by a simple label shown in parentheses after the abbreviation.
- The property `_tooltipAlign` has been removed.
+### kol-input-file
+
+- The property `_value` has been removed as it never served a purpose. Use the `getValue()` method instead to access the FileList.
+
+### kol-table-stateful
+
+- The DOM event `kol-selection-change` has been renamed to `kolSelectionChange`.
+
+### kol-table-stateless
+
+- The DOM event `kol-selection-change` has been renamed to `kolSelectionChange`.
+
## `focus`-methods
The public `focus`-methods have been removed from all components. Use `kolFocus` instead.
diff --git a/packages/components/.gitignore b/packages/components/.gitignore
index 2923bfed2c..7ace70dc01 100644
--- a/packages/components/.gitignore
+++ b/packages/components/.gitignore
@@ -1,4 +1,5 @@
/dist/
+/dist-e2e/
/doc/**
/loader/
/public/
diff --git a/packages/components/package.json b/packages/components/package.json
index eb16a19c7a..852536e86a 100644
--- a/packages/components/package.json
+++ b/packages/components/package.json
@@ -65,7 +65,7 @@
"test": "pnpm test:unit",
"test:unit": "cross-env NODE_ENV=test stencil test --spec --json --outputFile dist/jest-test-results.json",
"test:watch": "cross-env NODE_ENV=test stencil test --spec --watchAll",
- "test:e2e": "playwright test",
+ "test:e2e": "cross-env E2E=1 playwright test",
"postinstall": "pnpm exec playwright install",
"postpack": "mv package.bak.json package.json",
"prepack": "npm run build && cp package.json package.bak.json && rimraf dist/collection dist/kolibri/assets/@leanup dist/types/assets/@leanup && node scripts/anonymous.js && node scripts/minify.js",
diff --git a/packages/components/playwright.config.ts b/packages/components/playwright.config.ts
index dc31d041fa..84debd5bc0 100644
--- a/packages/components/playwright.config.ts
+++ b/packages/components/playwright.config.ts
@@ -3,7 +3,8 @@ import { createConfig, matchers } from '@stencil/playwright';
expect.extend(matchers);
-const TEST_URL = 'http://localhost:3333';
+const TEST_PORT = '3333';
+const TEST_URL = `http://localhost:${TEST_PORT}`;
/* See https://playwright.dev/docs/test-configuration */
export default createConfig({
@@ -30,8 +31,13 @@ export default createConfig({
use: {
baseURL: TEST_URL,
timezoneId: 'Europe/Berlin',
+ screenshot: 'only-on-failure',
+ trace: 'retain-on-failure',
},
webServer: {
url: TEST_URL,
+ reuseExistingServer: false,
+ /* The builtin Stencil server sometimes fails to serve some assets which leads to intermittent test failures. Use a more stable server (without watcher) for CI: */
+ ...(process.env.CI ? { command: `stencil build --dev && mv dist-e2e/kolibri dist-e2e/build && npx serve dist-e2e -p ${TEST_PORT} -L` } : {}),
},
});
diff --git a/packages/components/src/components/@deprecated/input/controller.ts b/packages/components/src/components/@deprecated/input/controller.ts
index 48aa7a540e..a97afdb03e 100644
--- a/packages/components/src/components/@deprecated/input/controller.ts
+++ b/packages/components/src/components/@deprecated/input/controller.ts
@@ -26,14 +26,14 @@ import {
validateHideLabel,
validateLabelWithExpertSlot,
validateMsg,
+ validateShortKey,
validateTabIndex,
validateTooltipAlign,
watchBoolean,
watchString,
- validateShortKey,
} from '../../../schema';
-import { stopPropagation, tryToDispatchKoliBriEvent } from '../../../utils/events';
+import { dispatchDomEvent, KolEvent } from '../../../utils/events';
import { ControlledInputController } from '../../input-adapter-leanup/controller';
import type { Props as AdapterProps } from '../../input-adapter-leanup/types';
@@ -161,12 +161,17 @@ export class InputController extends ControlledInputController implements Watche
validateAccessAndShortKey(this.component._accessKey, this.component._shortKey);
}
+ private emitEvent(type: KolEvent, value?: unknown): void {
+ if (this.host) {
+ dispatchDomEvent(this.host, type, value);
+ }
+ }
+
protected onBlur(event: Event): void {
this.component._touched = true;
// Event handling
- stopPropagation(event);
- tryToDispatchKoliBriEvent('blur', this.host);
+ this.emitEvent(KolEvent.blur);
// Callback
if (typeof this.component._on?.onBlur === 'function') {
@@ -179,10 +184,12 @@ export class InputController extends ControlledInputController implements Watche
* @param value - Optional value. Taken from event if not defined.
*/
protected onChange(event: Event, value?: StencilUnknown): void {
- value = value ?? (event.target as HTMLInputElement).value;
+ if (typeof value === 'undefined') {
+ value = (event.target as HTMLInputElement).value;
+ }
// Event handling
- tryToDispatchKoliBriEvent('change', this.host, value);
+ this.emitEvent(KolEvent.change, value);
// Callback
if (typeof this.component._on?.onChange === 'function') {
@@ -208,11 +215,12 @@ export class InputController extends ControlledInputController implements Watche
* @param value - Optional value. Taken from event if not defined.
*/
protected onInput(event: Event, shouldSetFormAssociatedValue = true, value?: StencilUnknown): void {
- value = value ?? (event.target as HTMLInputElement).value;
+ if (typeof value === 'undefined') {
+ value = (event.target as HTMLInputElement).value;
+ }
// Event handling
- stopPropagation(event);
- tryToDispatchKoliBriEvent('input', this.host, value);
+ this.emitEvent(KolEvent.input, value);
// Static form handling
if (shouldSetFormAssociatedValue) {
@@ -227,8 +235,7 @@ export class InputController extends ControlledInputController implements Watche
protected onClick(event: Event): void {
// Event handling
- stopPropagation(event);
- tryToDispatchKoliBriEvent('click', this.host);
+ this.emitEvent(KolEvent.click);
// Callback
if (typeof this.component._on?.onClick === 'function') {
@@ -238,8 +245,7 @@ export class InputController extends ControlledInputController implements Watche
protected onFocus(event: Event): void {
// Event handling
- stopPropagation(event);
- tryToDispatchKoliBriEvent('focus', this.host);
+ this.emitEvent(KolEvent.focus);
// Callback
if (typeof this.component._on?.onFocus === 'function') {
diff --git a/packages/components/src/components/accordion/accordion.e2e.ts b/packages/components/src/components/accordion/accordion.e2e.ts
index 49cb87424e..e20af0affe 100644
--- a/packages/components/src/components/accordion/accordion.e2e.ts
+++ b/packages/components/src/components/accordion/accordion.e2e.ts
@@ -1,5 +1,6 @@
import { expect } from '@playwright/test';
import { test } from '@stencil/playwright';
+import { KolEvent } from '../../utils/events';
test.describe('kol-accordion', () => {
test.describe('when accordion is enabled', () => {
@@ -24,6 +25,32 @@ test.describe('kol-accordion', () => {
await page.getByRole('button', { name: 'Accordion label' }).click();
await expect(page.locator('.collapsible__content')).toHaveAttribute('aria-hidden', 'true');
});
+
+ test('should emit "click" event when the title is clicked', async ({ page }) => {
+ const eventPromise = page.locator('kol-accordion').evaluate(async (element: HTMLKolAccordionElement, KolEvent) => {
+ return new Promise((resolve) => {
+ element.addEventListener(KolEvent.click, resolve);
+ });
+ }, KolEvent);
+ await page.waitForChanges();
+ await page.getByRole('button', { name: 'Accordion label' }).click();
+ await expect(eventPromise).resolves.toBeTruthy();
+ });
+
+ test('should call "onClick" callback when the title is clicked', async ({ page }) => {
+ const callbackPromise = page.locator('kol-accordion').evaluate(async (element: HTMLKolAccordionElement) => {
+ return new Promise((resolve) => {
+ element._on = {
+ onClick: (_event: MouseEvent, value?: boolean) => {
+ resolve(value);
+ },
+ };
+ });
+ });
+ await page.waitForChanges();
+ await page.getByRole('button', { name: 'Accordion label' }).click();
+ await expect(callbackPromise).resolves.toBe(true);
+ });
});
test.describe('when accordion is disabled', () => {
diff --git a/packages/components/src/components/accordion/shadow.tsx b/packages/components/src/components/accordion/shadow.tsx
index 6436b09caf..fd22b42a47 100644
--- a/packages/components/src/components/accordion/shadow.tsx
+++ b/packages/components/src/components/accordion/shadow.tsx
@@ -1,5 +1,5 @@
// https://codepen.io/mbxtr/pen/OJPOYg?html-preprocessor=haml
-import { Component, h, Method, Prop, State, Watch } from '@stencil/core';
+import { Component, Element, h, Method, Prop, State, Watch } from '@stencil/core';
import type { JSX } from '@stencil/core';
import type {
AccordionAPI,
@@ -15,6 +15,7 @@ import { featureHint, validateAccordionCallbacks, validateDisabled, validateLabe
import { nonce } from '../../utils/dev.utils';
import { watchHeadingLevel } from '../heading/validation';
import KolCollapsibleFc, { type CollapsibleProps } from '../../functional-components/Collapsible';
+import { dispatchDomEvent, KolEvent } from '../../utils/events';
featureHint(`[KolAccordion] Anfrage nach einer KolAccordionGroup bei dem immer nur ein Accordion geöffnet ist.
@@ -35,6 +36,8 @@ featureHint(`[KolAccordion] Tab-Sperre des Inhalts im geschlossenen Zustand.`);
shadow: true,
})
export class KolAccordion implements AccordionAPI, FocusableElement {
+ @Element() private readonly host?: HTMLKolAccordionElement;
+
private readonly nonce = nonce();
private buttonWcRef?: HTMLKolButtonWcElement;
@@ -58,6 +61,9 @@ export class KolAccordion implements AccordionAPI, FocusableElement {
*/
setTimeout(() => {
this.state._on?.onClick?.(event, this._open === true);
+ if (this.host) {
+ dispatchDomEvent(this.host, KolEvent.click, this._open === true);
+ }
});
};
diff --git a/packages/components/src/components/alert/alert.e2e.ts b/packages/components/src/components/alert/alert.e2e.ts
new file mode 100644
index 0000000000..949a3cbf03
--- /dev/null
+++ b/packages/components/src/components/alert/alert.e2e.ts
@@ -0,0 +1,37 @@
+import { expect } from '@playwright/test';
+import { test } from '@stencil/playwright';
+import { KolEvent } from '../../utils/events';
+
+test.describe('kol-alert', () => {
+ test.describe('Callbacks', () => {
+ test('should call "onClose" callback when the close button is clicked', async ({ page }) => {
+ await page.setContent('');
+ const callbackPromise = page.locator('kol-alert').evaluate(async (element: HTMLKolAlertElement) => {
+ return new Promise((resolve) => {
+ element._on = {
+ onClose: (_event: Event, value?: unknown) => {
+ resolve(value);
+ },
+ };
+ });
+ });
+ await page.waitForChanges();
+ await page.getByTestId('alert-close-button').click();
+ await expect(callbackPromise).resolves.toBeUndefined();
+ });
+ });
+
+ test.describe('DOM events', () => {
+ test('should emit "close" when close button is clicked', async ({ page }) => {
+ await page.setContent('');
+ const eventPromise = page.locator('kol-alert').evaluate(async (element: HTMLKolAlertElement, KolEvent) => {
+ return new Promise((resolve) => {
+ element.addEventListener(KolEvent.close, resolve);
+ });
+ }, KolEvent);
+ await page.waitForChanges();
+ await page.getByTestId('alert-close-button').click();
+ await expect(eventPromise).resolves.toBeTruthy();
+ });
+ });
+});
diff --git a/packages/components/src/components/alert/component.tsx b/packages/components/src/components/alert/component.tsx
index dfd2fc286b..4a3b71a914 100644
--- a/packages/components/src/components/alert/component.tsx
+++ b/packages/components/src/components/alert/component.tsx
@@ -1,9 +1,10 @@
import type { JSX } from '@stencil/core';
import { alertTypeOptions, alertVariantOptions, setState, validateHasCloser, validateLabel, watchBoolean, watchValidator } from '../../schema';
-import { Component, h, Prop, State, Watch } from '@stencil/core';
+import { Component, Element, h, Prop, State, Watch } from '@stencil/core';
import { watchHeadingLevel } from '../heading/validation';
import type { AlertAPI, AlertStates, AlertType, AlertVariant, HasCloserPropType, HeadingLevel, KoliBriAlertEventCallbacks, LabelPropType } from '../../schema';
import KolAlertFc, { type KolAlertFcProps } from '../../functional-components/Alert';
+import { dispatchDomEvent, KolEvent } from '../../utils/events';
/**
* @internal
@@ -14,8 +15,13 @@ import KolAlertFc, { type KolAlertFcProps } from '../../functional-components/Al
shadow: false,
})
export class KolAlertWc implements AlertAPI {
+ @Element() private readonly host?: HTMLKolAlertWcElement;
+
private readonly close = () => {
this._on?.onClose?.(new Event('Close'));
+ if (this.host) {
+ dispatchDomEvent(this.host, KolEvent.close);
+ }
};
private readonly handleAlertTimeout = () => {
diff --git a/packages/components/src/components/badge/badge.e2e.ts b/packages/components/src/components/badge/badge.e2e.ts
new file mode 100644
index 0000000000..19a3c7a67d
--- /dev/null
+++ b/packages/components/src/components/badge/badge.e2e.ts
@@ -0,0 +1,48 @@
+import { expect } from '@playwright/test';
+import { test } from '@stencil/playwright';
+import { KolEvent } from '../../utils/events';
+
+test.describe('kol-badge', () => {
+ test.describe('Callbacks', () => {
+ ['onClick', 'onMouseDown'].forEach((callbackName) => {
+ test(`should call ${callbackName} callback when smart button emits`, async ({ page }) => {
+ await page.setContent(``);
+ const kolBadge = page.locator('kol-badge');
+
+ const callbackPromise = kolBadge.evaluate((element: HTMLKolBadgeElement, callbackName) => {
+ return new Promise((resolve) => {
+ element._smartButton = {
+ _label: `Smart Button`,
+ _on: {
+ [callbackName]: () => {
+ resolve();
+ },
+ },
+ };
+ });
+ }, callbackName);
+ await page.waitForChanges();
+
+ await page.locator('button').click();
+ await expect(callbackPromise).resolves.toBeUndefined();
+ });
+ });
+ });
+
+ test.describe('DOM events', () => {
+ [KolEvent.click, KolEvent.mousedown].forEach((event) => {
+ test(`should emit ${event} when smart button emits ${event}`, async ({ page }) => {
+ const BADGE_PROPS = { _label: `Smart Button` };
+ await page.setContent(``);
+ const eventPromise = page.locator('kol-badge').evaluate(async (element, event) => {
+ return new Promise((resolve) => {
+ element.addEventListener(event, resolve);
+ });
+ }, event);
+ await page.waitForChanges();
+ await page.locator('button').dispatchEvent(event);
+ await expect(eventPromise).resolves.toBeTruthy();
+ });
+ });
+ });
+});
diff --git a/packages/components/src/components/button-link/button-link.e2e.ts b/packages/components/src/components/button-link/button-link.e2e.ts
new file mode 100644
index 0000000000..bff66a6705
--- /dev/null
+++ b/packages/components/src/components/button-link/button-link.e2e.ts
@@ -0,0 +1,50 @@
+import { expect } from '@playwright/test';
+import { test } from '@stencil/playwright';
+import { KolEvent } from '../../utils/events';
+
+test.describe('kol-button-link', () => {
+ test('it renders label', async ({ page }) => {
+ await page.setContent('');
+ const kolButton = page.locator('kol-button-link');
+ await expect(kolButton).toContainText('Test ButtonLink Element');
+ });
+
+ test.describe('Callbacks', () => {
+ ['onClick', 'onMouseDown'].forEach((callbackName) => {
+ test(`should call ${callbackName} callback when internal button emits`, async ({ page }) => {
+ await page.setContent('');
+ const kolButton = page.locator('kol-button-link');
+
+ const callbackPromise = kolButton.evaluate((element: HTMLKolButtonElement, callbackName) => {
+ return new Promise((resolve) => {
+ element._on = {
+ [callbackName]: () => {
+ resolve();
+ },
+ };
+ });
+ }, callbackName);
+ await page.waitForChanges();
+
+ await page.locator('button').click();
+ await expect(callbackPromise).resolves.toBeUndefined();
+ });
+ });
+ });
+
+ test.describe('DOM events', () => {
+ [KolEvent.click, KolEvent.mousedown].forEach((event) => {
+ test(`should emit ${event} when internal button emits ${event}`, async ({ page }) => {
+ await page.setContent('');
+ const eventPromise = page.locator('kol-button-link').evaluate(async (element, event) => {
+ return new Promise((resolve) => {
+ element.addEventListener(event, resolve);
+ });
+ }, event);
+ await page.waitForChanges();
+ await page.locator('button').dispatchEvent(event);
+ await expect(eventPromise).resolves.toBeTruthy();
+ });
+ });
+ });
+});
diff --git a/packages/components/src/components/button/button.e2e.ts b/packages/components/src/components/button/button.e2e.ts
index 4ef24e855d..203ba89a7d 100644
--- a/packages/components/src/components/button/button.e2e.ts
+++ b/packages/components/src/components/button/button.e2e.ts
@@ -1,5 +1,6 @@
import { expect } from '@playwright/test';
import { test } from '@stencil/playwright';
+import { KolEvent } from '../../utils/events';
test.describe('kol-button', () => {
test('it renders label', async ({ page }) => {
@@ -7,4 +8,43 @@ test.describe('kol-button', () => {
const kolButton = page.locator('kol-button');
await expect(kolButton).toContainText('Test Button Element');
});
+
+ test.describe('Callbacks', () => {
+ ['onClick', 'onMouseDown'].forEach((callbackName) => {
+ test(`should call ${callbackName} callback when internal button emits`, async ({ page }) => {
+ await page.setContent('');
+ const kolButton = page.locator('kol-button');
+
+ const callbackPromise = kolButton.evaluate((element: HTMLKolButtonElement, callbackName) => {
+ return new Promise((resolve) => {
+ element._on = {
+ [callbackName]: () => {
+ resolve();
+ },
+ };
+ });
+ }, callbackName);
+ await page.waitForChanges();
+
+ await page.locator('button').click();
+ await expect(callbackPromise).resolves.toBeUndefined();
+ });
+ });
+ });
+
+ test.describe('DOM events', () => {
+ [KolEvent.click, KolEvent.mousedown].forEach((event) => {
+ test(`should emit ${event} when internal button emits ${event}`, async ({ page }) => {
+ await page.setContent('');
+ const eventPromise = page.locator('kol-button').evaluate(async (element, event) => {
+ return new Promise((resolve) => {
+ element.addEventListener(event, resolve);
+ });
+ }, event);
+ await page.waitForChanges();
+ await page.locator('button').dispatchEvent(event);
+ await expect(eventPromise).resolves.toBeTruthy();
+ });
+ });
+ });
});
diff --git a/packages/components/src/components/button/component.tsx b/packages/components/src/components/button/component.tsx
index 496b871036..be34a72421 100644
--- a/packages/components/src/components/button/component.tsx
+++ b/packages/components/src/components/button/component.tsx
@@ -46,7 +46,7 @@ import {
import type { JSX } from '@stencil/core';
import { Component, Element, h, Host, Method, Prop, State, Watch } from '@stencil/core';
-import { stopPropagation, tryToDispatchKoliBriEvent } from '../../utils/events';
+import { dispatchDomEvent, KolEvent } from '../../utils/events';
import { nonce } from '../../utils/dev.utils';
import { propagateResetEventToForm, propagateSubmitEventToForm } from '../form/controller';
import { AssociatedInputController } from '../input-adapter-leanup/associated.controller';
@@ -90,11 +90,6 @@ export class KolButtonWc implements ButtonAPI, FocusableElement {
ref: this.buttonRef,
});
} else {
- // Event handling
- stopPropagation(event);
-
- tryToDispatchKoliBriEvent('click', this.host, this.state._value);
-
// TODO: Static form handling
this.controller.setFormAssociatedValue(this.state._value);
@@ -104,6 +99,17 @@ export class KolButtonWc implements ButtonAPI, FocusableElement {
this.state._on?.onClick(event, this.state._value);
}
}
+
+ if (this.host) {
+ dispatchDomEvent(this.host, KolEvent.click, this.state._value);
+ }
+ };
+
+ private readonly onMouseDown = (event: MouseEvent) => {
+ this.state?._on?.onMouseDown?.(event);
+ if (this.host) {
+ dispatchDomEvent(this.host, KolEvent.mousedown);
+ }
};
public render(): JSX.Element {
@@ -131,8 +137,8 @@ export class KolButtonWc implements ButtonAPI, FocusableElement {
disabled={this.state._disabled}
id={this.state._id}
name={this.state._name}
- {...this.state._on}
onClick={this.onClick}
+ onMouseDown={this.onMouseDown}
role={this.state._role}
tabIndex={this.state._tabIndex}
type={this.state._type}
diff --git a/packages/components/src/components/card/card.e2e.ts b/packages/components/src/components/card/card.e2e.ts
new file mode 100644
index 0000000000..f4f20d7f74
--- /dev/null
+++ b/packages/components/src/components/card/card.e2e.ts
@@ -0,0 +1,37 @@
+import { expect } from '@playwright/test';
+import { test } from '@stencil/playwright';
+import { KolEvent } from '../../utils/events';
+
+test.describe('kol-card', () => {
+ test.describe('Callbacks', () => {
+ test('should call "onClose" callback when the close button is clicked', async ({ page }) => {
+ await page.setContent('');
+ const callbackPromise = page.locator('kol-card').evaluate(async (element: HTMLKolCardElement) => {
+ return new Promise((resolve) => {
+ element._on = {
+ onClose: (_event: Event, value?: unknown) => {
+ resolve(value);
+ },
+ };
+ });
+ });
+ await page.waitForChanges();
+ await page.getByTestId('card-close-button').click();
+ await expect(callbackPromise).resolves.toBeUndefined();
+ });
+ });
+
+ test.describe('DOM events', () => {
+ test('should emit "close" when close button is clicked', async ({ page }) => {
+ await page.setContent('');
+ const eventPromise = page.locator('kol-card').evaluate(async (element: HTMLKolCardElement, KolEvent) => {
+ return new Promise((resolve) => {
+ element.addEventListener(KolEvent.close, resolve);
+ });
+ }, KolEvent);
+ await page.waitForChanges();
+ await page.getByTestId('card-close-button').click();
+ await expect(eventPromise).resolves.toBeTruthy();
+ });
+ });
+});
diff --git a/packages/components/src/components/card/shadow.tsx b/packages/components/src/components/card/shadow.tsx
index d503e964f9..ccd2b5d4d9 100644
--- a/packages/components/src/components/card/shadow.tsx
+++ b/packages/components/src/components/card/shadow.tsx
@@ -1,4 +1,4 @@
-import { Component, h, Prop, State, Watch } from '@stencil/core';
+import { Component, Element, h, Prop, State, Watch } from '@stencil/core';
import type { JSX } from '@stencil/core';
import type { CardAPI, CardStates, HasCloserPropType, HeadingLevel, KoliBriAlertEventCallbacks, KoliBriCardEventCallbacks, LabelPropType } from '../../schema';
import { setState, validateHasCloser, validateLabel } from '../../schema';
@@ -8,6 +8,7 @@ import { watchHeadingLevel } from '../heading/validation';
import { KolButtonWcTag } from '../../core/component-names';
import { KolHeadingFc } from '../../functional-components';
+import { dispatchDomEvent, KolEvent } from '../../utils/events';
/**
* @slot - Ermöglicht das Einfügen beliebigen HTML's in den Inhaltsbereich der Card.
@@ -20,10 +21,15 @@ import { KolHeadingFc } from '../../functional-components';
shadow: true,
})
export class KolCard implements CardAPI {
+ @Element() private readonly host?: HTMLKolCardElement;
+
private readonly close = () => {
if (this._on?.onClose !== undefined) {
this._on.onClose(new Event('Close'));
}
+ if (this.host) {
+ dispatchDomEvent(this.host, KolEvent.close);
+ }
};
private readonly on = {
@@ -44,6 +50,7 @@ export class KolCard implements CardAPI {
{this.state._hasCloser && (
-
+
@@ -81,7 +81,7 @@ exports[`kol-card should render with _label="Überschrift" _level=1 _hasCloser=t
-
+
@@ -133,7 +133,7 @@ exports[`kol-card should render with _label="Überschrift" _level=2 _hasCloser=t
-
+
@@ -185,7 +185,7 @@ exports[`kol-card should render with _label="Überschrift" _level=3 _hasCloser=t
-
+
@@ -237,7 +237,7 @@ exports[`kol-card should render with _label="Überschrift" _level=4 _hasCloser=t
-
+
@@ -289,7 +289,7 @@ exports[`kol-card should render with _label="Überschrift" _level=5 _hasCloser=t
-
+
@@ -341,7 +341,7 @@ exports[`kol-card should render with _label="Überschrift" _level=6 _hasCloser=t
-
+
diff --git a/packages/components/src/components/combobox/combobox.e2e.ts b/packages/components/src/components/combobox/combobox.e2e.ts
new file mode 100644
index 0000000000..82e46bced5
--- /dev/null
+++ b/packages/components/src/components/combobox/combobox.e2e.ts
@@ -0,0 +1,10 @@
+import { test } from '@stencil/playwright';
+import { testInputCallbacksAndEvents, testInputValueReflection } from '../../e2e';
+
+const COMPONENT_NAME = 'kol-combobox';
+const TEST_VALUE = 'Hello World';
+
+test.describe(COMPONENT_NAME, () => {
+ testInputValueReflection(COMPONENT_NAME, TEST_VALUE);
+ testInputCallbacksAndEvents(COMPONENT_NAME, TEST_VALUE);
+});
diff --git a/packages/components/src/components/combobox/shadow.tsx b/packages/components/src/components/combobox/shadow.tsx
index 6e57db76ac..6d691e485e 100644
--- a/packages/components/src/components/combobox/shadow.tsx
+++ b/packages/components/src/components/combobox/shadow.tsx
@@ -20,7 +20,6 @@ import type { JSX } from '@stencil/core';
import { Component, Element, Fragment, h, Host, Listen, Method, Prop, State, Watch } from '@stencil/core';
import { nonce } from '../../utils/dev.utils';
-import { stopPropagation, tryToDispatchKoliBriEvent } from '../../utils/events';
import { ComboboxController } from './controller';
import { KolIconTag, KolInputTag } from '../../core/component-names';
import { InternalUnderlinedBadgeText } from '../../functional-components';
@@ -85,6 +84,7 @@ export class KolCombobox implements ComboboxAPI {
private onInput(event: Event) {
const target = event.target as HTMLInputElement;
this.state._value = target.value;
+ this._value = target.value;
this.controller.onFacade.onInput(event);
this.setFilteredSuggestionsByQuery(target.value);
this._focusedOptionIndex = -1;
@@ -470,7 +470,7 @@ export class KolCombobox implements ComboboxAPI {
/**
* Defines the value of the input.
*/
- @Prop({ mutable: true }) public _value?: string;
+ @Prop({ mutable: true, reflect: true }) public _value?: string;
@State() public state: ComboboxStates = {
_hasValue: false,
@@ -625,16 +625,9 @@ export class KolCombobox implements ComboboxAPI {
}
private onChange(event: Event): void {
- // Event handling
- stopPropagation(event);
- tryToDispatchKoliBriEvent('change', this.host, this.state._value);
+ this.controller.onFacade.onChange(event);
// Static form handling
this.controller.setFormAssociatedValue(this.state._value as unknown as string);
-
- // Callback
- if (typeof this.state._on?.onChange === 'function' && !this._isOpen) {
- this.state._on.onChange(event, this.state._value);
- }
}
}
diff --git a/packages/components/src/components/combobox/test/__snapshots__/snapshot.spec.tsx.snap b/packages/components/src/components/combobox/test/__snapshots__/snapshot.spec.tsx.snap
index e38f058eac..f45ea2acdc 100644
--- a/packages/components/src/components/combobox/test/__snapshots__/snapshot.spec.tsx.snap
+++ b/packages/components/src/components/combobox/test/__snapshots__/snapshot.spec.tsx.snap
@@ -1,7 +1,7 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`kol-combobox should render with _label="Label" _name="field" _placeholder="Hier steht ein Platzhaltertext" _value="Herr" _suggestions=["Frau","Herr","Divers"] _accessKey="V" 1`] = `
-
+
@@ -26,7 +26,7 @@ exports[`kol-combobox should render with _label="Label" _name="field" _placehold
`;
exports[`kol-combobox should render with _label="Label" _name="field" _placeholder="Hier steht ein Platzhaltertext" _value="Herr" _suggestions=["Frau","Herr","Divers"] _alert=true 1`] = `
-
+
@@ -50,7 +50,7 @@ exports[`kol-combobox should render with _label="Label" _name="field" _placehold
`;
exports[`kol-combobox should render with _label="Label" _name="field" _placeholder="Hier steht ein Platzhaltertext" _value="Herr" _suggestions=["Frau","Herr","Divers"] _disabled=true 1`] = `
-
+
@@ -74,7 +74,7 @@ exports[`kol-combobox should render with _label="Label" _name="field" _placehold
`;
exports[`kol-combobox should render with _label="Label" _name="field" _placeholder="Hier steht ein Platzhaltertext" _value="Herr" _suggestions=["Frau","Herr","Divers"] _hint="Hint" 1`] = `
-
+
@@ -98,7 +98,7 @@ exports[`kol-combobox should render with _label="Label" _name="field" _placehold
`;
exports[`kol-combobox should render with _label="Label" _name="field" _placeholder="Hier steht ein Platzhaltertext" _value="Herr" _suggestions=["Frau","Herr","Divers"] _icons={"left":{"icon":"codicon codicon-arrow-left"},"right":{"icon":"codicon codicon-arrow-right"}} 1`] = `
-
+
@@ -122,7 +122,7 @@ exports[`kol-combobox should render with _label="Label" _name="field" _placehold
`;
exports[`kol-combobox should render with _label="Label" _name="field" _placeholder="Hier steht ein Platzhaltertext" _value="Herr" _suggestions=["Frau","Herr","Divers"] _icons={"left":{"icon":"codicon codicon-arrow-left"}} 1`] = `
-
+
@@ -146,7 +146,7 @@ exports[`kol-combobox should render with _label="Label" _name="field" _placehold
`;
exports[`kol-combobox should render with _label="Label" _name="field" _placeholder="Hier steht ein Platzhaltertext" _value="Herr" _suggestions=["Frau","Herr","Divers"] _icons={"right":{"icon":"codicon codicon-arrow-right"}} 1`] = `
-
+
@@ -170,7 +170,7 @@ exports[`kol-combobox should render with _label="Label" _name="field" _placehold
`;
exports[`kol-combobox should render with _label="Label" _name="field" _placeholder="Hier steht ein Platzhaltertext" _value="Herr" _suggestions=["Frau","Herr","Divers"] _msg={"_type":"error","_description":"Es ist ein Fehler aufgetreten"} _hideError=true 1`] = `
-
+
@@ -194,7 +194,7 @@ exports[`kol-combobox should render with _label="Label" _name="field" _placehold
`;
exports[`kol-combobox should render with _label="Label" _name="field" _placeholder="Hier steht ein Platzhaltertext" _value="Herr" _suggestions=["Frau","Herr","Divers"] _msg={"_type":"error","_description":"Es ist ein Fehler aufgetreten"} 1`] = `
-
+
@@ -218,7 +218,7 @@ exports[`kol-combobox should render with _label="Label" _name="field" _placehold
`;
exports[`kol-combobox should render with _label="Label" _name="field" _placeholder="Hier steht ein Platzhaltertext" _value="Herr" _suggestions=["Frau","Herr","Divers"] _readOnly=true 1`] = `
-
+
@@ -242,7 +242,7 @@ exports[`kol-combobox should render with _label="Label" _name="field" _placehold
`;
exports[`kol-combobox should render with _label="Label" _name="field" _placeholder="Hier steht ein Platzhaltertext" _value="Herr" _suggestions=["Frau","Herr","Divers"] _shortKey="S" 1`] = `
-
+
@@ -267,7 +267,7 @@ exports[`kol-combobox should render with _label="Label" _name="field" _placehold
`;
exports[`kol-combobox should render with _label="Label" _name="field" _placeholder="Hier steht ein Platzhaltertext" _value="Herr" _suggestions=["Frau","Herr","Divers"] _touched=true 1`] = `
-
+
@@ -291,7 +291,7 @@ exports[`kol-combobox should render with _label="Label" _name="field" _placehold
`;
exports[`kol-combobox should render with _label="Label" _name="field" _placeholder="Hier steht ein Platzhaltertext" _value="Herr" _suggestions=["Frau","Herr","Divers"] 1`] = `
-
+