diff --git a/404.html b/404.html index 54ae899ea4..997f419014 100644 --- a/404.html +++ b/404.html @@ -29,7 +29,7 @@ - + + + + + +
+

Checkboxes

+ + +

Headline

+ Lorem ipsum dolor sit amet, consectetur adipiscing elit. +
Suspendisse eu turpis elementum
+
+ + +

Headline

+ Lorem ipsum dolor sit amet, consectetur adipiscing elit. +
Suspendisse eu turpis elementum
+
+ + +

Headline

+ Lorem ipsum dolor sit amet, consectetur adipiscing elit. +
Suspendisse eu turpis elementum
+
+
diff --git a/assets/packages/@rhds/elements/elements/rh-tile/demo/color-context.html b/assets/packages/@rhds/elements/elements/rh-tile/demo/color-context.html new file mode 100644 index 0000000000..5a434819d2 --- /dev/null +++ b/assets/packages/@rhds/elements/elements/rh-tile/demo/color-context.html @@ -0,0 +1,206 @@ + + + + + + + +
+

Basic

+ + + 296 X 50 placeholder image +
Title
+

Link

+ Lorem ipsum dolor sit amet, consectetur adipiscing elit. +
Suspendisse eu turpis elementum
+
+ + +
Title
+

Link

+ Lorem ipsum dolor sit amet, consectetur adipiscing elit. +
Suspendisse eu turpis elementum
+
+ +

Full-width images

+ + 300 X 200 placeholder image +
Title
+

Link

+ Lorem ipsum dolor sit amet, consectetur adipiscing elit. +
Suspendisse eu turpis elementum
+
+ + + 300 X 170 placeholder image + +

Link

+ Lorem ipsum dolor sit amet, consectetur adipiscing elit. +
Suspendisse eu turpis elementum
+
+ +

Desaturated heading

+ + + Red Hat +
Title
+

Link

+ Lorem ipsum dolor sit amet, consectetur adipiscing elit. +
Suspendisse eu turpis elementum
+
+ +

Disabled

+ + +
Title
+

Link

+ Lorem ipsum dolor sit amet, consectetur adipiscing elit. +
Suspendisse eu turpis elementum
+
+

Compact

+ + +

Link

+ Lorem ipsum dolor sit amet, consectetur adipiscing elit. +
Suspendisse eu turpis elementum
+
+ + + Red Hat +

Link

+ Lorem ipsum dolor sit amet, consectetur adipiscing elit. +
Suspendisse eu turpis elementum
+
+ + + Red Hat +

Link

+
+ + + 300 X 50 placeholder image + +

Link

+ Lorem ipsum dolor sit amet, consectetur adipiscing elit. +
Suspendisse eu turpis elementum
+
+ + + 300 X 50 placeholder image +

Link

+ Lorem ipsum dolor sit amet, consectetur adipiscing elit. +
Suspendisse eu turpis elementum
+
+ + + + 300 X 50 placeholder image + + +

Checkboxes

+ + +

Headline

+ Lorem ipsum dolor sit amet, consectetur adipiscing elit. +
Suspendisse eu turpis elementum
+
+ + +

Headline

+ Lorem ipsum dolor sit amet, consectetur adipiscing elit. +
Suspendisse eu turpis elementum
+
+ + +

Headline

+ Lorem ipsum dolor sit amet, consectetur adipiscing elit. +
Suspendisse eu turpis elementum
+
+ +

Tile Group

+ + +

Headline

+ Lorem ipsum dolor sit amet, consectetur adipiscing elit. +
Suspendisse eu turpis elementum
+
+ + +

Headline

+ Lorem ipsum dolor sit amet, consectetur adipiscing elit. +
Suspendisse eu turpis elementum
+
+ + +
Title
+

Headline

+ Lorem ipsum dolor sit amet, consectetur adipiscing elit. +
Suspendisse eu turpis elementum
+
+
+ +

Tile Group, Disabled

+ + +

Headline

+ Lorem ipsum dolor sit amet, consectetur adipiscing elit. +
Suspendisse eu turpis elementum
+
+ + +

Headline

+ Lorem ipsum dolor sit amet, consectetur adipiscing elit. +
Suspendisse eu turpis elementum
+
+ + +

Headline

+ Lorem ipsum dolor sit amet, consectetur adipiscing elit. +
Suspendisse eu turpis elementum
+
+
+ +

Tile Group, Radio

+ + +

Headline

+ Lorem ipsum dolor sit amet, consectetur adipiscing elit. +
Suspendisse eu turpis elementum
+
+ + +

Headline

+ Lorem ipsum dolor sit amet, consectetur adipiscing elit. +
Suspendisse eu turpis elementum
+
+ + +

Headline

+ Lorem ipsum dolor sit amet, consectetur adipiscing elit. +
Suspendisse eu turpis elementum
+
+
+ +

Tile Group, Radio, Disabled

+ + +

Headline

+ Lorem ipsum dolor sit amet, consectetur adipiscing elit. +
Suspendisse eu turpis elementum
+
+ + +

Headline

+ Lorem ipsum dolor sit amet, consectetur adipiscing elit. +
Suspendisse eu turpis elementum
+
+ + +

Headline

+ Lorem ipsum dolor sit amet, consectetur adipiscing elit. +
Suspendisse eu turpis elementum
+
+
+
+
diff --git a/assets/packages/@rhds/elements/elements/rh-tile/demo/color-context.js b/assets/packages/@rhds/elements/elements/rh-tile/demo/color-context.js new file mode 100644 index 0000000000..827ef29ead --- /dev/null +++ b/assets/packages/@rhds/elements/elements/rh-tile/demo/color-context.js @@ -0,0 +1,3 @@ +import '@rhds/elements/lib/elements/rh-context-picker/rh-context-picker.js'; +import '@rhds/elements/lib/elements/rh-context-provider/rh-context-provider.js'; +import './rh-tile.js'; diff --git a/assets/packages/@rhds/elements/elements/rh-tile/demo/compact.html b/assets/packages/@rhds/elements/elements/rh-tile/demo/compact.html new file mode 100644 index 0000000000..d16b01fffa --- /dev/null +++ b/assets/packages/@rhds/elements/elements/rh-tile/demo/compact.html @@ -0,0 +1,46 @@ + + + + +
+

Compact

+ + +

Link

+ Lorem ipsum dolor sit amet, consectetur adipiscing elit. +
Suspendisse eu turpis elementum
+
+ + + Red Hat +

Link

+ Lorem ipsum dolor sit amet, consectetur adipiscing elit. +
Suspendisse eu turpis elementum
+
+ + + Red Hat +

Link

+
+ + + 300 X 50 placeholder image + +

Link

+ Lorem ipsum dolor sit amet, consectetur adipiscing elit. +
Suspendisse eu turpis elementum
+
+ + + 300 X 50 placeholder image +

Link

+ Lorem ipsum dolor sit amet, consectetur adipiscing elit. +
Suspendisse eu turpis elementum
+
+ + + + 300 X 50 placeholder image + + +
diff --git a/assets/packages/@rhds/elements/elements/rh-tile/demo/demo.css b/assets/packages/@rhds/elements/elements/rh-tile/demo/demo.css new file mode 100644 index 0000000000..4f11dcee1c --- /dev/null +++ b/assets/packages/@rhds/elements/elements/rh-tile/demo/demo.css @@ -0,0 +1,22 @@ +#demo-container { + margin: 36px 36px 0; + padding: 36px 0; + row-gap: 36px; +} + +#demo-container, rh-tile-group { + display: flex; + align-items: top; + flex-wrap: wrap; + column-gap: 36px; + row-gap: 36px; +} + +h2:not(rh-tile > h2), rh-tile-group { + flex: 1 0 100%; + margin: 0; +} + +rh-tile { + flex: 0 0 360px; +} \ No newline at end of file diff --git a/assets/packages/@rhds/elements/elements/rh-tile/demo/logo-red-hat.svg b/assets/packages/@rhds/elements/elements/rh-tile/demo/logo-red-hat.svg new file mode 100644 index 0000000000..7ccfd89b73 --- /dev/null +++ b/assets/packages/@rhds/elements/elements/rh-tile/demo/logo-red-hat.svg @@ -0,0 +1 @@ + diff --git a/assets/packages/@rhds/elements/elements/rh-tile/demo/rh-tile-group.html b/assets/packages/@rhds/elements/elements/rh-tile/demo/rh-tile-group.html new file mode 100644 index 0000000000..12cadff959 --- /dev/null +++ b/assets/packages/@rhds/elements/elements/rh-tile/demo/rh-tile-group.html @@ -0,0 +1,90 @@ + + + + +
+

Tile Group

+ + +

Headline

+ Lorem ipsum dolor sit amet, consectetur adipiscing elit. +
Suspendisse eu turpis elementum
+
+ + +

Headline

+ Lorem ipsum dolor sit amet, consectetur adipiscing elit. +
Suspendisse eu turpis elementum
+
+ + +
Title
+

Headline

+ Lorem ipsum dolor sit amet, consectetur adipiscing elit. +
Suspendisse eu turpis elementum
+
+
+ +

Tile Group, Disabled

+ + +

Headline

+ Lorem ipsum dolor sit amet, consectetur adipiscing elit. +
Suspendisse eu turpis elementum
+
+ + +

Headline

+ Lorem ipsum dolor sit amet, consectetur adipiscing elit. +
Suspendisse eu turpis elementum
+
+ + +

Headline

+ Lorem ipsum dolor sit amet, consectetur adipiscing elit. +
Suspendisse eu turpis elementum
+
+
+ +

Tile Group, Radio

+ + +

Headline

+ Lorem ipsum dolor sit amet, consectetur adipiscing elit. +
Suspendisse eu turpis elementum
+
+ + +

Headline

+ Lorem ipsum dolor sit amet, consectetur adipiscing elit. +
Suspendisse eu turpis elementum
+
+ + +

Headline

+ Lorem ipsum dolor sit amet, consectetur adipiscing elit. +
Suspendisse eu turpis elementum
+
+
+ +

Tile Group, Radio, Disabled

+ + +

Headline

+ Lorem ipsum dolor sit amet, consectetur adipiscing elit. +
Suspendisse eu turpis elementum
+
+ + +

Headline

+ Lorem ipsum dolor sit amet, consectetur adipiscing elit. +
Suspendisse eu turpis elementum
+
+ + +

Headline

+ Lorem ipsum dolor sit amet, consectetur adipiscing elit. +
Suspendisse eu turpis elementum
+
+
+
diff --git a/assets/packages/@rhds/elements/elements/rh-tile/demo/rh-tile.html b/assets/packages/@rhds/elements/elements/rh-tile/demo/rh-tile.html new file mode 100644 index 0000000000..467b36f234 --- /dev/null +++ b/assets/packages/@rhds/elements/elements/rh-tile/demo/rh-tile.html @@ -0,0 +1,58 @@ + + + + +
+

Basic

+ + + 296 X 50 placeholder image +
Title
+

Link

+ Lorem ipsum dolor sit amet, consectetur adipiscing elit. +
Suspendisse eu turpis elementum
+
+ + +
Title
+

Link

+ Lorem ipsum dolor sit amet, consectetur adipiscing elit. +
Suspendisse eu turpis elementum
+
+ +

Full-width images

+ + 300 X 200 placeholder image +
Title
+

Link

+ Lorem ipsum dolor sit amet, consectetur adipiscing elit. +
Suspendisse eu turpis elementum
+
+ + + 300 X 170 placeholder image + +

Link

+ Lorem ipsum dolor sit amet, consectetur adipiscing elit. +
Suspendisse eu turpis elementum
+
+ +

Desaturated heading

+ + + Red Hat +
Title
+

Link

+ Lorem ipsum dolor sit amet, consectetur adipiscing elit. +
Suspendisse eu turpis elementum
+
+ +

Disabled

+ + +
Title
+

Link

+ Lorem ipsum dolor sit amet, consectetur adipiscing elit. +
Suspendisse eu turpis elementum
+
+
diff --git a/assets/packages/@rhds/elements/elements/rh-tile/demo/rh-tile.js b/assets/packages/@rhds/elements/elements/rh-tile/demo/rh-tile.js new file mode 100644 index 0000000000..57a2e31eb7 --- /dev/null +++ b/assets/packages/@rhds/elements/elements/rh-tile/demo/rh-tile.js @@ -0,0 +1 @@ +import '@rhds/elements/rh-tile/rh-tile-group.js'; diff --git a/assets/packages/@rhds/elements/elements/rh-tile/docs/00-overview.md b/assets/packages/@rhds/elements/elements/rh-tile/docs/00-overview.md new file mode 100644 index 0000000000..d3942aaf72 --- /dev/null +++ b/assets/packages/@rhds/elements/elements/rh-tile/docs/00-overview.md @@ -0,0 +1,34 @@ +## Overview + +{{ tagName | getElementDescription }} + +{% example palette="light", + alt="Example of a default link tile and a selectable tile", + src="./tile-sample.png" %} + +## Sample element + + + 296 X 50 placeholder +
Title
+

Link

+ Lorem ipsum dolor sit amet, consectetur adipiscing elit. +
Suspendisse eu turpis elementum
+
+ +## Demo + + View a live version of this element and see how it can be customized. + {% playground tagName=tagName %}{% endplayground %} + {% cta href="./demo/", target="_blank" %} + View the `` demo in a new tab + {% endcta %} + +## When to use + +- When you need to group content in a linked container +- When you need an alternative to a group of cards with the same calls to action +- When you need to group content for a radio button or checkbox in a form + +{% repoStatus type="Element" %} + diff --git a/assets/packages/@rhds/elements/elements/rh-tile/docs/10-style.md b/assets/packages/@rhds/elements/elements/rh-tile/docs/10-style.md new file mode 100644 index 0000000000..f15eb8dfd0 --- /dev/null +++ b/assets/packages/@rhds/elements/elements/rh-tile/docs/10-style.md @@ -0,0 +1,147 @@ + +## Style + +A tile is available as a Link tile or Selectable tile. A link tile has two sizes and heading color options; the blue arrow in the bottom right corner helps distinguish it from card. A selectable tile has a consistent style for both the checkbox and radio button variants. + +### Anatomy +{% example palette="light", + alt="Default link tile with numbers pointing to locations of an image, an icon, text, and a footer", + src="../link-tile-anatomy.png" %} + +1) Image +2) Icon +3) Title +4) Heading +5) Body text +6) Footer +{.example-notes} + +{% example palette="light", + alt="Selectable tiles with numbers pointing to locations of text, a checkbox or radio button, and a footer", + src="../selectable-tile-anatomy.png" %} + +1) Heading +2) Form input (checkbox or radio button) +3) Body text +4) Footer +{.example-notes} + +### Sizes + +A link tile is available in Default and Compact sizes. A selectable tile has only one size which is based on the size of a compact tile. + +{% example palette="light", + alt="Examples of a link tile, compact tile, and selectable tile to show size differences", + src="../tile-sizes.png" %} + +## Theme + +Both the link tile and the selectable tile are available in dark and light themes. + +{% example palette="light", + alt="Light theme tiles use a white background, blue or black heading, black text, and a blue arrow icon", + src="../tile-light-theme.png" %} + +{% example palette="darkest", + alt="Dark theme tiles use a dark gray background, blue or white heading, white text, and a light blue arrow icon", + src="../tile-dark-theme.png" %} + +## Heading color + +A link tile has a blue heading by default, but a desaturated variant exists for both light and dark themes. The desaturated heading uses either a black or white heading. A selectable tile has a desaturated heading only and does not have the option for a blue heading. + +{% example palette="light", + alt="Examples of a light theme link tile with a blue heading, link tile with a black heading, and selectable tile with a black heading", + src="../tile-heading-color-light-theme.png" %} + +{% example palette="darkest", + alt="Examples of a dark theme link tile with a light blue heading, link tile with a white heading, and selectable tile with a white heading", + src="../tile-heading-color-dark-theme.png" %} + +## Space + +Space values remain the same at all breakpoints. + +### Link tile without image + +{% example palette="light", + alt="Default link tile and compact link tile with spacers showing padding and margins", + src="../space-link-tile-no-image.png" %} + +### Link tile with an image + +{% example palette="light", + alt="Link tiles that have full-width and default image sizes with spacers showing padding and margins", + src="../space-link-tile-with-image.png" %} + +### Selectable tile + +{% example palette="light", + alt="Selectable tile with spacers showing padding and margins", + src="../space-selectable-tile.png" %} + +## Interaction states + +Interaction states are visual representations used to communicate the status of an element or pattern. The interaction states of a default link tile are the same for a compact link tile as long as they use the same heading color. A selectable tile does not have an underlined heading to avoid users thinking it contains a link. + +### Hover + +{% example palette="light", + alt="On hover, light theme tiles have a light gray background, an underlined (and sometimes darker blue) heading, a darker blue arrow icon ", + src="../tile-states-hover-light-theme.png" %} + +{% example palette="darkest", + alt="On hover, dark theme tiles have a lighter gray background, an underlined (and sometimes lighter blue) heading, a lighter blue arrow icon ", + src="../tile-states-hover-dark-theme.png" %} + +### Focus + +{% alert title="Helpful tip" %} +The Focus state has the same styles as the Hover state. +{% endalert %} + +{% example palette="light", + alt="Focused light theme tiles have a blue focus ring and use hover state styling", + src="../tile-states-focus-light-theme.png" %} + +{% example palette="darkest", + alt="Focused dark theme tiles have a light blue focus ring and use hover state styling", + src="../tile-states-focus-dark-theme.png" %} + +### Active + +Only link tiles have an active state. Selectable tiles have a selected state instead. + +{% alert title="Helpful tip" %} +The Active state has the same styles as the Hover state. +{% endalert %} + +{% example palette="light", + alt="Active light theme link tiles use the focus state styles", + src="../tile-states-active-light-theme.png" %} + +{% example palette="darkest", + alt="Active dark theme link tiles use the focus state styles", + src="../tile-states-active-dark-theme.png" %} + +### Selected + +Only a selectable tile has a selected state. A link tile has an active state instead. + +{% example palette="light", + alt="When selected, the form input of light theme selectable tiles appears blue and filled or checked", + src="../tile-states-selected-light-theme.png" %} + +{% example palette="darkest", + alt="When selected, the form input of dark theme selectable tiles appears light blue and filled or checked", + src="../tile-states-selected-dark-theme.png" %} + +### Disabled + +{% example palette="light", + alt="Disabled light theme tiles have a light gray background and lighter gray text. Disabled link tiles have a ban icon.", + src="../tile-states-disabled-light-theme.png" %} + +{% example palette="darkest", + alt="Disabled dark theme tiles have a lighter gray background and light gray text. Disabled link tiles have a ban icon.", + src="../tile-states-disabled-dark-theme.png" %} diff --git a/assets/packages/@rhds/elements/elements/rh-tile/docs/20-guidelines.md b/assets/packages/@rhds/elements/elements/rh-tile/docs/20-guidelines.md new file mode 100644 index 0000000000..d1e0ce5f72 --- /dev/null +++ b/assets/packages/@rhds/elements/elements/rh-tile/docs/20-guidelines.md @@ -0,0 +1,134 @@ +## Usage + +A tile can be used when a clickable container is needed to provide one call to action or show one form input option. It can be grouped with similarly-structured and styled tiles in a tile group. There are two types, link tiles and selectable tiles. Both can be used in groups or individually, except for a selectable tile with a radio button, which always has to be grouped. + +### Tile vs. card + +The primary distinguishing factor between a tile and a card is that each tile can perform only one action because the whole surface is clickable. A tile also has the ability to be used as selectable items in a form. Tiles can be grouped together like card, however. + +## Variants + +### Link tiles + +A link tile has many different use cases, but it is especially helpful to use in place of a card group that would have repetitive calls to action. They can also be used in place of Brick calls to action if adding icons or images is necessary. + +#### Compact link tile + +A link tile has a compact variant that can be used in sections that need a denser concentration of information. To further condense each tile, a compact link tile does not have a title slot and the icon appears to the left of content, rather than above it. + +#### Desaturated heading + +The desaturated heading variant is best used for pages with many link tiles. For example, it can help prevent a blue heading from appearing visually overwhelming on a search results page, especially if each tile includes a logo. Other than the heading color, the hover, focus, and active states look the same as a default link tile and the arrow will always be blue. + +#### Image sizes + +For a link tile, there are two image sizes available. The Default size has spacing around the entire image. The Full-width image size bleeds to the top, left, and right edges. The default image size is recommended for logos, while illustrations or photos would work well as a full-width image. + +{% example palette="light", + alt="Examples of a logo in a tile with the default image size and a photo in a tile with the full-width image size", + src="../tile-variants-image-sizes.png" %} + +### Selectable tiles + +{% alert state="warning", title="Warning" %} +A selectable tile with a radio button must be used in a group. If there is only one choice listed, use a checkbox.{% endalert %} + +A selectable tile is a form element and can be used as either a radio button or a checkbox. The radio button should be used if only one option can be selected. A selectable tile with checkboxes should be used when a user can select more than one option. + +## Writing content + +The four content slots within a tile are title, heading, body, and footer. + +- ### Title + A title provides secondary descriptive context. A selectable tile does not have title slots. + +- ### Heading + In a link tile, the heading should indicate what clicking on the tile will do. In a selectable tile, the heading labels the radio button or checkbox. + +- ### Body + The body text expands on heading content and gives the user more information. + +- ### Footer + Footer text should be brief and be used for supplementary information only. + {.multi-column--min-400-wide style="padding:0;list-style-type:none;"} + +### Character count + +The recommended character counts below include spaces. Line counts are based on a default link tile at minimum width. + +| Element | Character count | Line count | +| -------------------------| ---------------- | ---------- | +| Title text | 20 | 1 | +| Heading text | 64 | 3 | +| Body text | 160 | 7 | +| Footer text | 25 | 1 | + +{.full-width .col-111} + +## Layouts + +Like a card, the default tile should have a minimum width of four grid columns, so there is a maximum of three default link tiles in one row. + +{% example palette="light", + alt="Three default link tiles in a row", + src="../tile-layouts-default-tile.png" %} + +The compact link tiles or selectable tiles can condense to a minimum width of three grid columns or a max of four compact tiles in a row. + +{% example palette="light", + alt="Four compact link tiles in a row", + src="../tile-layouts-compact-tile.png" %} + +## Behavior + +### Vertical height + +The vertical height of a tile will increase as more content is added. The vertical height of multiple tiles in one row matches the height of the tallest tile. + +{% example palette="light", + alt="Three link tiles with different amounts of content have the same height", + src="../tile-behavior-vertical-height.png" %} + +## Best practices + +### Link tile actions + +Do not use a link tile if it needs to link to more than one destination. + +{% example palette="wrong", + alt="Example of an incorrectly used link tile with a call to action in the body", + src="../best-practices-link-tile-actions-1.png" %} + +A link tile should not be used as a button. A link tile is akin to a call to action and should navigate a user somewhere else. + +{% example palette="wrong", + alt="Example of an incorrectly used link tile with “submit” as a heading and no other text", + src="../best-practices-link-tile-actions-2.png" %} + +### Tile groups + +Do not use different variants of a tile in one tile group. + +{% example palette="wrong", + alt="Example of an incorrectly styled tile group with a default link tile and a compact link tile", + src="../best-practices-tile-groups-1.png" %} + +When grouped, use the same number of content slots to make them easy to scan. + +{% example palette="wrong", + alt="Example of an incorrectly styled tile group with one tile that has only text and a second tile that includes a logo and a title", + src="../best-practices-tile-groups-2.png" %} + +If tiles have images, the images should have the same height. This will help the headings of each tile align vertically which also helps users scan more easily. + +{% example palette="wrong", + alt="Example of an incorrectly styled tile group with two tiles using different image heights", + src="../best-practices-tile-groups-3.png" %} + +### Footer content + +The footer of a link tile or selectable tile should not include calls to action, links, or buttons, but it can include non-interactive elements, like tags or badges. Ideally, footer content should be able to fit on one line, but it can wrap to two when necessary. + +{% example palette="wrong", + alt="Example of incorrectly adding a link in the footer of a link tile", + src="../best-practices-tile-footer-content.png" %} \ No newline at end of file diff --git a/assets/packages/@rhds/elements/elements/rh-tile/docs/30-code.md b/assets/packages/@rhds/elements/elements/rh-tile/docs/30-code.md new file mode 100644 index 0000000000..7b26b239aa --- /dev/null +++ b/assets/packages/@rhds/elements/elements/rh-tile/docs/30-code.md @@ -0,0 +1,15 @@ +{% renderInstallation %}{% endrenderInstallation %} + +{% band header="Usage" %} + {% alert state="warning", title="Warning" %} + Tiles require light DOM CSS to be included on the page in order to style links properly. + {% endalert %} + {% playground tagName=tile %}{% endplayground %} + {% cta href="./demo/", target="_blank" %} +View the demo in a new tab + {% endcta %} +{% endband %} + +{% renderCodeDocs hideDescription=true %}{% endrenderCodeDocs %} + +{% renderCodeDocs for='rh-tile-group' %}{% endrenderCodeDocs %} diff --git a/assets/packages/@rhds/elements/elements/rh-tile/docs/40-accessibility.md b/assets/packages/@rhds/elements/elements/rh-tile/docs/40-accessibility.md new file mode 100644 index 0000000000..d04705d611 --- /dev/null +++ b/assets/packages/@rhds/elements/elements/rh-tile/docs/40-accessibility.md @@ -0,0 +1,42 @@ +## Keyboard interactions + +A user should have the ability to use the Tab key to navigate to a tile or into a tile group. When tiles are in a group, a user will need to use arrow keys to navigate from one tile to another. Pressing the `Enter`/`Return` key will activate a link tile or select a selectable tile. + +{% example palette="light", + alt="Tile groups with labels showing which key to use for navigating", + src="../tile-keyboard-interactions.png" %} + +| Key {style="width: 25%" } | Result | +| ------------------------- | ------------------------------------------------------------------------------- | +| Tab | Moves focus to a solo tile or the first tile in a group | +| Shift + Tab | Moves focus to a previous solo tile or the last tile in a previous tile group | +| Left Arrow | Moves focus to the previous tile and activates it (horizontal tabs) | +| Right Arrow | Moves focus to the next tile and activates it (horizontal tabs) | +| Up Arrow | Moves focus to the previous tile and activates it (vertical tabs) | +| Arrow keys | Moves focus from one tile to another in a tile group | +| Enter | Activates a link tile or selects a selectable tile | + +## Focus order + +A logical focus order helps keyboard users operate our websites. Elements need to receive focus in an order that preserves meaning, therefore the focus order should make sense and not jump around randomly. In tile groups, focus moves from left to right and top to bottom. + +{% example palette="light", + alt="Tile groups with numbers showing the focus order", + src="../tile-focus-order.png" %} + +## Touch targets + +The whole tile is selectable, and the required heading or image would make each tile a large enough touch target. + +## Additional guidelines + +- Include alt text for a slotted image especially if it is wrapped in a link + +{% include 'accessibility/ariaguide.md' %} + +{% include 'accessibility/wcag.md' %} + +{% include 'accessibility/2.1.1-A.md' %} +{% include 'accessibility/2.1.3-AAA.md' %} +{% include 'accessibility/2.4.3-A.md' %} +{% include 'accessibility/2.5.5-AAA.md' %} \ No newline at end of file diff --git a/assets/packages/@rhds/elements/elements/rh-tile/docs/best-practices-link-tile-actions-1.png b/assets/packages/@rhds/elements/elements/rh-tile/docs/best-practices-link-tile-actions-1.png new file mode 100644 index 0000000000..64c6698b6d Binary files /dev/null and b/assets/packages/@rhds/elements/elements/rh-tile/docs/best-practices-link-tile-actions-1.png differ diff --git a/assets/packages/@rhds/elements/elements/rh-tile/docs/best-practices-link-tile-actions-2.png b/assets/packages/@rhds/elements/elements/rh-tile/docs/best-practices-link-tile-actions-2.png new file mode 100644 index 0000000000..03dc025005 Binary files /dev/null and b/assets/packages/@rhds/elements/elements/rh-tile/docs/best-practices-link-tile-actions-2.png differ diff --git a/assets/packages/@rhds/elements/elements/rh-tile/docs/best-practices-tile-footer-content.png b/assets/packages/@rhds/elements/elements/rh-tile/docs/best-practices-tile-footer-content.png new file mode 100755 index 0000000000..bc5f19b5f7 Binary files /dev/null and b/assets/packages/@rhds/elements/elements/rh-tile/docs/best-practices-tile-footer-content.png differ diff --git a/assets/packages/@rhds/elements/elements/rh-tile/docs/best-practices-tile-groups-1.png b/assets/packages/@rhds/elements/elements/rh-tile/docs/best-practices-tile-groups-1.png new file mode 100755 index 0000000000..9250ba332a Binary files /dev/null and b/assets/packages/@rhds/elements/elements/rh-tile/docs/best-practices-tile-groups-1.png differ diff --git a/assets/packages/@rhds/elements/elements/rh-tile/docs/best-practices-tile-groups-2.png b/assets/packages/@rhds/elements/elements/rh-tile/docs/best-practices-tile-groups-2.png new file mode 100755 index 0000000000..235f11485b Binary files /dev/null and b/assets/packages/@rhds/elements/elements/rh-tile/docs/best-practices-tile-groups-2.png differ diff --git a/assets/packages/@rhds/elements/elements/rh-tile/docs/best-practices-tile-groups-3.png b/assets/packages/@rhds/elements/elements/rh-tile/docs/best-practices-tile-groups-3.png new file mode 100755 index 0000000000..0fcfcef89d Binary files /dev/null and b/assets/packages/@rhds/elements/elements/rh-tile/docs/best-practices-tile-groups-3.png differ diff --git a/assets/packages/@rhds/elements/elements/rh-tile/docs/link-tile-anatomy.png b/assets/packages/@rhds/elements/elements/rh-tile/docs/link-tile-anatomy.png new file mode 100644 index 0000000000..40b1fe398c Binary files /dev/null and b/assets/packages/@rhds/elements/elements/rh-tile/docs/link-tile-anatomy.png differ diff --git a/assets/packages/@rhds/elements/elements/rh-tile/docs/screenshot.png b/assets/packages/@rhds/elements/elements/rh-tile/docs/screenshot.png new file mode 100644 index 0000000000..6380fccce9 Binary files /dev/null and b/assets/packages/@rhds/elements/elements/rh-tile/docs/screenshot.png differ diff --git a/assets/packages/@rhds/elements/elements/rh-tile/docs/selectable-tile-anatomy.png b/assets/packages/@rhds/elements/elements/rh-tile/docs/selectable-tile-anatomy.png new file mode 100644 index 0000000000..a3682748dd Binary files /dev/null and b/assets/packages/@rhds/elements/elements/rh-tile/docs/selectable-tile-anatomy.png differ diff --git a/assets/packages/@rhds/elements/elements/rh-tile/docs/space-link-tile-no-image.png b/assets/packages/@rhds/elements/elements/rh-tile/docs/space-link-tile-no-image.png new file mode 100755 index 0000000000..7285a545d5 Binary files /dev/null and b/assets/packages/@rhds/elements/elements/rh-tile/docs/space-link-tile-no-image.png differ diff --git a/assets/packages/@rhds/elements/elements/rh-tile/docs/space-link-tile-with-image.png b/assets/packages/@rhds/elements/elements/rh-tile/docs/space-link-tile-with-image.png new file mode 100755 index 0000000000..31718402e4 Binary files /dev/null and b/assets/packages/@rhds/elements/elements/rh-tile/docs/space-link-tile-with-image.png differ diff --git a/assets/packages/@rhds/elements/elements/rh-tile/docs/space-selectable-tile.png b/assets/packages/@rhds/elements/elements/rh-tile/docs/space-selectable-tile.png new file mode 100755 index 0000000000..9662d6fd74 Binary files /dev/null and b/assets/packages/@rhds/elements/elements/rh-tile/docs/space-selectable-tile.png differ diff --git a/assets/packages/@rhds/elements/elements/rh-tile/docs/tile-behavior-vertical-height.png b/assets/packages/@rhds/elements/elements/rh-tile/docs/tile-behavior-vertical-height.png new file mode 100755 index 0000000000..c57284e15c Binary files /dev/null and b/assets/packages/@rhds/elements/elements/rh-tile/docs/tile-behavior-vertical-height.png differ diff --git a/assets/packages/@rhds/elements/elements/rh-tile/docs/tile-dark-theme.png b/assets/packages/@rhds/elements/elements/rh-tile/docs/tile-dark-theme.png new file mode 100755 index 0000000000..f4b8d7408e Binary files /dev/null and b/assets/packages/@rhds/elements/elements/rh-tile/docs/tile-dark-theme.png differ diff --git a/assets/packages/@rhds/elements/elements/rh-tile/docs/tile-focus-order.png b/assets/packages/@rhds/elements/elements/rh-tile/docs/tile-focus-order.png new file mode 100644 index 0000000000..51a16b47bd Binary files /dev/null and b/assets/packages/@rhds/elements/elements/rh-tile/docs/tile-focus-order.png differ diff --git a/assets/packages/@rhds/elements/elements/rh-tile/docs/tile-heading-color-dark-theme.png b/assets/packages/@rhds/elements/elements/rh-tile/docs/tile-heading-color-dark-theme.png new file mode 100755 index 0000000000..f4b8d7408e Binary files /dev/null and b/assets/packages/@rhds/elements/elements/rh-tile/docs/tile-heading-color-dark-theme.png differ diff --git a/assets/packages/@rhds/elements/elements/rh-tile/docs/tile-heading-color-light-theme.png b/assets/packages/@rhds/elements/elements/rh-tile/docs/tile-heading-color-light-theme.png new file mode 100755 index 0000000000..62ad433ea7 Binary files /dev/null and b/assets/packages/@rhds/elements/elements/rh-tile/docs/tile-heading-color-light-theme.png differ diff --git a/assets/packages/@rhds/elements/elements/rh-tile/docs/tile-keyboard-interactions.png b/assets/packages/@rhds/elements/elements/rh-tile/docs/tile-keyboard-interactions.png new file mode 100644 index 0000000000..e43896c963 Binary files /dev/null and b/assets/packages/@rhds/elements/elements/rh-tile/docs/tile-keyboard-interactions.png differ diff --git a/assets/packages/@rhds/elements/elements/rh-tile/docs/tile-layouts-compact-tile.png b/assets/packages/@rhds/elements/elements/rh-tile/docs/tile-layouts-compact-tile.png new file mode 100644 index 0000000000..85fbc88dcc Binary files /dev/null and b/assets/packages/@rhds/elements/elements/rh-tile/docs/tile-layouts-compact-tile.png differ diff --git a/assets/packages/@rhds/elements/elements/rh-tile/docs/tile-layouts-default-tile.png b/assets/packages/@rhds/elements/elements/rh-tile/docs/tile-layouts-default-tile.png new file mode 100644 index 0000000000..f60cd6ca61 Binary files /dev/null and b/assets/packages/@rhds/elements/elements/rh-tile/docs/tile-layouts-default-tile.png differ diff --git a/assets/packages/@rhds/elements/elements/rh-tile/docs/tile-light-theme.png b/assets/packages/@rhds/elements/elements/rh-tile/docs/tile-light-theme.png new file mode 100755 index 0000000000..62ad433ea7 Binary files /dev/null and b/assets/packages/@rhds/elements/elements/rh-tile/docs/tile-light-theme.png differ diff --git a/assets/packages/@rhds/elements/elements/rh-tile/docs/tile-sample.png b/assets/packages/@rhds/elements/elements/rh-tile/docs/tile-sample.png new file mode 100755 index 0000000000..7f58b6a920 Binary files /dev/null and b/assets/packages/@rhds/elements/elements/rh-tile/docs/tile-sample.png differ diff --git a/assets/packages/@rhds/elements/elements/rh-tile/docs/tile-sizes.png b/assets/packages/@rhds/elements/elements/rh-tile/docs/tile-sizes.png new file mode 100644 index 0000000000..7a47f7bdf2 Binary files /dev/null and b/assets/packages/@rhds/elements/elements/rh-tile/docs/tile-sizes.png differ diff --git a/assets/packages/@rhds/elements/elements/rh-tile/docs/tile-states-active-dark-theme.png b/assets/packages/@rhds/elements/elements/rh-tile/docs/tile-states-active-dark-theme.png new file mode 100755 index 0000000000..afa8226910 Binary files /dev/null and b/assets/packages/@rhds/elements/elements/rh-tile/docs/tile-states-active-dark-theme.png differ diff --git a/assets/packages/@rhds/elements/elements/rh-tile/docs/tile-states-active-light-theme.png b/assets/packages/@rhds/elements/elements/rh-tile/docs/tile-states-active-light-theme.png new file mode 100755 index 0000000000..2d178943a6 Binary files /dev/null and b/assets/packages/@rhds/elements/elements/rh-tile/docs/tile-states-active-light-theme.png differ diff --git a/assets/packages/@rhds/elements/elements/rh-tile/docs/tile-states-disabled-dark-theme.png b/assets/packages/@rhds/elements/elements/rh-tile/docs/tile-states-disabled-dark-theme.png new file mode 100755 index 0000000000..77f04bc4a3 Binary files /dev/null and b/assets/packages/@rhds/elements/elements/rh-tile/docs/tile-states-disabled-dark-theme.png differ diff --git a/assets/packages/@rhds/elements/elements/rh-tile/docs/tile-states-disabled-light-theme.png b/assets/packages/@rhds/elements/elements/rh-tile/docs/tile-states-disabled-light-theme.png new file mode 100755 index 0000000000..06e9fc4805 Binary files /dev/null and b/assets/packages/@rhds/elements/elements/rh-tile/docs/tile-states-disabled-light-theme.png differ diff --git a/assets/packages/@rhds/elements/elements/rh-tile/docs/tile-states-focus-dark-theme.png b/assets/packages/@rhds/elements/elements/rh-tile/docs/tile-states-focus-dark-theme.png new file mode 100644 index 0000000000..07faf68be7 Binary files /dev/null and b/assets/packages/@rhds/elements/elements/rh-tile/docs/tile-states-focus-dark-theme.png differ diff --git a/assets/packages/@rhds/elements/elements/rh-tile/docs/tile-states-focus-light-theme.png b/assets/packages/@rhds/elements/elements/rh-tile/docs/tile-states-focus-light-theme.png new file mode 100644 index 0000000000..24d2826333 Binary files /dev/null and b/assets/packages/@rhds/elements/elements/rh-tile/docs/tile-states-focus-light-theme.png differ diff --git a/assets/packages/@rhds/elements/elements/rh-tile/docs/tile-states-hover-dark-theme.png b/assets/packages/@rhds/elements/elements/rh-tile/docs/tile-states-hover-dark-theme.png new file mode 100644 index 0000000000..128c89ebff Binary files /dev/null and b/assets/packages/@rhds/elements/elements/rh-tile/docs/tile-states-hover-dark-theme.png differ diff --git a/assets/packages/@rhds/elements/elements/rh-tile/docs/tile-states-hover-light-theme.png b/assets/packages/@rhds/elements/elements/rh-tile/docs/tile-states-hover-light-theme.png new file mode 100644 index 0000000000..362c7d2883 Binary files /dev/null and b/assets/packages/@rhds/elements/elements/rh-tile/docs/tile-states-hover-light-theme.png differ diff --git a/assets/packages/@rhds/elements/elements/rh-tile/docs/tile-states-selected-dark-theme.png b/assets/packages/@rhds/elements/elements/rh-tile/docs/tile-states-selected-dark-theme.png new file mode 100755 index 0000000000..229a4e9e50 Binary files /dev/null and b/assets/packages/@rhds/elements/elements/rh-tile/docs/tile-states-selected-dark-theme.png differ diff --git a/assets/packages/@rhds/elements/elements/rh-tile/docs/tile-states-selected-light-theme.png b/assets/packages/@rhds/elements/elements/rh-tile/docs/tile-states-selected-light-theme.png new file mode 100755 index 0000000000..3993f7a503 Binary files /dev/null and b/assets/packages/@rhds/elements/elements/rh-tile/docs/tile-states-selected-light-theme.png differ diff --git a/assets/packages/@rhds/elements/elements/rh-tile/docs/tile-variants-image-sizes.png b/assets/packages/@rhds/elements/elements/rh-tile/docs/tile-variants-image-sizes.png new file mode 100755 index 0000000000..d8344c8e8b Binary files /dev/null and b/assets/packages/@rhds/elements/elements/rh-tile/docs/tile-variants-image-sizes.png differ diff --git a/assets/packages/@rhds/elements/elements/rh-tile/rh-tile-group.css b/assets/packages/@rhds/elements/elements/rh-tile/rh-tile-group.css new file mode 100644 index 0000000000..4a7ce0af3b --- /dev/null +++ b/assets/packages/@rhds/elements/elements/rh-tile/rh-tile-group.css @@ -0,0 +1,3 @@ +:host([disabled]) { + pointer-events: none; +} \ No newline at end of file diff --git a/assets/packages/@rhds/elements/elements/rh-tile/rh-tile-group.d.ts b/assets/packages/@rhds/elements/elements/rh-tile/rh-tile-group.d.ts new file mode 100644 index 0000000000..7ce3134fe0 --- /dev/null +++ b/assets/packages/@rhds/elements/elements/rh-tile/rh-tile-group.d.ts @@ -0,0 +1,64 @@ +import { LitElement, type PropertyValueMap } from 'lit'; +import { type ColorPalette } from '../../lib/context/color/provider.js'; +import { RhTile } from './rh-tile.js'; +/** + * A group of `` elements which handles radio selection. + * @slot - tiles + */ +export declare class RhTileGroup extends LitElement { + #private; + static readonly styles: import("lit").CSSResult[]; + /** + * whether tile group interaction is disabled + */ + disabled: boolean; + /** + * if tile is checkable, whether only one tile can be checked + */ + radio: boolean; + /** + * Sets color theme based on parent context + */ + private on?; + /** + * Sets color palette, which affects the element's styles as well as descendants' color theme. + * Overrides parent color context. + * Your theme will influence these colors so check there first if you are seeing inconsistencies. + * See [CSS Custom Properties](#css-custom-properties) for default values + * + * Tile group always resets its context to `base`, unless explicitly provided with a `color-palette`. + */ + colorPalette?: ColorPalette; + /** + * all slotted tiles + */ + get tiles(): RhTile[]; + /** + * all selected tiles + */ + get selected(): RhTile | RhTile[]; + protected firstUpdated(): void; + protected updated(_changedProperties: PropertyValueMap | Map): void; + render(): import("lit-html").TemplateResult<1>; + /** sets focus on active tile */ + focus(): void; + /** + * programatically select a tile + * @param tile {RhTile | null | undefined} tile to select + */ + selectItem(tile: RhTile | null | undefined): void; + /** + * programatically toggle a tile + * @param tile {RhTile | null | undefined} tile to toggle + */ + toggleItem(tile: RhTile | null | undefined): void; + /** + * updates slotted tiles to set properties and keyboard navigation + */ + updateItems(): void; +} +declare global { + interface HTMLElementTagNameMap { + 'rh-tile-group': RhTileGroup; + } +} diff --git a/assets/packages/@rhds/elements/elements/rh-tile/rh-tile-group.js b/assets/packages/@rhds/elements/elements/rh-tile/rh-tile-group.js new file mode 100644 index 0000000000..8075c3ad90 --- /dev/null +++ b/assets/packages/@rhds/elements/elements/rh-tile/rh-tile-group.js @@ -0,0 +1,162 @@ +var _RhTileGroup_instances, _RhTileGroup_tiles, _RhTileGroup_initTiles, _RhTileGroup_tabindex, _RhTileGroup_internals, _RhTileGroup_setTiles, _RhTileGroup_onSelect, _RhTileGroup_onSlotchange; +import { __classPrivateFieldGet, __classPrivateFieldSet, __decorate } from "tslib"; +import { LitElement, html } from 'lit'; +import { classMap } from 'lit/directives/class-map.js'; +import { customElement } from 'lit/decorators/custom-element.js'; +import { property } from 'lit/decorators/property.js'; +import { colorContextConsumer } from '../../lib/context/color/consumer.js'; +import { colorContextProvider } from '../../lib/context/color/provider.js'; +import { getRandomId } from '@patternfly/pfe-core/functions/random.js'; +import { InternalsController } from '@patternfly/pfe-core/controllers/internals-controller.js'; +import { RovingTabindexController } from '@patternfly/pfe-core/controllers/roving-tabindex-controller.js'; +import { RhTile, TileSelectEvent } from './rh-tile.js'; +import { css } from "lit"; +const styles = css `:host([disabled]){pointer-events:none}`; +/** + * A group of `` elements which handles radio selection. + * @slot - tiles + */ +let RhTileGroup = class RhTileGroup extends LitElement { + constructor() { + super(...arguments); + _RhTileGroup_instances.add(this); + /** + * whether tile group interaction is disabled + */ + this.disabled = false; + /** + * if tile is checkable, whether only one tile can be checked + */ + this.radio = false; + _RhTileGroup_tiles.set(this, []); + _RhTileGroup_initTiles.set(this, false); + _RhTileGroup_tabindex.set(this, new RovingTabindexController(this)); + _RhTileGroup_internals.set(this, new InternalsController(this, {})); + } + /** + * all slotted tiles + */ + get tiles() { + return __classPrivateFieldGet(this, _RhTileGroup_tiles, "f"); + } + /** + * all selected tiles + */ + get selected() { + const selected = __classPrivateFieldGet(this, _RhTileGroup_tiles, "f")?.filter(tile => tile.checked); + const [first] = selected; + return this.radio ? first : selected; + } + firstUpdated() { + __classPrivateFieldGet(this, _RhTileGroup_internals, "f").role = this.radio ? 'radiogroup' : null; + this.updateItems(); + } + updated(_changedProperties) { + if (_changedProperties.has('radio')) { + __classPrivateFieldGet(this, _RhTileGroup_internals, "f").role = this.radio ? 'radiogroup' : null; + let selected; + __classPrivateFieldGet(this, _RhTileGroup_tiles, "f").forEach(tile => { + // @ts-expect-error: internal use of private prop. replace with context. see rh-tile.ts + tile.radioGroup = this.radio; + if (this.radio && !selected && tile.checked) { + selected = tile; + } + }); + this.selectItem(selected); + } + if (_changedProperties.has('disabled')) { + __classPrivateFieldGet(this, _RhTileGroup_internals, "f").ariaDisabled = this.disabled ? 'true' : 'false'; + __classPrivateFieldGet(this, _RhTileGroup_tiles, "f").forEach(tile => { + // @ts-expect-error: internal use of private prop. replace with context. see rh-tile.ts + tile.disabledGroup = this.disabled; + }); + } + } + render() { + const { on = '', radio } = this; + return html ` + + `; + } + /** sets focus on active tile */ + focus() { + (__classPrivateFieldGet(this, _RhTileGroup_tabindex, "f")?.activeItem || __classPrivateFieldGet(this, _RhTileGroup_tabindex, "f").firstItem)?.focus(); + } + /** + * programatically select a tile + * @param tile {RhTile | null | undefined} tile to select + */ + selectItem(tile) { + if (tile) { + tile.checked = true; + __classPrivateFieldGet(this, _RhTileGroup_instances, "m", _RhTileGroup_setTiles).call(this, tile); + } + } + /** + * programatically toggle a tile + * @param tile {RhTile | null | undefined} tile to toggle + */ + toggleItem(tile) { + if (tile?.checked) { + tile.checked = false; + } + else { + this.selectItem(tile); + } + } + /** + * updates slotted tiles to set properties and keyboard navigation + */ + updateItems() { + __classPrivateFieldSet(this, _RhTileGroup_tiles, [...this.querySelectorAll('rh-tile')], "f"); + __classPrivateFieldGet(this, _RhTileGroup_tiles, "f").forEach(tile => { + tile.checkable = true; + // @ts-expect-error: internal use of private prop. replace with context. see rh-tile.ts + tile.radioGroup = this.radio; + // @ts-expect-error: internal use of private prop. replace with context. see rh-tile.ts + tile.disabledGroup !== this.disabled; + tile.id = tile.id || getRandomId('rh-tile'); + }); + if (__classPrivateFieldGet(this, _RhTileGroup_initTiles, "f")) { + __classPrivateFieldGet(this, _RhTileGroup_tabindex, "f").updateItems(__classPrivateFieldGet(this, _RhTileGroup_tiles, "f")); + } + else { + __classPrivateFieldSet(this, _RhTileGroup_initTiles, true, "f"); + __classPrivateFieldGet(this, _RhTileGroup_tabindex, "f").initItems(__classPrivateFieldGet(this, _RhTileGroup_tiles, "f")); + } + } +}; +_RhTileGroup_tiles = new WeakMap(), _RhTileGroup_initTiles = new WeakMap(), _RhTileGroup_tabindex = new WeakMap(), _RhTileGroup_internals = new WeakMap(), _RhTileGroup_instances = new WeakSet(), _RhTileGroup_setTiles = function _RhTileGroup_setTiles(tile) { + // @ts-expect-error: internal use of private prop. replace with context. see rh-tile.ts + if (!this.disabled && (tile && tile.radioGroup || this.radio) && tile?.checked) { + __classPrivateFieldGet(this, _RhTileGroup_tiles, "f")?.forEach(item => { + if (tile !== item && item.checked) { + item.checked = false; + } + }); + } +}, _RhTileGroup_onSelect = function _RhTileGroup_onSelect(event) { + const tile = event.target; + __classPrivateFieldGet(this, _RhTileGroup_instances, "m", _RhTileGroup_setTiles).call(this, tile); +}, _RhTileGroup_onSlotchange = function _RhTileGroup_onSlotchange() { + this.updateItems(); +}; +RhTileGroup.styles = [styles]; +__decorate([ + property({ reflect: true, attribute: 'disabled', type: Boolean }) +], RhTileGroup.prototype, "disabled", void 0); +__decorate([ + property({ attribute: 'radio', type: Boolean }) +], RhTileGroup.prototype, "radio", void 0); +__decorate([ + colorContextConsumer() +], RhTileGroup.prototype, "on", void 0); +__decorate([ + colorContextProvider(), + property({ reflect: true, attribute: 'color-palette' }) +], RhTileGroup.prototype, "colorPalette", void 0); +RhTileGroup = __decorate([ + customElement('rh-tile-group') +], RhTileGroup); +export { RhTileGroup }; +//# sourceMappingURL=rh-tile-group.js.map \ No newline at end of file diff --git a/assets/packages/@rhds/elements/elements/rh-tile/rh-tile-group.js.map b/assets/packages/@rhds/elements/elements/rh-tile/rh-tile-group.js.map new file mode 100644 index 0000000000..6d07c835c1 --- /dev/null +++ b/assets/packages/@rhds/elements/elements/rh-tile/rh-tile-group.js.map @@ -0,0 +1 @@ +{"version":3,"file":"rh-tile-group.js","sourceRoot":"","sources":["rh-tile-group.ts"],"names":[],"mappings":"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","sourcesContent":["import { LitElement, html, type PropertyValueMap } from 'lit';\nimport { classMap } from 'lit/directives/class-map.js';\nimport { customElement } from 'lit/decorators/custom-element.js';\nimport { property } from 'lit/decorators/property.js';\nimport { colorContextConsumer, type ColorTheme } from '../../lib/context/color/consumer.js';\nimport { colorContextProvider, type ColorPalette } from '../../lib/context/color/provider.js';\nimport { getRandomId } from '@patternfly/pfe-core/functions/random.js';\nimport { InternalsController } from '@patternfly/pfe-core/controllers/internals-controller.js';\nimport { RovingTabindexController } from '@patternfly/pfe-core/controllers/roving-tabindex-controller.js';\nimport { RhTile, TileSelectEvent } from './rh-tile.js';\n\nimport styles from './rh-tile-group.css';\n\n/**\n * A group of `` elements which handles radio selection.\n * @slot - tiles\n */\n@customElement('rh-tile-group')\nexport class RhTileGroup extends LitElement {\n static readonly styles = [styles];\n\n /**\n * whether tile group interaction is disabled\n */\n @property({ reflect: true, attribute: 'disabled', type: Boolean }) disabled = false;\n\n /**\n * if tile is checkable, whether only one tile can be checked\n */\n @property({ attribute: 'radio', type: Boolean }) radio = false;\n\n /**\n * Sets color theme based on parent context\n */\n @colorContextConsumer() private on?: ColorTheme;\n\n /**\n * Sets color palette, which affects the element's styles as well as descendants' color theme.\n * Overrides parent color context.\n * Your theme will influence these colors so check there first if you are seeing inconsistencies.\n * See [CSS Custom Properties](#css-custom-properties) for default values\n *\n * Tile group always resets its context to `base`, unless explicitly provided with a `color-palette`.\n */\n @colorContextProvider()\n @property({ reflect: true, attribute: 'color-palette' }) colorPalette?: ColorPalette;\n\n #tiles: RhTile[] = [];\n #initTiles = false;\n\n #tabindex = new RovingTabindexController(this);\n #internals = new InternalsController(this, { });\n\n /**\n * all slotted tiles\n */\n get tiles() {\n return this.#tiles;\n }\n\n /**\n * all selected tiles\n */\n get selected() {\n const selected = this.#tiles?.filter(tile=> tile.checked);\n const [first] = selected;\n return this.radio ? first : selected;\n }\n\n protected firstUpdated(): void {\n this.#internals.role = this.radio ? 'radiogroup' : null;\n this.updateItems();\n }\n\n protected updated(_changedProperties: PropertyValueMap | Map): void {\n if (_changedProperties.has('radio')) {\n this.#internals.role = this.radio ? 'radiogroup' : null;\n let selected: RhTile | null | undefined;\n this.#tiles.forEach(tile => {\n // @ts-expect-error: internal use of private prop. replace with context. see rh-tile.ts\n tile.radioGroup = this.radio;\n if (this.radio && !selected && tile.checked) {\n selected = tile;\n }\n });\n this.selectItem(selected);\n }\n\n if (_changedProperties.has('disabled')) {\n this.#internals.ariaDisabled = this.disabled ? 'true' : 'false';\n this.#tiles.forEach(tile => {\n // @ts-expect-error: internal use of private prop. replace with context. see rh-tile.ts\n tile.disabledGroup = this.disabled;\n });\n }\n }\n\n render() {\n const { on = '', radio } = this;\n return html`\n \n `;\n }\n\n /** sets focus on active tile */\n focus() {\n (this.#tabindex?.activeItem || this.#tabindex.firstItem)?.focus();\n }\n\n /**\n * programatically select a tile\n * @param tile {RhTile | null | undefined} tile to select\n */\n selectItem(tile: RhTile | null | undefined) {\n if (tile) {\n tile.checked = true;\n this.#setTiles(tile);\n }\n }\n\n /**\n * programatically toggle a tile\n * @param tile {RhTile | null | undefined} tile to toggle\n */\n toggleItem(tile: RhTile | null | undefined) {\n if (tile?.checked) {\n tile.checked = false;\n } else {\n this.selectItem(tile);\n }\n }\n\n /**\n * updates slotted tiles to set properties and keyboard navigation\n */\n updateItems() {\n this.#tiles = [...this.querySelectorAll('rh-tile')];\n this.#tiles.forEach(tile => {\n tile.checkable = true;\n // @ts-expect-error: internal use of private prop. replace with context. see rh-tile.ts\n tile.radioGroup = this.radio;\n // @ts-expect-error: internal use of private prop. replace with context. see rh-tile.ts\n tile.disabledGroup !== this.disabled;\n tile.id = tile.id || getRandomId('rh-tile');\n });\n if (this.#initTiles) {\n this.#tabindex.updateItems(this.#tiles);\n } else {\n this.#initTiles = true;\n this.#tabindex.initItems(this.#tiles);\n }\n }\n\n #setTiles(tile: RhTile | null | undefined) {\n // @ts-expect-error: internal use of private prop. replace with context. see rh-tile.ts\n if (!this.disabled && (tile && tile.radioGroup || this.radio) && tile?.checked) {\n this.#tiles?.forEach(item => {\n if (tile !== item && item.checked) {\n item.checked = false;\n }\n });\n }\n }\n\n /**\n * handles TileSelectEvent\n * @param event {TileSelectEvent} tile click event\n */\n #onSelect(event: TileSelectEvent) {\n const tile = event.target as RhTile;\n this.#setTiles(tile);\n }\n\n /**\n * handles slot change by updating slotted tiles\n */\n #onSlotchange() {\n this.updateItems();\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'rh-tile-group': RhTileGroup;\n }\n}\n"]} \ No newline at end of file diff --git a/assets/packages/@rhds/elements/elements/rh-tile/rh-tile-group.ts b/assets/packages/@rhds/elements/elements/rh-tile/rh-tile-group.ts new file mode 100644 index 0000000000..1a09f57eef --- /dev/null +++ b/assets/packages/@rhds/elements/elements/rh-tile/rh-tile-group.ts @@ -0,0 +1,186 @@ +import { LitElement, html, type PropertyValueMap } from 'lit'; +import { classMap } from 'lit/directives/class-map.js'; +import { customElement } from 'lit/decorators/custom-element.js'; +import { property } from 'lit/decorators/property.js'; +import { colorContextConsumer, type ColorTheme } from '../../lib/context/color/consumer.js'; +import { colorContextProvider, type ColorPalette } from '../../lib/context/color/provider.js'; +import { getRandomId } from '@patternfly/pfe-core/functions/random.js'; +import { InternalsController } from '@patternfly/pfe-core/controllers/internals-controller.js'; +import { RovingTabindexController } from '@patternfly/pfe-core/controllers/roving-tabindex-controller.js'; +import { RhTile, TileSelectEvent } from './rh-tile.js'; + +import styles from './rh-tile-group.css'; + +/** + * A group of `` elements which handles radio selection. + * @slot - tiles + */ +@customElement('rh-tile-group') +export class RhTileGroup extends LitElement { + static readonly styles = [styles]; + + /** + * whether tile group interaction is disabled + */ + @property({ reflect: true, attribute: 'disabled', type: Boolean }) disabled = false; + + /** + * if tile is checkable, whether only one tile can be checked + */ + @property({ attribute: 'radio', type: Boolean }) radio = false; + + /** + * Sets color theme based on parent context + */ + @colorContextConsumer() private on?: ColorTheme; + + /** + * Sets color palette, which affects the element's styles as well as descendants' color theme. + * Overrides parent color context. + * Your theme will influence these colors so check there first if you are seeing inconsistencies. + * See [CSS Custom Properties](#css-custom-properties) for default values + * + * Tile group always resets its context to `base`, unless explicitly provided with a `color-palette`. + */ + @colorContextProvider() + @property({ reflect: true, attribute: 'color-palette' }) colorPalette?: ColorPalette; + + #tiles: RhTile[] = []; + #initTiles = false; + + #tabindex = new RovingTabindexController(this); + #internals = new InternalsController(this, { }); + + /** + * all slotted tiles + */ + get tiles() { + return this.#tiles; + } + + /** + * all selected tiles + */ + get selected() { + const selected = this.#tiles?.filter(tile=> tile.checked); + const [first] = selected; + return this.radio ? first : selected; + } + + protected firstUpdated(): void { + this.#internals.role = this.radio ? 'radiogroup' : null; + this.updateItems(); + } + + protected updated(_changedProperties: PropertyValueMap | Map): void { + if (_changedProperties.has('radio')) { + this.#internals.role = this.radio ? 'radiogroup' : null; + let selected: RhTile | null | undefined; + this.#tiles.forEach(tile => { + // @ts-expect-error: internal use of private prop. replace with context. see rh-tile.ts + tile.radioGroup = this.radio; + if (this.radio && !selected && tile.checked) { + selected = tile; + } + }); + this.selectItem(selected); + } + + if (_changedProperties.has('disabled')) { + this.#internals.ariaDisabled = this.disabled ? 'true' : 'false'; + this.#tiles.forEach(tile => { + // @ts-expect-error: internal use of private prop. replace with context. see rh-tile.ts + tile.disabledGroup = this.disabled; + }); + } + } + + render() { + const { on = '', radio } = this; + return html` + + `; + } + + /** sets focus on active tile */ + focus() { + (this.#tabindex?.activeItem || this.#tabindex.firstItem)?.focus(); + } + + /** + * programatically select a tile + * @param tile {RhTile | null | undefined} tile to select + */ + selectItem(tile: RhTile | null | undefined) { + if (tile) { + tile.checked = true; + this.#setTiles(tile); + } + } + + /** + * programatically toggle a tile + * @param tile {RhTile | null | undefined} tile to toggle + */ + toggleItem(tile: RhTile | null | undefined) { + if (tile?.checked) { + tile.checked = false; + } else { + this.selectItem(tile); + } + } + + /** + * updates slotted tiles to set properties and keyboard navigation + */ + updateItems() { + this.#tiles = [...this.querySelectorAll('rh-tile')]; + this.#tiles.forEach(tile => { + tile.checkable = true; + // @ts-expect-error: internal use of private prop. replace with context. see rh-tile.ts + tile.radioGroup = this.radio; + // @ts-expect-error: internal use of private prop. replace with context. see rh-tile.ts + tile.disabledGroup !== this.disabled; + tile.id = tile.id || getRandomId('rh-tile'); + }); + if (this.#initTiles) { + this.#tabindex.updateItems(this.#tiles); + } else { + this.#initTiles = true; + this.#tabindex.initItems(this.#tiles); + } + } + + #setTiles(tile: RhTile | null | undefined) { + // @ts-expect-error: internal use of private prop. replace with context. see rh-tile.ts + if (!this.disabled && (tile && tile.radioGroup || this.radio) && tile?.checked) { + this.#tiles?.forEach(item => { + if (tile !== item && item.checked) { + item.checked = false; + } + }); + } + } + + /** + * handles TileSelectEvent + * @param event {TileSelectEvent} tile click event + */ + #onSelect(event: TileSelectEvent) { + const tile = event.target as RhTile; + this.#setTiles(tile); + } + + /** + * handles slot change by updating slotted tiles + */ + #onSlotchange() { + this.updateItems(); + } +} + +declare global { + interface HTMLElementTagNameMap { + 'rh-tile-group': RhTileGroup; + } +} diff --git a/assets/packages/@rhds/elements/elements/rh-tile/rh-tile-lightdom.css b/assets/packages/@rhds/elements/elements/rh-tile/rh-tile-lightdom.css new file mode 100644 index 0000000000..539e11719f --- /dev/null +++ b/assets/packages/@rhds/elements/elements/rh-tile/rh-tile-lightdom.css @@ -0,0 +1,49 @@ +rh-tile a { + color: var(--rh-tile-link-color) !important; + text-decoration: var(--rh-tile-link-text-decoration, none) !important; +} + +rh-tile:focus-within a, +rh-tile a:is(:focus, :hover, :active) { + --rh-tile-link-text-decoration: underline; +} + +rh-tile a:not([slot="image"], [slot="headline"]) { + z-index: 2 !important; + position: relative !important; +} + +rh-tile[aria-disabled="true"] a { + color: var(--rh-tile-text-color-secondary, + var(--rh-color-text-secondary-on-light, #4d4d4d) + ) !important; +} + +rh-tile *:is([slot="image"], [slot="headline"]) a, +rh-tile a:is([slot="image"], [slot="headline"]) { + z-index: 1 !important; + position: static !important; + color: var(--rh-tile-link-color) !important; +} + +rh-tile *:is([slot="image"], [slot="headline"]) a:after, +rh-tile a:is([slot="image"], [slot="headline"]):after { + content: ""; + position: absolute; + inset: 0; + display: var(--rh-tile-link-after-display); +} + +rh-tile a[slot="image"] > :is(img, svg), +rh-tile [slot="image"]:is(img, svg) { + width: 100%; +} + +rh-tile:defined a:is(:focus, :hover, :active) { + outline: var(--rh-tile-link-outline) !important; +} + +rh-tile:defined :is([slot="image"], [slot="headline"]) a, +rh-tile:defined a:is([slot="image"], [slot="headline"]) { + --rh-tile-link-outline: none; +} diff --git a/assets/packages/@rhds/elements/elements/rh-tile/rh-tile.css b/assets/packages/@rhds/elements/elements/rh-tile/rh-tile.css new file mode 100644 index 0000000000..d11e9a078f --- /dev/null +++ b/assets/packages/@rhds/elements/elements/rh-tile/rh-tile.css @@ -0,0 +1,215 @@ +:host { + font-family: var(--rh-font-family-body-text, RedHatText, "Red Hat Text", "Noto Sans Arabic", "Noto Sans Hebrew", "Noto Sans JP", "Noto Sans KR", "Noto Sans Malayalam", "Noto Sans SC", "Noto Sans TC", "Noto Sans Thai", Helvetica, Arial, sans-serif); + font-size: var(--rh-font-size-body-text-md, 1rem); + font-weight: var(--rh-font-weight-heading-regular, 300); + line-height: var(--rh-line-height-body-text, 1.5); +} + +:host(:focus), +:host(:focus-within) { + outline: none !important; +} + +#outer { + position: relative; + padding: var(--_padding); + font-weight: var(--rh-font-weight-heading-medium, 500); + border-radius: var(--rh-border-radius-default, 3px); + border: var(--rh-border-width-sm, 1px) solid var(--rh-tile-border-color); + background-color: var(--rh-tile-background-color); + color: var(--rh-tile-text-color); + + --rh-tile-interactive-color: var(--rh-color-border-interactive-on-light, #0066cc); + --rh-tile-focus-interactive-color: var(--rh-color-interactive-blue-darkest, #004080); + --rh-tile-text-color: var(--rh-color-text-primary-on-light, #151515); + --rh-tile-text-color-secondary: var(--rh-color-text-secondary-on-light, #4d4d4d); + --rh-tile-background-color: var(--rh-color-surface-lightest, #ffffff); + --rh-tile-focus-background-color: var(--rh-color-surface-lighter, #f2f2f2); + --rh-tile-disabled-background-color: var(--rh-color-surface-light, #e0e0e0); + --rh-tile-border-color: var(--rh-color-border-subtle-on-light, #c7c7c7); + --rh-tile-link-color: var(--_interactive-color); + --_padding: var(--rh-space-2xl, 32px); + --_margin: var(--rh-space-lg, 16px); + --_interactive-color: var(--rh-tile-interactive-color); +} + +#outer.dark { + --rh-tile-interactive-color: var(--rh-color-border-interactive-on-dark, #73bcf7); + --rh-tile-focus-interactive-color: var(--rh-color-interactive-blue-lightest, #bee1f4); + --rh-tile-text-color: var(--rh-color-text-primary-on-dark, #ffffff); + --rh-tile-text-color-secondary: var(--rh-color-text-secondary-on-dark, #c7c7c7); + --rh-tile-background-color: var(--rh-color-surface-darkest, #151515); + --rh-tile-focus-background-color: var(--rh-color-surface-darker, #1f1f1f); + --rh-tile-disabled-background-color: var(--rh-color-surface-dark, #383838); + --rh-tile-border-color: var(--rh-color-border-subtle-on-dark, #707070); +} + +#outer:active, +#outer:hover, +#outer:focus, +#outer:focus-within { + --_interactive-color: var(--rh-tile-focus-interactive-color); +} + +#outer:is(.desaturated, .checkable) { + --rh-tile-link-color: var(--rh-tile-text-color); +} + +#outer.checkable { + --rh-tile-link-after-display: none; +} + +#outer:is(.compact, .checkable) { + --_padding: var(--rh-space-xl, 24px); +} + +:host(:focus-within) #outer { + outline: 3px solid var(--rh-tile-interactive-color); + outline-offset: 2px; +} + +:host(:is(:hover, :focus-within)) #outer { + background-color: var(--rh-tile-focus-background-color); +} + +#outer.disabled { + pointer-events: none !important; + color: var(--rh-tile-text-color-secondary) !important; + background-color: var(--rh-tile-disabled-background-color) !important; + + --_interactive-color: var(--rh-tile-text-color-secondary) !important; +} + +#outer:is(.compact, .checkable) #inner { + display: flex; + align-items: flex-start; + justify-content: space-between; +} + +#image { + --_bleed: calc(0px - var(--_padding)); +} + +#outer.bleed #image { + margin: var(--_bleed) var(--_bleed) 0; +} + +#outer:is(.compact, .checkable) #icon { + flex: 0 0 auto; +} + +#outer:is(.compact, .checkable) #content { + flex: 1 1 auto; +} + +#outer.checkable #header { + display: grid; + grid-template-columns: auto auto; + grid-template-rows: auto auto; +} + +#footer { + display: flex; + justify-content: space-between; + align-items: flex-end; +} + +#outer.checkable #title { + grid-column: 1 / 2; + grid-row: 1 / 2; +} + +#outer.checkable #headline { + grid-column: 1 / 2; + grid-row: 2 / 3; +} + +form { + grid-column: 2 / 3; + grid-row: 1 / 3; + align-self: flex-start; + justify-self: flex-end; + margin-bottom: var(--_margin); + margin-inline-start: var(--_margin); + accent-color: var(--_interactive-color); +} + +input[type="radio"] { + flex: 0 0 auto; +} + +pf-icon[icon="arrow-right"] { + color: var(--_interactive-color); + width: var(--rh-space-xl, 24px); + height: var(--rh-space-xl, 24px); +} + +svg { + fill: var(--rh-tile-text-color-secondary); + width: var(--rh-space-xl, 24px); + height: var(--rh-space-xl, 24px); +} + +#body { + margin: 0 0 var(--_margin); +} + +::slotted(*) { + margin-top: 0; + margin-bottom: var(--_margin); +} + +::slotted(:last-child), +#body ::slotted(:last-of-type) { + margin-bottom: 0; +} + +::slotted(:first-child), +#body ::slotted(:first-of-type) { + margin-top: 0; +} + +::slotted(a) { + color: var(--rh-tile-link-color) !important; +} + +::slotted([slot="image"]) { + display: block; + max-width: 100%; + margin-top: 0; + margin-bottom: var(--_padding); +} + +::slotted([slot="icon"]) { + width: 100%; + margin: 0 0 var(--_padding); + max-width: var(--rh-size-icon-05, 48px); +} + +::slotted([slot="title"]) { + text-transform: uppercase; +} + +#outer:is(.compact, .checkable) ::slotted([slot="icon"]) { + margin-inline-end: var(--_margin); + max-width: var(--rh-size-icon-03, 32px); + max-height: var(--rh-size-icon-03, 32px); +} + +#outer:is(.compact, .checkable) ::slotted([slot="headline"]), +#body { + font-size: var(--rh-font-size-body-text-lg, 1.125rem); +} + +#outer:is(.compact, .checkable) #body, +::slotted([slot="footer"]) { + font-size: var(--rh-font-size-body-text-sm, 0.875rem); +} + +#outer:is(.compact, .checkable) ::slotted([slot="footer"]) { + font-size: var(--rh-font-size-body-text-xs, 0.75rem); +} + +*:is(#image, #tile, #headline, #body, #footer) { + z-index: 2; +} \ No newline at end of file diff --git a/assets/packages/@rhds/elements/elements/rh-tile/rh-tile.d.ts b/assets/packages/@rhds/elements/elements/rh-tile/rh-tile.d.ts new file mode 100644 index 0000000000..53d68c3849 --- /dev/null +++ b/assets/packages/@rhds/elements/elements/rh-tile/rh-tile.d.ts @@ -0,0 +1,91 @@ +import { LitElement, type PropertyValueMap } from 'lit'; +import { type ColorPalette } from '../../lib/context/color/provider.js'; +import { ComposedEvent } from '@patternfly/pfe-core'; +import '@patternfly/elements/pf-icon/pf-icon.js'; +export declare class TileSelectEvent extends ComposedEvent { + target: RhTile; + constructor(); +} +/** + * A tile is a flexible layout with a clickable and contained surface. + * + * @summary Creates a clickable, contained surface + * + * @fires {TileSelectEvent} select - when tile is clicked + * @slot image - optional image on top of tile + * @slot icon - optional icon + * @slot title - optional title + * @slot headline - optional headline / link title + * @slot - optional body content + * @slot footer - optional footer + * @cssprop --rh-tile-text-color - color of text - {@default var(--rh-color-text-primary-on-light, #151515)} + * @cssprop --rh-tile-text-color-secondary - disabled text and icons - {@default var(--rh-color-text-secondary-on-light, #4d4d4d)} + * @cssprop --rh-tile-interactive-color - color of interactive elements - {@default var(--rh-color-border-interactive-on-light, #0066cc)} + * @cssprop --rh-tile-link-color - color of tile link - {@default var(--rh-tile-interactive-color)} + * @cssprop --rh-tile-link-text-decoration - tile link text decoration - {@default none} + * @cssprop --rh-tile-background-color - color tile surface - {@default var(--rh-color-surface-lightest, #ffffff)} + * @cssprop --rh-tile-focus-background-color - color tile surface on focus/hover - {@default var(--rh-color-surface-lighter, #f2f2f2)} + * @cssprop --rh-tile-disabled-background-color - color tile surface when disabled - {@default var(--rh-color-surface-light, #e0e0e0)} + * @cssprop --rh-tile-border-color - color of tile border - {@default var(--rh-color-border-subtle-on-light, #c7c7c7)} + */ +export declare class RhTile extends LitElement { + #private; + static readonly styles: import("lit").CSSResult[]; + private static readonly _disabledIcon; + /** + * whether tile interaction is disabled + */ + disabled: boolean; + private disabledGroup; + private radioGroup; + /** + * whether image is full-width (i.e. bleeds into the padding) + */ + bleed: boolean; + /** + * whether headline link text is a desaturated color instead of blue; + * `true` sets headline color to white on dark tiles or black on light tiles + */ + desaturated: boolean; + /** + * reduces tile padding for more compact spaces + */ + compact: boolean; + /** + * namespace of icon + */ + icon: boolean; + /** + * whether tile can be checked like a radio or checkbox: + * `false` (default) - tile behaves like a link; + * `true` - tile behaves like a checkbox unless it is part of an + * `rh-tile-group` with a `radio` type and more than one tile + */ + checkable: boolean; + /** + * if tile is checkable, whether it is currently checked + */ + checked: boolean; + /** + * Sets color theme based on parent context + */ + private on?; + /** + * Sets color palette, which affects the element's styles as well as descendants' color theme. + * Overrides parent color context. + * Your theme will influence these colors so check there first if you are seeing inconsistencies. + * See [CSS Custom Properties](#css-custom-properties) for default values + * + * Tile always resets its context to `base`, unless explicitly provided with a `color-palette`. + */ + colorPalette?: ColorPalette; + connectedCallback(): void; + protected updated(_changedProperties: PropertyValueMap | Map): Promise; + render(): import("lit-html").TemplateResult<1>; + disconnectedCallback(): void; +} +declare global { + interface HTMLElementTagNameMap { + 'rh-tile': RhTile; + } +} diff --git a/assets/packages/@rhds/elements/elements/rh-tile/rh-tile.js b/assets/packages/@rhds/elements/elements/rh-tile/rh-tile.js new file mode 100644 index 0000000000..53bd405022 --- /dev/null +++ b/assets/packages/@rhds/elements/elements/rh-tile/rh-tile.js @@ -0,0 +1,238 @@ +var _RhTile_instances, _RhTile_internals, _RhTile_onClick, _RhTile_onKeydown, _RhTile_onKeyup; +var RhTile_1; +import { __classPrivateFieldGet, __decorate } from "tslib"; +import { LitElement, html } from 'lit'; +import { classMap } from 'lit/directives/class-map.js'; +import { customElement } from 'lit/decorators/custom-element.js'; +import { property } from 'lit/decorators/property.js'; +import { colorContextConsumer } from '../../lib/context/color/consumer.js'; +import { colorContextProvider } from '../../lib/context/color/provider.js'; +import { InternalsController } from '@patternfly/pfe-core/controllers/internals-controller.js'; +import { ComposedEvent } from '@patternfly/pfe-core'; +import '@patternfly/elements/pf-icon/pf-icon.js'; +import { css } from "lit"; +const styles = css `:host{font-family:var(--rh-font-family-body-text, RedHatText, "Red Hat Text", "Noto Sans Arabic", "Noto Sans Hebrew", "Noto Sans JP", "Noto Sans KR", "Noto Sans Malayalam", "Noto Sans SC", "Noto Sans TC", "Noto Sans Thai", Helvetica, Arial, sans-serif);font-size:var(--rh-font-size-body-text-md, 1rem);font-weight:var(--rh-font-weight-heading-regular,300);line-height:var(--rh-line-height-body-text, 1.5)}:host(:focus),:host(:focus-within){outline:0!important}#outer{position:relative;padding:var(--_padding);font-weight:var(--rh-font-weight-heading-medium,500);border-radius:var(--rh-border-radius-default,3px);border:var(--rh-border-width-sm,1px) solid var(--rh-tile-border-color);background-color:var(--rh-tile-background-color);color:var(--rh-tile-text-color);--rh-tile-interactive-color:var(--rh-color-border-interactive-on-light, #0066cc);--rh-tile-focus-interactive-color:var(--rh-color-interactive-blue-darkest, #004080);--rh-tile-text-color:var(--rh-color-text-primary-on-light, #151515);--rh-tile-text-color-secondary:var(--rh-color-text-secondary-on-light, #4d4d4d);--rh-tile-background-color:var(--rh-color-surface-lightest, #ffffff);--rh-tile-focus-background-color:var(--rh-color-surface-lighter, #f2f2f2);--rh-tile-disabled-background-color:var(--rh-color-surface-light, #e0e0e0);--rh-tile-border-color:var(--rh-color-border-subtle-on-light, #c7c7c7);--rh-tile-link-color:var(--_interactive-color);--_padding:var(--rh-space-2xl, 32px);--_margin:var(--rh-space-lg, 16px);--_interactive-color:var(--rh-tile-interactive-color)}#outer.dark{--rh-tile-interactive-color:var(--rh-color-border-interactive-on-dark, #73bcf7);--rh-tile-focus-interactive-color:var(--rh-color-interactive-blue-lightest, #bee1f4);--rh-tile-text-color:var(--rh-color-text-primary-on-dark, #ffffff);--rh-tile-text-color-secondary:var(--rh-color-text-secondary-on-dark, #c7c7c7);--rh-tile-background-color:var(--rh-color-surface-darkest, #151515);--rh-tile-focus-background-color:var(--rh-color-surface-darker, #1f1f1f);--rh-tile-disabled-background-color:var(--rh-color-surface-dark, #383838);--rh-tile-border-color:var(--rh-color-border-subtle-on-dark, #707070)}#outer:active,#outer:focus,#outer:focus-within,#outer:hover{--_interactive-color:var(--rh-tile-focus-interactive-color)}#outer:is(.desaturated,.checkable){--rh-tile-link-color:var(--rh-tile-text-color)}#outer.checkable{--rh-tile-link-after-display:none}#outer:is(.compact,.checkable){--_padding:var(--rh-space-xl, 24px)}:host(:focus-within) #outer{outline:3px solid var(--rh-tile-interactive-color);outline-offset:2px}:host(:is(:hover,:focus-within)) #outer{background-color:var(--rh-tile-focus-background-color)}#outer.disabled{pointer-events:none!important;color:var(--rh-tile-text-color-secondary)!important;background-color:var(--rh-tile-disabled-background-color)!important;--_interactive-color:var(--rh-tile-text-color-secondary)!important}#outer:is(.compact,.checkable) #inner{display:flex;align-items:flex-start;justify-content:space-between}#image{--_bleed:calc(0px - var(--_padding))}#outer.bleed #image{margin:var(--_bleed) var(--_bleed) 0}#outer:is(.compact,.checkable) #icon{flex:0 0 auto}#outer:is(.compact,.checkable) #content{flex:1 1 auto}#outer.checkable #header{display:grid;grid-template-columns:auto auto;grid-template-rows:auto auto}#footer{display:flex;justify-content:space-between;align-items:flex-end}#outer.checkable #title{grid-column:1/2;grid-row:1/2}#outer.checkable #headline{grid-column:1/2;grid-row:2/3}form{grid-column:2/3;grid-row:1/3;align-self:flex-start;justify-self:flex-end;margin-bottom:var(--_margin);margin-inline-start:var(--_margin);accent-color:var(--_interactive-color)}input[type=radio]{flex:0 0 auto}pf-icon[icon=arrow-right]{color:var(--_interactive-color);width:var(--rh-space-xl,24px);height:var(--rh-space-xl,24px)}svg{fill:var(--rh-tile-text-color-secondary);width:var(--rh-space-xl,24px);height:var(--rh-space-xl,24px)}#body{margin:0 0 var(--_margin)}::slotted(*){margin-top:0;margin-bottom:var(--_margin)}#body ::slotted(:last-of-type),::slotted(:last-child){margin-bottom:0}#body ::slotted(:first-of-type),::slotted(:first-child){margin-top:0}::slotted(a){color:var(--rh-tile-link-color)!important}::slotted([slot=image]){display:block;max-width:100%;margin-top:0;margin-bottom:var(--_padding)}::slotted([slot=icon]){width:100%;margin:0 0 var(--_padding);max-width:var(--rh-size-icon-05,48px)}::slotted([slot=title]){text-transform:uppercase}#outer:is(.compact,.checkable) ::slotted([slot=icon]){margin-inline-end:var(--_margin);max-width:var(--rh-size-icon-03,32px);max-height:var(--rh-size-icon-03,32px)}#body,#outer:is(.compact,.checkable) ::slotted([slot=headline]){font-size:var(--rh-font-size-body-text-lg, 1.125rem)}#outer:is(.compact,.checkable) #body,::slotted([slot=footer]){font-size:var(--rh-font-size-body-text-sm, .875rem)}#outer:is(.compact,.checkable) ::slotted([slot=footer]){font-size:var(--rh-font-size-body-text-xs, .75rem)}:is(#image,#tile,#headline,#body,#footer){z-index:2}`; +import { state } from 'lit/decorators/state.js'; +export class TileSelectEvent extends ComposedEvent { + constructor() { + super('select'); + } +} +/** + * A tile is a flexible layout with a clickable and contained surface. + * + * @summary Creates a clickable, contained surface + * + * @fires {TileSelectEvent} select - when tile is clicked + * @slot image - optional image on top of tile + * @slot icon - optional icon + * @slot title - optional title + * @slot headline - optional headline / link title + * @slot - optional body content + * @slot footer - optional footer + * @cssprop --rh-tile-text-color - color of text - {@default var(--rh-color-text-primary-on-light, #151515)} + * @cssprop --rh-tile-text-color-secondary - disabled text and icons - {@default var(--rh-color-text-secondary-on-light, #4d4d4d)} + * @cssprop --rh-tile-interactive-color - color of interactive elements - {@default var(--rh-color-border-interactive-on-light, #0066cc)} + * @cssprop --rh-tile-link-color - color of tile link - {@default var(--rh-tile-interactive-color)} + * @cssprop --rh-tile-link-text-decoration - tile link text decoration - {@default none} + * @cssprop --rh-tile-background-color - color tile surface - {@default var(--rh-color-surface-lightest, #ffffff)} + * @cssprop --rh-tile-focus-background-color - color tile surface on focus/hover - {@default var(--rh-color-surface-lighter, #f2f2f2)} + * @cssprop --rh-tile-disabled-background-color - color tile surface when disabled - {@default var(--rh-color-surface-light, #e0e0e0)} + * @cssprop --rh-tile-border-color - color of tile border - {@default var(--rh-color-border-subtle-on-light, #c7c7c7)} + */ +let RhTile = RhTile_1 = class RhTile extends LitElement { + constructor() { + super(...arguments); + _RhTile_instances.add(this); + /** + * whether tile interaction is disabled + */ + this.disabled = false; + // TODO(bennyp): https://lit.dev/docs/data/context/#content + this.disabledGroup = false; + // TODO(bennyp): https://lit.dev/docs/data/context/#content + this.radioGroup = false; + /** + * whether image is full-width (i.e. bleeds into the padding) + */ + this.bleed = false; + /** + * whether headline link text is a desaturated color instead of blue; + * `true` sets headline color to white on dark tiles or black on light tiles + */ + this.desaturated = false; + /** + * reduces tile padding for more compact spaces + */ + this.compact = false; + /** + * namespace of icon + */ + this.icon = false; + /** + * whether tile can be checked like a radio or checkbox: + * `false` (default) - tile behaves like a link; + * `true` - tile behaves like a checkbox unless it is part of an + * `rh-tile-group` with a `radio` type and more than one tile + */ + this.checkable = false; + /** + * if tile is checkable, whether it is currently checked + */ + this.checked = false; + _RhTile_internals.set(this, new InternalsController(this, {})); + } + connectedCallback() { + super.connectedCallback(); + __classPrivateFieldGet(this, _RhTile_internals, "f").ariaChecked = this.checkable && this.checked ? 'true' : 'false'; + __classPrivateFieldGet(this, _RhTile_internals, "f").role = this.checkable && this.radioGroup ? 'radio' : this.checkable ? 'checkbox' : null; + if (this.checkable && !this.radioGroup) { + this.setAttribute('tabindex', '0'); + } + else if (!this.radioGroup) { + this.removeAttribute('tabindex'); + } + this.addEventListener('keydown', __classPrivateFieldGet(this, _RhTile_instances, "m", _RhTile_onKeydown)); + this.addEventListener('keyup', __classPrivateFieldGet(this, _RhTile_instances, "m", _RhTile_onKeyup)); + this.addEventListener('click', __classPrivateFieldGet(this, _RhTile_instances, "m", _RhTile_onClick)); + } + async updated(_changedProperties) { + if (_changedProperties.has('checked') || _changedProperties.has('checkable')) { + __classPrivateFieldGet(this, _RhTile_internals, "f").ariaChecked = this.checkable && this.checked ? 'true' : 'false'; + await this.updateComplete; + if (!this.checked) { + this.shadowRoot?.querySelector('form')?.reset(); + } + this.dispatchEvent(new TileSelectEvent()); + return; + } + if (_changedProperties.has('radio') || _changedProperties.has('checkable')) { + __classPrivateFieldGet(this, _RhTile_internals, "f").role = this.checkable && this.radioGroup ? 'radio' : this.checkable ? 'checkbox' : null; + if (this.checkable && !this.radioGroup) { + this.setAttribute('tabindex', '0'); + } + else if (!this.radioGroup) { + this.removeAttribute('tabindex'); + } + } + if (_changedProperties.has('disabled')) { + __classPrivateFieldGet(this, _RhTile_internals, "f").ariaDisabled = this.disabled ? 'true' : 'false'; + } + } + render() { + const { bleed, compact, checkable, checked, desaturated, on = '' } = this; + const disabled = this.disabledGroup || this.disabled; + return html ` +
+ ${this.checkable ? '' : html `
`} +
+ ${!this.checkable ? + html ` +
+ + ${!this.icon ? '' : html ``} + +
` : ''} +
+ +
+ +
+
+
+ `; + } + disconnectedCallback() { + this.removeEventListener('keydown', __classPrivateFieldGet(this, _RhTile_instances, "m", _RhTile_onKeydown)); + this.removeEventListener('keyup', __classPrivateFieldGet(this, _RhTile_instances, "m", _RhTile_onKeyup)); + this.removeEventListener('click', __classPrivateFieldGet(this, _RhTile_instances, "m", _RhTile_onClick)); + super.disconnectedCallback(); + } +}; +_RhTile_internals = new WeakMap(), _RhTile_instances = new WeakSet(), _RhTile_onClick = function _RhTile_onClick(event) { + const { target } = event; + if (target === this && this.checkable) { + this.checked = !this.checked; + } +}, _RhTile_onKeydown = function _RhTile_onKeydown(event) { + const { target, key } = event; + if (key === ' ' && target === this && this.checkable) { + event.preventDefault(); + event.stopImmediatePropagation(); + } +}, _RhTile_onKeyup = function _RhTile_onKeyup(event) { + const { target, key } = event; + if (['Enter', ' '].includes(key) && target === this && this.checkable && !this.disabled && !this.disabledGroup) { + this.checked = !this.checked; + } +}; +RhTile.styles = [styles]; +RhTile._disabledIcon = html ``; +__decorate([ + property({ reflect: true, attribute: 'disabled', type: Boolean }) +], RhTile.prototype, "disabled", void 0); +__decorate([ + state() +], RhTile.prototype, "disabledGroup", void 0); +__decorate([ + state() +], RhTile.prototype, "radioGroup", void 0); +__decorate([ + property({ attribute: 'bleed', type: Boolean }) +], RhTile.prototype, "bleed", void 0); +__decorate([ + property({ attribute: 'desaturated', type: Boolean }) +], RhTile.prototype, "desaturated", void 0); +__decorate([ + property({ attribute: 'compact', type: Boolean }) +], RhTile.prototype, "compact", void 0); +__decorate([ + property({ attribute: 'icon', type: String }) +], RhTile.prototype, "icon", void 0); +__decorate([ + property({ type: Boolean }) +], RhTile.prototype, "checkable", void 0); +__decorate([ + property({ attribute: 'checked', type: Boolean }) +], RhTile.prototype, "checked", void 0); +__decorate([ + colorContextConsumer() +], RhTile.prototype, "on", void 0); +__decorate([ + colorContextProvider(), + property({ reflect: true, attribute: 'color-palette' }) +], RhTile.prototype, "colorPalette", void 0); +RhTile = RhTile_1 = __decorate([ + customElement('rh-tile') +], RhTile); +export { RhTile }; +//# sourceMappingURL=rh-tile.js.map \ No newline at end of file diff --git a/assets/packages/@rhds/elements/elements/rh-tile/rh-tile.js.map b/assets/packages/@rhds/elements/elements/rh-tile/rh-tile.js.map new file mode 100644 index 0000000000..3c52b0d097 --- /dev/null +++ b/assets/packages/@rhds/elements/elements/rh-tile/rh-tile.js.map @@ -0,0 +1 @@ +{"version":3,"file":"rh-tile.js","sourceRoot":"","sources":["rh-tile.ts"],"names":[],"mappings":"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","sourcesContent":["import { LitElement, html, type PropertyValueMap } from 'lit';\nimport { classMap } from 'lit/directives/class-map.js';\nimport { customElement } from 'lit/decorators/custom-element.js';\nimport { property } from 'lit/decorators/property.js';\nimport { colorContextConsumer, type ColorTheme } from '../../lib/context/color/consumer.js';\nimport { colorContextProvider, type ColorPalette } from '../../lib/context/color/provider.js';\nimport { InternalsController } from '@patternfly/pfe-core/controllers/internals-controller.js';\nimport { ComposedEvent } from '@patternfly/pfe-core';\n\nimport '@patternfly/elements/pf-icon/pf-icon.js';\n\nimport styles from './rh-tile.css';\nimport { state } from 'lit/decorators/state.js';\n\nexport class TileSelectEvent extends ComposedEvent {\n declare target: RhTile;\n constructor() {\n super('select');\n }\n}\n\n/**\n * A tile is a flexible layout with a clickable and contained surface.\n *\n * @summary Creates a clickable, contained surface\n *\n * @fires {TileSelectEvent} select - when tile is clicked\n * @slot image - optional image on top of tile\n * @slot icon - optional icon\n * @slot title - optional title\n * @slot headline - optional headline / link title\n * @slot - optional body content\n * @slot footer - optional footer\n * @cssprop --rh-tile-text-color - color of text - {@default var(--rh-color-text-primary-on-light, #151515)}\n * @cssprop --rh-tile-text-color-secondary - disabled text and icons - {@default var(--rh-color-text-secondary-on-light, #4d4d4d)}\n * @cssprop --rh-tile-interactive-color - color of interactive elements - {@default var(--rh-color-border-interactive-on-light, #0066cc)}\n * @cssprop --rh-tile-link-color - color of tile link - {@default var(--rh-tile-interactive-color)}\n * @cssprop --rh-tile-link-text-decoration - tile link text decoration - {@default none}\n * @cssprop --rh-tile-background-color - color tile surface - {@default var(--rh-color-surface-lightest, #ffffff)}\n * @cssprop --rh-tile-focus-background-color - color tile surface on focus/hover - {@default var(--rh-color-surface-lighter, #f2f2f2)}\n * @cssprop --rh-tile-disabled-background-color - color tile surface when disabled - {@default var(--rh-color-surface-light, #e0e0e0)}\n * @cssprop --rh-tile-border-color - color of tile border - {@default var(--rh-color-border-subtle-on-light, #c7c7c7)}\n */\n@customElement('rh-tile')\nexport class RhTile extends LitElement {\n static readonly styles = [styles];\n\n private static readonly _disabledIcon = html``;\n\n /**\n * whether tile interaction is disabled\n */\n @property({ reflect: true, attribute: 'disabled', type: Boolean }) disabled = false;\n\n // TODO(bennyp): https://lit.dev/docs/data/context/#content\n @state() private disabledGroup = false;\n\n // TODO(bennyp): https://lit.dev/docs/data/context/#content\n @state() private radioGroup = false;\n\n /**\n * whether image is full-width (i.e. bleeds into the padding)\n */\n @property({ attribute: 'bleed', type: Boolean }) bleed = false;\n\n /**\n * whether headline link text is a desaturated color instead of blue;\n * `true` sets headline color to white on dark tiles or black on light tiles\n */\n @property({ attribute: 'desaturated', type: Boolean }) desaturated = false;\n\n /**\n * reduces tile padding for more compact spaces\n */\n @property({ attribute: 'compact', type: Boolean }) compact = false;\n\n /**\n * namespace of icon\n */\n @property({ attribute: 'icon', type: String }) icon = false;\n\n /**\n * whether tile can be checked like a radio or checkbox:\n * `false` (default) - tile behaves like a link;\n * `true` - tile behaves like a checkbox unless it is part of an\n * `rh-tile-group` with a `radio` type and more than one tile\n */\n @property({ type: Boolean }) checkable = false;\n\n /**\n * if tile is checkable, whether it is currently checked\n */\n @property({ attribute: 'checked', type: Boolean }) checked = false;\n\n /**\n * Sets color theme based on parent context\n */\n @colorContextConsumer() private on?: ColorTheme;\n\n /**\n * Sets color palette, which affects the element's styles as well as descendants' color theme.\n * Overrides parent color context.\n * Your theme will influence these colors so check there first if you are seeing inconsistencies.\n * See [CSS Custom Properties](#css-custom-properties) for default values\n *\n * Tile always resets its context to `base`, unless explicitly provided with a `color-palette`.\n */\n @colorContextProvider()\n @property({ reflect: true, attribute: 'color-palette' }) colorPalette?: ColorPalette;\n\n #internals = new InternalsController(this, { });\n\n connectedCallback(): void {\n super.connectedCallback();\n this.#internals.ariaChecked = this.checkable && this.checked ? 'true' : 'false';\n this.#internals.role = this.checkable && this.radioGroup ? 'radio' : this.checkable ? 'checkbox' : null;\n if (this.checkable && !this.radioGroup) {\n this.setAttribute('tabindex', '0');\n } else if (!this.radioGroup) {\n this.removeAttribute('tabindex');\n }\n this.addEventListener('keydown', this.#onKeydown);\n this.addEventListener('keyup', this.#onKeyup);\n this.addEventListener('click', this.#onClick);\n }\n\n protected async updated(_changedProperties: PropertyValueMap | Map) {\n if (_changedProperties.has('checked') || _changedProperties.has('checkable')) {\n this.#internals.ariaChecked = this.checkable && this.checked ? 'true' : 'false';\n await this.updateComplete;\n if (!this.checked) {\n this.shadowRoot?.querySelector('form')?.reset();\n }\n this.dispatchEvent(new TileSelectEvent());\n return;\n }\n\n if (_changedProperties.has('radio') || _changedProperties.has('checkable')) {\n this.#internals.role = this.checkable && this.radioGroup ? 'radio' : this.checkable ? 'checkbox' : null;\n if (this.checkable && !this.radioGroup) {\n this.setAttribute('tabindex', '0');\n } else if (!this.radioGroup) {\n this.removeAttribute('tabindex');\n }\n }\n\n if (_changedProperties.has('disabled')) {\n this.#internals.ariaDisabled = this.disabled ? 'true' : 'false';\n }\n }\n\n render() {\n const { bleed, compact, checkable, checked, desaturated, on = '' } = this;\n const disabled = this.disabledGroup || this.disabled;\n return html`\n
\n ${this.checkable ? '' : html`
`}\n
\n ${!this.checkable ?\n html`\n
\n \n ${!this.icon ? '' : html``}\n \n
` : ''}\n
\n
\n ${(!this.checkable && !this.compact) ?\n html`\n
\n \n
` : ''}\n
\n ${!this.checkable ? '' : html`\n
\n \n
\n `}\n
\n
\n
\n
\n ${!this.checkable && !this.disabled ?\n html`` : !this.checkable ?\n RhTile._disabledIcon : ''}\n
\n
\n
\n
\n `;\n }\n\n disconnectedCallback(): void {\n this.removeEventListener('keydown', this.#onKeydown);\n this.removeEventListener('keyup', this.#onKeyup);\n this.removeEventListener('click', this.#onClick);\n super.disconnectedCallback();\n }\n\n /**\n * handles tile click\n */\n #onClick(event: Event) {\n const { target } = event;\n if (target === this && this.checkable) {\n this.checked = !this.checked;\n }\n }\n\n /**\n * handles keydown and prevents scrolling when spacebar is clicked\n * @param event {KeyboardEvent}\n */\n #onKeydown(event: KeyboardEvent) {\n const { target, key } = event;\n if (key === ' ' && target === this && this.checkable) {\n event.preventDefault();\n event.stopImmediatePropagation();\n }\n }\n\n /**\n * handles key up and toggles input\n * @param event {KeyboardEvent}\n */\n #onKeyup(event: KeyboardEvent) {\n const { target, key } = event;\n if (['Enter', ' '].includes(key) && target === this && this.checkable && !this.disabled && !this.disabledGroup) {\n this.checked = !this.checked;\n }\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'rh-tile': RhTile;\n }\n}\n"]} \ No newline at end of file diff --git a/assets/packages/@rhds/elements/elements/rh-tile/rh-tile.ts b/assets/packages/@rhds/elements/elements/rh-tile/rh-tile.ts new file mode 100644 index 0000000000..2d1a2e286d --- /dev/null +++ b/assets/packages/@rhds/elements/elements/rh-tile/rh-tile.ts @@ -0,0 +1,250 @@ +import { LitElement, html, type PropertyValueMap } from 'lit'; +import { classMap } from 'lit/directives/class-map.js'; +import { customElement } from 'lit/decorators/custom-element.js'; +import { property } from 'lit/decorators/property.js'; +import { colorContextConsumer, type ColorTheme } from '../../lib/context/color/consumer.js'; +import { colorContextProvider, type ColorPalette } from '../../lib/context/color/provider.js'; +import { InternalsController } from '@patternfly/pfe-core/controllers/internals-controller.js'; +import { ComposedEvent } from '@patternfly/pfe-core'; + +import '@patternfly/elements/pf-icon/pf-icon.js'; + +import styles from './rh-tile.css'; +import { state } from 'lit/decorators/state.js'; + +export class TileSelectEvent extends ComposedEvent { + declare target: RhTile; + constructor() { + super('select'); + } +} + +/** + * A tile is a flexible layout with a clickable and contained surface. + * + * @summary Creates a clickable, contained surface + * + * @fires {TileSelectEvent} select - when tile is clicked + * @slot image - optional image on top of tile + * @slot icon - optional icon + * @slot title - optional title + * @slot headline - optional headline / link title + * @slot - optional body content + * @slot footer - optional footer + * @cssprop --rh-tile-text-color - color of text - {@default var(--rh-color-text-primary-on-light, #151515)} + * @cssprop --rh-tile-text-color-secondary - disabled text and icons - {@default var(--rh-color-text-secondary-on-light, #4d4d4d)} + * @cssprop --rh-tile-interactive-color - color of interactive elements - {@default var(--rh-color-border-interactive-on-light, #0066cc)} + * @cssprop --rh-tile-link-color - color of tile link - {@default var(--rh-tile-interactive-color)} + * @cssprop --rh-tile-link-text-decoration - tile link text decoration - {@default none} + * @cssprop --rh-tile-background-color - color tile surface - {@default var(--rh-color-surface-lightest, #ffffff)} + * @cssprop --rh-tile-focus-background-color - color tile surface on focus/hover - {@default var(--rh-color-surface-lighter, #f2f2f2)} + * @cssprop --rh-tile-disabled-background-color - color tile surface when disabled - {@default var(--rh-color-surface-light, #e0e0e0)} + * @cssprop --rh-tile-border-color - color of tile border - {@default var(--rh-color-border-subtle-on-light, #c7c7c7)} + */ +@customElement('rh-tile') +export class RhTile extends LitElement { + static readonly styles = [styles]; + + private static readonly _disabledIcon = html``; + + /** + * whether tile interaction is disabled + */ + @property({ reflect: true, attribute: 'disabled', type: Boolean }) disabled = false; + + // TODO(bennyp): https://lit.dev/docs/data/context/#content + @state() private disabledGroup = false; + + // TODO(bennyp): https://lit.dev/docs/data/context/#content + @state() private radioGroup = false; + + /** + * whether image is full-width (i.e. bleeds into the padding) + */ + @property({ attribute: 'bleed', type: Boolean }) bleed = false; + + /** + * whether headline link text is a desaturated color instead of blue; + * `true` sets headline color to white on dark tiles or black on light tiles + */ + @property({ attribute: 'desaturated', type: Boolean }) desaturated = false; + + /** + * reduces tile padding for more compact spaces + */ + @property({ attribute: 'compact', type: Boolean }) compact = false; + + /** + * namespace of icon + */ + @property({ attribute: 'icon', type: String }) icon = false; + + /** + * whether tile can be checked like a radio or checkbox: + * `false` (default) - tile behaves like a link; + * `true` - tile behaves like a checkbox unless it is part of an + * `rh-tile-group` with a `radio` type and more than one tile + */ + @property({ type: Boolean }) checkable = false; + + /** + * if tile is checkable, whether it is currently checked + */ + @property({ attribute: 'checked', type: Boolean }) checked = false; + + /** + * Sets color theme based on parent context + */ + @colorContextConsumer() private on?: ColorTheme; + + /** + * Sets color palette, which affects the element's styles as well as descendants' color theme. + * Overrides parent color context. + * Your theme will influence these colors so check there first if you are seeing inconsistencies. + * See [CSS Custom Properties](#css-custom-properties) for default values + * + * Tile always resets its context to `base`, unless explicitly provided with a `color-palette`. + */ + @colorContextProvider() + @property({ reflect: true, attribute: 'color-palette' }) colorPalette?: ColorPalette; + + #internals = new InternalsController(this, { }); + + connectedCallback(): void { + super.connectedCallback(); + this.#internals.ariaChecked = this.checkable && this.checked ? 'true' : 'false'; + this.#internals.role = this.checkable && this.radioGroup ? 'radio' : this.checkable ? 'checkbox' : null; + if (this.checkable && !this.radioGroup) { + this.setAttribute('tabindex', '0'); + } else if (!this.radioGroup) { + this.removeAttribute('tabindex'); + } + this.addEventListener('keydown', this.#onKeydown); + this.addEventListener('keyup', this.#onKeyup); + this.addEventListener('click', this.#onClick); + } + + protected async updated(_changedProperties: PropertyValueMap | Map) { + if (_changedProperties.has('checked') || _changedProperties.has('checkable')) { + this.#internals.ariaChecked = this.checkable && this.checked ? 'true' : 'false'; + await this.updateComplete; + if (!this.checked) { + this.shadowRoot?.querySelector('form')?.reset(); + } + this.dispatchEvent(new TileSelectEvent()); + return; + } + + if (_changedProperties.has('radio') || _changedProperties.has('checkable')) { + this.#internals.role = this.checkable && this.radioGroup ? 'radio' : this.checkable ? 'checkbox' : null; + if (this.checkable && !this.radioGroup) { + this.setAttribute('tabindex', '0'); + } else if (!this.radioGroup) { + this.removeAttribute('tabindex'); + } + } + + if (_changedProperties.has('disabled')) { + this.#internals.ariaDisabled = this.disabled ? 'true' : 'false'; + } + } + + render() { + const { bleed, compact, checkable, checked, desaturated, on = '' } = this; + const disabled = this.disabledGroup || this.disabled; + return html` +
+ ${this.checkable ? '' : html`
`} +
+ ${!this.checkable ? + html` +
+ + ${!this.icon ? '' : html``} + +
` : ''} +
+ +
+ +
+
+
+ `; + } + + disconnectedCallback(): void { + this.removeEventListener('keydown', this.#onKeydown); + this.removeEventListener('keyup', this.#onKeyup); + this.removeEventListener('click', this.#onClick); + super.disconnectedCallback(); + } + + /** + * handles tile click + */ + #onClick(event: Event) { + const { target } = event; + if (target === this && this.checkable) { + this.checked = !this.checked; + } + } + + /** + * handles keydown and prevents scrolling when spacebar is clicked + * @param event {KeyboardEvent} + */ + #onKeydown(event: KeyboardEvent) { + const { target, key } = event; + if (key === ' ' && target === this && this.checkable) { + event.preventDefault(); + event.stopImmediatePropagation(); + } + } + + /** + * handles key up and toggles input + * @param event {KeyboardEvent} + */ + #onKeyup(event: KeyboardEvent) { + const { target, key } = event; + if (['Enter', ' '].includes(key) && target === this && this.checkable && !this.disabled && !this.disabledGroup) { + this.checked = !this.checked; + } + } +} + +declare global { + interface HTMLElementTagNameMap { + 'rh-tile': RhTile; + } +} diff --git a/assets/packages/@rhds/elements/elements/rh-tile/test/rh-tile-group.spec.ts b/assets/packages/@rhds/elements/elements/rh-tile/test/rh-tile-group.spec.ts new file mode 100644 index 0000000000..915806260c --- /dev/null +++ b/assets/packages/@rhds/elements/elements/rh-tile/test/rh-tile-group.spec.ts @@ -0,0 +1,160 @@ +import { expect, html } from '@open-wc/testing'; +import { createFixture } from '@patternfly/pfe-tools/test/create-fixture.js'; +import { sendKeys, sendMouse } from '@web/test-runner-commands'; +import { RhTileGroup } from '@rhds/elements/rh-tile/rh-tile-group.js'; + +describe('', function() { + let element: RhTileGroup; + let tile1: HTMLElement; + let tile2: HTMLElement; + let tile3: HTMLElement; + const tileGroup = html` + + +
Title
+

Link

+ Lorem ipsum dolor sit amet, consectetur adipiscing elit. +
Suspendisse eu turpis elementum
+
+ + +
Title
+

Link

+ Lorem ipsum dolor sit amet, consectetur adipiscing elit. +
Suspendisse eu turpis elementum
+
+ + +
Title
+

Link

+ Lorem ipsum dolor sit amet, consectetur adipiscing elit. +
Suspendisse eu turpis elementum
+
+
`; + + async function arrowDown() { + await sendKeys({ down: 'ArrowDown' }); + await element.updateComplete; + } + + async function enter() { + await sendKeys({ press: 'Enter' }); + await element.updateComplete; + } + + async function arrowUp() { + await sendKeys({ down: 'ArrowUp' }); + await element.updateComplete; + } + + function tiles(element) { + return [...element.querySelectorAll('rh-tile')]; + } + + function input(element, checked = false) { + return element?.shadowRoot?.querySelector(`input[type="radio"]${checked ? ':checked' : ''}`); + } + + function inputs(element, checked = false) { + return tiles(element).map(tile => input(tile, checked)).filter(input=>input); + } + + describe('simply instantiating', function() { + it('imperatively instantiates', function() { + expect(document.createElement('rh-tile-group')).to.be.an.instanceof(RhTileGroup); + }); + + it('should upgrade', async function() { + element = await createFixture(html``); + const klass = customElements.get('rh-tile-group'); + expect(element) + .to.be.an.instanceOf(klass) + .and + .to.be.an.instanceOf(RhTileGroup); + }); + }); + + describe('radio tile', function() { + beforeEach(async function() { + element = await createFixture(tileGroup); + }); + + it('is accessible', function() { + expect(element) + .to.be.an.accessible; + }); + + it('has radio buttons', function() { + expect(tiles(element).length) + .to.equal(inputs(element).length); + }); + }); + + describe('as a radio group', async function() { + beforeEach(async function() { + element = await createFixture(tileGroup); + [tile1, tile2, tile3] = tiles(element); + await element.focus(); + }); + + it('sets focus', function() { + expect(document.activeElement) + .to.equal(tile1); + }); + + describe('arrow down', async function() { + beforeEach(async function() { + await arrowDown(); + }); + it('sets focus on second tile', function() { + expect(document.activeElement) + .to.equal(tile2); + }); + }); + + describe('arrow up', async function() { + beforeEach(async function() { + await arrowUp(); + }); + it('sets focus on last tile', function() { + expect(document.activeElement) + .to.equal(tile3); + }); + }); + + describe('only allows one item to be selected', async function() { + beforeEach(async function() { + element = await createFixture(tileGroup); + [tile1, tile2, tile3] = tiles(element); + await element.focus(); + }); + + it('only has one selected element', function() { + expect(element.selected) + .to.equal(tile1); + }); + + describe('only one tiles has a checked radio', function() { + const [checked1] = inputs(element, true); + const tileChecked = input(tile1, true); + + it('only has one checked radio button', function() { + expect(checked1) + .to.equal([tileChecked]); + }); + + describe('clicking second tile', async function() { + beforeEach(async function() { + tile2.focus(); + await enter(); + }); + + it('selects the second tile only', function() { + expect(element.selected) + .to.equal(tile2); + }); + }); + }); + }); + }); +}); diff --git a/assets/packages/@rhds/elements/elements/rh-tile/test/rh-tile.e2e.ts b/assets/packages/@rhds/elements/elements/rh-tile/test/rh-tile.e2e.ts new file mode 100644 index 0000000000..2bbf666e4b --- /dev/null +++ b/assets/packages/@rhds/elements/elements/rh-tile/test/rh-tile.e2e.ts @@ -0,0 +1,12 @@ +import { test } from '@playwright/test'; +import { PfeDemoPage } from '@patternfly/pfe-tools/test/playwright/PfeDemoPage.js'; + +const tagName = 'rh-tile'; + +test.describe(tagName, () => { + test('snapshot', async ({ page }) => { + const componentPage = new PfeDemoPage(page, tagName); + await componentPage.navigate(); + await componentPage.snapshot(); + }); +}); diff --git a/assets/packages/@rhds/elements/elements/rh-tile/test/rh-tile.spec.ts b/assets/packages/@rhds/elements/elements/rh-tile/test/rh-tile.spec.ts new file mode 100644 index 0000000000..2510947fda --- /dev/null +++ b/assets/packages/@rhds/elements/elements/rh-tile/test/rh-tile.spec.ts @@ -0,0 +1,102 @@ +import { expect, html } from '@open-wc/testing'; +import { createFixture } from '@patternfly/pfe-tools/test/create-fixture.js'; +import { a11ySnapshot } from '@patternfly/pfe-tools/test/a11y-snapshot.js'; +import { sendMouse, sendKeys } from '@web/test-runner-commands'; +import { RhTile } from '@rhds/elements/rh-tile/rh-tile.js'; + +describe('', function() { + let element: RhTile; + + async function click(element: HTMLElement) { + const { x, y, width, height } = element.getBoundingClientRect(); + const position = [x + width / 2, y + height / 2].map(Math.round) as [number, number]; + await sendMouse({ type: 'click', position }); + } + + async function enter() { + await sendKeys({ press: 'Enter' }); + await element.updateComplete; + } + + describe('simply instantiating', function() { + it('imperatively instantiates', function() { + expect(document.createElement('rh-tile')).to.be.an.instanceof(RhTile); + }); + + it('should upgrade', async function() { + element = await createFixture(html``); + const klass = customElements.get('rh-tile'); + expect(element) + .to.be.an.instanceOf(klass) + .and + .to.be.an.instanceOf(RhTile); + }); + }); + + describe('default tile', function() { + const tile = html` + 296 X 50 placeholder +
Title
+

Link

+ Lorem ipsum dolor sit amet, consectetur adipiscing elit. +
Suspendisse eu turpis elementum
+
`; + let element: RhTile; + + it('is accessible', async function() { + element = await createFixture(tile); + expect(element) + .to.be.an.accessible; + }); + }); + + describe('checkable tile', function() { + const tile = html` + 296 X 50 placeholder +
Title
+

Link

+ Lorem ipsum dolor sit amet, consectetur adipiscing elit. +
Suspendisse eu turpis elementum
+
`; + let element: RhTile; + + beforeEach(async function() { + element = await createFixture(tile); + }); + + it('is accessible', async function() { + await expect(element).to.be.an.accessible; + }); + + it('has a checkbox', async function() { + const snapshot = await a11ySnapshot(); + const checkboxes = snapshot?.children.filter(child=>child.role === 'checkbox'); + expect(checkboxes.length) + .to.equal(1); + }); + + describe('pressing Enter', async function() { + beforeEach(async function() { + element.focus(); + await enter(); + }); + + it('is checked', function() { + expect(element.checked) + .to.equal(true); + }); + + describe('clicking', async function() { + beforeEach(async function() { + element.checked = true; + await element.updateComplete; + await click(element); + }); + it('is unchecked', function() { + expect(element.checked) + .to.equal(false); + }); + }); + }); + }); +}); diff --git a/assets/playgrounds/rh-tile-group-playground.js b/assets/playgrounds/rh-tile-group-playground.js new file mode 100644 index 0000000000..c2a4e0548f --- /dev/null +++ b/assets/playgrounds/rh-tile-group-playground.js @@ -0,0 +1 @@ +export const configure = project => project.config = undefined; \ No newline at end of file diff --git a/assets/playgrounds/rh-tile-playground.js b/assets/playgrounds/rh-tile-playground.js new file mode 100644 index 0000000000..91c0bc0ef5 --- /dev/null +++ b/assets/playgrounds/rh-tile-playground.js @@ -0,0 +1,87 @@ +export const configure = project => project.config = { + "files": { + "demo/rhds-demo-base.css": { + "contentType": "text/css", + "content": "html,\nbody {\n margin: 0;\n}\n\nhtml {\n font-family: var(--rh-font-family-body-text, RedHatText, \"Red Hat Text\", \"Noto Sans Arabic\", \"Noto Sans Hebrew\", \"Noto Sans JP\", \"Noto Sans KR\", \"Noto Sans Malayalam\", \"Noto Sans SC\", \"Noto Sans TC\", \"Noto Sans Thai\", Overpass, Helvetica, Arial, sans-serif, \"Overpass\", Overpass, Helvetica, Arial, sans-serif);\n line-height: var(--rh-line-height-body-text, 1.5);\n font-size: 16px;\n}\n\n*,\n*:before,\n*:after {\n box-sizing: border-box;\n}\n\nh1,\nh2,\nh3,\nh4,\nh5,\nh6 {\n font-weight: var(--rh-font-weight-heading-medium, 500);\n font-family: var(--rh-font-family-heading, RedHatDisplay, \"Red Hat Display\", \"Noto Sans Arabic\", \"Noto Sans Hebrew\", \"Noto Sans JP\", \"Noto Sans KR\", \"Noto Sans Malayalam\", \"Noto Sans SC\", \"Noto Sans TC\", \"Noto Sans Thai\", Overpass, Helvetica, Arial, sans-serif, \"Overpass\", Overpass, Helvetica, Arial, sans-serif);\n}\n", + "hidden": true + }, + "demo/rh-tile-group/index.html": { + "contentType": "text/html", + "selected": false, + "content": "\n\n\n\n
\n

Tile Group

\n \n \n

Headline

\n Lorem ipsum dolor sit amet, consectetur adipiscing elit.\n
Suspendisse eu turpis elementum
\n
\n\n \n

Headline

\n Lorem ipsum dolor sit amet, consectetur adipiscing elit.\n
Suspendisse eu turpis elementum
\n
\n\n \n
Title
\n

Headline

\n Lorem ipsum dolor sit amet, consectetur adipiscing elit.\n
Suspendisse eu turpis elementum
\n
\n
\n \n

Tile Group, Disabled

\n \n \n

Headline

\n Lorem ipsum dolor sit amet, consectetur adipiscing elit.\n
Suspendisse eu turpis elementum
\n
\n\n \n

Headline

\n Lorem ipsum dolor sit amet, consectetur adipiscing elit.\n
Suspendisse eu turpis elementum
\n
\n\n \n

Headline

\n Lorem ipsum dolor sit amet, consectetur adipiscing elit.\n
Suspendisse eu turpis elementum
\n
\n
\n\n

Tile Group, Radio

\n \n \n

Headline

\n Lorem ipsum dolor sit amet, consectetur adipiscing elit.\n
Suspendisse eu turpis elementum
\n
\n\n \n

Headline

\n Lorem ipsum dolor sit amet, consectetur adipiscing elit.\n
Suspendisse eu turpis elementum
\n
\n\n \n

Headline

\n Lorem ipsum dolor sit amet, consectetur adipiscing elit.\n
Suspendisse eu turpis elementum
\n
\n
\n\n

Tile Group, Radio, Disabled

\n \n \n

Headline

\n Lorem ipsum dolor sit amet, consectetur adipiscing elit.\n
Suspendisse eu turpis elementum
\n
\n\n \n

Headline

\n Lorem ipsum dolor sit amet, consectetur adipiscing elit.\n
Suspendisse eu turpis elementum
\n
\n\n \n

Headline

\n Lorem ipsum dolor sit amet, consectetur adipiscing elit.\n
Suspendisse eu turpis elementum
\n
\n
\n
\n\n\n", + "label": "Tile Group" + }, + "demo/rh-tile-group/demo.css": { + "content": "#demo-container {\n margin: 36px 36px 0;\n padding: 36px 0;\n row-gap: 36px;\n}\n\n#demo-container, rh-tile-group {\n display: flex;\n align-items: top;\n flex-wrap: wrap;\n column-gap: 36px;\n row-gap: 36px;\n}\n\nh2:not(rh-tile > h2), rh-tile-group {\n flex: 1 0 100%;\n margin: 0;\n}\n\nrh-tile {\n flex: 0 0 360px;\n}", + "hidden": true + }, + "demo/rh-tile-lightdom.css": { + "content": "rh-tile a {\n color: var(--rh-tile-link-color) !important;\n text-decoration: var(--rh-tile-link-text-decoration, none) !important;\n}\n\nrh-tile:focus-within a, \nrh-tile a:is(:focus, :hover, :active) {\n --rh-tile-link-text-decoration: underline;\n}\n\nrh-tile a:not([slot=\"image\"], [slot=\"headline\"]) {\n z-index: 2 !important;\n position: relative !important;\n}\n\nrh-tile[aria-disabled=\"true\"] a {\n color: var(--rh-tile-text-color-secondary, \n var(--rh-color-text-secondary-on-light, #4d4d4d)\n ) !important;\n}\n\nrh-tile *:is([slot=\"image\"], [slot=\"headline\"]) a,\nrh-tile a:is([slot=\"image\"], [slot=\"headline\"]) {\n z-index: 1 !important;\n position: static !important;\n color: var(--rh-tile-link-color) !important;\n}\n\nrh-tile *:is([slot=\"image\"], [slot=\"headline\"]) a:after,\nrh-tile a:is([slot=\"image\"], [slot=\"headline\"]):after {\n content: \"\";\n position: absolute;\n inset: 0;\n display: var(--rh-tile-link-after-display);\n}\n\nrh-tile a[slot=\"image\"] > :is(img, svg),\nrh-tile [slot=\"image\"]:is(img, svg) {\n width: 100%;\n}\n\nrh-tile:defined a:is(:focus, :hover, :active) {\n outline: var(--rh-tile-link-outline) !important;\n}\n\nrh-tile:defined :is([slot=\"image\"], [slot=\"headline\"]) a,\nrh-tile:defined a:is([slot=\"image\"], [slot=\"headline\"]) {\n --rh-tile-link-outline: none;\n}\n", + "hidden": true + }, + "demo/rh-tile-group/rh-tile.js": { + "content": "import '@rhds/elements/rh-tile/rh-tile-group.js';\n", + "hidden": true + }, + "demo/index.html": { + "contentType": "text/html", + "selected": true, + "content": "\n\n\n\n
\n

Basic

\n\n \n \"296\n
Title
\n

Link

\n Lorem ipsum dolor sit amet, consectetur adipiscing elit.\n
Suspendisse eu turpis elementum
\n
\n\n \n
Title
\n

Link

\n Lorem ipsum dolor sit amet, consectetur adipiscing elit.\n
Suspendisse eu turpis elementum
\n
\n\n

Full-width images

\n \n \"300\n
Title
\n

Link

\n Lorem ipsum dolor sit amet, consectetur adipiscing elit.\n
Suspendisse eu turpis elementum
\n
\n\n \n \"300\n \n

Link

\n Lorem ipsum dolor sit amet, consectetur adipiscing elit.\n
Suspendisse eu turpis elementum
\n
\n\n

Desaturated heading

\n\n \n \"Red\n
Title
\n

Link

\n Lorem ipsum dolor sit amet, consectetur adipiscing elit.\n
Suspendisse eu turpis elementum
\n
\n\n

Disabled

\n\n \n
Title
\n

Link

\n Lorem ipsum dolor sit amet, consectetur adipiscing elit.\n
Suspendisse eu turpis elementum
\n
\n
\n\n\n", + "label": "Tile" + }, + "demo/demo.css": { + "content": "#demo-container {\n margin: 36px 36px 0;\n padding: 36px 0;\n row-gap: 36px;\n}\n\n#demo-container, rh-tile-group {\n display: flex;\n align-items: top;\n flex-wrap: wrap;\n column-gap: 36px;\n row-gap: 36px;\n}\n\nh2:not(rh-tile > h2), rh-tile-group {\n flex: 1 0 100%;\n margin: 0;\n}\n\nrh-tile {\n flex: 0 0 360px;\n}", + "hidden": true + }, + "rh-tile-lightdom.css": { + "content": "rh-tile a {\n color: var(--rh-tile-link-color) !important;\n text-decoration: var(--rh-tile-link-text-decoration, none) !important;\n}\n\nrh-tile:focus-within a, \nrh-tile a:is(:focus, :hover, :active) {\n --rh-tile-link-text-decoration: underline;\n}\n\nrh-tile a:not([slot=\"image\"], [slot=\"headline\"]) {\n z-index: 2 !important;\n position: relative !important;\n}\n\nrh-tile[aria-disabled=\"true\"] a {\n color: var(--rh-tile-text-color-secondary, \n var(--rh-color-text-secondary-on-light, #4d4d4d)\n ) !important;\n}\n\nrh-tile *:is([slot=\"image\"], [slot=\"headline\"]) a,\nrh-tile a:is([slot=\"image\"], [slot=\"headline\"]) {\n z-index: 1 !important;\n position: static !important;\n color: var(--rh-tile-link-color) !important;\n}\n\nrh-tile *:is([slot=\"image\"], [slot=\"headline\"]) a:after,\nrh-tile a:is([slot=\"image\"], [slot=\"headline\"]):after {\n content: \"\";\n position: absolute;\n inset: 0;\n display: var(--rh-tile-link-after-display);\n}\n\nrh-tile a[slot=\"image\"] > :is(img, svg),\nrh-tile [slot=\"image\"]:is(img, svg) {\n width: 100%;\n}\n\nrh-tile:defined a:is(:focus, :hover, :active) {\n outline: var(--rh-tile-link-outline) !important;\n}\n\nrh-tile:defined :is([slot=\"image\"], [slot=\"headline\"]) a,\nrh-tile:defined a:is([slot=\"image\"], [slot=\"headline\"]) {\n --rh-tile-link-outline: none;\n}\n", + "hidden": true + }, + "demo/rh-tile.js": { + "content": "import '@rhds/elements/rh-tile/rh-tile-group.js';\n", + "hidden": true + }, + "demo/checkable/index.html": { + "contentType": "text/html", + "selected": false, + "content": "\n\n\n\n
\n

Checkboxes

\n \n \n

Headline

\n Lorem ipsum dolor sit amet, consectetur adipiscing elit.\n
Suspendisse eu turpis elementum
\n
\n\n \n

Headline

\n Lorem ipsum dolor sit amet, consectetur adipiscing elit.\n
Suspendisse eu turpis elementum
\n
\n\n \n

Headline

\n Lorem ipsum dolor sit amet, consectetur adipiscing elit.\n
Suspendisse eu turpis elementum
\n
\n
\n\n\n", + "label": "Checkable" + }, + "demo/checkable/demo.css": { + "content": "#demo-container {\n margin: 36px 36px 0;\n padding: 36px 0;\n row-gap: 36px;\n}\n\n#demo-container, rh-tile-group {\n display: flex;\n align-items: top;\n flex-wrap: wrap;\n column-gap: 36px;\n row-gap: 36px;\n}\n\nh2:not(rh-tile > h2), rh-tile-group {\n flex: 1 0 100%;\n margin: 0;\n}\n\nrh-tile {\n flex: 0 0 360px;\n}", + "hidden": true + }, + "demo/checkable/rh-tile.js": { + "content": "import '@rhds/elements/rh-tile/rh-tile-group.js';\n", + "hidden": true + }, + "demo/color-context/index.html": { + "contentType": "text/html", + "selected": false, + "content": "\n\n\n\n\n\n\n
\n

Basic

\n\n \n \"296\n
Title
\n

Link

\n Lorem ipsum dolor sit amet, consectetur adipiscing elit.\n
Suspendisse eu turpis elementum
\n
\n\n \n
Title
\n

Link

\n Lorem ipsum dolor sit amet, consectetur adipiscing elit.\n
Suspendisse eu turpis elementum
\n
\n\n

Full-width images

\n \n \"300\n
Title
\n

Link

\n Lorem ipsum dolor sit amet, consectetur adipiscing elit.\n
Suspendisse eu turpis elementum
\n
\n\n \n \"300\n \n

Link

\n Lorem ipsum dolor sit amet, consectetur adipiscing elit.\n
Suspendisse eu turpis elementum
\n
\n\n

Desaturated heading

\n\n \n \"Red\n
Title
\n

Link

\n Lorem ipsum dolor sit amet, consectetur adipiscing elit.\n
Suspendisse eu turpis elementum
\n
\n\n

Disabled

\n\n \n
Title
\n

Link

\n Lorem ipsum dolor sit amet, consectetur adipiscing elit.\n
Suspendisse eu turpis elementum
\n
\n

Compact

\n \n \n

Link

\n Lorem ipsum dolor sit amet, consectetur adipiscing elit.\n
Suspendisse eu turpis elementum
\n
\n \n \n \"Red\n

Link

\n Lorem ipsum dolor sit amet, consectetur adipiscing elit.\n
Suspendisse eu turpis elementum
\n
\n \n \n \"Red\n

Link

\n
\n \n \n \"300\n \n

Link

\n Lorem ipsum dolor sit amet, consectetur adipiscing elit.\n
Suspendisse eu turpis elementum
\n
\n \n \n \"300\n

Link

\n Lorem ipsum dolor sit amet, consectetur adipiscing elit.\n
Suspendisse eu turpis elementum
\n
\n \n \n \n \"300\n \n \n

Checkboxes

\n \n \n

Headline

\n Lorem ipsum dolor sit amet, consectetur adipiscing elit.\n
Suspendisse eu turpis elementum
\n
\n \n \n

Headline

\n Lorem ipsum dolor sit amet, consectetur adipiscing elit.\n
Suspendisse eu turpis elementum
\n
\n \n \n

Headline

\n Lorem ipsum dolor sit amet, consectetur adipiscing elit.\n
Suspendisse eu turpis elementum
\n
\n \n

Tile Group

\n \n \n

Headline

\n Lorem ipsum dolor sit amet, consectetur adipiscing elit.\n
Suspendisse eu turpis elementum
\n
\n \n \n

Headline

\n Lorem ipsum dolor sit amet, consectetur adipiscing elit.\n
Suspendisse eu turpis elementum
\n
\n \n \n
Title
\n

Headline

\n Lorem ipsum dolor sit amet, consectetur adipiscing elit.\n
Suspendisse eu turpis elementum
\n
\n
\n \n

Tile Group, Disabled

\n \n \n

Headline

\n Lorem ipsum dolor sit amet, consectetur adipiscing elit.\n
Suspendisse eu turpis elementum
\n
\n \n \n

Headline

\n Lorem ipsum dolor sit amet, consectetur adipiscing elit.\n
Suspendisse eu turpis elementum
\n
\n \n \n

Headline

\n Lorem ipsum dolor sit amet, consectetur adipiscing elit.\n
Suspendisse eu turpis elementum
\n
\n
\n \n

Tile Group, Radio

\n \n \n

Headline

\n Lorem ipsum dolor sit amet, consectetur adipiscing elit.\n
Suspendisse eu turpis elementum
\n
\n \n \n

Headline

\n Lorem ipsum dolor sit amet, consectetur adipiscing elit.\n
Suspendisse eu turpis elementum
\n
\n \n \n

Headline

\n Lorem ipsum dolor sit amet, consectetur adipiscing elit.\n
Suspendisse eu turpis elementum
\n
\n
\n \n

Tile Group, Radio, Disabled

\n \n \n

Headline

\n Lorem ipsum dolor sit amet, consectetur adipiscing elit.\n
Suspendisse eu turpis elementum
\n
\n \n \n

Headline

\n Lorem ipsum dolor sit amet, consectetur adipiscing elit.\n
Suspendisse eu turpis elementum
\n
\n \n \n

Headline

\n Lorem ipsum dolor sit amet, consectetur adipiscing elit.\n
Suspendisse eu turpis elementum
\n
\n
\n
\n
\n\n\n", + "label": "Color Context" + }, + "demo/color-context/demo.css": { + "content": "#demo-container {\n margin: 36px 36px 0;\n padding: 36px 0;\n row-gap: 36px;\n}\n\n#demo-container, rh-tile-group {\n display: flex;\n align-items: top;\n flex-wrap: wrap;\n column-gap: 36px;\n row-gap: 36px;\n}\n\nh2:not(rh-tile > h2), rh-tile-group {\n flex: 1 0 100%;\n margin: 0;\n}\n\nrh-tile {\n flex: 0 0 360px;\n}", + "hidden": true + }, + "demo/color-context/color-context.js": { + "content": "import '@rhds/elements/lib/elements/rh-context-picker/rh-context-picker.js';\nimport '@rhds/elements/lib/elements/rh-context-provider/rh-context-provider.js';\nimport './rh-tile.js';\n", + "hidden": true + }, + "demo/compact/index.html": { + "contentType": "text/html", + "selected": false, + "content": "\n\n\n\n
\n

Compact

\n\n \n

Link

\n Lorem ipsum dolor sit amet, consectetur adipiscing elit.\n
Suspendisse eu turpis elementum
\n
\n\n \n \"Red\n

Link

\n Lorem ipsum dolor sit amet, consectetur adipiscing elit.\n
Suspendisse eu turpis elementum
\n
\n\n \n \"Red\n

Link

\n
\n\n \n \"300\n \n

Link

\n Lorem ipsum dolor sit amet, consectetur adipiscing elit.\n
Suspendisse eu turpis elementum
\n
\n\n \n \"300\n

Link

\n Lorem ipsum dolor sit amet, consectetur adipiscing elit.\n
Suspendisse eu turpis elementum
\n
\n\n \n \n \"300\n \n \n
\n\n\n", + "label": "Compact" + }, + "demo/compact/demo.css": { + "content": "#demo-container {\n margin: 36px 36px 0;\n padding: 36px 0;\n row-gap: 36px;\n}\n\n#demo-container, rh-tile-group {\n display: flex;\n align-items: top;\n flex-wrap: wrap;\n column-gap: 36px;\n row-gap: 36px;\n}\n\nh2:not(rh-tile > h2), rh-tile-group {\n flex: 1 0 100%;\n margin: 0;\n}\n\nrh-tile {\n flex: 0 0 360px;\n}", + "hidden": true + }, + "demo/compact/rh-tile.js": { + "content": "import '@rhds/elements/rh-tile/rh-tile-group.js';\n", + "hidden": true + } + } +}; \ No newline at end of file diff --git a/cheatsheet/index.html b/cheatsheet/index.html index d0e7e3ef7f..6865ac929f 100644 --- a/cheatsheet/index.html +++ b/cheatsheet/index.html @@ -29,7 +29,7 @@ - + + + + + + + +

+ rh-tile-group +

+
+

A group of <rh-tile> elements which handles radio selection.

+
+ +

+ Slots +

+
+
Default Slot +
+
+

tiles

+
+
+
+ +

+ Attributes +

+
+
disabled
+
+

whether tile group interaction is disabled

+
DOM Property
disabled
Type
+
boolean
+
+
Default
+
false
+
+
+
radio
+
+

if tile is checkable, whether only one tile can be checked

+
DOM Property
radio
Type
+
boolean
+
+
Default
+
false
+
+
+
color-palette
+
+

Sets color palette, which affects the element's styles as well as descendants' color theme. +Overrides parent color context. +Your theme will influence these colors so check there first if you are seeing inconsistencies. +See CSS Custom Properties for default values

+

Tile group always resets its context to base, unless explicitly provided with a color-palette.

+
DOM Property
colorPalette
Type
+
ColorPalette | undefined
+
+
Default
+
unknown
+
+
+
+
+ +

+ Methods +

+
+

None

+
+ +

+ Events +

+
+

None

+
+ +

+ CSS Shadow Parts +

+
+

None

+
+ +

+ CSS Custom Properties +

+
+

None

+ + + + + + + + + + + + + + + + + + © 2021-2023 Red Hat, Inc. + + + + Deploys by Netlify + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/elements/tile/demo/checkable/index.html b/elements/tile/demo/checkable/index.html new file mode 100644 index 0000000000..2874b12dd0 --- /dev/null +++ b/elements/tile/demo/checkable/index.html @@ -0,0 +1,51 @@ + + + + + Checkable | Red Hat Design System + + + + + + + + + + + + +
+
+ + + +
+

Checkboxes

+ + +

Headline

+ Lorem ipsum dolor sit amet, consectetur adipiscing elit. +
Suspendisse eu turpis elementum
+
+ + +

Headline

+ Lorem ipsum dolor sit amet, consectetur adipiscing elit. +
Suspendisse eu turpis elementum
+
+ + +

Headline

+ Lorem ipsum dolor sit amet, consectetur adipiscing elit. +
Suspendisse eu turpis elementum
+
+
+
+
+ + + \ No newline at end of file diff --git a/elements/tile/demo/color-context.js b/elements/tile/demo/color-context.js new file mode 100644 index 0000000000..827ef29ead --- /dev/null +++ b/elements/tile/demo/color-context.js @@ -0,0 +1,3 @@ +import '@rhds/elements/lib/elements/rh-context-picker/rh-context-picker.js'; +import '@rhds/elements/lib/elements/rh-context-provider/rh-context-provider.js'; +import './rh-tile.js'; diff --git a/elements/tile/demo/color-context/index.html b/elements/tile/demo/color-context/index.html new file mode 100644 index 0000000000..0ef4dadba2 --- /dev/null +++ b/elements/tile/demo/color-context/index.html @@ -0,0 +1,232 @@ + + + + + Color Context | Red Hat Design System + + + + + + + + + + + + +
+
+ + + + + + +
+

Basic

+ + + 296 X 50 placeholder image +
Title
+

Link

+ Lorem ipsum dolor sit amet, consectetur adipiscing elit. +
Suspendisse eu turpis elementum
+
+ + +
Title
+

Link

+ Lorem ipsum dolor sit amet, consectetur adipiscing elit. +
Suspendisse eu turpis elementum
+
+ +

Full-width images

+ + 300 X 200 placeholder image +
Title
+

Link

+ Lorem ipsum dolor sit amet, consectetur adipiscing elit. +
Suspendisse eu turpis elementum
+
+ + + 300 X 170 placeholder image + +

Link

+ Lorem ipsum dolor sit amet, consectetur adipiscing elit. +
Suspendisse eu turpis elementum
+
+ +

Desaturated heading

+ + + Red Hat +
Title
+

Link

+ Lorem ipsum dolor sit amet, consectetur adipiscing elit. +
Suspendisse eu turpis elementum
+
+ +

Disabled

+ + +
Title
+

Link

+ Lorem ipsum dolor sit amet, consectetur adipiscing elit. +
Suspendisse eu turpis elementum
+
+

Compact

+ + +

Link

+ Lorem ipsum dolor sit amet, consectetur adipiscing elit. +
Suspendisse eu turpis elementum
+
+ + + Red Hat +

Link

+ Lorem ipsum dolor sit amet, consectetur adipiscing elit. +
Suspendisse eu turpis elementum
+
+ + + Red Hat +

Link

+
+ + + 300 X 50 placeholder image + +

Link

+ Lorem ipsum dolor sit amet, consectetur adipiscing elit. +
Suspendisse eu turpis elementum
+
+ + + 300 X 50 placeholder image +

Link

+ Lorem ipsum dolor sit amet, consectetur adipiscing elit. +
Suspendisse eu turpis elementum
+
+ + + + 300 X 50 placeholder image + + +

Checkboxes

+ + +

Headline

+ Lorem ipsum dolor sit amet, consectetur adipiscing elit. +
Suspendisse eu turpis elementum
+
+ + +

Headline

+ Lorem ipsum dolor sit amet, consectetur adipiscing elit. +
Suspendisse eu turpis elementum
+
+ + +

Headline

+ Lorem ipsum dolor sit amet, consectetur adipiscing elit. +
Suspendisse eu turpis elementum
+
+ +

Tile Group

+ + +

Headline

+ Lorem ipsum dolor sit amet, consectetur adipiscing elit. +
Suspendisse eu turpis elementum
+
+ + +

Headline

+ Lorem ipsum dolor sit amet, consectetur adipiscing elit. +
Suspendisse eu turpis elementum
+
+ + +
Title
+

Headline

+ Lorem ipsum dolor sit amet, consectetur adipiscing elit. +
Suspendisse eu turpis elementum
+
+
+ +

Tile Group, Disabled

+ + +

Headline

+ Lorem ipsum dolor sit amet, consectetur adipiscing elit. +
Suspendisse eu turpis elementum
+
+ + +

Headline

+ Lorem ipsum dolor sit amet, consectetur adipiscing elit. +
Suspendisse eu turpis elementum
+
+ + +

Headline

+ Lorem ipsum dolor sit amet, consectetur adipiscing elit. +
Suspendisse eu turpis elementum
+
+
+ +

Tile Group, Radio

+ + +

Headline

+ Lorem ipsum dolor sit amet, consectetur adipiscing elit. +
Suspendisse eu turpis elementum
+
+ + +

Headline

+ Lorem ipsum dolor sit amet, consectetur adipiscing elit. +
Suspendisse eu turpis elementum
+
+ + +

Headline

+ Lorem ipsum dolor sit amet, consectetur adipiscing elit. +
Suspendisse eu turpis elementum
+
+
+ +

Tile Group, Radio, Disabled

+ + +

Headline

+ Lorem ipsum dolor sit amet, consectetur adipiscing elit. +
Suspendisse eu turpis elementum
+
+ + +

Headline

+ Lorem ipsum dolor sit amet, consectetur adipiscing elit. +
Suspendisse eu turpis elementum
+
+ + +

Headline

+ Lorem ipsum dolor sit amet, consectetur adipiscing elit. +
Suspendisse eu turpis elementum
+
+
+
+
+
+
+ + + \ No newline at end of file diff --git a/elements/tile/demo/compact/index.html b/elements/tile/demo/compact/index.html new file mode 100644 index 0000000000..0473da84d0 --- /dev/null +++ b/elements/tile/demo/compact/index.html @@ -0,0 +1,72 @@ + + + + + Compact | Red Hat Design System + + + + + + + + + + + + +
+
+ + + +
+

Compact

+ + +

Link

+ Lorem ipsum dolor sit amet, consectetur adipiscing elit. +
Suspendisse eu turpis elementum
+
+ + + Red Hat +

Link

+ Lorem ipsum dolor sit amet, consectetur adipiscing elit. +
Suspendisse eu turpis elementum
+
+ + + Red Hat +

Link

+
+ + + 300 X 50 placeholder image + +

Link

+ Lorem ipsum dolor sit amet, consectetur adipiscing elit. +
Suspendisse eu turpis elementum
+
+ + + 300 X 50 placeholder image +

Link

+ Lorem ipsum dolor sit amet, consectetur adipiscing elit. +
Suspendisse eu turpis elementum
+
+ + + + 300 X 50 placeholder image + + +
+
+
+ + + \ No newline at end of file diff --git a/elements/tile/demo/demo.css b/elements/tile/demo/demo.css new file mode 100644 index 0000000000..4f11dcee1c --- /dev/null +++ b/elements/tile/demo/demo.css @@ -0,0 +1,22 @@ +#demo-container { + margin: 36px 36px 0; + padding: 36px 0; + row-gap: 36px; +} + +#demo-container, rh-tile-group { + display: flex; + align-items: top; + flex-wrap: wrap; + column-gap: 36px; + row-gap: 36px; +} + +h2:not(rh-tile > h2), rh-tile-group { + flex: 1 0 100%; + margin: 0; +} + +rh-tile { + flex: 0 0 360px; +} \ No newline at end of file diff --git a/elements/tile/demo/index.html b/elements/tile/demo/index.html new file mode 100644 index 0000000000..34e0313b9f --- /dev/null +++ b/elements/tile/demo/index.html @@ -0,0 +1,84 @@ + + + + + Tile | Red Hat Design System + + + + + + + + + + + + +
+
+ + + +
+

Basic

+ + + 296 X 50 placeholder image +
Title
+

Link

+ Lorem ipsum dolor sit amet, consectetur adipiscing elit. +
Suspendisse eu turpis elementum
+
+ + +
Title
+

Link

+ Lorem ipsum dolor sit amet, consectetur adipiscing elit. +
Suspendisse eu turpis elementum
+
+ +

Full-width images

+ + 300 X 200 placeholder image +
Title
+

Link

+ Lorem ipsum dolor sit amet, consectetur adipiscing elit. +
Suspendisse eu turpis elementum
+
+ + + 300 X 170 placeholder image + +

Link

+ Lorem ipsum dolor sit amet, consectetur adipiscing elit. +
Suspendisse eu turpis elementum
+
+ +

Desaturated heading

+ + + Red Hat +
Title
+

Link

+ Lorem ipsum dolor sit amet, consectetur adipiscing elit. +
Suspendisse eu turpis elementum
+
+ +

Disabled

+ + +
Title
+

Link

+ Lorem ipsum dolor sit amet, consectetur adipiscing elit. +
Suspendisse eu turpis elementum
+
+
+
+
+ + + \ No newline at end of file diff --git a/elements/tile/demo/logo-red-hat.svg b/elements/tile/demo/logo-red-hat.svg new file mode 100644 index 0000000000..7ccfd89b73 --- /dev/null +++ b/elements/tile/demo/logo-red-hat.svg @@ -0,0 +1 @@ + diff --git a/elements/tile/demo/rh-tile-group/index.html b/elements/tile/demo/rh-tile-group/index.html new file mode 100644 index 0000000000..9017c26465 --- /dev/null +++ b/elements/tile/demo/rh-tile-group/index.html @@ -0,0 +1,116 @@ + + + + + Tile Group | Red Hat Design System + + + + + + + + + + + + +
+
+ + + +
+

Tile Group

+ + +

Headline

+ Lorem ipsum dolor sit amet, consectetur adipiscing elit. +
Suspendisse eu turpis elementum
+
+ + +

Headline

+ Lorem ipsum dolor sit amet, consectetur adipiscing elit. +
Suspendisse eu turpis elementum
+
+ + +
Title
+

Headline

+ Lorem ipsum dolor sit amet, consectetur adipiscing elit. +
Suspendisse eu turpis elementum
+
+
+ +

Tile Group, Disabled

+ + +

Headline

+ Lorem ipsum dolor sit amet, consectetur adipiscing elit. +
Suspendisse eu turpis elementum
+
+ + +

Headline

+ Lorem ipsum dolor sit amet, consectetur adipiscing elit. +
Suspendisse eu turpis elementum
+
+ + +

Headline

+ Lorem ipsum dolor sit amet, consectetur adipiscing elit. +
Suspendisse eu turpis elementum
+
+
+ +

Tile Group, Radio

+ + +

Headline

+ Lorem ipsum dolor sit amet, consectetur adipiscing elit. +
Suspendisse eu turpis elementum
+
+ + +

Headline

+ Lorem ipsum dolor sit amet, consectetur adipiscing elit. +
Suspendisse eu turpis elementum
+
+ + +

Headline

+ Lorem ipsum dolor sit amet, consectetur adipiscing elit. +
Suspendisse eu turpis elementum
+
+
+ +

Tile Group, Radio, Disabled

+ + +

Headline

+ Lorem ipsum dolor sit amet, consectetur adipiscing elit. +
Suspendisse eu turpis elementum
+
+ + +

Headline

+ Lorem ipsum dolor sit amet, consectetur adipiscing elit. +
Suspendisse eu turpis elementum
+
+ + +

Headline

+ Lorem ipsum dolor sit amet, consectetur adipiscing elit. +
Suspendisse eu turpis elementum
+
+
+
+
+
+ + + \ No newline at end of file diff --git a/elements/tile/demo/rh-tile.js b/elements/tile/demo/rh-tile.js new file mode 100644 index 0000000000..57a2e31eb7 --- /dev/null +++ b/elements/tile/demo/rh-tile.js @@ -0,0 +1 @@ +import '@rhds/elements/rh-tile/rh-tile-group.js'; diff --git a/elements/tile/guidelines/index.html b/elements/tile/guidelines/index.html new file mode 100644 index 0000000000..f57c347784 --- /dev/null +++ b/elements/tile/guidelines/index.html @@ -0,0 +1,1186 @@ + + + + Guidelines | Tile | Red Hat design system + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + +
+
+
+ +
+
+
+ +

+ Usage +

+
+

A tile can be used when a clickable container is needed to provide one call to action or show one form input option. It can be grouped with similarly-structured and styled tiles in a tile group. There are two types, link tiles and selectable tiles. Both can be used in groups or individually, except for a selectable tile with a radio button, which always has to be grouped.

+ +

+ Tile vs. card +

+
+

The primary distinguishing factor between a tile and a card is that each tile can perform only one action because the whole surface is clickable. A tile also has the ability to be used as selectable items in a form. Tiles can be grouped together like card, however.

+ +

+ Variants +

+
+ + + +

A link tile has many different use cases, but it is especially helpful to use in place of a card group that would have repetitive calls to action. They can also be used in place of Brick calls to action if adding icons or images is necessary.

+ + + +

A link tile has a compact variant that can be used in sections that need a denser concentration of information. To further condense each tile, a compact link tile does not have a title slot and the icon appears to the left of content, rather than above it.

+ +

+ Desaturated heading +

+
+

The desaturated heading variant is best used for pages with many link tiles. For example, it can help prevent a blue heading from appearing visually overwhelming on a search results page, especially if each tile includes a logo. Other than the heading color, the hover, focus, and active states look the same as a default link tile and the arrow will always be blue.

+ +

+ Image sizes +

+
+

For a link tile, there are two image sizes available. The Default size has spacing around the entire image. The Full-width image size bleeds to the top, left, and right edges. The default image size is recommended for logos, while illustrations or photos would work well as a full-width image.

+
+ Examples of a logo in a tile with the default image size and a photo in a tile with the full-width image size +
+ +

+ Selectable tiles +

+
+ +

Warning

+

A selectable tile with a radio button must be used in a group. If there is only one choice listed, use a checkbox.

+
+

A selectable tile is a form element and can be used as either a radio button or a checkbox. The radio button should be used if only one option can be selected. A selectable tile with checkboxes should be used when a user can select more than one option.

+ +

+ Writing content +

+
+

The four content slots within a tile are title, heading, body, and footer.

+
    +
  • + +

    + Title +

    +
    +

    A title provides secondary descriptive context. A selectable tile does not have title slots.

    +
  • +
  • + +

    + Heading +

    +
    +

    In a link tile, the heading should indicate what clicking on the tile will do. In a selectable tile, the heading labels the radio button or checkbox.

    +
  • +
  • + +

    + Body +

    +
    +

    The body text expands on heading content and gives the user more information.

    +
  • +
  • + + + +

    Footer text should be brief and be used for supplementary information only.

    +
  • +
+ +

+ Character count +

+
+

The recommended character counts below include spaces. Line counts are based on a default link tile at minimum width.

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
ElementCharacter countLine count
Title text201
Heading text643
Body text1607
Footer text251
+ +

+ Layouts +

+
+

Like a card, the default tile should have a minimum width of four grid columns, so there is a maximum of three default link tiles in one row.

+
+ Three default link tiles in a row +
+

The compact link tiles or selectable tiles can condense to a minimum width of three grid columns or a max of four compact tiles in a row.

+
+ Four compact link tiles in a row +
+ +

+ Behavior +

+
+ +

+ Vertical height +

+
+

The vertical height of a tile will increase as more content is added. The vertical height of multiple tiles in one row matches the height of the tallest tile.

+
+ Three link tiles with different amounts of content have the same height +
+ +

+ Best practices +

+
+ + + +

Do not use a link tile if it needs to link to more than one destination.

+
+ Example of an incorrectly used link tile with a call to action in the body +
+

A link tile should not be used as a button. A link tile is akin to a call to action and should navigate a user somewhere else.

+
+ Example of an incorrectly used link tile with “submit” as a heading and no other text +
+ +

+ Tile groups +

+
+

Do not use different variants of a tile in one tile group.

+
+ Example of an incorrectly styled tile group with a default link tile and a compact link tile +
+

When grouped, use the same number of content slots to make them easy to scan.

+
+ Example of an incorrectly styled tile group with one tile that has only text and a second tile that includes a logo and a title +
+

If tiles have images, the images should have the same height. This will help the headings of each tile align vertically which also helps users scan more easily.

+
+ Example of an incorrectly styled tile group with two tiles using different image heights +
+ + + +

The footer of a link tile or selectable tile should not include calls to action, links, or buttons, but it can include non-interactive elements, like tags or badges. Ideally, footer content should be able to fit on one line, but it can wrap to two when necessary.

+
+ Example of incorrectly adding a link in the footer of a link tile +
+ + + + + + + + +
+
+ + + + + + © 2021-2023 Red Hat, Inc. + + + + Deploys by Netlify + + + + + +
+
+ + +
+ + + + + + \ No newline at end of file diff --git a/elements/tile/index.html b/elements/tile/index.html new file mode 100644 index 0000000000..2f7686bf2f --- /dev/null +++ b/elements/tile/index.html @@ -0,0 +1,1029 @@ + + + + Overview | Tile | Red Hat design system + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + +
+
+
+ +
+
+
+ +

+ Overview +

+
+

A tile is a flexible layout with a clickable and contained surface.

+
+ Example of a default link tile and a selectable tile +
+ +

+ Sample element +

+
+ + 296 X 50 placeholder +
Title
+

Link

+ Lorem ipsum dolor sit amet, consectetur adipiscing elit. +
Suspendisse eu turpis elementum
+
+ +

+ Demo +

+
+

View a live version of this element and see how it can be customized.

+ + +
<link rel="stylesheet" href="demo.css">
<link rel="stylesheet" href="../rh-tile-lightdom.css">
<script type="module" src="rh-tile.js"></script>

<div id="demo-container">
<h2>Basic</h2>

<rh-tile>
<img slot="image" src="//fakeimg.pl/296x50" alt="296 X 50 placeholder image">
<div slot="title">Title</div>
<h2 slot="headline"><a href="#top">Link</a></h2>
Lorem ipsum dolor sit amet, consectetur adipiscing elit.
<div slot="footer">Suspendisse eu turpis elementum</div>
</rh-tile>

<rh-tile>
<div slot="title">Title</div>
<h2 slot="headline"><a href="#top">Link</a></h2>
Lorem ipsum dolor sit amet, consectetur adipiscing elit.
<div slot="footer">Suspendisse eu turpis elementum</div>
</rh-tile>

<h2>Full-width images</h2>
<rh-tile bleed>
<img slot="image" src="//fakeimg.pl/300x200" alt="300 X 200 placeholder image">
<div slot="title">Title</div>
<h2 slot="headline"><a href="#top">Link</a></h2>
Lorem ipsum dolor sit amet, consectetur adipiscing elit.
<div slot="footer">Suspendisse eu turpis elementum</div>
</rh-tile>

<rh-tile bleed>
<img slot="image" src="//fakeimg.pl/300x170" alt="300 X 170 placeholder image">
<pf-icon slot="icon" icon="aws" set="fab" size="xl"></pf-icon>
<h2 slot="headline"><a href="#top">Link</a></h2>
Lorem ipsum dolor sit amet, consectetur adipiscing elit.
<div slot="footer">Suspendisse eu turpis elementum</div>
</rh-tile>

<h2>Desaturated heading</h2>

<rh-tile desaturated>
<img slot ="icon" src="logo-red-hat.svg" alt="Red Hat">
<div slot="title">Title</div>
<h2 slot="headline"><a href="#top">Link</a></h2>
Lorem ipsum dolor sit amet, consectetur adipiscing elit.
<div slot="footer">Suspendisse eu turpis elementum</div>
</rh-tile>

<h2>Disabled</h2>

<rh-tile disabled>
<div slot="title">Title</div>
<h2 slot="headline"><a href="#top">Link</a></h2>
Lorem ipsum dolor sit amet, consectetur adipiscing elit.
<div slot="footer">Suspendisse eu turpis elementum</div>
</rh-tile>
</div>
+
+ View the <rh-tile> demo in a new tab + +

+ When to use +

+
+
    +
  • When you need to group content in a linked container
  • +
  • When you need an alternative to a group of cards with the same calls to action
  • +
  • When you need to group content for a radio button or checkbox in a form
  • +
+ + + + + + + + + +
+
+ + + + + + © 2021-2023 Red Hat, Inc. + + + + Deploys by Netlify + + + + + +
+
+ + +
+ + + + + + \ No newline at end of file diff --git a/elements/tile/link-tile-anatomy-360w.png b/elements/tile/link-tile-anatomy-360w.png new file mode 100644 index 0000000000..6299c81c1c Binary files /dev/null and b/elements/tile/link-tile-anatomy-360w.png differ diff --git a/elements/tile/link-tile-anatomy.png b/elements/tile/link-tile-anatomy.png new file mode 100644 index 0000000000..40b1fe398c Binary files /dev/null and b/elements/tile/link-tile-anatomy.png differ diff --git a/elements/tile/screenshot-340w.png b/elements/tile/screenshot-340w.png new file mode 100644 index 0000000000..14e5878606 Binary files /dev/null and b/elements/tile/screenshot-340w.png differ diff --git a/elements/tile/screenshot.png b/elements/tile/screenshot.png new file mode 100644 index 0000000000..6380fccce9 Binary files /dev/null and b/elements/tile/screenshot.png differ diff --git a/elements/tile/selectable-tile-anatomy-755w.png b/elements/tile/selectable-tile-anatomy-755w.png new file mode 100644 index 0000000000..56efb3f20d Binary files /dev/null and b/elements/tile/selectable-tile-anatomy-755w.png differ diff --git a/elements/tile/selectable-tile-anatomy.png b/elements/tile/selectable-tile-anatomy.png new file mode 100644 index 0000000000..a3682748dd Binary files /dev/null and b/elements/tile/selectable-tile-anatomy.png differ diff --git a/elements/tile/space-link-tile-no-image-752w.png b/elements/tile/space-link-tile-no-image-752w.png new file mode 100644 index 0000000000..4e9e99728d Binary files /dev/null and b/elements/tile/space-link-tile-no-image-752w.png differ diff --git a/elements/tile/space-link-tile-no-image.png b/elements/tile/space-link-tile-no-image.png new file mode 100755 index 0000000000..7285a545d5 Binary files /dev/null and b/elements/tile/space-link-tile-no-image.png differ diff --git a/elements/tile/space-link-tile-with-image-752w.png b/elements/tile/space-link-tile-with-image-752w.png new file mode 100644 index 0000000000..4d403a91cd Binary files /dev/null and b/elements/tile/space-link-tile-with-image-752w.png differ diff --git a/elements/tile/space-link-tile-with-image.png b/elements/tile/space-link-tile-with-image.png new file mode 100755 index 0000000000..31718402e4 Binary files /dev/null and b/elements/tile/space-link-tile-with-image.png differ diff --git a/elements/tile/space-selectable-tile-360w.png b/elements/tile/space-selectable-tile-360w.png new file mode 100644 index 0000000000..37ab150785 Binary files /dev/null and b/elements/tile/space-selectable-tile-360w.png differ diff --git a/elements/tile/space-selectable-tile.png b/elements/tile/space-selectable-tile.png new file mode 100755 index 0000000000..9662d6fd74 Binary files /dev/null and b/elements/tile/space-selectable-tile.png differ diff --git a/elements/tile/style/index.html b/elements/tile/style/index.html new file mode 100644 index 0000000000..bebdc04615 --- /dev/null +++ b/elements/tile/style/index.html @@ -0,0 +1,1150 @@ + + + + Style | Tile | Red Hat design system + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + +
+
+
+ +
+
+
+ +

+ Style +

+
+

A tile is available as a Link tile or Selectable tile. A link tile has two sizes and heading color options; the blue arrow in the bottom right corner helps distinguish it from card. A selectable tile has a consistent style for both the checkbox and radio button variants.

+ +

+ Anatomy +

+
+
+ Default link tile with numbers pointing to locations of an image, an icon, text, and a footer +
+
    +
  1. Image
  2. +
  3. Icon
  4. +
  5. Title
  6. +
  7. Heading
  8. +
  9. Body text
  10. +
  11. Footer
  12. +
+
+ Selectable tiles with numbers pointing to locations of text, a checkbox or radio button, and a footer +
+
    +
  1. Heading
  2. +
  3. Form input (checkbox or radio button)
  4. +
  5. Body text
  6. +
  7. Footer
  8. +
+ +

+ Sizes +

+
+

A link tile is available in Default and Compact sizes. A selectable tile has only one size which is based on the size of a compact tile.

+
+ Examples of a link tile, compact tile, and selectable tile to show size differences +
+ +

+ Theme +

+
+

Both the link tile and the selectable tile are available in dark and light themes.

+
+ Light theme tiles use a white background, blue or black heading, black text, and a blue arrow icon +
+
+ Dark theme tiles use a dark gray background, blue or white heading, white text, and a light blue arrow icon +
+ +

+ Heading color +

+
+

A link tile has a blue heading by default, but a desaturated variant exists for both light and dark themes. The desaturated heading uses either a black or white heading. A selectable tile has a desaturated heading only and does not have the option for a blue heading.

+
+ Examples of a light theme link tile with a blue heading, link tile with a black heading, and selectable tile with a black heading +
+
+ Examples of a dark theme link tile with a light blue heading, link tile with a white heading, and selectable tile with a white heading +
+ +

+ Space +

+
+

Space values remain the same at all breakpoints.

+ + + +
+ Default link tile and compact link tile with spacers showing padding and margins +
+ + + +
+ Link tiles that have full-width and default image sizes with spacers showing padding and margins +
+ +

+ Selectable tile +

+
+
+ Selectable tile with spacers showing padding and margins +
+ +

+ Interaction states +

+
+

Interaction states are visual representations used to communicate the status of an element or pattern. The interaction states of a default link tile are the same for a compact link tile as long as they use the same heading color. A selectable tile does not have an underlined heading to avoid users thinking it contains a link.

+ +

+ Hover +

+
+
+ On hover, light theme tiles have a light gray background, an underlined (and sometimes darker blue) heading, a darker blue arrow icon +
+
+ On hover, dark theme tiles have a lighter gray background, an underlined (and sometimes lighter blue) heading, a lighter blue arrow icon +
+ +

+ Focus +

+
+ +

Helpful tip

+

The Focus state has the same styles as the Hover state.

+
+
+ Focused light theme tiles have a blue focus ring and use hover state styling +
+
+ Focused dark theme tiles have a light blue focus ring and use hover state styling +
+ +

+ Active +

+
+

Only link tiles have an active state. Selectable tiles have a selected state instead.

+ +

Helpful tip

+

The Active state has the same styles as the Hover state.

+
+
+ Active light theme link tiles use the focus state styles +
+
+ Active dark theme link tiles use the focus state styles +
+ +

+ Selected +

+
+

Only a selectable tile has a selected state. A link tile has an active state instead.

+
+ When selected, the form input of light theme selectable tiles appears blue and filled or checked +
+
+ When selected, the form input of dark theme selectable tiles appears light blue and filled or checked +
+ +

+ Disabled +

+
+
+ Disabled light theme tiles have a light gray background and lighter gray text. Disabled link tiles have a ban icon. +
+
+ Disabled dark theme tiles have a lighter gray background and light gray text. Disabled link tiles have a ban icon. +
+ + + + + + + + + +
+
+ + + + + + © 2021-2023 Red Hat, Inc. + + + + Deploys by Netlify + + + + + +
+
+ + +
+ + + + + + \ No newline at end of file diff --git a/elements/tile/tile-behavior-vertical-height-870w.png b/elements/tile/tile-behavior-vertical-height-870w.png new file mode 100644 index 0000000000..68b28695f6 Binary files /dev/null and b/elements/tile/tile-behavior-vertical-height-870w.png differ diff --git a/elements/tile/tile-behavior-vertical-height.png b/elements/tile/tile-behavior-vertical-height.png new file mode 100755 index 0000000000..c57284e15c Binary files /dev/null and b/elements/tile/tile-behavior-vertical-height.png differ diff --git a/elements/tile/tile-dark-theme-752w.png b/elements/tile/tile-dark-theme-752w.png new file mode 100644 index 0000000000..fc3616b40c Binary files /dev/null and b/elements/tile/tile-dark-theme-752w.png differ diff --git a/elements/tile/tile-dark-theme.png b/elements/tile/tile-dark-theme.png new file mode 100755 index 0000000000..f4b8d7408e Binary files /dev/null and b/elements/tile/tile-dark-theme.png differ diff --git a/elements/tile/tile-focus-order-879w.png b/elements/tile/tile-focus-order-879w.png new file mode 100644 index 0000000000..3127daea9c Binary files /dev/null and b/elements/tile/tile-focus-order-879w.png differ diff --git a/elements/tile/tile-focus-order.png b/elements/tile/tile-focus-order.png new file mode 100644 index 0000000000..51a16b47bd Binary files /dev/null and b/elements/tile/tile-focus-order.png differ diff --git a/elements/tile/tile-heading-color-dark-theme-752w.png b/elements/tile/tile-heading-color-dark-theme-752w.png new file mode 100644 index 0000000000..fc3616b40c Binary files /dev/null and b/elements/tile/tile-heading-color-dark-theme-752w.png differ diff --git a/elements/tile/tile-heading-color-dark-theme.png b/elements/tile/tile-heading-color-dark-theme.png new file mode 100755 index 0000000000..f4b8d7408e Binary files /dev/null and b/elements/tile/tile-heading-color-dark-theme.png differ diff --git a/elements/tile/tile-heading-color-light-theme-752w.png b/elements/tile/tile-heading-color-light-theme-752w.png new file mode 100644 index 0000000000..1e49a6f6ef Binary files /dev/null and b/elements/tile/tile-heading-color-light-theme-752w.png differ diff --git a/elements/tile/tile-heading-color-light-theme.png b/elements/tile/tile-heading-color-light-theme.png new file mode 100755 index 0000000000..62ad433ea7 Binary files /dev/null and b/elements/tile/tile-heading-color-light-theme.png differ diff --git a/elements/tile/tile-keyboard-interactions-880w.png b/elements/tile/tile-keyboard-interactions-880w.png new file mode 100644 index 0000000000..d5386d5379 Binary files /dev/null and b/elements/tile/tile-keyboard-interactions-880w.png differ diff --git a/elements/tile/tile-keyboard-interactions.png b/elements/tile/tile-keyboard-interactions.png new file mode 100644 index 0000000000..e43896c963 Binary files /dev/null and b/elements/tile/tile-keyboard-interactions.png differ diff --git a/elements/tile/tile-layouts-compact-tile-870w.png b/elements/tile/tile-layouts-compact-tile-870w.png new file mode 100644 index 0000000000..a7b9e3f80b Binary files /dev/null and b/elements/tile/tile-layouts-compact-tile-870w.png differ diff --git a/elements/tile/tile-layouts-compact-tile.png b/elements/tile/tile-layouts-compact-tile.png new file mode 100644 index 0000000000..85fbc88dcc Binary files /dev/null and b/elements/tile/tile-layouts-compact-tile.png differ diff --git a/elements/tile/tile-layouts-default-tile-870w.png b/elements/tile/tile-layouts-default-tile-870w.png new file mode 100644 index 0000000000..d541913c71 Binary files /dev/null and b/elements/tile/tile-layouts-default-tile-870w.png differ diff --git a/elements/tile/tile-layouts-default-tile.png b/elements/tile/tile-layouts-default-tile.png new file mode 100644 index 0000000000..f60cd6ca61 Binary files /dev/null and b/elements/tile/tile-layouts-default-tile.png differ diff --git a/elements/tile/tile-light-theme-752w.png b/elements/tile/tile-light-theme-752w.png new file mode 100644 index 0000000000..1e49a6f6ef Binary files /dev/null and b/elements/tile/tile-light-theme-752w.png differ diff --git a/elements/tile/tile-light-theme.png b/elements/tile/tile-light-theme.png new file mode 100755 index 0000000000..62ad433ea7 Binary files /dev/null and b/elements/tile/tile-light-theme.png differ diff --git a/elements/tile/tile-sample-752w.png b/elements/tile/tile-sample-752w.png new file mode 100644 index 0000000000..10570f8b37 Binary files /dev/null and b/elements/tile/tile-sample-752w.png differ diff --git a/elements/tile/tile-sample.png b/elements/tile/tile-sample.png new file mode 100755 index 0000000000..7f58b6a920 Binary files /dev/null and b/elements/tile/tile-sample.png differ diff --git a/elements/tile/tile-sizes-752w.png b/elements/tile/tile-sizes-752w.png new file mode 100644 index 0000000000..d94d2e35be Binary files /dev/null and b/elements/tile/tile-sizes-752w.png differ diff --git a/elements/tile/tile-sizes.png b/elements/tile/tile-sizes.png new file mode 100644 index 0000000000..7a47f7bdf2 Binary files /dev/null and b/elements/tile/tile-sizes.png differ diff --git a/elements/tile/tile-states-active-dark-theme-764w.png b/elements/tile/tile-states-active-dark-theme-764w.png new file mode 100644 index 0000000000..a872e23e74 Binary files /dev/null and b/elements/tile/tile-states-active-dark-theme-764w.png differ diff --git a/elements/tile/tile-states-active-dark-theme.png b/elements/tile/tile-states-active-dark-theme.png new file mode 100755 index 0000000000..afa8226910 Binary files /dev/null and b/elements/tile/tile-states-active-dark-theme.png differ diff --git a/elements/tile/tile-states-active-light-theme-764w.png b/elements/tile/tile-states-active-light-theme-764w.png new file mode 100644 index 0000000000..bdf2cf501f Binary files /dev/null and b/elements/tile/tile-states-active-light-theme-764w.png differ diff --git a/elements/tile/tile-states-active-light-theme.png b/elements/tile/tile-states-active-light-theme.png new file mode 100755 index 0000000000..2d178943a6 Binary files /dev/null and b/elements/tile/tile-states-active-light-theme.png differ diff --git a/elements/tile/tile-states-disabled-dark-theme-752w.png b/elements/tile/tile-states-disabled-dark-theme-752w.png new file mode 100644 index 0000000000..fafb662b02 Binary files /dev/null and b/elements/tile/tile-states-disabled-dark-theme-752w.png differ diff --git a/elements/tile/tile-states-disabled-dark-theme.png b/elements/tile/tile-states-disabled-dark-theme.png new file mode 100755 index 0000000000..77f04bc4a3 Binary files /dev/null and b/elements/tile/tile-states-disabled-dark-theme.png differ diff --git a/elements/tile/tile-states-disabled-light-theme-752w.png b/elements/tile/tile-states-disabled-light-theme-752w.png new file mode 100644 index 0000000000..0a4da019f1 Binary files /dev/null and b/elements/tile/tile-states-disabled-light-theme-752w.png differ diff --git a/elements/tile/tile-states-disabled-light-theme.png b/elements/tile/tile-states-disabled-light-theme.png new file mode 100755 index 0000000000..06e9fc4805 Binary files /dev/null and b/elements/tile/tile-states-disabled-light-theme.png differ diff --git a/elements/tile/tile-states-focus-dark-theme-764w.png b/elements/tile/tile-states-focus-dark-theme-764w.png new file mode 100644 index 0000000000..61e2d9f05a Binary files /dev/null and b/elements/tile/tile-states-focus-dark-theme-764w.png differ diff --git a/elements/tile/tile-states-focus-dark-theme.png b/elements/tile/tile-states-focus-dark-theme.png new file mode 100644 index 0000000000..07faf68be7 Binary files /dev/null and b/elements/tile/tile-states-focus-dark-theme.png differ diff --git a/elements/tile/tile-states-focus-light-theme-764w.png b/elements/tile/tile-states-focus-light-theme-764w.png new file mode 100644 index 0000000000..957751f134 Binary files /dev/null and b/elements/tile/tile-states-focus-light-theme-764w.png differ diff --git a/elements/tile/tile-states-focus-light-theme.png b/elements/tile/tile-states-focus-light-theme.png new file mode 100644 index 0000000000..24d2826333 Binary files /dev/null and b/elements/tile/tile-states-focus-light-theme.png differ diff --git a/elements/tile/tile-states-hover-dark-theme-752w.png b/elements/tile/tile-states-hover-dark-theme-752w.png new file mode 100644 index 0000000000..60c6a917fc Binary files /dev/null and b/elements/tile/tile-states-hover-dark-theme-752w.png differ diff --git a/elements/tile/tile-states-hover-dark-theme.png b/elements/tile/tile-states-hover-dark-theme.png new file mode 100644 index 0000000000..128c89ebff Binary files /dev/null and b/elements/tile/tile-states-hover-dark-theme.png differ diff --git a/elements/tile/tile-states-hover-light-theme-752w.png b/elements/tile/tile-states-hover-light-theme-752w.png new file mode 100644 index 0000000000..409ed30a6d Binary files /dev/null and b/elements/tile/tile-states-hover-light-theme-752w.png differ diff --git a/elements/tile/tile-states-hover-light-theme.png b/elements/tile/tile-states-hover-light-theme.png new file mode 100644 index 0000000000..362c7d2883 Binary files /dev/null and b/elements/tile/tile-states-hover-light-theme.png differ diff --git a/elements/tile/tile-states-selected-dark-theme-752w.png b/elements/tile/tile-states-selected-dark-theme-752w.png new file mode 100644 index 0000000000..e7b362aea6 Binary files /dev/null and b/elements/tile/tile-states-selected-dark-theme-752w.png differ diff --git a/elements/tile/tile-states-selected-dark-theme.png b/elements/tile/tile-states-selected-dark-theme.png new file mode 100755 index 0000000000..229a4e9e50 Binary files /dev/null and b/elements/tile/tile-states-selected-dark-theme.png differ diff --git a/elements/tile/tile-states-selected-light-theme-752w.png b/elements/tile/tile-states-selected-light-theme-752w.png new file mode 100644 index 0000000000..5e669a0bcf Binary files /dev/null and b/elements/tile/tile-states-selected-light-theme-752w.png differ diff --git a/elements/tile/tile-states-selected-light-theme.png b/elements/tile/tile-states-selected-light-theme.png new file mode 100755 index 0000000000..3993f7a503 Binary files /dev/null and b/elements/tile/tile-states-selected-light-theme.png differ diff --git a/elements/tile/tile-variants-image-sizes-750w.png b/elements/tile/tile-variants-image-sizes-750w.png new file mode 100644 index 0000000000..9a42637a2e Binary files /dev/null and b/elements/tile/tile-variants-image-sizes-750w.png differ diff --git a/elements/tile/tile-variants-image-sizes.png b/elements/tile/tile-variants-image-sizes.png new file mode 100755 index 0000000000..d8344c8e8b Binary files /dev/null and b/elements/tile/tile-variants-image-sizes.png differ diff --git a/elements/timestamp/accessibility/index.html b/elements/timestamp/accessibility/index.html index becd3bb52b..b9d70bb5c0 100644 --- a/elements/timestamp/accessibility/index.html +++ b/elements/timestamp/accessibility/index.html @@ -37,7 +37,7 @@ - + + +