@sapudex/web-components 2.31.0 → 2.32.1
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/specs/Breadcrumbs.cy.tsx +26 -0
- package/cypress/specs/MediaPlayer.cy.tsx +209 -0
- package/cypress/specs/SecondaryNavigationDesktop.cy.tsx +74 -21
- package/cypress/specs/SecondaryNavigationMobile.cy.tsx +58 -1
- package/cypress/specs/SelectBox.cy.tsx +35 -0
- package/cypress/specs/StepInput.cy.tsx +507 -0
- package/cypress/specs/TabNavigation.cy.tsx +603 -39
- package/cypress/support/component-imports.instrumented.ts +4 -0
- package/cypress/support/component-imports.src.ts +7 -3
- package/dist/Breadcrumbs.d.ts +5 -0
- package/dist/Breadcrumbs.js +8 -1
- package/dist/Breadcrumbs.js.map +1 -1
- package/dist/HeroBanner.d.ts +0 -3
- package/dist/HeroBanner.js +0 -5
- package/dist/HeroBanner.js.map +1 -1
- package/dist/HeroBannerTemplate.d.ts +2 -0
- package/dist/HeroBannerTemplate.js +6 -1
- package/dist/HeroBannerTemplate.js.map +1 -1
- package/dist/MastheadItem.js +5 -4
- package/dist/MastheadItem.js.map +1 -1
- package/dist/MediaPlayer.d.ts +15 -0
- package/dist/MediaPlayer.js +28 -0
- package/dist/MediaPlayer.js.map +1 -1
- package/dist/SecondaryNavigation.d.ts +12 -2
- package/dist/SecondaryNavigation.js +59 -8
- package/dist/SecondaryNavigation.js.map +1 -1
- package/dist/SecondaryNavigationItem.d.ts +0 -1
- package/dist/SecondaryNavigationItem.js +0 -4
- package/dist/SecondaryNavigationItem.js.map +1 -1
- package/dist/SecondaryNavigationSubItem.js +1 -1
- package/dist/SecondaryNavigationSubItem.js.map +1 -1
- package/dist/SelectBase.js +2 -1
- package/dist/SelectBase.js.map +1 -1
- package/dist/StepInput.d.ts +3 -0
- package/dist/StepInput.js +17 -0
- package/dist/StepInput.js.map +1 -1
- package/dist/StepInputTemplate.js +1 -1
- package/dist/StepInputTemplate.js.map +1 -1
- package/dist/Tab.d.ts +1 -1
- package/dist/Tab.js +3 -3
- package/dist/Tab.js.map +1 -1
- package/dist/TabNavigation.d.ts +64 -0
- package/dist/TabNavigation.js +124 -1
- package/dist/TabNavigation.js.map +1 -1
- package/dist/assets/{InputSuggestions-i2kFpCfC.js → InputSuggestions-DeXhpK0F.js} +1 -1
- package/dist/assets/{ListItemStandardExpandableTextTemplate-C1ceDaxu.js → ListItemStandardExpandableTextTemplate-jMEdrC07.js} +1 -1
- package/dist/assets/{bundle.esm-DQ3cxywT.js → bundle.esm-CwJAt93x.js} +219 -219
- package/dist/assets/messagebundle_en-iNqRB1VZ.js +1 -0
- package/dist/css/themes/BreadcrumbsPopover.css +1 -1
- package/dist/css/themes/FilterMenu.css +1 -1
- package/dist/css/themes/HeroBanner.css +1 -1
- package/dist/css/themes/Modal.css +1 -1
- package/dist/css/themes/RatingIndicator.css +1 -1
- package/dist/css/themes/SecondaryNavigationItem.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 +221 -0
- package/dist/custom-elements.json +149 -0
- package/dist/generated/assets/i18n/messagebundle_en.json +1 -1
- package/dist/generated/i18n/i18n-defaults.js +1 -1
- package/dist/generated/i18n/i18n-defaults.js.map +1 -1
- package/dist/generated/templates/SecondaryNavigationTemplate.lit.js +1 -1
- package/dist/generated/templates/SecondaryNavigationTemplate.lit.js.map +1 -1
- package/dist/generated/templates/TabNavigationTemplate.lit.js +10 -8
- package/dist/generated/templates/TabNavigationTemplate.lit.js.map +1 -1
- package/dist/generated/themes/BreadcrumbsPopover.css.d.ts +1 -1
- package/dist/generated/themes/BreadcrumbsPopover.css.js +1 -1
- package/dist/generated/themes/BreadcrumbsPopover.css.js.map +1 -1
- package/dist/generated/themes/FilterMenu.css.d.ts +1 -1
- package/dist/generated/themes/FilterMenu.css.js +1 -1
- package/dist/generated/themes/FilterMenu.css.js.map +1 -1
- package/dist/generated/themes/HeroBanner.css.d.ts +1 -1
- package/dist/generated/themes/HeroBanner.css.js +1 -1
- package/dist/generated/themes/HeroBanner.css.js.map +1 -1
- package/dist/generated/themes/Modal.css.d.ts +1 -1
- package/dist/generated/themes/Modal.css.js +1 -1
- package/dist/generated/themes/Modal.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/SecondaryNavigationItem.css.d.ts +1 -1
- package/dist/generated/themes/SecondaryNavigationItem.css.js +1 -1
- package/dist/generated/themes/SecondaryNavigationItem.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/messagebundle.properties +1 -1
- package/dist/messagebundle_en.properties +1 -1
- package/dist/vscode.html-custom-data.json +23 -3
- package/dist/web-types.json +64 -4
- package/package.json +1 -1
- package/src/Breadcrumbs.ts +9 -1
- package/src/HeroBanner.ts +0 -5
- package/src/HeroBannerTemplate.tsx +6 -1
- package/src/MastheadItem.ts +5 -4
- package/src/MediaPlayer.ts +35 -0
- package/src/SecondaryNavigation.hbs +1 -0
- package/src/SecondaryNavigation.ts +77 -9
- package/src/SecondaryNavigationItem.ts +0 -6
- package/src/SecondaryNavigationSubItem.ts +1 -1
- package/src/SelectBase.ts +2 -1
- package/src/StepInput.ts +20 -0
- package/src/StepInputTemplate.tsx +1 -1
- package/src/Tab.ts +4 -4
- package/src/TabNavigation.hbs +15 -0
- package/src/TabNavigation.ts +134 -1
- package/src/generated/i18n/i18n-defaults.ts +1 -1
- package/src/generated/templates/SecondaryNavigationTemplate.lit.ts +1 -1
- package/src/generated/templates/TabNavigationTemplate.lit.ts +10 -8
- package/src/generated/themes/BreadcrumbsPopover.css.ts +1 -1
- package/src/generated/themes/FilterMenu.css.ts +1 -1
- package/src/generated/themes/HeroBanner.css.ts +1 -1
- package/src/generated/themes/Modal.css.ts +1 -1
- package/src/generated/themes/RatingIndicator.css.ts +1 -1
- package/src/generated/themes/SecondaryNavigationItem.css.ts +1 -1
- package/src/generated/themes/Slider.css.ts +1 -1
- package/src/generated/themes/TabNavigation.css.ts +1 -1
- package/src/i18n/messagebundle.properties +1 -1
- package/src/i18n/messagebundle_en.properties +1 -1
- package/src/themes/BreadcrumbsPopover.css +2 -2
- package/src/themes/FilterMenu.css +5 -1
- package/src/themes/HeroBanner.css +93 -76
- package/src/themes/Modal.css +3 -2
- package/src/themes/SecondaryNavigationItem.css +4 -1
- package/src/themes/TabNavigation.css +27 -16
- package/dist/assets/messagebundle_en-DWAgV5VH.js +0 -1
- package/dist/generated/templates/HeroBannerTemplate.lit.d.ts +0 -3
- package/dist/generated/templates/HeroBannerTemplate.lit.js +0 -15
- package/dist/generated/templates/HeroBannerTemplate.lit.js.map +0 -1
- package/src/HeroBanner.hbs +0 -46
- package/src/generated/templates/HeroBannerTemplate.lit.ts +0 -19
package/src/MastheadItem.ts
CHANGED
|
@@ -491,6 +491,7 @@ class UDExMastheadItem extends UI5Element implements IMastheadItem {
|
|
|
491
491
|
|
|
492
492
|
calculateMarginInlineStart(rect: DOMRect): number | null {
|
|
493
493
|
const { left, right } = rect;
|
|
494
|
+
const viewportWidth = document.documentElement.clientWidth;
|
|
494
495
|
|
|
495
496
|
if (this.isLtrDirection && left < 0) {
|
|
496
497
|
return left * -1 + 15;
|
|
@@ -500,12 +501,12 @@ class UDExMastheadItem extends UI5Element implements IMastheadItem {
|
|
|
500
501
|
return left - 15;
|
|
501
502
|
}
|
|
502
503
|
|
|
503
|
-
if (this.isRtlDirection && right >
|
|
504
|
-
return right -
|
|
504
|
+
if (this.isRtlDirection && right > viewportWidth) {
|
|
505
|
+
return right - viewportWidth + 15;
|
|
505
506
|
}
|
|
506
507
|
|
|
507
|
-
if (this.isLtrDirection && right >
|
|
508
|
-
return
|
|
508
|
+
if (this.isLtrDirection && right > viewportWidth) {
|
|
509
|
+
return viewportWidth - right - 15;
|
|
509
510
|
}
|
|
510
511
|
|
|
511
512
|
return null;
|
package/src/MediaPlayer.ts
CHANGED
|
@@ -35,6 +35,10 @@ type UDExMediaPlayerVideoProgressEventDetail = {
|
|
|
35
35
|
progress: number,
|
|
36
36
|
}
|
|
37
37
|
|
|
38
|
+
type UDExMediaPlayerVideojsReadyEventDetail = {
|
|
39
|
+
videojs: any,
|
|
40
|
+
}
|
|
41
|
+
|
|
38
42
|
/**
|
|
39
43
|
* @class
|
|
40
44
|
*
|
|
@@ -117,6 +121,15 @@ type UDExMediaPlayerVideoProgressEventDetail = {
|
|
|
117
121
|
* @public
|
|
118
122
|
*/
|
|
119
123
|
@event("video75", { bubbles: true })
|
|
124
|
+
/**
|
|
125
|
+
* Fires when the VideoJS library is loaded but before the player is created.
|
|
126
|
+
* Use this event to register custom VideoJS plugins via
|
|
127
|
+
* <code>event.detail.videojs.registerPlugin()</code>.
|
|
128
|
+
*
|
|
129
|
+
* @public
|
|
130
|
+
* @param {object} videojs the VideoJS constructor object
|
|
131
|
+
*/
|
|
132
|
+
@event("videojsReady", { bubbles: true })
|
|
120
133
|
class UDExMediaPlayer extends UI5Element {
|
|
121
134
|
eventDetails!: {
|
|
122
135
|
"videoStart": void,
|
|
@@ -127,6 +140,7 @@ class UDExMediaPlayer extends UI5Element {
|
|
|
127
140
|
"video25": void,
|
|
128
141
|
"video50": void,
|
|
129
142
|
"video75": void,
|
|
143
|
+
"videojsReady": UDExMediaPlayerVideojsReadyEventDetail,
|
|
130
144
|
};
|
|
131
145
|
/**
|
|
132
146
|
* Defines the options object of video.js element
|
|
@@ -251,6 +265,20 @@ class UDExMediaPlayer extends UI5Element {
|
|
|
251
265
|
videoStart!: boolean;
|
|
252
266
|
videoReady!: boolean;
|
|
253
267
|
videoProgress!: number;
|
|
268
|
+
private _pendingPlugins: Array<{ name: string; plugin: (...args: any[]) => any }> = [];
|
|
269
|
+
|
|
270
|
+
/**
|
|
271
|
+
* Registers a custom VideoJS plugin to be applied before player initialization.
|
|
272
|
+
* Must be called before the component renders.
|
|
273
|
+
* For plugins registered after rendering, use the videojsReady event instead.
|
|
274
|
+
*
|
|
275
|
+
* @param name - The plugin name
|
|
276
|
+
* @param plugin - The plugin function or class
|
|
277
|
+
* @public
|
|
278
|
+
*/
|
|
279
|
+
registerPlugin(name: string, plugin: (...args: any[]) => any): void {
|
|
280
|
+
this._pendingPlugins.push({ name, plugin });
|
|
281
|
+
}
|
|
254
282
|
|
|
255
283
|
getPlayedTime = (target: EventTarget): number => {
|
|
256
284
|
const progressControl = (target as any)?.player.controlBar?.progressControl?.childNameIndex_.seekBar;
|
|
@@ -518,6 +546,13 @@ class UDExMediaPlayer extends UI5Element {
|
|
|
518
546
|
window.videojs = videojs;
|
|
519
547
|
}
|
|
520
548
|
|
|
549
|
+
this._pendingPlugins.forEach(({ name, plugin }) => {
|
|
550
|
+
videojs.registerPlugin(name, plugin);
|
|
551
|
+
});
|
|
552
|
+
this._pendingPlugins = [];
|
|
553
|
+
|
|
554
|
+
this.fireDecoratorEvent("videojsReady", { videojs });
|
|
555
|
+
|
|
521
556
|
const options = this.getOptionsValue();
|
|
522
557
|
const language: string = options?.language;
|
|
523
558
|
if (language) {
|
|
@@ -70,6 +70,7 @@
|
|
|
70
70
|
aria-label="{{mobileMenuOpenerAriaLabel}}"
|
|
71
71
|
label="{{heading}}"
|
|
72
72
|
mobile-link-title="{{title}}"
|
|
73
|
+
@ui5-nav-item-click="{{handleMobileMenuOpenerClick}}"
|
|
73
74
|
@ui5-sub-item-click="{{handleSubItemClick}}"
|
|
74
75
|
_is-mobile-menu-opener
|
|
75
76
|
.subItems="{{this.parsedItems}}">
|
|
@@ -34,8 +34,10 @@ type UDExSecondaryNavigationClickEventDetail = {
|
|
|
34
34
|
originalEvent: Event,
|
|
35
35
|
clickedItem: NavItem;
|
|
36
36
|
clickedIndex: number;
|
|
37
|
+
isMore?: boolean,
|
|
37
38
|
isMobile?: boolean,
|
|
38
39
|
analyticsName: AnalyticsName,
|
|
40
|
+
analyticsPath: Array<string>,
|
|
39
41
|
sourceNode: HTMLElement,
|
|
40
42
|
};
|
|
41
43
|
|
|
@@ -45,6 +47,12 @@ type UDExSecondaryNavigationHeadingClickEventDetail = {
|
|
|
45
47
|
sourceNode: HTMLElement,
|
|
46
48
|
};
|
|
47
49
|
|
|
50
|
+
type UDExSecondaryNavigationMobileMenuOpenerClickEventDetail = {
|
|
51
|
+
originalEvent: Event,
|
|
52
|
+
analyticsName: AnalyticsName,
|
|
53
|
+
sourceNode: HTMLElement,
|
|
54
|
+
};
|
|
55
|
+
|
|
48
56
|
/**
|
|
49
57
|
* @class
|
|
50
58
|
*
|
|
@@ -97,10 +105,23 @@ type UDExSecondaryNavigationHeadingClickEventDetail = {
|
|
|
97
105
|
*/
|
|
98
106
|
@event("heading-click", { cancelable: true, bubbles: true })
|
|
99
107
|
|
|
108
|
+
/**
|
|
109
|
+
* The event is triggered on user interaction with the mobile menu opener
|
|
110
|
+
*
|
|
111
|
+
* @allowPreventDefault
|
|
112
|
+
* @public
|
|
113
|
+
* @param {Event} originalEvent The original event object
|
|
114
|
+
* @param {AnalyticsName} analyticsName The analytics name for the mobile menu opener
|
|
115
|
+
* @param {HTMLElement} sourceNode The source node of the mobile menu opener
|
|
116
|
+
*
|
|
117
|
+
*/
|
|
118
|
+
@event("mobile-menu-opener-click", { cancelable: true, bubbles: true })
|
|
119
|
+
|
|
100
120
|
class UDExSecondaryNavigation extends UI5Element {
|
|
101
121
|
eventDetails!: {
|
|
102
122
|
"item-click": UDExSecondaryNavigationClickEventDetail,
|
|
103
123
|
"heading-click": UDExSecondaryNavigationHeadingClickEventDetail,
|
|
124
|
+
"mobile-menu-opener-click": UDExSecondaryNavigationMobileMenuOpenerClickEventDetail,
|
|
104
125
|
};
|
|
105
126
|
/**
|
|
106
127
|
* Defines an aria label for the mobile menu opener
|
|
@@ -247,7 +268,7 @@ class UDExSecondaryNavigation extends UI5Element {
|
|
|
247
268
|
});
|
|
248
269
|
|
|
249
270
|
if ((steps.at(-1) || 0) <= availableWidth) {
|
|
250
|
-
this._visibleItems
|
|
271
|
+
this._visibleItems = [...this.parsedItems];
|
|
251
272
|
this._showMoreButton = false;
|
|
252
273
|
this.refreshRendering();
|
|
253
274
|
return;
|
|
@@ -256,8 +277,8 @@ class UDExSecondaryNavigation extends UI5Element {
|
|
|
256
277
|
if (this.parsedItems) {
|
|
257
278
|
// @ts-ignore
|
|
258
279
|
const lastVisibleIndex: number = steps.findLastIndex((size: number) => size < (availableWidth - moreButtonWidth - itemsGap));
|
|
259
|
-
this._visibleItems
|
|
260
|
-
this._overflowItems
|
|
280
|
+
this._visibleItems = this.parsedItems.slice(0, lastVisibleIndex + 1);
|
|
281
|
+
this._overflowItems = this.parsedItems.slice(lastVisibleIndex + 1);
|
|
261
282
|
this._showMoreButton = true;
|
|
262
283
|
this.refreshRendering();
|
|
263
284
|
}
|
|
@@ -345,7 +366,7 @@ class UDExSecondaryNavigation extends UI5Element {
|
|
|
345
366
|
active,
|
|
346
367
|
mobileLinkTitle,
|
|
347
368
|
items: subItems,
|
|
348
|
-
});
|
|
369
|
+
}, this.getAnalyticsPath(title, path), title === this.moreButtonText);
|
|
349
370
|
|
|
350
371
|
if (prevented) {
|
|
351
372
|
e.preventDefault();
|
|
@@ -366,7 +387,9 @@ class UDExSecondaryNavigation extends UI5Element {
|
|
|
366
387
|
const { originalEvent: actualOriginalEvent, index } = e.detail;
|
|
367
388
|
const item = e.detail.item as UDExSecondaryNavigationSubItem;
|
|
368
389
|
const { items } = item as NavItem;
|
|
369
|
-
const
|
|
390
|
+
const analyticsPath = this.getAnalyticsPath(item.title, item.path);
|
|
391
|
+
const isMore = this._clickedNavItem?.title === this.moreButtonText;
|
|
392
|
+
const prevented = !this.fireEventItemClick(actualOriginalEvent, index, item, analyticsPath, isMore);
|
|
370
393
|
|
|
371
394
|
if (prevented) {
|
|
372
395
|
e.preventDefault();
|
|
@@ -397,10 +420,14 @@ class UDExSecondaryNavigation extends UI5Element {
|
|
|
397
420
|
{
|
|
398
421
|
items, target, path, title, active, mobileLinkTitle,
|
|
399
422
|
}: NavItem,
|
|
423
|
+
analyticsPath: Array<string> = [],
|
|
424
|
+
isMore: boolean = false,
|
|
400
425
|
): boolean {
|
|
401
426
|
return this.fireDecoratorEvent("item-click", {
|
|
402
427
|
...(this.isMobileScreen && { isMobile: true }),
|
|
428
|
+
...(isMore && { isMore: true }),
|
|
403
429
|
analyticsName: AnalyticsName.HeaderSub,
|
|
430
|
+
analyticsPath,
|
|
404
431
|
sourceNode: e?.currentTarget as HTMLElement,
|
|
405
432
|
originalEvent: e,
|
|
406
433
|
clickedItem: {
|
|
@@ -415,25 +442,62 @@ class UDExSecondaryNavigation extends UI5Element {
|
|
|
415
442
|
});
|
|
416
443
|
}
|
|
417
444
|
|
|
445
|
+
getAnalyticsPath(clickedTitle: string, clickedPath?: string): Array<string> {
|
|
446
|
+
const getLabel = (item: NavItem) => (this.isMobileScreen ? (item.mobileLinkTitle || item.title) : item.title);
|
|
447
|
+
const findPath = (items: Array<NavItem>, parentPath: Array<string>): Array<string> | null => items.reduce<Array<string> | null>((found, item) => {
|
|
448
|
+
if (found !== null) {
|
|
449
|
+
return found;
|
|
450
|
+
}
|
|
451
|
+
if (item.title === clickedTitle && (!clickedPath || item.path === clickedPath)) {
|
|
452
|
+
return [...parentPath, getLabel(item)];
|
|
453
|
+
}
|
|
454
|
+
if (item.items?.length) {
|
|
455
|
+
return findPath(item.items, [...parentPath, getLabel(item)]);
|
|
456
|
+
}
|
|
457
|
+
return null;
|
|
458
|
+
}, null);
|
|
459
|
+
return findPath(this.parsedItems, []) || [];
|
|
460
|
+
}
|
|
461
|
+
|
|
418
462
|
setActiveItem(navItems: Array<NavItem>, clickedItem: UDExSecondaryNavigationItemBase): void {
|
|
419
|
-
const updateNav = (items: Array<NavItem>, { title, path }: UDExSecondaryNavigationItemBase) => {
|
|
463
|
+
const updateNav = (items: Array<NavItem>, { title, path }: UDExSecondaryNavigationItemBase): boolean => {
|
|
464
|
+
let hasActiveDescendant = false;
|
|
465
|
+
|
|
420
466
|
items.forEach(item => {
|
|
421
467
|
if (item.title === title && (item.path === path || !item.path)) {
|
|
422
468
|
item.active = true;
|
|
469
|
+
hasActiveDescendant = true;
|
|
423
470
|
return;
|
|
424
471
|
}
|
|
425
|
-
delete item.active;
|
|
426
472
|
|
|
427
473
|
if (item.items) {
|
|
428
|
-
updateNav(item.items, clickedItem);
|
|
474
|
+
const childIsActive = updateNav(item.items, clickedItem);
|
|
475
|
+
if (childIsActive) {
|
|
476
|
+
item.active = true;
|
|
477
|
+
hasActiveDescendant = true;
|
|
478
|
+
} else {
|
|
479
|
+
delete item.active;
|
|
480
|
+
}
|
|
481
|
+
} else {
|
|
482
|
+
delete item.active;
|
|
429
483
|
}
|
|
430
484
|
});
|
|
485
|
+
|
|
486
|
+
return hasActiveDescendant;
|
|
431
487
|
};
|
|
432
488
|
|
|
433
489
|
updateNav(navItems, clickedItem);
|
|
434
490
|
this.navItems = JSON.stringify(navItems);
|
|
435
491
|
}
|
|
436
492
|
|
|
493
|
+
handleMobileMenuOpenerClick(e: CustomEvent): void {
|
|
494
|
+
this.fireDecoratorEvent("mobile-menu-opener-click", {
|
|
495
|
+
analyticsName: AnalyticsName.HeaderSub,
|
|
496
|
+
sourceNode: e.target as HTMLElement,
|
|
497
|
+
originalEvent: e,
|
|
498
|
+
});
|
|
499
|
+
}
|
|
500
|
+
|
|
437
501
|
handleOutsideClick(): void {
|
|
438
502
|
document.addEventListener("mousedown", this.outsideClickListener);
|
|
439
503
|
}
|
|
@@ -545,4 +609,8 @@ class UDExSecondaryNavigation extends UI5Element {
|
|
|
545
609
|
UDExSecondaryNavigation.define();
|
|
546
610
|
|
|
547
611
|
export default UDExSecondaryNavigation;
|
|
548
|
-
export type {
|
|
612
|
+
export type {
|
|
613
|
+
UDExSecondaryNavigationClickEventDetail,
|
|
614
|
+
UDExSecondaryNavigationHeadingClickEventDetail,
|
|
615
|
+
UDExSecondaryNavigationMobileMenuOpenerClickEventDetail,
|
|
616
|
+
};
|
|
@@ -166,7 +166,6 @@ class UDExSecondaryNavigationItem extends UDExSecondaryNavigationItemBase {
|
|
|
166
166
|
_dropdownHistory: Array<Array<NavItem>> = [];
|
|
167
167
|
_shouldFocusFirstSubItem!: boolean;
|
|
168
168
|
_subTitle!: string | undefined;
|
|
169
|
-
_shouldResetTabIndex!: boolean;
|
|
170
169
|
_shouldSetTabIndex!: boolean;
|
|
171
170
|
|
|
172
171
|
onAfterRendering(): void {
|
|
@@ -187,11 +186,6 @@ class UDExSecondaryNavigationItem extends UDExSecondaryNavigationItemBase {
|
|
|
187
186
|
this._tabIndex = "0";
|
|
188
187
|
this._shouldSetTabIndex = false;
|
|
189
188
|
}
|
|
190
|
-
|
|
191
|
-
if (this._shouldResetTabIndex) {
|
|
192
|
-
this._tabIndex = "-1";
|
|
193
|
-
this._shouldResetTabIndex = false;
|
|
194
|
-
}
|
|
195
189
|
}
|
|
196
190
|
|
|
197
191
|
onBeforeRendering() : void {
|
|
@@ -121,7 +121,7 @@ class UDExSecondaryNavigationSubItem extends UDExSecondaryNavigationItemBase {
|
|
|
121
121
|
|
|
122
122
|
get backButtonAriaLabel(): string {
|
|
123
123
|
const label = translate(UDExSecondaryNavigationSubItem, BACK_BUTTON_LABEL);
|
|
124
|
-
return `${
|
|
124
|
+
return `${this.itemLabel}, ${label}`;
|
|
125
125
|
}
|
|
126
126
|
}
|
|
127
127
|
|
package/src/SelectBase.ts
CHANGED
|
@@ -194,7 +194,7 @@ class UDExSelectBase extends UDExSearchableListBase {
|
|
|
194
194
|
}
|
|
195
195
|
|
|
196
196
|
onInvalidation({ name }: ChangeInfo): void {
|
|
197
|
-
if (name === "default" && this.modeSingleSelect) {
|
|
197
|
+
if (name === "default" && this.modeSingleSelect && !this._inputValue) {
|
|
198
198
|
this.setSelectOption();
|
|
199
199
|
}
|
|
200
200
|
}
|
|
@@ -340,6 +340,7 @@ class UDExSelectBase extends UDExSearchableListBase {
|
|
|
340
340
|
e.stopPropagation();
|
|
341
341
|
e.preventDefault();
|
|
342
342
|
this._selectedOption = "";
|
|
343
|
+
this._inputValue = e.key;
|
|
343
344
|
this._search.value = e.key;
|
|
344
345
|
this._search.focus();
|
|
345
346
|
this.onSearch(this._search.value);
|
package/src/StepInput.ts
CHANGED
|
@@ -294,6 +294,18 @@ class UDExStepInput extends UI5Element {
|
|
|
294
294
|
this._setButtonState();
|
|
295
295
|
}
|
|
296
296
|
|
|
297
|
+
onAfterRendering() {
|
|
298
|
+
this._skipLiveAnnouncement = false;
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
// Plain (non-reactive) flag — set before a re-render when focus is being
|
|
302
|
+
// redirected to the input so the live region stays silent for that render.
|
|
303
|
+
private _skipLiveAnnouncement = false;
|
|
304
|
+
|
|
305
|
+
get _liveRegionText() {
|
|
306
|
+
return this._skipLiveAnnouncement ? "" : this._valuePrecisioned;
|
|
307
|
+
}
|
|
308
|
+
|
|
297
309
|
get input() {
|
|
298
310
|
return this.inputOuter.shadowRoot!.querySelector("input")!;
|
|
299
311
|
}
|
|
@@ -405,6 +417,10 @@ class UDExStepInput extends UI5Element {
|
|
|
405
417
|
if (!this._incIconInactive) {
|
|
406
418
|
this._modifyValue(this.step, true);
|
|
407
419
|
this._previousValue = this.value;
|
|
420
|
+
if (this._incIconDisabled) {
|
|
421
|
+
this._skipLiveAnnouncement = true;
|
|
422
|
+
this.input.focus();
|
|
423
|
+
}
|
|
408
424
|
}
|
|
409
425
|
}
|
|
410
426
|
|
|
@@ -412,6 +428,10 @@ class UDExStepInput extends UI5Element {
|
|
|
412
428
|
if (!this._decIconInactive) {
|
|
413
429
|
this._modifyValue(-this.step, true);
|
|
414
430
|
this._previousValue = this.value;
|
|
431
|
+
if (this._decIconDisabled) {
|
|
432
|
+
this._skipLiveAnnouncement = true;
|
|
433
|
+
this.input.focus();
|
|
434
|
+
}
|
|
415
435
|
}
|
|
416
436
|
}
|
|
417
437
|
|
|
@@ -60,6 +60,6 @@ export default function StepInputTemplate(this: UDExStepInput) {
|
|
|
60
60
|
></UDExControlButton>
|
|
61
61
|
</>)
|
|
62
62
|
}
|
|
63
|
-
<div class="hidden" aria-live="polite">{this.
|
|
63
|
+
<div class="hidden" aria-live="polite">{this._liveRegionText}</div>
|
|
64
64
|
</div>);
|
|
65
65
|
}
|
package/src/Tab.ts
CHANGED
|
@@ -299,6 +299,10 @@ class UDExTab extends UI5Element implements ITab {
|
|
|
299
299
|
return this.effectiveSelected && this.hasBodyText && this._isVertical;
|
|
300
300
|
}
|
|
301
301
|
|
|
302
|
+
get hasBodyTextOrLink(): boolean {
|
|
303
|
+
return this._isVertical && (this.hasBodyText || this.hasLinkSlot);
|
|
304
|
+
}
|
|
305
|
+
|
|
302
306
|
get hasLinkSlot(): boolean {
|
|
303
307
|
return this.link && this.link.length > 0;
|
|
304
308
|
}
|
|
@@ -314,10 +318,6 @@ class UDExTab extends UI5Element implements ITab {
|
|
|
314
318
|
return this.link.map(l => l.outerHTML).join("");
|
|
315
319
|
}
|
|
316
320
|
|
|
317
|
-
get hasBodyTextOrLink(): boolean {
|
|
318
|
-
return this._isVertical && (this.hasBodyText || this.hasLinkSlot);
|
|
319
|
-
}
|
|
320
|
-
|
|
321
321
|
get effectiveSelected(): boolean {
|
|
322
322
|
return this.selected || this._selected;
|
|
323
323
|
}
|
package/src/TabNavigation.hbs
CHANGED
|
@@ -4,6 +4,16 @@
|
|
|
4
4
|
class="udex-tab-navigation__header"
|
|
5
5
|
part="tab-navigation-header"
|
|
6
6
|
@keydown="{{handleKeyDown}}">
|
|
7
|
+
{{#if showPlayButton}}
|
|
8
|
+
<udex-button
|
|
9
|
+
class="udex-tab-navigation__play-button"
|
|
10
|
+
design="Tertiary"
|
|
11
|
+
size="Large"
|
|
12
|
+
icon="{{playBtnIcon}}"
|
|
13
|
+
tooltip="{{playBtnTooltipText}}"
|
|
14
|
+
@click="{{onPlayButtonClick}}">
|
|
15
|
+
</udex-button>
|
|
16
|
+
{{/if}}
|
|
7
17
|
<div
|
|
8
18
|
id="{{_id}}-header-tabs"
|
|
9
19
|
class="udex-tab-navigation__header-tabs"
|
|
@@ -49,6 +59,11 @@
|
|
|
49
59
|
{{#if this._overflowItems.length}}
|
|
50
60
|
{{tabNavigationPopover}}
|
|
51
61
|
{{/if}}
|
|
62
|
+
{{#if showFooterSlot}}
|
|
63
|
+
<div class="udex-tab-navigation__footer" part="tab-navigation-footer">
|
|
64
|
+
<slot name="footer"></slot>
|
|
65
|
+
</div>
|
|
66
|
+
{{/if}}
|
|
52
67
|
</div>
|
|
53
68
|
<div
|
|
54
69
|
class="udex-tab-navigation__content"
|
package/src/TabNavigation.ts
CHANGED
|
@@ -18,9 +18,11 @@ import Icon from "@ui5/webcomponents/dist/Icon.js";
|
|
|
18
18
|
import "@ui5/webcomponents-icons/dist/navigation-down-arrow.js";
|
|
19
19
|
import i18n from "@ui5/webcomponents-base/dist/decorators/i18n.js";
|
|
20
20
|
import type I18nBundle from "@ui5/webcomponents-base/dist/i18nBundle.js";
|
|
21
|
-
import { MORE } from "./generated/i18n/i18n-defaults.js";
|
|
21
|
+
import { MORE, PLAY_BUTTON_ACCESSIBLE_NAME, PAUSE_BUTTON_ACCESSIBLE_NAME } from "./generated/i18n/i18n-defaults.js";
|
|
22
22
|
import { BreakpointUtils } from "./utils/Breakpoints.js";
|
|
23
23
|
import "@ui5/webcomponents-icons/dist/slim-arrow-right.js";
|
|
24
|
+
import "@ui5/webcomponents-icons/dist/play.js";
|
|
25
|
+
import "@ui5/webcomponents-icons/dist/pause.js";
|
|
24
26
|
import UDExButton from "./Button.js";
|
|
25
27
|
|
|
26
28
|
// Templates
|
|
@@ -49,6 +51,16 @@ export enum UDExTabNavigationOrientation {
|
|
|
49
51
|
Vertical = "Vertical",
|
|
50
52
|
}
|
|
51
53
|
|
|
54
|
+
export enum UDExTabNavigationPlacement {
|
|
55
|
+
Start = "Start",
|
|
56
|
+
End = "End",
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
export enum UDExTabNavigationVerticalAlignment {
|
|
60
|
+
Top = "Top",
|
|
61
|
+
Center = "Center",
|
|
62
|
+
}
|
|
63
|
+
|
|
52
64
|
type UDExTabNavigationClickDetail = {
|
|
53
65
|
currentPage: number
|
|
54
66
|
}
|
|
@@ -132,6 +144,53 @@ class UDExTabNavigation extends UI5Element {
|
|
|
132
144
|
@property()
|
|
133
145
|
orientation: `${UDExTabNavigationOrientation}` = UDExTabNavigationOrientation.Horizontal;
|
|
134
146
|
|
|
147
|
+
/**
|
|
148
|
+
* Defines the placement of the tab strip relative to the content area.
|
|
149
|
+
* Applies to Vertical orientation only.
|
|
150
|
+
*
|
|
151
|
+
* @public
|
|
152
|
+
* @default "Start"
|
|
153
|
+
*/
|
|
154
|
+
@property()
|
|
155
|
+
placement: `${UDExTabNavigationPlacement}` = UDExTabNavigationPlacement.Start;
|
|
156
|
+
|
|
157
|
+
/**
|
|
158
|
+
* Defines the vertical alignment of the tab strip relative to the content area.
|
|
159
|
+
* Applies to Vertical orientation only.
|
|
160
|
+
*
|
|
161
|
+
* @public
|
|
162
|
+
* @default "Top"
|
|
163
|
+
*/
|
|
164
|
+
@property()
|
|
165
|
+
verticalAlignment: `${UDExTabNavigationVerticalAlignment}` = UDExTabNavigationVerticalAlignment.Top;
|
|
166
|
+
|
|
167
|
+
/**
|
|
168
|
+
* Enables automatic tab switching for Vertical orientation.
|
|
169
|
+
*
|
|
170
|
+
* @public
|
|
171
|
+
* @default false
|
|
172
|
+
*/
|
|
173
|
+
@property({ type: Boolean })
|
|
174
|
+
autoPlay: boolean = false;
|
|
175
|
+
|
|
176
|
+
/**
|
|
177
|
+
* Defines the interval in milliseconds between automatic tab switches.
|
|
178
|
+
* Applies only when autoPlay is enabled.
|
|
179
|
+
*
|
|
180
|
+
* @public
|
|
181
|
+
* @default 5000
|
|
182
|
+
*/
|
|
183
|
+
@property({ type: Number })
|
|
184
|
+
autoPlayInterval: number = 5000;
|
|
185
|
+
|
|
186
|
+
/**
|
|
187
|
+
* Indicates whether the auto-play is paused.
|
|
188
|
+
*
|
|
189
|
+
* @private
|
|
190
|
+
*/
|
|
191
|
+
@property({ type: Boolean, noAttribute: true })
|
|
192
|
+
_isPaused: boolean = false;
|
|
193
|
+
|
|
135
194
|
/**
|
|
136
195
|
* Defines the background color of the component.
|
|
137
196
|
*
|
|
@@ -182,6 +241,16 @@ class UDExTabNavigation extends UI5Element {
|
|
|
182
241
|
})
|
|
183
242
|
items!: Array<ITab>;
|
|
184
243
|
|
|
244
|
+
/**
|
|
245
|
+
* Defines optional content rendered below the tab list in Vertical orientation.
|
|
246
|
+
* Use to place a button or any action element beneath the tabs.
|
|
247
|
+
*
|
|
248
|
+
* @slot footer
|
|
249
|
+
* @public
|
|
250
|
+
*/
|
|
251
|
+
@slot({ type: HTMLElement })
|
|
252
|
+
footer!: Array<HTMLElement>;
|
|
253
|
+
|
|
185
254
|
@i18n("@sapudex/web-components")
|
|
186
255
|
static i18nBundle: I18nBundle;
|
|
187
256
|
|
|
@@ -192,6 +261,7 @@ class UDExTabNavigation extends UI5Element {
|
|
|
192
261
|
_isExpanded: boolean = false;
|
|
193
262
|
_maxTitleLength: number = 25;
|
|
194
263
|
_maxTitleLengthInSecondLines: number = this._maxTitleLength * 2;
|
|
264
|
+
_autoPlayTimer?: number;
|
|
195
265
|
|
|
196
266
|
constructor() {
|
|
197
267
|
super();
|
|
@@ -217,11 +287,20 @@ class UDExTabNavigation extends UI5Element {
|
|
|
217
287
|
if (isDesktop()) {
|
|
218
288
|
this.setAttribute("desktop", "");
|
|
219
289
|
}
|
|
290
|
+
if (this.showPlayButton) {
|
|
291
|
+
const prefersReducedMotion = window.matchMedia("(prefers-reduced-motion: reduce)").matches;
|
|
292
|
+
if (prefersReducedMotion) {
|
|
293
|
+
this._isPaused = true;
|
|
294
|
+
} else {
|
|
295
|
+
this._startAutoPlay();
|
|
296
|
+
}
|
|
297
|
+
}
|
|
220
298
|
}
|
|
221
299
|
|
|
222
300
|
onExitDOM(): void {
|
|
223
301
|
ResizeHandler.deregister(this.getHeader(), this._handleResizeBound);
|
|
224
302
|
window.removeEventListener("resize", this._handleWindowResizeBound);
|
|
303
|
+
this._stopAutoPlay();
|
|
225
304
|
}
|
|
226
305
|
|
|
227
306
|
_handleWindowResize() {
|
|
@@ -334,6 +413,10 @@ class UDExTabNavigation extends UI5Element {
|
|
|
334
413
|
this._selectedTab = this.items[selectedTabIndex] as Tab;
|
|
335
414
|
this.updateSelectedTab(selectedTabIndex);
|
|
336
415
|
this.emitClickEvent(selectedTabIndex + 1);
|
|
416
|
+
|
|
417
|
+
if (this.showPlayButton && !this._isPaused) {
|
|
418
|
+
this._startAutoPlay();
|
|
419
|
+
}
|
|
337
420
|
}
|
|
338
421
|
|
|
339
422
|
getTab(el: HTMLElement | null): Tab | false {
|
|
@@ -921,6 +1004,56 @@ class UDExTabNavigation extends UI5Element {
|
|
|
921
1004
|
tab._isMobile = isMobile;
|
|
922
1005
|
});
|
|
923
1006
|
}
|
|
1007
|
+
|
|
1008
|
+
_startAutoPlay(): void {
|
|
1009
|
+
this._stopAutoPlay();
|
|
1010
|
+
this._isPaused = false;
|
|
1011
|
+
this._autoPlayTimer = window.setInterval(() => {
|
|
1012
|
+
this._advanceTab();
|
|
1013
|
+
}, this.autoPlayInterval);
|
|
1014
|
+
}
|
|
1015
|
+
|
|
1016
|
+
_stopAutoPlay(): void {
|
|
1017
|
+
if (this._autoPlayTimer !== undefined) {
|
|
1018
|
+
window.clearInterval(this._autoPlayTimer);
|
|
1019
|
+
this._autoPlayTimer = undefined;
|
|
1020
|
+
}
|
|
1021
|
+
}
|
|
1022
|
+
|
|
1023
|
+
_advanceTab(): void {
|
|
1024
|
+
const currentIndex = (this.items as Array<Tab>).findIndex(item => item === this._selectedTab);
|
|
1025
|
+
const nextIndex = (currentIndex + 1) % this.items.length;
|
|
1026
|
+
this._selectedTab = this.items[nextIndex] as Tab;
|
|
1027
|
+
this.updateSelectedTab(nextIndex);
|
|
1028
|
+
this.emitClickEvent(nextIndex + 1);
|
|
1029
|
+
}
|
|
1030
|
+
|
|
1031
|
+
onPlayButtonClick(): void {
|
|
1032
|
+
if (this._isPaused) {
|
|
1033
|
+
this._startAutoPlay();
|
|
1034
|
+
} else {
|
|
1035
|
+
this._stopAutoPlay();
|
|
1036
|
+
this._isPaused = true;
|
|
1037
|
+
}
|
|
1038
|
+
}
|
|
1039
|
+
|
|
1040
|
+
get showPlayButton(): boolean {
|
|
1041
|
+
return this.isVertical && this.autoPlay;
|
|
1042
|
+
}
|
|
1043
|
+
|
|
1044
|
+
get showFooterSlot(): boolean {
|
|
1045
|
+
return this.isVertical && this.footer?.length > 0;
|
|
1046
|
+
}
|
|
1047
|
+
|
|
1048
|
+
get playBtnIcon(): string {
|
|
1049
|
+
return this._isPaused ? "play" : "pause";
|
|
1050
|
+
}
|
|
1051
|
+
|
|
1052
|
+
get playBtnTooltipText(): string {
|
|
1053
|
+
return this._isPaused
|
|
1054
|
+
? translate(UDExTabNavigation, PLAY_BUTTON_ACCESSIBLE_NAME)
|
|
1055
|
+
: translate(UDExTabNavigation, PAUSE_BUTTON_ACCESSIBLE_NAME);
|
|
1056
|
+
}
|
|
924
1057
|
}
|
|
925
1058
|
|
|
926
1059
|
UDExTabNavigation.define();
|