Skip to content

Commit

Permalink
feat(tabs): add actions section
Browse files Browse the repository at this point in the history
  • Loading branch information
dtsanevmw committed Nov 19, 2024
1 parent bed30e6 commit d1acb23
Show file tree
Hide file tree
Showing 13 changed files with 410 additions and 77 deletions.
89 changes: 89 additions & 0 deletions .storybook/stories/tabs/tabs-actions.stories.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
/*
* Copyright (c) 2016-2024 Broadcom. All Rights Reserved.
* The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries.
* This software is released under MIT license.
* The full license information can be found in LICENSE in the root directory of this project.
*/

import { ClrTabs, ClrTabsModule } from '@clr/angular';
import { moduleMetadata, StoryFn, StoryObj } from '@storybook/angular';

import { TabsLayout } from '../../../projects/angular/src/layout/tabs/enums/tabs-layout.enum';

export default {
title: 'Tabs/Tabs Actions',
decorators: [
moduleMetadata({
imports: [ClrTabsModule],
}),
],
component: ClrTabs,
argTypes: {
// inputs
clrLayout: { control: 'inline-radio', options: TabsLayout },
// methods
closeOnEscapeKey: { control: { disable: true }, table: { disable: true } },
closeOnFocusOut: { control: { disable: true }, table: { disable: true } },
closeOnOutsideClick: { control: { disable: true }, table: { disable: true } },
openOverflowOnFocus: { control: { disable: true }, table: { disable: true } },
resetKeyFocusCurrentToActive: { control: { disable: true }, table: { disable: true } },
toggleOverflowOnClick: { control: { disable: true }, table: { disable: true } },
toggleOverflowOnPosition: { control: { disable: true }, table: { disable: true } },
// story helpers
createArray: { control: { disable: true }, table: { disable: true } },
clickTabAction: { control: { disable: true }, table: { disable: true } },
tabCount: { control: { type: 'number', min: 1, max: 100 } },
activeTab: { control: { type: 'number', min: 1, max: 100 } },
},
args: {
// inputs
clrLayout: TabsLayout.HORIZONTAL,
// story helpers
createArray: n => new Array(n),
clickTabAction: () => alert('Tab action clicked!'),
tabCount: 4,
activeTab: 1,
title: 'Tab',
content: 'Tab Content',
},
};

const tabsTemplate: StoryFn = args => ({
template: `
<clr-tabs [clrLayout]="clrLayout">
<clr-tabs-actions position="right">
<button class="btn btn-icon btn-link" (click)="clickTabAction()" clrTabAction>
<cds-icon shape="plus"></cds-icon>
Tab Action
</button>
</clr-tabs-actions>
<clr-tab *ngFor="let _ of createArray(tabCount); let i = index">
<button clrTabLink>{{ title }} {{ i + 1 }}</button>
<clr-tab-content *clrIfActive="activeTab === i + 1">
<p>{{ content }} {{ i + 1 }}</p>
</clr-tab-content>
</clr-tab>
</clr-tabs>
`,
props: { ...args },
});

export const Tabs: StoryObj = {
render: tabsTemplate,
};

export const VerticalTabs: StoryObj = {
render: tabsTemplate,
args: {
clrLayout: TabsLayout.VERTICAL,
},
};

export const TabsResponsive: StoryObj = {
render: tabsTemplate,
parameters: {
viewport: {
defaultViewport: 'large',
},
},
};
51 changes: 39 additions & 12 deletions projects/angular/clarity.api.md
Original file line number Diff line number Diff line change
Expand Up @@ -99,17 +99,17 @@ export class ClarityModule {
// Warning: (ae-forgotten-export) The symbol "i8_6" needs to be exported by the entry point index.d.ts
// Warning: (ae-forgotten-export) The symbol "i9_2" needs to be exported by the entry point index.d.ts
// Warning: (ae-forgotten-export) The symbol "i10_4" needs to be exported by the entry point index.d.ts
// Warning: (ae-forgotten-export) The symbol "i11_4" needs to be exported by the entry point index.d.ts
// Warning: (ae-forgotten-export) The symbol "i11_3" needs to be exported by the entry point index.d.ts
// Warning: (ae-forgotten-export) The symbol "i12_3" needs to be exported by the entry point index.d.ts
// Warning: (ae-forgotten-export) The symbol "i13_3" needs to be exported by the entry point index.d.ts
// Warning: (ae-forgotten-export) The symbol "i13_4" needs to be exported by the entry point index.d.ts
// Warning: (ae-forgotten-export) The symbol "i14_2" needs to be exported by the entry point index.d.ts
// Warning: (ae-forgotten-export) The symbol "i15" needs to be exported by the entry point index.d.ts
// Warning: (ae-forgotten-export) The symbol "i16_2" needs to be exported by the entry point index.d.ts
// Warning: (ae-forgotten-export) The symbol "i17_2" needs to be exported by the entry point index.d.ts
// Warning: (ae-forgotten-export) The symbol "i18_2" needs to be exported by the entry point index.d.ts
//
// (undocumented)
static ɵmod: i0.ɵɵNgModuleDeclaration<ClarityModule, never, never, [typeof i1.ClrEmphasisModule, typeof i2_4.ClrDataModule, typeof i3_2.ClrIconModule, typeof i4_12.ClrModalModule, typeof i5_7.ClrLoadingModule, typeof i6_2.ClrConditionalModule, typeof i7_6.ClrFocusOnViewInitModule, typeof i8_6.ClrButtonModule, typeof i9_2.ClrFormsModule, typeof i10_4.ClrLayoutModule, typeof i11_4.ClrPopoverModule, typeof i12_3.ClrWizardModule, typeof i13_3.ClrSidePanelModule, typeof i14_2.ClrStepperModule, typeof i15.ClrSpinnerModule, typeof i16_2.ClrProgressBarModule, typeof i17_2.ClrPopoverModuleNext, typeof i18_2.ClrTimelineModule]>;
static ɵmod: i0.ɵɵNgModuleDeclaration<ClarityModule, never, never, [typeof i1.ClrEmphasisModule, typeof i2_4.ClrDataModule, typeof i3_2.ClrIconModule, typeof i4_12.ClrModalModule, typeof i5_7.ClrLoadingModule, typeof i6_2.ClrConditionalModule, typeof i7_6.ClrFocusOnViewInitModule, typeof i8_6.ClrButtonModule, typeof i9_2.ClrFormsModule, typeof i10_4.ClrLayoutModule, typeof i11_3.ClrPopoverModule, typeof i12_3.ClrWizardModule, typeof i13_4.ClrSidePanelModule, typeof i14_2.ClrStepperModule, typeof i15.ClrSpinnerModule, typeof i16_2.ClrProgressBarModule, typeof i17_2.ClrPopoverModuleNext, typeof i18_2.ClrTimelineModule]>;
}

// @public (undocumented)
Expand Down Expand Up @@ -3905,10 +3905,10 @@ export class ClrStepperModule {
// Warning: (ae-forgotten-export) The symbol "i3_27" needs to be exported by the entry point index.d.ts
// Warning: (ae-forgotten-export) The symbol "i4_18" needs to be exported by the entry point index.d.ts
// Warning: (ae-forgotten-export) The symbol "i5_14" needs to be exported by the entry point index.d.ts
// Warning: (ae-forgotten-export) The symbol "i8_8" needs to be exported by the entry point index.d.ts
// Warning: (ae-forgotten-export) The symbol "i8_9" needs to be exported by the entry point index.d.ts
//
// (undocumented)
static ɵmod: i0.ɵɵNgModuleDeclaration<ClrStepperModule, [typeof i1_48.ClrStepper, typeof i2_35.ClrStepButton, typeof i3_27.ClrStepperPanel, typeof i4_18.StepperOompaLoompa, typeof i5_14.StepperWillyWonka], [typeof i6.CommonModule, typeof i3_2.ClrIconModule, typeof i8_8.ClrAccordionModule], [typeof i1_48.ClrStepper, typeof i2_35.ClrStepButton, typeof i3_27.ClrStepperPanel, typeof i4_18.StepperOompaLoompa, typeof i5_14.StepperWillyWonka, typeof i8_8.ClrAccordionModule]>;
static ɵmod: i0.ɵɵNgModuleDeclaration<ClrStepperModule, [typeof i1_48.ClrStepper, typeof i2_35.ClrStepButton, typeof i3_27.ClrStepperPanel, typeof i4_18.StepperOompaLoompa, typeof i5_14.StepperWillyWonka], [typeof i6.CommonModule, typeof i3_2.ClrIconModule, typeof i8_9.ClrAccordionModule], [typeof i1_48.ClrStepper, typeof i2_35.ClrStepButton, typeof i3_27.ClrStepperPanel, typeof i4_18.StepperOompaLoompa, typeof i5_14.StepperWillyWonka, typeof i8_9.ClrAccordionModule]>;
}

// @public (undocumented)
Expand Down Expand Up @@ -3974,6 +3974,14 @@ export class ClrTab {
static ɵfac: i0.ɵɵFactoryDeclaration<ClrTab, never>;
}

// @public (undocumented)
export class ClrTabAction {
// (undocumented)
static ɵdir: i0.ɵɵDirectiveDeclaration<ClrTabAction, "[clrTabAction]", never, {}, {}, never, never, false, never>;
// (undocumented)
static ɵfac: i0.ɵɵFactoryDeclaration<ClrTabAction, never>;
}

// @public (undocumented)
export class ClrTabContent implements OnDestroy {
constructor(ifActiveService: IfActiveService, id: number, tabsService: TabsService);
Expand Down Expand Up @@ -4086,6 +4094,8 @@ export class ClrTabs implements AfterContentInit, OnDestroy {
// (undocumented)
set tabOverflowEl(value: ElementRef<HTMLElement>);
// (undocumented)
tabsActions: QueryList<ElementRef>;
// (undocumented)
tabsId: number;
// (undocumented)
tabsService: TabsService;
Expand All @@ -4096,11 +4106,26 @@ export class ClrTabs implements AfterContentInit, OnDestroy {
// (undocumented)
toggleService: ClrPopoverToggleService;
// (undocumented)
static ɵcmp: i0.ɵɵComponentDeclaration<ClrTabs, "clr-tabs", never, { "layout": "clrLayout"; }, {}, ["tabs"], never, false, [{ directive: typeof i1_6.ClrPopoverHostDirective; inputs: {}; outputs: {}; }]>;
static ɵcmp: i0.ɵɵComponentDeclaration<ClrTabs, "clr-tabs", never, { "layout": "clrLayout"; }, {}, ["tabsActions", "tabs"], ["clr-tabs-actions"], false, [{ directive: typeof i1_6.ClrPopoverHostDirective; inputs: {}; outputs: {}; }]>;
// (undocumented)
static ɵfac: i0.ɵɵFactoryDeclaration<ClrTabs, never>;
}

// @public (undocumented)
export class ClrTabsActions {
// (undocumented)
actions: QueryList<ElementRef>;
// (undocumented)
position: ClrTabsActionsPosition;
// (undocumented)
static ɵcmp: i0.ɵɵComponentDeclaration<ClrTabsActions, "clr-tabs-actions", never, { "position": "position"; }, {}, ["actions"], ["*"], false, never>;
// (undocumented)
static ɵfac: i0.ɵɵFactoryDeclaration<ClrTabsActions, never>;
}

// @public (undocumented)
export type ClrTabsActionsPosition = 'left' | 'right';

// @public (undocumented)
export class ClrTabsModule {
constructor();
Expand All @@ -4115,10 +4140,12 @@ export class ClrTabsModule {
// Warning: (ae-forgotten-export) The symbol "i5_11" needs to be exported by the entry point index.d.ts
// Warning: (ae-forgotten-export) The symbol "i6_8" needs to be exported by the entry point index.d.ts
// Warning: (ae-forgotten-export) The symbol "i7_7" needs to be exported by the entry point index.d.ts
// Warning: (ae-forgotten-export) The symbol "i11_3" needs to be exported by the entry point index.d.ts
// Warning: (ae-forgotten-export) The symbol "i8_7" needs to be exported by the entry point index.d.ts
// Warning: (ae-forgotten-export) The symbol "i9_6" needs to be exported by the entry point index.d.ts
// Warning: (ae-forgotten-export) The symbol "i13_3" needs to be exported by the entry point index.d.ts
//
// (undocumented)
static ɵmod: i0.ɵɵNgModuleDeclaration<ClrTabsModule, [typeof i1_41.ClrTabContent, typeof i2_29.ClrTab, typeof i3_21.ClrTabs, typeof i4_14.ClrTabOverflowContent, typeof i5_11.ClrTabLink, typeof i6_8.TabsWillyWonka, typeof i7_7.ActiveOompaLoompa], [typeof i6.CommonModule, typeof i6_2.ClrConditionalModule, typeof i3_2.ClrIconModule, typeof i11_3.ClrTemplateRefModule, typeof i49.ClrKeyFocusModule], [typeof i1_41.ClrTabContent, typeof i2_29.ClrTab, typeof i3_21.ClrTabs, typeof i4_14.ClrTabOverflowContent, typeof i5_11.ClrTabLink, typeof i6_8.TabsWillyWonka, typeof i7_7.ActiveOompaLoompa, typeof i6_2.ClrConditionalModule]>;
static ɵmod: i0.ɵɵNgModuleDeclaration<ClrTabsModule, [typeof i1_41.ClrTabContent, typeof i2_29.ClrTab, typeof i3_21.ClrTabs, typeof i4_14.ClrTabOverflowContent, typeof i5_11.ClrTabLink, typeof i6_8.ClrTabAction, typeof i7_7.ClrTabsActions, typeof i8_7.TabsWillyWonka, typeof i9_6.ActiveOompaLoompa], [typeof i6.CommonModule, typeof i6_2.ClrConditionalModule, typeof i3_2.ClrIconModule, typeof i13_3.ClrTemplateRefModule, typeof i49.ClrKeyFocusModule], [typeof i1_41.ClrTabContent, typeof i2_29.ClrTab, typeof i3_21.ClrTabs, typeof i4_14.ClrTabOverflowContent, typeof i5_11.ClrTabLink, typeof i6_8.ClrTabAction, typeof i7_7.ClrTabsActions, typeof i8_7.TabsWillyWonka, typeof i9_6.ActiveOompaLoompa, typeof i6_2.ClrConditionalModule]>;
}

// @public (undocumented)
Expand Down Expand Up @@ -4707,13 +4734,13 @@ export class ClrWizardModule {
// Warning: (ae-forgotten-export) The symbol "i5_13" needs to be exported by the entry point index.d.ts
// Warning: (ae-forgotten-export) The symbol "i6_9" needs to be exported by the entry point index.d.ts
// Warning: (ae-forgotten-export) The symbol "i7_8" needs to be exported by the entry point index.d.ts
// Warning: (ae-forgotten-export) The symbol "i8_7" needs to be exported by the entry point index.d.ts
// Warning: (ae-forgotten-export) The symbol "i9_6" needs to be exported by the entry point index.d.ts
// Warning: (ae-forgotten-export) The symbol "i8_8" needs to be exported by the entry point index.d.ts
// Warning: (ae-forgotten-export) The symbol "i9_7" needs to be exported by the entry point index.d.ts
// Warning: (ae-forgotten-export) The symbol "i10_5" needs to be exported by the entry point index.d.ts
// Warning: (ae-forgotten-export) The symbol "i11_5" needs to be exported by the entry point index.d.ts
// Warning: (ae-forgotten-export) The symbol "i11_4" needs to be exported by the entry point index.d.ts
//
// (undocumented)
static ɵmod: i0.ɵɵNgModuleDeclaration<ClrWizardModule, [typeof i1_46.ClrWizard, typeof i2_34.ClrWizardPage, typeof i3_26.ClrWizardStepnav, typeof i4_17.ClrWizardStepnavItem, typeof i5_13.ClrWizardButton, typeof i6_9.ClrWizardHeaderAction, typeof i7_8.ClrWizardTitle, typeof i8_7.ClrWizardPageTitle, typeof i9_6.ClrWizardPageNavTitle, typeof i10_5.ClrWizardPageButtons, typeof i11_5.ClrWizardPageHeaderActions], [typeof i6.CommonModule, typeof i4_12.ClrModalModule, typeof i1_2.ClrAlertModule], [typeof i1_46.ClrWizard, typeof i2_34.ClrWizardPage, typeof i3_26.ClrWizardStepnav, typeof i4_17.ClrWizardStepnavItem, typeof i5_13.ClrWizardButton, typeof i6_9.ClrWizardHeaderAction, typeof i7_8.ClrWizardTitle, typeof i8_7.ClrWizardPageTitle, typeof i9_6.ClrWizardPageNavTitle, typeof i10_5.ClrWizardPageButtons, typeof i11_5.ClrWizardPageHeaderActions]>;
static ɵmod: i0.ɵɵNgModuleDeclaration<ClrWizardModule, [typeof i1_46.ClrWizard, typeof i2_34.ClrWizardPage, typeof i3_26.ClrWizardStepnav, typeof i4_17.ClrWizardStepnavItem, typeof i5_13.ClrWizardButton, typeof i6_9.ClrWizardHeaderAction, typeof i7_8.ClrWizardTitle, typeof i8_8.ClrWizardPageTitle, typeof i9_7.ClrWizardPageNavTitle, typeof i10_5.ClrWizardPageButtons, typeof i11_4.ClrWizardPageHeaderActions], [typeof i6.CommonModule, typeof i4_12.ClrModalModule, typeof i1_2.ClrAlertModule], [typeof i1_46.ClrWizard, typeof i2_34.ClrWizardPage, typeof i3_26.ClrWizardStepnav, typeof i4_17.ClrWizardStepnavItem, typeof i5_13.ClrWizardButton, typeof i6_9.ClrWizardHeaderAction, typeof i7_8.ClrWizardTitle, typeof i8_8.ClrWizardPageTitle, typeof i9_7.ClrWizardPageNavTitle, typeof i10_5.ClrWizardPageButtons, typeof i11_4.ClrWizardPageHeaderActions]>;
}

// @public
Expand Down
128 changes: 70 additions & 58 deletions projects/angular/src/layout/tabs/_tabs.clarity.scss
Original file line number Diff line number Diff line change
Expand Up @@ -36,77 +36,89 @@
[data-hidden='true'] {
display: none;
}
}

button.nav-link {
border-radius: 0;
text-transform: capitalize;
min-width: 0;
}
button.nav-link {
border-radius: 0;
text-transform: capitalize;
min-width: 0;
}

.tabs-overflow {
position: relative;
.tabs-overflow {
position: relative;

.dropdown-menu {
padding: tokens.$cds-global-space-0;
box-shadow: tokens.$cds-alias-object-shadow-100;
overflow: hidden;
}
.dropdown-menu {
padding: tokens.$cds-global-space-0;
box-shadow: tokens.$cds-alias-object-shadow-100;
overflow: hidden;
}

.btn {
line-height: mixins.baselinePx(20);
font-size: tokens.$cds-alias-typography-font-size-4;
padding: tokens.$cds-global-space-5 tokens.$cds-global-space-6;
border-radius: tokens.$cds-global-space-0;
.btn {
line-height: mixins.baselinePx(20);
font-size: tokens.$cds-alias-typography-font-size-4;
padding: tokens.$cds-global-space-5 tokens.$cds-global-space-6;
border-radius: tokens.$cds-global-space-0;
}
}
}

.tab-content {
display: inline;
}

@include mixins.fixForIE11AndUp {
.tab-content {
display: inline-block;
width: 100%;
display: inline;
}
}

.tabs-vertical {
display: flex;

// Must be direct child, so horizontal tabs can be nested in vertical tabs
& > .nav {
height: auto;
box-shadow: none;
flex-direction: column;
align-items: stretch;
margin-right: tokens.$cds-global-space-9;
overflow: auto;
flex-shrink: 0;
padding: tokens.$cds-global-space-3;
width: mixins.baselinePx(240);
min-width: tokens.$cds-global-space-12;

gap: tokens.$cds-global-space-5;

.nav-link {
text-align: left;
padding: 0 tokens.$cds-global-space-6;
border: none;
flex-shrink: 0;
margin-top: 0;
margin-left: 0;
@include mixins.fixForIE11AndUp {
.tab-content {
display: inline-block;
width: 100%;
}
}

&.btn {
margin-bottom: tokens.$cds-global-space-1;
}
.tabs-vertical {
display: flex;

// Must be direct child, so horizontal tabs can be nested in vertical tabs
& > .nav {
height: auto;
box-shadow: none;
flex-direction: column;
align-items: stretch;
margin-right: tokens.$cds-global-space-9;
overflow: auto;
flex-shrink: 0;
padding: tokens.$cds-global-space-3;
width: mixins.baselinePx(240);
min-width: tokens.$cds-global-space-12;

gap: tokens.$cds-global-space-5;

.nav-link {
text-align: left;
padding: 0 tokens.$cds-global-space-6;
border: none;
flex-shrink: 0;
margin-top: 0;
margin-left: 0;
width: 100%;

&.btn {
margin-bottom: tokens.$cds-global-space-1;
}

&.active,
&:hover {
@include nav-link-border-appearence('left');
&.active,
&:hover {
@include nav-link-border-appearence('left');
}
}
}
}

.tabs-actions {
display: inline-flex;
width: 100%;

&[position~='left'] {
justify-content: start;
}
&[position~='right'] {
justify-content: end;
}
}
}
2 changes: 2 additions & 0 deletions projects/angular/src/layout/tabs/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,12 @@
*/

export * from './tabs';
export * from './tabs-actions';
export * from './tab';
export * from './tab-content';
export * from './tab-overflow-content';
export * from './tab-link.directive';
export * from './tab-action.directive';
export * from './tabs.module';

export { TabsWillyWonka as ÇlrTabsWillyWonka } from './chocolate/tabs-willy-wonka';
Expand Down
16 changes: 16 additions & 0 deletions projects/angular/src/layout/tabs/tab-action.directive.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
/*
* Copyright (c) 2016-2024 Broadcom. All Rights Reserved.
* The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries.
* This software is released under MIT license.
* The full license information can be found in LICENSE in the root directory of this project.
*/

import { Directive } from '@angular/core';

@Directive({
selector: '[clrTabAction]',
host: {
tabindex: '0',
},
})
export class ClrTabAction {}
Loading

0 comments on commit d1acb23

Please sign in to comment.