Skip to content

Commit

Permalink
feat(ui5-icon): introduce interactive property (#1592)
Browse files Browse the repository at this point in the history
  • Loading branch information
fifoosid authored May 13, 2020
1 parent 47d37c3 commit b898cd3
Show file tree
Hide file tree
Showing 5 changed files with 134 additions and 2 deletions.
6 changes: 6 additions & 0 deletions packages/main/src/Icon.hbs
Original file line number Diff line number Diff line change
@@ -1,12 +1,18 @@
<svg
class="ui5-icon-root"
tabindex="{{tabIndex}}"
dir="{{dir}}"
viewBox="0 0 512 512"
role="img"
focusable="false"
preserveAspectRatio="xMidYMid meet"
aria-label="{{accessibleNameText}}"
xmlns="http://www.w3.org/2000/svg"
@focusin={{_onfocusin}}
@focusout={{_onfocusout}}
@keydown={{_onkeydown}}
@keyup={{_onkeyup}}
@click={{_onclick}}
>
{{#if hasIconTooltip}}
<title id="{{_id}}-tooltip">{{accessibleNameText}}</title>
Expand Down
61 changes: 61 additions & 0 deletions packages/main/src/Icon.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { getRTL } from "@ui5/webcomponents-base/dist/config/RTL.js";
import { getIconData, getIconDataSync } from "@ui5/webcomponents-base/dist/SVGIconRegistry.js";
import createStyleInHead from "@ui5/webcomponents-base/dist/util/createStyleInHead.js";
import { fetchI18nBundle, getI18nBundle } from "@ui5/webcomponents-base/dist/i18nBundle.js";
import { isSpace, isEnter } from "@ui5/webcomponents-base/dist/Keys.js";
import IconTemplate from "./generated/templates/IconTemplate.lit.js";

// Styles
Expand All @@ -17,6 +18,17 @@ const ICON_NOT_FOUND = "ICON_NOT_FOUND";
const metadata = {
tag: "ui5-icon",
properties: /** @lends sap.ui.webcomponents.main.Icon.prototype */ {
/**
* Defines if the icon is interactive (focusable and pressable)
* @type {boolean}
* @defaultvalue false
* @public
* @since 1.0.0-rc.8
*/
interactive: {
type: Boolean,
},

/**
* Defines the unique identifier (icon name) of each <code>ui5-icon</code>.
* <br><br>
Expand Down Expand Up @@ -77,6 +89,13 @@ const metadata = {
noAttribute: true,
},

/**
* @private
*/
focused: {
type: Boolean,
},

/**
* @private
*/
Expand All @@ -85,6 +104,14 @@ const metadata = {
},
},
events: {
/**
* Fired on mouseup, space and enter if icon is interactive
* @private
* @since 1.0.0-rc.8
*/
click: {

},
},
};

Expand Down Expand Up @@ -137,6 +164,40 @@ class Icon extends UI5Element {
await fetchI18nBundle("@ui5/webcomponents");
}

_onfocusin(event) {
if (this.interactive) {
this.focused = true;
}
}

_onfocusout(event) {
this.focused = false;
}

_onkeydown(event) {
if (this.interactive && isEnter(event)) {
this.fireEvent("click");
}
}

_onkeyup(event) {
if (this.interactive && isSpace(event)) {
this.fireEvent("click");
}
}

_onclick(event) {
if (this.interactive) {
event.preventDefault();
// Prevent the native event and fire custom event because otherwise the noConfict event won't be thrown
this.fireEvent("click");
}
}

get tabIndex() {
return this.interactive ? "0" : "-1";
}

static createGlobalStyle() {
if (!window.ShadyDOM) {
return;
Expand Down
5 changes: 5 additions & 0 deletions packages/main/src/themes/Icon.css
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,10 @@
outline: none;
}

:host([interactive][focused]) .ui5-icon-root {
outline: 1px dotted var(--sapContent_FocusColor);
}

:host(:not([dir="ltr"])) .ui5-icon-root[dir=rtl] {
transform: scale(-1, -1);
transform-origin: center;
Expand All @@ -27,4 +31,5 @@
display:flex;
transform: scale(1, -1);
transform-origin: center;
outline: none;
}
24 changes: 23 additions & 1 deletion packages/main/test/pages/Icon.html
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,29 @@
></ui5-icon>
</ui5-datepicker>

<br/><br/>
<br/><br/>

<ui5-icon id="interactive-icon" name="add-equipment" class="icon-blue icon-medium" interactive></ui5-icon>
<ui5-icon id="non-interactive-icon" name="add-equipment" class="icon-blue icon-medium"></ui5-icon>
<ui5-input id="click-event" value="0"></ui5-input>

<br/>
<br/>

<script>
var icon = document.getElementById("interactive-icon"),
nonInteractiveIcon = document.getElementById("non-interactive-icon"),
input = document.getElementById("click-event"),
inputValue = 0;

icon.addEventListener("ui5-click", function() {
input.value = ++inputValue;
});

nonInteractiveIcon.addEventListener("ui5-click", function() {
input.value = ++inputValue;
});
</script>

<script type="module">
(async () => {
Expand Down
40 changes: 39 additions & 1 deletion packages/main/test/specs/Icon.spec.js
Original file line number Diff line number Diff line change
@@ -1 +1,39 @@
const assert = require("chai").assert;
const assert = require("chai").assert;

describe("Icon general interaction", () => {
browser.url("http://localhost:8080/test-resources/pages/Icon.html");

it("Tests icon rendering", () => {
const iconRoot = browser.$("#interactive-icon").shadow$("ui5-icon-root");

assert.ok(iconRoot, "Icon is rendered");
});

it("Tests if clicked event is thrown for interactive icons", () => {
const iconRoot = browser.$("#interactive-icon").shadow$(".ui5-icon-root");
const input = browser.$("#click-event");

iconRoot.click();
assert.strictEqual(input.getAttribute("value"), "1", "Mouse click throws event");

iconRoot.keys("Enter");
assert.strictEqual(input.getAttribute("value"), "2", "Enter throws event");

iconRoot.keys("Space");
assert.strictEqual(input.getAttribute("value"), "3", "Space throws event");
});

it("Tests if clicked event is not thrown for non interactive icons", () => {
const iconRoot = browser.$("#non-interactive-icon");
const input = browser.$("#click-event");

iconRoot.click();
assert.strictEqual(input.getAttribute("value"), "3", "Mouse click throws event");

iconRoot.keys("Enter");
assert.strictEqual(input.getAttribute("value"), "3", "Enter throws event");

iconRoot.keys("Space");
assert.strictEqual(input.getAttribute("value"), "3", "Space throws event");
});
});

0 comments on commit b898cd3

Please sign in to comment.