Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions packages/fiori/src/themes/ShellBar.css
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,16 @@
--_ui5_button_focused_border: var(--_ui5_shellbar_button_focused_border);
}

/* ============================================================================
CONTENT SLOT BUTTONS
============================================================================ */

::slotted([ui5-button][slot^="content"]),
::slotted([ui5-toggle-button][slot^="content"]) {
height: 2.25rem;
min-width: 2.25rem;
}

/* ============================================================================
ACTION BUTTONS (Items & Internal Actions)
============================================================================ */
Expand Down
186 changes: 186 additions & 0 deletions packages/fiori/test/pages/ShellBar_Overflow.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,186 @@
<!DOCTYPE html>
<html>

<head>
<meta charset="utf-8">
<title>Shell Bar - Application-Level Overflow</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">

<script src="%VITE_BUNDLE_PATH%" type="module"></script>
<link rel="stylesheet" type="text/css" href="./styles/ShellBar.css">

<style>
#popoverContent {
padding: 0.5rem;
display: flex;
flex-direction: column;
gap: 0.5rem;
}
</style>
</head>

<body class="shellbar1auto">

<ui5-popover id="popover" placement="Bottom" horizontal-align="End">
<div id="popoverContent"></div>
</ui5-popover>

<div id="container" style="width: 100%;">
<ui5-shellbar id="shellbar" show-notifications>
<ui5-button icon="menu2" slot="startButton"></ui5-button>
<ui5-shellbar-branding slot="branding">
Analytics Dashboard
<img src="https://upload.wikimedia.org/wikipedia/commons/5/59/SAP_2011_logo.svg" slot="logo" />
</ui5-shellbar-branding>
<ui5-avatar slot="profile" initials="AD"></ui5-avatar>
</ui5-shellbar>
</div>

<div style="display: flex; align-items: center; gap: 1rem; margin-top: 1.5rem; padding: 0 1rem;">
<ui5-label for="slider">Resize ShellBar:</ui5-label>
<ui5-slider id="slider" style="flex: 1;" min="30" max="100" value="100" show-tooltip></ui5-slider>
</div>

<script>
const shellbar = document.getElementById("shellbar");
const popover = document.getElementById("popover");
const popoverContent = document.getElementById("popoverContent");

// Shared state
const state = {
region: "na",
liveMode: true,
hiddenIds: new Set()
};

// Item definitions
const items = [
{
id: "regionSelect",
create: () => {
const el = document.createElement("ui5-select");
["North America:na", "Europe:eu", "Asia Pacific:apac"].forEach(item => {
const [text, value] = item.split(":");
const opt = document.createElement("ui5-option");
opt.textContent = text;
opt.value = value;
if (value === state.region) opt.selected = true;
el.appendChild(opt);
});
el.addEventListener("ui5-change", (e) => {
state.region = e.detail.selectedOption.value;
syncAll();
});
return el;
},
sync: (el) => {
const opt = el.querySelector(`ui5-option[value="${state.region}"]`);
if (opt) opt.selected = true;
}
},
{
id: "devTag",
create: () => {
const el = document.createElement("ui5-tag");
el.textContent = "Development";
return el;
}
},
{
id: "spacer",
create: () => document.createElement("ui5-shellbar-spacer")
},
{
id: "refreshBtn",
create: () => {
const el = document.createElement("ui5-button");
el.icon = "refresh";
el.textContent = "Refresh";
return el;
}
},
{
id: "liveSwitch",
create: () => {
const wrapper = document.createElement("div");
wrapper.style.cssText = "display: flex; align-items: center; gap: 0.5rem;";
const sw = document.createElement("ui5-switch");
sw.checked = state.liveMode;
sw.addEventListener("ui5-change", (e) => {
state.liveMode = e.target.checked;
syncAll();
});
const label = document.createElement("ui5-label");
label.textContent = "Live";
wrapper.append(sw, label);
return wrapper;
},
sync: (el) => {
const sw = el.querySelector("ui5-switch");
if (sw) sw.checked = state.liveMode;
}
}
];

// Sync state to all elements (shellbar + popover)
function syncAll() {
items.forEach(item => {
if (!item.sync) return;
const shellbarEl = document.getElementById(item.id);
const popoverEl = document.getElementById(`${item.id}-popover`);
if (shellbarEl) item.sync(shellbarEl);
if (popoverEl) item.sync(popoverEl);
});
}

// Render items in shellbar
items.forEach((item, index) => {
const el = item.create();
el.id = item.id;
el.slot = "content";
el.dataset.hideOrder = String(index + 1);
shellbar.appendChild(el);
});

// Overflow button
const overflowBtn = document.createElement("ui5-button");
overflowBtn.icon = "slim-arrow-down";
overflowBtn.slot = "content";
overflowBtn.dataset.hideOrder = "999";
overflowBtn.addEventListener("click", () => {
popover.opener = overflowBtn;
popover.open = !popover.open;
});

// Handle visibility changes
shellbar.addEventListener("content-item-visibility-change", (e) => {
state.hiddenIds = new Set(e.detail.items.map(el => el.id));

// Rebuild popover content
popoverContent.innerHTML = "";
items.forEach(item => {
if (state.hiddenIds.has(item.id)) {
const el = item.create();
el.id = `${item.id}-popover`;
popoverContent.appendChild(el);
}
});

// Show/hide overflow button
if (state.hiddenIds.size > 0) {
shellbar.prepend(overflowBtn);
} else {
overflowBtn.remove();
popover.open = false;
}
});

// Slider resize
document.getElementById("slider").addEventListener("input", (e) => {
document.getElementById("container").style.width = `${e.target.value}%`;
});
</script>

</body>

</html>
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import EmbeddedBackNavigation from "../../../_samples/fiori/ShellBar/EmbeddedBac
import MultipleNonProductiveInstances from "../../../_samples/fiori/ShellBar/MultipleNonProductiveInstances/MultipleNonProductiveInstances.md";
import MultipleProductiveInstances from "../../../_samples/fiori/ShellBar/MultipleProductiveInstances/MultipleProductiveInstances.md";
import TrialExample from "../../../_samples/fiori/ShellBar/TrialExample/TrialExample.md";
import Overflow from "../../../_samples/fiori/ShellBar/Overflow/Overflow.md";

<%COMPONENT_OVERVIEW%>

Expand Down Expand Up @@ -39,4 +40,9 @@ ShellBar setup for multiple productive system instances with region indicators.
### Multiple Non-Productive Instances
ShellBar setup for multiple non-productive system instances with system and region tags.

<MultipleNonProductiveInstances />
<MultipleNonProductiveInstances />

### Application-Level Overflow
This sample demonstrates how applications can implement custom overflow handling for content items. When the ShellBar becomes narrow, content items are hidden and the application renders them in a custom popover. The sample listens to the `content-item-visibility-change` event and manages its own overflow button and popover. Use the slider to resize and observe the overflow behavior.

<Overflow />
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
import html from '!!raw-loader!./sample.html';
import js from '!!raw-loader!./main.js';

<Editor html={html} js={js} />
59 changes: 59 additions & 0 deletions packages/website/docs/_samples/fiori/ShellBar/Overflow/main.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
import "@ui5/webcomponents/dist/Avatar.js";
import "@ui5/webcomponents/dist/Button.js";
import "@ui5/webcomponents/dist/Text.js";
import "@ui5/webcomponents/dist/Tag.js";
import "@ui5/webcomponents/dist/Label.js";
import "@ui5/webcomponents/dist/Slider.js";
import "@ui5/webcomponents/dist/Popover.js";

import "@ui5/webcomponents-fiori/dist/ShellBar.js";
import "@ui5/webcomponents-fiori/dist/ShellBarBranding.js";
import "@ui5/webcomponents-fiori/dist/ShellBarSpacer.js";
import "@ui5/webcomponents-fiori/dist/ShellBarItem.js";

import "@ui5/webcomponents/dist/Icon.js";

import "@ui5/webcomponents-icons/dist/menu2.js";
import "@ui5/webcomponents-icons/dist/slim-arrow-down.js";
import "@ui5/webcomponents-icons/dist/example.js";
import "@ui5/webcomponents-icons/dist/sys-help.js";

const shellbar = document.getElementById("shellbar");
const popover = document.getElementById("popover");
const popoverContent = document.getElementById("popover-content");

// Create overflow button (added to shellbar when items are hidden)
const overflowBtn = document.createElement("ui5-button");
overflowBtn.icon = "slim-arrow-down";
overflowBtn.slot = "content";
overflowBtn.dataset.hideOrder = "999"; // Never hide the overflow button
overflowBtn.addEventListener("click", () => {
popover.opener = overflowBtn;
popover.open = !popover.open;
});

// Listen for content items becoming hidden/visible
shellbar.addEventListener("content-item-visibility-change", (e) => {
const hiddenItems = e.detail.items;

// Update popover with clones of hidden items
popoverContent.innerHTML = "";
hiddenItems.forEach(item => {
const clone = item.cloneNode(true);
clone.removeAttribute("slot");
popoverContent.appendChild(clone);
});

// Show/hide overflow button based on whether items are hidden
if (hiddenItems.length > 0) {
shellbar.prepend(overflowBtn);
} else {
overflowBtn.remove();
popover.open = false;
}
});

// Slider to resize shellbar container
document.getElementById("slider").addEventListener("input", (e) => {
document.getElementById("container").style.width = `${e.target.value}%`;
});
50 changes: 50 additions & 0 deletions packages/website/docs/_samples/fiori/ShellBar/Overflow/sample.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
<!-- playground-fold -->
<!DOCTYPE html>
<html lang="en">

<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Sample</title>
</head>

<body style="background-color: var(--sapBackgroundColor); height: 200px;">
<!-- playground-fold-end -->

<ui5-popover id="popover" placement="Bottom" horizontal-align="End">
<div id="popover-content" style="padding: 0.5rem; display: flex; flex-direction: column; gap: 0.5rem;"></div>
</ui5-popover>

<div id="container">
<ui5-shellbar id="shellbar" show-notifications>
<ui5-button icon="menu2" slot="startButton"></ui5-button>
<ui5-shellbar-branding slot="branding">
Product
<img slot="logo" src="../assets/images/sap-logo-svg.svg" />
</ui5-shellbar-branding>

<!-- Content items with data-hide-order defining hide priority -->
<ui5-text slot="content" data-hide-order="1">Customer Rainbird</ui5-text>
<ui5-tag slot="content" design="Set2" color-scheme="4">
<ui5-icon slot="icon" name="example"></ui5-icon>
Development - System 1
</ui5-tag>

<ui5-shellbar-item icon="sys-help" text="Help"></ui5-shellbar-item>

<ui5-avatar slot="profile">
<img src="../assets/images/avatars/man_avatar_3.png" />
</ui5-avatar>
</ui5-shellbar>
</div>

<br>
<ui5-label for="slider">Resize:</ui5-label>
<ui5-slider id="slider" min="30" max="100" value="100" label-interval="0" show-tooltip></ui5-slider>

<!-- playground-fold -->
<script type="module" src="main.js"></script>
</body>

</html>
<!-- playground-fold-end -->
Loading