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
23 changes: 23 additions & 0 deletions packages/main/src/Input.ts
Original file line number Diff line number Diff line change
Expand Up @@ -816,6 +816,9 @@ class Input extends UI5Element implements SuggestionComponent, IFormInputElement
}

onAfterRendering() {
// Add class to interactive icons for styling
this._styleInteractiveIcons();

if (this.showSuggestions && this.Suggestions?._getPicker()) {
this._listWidth = this.Suggestions._getListWidth();

Expand Down Expand Up @@ -846,6 +849,26 @@ class Input extends UI5Element implements SuggestionComponent, IFormInputElement
}
}

_styleInteractiveIcons() {
// Add a class to interactive icons so CSS can style them
this.icon.forEach(iconEl => {
const isInteractive = (iconEl as any).mode === "Interactive";
if (isInteractive) {
iconEl.classList.add("ui5-input-icon-interactive");
// Make the icon host focusable so clicking anywhere (including padding) focuses it
iconEl.setAttribute("tabindex", "0");
// Remove tabindex from the SVG inside so only the host is focusable
const svg = iconEl.shadowRoot?.querySelector("svg");
if (svg) {
svg.removeAttribute("tabindex");
}
} else {
iconEl.classList.remove("ui5-input-icon-interactive");
iconEl.removeAttribute("tabindex");
}
});
}

_adjustSelectionRange() {
const innerInput = this.getInputDOMRefSync()!;
const visibleItems = this.Suggestions?._getItems().filter(item => !item.hidden) as IInputSuggestionItemSelectable[];
Expand Down
11 changes: 11 additions & 0 deletions packages/main/src/themes/Icon.css
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,17 @@
border-radius: var(--ui5-icon-focus-border-radius);
}

/* Interactive icons inside Input - constrain SVG size to 1rem and suppress focus (Input handles it) */
:host(.ui5-input-icon-interactive) .ui5-icon-root {
height: 1rem;
width: 1rem;
}

:host(.ui5-input-icon-interactive[desktop]) .ui5-icon-root:focus,
:host(.ui5-input-icon-interactive) .ui5-icon-root:focus-visible {
outline: none;
}

.ui5-icon-root {
display:flex;
height: 100%;
Expand Down
129 changes: 99 additions & 30 deletions packages/main/src/themes/Input.css
Original file line number Diff line number Diff line change
Expand Up @@ -389,53 +389,122 @@
align-items: center;
}

/* TODO: Remove this after parser is fixed
- this statement is transformed to [ui5-multi-combobox] [ui5-icon] which
affects all icons in the combobox incuding these in the list items
*/
::slotted([ui5-icon][slot="icon"]) {
/* Style interactive icons directly - they look like buttons */
/* Interactive icons with button-like styling */
::slotted([ui5-icon][slot="icon"].ui5-input-icon-interactive) {
align-self: start;
padding: var(--_ui5_input_custom_icon_padding);
/* Normalize like libraries overrule the selector, thefore we need !important */
box-sizing: content-box !important;
color: var(--_ui5_input_icon_color);
cursor: pointer;
padding: 0;
width: var(--_ui5_input_icon_width);
min-width: var(--_ui5_input_icon_width);
height: var(--_ui5_input_icon_wrapper_height);
display: flex;
align-items: center;
justify-content: center;
background-color: transparent;
border-radius: var(--_ui5_input_icon_border_radius);
transition: background 0.1s ease-in-out;
outline: none;
box-sizing: border-box;
font-size: 1rem;
flex-shrink: 0;
}

::slotted([ui5-icon][slot="icon"].ui5-input-icon-interactive:hover) {
background: var(--_ui5_input_icon_hover_bg);
box-shadow: var(--_ui5_input_icon_box_shadow);
}

::slotted([ui5-icon][slot="icon"].ui5-input-icon-interactive:focus),
::slotted([ui5-icon][slot="icon"].ui5-input-icon-interactive:focus-visible) {
outline: var(--sapContent_FocusWidth) var(--sapContent_FocusStyle) var(--sapContent_FocusColor);
outline-offset: -2px;
background: var(--_ui5_input_icon_hover_bg);
box-shadow: var(--_ui5_input_icon_box_shadow);
}

::slotted([ui5-icon][slot="icon"].ui5-input-icon-interactive:active) {
background-color: var(--sapButton_Active_Background);
color: var(--_ui5_input_icon_pressed_color);
box-shadow: var(--_ui5_input_icon_box_shadow);
border-inline-start: var(--_ui5_select_hover_icon_left_border);
}

/* Value state specific focus colors */
:host([value-state="Negative"]) ::slotted([ui5-icon][slot="icon"].ui5-input-icon-interactive:focus),
:host([value-state="Negative"]) ::slotted([ui5-icon][slot="icon"].ui5-input-icon-interactive:focus-visible) {
outline-color: var(--_ui5_input_focused_value_state_error_focus_outline_color);
box-shadow: var(--_ui5_input_error_icon_box_shadow);
}

:host([value-state="Critical"]) ::slotted([ui5-icon][slot="icon"].ui5-input-icon-interactive:focus),
:host([value-state="Critical"]) ::slotted([ui5-icon][slot="icon"].ui5-input-icon-interactive:focus-visible) {
outline-color: var(--_ui5_input_focused_value_state_warning_focus_outline_color);
box-shadow: var(--_ui5_input_warning_icon_box_shadow);
}

:host([value-state="Positive"]) ::slotted([ui5-icon][slot="icon"].ui5-input-icon-interactive:focus),
:host([value-state="Positive"]) ::slotted([ui5-icon][slot="icon"].ui5-input-icon-interactive:focus-visible) {
outline-color: var(--_ui5_input_focused_value_state_success_focus_outline_color);
box-shadow: var(--_ui5_input_success_icon_box_shadow);
}

:host([value-state="Information"]) ::slotted([ui5-icon][slot="icon"].ui5-input-icon-interactive:focus),
:host([value-state="Information"]) ::slotted([ui5-icon][slot="icon"].ui5-input-icon-interactive:focus-visible) {
box-shadow: var(--_ui5_input_information_icon_box_shadow);
}

/* Value state specific hover box-shadows */
:host([value-state="Negative"]) ::slotted([ui5-icon][slot="icon"].ui5-input-icon-interactive:hover) {
box-shadow: var(--_ui5_input_error_icon_box_shadow);
}

:host([value-state="Critical"]) ::slotted([ui5-icon][slot="icon"].ui5-input-icon-interactive:hover) {
box-shadow: var(--_ui5_input_warning_icon_box_shadow);
}

:host([value-state="Positive"]) ::slotted([ui5-icon][slot="icon"].ui5-input-icon-interactive:hover) {
box-shadow: var(--_ui5_input_success_icon_box_shadow);
}

:host([value-state="Negative"]) .inputIcon,
:host([value-state="Critical"]) .inputIcon{
padding: var(--_ui5_input_error_warning_icon_padding);
:host([value-state="Information"]) ::slotted([ui5-icon][slot="icon"].ui5-input-icon-interactive:hover) {
box-shadow: var(--_ui5_input_information_icon_box_shadow);
}

:host([value-state="Negative"][focused]) .inputIcon,
:host([value-state="Critical"][focused]) .inputIcon{
padding: var(--_ui5_input_error_warning_focused_icon_padding);
/* Decorative icons keep their normal styling */
::slotted([ui5-icon][slot="icon"]:not(.ui5-input-icon-interactive)) {
align-self: start;
padding: var(--_ui5_input_custom_icon_padding);
box-sizing: content-box;
color: var(--_ui5_input_icon_color);
}

:host([value-state="Information"]) .inputIcon {
padding: var(--_ui5_input_information_icon_padding);
/* Adjust height for value states with thicker borders (Negative, Critical, Information) */
:host([value-state]:not([value-state="None"]):not([value-state="Positive"])) ::slotted([ui5-icon][slot="icon"].ui5-input-icon-interactive) {
--_ui5_input_icon_wrapper_height: var(--_ui5_input_icon_wrapper_state_height);
}

:host([value-state="Information"][focused]) .inputIcon {
padding: var(--_ui5_input_information_focused_icon_padding);
/* Adjust height for Positive state */
:host([value-state="Positive"]) ::slotted([ui5-icon][slot="icon"].ui5-input-icon-interactive) {
--_ui5_input_icon_wrapper_height: var(--_ui5_input_icon_wrapper_success_state_height);
}

:host([value-state="Negative"]) ::slotted(.inputIcon[ui5-icon]),
:host([value-state="Negative"]) ::slotted([ui5-icon][slot="icon"]),
:host([value-state="Critical"]) ::slotted([ui5-icon][slot="icon"]) {
padding: var(--_ui5_input_error_warning_custom_icon_padding);
/* Value state styling for interactive icons - pressed color */
:host([value-state="Negative"]) ::slotted([ui5-icon][slot="icon"].ui5-input-icon-interactive) {
--_ui5_input_icon_pressed_color: var(--_ui5_input_icon_error_pressed_color);
}

:host([value-state="Negative"][focused]) ::slotted(.inputIcon[ui5-icon]),
:host([value-state="Negative"][focused]) ::slotted([ui5-icon][slot="icon"]),
:host([value-state="Critical"][focused]) ::slotted([ui5-icon][slot="icon"]) {
padding: var(--_ui5_input_error_warning_custom_focused_icon_padding);
:host([value-state="Critical"]) ::slotted([ui5-icon][slot="icon"].ui5-input-icon-interactive) {
--_ui5_input_icon_pressed_color: var(--_ui5_input_icon_warning_pressed_color);
}

:host([value-state="Information"]) ::slotted([ui5-icon][slot="icon"]) {
padding: var(--_ui5_input_information_custom_icon_padding);
:host([value-state="Information"]) ::slotted([ui5-icon][slot="icon"].ui5-input-icon-interactive) {
--_ui5_input_icon_pressed_color: var(--_ui5_input_icon_information_pressed_color);
}

:host([value-state="Information"][focused]) ::slotted([ui5-icon][slot="icon"]) {
padding: var(--_ui5_input_information_custom_focused_icon_padding);
:host([value-state="Positive"]) ::slotted([ui5-icon][slot="icon"].ui5-input-icon-interactive) {
--_ui5_input_icon_pressed_color: var(--_ui5_input_icon_success_pressed_color);
}

:host([value-state="Negative"]) .inputIcon:active,
Expand Down
Loading
Loading