Skip to content

Commit

Permalink
feat: add Tabs component (#341)
Browse files Browse the repository at this point in the history
Co-authored-by: Radoslav Karaivanov <rkaraivanov@infragistics.com>
Co-authored-by: sivanova <sivanova@infragistics.com>
Co-authored-by: Silvia Ivanova <59446295+SisIvanova@users.noreply.github.com>
Co-authored-by: Simeon Simeonoff <sim.simeonoff@gmail.com>
  • Loading branch information
5 people authored Jul 7, 2022
1 parent 841674b commit 6fa846c
Show file tree
Hide file tree
Showing 23 changed files with 1,844 additions and 0 deletions.
6 changes: 6 additions & 0 deletions src/components/common/definitions/defineAllComponents.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,9 @@ import IgcSliderComponent from '../../slider/slider.js';
import IgcSnackbarComponent from '../../snackbar/snackbar.js';
import IgcToastComponent from '../../toast/toast.js';
import IgcSliderLabelComponent from '../../slider/slider-label.js';
import IgcTabsComponent from '../../tabs/tabs.js';
import IgcTabComponent from '../../tabs/tab.js';
import IgcTabPanelComponent from '../../tabs/tab-panel.js';
import { defineComponents } from './defineComponents.js';
import IgcCircularGradientComponent from '../../progress/circular-gradient.js';
import IgcDateTimeInputComponent from '../../date-time-input/date-time-input.js';
Expand Down Expand Up @@ -86,6 +89,9 @@ const allComponents: CustomElementConstructor[] = [
IgcToastComponent,
IgcSliderLabelComponent,
IgcRangeSliderComponent,
IgcTabsComponent,
IgcTabComponent,
IgcTabPanelComponent,
IgcCircularProgressComponent,
IgcLinearProgressComponent,
IgcCircularGradientComponent,
Expand Down
36 changes: 36 additions & 0 deletions src/components/common/util.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,39 @@ export const asPercent = (part: number, whole: number) => (part / whole) * 100;

export const clamp = (number: number, min: number, max: number) =>
Math.max(min, Math.min(number, max));

/**
*
* Returns an element's offset relative to its parent. Similar to element.offsetTop and element.offsetLeft, except the
* parent doesn't have to be positioned relative or absolute.
*
* Work around for the following issues in Chromium based browsers:
*
* https://bugs.chromium.org/p/chromium/issues/detail?id=1330819
* https://bugs.chromium.org/p/chromium/issues/detail?id=1334556
*
*/
export function getOffset(element: HTMLElement, parent: HTMLElement) {
const { top, left, bottom, right } = element.getBoundingClientRect();
const {
top: pTop,
left: pLeft,
bottom: pBottom,
right: pRight,
} = parent.getBoundingClientRect();

return {
top: Math.round(top - pTop),
left: Math.round(left - pLeft),
right: Math.round(right - pRight),
bottom: Math.round(bottom - pBottom),
};
}

export function createCounter(start = 0) {
let i = start;
return function () {
i++;
return i;
};
}
38 changes: 38 additions & 0 deletions src/components/tabs/tab-panel.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import { html, LitElement } from 'lit';
import { createCounter } from '../common/util.js';
import { styles } from './themes/light/tab-panel.base.css.js';

/**
* Represents the content of a tab
*
* @element igc-tab-panel
*
* @slot - Renders the content.
*/
export default class IgcTabPanelComponent extends LitElement {
public static readonly tagName = 'igc-tab-panel';

public static override styles = styles;

private static readonly increment = createCounter();

public override connectedCallback() {
this.setAttribute('role', 'tabpanel');
this.tabIndex = this.hasAttribute('tabindex') ? this.tabIndex : 0;
this.slot = this.slot.length > 0 ? this.slot : 'panel';
this.id =
this.id.length > 0
? this.id
: `igc-tab-panel-${IgcTabPanelComponent.increment()}`;
}

protected override render() {
return html`<slot></slot>`;
}
}

declare global {
interface HTMLElementTagNameMap {
'igc-tab-panel': IgcTabPanelComponent;
}
}
85 changes: 85 additions & 0 deletions src/components/tabs/tab.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
import { html, LitElement } from 'lit';
import { property, query } from 'lit/decorators.js';
import { themes } from '../../theming/theming-decorator.js';
import { createCounter } from '../common/util.js';
import { styles } from './themes/light/tab.base.css.js';
import { styles as bootstrap } from './themes/light/tab.bootstrap.css.js';
import { styles as fluent } from './themes/light/tab.fluent.css.js';
import { styles as indigo } from './themes/light/tab.indigo.css.js';

/**
* Represents the tab header.
*
* @element igc-tab
*
* @slot prefix - Renders before the tab header content.
* @slot - Renders the tab header content.
* @slot suffix - Renders after the tab header content.
*
* @csspart content - The content wrapper.
* @csspart prefix - The prefix wrapper.
* @csspart suffix - The suffix wrapper.
*/
@themes({ bootstrap, fluent, indigo })
export default class IgcTabComponent extends LitElement {
public static readonly tagName = 'igc-tab';

public static override styles = styles;

private static readonly increment = createCounter();

@query('[part="base"]', true)
private tab!: HTMLElement;

/** The id of the tab panel which will be controlled by the tab. */
@property({ type: String })
public panel = '';

/** Determines whether the tab is selected. */
@property({ type: Boolean, reflect: true })
public selected = false;

/** Determines whether the tab is disabled. */
@property({ type: Boolean, reflect: true })
public disabled = false;

public override connectedCallback(): void {
super.connectedCallback();
this.id =
this.id.length > 0 ? this.id : `igc-tab-${IgcTabComponent.increment()}`;
}

/** Sets focus to the tab. */
public override focus(options?: FocusOptions) {
this.tab.focus(options);
}

/** Removes focus from the tab. */
public override blur() {
this.tab.blur();
}

protected override render() {
return html`
<div
part="base"
role="tab"
aria-disabled=${this.disabled ? 'true' : 'false'}
aria-selected=${this.selected ? 'true' : 'false'}
tabindex=${this.disabled || !this.selected ? -1 : 0}
>
<slot name="prefix" part="prefix"></slot>
<div part="content">
<slot></slot>
</div>
<slot name="suffix" part="suffix"></slot>
</div>
`;
}
}

declare global {
interface HTMLElementTagNameMap {
'igc-tab': IgcTabComponent;
}
}
Loading

0 comments on commit 6fa846c

Please sign in to comment.