Skip to content

Commit

Permalink
[HTML] Add support for icons in action buttons (#1511)
Browse files Browse the repository at this point in the history
* Replace ContainerStyle string enum with class + static fields

* Update default card

* Improve hover behavior for Image with selectAction

* Finalize support for width/height in Image and Column

* Add support for icons on action buttons

* Cleanup

* Fix handling of buttons without title
  • Loading branch information
dclaux authored May 25, 2018
1 parent 9925aaf commit 8e82b60
Show file tree
Hide file tree
Showing 11 changed files with 153 additions and 41 deletions.
1 change: 0 additions & 1 deletion source/nodejs/adaptivecards-visualizer/css/liveTile.css
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,6 @@ a.ac-anchor:visited:active {
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
height: 31px;
background-color: rgba(0, 0, 0, 0.1);
color: white;
border: 2px solid transparent;
Expand Down
10 changes: 8 additions & 2 deletions source/nodejs/adaptivecards-visualizer/css/outlook.css
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,6 @@ a.ac-anchor:visited:active {
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
height: 31px;
background-color: white;
color: #0078D7;
border: 1px solid #B2E0FF;
Expand Down Expand Up @@ -106,10 +105,17 @@ a.ac-anchor:visited:active {
font-size: 10px;
font-style: normal;
font-weight: 900;
margin: auto 0px auto 6px;
content: '\E70D';
}

.ac-pushButton.noIcon.expandable:after, .ac-pushButton.iconLeft.expandable:after {
margin: auto 0px auto 6px;
}

.ac-pushButton.iconAbove.expandable:after {
margin-top: 6px;
}

.ac-pushButton.expandable.expanded:after {
content: '\E70E';
}
Expand Down
16 changes: 10 additions & 6 deletions source/nodejs/adaptivecards-visualizer/css/skype.css
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,12 @@
}

.skypeContainer {
display: -webkit-box;
display: -ms-flexbox;
display: flex;
-ms-flex-align: start;
align-items: flex-start;
-webkit-box-align: start;
-ms-flex-align: start;
align-items: flex-start;
}

a.ac-anchor {
Expand Down Expand Up @@ -59,7 +61,6 @@ a.ac-anchor:visited:active {
font-size: 14px;
font-weight: 400;
padding: 4px 10px 6px 10px;
height: 31px;
background-color: white;
color: #0078d7;
}
Expand Down Expand Up @@ -107,7 +108,8 @@ a.ac-anchor:visited:active {
.hexagon {
overflow: hidden;
visibility: hidden;
transform: rotate(120deg);
-webkit-transform: rotate(120deg);
transform: rotate(120deg);
cursor: pointer;
width: 50px;
height: 40px;
Expand All @@ -118,7 +120,8 @@ a.ac-anchor:visited:active {
overflow: hidden;
width: 100%;
height: 100%;
transform: rotate(-60deg);
-webkit-transform: rotate(-60deg);
transform: rotate(-60deg);
}

.hexagon-in2 {
Expand All @@ -129,5 +132,6 @@ a.ac-anchor:visited:active {
background-image: url(../assets/bot-framework.png);
background-size: 50px 50px;
visibility: visible;
transform: rotate(-60deg);
-webkit-transform: rotate(-60deg);
transform: rotate(-60deg);
}
1 change: 0 additions & 1 deletion source/nodejs/adaptivecards-visualizer/css/teams.css
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,6 @@ a.ac-anchor:visited:active {
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
height: 31px;
background-color: white;
color: #5D60B3;
border: 2px solid #5D60B3;
Expand Down
1 change: 0 additions & 1 deletion source/nodejs/adaptivecards-visualizer/css/toast.css
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,6 @@ a.ac-anchor:visited:active {
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
height: 31px;
background-color: rgba(255, 255, 255, 0.2);
color: white;
border: 2px solid transparent;
Expand Down
1 change: 0 additions & 1 deletion source/nodejs/adaptivecards-visualizer/css/webchat.css
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,6 @@ a.ac-anchor:visited:active {
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
height: 31px;
border: none;
}

Expand Down
2 changes: 1 addition & 1 deletion source/nodejs/adaptivecards/scss/base.scss
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ $font-family: 'Segoe UI', sans-serif;
@mixin base-push-button(
$font-size: 14px,
$font-weight: 600,
$height: 31px,
$height: null,
$padding: 4px 10px 5px 10px,
$user-select: none,

Expand Down
112 changes: 84 additions & 28 deletions source/nodejs/adaptivecards/src/card-elements.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1120,7 +1120,7 @@ export class Image extends CardElement {
if (value) {
if (typeof value === "string") {
try {
let size = SizeAndUnit.parse(value);
let size = Utils.SizeAndUnit.parse(value);

if (size.unit == Enums.SizeUnit.Pixel) {
return size.physicalSize;
Expand Down Expand Up @@ -1276,6 +1276,7 @@ export class Image extends CardElement {
backgroundColor: string;
url: string;
size: Enums.Size = Enums.Size.Auto;
width: Utils.SizeAndUnit;
pixelWidth?: number = null;
pixelHeight?: number = null;
altText: string = "";
Expand Down Expand Up @@ -2110,19 +2111,17 @@ enum ActionButtonState {
}

class ActionButton {
private _action: Action;
private _element: HTMLButtonElement = null;
private _state: ActionButtonState = ActionButtonState.Normal;
private _text: string;

private updateCssStyle() {
let hostConfig = this.action.parent.hostConfig;

this.action.renderedElement.className = hostConfig.makeCssClassName("ac-pushButton");

if (this.action instanceof ShowCardAction) {
this.action.renderedElement.classList.add(hostConfig.makeCssClassName("expandable"));
}
this.action.renderedElement.classList.remove(hostConfig.makeCssClassName("expanded"));
this.action.renderedElement.classList.remove(hostConfig.makeCssClassName("subdued"));

switch (this._state) {
switch (this._state) {
case ActionButtonState.Expanded:
this.action.renderedElement.classList.add(hostConfig.makeCssClassName("expanded"));
break;
Expand Down Expand Up @@ -2151,16 +2150,6 @@ class ActionButton {
}
}

get text(): string {
return this._text;
}

set text(value: string) {
this._text = value;
this.action.renderedElement.innerText = this._text;
this.action.renderedElement.setAttribute("aria-label", this._text);
}

get state(): ActionButtonState {
return this._state;
}
Expand All @@ -2181,28 +2170,89 @@ export abstract class Action {
this._actionCollection = actionCollection;
}

protected addCssClasses(element: HTMLElement) {
// Do nothing in base implementation
}

abstract getJsonTypeName(): string;

id: string;
title: string;
iconUrl: string;

toJSON() {
let result = {};

Utils.setProperty(result, "type", this.getJsonTypeName());
Utils.setProperty(result, "id", this.id);
Utils.setProperty(result, "title", this.title);
Utils.setProperty(result, "iconUrl", this.iconUrl);

return result;
}

render() {
// Cache hostConfig for perf
let hostConfig = this.parent.hostConfig;

var buttonElement = document.createElement("button");
buttonElement.className = hostConfig.makeCssClassName("ac-pushButton");

this.addCssClasses(buttonElement);

buttonElement.setAttribute("aria-label", this.title);
buttonElement.type = "button";
buttonElement.style.display = "flex";
buttonElement.style.alignItems = "center";
buttonElement.style.justifyContent = "center";

let hasTitle = !Utils.isNullOrEmpty(this.title);

buttonElement.style.overflow = "hidden";
buttonElement.style.whiteSpace = "nowrap";
buttonElement.style.textOverflow = "ellipsis";
if (Utils.isNullOrEmpty(this.iconUrl)) {
buttonElement.classList.add("noIcon");
buttonElement.style.overflow = "hidden";
buttonElement.style.whiteSpace = "nowrap";
buttonElement.style.textOverflow = "ellipsis";

if (hasTitle) {
buttonElement.innerText = this.title;
}
}
else {
let iconElement = document.createElement("div");
iconElement.style.width = hostConfig.actions.iconSize + "px";
iconElement.style.height = hostConfig.actions.iconSize + "px";;
iconElement.style.backgroundImage = "url('" + this.iconUrl + "')";
iconElement.style.backgroundPositionX = "center";
iconElement.style.backgroundPositionY = "center";
iconElement.style.backgroundRepeat = "no-repeat";
iconElement.style.backgroundSize = "contain";

let titleElement = document.createElement("div");

if (hasTitle) {
titleElement.innerText = this.title;
}

if (hostConfig.actions.iconPlacement == Enums.ActionIconPlacement.AboveTitle) {
buttonElement.classList.add("iconAbove");
buttonElement.style.flexDirection = "column";

if (hasTitle) {
iconElement.style.marginBottom = "4px";
}
}
else {
buttonElement.classList.add("iconLeft");

if (hasTitle) {
iconElement.style.marginRight = "4px";
}
}

buttonElement.appendChild(iconElement);
buttonElement.appendChild(titleElement);
}

this._renderedElement = buttonElement;
}
Expand Down Expand Up @@ -2243,6 +2293,7 @@ export abstract class Action {
parse(json: any) {
this.id = json["id"];
this.title = json["title"];
this.iconUrl = json["iconUrl"];
}

remove(): boolean {
Expand Down Expand Up @@ -2488,6 +2539,12 @@ export class HttpAction extends Action {
}

export class ShowCardAction extends Action {
protected addCssClasses(element: HTMLElement) {
super.addCssClasses(element);

element.classList.add(this.parent.hostConfig.makeCssClassName("expandable"));
}

readonly card: AdaptiveCard = new InlineAdaptiveCard();

getJsonTypeName(): string {
Expand Down Expand Up @@ -2852,7 +2909,6 @@ class ActionCollection {
actionButton.action.renderedElement.style.overflow = "hidden";
actionButton.action.renderedElement.style.overflow = "table-cell";
actionButton.action.renderedElement.style.flex = this._owner.hostConfig.actions.actionAlignment === Enums.ActionAlignment.Stretch ? "0 1 100%" : "0 1 auto";
actionButton.text = this.items[i].title;
actionButton.onClick = (ab) => { this.actionClicked(ab); };

this.buttons.push(actionButton);
Expand Down Expand Up @@ -3797,7 +3853,7 @@ export class Column extends Container {
renderedElement.style.minWidth = "0";
}

if (this.width instanceof SizeAndUnit) {
if (this.width instanceof Utils.SizeAndUnit) {
if (this.width.unit == Enums.SizeUnit.Pixel) {
renderedElement.style.flex = "0 0 " + this.width.physicalSize + "px";
}
Expand All @@ -3818,7 +3874,7 @@ export class Column extends Container {
return Enums.Orientation.Vertical;
}

width: SizeAndUnit | "auto" | "stretch" = "auto";
width: Utils.SizeAndUnit | "auto" | "stretch" = "auto";

getJsonTypeName(): string {
return "Column";
Expand Down Expand Up @@ -3863,7 +3919,7 @@ export class Column extends Container {

if (typeof jsonWidth === "number") {
if (jsonWidth > 0) {
this.width = new SizeAndUnit(jsonWidth, Enums.SizeUnit.Weight);
this.width = new Utils.SizeAndUnit(jsonWidth, Enums.SizeUnit.Weight);
}
else {
invalidWidth = true;
Expand All @@ -3872,7 +3928,7 @@ export class Column extends Container {
else if (typeof jsonWidth === "string") {
if (jsonWidth != "auto" && jsonWidth != "stretch") {
try {
this.width = SizeAndUnit.parse(jsonWidth);
this.width = Utils.SizeAndUnit.parse(jsonWidth);
}
catch (e) {
invalidWidth = true;
Expand Down Expand Up @@ -3964,15 +4020,15 @@ export class ColumnSet extends CardElementContainer {
var totalWeight: number = 0;

for (let column of this._columns) {
if (column.width instanceof SizeAndUnit && (column.width.unit == Enums.SizeUnit.Weight)) {
if (column.width instanceof Utils.SizeAndUnit && (column.width.unit == Enums.SizeUnit.Weight)) {
totalWeight += column.width.physicalSize;
}
}

var renderedColumnCount: number = 0;

for (let column of this._columns) {
if (column.width instanceof SizeAndUnit && column.width.unit == Enums.SizeUnit.Weight && totalWeight > 0) {
if (column.width instanceof Utils.SizeAndUnit && column.width.unit == Enums.SizeUnit.Weight && totalWeight > 0) {
var computedWeight = 100 / totalWeight * column.width.physicalSize;

// Best way to emulate "internal" access I know of
Expand Down
5 changes: 5 additions & 0 deletions source/nodejs/adaptivecards/src/enums.ts
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,11 @@ export enum BackgroundImageMode {
Repeat
}

export enum ActionIconPlacement {
LeftOfTitle,
AboveTitle
}

/*
This should really be a string enum, e.g.
Expand Down
14 changes: 14 additions & 0 deletions source/nodejs/adaptivecards/src/host-config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,8 @@ export class ActionsConfig {
preExpandSingleShowCardAction?: boolean = false;
actionsOrientation: Enums.Orientation = Enums.Orientation.Horizontal;
actionAlignment: Enums.ActionAlignment = Enums.ActionAlignment.Left;
iconPlacement: Enums.ActionIconPlacement = Enums.ActionIconPlacement.LeftOfTitle;
iconSize: number = 24;

constructor(obj?: any) {
if (obj) {
Expand All @@ -147,6 +149,18 @@ export class ActionsConfig {
this.preExpandSingleShowCardAction = Utils.getValueOrDefault<boolean>(obj["preExpandSingleShowCardAction"], false);
this.actionsOrientation = Utils.parseHostConfigEnum(Enums.Orientation, obj["actionsOrientation"], Enums.Orientation.Horizontal);
this.actionAlignment = Utils.parseHostConfigEnum(Enums.ActionAlignment, obj["actionAlignment"], Enums.ActionAlignment.Left);
this.iconPlacement = Utils.parseHostConfigEnum(Enums.ActionIconPlacement, obj["iconPlacement"], Enums.ActionIconPlacement.LeftOfTitle);

try {
let sizeAndUnit = Utils.SizeAndUnit.parse(obj["iconSize"]);

if (sizeAndUnit.unit == Enums.SizeUnit.Pixel) {
this.iconSize = sizeAndUnit.physicalSize;
}
}
catch (e) {
// Swallow this, keep default icon size
}
}
}

Expand Down
Loading

0 comments on commit 8e82b60

Please sign in to comment.