Skip to content

Commit b9ce4e9

Browse files
committed
feat: Allow users to project interactive content
Signed-off-by: Akshat Patel <[email protected]>
1 parent dfcc603 commit b9ce4e9

File tree

6 files changed

+120
-34
lines changed

6 files changed

+120
-34
lines changed
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
import { Directive, HostBinding } from "@angular/core";
2+
3+
@Directive({
4+
selector: "[cdsAboveFold], [ibmAboveFold]"
5+
})
6+
export class ExpandableTileAboveFoldDirective {
7+
@HostBinding("class.cds--tile-content__above-the-fold") aboveFold = true;
8+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
import { Directive, HostBinding } from "@angular/core";
2+
3+
@Directive({
4+
selector: "[cdsBelowFold], [ibmBelowFold]"
5+
})
6+
export class ExpandableTileBelowFoldDirective {
7+
@HostBinding("class.cds--tile-content__below-the-fold") belowFold = true;
8+
}

src/tiles/expandable-tile.component.ts

Lines changed: 62 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,10 @@ import {
22
Component,
33
Input,
44
ElementRef,
5-
AfterContentInit
5+
AfterViewInit,
6+
ViewChild
67
} from "@angular/core";
7-
import { I18n, Overridable } from "carbon-components-angular/i18n";
8+
import { I18n } from "carbon-components-angular/i18n";
89
import { merge } from "carbon-components-angular/utils";
910

1011
export interface ExpandableTileTranslations {
@@ -16,39 +17,75 @@ export interface ExpandableTileTranslations {
1617
selector: "cds-expandable-tile, ibm-expandable-tile",
1718
template: `
1819
<button
20+
*ngIf="!interactive"
1921
class="cds--tile cds--tile--expandable"
2022
[ngClass]="{
2123
'cds--tile--is-expanded' : expanded,
2224
'cds--tile--light': theme === 'light'
2325
}"
2426
[ngStyle]="{'max-height': expandedHeight + 'px'}"
2527
type="button"
26-
(click)="onClick()">
27-
<div class="cds--tile__chevron">
28-
<svg *ngIf="!expanded" width="12" height="7" viewBox="0 0 12 7" [attr.title]="expand.subject | async" role="img">
29-
<title>{{expand.subject | async}}</title>
30-
<path fill-rule="nonzero" d="M6.002 5.55L11.27 0l.726.685L6.003 7 0 .685.726 0z"/>
31-
</svg>
32-
<svg *ngIf="expanded" width="12" height="7" viewBox="0 0 12 7" [attr.title]="collapse.subject | async" role="img">
33-
<title>{{collapse.subject | async}}</title>
34-
<path fill-rule="nonzero" d="M6.002 5.55L11.27 0l.726.685L6.003 7 0 .685.726 0z"/>
35-
</svg>
36-
</div>
37-
<div class="cds--tile-content">
38-
<ng-content select=".cds--tile-content__above-the-fold"></ng-content>
39-
<ng-content select=".cds--tile-content__below-the-fold"></ng-content>
40-
</div>
28+
(click)="onClick()"
29+
[attr.aria-expanded]="expanded"
30+
[attr.title]="(expanded ? collapse.subject : expand.subject) | async">
31+
<ng-container *ngTemplateOutlet="expandableTileContent"></ng-container>
4132
</button>
33+
34+
<div
35+
*ngIf="interactive"
36+
class="cds--tile cds--tile--expandable cds--tile--expandable--interactive"
37+
[ngClass]="{
38+
'cds--tile--is-expanded' : expanded,
39+
'cds--tile--light': theme === 'light'
40+
}"
41+
[ngStyle]="{'max-height': expandedHeight + 'px'}"
42+
[attr.title]="(expanded ? collapse.subject : expand.subject) | async">
43+
<ng-container *ngTemplateOutlet="expandableTileContent"></ng-container>
44+
</div>
45+
46+
<ng-template #chevronIcon>
47+
<svg cdsIcon="chevron--down" size="16"></svg>
48+
</ng-template>
49+
50+
<ng-template #expandableTileContent>
51+
<div #container>
52+
<div class="cds--tile-content">
53+
<ng-content select="[cdsAboveFold],[ibmAboveFold],.cds--tile-content__above-the-fold"></ng-content>
54+
</div>
55+
<div *ngIf="!interactive" class="cds--tile__chevron">
56+
<ng-container *ngTemplateOutlet="chevronIcon"></ng-container>
57+
</div>
58+
<button
59+
*ngIf="interactive"
60+
class="cds--tile__chevron cds--tile__chevron--interactive"
61+
type="button"
62+
(click)="onClick()"
63+
[attr.aria-expanded]="expanded"
64+
[attr.aria-label]="(expanded ? collapse.subject : expand.subject) | async">
65+
<ng-container *ngTemplateOutlet="chevronIcon"></ng-container>
66+
</button>
67+
<div class="cds--tile-content">
68+
<ng-content select="[cdsBelowFold],[ibmBelowFold],.cds--tile-content__below-the-fold"></ng-content>
69+
</div>
70+
</div>
71+
</ng-template>
4272
`
4373
})
44-
export class ExpandableTile implements AfterContentInit {
74+
export class ExpandableTile implements AfterViewInit {
4575
/**
4676
* @deprecated since v5 - Use `cdsLayer` directive instead
4777
* Set to `"light"` to apply the light style
4878
*/
4979
@Input() theme: "light" | "dark" = "dark";
5080

81+
/**
82+
* Set to `true` to expand by default
83+
*/
5184
@Input() expanded = false;
85+
/**
86+
* Set to `true` to toggle interactive
87+
*/
88+
@Input() interactive = false;
5289
/**
5390
* Expects an object that contains some or all of:
5491
* ```
@@ -65,21 +102,22 @@ export class ExpandableTile implements AfterContentInit {
65102
this.collapse.override(valueWithDefaults.COLLAPSE);
66103
}
67104

105+
@ViewChild("container") tileContainer: ElementRef;
106+
68107
tileMaxHeight = 0;
69108
currentExpandedHeight = 0;
70-
element = this.elementRef.nativeElement;
71109

72110
expand = this.i18n.getOverridable("TILES.EXPAND");
73111
collapse = this.i18n.getOverridable("TILES.COLLAPSE");
74112

75-
constructor(protected i18n: I18n, protected elementRef: ElementRef) {}
113+
constructor(protected i18n: I18n, protected element: ElementRef) {}
76114

77-
ngAfterContentInit() {
115+
ngAfterViewInit() {
78116
this.updateMaxHeight();
79117
}
80118

81119
get expandedHeight() {
82-
const tile = this.element.querySelector(".cds--tile");
120+
const tile = this.element.nativeElement.querySelector(".cds--tile");
83121
const tilePadding
84122
= parseInt(getComputedStyle(tile).paddingBottom, 10) + parseInt(getComputedStyle(tile).paddingTop, 10);
85123
const expandedHeight = this.tileMaxHeight + tilePadding;
@@ -91,9 +129,9 @@ export class ExpandableTile implements AfterContentInit {
91129

92130
updateMaxHeight() {
93131
if (this.expanded) {
94-
this.tileMaxHeight = this.element.querySelector(".cds--tile-content").getBoundingClientRect().height;
132+
this.tileMaxHeight = this.tileContainer.nativeElement.getBoundingClientRect().height;
95133
} else {
96-
this.tileMaxHeight = this.element.querySelector(".cds--tile-content__above-the-fold").getBoundingClientRect().height;
134+
this.tileMaxHeight = this.element.nativeElement.querySelector(".cds--tile-content__above-the-fold").getBoundingClientRect().height;
97135
}
98136
}
99137

src/tiles/expandable-tile.stories.ts

Lines changed: 32 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,19 @@
11
/* tslint:disable variable-name */
22

3-
import { moduleMetadata, Meta, Story } from "@storybook/angular";
3+
import { moduleMetadata, Meta, Story } from "@storybook/angular";
44
import { LayerModule } from "../layer";
5+
import { ButtonModule } from "../button";
56
import { TilesModule, ExpandableTile } from "./";
67

78
export default {
89
title: "Components/Tiles/Expandable",
910
decorators: [
1011
moduleMetadata({
11-
imports: [TilesModule, LayerModule]
12+
imports: [
13+
ButtonModule,
14+
LayerModule,
15+
TilesModule
16+
]
1217
})
1318
],
1419
component: ExpandableTile
@@ -18,39 +23,56 @@ const Template: Story<ExpandableTile> = (args) => ({
1823
props: args,
1924
template: `
2025
<cds-expandable-tile>
21-
<span class="cds--tile-content__above-the-fold" style="height: 200px">Above the fold content here</span>
22-
<span class="cds--tile-content__below-the-fold" style="height: 400px">Below the fold content here</span>
26+
<span cdsAboveFold style="height: 200px">Above the fold content here</span>
27+
<span cdsBelowFold style="height: 400px">Below the fold content here</span>
2328
</cds-expandable-tile>
2429
`
2530
});
2631
export const Basic = Template.bind({});
2732

33+
const InteractiveTemplate: Story<ExpandableTile> = (args) => ({
34+
props: args,
35+
template: `
36+
<cds-expandable-tile [interactive]="true">
37+
<span cdsAboveFold style="height: 200px">
38+
Above the fold content
39+
<button ibmButton>Click me!</button>
40+
</span>
41+
<span cdsBelowFold style="height: 400px">
42+
Below the fold content here
43+
<button ibmButton>No me!</button>
44+
</span>
45+
</cds-expandable-tile>
46+
`
47+
});
48+
export const Interactive = InteractiveTemplate.bind({});
49+
2850
const LayerTemplate: Story<ExpandableTile> = (args) => ({
2951
props: args,
3052
template: `
3153
<cds-expandable-tile>
32-
<span class="cds--tile-content__above-the-fold" style="height: 200px">
54+
<span cdsAboveFold style="height: 200px">
3355
First Layer, above the fold content here
3456
</span>
35-
<span class="cds--tile-content__below-the-fold" style="height: 400px">
57+
<span cdsBelowFold style="height: 400px">
3658
First Layer, below the fold content here
3759
</span>
3860
</cds-expandable-tile>
3961
<div cdsLayer>
4062
<cds-expandable-tile>
41-
<span class="cds--tile-content__above-the-fold" style="height: 200px">
63+
<span cdsAboveFold style="height: 200px">
4264
Second layer, above the fold content here
4365
</span>
44-
<span class="cds--tile-content__below-the-fold" style="height: 400px">
66+
<span cdsBelowFold style="height: 400px">
4567
Second layer, below the fold content here
4668
</span>
4769
</cds-expandable-tile>
4870
<div cdsLayer>
4971
<cds-expandable-tile>
50-
<span class="cds--tile-content__above-the-fold" style="height: 200px">
72+
<span cdsAboveFold style="height: 200px">
5173
Third layer, above the fold content here
5274
</span>
53-
<span class="cds--tile-content__below-the-fold" style="height: 400px">
75+
<span cdsBelowFold style="height: 400px">
5476
Third layer, below the fold content here
5577
</span>
5678
</cds-expandable-tile>

src/tiles/index.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
export * from "./clickable-tile.component";
22
export * from "./expandable-tile.component";
3+
export * from "./expandable-tile-above.directive";
4+
export * from "./expandable-tile-below.directive";
35
export * from "./selection-tile.component";
46
export * from "./tile-group.component";
57
export * from "./tile-selection.interface";

src/tiles/tiles.module.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,29 +4,37 @@ import { CommonModule } from "@angular/common";
44
import { Tile } from "./tile.component";
55
import { ClickableTile } from "./clickable-tile.component";
66
import { ExpandableTile } from "./expandable-tile.component";
7+
import { ExpandableTileAboveFoldDirective } from "./expandable-tile-above.directive";
8+
import { ExpandableTileBelowFoldDirective } from "./expandable-tile-below.directive";
79
import { SelectionTile } from "./selection-tile.component";
810
import { TileGroup } from "./tile-group.component";
911
import { I18nModule } from "carbon-components-angular/i18n";
12+
import { IconModule } from "carbon-components-angular/icon";
1013
import { LinkModule } from "carbon-components-angular/link";
1114

1215
@NgModule({
1316
declarations: [
1417
Tile,
1518
ClickableTile,
19+
ExpandableTileAboveFoldDirective,
20+
ExpandableTileBelowFoldDirective,
1621
ExpandableTile,
1722
SelectionTile,
1823
TileGroup
1924
],
2025
exports: [
2126
Tile,
2227
ClickableTile,
28+
ExpandableTileAboveFoldDirective,
29+
ExpandableTileBelowFoldDirective,
2330
ExpandableTile,
2431
SelectionTile,
2532
TileGroup
2633
],
2734
imports: [
2835
CommonModule,
2936
I18nModule,
37+
IconModule,
3038
LinkModule
3139
]
3240
})

0 commit comments

Comments
 (0)