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
31 changes: 31 additions & 0 deletions packages/fiori/src/ShellBarSearch.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,18 @@
import property from "@ui5/webcomponents-base/dist/decorators/property.js";
import slot from "@ui5/webcomponents-base/dist/decorators/slot.js";
import customElement from "@ui5/webcomponents-base/dist/decorators/customElement.js";
import Search from "./Search.js";
import { isPhone } from "@ui5/webcomponents-base/dist/Device.js";
import ShellBarSearchTemplate from "./ShellBarSearchTemplate.js";
import ShellBarSearchCss from "./generated/themes/ShellBarSearch.css.js";
import BusyIndicatorSize from "@ui5/webcomponents/dist/types/BusyIndicatorSize.js";

import {
SEARCH_FIELD_SEARCH_ICON,
SHELLBAR_SEARCH_EXPANDED,
SHELLBAR_SEARCH_COLLAPSED,
} from "./generated/i18n/i18n-defaults.js";
import type BusyState from "@ui5/webcomponents/dist/BusyState.js";

/**
* @class
Expand Down Expand Up @@ -38,6 +41,13 @@ class ShellBarSearch extends Search {
@property({ type: Boolean })
autoOpen = false;

/**
* Defines the busy state configuration for the search field.
* @public
*/
@slot({ type: HTMLElement, invalidateOnChildChange: true })
busyState!: Array<BusyState>;

_handleSearchIconPress() {
super._handleSearchIconPress();

Expand Down Expand Up @@ -98,6 +108,27 @@ class ShellBarSearch extends Search {
this.collapsed = true;
}
}

/**
* Returns the busy state configuration based on the slotted ui5-busy-state element.
* @private
*/
get busyStateConfig(): { active: boolean; size: `${BusyIndicatorSize}` } {
if (this.busyState.length === 0) {
return { active: false, size: BusyIndicatorSize.M };
}

const busyStateElement = this.busyState[0];

// If size is Auto, use the component's default (S for collapsed, M for expanded)
const defaultSize = this.collapsed ? BusyIndicatorSize.S : BusyIndicatorSize.M;
const size = busyStateElement.size === "Auto" ? defaultSize : busyStateElement.size;

return {
active: busyStateElement.active,
size,
};
}
}

ShellBarSearch.define();
Expand Down
11 changes: 10 additions & 1 deletion packages/fiori/src/ShellBarSearchTemplate.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,20 @@
import BusyIndicator from "@ui5/webcomponents/dist/BusyIndicator.js";
import SearchFieldTemplate from "./SearchFieldTemplate.js";
import type ShellBarSearch from "./ShellBarSearch.js";
import ShellBarSearchPopoverTemplate from "./ShellBarSearchPopoverTemplate.js";

export default function ShellBarSearchTemplate(this: ShellBarSearch) {
return (
<>
{ SearchFieldTemplate.call(this) }
<BusyIndicator
size={this.busyStateConfig.size}
active={this.busyStateConfig.active}
style={{
width: this.collapsed ? "" : "100%",
}}
>
{ SearchFieldTemplate.call(this) }
</BusyIndicator>
{ ShellBarSearchPopoverTemplate.call(this) }
</>
);
Expand Down
161 changes: 161 additions & 0 deletions packages/fiori/test/pages/ShellBar_busy_search_poc.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,161 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>ShellBar - Busy Search POC</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">

<script data-ui5-config type="application/json">
{
"rtl": false
}
</script>

<script src="%VITE_BUNDLE_PATH%" type="module"></script>

<style>
body {
font-family: "72", "72full", Arial, Helvetica, sans-serif;
padding: 1rem;
}

.demo-section {
margin-bottom: 2rem;
}

h2 {
margin-bottom: 1rem;
}

.controls {
margin-bottom: 1rem;
}

code {
background: #f5f5f5;
padding: 2px 6px;
border-radius: 3px;
font-family: monospace;
}

p {
margin: 0.5rem 0;
}
</style>
</head>

<body>
<h1>ShellBar Search with Busy State - POC</h1>
<p><strong>Pattern:</strong> Data provider component pattern with <code>ui5-busy-state</code></p>
<p><strong>Implementation:</strong> Abstract ui5-busy-state component provides configuration, BusyIndicator rendered internally</p>

<div class="demo-section">
<h2>ShellBar with Busy Search (Size: Auto → M)</h2>
<p>Using <code>size="Auto"</code> lets ShellBarSearch decide the default size (M).</p>

<div class="controls">
<ui5-button id="toggleBusyShellBar">Toggle Busy State</ui5-button>
</div>

<ui5-shellbar
id="shellbar"
primary-title="Corporate Portal"
secondary-title="secondary title"
show-notifications
notifications-count="22">

<ui5-shellbar-search
id="shellbarSearch"
slot="searchField"
placeholder="Search...">
<ui5-busy-state slot="busyState" size="Auto"></ui5-busy-state>
</ui5-shellbar-search>

<ui5-avatar slot="profile" initials="JD"></ui5-avatar>
</ui5-shellbar>
</div>

<div class="demo-section">
<h2>Standalone with Size M</h2>
<p>Explicitly setting <code>size="M"</code>.</p>

<div class="controls">
<ui5-button id="toggleBusyStandalone">Toggle Busy State</ui5-button>
</div>

<ui5-shellbar-search
id="standaloneSearch"
placeholder="Search items...">
<ui5-busy-state id="standaloneBusyState" slot="busyState" size="M"></ui5-busy-state>
</ui5-shellbar-search>
</div>

<div class="demo-section">
<h2>Collapsed with Size S</h2>
<p>Using <code>size="S"</code> for small busy indicator.</p>

<div class="controls">
<ui5-button id="toggleBusyCollapsed">Toggle Busy State</ui5-button>
</div>

<ui5-shellbar-search
id="collapsedSearch"
collapsed
placeholder="Search...">
<ui5-busy-state id="collapsedBusyState" slot="busyState" size="S"></ui5-busy-state>
</ui5-shellbar-search>
</div>

<div class="demo-section">
<h2>With Size L</h2>
<p>Using <code>size="L"</code> for large busy indicator.</p>

<div class="controls">
<ui5-button id="toggleBusyLarge">Toggle Busy State</ui5-button>
</div>

<ui5-shellbar-search
id="largeSearch"
placeholder="Search...">
<ui5-busy-state id="largeBusyState" slot="busyState" size="L"></ui5-busy-state>
</ui5-shellbar-search>
</div>

<script>
// ShellBar example
const shellbarBusyState = document.getElementById("shellbarBusyState");
const toggleShellBar = document.getElementById("toggleBusyShellBar");

toggleShellBar.addEventListener("click", () => {
console.log("toggleShellBar clicked");
debugger;
shellbarBusyState.active = !shellbarBusyState.active;
});

// Standalone example
const standaloneBusyState = document.getElementById("standaloneBusyState");
const toggleStandalone = document.getElementById("toggleBusyStandalone");

toggleStandalone.addEventListener("click", () => {
standaloneBusyState.active = !standaloneBusyState.active;
});

// Collapsed example
const collapsedBusyState = document.getElementById("collapsedBusyState");
const toggleCollapsed = document.getElementById("toggleBusyCollapsed");

toggleCollapsed.addEventListener("click", () => {
collapsedBusyState.active = !collapsedBusyState.active;
});

// Large example
const largeBusyState = document.getElementById("largeBusyState");
const toggleLarge = document.getElementById("toggleBusyLarge");

toggleLarge.addEventListener("click", () => {
largeBusyState.active = !largeBusyState.active;
});
</script>
</body>
</html>

58 changes: 58 additions & 0 deletions packages/main/src/BusyState.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
import UI5Element from "@ui5/webcomponents-base/dist/UI5Element.js";
import customElement from "@ui5/webcomponents-base/dist/decorators/customElement.js";
import property from "@ui5/webcomponents-base/dist/decorators/property.js";
import type BusyIndicatorSize from "./types/BusyIndicatorSize.js";

/**
* @class
*
* ### Overview
*
* The `ui5-busy-state` component is an abstract data provider component that configures
* busy state behavior in other components. It does not render anything itself, but provides
* configuration properties that parent components read to display busy indicators.
*
* ### Usage
*
* This component is meant to be slotted into components that support busy state configuration,
* such as `ui5-shellbar-search`.
*
* ```html
* <ui5-shellbar-search>
* <ui5-busy-state slot="busyState" active size="M"></ui5-busy-state>
* </ui5-shellbar-search>
* ```
*
* ### ES6 Module Import
*
* `import "@ui5/webcomponents/dist/BusyState.js";`
*
* @constructor
* @extends UI5Element
* @public
* @since 2.17.0
*/
@customElement({
tag: "ui5-busy-state",
})
class BusyState extends UI5Element {
/**
* Defines whether the busy state is active.
* @default false
* @public
*/
@property({ type: Boolean })
active = false;

/**
* Defines the size of the busy indicator.
* @default "Auto"
* @public
*/
@property()
size: `${BusyIndicatorSize}` = "Auto";
}

BusyState.define();

export default BusyState;
1 change: 1 addition & 0 deletions packages/main/src/bundle.esm.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ import AvatarGroup from "./AvatarGroup.js";
import Bar from "./Bar.js";
import Breadcrumbs from "./Breadcrumbs.js";
import BusyIndicator from "./BusyIndicator.js";
import BusyState from "./BusyState.js";
import Button from "./Button.js";
import ButtonBadge from "./ButtonBadge.js";
import Card from "./Card.js";
Expand Down
7 changes: 7 additions & 0 deletions packages/main/src/types/BusyIndicatorSize.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,13 @@
* @public
*/
enum BusyIndicatorSize {
/**
* automatic size (component decides)
* @public
* @since 2.17.0
*/
Auto = "Auto",

/**
* small size
* @public
Expand Down
Loading