Skip to content

Commit 931fbe0

Browse files
authored
feat(ui5-segmentedbutton): initial implementation (#1164)
1 parent 323968e commit 931fbe0

File tree

11 files changed

+453
-6
lines changed

11 files changed

+453
-6
lines changed

packages/main/bundle.esm.js

+1
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ import Popover from "./dist/Popover.js";
3131
import Panel from "./dist/Panel.js";
3232
import RadioButton from "./dist/RadioButton.js";
3333
import ResponsivePopover from "./dist/ResponsivePopover.js";
34+
import SegmentedButton from "./dist/SegmentedButton.js";
3435
import Select from "./dist/Select.js";
3536
import Option from "./dist/Option.js";
3637
import Switch from "./dist/Switch.js";

packages/main/src/Button.js

+17-1
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,16 @@ const metadata = {
136136
_iconSettings: {
137137
type: Object,
138138
},
139+
140+
/**
141+
* Defines the tabIndex of the component.
142+
* @private
143+
*/
144+
_tabIndex: {
145+
type: String,
146+
defaultValue: "0",
147+
noAttribute: true,
148+
},
139149
},
140150
slots: /** @lends sap.ui.webcomponents.main.Button.prototype */ {
141151
/**
@@ -314,7 +324,13 @@ class Button extends UI5Element {
314324
}
315325

316326
get tabIndexValue() {
317-
return this.nonFocusable ? "-1" : "0";
327+
const tabindex = this.getAttribute("tabindex");
328+
329+
if (tabindex) {
330+
return tabindex;
331+
}
332+
333+
return this.nonFocusable ? "-1" : this._tabIndex;
318334
}
319335

320336
static async define(...params) {

packages/main/src/SegmentedButton.hbs

+6
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
<div
2+
@click="{{_onclick}}"
3+
class="ui5-segmentedbutton-root"
4+
>
5+
<slot></slot>
6+
</div>

packages/main/src/SegmentedButton.js

+185
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,185 @@
1+
import UI5Element from "@ui5/webcomponents-base/dist/UI5Element.js";
2+
import ItemNavigation from "@ui5/webcomponents-base/dist/delegate/ItemNavigation.js";
3+
import litRender from "@ui5/webcomponents-base/dist/renderer/LitRenderer.js";
4+
import ResizeHandler from "@ui5/webcomponents-base/dist/delegate/ResizeHandler.js";
5+
6+
// Template
7+
import SegmentedButtonTemplate from "./generated/templates/SegmentedButtonTemplate.lit.js";
8+
9+
// Styles
10+
import SegmentedButtonCss from "./generated/themes/SegmentedButton.css.js";
11+
12+
/**
13+
* @public
14+
*/
15+
const metadata = {
16+
tag: "ui5-segmentedbutton",
17+
properties: /** @lends sap.ui.webcomponents.main.SegmentedButton.prototype */ {},
18+
slots: /** @lends sap.ui.webcomponents.main.SegmentedButton.prototype */ {
19+
20+
/**
21+
* Defines the buttons of <code>ui5-segmentedbutton</code>.
22+
* <br><br>
23+
* <b>Note:</b> Multiple buttons are allowed.
24+
* <br><br>
25+
* <b>Note:</b> Use the <code>ui5-togglebutton</code> for the intended design.
26+
* @type {HTMLElement[]}
27+
* @slot
28+
* @public
29+
*/
30+
"default": {
31+
propertyName: "buttons",
32+
type: HTMLElement,
33+
},
34+
},
35+
events: /** @lends sap.ui.webcomponents.main.SegmentedButton.prototype */ {
36+
37+
/**
38+
* Fired when the selected button changes.
39+
*
40+
* @event
41+
* @param {HTMLElement} selectedButton the pressed button.
42+
* @public
43+
*/
44+
selectionChange: {
45+
detail: {
46+
selectedButton: { type: HTMLElement },
47+
},
48+
},
49+
},
50+
};
51+
52+
/**
53+
* @class
54+
*
55+
* <h3 class="comment-api-title">Overview</h3>
56+
*
57+
* The <code>SegmentedButton</code> shows a group of buttons. When the user clicks or taps
58+
* one of the buttons, it stays in a pressed state. It automatically resizes the buttons
59+
* to fit proportionally within the component. When no width is set, the component uses the available width.
60+
* <br><br>
61+
* <b>Note:</b> There can be just one selected <code>button</code> at a time.
62+
*
63+
* <h3>ES6 Module Import</h3>
64+
*
65+
* <code>import "@ui5/webcomponents/dist/SegmentedButton";</code>
66+
*
67+
* @constructor
68+
* @author SAP SE
69+
* @alias sap.ui.webcomponents.main.SegmentedButton
70+
* @extends sap.ui.webcomponents.base.UI5Element
71+
* @tagname ui5-segmentedbutton
72+
* @since 1.0.0-rc.6
73+
* @public
74+
*/
75+
class SegmentedButton extends UI5Element {
76+
static get metadata() {
77+
return metadata;
78+
}
79+
80+
static get render() {
81+
return litRender;
82+
}
83+
84+
static get template() {
85+
return SegmentedButtonTemplate;
86+
}
87+
88+
static get styles() {
89+
return SegmentedButtonCss;
90+
}
91+
92+
constructor() {
93+
super();
94+
this.initItemNavigation();
95+
96+
this.absoluteWidthSet = false; // set to true whenever we set absolute width to the component
97+
this.percentageWidthSet = false; // set to true whenever we set 100% width to the component
98+
}
99+
100+
onEnterDOM() {
101+
this._handleResizeBound = this._handleResize.bind(this);
102+
103+
ResizeHandler.register(document.body, this._handleResizeBound);
104+
}
105+
106+
onExitDOM() {
107+
ResizeHandler.deregister(document.body, this._handleResizeBound);
108+
}
109+
110+
onBeforeRendering() {
111+
this.normalizeSelection();
112+
}
113+
114+
async onAfterRendering() {
115+
await Promise.all(this.buttons.map(button => button._waitForDomRef));
116+
this.widths = this.buttons.map(button => button.offsetWidth);
117+
}
118+
119+
initItemNavigation() {
120+
this._itemNavigation = new ItemNavigation(this);
121+
122+
this._itemNavigation.getItemsCallback = () => this.getSlottedNodes("buttons");
123+
}
124+
125+
normalizeSelection() {
126+
this._selectedButton = this.buttons.filter(button => button.pressed).pop();
127+
128+
if (this._selectedButton) {
129+
this.buttons.forEach(button => {
130+
button.pressed = false;
131+
});
132+
this._selectedButton.pressed = true;
133+
}
134+
}
135+
136+
_onclick(event) {
137+
if (event.target !== this._selectedButton) {
138+
if (this._selectedButton) {
139+
this._selectedButton.pressed = false;
140+
}
141+
this._selectedButton = event.target;
142+
this.fireEvent("selectionChange", {
143+
selectedButton: this._selectedButton,
144+
});
145+
}
146+
this._selectedButton.pressed = true;
147+
148+
this._itemNavigation.update(this._selectedButton);
149+
150+
return this;
151+
}
152+
153+
_handleResize() {
154+
const parentWidth = this.parentNode.offsetWidth;
155+
156+
if (!this.style.width || this.percentageWidthSet) {
157+
this.style.width = `${Math.max(...this.widths) * this.buttons.length}px`;
158+
this.absoluteWidthSet = true;
159+
}
160+
161+
this.buttons.forEach(button => {
162+
button.style.width = "100%";
163+
});
164+
165+
if (parentWidth <= this.offsetWidth && this.absoluteWidthSet) {
166+
this.style.width = "100%";
167+
this.percentageWidthSet = true;
168+
}
169+
}
170+
171+
/**
172+
* Currently selected button.
173+
*
174+
* @readonly
175+
* @type { ui5-togglebutton }
176+
* @public
177+
*/
178+
get selectedButton() {
179+
return this._selectedButton;
180+
}
181+
}
182+
183+
SegmentedButton.define();
184+
185+
export default SegmentedButton;

packages/main/src/Select.js

+2-2
Original file line numberDiff line numberDiff line change
@@ -127,10 +127,10 @@ const metadata = {
127127
},
128128
events: /** @lends sap.ui.webcomponents.main.Select.prototype */ {
129129
/**
130-
* Fired when the selected item changes.
130+
* Fired when the selected option changes.
131131
*
132132
* @event
133-
* @param {HTMLElement} item the selected item.
133+
* @param {HTMLElement} selectedOption the selected option.
134134
* @public
135135
*/
136136
change: {

packages/main/src/themes/Button.css

+10-3
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,9 @@
5050
color: inherit;
5151
text-shadow: inherit;
5252
font: inherit;
53+
white-space: inherit;
54+
overflow: inherit;
55+
text-overflow: inherit;
5356
}
5457

5558
:host(:not([active]):hover) {
@@ -83,6 +86,9 @@
8386
.ui5-button-text {
8487
outline: none;
8588
position: relative;
89+
white-space: inherit;
90+
overflow: inherit;
91+
text-overflow: inherit;
8692
}
8793

8894
:host([has-icon]) .ui5-button-text {
@@ -104,9 +110,10 @@
104110
}
105111

106112
bdi {
107-
display: flex;
108-
justify-content: flex-start;
109-
align-items: center;
113+
display: block;
114+
white-space: inherit;
115+
overflow: inherit;
116+
text-overflow: inherit;
110117
}
111118

112119
:host([active]:not([disabled])) {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
:host(:not([hidden])) {
2+
display: inline-block;
3+
}
4+
5+
.ui5-segmentedbutton-root {
6+
display: flex;
7+
}
8+
9+
::slotted(ui5-togglebutton) {
10+
border-radius: 0;
11+
height: 2.75rem;
12+
min-width: 2.5rem;
13+
white-space: nowrap;
14+
overflow: hidden;
15+
text-overflow: ellipsis;
16+
}
17+
18+
::slotted(ui5-togglebutton:nth-child(odd)) {
19+
border: 1px solid var(--sapButton_Selected_BorderColor);
20+
border-right: 0;
21+
border-left: 0;
22+
}
23+
24+
::slotted(ui5-togglebutton:last-child) {
25+
border-top-right-radius: 0.375rem;
26+
border-bottom-right-radius: 0.375rem;
27+
border-right: 1px solid var(--sapButton_Selected_BorderColor);
28+
}
29+
30+
::slotted(ui5-togglebutton:first-child) {
31+
border-top-left-radius: 0.375rem;
32+
border-bottom-left-radius: 0.375rem;
33+
border-left: 1px solid var(--sapButton_Selected_BorderColor);
34+
}

0 commit comments

Comments
 (0)