@sapudex/web-components 2.25.1 → 2.27.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/cypress/fixtures/profile-menu.ts +2 -1
- package/cypress/specs/MastheadProfileMenu.cy.tsx +21 -6
- package/cypress/specs/TabNavigation.cy.tsx +1024 -0
- package/cypress/support/component-imports.src.ts +4 -0
- package/dist/List.d.ts +9 -0
- package/dist/List.js +33 -2
- package/dist/List.js.map +1 -1
- package/dist/MastheadCountrySelector.d.ts +11 -0
- package/dist/MastheadCountrySelector.js +71 -14
- package/dist/MastheadCountrySelector.js.map +1 -1
- package/dist/MastheadItem.d.ts +1 -0
- package/dist/MastheadItem.js +9 -1
- package/dist/MastheadItem.js.map +1 -1
- package/dist/MastheadMenu.d.ts +11 -0
- package/dist/MastheadMenu.js +43 -13
- package/dist/MastheadMenu.js.map +1 -1
- package/dist/MastheadProfileMenu.d.ts +33 -3
- package/dist/MastheadProfileMenu.js +93 -5
- package/dist/MastheadProfileMenu.js.map +1 -1
- package/dist/Pagination.d.ts +2 -0
- package/dist/Pagination.js +31 -6
- package/dist/Pagination.js.map +1 -1
- package/dist/PaginationTemplate.js +6 -5
- package/dist/PaginationTemplate.js.map +1 -1
- package/dist/Tab.d.ts +57 -0
- package/dist/Tab.js +67 -0
- package/dist/Tab.js.map +1 -1
- package/dist/TabNavigation.d.ts +25 -3
- package/dist/TabNavigation.js +96 -18
- package/dist/TabNavigation.js.map +1 -1
- package/dist/Tooltip.js +3 -5
- package/dist/Tooltip.js.map +1 -1
- package/dist/TooltipTemplate.d.ts +2 -0
- package/dist/TooltipTemplate.js +7 -0
- package/dist/TooltipTemplate.js.map +1 -0
- package/dist/assets/{InputSuggestions-CTFZ6hH-.js → InputSuggestions-Bm_0fOBQ.js} +1 -1
- package/dist/assets/{ListItemStandardExpandableTextTemplate-wXdCijez.js → ListItemStandardExpandableTextTemplate-CHXlUP-E.js} +1 -1
- package/dist/assets/{bundle.esm-BXCZ9BP3.js → bundle.esm-D_SXCGNu.js} +219 -219
- package/dist/css/themes/MastheadCountrySelector.css +1 -1
- package/dist/css/themes/MastheadItem.css +1 -1
- package/dist/css/themes/MastheadMenu.css +1 -1
- package/dist/css/themes/MastheadMenuItem.css +1 -1
- package/dist/css/themes/MastheadProfileMenu.css +1 -1
- package/dist/css/themes/Quote.css +1 -1
- package/dist/css/themes/RatingIndicator.css +1 -1
- package/dist/css/themes/Slider.css +1 -1
- package/dist/css/themes/TabNavigation.css +1 -1
- package/dist/custom-elements-internal.json +60 -1
- package/dist/custom-elements.json +52 -1
- package/dist/generated/templates/MastheadCountrySelectorTemplate.lit.js +1 -1
- package/dist/generated/templates/MastheadCountrySelectorTemplate.lit.js.map +1 -1
- package/dist/generated/templates/MastheadProfileMenuTemplate.lit.js +7 -5
- package/dist/generated/templates/MastheadProfileMenuTemplate.lit.js.map +1 -1
- package/dist/generated/templates/TabHeaderTemplate.lit.js +30 -11
- package/dist/generated/templates/TabHeaderTemplate.lit.js.map +1 -1
- package/dist/generated/templates/TabNavigationTemplate.lit.js +8 -6
- package/dist/generated/templates/TabNavigationTemplate.lit.js.map +1 -1
- package/dist/generated/themes/MastheadCountrySelector.css.d.ts +1 -1
- package/dist/generated/themes/MastheadCountrySelector.css.js +1 -1
- package/dist/generated/themes/MastheadCountrySelector.css.js.map +1 -1
- package/dist/generated/themes/MastheadItem.css.d.ts +1 -1
- package/dist/generated/themes/MastheadItem.css.js +1 -1
- package/dist/generated/themes/MastheadItem.css.js.map +1 -1
- package/dist/generated/themes/MastheadMenu.css.d.ts +1 -1
- package/dist/generated/themes/MastheadMenu.css.js +1 -1
- package/dist/generated/themes/MastheadMenu.css.js.map +1 -1
- package/dist/generated/themes/MastheadMenuItem.css.d.ts +1 -1
- package/dist/generated/themes/MastheadMenuItem.css.js +1 -1
- package/dist/generated/themes/MastheadMenuItem.css.js.map +1 -1
- package/dist/generated/themes/MastheadProfileMenu.css.d.ts +1 -1
- package/dist/generated/themes/MastheadProfileMenu.css.js +1 -1
- package/dist/generated/themes/MastheadProfileMenu.css.js.map +1 -1
- package/dist/generated/themes/Quote.css.d.ts +1 -1
- package/dist/generated/themes/Quote.css.js +1 -1
- package/dist/generated/themes/Quote.css.js.map +1 -1
- package/dist/generated/themes/RatingIndicator.css.d.ts +1 -1
- package/dist/generated/themes/RatingIndicator.css.js +1 -1
- package/dist/generated/themes/RatingIndicator.css.js.map +1 -1
- package/dist/generated/themes/Slider.css.d.ts +1 -1
- package/dist/generated/themes/Slider.css.js +1 -1
- package/dist/generated/themes/Slider.css.js.map +1 -1
- package/dist/generated/themes/TabNavigation.css.d.ts +1 -1
- package/dist/generated/themes/TabNavigation.css.js +1 -1
- package/dist/generated/themes/TabNavigation.css.js.map +1 -1
- package/dist/types/List.d.ts +6 -0
- package/dist/types/List.js +7 -0
- package/dist/types/List.js.map +1 -1
- package/dist/vscode.html-custom-data.json +12 -2
- package/dist/web-types.json +32 -7
- package/package.json +1 -1
- package/src/List.ts +41 -2
- package/src/MastheadCountrySelector.hbs +20 -16
- package/src/MastheadCountrySelector.ts +83 -16
- package/src/MastheadItem.ts +10 -1
- package/src/MastheadMenu.ts +56 -13
- package/src/MastheadProfileMenu.hbs +43 -26
- package/src/MastheadProfileMenu.ts +124 -7
- package/src/Pagination.ts +32 -6
- package/src/PaginationTemplate.tsx +19 -16
- package/src/Tab.ts +98 -0
- package/src/TabHeader.hbs +85 -33
- package/src/TabNavigation.hbs +16 -0
- package/src/TabNavigation.ts +109 -21
- package/src/Tooltip.ts +7 -6
- package/src/TooltipTemplate.tsx +29 -0
- package/src/generated/templates/MastheadCountrySelectorTemplate.lit.ts +1 -1
- package/src/generated/templates/MastheadProfileMenuTemplate.lit.ts +7 -5
- package/src/generated/templates/TabHeaderTemplate.lit.ts +29 -10
- package/src/generated/templates/TabNavigationTemplate.lit.ts +8 -6
- package/src/generated/themes/MastheadCountrySelector.css.ts +1 -1
- package/src/generated/themes/MastheadItem.css.ts +1 -1
- package/src/generated/themes/MastheadMenu.css.ts +1 -1
- package/src/generated/themes/MastheadMenuItem.css.ts +1 -1
- package/src/generated/themes/MastheadProfileMenu.css.ts +1 -1
- package/src/generated/themes/Quote.css.ts +1 -1
- package/src/generated/themes/RatingIndicator.css.ts +1 -1
- package/src/generated/themes/Slider.css.ts +1 -1
- package/src/generated/themes/TabNavigation.css.ts +1 -1
- package/src/themes/MastheadCountrySelector.css +70 -10
- package/src/themes/MastheadItem.css +0 -1
- package/src/themes/MastheadMenu.css +1 -2
- package/src/themes/MastheadMenuItem.css +1 -0
- package/src/themes/MastheadProfileMenu.css +113 -17
- package/src/themes/Quote.css +1 -1
- package/src/themes/TabNavigation.css +203 -1
- package/src/types/List.ts +7 -0
- package/cypress/downloads/downloads.html +0 -0
- package/dist/generated/templates/TooltipTemplate.lit.d.ts +0 -3
- package/dist/generated/templates/TooltipTemplate.lit.js +0 -8
- package/dist/generated/templates/TooltipTemplate.lit.js.map +0 -1
- package/src/Tooltip.hbs +0 -22
- package/src/generated/templates/TooltipTemplate.lit.ts +0 -12
|
@@ -5,6 +5,7 @@ import slot from "@ui5/webcomponents-base/dist/decorators/slot.js";
|
|
|
5
5
|
import event from "@ui5/webcomponents-base/dist/decorators/event-strict.js";
|
|
6
6
|
import litRender from "@ui5/webcomponents-base/dist/renderer/LitRenderer.js";
|
|
7
7
|
import i18n from "@ui5/webcomponents-base/dist/decorators/i18n.js";
|
|
8
|
+
import { isDesktop } from "@ui5/webcomponents-base/dist/Device.js";
|
|
8
9
|
import type I18nBundle from "@ui5/webcomponents-base/dist/i18nBundle.js";
|
|
9
10
|
import {
|
|
10
11
|
LOGOUT, SWITCH_ACCOUNT, BACK, OTHER_IDENTITIES, ADD_OR_REMOVE_ACCOUNT,
|
|
@@ -13,6 +14,7 @@ import { isEscape } from "@ui5/webcomponents-base/Keys.js";
|
|
|
13
14
|
import UDExMastheadMenu from "./MastheadMenu.js";
|
|
14
15
|
import UDExButton from "./Button.js";
|
|
15
16
|
import UDExList from "./List.js";
|
|
17
|
+
import UDExLink from "./Link.js";
|
|
16
18
|
import UDExListItem from "./ListItem.js";
|
|
17
19
|
import UDExMastheadMenuItem from "./MastheadMenuItem.js";
|
|
18
20
|
import MastheadProfileMenuTemplate from "./generated/templates/MastheadProfileMenuTemplate.lit.js";
|
|
@@ -37,6 +39,7 @@ export interface UserData {
|
|
|
37
39
|
email?: string,
|
|
38
40
|
avatarUrl?: string,
|
|
39
41
|
avatarInitials?: string
|
|
42
|
+
fallbackIcon?: string,
|
|
40
43
|
}
|
|
41
44
|
|
|
42
45
|
export interface UserIdentity {
|
|
@@ -96,6 +99,7 @@ type UDExMastheadProfileMenuAddOrRemoveClickEventDetail = {
|
|
|
96
99
|
UDExListItem,
|
|
97
100
|
UDExButton,
|
|
98
101
|
UDExList,
|
|
102
|
+
UDExLink,
|
|
99
103
|
],
|
|
100
104
|
})
|
|
101
105
|
|
|
@@ -198,13 +202,29 @@ class UDExMastheadProfileMenu extends UI5Element {
|
|
|
198
202
|
_openIdentities: boolean = false;
|
|
199
203
|
|
|
200
204
|
/**
|
|
201
|
-
*
|
|
205
|
+
* Defines the request render state
|
|
206
|
+
*
|
|
207
|
+
* @private
|
|
208
|
+
*/
|
|
209
|
+
@property({ type: Boolean, noAttribute: true })
|
|
210
|
+
_requestRender = false;
|
|
211
|
+
|
|
212
|
+
/**
|
|
213
|
+
* Slot for message strip.
|
|
202
214
|
*
|
|
203
215
|
* @public
|
|
204
216
|
*/
|
|
205
217
|
@slot({ type: Node, "default": false })
|
|
206
218
|
message!: Array<Node>;
|
|
207
219
|
|
|
220
|
+
/**
|
|
221
|
+
* Slot for logout button.
|
|
222
|
+
*
|
|
223
|
+
* @public
|
|
224
|
+
*/
|
|
225
|
+
@slot({ type: HTMLElement })
|
|
226
|
+
logoutButton!: Array<Node>;
|
|
227
|
+
|
|
208
228
|
@i18n("@sapudex/web-components")
|
|
209
229
|
static i18nBundle: I18nBundle;
|
|
210
230
|
|
|
@@ -212,6 +232,8 @@ class UDExMastheadProfileMenu extends UI5Element {
|
|
|
212
232
|
_handleResizeBound: ResizeObserverCallback;
|
|
213
233
|
_shouldFocusBackBtn!: boolean;
|
|
214
234
|
_shouldFocusSwitchBtn!: boolean;
|
|
235
|
+
_identitiesListClassName = "udex-masthead-profile-menu__identities-list";
|
|
236
|
+
_profileMenuLinksClassName = "udex-masthead-profile-menu__links";
|
|
215
237
|
|
|
216
238
|
constructor() {
|
|
217
239
|
super();
|
|
@@ -223,10 +245,14 @@ class UDExMastheadProfileMenu extends UI5Element {
|
|
|
223
245
|
this.updateFocusState(this._shouldFocusBackBtn, this.focusBackBtn.bind(this));
|
|
224
246
|
this.updateFocusState(this._shouldFocusSwitchBtn, this.focusSwitchBtn.bind(this));
|
|
225
247
|
this.setMenuItemsMobileMode();
|
|
248
|
+
this.checkScrollableElements();
|
|
226
249
|
}
|
|
227
250
|
|
|
228
251
|
onEnterDOM(): void {
|
|
229
252
|
ResizeHandler.register(this, this._handleResizeBound);
|
|
253
|
+
if (isDesktop()) {
|
|
254
|
+
this.setAttribute("desktop", "");
|
|
255
|
+
}
|
|
230
256
|
}
|
|
231
257
|
|
|
232
258
|
onExitDOM(): void {
|
|
@@ -239,6 +265,8 @@ class UDExMastheadProfileMenu extends UI5Element {
|
|
|
239
265
|
if (this.profileMenuLinks) {
|
|
240
266
|
this.profileMenuLinks._isMobileMode = this.isMobile;
|
|
241
267
|
}
|
|
268
|
+
|
|
269
|
+
this.checkScrollableElements();
|
|
242
270
|
}
|
|
243
271
|
|
|
244
272
|
handleSwitcherClick(): void {
|
|
@@ -247,8 +275,8 @@ class UDExMastheadProfileMenu extends UI5Element {
|
|
|
247
275
|
this._shouldFocusSwitchBtn = !this._openIdentities;
|
|
248
276
|
}
|
|
249
277
|
|
|
250
|
-
|
|
251
|
-
this.
|
|
278
|
+
handleUserLogoutClick(e: PointerEvent): void {
|
|
279
|
+
this.fireLogoutClick(e);
|
|
252
280
|
if (this._isMobileMode) {
|
|
253
281
|
this.closeMenu();
|
|
254
282
|
}
|
|
@@ -318,15 +346,18 @@ class UDExMastheadProfileMenu extends UI5Element {
|
|
|
318
346
|
}
|
|
319
347
|
}
|
|
320
348
|
|
|
321
|
-
|
|
349
|
+
fireLogoutClick(e: PointerEvent): void {
|
|
322
350
|
const item = e.target as UDExMastheadMenuItem;
|
|
323
|
-
|
|
324
|
-
this.fireDecoratorEvent("logout", {
|
|
351
|
+
const executeEvent = this.fireDecoratorEvent("logout", {
|
|
325
352
|
item,
|
|
326
|
-
sourceNode: item.shadowRoot?.querySelector("
|
|
353
|
+
sourceNode: item.shadowRoot?.querySelector("a") as HTMLElement,
|
|
327
354
|
originalEvent: e,
|
|
328
355
|
analyticsName: AnalyticsName.Header,
|
|
329
356
|
});
|
|
357
|
+
|
|
358
|
+
if (!executeEvent) {
|
|
359
|
+
e.preventDefault();
|
|
360
|
+
}
|
|
330
361
|
}
|
|
331
362
|
|
|
332
363
|
fireMenuItemClick(e: CustomEvent): void {
|
|
@@ -340,6 +371,84 @@ class UDExMastheadProfileMenu extends UI5Element {
|
|
|
340
371
|
});
|
|
341
372
|
}
|
|
342
373
|
|
|
374
|
+
checkScrollableElements(): void {
|
|
375
|
+
if (this._openIdentities) {
|
|
376
|
+
this.checkScrollableElement(this.identitiesHTMLElement, this._identitiesListClassName);
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
if (this.isMobile) {
|
|
380
|
+
this.checkScrollableElement(this.profileMenuHTMLElement, this._profileMenuLinksClassName);
|
|
381
|
+
}
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
checkScrollableElement(element: HTMLElement, className: string): void {
|
|
385
|
+
if (element) {
|
|
386
|
+
requestAnimationFrame(() => {
|
|
387
|
+
if (this.isScrollableElement(element)) {
|
|
388
|
+
element.classList.add(`${className}_scrollable`);
|
|
389
|
+
}
|
|
390
|
+
});
|
|
391
|
+
}
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
scrollToTopProfileMenu(): void {
|
|
395
|
+
setTimeout(() => {
|
|
396
|
+
this.profileMenuHTMLElement.scrollTop = 0;
|
|
397
|
+
}, 0);
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
isScrollableElement(element: HTMLElement): boolean {
|
|
401
|
+
return element.scrollHeight > element.clientHeight;
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
handleProfileMenuShadowVisible(): void {
|
|
405
|
+
this.toggleScrollableClass(
|
|
406
|
+
this.profileMenuHTMLElement,
|
|
407
|
+
this._profileMenuLinksClassName,
|
|
408
|
+
this.scrollBottomProfileMenu,
|
|
409
|
+
);
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
handleIdentitiesListShadowVisible(): void {
|
|
413
|
+
this.toggleScrollableClass(
|
|
414
|
+
this.identitiesHTMLElement,
|
|
415
|
+
this._identitiesListClassName,
|
|
416
|
+
this.scrollBottomIdentitiesList,
|
|
417
|
+
);
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
toggleScrollableClass(el: HTMLElement, className: string, scrollBottom: number): void {
|
|
421
|
+
if (scrollBottom === 0) {
|
|
422
|
+
el.classList.remove(`${className}_scrollable`);
|
|
423
|
+
} else {
|
|
424
|
+
el.classList.add(`${className}_scrollable`);
|
|
425
|
+
}
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
get scrollBottomIdentitiesList(): number {
|
|
429
|
+
return this.calculateScrollBottom(this.identitiesHTMLElement);
|
|
430
|
+
}
|
|
431
|
+
|
|
432
|
+
get scrollBottomProfileMenu(): number {
|
|
433
|
+
return this.calculateScrollBottom(this.profileMenuHTMLElement);
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
calculateScrollBottom(element: HTMLElement): number {
|
|
437
|
+
return element.scrollHeight - element.scrollTop - element.clientHeight;
|
|
438
|
+
}
|
|
439
|
+
|
|
440
|
+
get profileMenuHTMLElement(): HTMLElement {
|
|
441
|
+
return this.getElementByClassName(this._profileMenuLinksClassName);
|
|
442
|
+
}
|
|
443
|
+
|
|
444
|
+
get identitiesHTMLElement(): HTMLElement {
|
|
445
|
+
return this.getElementByClassName(this._identitiesListClassName);
|
|
446
|
+
}
|
|
447
|
+
|
|
448
|
+
getElementByClassName(className: string): HTMLElement {
|
|
449
|
+
return this.shadowRoot?.querySelector<HTMLElement>(`.${className}`) as HTMLElement;
|
|
450
|
+
}
|
|
451
|
+
|
|
343
452
|
closeMenu():void {
|
|
344
453
|
this._mastheadShell.closeMobileMenu();
|
|
345
454
|
this._mastheadShell.mobileBtn?.focus();
|
|
@@ -381,6 +490,10 @@ class UDExMastheadProfileMenu extends UI5Element {
|
|
|
381
490
|
return !!this.message.length;
|
|
382
491
|
}
|
|
383
492
|
|
|
493
|
+
get hasLogoutButton(): boolean {
|
|
494
|
+
return !!this.logoutButton.length;
|
|
495
|
+
}
|
|
496
|
+
|
|
384
497
|
get logoutLink(): boolean {
|
|
385
498
|
return !!this.logoutUrl?.length;
|
|
386
499
|
}
|
|
@@ -425,6 +538,10 @@ class UDExMastheadProfileMenu extends UI5Element {
|
|
|
425
538
|
get isMobile(): boolean {
|
|
426
539
|
return this.isAtMostBreakpointSizeM || this.mastheadShell?.isMobileMenuMode;
|
|
427
540
|
}
|
|
541
|
+
|
|
542
|
+
get hasActionButton(): boolean {
|
|
543
|
+
return this.logoutLink || this.hasLogoutButton;
|
|
544
|
+
}
|
|
428
545
|
}
|
|
429
546
|
|
|
430
547
|
UDExMastheadProfileMenu.define();
|
package/src/Pagination.ts
CHANGED
|
@@ -237,7 +237,7 @@ class UDExPagination extends UI5Element {
|
|
|
237
237
|
const effectiveDisabledText = this._prevButtonPseudoDisabled ? `${translate(UDExPagination, DISABLED)}` : "";
|
|
238
238
|
return `${translate(UDExPagination, PREVIOUS_PAGE)} ${effectiveDisabledText}`;
|
|
239
239
|
}
|
|
240
|
-
return `${translate(UDExPagination, PREVIOUS_PAGE)}. ${this.activatePageAccessibleText} ${this.currentPageIndex}`;
|
|
240
|
+
return `${this.typeShort && this.nextButtonDisabled ? this.paginationShortAccessibleName : ""} ${translate(UDExPagination, PREVIOUS_PAGE)}. ${this.activatePageAccessibleText} ${this.currentPageIndex}`;
|
|
241
241
|
}
|
|
242
242
|
|
|
243
243
|
get previousBtnTooltip(): string {
|
|
@@ -249,7 +249,7 @@ class UDExPagination extends UI5Element {
|
|
|
249
249
|
const effectiveDisabledText = this._nextButtonPseudoDisabled ? `${translate(UDExPagination, DISABLED)}` : "";
|
|
250
250
|
return `${translate(UDExPagination, NEXT_PAGE)} ${effectiveDisabledText}`;
|
|
251
251
|
}
|
|
252
|
-
return `${translate(UDExPagination, NEXT_PAGE)}. ${this.activatePageAccessibleText} ${this.currentPageIndex + 2}`;
|
|
252
|
+
return `${this.typeShort && this.prevButtonDisabled ? this.paginationShortAccessibleName : ""} ${translate(UDExPagination, NEXT_PAGE)}. ${this.activatePageAccessibleText} ${this.currentPageIndex + 2}`;
|
|
253
253
|
}
|
|
254
254
|
|
|
255
255
|
get nextBtnTooltip(): string {
|
|
@@ -304,9 +304,17 @@ class UDExPagination extends UI5Element {
|
|
|
304
304
|
}
|
|
305
305
|
|
|
306
306
|
this.currentPageIndex = currentPage + 1;
|
|
307
|
+
const isLastPage = this.currentPageIndex === (this.pages - 1);
|
|
307
308
|
this._pageFocusedManually = false;
|
|
309
|
+
this._nextButtonPseudoDisabled = isLastPage;
|
|
308
310
|
|
|
309
|
-
|
|
311
|
+
if (isLastPage) {
|
|
312
|
+
if (this.typeShort) {
|
|
313
|
+
this.focusActiveArrow();
|
|
314
|
+
} else {
|
|
315
|
+
this.focusActivePage();
|
|
316
|
+
}
|
|
317
|
+
}
|
|
310
318
|
|
|
311
319
|
this.emitChangeEvent();
|
|
312
320
|
}
|
|
@@ -333,10 +341,19 @@ class UDExPagination extends UI5Element {
|
|
|
333
341
|
if (this.pages && currentPage <= 0) {
|
|
334
342
|
return;
|
|
335
343
|
}
|
|
344
|
+
|
|
336
345
|
this.currentPageIndex -= 1;
|
|
346
|
+
const isFirstPage = this.currentPageIndex === 0;
|
|
337
347
|
this._pageFocusedManually = false;
|
|
348
|
+
this._prevButtonPseudoDisabled = isFirstPage;
|
|
338
349
|
|
|
339
|
-
|
|
350
|
+
if (isFirstPage) {
|
|
351
|
+
if (this.typeShort) {
|
|
352
|
+
this.focusActiveArrow();
|
|
353
|
+
} else {
|
|
354
|
+
this.focusActivePage();
|
|
355
|
+
}
|
|
356
|
+
}
|
|
340
357
|
|
|
341
358
|
this.emitChangeEvent();
|
|
342
359
|
}
|
|
@@ -423,10 +440,19 @@ class UDExPagination extends UI5Element {
|
|
|
423
440
|
this.fireDecoratorEvent("change", { currentPage: this.currentPageIndex + 1 });
|
|
424
441
|
}
|
|
425
442
|
|
|
443
|
+
focusActivePage() {
|
|
444
|
+
const activePageItem = this.shadowRoot?.querySelector<HTMLElement>(`.udex-pagination__page[data-index="${this.currentPageIndex}"]`);
|
|
445
|
+
activePageItem?.focus();
|
|
446
|
+
}
|
|
447
|
+
|
|
448
|
+
focusActiveArrow() {
|
|
449
|
+
const activeArrow = this.shadowRoot?.querySelector(`.udex-pagination__arrow--${this.currentPageIndex === 0 ? "next" : "prev"}`);
|
|
450
|
+
activeArrow?.shadowRoot?.querySelector<HTMLElement>("button")?.focus();
|
|
451
|
+
}
|
|
452
|
+
|
|
426
453
|
onAfterRendering() {
|
|
427
454
|
if (this._pageFocusedManually) {
|
|
428
|
-
|
|
429
|
-
activePageItem?.focus();
|
|
455
|
+
this.focusActivePage();
|
|
430
456
|
}
|
|
431
457
|
|
|
432
458
|
if (this.type === UDExPaginationType.full) {
|
|
@@ -10,13 +10,15 @@ export default function PaginationTemplate(this: UDExPagination) {
|
|
|
10
10
|
// This can maybe be cleaned up nicer as we can't simply
|
|
11
11
|
// return empty("return;") as the renderer expects an element
|
|
12
12
|
if (!this.pages) { return (<></>); }
|
|
13
|
+
const rootClass = "udex-pagination";
|
|
13
14
|
|
|
14
15
|
return (
|
|
15
16
|
<nav class={this.paginationClass} role="navigation" aria-label={this.paginationAccessibleName}>
|
|
16
|
-
<ul class=
|
|
17
|
-
<li class=
|
|
17
|
+
<ul class={`${rootClass}__list`}>
|
|
18
|
+
<li class={`${rootClass}__item ${rootClass}__item--prev`}>
|
|
18
19
|
<UDExButton
|
|
19
|
-
|
|
20
|
+
class={`${rootClass}__arrow ${rootClass}__arrow--prev`}
|
|
21
|
+
disabled={this.effectivePrevButtonDisabled}
|
|
20
22
|
{...(this._prevButtonPseudoDisabled ? { "_aria-disabled": "" } : {})}
|
|
21
23
|
accessible-name={this.previousPageAccessibleName}
|
|
22
24
|
tooltip={this.previousBtnTooltip}
|
|
@@ -28,12 +30,13 @@ export default function PaginationTemplate(this: UDExPagination) {
|
|
|
28
30
|
></UDExButton>
|
|
29
31
|
</li>
|
|
30
32
|
|
|
31
|
-
{ this.typeFull ? renderFullPagination.call(this) : "" }
|
|
32
|
-
{ this.typeShort ? renderShortPagination.call(this) : "" }
|
|
33
|
+
{ this.typeFull ? renderFullPagination.call(this, rootClass) : "" }
|
|
34
|
+
{ this.typeShort ? renderShortPagination.call(this, rootClass) : "" }
|
|
33
35
|
|
|
34
|
-
<li class=
|
|
36
|
+
<li class={`${rootClass}__item ${rootClass}__item--next`}>
|
|
35
37
|
<UDExButton
|
|
36
|
-
|
|
38
|
+
class={`${rootClass}__arrow ${rootClass}__arrow--next`}
|
|
39
|
+
disabled={this.effectiveNextButtonDisabled}
|
|
37
40
|
{...(this._nextButtonPseudoDisabled ? { "_aria-disabled": "" } : {})}
|
|
38
41
|
accessible-name={this.nextPageAccessibleName}
|
|
39
42
|
tooltip={this.nextBtnTooltip}
|
|
@@ -49,12 +52,12 @@ export default function PaginationTemplate(this: UDExPagination) {
|
|
|
49
52
|
);
|
|
50
53
|
}
|
|
51
54
|
|
|
52
|
-
function renderFullPagination(this: UDExPagination) {
|
|
55
|
+
function renderFullPagination(this: UDExPagination, rootClass: string) {
|
|
53
56
|
return this.pagination.map((page, i) => {
|
|
54
57
|
return (
|
|
55
|
-
<li key={i} class=
|
|
58
|
+
<li key={i} class={`${rootClass}__item`}>
|
|
56
59
|
<a
|
|
57
|
-
class=
|
|
60
|
+
class={`${rootClass}__page`}
|
|
58
61
|
href="#"
|
|
59
62
|
aria-label={page.accessibleName}
|
|
60
63
|
onClick={this.onPageClick}
|
|
@@ -62,19 +65,19 @@ function renderFullPagination(this: UDExPagination) {
|
|
|
62
65
|
aria-current={page.ariaCurrent as AriaCurrent}
|
|
63
66
|
data-index={page.index}
|
|
64
67
|
>
|
|
65
|
-
<span class=
|
|
68
|
+
<span class={`${rootClass}__page--value`}>{page.value}</span>
|
|
66
69
|
</a>
|
|
67
70
|
</li>
|
|
68
71
|
);
|
|
69
72
|
});
|
|
70
73
|
}
|
|
71
74
|
|
|
72
|
-
function renderShortPagination(this: UDExPagination) {
|
|
75
|
+
function renderShortPagination(this: UDExPagination, rootClass: string) {
|
|
73
76
|
return (
|
|
74
|
-
<li class=
|
|
75
|
-
<span class=
|
|
76
|
-
<span class=
|
|
77
|
-
<span class=
|
|
77
|
+
<li class={`${rootClass}__item ${rootClass}__item--short`} tab-index="-1" aria-label={this.paginationShortAccessibleName}>
|
|
78
|
+
<span class={`${rootClass}__item--short-value`}>{this.shortTextStart}</span>
|
|
79
|
+
<span class={`${rootClass}__item--short-separator`}>{this.shortTextSeparator}</span>
|
|
80
|
+
<span class={`${rootClass}__item--short-value`}>{this.shortTextEnd}</span>
|
|
78
81
|
</li>
|
|
79
82
|
);
|
|
80
83
|
}
|
package/src/Tab.ts
CHANGED
|
@@ -25,14 +25,18 @@ export interface ITab extends UI5Element {
|
|
|
25
25
|
selected?: boolean;
|
|
26
26
|
numberBadge?: string;
|
|
27
27
|
text?: string;
|
|
28
|
+
bodyText?: string;
|
|
28
29
|
showAttentionBadge?: boolean;
|
|
29
30
|
accessibleName?: string;
|
|
30
31
|
href?: string;
|
|
31
32
|
content?: Array<Node>;
|
|
33
|
+
link?: Array<HTMLElement>;
|
|
32
34
|
hasIcon: boolean;
|
|
35
|
+
isMobile: boolean;
|
|
33
36
|
isOnSelectedTab: boolean;
|
|
34
37
|
hasNotIcon: boolean;
|
|
35
38
|
hasNotHref: boolean;
|
|
39
|
+
hasLinkSlot: boolean;
|
|
36
40
|
selectedClass: string;
|
|
37
41
|
tabNavigation: any;
|
|
38
42
|
_individualSlot: string;
|
|
@@ -40,6 +44,8 @@ export interface ITab extends UI5Element {
|
|
|
40
44
|
_slotName: string;
|
|
41
45
|
_selected?: boolean;
|
|
42
46
|
_tabIndex: string;
|
|
47
|
+
_isMobile: boolean;
|
|
48
|
+
_isVertical: boolean;
|
|
43
49
|
_iconWithoutBackground: boolean;
|
|
44
50
|
_posinset?: number;
|
|
45
51
|
_setsize?: number;
|
|
@@ -91,6 +97,16 @@ class UDExTab extends UI5Element implements ITab {
|
|
|
91
97
|
*/
|
|
92
98
|
@property({ type: String })
|
|
93
99
|
text!: string;
|
|
100
|
+
|
|
101
|
+
/**
|
|
102
|
+
* Defines the body text (supplementary description) of the tab.
|
|
103
|
+
* Optional text to provide additional context or explanation.
|
|
104
|
+
*
|
|
105
|
+
* @public
|
|
106
|
+
*/
|
|
107
|
+
@property({ type: String })
|
|
108
|
+
bodyText?: string;
|
|
109
|
+
|
|
94
110
|
/**
|
|
95
111
|
* Accessible name for tab.
|
|
96
112
|
*
|
|
@@ -167,6 +183,32 @@ class UDExTab extends UI5Element implements ITab {
|
|
|
167
183
|
@property({ type: String })
|
|
168
184
|
_tabIndex!: string;
|
|
169
185
|
|
|
186
|
+
/**
|
|
187
|
+
* Defines if the viewport is mobile size.
|
|
188
|
+
*
|
|
189
|
+
* @private
|
|
190
|
+
* @default false
|
|
191
|
+
*/
|
|
192
|
+
@property({ type: Boolean, noAttribute: true })
|
|
193
|
+
_isMobile: boolean = false;
|
|
194
|
+
|
|
195
|
+
/**
|
|
196
|
+
* Defines if the tab navigation is in vertical orientation.
|
|
197
|
+
*
|
|
198
|
+
* @private
|
|
199
|
+
* @default false
|
|
200
|
+
*/
|
|
201
|
+
@property({ type: Boolean, noAttribute: true })
|
|
202
|
+
_isVertical: boolean = false;
|
|
203
|
+
|
|
204
|
+
/**
|
|
205
|
+
* Defines the width of the tab.
|
|
206
|
+
*
|
|
207
|
+
* @private
|
|
208
|
+
*/
|
|
209
|
+
@property({ type: String, noAttribute: true })
|
|
210
|
+
_width?: string;
|
|
211
|
+
|
|
170
212
|
/**
|
|
171
213
|
* Defines the background color of the component.
|
|
172
214
|
*
|
|
@@ -185,6 +227,16 @@ class UDExTab extends UI5Element implements ITab {
|
|
|
185
227
|
@slot({ type: Node, "default": true })
|
|
186
228
|
content!: Array<Node>;
|
|
187
229
|
|
|
230
|
+
/**
|
|
231
|
+
* Defines the link(s) to be displayed in the tab header (vertical orientation only).
|
|
232
|
+
* Use this slot to add one or more udex-link elements to the tab button.
|
|
233
|
+
*
|
|
234
|
+
* @slot link
|
|
235
|
+
* @public
|
|
236
|
+
*/
|
|
237
|
+
@slot({ type: HTMLElement })
|
|
238
|
+
link!: Array<HTMLElement>;
|
|
239
|
+
|
|
188
240
|
@i18n("@sapudex/web-components")
|
|
189
241
|
static i18nBundle: I18nBundle;
|
|
190
242
|
|
|
@@ -219,6 +271,14 @@ class UDExTab extends UI5Element implements ITab {
|
|
|
219
271
|
return this.hasIcon ? " udex-tab-navigation__button-tab--icon" : "";
|
|
220
272
|
}
|
|
221
273
|
|
|
274
|
+
get isMobile(): boolean {
|
|
275
|
+
return this._isMobile;
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
get isMobileVertical(): boolean {
|
|
279
|
+
return this._isMobile && this._isVertical;
|
|
280
|
+
}
|
|
281
|
+
|
|
222
282
|
get hasNotIcon(): boolean {
|
|
223
283
|
return !this.icon && this.showAttentionBadge;
|
|
224
284
|
}
|
|
@@ -227,6 +287,37 @@ class UDExTab extends UI5Element implements ITab {
|
|
|
227
287
|
return !this.href;
|
|
228
288
|
}
|
|
229
289
|
|
|
290
|
+
get hasBodyText(): boolean {
|
|
291
|
+
return !!this.bodyText;
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
/**
|
|
295
|
+
* Returns true if aria-describedby should point to bodyText.
|
|
296
|
+
* Only applies to selected tabs with bodyText in vertical orientation.
|
|
297
|
+
*/
|
|
298
|
+
get ariaDescribedByBodyText(): boolean {
|
|
299
|
+
return this.effectiveSelected && this.hasBodyText && this._isVertical;
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
get hasLinkSlot(): boolean {
|
|
303
|
+
return this.link && this.link.length > 0;
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
/**
|
|
307
|
+
* Returns the HTML content of the link slot elements.
|
|
308
|
+
* This is used to render the links in the TabHeader template.
|
|
309
|
+
*/
|
|
310
|
+
get linkSlotHtml(): string {
|
|
311
|
+
if (!this.link || this.link.length === 0) {
|
|
312
|
+
return "";
|
|
313
|
+
}
|
|
314
|
+
return this.link.map(l => l.outerHTML).join("");
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
get hasBodyTextOrLink(): boolean {
|
|
318
|
+
return this._isVertical && (this.hasBodyText || this.hasLinkSlot);
|
|
319
|
+
}
|
|
320
|
+
|
|
230
321
|
get effectiveSelected(): boolean {
|
|
231
322
|
return this.selected || this._selected;
|
|
232
323
|
}
|
|
@@ -265,6 +356,13 @@ class UDExTab extends UI5Element implements ITab {
|
|
|
265
356
|
return this.href && this.effectiveSelected ? "1" : "-1";
|
|
266
357
|
}
|
|
267
358
|
|
|
359
|
+
get widthStyle(): string {
|
|
360
|
+
if (this._width && this._width !== "auto") {
|
|
361
|
+
return `width: ${this._width};`;
|
|
362
|
+
}
|
|
363
|
+
return "";
|
|
364
|
+
}
|
|
365
|
+
|
|
268
366
|
get tabNavigation() {
|
|
269
367
|
return executeTemplate(UDExTab.headerTemplate, this);
|
|
270
368
|
}
|
package/src/TabHeader.hbs
CHANGED
|
@@ -1,34 +1,81 @@
|
|
|
1
|
-
{{#if
|
|
2
|
-
<
|
|
3
|
-
|
|
4
|
-
class="udex-tab-navigation__button-tab {{selectedClass}} {{classWithIconWithoutBackground}} {{buttonClassWithIcon}}"
|
|
5
|
-
tabindex="{{this._tabIndex}}"
|
|
6
|
-
type="button"
|
|
7
|
-
role="tab"
|
|
8
|
-
aria-describedby="udex-tab-navigation__{{this._id}}__accessible-name"
|
|
9
|
-
aria-posinset="{{this._posinset}}"
|
|
10
|
-
aria-setsize="{{this._setsize}}"
|
|
11
|
-
aria-controls="{{this._contentId}}"
|
|
12
|
-
aria-selected="{{this.effectiveSelected}}"
|
|
13
|
-
aria-labelledby="{{this.ariaLabelledBy}}"
|
|
1
|
+
{{#if hasBodyTextOrLink}}
|
|
2
|
+
<div class="udex-tab-navigation__tab-wrapper"
|
|
3
|
+
role="presentation"
|
|
14
4
|
._realTab="{{this}}"
|
|
15
|
-
style="
|
|
16
|
-
{{
|
|
17
|
-
|
|
5
|
+
{{#if this.widthStyle}}style="{{this.widthStyle}}"{{/if}}>
|
|
6
|
+
{{#if hasNotHref}}
|
|
7
|
+
<button
|
|
8
|
+
id="{{this._id}}"
|
|
9
|
+
class="udex-tab-navigation__button-tab {{selectedClass}} {{classWithIconWithoutBackground}} {{buttonClassWithIcon}}"
|
|
10
|
+
type="button"
|
|
11
|
+
role="tab"
|
|
12
|
+
tabindex="{{this._tabIndex}}"
|
|
13
|
+
aria-posinset="{{this._posinset}}"
|
|
14
|
+
aria-setsize="{{this._setsize}}"
|
|
15
|
+
aria-controls="{{this._contentId}}"
|
|
16
|
+
aria-selected="{{this.effectiveSelected}}">
|
|
17
|
+
{{>tab-content}}
|
|
18
|
+
{{#if this.ariaDescribedByBodyText}}
|
|
19
|
+
<span class="visually-hidden">{{bodyText}}</span>
|
|
20
|
+
{{/if}}
|
|
21
|
+
</button>
|
|
22
|
+
{{else}}
|
|
23
|
+
<a
|
|
24
|
+
id="{{this._id}}"
|
|
25
|
+
class="udex-tab-navigation__button-tab {{selectedClass}} {{classWithIconWithoutBackground}} {{buttonClassWithIcon}}"
|
|
26
|
+
href="{{href}}"
|
|
27
|
+
target="{{target}}"
|
|
28
|
+
role="tab"
|
|
29
|
+
tabindex="{{this.linkTabIndex}}"
|
|
30
|
+
aria-posinset="{{this._posinset}}"
|
|
31
|
+
aria-setsize="{{this._setsize}}">
|
|
32
|
+
{{>tab-content}}
|
|
33
|
+
{{#if this.ariaDescribedByBodyText}}
|
|
34
|
+
<span class="visually-hidden">{{bodyText}}</span>
|
|
35
|
+
{{/if}}
|
|
36
|
+
</a>
|
|
37
|
+
{{/if}}
|
|
38
|
+
{{#if hasBodyText}}
|
|
39
|
+
<p class="udex-tab-navigation__button-body-text">{{bodyText}}</p>
|
|
40
|
+
{{/if}}
|
|
41
|
+
{{#if hasLinkSlot}}
|
|
42
|
+
<div class="udex-tab-navigation__button-links">
|
|
43
|
+
{{{linkSlotHtml}}}
|
|
44
|
+
</div>
|
|
45
|
+
{{/if}}
|
|
46
|
+
</div>
|
|
18
47
|
{{else}}
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
48
|
+
{{#if hasNotHref}}
|
|
49
|
+
<button
|
|
50
|
+
id="{{this._id}}"
|
|
51
|
+
class="udex-tab-navigation__button-tab {{selectedClass}} {{classWithIconWithoutBackground}} {{buttonClassWithIcon}}"
|
|
52
|
+
tabindex="{{this._tabIndex}}"
|
|
53
|
+
type="button"
|
|
54
|
+
role="tab"
|
|
55
|
+
aria-describedby="udex-tab-navigation__{{this._id}}__accessible-name"
|
|
56
|
+
aria-posinset="{{this._posinset}}"
|
|
57
|
+
aria-setsize="{{this._setsize}}"
|
|
58
|
+
aria-controls="{{this._contentId}}"
|
|
59
|
+
aria-selected="{{this.effectiveSelected}}"
|
|
60
|
+
._realTab="{{this}}"
|
|
61
|
+
{{#if this.widthStyle}}style="{{this.widthStyle}}"{{/if}}>
|
|
62
|
+
{{>tab-content}}
|
|
63
|
+
</button>
|
|
64
|
+
{{else}}
|
|
65
|
+
<a
|
|
66
|
+
id="{{this._id}}"
|
|
67
|
+
class="udex-tab-navigation__button-tab {{selectedClass}} {{classWithIconWithoutBackground}} {{buttonClassWithIcon}}"
|
|
68
|
+
tabindex="{{this.linkTabIndex}}"
|
|
69
|
+
role="tab"
|
|
70
|
+
aria-posinset="{{this._posinset}}"
|
|
71
|
+
aria-setsize="{{this._setsize}}"
|
|
72
|
+
href="{{href}}"
|
|
73
|
+
target="{{target}}"
|
|
74
|
+
{{#if this.widthStyle}}style="{{this.widthStyle}}"{{/if}}
|
|
75
|
+
._realTab="{{this}}">
|
|
76
|
+
{{>tab-content}}
|
|
77
|
+
</a>
|
|
78
|
+
{{/if}}
|
|
32
79
|
{{/if}}
|
|
33
80
|
|
|
34
81
|
{{#*inline "tab-content"}}
|
|
@@ -56,9 +103,14 @@
|
|
|
56
103
|
{{numberBadge}}
|
|
57
104
|
</udex-badge>
|
|
58
105
|
{{/if}}
|
|
106
|
+
{{#if hasNotIcon}}
|
|
107
|
+
<span class="udex-tab-navigation__button-badge"></span>
|
|
108
|
+
{{/if}}
|
|
59
109
|
</p>
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
110
|
+
<span
|
|
111
|
+
class="visually-hidden"
|
|
112
|
+
id="udex-tab-navigation__{{this._id}}__accessible-name"
|
|
113
|
+
>
|
|
114
|
+
{{accessibleNameText}}
|
|
115
|
+
</span>
|
|
64
116
|
{{/inline}}
|