From 831702288a12d8fa4cf73d16d71470009c44d027 Mon Sep 17 00:00:00 2001 From: Ivaylo Plashkov Date: Wed, 29 Jan 2020 12:09:28 +0200 Subject: [PATCH 01/12] feat(ui5-segmentedbutton): initial implementation --- packages/main/bundle.esm.js | 1 + packages/main/src/SegmentedButton.hbs | 8 + packages/main/src/SegmentedButton.js | 155 ++++++++++++++++++ packages/main/src/themes/Button.css | 13 +- packages/main/src/themes/SegmentedButton.css | 35 ++++ packages/main/test/pages/SegmentedButton.html | 68 ++++++++ 6 files changed, 277 insertions(+), 3 deletions(-) create mode 100644 packages/main/src/SegmentedButton.hbs create mode 100644 packages/main/src/SegmentedButton.js create mode 100644 packages/main/src/themes/SegmentedButton.css create mode 100644 packages/main/test/pages/SegmentedButton.html diff --git a/packages/main/bundle.esm.js b/packages/main/bundle.esm.js index ae5be1d7db48..6e986e6c0268 100644 --- a/packages/main/bundle.esm.js +++ b/packages/main/bundle.esm.js @@ -30,6 +30,7 @@ import Link from "./dist/Link.js"; import Popover from "./dist/Popover.js"; import Panel from "./dist/Panel.js"; import RadioButton from "./dist/RadioButton.js"; +import SegmentedButton from "./dist/SegmentedButton"; import Select from "./dist/Select.js"; import Option from "./dist/Option.js"; import Switch from "./dist/Switch.js"; diff --git a/packages/main/src/SegmentedButton.hbs b/packages/main/src/SegmentedButton.hbs new file mode 100644 index 000000000000..de2386845e5d --- /dev/null +++ b/packages/main/src/SegmentedButton.hbs @@ -0,0 +1,8 @@ +
+ {{#each buttons}} + + {{/each}} +
\ No newline at end of file diff --git a/packages/main/src/SegmentedButton.js b/packages/main/src/SegmentedButton.js new file mode 100644 index 000000000000..7cdbc9a8cb0d --- /dev/null +++ b/packages/main/src/SegmentedButton.js @@ -0,0 +1,155 @@ +import UI5Element from "@ui5/webcomponents-base/dist/UI5Element.js"; +import litRender from "@ui5/webcomponents-base/dist/renderer/LitRenderer.js"; +import ResizeHandler from "@ui5/webcomponents-base/dist/delegate/ResizeHandler.js"; + +// Template +import SegmentedButtonTemplate from "./generated/templates/SegmentedButtonTemplate.lit.js"; + +// Styles +import SegmentedButtonCss from "./generated/themes/SegmentedButton.css.js"; + +/** + * @public + */ +const metadata = { + tag: "ui5-segmentedbutton", + properties: /** @lends sap.ui.webcomponents.main.SegmentedButton.prototype */ {}, + slots: /** @lends sap.ui.webcomponents.main.SegmentedButton.prototype */ { + + /** + * Defines the buttons of ui5-segmentedbutton. + *

+ * Note: Multiple buttons are allowed. + *

+ * Note: Use the ui5-togglebutton for the intended design. + * @type {HTMLElement[]} + * @slot + * @public + */ + "default": { + propertyName: "buttons", + type: HTMLElement, + individualSlots: true, + }, + }, + events: /** @lends sap.ui.webcomponents.main.SegmentedButton.prototype */ { + + /** + * Fired when the ui5-segmentedbutton selection button changes. + * + * @event + * @public + */ + selectionChange: { + detail: { + selectedButton: { type: HTMLElement }, + }, + }, + }, +}; + +/** + * @class + * + *

Overview

+ * + * The SegmentedButton shows a group of buttons. When the user clicks or taps + * one of the buttons, it stays in a pressed state. It automatically resizes the buttons + * to fit proportionally within the control. When no width is set, the control uses the available width. + * + *

ES6 Module Import

+ * + * import "@ui5/webcomponents/dist/SegmentedButton"; + * + * @constructor + * @author SAP SE + * @alias sap.ui.webcomponents.main.SegmentedButton + * @extends sap.ui.webcomponents.base.UI5Element + * @tagname ui5-segmentedbutton + * @public + */ +class SegmentedButton extends UI5Element { + static get metadata() { + return metadata; + } + + static get render() { + return litRender; + } + + static get template() { + return SegmentedButtonTemplate; + } + + static get styles() { + return SegmentedButtonCss; + } + + onEnterDOM() { + this._handleResizeBound = this._handleResize.bind(this); + + ResizeHandler.register(document.body, this._handleResizeBound); + } + + onExitDOM() { + ResizeHandler.deregister(document.body, this._handleResizeBound); + } + + onBeforeRendering() { + this.syncSelection(); + } + + onAfterRendering() { + this.widths = this.buttons.map(button => button.offsetWidth); + } + + syncSelection() { + this._selectedButton = this.buttons.filter(button => button.pressed).pop(); + + if (this._selectedButton) { + this.buttons.forEach(button => { + button.pressed = false; + }); + this._selectedButton.pressed = true; + } + } + + _onclick(event) { + return this.toggle(event); + } + + toggle(event) { + if (event.target !== this.selectedButton) { + if (this._selectedButton) { + this._selectedButton.pressed = false; + } + this._selectedButton = event.target; + this.fireEvent("selectionChange", { + selectedButton: this._selectedButton, + }); + } + + return this; + } + + get selectedButton() { + return this._selectedButton; + } + + _handleResize() { + const documentWidth = document.body.clientWidth; + + this.style.width = `${Math.max(...this.widths) * this.buttons.length}px`; + this.buttons.forEach(button => { + button.style.width = "100%"; + }); + + if (documentWidth <= this.offsetWidth) { + this.style.width = "100%"; + } + } +} + +SegmentedButton.define(); + +export default SegmentedButton; diff --git a/packages/main/src/themes/Button.css b/packages/main/src/themes/Button.css index b0992e3a6adf..e4e6ebd5985a 100644 --- a/packages/main/src/themes/Button.css +++ b/packages/main/src/themes/Button.css @@ -50,6 +50,9 @@ color: inherit; text-shadow: inherit; font: inherit; + white-space: inherit; + overflow: inherit; + text-overflow: inherit; } :host(:not([active]):hover) { @@ -83,6 +86,9 @@ .ui5-button-text { outline: none; position: relative; + white-space: inherit; + overflow: inherit; + text-overflow: inherit; } :host([has-icon]) .ui5-button-text { @@ -104,9 +110,10 @@ } bdi { - display: flex; - justify-content: flex-start; - align-items: center; + display: block; + white-space: inherit; + overflow: inherit; + text-overflow: inherit; } :host([active]:not([disabled])) { diff --git a/packages/main/src/themes/SegmentedButton.css b/packages/main/src/themes/SegmentedButton.css new file mode 100644 index 000000000000..f4e58640ef6b --- /dev/null +++ b/packages/main/src/themes/SegmentedButton.css @@ -0,0 +1,35 @@ +:host(:not([hidden])) { + display: inline-block; +} + +.ui5-segmentedbutton-root { + display: flex; +} + +::slotted(*) { + display: inline-block; + border-radius: 0; + height: 2.75rem; + min-width: 2.5rem; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; +} + +::slotted(:not(ui5-mdk-toolbar-spacer):nth-child(odd)) { + border: 1px solid var(--sapButton_Selected_BorderColor); + border-right: 0; + border-left: 0; +} + +::slotted(:not(ui5-mdk-toolbar-spacer):last-child) { + border-top-right-radius: 0.375rem; + border-bottom-right-radius: 0.375rem; + border-right: 1px solid var(--sapButton_Selected_BorderColor); +} + +::slotted(:not(ui5-mdk-toolbar-spacer):first-child) { + border-top-left-radius: 0.375rem; + border-bottom-left-radius: 0.375rem; + border-left: 1px solid var(--sapButton_Selected_BorderColor); +} \ No newline at end of file diff --git a/packages/main/test/pages/SegmentedButton.html b/packages/main/test/pages/SegmentedButton.html new file mode 100644 index 000000000000..d64cf6f76f30 --- /dev/null +++ b/packages/main/test/pages/SegmentedButton.html @@ -0,0 +1,68 @@ + + + + + + + ui5-segmentedbutton + + + + + + + + + + +
+

ui5-segmentedbutton

+
+ +
+
+

Segmentedbutton example

+
+
+ + + Pressed ToggleButton + Pressed ToggleButton + +
+ +
+

Example with 4 buttons

+ + + A + Pressed ToggleButton + asfsa + Pressed ToggleButton + +
+ +
+

Example with 5 buttons

+ + + A + Pressed ToggleButton + asfsa + Pressed ToggleButton + asfsa + + +

Example with Icons

+ + + + + + +
+
+
+
+ + From 58e4732e13f998fe70ea2c694ce05a4f9947a519 Mon Sep 17 00:00:00 2001 From: Ivaylo Plashkov Date: Wed, 29 Jan 2020 21:00:29 +0200 Subject: [PATCH 02/12] test page examples updated --- packages/main/src/SegmentedButton.js | 1 + packages/main/test/pages/SegmentedButton.html | 82 +++++++++---------- 2 files changed, 42 insertions(+), 41 deletions(-) diff --git a/packages/main/src/SegmentedButton.js b/packages/main/src/SegmentedButton.js index 7cdbc9a8cb0d..e3982594eb62 100644 --- a/packages/main/src/SegmentedButton.js +++ b/packages/main/src/SegmentedButton.js @@ -100,6 +100,7 @@ class SegmentedButton extends UI5Element { } onAfterRendering() { + debugger this.widths = this.buttons.map(button => button.offsetWidth); } diff --git a/packages/main/test/pages/SegmentedButton.html b/packages/main/test/pages/SegmentedButton.html index d64cf6f76f30..38acf393db23 100644 --- a/packages/main/test/pages/SegmentedButton.html +++ b/packages/main/test/pages/SegmentedButton.html @@ -15,54 +15,54 @@ -
-

ui5-segmentedbutton

-
+
+

ui5-segmentedbutton

+
-
-
-

Segmentedbutton example

-
-
- - - Pressed ToggleButton - Pressed ToggleButton - -
+
+
+

Segmentedbutton example

+
+
+ + + ToggleButton + Button + +
-
-

Example with 4 buttons

+
+

Example with 4 buttons

- - A - Pressed ToggleButton - asfsa - Pressed ToggleButton - -
+ + Button + Button + Click + Pressed ToggleButton + +
-
-

Example with 5 buttons

+
+

Example with 5 buttons

- - A - Pressed ToggleButton - asfsa - Pressed ToggleButton - asfsa - + + Word + Pressed ToggleButton With Bigger Text + Button + Pressed ToggleButton + A + -

Example with Icons

+

Example with Icons

- - - - - -
-
+ + + + + +
-
+ + From a00477cae553a183aeb8b631d0398f0b87b4b7d2 Mon Sep 17 00:00:00 2001 From: Ivaylo Plashkov Date: Wed, 29 Jan 2020 21:37:28 +0200 Subject: [PATCH 03/12] togglebutton can no longer be deactivated if once pressed --- packages/main/src/SegmentedButton.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/main/src/SegmentedButton.js b/packages/main/src/SegmentedButton.js index e3982594eb62..47428cf95184 100644 --- a/packages/main/src/SegmentedButton.js +++ b/packages/main/src/SegmentedButton.js @@ -100,7 +100,6 @@ class SegmentedButton extends UI5Element { } onAfterRendering() { - debugger this.widths = this.buttons.map(button => button.offsetWidth); } @@ -129,6 +128,7 @@ class SegmentedButton extends UI5Element { selectedButton: this._selectedButton, }); } + event.target.pressed = true; return this; } From 6b708f9cb1210c34ae33f5bef980fbcd253c2901 Mon Sep 17 00:00:00 2001 From: Ivaylo Plashkov Date: Fri, 31 Jan 2020 12:44:29 +0200 Subject: [PATCH 04/12] fixed styles and resizing in IE --- packages/main/src/SegmentedButton.js | 5 +++-- packages/main/src/themes/SegmentedButton.css | 9 ++++----- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/packages/main/src/SegmentedButton.js b/packages/main/src/SegmentedButton.js index 47428cf95184..73061e92f41a 100644 --- a/packages/main/src/SegmentedButton.js +++ b/packages/main/src/SegmentedButton.js @@ -99,8 +99,9 @@ class SegmentedButton extends UI5Element { this.syncSelection(); } - onAfterRendering() { - this.widths = this.buttons.map(button => button.offsetWidth); + async onAfterRendering () { + await Promise.all(this.buttons.map(button => button._waitForDomRef)); + this.widths = this.buttons.map(button => button.offsetWidth); } syncSelection() { diff --git a/packages/main/src/themes/SegmentedButton.css b/packages/main/src/themes/SegmentedButton.css index f4e58640ef6b..f12b5f908809 100644 --- a/packages/main/src/themes/SegmentedButton.css +++ b/packages/main/src/themes/SegmentedButton.css @@ -6,8 +6,7 @@ display: flex; } -::slotted(*) { - display: inline-block; +::slotted(ui5-togglebutton) { border-radius: 0; height: 2.75rem; min-width: 2.5rem; @@ -16,19 +15,19 @@ text-overflow: ellipsis; } -::slotted(:not(ui5-mdk-toolbar-spacer):nth-child(odd)) { +::slotted(ui5-togglebutton:nth-child(odd)) { border: 1px solid var(--sapButton_Selected_BorderColor); border-right: 0; border-left: 0; } -::slotted(:not(ui5-mdk-toolbar-spacer):last-child) { +::slotted(ui5-togglebutton:last-child) { border-top-right-radius: 0.375rem; border-bottom-right-radius: 0.375rem; border-right: 1px solid var(--sapButton_Selected_BorderColor); } -::slotted(:not(ui5-mdk-toolbar-spacer):first-child) { +::slotted(ui5-togglebutton:first-child) { border-top-left-radius: 0.375rem; border-bottom-left-radius: 0.375rem; border-left: 1px solid var(--sapButton_Selected_BorderColor); From 7efe5d3e76f06a4fcb06450ce0dbc8c06ea896b8 Mon Sep 17 00:00:00 2001 From: Ivaylo Plashkov Date: Fri, 31 Jan 2020 13:54:20 +0200 Subject: [PATCH 05/12] fixed eslint errors --- packages/main/bundle.esm.js | 2 +- packages/main/src/SegmentedButton.hbs | 2 +- packages/main/src/SegmentedButton.js | 4 +- packages/main/src/themes/SegmentedButton.css | 2 +- packages/main/test/pages/SegmentedButton.html | 85 ++++++++++--------- 5 files changed, 49 insertions(+), 46 deletions(-) diff --git a/packages/main/bundle.esm.js b/packages/main/bundle.esm.js index 6e986e6c0268..9a7e253bc967 100644 --- a/packages/main/bundle.esm.js +++ b/packages/main/bundle.esm.js @@ -30,7 +30,7 @@ import Link from "./dist/Link.js"; import Popover from "./dist/Popover.js"; import Panel from "./dist/Panel.js"; import RadioButton from "./dist/RadioButton.js"; -import SegmentedButton from "./dist/SegmentedButton"; +import SegmentedButton from "./dist/SegmentedButton.js"; import Select from "./dist/Select.js"; import Option from "./dist/Option.js"; import Switch from "./dist/Switch.js"; diff --git a/packages/main/src/SegmentedButton.hbs b/packages/main/src/SegmentedButton.hbs index de2386845e5d..1b9e795f1529 100644 --- a/packages/main/src/SegmentedButton.hbs +++ b/packages/main/src/SegmentedButton.hbs @@ -5,4 +5,4 @@ {{#each buttons}} {{/each}} - \ No newline at end of file + diff --git a/packages/main/src/SegmentedButton.js b/packages/main/src/SegmentedButton.js index 73061e92f41a..28deb5af6f38 100644 --- a/packages/main/src/SegmentedButton.js +++ b/packages/main/src/SegmentedButton.js @@ -99,9 +99,9 @@ class SegmentedButton extends UI5Element { this.syncSelection(); } - async onAfterRendering () { + async onAfterRendering() { await Promise.all(this.buttons.map(button => button._waitForDomRef)); - this.widths = this.buttons.map(button => button.offsetWidth); + this.widths = this.buttons.map(button => button.offsetWidth); } syncSelection() { diff --git a/packages/main/src/themes/SegmentedButton.css b/packages/main/src/themes/SegmentedButton.css index f12b5f908809..2b58bf3d117a 100644 --- a/packages/main/src/themes/SegmentedButton.css +++ b/packages/main/src/themes/SegmentedButton.css @@ -31,4 +31,4 @@ border-top-left-radius: 0.375rem; border-bottom-left-radius: 0.375rem; border-left: 1px solid var(--sapButton_Selected_BorderColor); -} \ No newline at end of file +} diff --git a/packages/main/test/pages/SegmentedButton.html b/packages/main/test/pages/SegmentedButton.html index 38acf393db23..05c64c4cae85 100644 --- a/packages/main/test/pages/SegmentedButton.html +++ b/packages/main/test/pages/SegmentedButton.html @@ -1,5 +1,6 @@ + @@ -15,54 +16,56 @@ -
-

ui5-segmentedbutton

-
+
+

ui5-segmentedbutton

+
-
-
-

Segmentedbutton example

-
-
- - - ToggleButton - Button - -
+
+
+

Segmentedbutton example

+
+
+ + + ToggleButton + Button + +
-
-

Example with 4 buttons

+
+

Example with 4 buttons

- - Button - Button - Click - Pressed ToggleButton - -
+ + Button + Button + Click + Pressed ToggleButton + +
-
-

Example with 5 buttons

+
+

Example with 5 buttons

- - Word - Pressed ToggleButton With Bigger Text - Button - Pressed ToggleButton - A - + + Word + Pressed ToggleButton With Bigger Text + Button + Pressed ToggleButton + A + +
-

Example with Icons

+
+

Example with Icons

- - - - - -
+ + + + + +
+
-
-
+ From cacb9125087f2c6a1807dfa59c86a27b37876018 Mon Sep 17 00:00:00 2001 From: Ivaylo Plashkov Date: Sun, 2 Feb 2020 20:07:32 +0200 Subject: [PATCH 06/12] added tests --- packages/main/src/SegmentedButton.js | 29 +++++------ packages/main/test/pages/SegmentedButton.html | 6 +-- .../main/test/specs/SegmentedButton.spec.js | 48 +++++++++++++++++++ 3 files changed, 66 insertions(+), 17 deletions(-) create mode 100644 packages/main/test/specs/SegmentedButton.spec.js diff --git a/packages/main/src/SegmentedButton.js b/packages/main/src/SegmentedButton.js index 28deb5af6f38..48d40e9c313c 100644 --- a/packages/main/src/SegmentedButton.js +++ b/packages/main/src/SegmentedButton.js @@ -35,14 +35,15 @@ const metadata = { events: /** @lends sap.ui.webcomponents.main.SegmentedButton.prototype */ { /** - * Fired when the ui5-segmentedbutton selection button changes. + * Fired when the pressed button changes. * * @event + * @param {HTMLElement} pressedButton the pressed button. * @public */ - selectionChange: { + pressChange: { detail: { - selectedButton: { type: HTMLElement }, + pressedButton: { type: HTMLElement }, }, }, }, @@ -105,13 +106,13 @@ class SegmentedButton extends UI5Element { } syncSelection() { - this._selectedButton = this.buttons.filter(button => button.pressed).pop(); + this._pressedButton = this.buttons.filter(button => button.pressed).pop(); - if (this._selectedButton) { + if (this._pressedButton) { this.buttons.forEach(button => { button.pressed = false; }); - this._selectedButton.pressed = true; + this._pressedButton.pressed = true; } } @@ -120,13 +121,13 @@ class SegmentedButton extends UI5Element { } toggle(event) { - if (event.target !== this.selectedButton) { - if (this._selectedButton) { - this._selectedButton.pressed = false; + if (event.target !== this.pressedButton) { + if (this._pressedButton) { + this._pressedButton.pressed = false; } - this._selectedButton = event.target; - this.fireEvent("selectionChange", { - selectedButton: this._selectedButton, + this._pressedButton = event.target; + this.fireEvent("pressChange", { + pressedButton: this._pressedButton, }); } event.target.pressed = true; @@ -134,8 +135,8 @@ class SegmentedButton extends UI5Element { return this; } - get selectedButton() { - return this._selectedButton; + get pressedButton() { + return this._pressedButton; } _handleResize() { diff --git a/packages/main/test/pages/SegmentedButton.html b/packages/main/test/pages/SegmentedButton.html index 05c64c4cae85..9f348e8f986d 100644 --- a/packages/main/test/pages/SegmentedButton.html +++ b/packages/main/test/pages/SegmentedButton.html @@ -25,8 +25,8 @@

ui5-segmentedbutton

Segmentedbutton example

- - + + ToggleButton Button @@ -46,7 +46,7 @@

Example with 4 buttons

Example with 5 buttons

- + Word Pressed ToggleButton With Bigger Text Button diff --git a/packages/main/test/specs/SegmentedButton.spec.js b/packages/main/test/specs/SegmentedButton.spec.js new file mode 100644 index 000000000000..2273ec4c68b8 --- /dev/null +++ b/packages/main/test/specs/SegmentedButton.spec.js @@ -0,0 +1,48 @@ +const assert = require("chai").assert; + +describe("SegmentedButton general interaction", () => { + browser.url("http://localhost:8080/test-resources/pages/SegmentedButton.html"); + + it("tests rendering of segmentedbutton", () => { + const segmentedButton = browser.$("#segButton1"); + const toggleButton1 = browser.$("#segButton1 > ui5-togglebutton:first-child"); + const toggleButton2 = browser.$("#segButton1 > ui5-togglebutton:nth-child(2)"); + const toggleButton3 = browser.$("#segButton1 > ui5-togglebutton:last-child"); + + // all buttons should be rendered + assert.ok(segmentedButton.isExisting(), "SegmentedButton is rendered"); + assert.ok(toggleButton1.isExisting(), "First ToggleButton is rendered"); + assert.ok(toggleButton2.isExisting(), "Second ToggleButton is rendered"); + assert.ok(toggleButton3.isExisting(), "Third ToggleButton is rendered"); + }); + + it("tests if pressed attribute is applied", () => { + const toggleButton = browser.$("#segButton1 > ui5-togglebutton:first-child"); + + assert.ok(toggleButton.getProperty("pressed"), "ToggleButton has property pressed"); + }); + + it("tests if pressed attribute is switched to the newly pressed button", () => { + const firstToggleButton = browser.$("#segButton1 > ui5-togglebutton:first-child"); + const lastToggleButton = browser.$("#segButton1 > ui5-togglebutton:last-child"); + + lastToggleButton.click(); + + assert.ok(lastToggleButton.getProperty("pressed"), "Last ToggleButton has property pressed"); + assert.ok(!firstToggleButton.getProperty("pressed"), "First ToggleButton should not be pressed anymore"); + }); + + it("tests if pressed attribute is applied only to last child when all buttons are pressed", () => { + const toggleButton1 = browser.$("#segButton2 > ui5-togglebutton:first-child"); + const toggleButton2 = browser.$("#segButton2 > ui5-togglebutton:nth-child(2)"); + const toggleButton3 = browser.$("#segButton2 > ui5-togglebutton:nth-child(3)"); + const toggleButton4 = browser.$("#segButton2 > ui5-togglebutton:last-child"); + + // only last button should be pressed + assert.ok(!toggleButton1.getProperty("pressed"), "ToggleButton should not be pressed"); + assert.ok(!toggleButton2.getProperty("pressed"), "ToggleButton should not be pressed"); + assert.ok(!toggleButton3.getProperty("pressed"), "ToggleButton should not be pressed"); + assert.ok(toggleButton4.getProperty("pressed"), "ToggleButton has property pressed"); + + }); +}); From ac33ee862e2a2181dda29d835fd29dfe34196942 Mon Sep 17 00:00:00 2001 From: Ivaylo Plashkov Date: Tue, 4 Feb 2020 19:09:31 +0200 Subject: [PATCH 07/12] fixed behaviour and added docs --- packages/main/src/SegmentedButton.js | 57 +++++++++++-------- packages/main/src/Select.js | 4 +- packages/main/test/pages/SegmentedButton.html | 2 +- 3 files changed, 35 insertions(+), 28 deletions(-) diff --git a/packages/main/src/SegmentedButton.js b/packages/main/src/SegmentedButton.js index 48d40e9c313c..4187ceadd4c8 100644 --- a/packages/main/src/SegmentedButton.js +++ b/packages/main/src/SegmentedButton.js @@ -35,15 +35,15 @@ const metadata = { events: /** @lends sap.ui.webcomponents.main.SegmentedButton.prototype */ { /** - * Fired when the pressed button changes. + * Fired when the selected button changes. * * @event - * @param {HTMLElement} pressedButton the pressed button. + * @param {HTMLElement} selectedButton the pressed button. * @public */ - pressChange: { + selectionChange: { detail: { - pressedButton: { type: HTMLElement }, + selectedButton: { type: HTMLElement }, }, }, }, @@ -97,7 +97,7 @@ class SegmentedButton extends UI5Element { } onBeforeRendering() { - this.syncSelection(); + this.normalizeSelection(); } async onAfterRendering() { @@ -105,44 +105,40 @@ class SegmentedButton extends UI5Element { this.widths = this.buttons.map(button => button.offsetWidth); } - syncSelection() { - this._pressedButton = this.buttons.filter(button => button.pressed).pop(); + normalizeSelection() { + this._selectedButton = this.buttons.filter(button => button.pressed).pop(); - if (this._pressedButton) { + console.log(this._selectedButton) + if (this._selectedButton) { this.buttons.forEach(button => { button.pressed = false; }); - this._pressedButton.pressed = true; + this._selectedButton.pressed = true; } } _onclick(event) { - return this.toggle(event); - } - - toggle(event) { - if (event.target !== this.pressedButton) { - if (this._pressedButton) { - this._pressedButton.pressed = false; + if (event.target !== this._selectedButton) { + if (this._selectedButton) { + this._selectedButton.pressed = false; } - this._pressedButton = event.target; - this.fireEvent("pressChange", { - pressedButton: this._pressedButton, + this._selectedButton = event.target; + this.fireEvent("selectionChange", { + selectedButton: this._selectedButton, }); } - event.target.pressed = true; + this._selectedButton.pressed = true; return this; } - get pressedButton() { - return this._pressedButton; - } - _handleResize() { const documentWidth = document.body.clientWidth; + + if (!this.style.width) { + this.style.width = `${Math.max(...this.widths) * this.buttons.length}px`; + } - this.style.width = `${Math.max(...this.widths) * this.buttons.length}px`; this.buttons.forEach(button => { button.style.width = "100%"; }); @@ -151,6 +147,17 @@ class SegmentedButton extends UI5Element { this.style.width = "100%"; } } + + /** + * Currently selected button. + * + * @readonly + * @type { ui5-togglebutton } + * @public + */ + get selectedButton() { + return this._selectedButton; + } } SegmentedButton.define(); diff --git a/packages/main/src/Select.js b/packages/main/src/Select.js index f0f084895e34..f50e9bb4ec08 100644 --- a/packages/main/src/Select.js +++ b/packages/main/src/Select.js @@ -122,10 +122,10 @@ const metadata = { }, events: /** @lends sap.ui.webcomponents.main.Select.prototype */ { /** - * Fired when the selected item changes. + * Fired when the selected option changes. * * @event - * @param {HTMLElement} item the selected item. + * @param {HTMLElement} selectedOption the selected option. * @public */ change: { diff --git a/packages/main/test/pages/SegmentedButton.html b/packages/main/test/pages/SegmentedButton.html index 9f348e8f986d..718db00c4e4d 100644 --- a/packages/main/test/pages/SegmentedButton.html +++ b/packages/main/test/pages/SegmentedButton.html @@ -58,7 +58,7 @@

Example with 5 buttons

Example with Icons

- + From 6affe4f1d20c89b75473c4bac06080e235914c13 Mon Sep 17 00:00:00 2001 From: Ivaylo Plashkov Date: Tue, 4 Feb 2020 19:13:36 +0200 Subject: [PATCH 08/12] fixed lint errors --- packages/main/src/SegmentedButton.js | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/packages/main/src/SegmentedButton.js b/packages/main/src/SegmentedButton.js index 4187ceadd4c8..fcdcee5ff7b6 100644 --- a/packages/main/src/SegmentedButton.js +++ b/packages/main/src/SegmentedButton.js @@ -108,7 +108,6 @@ class SegmentedButton extends UI5Element { normalizeSelection() { this._selectedButton = this.buttons.filter(button => button.pressed).pop(); - console.log(this._selectedButton) if (this._selectedButton) { this.buttons.forEach(button => { button.pressed = false; @@ -134,7 +133,7 @@ class SegmentedButton extends UI5Element { _handleResize() { const documentWidth = document.body.clientWidth; - + if (!this.style.width) { this.style.width = `${Math.max(...this.widths) * this.buttons.length}px`; } @@ -150,7 +149,7 @@ class SegmentedButton extends UI5Element { /** * Currently selected button. - * + * * @readonly * @type { ui5-togglebutton } * @public From 125cc58a0019013e0a799df6659f991a9061ca38 Mon Sep 17 00:00:00 2001 From: Ivaylo Plashkov Date: Wed, 5 Feb 2020 13:26:55 +0200 Subject: [PATCH 09/12] removed individualSlot --- packages/main/src/SegmentedButton.hbs | 4 +--- packages/main/src/SegmentedButton.js | 1 - packages/main/test/pages/SegmentedButton.html | 2 +- 3 files changed, 2 insertions(+), 5 deletions(-) diff --git a/packages/main/src/SegmentedButton.hbs b/packages/main/src/SegmentedButton.hbs index 1b9e795f1529..211dbd9fb890 100644 --- a/packages/main/src/SegmentedButton.hbs +++ b/packages/main/src/SegmentedButton.hbs @@ -2,7 +2,5 @@ @click="{{_onclick}}" class="ui5-segmentedbutton-root" > - {{#each buttons}} - - {{/each}} +
diff --git a/packages/main/src/SegmentedButton.js b/packages/main/src/SegmentedButton.js index fcdcee5ff7b6..c50f99a95c74 100644 --- a/packages/main/src/SegmentedButton.js +++ b/packages/main/src/SegmentedButton.js @@ -29,7 +29,6 @@ const metadata = { "default": { propertyName: "buttons", type: HTMLElement, - individualSlots: true, }, }, events: /** @lends sap.ui.webcomponents.main.SegmentedButton.prototype */ { diff --git a/packages/main/test/pages/SegmentedButton.html b/packages/main/test/pages/SegmentedButton.html index 718db00c4e4d..9f348e8f986d 100644 --- a/packages/main/test/pages/SegmentedButton.html +++ b/packages/main/test/pages/SegmentedButton.html @@ -58,7 +58,7 @@

Example with 5 buttons

Example with Icons

- + From 60063a36c4f4e1329683feca2cb7a52f4161870d Mon Sep 17 00:00:00 2001 From: Ivaylo Plashkov Date: Mon, 10 Feb 2020 13:38:44 +0200 Subject: [PATCH 10/12] add: keyboard handling and sample page. --- packages/main/src/Button.js | 18 ++++- packages/main/src/SegmentedButton.js | 29 +++++++- packages/main/test/pages/SegmentedButton.html | 12 +++- .../test/samples/SegmentedButton.sample.html | 70 +++++++++++++++++++ 4 files changed, 124 insertions(+), 5 deletions(-) create mode 100644 packages/main/test/samples/SegmentedButton.sample.html diff --git a/packages/main/src/Button.js b/packages/main/src/Button.js index daa9b41f84bd..1ea5d88dfbbc 100644 --- a/packages/main/src/Button.js +++ b/packages/main/src/Button.js @@ -136,6 +136,16 @@ const metadata = { _iconSettings: { type: Object, }, + + /** + * Defines the tabIndex of the component. + * @private + */ + _tabIndex: { + type: String, + defaultValue: "0", + noAttribute: true, + }, }, slots: /** @lends sap.ui.webcomponents.main.Button.prototype */ { /** @@ -314,7 +324,13 @@ class Button extends UI5Element { } get tabIndexValue() { - return this.nonFocusable ? "-1" : "0"; + const tabindex = this.getAttribute("tabindex"); + + if (tabindex) { + return tabindex; + } + + return this.nonFocusable ? "-1" : this._tabIndex; } static async define(...params) { diff --git a/packages/main/src/SegmentedButton.js b/packages/main/src/SegmentedButton.js index c50f99a95c74..bd36db447acf 100644 --- a/packages/main/src/SegmentedButton.js +++ b/packages/main/src/SegmentedButton.js @@ -1,4 +1,6 @@ import UI5Element from "@ui5/webcomponents-base/dist/UI5Element.js"; +import ItemNavigation from "@ui5/webcomponents-base/dist/delegate/ItemNavigation.js"; +import NavigationMode from "@ui5/webcomponents-base/dist/types/NavigationMode.js"; import litRender from "@ui5/webcomponents-base/dist/renderer/LitRenderer.js"; import ResizeHandler from "@ui5/webcomponents-base/dist/delegate/ResizeHandler.js"; @@ -55,7 +57,9 @@ const metadata = { * * The SegmentedButton shows a group of buttons. When the user clicks or taps * one of the buttons, it stays in a pressed state. It automatically resizes the buttons - * to fit proportionally within the control. When no width is set, the control uses the available width. + * to fit proportionally within the component. When no width is set, the component uses the available width. + *

+ * Note: There can be just one selected button at a time. * *

ES6 Module Import

* @@ -66,6 +70,7 @@ const metadata = { * @alias sap.ui.webcomponents.main.SegmentedButton * @extends sap.ui.webcomponents.base.UI5Element * @tagname ui5-segmentedbutton + * @since 1.0.0-rc.6 * @public */ class SegmentedButton extends UI5Element { @@ -85,6 +90,14 @@ class SegmentedButton extends UI5Element { return SegmentedButtonCss; } + constructor() { + super(); + this.initItemNavigation(); + + this.absoluteWidthSet = false; // set to true whenever we set absolute width to the component + this.percentageWidthSet = false; // set to true whenever we set 100% width to the component + } + onEnterDOM() { this._handleResizeBound = this._handleResize.bind(this); @@ -104,6 +117,14 @@ class SegmentedButton extends UI5Element { this.widths = this.buttons.map(button => button.offsetWidth); } + initItemNavigation() { + this._itemNavigation = new ItemNavigation(this, { + navigationMode: NavigationMode.Horizontal, + }); + + this._itemNavigation.getItemsCallback = () => this.getSlottedNodes("buttons"); + } + normalizeSelection() { this._selectedButton = this.buttons.filter(button => button.pressed).pop(); @@ -133,16 +154,18 @@ class SegmentedButton extends UI5Element { _handleResize() { const documentWidth = document.body.clientWidth; - if (!this.style.width) { + if (!this.style.width || this.percentageWidthSet) { this.style.width = `${Math.max(...this.widths) * this.buttons.length}px`; + this.absoluteWidthSet = true; } this.buttons.forEach(button => { button.style.width = "100%"; }); - if (documentWidth <= this.offsetWidth) { + if (documentWidth <= this.offsetWidth && this.absoluteWidthSet) { this.style.width = "100%"; + this.percentageWidthSet = true; } } diff --git a/packages/main/test/pages/SegmentedButton.html b/packages/main/test/pages/SegmentedButton.html index 9f348e8f986d..e71acdd81ed3 100644 --- a/packages/main/test/pages/SegmentedButton.html +++ b/packages/main/test/pages/SegmentedButton.html @@ -58,7 +58,17 @@

Example with 5 buttons

Example with Icons

- + + + + + +
+ +
+

Example with Icons

+ + diff --git a/packages/main/test/samples/SegmentedButton.sample.html b/packages/main/test/samples/SegmentedButton.sample.html new file mode 100644 index 000000000000..e00f8f7cddea --- /dev/null +++ b/packages/main/test/samples/SegmentedButton.sample.html @@ -0,0 +1,70 @@ +
+

SegmentedButton

+
+ +
+
+ +
@ui5/webcomponents
+ +
<ui5-segmentedbutton>
+ +
+

Basic SegmentedButton

+
+ + Map + Satellite + Terrain + +
+

+<ui5-segmentedbutton>
+    <ui5-togglebutton>Map</ui5-togglebutton>
+    <ui5-togglebutton pressed>Satellite</ui5-togglebutton>
+    <ui5-togglebutton>Terrain</ui5-togglebutton>
+</ui5-segmentedbutton>
+	
+
+ +
+

SegmentedButton with Icons

+
+ + + + + +
+

+<ui5-segmentedbutton>
+	<ui5-togglebutton icon="employee" pressed></ui5-togglebutton>
+	<ui5-togglebutton icon="menu"></ui5-togglebutton>
+	<ui5-togglebutton icon="factory"></ui5-togglebutton>
+</ui5-segmentedbutton>
+	
+
+ +
+

SegmentedButton with 5 ToggleButtons

+
+ + Button + Pressed ToggleButton With Bigger Text + Button + Pressed ToggleButton + Press me + +
+

+<ui5-segmentedbutton>
+	<ui5-togglebutton>Button</ui5-togglebutton>
+	<ui5-togglebutton pressed>Pressed ToggleButton With Bigger Text</ui5-togglebutton pressed>
+	<ui5-togglebutton>Button</ui5-togglebutton>
+	<ui5-togglebutton>ToggleButton</ui5-togglebutton>
+	<ui5-togglebutton>Press me</ui5-togglebutton>
+</ui5-segmentedbutton>
+	
+
+ + From 0586c751905ed00541b9d0fbd85185f74b260a62 Mon Sep 17 00:00:00 2001 From: Ivaylo Plashkov Date: Mon, 10 Feb 2020 14:29:46 +0200 Subject: [PATCH 11/12] fixed resize handling --- packages/main/src/SegmentedButton.js | 11 ++++---- packages/main/test/pages/SegmentedButton.html | 25 +++++++++++++------ .../test/samples/SegmentedButton.sample.html | 16 ++++++------ 3 files changed, 31 insertions(+), 21 deletions(-) diff --git a/packages/main/src/SegmentedButton.js b/packages/main/src/SegmentedButton.js index bd36db447acf..171d4e60d1af 100644 --- a/packages/main/src/SegmentedButton.js +++ b/packages/main/src/SegmentedButton.js @@ -1,6 +1,5 @@ import UI5Element from "@ui5/webcomponents-base/dist/UI5Element.js"; import ItemNavigation from "@ui5/webcomponents-base/dist/delegate/ItemNavigation.js"; -import NavigationMode from "@ui5/webcomponents-base/dist/types/NavigationMode.js"; import litRender from "@ui5/webcomponents-base/dist/renderer/LitRenderer.js"; import ResizeHandler from "@ui5/webcomponents-base/dist/delegate/ResizeHandler.js"; @@ -118,9 +117,7 @@ class SegmentedButton extends UI5Element { } initItemNavigation() { - this._itemNavigation = new ItemNavigation(this, { - navigationMode: NavigationMode.Horizontal, - }); + this._itemNavigation = new ItemNavigation(this); this._itemNavigation.getItemsCallback = () => this.getSlottedNodes("buttons"); } @@ -148,11 +145,13 @@ class SegmentedButton extends UI5Element { } this._selectedButton.pressed = true; + this._itemNavigation.update(this._selectedButton); + return this; } _handleResize() { - const documentWidth = document.body.clientWidth; + const parentWidth = this.parentNode.offsetWidth; if (!this.style.width || this.percentageWidthSet) { this.style.width = `${Math.max(...this.widths) * this.buttons.length}px`; @@ -163,7 +162,7 @@ class SegmentedButton extends UI5Element { button.style.width = "100%"; }); - if (documentWidth <= this.offsetWidth && this.absoluteWidthSet) { + if (parentWidth <= this.offsetWidth && this.absoluteWidthSet) { this.style.width = "100%"; this.percentageWidthSet = true; } diff --git a/packages/main/test/pages/SegmentedButton.html b/packages/main/test/pages/SegmentedButton.html index e71acdd81ed3..9a40bd8a9706 100644 --- a/packages/main/test/pages/SegmentedButton.html +++ b/packages/main/test/pages/SegmentedButton.html @@ -56,24 +56,35 @@

Example with 5 buttons

-

Example with Icons

+

Example with Icons and custom width

- - + +
-

Example with Icons

+

SegmentedButton with 100% width

- - - + Pressed ToggleButton + ToggleButton + ToggleButton
+ +
+

SegmentedButton wrapped in a container with set width

+
+ + + + + +
+
diff --git a/packages/main/test/samples/SegmentedButton.sample.html b/packages/main/test/samples/SegmentedButton.sample.html index e00f8f7cddea..69b0cb78ae4d 100644 --- a/packages/main/test/samples/SegmentedButton.sample.html +++ b/packages/main/test/samples/SegmentedButton.sample.html @@ -38,9 +38,9 @@

SegmentedButton with Icons


 <ui5-segmentedbutton>
-	<ui5-togglebutton icon="employee" pressed></ui5-togglebutton>
-	<ui5-togglebutton icon="menu"></ui5-togglebutton>
-	<ui5-togglebutton icon="factory"></ui5-togglebutton>
+    <ui5-togglebutton icon="employee" pressed></ui5-togglebutton>
+    <ui5-togglebutton icon="menu"></ui5-togglebutton>
+    <ui5-togglebutton icon="factory"></ui5-togglebutton>
 </ui5-segmentedbutton>
 	
@@ -58,11 +58,11 @@

SegmentedButton with 5 ToggleButtons


 <ui5-segmentedbutton>
-	<ui5-togglebutton>Button</ui5-togglebutton>
-	<ui5-togglebutton pressed>Pressed ToggleButton With Bigger Text</ui5-togglebutton pressed>
-	<ui5-togglebutton>Button</ui5-togglebutton>
-	<ui5-togglebutton>ToggleButton</ui5-togglebutton>
-	<ui5-togglebutton>Press me</ui5-togglebutton>
+    <ui5-togglebutton>Button</ui5-togglebutton>
+    <ui5-togglebutton pressed>Pressed ToggleButton With Bigger Text</ui5-togglebutton>
+    <ui5-togglebutton>Button</ui5-togglebutton>
+    <ui5-togglebutton>ToggleButton</ui5-togglebutton>
+    <ui5-togglebutton>Press me</ui5-togglebutton>
 </ui5-segmentedbutton>
 	
From 263f52657d45179bf253a40468185d5b9168936f Mon Sep 17 00:00:00 2001 From: Ivaylo Plashkov Date: Mon, 10 Feb 2020 14:40:12 +0200 Subject: [PATCH 12/12] fixed identation --- .../test/samples/SegmentedButton.sample.html | 6 +- .../main/test/specs/SegmentedButton.spec.js | 83 ++++++++----------- .../build-scripts/samples-prepare.js | 1 + 3 files changed, 39 insertions(+), 51 deletions(-) diff --git a/packages/main/test/samples/SegmentedButton.sample.html b/packages/main/test/samples/SegmentedButton.sample.html index 69b0cb78ae4d..ac0b0c012318 100644 --- a/packages/main/test/samples/SegmentedButton.sample.html +++ b/packages/main/test/samples/SegmentedButton.sample.html @@ -12,7 +12,7 @@

SegmentedButton

Basic SegmentedButton

- + Map Satellite Terrain @@ -49,8 +49,8 @@

SegmentedButton with Icons

SegmentedButton with 5 ToggleButtons

- Button - Pressed ToggleButton With Bigger Text + Button + Pressed ToggleButton With Bigger Text Button Pressed ToggleButton Press me diff --git a/packages/main/test/specs/SegmentedButton.spec.js b/packages/main/test/specs/SegmentedButton.spec.js index 2273ec4c68b8..385f5c992f94 100644 --- a/packages/main/test/specs/SegmentedButton.spec.js +++ b/packages/main/test/specs/SegmentedButton.spec.js @@ -1,48 +1,35 @@ -const assert = require("chai").assert; - -describe("SegmentedButton general interaction", () => { - browser.url("http://localhost:8080/test-resources/pages/SegmentedButton.html"); - - it("tests rendering of segmentedbutton", () => { - const segmentedButton = browser.$("#segButton1"); - const toggleButton1 = browser.$("#segButton1 > ui5-togglebutton:first-child"); - const toggleButton2 = browser.$("#segButton1 > ui5-togglebutton:nth-child(2)"); - const toggleButton3 = browser.$("#segButton1 > ui5-togglebutton:last-child"); - - // all buttons should be rendered - assert.ok(segmentedButton.isExisting(), "SegmentedButton is rendered"); - assert.ok(toggleButton1.isExisting(), "First ToggleButton is rendered"); - assert.ok(toggleButton2.isExisting(), "Second ToggleButton is rendered"); - assert.ok(toggleButton3.isExisting(), "Third ToggleButton is rendered"); - }); - - it("tests if pressed attribute is applied", () => { - const toggleButton = browser.$("#segButton1 > ui5-togglebutton:first-child"); - - assert.ok(toggleButton.getProperty("pressed"), "ToggleButton has property pressed"); - }); - - it("tests if pressed attribute is switched to the newly pressed button", () => { - const firstToggleButton = browser.$("#segButton1 > ui5-togglebutton:first-child"); - const lastToggleButton = browser.$("#segButton1 > ui5-togglebutton:last-child"); - - lastToggleButton.click(); - - assert.ok(lastToggleButton.getProperty("pressed"), "Last ToggleButton has property pressed"); - assert.ok(!firstToggleButton.getProperty("pressed"), "First ToggleButton should not be pressed anymore"); - }); - - it("tests if pressed attribute is applied only to last child when all buttons are pressed", () => { - const toggleButton1 = browser.$("#segButton2 > ui5-togglebutton:first-child"); - const toggleButton2 = browser.$("#segButton2 > ui5-togglebutton:nth-child(2)"); - const toggleButton3 = browser.$("#segButton2 > ui5-togglebutton:nth-child(3)"); - const toggleButton4 = browser.$("#segButton2 > ui5-togglebutton:last-child"); - - // only last button should be pressed - assert.ok(!toggleButton1.getProperty("pressed"), "ToggleButton should not be pressed"); - assert.ok(!toggleButton2.getProperty("pressed"), "ToggleButton should not be pressed"); - assert.ok(!toggleButton3.getProperty("pressed"), "ToggleButton should not be pressed"); - assert.ok(toggleButton4.getProperty("pressed"), "ToggleButton has property pressed"); - - }); -}); +const assert = require("chai").assert; + +describe("SegmentedButton general interaction", () => { + browser.url("http://localhost:8080/test-resources/pages/SegmentedButton.html"); + + it("tests if pressed attribute is applied", () => { + const toggleButton = browser.$("#segButton1 > ui5-togglebutton:first-child"); + + assert.ok(toggleButton.getProperty("pressed"), "ToggleButton has property pressed"); + }); + + it("tests if pressed attribute is switched to the newly pressed button", () => { + const firstToggleButton = browser.$("#segButton1 > ui5-togglebutton:first-child"); + const lastToggleButton = browser.$("#segButton1 > ui5-togglebutton:last-child"); + + lastToggleButton.click(); + + assert.ok(lastToggleButton.getProperty("pressed"), "Last ToggleButton has property pressed"); + assert.ok(!firstToggleButton.getProperty("pressed"), "First ToggleButton should not be pressed anymore"); + }); + + it("tests if pressed attribute is applied only to last child when all buttons are pressed", () => { + const toggleButton1 = browser.$("#segButton2 > ui5-togglebutton:first-child"); + const toggleButton2 = browser.$("#segButton2 > ui5-togglebutton:nth-child(2)"); + const toggleButton3 = browser.$("#segButton2 > ui5-togglebutton:nth-child(3)"); + const toggleButton4 = browser.$("#segButton2 > ui5-togglebutton:last-child"); + + // only last button should be pressed + assert.ok(!toggleButton1.getProperty("pressed"), "ToggleButton should not be pressed"); + assert.ok(!toggleButton2.getProperty("pressed"), "ToggleButton should not be pressed"); + assert.ok(!toggleButton3.getProperty("pressed"), "ToggleButton should not be pressed"); + assert.ok(toggleButton4.getProperty("pressed"), "ToggleButton has property pressed"); + + }); +}); diff --git a/packages/playground/build-scripts/samples-prepare.js b/packages/playground/build-scripts/samples-prepare.js index 2988a0e39ef9..e51095b13d2a 100644 --- a/packages/playground/build-scripts/samples-prepare.js +++ b/packages/playground/build-scripts/samples-prepare.js @@ -13,6 +13,7 @@ const components = []; // Add new components here const newComponents = [ "ComboBox", + "SegmentedButton", ]; packages.forEach(package => {