Skip to content

Commit 70d44b1

Browse files
nnaydenowvladitasev
authored andcommitted
feat(ui5-product-switch): initial implementation (#971)
1 parent 2148b94 commit 70d44b1

18 files changed

+807
-0
lines changed

packages/fiori/bundle.esm.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,5 +9,7 @@ import "./dist/json-imports/LocaleData.js" // same as above
99
import "./dist/features/CoPilotAnimation.js";
1010

1111
// FIORI components
12+
import ProductSwitch from "./dist/ProductSwitch.js";
13+
import ProductSwitchItem from "./dist/ProductSwitchItem.js";
1214
import ShellBar from "./dist/ShellBar.js";
1315
import ShellBarItem from "./dist/ShellBarItem.js";
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
<div class="ui5-product-switch-root" @focusin={{_onfocusin}}>
2+
<slot></slot>
3+
</div>
Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
1+
import UI5Element from "@ui5/webcomponents-base/dist/UI5Element.js";
2+
import ItemNavigation from "@ui5/webcomponents-base/dist/delegate/ItemNavigation.js";
3+
import ResizeHandler from "@ui5/webcomponents-base/dist/delegate/ResizeHandler.js";
4+
import Integer from "@ui5/webcomponents-base/dist/types/Integer.js";
5+
import litRender from "@ui5/webcomponents-base/dist/renderer/LitRenderer.js";
6+
import ProductSwitchTemplate from "./generated/templates/ProductSwitchTemplate.lit.js";
7+
8+
// Styles
9+
import ProductSwitchCss from "./generated/themes/ProductSwitch.css.js";
10+
11+
12+
const metadata = {
13+
tag: "ui5-product-switch",
14+
properties: {
15+
/**
16+
* Indicates how many columns are displayed.
17+
* @private
18+
*/
19+
desktopColumns: {
20+
type: Integer,
21+
},
22+
},
23+
slots: {
24+
/**
25+
* Defines the items of the <code>ui5-product-switch</code>.
26+
*
27+
* @type {HTMLElement[]}
28+
* @slot
29+
* @public
30+
*/
31+
"default": {
32+
propertyName: "items",
33+
type: HTMLElement,
34+
},
35+
},
36+
};
37+
38+
/**
39+
* @class
40+
* <h3 class="comment-api-title">Overview</h3>
41+
*
42+
* The <code>ui5-product-switch</code> is a Fiori specific web component that is used in <code>ui5-shellbar</code> and allows the user easy switching between products.
43+
* <br><br>
44+
* <h3>ES6 Module Import</h3>
45+
* <code>import "@ui5/webcomponents-fiori/dist/ProductSwitch.js";</code>
46+
*
47+
* @constructor
48+
* @author SAP SE
49+
* @alias sap.ui.webcomponents.fiori.ProductSwitch
50+
* @extends sap.ui.webcomponents.base.UI5Element
51+
* @tagname ui5-product-switch
52+
* @appenddocs ProductSwitchItem
53+
* @public
54+
* @since 1.0.0-rc.5
55+
*/
56+
class ProductSwitch extends UI5Element {
57+
constructor() {
58+
super();
59+
60+
this.initItemNavigation();
61+
}
62+
63+
initItemNavigation() {
64+
this._itemNavigation = new ItemNavigation(this, { rowSize: 4 });
65+
this._itemNavigation.getItemsCallback = () => this.items;
66+
}
67+
68+
static get metadata() {
69+
return metadata;
70+
}
71+
72+
static get render() {
73+
return litRender;
74+
}
75+
76+
static get styles() {
77+
return ProductSwitchCss;
78+
}
79+
80+
static get template() {
81+
return ProductSwitchTemplate;
82+
}
83+
84+
static get ROW_MIN_WIDTH() {
85+
return {
86+
ONE_COLUMN: 600,
87+
THREE_COLUMN: 900,
88+
};
89+
}
90+
91+
onEnterDOM() {
92+
this._handleResizeBound = this._handleResize.bind(this);
93+
94+
ResizeHandler.register(document.body, this._handleResizeBound);
95+
}
96+
97+
onExitDOM() {
98+
ResizeHandler.deregister(document.body, this._handleResizeBound);
99+
}
100+
101+
onBeforeRendering() {
102+
this.desktopColumns = this.items.length > 6 ? 4 : 3;
103+
}
104+
105+
_handleResize() {
106+
const documentWidth = document.body.clientWidth;
107+
108+
if (documentWidth <= this.constructor.ROW_MIN_WIDTH.ONE_COLUMN) {
109+
this._itemNavigation.rowSize = 1;
110+
} else if (documentWidth <= this.constructor.ROW_MIN_WIDTH.THREE_COLUMN || this.items.length <= 6) {
111+
this._itemNavigation.rowSize = 3;
112+
} else {
113+
this._itemNavigation.rowSize = 4;
114+
}
115+
}
116+
117+
_onfocusin(event) {
118+
const target = event.target;
119+
120+
this._itemNavigation.update(target);
121+
}
122+
}
123+
124+
ProductSwitch.define();
125+
126+
export default ProductSwitch;
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
{{#if targetSrc}}
2+
<a class="ui5-product-switch-item-root"
3+
data-sap-focus-ref
4+
@focusout="{{_onfocusout}}"
5+
@focusin="{{_onfocusin}}"
6+
@mousedown="{{_onmousedown}}"
7+
@keydown="{{_onkeydown}}"
8+
@keyup="{{_onkeyup}}"
9+
tabindex={{_tabIndex}}
10+
href="{{targetSrc}}"
11+
target="{{target}}">
12+
{{> item}}
13+
</a>
14+
{{else}}
15+
<div
16+
class="ui5-product-switch-item-root"
17+
data-sap-focus-ref
18+
@focusout="{{_onfocusout}}"
19+
@focusin="{{_onfocusin}}"
20+
@mousedown="{{_onmousedown}}"
21+
@keydown="{{_onkeydown}}"
22+
@keyup="{{_onkeyup}}"
23+
tabindex={{_tabIndex}}>
24+
{{> item}}
25+
</div>
26+
{{/if}}
27+
28+
{{#*inline "item"}}
29+
{{#if icon}}
30+
<ui5-icon
31+
class="ui5-product-switch-item-icon"
32+
name="{{icon}}"
33+
></ui5-icon>
34+
{{/if}}
35+
<span class="ui5-product-switch-item-text-content">
36+
{{#if heading}}
37+
<span class="ui5-product-switch-item-heading">{{heading}}</span>
38+
{{/if}}
39+
{{#if subtitle}}
40+
<span class="ui5-product-switch-item-subtitle">{{subtitle}}</span>
41+
{{/if}}
42+
</span>
43+
{{/inline}}
Lines changed: 201 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,201 @@
1+
import UI5Element from "@ui5/webcomponents-base/dist/UI5Element.js";
2+
import litRender from "@ui5/webcomponents-base/dist/renderer/LitRenderer.js";
3+
import { isSpace, isEnter } from "@ui5/webcomponents-base/dist/events/PseudoEvents.js";
4+
import ProductSwitchItemTemplate from "./generated/templates/ProductSwitchItemTemplate.lit.js";
5+
6+
// Styles
7+
import ProductSwitchItemCss from "./generated/themes/ProductSwitchItem.css.js";
8+
9+
10+
const metadata = {
11+
tag: "ui5-product-switch-item",
12+
properties: {
13+
/**
14+
* Defines the title of the <code>ui5-product-switch-item</code>.
15+
* @type {string}
16+
* @defaultvalue ""
17+
* @public
18+
*/
19+
heading: {
20+
type: String,
21+
},
22+
/**
23+
* Defines the subtitle of the <code>ui5-product-switch-item</code>.
24+
* @type {string}
25+
* @defaultvalue ""
26+
* @public
27+
*/
28+
subtitle: {
29+
type: String,
30+
},
31+
/**
32+
* Defines the icon to be displayed as a graphical element within the <code>ui5-product-switch-item</code>.
33+
* <br><br>
34+
* Example:
35+
* <br>
36+
* <pre>ui5-product-switch-item icon="palette"</pre>
37+
*
38+
* See all the available icons in the <ui5-link target="_blank" href="https://openui5.hana.ondemand.com/test-resources/sap/m/demokit/iconExplorer/webapp/index.html" class="api-table-content-cell-link">Icon Explorer</ui5-link>.
39+
*
40+
* @type {string}
41+
* @defaultvalue ""
42+
* @public
43+
*/
44+
icon: {
45+
type: String,
46+
},
47+
/**
48+
* Specifies a target where the <code>targetSrc</code> content must be open.
49+
* Options are the standard values for window.open() supported by browsers: _self, _top, _blank, _parent, _search. Alternatively, a frame name can be entered.
50+
* @type {string}
51+
* @defaultvalue "_self"
52+
* @public
53+
*/
54+
target: {
55+
type: String,
56+
defaultValue: "_self",
57+
},
58+
/**
59+
* Defines the <code>ui5-product-switch-item</code> target URI. Supports standard hyperlink behavior.
60+
* @type {string}
61+
* @defaultvalue ""
62+
* @public
63+
*/
64+
targetSrc: {
65+
type: String,
66+
},
67+
/**
68+
* Used to switch the active state (pressed or not) of the <code>ui5-product-switch-item</code>.
69+
* @private
70+
*/
71+
active: {
72+
type: Boolean,
73+
},
74+
/**
75+
* Indicates whether the element is focused.
76+
* @private
77+
*/
78+
focused: {
79+
type: Boolean,
80+
},
81+
_tabIndex: {
82+
type: String,
83+
defaultValue: "-1",
84+
noAttribute: true,
85+
},
86+
},
87+
slots: {
88+
//
89+
},
90+
events: {
91+
/**
92+
* Fired when the <code>ui5-product-switch-item</code> is activated either with a
93+
* click/tap or by using the Enter or Space key.
94+
*
95+
* @event
96+
* @public
97+
*/
98+
click: {},
99+
_focused: {},
100+
},
101+
};
102+
103+
/**
104+
* @class
105+
* <h3 class="comment-api-title">Overview</h3>
106+
* The <code>ui5-product-switch-item</code> represents the items displayed in the <code>ui5-product-switch</code> web component
107+
* <b>Note:</b> <code>ui5-product-switch-item</code> is not supported when used outside of <code>ui5-product-switch</code>.
108+
* <br><br>
109+
* <h3>ES6 Module Import</h3>
110+
* <code>import "@ui5/webcomponents-fiori/dist/ProductSwitchItem.js";</code>
111+
*
112+
* @constructor
113+
* @author SAP SE
114+
* @alias sap.ui.webcomponents.fiori.ProductSwitchItem
115+
* @extends sap.ui.webcomponents.base.UI5Element
116+
* @tagname ui5-product-switch-item
117+
* @public
118+
* @since 1.0.0-rc.5
119+
*/
120+
class ProductSwitchItem extends UI5Element {
121+
constructor() {
122+
super();
123+
124+
this._deactivate = () => {
125+
if (this.active) {
126+
this.active = false;
127+
}
128+
};
129+
}
130+
131+
static get metadata() {
132+
return metadata;
133+
}
134+
135+
static get render() {
136+
return litRender;
137+
}
138+
139+
static get styles() {
140+
return ProductSwitchItemCss;
141+
}
142+
143+
static get template() {
144+
return ProductSwitchItemTemplate;
145+
}
146+
147+
onEnterDOM() {
148+
document.addEventListener("mouseup", this._deactivate);
149+
}
150+
151+
onExitDOM() {
152+
document.removeEventListener("mouseup", this._deactivate);
153+
}
154+
155+
_onmousedown() {
156+
this.active = true;
157+
}
158+
159+
_onkeydown(event) {
160+
if (isSpace(event) || isEnter(event)) {
161+
this.active = true;
162+
}
163+
164+
if (isSpace(event)) {
165+
event.preventDefault();
166+
}
167+
168+
if (isEnter(event)) {
169+
this._fireItemClick();
170+
}
171+
}
172+
173+
_onkeyup(event) {
174+
if (isSpace(event) || isEnter(event)) {
175+
this.active = false;
176+
}
177+
178+
if (isSpace(event)) {
179+
this._fireItemClick();
180+
}
181+
}
182+
183+
_onfocusout() {
184+
this.active = false;
185+
this.focused = false;
186+
}
187+
188+
_onfocusin(event) {
189+
this.focused = true;
190+
191+
this.fireEvent("_focused", event);
192+
}
193+
194+
_fireItemClick() {
195+
this.fireEvent("click", { item: this });
196+
}
197+
}
198+
199+
ProductSwitchItem.define();
200+
201+
export default ProductSwitchItem;

0 commit comments

Comments
 (0)