diff --git a/docs/Public Module Imports.md b/docs/Public Module Imports.md index 8cebc472da6a..b7e729d2cd70 100644 --- a/docs/Public Module Imports.md +++ b/docs/Public Module Imports.md @@ -25,9 +25,10 @@ For API documentation and samples, please check the [UI5 Web Components Playgrou | Avatar | `ui5-avatar` | `import "@ui5/webcomponents/dist/Avatar.js";` | | Avatar Group | `ui5-avatar-group` | `import "@ui5/webcomponents/dist/AvatarGroup.js";` | | Badge | `ui5-badge` | `import "@ui5/webcomponents/dist/Badge.js";` | -| Busy Indicator | `ui5-busy-indicator` | `import "@ui5/webcomponents/dist/BusyIndicator.js";` | +| Busy Indicator | `ui5-busy-indicator` | `import "@ui5/webcomponents/dist/BusyIndicator.js";` | | Button | `ui5-button` | `import "@ui5/webcomponents/dist/Button.js";` | | Card | `ui5-card` | `import "@ui5/webcomponents/dist/Card.js";` | +| CardHeader | `ui5-card-header` | `import "@ui5/webcomponents/dist/CardHeader.js";` | | Carousel | `ui5-carousel` | `import "@ui5/webcomponents/dist/Carousel.js";` | | Checkbox | `ui5-checkbox` | `import "@ui5/webcomponents/dist/CheckBox.js";` | | Color Palette | `ui5-color-palette` | `import "@ui5/webcomponents/dist/ColorPalette.js";` | @@ -57,8 +58,8 @@ For API documentation and samples, please check the [UI5 Web Components Playgrou | Responsive Popover | `ui5-responsive-popover` | `import "@ui5/webcomponents/dist/ResponsivePopover.js";` | | Select | `ui5-select` | `import "@ui5/webcomponents/dist/Select.js";` | | Select Option | `ui5-option` | comes with `ui5-select ` | -| Segmented Button | `ui5-segmented-button` | `import "@ui5/webcomponents/dist/SegmentedButton.js";` | -| Segmented Button Item | `ui5-segmented-button-item`| comes with `ui5-segmented-button ` | +| Segmented Button | `ui5-segmented-button` | `import "@ui5/webcomponents/dist/SegmentedButton.js";` | +| Segmented Button Item | `ui5-segmented-button-item`| comes with `ui5-segmented-button ` | | Suggestion Item | `ui5-suggestion-item` | comes with `InputSuggestions.js` feature - see below | | Slider | `ui5-slider` | `import "@ui5/webcomponents/dist/Slider.js";` | | Step Input | `ui5-step-input` | `import "@ui5/webcomponents/dist/StepInput.js";` | diff --git a/packages/fiori/test/pages/Timeline.html b/packages/fiori/test/pages/Timeline.html index 63915135a592..40c196eaff0d 100644 --- a/packages/fiori/test/pages/Timeline.html +++ b/packages/fiori/test/pages/Timeline.html @@ -74,9 +74,9 @@

ui5-timeline

Timeline within Card

- + + + diff --git a/packages/main/bundle.common.js b/packages/main/bundle.common.js index 3637ac716810..e37a863c59f1 100644 --- a/packages/main/bundle.common.js +++ b/packages/main/bundle.common.js @@ -36,6 +36,7 @@ import Badge from "./dist/Badge.js"; import BusyIndicator from "./dist/BusyIndicator.js"; import Button from "./dist/Button.js"; import Card from "./dist/Card.js"; +import CardHeader from "./dist/CardHeader.js"; import Carousel from "./dist/Carousel.js"; import CheckBox from "./dist/CheckBox.js"; import ColorPalette from "./dist/ColorPalette.js"; diff --git a/packages/main/src/Card.hbs b/packages/main/src/Card.hbs index 2840394ebd8b..56026d0f39a2 100644 --- a/packages/main/src/Card.hbs +++ b/packages/main/src/Card.hbs @@ -1,44 +1,16 @@
+ aria-labelledby="{{ariaLabelledByCard}}" +> + {{#if hasHeader}} -
- - {{#if hasAvatar}} -
- -
- {{/if}} - -
- {{#if titleText}} -
{{titleText}}
- {{/if}} - - {{#if subtitleText}} -
{{subtitleText}}
- {{/if}} -
- - {{#if hasAction}} - - {{else}} - {{status}} - {{/if}} +
+
{{/if}} -
diff --git a/packages/main/src/Card.js b/packages/main/src/Card.js index 22014cf7e823..2e3168aa9655 100644 --- a/packages/main/src/Card.js +++ b/packages/main/src/Card.js @@ -2,16 +2,12 @@ import UI5Element from "@ui5/webcomponents-base/dist/UI5Element.js"; import litRender from "@ui5/webcomponents-base/dist/renderer/LitRenderer.js"; import { fetchI18nBundle, getI18nBundle } from "@ui5/webcomponents-base/dist/i18nBundle.js"; import { getEffectiveAriaLabelText } from "@ui5/webcomponents-base/dist/util/AriaLabelHelper.js"; -import { isSpace, isEnter } from "@ui5/webcomponents-base/dist/Keys.js"; import CardTemplate from "./generated/templates/CardTemplate.lit.js"; import Icon from "./Icon.js"; import { ARIA_ROLEDESCRIPTION_CARD, - AVATAR_TOOLTIP, ARIA_LABEL_CARD_CONTENT, - ARIA_ROLEDESCRIPTION_CARD_HEADER, - ARIA_ROLEDESCRIPTION_INTERACTIVE_CARD_HEADER, } from "./generated/i18n/i18n-defaults.js"; // Styles @@ -38,82 +34,20 @@ const metadata = { }, /** - * Defines the visual representation in the header of the card. - * Supports images and icons. + * Defines the header of the component. *

- * Note: - * SAP-icons font provides numerous options. To find all the available icons, see the - * Icon Explorer. + * Note: Use ui5-card-header for the intended design. * @type {HTMLElement[]} - * @slot - * @public - */ - avatar: { - type: HTMLElement, - }, - - /** - * Defines an action, displayed in the right most part of the header. - *

- * Note: If set, the status text will not be displayed, - * you can either have action, or status. - * @type {HTMLElement[]} - * @slot + * @since 1.0.0-rc.15 + * @slot content * @public - * @since 1.0.0-rc.8 */ - action: { + header: { type: HTMLElement, }, }, properties: /** @lends sap.ui.webcomponents.main.Card.prototype */ { - /** - * Defines the title displayed in the component header. - * @type {string} - * @defaultvalue "" - * @public - * @since 1.0.0-rc.15 - */ - titleText: { - type: String, - }, - - /** - * Defines the subtitle displayed in the component header. - * @type {string} - * @defaultvalue "" - * @public - * @since 1.0.0-rc5 - */ - subtitleText: { - type: String, - }, - - /** - * Defines the status displayed in the component header. - *

- * Note: If the action slot is set, the status will not be displayed, - * you can either have action, or status. - * @type {string} - * @defaultvalue "" - * @public - */ - status: { - type: String, - }, - - /** - * Defines if the component header would be interactive, - * e.g gets hover effect, gets focused and headerPress event is fired, when it is pressed. - * @type {boolean} - * @defaultvalue false - * @public - */ - headerInteractive: { - type: Boolean, - }, - /** * Sets the accessible aria name of the component. * @@ -138,25 +72,8 @@ const metadata = { type: String, defaultValue: "", }, - - _headerActive: { - type: Boolean, - noAttribute: true, - }, - }, - events: /** @lends sap.ui.webcomponents.main.Card.prototype */ { - - /** - * Fired when the component header is activated - * by mouse/tap or by using the Enter or Space key. - *

- * Note: The event would be fired only if the headerInteractive property is set to true. - * @event sap.ui.webcomponents.main.Card#header-click - * @public - * @since 0.10.0 - */ - "header-click": {}, }, + events: /** @lends sap.ui.webcomponents.main.Card.prototype */ {}, }; /** @@ -166,26 +83,19 @@ const metadata = { * The ui5-card is a component that represents information in the form of a * tile with separate header and content areas. * The content area of a ui5-card can be arbitrary HTML content. - * The header can be used through several properties, such as: titleText, subtitleText, status - * and two slots: avatar and action. + * The header can be used through slot header. For which there is a ui5-card-header component to achieve the card look and fill. * - *

Keyboard handling

- * In case you enable headerInteractive property, you can press the ui5-card header by Space and Enter keys. + * Note: We recommend the usage of ui5-card-header for the header slot, so advantage can be taken for keyboard handling, styling and accessibility. * *

CSS Shadow Parts

* * CSS Shadow Parts allow developers to style elements inside the Shadow DOM. - *
- * The ui5-card exposes the following CSS Shadow Parts: - *
    - *
  • title - Used to style the title of the card
  • - *
  • subtitle - Used to style the subtitle of the card
  • - *
  • status - Used to style the status of the card
  • - *
* *

ES6 Module Import

* * import "@ui5/webcomponents/dist/Card"; + *
+ * import "@ui5/webcomponents/dist/CardHeader.js"; (for ui5-card-header) * * @constructor * @author SAP SE @@ -219,36 +129,13 @@ class Card extends UI5Element { get classes() { return { - main: { - "ui5-card-root": true, - "ui5-card--nocontent": !this.content.length, - }, - header: { - "ui5-card-header": true, - "ui5-card-header--interactive": this.headerInteractive, - "ui5-card-header--active": this.headerInteractive && this._headerActive, - }, + "ui5-card-root": true, + "ui5-card--nocontent": !this.content.length, }; } - get icon() { - return !!this.avatar && this.avatar.startsWith("sap-icon://"); - } - - get image() { - return !!this.avatar && !this.icon; - } - - get ariaHeaderRole() { - return this.headerInteractive ? "button" : "heading"; - } - - get ariaLevel() { - return this.headerInteractive ? undefined : "3"; - } - get hasHeader() { - return !!(this.titleText || this.subtitleText || this.status || this.hasAction || this.avatar); + return !!this.header.length; } get ariaLabelText() { @@ -259,46 +146,18 @@ class Card extends UI5Element { return this.i18nBundle.getText(ARIA_ROLEDESCRIPTION_CARD); } - get ariaCardHeaderRoleDescription() { - return this.headerInteractive ? this.i18nBundle.getText(ARIA_ROLEDESCRIPTION_INTERACTIVE_CARD_HEADER) : this.i18nBundle.getText(ARIA_ROLEDESCRIPTION_CARD_HEADER); - } - - get ariaCardAvatarLabel() { - return this.i18nBundle.getText(AVATAR_TOOLTIP); - } - get ariaCardContentLabel() { return this.i18nBundle.getText(ARIA_LABEL_CARD_CONTENT); } - get ariaLabelledByHeader() { - const labels = []; - - if (this.subtitleText) { - labels.push(`${this._id}-subtitle`); - } - - if (this.status) { - labels.push(`${this._id}-status`); - } - - if (this.hasAvatar) { - labels.push(`${this._id}-avatar`); - } - - return labels.length !== 0 ? labels.join(" ") : undefined; - } - get ariaLabelledByCard() { - return this.titleText ? `${this._id}-title ${this._id}-desc` : `${this._id}-desc`; - } - - get hasAvatar() { - return !!this.avatar.length; - } - - get hasAction() { - return !!this.action.length; + let labels; + if (this.hasHeader) { + labels = this.header[0].hasAttribute("title-text") ? `${this._id}--header-title ${this._id}-desc` : `${this._id}-desc`; + } else { + labels = `${this._id}-desc`; + } + return labels; } static get dependencies() { @@ -308,46 +167,6 @@ class Card extends UI5Element { static async onDefine() { await fetchI18nBundle("@ui5/webcomponents"); } - - _headerClick() { - if (this.headerInteractive) { - this.fireEvent("header-click"); - } - } - - _headerKeydown(event) { - if (!this.headerInteractive) { - return; - } - - const enter = isEnter(event); - const space = isSpace(event); - - this._headerActive = enter || space; - - if (enter) { - this.fireEvent("header-click"); - return; - } - - if (space) { - event.preventDefault(); - } - } - - _headerKeyup(event) { - if (!this.headerInteractive) { - return; - } - - const space = isSpace(event); - - this._headerActive = false; - - if (space) { - this.fireEvent("header-click"); - } - } } Card.define(); diff --git a/packages/main/src/CardHeader.hbs b/packages/main/src/CardHeader.hbs new file mode 100644 index 000000000000..960366a969f5 --- /dev/null +++ b/packages/main/src/CardHeader.hbs @@ -0,0 +1,34 @@ +
+ {{#if hasAvatar}} +
+ +
+ {{/if}} + +
+ {{#if titleText}} +
{{titleText}}
+ {{/if}} + + {{#if subtitleText}} +
{{subtitleText}}
+ {{/if}} +
+ + {{#if hasAction}} + + {{else}} + {{status}} + {{/if}} +
\ No newline at end of file diff --git a/packages/main/src/CardHeader.js b/packages/main/src/CardHeader.js new file mode 100644 index 000000000000..b788b498cf89 --- /dev/null +++ b/packages/main/src/CardHeader.js @@ -0,0 +1,302 @@ +import UI5Element from "@ui5/webcomponents-base/dist/UI5Element.js"; +import litRender from "@ui5/webcomponents-base/dist/renderer/LitRenderer.js"; +import { fetchI18nBundle, getI18nBundle } from "@ui5/webcomponents-base/dist/i18nBundle.js"; +import { getEffectiveAriaLabelText } from "@ui5/webcomponents-base/dist/util/AriaLabelHelper.js"; +import { isSpace, isEnter } from "@ui5/webcomponents-base/dist/Keys.js"; +import CardHeaderTemplate from "./generated/templates/CardHeaderTemplate.lit.js"; +import Icon from "./Icon.js"; + +import { + AVATAR_TOOLTIP, + ARIA_ROLEDESCRIPTION_CARD_HEADER, + ARIA_ROLEDESCRIPTION_INTERACTIVE_CARD_HEADER, +} from "./generated/i18n/i18n-defaults.js"; + +// Styles +import cardHeaderCss from "./generated/themes/CardHeader.css.js"; + +/** + * @public + */ +const metadata = { + tag: "ui5-card-header", + languageAware: true, + managedSlots: true, + slots: /** @lends sap.ui.webcomponents.main.CardHeader.prototype */ { + + /** + * Defines an avatar image, displayed in the left most part of the header. + * @type {HTMLElement[]} + * @slot + * @public + */ + avatar: { + type: HTMLElement, + }, + + /** + * Defines an action, displayed in the right most part of the header. + *

+ * Note: If set, the status text will not be displayed, + * you can either have action, or status. + * @type {HTMLElement[]} + * @slot + * @public + */ + action: { + type: HTMLElement, + }, + }, + properties: /** @lends sap.ui.webcomponents.main.CardHeader.prototype */ { + + /** + * Defines the title displayed in the component header. + * @type {string} + * @defaultvalue "" + * @public + */ + titleText: { + type: String, + }, + + /** + * Defines the subtitle displayed in the component header. + * @type {string} + * @defaultvalue "" + * @public + */ + subtitleText: { + type: String, + }, + + /** + * Defines the status displayed in the component header. + *

+ * Note: If the action slot is set, the status will not be displayed, + * you can either have action, or status. + * @type {string} + * @defaultvalue "" + * @public + */ + status: { + type: String, + }, + + /** + * Defines if the component header would be interactive, + * e.g gets hover effect, gets focused and headerPress event is fired, when it is pressed. + * @type {boolean} + * @defaultvalue false + * @public + */ + headerInteractive: { + type: Boolean, + }, + + /** + * Defines the aria-label attribute for the component + * + * @type {String} + * @private + * @defaultvalue "" + */ + ariaLabel: { + type: String, + }, + + /** + * Receives id(or many ids) of the elements that label the component + * + * @type {String} + * @defaultvalue "" + * @private + */ + ariaLabelledby: { + type: String, + defaultValue: "", + }, + + _headerActive: { + type: Boolean, + noAttribute: true, + }, + }, + events: /** @lends sap.ui.webcomponents.main.CardHeader.prototype */ { + + /** + * Fired when the header is activated + * by mouse/tap or by using the Enter or Space key. + *

+ * Note: The event would be fired only if the headerInteractive property is set to true. + * @event sap.ui.webcomponents.main.CarHeader#header-click + * @public + */ + "click": {}, + }, +}; + +/** + * @class + *

Overview

+ * + * The ui5-card-header is a component that represents information in the header slot + * of the ui5-card component. + * The header can be used through several properties, such as: titleText, subtitleText, status + * and two slots: avatar and action. + * + *

Keyboard handling

+ * In case you enable headerInteractive property, you can press the ui5-card header by Space and Enter keys. + * + *

CSS Shadow Parts

+ * + * CSS Shadow Parts allow developers to style elements inside the Shadow DOM. + *
+ * The ui5-card exposes the following CSS Shadow Parts: + *
    + *
  • title - Used to style the title of the card
  • + *
  • subtitle - Used to style the subtitle of the card
  • + *
  • status - Used to style the status of the card
  • + *
+ * + *

ES6 Module Import

+ * + * import "@ui5/webcomponents/dist/CardHeader"; + * + * @constructor + * @author SAP SE + * @alias sap.ui.webcomponents.main.CardHeader + * @extends sap.ui.webcomponents.base.UI5Element + * @tagname ui5-card-header + * @appenddocs CardHeader + * @public + * @since 1.0.0-rc.15 + */ +class CardHeader extends UI5Element { + constructor() { + super(); + + this.i18nBundle = getI18nBundle("@ui5/webcomponents"); + } + + static get metadata() { + return metadata; + } + + static get render() { + return litRender; + } + + static get template() { + return CardHeaderTemplate; + } + + static get styles() { + return cardHeaderCss; + } + + get classes() { + return { + "ui5-card-header": true, + "ui5-card-header--interactive": this.headerInteractive, + "ui5-card-header--active": this.headerInteractive && this._headerActive, + }; + } + + get ariaHeaderRole() { + return this.headerInteractive ? "button" : "heading"; + } + + get ariaLevel() { + return this.headerInteractive ? undefined : "3"; + } + + get ariaLabelText() { + return getEffectiveAriaLabelText(this); + } + + get ariaCardHeaderRoleDescription() { + return this.headerInteractive ? this.i18nBundle.getText(ARIA_ROLEDESCRIPTION_INTERACTIVE_CARD_HEADER) : this.i18nBundle.getText(ARIA_ROLEDESCRIPTION_CARD_HEADER); + } + + get ariaCardAvatarLabel() { + return this.i18nBundle.getText(AVATAR_TOOLTIP); + } + + get ariaLabelledByHeader() { + const labels = []; + + if (this.subtitleText) { + labels.push(`${this._id}-subtitle`); + } + + if (this.status) { + labels.push(`${this._id}-status`); + } + + if (this.hasAvatar) { + labels.push(`${this._id}-avatar`); + } + + return labels.length !== 0 ? labels.join(" ") : undefined; + } + + get hasAvatar() { + return !!this.avatar.length; + } + + get hasAction() { + return !!this.action.length; + } + + static get dependencies() { + return [Icon]; + } + + static async onDefine() { + await fetchI18nBundle("@ui5/webcomponents"); + } + + _headerClick() { + if (this.headerInteractive) { + this.fireEvent("click"); + } + } + + _headerKeydown(event) { + if (!this.headerInteractive) { + return; + } + + const enter = isEnter(event); + const space = isSpace(event); + + this._headerActive = enter || space; + + if (enter) { + this.fireEvent("click"); + return; + } + + if (space) { + event.preventDefault(); + } + } + + _headerKeyup(event) { + if (!this.headerInteractive) { + return; + } + + const space = isSpace(event); + + this._headerActive = false; + + if (space) { + this.fireEvent("click"); + } + } +} + +CardHeader.define(); + +export default CardHeader; diff --git a/packages/main/src/themes/Card.css b/packages/main/src/themes/Card.css index 5bec17043130..a1bc65c9eeef 100644 --- a/packages/main/src/themes/Card.css +++ b/packages/main/src/themes/Card.css @@ -19,137 +19,17 @@ box-sizing: border-box; } -.ui5-card-header { - position: relative; - display: flex; - align-items: center; - background: var(--sapTile_Background); - border-bottom: 1px solid var(--_ui5_card_header_border_color); - padding: var(--_ui5_card_content_padding); - outline: none; -} - -:host([subtitleText]) .ui5-card-header { - align-items: flex-start; -} - /* Card with no content */ .ui5-card-root.ui5-card--nocontent { height: auto; } -.ui5-card-root.ui5-card--nocontent .ui5-card-header { - border-bottom: none; -} - -.ui5-card-header:focus:before { - outline: none; - content: ""; - position: absolute; - border: var(--_ui5_card_header_focus_border); - pointer-events: none; - top: 1px; - left: 1px; - right: 1px; - bottom: 1px; -} - -.ui5-card-header.ui5-card-header--interactive:hover { - cursor: pointer; - background: var(--_ui5_card_header_hover_bg); -} - -.ui5-card-header.ui5-card-header--active, -.ui5-card-header.ui5-card-header--interactive:active { - background: var(--_ui5_card_header_active_bg); +.ui5-card-root.ui5-card--nocontent .ui5-card-header-root { + border-bottom: none; } -.ui5-card-header .ui5-card-header-text { - flex: 1; - pointer-events: none; +.ui5-card-root .ui5-card-header-root { + display: block; + border-bottom: 1px solid var(--_ui5_card_header_border_color); } -.ui5-card-header .ui5-card-avatar { - height: 3rem; - width: 3rem; - display: flex; - align-items: center; - justify-content: center; - margin-right: .75rem; - pointer-events: none; -} - -::slotted([ui5-icon]) { - width: 1.5rem; - height: 1.5rem; - color: var(--sapTile_IconColor); -} - -::slotted(img[slot="avatar"]) { - width: 100%; - height: 100%; - border-radius: 50%; -} - -.ui5-card-header .ui5-card-status { - display: inline-block; - font-family: "72override", var(--sapFontFamily); - font-size: var(--sapFontSmallSize); - color: var(--sapTile_TextColor); - text-align: left; - line-height: 1.125rem; - padding-left: 1rem; - margin-left: auto; - text-overflow: ellipsis; - overflow: hidden; - white-space: nowrap; -} - -.ui5-card-header .ui5-card-header-text .ui5-card-title { - font-family: "72override", var(--sapFontFamily); - font-size: var(--sapFontHeader5Size); - font-weight: normal; - color: var(--sapTile_TitleTextColor); - max-height: 3.5rem; -} - -.ui5-card-header .ui5-card-header-text .ui5-card-subtitle { - font-family: "72override", var(--sapFontFamily); - font-size: var(--sapFontSize); - font-weight: normal; - color: var(--sapTile_TextColor); - margin-top: .5rem; - max-height: 2.1rem; -} - -.ui5-card-header .ui5-card-header-text .ui5-card-title, -.ui5-card-header .ui5-card-header-text .ui5-card-subtitle { - text-align: left; - text-overflow: ellipsis; - white-space: normal; - word-wrap: break-word; - overflow: hidden; - -webkit-line-clamp: 2; - -webkit-box-orient: vertical; - display: -webkit-box; - max-width: 100%; -} - -[dir="rtl"] .ui5-card-header .ui5-card-avatar { - margin-left: .75rem; - margin-right: 0; -} - -[dir="rtl"] .ui5-card-header .ui5-card-status { - padding-right: 1rem; - padding-left: 0rem; - margin-right: auto; -} - -[dir="rtl"] .ui5-card-header .ui5-card-header-text .ui5-card-title { - text-align: right; -} - -[dir="rtl"] .ui5-card-header .ui5-card-header-text .ui5-card-subtitle { - text-align: right; -} diff --git a/packages/main/src/themes/CardHeader.css b/packages/main/src/themes/CardHeader.css new file mode 100644 index 000000000000..706db03453ca --- /dev/null +++ b/packages/main/src/themes/CardHeader.css @@ -0,0 +1,125 @@ +@import "./InvisibleTextStyles.css"; + +.ui5-card-header { + position: relative; + display: flex; + align-items: center; + padding: var(--_ui5_card_content_padding); + outline: none; +} + +:host([subtitleText]) .ui5-card-header { + align-items: flex-start; +} + +.ui5-card-header:focus:before { + outline: none; + content: ""; + position: absolute; + border: var(--_ui5_card_header_focus_border); + pointer-events: none; + top: 1px; + left: 1px; + right: 1px; + bottom: 1px; +} + +.ui5-card-header.ui5-card-header--interactive:hover { + cursor: pointer; + background: var(--_ui5_card_header_hover_bg); +} + +.ui5-card-header.ui5-card-header--active, +.ui5-card-header.ui5-card-header--interactive:active { + background: var(--_ui5_card_header_active_bg); +} + +.ui5-card-header .ui5-card-header-text { + flex: 1; + pointer-events: none; +} + +.ui5-card-header .ui5-card-header-avatar { + height: 3rem; + width: 3rem; + display: flex; + align-items: center; + justify-content: center; + margin-right: .75rem; + pointer-events: none; +} + +::slotted([ui5-icon]) { + width: 1.5rem; + height: 1.5rem; + color: var(--sapTile_IconColor); +} + +::slotted(img[slot="avatar"]) { + width: 100%; + height: 100%; + border-radius: 50%; +} + +.ui5-card-header .ui5-card-header-status { + display: inline-block; + font-family: "72override", var(--sapFontFamily); + font-size: var(--sapFontSmallSize); + color: var(--sapTile_TextColor); + text-align: left; + line-height: 1.125rem; + padding-left: 1rem; + margin-left: auto; + text-overflow: ellipsis; + overflow: hidden; + white-space: nowrap; +} + +.ui5-card-header .ui5-card-header-text .ui5-card-header-title { + font-family: "72override", var(--sapFontFamily); + font-size: var(--sapFontHeader5Size); + font-weight: normal; + color: var(--sapTile_TitleTextColor); + max-height: 3.5rem; +} + +.ui5-card-header .ui5-card-header-text .ui5-card-header-subtitle { + font-family: "72override", var(--sapFontFamily); + font-size: var(--sapFontSize); + font-weight: normal; + color: var(--sapTile_TextColor); + margin-top: .5rem; + max-height: 2.1rem; +} + +.ui5-card-header .ui5-card-header-text .ui5-card-header-title, +.ui5-card-header .ui5-card-header-text .ui5-card-header-subtitle { + text-align: left; + text-overflow: ellipsis; + white-space: normal; + word-wrap: break-word; + overflow: hidden; + -webkit-line-clamp: 2; + -webkit-box-orient: vertical; + display: -webkit-box; + max-width: 100%; +} + +[dir="rtl"] .ui5-card-header .ui5-card-header-avatar { + margin-left: .75rem; + margin-right: 0; +} + +[dir="rtl"] .ui5-card-header .ui5-card-header-status { + padding-right: 1rem; + padding-left: 0rem; + margin-right: auto; +} + +[dir="rtl"] .ui5-card-header .ui5-card-header-text .ui5-card-header-title { + text-align: right; +} + +[dir="rtl"] .ui5-card-header .ui5-card-header-text .ui5-card-header-subtitle { + text-align: right; +} diff --git a/packages/main/test/pages/Card.html b/packages/main/test/pages/Card.html index e5a9ec113b53..7421dc9de1f6 100644 --- a/packages/main/test/pages/Card.html +++ b/packages/main/test/pages/Card.html @@ -3,7 +3,7 @@ - + Card @@ -22,11 +22,15 @@ + + Template Based Segmentation Segmentation Models @@ -38,18 +42,28 @@ - + + + Template Based Segmentation Segmentation Models - + + + Template Based Segmentation Segmentation Models @@ -57,7 +71,16 @@ - + + + + Add activity + + Increase customer satisfaction by 10% using marketing methods @@ -66,13 +89,17 @@ Get 1000 survey responses to annual employee survey - - - Add activity - - + + + + Add activity + + Increase customer satisfaction by 10% using marketing methods @@ -81,13 +108,17 @@ Get 1000 survey responses to annual employee survey - - - Add activity - - + + + + + Add activity + + Increase customer satisfaction by 10% using marketing methods @@ -96,33 +127,67 @@ Get 1000 survey responses to annual employee survey - - - -

Test accessibleName and ariaLabelledBy

+ +
info text + id="textAreaAriaLabelledBy"> + + + +
+ Test +
+ + + Increase customer satisfaction by 10% using marketing methods + + + Get 1000 survey responses to annual employee survey + + +
+ + + + + Increase customer satisfaction by 10% using marketing methods + + + Get 1000 survey responses to annual employee survey + + + + - - + + + - - - - - - Template Based Segmentation - Segmentation Models - Marketing plans - - - - - - - - - Template Based Segmentation - Segmentation Models - - - - - - Template Based Segmentation - Segmentation Models - - - - - - Template Based Segmentation - Segmentation Models - Marketing plans - - - - - - - - - Template Based Segmentation - Segmentation Models - - - - - - Template Based Segmentation - Segmentation Models - - - - - - Template Based Segmentation - Segmentation Models - Marketing plans - - - - - - - - - Template Based Segmentation - Segmentation Models - - - - - - Template Based Segmentation - Segmentation Models - - - - - - - Template Based Segmentation - Segmentation Models - - - - - - Template Based Segmentation - Segmentation Models - - - - - - - - - - Template Based Segmentation - Segmentation Models - Marketing plans - - - - - - - - - Template Based Segmentation - Segmentation Models - - - - - - Template Based Segmentation - Segmentation Models - - - - - - Template Based Segmentation - Segmentation Models - Marketing plans - - - - - - - - - Template Based Segmentation - Segmentation Models - - - - - - Template Based Segmentation - Segmentation Models - - - - - - Template Based Segmentation - Segmentation Models - Marketing plans - - - - - - - - - Template Based Segmentation - Segmentation Models - - - - - - Template Based Segmentation - Segmentation Models - - - - - - - Template Based Segmentation - Segmentation Models - - - - - - Template Based Segmentation - Segmentation Models - - - - - - - - - Template Based Segmentation - Segmentation Models - Marketing plans - - - - - - - - - Template Based Segmentation - Segmentation Models - - - - - - Template Based Segmentation - Segmentation Models - - - - - - Template Based Segmentation - Segmentation Models - Marketing plans - - - - - - - - - Template Based Segmentation - Segmentation Models - - - - - - Template Based Segmentation - Segmentation Models - - - - - - Template Based Segmentation - Segmentation Models - Marketing plans - - - - - - - - - Template Based Segmentation - Segmentation Models - - - - - - - - Button 1 - Button 2 - Button 3 - - - - Button 1 - Button 2 - Button 3 - Button 4 - Button 5 - Button 6 - Button 7 - Button 8 - Button 9 - - - - Button 1 - Button 2 - Button 3 - - - - - - Template Based Segmentation - Segmentation Models - Marketing plans - - - - - - - New Items - Voluptate do eu cupidatat - elit est culpa. Reprehenderit eiusmod voluptate ex est dolor nostrud Lorem Lorem do nisi laborum veniam. - Sint do non culpa aute occaecat labore ipsum veniam minim tempor est. Duis pariatur aute culpa irure ad - excepteur pariatur culpa culpa ea duis occaecat aute irure. Ipsum velit culpa non exercitation ex - laboris deserunt in eu non officia in. Laborum sunt aliqua labore cupidatat sunt labore. - Laptop Lenovo - IPhone 3 - - - - Option 1 - Option 2 - Option 3 - Option 1 - Option 2 - Option 3 - - - - - Button 1 - Button 2 - Button 3 - Button 4 - Button 5 - Button 6 - Button 7 - Button 8 - - - Carousel with one page - The arrows and dots are not displayed - - - Button 1 - Button 2 - Button 3 - - - - Button 1 - Button 2 - Button 3 - Button 4 - Button 5 - Button 6 - Button 7 - Button 8 - - - - - - Button 1 - Button 2 - Button 3 - Button 4 - Button 5 - Button 6 - Button 7 - Button 8 - Button 9 - Button 10 - - - - Carousel with hidden page indicator - arrows-placement="Navigation" - - Button 1 - Button 2 - Button 3 - - - Carousel with hidden page indicator and hidden navigation arrows - arrows-placement="Navigation" - - Button 1 - Button 2 - Button 3 - + + + + + + + + Template Based Segmentation + Segmentation Models + Marketing plans + + + + + + + + + + + Template Based Segmentation + Segmentation Models + + + + + + + + Template Based Segmentation + Segmentation Models + + + + + + + + Template Based Segmentation + Segmentation Models + Marketing plans + + + + + + + + + + + Template Based Segmentation + Segmentation Models + + + + + + + + Template Based Segmentation + Segmentation Models + + + + + + + + Template Based Segmentation + Segmentation Models + Marketing plans + + + + + + + + + + + Template Based Segmentation + Segmentation Models + + + + + + + + Template Based Segmentation + Segmentation Models + + + + + + + + + Template Based Segmentation + Segmentation Models + + + + + + + + Template Based Segmentation + Segmentation Models + + + + + + + + + + + + Template Based Segmentation + Segmentation Models + Marketing plans + + + + + + + + + + + Template Based Segmentation + Segmentation Models + + + + + + + + Template Based Segmentation + Segmentation Models + + + + + + + + Template Based Segmentation + Segmentation Models + Marketing plans + + + + + + + + + + + Template Based Segmentation + Segmentation Models + + + + + + + + Template Based Segmentation + Segmentation Models + + + + + + + + Template Based Segmentation + Segmentation Models + Marketing plans + + + + + + + + + + + Template Based Segmentation + Segmentation Models + + + + + + + + Template Based Segmentation + Segmentation Models + + + + + + + + + Template Based Segmentation + Segmentation Models + + + + + + + + Template Based Segmentation + Segmentation Models + + + + + + + + + + + Template Based Segmentation + Segmentation Models + Marketing plans + + + + + + + + + + + Template Based Segmentation + Segmentation Models + + + + + + + + Template Based Segmentation + Segmentation Models + + + + + + + + Template Based Segmentation + Segmentation Models + Marketing plans + + + + + + + + + + + Template Based Segmentation + Segmentation Models + + + + + + + + Template Based Segmentation + Segmentation Models + + + + + + + + Template Based Segmentation + Segmentation Models + Marketing plans + + + + + + + + + + + Template Based Segmentation + Segmentation Models + + + + + + + + Button 1 + Button 2 + Button 3 + + + + Button 1 + Button 2 + Button 3 + Button 4 + Button 5 + Button 6 + Button 7 + Button 8 + Button 9 + + + + Button 1 + Button 2 + Button 3 + + + + + + + + Template Based Segmentation + Segmentation Models + Marketing plans + + + + + + + New Items + Voluptate do eu cupidatat + elit est culpa. Reprehenderit eiusmod voluptate ex est dolor nostrud Lorem Lorem do nisi laborum veniam. + Sint do non culpa aute occaecat labore ipsum veniam minim tempor est. Duis pariatur aute culpa irure ad + excepteur pariatur culpa culpa ea duis occaecat aute irure. Ipsum velit culpa non exercitation ex + laboris deserunt in eu non officia in. Laborum sunt aliqua labore cupidatat sunt labore. + Laptop Lenovo + IPhone 3 + + + + Option 1 + Option 2 + Option 3 + Option 1 + Option 2 + Option 3 + + + + + Button 1 + Button 2 + Button 3 + Button 4 + Button 5 + Button 6 + Button 7 + Button 8 + + + Carousel with one page + The arrows and dots are not displayed + + + Button 1 + Button 2 + Button 3 + + + + Button 1 + Button 2 + Button 3 + Button 4 + Button 5 + Button 6 + Button 7 + Button 8 + + + + + + Button 1 + Button 2 + Button 3 + Button 4 + Button 5 + Button 6 + Button 7 + Button 8 + Button 9 + Button 10 + + + + Carousel with hidden page indicator + arrows-placement="Navigation" + + Button 1 + Button 2 + Button 3 + + + Carousel with hidden page indicator and hidden navigation arrows + arrows-placement="Navigation" + + Button 1 + Button 2 + Button 3 + diff --git a/packages/main/test/pages/Components.html b/packages/main/test/pages/Components.html index d743aa3c7d04..5fd262f3d2e9 100644 --- a/packages/main/test/pages/Components.html +++ b/packages/main/test/pages/Components.html @@ -2,7 +2,7 @@ - + Default values test page @@ -39,7 +39,10 @@ - + diff --git a/packages/main/test/pages/Kitchen.html b/packages/main/test/pages/Kitchen.html index bae835855a83..0c94ea5a7129 100644 --- a/packages/main/test/pages/Kitchen.html +++ b/packages/main/test/pages/Kitchen.html @@ -24,19 +24,19 @@ } - - - + + + @@ -92,11 +92,10 @@
- + style="flex-basis:20%;"> + + + Java EE @@ -105,11 +104,10 @@ - + style="flex-basis:20%;"> + + + C/C++ @@ -118,10 +116,10 @@ - + style="flex-basis:20%;"> + + + Photoshop CorelDRAW @@ -129,11 +127,10 @@ - + style="flex-basis:20%;"> + + + JavaScript @@ -143,18 +140,17 @@ - + style="flex-basis:20%;"> + + + - + style="flex-basis:20%;"> + + +
diff --git a/packages/main/test/pages/Kitchen.openui5.html b/packages/main/test/pages/Kitchen.openui5.html index 377321d70fe3..09fb8ed80331 100644 --- a/packages/main/test/pages/Kitchen.openui5.html +++ b/packages/main/test/pages/Kitchen.openui5.html @@ -79,11 +79,10 @@
- + style="flex-basis:20%;"> + + + Java EE @@ -92,11 +91,10 @@ - + style="flex-basis:20%;"> + + + C/C++ @@ -105,10 +103,10 @@ - + style="flex-basis:20%;"> + + + Photoshop @@ -117,11 +115,10 @@ - + style="flex-basis:20%;"> + + + JavaScript @@ -323,7 +320,7 @@ Tomato - + Wine @@ -389,7 +386,7 @@ style="flex: 0 0 400px" show-exceeded-text > - +
diff --git a/packages/main/test/samples/Card.sample.html b/packages/main/test/samples/Card.sample.html index 285c0f4a91c9..eb680e72d1ef 100644 --- a/packages/main/test/samples/Card.sample.html +++ b/packages/main/test/samples/Card.sample.html @@ -70,7 +70,9 @@

Card

Card with List

- + + + View All @@ -80,12 +82,14 @@

Card with List

Monique Legrand Isabella Adams - +
- - - + + + + +
Richard Wilson @@ -105,8 +109,10 @@

Card with List

} - - + + + + View All
@@ -117,8 +123,10 @@

Card with List

- - + + + +
Richard Wilson @@ -133,7 +141,9 @@

Card with List

Card with Table

- + + + @@ -206,23 +216,25 @@

Card with Table

.status-warning {color: #e9730c;} .status-success {color: #107e3e;} - + + + - Sales Order + Sales Order - Customer + Customer - Net Amount + Net Amount - Status + Status @@ -249,7 +261,9 @@

Card with Table

Card with Timeline

- + + + @@ -263,10 +277,9 @@

Card with Timeline


-<ui5-card
-	title-text="Upcoming Activities"
-	subtitle-text="For Today"
-	class="meidum">
+<ui5-card class="meidum">
+		<ui5-card-header slot="header" title-text="Upcoming Activities" subtitle-text="For Today">
+		</ui5-card-header>
 	<ui5-timeline>
 		<ui5-timeline-item id="test-item" title-text="called" timestamp="1487583000000" icon="phone" name="John Smith" name-clickable></ui5-timeline-item>
 		<ui5-timeline-item title-text="Weekly Sync - CP Design" timestamp="1517349600000" icon="calendar">
@@ -283,8 +296,10 @@ <h3>Card with Timeline</h3>
 <section>
 	<h3>More Cards</h3>
 	<div class="snippet card-container">
-		<ui5-card title-text="David Willams" subtitle-text="Sales Manager" class="small">
-			<img src="../../../assets/images/avatars/man_avatar_1.png" slot="avatar" />
+		<ui5-card class="small">
+			<ui5-card-header slot="header" title-text="David Willams" subtitle-text="Sales Manager">
+				<img src="../../../assets/images/avatars/man_avatar_1.png" slot="avatar" />
+			</ui5-card-header>
 
 			<ui5-list separators="Inner" class="content-padding">
 				<ui5-li icon="competitor" icon-end>Personal Development</ui5-li>
@@ -293,11 +308,9 @@ <h3>More Cards</h3>
 			</ui5-list>
 		</ui5-card>
 
-		<ui5-card
-			title-text="Project Cloud Transformation"
-			subtitle-text="Revenue per Product | EUR"
-			status="3 of 3"
-			class="small">
+		<ui5-card class="small">
+			<ui5-card-header slot="header" title-text="Project Cloud Transformation" subtitle-text="Revenue per Product | EUR" status="3 of 3">
+			</ui5-card-header>
 			<ui5-list separators="None" class="content-padding">
 				<ui5-li-custom>
 					<div class="item">
@@ -337,9 +350,11 @@ <h3>More Cards</h3>
 			</ui5-list>
 		</ui5-card>
 
-		<ui5-card title-text="Dona Maria Moore" subtitle-text="Senior Sales Executive" class="small">
-			<img src="../../../assets/images/avatars/man_avatar_1.png" slot="avatar" />
-			
+		<ui5-card class="small">
+			<ui5-card-header slot="header" title-text="Dona Maria Moore" subtitle-text="Senior Sales Executive">
+				<img src="../../../assets/images/avatars/man_avatar_1.png" slot="avatar" />
+			</ui5-card-header>
+
 			<div class="content content-padding">
 				<ui5-title level="H5" style="padding-bottom: 1rem;">Contact details</ui5-title>
 
@@ -362,9 +377,11 @@ <h3>More Cards</h3>
 	</div>
 
 	<pre class="prettyprint lang-html"><xmp>
-<ui5-card title-text="David Willams" subtitle-text="Sales Manager" class="small">
-	<img src="../../../assets/images/avatars/man_avatar_1.png" slot="avatar" />
-	
+<ui5-card class="small">
+	<ui5-card-header slot="header" title-text="David Willams" subtitle-text="Sales Manager" >
+				<img src="../../../assets/images/avatars/man_avatar_1.png" slot="avatar" />
+	</ui5-card-header>
+
 	<ui5-list separators="Inner" class="content-padding">
 		<ui5-li icon="competitor" icon-end>Personal Development</ui5-li>
 		<ui5-li icon="wallet" icon-end>Finance</ui5-li>
@@ -391,7 +408,9 @@ <h3>More Cards</h3>
 .status-success {color: #107e3e;}
 </style>
 
-<ui5-card title-text="Project Cloud Transformation" subtitle-text="Revenue per Product | EUR" status="3 of 3" class="small">
+<ui5-card class="small">
+	   <ui5-card-header slot="header" title-text="Project Cloud Transformation" subtitle-text="Revenue per Product | EUR" status="3 of 3">
+	   </ui5-card-header>
 	<ui5-list separators="None" class="content-padding">
 		<ui5-li-custom>
 			<div class="item">
@@ -408,9 +427,11 @@ <h3>More Cards</h3>
 	</ui5-list>
 </ui5-card>
 
-<ui5-card title-text="Dona Maria Moore" subtitle-text="Senior Sales Executive" class="small">
-	<img src="../../../assets/images/avatars/man_avatar_1.png" slot="avatar" />
-	
+<ui5-card class="small">
+	<ui5-card-header slot="header" title-text="Dona Maria Moore" subtitle-text="Senior Sales Executive">
+		<img src="../../../assets/images/avatars/man_avatar_1.png" slot="avatar" />
+	</ui5-card-header>
+
 	<div class="content content-padding">
 		<ui5-title level="H5" style="padding-bottom: 1rem;">Contact details</ui5-title>
 
diff --git a/packages/main/test/specs/Card.spec.js b/packages/main/test/specs/Card.spec.js
index bf83f64df2dc..9e246341b4d3 100644
--- a/packages/main/test/specs/Card.spec.js
+++ b/packages/main/test/specs/Card.spec.js
@@ -13,14 +13,14 @@ describe("Card general interaction", () => {
 	});
 
 	it("tests status not rendered, when action is set", () => {
-		const status = browser.$("#actionCard").shadow$(".ui5-card-status");
+		const status = browser.$("#actionCardHeader").shadow$(".ui5-card-header-status");
 
 		assert.notOk(status.isExisting(), "The status DOM is not rendered.");
 	});
 
 	it("tests headerPress upon click, Enter and Space", () => {
-		const cardHeader = browser.$("#card").shadow$(".ui5-card-header");
-		const cardHeader2 = browser.$("#card2").shadow$(".ui5-card-header");
+		const cardHeader = browser.$("#cardHeader").shadow$(".ui5-card-header");
+		const cardHeader2 = browser.$("#cardHeader2").shadow$(".ui5-card-header");
 		const field = browser.$("#field");
 
 		cardHeader.click();
@@ -49,23 +49,25 @@ describe("Card general interaction", () => {
 	});
 
 	it("Tests internal aria-labelledby labeling", () => {
-		const card1 = $("#card2").shadow$(".ui5-card-root");
-		const card1Id = $("#card2").getProperty("_id");
-		const header = $("#card2").shadow$(".ui5-card-header");
-		const card2 = $("#card3").shadow$(".ui5-card-root");
-		const card2Id = $("#card3").getProperty("_id");
-		const header2 = $("#card3").shadow$(".ui5-card-header");
-		const EXPECTED_ARIA_LABELLEDBY_CARD = `${card1Id}-title ${card1Id}-desc`;
-		const EXPECTED_ARIA_LABELLEDBY_HEADER = `${card1Id}-subtitle ${card1Id}-status ${card1Id}-avatar`;
-		const EXPECTED_ARIA_LABELLEDBY_CARD2 = `${card2Id}-title ${card2Id}-desc`;
-		const EXPECTED_ARIA_LABELLEDBY_HEADER2 = `${card2Id}-subtitle`;
+		const card1 = $("#textAreaAriaLabel").shadow$(".ui5-card-root");
+		const card1Id = $("#textAreaAriaLabel").getProperty("_id");
+		const header = $("#header").shadow$(".ui5-card-header");
+		const headerId = $("#header").getProperty("_id");
+		const card2 = $("#textAreaAriaLabelledBy").shadow$(".ui5-card-root");
+		const card2Id = $("#textAreaAriaLabelledBy").getProperty("_id");
+		const header2 = $("#header2").shadow$(".ui5-card-header");
+		const headerId2 = $("#header2").getProperty("_id");
+		const EXPECTED_ARIA_LABELLEDBY_CARD = `${card1Id}--header-title ${card1Id}-desc`;
+		const EXPECTED_ARIA_LABELLEDBY_HEADER = `${headerId}-subtitle ${headerId}-status`;
+		const EXPECTED_ARIA_LABELLEDBY_CARD2 = `${card2Id}--header-title ${card2Id}-desc`;
+		const EXPECTED_ARIA_LABELLEDBY_HEADER2 = `${headerId2}-subtitle`;
 
 		assert.strictEqual(card1.getAttribute("aria-labelledby"), EXPECTED_ARIA_LABELLEDBY_CARD,
 			"The aria-labelledby of card is correctly set internally.");
 		assert.strictEqual(header.getAttribute("aria-labelledby"), EXPECTED_ARIA_LABELLEDBY_HEADER,
 			"The aria-labelledby is correctly set internally.");
 		assert.strictEqual(card2.getAttribute("aria-labelledby"), EXPECTED_ARIA_LABELLEDBY_CARD2,
-			"The aria-labelledby of card is correctly set internally.");
+			"The aria-labelledby of card is correctly set internally.3");
 		assert.strictEqual(header2.getAttribute("aria-labelledby"), EXPECTED_ARIA_LABELLEDBY_HEADER2,
 			"The aria-labelledby is correctly set internally.");
 	});