Skip to content

Commit

Permalink
feat(core/group): handle preventDefault for events (#1454)
Browse files Browse the repository at this point in the history
  • Loading branch information
danielleroux authored Sep 9, 2024
1 parent 1e16bce commit da1f10e
Show file tree
Hide file tree
Showing 10 changed files with 209 additions and 45 deletions.
5 changes: 5 additions & 0 deletions .changeset/violet-ducks-refuse.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@siemens/ix': patch
---

fix(core/group): remove max-width restriction
5 changes: 5 additions & 0 deletions .changeset/wicked-avocados-glow.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@siemens/ix': minor
---

feat(core/group): handle preventDefault for events
8 changes: 7 additions & 1 deletion packages/core/component-doc.json
Original file line number Diff line number Diff line change
Expand Up @@ -7212,7 +7212,13 @@
"styles": [],
"slots": [],
"parts": [],
"listeners": []
"listeners": [
{
"event": "selectedChanged",
"capture": false,
"passive": false
}
]
},
{
"dirPath": "src/components/group",
Expand Down
3 changes: 2 additions & 1 deletion packages/core/src/components/group/group.scss
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,8 @@
display: flex;
flex-direction: column;
position: relative;
max-width: 19.75rem;
width: 19.75rem;
min-width: 12rem;
border-color: var(--theme-group-item--border-color);

.group-header {
Expand Down
93 changes: 56 additions & 37 deletions packages/core/src/components/group/group.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,10 @@ import {
EventEmitter,
h,
Host,
Listen,
Prop,
State,
Watch,
} from '@stencil/core';
import { createMutationObserver } from '../utils/mutation-observer';
import { hasSlottedElements } from '../utils/shadow-dom';
Expand Down Expand Up @@ -87,6 +89,13 @@ export class Group {

private observer: MutationObserver = null!;

@Watch('selected')
selectedChanged(newSelected: boolean) {
if (newSelected === false) {
this.changeItemIndex();
}
}

get dropdownItems() {
return Array.from(
this.hostElement.querySelectorAll('ix-group-dropdown-item')
Expand All @@ -104,38 +113,59 @@ export class Group {
}

private onExpandClick(event: Event) {
const oldCollapsed = this.collapsed;
this.collapsed = !this.collapsed;

this.collapsedChanged.emit(this.collapsed);
const { defaultPrevented } = this.collapsedChanged.emit(this.collapsed);
event.stopPropagation();

if (defaultPrevented) {
this.collapsed = oldCollapsed;
}
}

private onHeaderClick(event: Event) {
this.setGroupSelection(!this.selected);

if (this.suppressHeaderSelection) {
this.onExpandClick(event);
return;
}

this.changeHeaderSelection(!this.selected);
this.changeItemIndex();
}

private onItemClick(index?: number) {
const newIndex = index === this.index ? undefined : index;
this.selectItem.emit(newIndex);
private changeHeaderSelection(newSelection: boolean) {
const oldIsHeaderSelected = this.selected;
const newIsHeaderSelected = newSelection;
this.selected = newIsHeaderSelected;
const { defaultPrevented } = this.selectGroup.emit(newIsHeaderSelected);

this.index = newIndex;
if (defaultPrevented) {
this.selected = oldIsHeaderSelected;
return;
}
}

if (this.index !== undefined && this.index >= 0) {
this.itemSelected = true;
} else this.itemSelected = false;
private changeItemIndex(index?: number) {
const oldIndex = this.index;
const newIndex = index === this.index ? undefined : index;

this.setGroupSelection(false);
}
if (this.index === newIndex) {
return;
}

private setGroupSelection(selection: boolean) {
if (!this.suppressHeaderSelection) {
this.selected = selection;
this.selectGroup.emit(this.selected);
this.index = newIndex;
const { defaultPrevented } = this.selectItem.emit(newIndex);
if (defaultPrevented) {
this.index = oldIndex;
return;
}

const items = this.groupItems;
items.forEach((item, i) => {
item.selected = i === this.index;
});

this.itemSelected = items.some((item) => item.selected);
}

private onSlotChange() {
Expand All @@ -150,12 +180,6 @@ export class Group {

componentWillRender() {
this.groupItems.forEach((item, index) => {
if (this.selected === true) {
item.selected = false;
this.index = undefined;
this.itemSelected = false;
return;
}
item.selected = index === this.index;
item.index = index;
});
Expand All @@ -165,26 +189,12 @@ export class Group {
this.observer = createMutationObserver(() => {
this.slotSize = this.groupItems.length;
});

if (!this.groupContent) {
return;
}

this.observer.observe(this.groupContent, {
childList: true,
});

this.groupContent?.addEventListener(
'selectedChanged',
(evt: CustomEvent<HTMLIxGroupItemElement>) => {
if (evt.detail.suppressSelection) {
evt.stopPropagation();
return;
}

this.onItemClick(evt.detail.index);
}
);
}

disconnectedCallback() {
Expand All @@ -193,6 +203,15 @@ export class Group {
}
}

@Listen('selectedChanged')
onItemClicked(event: CustomEvent) {
if (event.target instanceof HTMLElement) {
const item = event.target as HTMLIxGroupItemElement;
const index = this.groupItems.indexOf(item);
this.changeItemIndex(index);
}
}

render() {
return (
<Host>
Expand Down
50 changes: 47 additions & 3 deletions packages/core/src/components/group/test/group.ct.ts
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ test('suppress selection should not stop event propagation', async ({
await expect(groupItem).toHaveText('Item 1Clicked');
});

test('prevent default', async ({ mount, page }) => {
test('item prevent default selection item event', async ({ mount, page }) => {
await mount(`
<ix-group>
<ix-group-item>Item 1</ix-group-item>
Expand All @@ -97,9 +97,53 @@ test('prevent default', async ({ mount, page }) => {
await expect(group).toHaveClass(/hydrated/);

await group.evaluate((item) => {
item.addEventListener('selectedChanged', (e) => e.preventDefault());
item.addEventListener('selectItem', (e) => e.preventDefault());
});

await groupItem.click();
await expect(groupItem).not.toHaveClass('/hydrated selected');
await expect(groupItem).not.toHaveClass(/hydrated selected/);
});

test('group header prevent default collapse/expand', async ({
mount,
page,
}) => {
await mount(`
<ix-group>
<ix-group-item>Item 1</ix-group-item>
<ix-group-item>Item 2</ix-group-item>
</ix-group>
`);
const group = page.locator('ix-group');
const expandIcon = group.getByTestId('expand-collapsed-icon');

await group.evaluate((item) => {
item.addEventListener('collapsedChanged', (e) => e.preventDefault());
});

await expandIcon.click();

await expect(group).toHaveAttribute('collapsed');
});

test('group header prevent default selection event', async ({
mount,
page,
}) => {
await mount(`
<ix-group header="Test" sub-header="Test2">
<ix-group-item>Item 1</ix-group-item>
<ix-group-item>Item 2</ix-group-item>
</ix-group>
`);
const group = page.locator('ix-group');
const groupHeader = group.locator('.group-header');

await group.evaluate((item) => {
item.addEventListener('selectGroup', (e) => e.preventDefault());
});

await groupHeader.click();

await expect(group).not.toHaveAttribute('selected');
});
74 changes: 74 additions & 0 deletions packages/core/src/tests/group/adapt-width/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
<!--
SPDX-FileCopyrightText: 2024 Siemens AG
SPDX-License-Identifier: MIT
-->

<html>
<head>
<meta charset="utf-8" />
<meta
name="viewport"
content="width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=5.0"
/>
<title>Stencil Component Starter</title>
<style>
ix-group {
margin-bottom: 3rem;
}
</style>
</head>
<body>
<ix-group id="group" header="Header text" sub-header="Subheader text">
<ix-group-item text="Example text 1"></ix-group-item>
<ix-group-item text="Example text 2"></ix-group-item>
<ix-group-item text="Example text 3"></ix-group-item>
</ix-group>

<ix-group
style="width: 10px"
header="testasdjaskd aksjhd kjashd kjashd kjashd kjashd "
subHeader="test2alskdj aslkd jaslkdjaslkjd laksjd lkasjd lkasj das"
>
<ix-group-item
text="Long long long long long longLong long long long long longLong long
long long long longLong long long long long longLong long long long
long long"
></ix-group-item>

<ix-group-item>
Long long long long long longLong long long long long longLong long long
long long longLong long long long long longLong long long long long long
</ix-group-item>
</ix-group>

<ix-group
style="width: 50rem"
header="testasdjaskd aksjhd kjashd kjashd kjashd kjashd "
subHeader="test2alskdj aslkd jaslkdjaslkjd laksjd lkasjd lkasj das"
>
<ix-group-item
text="Long long long long long longLong long long long long longLong long
long long long longLong long long long long longLong long long long
long long"
></ix-group-item>

<ix-group-item>
Long long long long long longLong long long long long longLong long long
long long longLong long long long long longLong long long long long long
</ix-group-item>
</ix-group>

<ix-group
style="width: fit-content"
header="testasdjaskd aksjhd kjashd kjashd kjashd kjashd "
subHeader="test2alskdj aslkd jaslkdjaslkjd laksjd lkasjd lkasj das"
>
<ix-group-item
text="Long long long long long longLong long long long long longLong long
long long long longLong long long long"
></ix-group-item>
</ix-group>
<script src="http://127.0.0.1:8080/scripts/e2e/load-e2e-runtime.js"></script>
</body>
</html>
16 changes: 13 additions & 3 deletions packages/core/src/tests/group/group.e2e.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,10 +38,20 @@ regressionTest.describe('group', () => {

regressionTest('item selected', async ({ page }) => {
await page.goto('group/basic');
await page.locator('.btn-expand-header ix-icon').click();
await page.locator('text=Example text 1').first().click();
await page.locator('text=Example text 2').first().hover();
await page.getByTestId('expand-collapsed-icon').click();
await page.locator('text=Example text 1').click();
await page.locator('text=Example text 2').hover();

expect(await page.screenshot({ fullPage: true })).toMatchSnapshot();
});

regressionTest('adapt-width', async ({ page }) => {
await page.goto('group/adapt-width');
const children = await page.locator('ix-group').all();
for (const child of children) {
const groupExpand = child.getByTestId('expand-collapsed-icon');
await groupExpand.click();
}
expect(await page.screenshot({ fullPage: true })).toMatchSnapshot();
});
});
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.

0 comments on commit da1f10e

Please sign in to comment.