diff --git a/packages/main/src/CheckBox.hbs b/packages/main/src/CheckBox.hbs index d2f9d38c4a54..8d56a887859f 100644 --- a/packages/main/src/CheckBox.hbs +++ b/packages/main/src/CheckBox.hbs @@ -17,30 +17,37 @@ @click="{{_onclick}}" @focusout="{{_onfocusout}}" > + + {{#if isDisplayOnly}} +
+ +
+ {{else}}
{{#if isCompletelyChecked}} {{/if}} - -
+ {{/if}} + + - {{#if text}} - {{text}} - {{/if}} + {{#if text}} + {{text}} + {{/if}} - {{#if hasValueState}} - {{valueStateText}} - {{/if}} + {{#if hasValueState}} + {{valueStateText}} + {{/if}} - + diff --git a/packages/main/src/CheckBox.ts b/packages/main/src/CheckBox.ts index 785a133f890f..3600f7470ad4 100644 --- a/packages/main/src/CheckBox.ts +++ b/packages/main/src/CheckBox.ts @@ -12,6 +12,9 @@ import { getFeature } from "@ui5/webcomponents-base/dist/FeaturesRegistry.js"; import { getEffectiveAriaLabelText } from "@ui5/webcomponents-base/dist/util/AriaLabelHelper.js"; import { isSpace, isEnter } from "@ui5/webcomponents-base/dist/Keys.js"; import "@ui5/webcomponents-icons/dist/accept.js"; +import "@ui5/webcomponents-icons/dist/complete.js"; +import "@ui5/webcomponents-icons/dist/border.js"; +import "@ui5/webcomponents-icons/dist/tri-state.js"; import Icon from "./Icon.js"; import Label from "./Label.js"; import WrappingType from "./types/WrappingType.js"; @@ -139,6 +142,19 @@ class CheckBox extends UI5Element implements IFormElement { @property({ type: Boolean }) readonly!: boolean; + /** + * Determines whether the ui5-checkbox is in display only state. + * + * When set to true, the ui5-checkbox is not interactive, not editable, not focusable + * and not in the tab chain. This setting is used for forms in review mode. + * + * When the property disabled is set to true this property has no effect. + * @since 1.22.0 + * @default false + */ + @property({ type: Boolean }) + displayOnly!: boolean; + /** * Defines whether the component is required. * @@ -346,7 +362,7 @@ class CheckBox extends UI5Element implements IFormElement { } canToggle() { - return !(this.disabled || this.readonly); + return !(this.disabled || this.readonly || this.displayOnly); } valueStateTextMappings() { @@ -370,7 +386,7 @@ class CheckBox extends UI5Element implements IFormElement { } get ariaReadonly() { - return this.readonly ? "true" : undefined; + return this.readonly || this.displayOnly ? "true" : undefined; } get effectiveAriaDisabled() { @@ -405,13 +421,27 @@ class CheckBox extends UI5Element implements IFormElement { get effectiveTabIndex() { const tabindex = this.getAttribute("tabindex"); - return this.disabled ? undefined : tabindex || "0"; + return this.disabled || this.displayOnly ? undefined : tabindex || "0"; } get isCompletelyChecked() { return this.checked && !this.indeterminate; } + get isDisplayOnly() { + return this.displayOnly && !this.disabled; + } + + get displayOnlyIcon() { + if (this.isCompletelyChecked) { + return "complete"; + } + if (this.checked && this.indeterminate) { + return "tri-state"; + } + return "border"; + } + static async onDefine() { CheckBox.i18nBundle = await getI18nBundle("@ui5/webcomponents"); } diff --git a/packages/main/src/themes/CheckBox.css b/packages/main/src/themes/CheckBox.css index 341d8a2a3746..d9b30976c711 100644 --- a/packages/main/src/themes/CheckBox.css +++ b/packages/main/src/themes/CheckBox.css @@ -224,7 +224,7 @@ height: var(--_ui5_checkbox_partially_icon_size); } -.ui5-checkbox-inner input { +:host input { -webkit-appearance: none; visibility: hidden; width: 0; @@ -253,4 +253,21 @@ transform: translate(-50%, -50%); } +/* Display only mode */ +:host([display-only]) { + cursor: default; +} +:host([display-only]) .ui5-checkbox-display-only-icon-inner [ui5-icon] { + color: var(--sapTextColor); +} + +:host([display-only]) .ui5-checkbox-display-only-icon-inner { + min-width: var(--_ui5_checkbox_inner_width_height); + max-width: var(--_ui5_checkbox_inner_width_height); + height: var(--_ui5_checkbox_inner_width_height); + max-height: var(--_ui5_checkbox_inner_width_height); + display: flex; + align-items: center; + justify-content: center; +} diff --git a/packages/main/test/pages/CheckBox.html b/packages/main/test/pages/CheckBox.html index 5ccfaf3461bf..5d289ca3369d 100644 --- a/packages/main/test/pages/CheckBox.html +++ b/packages/main/test/pages/CheckBox.html @@ -29,6 +29,9 @@ + + +

@@ -40,6 +43,7 @@ Change Event Test +
@@ -79,10 +83,11 @@ var input = document.querySelector("#field"); var checkBox1 = document.querySelector("#cb1"); var checkBox2 = document.querySelector("#cb2"); + var displayOnlyCb = document.querySelector("#displayOnlyCb"); var cbFormSubmitted = document.querySelector("#cbFormSubmitted"); var counter = 0; - [checkBox1, checkBox2].forEach(function(el) { + [checkBox1, checkBox2, displayOnlyCb].forEach(function(el) { el.addEventListener("ui5-change", function(event) { counter += 1; input.value = counter; diff --git a/packages/main/test/specs/CheckBox.spec.js b/packages/main/test/specs/CheckBox.spec.js index d03614430b07..533b969c1f7e 100644 --- a/packages/main/test/specs/CheckBox.spec.js +++ b/packages/main/test/specs/CheckBox.spec.js @@ -33,6 +33,17 @@ describe("CheckBox general interaction", () => { assert.strictEqual(await field.getProperty("value"), "3", "Change event should not be called any more"); }); + it("tests change events not fired when displayOnly", async () => { + const checkBox = await browser.$("#displayOnlyCb"); + const field = await browser.$("#field"); + + await checkBox.click(); + await checkBox.keys("Space"); + await checkBox.keys("Enter"); + + assert.strictEqual(await field.getProperty("value"), "3", "Change event should not be called any more"); + }); + it("tests truncating and wrapping", async () => { const CHECKBOX_DEFAULT_HEIGHT = 44; const truncatingCb = await browser.$("#truncatingCb").shadow$(".ui5-checkbox-root"); @@ -105,4 +116,39 @@ describe("CheckBox general interaction", () => { assert.strictEqual(await browser.$("#cbFormSubmitted").getValue(), "true", "Form is submitted"); }); + + it("tests displayOnly mode - checkbox cannot be toggled", async () => { + const checkBox = await browser.$("#displayOnlyCb"); + const initialCheck = await checkBox.getProperty("checked"); + + await checkBox.click(); + + assert.strictEqual(await checkBox.getProperty("checked"), initialCheck, "Checkbox state should not be changed"); + }); + + it("tests displayOnly mode - checkbox is not focusable", async () => { + const checkBox = await browser.$("#displayOnlyCb"); + + await checkBox.click(); + + assert.strictEqual(await checkBox.isFocused(), false, "Checkbox should not be focusable"); + }); + + it("tests displayOnly mode - checkbox is not in the tab chain", async () => { + const checkbox = await browser.$("#displayOnlyCb").shadow$(".ui5-checkbox-root"); + assert.strictEqual(await checkbox.getAttribute("tabindex"), null, "Checkbox should not be in the tab chain"); + }); + + it("tests displayOnly mode - displays the correct icon", async () => { + const checkBox = await browser.$("#displayOnlyCb"); + const icon = await checkBox.shadow$("ui5-icon"); + + assert.strictEqual(await icon.getAttribute("name"), "border", "Displays the correct icon for not checked"); + + await checkBox.setAttribute("checked", "true"); + assert.strictEqual(await icon.getAttribute("name"), "complete", "Displays the correct icon for checked"); + + await checkBox.setAttribute("indeterminate", "true"); + assert.strictEqual(await icon.getAttribute("name"), "tri-state", "Displays the correct icon for indeterminate checked"); + }); });