Skip to content
Merged
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
84 changes: 84 additions & 0 deletions packages/main/cypress/specs/Select.cy.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -443,6 +443,76 @@ describe("Select - Accessibility", () => {
.find("#accessibleDescription")
.should("have.text", "First description Updated second description Third description");
});

it("should not display tooltip when Select is not readonly", () => {
cy.mount(
<Select style="width: 50px">
<Option selected>VeryLongOptionTextThatWillBeTruncated</Option>
<Option >Short</Option>
</Select>
);

cy.get("[ui5-select]")
.shadow()
.find(".ui5-select-root")
.should("not.have.attr", "title");
});

it("should display user tooltip with precedence over the default tooltip", () => {
cy.mount(
<Select style="width: 50px" tooltip="Custom tooltip" readonly>
<Option selected>VeryLongOptionTextThatWillBeTruncated</Option>
<Option >Short</Option>
</Select>
);

cy.get("[ui5-select]")
.shadow()
.find(".ui5-select-root")
.should("have.attr", "title", "Custom tooltip");
});

it("should display default tooltip (text + additionalText) if it is read-only and text is truncated, even if tooltip is not set", () => {
cy.mount(
<Select style="width: 50px" readonly>
<Option additionalText="AdditionalInfo" selected>VeryLongOptionText</Option>
<Option >Short</Option>
</Select>
);

cy.get("[ui5-select]")
.shadow()
.find(".ui5-select-root")
.should("have.attr", "title", "VeryLongOptionText – AdditionalInfo");
});

it("should display default tooltip (text) if it is read-only and text is truncated, even if tooltip is not set", () => {
cy.mount(
<Select style="width: 50px" readonly>
<Option selected>VeryLongOptionTextThatWillBeTruncated</Option>
<Option >Short</Option>
</Select>
);

cy.get("[ui5-select]")
.shadow()
.find(".ui5-select-root")
.should("have.attr", "title", "VeryLongOptionTextThatWillBeTruncated");
});

it("should show the text and additionalText, separated by '-' when select is read-only", () => {
cy.mount(
<Select readonly>
<Option additionalText="ExtraInfo" selected>SelectedOption</Option>
<Option additionalText="OtherInfo">OtherOption</Option>
</Select>
);

cy.get("[ui5-select]")
.shadow()
.find(".ui5-select-label-root")
.should("contain.text", "SelectedOption – ExtraInfo");
});
});

describe("Select - Popover", () => {
Expand Down Expand Up @@ -489,6 +559,20 @@ describe("Select - Properties", () => {

cy.get("[ui5-select]").should("have.prop", "formFormattedValue", "");
});

it("Should show the selected two-column-separator when select is read-only", () => {
cy.mount(
<Select readonly two-column-separator="VerticalLine">
<Option additionalText="Additional1" selected>First</Option>
<Option additionalText="Additional2">Second</Option>
</Select>
);

cy.get("[ui5-select]")
.shadow()
.find(".ui5-select-label-root")
.should("contain.text", " | ");
});
});

describe("Select - Validation", () => {
Expand Down
76 changes: 74 additions & 2 deletions packages/main/src/Select.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import {
getEffectiveAriaDescriptionText,
} from "@ui5/webcomponents-base/dist/util/AccessibilityTextsHelper.js";
import ValueState from "@ui5/webcomponents-base/dist/types/ValueState.js";
import SelectTwoColumnSeparator from "./types/SelectTwoColumnSeparator.js";
import "@ui5/webcomponents-icons/dist/error.js";
import "@ui5/webcomponents-icons/dist/alert.js";
import "@ui5/webcomponents-icons/dist/sys-enter-2.js";
Expand Down Expand Up @@ -337,6 +338,16 @@ class Select extends UI5Element implements IFormInputElement {
@property()
tooltip?: string;

/**
* Defines the separator type for the two columns layout when Select is in read-only mode.
*
* @default "Dash"
* @public
* @since 2.15.0
*/
@property()
twoColumnSeparator: `${SelectTwoColumnSeparator}` = "Dash";

/**
* Constantly updated value of texts collected from the associated description texts
* @private
Expand Down Expand Up @@ -582,8 +593,69 @@ class Select extends UI5Element implements IFormInputElement {
return this.options.find(option => option.selected);
}

get text() {
return this.selectedOption?.effectiveDisplayText;
/**
* Helper function to build display text with separator when additional text exists
* @param mainText - The main text content
* @param additionalText - The additional text (optional)
* @returns The combined text with separator if additionalText exists, otherwise just mainText
* @private
*/
_buildDisplayText(mainText: string, additionalText?: string) {
if (!additionalText) {
return mainText;
}

return `${mainText} ${this._separatorSymbol} ${additionalText}`;
}

get text(): string {
const selectedOption = this.selectedOption;
if (!selectedOption) {
return "";
}

// Only show separator when readonly and there's additional text
if (this.readonly && selectedOption.additionalText) {
return this._buildDisplayText(
selectedOption.effectiveDisplayText,
selectedOption.additionalText,
);
}

return selectedOption.effectiveDisplayText;
}

get _effectiveTooltip(): string | undefined {
// User-defined tooltip takes precedence
if (this.tooltip) {
return this.tooltip;
}

// Provide default tooltip for readonly mode to show full content
if (this.readonly) {
const selectedOption = this.selectedOption;
if (!selectedOption) {
return undefined;
}

// Use textContent for tooltip to show actual text content, not display text
const mainText = selectedOption.textContent || "";
return this._buildDisplayText(mainText, selectedOption.additionalText);
}

return undefined;
}

get _separatorSymbol(): string {
switch (this.twoColumnSeparator) {
case SelectTwoColumnSeparator.Bullet:
return "·"; // Middle dot (U+00B7)
case SelectTwoColumnSeparator.VerticalLine:
return "|"; // Vertical line (U+007C)
case SelectTwoColumnSeparator.Dash:
default:
return "–"; // En dash (U+2013)
}
}

_toggleRespPopover() {
Expand Down
2 changes: 1 addition & 1 deletion packages/main/src/SelectTemplate.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ export default function SelectTemplate(this: Select) {
}}
id={`${this._id}-select`}
onClick={this._onclick}
title={this.tooltip}
title={this._effectiveTooltip}
>
{!this.icon && this.selectedOptionIcon &&
<Icon
Expand Down
25 changes: 25 additions & 0 deletions packages/main/src/types/SelectTwoColumnSeparator.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
/**
* Defines the separator types for Select component two-column layout.
* @public
*/
enum SelectTwoColumnSeparator {
/**
* Will show bullet(·) as separator on two columns layout when Select is in read-only mode.
* @public
*/
Bullet = "Bullet",

/**
* Will show N-dash(–) as separator on two columns layout when Select is in read-only mode.
* @public
*/
Dash = "Dash",

/**
* Will show vertical line(|) as separator on two columns layout when Select is in read-only mode.
* @public
*/
VerticalLine = "VerticalLine",
}

export default SelectTwoColumnSeparator;
45 changes: 45 additions & 0 deletions packages/main/test/pages/Select.html
Original file line number Diff line number Diff line change
Expand Up @@ -300,6 +300,30 @@ <h2>icon prop</h2>
<ui5-button id="btnCheckFormValidity">Check Validity</ui5-button>
</form>
</section>

<section>
<h3>Separator configuration</h3>
<div>
<span>Two column separator:</span>
<ui5-select id="selectSeparators">
<ui5-option selected>Dash</ui5-option>
<ui5-option>Bullet</ui5-option>
<ui5-option>VerticalLine</ui5-option>
</ui5-select>
</div>

<div style="display: flex; align-items: center; gap: 16px; margin-bottom: 16px;">
<span>Read-only:</span>
<ui5-switch id="editableSwitch" checked text-on="Yes" text-off="No"></ui5-switch>
</div>

<ui5-select id="selectWithSeparator" readonly="false" two-column-separator="VerticalLine">
<ui5-option additional-text="DZ">Algeria</ui5-option>
<ui5-option selected additional-text="AR">Argentina</ui5-option>
<ui5-option additional-text="AU">Australia</ui5-option>
</ui5-select>
</section>

</body>
<script>
var countries = [{ key: "Aus", text: "Australia" }, { key: "Aruba", text: "Aruba" }, { key: "Antigua", text: "Antigua and Barbuda" }, { key: "Bel", text: "Belgium" }, { key: "Bg", text: "Bulgaria" }, { key: "Bra", text: "Brazil" }];
Expand Down Expand Up @@ -446,5 +470,26 @@ <h2>icon prop</h2>
formValidationMessage.innerText = `checkValidity(): ${isValid} ${delayed ? '( Delayed check )' : ''}`;
formValidationMessage.design = isValid ? "Positive" : "Negative";
}

document.addEventListener('DOMContentLoaded', function() {
const selectSeparators = document.getElementById('selectSeparators');
const selectWithSeparator = document.getElementById('selectWithSeparator');
const editableSwitch = document.getElementById('editableSwitch');

selectSeparators.addEventListener('ui5-change', function(e) {
const selectedSeparator = e.detail.selectedOption.textContent;
selectWithSeparator.setAttribute('two-column-separator', selectedSeparator);
});

editableSwitch.addEventListener('ui5-change', function(e) {
const isChecked = e.target.checked;

if (isChecked) {
selectWithSeparator.readonly = true;
} else {
selectWithSeparator.readonly = false;
}
});
});
</script>
</html>
Loading