Skip to content

Commit

Permalink
feat(core/tabs): add additional navigation events (#669)
Browse files Browse the repository at this point in the history
  • Loading branch information
danielleroux committed Aug 7, 2023
1 parent 9c9cb0e commit d800f29
Show file tree
Hide file tree
Showing 7 changed files with 230 additions and 13 deletions.
18 changes: 16 additions & 2 deletions packages/angular/src/components.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1889,11 +1889,19 @@ export class IxTabItem {
constructor(c: ChangeDetectorRef, r: ElementRef, protected z: NgZone) {
c.detach();
this.el = r.nativeElement;
proxyOutputs(this, this.el, ['tabClick']);
}
}


export declare interface IxTabItem extends Components.IxTabItem {}
import type { TabClickDetail as IIxTabItemTabClickDetail } from '@siemens/ix';

export declare interface IxTabItem extends Components.IxTabItem {
/**
* On tab click @since 2.0.0
*/
tabClick: EventEmitter<CustomEvent<IIxTabItemTabClickDetail>>;
}


@ProxyCmp({
Expand All @@ -1911,11 +1919,17 @@ export class IxTabs {
constructor(c: ChangeDetectorRef, r: ElementRef, protected z: NgZone) {
c.detach();
this.el = r.nativeElement;
proxyOutputs(this, this.el, ['selectedChange']);
}
}


export declare interface IxTabs extends Components.IxTabs {}
export declare interface IxTabs extends Components.IxTabs {
/**
* `selected` property changed @since 2.0.0
*/
selectedChange: EventEmitter<CustomEvent<number>>;
}


@ProxyCmp({
Expand Down
39 changes: 37 additions & 2 deletions packages/core/component-doc.json
Original file line number Diff line number Diff line change
Expand Up @@ -9397,7 +9397,22 @@
}
],
"methods": [],
"events": [],
"events": [
{
"event": "tabClick",
"detail": "{ nativeEvent: MouseEvent; }",
"bubbles": true,
"cancelable": true,
"composed": true,
"docs": "On tab click",
"docsTags": [
{
"name": "since",
"text": "2.0.0"
}
]
}
],
"styles": [],
"slots": [],
"parts": [],
Expand Down Expand Up @@ -9531,7 +9546,22 @@
}
],
"methods": [],
"events": [],
"events": [
{
"event": "selectedChange",
"detail": "number",
"bubbles": true,
"cancelable": true,
"composed": true,
"docs": "`selected` property changed",
"docsTags": [
{
"name": "since",
"text": "2.0.0"
}
]
}
],
"styles": [],
"slots": [],
"parts": [],
Expand All @@ -9541,6 +9571,11 @@
"target": "window",
"capture": false,
"passive": true
},
{
"event": "tabClick",
"capture": false,
"passive": false
}
]
},
Expand Down
20 changes: 20 additions & 0 deletions packages/core/src/components.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ import { KeyValueLabelPosition } from "./components/key-value/key-value";
import { IxModalSize } from "./components/modal/modal";
import { PushCardVariant } from "./components/push-card/push-card";
import { SplitButtonVariant } from "./components/split-button/split-button";
import { TabClickDetail } from "./components/tab-item/tab-item";
import { TimePickerCorners } from "./components/time-picker/time-picker";
import { ToastConfig, ToastType } from "./components/toast/toast-utils";
import { TypedEvent } from "./components/utils/typed-event";
Expand Down Expand Up @@ -59,6 +60,7 @@ export { KeyValueLabelPosition } from "./components/key-value/key-value";
export { IxModalSize } from "./components/modal/modal";
export { PushCardVariant } from "./components/push-card/push-card";
export { SplitButtonVariant } from "./components/split-button/split-button";
export { TabClickDetail } from "./components/tab-item/tab-item";
export { TimePickerCorners } from "./components/time-picker/time-picker";
export { ToastConfig, ToastType } from "./components/toast/toast-utils";
export { TypedEvent } from "./components/utils/typed-event";
Expand Down Expand Up @@ -2130,6 +2132,14 @@ export interface IxSplitButtonItemCustomEvent<T> extends CustomEvent<T> {
detail: T;
target: HTMLIxSplitButtonItemElement;
}
export interface IxTabItemCustomEvent<T> extends CustomEvent<T> {
detail: T;
target: HTMLIxTabItemElement;
}
export interface IxTabsCustomEvent<T> extends CustomEvent<T> {
detail: T;
target: HTMLIxTabsElement;
}
export interface IxTimePickerCustomEvent<T> extends CustomEvent<T> {
detail: T;
target: HTMLIxTimePickerElement;
Expand Down Expand Up @@ -4606,6 +4616,11 @@ declare namespace LocalJSX {
* Set layout width style
*/
"layout"?: 'auto' | 'stretched';
/**
* On tab click
* @since 2.0.0
*/
"onTabClick"?: (event: IxTabItemCustomEvent<TabClickDetail>) => void;
/**
* Set selected placement
*/
Expand All @@ -4628,6 +4643,11 @@ declare namespace LocalJSX {
* Set layout width style
*/
"layout"?: 'auto' | 'stretched';
/**
* `selected` property changed
* @since 2.0.0
*/
"onSelectedChange"?: (event: IxTabsCustomEvent<number>) => void;
/**
* Set placement style
*/
Expand Down
22 changes: 21 additions & 1 deletion packages/core/src/components/tab-item/tab-item.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,11 @@
* LICENSE file in the root directory of this source tree.
*/

import { Component, h, Host, Prop } from '@stencil/core';
import { Component, Event, EventEmitter, h, Host, Prop } from '@stencil/core';

export type TabClickDetail = {
nativeEvent: MouseEvent;
};

@Component({
tag: 'ix-tab-item',
Expand Down Expand Up @@ -55,6 +59,13 @@ export class TabItem {
*/
@Prop() placement: 'bottom' | 'top' = 'bottom';

/**
* On tab click
*
* @since 2.0.0
*/
@Event() tabClick: EventEmitter<TabClickDetail>;

private tabItemClasses(props: {
selected: boolean;
disabled: boolean;
Expand Down Expand Up @@ -89,6 +100,15 @@ export class TabItem {
circle: this.rounded,
})}
tabIndex={0}
onClick={(event: MouseEvent) => {
const clientEvent = this.tabClick.emit({
nativeEvent: event,
});

if (clientEvent.defaultPrevented) {
event.stopPropagation();
}
}}
>
<div
class={{
Expand Down
40 changes: 34 additions & 6 deletions packages/core/src/components/tabs/tabs.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@
import {
Component,
Element,
Event,
EventEmitter,
h,
Host,
Listen,
Expand Down Expand Up @@ -52,6 +54,13 @@ export class Tabs {
*/
@Prop() placement: 'bottom' | 'top' = 'bottom';

/**
* `selected` property changed
*
* @since 2.0.0
*/
@Event() selectedChange: EventEmitter<number>;

@State() totalItems = 0;
@State() currentScrollAmount = 0;
@State() scrollAmount = 100;
Expand Down Expand Up @@ -164,7 +173,14 @@ export class Tabs {
}

private clickTab(index: number) {
if (this.dragStop()) return;
if (this.dragStop()) {
return;
}

const { defaultPrevented } = this.selectedChange.emit(index);
if (defaultPrevented) {
return;
}

this.setSelected(index);
this.moveTabToView(index);
Expand Down Expand Up @@ -236,17 +252,29 @@ export class Tabs {

componentDidLoad() {
const tabs = this.getTabs();
tabs.forEach((element, index) => {
const isDisabled = element.getAttribute('disabled') !== null;
if (!isDisabled)
element.addEventListener('click', () => this.clickTab(index));

tabs.forEach((element) => {
element.addEventListener('mousedown', (event) =>
this.dragStart(element, event)
);
});
}

@Listen('tabClick')
onTabClick(event: CustomEvent) {
if (event.defaultPrevented) {
return;
}

const target = event.target;
const tabs = this.getTabs();

tabs.forEach((tab, index) => {
if (!tab.disabled && tab === target) {
this.clickTab(index);
}
});
}

render() {
return (
<Host>
Expand Down
98 changes: 98 additions & 0 deletions packages/core/src/components/tabs/test/tabs.ct.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
/*
* SPDX-FileCopyrightText: 2023 Siemens AG
*
* SPDX-License-Identifier: MIT
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
/*
* SPDX-FileCopyrightText: 2023 Siemens AG
*
* SPDX-License-Identifier: MIT
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
import { expect } from '@playwright/test';
import { test } from '@utils/test';

test('renders', async ({ mount, page }) => {
await mount(`
<ix-tabs>
<ix-tab-item>Item 1</ix-tab-item>
<ix-tab-item>Item 2</ix-tab-item>
<ix-tab-item>Item 3</ix-tab-item>
</ix-tabs>
`);
const tabs = page.locator('ix-tabs');
const tab = page.locator('ix-tab-item').nth(0);

await expect(tabs).toHaveClass(/hydrated/);
await expect(tab).toHaveClass(/selected/);
});

test('should change tab', async ({ mount, page }) => {
await mount(`
<ix-tabs>
<ix-tab-item>Item 1</ix-tab-item>
<ix-tab-item>Item 2</ix-tab-item>
<ix-tab-item>Item 3</ix-tab-item>
</ix-tabs>
`);
const tabs = page.locator('ix-tabs');
const tab = page.locator('ix-tab-item').nth(2);

await tab.click();

await expect(tabs).toHaveClass(/hydrated/);
await expect(tab).toHaveClass(/selected/);
});

test('should not change tab by tab click event', async ({ mount, page }) => {
await mount(`
<ix-tabs>
<ix-tab-item>Item 1</ix-tab-item>
<ix-tab-item>Item 2</ix-tab-item>
<ix-tab-item>Item 3</ix-tab-item>
</ix-tabs>
`);
const tabs = page.locator('ix-tabs');
const firstTab = page.locator('ix-tab-item').nth(0);
const lastTab = page.locator('ix-tab-item').nth(2);

lastTab.evaluate((tabElement) => {
tabElement.addEventListener('tabClick', (event) => event.preventDefault());
});

await lastTab.click();

await expect(tabs).toHaveClass(/hydrated/);
await expect(firstTab).toHaveClass(/selected/);
await expect(lastTab).not.toHaveClass(/selected/);
});

test('should not change tab by tabs event', async ({ mount, page }) => {
await mount(`
<ix-tabs>
<ix-tab-item>Item 1</ix-tab-item>
<ix-tab-item>Item 2</ix-tab-item>
<ix-tab-item>Item 3</ix-tab-item>
</ix-tabs>
`);
const tabs = page.locator('ix-tabs');
const firstTab = page.locator('ix-tab-item').nth(0);
const lastTab = page.locator('ix-tab-item').nth(2);

tabs.evaluate((tabElement) => {
tabElement.addEventListener('selectedChange', (event) =>
event.preventDefault()
);
});

await lastTab.click();

await expect(tabs).toHaveClass(/hydrated/);
await expect(firstTab).toHaveClass(/selected/);
await expect(lastTab).not.toHaveClass(/selected/);
});
6 changes: 4 additions & 2 deletions packages/vue/src/components.ts
Original file line number Diff line number Diff line change
Expand Up @@ -654,7 +654,8 @@ export const IxTabItem = /*@__PURE__*/ defineContainer<JSX.IxTabItem>('ix-tab-it
'rounded',
'counter',
'layout',
'placement'
'placement',
'tabClick'
]);


Expand All @@ -663,7 +664,8 @@ export const IxTabs = /*@__PURE__*/ defineContainer<JSX.IxTabs>('ix-tabs', undef
'rounded',
'selected',
'layout',
'placement'
'placement',
'selectedChange'
]);


Expand Down

0 comments on commit d800f29

Please sign in to comment.