diff --git a/.changeset/big-glasses-drum.md b/.changeset/big-glasses-drum.md new file mode 100644 index 0000000000..2a7e2bdcf3 --- /dev/null +++ b/.changeset/big-glasses-drum.md @@ -0,0 +1,5 @@ +--- +"@rhds/elements": patch +--- + +``: corrected focus when keyboard navigating options menu diff --git a/.changeset/chilly-shrimps-call.md b/.changeset/chilly-shrimps-call.md new file mode 100644 index 0000000000..392f34d8b2 --- /dev/null +++ b/.changeset/chilly-shrimps-call.md @@ -0,0 +1,7 @@ +--- +"@rhds/elements": minor +--- +``: add `link="private"` attribute, indicating that the link is +private, which changes the link icon from an arrow to a padlock, and +`link="external"` attribute, which changes the link icon to the "external link" +icon diff --git a/.changeset/dry-jobs-rest.md b/.changeset/dry-jobs-rest.md new file mode 100644 index 0000000000..9294f7da4a --- /dev/null +++ b/.changeset/dry-jobs-rest.md @@ -0,0 +1,11 @@ +--- +"@rhds/elements": minor +--- +`` added `--rh-card-header-background-on-light` and `--rh-card-header-background-on-dark` CSS custom properties + +```css +rh-card.custom-card { + --rh-card-header-background-on-light: cornflowerblue; + --rh-card-header-background-on-dark: darkblue; +} +``` diff --git a/.changeset/flat-bats-walk.md b/.changeset/flat-bats-walk.md new file mode 100644 index 0000000000..7aa5f18edf --- /dev/null +++ b/.changeset/flat-bats-walk.md @@ -0,0 +1,4 @@ +--- +"@rhds/elements": patch +--- +``: use theme tokens diff --git a/.changeset/forty-toes-exercise.md b/.changeset/forty-toes-exercise.md new file mode 100644 index 0000000000..5ee0ed4b2f --- /dev/null +++ b/.changeset/forty-toes-exercise.md @@ -0,0 +1,5 @@ +--- +"@rhds/elements": patch +--- + +``: Make ``'s bold. diff --git a/.changeset/gentle-rings-scream.md b/.changeset/gentle-rings-scream.md new file mode 100644 index 0000000000..211ac1c711 --- /dev/null +++ b/.changeset/gentle-rings-scream.md @@ -0,0 +1,5 @@ +--- +"@rhds/elements": patch +--- + +``: tables now adjust to the size of their containing element, not to the size of the viewport. \ No newline at end of file diff --git a/.changeset/giant-planets-argue.md b/.changeset/giant-planets-argue.md new file mode 100644 index 0000000000..7bb6becc29 --- /dev/null +++ b/.changeset/giant-planets-argue.md @@ -0,0 +1,5 @@ +--- +"@rhds/elements": patch +--- + +``: removed arrow-key keyboard navigation in favor of tab navigation. diff --git a/.changeset/gold-years-hang.md b/.changeset/gold-years-hang.md new file mode 100644 index 0000000000..9b63c21d74 --- /dev/null +++ b/.changeset/gold-years-hang.md @@ -0,0 +1,4 @@ +--- +"@rhds/elements": patch +--- +``: use official red hat icons diff --git a/.changeset/gorgeous-impalas-knock.md b/.changeset/gorgeous-impalas-knock.md new file mode 100644 index 0000000000..481b27b3b5 --- /dev/null +++ b/.changeset/gorgeous-impalas-knock.md @@ -0,0 +1,16 @@ +--- +"@rhds/elements": minor +--- + +``: + - removed arrow-key keyboard navigation in favor of tab navigation. + - add `accessible-label` attribute to explicitly label landmark. + - corrects overflow icons + + ``` + + Help + Contact Us + FAQ + + ``` diff --git a/.changeset/great-adults-hear.md b/.changeset/great-adults-hear.md new file mode 100644 index 0000000000..704268400c --- /dev/null +++ b/.changeset/great-adults-hear.md @@ -0,0 +1,14 @@ +--- +"@rhds/elements": minor +--- +``: syntax highlighting via prerendered prismjs code-blocks. Use +the `highlighting="prerendered"` attribute when rendering code blocks using +server side prism, e.g. in a markdown fenced code block. + +```html + +
a {
+  color: var(--rh-color-interactive-primary-default);
+  }
+
+``` diff --git a/.changeset/heavy-roses-poke.md b/.changeset/heavy-roses-poke.md new file mode 100644 index 0000000000..3a8a3690b8 --- /dev/null +++ b/.changeset/heavy-roses-poke.md @@ -0,0 +1,4 @@ +--- +"@rhds/elements": minor +--- +`` added `red-orange`, `yellow`, and `teal` colors. **NOTE** that `cyan` is now deprecated, but will continue to work using the `teal` colors. diff --git a/.changeset/khaki-rings-confess.md b/.changeset/khaki-rings-confess.md new file mode 100644 index 0000000000..0eb0e4e8e9 --- /dev/null +++ b/.changeset/khaki-rings-confess.md @@ -0,0 +1,5 @@ +--- +"@rhds/elements": minor +--- + +``: added auto-generated table cell headings for responsive layout on small screens. diff --git a/.changeset/large-geese-suffer.md b/.changeset/large-geese-suffer.md new file mode 100644 index 0000000000..b0a6379b94 --- /dev/null +++ b/.changeset/large-geese-suffer.md @@ -0,0 +1,5 @@ +--- +"@rhds/elements": patch +--- + +``: tabs now adjust to the size of their containing element, not to the size of the viewport. diff --git a/.changeset/mean-months-laugh.md b/.changeset/mean-months-laugh.md new file mode 100644 index 0000000000..69916444ad --- /dev/null +++ b/.changeset/mean-months-laugh.md @@ -0,0 +1,4 @@ +--- +"@rhds/elements": patch +--- +``: hide header when it is empty diff --git a/.changeset/olive-ghosts-push.md b/.changeset/olive-ghosts-push.md new file mode 100644 index 0000000000..e2051e5cca --- /dev/null +++ b/.changeset/olive-ghosts-push.md @@ -0,0 +1,4 @@ +--- +"@rhds/elements": patch +--- +``: add a playback control to the mini layout diff --git a/.changeset/rich-kangaroos-suffer.md b/.changeset/rich-kangaroos-suffer.md new file mode 100644 index 0000000000..94c4946796 --- /dev/null +++ b/.changeset/rich-kangaroos-suffer.md @@ -0,0 +1,5 @@ +--- +"@rhds/elements": patch +--- + +``: style some slotted links diff --git a/.changeset/rotten-bottles-suffer.md b/.changeset/rotten-bottles-suffer.md new file mode 100644 index 0000000000..294007c677 --- /dev/null +++ b/.changeset/rotten-bottles-suffer.md @@ -0,0 +1,8 @@ +--- +"@rhds/elements": minor +--- +``: added desaturated variant: + +```html +New +``` diff --git a/.changeset/seven-bats-grin.md b/.changeset/seven-bats-grin.md new file mode 100644 index 0000000000..d3a7c2ac21 --- /dev/null +++ b/.changeset/seven-bats-grin.md @@ -0,0 +1,8 @@ +--- +"@rhds/elements": minor +--- +``: added `size` attribute. + +```html +New +``` diff --git a/.changeset/shaggy-foxes-smoke.md b/.changeset/shaggy-foxes-smoke.md new file mode 100644 index 0000000000..ab1ae1ce9d --- /dev/null +++ b/.changeset/shaggy-foxes-smoke.md @@ -0,0 +1,5 @@ +--- +"@rhds/elements": patch +--- + +``: corrected layout when rendering some image slotted elements diff --git a/.changeset/short-maps-beg.md b/.changeset/short-maps-beg.md new file mode 100644 index 0000000000..c645750bab --- /dev/null +++ b/.changeset/short-maps-beg.md @@ -0,0 +1,6 @@ +--- +"@rhds/elements": minor +--- +``: added new states: `info`, `neutral`, and `caution`, and deprecated +`note` (now an alias to `info`), `default` (now an alias to `neutral`), and +`error` (now an alias to `danger`). diff --git a/.changeset/shy-taxis-knock.md b/.changeset/shy-taxis-knock.md new file mode 100644 index 0000000000..9e97495827 --- /dev/null +++ b/.changeset/shy-taxis-knock.md @@ -0,0 +1,4 @@ +--- +"@rhds/elements": patch +--- +``: now supports color [theming](https://ux.redhat.com/theming/) diff --git a/.changeset/six-toys-learn.md b/.changeset/six-toys-learn.md new file mode 100644 index 0000000000..b25f89ada0 --- /dev/null +++ b/.changeset/six-toys-learn.md @@ -0,0 +1,5 @@ +--- +"@rhds/elements": patch +--- + +``: allow tabs to participate in advanced layouts diff --git a/.changeset/slick-ants-cover.md b/.changeset/slick-ants-cover.md new file mode 100644 index 0000000000..aa65ae2c22 --- /dev/null +++ b/.changeset/slick-ants-cover.md @@ -0,0 +1,4 @@ +--- +"@rhds/elements": patch +--- +``: ensure link is always at top of the page, per guidelines diff --git a/.changeset/slimy-guests-rescue.md b/.changeset/slimy-guests-rescue.md new file mode 100644 index 0000000000..1c1f9469e6 --- /dev/null +++ b/.changeset/slimy-guests-rescue.md @@ -0,0 +1,9 @@ +--- +"@rhds/elements": minor +--- +``: add `icon-set` attribute, corresponding to `` + +```html +Donate +``` diff --git a/.changeset/sour-cloths-poke.md b/.changeset/sour-cloths-poke.md new file mode 100644 index 0000000000..c4dd869c29 --- /dev/null +++ b/.changeset/sour-cloths-poke.md @@ -0,0 +1,4 @@ +--- +"@rhds/elements": patch +--- +``: use `` for status indicators diff --git a/.changeset/swift-nails-notice.md b/.changeset/swift-nails-notice.md new file mode 100644 index 0000000000..eccc194d52 --- /dev/null +++ b/.changeset/swift-nails-notice.md @@ -0,0 +1,13 @@ +--- +"@rhds/elements": minor +--- + +``: + - removed arrow-key keyboard navigation in favor of tab navigation. + - add `accessible-label` attribute to explicitly label landmark. + + ``` + + ... + + ``` \ No newline at end of file diff --git a/.changeset/tall-bags-pipe.md b/.changeset/tall-bags-pipe.md new file mode 100644 index 0000000000..bdd54d7081 --- /dev/null +++ b/.changeset/tall-bags-pipe.md @@ -0,0 +1,17 @@ +--- +"@rhds/elements": minor +--- +``: added new states: + + * `danger` + * `warning` + * `caution` + * `neutral` + * `info` + +We deprecated: + + * `critical` (now an alias to `danger`) + * `important` (now an alias to `caution`) + * `moderate` (now an alias to `warning`) + * `note` (now an alias to `info`) diff --git a/.changeset/tall-corners-punch.md b/.changeset/tall-corners-punch.md new file mode 100644 index 0000000000..5845c05642 --- /dev/null +++ b/.changeset/tall-corners-punch.md @@ -0,0 +1,17 @@ +--- +"@rhds/elements": minor +--- +``: added optional `href` attribute: + +```html +Skip to main content +``` + +is equivalent to: + +```html + + Skip to main content + +``` + diff --git a/.changeset/tricky-windows-draw.md b/.changeset/tricky-windows-draw.md new file mode 100644 index 0000000000..ff7977089b --- /dev/null +++ b/.changeset/tricky-windows-draw.md @@ -0,0 +1,5 @@ +--- +"@rhds/elements": minor +--- + +``: Added `highlighting="client"` for client-side syntax highlighting with Red Hat colour scheme diff --git a/.changeset/wild-apples-enjoy.md b/.changeset/wild-apples-enjoy.md new file mode 100644 index 0000000000..571b66f43f --- /dev/null +++ b/.changeset/wild-apples-enjoy.md @@ -0,0 +1,9 @@ +--- +"@rhds/elements": minor +--- +``: added `href` attribute + +```html +Info +``` diff --git a/.changeset/wild-bulldogs-draw.md b/.changeset/wild-bulldogs-draw.md new file mode 100644 index 0000000000..41394f057f --- /dev/null +++ b/.changeset/wild-bulldogs-draw.md @@ -0,0 +1,28 @@ +--- +"@rhds/elements": minor +--- + +Theming: Added [theming tokens][theming] to most elements + +Theming tokens let authors respond to the currently-active colour palette, and +are especially useful when implementing [patterns][patterns] using themeable +elements. + +```html + +

Lorem ipsum dolor sit amet, consectetur adipiscing elit.

+ Call to action +
+ + +``` + +[theming]: ux.redhat.com/theming +[patterns]: https://ux.redhat.com/patterns/ diff --git a/.gitignore b/.gitignore index ddd8f128a9..c8d9a6a294 100644 --- a/.gitignore +++ b/.gitignore @@ -8,8 +8,9 @@ node_modules _site docs/pfe.min* docs/assets/playgrounds/ +docs/assets/javascript/elements/*.js.map +docs/assets/javascript/elements/*.d.ts docs/assets/javascript/elements/*.js -!docs/assets/javascript/elements/uxdot-pattern.js docs/_data/playgrounds.json # Build artifacts diff --git a/.pfe.config.json b/.pfe.config.json index 24499216d2..a37b6a7d91 100644 --- a/.pfe.config.json +++ b/.pfe.config.json @@ -16,7 +16,7 @@ "description": "Red Hat Design System", "componentSubpath": "elements", "stylesheets": [ - "/docs/styles/dev-server/styles.css" + "/docs/styles/demo/dev-server.css" ] } } diff --git a/.stylelintrc.yml b/.stylelintrc.yml index a03f0401fd..d7c764e0b1 100644 --- a/.stylelintrc.yml +++ b/.stylelintrc.yml @@ -2,8 +2,13 @@ extends: - stylelint-config-standard - '@stylistic/stylelint-config' +plugins: + - ./node_modules/@rhds/tokens/plugins/stylelint.js + - '@stylistic/stylelint-plugin' + ignoreFiles: - node_modules/**/* + - docs/assets/javascript/elements/*.js rules: alpha-value-notation: number # TODO: fix for `percentage` in tokens @@ -19,6 +24,7 @@ rules: - ignoreShorthands: - /grid/ + media-feature-range-notation: prefix number-max-precision: 6 no-descending-specificity: - true @@ -42,84 +48,25 @@ rules: - ignorePseudoElements: - /part(.*)/ - '@stylistic/string-quotes': double + '@stylistic/string-quotes': single '@stylistic/selector-combinator-space-after': always '@stylistic/selector-combinator-space-before': always + '@stylistic/function-parentheses-newline-inside': never-multi-line + '@stylistic/function-comma-newline-after': always-multi-line '@stylistic/indentation': - - 2 - - indentInsideParens: 'once-at-root-twice-in-block' + - 2 + - indentInsideParens: 'once-at-root-twice-in-block' '@stylistic/max-line-length': - 100 - - ignorePattern: /--rh-font-family-/ + - ignorePattern: /(--rh-font-family-|https:\/\/)/ + rhds/deprecated: true rhds/token-values: true rhds/no-unknown-token-name: - true - - migrations: - # reds - --rh-color-red-50: --rh-color-red-10 - --rh-color-red-100: --rh-color-red-20 - --rh-color-red-200: --rh-color-red-30 - --rh-color-red-300: --rh-color-red-40 - --rh-color-red-400: --rh-color-red-50 - --rh-color-red-500: --rh-color-red-50 - --rh-color-red-600: --rh-color-red-60 - --rh-color-red-700: --rh-color-red-60 - --rh-color-red-800: --rh-color-red-70 - # oranges - --rh-color-orange-50: --rh-color-orange-10 - --rh-color-orange-100: --rh-color-orange-30 - --rh-color-orange-300: --rh-color-orange-40 - --rh-color-orange-500: --rh-color-orange-60 - --rh-color-orange-700: --rh-color-orange-70 - # yellows (previously golds) - --rh-color-gold-50: --rh-color-yellow-10 - --rh-color-gold-400: --rh-color-yellow-40 - --rh-color-gold-600: --rh-color-yellow-70 - # greens - --rh-color-green-50: --rh-color-green-10 - --rh-color-green-100: --rh-color-green-20 - --rh-color-green-500: --rh-color-green-60 - --rh-color-green-600: --rh-color-green-70 - # teals (previously cyans) - --rh-color-cyan-50: --rh-color-teal-10 - --rh-color-cyan-100: --rh-color-teal-30 - --rh-color-cyan-300: --rh-color-teal-50 - --rh-color-cyan-400: --rh-color-teal-60 - --rh-color-cyan-500: --rh-color-teal-70 - # blues - --rh-color-blue-50: --rh-color-blue-10 - --rh-color-blue-100: --rh-color-blue-20 - --rh-color-blue-200: --rh-color-blue-30 - --rh-color-blue-250: --rh-color-blue-40 - --rh-color-blue-400: --rh-color-blue-50 - --rh-color-blue-500: --rh-color-blue-60 - --rh-color-blue-600: --rh-color-blue-70 - # purples - --rh-color-purple-50: --rh-color-purple-10 - --rh-color-purple-100: --rh-color-purple-20 - --rh-color-purple-300: --rh-color-purple-40 - --rh-color-purple-500: --rh-color-purple-60 - --rh-color-purple-700: --rh-color-purple-70 - # grays - --rh-color-gray-05: --rh-color-gray-10 - --rh-color-gray-10: --rh-color-gray-20 - --rh-color-gray-20: --rh-color-gray-30 - --rh-color-gray-30: --rh-color-gray-40 - --rh-color-gray-40: --rh-color-gray-50 - --rh-color-gray-50: --rh-color-gray-60 - --rh-color-gray-60: --rh-color-gray-70 - --rh-color-gray-70: --rh-color-gray-80 - --rh-color-gray-80: --rh-color-gray-90 - --rh-color-gray-90: --rh-color-gray-95 - --rh-color-black: --rh-color-gray-100 - - media-feature-range-notation: prefix - -plugins: - - ./node_modules/@rhds/tokens/plugins/stylelint.cjs - - '@stylistic/stylelint-plugin' + - allowed: + - --rh-icon-size overrides: - files: diff --git a/CHANGELOG.md b/CHANGELOG.md index aef1d6c393..c183b05d08 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -175,7 +175,7 @@ - fa2c4d2: ``: Removed previously-deprecated `color-palette` attribute - Use themable containers (e.g. `` or ``) instead. + Use themeable containers (e.g. `` or ``) instead. Before: diff --git a/declaration.d.ts b/declaration.d.ts index 8fb49f9bc2..f8afc5e132 100644 --- a/declaration.d.ts +++ b/declaration.d.ts @@ -3,10 +3,7 @@ declare module '*.css' { export default style; } -/** - * @see https://github.com/nonara/ts-patch/issues/93 - * @see https://github.com/cevek/ttypescript/issues/140 - */ -declare module '@rhds/tokens/media.js' { - export * from '@rhds/tokens/js/media.js'; +declare module 'prism-esm/plugins/line-numbers/prism-line-numbers.js' { + import type { Prism } from "prism-esm"; + export function Plugin(prism: Prism): void } diff --git a/docs/404.njk b/docs/404.njk index 465b133aec..d5b2b853c8 100644 --- a/docs/404.njk +++ b/docs/404.njk @@ -9,19 +9,19 @@ permalink: 404.html

This is embarrassing, we can’t find that page

Try one of these popular links instead

Contact us

-

If you feel that you reached this page in error, contact us and we'll point you in the right direction.

+

If you feel that you reached this page in error, contact us and we'll point you in the right direction.

Feedback or requests

diff --git a/docs/_data/relatedItems.yaml b/docs/_data/relatedItems.yaml index cdaaad1cb1..259c899855 100644 --- a/docs/_data/relatedItems.yaml +++ b/docs/_data/relatedItems.yaml @@ -104,7 +104,6 @@ rh-tabs: - rh-pagination - rh-progress-steps rh-tag: - - rh-avatar - rh-badge - rh-button rh-tile: diff --git a/docs/_data/repoStatus.yaml b/docs/_data/repoStatus.yaml index bb64bcc5fd..f41da38f18 100644 --- a/docs/_data/repoStatus.yaml +++ b/docs/_data/repoStatus.yaml @@ -423,7 +423,7 @@ - name: RH Elements status: Ready - name: RH Shared Libs - status: Ready + status: In Progress - name: Documentation status: Ready - tagName: rh-tile diff --git a/docs/_includes/layouts/base.njk b/docs/_includes/layouts/base.njk index fa131fd377..0867aad340 100644 --- a/docs/_includes/layouts/base.njk +++ b/docs/_includes/layouts/base.njk @@ -17,8 +17,8 @@ {% include "../partials/meta.html" %} - + {# On browsers that don't yet support native declarative shadow DOM, a paint can occur after some or all pre-rendered HTML has been parsed, @@ -45,7 +45,7 @@ - Skip to main content + Skip to main content {{ content | safe }} diff --git a/docs/_includes/layouts/demo.njk b/docs/_includes/layouts/demo.njk deleted file mode 100644 index d346800d5b..0000000000 --- a/docs/_includes/layouts/demo.njk +++ /dev/null @@ -1,26 +0,0 @@ - - - - - - - {{ demo.title or demo.tagName }} | Red Hat Design System - - - - - - - - - - {% if demo.filePath %} -
- {%- include demo.filePath -%} -
{%- else -%} -

No Demo. Open an issue!

{%- endif -%} - - - diff --git a/docs/_includes/layouts/pages/basic.njk b/docs/_includes/layouts/pages/basic.njk index 3258f6ee8e..d782e48fd5 100755 --- a/docs/_includes/layouts/pages/basic.njk +++ b/docs/_includes/layouts/pages/basic.njk @@ -1,39 +1,48 @@ --- layout: layouts/base.njk -importElements: - - rh-cta - - rh-footer - - rh-alert - - rh-subnav - - rh-tag --- - + - + {%- if tokenSearch %} - - + + {%- endif %} {% include 'partials/component/masthead.njk' %} {% include 'partials/component/sidenav.njk' %} -
-
0 %}class="has-toc"{% endif %}> +{%- if hasToc -%} + {%- set tagsForThisPageToc = tocTags or ['h2'] -%} + {%- set table = content | toc(tags=tagsForThisPageToc) -%} +{%- endif -%} + + +
0 }}> {% include 'partials/component/header.njk' %} - {% if hasToc and (content | toc).length > 0 %} -
- - {{ content | toc | safe }} - -
+ + {% if table.length > 0 %} + + {{ table | safe }} + {% endif %}
{{ content | safe }} + {% include "partials/component/edit-this-page.njk" %}
- +
{% include "partials/component/back-to-top.njk" %} -
+ {% include 'partials/component/footer.njk' %} diff --git a/docs/_includes/layouts/pages/elements.njk b/docs/_includes/layouts/pages/elements.njk index c7ccfc5373..39b54829b1 100644 --- a/docs/_includes/layouts/pages/elements.njk +++ b/docs/_includes/layouts/pages/elements.njk @@ -3,26 +3,22 @@ layout: layouts/base.njk eleventyComputed: slug: '{{ doc.slug or element.slug }}' title: "{{ doc.pageTitle }} | {{ slug | deslugify }}" - importElements: - - rh-alert - - rh-cta - - rh-footer - - rh-subnav - - rh-code-block - - rh-table - - rh-accordion - - rh-badge - - rh-tag - - "{{ doc.tagName or element.tagName }}" --- +{%- set inProgress = doc.docsPage.manifest -%} +{%- set prettyName -%}{{ (doc.alias or doc.slug or element.slug) | deslugify }}{% endset %} +{%- set planned = isPlanned(repoStatus, prettyName) %} +{%- set manifest = doc.docsPage.manifest -%} +{%- set tagName = doc.tagName or element.tagName -%} +{%- set demos = manifest and manifest.getDemos(doc.docsPage.tagName) -%} +{%- set demosUrl -%}/elements/{{ slug }}/demos/{%- endset -%} + {% if doc.pageTitle == 'Code' %} - + {% endif %} - - + {%- if slug == 'audio-player' %} - -
- `} - `); - }); }; + diff --git a/docs/_plugins/tokensHelpers.cjs b/docs/_plugins/tokensHelpers.cjs index 72c9d64bc0..eaa5648a81 100644 --- a/docs/_plugins/tokensHelpers.cjs +++ b/docs/_plugins/tokensHelpers.cjs @@ -1,76 +1,37 @@ -// @ts-check -const { join } = require('node:path'); -const { readFile } = require('node:fs/promises'); +const tokensJSON = require('@rhds/tokens/json/rhds.tokens.json'); +const { tokens: tokensMeta } = require('@rhds/tokens/meta.js'); -const getDocs = (x, options) => x?.$extensions?.[options.docsExtension]; const capitalize = x => `${x.at(0).toUpperCase()}${x.slice(1)}`; -/** Returns a string with common indent stripped from each line. Useful for templating HTML */ -function dedent(str) { - const stripped = str.replace(/^\n/, ''); - const match = stripped.match(/^\s+/); - return match ? stripped.replace(new RegExp(`^${match[0]}`, 'gm'), '') : str; -} +/* eslint-disable jsdoc/check-tag-names */ +/** @typedef {Exclude, undefined|null>} DesignToken */ +/* eslint-enable jsdoc/check-tag-names */ -/** HTML attribute values should use single quotes to avoid breaking out of the value's surrounding double quotes */ +/** + * HTML attribute values should use single quotes to avoid breaking out of the value's surrounding double quotes + * @param {string} x + */ function escapeDoubleQuotes(x) { return x?.toString().replaceAll('"', '\''); } -/** Converts an object mapping css property names to values into a CSS rule for inlining into HTML */ -function styleMap(objt) { - return Object.entries(objt).map(([k, v]) => `${k}: ${escapeDoubleQuotes(v)}`).join(';'); -} - -/** When recursing over the token categories, it's helpful to get the containing category for things like docs and key names */ +/** + * When recursing over the token categories, it's helpful to get the containing category for things like docs and key names + * @param {object} options + * @param {DesignToken[]} tokens + */ function getParentCollection(options, tokens) { - let parent = options.parent ?? tokens; - - let collection; - + const parent = options.parent ?? tokens; const key = options.path.split('.').pop(); - options.path.split('.').forEach((part, i, a) => { - collection = parent[part]; - if (a[i + 1]) { - parent = collection; - } - }); - return { parent, key }; } -/** Try to get the path to a token source file. Not all object values in a token collection have that metadata attached */ -function getFilePathGuess(collection) { - return Object.values(collection).reduce((path, val) => - path || typeof val !== 'object' ? path - : '$value' in val ? val.filePath - : getFilePathGuess(val), ''); -} - -/** Get the markdown description in a category's docs extension */ -function getDescription(collection, options) { - const { - filePath = getFilePathGuess(collection), - description = '', - descriptionFile, - } = getDocs(collection, options) ?? {}; - - if (description) { - return description; - } else if (descriptionFile) { - return readFile(join(process.cwd(), filePath, '..', descriptionFile), 'utf-8'); - } else { - return ''; - } -} - -/** @typedef {ReturnType} DesignToken */ -/** @typedef {import('custom-elements-manifest').CssCustomProperty} CssCustomProperty */ /** @param {DesignToken|CssCustomProperty} token*/ function getVariableSyntax(token) { return `var(--${token.name}, ${escapeDoubleQuotes(token.$value ?? token.default)})`; } +/** @param {DesignToken} token*/ function copyCell(token) { const variable = getVariableSyntax(token); return /* html */` @@ -80,9 +41,10 @@ function copyCell(token) { - `; + `.trim(); } +/** @param {DesignToken} token */ function getTokenCategorySlug(token) { const name = `--${token.name}`.replace('----', '--'); const data = require('@rhds/tokens/meta.js').tokens.get(name); @@ -93,19 +55,64 @@ function getTokenCategorySlug(token) { } } +/** @param {DesignToken} token */ function getTokenHref(token) { return `https://ux.redhat.com/tokens/${getTokenCategorySlug(token)}/#${token.name}`; } +/** @param {string} path */ +function resolveTokens(path) { + let tokens = tokensJSON; + for (const part of path.split('.')) { + tokens = tokens[part]; + } + return tokens; +} + +/** @param {DesignToken} x */ +const getDocs = x => x?.$extensions?.['com.redhat.ux']; + +/** + * Returns a string with common indent stripped from each line. Useful for templating HTML + * @param {string} str + */ +function dedent(str) { + const stripped = str.replace(/^\n/, ''); + const match = stripped.match(/^\s+/); + return match ? stripped.replace(new RegExp(`^${match[0]}`, 'gm'), '') : str; +} + +/** @param {DesignToken} token */ +const isThemeColorToken = token => + token.$type === 'color' && Array.isArray(token.original?.$value); + +/** + * Converts an object mapping css property names to values into a CSS rule for inlining into HTML + * @param {object} objt + */ +function styleMap(objt) { + return Object.entries(objt) + .map(([k, v]) => `${k}: ${escapeDoubleQuotes(v)}`) + .join(';'); +} + +/** @param {object} classInfo */ +function classMap(classInfo) { + return Object.keys(classInfo) + .filter(key => classInfo[key]) + .join(' '); +} + module.exports = { capitalize, copyCell, - dedent, - escapeDoubleQuotes, - getDescription, - getDocs, getParentCollection, getTokenHref, getVariableSyntax, + resolveTokens, + getDocs, + dedent, + isThemeColorToken, styleMap, + classMap, }; diff --git a/docs/about/how-we-build.md b/docs/about/how-we-build.md deleted file mode 100644 index 2cc31dabe8..0000000000 --- a/docs/about/how-we-build.md +++ /dev/null @@ -1,180 +0,0 @@ ---- -layout: layouts/pages/basic.njk -title: How we build -order: 10 -hasToc: true -tags: - - about -importElements: - - rh-table ---- - - - - -## Building experiences for the web - -The Red Hat Design System (RHDS) allows designers and developers across different teams to build branded experiences consistently. Based on the foundations of PatternFly and the Red Hat Brand Standards, our design system reflects the Red Hat brand digitally. - - -## Foundations - -The Red Hat brand has a strong voice. To make our design system feel like Red Hat, we use foundations like color, space, and typography to enhance our components, and use icons and illustrations to enhance our layouts. Our end goal is to elevate the Red Hat brand across our digital properties. - - -
- - -## PatternFly - -PatternFly is the open source design system for Red Hat products, it is also the foundation for our components. We share design when possible by contributing ideas back to PatternFly to help grow its capabilities. When building a new component or updating an existing component, PatternFly is always our first source of inspiration. - -PatternFly can be used by designers and developers inside and outside of Red Hat. PatternFly is used to create React applications and provide HTML and CSS assets for other web projects. The Red Hat Design System is used to create Red Hat-branded websites or other digital properties. We collaborate with the Red Hat User Experience Design (UXD) team as they build user interface components for PatternFly. - -By sharing ideas between the PatternFly and RHDDS teams, we create a design language across all of Red Hat, for each stage of the customer lifecycle. - - - Visit PatternFly - - - -
- Example PatternFly components -
Examples of PatternFly components
-
-
- - -## PatternFly Elements - -The PatternFly Elements (PFE) project leverages the PatternFly design system and some code elements to create an accessible and open source web component library. Web components, or native custom HTML tags, allow users to easily include design system foundations and components across their websites and applications. - -PFE components not only work in any application framework, they are evergreen, meaning the components themselves can be upgraded easily which allows for consistency, scalability, and flexibility. PFE components are used across many of the core Red Hat websites, including redhat.com, access.redhat.com, developers.redhat.com, connect.redhat.com, and more. - - - Visit PatternFly Elements - -
- -
- Example PFE components -
Examples of PFE components that are not themed
-
-
- -
- Example PFE components -
Examples of PFE components themed with Red Hat CSS variables
-
-
-
- - -## Visual examples - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Design systemImplementationExample
- PatternFly - - PatternFly components - Example PatternFly components
- PFE - - PFE components - Example PFE components
- PFE + RHDDS - - PFE components themed with Red Hat CSS variablesExample PFE components with Red Hat CSS variables
-
- - -
-
-

WebRH

-

WebRH is an asset library of components and patterns created within Red Hat Marketing. The goal was to bring consistency to redhat.com and now other Red Hat web properties that are built on Drupal. These patterns are leveraged by Drupal through tools that make up the Flexible Template System.

WebRH contains components and patterns including JSON schemas, Twig templates (to be used in Drupal), custom CSS, and PFE web components. WebRH creates flexible patterns within Drupal so content editors can create visually-consistent experiences with unstructured data or content.

A copy of the WebRH library is viewable within the Schema Editor and allows anyone to build and test new and existing patterns through a user interface similar to FTS in Drupal.

- - Learn more about WebRH - -
-
- -
- WebRH screenshot -
Example of a WebRH pattern being customized in the Schema Editor (formerly Patternkit)
-
-
-
-
- -
-
-

Flexible Template System

-

The Flexible Template System (FTS) refers to the authoring tools and patterns used to build pages within the Drupal CMS. Fields for content and settings that control design and layout are exposed to content editors which simplifies the page building process. Using patterns enables authors to have flexibility with page layout and design without having to write code. Various patterns from the WebRH library are loaded inside Drupal based on the content type. Different content types have different purposes and use different patterns. The Flexible template content type is for general use.

In Drupal 7, WebRH patterns are built with a local version of Patternkit and then imported into Drupal with the Pattern Builder module.

In Drupal 8+, the Patternkit module will fetch the WebRH patterns via PatternAPI, a services layer which dynamically pulls the appropriate pattern by name and version.

- - Learn more about FTS - -
-
- -
- FTS screenshot -
Example of an FTS pattern being customized in Drupal
-
-
-
-
- - -## Patternkit - -Patternkit 2.x is a Drupal 8+ module that connects libraries like WebRH to content management systems like Drupal. It leverages the JSON Schema Editor to expose the fields defined within the component and pattern schemas, so content authors can add content and change settings while seeing the results in real time. - -Patternkit 1.x is used by developers to develop, test, and demo WebRH patterns. The WebRH Schema Editor (formerly known as Patternkit) is a playground to interact with the WebRH pattern library. It is hosted on OpenShift and is updated every three weeks to show the latest updates to WebRH. - - - Learn more about Patternkit - - - -## WebDMS - -WebDMS is a custom Bootstrap 4 implementation that allows for rapid development, a very short learning curve, and immense flexibility. It is custom development for projects with outside-of-the-box design, interactivity, engagement, and motion needs. Because of the flexibility and fast iteration speed, we are able to test new designs and then solidify them into FTS patterns if we find that they are used across multiple pages. - - -
- Example of WebDMS patterns showing hybrid cloud - Example of WebDMS patterns showing implementation of jumplinks -
Examples of WebDMS applied on top of the Red Hat Design System
-
-
- - - -

Other resources

-

To learn how to use our design system kit and libraries, visit this page.

-
diff --git a/docs/about/index.md b/docs/about/index.md index 0fd4aaf3fa..a5499b9a17 100644 --- a/docs/about/index.md +++ b/docs/about/index.md @@ -6,177 +6,158 @@ tags: - about --- - - #fundamentals h3 { - margin-block: var(--rh-space-2xl, 32px); - } + +
- :is(#approach, #fundamentals) .item { - display: flex; - flex-direction: column; +## We create Red Hat digital experiences - justify-content: center; - } +Red Hat teams work across the world in a range of disciplines, from UX research +and digital design to web development and content strategy. The Red Hat Design +System (RHDS) for digital experiences allows designers and developers to build +branded user experiences consistently and to make every digital interaction with +Red Hat reflect our core brand traits: open, authentic, helpful, and brave. - #approach .item:nth-child(1) { - order: 1; - } +
- #approach .item:nth-child(2) { - order: 2; - } +## We’re guided by our core principles - #approach .item:nth-child(3) { - order: 4; - } +
+ + +

User-centered

+

We focus on the people for which we are designing, and this advocacy extends beyond the customer to include the experience of Red Hat associates.

+
+ + +

Co-creative

+

UX design is a team sport. Many people both within Red Hat, and with outside feedback, contribute to creating the user experience.

+
+ + +

Holistic

+

We consider the end-to-end experience, not just a single moment, single website, service encounter, or journey stage.

+
+ + +

Orchestrated

+

Processes, tools, and roles must be aligned to deliver and maintain an optimal Red Hat digital experience

+
+
- #approach .item:nth-child(4) { - order: 3; - } +## We rely on our foundations - #approach .item:nth-child(5) { - order: 5; - } +The Red Hat brand has a strong voice. To make our design system feel like Red +Hat, we use foundations like [color](/foundations/color/), +[space](/foundations/spacing/), and [typography](/foundations/typography/) to +enhance our elements and patterns and to align them to Red Hat’s [design +language standards](https://www.redhat.com/en/about/brand/standards). - #approach .item:nth-child(6) { - order: 6; - } +### Red Hat brand standards - #approach .item:nth-child(7) { - order: 8; - } +Red Hat brand standards are the source code for our identity. They govern how we +look and sound in all types of media. We follow brand standards to unify Red Hat +digital experiences and stay up-to-date with our brand as it grows, improves, +and adapts to meet new challenges. - #approach .item:nth-child(8) { - order: 7; - } +Learn about the Red Hat brand - :is(#approach, #fundamentals) .item p { - font-size: var(--rh-font-size-body-text-lg, 1.125rem); - } + + the words 'brand standards' framed by elements and shapes in ReEd Hat colors + - #approach .item h3 { - margin-block-start: 0; - } +### Design tokens - #approach .item img { - width: 100%; - } +Our foundations are implemented through design tokens, which are used in lieu of +hard-coded values for color, text attributes, spacing, and more. Tokens help us +keep web components flexible and scalable. Additionally, semantic token names +help us assign consistent meanings that correspond with foundational guidelines. - #fundamentals .grid { - margin-block-end: var(--rh-space-4xl, 64px); - } +Learn about our tokens - #fundamentals { - text-align: center; - } + + Flow showing how a color like brand red becomes a token, how it is named, and how it is applied to a call to action + - #fundamentals .item { - text-align: left; - } +## We build Web Components - #fundamentals .item img { - max-width: 70px; - } +Our team is building an open source, Web Component-driven development system to +build scalable UI elements and patterns. By using Web Components, it allows +developers to use our code with encapsulated functionality and styles in any +framework or platform. - hr { - margin-block: var(--rh-space-5xl, 80px); - } +Learn about the benefits of Web Components - @container container (min-width: 576px) { - #approach .item:nth-child(n) { - order: unset; - } - } - + + Example of a card next to the Web Component's code + - - - -

We create Red Hat digital experiences

-

Our teams work across the world in a range of disciplines, from UX research and digital design to web development and content strategy. We collaborate to make every digital interaction with Red Hat reflect our core brand traits which are open, authentic, helpful, and brave.

-
- -
- -
-

Our approach

- -
-
-

Brand standards

-

Red Hat brand standards are the source code for our identity. They govern how we look and sound in all types of media. We follow brand standards to unify Red Hat digital experiences and stay up-to-date with our brand as it grows, improves, and adapts to meet new challenges.

-
-
- Red Hat brand standards -
-
- PatternFly -
-
-

PatternFly collaboration

-

We collaborate with PatternFly, an open source design system for enterprise product experiences. Using PatternFly as a foundation, we create intuitive and scalable Red Hat digital experiences the open source way.

-
-
-

Shared language and vision

-

We leverage similar elements as PatternFly, so designers no longer need to reinvent the wheel when choosing components. For example, an Accordion used in a Red Hat web application will look the same when used on a website.

-
-
- Shared language -
-
- Web components -
-
-

Web components

-

Our team is building an open source web component-driven development system to build scalable UI elements. This open source community project supports many components in our design system.

-
-
-
+## We look for opportunities to align -
- -
-

Fundamentals

-
-
- Flexibility -

Flexible

-

Our components can be arranged in a number of ways and CSS variables can be used for further customization.

-
-
- Accessibility -

Accessible

-

The goal of our design system is to create meaningful experiences that work for everyone, regardless of ability.

-
-
- Consistency -

Consistent

-

Our documentation and tools streamline collaboration so teams can create consistent and on-brand experiences.

-
-
- Scalability -

Scalable

-

Our system enables teams to work concurrently across the Red Hat system of websites and beyond.

-
-
- - Get started - -
+### PatternFly + +In addition to RHDS, Red Hat uses PatternFly, an open source design system, for +its products. We share design and foundations when possible by collaborating +with the PatternFly team. When building a new component or updating an existing +component, PatternFly is always our first source of inspiration.  + +By sharing ideas between the PatternFly and RHDS teams, we create a design +language across all of Red Hat, for each stage of the customer lifecycle. + +Visit PatternFly + +### PatternFly Elements + +The PatternFly Elements (PFE) project leverages the PatternFly design system and +some code elements to create an accessible and open source Web Component +library.  + +Like RHDS Web Components, PFE Web Components not only work in any application +framework, they are evergreen. This means that the components themselves can be +upgraded easily, allowing for consistency, scalability, and flexibility. + +Visit PatternFly Elements + + + A back-to-top element that looks the same in RHDS, PatternFly, and PatternFly Elements + + +## We provide support + +Whether you are implementing an element or pattern or contributing to the design +system, the RHDS team is here to help. Our [Design/code status][dcs] table shows +where everything is available, including whether they’ve been added to the Red +Hat Shared Libraries, which makes our Web Components ready for use in Drupal, +React, plain HTML, and other frameworks. We also have multiple ways for you to +reach our team about bugs, feature requests, and more. + +Get support + + +

Release Notes

+

To see what foundations, tokens, elements, or patterns have been released recently, check out our release notes.

+
+ +[dcs]: /design-code-status/ diff --git a/docs/about/roadmap.md b/docs/about/roadmap.md index 02d35a675e..8081de118c 100644 --- a/docs/about/roadmap.md +++ b/docs/about/roadmap.md @@ -9,7 +9,7 @@ importElements: - rh-tile --- - + ## Overview @@ -59,23 +51,23 @@ Wherever meaningful images or other non-text elements are used on a page, you mu Images loaded via the `` element typically use the alt attribute for their alternative text: - - - +```html rhcodeblock +Description of image +``` Inline SVGs that compose simple images commonly use a combination of the `role="img"` attribute and a `` element as the first child of the `<svg>` element: -<rh-code-block> - <script type="text/html"><svg role="img"> +```html rhcodeblock +<svg role="img"> <title>Description of image - -
+ +``` Other non-text elements (e.g., ASCII emoticons) may use ARIA attributes, like `aria-label` or `aria-labelledby`: - - - +```html rhcodeblock +:O +``` These are not the only means of providing alt text for non-text elements, but they cover many common situations. For less-common cases, view the [WCAG 2.1 documentation](https://www.w3.org/WAI/WCAG21/Understanding/non-text-content.html). @@ -105,7 +97,7 @@ Note that background images inserted into a page via CSS are always considered d When writing alternative text, it’s important to first consider the image’s context. An image’s meaning or function may be more relevant than its literal depiction. So, the same image may need very different alt text in different contexts. - + George Bailey hugs his wife, Mary, and holds his daughter, Zuzu, in the movie It's a Wonderful Life @@ -115,46 +107,49 @@ Depending on whether a web page is about the plot of the 1946 movie It’s a Won Images acting as buttons or links are functional, and thus serve different purposes than images supporting the surrounding text. -
- Red Hat homepage +
+ + Red Hat homepage +
If the above image supplements the text of an article about Red Hat or our products, the appropriate alt text could be something like `"Red Hat, Inc. logo."` But if that image is a link pointing to the corporate homepage, you might want something along the lines of `"Red Hat homepage"` for your alt text: - - - + +``` ### Grouped images Grouped images that convey a single meaning (e.g., movie rating stars), can be grouped within an element with a single label (e.g., aria-label) that describes the meaning of the entire group. - - - + +``` Or the first element of the group can have alt text, while the others are hidden: - - - + +``` ### Embedded media (and other non-text) titles Though the techniques may vary, meaningful embedded media objects require text alternatives—just like images do. This applies to `
- ### Alignment The icon and the link are always vertically-aligned. @@ -87,12 +79,10 @@ The icon and the link are always vertically-aligned. Link with icon alignment
- ## Interaction states The link has the same interaction states as a Link whereas the icon doesn't have any interaction states. - ## Spacing Link with icon uses [space tokens](/tokens/space/) to define spacing values between elements. @@ -102,10 +92,7 @@ Link with icon uses [space tokens](/tokens/space/) to define spacing values betw -{% spacerTokensTable - tokens="--rh-space-lg" %} -{% endspacerTokensTable %} +{% spacerTokensTable tokens="--rh-space-lg" %}{% endspacerTokensTable %} - {% include 'partials/component/feedback.html' %} diff --git a/docs/patterns/link/index.md b/docs/patterns/link/index.md index 105c3b6568..d3ec997e50 100644 --- a/docs/patterns/link/index.md +++ b/docs/patterns/link/index.md @@ -7,8 +7,8 @@ tags: - pattern --- - - + + ## Overview @@ -27,7 +27,7 @@ Links are navigational elements that allow a user to move between content, pages View a live version of the Call to action link and see how it can be customized. -Customize component via Elements +Customize component via Elements ## Style diff --git a/docs/patterns/logo-wall/examples.md b/docs/patterns/logo-wall/examples.md index 4f4dff4a36..c02d365167 100644 --- a/docs/patterns/logo-wall/examples.md +++ b/docs/patterns/logo-wall/examples.md @@ -15,31 +15,31 @@ importElements: - rh-surface --- - - - + + ## Within a promo band (bordered) -{% uxdotPattern stacked=true, css='./logo-wall-lightdom.css' %} +{% uxdotPattern stacked=true, css='./logo-wall-lightdom.css', target="example-1x1-grid" %} {% include './patterns/1x1-grid.html' %} {% enduxdotPattern %} ## Within a promo band (borderless) -{% uxdotPattern stacked=true, css='./logo-wall-lightdom.css' %} +{% uxdotPattern stacked=true, css='./logo-wall-lightdom.css', target="example-1x1-grid-flat" %} {% include './patterns/1x1-grid-flat.html' %} {% enduxdotPattern %} ## With 2x2 grid -{% uxdotPattern stacked=true, css='./logo-wall-lightdom.css' %} +{% uxdotPattern stacked=true, css='./logo-wall-lightdom.css', target="example-2x2-grid" %} {% include './patterns/2x2-grid.html' %} {% enduxdotPattern %} ## With 2x3 grid -{% uxdotPattern stacked=true, css='./logo-wall-lightdom.css' %} +{% uxdotPattern stacked=true, css='./logo-wall-lightdom.css', target="example-2x3-grid" %} {% include './patterns/2x3-grid.html' %} {% enduxdotPattern %} diff --git a/docs/patterns/logo-wall/guidelines.md b/docs/patterns/logo-wall/guidelines.md index d21b1598f7..5f18b2268b 100644 --- a/docs/patterns/logo-wall/guidelines.md +++ b/docs/patterns/logo-wall/guidelines.md @@ -78,6 +78,34 @@ When displaying our partners' logos, it is essential to respect their brand iden +### Art Direction + +When alternating graphics depending on the color palette, You should be careful select +only the themable container which is the direct ancestor of the logo wall. + +
+ + + Examples of two Red Hat logos in dark and light themes against background colors that ensure enough color contrast. + +

Ensure that the color contrast between each logo and the background meets accessibility standards.

+
+ + + + Examples of two Red Hat logos in dark and light themes against background colors that do not provide enough contrast. + +

Place a logo over a background that does not meet accessibility standards.

+
+
+ +See [theming developer docs](/theming/developers/) for more information. + +`` Planned is expected to help +with this case + ### Logo sizes
diff --git a/docs/patterns/logo-wall/logo-wall-lightdom.css b/docs/patterns/logo-wall/logo-wall-lightdom.css index e59d12e902..048894cc2a 100644 --- a/docs/patterns/logo-wall/logo-wall-lightdom.css +++ b/docs/patterns/logo-wall/logo-wall-lightdom.css @@ -32,6 +32,10 @@ padding: var(--rh-space-lg, 16px); } +.logo-wall--borderless > * { + padding: var(--rh-space-lg, 16px) var(--rh-space-md, 8px); +} + .logo-wall--bordered > *:hover { background-color: var(--rh-color-gray-10, #f2f2f2); cursor: pointer; @@ -44,7 +48,7 @@ .logo-wall > * a:after { z-index: 3; - content: ""; + content: ''; position: absolute; inset: 0; display: block; @@ -56,26 +60,22 @@ min-height: var(--logo-wall-logo-min-height); } -[color-palette^="dark"] .logo-wall--bordered > :hover { +[color-palette^='dark'] .logo-wall--bordered > :hover { background-color: var(--rh-color-gray-60, #4d4d4d); } -[color-palette^="dark"] .logo-wall--bordered > :is(:focus, :active) { +[color-palette^='dark'] .logo-wall--bordered > :is(:focus, :active) { background-color: var(--rh-color-gray-60, #4d4d4d); } -[color-palette^="dark"] .logo-wall--light { +[color-palette^='dark'] > .logo-wall-container .logo-wall--light { display: none; } -[color-palette^="light"] .logo-wall--dark { +[color-palette^='light'] > .logo-wall-container .logo-wall--dark { display: none; } -.logo-wall--borderless > * { - padding: var(--rh-space-lg, 16px) var(--rh-space-md, 8px); -} - .logo-wall--borderless > :hover { box-shadow: 0 3px var(--rh-color-accent-brand-on-light, #ee0000); } @@ -104,13 +104,6 @@ } } -@container logo-wall-container (min-width: 992px) { - .logo-wall { - flex-wrap: nowrap; - max-width: var(--logo-wall-container-max-width, 1070px); - } -} - @container logo-wall-container (min-width: 1200px) { .logo-wall { max-width: none; diff --git a/docs/patterns/logo-wall/patterns/1x1-grid-flat.html b/docs/patterns/logo-wall/patterns/1x1-grid-flat.html index e54baf8d7a..a80af76668 100644 --- a/docs/patterns/logo-wall/patterns/1x1-grid-flat.html +++ b/docs/patterns/logo-wall/patterns/1x1-grid-flat.html @@ -1,4 +1,4 @@ -
+
Organizations succeeding with Red Hat
@@ -28,13 +28,13 @@
Organizations succeeding with Red Hat
See all customer stories -
+ diff --git a/docs/patterns/logo-wall/patterns/1x1-grid.html b/docs/patterns/logo-wall/patterns/1x1-grid.html index d57a4589d6..fb7b2b5092 100644 --- a/docs/patterns/logo-wall/patterns/1x1-grid.html +++ b/docs/patterns/logo-wall/patterns/1x1-grid.html @@ -1,4 +1,4 @@ -
+
Organizations succeeding with Red Hat
@@ -29,12 +29,12 @@
Organizations succeeding with Red Hat
See all customer stories
-
+ diff --git a/docs/patterns/logo-wall/patterns/2x2-grid.html b/docs/patterns/logo-wall/patterns/2x2-grid.html index 710dff9b3b..07be007d23 100644 --- a/docs/patterns/logo-wall/patterns/2x2-grid.html +++ b/docs/patterns/logo-wall/patterns/2x2-grid.html @@ -1,4 +1,4 @@ -
+

Need a business partner?

In the digital transformation journey we’re on, there’s a lot of change. There’s a need to reach markets quickly. And to do that we need productive developers who are able to get ideas into production safely, in a day, every day.

@@ -24,21 +24,19 @@

Need a business partner?

-
+ diff --git a/docs/patterns/logo-wall/patterns/2x3-grid.html b/docs/patterns/logo-wall/patterns/2x3-grid.html index 62f04f870c..8aa4be5393 100644 --- a/docs/patterns/logo-wall/patterns/2x3-grid.html +++ b/docs/patterns/logo-wall/patterns/2x3-grid.html @@ -1,4 +1,4 @@ -
+

Need a business partner?

In the digital transformation journey we’re on, there’s a lot of change. There’s a need to reach markets quickly. And to do that we need productive developers who are able to get ideas into production safely, in a day, every day.

@@ -32,16 +32,15 @@

Need a business partner?

- + diff --git a/docs/patterns/search-bar/index.md b/docs/patterns/search-bar/index.md index 06f56efaca..9985e400e7 100644 --- a/docs/patterns/search-bar/index.md +++ b/docs/patterns/search-bar/index.md @@ -5,34 +5,35 @@ layout: layouts/pages/basic.njk hasToc: true tags: - pattern +spacerTokens: + - --rh-space-sm + - --rh-space-md + - --rh-space-lg --- - - + + ## Overview A Search bar is a horizontal grouping of a form field with placeholder text and a button. It allows a user to input text and then perform a search. - ## Sample pattern - Search bar component sample + Search bar component sample - ## Style A search bar includes a narrow but wide form field with placeholder text and a red button that is placed on the right. - Search bar component blueprint + Search bar component blueprint - #### Button A search bar includes a button so a user can perform a search. A call to action @@ -41,14 +42,15 @@ search, so a button must be used instead.

Learn more

-

Visit the Button or Call to action element pages to learn more about how to use buttons and calls to action.

+

Visit the Button or Call to action element pages to learn + more about how to use buttons and calls to action.

- Search bar component button vs. CTA + Search bar component button vs. CTA - ## Theme #### Light theme @@ -56,19 +58,17 @@ search, so a button must be used instead. The light theme search bar includes a light theme form field and red button. - Search bar component, light theme + Search bar component, light theme - #### Dark theme For now, the light theme search bar can also be used in the dark theme. - Search bar component, dark theme + Search bar component, dark theme - ## Usage A search bar is best used to give a user the ability to search for something and @@ -80,10 +80,9 @@ A search bar can be used in most layouts. It has no set width other than the boundaries of whatever container or grid it is placed in. - Search bar component usage + Search bar component usage - #### Content The text within a search bar indicates how wide or narrow a search will be. If @@ -92,10 +91,9 @@ search through an entire website. If the text is *specific* (Search all resources), a user might expect to search through an individual page. - Search bar component placeholder text options + Search bar component placeholder text options - ## Behavior #### Form field @@ -107,14 +105,13 @@ change.

Learn more

-

Visit the Form pattern page to learn more about form fields.

+

Visit the Form pattern page to learn more about form fields.

- Search bar component styling changes + Search bar component styling changes - #### Typeahead Typeahead allows a user to narrow down a displayed list of options when they @@ -122,10 +119,9 @@ input text within a form field, it is recommended for lists with more than 10 options. - Search bar component typeahead + Search bar component typeahead - #### Errors If focus is moved from the form field to the button, an error will not be @@ -134,38 +130,36 @@ form field, an error will be displayed.

Learn more

-

Visit the Form pattern page to learn more about form field errors.

+

Visit the Form pattern page to learn more about form field errors.

- Search bar component form field errors + Search bar component form field errors - ## Interaction states

Learn more

-

Visit the Form or Button pages to learn more about interaction states.

+

Visit the Form or Button pages to learn more about interaction + states.

- #### Link - Search bar component interaction state, link + Search bar component interaction state, link - #### Hover A blue line appears at the bottom of the form field indicating it is selectable. - Search bar component interaction state, hover + Search bar component interaction state, hover - #### Focus When the focus is moved to the form field via keyboard, the placeholder text @@ -173,10 +167,9 @@ will disappear and a blinking cursor will take its place. When the focus is moved away, the placeholder text will be visible again. - Search bar component interaction state, focus + Search bar component interaction state, focus - #### Active When the focus is moved to the form field via cursor, the placeholder text will @@ -184,10 +177,9 @@ disappear and a blinking cursor will take its place. When the focus is moved away, the placeholder text will be visible again. - Search bar component interaction state, active + Search bar component interaction state, active - #### Tab order When the Tab key is pressed repeatedly, the focus will highlight the form field @@ -195,10 +187,9 @@ first and then the button. A user can move the focus from the form field to the button without an error being displayed. - Search bar component tab order + Search bar component tab order - ## Accessibility @@ -230,7 +221,6 @@ button without an error being displayed. - ## Responsive design A search bar mostly remains the same on large and small screens. While it can @@ -240,24 +230,21 @@ whereas the button always stays the same size. #### Desktop - Search bar component responsive design, desktop + Search bar component responsive design, desktop - #### Tablet - Search bar component responsive design, tablet + Search bar component responsive design, tablet - #### Mobile - Search bar component responsive design, mobile + Search bar component responsive design, mobile - ## Best practices #### Long placeholder text @@ -266,29 +253,26 @@ Do not write placeholder text too long, it should be short and to the point (maximum 30 characters). - Search component best practice 1 + Search component best practice 1 - #### Call to action as button Do not replace the button with a call to action. - Search component best practice 2 + Search component best practice 2 - #### Different style or color Do not use a different button color or style when using a search bar on Red Hat *marketing* websites. - Search component best practice 3 + Search component best practice 3 - #### Disabled Do not disable the button until a user inputs text in the form field. The button @@ -296,49 +280,42 @@ should always be active and if a user tries to perform a search without any text in the form field, an error should be displayed instead. - Search component best practice 4 + Search component best practice 4 - #### Solo button Avoid using the search button on its own without a form field.

Learn more

-

Visit the Button component page to learn more about how to use buttons.

+

Visit the Button component page to learn more about how to use buttons.

- Search component best practice 5 + Search component best practice 5 - #### Rearranging the component Do not rearrange a search bar by placing the button below the form field or changing its width. - Search component best practice 6 + Search component best practice 6 - ## Spacing A search bar uses [space tokens](/tokens/space/) to define spacing values between elements. - Search bar spacing + Search bar spacing -{% spacerTokensTable headingLevel="3", tokens=[ - '--rh-space-sm', - '--rh-space-md', - '--rh-space-lg', -'' ] %}{% endspacerTokensTable %} +{% spacerTokensTable headingLevel="3", tokens=spacerTokens %}{% endspacerTokensTable %} diff --git a/docs/patterns/skip-navigation/index.md b/docs/patterns/skip-navigation/index.md index d623070dc6..d3445fcdc5 100644 --- a/docs/patterns/skip-navigation/index.md +++ b/docs/patterns/skip-navigation/index.md @@ -4,84 +4,84 @@ order: 90 hasToc: true tags: - pattern +spacerTokens: + - --rh-space-sm + - --rh-space-md --- - - + + ## Overview -Skip navigation is a styled link that appears at the top of a page when the Tab key is pressed. It bypasses the navigation and jumps users down to the main content when selected. +Skip navigation is a styled link that appears at the top of a page when the Tab +key is pressed. It bypasses the navigation and jumps users down to the main +content when selected. ## Sample pattern - Skip navigation + Skip navigation - ## Style -Skip to main content is a styled link that consists of a text label and a background container. Even though it looks like a Button, it functions more like a jump link. +Skip to main content is a styled link that consists of a text label and a +background container. Even though it looks like a Button, it functions more like +a jump link. - Skip navigation specs + Skip navigation specs - ## Usage -A skip to main content link helps some users browse the web more effectively. It should be invisible on every page as a commitment to accessibility. +A skip to main content link helps some users browse the web more effectively. It +should be invisible on every page as a commitment to accessibility. - Skip navigation usage + Skip navigation usage - Skip navigation usage + Skip navigation usage - Skip navigation usage + Skip navigation usage - ## Best practices Don't apply the skip to main content link style to other components. - Skip navigation style errors + Skip navigation style errors - ## Behavior -When a user presses the Tab key upon page load, the skip to main content link will appear centered at the top above the navigation. When a user presses the Enter key, the page will move down and the focus indicator should highlight the main content. +When a user presses the Tab key upon page load, the skip to main content link +will appear centered at the top above the navigation. When a user presses the +Enter key, the page will move down and the focus indicator should highlight the +main content. - Skip navigation behavior + Skip navigation behavior - ## Spacing A skip to main content link uses [space tokens](/tokens/space/) to define spacing values between elements. - Skip navigation spacing diagram + Skip navigation spacing diagram -{% spacerTokensTable - headline="", - caption='', - headingLevel="4", - tokens="--rh-space-sm,--rh-space-md" %} -{% endspacerTokensTable %} +{% spacerTokensTable headingLevel="4", tokens=spacerTokens %}{% endspacerTokensTable %} - {% include 'partials/component/feedback.html' %} diff --git a/docs/patterns/sticky-banner/index.md b/docs/patterns/sticky-banner/index.md index 0dad413264..5167573794 100644 --- a/docs/patterns/sticky-banner/index.md +++ b/docs/patterns/sticky-banner/index.md @@ -4,202 +4,235 @@ order: 100 hasToc: true tags: - pattern +spacerTokens: + - --rh-space-md + - --rh-space-lg + - --rh-space-xl + - --rh-space-2xl + - --rh-space-3xl + - --rh-space-4xl --- - - + + ## Overview -A Sticky banner slides into view at a certain scroll position and then anchors itself to the bottom edge of a browser window. It stays in one place as content scrolls underneath until a user dismisses them. - +A Sticky banner slides into view at a certain scroll position and then anchors +itself to the bottom edge of a browser window. It stays in one place as content +scrolls underneath until a user dismisses them. ## Sample pattern - Sticky banner + Sticky banner - ## Style -A sticky banner can be used in the light theme only. The large size can include a thumbnail image on large screens, but both sizes can include a headline, text, a call to action, and a background container with a subtle drop shadow. A close button also needs to be included in both sizes. +A sticky banner can be used in the light theme only. The large size can include +a thumbnail image on large screens, but both sizes can include a headline, text, +a call to action, and a background container with a subtle drop shadow. A close +button also needs to be included in both sizes. - Sticky banner style + Sticky banner style - ### Sizes -Large and Small are the two sticky banner sizes. The large size spans the full-width of the browser window and therefore can’t have rounded corners. The small size is fixed width and features rounded corners on top. The large size can feature more than the small size as well, including a thumbnail image, more text, and a larger call to action. +Large and Small are the two sticky banner sizes. The large size spans the +full-width of the browser window and therefore can’t have rounded corners. The +small size is fixed width and features rounded corners on top. The large size +can feature more than the small size as well, including a thumbnail image, more +text, and a larger call to action. - Sticky banner large size + Sticky banner large size - Sticky banner small size + Sticky banner small size - ### Content -Content in the large size falls within the 12-column grid whereas content in the small size is determined by the width of the banner container. +Content in the large size falls within the 12-column grid whereas content in the +small size is determined by the width of the banner container. ### Call to action -The large sticky banner features a Primary call to action and the small sticky banner features a Default call to action. The large size should have a Primary call to action, even if the same style is present somewhere else on the page. The banner is shown after a user has scrolled past the hero to avoid displaying two Primary calls to action simultaneously. +The large sticky banner features a Primary call to action and the small sticky +banner features a Default call to action. The large size should have a Primary +call to action, even if the same style is present somewhere else on the page. +The banner is shown after a user has scrolled past the hero to avoid displaying +two Primary calls to action simultaneously. ## Usage -A sticky banner is used on the bottom of pages where a secondary or personalized offer can be shown to users without interrupting their experience. +A sticky banner is used on the bottom of pages where a secondary or personalized +offer can be shown to users without interrupting their experience. ### Large vs. small -The large sticky banner can be used to promote an important offer on most websites, like the home page. The small sticky banner can be used to promote a less important offer on specific websites, like a product or article page. The importance of the asset determines the size of the sticky banner that’s used. +The large sticky banner can be used to promote an important offer on most +websites, like the home page. The small sticky banner can be used to promote a +less important offer on specific websites, like a product or article page. The +importance of the asset determines the size of the sticky banner that’s used. ### Placement -A sticky banner is anchored on the bottom of the page where it doesn’t distract a user from the page content. It can be used in light or dark environments because it scrolls on top of content and the backgrounds contain a drop shadow to help give it some depth. A user must close the Cookie banner for a sticky banner to appear. +A sticky banner is anchored on the bottom of the page where it doesn’t distract +a user from the page content. It can be used in light or dark environments +because it scrolls on top of content and the backgrounds contain a drop shadow +to help give it some depth. A user must close the Cookie banner for a sticky +banner to appear. - Sticky banner desktop placement + Sticky banner desktop placement - Sticky banner mobile placement + Sticky banner mobile placement - ### Layout -The large sticky banner background spans the width of a browser window. The content inside falls within a 12-column grid on large screens and a one-column grid on small screens. +The large sticky banner background spans the width of a browser window. The +content inside falls within a 12-column grid on large screens and a one-column +grid on small screens. ### Content -A sticky banner has limited vertical height, so keep content short and only include essential information. A sticky banner can include a thumbnail image, a headline, text, and a call to action, but not all elements are required. +A sticky banner has limited vertical height, so keep content short and only +include essential information. A sticky banner can include a thumbnail image, a +headline, text, and a call to action, but not all elements are required. - The headline shouldn’t break to two lines on any screen size (35 - 40 characters) - The text shouldn’t break to three lines on any screen size (85 - 110 characters) - A sticky banner should clearly describe what a visitor is getting if they choose to continue - The thumbnail image, headline, text, and call to action should all align to the specific resource that’s being promoted< - ## Best practices Don't change the large sticky banner to be fixed width. - Fixed width issue - - + Fixed width issue + -Don’t omit the thumbnail image from the sticky banner on large screens like Desktop or Tablet, landscape, it helps users get a better idea of what they’re downloading. +Don’t omit the thumbnail image from the sticky banner on large screens like +Desktop or Tablet, landscape, it helps users get a better idea of what they’re +downloading. - Full width small banner issue - - + Full width small banner 
+    issue + Don’t omit the drop shadow because the banner will blend into the background. - Banner without thumbnail issue + Banner without thumbnail 
+    issue - ## Behavior -The behavior of a sticky banner is similar to a Sticky card, they stick to the edge of a browser window and remain there until a user dismisses them. The difference is that a sticky banner is conversion-driven, they promote a more important offer that drives a user to a landing page whereas a sticky card promotes a less important offer like a resource or webinar. +The behavior of a sticky banner is similar to a Sticky card, they stick to the +edge of a browser window and remain there until a user dismisses them. The +difference is that a sticky banner is conversion-driven, they promote a more +important offer that drives a user to a landing page whereas a sticky card +promotes a less important offer like a resource or webinar. - Sticky banner behavior - - + Sticky banner behavior + ### Sliding -A sticky banner slides into view when a user reaches a specific scroll position on a page, usually somewhere below the fold. - +A sticky banner slides into view when a user reaches a specific scroll position +on a page, usually somewhere below the fold. ### Dismissing -A user can click on or tap the close button if they want to dismiss a sticky banner from their view. The page’s scroll position won’t be impacted and the sticky banner won’t return in the same browsing session after it’s closed. - +A user can click on or tap the close button if they want to dismiss a sticky +banner from their view. The page’s scroll position won’t be impacted and the +sticky banner won’t return in the same browsing session after it’s closed. ## Responsive design ### Breakpoints -A sticky banner can work on both large and small screens. Some elements will be dropped when space reduces to keep the layout clean and organized. - +A sticky banner can work on both large and small screens. Some elements will be +dropped when space reduces to keep the layout clean and organized. ### Desktop - - Sticky banner desktop breakpoint + +Sticky banner desktop 
+  breakpoint - ### Tablet - - Sticky banner tablet breakpoint + +Sticky banner tablet 
+  breakpoint - ### Mobile, landscape
- - Sticky banner mobile landscape breakpoint + + Sticky 
+      banner mobile landscape breakpoint -
Some text styles reduce in size on small screens. Learn more about typography on mobile.
+
Some text styles reduce in size on small screens. Learn more about + typography on mobile.
- ### Mobile, portrait - - Sticky banner mobile portrait breakpoint + +Sticky banner 
+  mobile portrait breakpoint - ## Interaction states -Since a sticky banner can consist of a variety of elements, refer to the specific interaction states that are assigned to each style and component for more information. - +Since a sticky banner can consist of a variety of elements, refer to the +specific interaction states that are assigned to each style and component for +more information. ## Spacing -Both sticky banners use [space tokens](/tokens/space/) to define spacing -values between elements. - +Both sticky banners use [space tokens](/tokens/space/) to define spacing values +between elements. ### Large size - Sticky banner large spacing + Sticky banner large 
+    spacing - ### Small size -Content padding defines how far away elements are from each other inside each section. +Content padding defines how far away elements are from each other inside each +section. - Sticky banner small spacing + Sticky banner small 
+    spacing - {% spacerTokensTable - headline="", - caption='', - headingLevel="4", - tokens="--rh-space-md, --rh-space-lg, --rh-space-xl, --rh-space-2xl, --rh-space-3xl, --rh-space-4xl" %} - {% endspacerTokensTable %} +{% spacerTokensTable headingLevel="4", tokens=spacerTokens %}{% endspacerTokensTable %} - {% include 'partials/component/feedback.html' %} diff --git a/docs/patterns/sticky-card/index.md b/docs/patterns/sticky-card/index.md index ccf6af9e22..d63844e4d4 100644 --- a/docs/patterns/sticky-card/index.md +++ b/docs/patterns/sticky-card/index.md @@ -4,98 +4,117 @@ order: 110 hasToc: true tags: - pattern +spacerTokens: + - --rh-space-lg + - --rh-space-xl --- - - + + ## Overview -Sticky cards slide into view at a certain scroll position and then anchor themselves to the edge of a browser window. They stay in one place as content scrolls underneath until a user dismisses them. - +Sticky cards slide into view at a certain scroll position and then anchor +themselves to the edge of a browser window. They stay in one place as content +scrolls underneath until a user dismisses them. ## Sample pattern - Sticky card + Sticky card - ## Style A sticky card acts as a small container for a limited amount of content. - Sticky card style + Sticky card style - ### Theme -The required elements in a sticky card are a close button, a title or a headline, a call to action, and a container (the light theme container features a drop shadow). The container consists of a background color and two rounded corners on the left or the right side, depending on the orientation. A thin border is also required even if the sticky card background color is different than the page background color. +The required elements in a sticky card are a close button, a title or a +headline, a call to action, and a container (the light theme container features +a drop shadow). The container consists of a background color and two rounded +corners on the left or the right side, depending on the orientation. A thin +border is also required even if the sticky card background color is different +than the page background color. - Sticky card light theme + Sticky card light theme - Sticky card dark theme + Sticky card dark theme ### Layout -A sticky card features header, body, and footer sections, just like a normal Card. Header, body, and footer sections can only include a limited amount of content to ensure that the card doesn’t become too tall. - +A sticky card features header, body, and footer sections, just like a normal +Card. Header, body, and footer sections can only include a limited amount of +content to ensure that the card doesn’t become too tall. ### Close button -A close button is required for accessibility if a user wants to dismiss the sticky card from their view if they find it distracting. - +A close button is required for accessibility if a user wants to dismiss the +sticky card from their view if they find it distracting. ### Header -The header section can feature only a limited amount of content like a card title or a small headline. This required section introduces what the content is and shouldn’t be hidden. - +The header section can feature only a limited amount of content like a card +title or a small headline. This required section introduces what the content is +and shouldn’t be hidden. ### Body -To keep the vertical height short, the body section can only include a small amount of text or a small image thumbnail. If a card title and a headline are enough to explain what the content is, the body section can be hidden. - +To keep the vertical height short, the body section can only include a small +amount of text or a small image thumbnail. If a card title and a headline are +enough to explain what the content is, the body section can be hidden. ### Footer -The footer section can include normal links or a call to action. A sticky card footer is always required and shouldn't be hidden. +The footer section can include normal links or a call to action. A sticky card +footer is always required and shouldn't be hidden. - Sticky card content sections + Sticky card content sections - ## Usage -The sticky card placement is different than the normal card placement, where a normal card lives in a predetermined spot on a page. A sticky card slides into view only when a user reaches a specific scroll position on a page. When it does, it stays fixed to the edge of the page and it floats above content and layouts when a user scrolls. It should only be used to feature secondary content that’s helpful to a user, like a resource or webinar. +The sticky card placement is different than the normal card placement, where a +normal card lives in a predetermined spot on a page. A sticky card slides into +view only when a user reaches a specific scroll position on a page. When it +does, it stays fixed to the edge of the page and it floats above content and +layouts when a user scrolls. It should only be used to feature secondary content +that’s helpful to a user, like a resource or webinar. ### Layout -A sticky card can be placed on the left or the right edge of a page and it has a fixed width of 262px. +A sticky card can be placed on the left or the right edge of a page and it has a +fixed width of 262px. - Sticky card on right side + Sticky card on right side - ### Content -A sticky card has limited vertical height, so keep content short and only include essential information. A sticky card can include a card title, a headline, text, and a call to action, but not all of these elements need to be included at the same time. Move any extra content to other parts of the page if possible. +A sticky card has limited vertical height, so keep content short and only +include essential information. A sticky card can include a card title, a +headline, text, and a call to action, but not all of these elements need to be +included at the same time. Move any extra content to other parts of the page if +possible. - Sticky card content sections + Sticky card content sections - ### Character count -The recommended maximum character count for the elements of a sticky card are listed below and include spaces. +The recommended maximum character count for the elements of a sticky card are +listed below and include spaces. @@ -126,99 +145,103 @@ The recommended maximum character count for the elements of a sticky card are li
- ### Alignment -Text and other content in a sticky card is always left-aligned, even if the sticky card is anchored to the right edge of a page. +Text and other content in a sticky card is always left-aligned, even if the +sticky card is anchored to the right edge of a page. ## Best practices Don’t use more than one sticky card per page. - Sticky card multiple issue + Sticky card multiple issue Don’t change the width of a sticky card on large screens, it’s fixed at 262px. - Sticky card width issue + Sticky card width issue Don’t anchor a sticky card on small screens, it covers too much content. - Sticky card overlap issue + Sticky card overlap issue Don't omit the close button, it’s needed for accessibility. - Sticky card close button issue + Sticky card close button issue Don’t use more than one call to action. - Sticky card call to action issue + Sticky card call to action issue - ## Behavior ### Sliding -A sticky card is always hidden until it slides into view. The trigger is when a user reaches a specific scroll position on a page, which should be below the fold to avoid distracting a user as soon as a page loads. - +A sticky card is always hidden until it slides into view. The trigger is when a +user reaches a specific scroll position on a page, which should be below the +fold to avoid distracting a user as soon as a page loads. ### Scrolling -A sticky card can be anchored to the left or the right edge of a page and it stays in the same position when a user scrolls up or down. Any content below will scroll underneath, but it will be partially covered. - +A sticky card can be anchored to the left or the right edge of a page and it +stays in the same position when a user scrolls up or down. Any content below +will scroll underneath, but it will be partially covered. ### Dismissing -A user can click on or tap the close button if they want to dismiss the sticky card from their view. The page’s scroll position won’t be impacted and the sticky card won’t return in the same browsing session after it’s closed. - +A user can click on or tap the close button if they want to dismiss the sticky +card from their view. The page’s scroll position won’t be impacted and the +sticky card won’t return in the same browsing session after it’s closed. ### Vertical height -The vertical height of a sticky card greatly expands when too much content is placed inside. Doing this will cover too much content and negatively impact the user experience, so keep the content short to maintain as close to a square aspect ratio as possible. +The vertical height of a sticky card greatly expands when too much content is +placed inside. Doing this will cover too much content and negatively impact the +user experience, so keep the content short to maintain as close to a square +aspect ratio as possible. - Sticky card vertical height caution + Sticky card vertical height caution - ## Breakpoints -A sticky card is 262px wide on large screens only. On small screens, it acts like a normal card and is placed in a predetermined spot on a page, but it maintains the same styles. - +A sticky card is 262px wide on large screens only. On small screens, it acts +like a normal card and is placed in a predetermined spot on a page, but it +maintains the same styles. ### Desktop - Sticky card desktop layout + Sticky card desktop layout - ### Tablet - Sticky card tablet layout + Sticky card tablet layout - ### Mobile - Sticky card mobile layout + Sticky card mobile layout - ## Interaction states -Since a sticky card can consist of a variety of elements, refer to the specific interaction states that are assigned to each style and component for more information. +Since a sticky card can consist of a variety of elements, refer to the specific +interaction states that are assigned to each style and component for more +information. ## Spacing @@ -226,17 +249,11 @@ A sticky card uses [space tokens](/tokens/space/) to define spacing values between elements. - Sticky card spacing + Sticky card spacing -{% spacerTokensTable - headline="", - caption='', - headingLevel="4", - tokens="--rh-space-lg, --rh-space-xl" %} -{% endspacerTokensTable %} +{% spacerTokensTable headingLevel="4", tokens=spacerTokens %}{% endspacerTokensTable %} - {% include 'partials/component/feedback.html' %} diff --git a/docs/patterns/tabs/examples.md b/docs/patterns/tabs/examples.md new file mode 100644 index 0000000000..e69de29bb2 diff --git a/docs/patterns/tabs/index.md b/docs/patterns/tabs/index.md index 46694b988c..34975b967c 100644 --- a/docs/patterns/tabs/index.md +++ b/docs/patterns/tabs/index.md @@ -6,7 +6,7 @@ tags: - pattern --- - + + + + +## Accented tile + +The accented tile pattern should be used to draw attention to a specifc tile or +set of tiles. Be careful not to apply the accented tile pattern to all tiles +within a page, otherwise the accent effect will be lost. After all, "if +everything is special, then nothing is special." + +{% uxdotPattern %}{% include './patterns/accented-tile.html' %}{% enduxdotPattern %} + +View accented tile demo diff --git a/docs/patterns/tile/index.md b/docs/patterns/tile/index.md index c6881dd784..a24436419d 100644 --- a/docs/patterns/tile/index.md +++ b/docs/patterns/tile/index.md @@ -1,89 +1,60 @@ --- -title: Tile -layout: layouts/pages/basic.njk +title: Overview +heading: Tile +sidenavTitle: Tile +layout: layouts/pages/pattern.njk hasToc: true order: 120 tags: - pattern -importElements: - - rh-tile - - rh-cta - - rh-surface - - rh-code-block + - tilePatterns +subnav: + collection: tilePatterns + order: 1 --- - - + + + + - +## Customizing tiles -## Overview +Tiles act as both themeable containers and also respond to the color theme from +their themeable containers. -Tiles are flexible layouts with clickable and contained surfaces. +Customize tiles by setting custom values for the element's color tokens. By +setting the theme tokens for both `dark` and `light` color themes, you can theme +an entire page or section. + +Examples include: + - [`--rh-color-border-interactive-on-light`](/tokens/color/#rh-color-border-interactive-on-light) + - [`--rh-color-border-interactive-on-dark`](/tokens/color/#rh-color-border-interactive-on-dark) + - [`--rh-color-interactive-primary-hover-on-light`](/tokens/color/#rh-color-interactive-primary-hover-on-light) + - [`--rh-color-interactive-primary-hover-on-dark`](/tokens/color/#rh-color-interactive-primary-hover-on-dark) + - [`--rh-color-text-primary-on-light`](/tokens/color/#rh-color-text-primary-on-light) + - [`--rh-color-text-primary-on-dark`](/tokens/color/#rh-color-text-primary-on-dark) -## Accented tile +For more information, please see the docs on [theming][theming] and +[`` css custom properties][css-props]. -The accented tile pattern should be used to draw attention to a specifc tile or set of tiles. Be careful not to apply the accented tile pattern to all tiles within a page, otherwise the accent effect will be lost. After all, "if everything is special, then nothing is special." +{% uxdotPattern stacked=true, target="custom-tiles" %}{% include './patterns/custom-themes.html' %}{% enduxdotPattern %} -
-
-

Example

- - -

Link

- Lorem ipsum dolor sit amet, consectetur adipiscing elit. -
-
-
-
-

CSS

- - - -
-
-View accented tile demo +[element]: /elements/tile/ +[css-props]: /elements/tile/code/#css-custom-properties +[theming]: /theming/ diff --git a/docs/patterns/tile/patterns/accented-tile.html b/docs/patterns/tile/patterns/accented-tile.html new file mode 100644 index 0000000000..d7ef722685 --- /dev/null +++ b/docs/patterns/tile/patterns/accented-tile.html @@ -0,0 +1,24 @@ + +

Link

+ Lorem ipsum dolor sit amet, consectetur adipiscing elit. +
+ + diff --git a/docs/patterns/tile/patterns/custom-themes.html b/docs/patterns/tile/patterns/custom-themes.html new file mode 100644 index 0000000000..6649de7010 --- /dev/null +++ b/docs/patterns/tile/patterns/custom-themes.html @@ -0,0 +1,30 @@ + + +

Link

+ Lorem ipsum dolor sit amet, consectetur adipiscing elit. +
+ +

Link

+ Lorem ipsum dolor sit amet, consectetur adipiscing elit. +
+
+ + diff --git a/docs/patterns/video-thumbnail/index.md b/docs/patterns/video-thumbnail/index.md index b80fb5483c..6e1391f24d 100644 --- a/docs/patterns/video-thumbnail/index.md +++ b/docs/patterns/video-thumbnail/index.md @@ -6,9 +6,8 @@ tags: - pattern --- - - - + + ## Overview @@ -17,111 +16,99 @@ A Video thumbnail is a graphical preview of a video overlayed with a play button ## Sample pattern - Video thumbnail + Video thumbnail - ## Style A video thumbnail is a combination of a graphic with a slightly transparent play button on top. A video thumbnail can also include an optional caption underneath that explains what the video is. - Video thumbnail specs + Video thumbnail specs - ## Theme - Video thumbnail light theme + Video thumbnail light theme - Video thumbnail dark theme + Video thumbnail dark theme - ### Button A video thumbnail can include either a light or a dark play button, depending on the image underneath. If an image is lighter, use a dark play button for accessibility and vice versa.
- Play button on light theme + Play button on light theme - Play button on dark theme + Play button on dark theme
- ## Usage A video thumbnail can be used to indicate that a video can be played and using a caption underneath isn’t required. - ### Layouts A video thumbnail can be used in most layouts that have enough space to accommodate a small image with a play button on top. A video thumbnail used in a card is a good example of a minimum size. - Specs of video button thumbnail + Specs of video button thumbnail - ### Caption An optional descriptor caption can be placed underneath the video thumbnail, it can be left- or center-aligned, depending on how the video is oriented. - ### Character counts A caption should be limited to 150 characters. - ## Best practices Don't reposition the play button. - Don't reposition play button + Don't reposition play button Don't change the aspect ratio of a video thumbnail. - Don't change aspect ratio + Don't change aspect ratio - ## Behavior ### Modal When a video thumbnail is smaller than six columns, selecting the play button triggers a [Video player modal](../modal) where a larger version of the video will play on top of a background overlay. - ### Inline When a video thumbnail is larger than six columns, the video will play inline on the page. - ## Responsive design A video thumbnail changes size, but it should maintain its aspect ratio across all screen sizes. The caption also maintains the same text size, but changes alignment to match the video thumbnail. - ### Desktop, centered - Video thumbnail centered + Video thumbnail centered When centered, the video thumbnail and caption should span six grid columns - Video thumbnail sides + Video thumbnail sides When aligned on the left or right edge of the grid, the video thumbnail and caption should span five grid columns @@ -129,75 +116,67 @@ When aligned on the left or right edge of the grid, the video thumbnail and capt ### Mobile - Video thumbnail on mobile + Video thumbnail on mobile - ## Interaction states The only interactive element in a video thumbnail is the play button. For more information about modal interaction states, see [Video player modal](../modal). - ### Default - Video thumbnail default state + Video thumbnail default state - ### Focus - Video thumbnail focus state + Video thumbnail focus state - ### Hover - Video thumbnail hover state + Video thumbnail hover state - ### Active - Video thumbnail active state + Video thumbnail active state
- Video thumbnail hover state light + Video thumbnail hover state light
The dark play button background becomes 25% darker on hover
- Video thumbnail hover state dark + Video thumbnail hover state dark
The light play button background becomes 25% lighter on hover
- ## Spacing A video thumbnail uses [space tokens](/tokens/space/) to define spacing values between elements. - Video thumbnail spacing specs + Video thumbnail spacing specs - {% spacerTokensTable - headline="", + {% spacerTokensTable headline="", caption='', headingLevel="4", tokens="--rh-space-xl" %} {% endspacerTokensTable %} - {% include 'partials/component/feedback.html' %} diff --git a/docs/release-notes/index.md b/docs/release-notes/index.md index 584f0bcf11..1fcc918730 100644 --- a/docs/release-notes/index.md +++ b/docs/release-notes/index.md @@ -2,16 +2,16 @@ layout: layouts/pages/basic.njk title: Release notes hasToc: true -importElements: - - rh-tile - - rh-tag - - rh-alert --- - - + + - + + +{% macro j() %}Major{% endmacro %} +{% macro i() %}Minor{% endmacro %} +{% macro p() %}Patch{% endmacro %} ## Changelog -We are continually making changes in order to improve and grow the Red Hat Design System. If you think changes need to be made to a component, foundation, or anything else, please submit a [GitHub issue](https://github.com/RedHat-UX/red-hat-design-system/issues). +We are continually making changes in order to improve and grow the Red Hat +Design System. If you think changes need to be made to a component, foundation, +or anything else, please submit a [GitHub issue][issues]. Changelog +
+ +## Version 2.1.0 +Released October 1, 2024 + +### Highlights + + + +| Change | Type | Notes | +| ----------------------------------- | ------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| Theming: added theming tokens to most elements | {{i()}} | New theming tokens allow page-level and container-level colour palettes on patterns and elements. | +| ``: added new `state` colors | {{i()}} | Added `info`, `neutral`, and `caution`. Deprecated `note` (aliasing `info`), `default` (aliasing `neutral`), and `error` (aliasing `danger`). | +| ``: improved accessibility | {{i()}} | Removed arrow-key keyboard navigation in favor of tab navigation through accordion sets. | +| ``: added new `state` colors | {{i()}} | Added `danger`, `warning`, `caution`, `neutral`, and `info`. Deprecated `critical` (aliasing `danger`), `important` (aliasing `caution`), `moderate` (aliasing `warning`), and `note` (aliasing `info`). | +| ``: added `icon-set` attribute | {{i()}} | Added `icon-set="..."` attribute, which corresponds to ``. | +| ``: added header background theming API | {{i()}} | Using `--rh-card-header-background-on-light` and `--rh-card-header-background-on-dark` CSS custom props allows for theming the card header's background. | +| ``: added syntax highlighting | {{i()}} | Code blocks now have optional Red Hat color-themed syntax highlighting via client side or server side (prerendered prismjs code-blocks). | +| ``: improved responsive layout API | {{i()}} | Added auto-generated table cell headings for responsive layout on small screens. | +| ``: added new tag colors | {{i()}} | Added `red-orange`, `yellow`, and `teal` colors. Deprecated `cyan`, aliasing it to `teal`. | +| ``: added `destaurated` variant | {{i()}} | Added `variant="desaturated"` to reduce visual prominence or to better fit a specific theme or visual style. | +| ``: added `size` attribute | {{i()}} | Added `size="compact"` for areas where space is limited. | +| ``: added optional `href` attribute | {{i()}} | Adding `href` attribute to `` removes the need for slotting an anchor element (``) on linked tags. | +| ``: added `private` and `external` link variants | {{i()}} | Using `link="private"` or `link="external"` indicates whether the link is private or external and changes the tile icon from an arrow to a padlock or external link icons respectively. | +| ``: added optional `href` attribute | {{i()}} | Adding `href` attribute to `` removes the need for slotting an anchor element (``). | +| ``: added mini playback control | {{p()}} | Mini layout now has playback control. | +| ``: improved accessibility | {{p()}} | Removed arrow-key keyboard navigation in favor of tab navigation through navigation items and added `accessible-label` attribute to explicitly label landmark. | +| ``: improved accessibility | {{p()}} | Removed arrow-key keyboard navigation in favor of tab navigation through navigation items and added `accessible-label` attribute to explicitly label landmark. | +| ``: added container query support | {{p()}} | Tables now adjust to the size of their containing element, not the viewport size. | +| ``: added container query support | {{p()}} | Tabs now adjust to the size of their containing element, not the viewport size. | +| ``: added advanced layout support | {{p()}} | Tabs can now participate in advanced layouts, like `display: subgrid`. | + + + +View all version 2.1 release notes + +
+ + +
## Version 2.0.0 Released August 27, 2024 -

Upgrading?

-

If you're upgrading to version 2.0, read our changelog for upgrade instructions.

+

Upgrading?

+

If you're upgrading to version 2.0, read our changelog for upgrade instructions.

### Highlights - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
ChangeTypeNotes
<rh-accordion> accessibility improvementsMajorRemoved the heading-tag and heading-text attributes from the rh-accordion-header element to improve accessibility.
<rh-accordion> API changesMajorRemoved the unused icon part (and attribute) and the (previously undocumented) container part from <rh-accordion-header>. Removed unused bordered attribute.
<rh-footer> API changesMajorRemoved deprecated <rh-global-footer> element and deprecated global slot. Use <rh-footer-universal> element and universal slot.
<rh-cta> API changesMajorRemoved read-only cta property; use data-analytics attributes instead.
<rh-tabs> JavaScript API changesMajorRemoved deprectated RhTabs.isTab() and RhTabs.isPanel() static class methods.
<rh-tabs> HTML/CSS API changesMajorRemoved deprectated theme attribute for the tabs and panels; use the --rh-tabs-active-border-color CSS property directly.
<rh-dialog> API changesMajorRemoved deprecated --rh-modal-video-aspect-ratio CSS custom property.
<rh-footer> API changesMajorRemoved deprecated CSS custom properties.
<rh-table> API changesMajorRemoved deprecated CSS custom properties.
<rh-spinner> API changesMajorRemoved deprecated color-palette attribute.
<rh-cta> API changesMajorRemoved previously-deprecated color-palette attribute.
<rh-alert> API changesMajorRemoved deprecated toast boolean attribute.
<rh-navigation-secondary> API changesMajorRemoved deprecated alias <rh-secondary-nav>.
<rh-tabs> API changesMajorRemoved box and vertical attributes from <rh-tab>; set them on <rh-tabs> instead.
Changed RHDS entrypointMajorRemoved the rhds.min.js entrypoint and replaced it with a module that reexports all our element modules.
Added <rh-icon>MinorIcons represents general concepts and can support text as a decorative element. The <rh-icon> element allows experience and content authors to add Red Hat icons of varying dimensions in the same area without shifting surrounding content.
Added <rh-switch>MinorA switch toggles the state of a setting (between on and off). Switches and checkboxes can often be used interchangeably, but the switch provides a more explicit, visible representation on a setting.
Added <rh-health-index>MinorHealth index grades the health or security level of something.
Added <rh-video-embed>MinorA video embed is a graphical preview of a video overlayed with a play button. When clicked, the YouTube video will begin playing.
Added <rh-breadcrumb>MinorA breadcrumb navigation is a secondary navigation element consisting of a list of links to the parent pages of the current page in hierarchical order. It helps users find their place within a website or web application.
Added promo variant to <rh-card>MinorThe promo card variant allows users to easily display text and optionally an image side by side.
Added open variant and small size to <rh-pagination>MinorUsers can now further customize pagination by choosing which variant and size are most appropriate for their applications.
Added static toast method to <rh-alert>MinorThe toast method allows for toast-like alert messages.
Added dark color palette to <rh-pagination>MinorPagination now responds to themable containers like <rh-surface>.
Added light DOM shim for <rh-cta>MinorAdded rh-cta-lightdom-shim.css as an optional file to help reduce layout shift before element is defined, where declarative shadow DOM is not an option.
Added <rh-card> heading custom propertiesMinorUser can now cumstomize CSS custom properties for card headings.
Added href attribute to <rh-cta>MinorUsers can now set the href directly on <rh-cta> rather than slotting an anchor tag.
Added icon-set attribute to <rh-cta>MinorUsers can now choose an icon-set in their call-to-action.
Fix <rh-tile-group> grid layoutPatchCorrected application of grid layout to slotted elements.
Updated <rh-cta> focus statesPatchChanged focus states to mimic hover states and an additional outline.
+ +| Change | Type | Notes | +| ---------------------------------------------------------- | ------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `` accessibility improvements | {{j()}} | Removed the `heading-tag` and `heading-text` attributes from the `rh-accordion-header` element to improve accessibility. | +| `` API changes | {{j()}} | Removed the unused `icon` part (and attribute) and the (previously undocumented) `container` part from ``. Removed unused `bordered` attribute. | +| `` API changes | {{j()}} | Removed deprecated `` element and deprecated `global` slot. Use `` element and `universal` slot. | +| `` API changes | {{j()}} | Removed read-only `cta` property; use `data-analytics` attributes instead. | +| `` JavaScript API changes | {{j()}} | Removed deprectated `RhTabs.isTab()` and `RhTabs.isPanel()` static class methods. | +| `` HTML/CSS API changes | {{j()}} | Removed deprectated `theme` attribute for the tabs and panels; use the `--rh-tabs-active-border-color` CSS property directly. | +| `` API changes | {{j()}} | Removed deprecated `--rh-modal-video-aspect-ratio` CSS custom property. | +| `` API changes | {{j()}} | Removed deprecated CSS custom properties. | +| `` API changes | {{j()}} | Removed deprecated CSS custom properties. | +| `` API changes | {{j()}} | Removed deprecated `color-palette` attribute. | +| `` API changes | {{j()}} | Removed previously-deprecated `color-palette` attribute. | +| `` API changes | {{j()}} | Removed deprecated `toast` boolean attribute. | +| `` API changes | {{j()}} | Removed deprecated alias ``. | +| `` API changes | {{j()}} | Removed `box` and `vertical` attributes from ``; set them on `` instead. | +| Changed RHDS entrypoint | {{j()}} | Removed the `rhds.min.js` entrypoint and replaced it with a module that reexports all our element modules. | +| Added `` | {{i()}} | Icons represents general concepts and can support text as a decorative element. The `` element allows experience and content authors to add Red Hat icons of varying dimensions in the same area without shifting surrounding content. | +| Added `` | {{i()}} | A switch toggles the state of a setting (between on and off). Switches and checkboxes can often be used interchangeably, but the switch provides a more explicit, visible representation on a setting. | +| Added `` | {{i()}} | Health index grades the health or security level of something. | +| Added `` | {{i()}} | A video embed is a graphical preview of a video overlayed with a play button. When clicked, the YouTube video will begin playing. | +| Added `` | {{i()}} | A breadcrumb navigation is a secondary navigation element consisting of a list of links to the parent pages of the current page in hierarchical order. It helps users find their place within a website or web application. | +| Added `promo` variant to `` | {{i()}} | The promo card variant allows users to easily display text and optionally an image side by side. | +| Added `open` variant and `small` size to `` | {{i()}} | Users can now further customize pagination by choosing which variant and size are most appropriate for their applications. | +| Added static `toast` method to `` | {{i()}} | The `toast` method allows for toast-like alert messages. | +| Added dark color palette to `` | {{i()}} | Pagination now responds to themeable containers like ``. | +| Added light DOM shim for `` | {{i()}} | Added `rh-cta-lightdom-shim.css` as an optional file to help reduce layout shift before element is defined, where declarative shadow DOM is not an option. | +| Added `` heading custom properties | {{i()}} | User can now cumstomize CSS custom properties for card headings. | +| Added `href` attribute to `` | {{i()}} | Users can now set the `href` directly on `` rather than slotting an anchor tag. | +| Added `icon-set` attribute to `` | {{i()}} | Users can now choose an `icon-set` in their call-to-action. | +| Fix `` grid layout | {{p()}} | Corrected application of grid layout to slotted elements. | +| Updated `` focus states | {{p()}} | Changed focus states to mimic hover states and an additional outline. | + -View version 2.0 release notes +View all version 2.0 release notes
@@ -242,70 +167,25 @@ Released April 22, 2024 ### Highlights - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
ChangeTypeNotes
Added <rh-site-status>MinorWebsite status communicates the operational status of a website or domain using a status icon and link. It is usually located in the Footer component.
Added <rh-back-to-top>MinorBack to top component is a fragment link that allows users to quickly navigate to the top of a lengthy content.
Added <rh-skip-link>MinorA skip link is used to skip repetitive content on a page. It is hidden by default and can be activated by hitting the Tab key after loading/refreshing a page.
Updated <rh-code-block>MinorAdded line numbers option, "Show more" toggle, copy and wrap actions, to <rh-code-block>
Updated <rh-menu>PatchImproved focus accessibility for keyboard navigation users on Firefox.
Updated <rh-button>PatchImproved focus accessibility on Firefox.
Updated <rh-accordion>PatchAdded an accents slot with placement options as inline and bottom.
Updated <rh-alert>PatchMake sure alerts always have to correct (lightest) color palette.
Updated <rh-tabs>PatchAllow tabs with long text content to fit into different-sized containers.
Updated PatternFly Elements toolingMinorPatch update to dependencies, including Lit version 3.
+ +| Change | Type | Notes | +| ---------------------------------------------------------- | ------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| Added `` | {{i()}} | Website status communicates the operational status of a website or domain using a status icon and link. It is usually located in the Footer component. | +| Added `` | {{i()}} | Back to top component is a fragment link that allows users to quickly navigate to the top of a lengthy content. | +| Added `` | {{i()}} | A skip link is used to skip repetitive content on a page. It is hidden by default and can be activated by hitting the Tab key after loading/refreshing a page. | +| Updated `` | {{i()}} | Added line numbers option, "Show more" toggle, copy and wrap actions, to `` | +| Updated `` | {{p()}} | Improved focus accessibility for keyboard navigation users on Firefox. | +| Updated `` | {{p()}} | Improved focus accessibility on Firefox. | +| Updated `` | {{p()}} | Added an accents slot with placement options as inline and bottom. | +| Updated `` | {{p()}} | Make sure alerts always have to correct (lightest) color palette. | +| Updated `` | {{p()}} | Allow tabs with long text content to fit into different-sized containers. | +| Updated PatternFly Elements tooling | {{i()}} | [Patch update to dependencies][pfepatchlit3], including Lit version 3. | +
-View version 1.4 release notes +[pfepatchlit3]: https://github.com/patternfly/patternfly-elements/releases/tag/%40patternfly%2Fpfe-core%403.0.0 + +View all version 1.4 release notes @@ -317,50 +197,21 @@ Released January 11, 2024 ### Highlights - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
ChangeTypeNotes
Added <rh-surface>Minora content container that provides accessible background and font color theming for its child elements.
Updated to RH Tokens 2.0MinorUses RHDS Tokens version 2.0. See v1.3 release notes for important info regarding this update.
Updated <rh-tabs-panel>MinorTab Panels can now have their margin and padding overridden.
Updated <rh-pagination>MinorAdded numeric CSS shadow part.
Added accessible-label to <rh-tile>MinorTile's form control labels can now be customized.
Fixed <rh-tile> radio and checkboxesMinorRadio and checkbox tiles now submit their values in <form> elements.
+ +| Change | Type | Notes | +| --------------------------------------- | ------- | ---------------------------------------------------------------------------------------------------------- | +| Added `` | {{i()}} | a content container that provides accessible background and font color theming for its child elements. | +| Updated to `RH Tokens 2.0` | {{i()}} | Uses RHDS Tokens version 2.0. [See v1.3 release notes][tokens13] for important info regarding this update. | +| Updated `` | {{i()}} | Tab Panels can now have their margin and padding overridden. | +| Updated `` | {{i()}} | Added `numeric` CSS shadow part. | +| Added `accessible-label` to `` | {{i()}} | Tile's form control labels can now be customized. | +| Fixed `` radio and checkboxes | {{i()}} | Radio and checkbox tiles now submit their values in `
` elements. | + -View version 1.3 release notes +[tokens13]: https://github.com/RedHat-UX/red-hat-design-system/releases/tag/v1.3.0 + +View all version 1.3 release notes @@ -372,55 +223,20 @@ Released October 16, 2023 ### Highlights - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
ChangeTypeNotes
Added <rh-table>MinorA table is a container for displaying information. It allows a user to scan, examine, and compare large amounts of data.
Added <rh-tile>MinorA tile is a flexible layout with a clickable and contained surface.
Added <rh-timestamp>MinorProvides consistent formats for displaying date and time values.
Added <rh-navigation-secondary> current page indicator supportMinorUpdated support for a current page indicator using aria-current="page".
Fixed <rh-card> header slotMinorCard's header slot now displays items vertically instead of stacking, allowing for more than one item to display in the header.
Improved keyboard navigation on <rh-navigation-secondary>PatchSecondary Navigation now has improved keyboard navigation.
Fixed <rh-cta> brick variantPatchBrick variants of calls to action (CTAs) are now full width.
+ +| Change | Type | Notes | +| ---------------------------------------------------------------- | ------- | ------------------------------------------------------------------------------------------------------------------------------- | +| Added `` | {{i()}} | A table is a container for displaying information. It allows a user to scan, examine, and compare large amounts of data. | +| Added `` | {{i()}} | A tile is a flexible layout with a clickable and contained surface. | +| Added `` | {{i()}} | Provides consistent formats for displaying date and time values. | +| Added `` current page indicator support | {{i()}} | Updated support for a current page indicator using `aria-current="page"`. | +| Fixed `` `header` slot | {{i()}} | Card's header slot now displays items vertically instead of stacking, allowing for more than one item to display in the header. | +| Improved keyboard navigation on `` | {{p()}} | Secondary Navigation now has improved keyboard navigation. | +| Fixed `` `brick` variant | {{p()}} | Brick variants of calls to action (CTAs) are now full width. | + -View version 1.2 release notes +View all version 1.2 release notes @@ -432,45 +248,20 @@ Released July 5, 2023 ### Highlights - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
ChangeTypeNotes
Added <rh-card>MinorCard creates a component with a header, body, and footer. The header and footer are optional.
Added <rh-audio-player>MinorAudio-player creates a custom UI for audio files.
Added <rh-code-block>MinorA container for a block of code. May be composed into a toolbar or contain copy buttons or other interactive components.
Added new CSS custom properties for <rh-tooltip>MinorNew CSS custom properties, like --rh-tooltip-arrow-size, --rh-tooltip-content-background-color, and more!
Added outline variant for <rh-tag>MinorNow you can use variant="outline".
+ +| Change | Type | Notes | +| ---------------------------------------------------------- | ------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| Added `` | {{i()}} | Card creates a component with a header, body, and footer. The header and footer are optional. | +| Added `` | {{i()}} | Audio-player creates a custom UI for audio files. | +| Added `` | {{i()}} | A container for a block of code. May be composed into a toolbar or contain copy buttons or other interactive components. | +| Added new CSS custom properties for `` | {{i()}} | New CSS custom properties, like `--rh-tooltip-arrow-size`, `--rh-tooltip-content-background-color`, and more! | +| Added outline variant for `` | {{i()}} | Now you can use `variant="outline"`. | +
-View version 1.1 release notes + +View all version 1.1 release notes + @@ -482,116 +273,32 @@ Released April 3, 2023 ### Highlights - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
ChangeTypeNotes
Added <rh-cta>MajorA Call to Action is a styled link that directs a user to other pages or sometimes displays hidden content.
Added <rh-secondary-nav>MajorA non-primary navigation for products and subcategory pages.
Added <rh-global-footer>MajorA standalone global footer component.
Renamed <rh-global-footer> to <rh-footer-universal>MajorRenamed the global slot to universal.
Renamed <rh-secondary-nav> to <rh-navigation-secondary>MajorRenamed the component and all sub components to <rh-navigation-secondary-*>.
Added <rh-spinner>MinorSpinner consists of an animated circle and sometimes a message, and it indicates that a section is loading.
Added <rh-button>MinorButton is a form-associated custom element. Buttons allow users to perform an action when triggered.
Added <rh-tag>MinorA tag is an inline-block element component that provides a distinct visual style for metadata in a UI.
Added <rh-blockquote>MinorDisplays a quote with author's name and title.
Added <rh-subnav>MinorThe subnav component is used when an alternate navigation structure is needed to provide additional navigation on a site that does not need the product branding or structural depth that rh-secondary-nav provides.
Added <rh-tabs>MinorA tab set of layered content, including tab widgets and their associated tab panel.
Added <rh-accordion>MinorAccordion displays multiple, related disclosure widgets.
Added <rh-alert>MinorAn alert displays auxiliary information on a website. An alert can have one of several states of severity.
Added <rh-avatar>MinorAn Avatar is a placeholder graphic for a photo or an image that is placed to the left or on top of text.
Added <rh-pagination>MinorPagination is a web component for navigating paginated content.
Added <rh-stat>MinorAn element which can be used to display statistics inside of an app.
Added <rh-badge>MinorA badge is used to annotate other information with numerical content.
Added <rh-tooltip>MinorA tooltip displays floating content next to a portion of inline content.
Added <rh-footer>MinorA universal footer component.
-
+| Change | Type | Notes | +| ---------------------------------------------------------- | ------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| Added `` | {{j()}} | A Call to Action is a styled link that directs a user to other pages or sometimes displays hidden content. | +| Added `` | {{j()}} | A non-primary navigation for products and subcategory pages. | +| Added `` | {{j()}} | A standalone global footer component. | +| Renamed `` to `` | {{j()}} | Renamed the global slot to universal. | +| Renamed `` to `` | {{j()}} | Renamed the component and all sub components to ``. | +| Added `` | {{i()}} | Spinner consists of an animated circle and sometimes a message, and it indicates that a section is loading. | +| Added `` | {{i()}} | Button is a form-associated custom element. Buttons allow users to perform an action when triggered. | +| Added `` | {{i()}} | A tag is an inline-block element component that provides a distinct visual style for metadata in a UI. | +| Added `` | {{i()}} | Displays a quote with author's name and title. | +| Added `` | {{i()}} | The subnav component is used when an alternate navigation structure is needed to provide additional navigation on a site that does not need the product branding or structural depth that `rh-secondary-nav` provides. | +| Added `` | {{i()}} | A tab set of layered content, including tab widgets and their associated tab panel. | +| Added `` | {{i()}} | Accordion displays multiple, related disclosure widgets. | +| Added `` | {{i()}} | An alert displays auxiliary information on a website. An alert can have one of several states of severity. | +| Added `` | {{i()}} | An Avatar is a placeholder graphic for a photo or an image that is placed to the left or on top of text. | +| Added `` | {{i()}} | Pagination is a web component for navigating paginated content. | +| Added `` | {{i()}} | An element which can be used to display statistics inside of an app. | +| Added `` | {{i()}} | A badge is used to annotate other information with numerical content. | +| Added `` | {{i()}} | A tooltip displays floating content next to a portion of inline content. | +| Added `` | {{i()}} | A universal footer component. | + +
-View version 1.0 release notes +View all version 1.0 release notes @@ -599,11 +306,17 @@ Released April 3, 2023 ## Older versions -For release notes on older versions, please [view our release notes on GitHub](https://github.com/RedHat-UX/red-hat-design-system/releases). +For release notes on older versions, please [view our release notes on +GitHub][releasenotes].

Roadmap

-

For an up-to-date outline of what we're working on and what we're planning to do in the Red Hat Design System, visit our roadmap.

+

For an up-to-date outline of what we're working on and what we're planning + to do in the Red Hat Design System, visit our + roadmap.

+ +[releasenotes]: https://github.com/RedHat-UX/red-hat-design-system/releases +[issues]: https://github.com/RedHat-UX/red-hat-design-system/issues diff --git a/docs/release-notes/prerelease.md b/docs/release-notes/prerelease.md index 447a174543..4ca1613e0c 100644 --- a/docs/release-notes/prerelease.md +++ b/docs/release-notes/prerelease.md @@ -6,12 +6,12 @@ importElements: - rh-table --- - +

Beta release notes

- Return to Release notes + Return to Release notes
@@ -182,11 +182,11 @@ importElements: How we build - Added a How we build page to the About section, it includes details about how to build branded experiences using the various repos. + Added a How we build page to the About section, it includes details about how to build branded experiences using the various repos. Overview - Added an Overview page to the Get started section, it includes details about available libraries, how to access libraries, and includes a video of how to use libraries. + Added an Overview page to the Get started section, it includes details about available libraries, how to access libraries, and includes a video of how to use libraries. Design system kit diff --git a/docs/styles/demo/dev-server.css b/docs/styles/demo/dev-server.css new file mode 100644 index 0000000000..d9eeea4b03 --- /dev/null +++ b/docs/styles/demo/dev-server.css @@ -0,0 +1,62 @@ +@layer + reset, + fonts, + tokens, + typography, + base, + layout; + +@import url('../reset.css') layer(reset); +@import url('../fonts.css') layer(fonts); +@import url('/node_modules/@rhds/tokens/css/global.css') layer(tokens); +@import url('../typography.css') layer(typography); + +@layer base { + /** + * PFE based styles as we do not have control over the + * html layout that is upstream with no current override + */ + #main-header { + --pf-theme--color--surface--accent: black; + --pf-theme--color--accent: black; + } +} + +@layer layout { + html, + body, + #main { height: 100%; } + + [data-demo] { + display: contents; + } + + #main { + display: block; + position: relative; + max-height: initial; + } + + #nav { + height: 100%; + } + + #main-header rh-context-picker { + margin-inline-start: auto; + } + + #main-header a img { + margin-inline-end: 0; + } + + /* offset the padding on the demo container from above */ + rh-context-demo { + min-height: calc(100% + 2 * var(--rh-space-xl, 24px)); + height: auto; + } +} + +#source-control { + margin-inline-start: unset; +} + diff --git a/docs/styles/demo/styles.css b/docs/styles/demo/styles.css new file mode 100644 index 0000000000..7f5606a6b2 --- /dev/null +++ b/docs/styles/demo/styles.css @@ -0,0 +1,16 @@ +@layer + reset, + fonts, + tokens, + typography; + +@import url('../reset.css') layer(reset); +@import url('../fonts.css') layer(fonts); +@import url('/assets/packages/@rhds/tokens/css/global.css') layer(tokens); +@import url('../typography.css') layer(typography); + +html, +body, +main { + height: 100%; +} diff --git a/docs/styles/dev-server/styles.css b/docs/styles/dev-server/styles.css deleted file mode 100644 index d0d931b0b6..0000000000 --- a/docs/styles/dev-server/styles.css +++ /dev/null @@ -1,49 +0,0 @@ -@layer - reset, - fonts, - typography, - base, - layout, - third-party; - -@import url("../reset.css") layer(reset); -@import url("../fonts.css") layer(fonts); -@import url("../typography.css") layer(typography); -@import url("../third-party/prism-rhds.css") layer(third-party); - -@layer base { - /** - * PFE based styles as we do not have control over the - * html layout that is upstream with no current override - */ - #main-header { - --pf-theme--color--surface--accent: black; - --pf-theme--color--accent: black; - } -} - -@layer layout { - [data-demo] { - display: contents; - } - - main { - display: block; - position: relative; - max-height: initial; - } - - #nav { - height: 100%; - } - - #main-header a img { - margin-right: 0; - } - - /* offset the padding on the demo container from above */ - rh-context-demo { - min-height: calc(100% + 2 * var(--rh-space-xl, 24px)); - height: auto; - } -} diff --git a/docs/styles/fonts.css b/docs/styles/fonts.css index 4940ed0b6d..f3c8b8e8ed 100644 --- a/docs/styles/fonts.css +++ b/docs/styles/fonts.css @@ -1,6 +1,6 @@ @font-face { font-family: RedHatDisplay; - src: url("../assets/fonts/RedHatDisplay/RedHatDisplay-Regular.woff"); + src: url('../assets/fonts/RedHatDisplay/RedHatDisplay-Regular.woff'); font-style: normal; font-weight: 300; text-rendering: optimizelegibility; @@ -8,7 +8,7 @@ @font-face { font-family: RedHatDisplay; - src: url("../assets/fonts/RedHatDisplay/RedHatDisplay-Medium.woff"); + src: url('../assets/fonts/RedHatDisplay/RedHatDisplay-Medium.woff'); font-style: normal; font-weight: 400; text-rendering: optimizelegibility; @@ -16,7 +16,7 @@ @font-face { font-family: RedHatDisplay; - src: url("../assets/fonts/RedHatDisplay/RedHatDisplay-Bold.woff"); + src: url('../assets/fonts/RedHatDisplay/RedHatDisplay-Bold.woff'); font-style: normal; font-weight: 700; text-rendering: optimizelegibility; @@ -24,7 +24,7 @@ @font-face { font-family: RedHatText; - src: url("../assets/fonts/RedHatText/RedHatText-Regular.woff"); + src: url('../assets/fonts/RedHatText/RedHatText-Regular.woff'); font-style: normal; font-weight: 400; text-rendering: optimizelegibility; @@ -32,7 +32,7 @@ @font-face { font-family: RedHatText; - src: url("../assets/fonts/RedHatText/RedHatText-Medium.woff"); + src: url('../assets/fonts/RedHatText/RedHatText-Medium.woff'); font-style: normal; font-weight: 700; text-rendering: optimizelegibility; @@ -40,7 +40,7 @@ @font-face { font-family: RedHatMono; - src: url("../assets/fonts/RedHatMono/RedHatMono-Bold.woff2") format("woff2"); + src: url('../assets/fonts/RedHatMono/RedHatMono-Bold.woff2') format('woff2'); font-weight: bold; font-style: normal; font-display: swap; @@ -48,7 +48,7 @@ @font-face { font-family: RedHatMono; - src: url("../assets/fonts/RedHatMono/RedHatMono-BoldItalic.woff2") format("woff2"); + src: url('../assets/fonts/RedHatMono/RedHatMono-BoldItalic.woff2') format('woff2'); font-weight: bold; font-style: italic; font-display: swap; @@ -56,7 +56,7 @@ @font-face { font-family: RedHatMono; - src: url("../assets/fonts/RedHatMono/RedHatMono-Italic.woff2") format("woff2"); + src: url('../assets/fonts/RedHatMono/RedHatMono-Italic.woff2') format('woff2'); font-weight: normal; font-style: italic; font-display: swap; @@ -64,7 +64,7 @@ @font-face { font-family: RedHatMono; - src: url("../assets/fonts/RedHatMono/RedHatMono-Light.woff2") format("woff2"); + src: url('../assets/fonts/RedHatMono/RedHatMono-Light.woff2') format('woff2'); font-weight: 300; font-style: normal; font-display: swap; @@ -72,7 +72,7 @@ @font-face { font-family: RedHatMono; - src: url("../assets/fonts/RedHatMono/RedHatMono-LightItalic.woff2") format("woff2"); + src: url('../assets/fonts/RedHatMono/RedHatMono-LightItalic.woff2') format('woff2'); font-weight: 300; font-style: italic; font-display: swap; @@ -80,7 +80,7 @@ @font-face { font-family: RedHatMono; - src: url("../assets/fonts/RedHatMono/RedHatMono-Medium.woff2") format("woff2"); + src: url('../assets/fonts/RedHatMono/RedHatMono-Medium.woff2') format('woff2'); font-weight: 500; font-style: normal; font-display: swap; @@ -88,7 +88,7 @@ @font-face { font-family: RedHatMono; - src: url("../assets/fonts/RedHatMono/RedHatMono-MediumItalic.woff2") format("woff2"); + src: url('../assets/fonts/RedHatMono/RedHatMono-MediumItalic.woff2') format('woff2'); font-weight: 500; font-style: italic; font-display: swap; @@ -96,7 +96,7 @@ @font-face { font-family: RedHatMono; - src: url("../assets/fonts/RedHatMono/RedHatMono-Regular.woff2") format("woff2"); + src: url('../assets/fonts/RedHatMono/RedHatMono-Regular.woff2') format('woff2'); font-weight: normal; font-style: normal; font-display: swap; @@ -104,7 +104,7 @@ @font-face { font-family: RedHatMono; - src: url("../assets/fonts/RedHatMono/RedHatMono-SemiBold.woff2") format("woff2"); + src: url('../assets/fonts/RedHatMono/RedHatMono-SemiBold.woff2') format('woff2'); font-weight: 600; font-style: normal; font-display: swap; @@ -112,7 +112,7 @@ @font-face { font-family: RedHatMono; - src: url("../assets/fonts/RedHatMono/RedHatMono-SemiBoldItalic.woff2") format("woff2"); + src: url('../assets/fonts/RedHatMono/RedHatMono-SemiBoldItalic.woff2') format('woff2'); font-weight: 600; font-style: italic; font-display: swap; diff --git a/docs/styles/grid.css b/docs/styles/grid.css index 044d973147..e2fc89c79c 100644 --- a/docs/styles/grid.css +++ b/docs/styles/grid.css @@ -5,7 +5,7 @@ .grid { display: grid; grid-template-columns: 1fr; - gap: var(--rh-space-2xl, 32px); + gap: var(--rh-space-2xl); } @container container (min-width: 576px) { @@ -31,10 +31,11 @@ } /* content with image layout */ + /* TODO: possibly a separate layout pattern */ .layout-content-image { grid-template-rows: auto; - grid-template-areas: "image" "content"; + grid-template-areas: 'image' 'content'; } .layout-content-image > .content-block { @@ -48,11 +49,11 @@ @container container (min-width: 768px) { .layout-content-image { grid-template-columns: 2fr 1fr; - grid-template-areas: "content image"; + grid-template-areas: 'content image'; } .layout-content-image.reversed { grid-template-columns: 1fr 2fr; - grid-template-areas: "image content"; + grid-template-areas: 'image content'; } -} \ No newline at end of file +} diff --git a/docs/styles/not-defined.css b/docs/styles/not-defined.css index df1ba1a22b..abdff7b4bf 100644 --- a/docs/styles/not-defined.css +++ b/docs/styles/not-defined.css @@ -5,23 +5,23 @@ uxdot-hero:not(:defined) { align-items: center; } -uxdot-hero:not(:defined) [slot="header"] { - color: var(--rh-color-text-brand-on-light, #ee0000); +uxdot-hero:not(:defined) [slot='header'] { + color: var(--rh-color-text-brand-on-light); margin-block-end: 0; text-transform: uppercase; - font-weight: var(--rh-font-weight-code-medium, 500); - font-size: var(--rh-font-size-code-lg, 1.125rem) !important; + font-weight: var(--rh-font-weight-code-medium); + font-size: var(--rh-font-size-code-lg) !important; } -uxdot-hero:not(:defined) [slot="tagline"] { - font-size: var(--rh-font-size-heading-2xl, 3rem) !important; - margin-block: var(--rh-space-lg, 16px) !important; +uxdot-hero:not(:defined) [slot='tagline'] { + font-size: var(--rh-font-size-heading-2xl) !important; + margin-block: var(--rh-space-lg) !important; text-align: center; } -uxdot-hero:not(:defined) [slot="image"] { +uxdot-hero:not(:defined) [slot='image'] { width: 100%; - margin-block-start: var(--rh-space-4xl, 64px); + margin-block-start: var(--rh-space-4xl); } uxdot-example:not(:defined) img { @@ -31,8 +31,8 @@ uxdot-example:not(:defined) img { rh-subnav:not(:defined) { display: flex; flex-direction: row; - gap: var(--rh-space-md, 8px); - margin-block-start: var(--rh-space-2xl, 32px); + gap: var(--rh-space-md); + margin-block-start: var(--rh-space-2xl); max-width: 100%; overflow-x: scroll; } @@ -40,12 +40,12 @@ rh-subnav:not(:defined) { rh-subnav:not(:defined) a { display: block; white-space: nowrap; - padding: var(--rh-space-lg, 16px) var(--rh-space-2xl, 32px); + padding: var(--rh-space-lg); text-decoration: none; - color: var(--rh-color-text-secondary-on-light, #4d4d4d); + color: var(--rh-color-text-secondary-on-light); position: relative; } rh-subnav:not(:defined) a[active] { - border-block-end: 3px solid var(--rh-color-accent-brand-on-light, #ee0000); + border-block-end: 3px solid var(--rh-color-accent-brand-on-light); } diff --git a/docs/styles/pages/backpage.css b/docs/styles/pages/backpage.css index e3ecefb30b..ca050376e6 100644 --- a/docs/styles/pages/backpage.css +++ b/docs/styles/pages/backpage.css @@ -4,167 +4,168 @@ width: 100%; grid-template-columns: 1fr; grid-template-areas: - "header" - "content"; + 'header' + 'content'; row-gap: var(--rh-space-4xl); &.has-toc { grid-template-areas: - "header" - "aside" - "content"; + 'header' + 'aside' + 'content'; } - @container main (min-width: 992px) { - row-gap: var(--rh-space-6xl); - } + & .aside { + grid-area: aside; + padding-inline: var(--rh-space-lg); - @container main (min-width: 1440px) { - grid-template-columns: - minmax( - var(--container-min-width), - var(--container-max-width) - ) - minmax(14rem, 1fr); - grid-template-areas: - "header header" - "content content"; - - &.has-toc { - grid-template-areas: - "header header" - "content aside"; - - & .aside { - height: max-content; - max-width: 320px; - padding-inline: 0 var(--rh-space-2xl); - position: sticky; - - /* masthead height (72px) + padding (32px) */ - top: calc(var(--uxdot-masthead-max-height) + var(--rh-space-2xl)); - } - - &:has(uxdot-header[has-subnav]) .aside { - /* masthead height (72px) + sub-nav height (56px) + padding (32px) */ - top: calc(var(--uxdot-masthead-max-height) + 56px + var(--rh-space-2xl)); - } + @container main (width >= 1440px) { + padding-inline: 0 var(--rh-space-2xl); } } - } - uxdot-header { - grid-area: header; - } + & .container { + grid-area: content; + container-type: inline-size; + container-name: container; - .aside { - grid-area: aside; - padding-inline: var(--rh-space-lg); + & > section { + margin-block-start: var(--rh-space-6xl); + } - @container main (min-width: 576px) { - padding-inline: var(--rh-space-2xl); - } + & > section:first-of-type { + margin-block-start: 0; + } - @container main (min-width: 768px) { - padding-inline: var(--rh-space-3xl); - } + & h2, + uxdot-copy-permalink h2 { + font-size: var(--rh-font-size-heading-md); /* RHDS h4 heading font size */ + } - @container main (min-width: 992px) { - padding-inline: var(--rh-space-6xl); - } - } + & h3, + uxdot-copy-permalink h3 { + font-size: var(--rh-font-size-heading-sm); /* RHDS h5 heading font size */ + } - .container { - grid-area: content; - container-type: inline-size; - container-name: container; + & h4, + uxdot-copy-permalink h4 { + font-size: var(--rh-font-size-heading-xs); /* RHDS h6 heading font size */ + } - & > section { - margin-block-start: var(--rh-space-6xl); - } + & h5, + uxdot-copy-permalink h5 { + font-size: 1.125rem; /* Not a RHDS token */ + } - & > section:first-of-type { - margin-block-start: 0; - } - } + & h6, + uxdot-copy-permalink h6 { + font-size: 1rem; /* Not a RHDS token */ + } - .container h2, - uxdot-copy-permalink h2 { - font-size: var(--rh-font-size-heading-md); /* RHDS h4 heading font size */ - } + /** + * when in a article container + * where a h2 or uxdot-copy-permalink is used + * as a section break (no landmark) + */ + & > :where(uxdot-copy-permalink.h2, h2), + & > :not(section, uxdot-copy-permalink) > :where(uxdot-copy-permalink.h2, h2), + & > section > :where(uxdot-copy-permalink.h2, h2) { + margin-block-start: var(--rh-space-6xl); + } - .container h3, - uxdot-copy-permalink h3 { - font-size: var(--rh-font-size-heading-sm); /* RHDS h5 heading font size */ - } + /** + * TODO: get rid of inline style/link/script tags inside of container + * if a section, h2 or uxdot-copy-permalink is the first child of an article container + */ + & :where(uxdot-copy-permalink.h2, h2, section):first-child, + & :where(style, link, script):first-child + :where(uxdot-copy-permalink.h2, h2, section), + & :where(style, link, script):first-child + :where( + style, link) + :where(uxdot-copy-permalink.h2, h2, section), + & :where(style, link, script):first-child + :where( + style, link, script) + :where(style, link, script) + :where( + uxdot-copy-permalink.h2, h2, section) { + margin-block-start: 0; + } - .container h4, - uxdot-copy-permalink h4 { - font-size: var(--rh-font-size-heading-xs); /* RHDS h6 heading font size */ - } + /** + * when in a article container + * where a h3 or uxdot-copy-permalink is used + * as a section break (no landmark) + */ + & > :where(uxdot-copy-permalink.h3, h3), + & > :not(section, uxdot-copy-permalink) > :where(uxdot-copy-permalink.h3, h3), + & > section > :where(uxdot-copy-permalink.h3, h3) { + margin-block-start: var(--rh-space-4xl); + } - .container h5, - uxdot-copy-permalink h5 { - font-size: 1.125rem; /* Not a RHDS token */ + /** + * when in a article container + * where a h4 or uxdot-copy-permalink is used + * as a section break (no landmark) + */ + & > :where(uxdot-copy-permalink.h4, h4), + & > :not(section, uxdot-copy-permalink) > :where(uxdot-copy-permalink.h4, h4), + & > section > :where(uxdot-copy-permalink.h4, h4) { + margin-block-start: var(--rh-space-3xl); + } + } } - .container h6, - uxdot-copy-permalink h6 { - font-size: 1rem; /* Not a RHDS token */ + uxdot-header { + grid-area: header; } :where(article .container rh-code-block) { - max-width: 56rem; + max-width: 56rem; /* warning: magic number */ } - /* - when in a article container - where a h2 or uxdot-copy-permalink is used - as a section break (no landmark) - */ - .container > :where(uxdot-copy-permalink.h2, h2), - /* not when the h2 is a child of a section */ - .container > :not(section, uxdot-copy-permalink) > :where(uxdot-copy-permalink.h2, h2), - /* if a section landmark is used */ - .container > section > :where(uxdot-copy-permalink.h2, h2) { - margin-block-start: var(--rh-space-6xl); - } + uxdot-toc { + @container main (width >= 576px) { + padding-inline: var(--rh-space-2xl); + } + + @container main (width >= 768px) { + padding-inline: var(--rh-space-3xl); + } - /* TODO: get rid of inline style/link/script tags inside of container - if a section, h2 or uxdot-copy-permalink is the first child of an article container */ - .container :where(uxdot-copy-permalink.h2, h2, section):first-child, - .container :where(style, link, script):first-child + :where(uxdot-copy-permalink.h2, h2, section), - .container :where(style, link, script):first-child + :where( - style, link) + :where(uxdot-copy-permalink.h2, h2, section), - .container :where(style, link, script):first-child + :where( - style, link, script) + :where(style, link, script) + :where( - uxdot-copy-permalink.h2, h2, section) { - margin-block-start: 0; + @container main (width >= 992px) { + padding-inline: var(--rh-space-6xl); + } + + @container main (width >= 1440px) { + padding-inline: 0; + } } - /* - when in a article container - where a h3 or uxdot-copy-permalink is used - as a section break (no landmark) - */ - .container > :where(uxdot-copy-permalink.h3, h3), - /* not when the h2 is a child of a section */ - .container > :not(section, uxdot-copy-permalink) > :where(uxdot-copy-permalink.h3, h3), - /* if a section landmark is used */ - .container > section > :where(uxdot-copy-permalink.h3, h3) { - margin-block-start: var(--rh-space-4xl); + @container main (width >= 992px) { + article { + row-gap: var(--rh-space-6xl); + } } - /* - when in a article container - where a h4 or uxdot-copy-permalink is used - as a section break (no landmark) - */ - .container > :where(uxdot-copy-permalink.h4, h4), - /* not when the h2 is a child of a section */ - .container > :not(section, uxdot-copy-permalink) > :where(uxdot-copy-permalink.h4, h4), - /* if a section landmark is used */ - .container > section > :where(uxdot-copy-permalink.h4, h4) { - margin-block-start: var(--rh-space-3xl); + /* this follows the @media queries so that it can override the aside */ + @container main (width >= 1440px) { + article { + grid-template-columns: + minmax(var(--container-min-width), + var(--container-max-width)) + minmax(14rem, 1fr); + grid-template-areas: + 'header header' + 'content content'; + } + + article.has-toc { + grid-template-areas: + 'header header' + 'content aside'; + + & uxdot-toc { + max-width: 320px; + position: sticky; + height: max-content; + top: calc(var(--uxdot-masthead-max-height) + var(--rh-space-2xl) * 3); + } + } } } diff --git a/docs/styles/pages/code.css b/docs/styles/pages/code.css index eee4bb4372..4289554d8b 100644 --- a/docs/styles/pages/code.css +++ b/docs/styles/pages/code.css @@ -3,13 +3,13 @@ * Only loaded on the {Element} > Code pages **/ rh-accordion-panel[expanded]::part(container) { - background-color: var(--rh-color-surface-lighter, #f2f2f2); + background-color: var(--rh-color-surface-lighter); } rh-accordion-panel[expanded] rh-table { --rh-table-row-background-hover-color: #f8f8f8; - background-color: var(--rh-color-surface-lightest, #ffffff); + background-color: var(--rh-color-surface-lightest); margin: 0; } @@ -18,7 +18,7 @@ rh-accordion-panel[expanded] rh-table tbody tr:last-child { } rh-accordion-panel[expanded] rh-table th { - font-size: var(--rh-font-size-body-text-sm, 0.875rem); + font-size: var(--rh-font-size-body-text-sm); } rh-accordion-panel[expanded] rh-table :is(pre, code) { @@ -28,3 +28,7 @@ rh-accordion-panel[expanded] rh-table :is(pre, code) { rh-accordion-panel[expanded] rh-table :is(th, td) p { margin-block: 0; } + +rh-accordion details summary { + font-weight: var(--rh-font-weight-heading-medium, 500); +} diff --git a/docs/styles/pages/home.css b/docs/styles/pages/home.css index e406e6ad0b..f360b0223b 100644 --- a/docs/styles/pages/home.css +++ b/docs/styles/pages/home.css @@ -1,12 +1,12 @@ @layer page { /* Homepage */ .container { - padding-block-start: var(--rh-space-4xl, 64px); + padding-block-start: var(--rh-space-4xl); } #feature { display: block; - padding-block: var(--rh-space-3xl, 48px); + padding-block: var(--rh-space-3xl); } #feature::part(container), @@ -19,23 +19,23 @@ } #feature::part(header) { - font-size: var(--rh-font-size-heading-xl, 2.5rem); - color: var(--rh-color-text-brand-on-light, #ee0000); - margin-block-start: var(--rh-space-3xl, 48px); - margin-inline: var(--rh-space-3xl, 48px); + font-size: var(--rh-font-size-heading-xl); + color: var(--rh-color-text-brand-on-light); + margin-block-start: var(--rh-space-3xl); + margin-inline: var(--rh-space-3xl); text-align: center; } #feature::part(body) { justify-content: center; text-align: center; - font-size: var(--rh-font-size-body-text-lg, 1.125rem); + font-size: var(--rh-font-size-body-text-lg); max-width: 55rem; } #feature::part(footer) { - gap: var(--rh-space-3xl, 48px); - margin-block-end: var(--rh-space-3xl, 48px); + gap: var(--rh-space-3xl); + margin-block-end: var(--rh-space-3xl); } #get-started { @@ -44,27 +44,26 @@ } rh-tile > h2 { - font-size: var(--rh-font-size-heading-xs, 1.25rem) !important; - margin-block-start: var(--rh-space-2xl, 32px) !important; + font-size: var(--rh-font-size-heading-xs) !important; + margin-block-start: var(--rh-space-2xl) !important; } #get-started > h2 { - font-size: var(--rh-font-size-heading-lg, 2.25rem); - font-weight: var(--rh-font-weight-heading-medium, 500); - margin-block-start: var(--rh-space-3xl, 48px); - margin-block-end: var(--rh-space-xl, 24px); + font-size: var(--rh-font-size-heading-lg); + font-weight: var(--rh-font-weight-heading-medium); + margin-block: var(--rh-space-3xl); max-width: 100%; /* overrides base max width */ } #get-started > p { max-width: 100%; /* overrides base max width */ - margin: 0 auto var(--rh-space-3xl, 48px); + margin: 0 auto var(--rh-space-3xl); } @container get-started (min-width: 768px) { rh-tile h2 { - font-size: var(--rh-font-size-heading-sm, 1.5rem) !important; - margin-block-start: var(--rh-space-2xl, 32px) !important; + font-size: var(--rh-font-size-heading-sm) !important; + margin-block-start: var(--rh-space-2xl) !important; } } @@ -78,7 +77,7 @@ #contribute { display: block; - margin-block-start: var(--rh-space-5xl, 80px); + margin-block-start: var(--rh-space-5xl); } #contribute::part(container) { @@ -86,21 +85,21 @@ } #contribute::part(header) { - 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", Helvetica, Arial, sans-serif); - font-size: var(--rh-font-size-heading-lg, 2.25rem); + font-family: var(--rh-font-family-heading); + font-size: var(--rh-font-size-heading-lg); } #contribute::part(body) { - font-size: var(--rh-font-size-body-text-lg, 1.125rem); + font-size: var(--rh-font-size-body-text-lg); } #contribute::part(footer) { - padding-block-start: var(--rh-space-xl, 24px); + padding-block-start: var(--rh-space-xl); } @container main (min-width: 576px) { .container { - padding-block-start: var(--rh-space-6xl, 96px); + padding-block-start: var(--rh-space-6xl); } } } diff --git a/docs/styles/reset.css b/docs/styles/reset.css index c7c8da7cce..381f1c8279 100644 --- a/docs/styles/reset.css +++ b/docs/styles/reset.css @@ -1,53 +1,53 @@ +/* Box sizing rules */ +*, +*:before, +*:after { + box-sizing: border-box; +} - /* Box sizing rules */ - *, - *:before, - *:after { - box-sizing: border-box; - } +/* Remove default margin */ +:where(body, +h1, +h2, +h3, +h4, +h5, +h6, +p, +li, +figure, +figcaption, +blockquote, +dl, +dd) { + margin: 0; +} - /* Remove default margin */ - :where(body, - h1, - h2, - h3, - h4, - p, - li, - figure, - figcaption, - blockquote, - dl, - dd) { - margin: 0; - } +/* Default scroll behavior */ +html:focus-within { + scroll-behavior: smooth; +} - /* Default scroll behavior */ - html:focus-within { - scroll-behavior: smooth; - } +/* Inherit fonts for inputs and buttons */ +:where(input, +button, +textarea, +select) { + font: inherit; +} - /* Inherit fonts for inputs and buttons */ - :where(input, - button, - textarea, - select) { - font: inherit; +/* Remove all animations and transitions for people that prefer not to see them */ +@media (prefers-reduced-motion: reduce) { + html:focus-within { + scroll-behavior: auto; } - /* Remove all animations and transitions for people that prefer not to see them */ - @media (prefers-reduced-motion: reduce) { - html:focus-within { - scroll-behavior: auto; - } - - *, - *:before, - *:after { - animation-duration: 0.01ms !important; - animation-iteration-count: 1 !important; - transition-duration: 0.01ms !important; - scroll-behavior: auto !important; - } + *, + *:before, + *:after { + animation-duration: 0.01ms !important; + animation-iteration-count: 1 !important; + transition-duration: 0.01ms !important; + scroll-behavior: auto !important; } } diff --git a/docs/styles/rh-code-block-lightdom.css b/docs/styles/rh-code-block-lightdom.css new file mode 100644 index 0000000000..b266f521ea --- /dev/null +++ b/docs/styles/rh-code-block-lightdom.css @@ -0,0 +1,76 @@ +rh-code-block { + --_styles-applied: true; + & > pre { opacity: 1; } + + & code[class*='language-'], + & pre[class*='language-'] { + color: var(--_code-color); + font-family: var(--rh-font-family-code, RedHatMono, 'Red Hat Mono', 'Courier New', Courier, monospace); + text-align: left; + white-space: pre; + word-spacing: normal; + word-break: normal; + word-wrap: normal; + line-height: var(--rh-line-height-code, 1.5); + tab-size: 4; + hyphens: none; + background: transparent; + } + + & pre[class*='language-']::selection, + & pre[class*='language-'] ::selection, + & code[class*='language-']::selection, + & code[class*='language-'] ::selection { + text-shadow: none; + background: var(--_selected-text-background); + } + + @media print { + & code[class*='language-'], + & pre[class*='language-'] { + text-shadow: none; + } + } + + & .token.atrule { color: var(--_at-rule-color); } + & .token.attr-name { color: var(--_attr-name-color); } + & .token.attr-value { color: var(--_attr-value-color); } + & .token.bold { font-weight: var(--_important-color); } + & .token.boolean { color: var(--_boolean-color); } + & .token.builtin { color: var(--_built-in-color); } + & .token.cdata { color: var(--_cdata-color); } + & .token.char { color: var(--_character-color); } + & .token.class-name { color: var(--_class-name-color); } + & .token.comment { color: var(--_comment-color); } + & .token.constant { color: var(--_constant-color); } + & .token.deleted { color: var(--_deleted-color); } + & .token.function { color: var(--_function-name-color); } + & .token.important { color: var(--_important-color); } + & .token.inserted { color: var(--_inserted-color); } + & .token.keyword { color: var(--_keyword-color); } + & .token.namespace { color: var(--_namespace-color); } + & .token.number { color: var(--_number-color); } + & .token.operator { color: var(--_operator-color); } + & .token.property { color: var(--_property-color); } + & .token.punctuation { color: var(--_punctuation-color); } + & .token.regex { color: var(--_regex-color); } + & .token.selector { color: var(--_selector-color); } + & .token.string { color: var(--_string-color); } + & .token.symbol { color: var(--_symbol-color); } + & .token.tag { color: var(--_tag-color); } + & .token.url { color: var(--_url-color); } + & .token.variable { color: var(--_variable-color); } + + & .token.italic { font-style: italic; } + + & .token.entity { + color: var(--_entity-color); + cursor: help; + } + + & .token.prolog, + & .token.doctype { color: var(--_doctype-color); } + + & .language-css .token.string, + & .style .token.string { color: var(--_operator-color); } +} diff --git a/docs/styles/samp.css b/docs/styles/samp.css index 62c2d2e809..6db80ba899 100644 --- a/docs/styles/samp.css +++ b/docs/styles/samp.css @@ -1,183 +1,249 @@ /* Spacers */ -samp.space { - width: var(--samp-space-size); - aspect-ratio: 1/1; - outline: - var(--rh-border-width-sm, 1px) - dashed - var(--samp-space-color, var(--rh-color-surface-darkest, #151515)); - color: var(--samp-space-color, var(--rh-color-text-primary-on-light, #151515)); - display: flex; - justify-content: center; - align-items: center; - position: relative; - font-size: var(--rh-font-size-body-text-xs, 0.75rem); -} - -samp.space span { - display: flex; - align-items: center; - justify-content: center; - line-height: 1rem; - min-height: 100%; -} - -samp.space:before { - content: ""; - width: var(--samp-space-size); - aspect-ratio: 1/1; - background-color: var(--samp-space-color, var(--rh-color-surface-darkest, #151515)); - opacity: 0.125; - z-index: -1; - position: absolute; -} - -samp.space span.offset { - position: absolute; - left: calc(var(--samp-space-size) + 2px); -} - -samp.space.size-4:before { - opacity: 1; -} - -samp.space.sm, -samp.space.size-6 { - color: #c58c00; -} - -samp.space.size-6:before { - opacity: 1; -} - -samp.space.md, -samp.space.size-8 { - color: #51a549; -} - -/* Lengths */ -samp.length { - width: var(--samp-length-size); - background-color: var(--rh-color-surface-darkest, #151515); - - /* Linting rule issue */ - /* stylelint-disable-next-line rhds/token-values */ - opacity: var(--rh-opacity-60, 0.6); - display: block; - border-bottom: 2px solid var(--rh-color-border-strong-on-light, #151515); - position: relative; -} - -samp.length:before, -samp.length:after { - content: " "; - position: absolute; - display: block; - height: var(--rh-length-xs, 4px); - width: 0; - inset-block: calc(-1 * var(--rh-length-xs, 4px)); - border-style: solid; - border-inline-width: var(--rh-border-width-md, 2px) 0; - border-color: var(--rh-color-border-interactive-on-light, #0066cc); -} - -samp.length:before { - inset-inline: -2px 100%; -} - -samp.length:after { - inset-inline: 100% 2px; -} - -/* Icons */ -samp.icon { - aspect-ratio: 1; - display: block; - width: var(--samp-icon-size); - border: var(--rh-border-width-md, 2px) dotted var(--rh-color-border-strong-on-light, #151515); -} - -/* Fonts */ -samp.font { - font-size: var(--samp-font-size, var(--rh-font-size-body-text-md, 1rem)); - font-family: var(--samp-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-weight: var(--samp-font-weight, var(--rh-font-weight-body-text-regular, 400)); -} - -samp.font.heading { - font-size: var(--samp-font-size, var(--rh-font-size-heading-md, 1.75rem)); - 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", Helvetica, Arial, sans-serif); -} - -samp.font.code { - font-family: var(--rh-font-family-code, RedHatMono, "Red Hat Mono", "Courier New", Courier, monospace); -} - -/* Colors */ -samp.color { - color: var(--samp-color); -} - -samp.color:not(.border, .text) { - aspect-ratio: 1; - height: var(--rh-length-xl, 24px); - display: block; - border-radius: 100%; - border: 1px solid transparent; - background: var(--samp-color); -} - -samp.color:not(.border, .text, .dark) { - border-color: var(--rh-color-border-strong-on-light, #151515); -} - -/* Line height */ -samp.line-height { - line-height: var(--samp-line-height); -} - -/* Box shadow */ -samp.box-shadow { - height: var(--rh-length-2xl, 32px); - aspect-ratio: 1; - border-radius: var(--rh-border-radius-default, 3px); - box-shadow: var(--samp-box-shadow); - display: block; -} - -/* Border */ -samp.border { - width: var(--rh-length-2xl, 32px); - aspect-ratio: 2; - display: block; +samp:not(.swatch) { + &.space { + width: var(--samp-space-size); + aspect-ratio: 1/1; + outline: + var(--rh-border-width-sm) + dashed + var(--samp-space-color, var(--rh-color-surface-darkest)); + color: var(--samp-space-color, var(--rh-color-text-primary-on-light)); + display: flex; + justify-content: center; + align-items: center; + position: relative; + font-size: var(--rh-font-size-body-text-xs); + + & span { + display: flex; + align-items: center; + justify-content: center; + line-height: 1rem; + min-height: 100%; + } + + &:before { + content: ''; + width: var(--samp-space-size); + aspect-ratio: 1/1; + background-color: var(--samp-space-color, var(--rh-color-surface-darkest)); + opacity: 0.125; + z-index: -1; + position: absolute; + } + + & span.offset { + position: absolute; + left: calc(var(--samp-space-size) + 2px); + } + + &.size-4:before { + opacity: 1; + } + + &.sm, + &.size-6 { + color: #c58c00; + } + + &.size-6:before { + opacity: 1; + } + + &.md, + &.size-8 { + color: #51a549; + } + } + + /* Lengths */ + &.length { + width: var(--samp-length-size); + background-color: var(--rh-color-surface-darkest); + + /* Linting rule issue */ + /* stylelint-disable-next-line rhds/token-values */ + opacity: var(--rh-opacity-60); + display: block; + border-bottom: 2px solid var(--rh-color-border-strong-on-light); + position: relative; + + &:before, + &:after { + content: ' '; + position: absolute; + display: block; + height: var(--rh-length-xs); + width: 0; + inset-block: calc(-1 * var(--rh-length-xs)); + border-style: solid; + border-inline-width: var(--rh-border-width-md) 0; + border-color: var(--rh-color-border-interactive-on-light); + } + + &:before { + inset-inline: -2px 100%; + } + + &:after { + inset-inline: 100% 2px; + } + } + + /* Icons */ + &.icon { + aspect-ratio: 1; + display: block; + width: var(--samp-icon-size); + border: var(--rh-border-width-md) dotted var(--rh-color-border-strong); + } + + /* Fonts */ + &.font { + font-size: var(--samp-font-size, var(--rh-font-size-body-text-md)); + font-family: var(--samp-font-family, var(--rh-font-family-body-text)); + font-weight: var(--samp-font-weight, var(--rh-font-weight-body-text-regular)); + + &.heading { + font-size: var(--samp-font-size, var(--rh-font-size-heading-md)); + font-family: var(--rh-font-family-heading); + } + + &.code { + font-family: var(--rh-font-family-code); + } + } + + /* Colors */ + &.color { + color: var(--samp-color); + + &:not(.border, .text) { + aspect-ratio: 1; + height: var(--rh-length-xl); + display: block; + border-radius: 100%; + border: 1px solid transparent; + background: var(--samp-color); + } + + &:not(.border, .text, .dark) { + border-color: var(--rh-color-border-strong-on-light); + } + } + + /* Line height */ + &.line-height { + line-height: var(--samp-line-height); + } + + /* Box shadow */ + &.box-shadow { + height: var(--rh-length-2xl); + aspect-ratio: 1; + border-radius: var(--rh-border-radius-default); + box-shadow: var(--samp-box-shadow); + display: block; + } + + /* Border */ + &.border { + width: var(--rh-length-2xl); + aspect-ratio: 2; + display: block; + border-style: solid; + border-width: var(--samp-space-size, var(--rh-border-width-md)); + border-color: var(--samp-color, var(--rh-color-border-strong-on-light)); + border-radius: var(--samp-radius, var(--rh-border-radius-default)); + + &.sm { + border-width: var(--samp-space-size, var(--rh-border-width-sm)); + } + + &.md { + border-width: var(--samp-space-size, var(--rh-border-width-md)); + } + + &.lg { + border-width: var(--samp-space-size, var(--rh-border-width-lg)); + } + } + + /* Opacity */ + &.opacity { + opacity: var(--samp-opacity); + background-color: black; + display: block; + width: var(--rh-length-xl); + aspect-ratio: 1; + } + + /* Breakpoints */ + &.breakpoint img { + max-height: var(--rh-length-3xl); + } +} + +samp.swatch { + width: max-content; + border-radius: var(--rh-border-radius-pill); + border-width: var(--rh-border-width-sm); border-style: solid; - border-width: var(--samp-space-size, var(--rh-border-width-md, 2px)); - border-color: var(--samp-color, var(--rh-color-border-strong-on-light, #151515)); - border-radius: var(--samp-radius, var(--rh-border-radius-default, 3px)); -} - -samp.border.sm { - border-width: var(--samp-space-size, var(--rh-border-width-sm, 1px)); -} - -samp.border.md { - border-width: var(--samp-space-size, var(--rh-border-width-md, 2px)); -} - -samp.border.lg { - border-width: var(--samp-space-size, var(--rh-border-width-lg, 3px)); -} - -/* Opacity */ -samp.opacity { - opacity: var(--samp-opacity); - background-color: black; - display: block; - width: var(--rh-length-xl, 24px); - aspect-ratio: 1; -} + border-color: oklch(from var(--swatch-color) calc(l + var(--_offset)) c h); + padding: var(--rh-space-xs) var(--rh-space-md); + display: inline; + position: relative; -/* Breakpoints */ -samp.breakpoint img { - max-height: var(--rh-length-3xl, 48px); + /* stylelint-disable-next-line no-descending-specificity */ + & span { + display: block; + width: max-content; + line-height: 1; + inset-block-end: 4px; + } + + &.color { + transition-property: background-color, border-color; + transition-duration: var(--rh-animation-speed); + transition-timing-function: var(--rh-animation-timing); + background-color: var(--swatch-color); + font-family: var(--rh-font-family-body-text); + font-size: var(--rh-font-size-body-text-sm); + + &.isLight { + color: var(--rh-color-text-primary-on-light); + } + + &.isDark { + color: var(--rh-color-text-primary-on-dark); + } + } + + &.font { + color: var(--swatch-color); + transition: color var(--rh-animation-speed) var(--rh-animation-timing); + font-size: var(--rh-font-size-heading-lg); + font-weight: var(--rh-font-weight-heading-bold); + border-radius: var(--rh-border-radius-default); + padding: var(--rh-space-sm) var(--rh-space-md); + + & span:last-child { + font-size: var(--rh-font-size-body-text-md); + } + } + + &.border { + border-color: var(--swatch-color); + border-width: var(--rh-border-width-lg); + } + + &.icon { + display: inline-flex; + align-items: center; + gap: var(--rh-space-xs); + + & rh-icon { + color: var(--swatch-color); + } + } } diff --git a/docs/styles/styles.css b/docs/styles/styles.css index 234d93776f..c13c792236 100644 --- a/docs/styles/styles.css +++ b/docs/styles/styles.css @@ -1,6 +1,7 @@ @layer reset, fonts, + tokens, typography, base, grid, @@ -13,17 +14,18 @@ page, overrides; -@import url("not-defined.css") layer(not-defined); -@import url("reset.css") layer(reset); -@import url("fonts.css") layer(fonts); -@import url("typography.css") layer(typography); -@import url("grid.css") layer(grid); -@import url("lightdom.css") layer(lightdom); -@import url("third-party/prism-rhds.css") layer(third-party); +@import url('not-defined.css') layer(not-defined); +@import url('reset.css') layer(reset); +@import url('fonts.css') layer(fonts); +@import url('/assets/packages/@rhds/tokens/css/global.css') layer(tokens); +@import url('typography.css') layer(typography); +@import url('grid.css') layer(grid); +@import url('lightdom.css') layer(lightdom); +@import url('third-party/prism-rhds.css') layer(third-party); @layer base { body { - color: var(--rh-color-text-primary-on-light); + color: var(--rh-color-text-primary); } :where(p, ul, ol, dl) { @@ -35,22 +37,19 @@ } a { - color: var(--rh-color-interactive-blue-darker); + color: var(--rh-color-interactive-primary-default); } a:hover { - color: var(--rh-color-interactive-blue-darkest); + color: var(--rh-color-interactive-primary-hover); } a:visited { - color: var(--rh-color-interactive-purple-darker); + color: var(--rh-color-interactive-primary-visited-default); } hr { - border-block-start: - var(--rh-border-width-sm) - solid - var(--rh-color-border-subtle-on-light); + border-block-start: var(--rh-border-width-sm) solid var(--rh-color-border-subtle); border-inline: none; border-block-end: none; margin-block-end: var(--rh-space-2xl); @@ -61,7 +60,7 @@ } figcaption { - color: var(--rh-color-text-secondary-on-light); + color: var(--rh-color-text-secondary); } .visually-hidden { @@ -90,23 +89,28 @@ body { display: grid; grid-template-rows: max-content 1fr max-content; - grid-template-areas: "header" "main" "footer"; + grid-template-areas: 'header' 'main' 'footer'; position: relative; min-height: 100dvh; } body:has(uxdot-sidenav:not(:defined)) { grid-template-rows: max-content max-content 1fr max-content; - grid-template-areas: "header" "nav" "main" "footer"; + grid-template-areas: 'header' 'nav' 'main' 'footer'; } - main { + /* stylelint-disable rhds/token-values */ + #main { grid-area: main; - border-inline-start: var(--rh-border-width-sm) solid var(--rh-color-border-subtle-on-light); + border-inline-start: + var(--rh-border-width-sm) + solid + var(--rh-color-border-subtle, var(--rh-color-border-subtle-on-light)); container-type: inline-size; container-name: main; padding-block-start: var(--uxdot-masthead-max-height); } + /* stylelint-enable rhds/token-values */ .container { padding-inline: var(--rh-space-lg); @@ -130,17 +134,17 @@ grid-template-rows: max-content 1fr max-content; grid-template-columns: minmax(300px, 320px) max-content 1fr; grid-template-areas: - "header header header" - "nav main main" - "nav footer footer"; + 'header header header' + 'nav main main' + 'nav footer footer'; } body:has(uxdot-sidenav:not(:defined)) { grid-template-rows: max-content 1fr max-content; grid-template-areas: - "header header header" - "nav main main" - "nav footer footer"; + 'header header header' + 'nav main main' + 'nav footer footer'; } } @@ -202,6 +206,10 @@ margin-block-start: var(--rh-space-2xl); } + rh-cta + uxdot-example { + margin-block-start: var(--rh-space-2xl); + } + rh-table { margin-block: var(--rh-space-3xl); } @@ -230,9 +238,9 @@ * KBD and code pattern **/ - :where(code) { + :where(code:not([class^='language-'])) { padding-inline: var(--rh-space-xs); - background: var(--rh-color-surface-light); + background: oklch(from var(--rh-color-surface) calc(l - 0.05) c h); border-radius: var(--rh-border-radius-default); font-size: var(--rh-font-size-code-md); font-weight: var(--rh-font-weight-code-regular); @@ -248,7 +256,7 @@ } :where(kbd) { - --_uxdot-kbd-color-border: var(--rh-color-border-subtle-on-light); + --_uxdot-kbd-color-border: var(--rh-color-border-subtle); background-color: var(--rh-color-surface-lightest); border-radius: var(--rh-border-radius-default); @@ -300,6 +308,12 @@ top: -118px; /* masthead (72px) + subnav (56px) - header desktop (246px) */ } } + + #edit-this-page { + border-block-start: var(--rh-border-width-sm) solid var(--rh-color-border-subtle); + margin-block-start: var(--rh-space-6xl); + padding-block-start: var(--rh-space-lg); + } } @layer overrides { diff --git a/docs/styles/third-party/prism-rhds.css b/docs/styles/third-party/prism-rhds.css index aa2a504129..fc452e77d5 100644 --- a/docs/styles/third-party/prism-rhds.css +++ b/docs/styles/third-party/prism-rhds.css @@ -10,7 +10,7 @@ * Based off prism.css **/ -:is(code, pre)[class*="language-"] { +:is(code, pre)[class*='language-'] { color: black; background: none; text-shadow: 0 1px white; @@ -25,35 +25,35 @@ hyphens: none; } -pre[class*="language-"]::selection, -pre[class*="language-"] ::selection, -code[class*="language-"]::selection, -code[class*="language-"] ::selection { +pre[class*='language-']::selection, +pre[class*='language-'] ::selection, +code[class*='language-']::selection, +code[class*='language-'] ::selection { text-shadow: none; background: #b3d4fc; } @media print { - code[class*="language-"], - pre[class*="language-"] { + code[class*='language-'], + pre[class*='language-'] { text-shadow: none; } } /* Code blocks */ -pre[class*="language-"] { +pre[class*='language-'] { padding: 1em; margin: 0.5em 0; overflow: auto; } -:not(pre) > code[class*="language-"], -pre[class*="language-"] { +:not(pre) > code[class*='language-'], +pre[class*='language-'] { background: #f5f5f5; } /* Inline code */ -:not(pre) > code[class*="language-"] { +:not(pre) > code[class*='language-'] { padding: 0.1em; border-radius: 0.3em; white-space: normal; diff --git a/docs/styles/tokens-pages.css b/docs/styles/tokens-pages.css new file mode 100644 index 0000000000..3e750e345f --- /dev/null +++ b/docs/styles/tokens-pages.css @@ -0,0 +1,58 @@ +.variants > td { + padding-block: var(--rh-space-md); +} + +uxdot-copy-permalink ~ .token-category > uxdot-copy-permalink { + margin-block-start: var(--rh-space-2xl); +} + +rh-card.swatches { + --rh-card-header-background-on-light: var(--rh-color-surface-light); + --rh-card-header-background-on-dark: var(--rh-color-surface-dark); + + display: block; + + &[color-palette^='light'] { + --_offset: -0.3; + } + + &[color-palette^='dark'] { + --_offset: 0.3; + } + + &::part(header) { + margin: 0; + padding: var(--rh-space-lg) var(--rh-space-2xl); + gap: var(--rh-space-lg); + font-weight: var(--rh-font-weight-heading-regular); + font-size: var(--rh-font-size-body-text-md); + font-family: var(--rh-font-family-body-text); + align-items: center; + flex-flow: row wrap; + } + + & h4 { + font-weight: inherit !important; + font-size: inherit !important; + font-family: inherit !important; + text-transform: uppercase; + + /* deprecated? */ + } + + &::part(body) { + display: flex; + flex-wrap: wrap; + gap: var(--rh-space-md); + } + + & label { + margin-inline-start: auto; + font-size: var(--rh-font-size-body-text-md); + font-weight: var(--rh-font-weight-body-text-regular); + } + + & figure { + margin: 0; + } +} diff --git a/docs/styles/typography.css b/docs/styles/typography.css index 846dfdb884..d2ac3b2a6a 100644 --- a/docs/styles/typography.css +++ b/docs/styles/typography.css @@ -1,53 +1,53 @@ body { - 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-family: var(--rh-font-family-body-text); font-size: 1rem; - line-height: var(--rh-line-height-body-text, 1.5); + line-height: var(--rh-line-height-body-text); } :where(h1, h2, h3, h4, h5, h6) { - 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", Helvetica, Arial, sans-serif); - line-height: var(--rh-line-height-heading, 1.3); + font-family: var(--rh-font-family-heading); + line-height: var(--rh-line-height-heading); } :where(code) { - font-family: var(--rh-font-family-code, RedHatMono, "Red Hat Mono", "Courier New", Courier, monospace); - line-height: var(--rh-line-height-code, 1.5); + font-family: var(--rh-font-family-code); + line-height: var(--rh-line-height-code); } :where(kbd) { - 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-family: var(--rh-font-family-body-text); font-size: 1rem; - line-height: var(--rh-line-height-body-text, 1.5); + line-height: var(--rh-line-height-body-text); } :where(h1) { - font-size: var(--rh-font-size-heading-2xl, 3rem); + font-size: var(--rh-font-size-heading-2xl); } :where(h2) { - font-size: var(--rh-font-size-heading-xl, 2.5rem); + font-size: var(--rh-font-size-heading-xl); } :where(h3) { - font-size: var(--rh-font-size-heading-lg, 2.25rem); + font-size: var(--rh-font-size-heading-lg); } :where(h4) { - font-size: var(--rh-font-size-heading-md, 1.75rem); + font-size: var(--rh-font-size-heading-md); } :where(h5) { - font-size: var(--rh-font-size-heading-sm, 1.5rem); + font-size: var(--rh-font-size-heading-sm); } :where(h6) { - font-size: var(--rh-font-size-heading-xs, 1.25rem); + font-size: var(--rh-font-size-heading-xs); } :where(p) { - font-size: var(--rh-font-size-body-text-md, 1rem); + font-size: var(--rh-font-size-body-text-md); } :where(p, h1, h2, h3, h4, h5, h6, li) { - max-width: 56rem; + max-width: 56rem; /* warning: magic number */ } diff --git a/docs/support/index.md b/docs/support/index.md index 44c9121bb7..630a4e9aa8 100644 --- a/docs/support/index.md +++ b/docs/support/index.md @@ -5,12 +5,12 @@ hasToc: false tags: - support importElements: - - rh-tile + - rh-tile - rh-tag --- - - + + + + + +The Red Hat Design System features a powerful, flexible, and easy-to-use theming system. + +## What is theming? + +We use theming to modify our elements and patterns so they fit a specific visual style. Themes can be applied to an element, a page, or a UI. A common theming use case is dark theme or dark mode. + +## How does it work? + +Our design system includes built-in branded and accessible defaults, so all you need to do if you want to create digital experiences that feel like Red Hat is to write a few lines of HTML. + +When we want to flex our design muscles, our elements include powerful theming primitives in the form of **slots**, **design tokens**, and **CSS shadow parts**. These primitives enable you to theme a single element, section, page, or entire app UI. + + diff --git a/docs/theming/patterns/band.html b/docs/theming/patterns/band.html new file mode 100644 index 0000000000..4ffd051c71 --- /dev/null +++ b/docs/theming/patterns/band.html @@ -0,0 +1,89 @@ + +
+ +

Card

+

Lorem ipsum dolor sit amet, consectetur adipiscing elit. + Nullam eleifend elit sed est egestas, a sollicitudin mauris + tincidunt.

+ + Call to action + +
+ +

Card

+

Lorem ipsum dolor sit amet, consectetur adipiscing elit. + Nullam eleifend elit sed est egestas, a sollicitudin mauris + tincidunt.

+ + Call to action + +
+ +

Card

+

Lorem ipsum dolor sit amet, consectetur adipiscing elit. + Nullam eleifend elit sed est egestas, a sollicitudin mauris + tincidunt.

+ + Call to action + +
+
+
+ + diff --git a/docs/theming/patterns/card-bordeaux.html b/docs/theming/patterns/card-bordeaux.html new file mode 100644 index 0000000000..7a5a56a225 --- /dev/null +++ b/docs/theming/patterns/card-bordeaux.html @@ -0,0 +1,75 @@ + +
    +
  • This card uses a custom theme
  • +
  • Links also are affected
  • +
  • See how it reacts when you change the color-palette
  • +
+ Call to action +
+ + + You can also set a color palette on a specific element + + + + + diff --git a/docs/theming/patterns/card-child-consumers.html b/docs/theming/patterns/card-child-consumers.html new file mode 100644 index 0000000000..9b4474ece2 --- /dev/null +++ b/docs/theming/patterns/card-child-consumers.html @@ -0,0 +1,16 @@ + +

+ The card and CTA respond to the theme of their container. + On a light container, the CTA uses the light theme, and dark on dark. +

+ Fine! +
+ + +

+ The card uses the "darkest" palette. + The CTA is always themed with the "dark" theme, because the card + sets its own palette, rather than responding to it's container's. +

+ Nice! +
diff --git a/docs/theming/patterns/card-consumer-provider.html b/docs/theming/patterns/card-consumer-provider.html new file mode 100644 index 0000000000..a3dbb5adcb --- /dev/null +++ b/docs/theming/patterns/card-consumer-provider.html @@ -0,0 +1,23 @@ + +

Consumer

+ passive +

This card acts as a consumer. + It will always receive its parent's ColorTheme.

+ Read card docs +
+ + +

Provider

+ active +

This card acts as a provider. + Try changing this card's + color-palette + and see how it affects this card's children. +

+ + Read CTA docs +
+ diff --git a/docs/theming/patterns/card-default-vs-set-palette.html b/docs/theming/patterns/card-default-vs-set-palette.html new file mode 100644 index 0000000000..a1caa1e629 --- /dev/null +++ b/docs/theming/patterns/card-default-vs-set-palette.html @@ -0,0 +1,13 @@ + +

+ This card uses the default + color palette. +

+
+ + +

+ This card uses the author-set + "darkest" color palette. +

+
diff --git a/docs/theming/patterns/collage.html b/docs/theming/patterns/collage.html new file mode 100644 index 0000000000..361dfd41f1 --- /dev/null +++ b/docs/theming/patterns/collage.html @@ -0,0 +1,75 @@ +
+ + + Results from Customer Portal + +

Hey now! They're all looking pretty good!

+
+
+ Get started + + +
    +
  1. 1
  2. +
  3. 2
  4. +
  5. 3
  6. +
  7. 4
  8. +
  9. 5
  10. +
+
+ +

Create, manage, and dynamically scale automation across your entire enterprise.

+ Get product details +
+

More cloud choice. Less cloud management.

+ + App development and delivery + Modernize existing apps + AI/ML + Edge computing + +
+ + diff --git a/docs/theming/patterns/patterns.11tydata.yaml b/docs/theming/patterns/patterns.11tydata.yaml new file mode 100644 index 0000000000..6f31564eca --- /dev/null +++ b/docs/theming/patterns/patterns.11tydata.yaml @@ -0,0 +1 @@ +eleventyExcludeFromCollections: true diff --git a/docs/theming/theming.11tydata.yaml b/docs/theming/theming.11tydata.yaml new file mode 100644 index 0000000000..0db39920b2 --- /dev/null +++ b/docs/theming/theming.11tydata.yaml @@ -0,0 +1,3 @@ +layout: layouts/pages/basic.njk +tags: + - theming diff --git a/docs/tokens/index.md b/docs/tokens/index.md index 276c891351..1595bbd3ba 100644 --- a/docs/tokens/index.md +++ b/docs/tokens/index.md @@ -1,6 +1,6 @@ --- layout: layouts/pages/basic.njk -title: Overview +title: Overvie hasToc: true tokenSearch: true importElements: @@ -8,10 +8,10 @@ importElements: - rh-code-block --- - + - - -{% category path = cat.path or cat.slug, - name = cat.path and cat.slug, - exclude = cat.exclude, - include = cat.include %} - -{% include 'partials/component/feedback.html' %} diff --git a/elements/rh-accordion/context.ts b/elements/rh-accordion/context.ts index 64dd3ac94c..b6adb2d80e 100644 --- a/elements/rh-accordion/context.ts +++ b/elements/rh-accordion/context.ts @@ -3,6 +3,8 @@ import { createContextWithRoot } from '@patternfly/pfe-core/functions/context.js export interface RhAccordionContext { accents?: 'inline' | 'bottom'; large: boolean; + /** if this accordion has at least one expanded panel */ + expanded: boolean; } export const context = createContextWithRoot(Symbol('rh-accordion-context')); diff --git a/elements/rh-accordion/demo/initially-expanded.html b/elements/rh-accordion/demo/initially-expanded.html new file mode 100644 index 0000000000..48436520f2 --- /dev/null +++ b/elements/rh-accordion/demo/initially-expanded.html @@ -0,0 +1,21 @@ + + +

Item One

+ +

Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.

+
+ +

Item Two

+ +

Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.

+
+ +

Item Three

+ +

Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.

+
+
+ + diff --git a/elements/rh-accordion/docs/10-style.md b/elements/rh-accordion/docs/10-style.md index e670346392..8bea1353dd 100644 --- a/elements/rh-accordion/docs/10-style.md +++ b/elements/rh-accordion/docs/10-style.md @@ -4,7 +4,7 @@ Accordion panels include title text, a chevron icon, body text, and other conten ### Anatomy - Anatomy of an accordion with lots of annotations pointing to various parts + Anatomy of an accordion with lots of annotations pointing to various parts 1) Collapsed panel @@ -22,7 +22,7 @@ Accordion panels include title text, a chevron icon, body text, and other conten There are two available sizes and the only difference is the title text size. You can use the Small size on large breakpoints, but not the Large size on small breakpoints due to the potential of long title text wrapping to more than two lines. - A large size accordion with text underneath saying ‘Large size’ and a small size accordion with text underneath saying ‘Small size’ + A large size accordion with text underneath saying ‘Large size’ and a small size accordion with text underneath saying ‘Small size’ ## Theme @@ -30,13 +30,13 @@ An accordion is available in both light and dark themes. The light theme expande ### Light theme - Light theme accordion with an expanded panel + Light theme accordion with an expanded panel ### Dark theme - Dark theme accordion with an expanded panel + Dark theme accordion with an expanded panel ## Configuration @@ -44,7 +44,7 @@ An accordion is available in both light and dark themes. The light theme expande An expanded panel does not have a maximum height, but it may scroll if constrained by vertical space. The width of an accordion varies based on content and page layout. Title text and icons are horizontally aligned. - How an accordion is constructed showing alignment, space, scrolling, and width details + How an accordion is constructed showing alignment, space, scrolling, and width details ### Accent slot @@ -52,27 +52,27 @@ An expanded panel does not have a maximum height, but it may scroll if constrain The accent slot can be positioned inline or below the panel's title. This can contain tags, badges, or other small elements with secondary information. - Accordion panel with two tags in inline accent slot and an accordion with two tags below the title + Accordion panel with two tags in inline accent slot and an accordion with two tags below the title ### Nested panels Panels can be nested to help organize complex or granular sections of content. - An accordion with an expanded panel and a nested expanded panel + An accordion with an expanded panel and a nested expanded panel ### Stacked panels Multiple panels can be expanded simultaneously even when nested. - An accordion with one collapsed panel on top and two stacked expanded panels below + An accordion with one collapsed panel on top and two stacked expanded panels below ## Space - Accordion spacing within panels and in between elements like titles, body text, rules, and icons + Accordion spacing within panels and in between elements like titles, body text, rules, and icons @@ -90,11 +90,11 @@ Interaction states are visual representations used to communicate the status of ### Hover - Light theme accordion with a hover state + Light theme accordion with a hover state - Dark theme accordion with a hover state + Dark theme accordion with a hover state @@ -120,11 +120,11 @@ Interaction states are visual representations used to communicate the status of ### Focus - Light theme accordion with a focus state + Light theme accordion with a focus state - Dark theme accordion with a focus state + Dark theme accordion with a focus state @@ -154,11 +154,11 @@ Interaction states are visual representations used to communicate the status of ### Active - Light theme accordion with an active state + Light theme accordion with an active state - Dark theme accordion with an active state + Dark theme accordion with an active state diff --git a/elements/rh-accordion/docs/20-guidelines.md b/elements/rh-accordion/docs/20-guidelines.md index bbbd630100..506082524d 100644 --- a/elements/rh-accordion/docs/20-guidelines.md +++ b/elements/rh-accordion/docs/20-guidelines.md @@ -1,30 +1,50 @@ -## Usage -Use an accordion to organize a large amount of content into sections. This allows users to scan through critical information first and then access additional information when needed. Users can also compare information by expanding multiple panels simultaneously. - -### When to use an accordion -Using an accordion provides an easy way to organize content while reducing page scrolling, but at the expense of hiding information or burdening users with more clicks. There is a chance that important information will be missed or not immediately noticed by users. Therefore, if reading important information is critical to the user experience or if important information requires more focus and less clicking, it is advised to not use an accordion. - -### Accordion vs. disclosure -An accordion is used to organize important information whereas a [Disclosure](/patterns/disclosure/) can be used to organize secondary information that might not be critical to read or impact the experience. An accordion can also accommodate multiple sections of content, whereas a disclosure can only accommodate one. +## Usage +Use an accordion to organize a large amount of content into sections. This +allows users to scan through critical information first and then access +additional information when needed. Users can also compare information by +expanding multiple panels simultaneously. + +### When to use an accordion +Using an accordion provides an easy way to organize content while reducing page +scrolling, but at the expense of hiding information or burdening users with more +clicks. There is a chance that important information will be missed or not +immediately noticed by users. Therefore, if reading important information is +critical to the user experience or if important information requires more focus +and less clicking, it is advised to not use an accordion. + +### Accordion vs. disclosure +An accordion is used to organize important information whereas a +[Disclosure](/patterns/disclosure/) can be used to organize secondary +information that might not be critical to read or impact the experience. An +accordion can also accommodate multiple sections of content, whereas a +disclosure can only accommodate one. - Comparison of how to use accordion vs. disclosure elements showing an accordion on top and a disclosure on the bottom + Comparison of how to use accordion vs. disclosure elements showing an accordion on top and a disclosure on the bottom -### Sizes -It is acceptable to use the Small size on large breakpoints, but do not use the Large size on small breakpoints. +### Sizes +It is acceptable to use the Small size on large breakpoints, but do not use the +Large size on small breakpoints. - Size comparison of accordions; a wide small size accordion is on top, which is acceptable to use, and a thin large size accordion below it which is not acceptable to use + Size comparison of accordions; a wide small size accordion is on top, which is acceptable to use, and a thin large size accordion below it which is not acceptable to use +## Writing content -## Writing content -### Title text -Title text should be written concisely so users know what to expect when they expand a panel. Beware of long character counts especially on small breakpoints or when translated. If title text is too long, create another section. Do not write title text to sound like a call to action, make it as easy as possible for users to understand the content within. +### Title text +Title text should be written concisely so users know what to expect when they +expand a panel. Beware of long character counts especially on small breakpoints +or when translated. If title text is too long, create another section. Do not +write title text to sound like a call to action, make it as easy as possible for +users to understand the content within. - Title text examples of various lengths; it should not be too long, too short, or too vague + Title text examples of various lengths; it should not be too long, too short, or too vague 1) Title text is too long and should be broken into two sections @@ -32,140 +52,121 @@ Title text should be written concisely so users know what to expect when they ex 3) Title text should not be written like a call to action {.example-notes} -### Character count -Title text should have fewer characters to help users make sense of what the content will be when they expand a panel. +### Character count + +Title text should have fewer characters to help users make sense of what the +content will be when they expand a panel. - - - - - - - - - - - - - -
Title textCharacter count
Title text65
+ +| Title text | Character count | +|------------|-----------------| +| Title text | 65 | +
- -### Panel content -When a panel is expanded, some content must appear below the title text and chevron icon. Content can include text, cards, images, etc. Text blocks should not exceed `750px` to maintain optimal readability. + +### Panel content + +When a panel is expanded, some content must appear below the title text and +chevron icon. Content can include text, cards, images, etc. Text blocks should +not exceed `750px` to maintain optimal readability. - Accordion showing different elements you may include in the expanded panel like headings, body text, links, cards, and more + Accordion showing different elements you may include in the expanded panel like headings, body text, links, cards, and more -### Long title text +### Long title text + Title text can be two lines on small breakpoints, but no more. - Two accordions; one wide accordion with the text title on one line and one thin accordion with the text title on two lines + Two accordions; one wide accordion with the text title on one line and one thin accordion with the text title on two lines -## Layout -The width of an accordion can be adjusted on large breakpoints to fit fewer columns if necessary. +## Layout + +The width of an accordion can be adjusted on large breakpoints to fit fewer +columns if necessary. - A wider accordion placed on a 12-column grid and occupying four grid columns + A wider accordion placed on a 12-column grid and occupying four grid columns ## Behavior -### Expanding and collapsing panels -Users can expand and collapse panels one at a time by default. More than one or all panels cannot be expanded at once unless that functionality is added along with an **Expand all** button. When a panel is collapsed, the caret points down. When a panel is expanded, the caret animates to point up. +### Expanding and collapsing panels +Users can expand and collapse panels one at a time by default. More than one or +all panels cannot be expanded at once unless that functionality is added along +with an **Expand all** button. When a panel is collapsed, the caret points down. +When a panel is expanded, the caret animates to point up. -### Expanding multiple panels -Users can expand multiple panels simultaneously either stacked on top of each other or not. Expanding one panel does not collapse another. +### Expanding multiple panels +Users can expand multiple panels simultaneously either stacked on top of each +other or not. Expanding one panel does not collapse another. - - Two accordions; one is showing two expanded panels stacked on top of each other and the other is showing two expanded panels and one collapsed panel in between + + Two accordions; one is showing two expanded panels stacked on top of each other and the other is showing two expanded panels and one collapsed panel in between -## Responsive design -An accordion changes from the Large size to the Small size as breakpoints get smaller. +## Responsive design + +An accordion changes from the Large size to the Small size as breakpoints get +smaller. - Accordions on large breakpoints + Accordions on large breakpoints - Accordions on small breakpoints + Accordions on small breakpoints ### Breakpoints - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
BreakpointRangeSize
Desktop, large> 1680pxSmall and Large
Desktop, medium1440px - 1679pxSmall and Large
Desktop, small1200px - 1439pxSmall and Large
Tablet, large992px - 1199pxSmall and Large
Tablet, small768px - 991pxSmall and Large
Mobile, large576px - 767pxSmall only
Mobile, small< 575pxSmall only
+ +| Breakpoint | Range | Size | +|-----------------|-----------------|-----------------| +| Desktop, large | > 1680px | Small and Large | +| Desktop, medium | 1440px - 1679px | Small and Large | +| Desktop, small | 1200px - 1439px | Small and Large | +| Tablet, large | 992px - 1199px | Small and Large | +| Tablet, small | 768px - 991px | Small and Large | +| Mobile, large | 576px - 767px | Small only | +| Mobile, small | < 575px | Small only | +
-## Best practices -### One panel +## Best practices +### One panel + Do not display one panel only, use an expandable section instead. - Accordion having only one panel is incorrect usage + Accordion having only one panel is incorrect usage -### Text readability +### Text readability + Text within panels should not exceed `750px` to maintain optimal readability. - Accordion with body text exceeding 750px wide which is incorrect usage + Accordion with body text exceeding 750px wide which is incorrect usage +### Mixing themes -### Mixing themes Do not use a dark theme accordion in a light theme environment and vice versa. - Do not use a dark theme accordion in a light theme environment and vice versa + Do not use a dark theme accordion in a light theme environment and vice versa diff --git a/elements/rh-accordion/docs/40-accessibility.md b/elements/rh-accordion/docs/40-accessibility.md index 72b7c1dfc0..df7b3fc305 100644 --- a/elements/rh-accordion/docs/40-accessibility.md +++ b/elements/rh-accordion/docs/40-accessibility.md @@ -2,7 +2,7 @@ Each panel is a focus stop where `Enter` or `Space` expands or collapses each panel. - Accordion keyboard interactions; pressing Tab will focus the top panel, pressing Tab again will move focus to the next panel underneath, and pressing Enter or Space will expand the panel + Accordion keyboard interactions; pressing Tab will focus the top panel, pressing Tab again will move focus to the next panel underneath, and pressing Enter or Space will expand the panel @@ -35,14 +35,14 @@ Each panel is a focus stop where `Enter` or `Space` expands or collapses each pa {% include 'partials/accessibility/focusorder.md' %} - Accordion showing the order how focus moves through the element when pressing Tab continuously + Accordion showing the order how focus moves through the element when pressing Tab continuously ## Touch targets Each panel is selectable instead of only title text or the chevrons. - Accordion showing touch target size examples for large and small sizes + Accordion showing touch target size examples for large and small sizes {% include 'partials/accessibility/ariaguide.md' %} diff --git a/elements/rh-accordion/docs/rh-accordion.md b/elements/rh-accordion/docs/rh-accordion.md deleted file mode 100644 index caec4ac616..0000000000 --- a/elements/rh-accordion/docs/rh-accordion.md +++ /dev/null @@ -1,17 +0,0 @@ -{% renderOverview %} - -{% endrenderOverview %} - -## Usage - -{% renderSlots %}{% endrenderSlots %} - -{% renderAttributes %}{% endrenderAttributes %} - -{% renderMethods %}{% endrenderMethods %} - -{% renderEvents %}{% endrenderEvents %} - -{% renderCssCustomProperties %}{% endrenderCssCustomProperties %} - -{% renderCssParts %}{% endrenderCssParts %} diff --git a/elements/rh-accordion/rh-accordion-header.css b/elements/rh-accordion/rh-accordion-header.css index 9c0bd63894..907839767f 100644 --- a/elements/rh-accordion/rh-accordion-header.css +++ b/elements/rh-accordion/rh-accordion-header.css @@ -3,13 +3,10 @@ --_padding-inline-end: var(--rh-space-xl, 24px); --_padding-block-end: var(--rh-space-lg, 16px); --_padding-inline-start: var(--rh-space-xl, 24px); - --_text-color: var(--rh-color-text-primary-on-light, #151515); - --_active-text-color: var(--rh-color-text-primary-on-light, #151515); - --_background-color: var(--rh-color-surface-lightest, #ffffff); - --_active-background-color: var(--_rhds-background-color, #f2f2f2); + --_active-text-color: var(--rh-color-text-primary); --_font-size: var(--rh-font-size-body-text-lg, 1.125rem); --_after-background-color: transparent; - --_expanded-background-color: var(--rh-color-accent-brand-on-light, #ee0000); + --_expanded-background-color: var(--rh-color-accent-brand); --_isRTL: -1; } @@ -17,8 +14,8 @@ font-size: 100%; padding: 0; margin: 0; - color: var(--rh-color-text-primary-on-light, #151515); - background-color: var(--_rhds-background-color, var(--rh-color-surface-lightest, #ffffff)); + color: var(--rh-color-text-primary); + background-color: var(--rh-color-surface); font-weight: var(--rh-font-weight-heading-medium, 500); } @@ -27,14 +24,6 @@ a { cursor: pointer; } -.dark { - --_text-color: var(--rh-color-text-primary-on-dark, #ffffff); - --_background-color: var(--rh-color-surface-darkest, #151515); - --_active-background-color: var(--rh-color-surface-darkest, #151515); - --_active-text-color: var(--rh-color-text-primary-on-dark, #ffffff); - --_expanded-background-color: var(--rh-color-accent-brand-on-dark, #ee0000); -} - .rtl { --_isRTL: 1; } @@ -50,19 +39,19 @@ a { border-inline-end: var(--rh-border-width-sm, 1px) solid - var(--_border-color, var(--rh-color-border-subtle-on-dark, #707070)); + var(--rh-color-border-subtle); } :host(.animating) #button, :host([expanded]) #button { - border-inline-end-color: var(--rh-color-border-subtle-on-light, #c7c7c7); - border-inline-start-color: var(--rh-color-border-subtle-on-light, #c7c7c7); + border-inline-end-color: var(--rh-color-border-subtle); + border-inline-start-color: var(--rh-color-border-subtle); } #button, #button:before, #button:after { - background-color: var(--_background-color, transparent); + background-color: var(--rh-color-surface); } #icon { @@ -79,14 +68,13 @@ a { var(--_padding-inline-end) var(--_padding-block-end) var(--_padding-inline-start); - 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-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(--_font-size); - font-weight: var(--rh-font-weight-body-text-medium, 500); - color: var(--_text-color); + color: var(--rh-color-text-primary); } #button #icon { - fill: var(--_text-color); + fill: currentcolor; } #button:after { @@ -100,7 +88,7 @@ span { text-align: start; } -[part="container"] { +[part='container'] { display: flex; gap: var(--rh-space-xl, 24px); container-type: inline-size; @@ -109,20 +97,24 @@ span { #header-container { display: flex; gap: var(--rh-space-md, 8px); +} - &.bottom { - flex-direction: column; - } +#header-container.bottom { + flex-direction: column; +} + +#header-text { + font-weight: var(--rh-font-weight-heading-bold, 700); } -[part="accents"] { +[part='accents'] { display: flex; flex-wrap: wrap; gap: var(--rh-space-md, 8px); } .expanded #button { - --_after-background-color: var(--_expanded-background-color); + --_after-background-color: var(--rh-color-accent-brand); } .expanded #button #icon { @@ -132,7 +124,7 @@ span { #button:hover, #button:active, #button:focus { - background-color: var(--_active-background-color); + background-color: var(--rh-color-surface); } #button:hover span, @@ -157,12 +149,20 @@ span { } .toggle:after { - content: ""; + content: ''; position: absolute; inset-block: 0; inset-inline-start: 0; } +.expanded.on.light { + --rh-color-surface: var(--rh-color-surface-lightest, #ffffff); +} + +.expanded.on.dark { + --rh-color-surface: var(--rh-color-surface-darkest, #151515); +} + @container (min-width: 576px) { #header-container:not(.bottom) { flex-direction: row; diff --git a/elements/rh-accordion/rh-accordion-header.ts b/elements/rh-accordion/rh-accordion-header.ts index d22193107f..5400ae0398 100644 --- a/elements/rh-accordion/rh-accordion-header.ts +++ b/elements/rh-accordion/rh-accordion-header.ts @@ -40,15 +40,13 @@ const isAccordion = (x: EventTarget): x is RhAccordion => * @csspart text - inline element containing the heading text or slotted heading content * @csspart accents - container for accents within the header * @slot - accordion toggle content - * @slot accents + * @slot accents - * These elements will appear inline by default with the header title, between the header and the chevron * (or after the chevron and header in disclosure mode). There is an option to set the accents placement to bottom * @fires {AccordionHeaderChangeEvent} change - when the open panels change */ @customElement('rh-accordion-header') export class RhAccordionHeader extends LitElement { - static readonly version = '{{version}}'; - static readonly styles = [styles]; @property({ type: Boolean, reflect: true }) expanded = false; @@ -87,12 +85,12 @@ export class RhAccordionHeader extends LitElement { const { accents, large = false } = this.ctx ?? {}; const rtl = this.#dir.dir === 'rtl'; return html` -
+
+ + +
+ ${this.label} + + `; + } + + #onPlaybackRateSelect(event: Event) { + if (!this.disabled && event.target instanceof HTMLSelectElement) { + const val = !event.target.value ? 1.00 : parseFloat(event.target.value); + this.dispatchEvent(new RhAudioPlayerRateSelectEvent(val)); + } + } + + #validPlaybackRate(number: number) { + const { pbrMax, pbrStep, pbrMin } = RhAudioPlayerRateStepper; + // ensures number between min and maxk + const inRange = Math.max(pbrMin, Math.min(pbrMax, number)); + // used to round number to nearest step + const multiplier = 1 / pbrStep; + return Math.round(inRange * multiplier) / multiplier; + } + + /** + * Increases media playback rate by playback rate step value + */ + #inc() { + this.#fire(this.playbackRate + RhAudioPlayerRateStepper.pbrStep); + } + + /** + * Decreases media playback rate by playback rate step value + */ + #dec() { + this.#fire(this.playbackRate - RhAudioPlayerRateStepper.pbrStep); + } + + #fire(rate: number) { + if (this.#validPlaybackRate(rate)) { + const event = new RhAudioPlayerRateSelectEvent(rate); + this.dispatchEvent(event); + } + } +} + +export class RhAudioPlayerRateSelectEvent extends Event { + constructor(public playbackRate: number) { + super('playback-rate-select', { bubbles: true, cancelable: true }); + } +} + +declare global { + interface HTMLElementTagNameMap { + 'rh-audio-player-rate-stepper': RhAudioPlayerRateStepper; + } + interface HTMLElementEventMap { + 'playback-rate-select': RhAudioPlayerRateSelectEvent; + 'rh-audio-player-rate-stepper': RhAudioPlayerRateStepper; + } +} diff --git a/elements/rh-audio-player/rh-audio-player-scrolling-text-overflow.css b/elements/rh-audio-player/rh-audio-player-scrolling-text-overflow.css index c611324c85..8c9b2b047d 100644 --- a/elements/rh-audio-player/rh-audio-player-scrolling-text-overflow.css +++ b/elements/rh-audio-player/rh-audio-player-scrolling-text-overflow.css @@ -20,18 +20,14 @@ overflow-y: visible; --_fade-color: - var( - --rh-audio-player-scrolling-text-overflow-background-color, - var(--rh-color-surface-lightest, #ffffff) - ); + var(--rh-audio-player-scrolling-text-overflow-background-color, + var(--rh-color-surface-lightest, #ffffff)); } #outer.dark { --_fade-color: - var( - --rh-audio-player-scrolling-text-overflow-background-color, - var(--rh-color-surface-darkest, #151515) - ); + var(--rh-audio-player-scrolling-text-overflow-background-color, + var(--rh-color-surface-darkest, #151515)); } #outer.rtl { @@ -59,7 +55,7 @@ slot { #fade { position: absolute; height: 150%; - content: " "; + content: ' '; top: -25%; right: 0; width: 3em; diff --git a/elements/rh-audio-player/rh-audio-player-scrolling-text-overflow.ts b/elements/rh-audio-player/rh-audio-player-scrolling-text-overflow.ts index c1874fd038..0821deb196 100644 --- a/elements/rh-audio-player/rh-audio-player-scrolling-text-overflow.ts +++ b/elements/rh-audio-player/rh-audio-player-scrolling-text-overflow.ts @@ -6,7 +6,6 @@ import { colorContextConsumer, type ColorTheme } from '../../lib/context/color/c import styles from './rh-audio-player-scrolling-text-overflow.css'; - /** * Audio Player Scrolling Text Overflow * @slot - inline text to scroll if wider than host @@ -21,13 +20,18 @@ export class RhAudioPlayerScrollingTextOverflow extends LitElement { #scrolling = false; - #style = getComputedStyle(this); + #style?: CSSStyleDeclaration; get #isScrollable() { const outer = this.shadowRoot?.getElementById('outer'); return (outer?.scrollWidth ?? 0) > (outer?.clientWidth ?? 0); } + connectedCallback(): void { + super.connectedCallback(); + this.#style = getComputedStyle(this); + } + firstUpdated() { const letters = this.textContent?.length || 0; const ms = Math.round(letters * 400); @@ -36,15 +40,15 @@ export class RhAudioPlayerScrollingTextOverflow extends LitElement { } render() { - const { on = '' } = this; - const { direction } = this.#style; + const { on = 'light' } = this; + const { direction } = this.#style ?? {}; return html`
+ class="${classMap({ [on]: true, [direction || 'auto']: true })}" + @mouseover=${this.startScrolling} + @mouseout=${this.stopScrolling} + @focus=${this.startScrolling} + @blur=${this.stopScrolling}>
diff --git a/elements/rh-audio-player/rh-audio-player-subscribe.css b/elements/rh-audio-player/rh-audio-player-subscribe.css index 63fe17b679..bb785b2e7f 100644 --- a/elements/rh-audio-player/rh-audio-player-subscribe.css +++ b/elements/rh-audio-player/rh-audio-player-subscribe.css @@ -1,14 +1,14 @@ -*[part="body"] { +*[part='body'] { max-height: 240px; overflow-y: auto; } -::slotted([slot="link"]) { +::slotted([slot='link']) { display: block; } @media (min-width: 576px) { - slot[part="links"] { + slot[part='links'] { display: flex; align-items: stretch; justify-content: space-between; diff --git a/elements/rh-audio-player/rh-audio-player.css b/elements/rh-audio-player/rh-audio-player.css index e662980323..70878fcd54 100644 --- a/elements/rh-audio-player/rh-audio-player.css +++ b/elements/rh-audio-player/rh-audio-player.css @@ -1,28 +1,33 @@ :host { - display: flex !important; - width: var(--_player-width, 304px); - flex-direction: column; - align-items: stretch; line-height: var(--rh-line-height-body-text, 1.5); font-weight: var(--rh-font-weight-body-text-regular, 400); font-size: var(--rh-font-size-code-md, 1rem); - 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); - - --_player-width: 328px; + 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); } -:host([hidden]), -*[hidden] { +[hidden] { display: none !important; border-radius: var(--rh-border-radius-default, 3px); } +rh-icon { + color: inherit; +} + +button { + color: var(--_text-color); +} + #container { - display: contents; + display: flex; + flex-direction: column; + align-items: stretch; color: var(--_text-color); background-color: transparent; border-radius: var(--rh-border-radius-default, 3px); + width: var(--_player-width, 304px); + --_player-width: 328px; --_poster-size: 40px; --_player-padding: var(--rh-space-lg, 16px); --_icon-gap: var(--rh-space-xl, 24px); @@ -33,96 +38,91 @@ --_about-heading-display: flex; --_box-shadow: var(--rh-box-shadow-md, 0 4px 6px 1px rgba(21, 21, 21, 0.25)); --_secondary-opacity: var(--rh-audio-player-secondary-opacity, 1); + --_text-color: var(--rh-audio-player-text-color, var(--rh-color-text-primary)); + --_border-color: var(--rh-color-border-subtle); + --_surface-color: + var(--rh-audio-player-background-color, + var(--rh-color-surface-lightest, #ffffff)); + --_secondary-text-color: + var(--rh-audio-player-secondary-text-color, + var(--rh-color-text-secondary)); + --_static-border-color: var(--rh-color-border-subtle); + --_static-text-color: var(--rh-color-text-primary); + --_static-highlight-color: var(--rh-color-interactive-primary-hover); + --_static-undeline-color: var(--rh-color-border-subtle); + --_static-surface-color: var(--rh-color-surface-lightest, #ffffff); + --_static-surface-focus-color: var(--rh-color-surface-light, #e0e0e0); --rh-tooltip-content-padding-block-start: var(--rh-space-md, 8px); --rh-tooltip-content-padding-block-end: var(--rh-space-md, 8px); --rh-tooltip-content-padding-inline-start: var(--rh-space-md, 8px); --rh-tooltip-content-padding-inline-end: var(--rh-space-md, 8px); -} + --rh-audio-player-scrolling-text-overflow-background-color: var(--_surface-color); -#container.mobile-safari { - --_time-slider-extension: - calc( - var(--_button-size, 40px) + var( - --_icon-gap, - var(--rh-space-xl, 24px) - ) - ); -} + &.dark { + --_surface-color: + var(--rh-audio-player-background-color, + var(--rh-color-surface-darkest, #151515)); + --_box-shadow: none; + --_static-highlight-color: var(--rh-color-surface-dark, #383838); + --_static-surface-color: var(--rh-color-surface-darkest, #151515); + --_static-surface-focus-color: var(--rh-color-surface-dark, #383838); + + &.has-accent-color { + --_static-highlight-color: var(--rh-color-interactive-primary-hover); + --_static-surface-color: var(--rh-color-surface-lightest, #ffffff); + --_static-surface-focus-color: var(--rh-color-surface-light, #e0e0e0); + --_border-color: rgba(255, 255, 255, 0.5); + --_secondary-opacity: var(--rh-audio-player-secondary-opacity, 0.75); + } + } + + &.mobile-safari { + --_time-slider-extension: + calc(var(--_button-size, 40px) + var(--_icon-gap, + var(--rh-space-xl, 24px))); + } -#container.has-accent-color { - --_border-color: rgba(0, 0, 0, 0.5); - --_secondary-text-color: - var( - --rh-audio-player-secondary-text-color, - var(--rh-color-text-primary-on-light, #151515) - ); - --_range-track-color: rgb(255 255 255 / 0.5); - --_secondary-opacity: var(--rh-audio-player-secondary-opacity, 0.75); - --_static-border-color: transparent; - --_static-overlay-focus-color: rgba(80, 80, 80, 0.5); - --_static-overlay-color: rgba(0, 0, 0, 0.5); -} - -#container.light { - --_text-color: var(--rh-audio-player-text-color, var(--rh-color-text-primary-on-light, #151515)); - --_border-color: var(--rh-color-border-subtle-on-light, #c7c7c7); - --_surface-color: - var( - --rh-audio-player-background-color, - var(--rh-color-surface-lightest, #ffffff) - ); - --_secondary-text-color: - var( - --rh-audio-player-secondary-text-color, - var(--rh-color-text-secondary-on-light, #4d4d4d) - ); -} + &.has-accent-color { + --_border-color: rgba(0, 0, 0, 0.5); + --_secondary-text-color: + var(--rh-audio-player-secondary-text-color, + var(--rh-color-text-primary)); + --_range-track-color: rgb(255 255 255 / 0.5); + --_secondary-opacity: var(--rh-audio-player-secondary-opacity, 0.75); + --_static-border-color: transparent; + --_static-overlay-focus-color: rgba(80, 80, 80, 0.5); + --_static-overlay-color: rgba(0, 0, 0, 0.5); + } -#container.dark { - --_text-color: var(--rh-audio-player-text-color, var(--rh-color-text-primary-on-dark, #ffffff)); - --_border-color: var(--rh-color-border-subtle-on-dark, #707070); - --_surface-color: - var( - --rh-audio-player-background-color, - var(--rh-color-surface-darkest, #151515) - ); - --_box-shadow: none; - --_secondary-text-color: - var( - --rh-audio-player-secondary-text-color, - var(--rh-color-text-secondary-on-dark, #c7c7c7) - ); - --_static-border-color: var(--rh-color-border-subtle-on-dark, #707070); - --_static-text-color: var(--rh-color-text-primary-on-dark, #ffffff); - --_static-highlight-color: var(--rh-color-surface-dark, #383838); - --_static-underline-color: var(--rh-color-border-subtle-on-light, #c7c7c7); - --_static-surface-color: var(--rh-color-surface-darkest, #151515); - --_static-surface-focus-color: var(--rh-color-surface-dark, #383838); -} - -#container, -#container.dark.has-accent-color { - --_static-border-color: var(--rh-color-border-subtle-on-light, #c7c7c7); - --_static-text-color: var(--rh-color-text-primary-on-light, #151515); - --_static-highlight-color: var(--rh-color-interactive-blue-lightest, #b9dafc); - --_static-undeline-color: var(--rh-color-border-subtle-on-dark, #707070); - --_static-surface-color: var(--rh-color-surface-lightest, #ffffff); - --_static-surface-focus-color: var(--rh-color-surface-light, #e0e0e0); - --rh-audio-player-scrolling-text-overflow-background-color: var(--_surface-color); + &.show-menu { + --_time-slider-base: 128px; + } + + &.rtl, + .rtl button { + text-align: right; + } + + &.mediatitle { + --_about-mediatitle-display: block; + --_about-heading-display: none; + } } -#container.dark.has-accent-color { - --_border-color: rgba(255, 255, 255, 0.5); - --_secondary-opacity: var(--rh-audio-player-secondary-opacity, 0.75); +rh-audio-player-rate-stepper { + margin-inline: 10px 2px; + width: auto; } -#container.show-menu { - --_time-slider-base: 128px; +svg.scrubber { + fill: var(--_text-color); + height: var(--_svg-size); + width: var(--_svg-size); + padding: var(--_icon-padding); } -#container.rtl, -.rtl button { - text-align: right; +#mini-playback-rate { + margin-inline: auto; } ::slotted(rh-audio-player-about), @@ -131,7 +131,7 @@ background-color: var(--_static-surface-color); } -::slotted([slot="series"]) { +::slotted([slot='series']) { letter-spacing: var(--rh-letter-spacing-body-text, 0.0125rem) !important; font-size: var(--rh-font-size-body-text-xs, 0.75rem) !important; font-weight: var(--rh-font-weight-heading-medium, 500) !important; @@ -139,9 +139,9 @@ padding: 0 !important; } -::slotted([slot="title"]) { +::slotted([slot='title']) { font-size: var(--rh-font-size-body-text-xl, 1.25rem) !important; - 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", Helvetica, Arial, sans-serif) !important; + 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', Helvetica, Arial, sans-serif) !important; font-weight: var(--rh-font-weight-heading-medium, 500) !important; line-height: var(--rh-line-height-heading, 1.3) !important; margin: 0 0 var(--rh-space-lg, 16px) !important; @@ -149,7 +149,7 @@ } #mediatitle { - 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", Helvetica, Arial, sans-serif); + 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', Helvetica, Arial, sans-serif); font-size: var(--rh-font-size-heading-xs, 1.25rem); font-weight: var(--rh-font-weight-heading-medium, 500); height: 26px; @@ -161,18 +161,13 @@ height: 18px; line-height: 1; font-weight: var(--rh-font-weight-body-text-regular, 400); - 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-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); letter-spacing: var(--rh-letter-spacing-body-text, 0.0125rem); margin: 0 0 var(--rh-space-md, 8px); color: var(--_secondary-text-color); opacity: var(--_secondary-opacity, 1); } -:host([mediatitle]) #container { - --_about-mediatitle-display: block; - --_about-heading-display: none; -} - :host(:focus-within) { z-index: 2; } @@ -200,23 +195,33 @@ display: block; } -*[part="toolbar"], -*[part="panel"] { +#toolbar { + position: relative; + display: flex; + align-items: center; + padding-inline-end: var(--rh-space-md, 8px); + width: max-content; +} + +#toolbar, +#panel { background-color: var(--_surface-color); border: 1px solid var(--_border-color); border-radius: var(--rh-border-radius-default, 3px); padding: var(--_player-padding); } -#container.has-accent-color *[part="toolbar"], -#container.has-accent-color *[part="panel"] { - border: none; +#panel { + width: calc(var(--_player-width) - 2 * var(--_player-padding) - 2); + + & ::slotted(*) { + color: var(--_text-color) !important; + } } -*[part="toolbar"] { - display: flex; - align-items: center; - padding-inline-end: var(--rh-space-md, 8px); +.has-accent-color #toolbar, +.has-accent-color #panel { + border: none; } rh-tooltip { @@ -240,8 +245,6 @@ rh-tooltip > label { #full-current, #duration, #volume-tooltip, -#full-playback-rate-tooltip, -#playback-rate-tooltip, #rewind-tooltip, #full-play-tooltip, #forward-tooltip, @@ -249,8 +252,10 @@ rh-tooltip > label { display: none; } -#full-playback-rate-tooltip:before { - content: ""; +#rewind, +#forward { + display: grid; + place-items: center; } #mediaseries, @@ -259,19 +264,11 @@ rh-tooltip > label { white-space: nowrap; } -::slotted([slot="series"]), -::slotted([slot="title"]) { +::slotted([slot='series']), +::slotted([slot='title']) { margin: 0; } -*[part="panel"] { - width: calc(var(--_player-width) - 2 * var(--_player-padding) - 2); -} - -*[part="panel"] ::slotted(*) { - color: var(--_text-color) !important; -} - #poster { display: none; height: var(--_poster-size); @@ -283,7 +280,7 @@ rh-tooltip > label { margin-inline-end: var(--_icon-gap); } -input[type="range"] { +input[type='range'] { margin: 2px 0; display: flex; } @@ -326,13 +323,13 @@ input[type="range"] { #duration { color: var(--_secondary-text-color); opacity: var(--_secondary-opacity, 1); - font-family: var(--rh-font-family-code, RedHatMono, "Red Hat Mono", "Courier New", Courier, monospace); + font-family: var(--rh-font-family-code, RedHatMono, 'Red Hat Mono', 'Courier New', Courier, monospace); font-size: var(--rh-font-size-code-xs, 0.75rem); line-height: var(--rh-line-height-code, 1.5); } -.rtl #mute svg { - transform: rotate(180deg); +.rtl #mute rh-icon { + rotate: 180deg; } #volume-tooltip { @@ -340,23 +337,16 @@ input[type="range"] { margin-inline: 0 calc(var(--_icon-gap) / 2); } -#playback-rate-tooltip, -#full-playback-rate-tooltip { - width: auto; - - --_svg-size: 12px; -} - #play-tooltip { margin: 0; --_icon-gap: 16px; - --_svg-size: 18px; + --rh-icon-size: 18px; } #full-play-tooltip { --_button-size: 56px; - --_icon-padding: calc((var(--_button-size) - var(--_svg-size)) / 2); + --_icon-padding: calc((var(--_button-size) - var(--rh-icon-size)) / 2); --_icon-margin: calc(var(--_icon-gap) / 2); } @@ -364,11 +354,7 @@ input[type="range"] { #mute-tooltip, #close-tooltip, #menu-tooltip { - --_svg-size: var(--rh-size-icon-02, 24px); -} - -[part="toolbar"] { - position: relative; + --rh-icon-size: var(--rh-size-icon-02, 24px); } #menu-button { @@ -377,12 +363,12 @@ input[type="range"] { width: max-content; } -:host([expanded]) #menu-tooltip { +.expanded #menu-tooltip { display: none; } -:host([expanded]) #close-tooltip, -:host(:not([expanded])) #menu-tooltip { +.expanded #close-tooltip, +:not(.expanded) #menu-tooltip { display: inline-block; } @@ -399,8 +385,9 @@ rh-menu { z-index: 2; } -rh-menu[aria-hidden="true"], -rh-menu[aria-hidden="true"] > * { +rh-menu[inert], +rh-menu[aria-hidden='true'], +rh-menu[aria-hidden='true'] > * { z-index: -1; } @@ -423,7 +410,8 @@ rh-menu::part(menu) { border: none; } -rh-menu[aria-hidden="false"]::part(menu) { +rh-menu:not([inert])::part(menu), +rh-menu[aria-hidden='false']::part(menu) { opacity: 1; pointer-events: all; } @@ -437,7 +425,7 @@ rh-menu > button { background-color: var(--_static-overlay-color); font-size: var(--rh-font-size-body-text-md, 1rem); line-height: var(--rh-line-height-body-text, 1.5); - 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-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); } rh-menu > button:hover { @@ -449,7 +437,7 @@ rh-menu > button:focus { } #container.has-accent-color rh-menu > button { - color: var(--rh-color-text-primary-on-dark, #ffffff); + color: var(--rh-color-text-primary); } #container.rtl rh-menu > button { @@ -459,348 +447,295 @@ rh-menu > button:focus { #play, #full-play { border-radius: 50%; - background-color: var(--_text-color); -} - -#play svg, -#full-play svg { - fill: var(--rh-audio-player-icon-background-color, var(--_surface-color)); -} - -#playback-rate-tooltip { - margin-inline: 10px 2px; -} - -#playback-rate-stepper, -#full-playback-rate-stepper { - display: flex; - align-items: center; -} - -#playback-rate, -#full-playback-rate, -#playback-rate-suffix, -#full-playback-rate-suffix { - color: var(--_text-color); - font-size: var(--rh-font-size-code-md, 1rem); - font-family: var(--rh-font-family-code, RedHatMono, "Red Hat Mono", "Courier New", Courier, monospace); -} - -#playback-rate, -#full-playback-rate { - appearance: none; - line-height: 36px; - padding: 2px 0; - border: none; - color: var(--_text-color); background-color: var(--_surface-color); + color: var(--rh-audio-player-icon-background-color, var(--_text-color)); } -:host([expanded]) *[part="toolbar"] { - border-block-end: 0; - border-radius: var(--rh-border-radius-default, 3px) var(--rh-border-radius-default, 3px) 0 0; -} +.expanded { + & #toolbar { + border-block-end: 0; + border-radius: var(--rh-border-radius-default, 3px) var(--rh-border-radius-default, 3px) 0 0; + } -:host([expanded]) *[part="panel"] { - border-block-start: 0; - padding-block-start: 0; - border-radius: 0 0 var(--rh-border-radius-default, 3px) var(--rh-border-radius-default, 3px); -} + & #panel { + border-block-start: 0; + padding-block-start: 0; + border-radius: 0 0 var(--rh-border-radius-default, 3px) var(--rh-border-radius-default, 3px); -:host([expanded]) *[part="panel"] slot { - display: block; + & slot { + display: block; + } + } } @media (min-width: 360px) { - :host { - --_player-width: 360px; - } - #container { + --_player-width: 360px; --_time-slider-base: 191px; - } - #container.show-menu { - --_time-slider-base: 160px; + &.show-menu { + --_time-slider-base: 160px; + } } } @media (min-width: 576px) { - :host { - --_player-width: 503px; - } - #container { + --_player-width: 503px; --_time-slider-base: 334px; - } - - #container.show-menu { - --_time-slider-base: 303px; - } - :host([layout^="compact"]) { - --_player-width: 576px; - } - - :host([layout^="compact"]) #container { - --_time-slider-base: 256px; - - padding-inline-end: var(--_player-padding); - } - - :host([layout^="compact"]) #container.show-menu { - --_time-slider-base: 225px; - } - - :host([layout^="compact"]) #container.mobile-safari { - --_time-slider-extension: - calc( - 80px + var(--_button-size, 40px) + 1.5 * var( - --_icon-gap, - var(--rh-space-xl, 24px) - ) - ); - } - - :host([layout="compact-wide"]) { - width: 100%; - } - - :host([layout="compact"]) *[part="toolbar"] { - padding-inline-end: var(--_player-padding); - } - - :host([layout="compact-wide"]) *[part="toolbar"] { - justify-content: center; - width: auto; - padding: var(--_player-padding) calc((100% - var(--_player-width) - 2px) / 2); - } - - :host([layout="compact-wide"]) #time-tooltip, - :host([layout="compact-wide"]) #time { - width: var(--_time-slider-width); - flex: 0 0 var(--_time-slider-width); - margin-inline-start: var(--rh-space-md, 8px); - } - - :host([layout^="compact"]) #volume { - width: 80px; - } - - :host([layout]) #mute-tooltipp { - --_svg-size: var(--rh-size-icon-02, 24px); - } - - :host([layout="full"]) { - --_player-width: 504px; - } - - :host([layout="full"]) #container { - --_icon-gap: var(--rh-space-xl, 24px); - --_player-padding: var(--rh-space-xl, 24px); - --_time-slider-base: 314px; - } - - :host([layout="full"]) #container.mobile-safari { - --_time-slider-extension: - calc( - 80px + var(--_button-size, 40px) + var( - --_icon-gap, - var(--rh-space-xl, 24px) - ) - ); - } - - :host([layout="full"][mediatitle]) #container { - --_about-mediatitle-display: none; - --_about-heading-display: flex; - } - - :host([layout="full"]) *[part="toolbar"] { - padding-inline-end: var(--_player-padding); - } - - :host([layout="full"]:not([expanded])) *[part="toolbar"] { - flex-wrap: wrap; - height: 184px; - } - - :host([layout]) .spacer, - :host([layout="full"]) #current, - :host([layout="full"]:not([expanded])) #play-tooltip, - :host([layout="full"][expanded]) #time-tooltip, - :host([layout="full"][expanded]) #mute-tooltip, - :host([layout="full"]) #playback-rate-tooltip { - display: none; - } - - :host([layout^="compact"]) #current, - :host([layout="full"]:not([expanded])) .full-spacer { - display: inline-block; - } - - :host([layout^="compact"]) #volume-tooltip, - :host([layout="full"]:not([expanded])) #full-current, - :host([layout="full"]:not([expanded])) #duration, - :host([layout="full"]:not([expanded])) #volume-tooltip, - :host([layout="full"]:not([expanded])) #full-playback-rate-tooltip, - :host([layout="full"]:not([expanded])) #rewind-tooltip, - :host([layout="full"]:not([expanded])) #full-play-tooltip, - :host([layout="full"]:not([expanded])) #forward-tooltip { - display: flex; - } - - :host([layout="full"]) #time-tooltip { - margin-inline: 0 calc(var(--_icon-gap) / 2); - } - - :host([layout="full"]) #full-current, - :host([layout="full"]) #duration { - flex: 0 0 calc(var(--_time-slider-width) / 2); - margin: -4px 0 var(--rh-length-lg, 16px); - } - - :host([layout="full"]) #duration { - flex: 0 0 calc(var(--_time-slider-width) / 2); - justify-content: flex-end; - margin-inline-end: 140px; - } - - :host([dir="rtl"][layout="full"]) #duration { - justify-content: flex-start; - } - - :host([layout="full"]) #container.mobile-safari #duration { - margin-inline-end: -4px; - } - - :host([layout="full"]) #mute-tooltip { - margin-inline-start: var(--_icon-margin); - } - - :host([layout="full"]) #volume-tooltip { - flex: 0 0 80px; - margin-inline-end: 0; - } - - :host([layout="full"]) #volume { - width: 80px; - } - - :host([layout="full"]) #full-playback-rate-tooltip { - flex: 0 0 auto; - text-align: right; - margin: 0 var(--_icon-margin) 0 -6px; - } - - :host([dir="rtl"][layout="full"]) #full-playback-rate-tooltip { - text-align: right; - } - - :host([layout="full"]) #menu { - flex: 0 0 auto; - } - - :host([layout="full"][expanded]) #close-tooltip, - :host([layout="full"][expanded]) #menu { - margin: 0; - } - - :host([layout="full"]) #menu-tooltip svg { - transform: rotate(90deg); - } - - :host([layout="full"]) #full-title { - display: block; - flex: 0 0 454px; - } - - :host([layout="full"][expanded]) #full-title { - flex: 0 0 calc(100% - 112px); - overflow: hidden; - margin: 0 var(--rh-length-lg, 16px); - } - - :host([layout="full"]) *[part="panel"] { - padding-block-start: var(--rh-length-md, 8px); - } - - :host([expanded][layout="compact-wide"]) *[part="panel"] { - padding: 0; - } - - :host([expanded][layout="compact-wide"]) *[part="panel"] slot { - width: calc(var(--_player-width) - 2 * var(--_player-padding)); - margin: 0 auto; + &.show-menu { + --_time-slider-base: 303px; + } + + &:is(.compact,.compact-wide) { + --_player-width: 576px; + --_time-slider-base: 256px; + + padding-inline-end: var(--_player-padding); + + & #volume { + width: 80px; + } + + &.show-menu { + --_time-slider-base: 225px; + } + + &.mobile-safari { + --_time-slider-extension: + calc(80px + var(--_button-size, 40px) + 1.5 * var(--_icon-gap, + var(--rh-space-xl, 24px))); + } + } + + &.compact-wide { + width: 100%; + + &.expanded #panel { + padding: 0; + + & slot { + width: calc(var(--_player-width) - 2 * var(--_player-padding)); + margin: 0 auto; + } + } + + & #toolbar { + justify-content: center; + width: auto; + padding: var(--_player-padding) calc((100% - var(--_player-width) - 2px) / 2); + } + + & #time-tooltip, + & #time { + width: var(--_time-slider-width); + flex: 0 0 var(--_time-slider-width); + margin-inline-start: var(--rh-space-md, 8px); + } + } + + &.compact #toolbar { + padding-inline-end: var(--_player-padding); + } + + &:not(.mini) #mute-tooltip { + --rh-icon-size: var(--rh-size-icon-02, 24px); + } + + &.full { + --_player-width: 504px; + --_icon-gap: var(--rh-space-xl, 24px); + --_player-padding: var(--rh-space-xl, 24px); + --_time-slider-base: 314px; + + & #toolbar { + padding-inline-end: var(--_player-padding); + width: calc(var(--_player-width) - var(--_poster-size) - var(--_icon-gap) * 3); + } + + &.expanded #toolbar { + width: auto; + } + + & #time-tooltip { + margin-inline: 0 calc(var(--_icon-gap) / 2); + } + + & #full-current, + & #duration { + flex: 0 0 calc(var(--_time-slider-width) / 2); + margin: -4px 0 var(--rh-length-lg, 16px); + } + + & #duration { + flex: 0 0 calc(var(--_time-slider-width) / 2); + justify-content: flex-end; + margin-inline-end: 140px; + } + + & #mute-tooltip { + margin-inline-start: var(--_icon-margin); + } + + & #volume-tooltip { + flex: 0 0 80px; + margin-inline-end: 0; + } + + & #volume { + width: 80px; + } + + & rh-audio-player-rate-stepper { + flex: 0 0 auto; + text-align: right; + margin: 0 var(--_icon-margin) 0 -6px; + } + + & #menu { + flex: 0 0 auto; + } + + & #full-title { + display: block; + flex: 0 0 454px; + } + + /* this will complain either way */ + /* stylelint-disable-next-line no-descending-specificity */ + & #panel { + padding-block-start: var(--rh-length-md, 8px); + } + + &.mobile-safari { + --_time-slider-extension: + calc(80px + var(--_button-size, 40px) + var(--_icon-gap, + var(--rh-space-xl, 24px))); + + & #duration { + margin-inline-end: -4px; + } + } + + &.mediatitle { + --_about-mediatitle-display: none; + --_about-heading-display: flex; + } + + &:not(.expanded) #toolbar { + flex-wrap: wrap; + height: 184px; + } + + &.rtl { + & #duration { + justify-content: flex-start; + } + } + + &.expanded { + & #close-tooltip, + & #menu { + margin: 0; + } + + & #full-title { + flex: 0 0 calc(100% - 112px); + overflow: hidden; + margin: 0 var(--rh-length-lg, 16px); + } + } + } + + &:not(.mini) .spacer, + &.full #current, + &.full:not(.expanded) #play-tooltip, + &.full.expanded #time-tooltip, + &.full.expanded #mute-tooltip { + display: none; + } + + &:is(.compact,.compact-wide) #current, + &.full:not(.expanded) .full-spacer { + display: inline-block; + } + + &:is(.compact,.compact-wide) #volume-tooltip, + &.full:not(.expanded) #full-current, + &.full:not(.expanded) #duration, + &.full:not(.expanded) #volume-tooltip, + &.full:not(.expanded) #rewind-tooltip, + &.full:not(.expanded) #full-play-tooltip, + &.full:not(.expanded) #forward-tooltip { + display: flex; + } } } @media (min-width: 768px) { - :host([layout^="compact"]) #container { - --_time-slider-base: 221px; - } - - :host([layout^="compact"]) #container.show-menu { - --_time-slider-base: 190px; - } - - :host([layout^="compact"]) { - --_player-width: 650px; - } - - :host([poster][layout^="compact"]) { - --_player-width: 714px; - } - - :host([layout^="compact"]) #playback-rate-tooltip, - :host([poster][layout^="compact"]) #poster { - display: inline-block; - } - - :host([poster][layout="full"]) { - --_player-width: 712px; - } - - :host([poster][layout="full"]) #container { - --_time-slider-base: 314px; - } - - :host([poster][layout="full"][expanded]) #poster { - display: inline-block; - padding-inline-end: var(--rh-length-lg, 16px); - } - - :host([layout="full"][poster][expanded]) #full-title { - flex: 0 0 calc(100% - 168px); - } - - :host([poster][layout="full"]:not([expanded])) #container { - --_poster-size: 184px; - } - - :host([poster][layout="full"]:not([expanded])) *[part="toolbar"] { - padding-inline-start: calc(var(--_player-padding) * 2 + var(--_poster-size)); - } - - :host([poster][layout="full"]:not([expanded])) #poster { - position: relative; - overflow: visible; - display: block; - height: 0; - flex: 0 0 100%; - } - - :host([layout="full"][poster][expanded]) #poster > img { - margin-inline-end: 0; - } - - :host([poster][layout="full"]:not([expanded])) #poster > img { - position: absolute; - left: calc(-184px - var(--_player-padding)); - } - - :host([poster][layout="full"]:not([expanded])) #container.rtl #poster > img { - right: calc(-184px - var(--_player-padding)); - left: unset; + #container { + &:is(.compact,.compact-wide) { + --_time-slider-base: 221px; + --_player-width: 650px; + + &.show-menu { + --_time-slider-base: 190px; + } + + &.poster { + --_player-width: 714px; + } + } + + &:is(.compact,.compact-wide).poster #poster { + display: inline-block; + } + + &.full.poster { + --_player-width: 712px; + --_time-slider-base: 314px; + + &:not(.expanded) { + --_poster-size: 184px; + + & #toolbar { + padding-inline-start: calc(var(--_player-padding) * 2 + var(--_poster-size)); + } + + & #poster { + position: relative; + overflow: visible; + display: block; + height: 0; + flex: 0 0 100%; + + & > img { + position: absolute; + left: calc(-184px - var(--_player-padding)); + } + } + } + + &.expanded { + & #poster { + display: inline-block; + padding-inline-end: var(--rh-length-lg, 16px); + + & > img { + margin-inline-end: 0; + } + } + + & #full-title { + flex: 0 0 calc(100% - 168px); + } + + &.rtl #poster > img { + right: calc(-184px - var(--_player-padding)); + left: unset; + } + } + } } } diff --git a/elements/rh-audio-player/rh-audio-player.ts b/elements/rh-audio-player/rh-audio-player.ts index 21e0dae273..94400c495e 100644 --- a/elements/rh-audio-player/rh-audio-player.ts +++ b/elements/rh-audio-player/rh-audio-player.ts @@ -20,6 +20,7 @@ import { I18nController } from '../../lib/I18nController.js'; import { RhMenu } from '../rh-menu/rh-menu.js'; import { RhCue, getFormattedTime } from './rh-cue.js'; import { RhAudioPlayerAbout } from './rh-audio-player-about.js'; +import { RhAudioPlayerRateSelectEvent } from './rh-audio-player-rate-stepper.js'; import { RhAudioPlayerSubscribe } from './rh-audio-player-subscribe.js'; import { RhTranscript } from './rh-transcript.js'; import { RhAudioPlayerScrollingTextOverflow } from './rh-audio-player-scrolling-text-overflow.js'; @@ -30,6 +31,7 @@ import styles from './rh-audio-player.css'; import '@rhds/elements/rh-surface/rh-surface.js'; import '@rhds/elements/rh-tooltip/rh-tooltip.js'; +import '@rhds/elements/rh-icon/rh-icon.js'; /** * An audio player plays audio clips in the browser and includes other features. @@ -62,99 +64,6 @@ export class RhAudioPlayer extends LitElement { private static instances = new Set(); - // TODO: use rh-icon - private static icons = { - close: html` - - - - `, - download: html` - - - - `, - forward: html` - - - - - - - - `, - menuKebab: html` - - - - - - `, - menuMeatball: html` - - - - - - `, - pause: html` - - - - - `, - play: html` - - - - `, - playbackRateFaster: html` - - - - `, - playbackRateSlower: html` - - - - `, - rewind: html` - - - - - - - - `, - volumeMax: html` - - - - - - `, - volumeMuted: html` - - - - - `, - }; - static enUS = { 'play': 'Play', 'pause': 'Pause', @@ -187,7 +96,7 @@ export class RhAudioPlayer extends LitElement { * - `compact-wide`: like compact but full width * - `full`: maximal controls and artwork */ - @property({ reflect: true }) layout?: 'mini' | 'compact' | 'compact-wide' | 'full'; + @property({ reflect: true }) layout: 'mini' | 'compact' | 'compact-wide' | 'full' = 'mini'; /** URL to audio's artwork */ @property({ reflect: true }) poster?: string; @@ -239,14 +148,6 @@ export class RhAudioPlayer extends LitElement { #unmutedVolume = this.volume; - #pbrMin = 0.25; - - #pbrMax = 2; - - #pbrStep = 0.25; - - #pbrFixed = 2; - #styles?: CSSStyleDeclaration; // this is used inasmuch as children receive the context, @@ -348,16 +249,6 @@ export class RhAudioPlayer extends LitElement { } } - /** - * gets list of allowable playback rates - */ - get #playbackRates() { - return [ - ...Array(Math.round(this.#pbrMax / this.#pbrStep)).keys()].map(k => - k * this.#pbrStep + this.#pbrMin - ); - } - /** * gets media media time if set */ @@ -449,11 +340,10 @@ export class RhAudioPlayer extends LitElement { } render() { - const { on = '' } = this; + const { expanded, mediatitle, on = 'light', layout, poster } = this; const { dir } = this.#dir; const { open, styles = {} } = this.#menufloat; const showMenu = this.#hasMenu; - const muteicon = !this.muted ? RhAudioPlayer.icons.volumeMax : RhAudioPlayer.icons.volumeMuted; const mutelabel = !this.muted ? this.#translation.get('mute') : this.#translation.get('unmute'); const rewinddisabled = !this.#mediaElement @@ -469,7 +359,6 @@ export class RhAudioPlayer extends LitElement { !this.paused ? this.#translation.get('pause') : this.#translation.get('play'); const playdisabled = this.#readyState < 3 && this.duration < 1; - const playicon = !this.paused ? RhAudioPlayer.icons.pause : RhAudioPlayer.icons.play; const currentTimeQ = (this.currentTime / this.duration); const currentTimePct = (Number.isNaN(currentTimeQ) ? 0 : currentTimeQ) * 100; @@ -480,19 +369,25 @@ export class RhAudioPlayer extends LitElement { -
${!this.poster ? '' : html` -
`} + aria-label="Media Controls">${!poster ? '' : html` +
`} ${playlabel} @@ -516,23 +411,28 @@ export class RhAudioPlayer extends LitElement { + class="toolbar-button" + aria-label="${this.#translation.get('seek')}" + min="0" + max="100" + step="1" + type="range" + value="${currentTimePct}" + ?disabled="${this.duration === 0}" + @input=${this.#onTimeSlider}> ${this.#translation.get('seek')} ${this.#elapsedText} -
${this.#isMini ? '' : html` +
- ${this.#playbackRateTemplate()}`} + ${this.#isMobileSafari ? '' : html` @@ -542,7 +442,7 @@ export class RhAudioPlayer extends LitElement { class="toolbar-button" ?disabled=${!this.#mediaElement} @click=${this.#onMuteButton}> - ${muteicon} + ${mutelabel} ${this.#isMini ? '' : html` @@ -571,7 +471,12 @@ export class RhAudioPlayer extends LitElement {
- ${this.#playbackRateTemplate('full-playback-rate')} + ${this.#translation.get('rewind')} @@ -591,7 +503,7 @@ export class RhAudioPlayer extends LitElement { ?disabled=${!this.#mediaElement || playdisabled} @click=${this.#onPlayClick} @focus=${this.#onPlayFocus}> - ${playicon} + ${playlabel} @@ -602,28 +514,38 @@ export class RhAudioPlayer extends LitElement { class="toolbar-button" ?disabled=${forwarddisabled} @click=${() => this.forward()}> - ${RhAudioPlayer.icons.forward} + + + + + ${this.#translation.get('advance')} `}${!this.#hasMenu ? '' : html` - + ${this.#translation.get('menu')} ${this.#panels.map(x => !x.panel ? '' : html` `)} + `} ${this.#translation.get('close')} @@ -676,44 +604,6 @@ export class RhAudioPlayer extends LitElement { `; } - /** template for playback rate controls */ - #playbackRateTemplate(id = 'playback-rate') { - return html` - -
- - - -
- ${this.#translation.get('speed')} -
- `; - } - async firstUpdated() { // waiting for next render so that rh-menu is present in shadow root await this.updateComplete; @@ -738,6 +628,21 @@ export class RhAudioPlayer extends LitElement { this.#updateTranscriptLabels(); } + #getMenuItems(items: HTMLElement[]) { + const ministepperid = 'mini-playback-rate'; + if (this.#isMini) { + return [ + ...items.filter(x => x.id !== ministepperid), + ...this.shadowRoot + ?.getElementById(ministepperid) + ?.shadowRoot + ?.querySelectorAll('.tabbable') ?? [], + ]; + } else { + return items; + } + } + #updateMenuLabels() { if (this.#about?.menuLabel) { this.#about.menuLabel = this.#translation.get('about'); @@ -878,11 +783,9 @@ export class RhAudioPlayer extends LitElement { * by updating component playbackRate property */ #onPlaybackRateSelect(event: Event) { - if (this.#mediaElement) { - const target = event?.target as HTMLSelectElement; - const val = !target || !target.value ? 1.00 : parseFloat(target.value); - const pbr = this.#validPlaybackRate(val); - this.#mediaElement.playbackRate = this.playbackRate = pbr; + if (event instanceof RhAudioPlayerRateSelectEvent && this.#mediaElement) { + this.playbackRate = event.playbackRate; + this.#mediaElement.playbackRate = event.playbackRate; } } @@ -1015,17 +918,6 @@ export class RhAudioPlayer extends LitElement { } } - /** - * ensures playback rate value falls between playback rate minimum and maximum values - */ - #validPlaybackRate(number: number) { - // ensures number between min and maxk - const inRange = Math.max(this.#pbrMin, Math.min(this.#pbrMax, number)); - // used to round number to nearest step - const multiplier = 1 / this.#pbrStep; - return Math.round(inRange * multiplier) / multiplier; - } - /** * opens particular panel open or closes panels if none given */ @@ -1072,6 +964,7 @@ export class RhAudioPlayer extends LitElement { async #onMenuKeydown(event: KeyboardEvent) { if (event.key === 'Escape') { await this.#hideMenu(); + this.shadowRoot?.querySelector('#menu-button')?.focus(); } } @@ -1146,7 +1039,8 @@ export class RhAudioPlayer extends LitElement { #onWindowClick = (event: MouseEvent) => { const menu = this.shadowRoot?.getElementById('menu-button'); - if (!menu || !event.composedPath().includes(menu)) { + const path = event.composedPath(); + if (!menu || !path.includes(menu) && !path.some(x => x instanceof RhMenu)) { this.#hideMenu(); } }; @@ -1170,28 +1064,6 @@ export class RhAudioPlayer extends LitElement { } } - /** - * Increases media playback rate by playback rate step value - */ - incrementPlaybackrate() { - if (this.#mediaElement) { - this.#mediaElement.playbackRate = - this.playbackRate = - this.#validPlaybackRate(this.#mediaElement.playbackRate + this.#pbrStep); - } - } - - /** - * Decreases media playback rate by playback rate step value - */ - decrementPlaybackrate() { - if (this.#mediaElement) { - this.#mediaElement.playbackRate = - this.playbackRate = - this.#validPlaybackRate(this.#mediaElement.playbackRate - this.#pbrStep); - } - } - /** * Pauses playback */ diff --git a/elements/rh-audio-player/rh-cue.css b/elements/rh-audio-player/rh-cue.css index 77bd454f50..dff047005d 100644 --- a/elements/rh-audio-player/rh-cue.css +++ b/elements/rh-audio-player/rh-cue.css @@ -22,16 +22,16 @@ a { color: currentcolor; } -a[id$="text"] { +a[id$='text'] { border-block-end: 1px dotted transparent; } -a[id$="text"]:hover { +a[id$='text']:hover { background-color: var(--_static-surface-color); border-block-end-color: var(--_static-underline-color); } -a[active][id$="text"] { +a[active][id$='text'] { color: var(--_static-text-color); background-color: var(--_static-highlight-color); } @@ -51,11 +51,11 @@ h6 { } #voice { - 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", Helvetica, Arial, sans-serif); + 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', Helvetica, Arial, sans-serif); } #start { - font-family: var(--rh-font-family-code, RedHatMono, "Red Hat Mono", "Courier New", Courier, monospace); + font-family: var(--rh-font-family-code, RedHatMono, 'Red Hat Mono', 'Courier New', Courier, monospace); } a #start { diff --git a/elements/rh-audio-player/rh-transcript.css b/elements/rh-audio-player/rh-transcript.css index f5d5f818bb..5b24565af5 100644 --- a/elements/rh-audio-player/rh-transcript.css +++ b/elements/rh-audio-player/rh-transcript.css @@ -15,7 +15,7 @@ label, #download-tooltip { margin-inline-start: var(--rh-space-md, 8px); - --_svg-size: 18px; + --rh-icon-size: 18px; } #cues { @@ -27,3 +27,8 @@ label, color: var(--_static-text-color); background-color: var(--_static-surface-color); } + +button, +rh-icon { + color: inherit; +} diff --git a/elements/rh-audio-player/rh-transcript.ts b/elements/rh-audio-player/rh-transcript.ts index e23e75a2d0..a68812623d 100644 --- a/elements/rh-audio-player/rh-transcript.ts +++ b/elements/rh-audio-player/rh-transcript.ts @@ -16,12 +16,7 @@ import styles from './rh-transcript.css'; import './rh-audio-player-scrolling-text-overflow.js'; import '@rhds/elements/rh-tooltip/rh-tooltip.js'; - -const icon = html` - - - -`; +import '@rhds/elements/rh-icon/rh-icon.js'; /** * Audio Player Transcript Panel @@ -58,28 +53,6 @@ export class RhTranscript extends LitElement { parent: new HeadingLevelContextConsumer(this), }); - render() { - return html` - - ${this.#headings.wrap(this.menuLabel)} - -
${this._cues.length < 0 ? '' : html` - - - - ${this.downloadLabel} - `} -
- - `; - } - set autoscrollLabel(label: string) { this._autoscroll = label; } @@ -96,6 +69,10 @@ export class RhTranscript extends LitElement { return this._download || 'Download'; } + get downloadText() { + return this._cues.map(cue =>cue.downloadText).join('\n\n'); + } + set menuLabel(label: string) { this._label = label; } @@ -104,6 +81,30 @@ export class RhTranscript extends LitElement { return this.label || this._label || 'About the episode'; } + render() { + return html` + + ${this.#headings.wrap(this.menuLabel)} + +
${this._cues.length < 0 ? '' : html` + + + + ${this.downloadLabel} + `} +
+ + `; + } + #updateCues(currentTime?: number) { let activeCue: RhCue; this._cues.forEach((cue, index)=>{ @@ -160,10 +161,6 @@ export class RhTranscript extends LitElement { this.dispatchEvent(new Event('transcriptdownload', { bubbles: true })); } - get downloadText() { - return this._cues.map(cue =>cue.downloadText).join('\n\n'); - } - setActiveCues(currentTime = 0) { this.#updateCues(currentTime); } diff --git a/elements/rh-audio-player/test/rh-audio-player.spec.ts b/elements/rh-audio-player/test/rh-audio-player.spec.ts index c47a5484a3..633e43de7d 100644 --- a/elements/rh-audio-player/test/rh-audio-player.spec.ts +++ b/elements/rh-audio-player/test/rh-audio-player.spec.ts @@ -1,9 +1,13 @@ import { expect, html, aTimeout, oneEvent } 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 { setViewport, sendKeys, sendMouse } from '@web/test-runner-commands'; +import { clickElementAtCenter } from '@patternfly/pfe-tools/test/utils.js'; import { ifDefined } from 'lit/directives/if-defined.js'; +import { querySelectorDeep } from 'query-selector-shadow-dom'; + import { RhAudioPlayer } from '../rh-audio-player.js'; import { RhAudioPlayerAbout } from '../rh-audio-player-about.js'; import { RhAudioPlayerScrollingTextOverflow } from '../rh-audio-player-scrolling-text-overflow.js'; @@ -12,9 +16,18 @@ import { RhAudioPlayerSubscribe } from '../rh-audio-player-subscribe.js'; import { RhCue } from '../rh-cue.js'; import { RhTranscript } from '../rh-transcript.js'; + +function press(key: string) { + return async function() { + await sendKeys({ press: key }); + }; +} + describe('', function() { let element: RhAudioPlayer; + const updateComplete = () => element.updateComplete; + // ACTIONS function setupForLayout(layout?: RhAudioPlayer['layout']) { @@ -63,7 +76,7 @@ describe('', function() { } async function clickMute() { - const button = getShadowElementBySelector('#mute') as HTMLButtonElement; + const button = querySelectorDeep('#mute') as HTMLButtonElement; button!.click(); await element.updateComplete; } @@ -84,7 +97,7 @@ describe('', function() { } async function clickMenu() { - const button = getShadowElementBySelector('#menu') as HTMLButtonElement; + const button = querySelectorDeep('#menu') as HTMLButtonElement; const x = button.offsetLeft + 5; const y = button.offsetTop + 5; await sendMouse({ type: 'click', position: [x, y] }); @@ -100,7 +113,7 @@ describe('', function() { } async function clickClose() { - const button = getShadowElementBySelector('#close') as HTMLButtonElement; + const button = querySelectorDeep('#close') as HTMLButtonElement; const x = button.offsetLeft + 5; const y = button.offsetTop + 5; await sendMouse({ type: 'click', position: [x, y] }); @@ -115,12 +128,12 @@ describe('', function() { */ async function clickForward() { - const button = getShadowElementBySelector('#forward') as HTMLButtonElement; + const button = querySelectorDeep('#forward') as HTMLButtonElement; button!.click(); } async function clickRewind() { - const button = getShadowElementBySelector('#rewind') as HTMLButtonElement; + const button = querySelectorDeep('#rewind') as HTMLButtonElement; button!.click(); } @@ -130,16 +143,13 @@ describe('', function() { }; } - async function tab() { - await sendKeys({ press: 'Tab' }); - } - /** * seeks via setting the time range slider input + * @param percent how much */ function seekViaSlider(percent: 0 | 10 | 20 | 30 | 40 | 50 | 60 | 70 | 80 | 90 | 100) { return async function() { - const range = getShadowElementBySelector('#time') as HTMLInputElement; + const range = querySelectorDeep('#time') as HTMLInputElement; const x = Math.floor(range.offsetLeft + range.offsetWidth * (percent / 100)); const y = Math.floor(range.offsetTop + range.offsetHeight / 2); await sendMouse({ type: 'click', position: [x, y] }); @@ -154,11 +164,6 @@ describe('', function() { // ASSERTIONS - // TODO: use testing actions to click on specific pixels, rather than shadowroot queries. this will also test layout accuracy to a degree - function getShadowElementBySelector(query: string) { - return element?.shadowRoot?.querySelector(query); - } - function getShadowElementByAriaLabel(label: string) { return element?.shadowRoot?.querySelector(`[aria-label="${label}"]`); } @@ -205,8 +210,9 @@ describe('', function() { `); }); beforeEach(sleep(100)); + beforeEach(() => element.updateComplete); it('has spanish-language buttons', function() { - expect(getShadowElementBySelector('#time')?.getAttribute('aria-label'), 'time slider label').to.equal('Buscar'); + expect(querySelectorDeep('#time')?.getAttribute('aria-label'), 'time slider label').to.equal('Buscar'); }); }); @@ -258,42 +264,46 @@ describe('', function() { describe('without layout', function() { beforeEach(setupForLayout()); it('has width', assertHasWidth); - it('displays the correct elements', function() { - expect(getShadowElementByAriaLabel('Play'), 'Play').to.exist.and.to.be.visible; - expect(getShadowElementByAriaLabel('Seek'), 'Seek').to.exist.and.to.be.visible; - expect(getShadowElementByAriaLabel('Mute'), 'Mute').to.exist.and.to.be.visible; - expect(getShadowElementByAriaLabel('More options'), 'More options').to.exist.and.to.be.visible; + it('displays the correct elements', async function() { + expect(await a11ySnapshot()) + .to.axContainName('Play') + .and.to.axContainName('Seek') + .and.to.axContainName('Mute') + .and.to.axContainName('More options'); }); }); describe('compact layout', function() { beforeEach(setupForLayout('compact')); it('has width', assertHasWidth); - it('displays the correct elements', function() { - expect(getShadowElementByAriaLabel('Play'), 'Play').to.exist.and.to.be.visible; - expect(getShadowElementByAriaLabel('Seek'), 'Seek').to.exist.and.to.be.visible; - expect(getShadowElementByAriaLabel('Mute'), 'Mute').to.exist.and.to.be.visible; - expect(getShadowElementByAriaLabel('Speed'), 'Speed').to.exist.and.to.be.visible; - expect(getShadowElementByAriaLabel('Volume'), 'Volume').to.exist.and.to.be.visible; - expect(getShadowElementByAriaLabel('More options'), 'More options').to.exist.and.to.be.visible; + it('displays the correct elements', async function() { + expect(await a11ySnapshot()) + .to.axContainName('Play') + .and.to.axContainName('Seek') + .and.to.axContainName('Mute') + .and.to.axContainName('Speed') + .and.to.axContainName('Volume') + .and.to.axContainName('More options'); }); }); describe('compact-wide layout', function() { beforeEach(setupForLayout('compact-wide')); it('has width', assertHasWidth); - it('displays the correct elements', function() { - expect(getShadowElementByAriaLabel('Play'), 'Play').to.exist.and.to.be.visible; - expect(getShadowElementByAriaLabel('Seek'), 'Seek').to.exist.and.to.be.visible; - expect(getShadowElementByAriaLabel('Mute'), 'Mute').to.exist.and.to.be.visible; - expect(getShadowElementByAriaLabel('Speed'), 'Speed').to.exist.and.to.be.visible; - expect(getShadowElementByAriaLabel('Volume'), 'Volume').to.exist.and.to.be.visible; - expect(getShadowElementByAriaLabel('More options'), 'More options').to.exist.and.to.be.visible; + it('displays the correct elements', async function() { + expect(await a11ySnapshot()) + .to.axContainName('Play') + .and.to.axContainName('Seek') + .and.to.axContainName('Mute') + .and.to.axContainName('Speed') + .and.to.axContainName('Volume') + .and.to.axContainName('More options'); }); - it('has mute button enabled', function() { - const button = getShadowElementBySelector('#mute') as HTMLButtonElement; - expect(button?.disabled, 'state').to.be.false; + it('has mute button enabled', async function() { + expect(await a11ySnapshot()) + .axQuery({ name: 'Mute' }) + .to.not.have.axProperty('disabled', true); }); describe('setting volume to 0.5', function() { @@ -336,10 +346,8 @@ describe('', function() { }); describe('then pressing Enter on the keyboard', function() { beforeEach(sleep(100)); - beforeEach(async function() { - await sendKeys({ press: 'Enter' }); - await element.updateComplete; - }); + beforeEach(press('Enter')); + beforeEach(updateComplete); it('plays', function() { expect(element.paused, 'paused').to.be.false; }); @@ -365,31 +373,37 @@ describe('', function() { }); }); - describe('testing playback rate', function() { + describe('clicking playback rate select', function() { beforeEach(waitForCanplaythrough); - let startrate: number; - it('sets playback rate', async function() { - const pbr = getShadowElementBySelector('#playback-rate') as HTMLSelectElement; - pbr.selectedIndex = 0; - pbr.click(); - await element.updateComplete; - expect(element?.playbackRate).to.equal(0.25); + beforeEach(async function() { + await clickElementAtCenter(querySelectorDeep('rh-audio-player-rate-stepper:not([hidden]) select')!); + }); + describe('ArrowUp, Enter', function() { + beforeEach(press('ArrowUp')); + beforeEach(press('Enter')); + it('sets playback rate', function() { + expect(element?.playbackRate).to.equal(0.75); + }); }); + }); - it('increments playback rate', async function() { - const down = getShadowElementBySelector('#playback-rate-stepdown') as HTMLButtonElement; - startrate = element?.playbackRate; - down?.click(); - await element.updateComplete; - expect(element?.playbackRate).to.equal(startrate - 0.25); + describe('clicking rate stepdown', function() { + beforeEach(waitForCanplaythrough); + beforeEach(async function() { + await clickElementAtCenter(querySelectorDeep('#stepdown')!); }); + it('sets playback rate', function() { + expect(element?.playbackRate).to.equal(0.75); + }); + }); - it('decrements playback rate', async function() { - const up = getShadowElementBySelector('#playback-rate-stepup') as HTMLButtonElement; - startrate = element?.playbackRate; - up?.click(); - await element.updateComplete; - expect(element?.playbackRate).to.equal(startrate + 0.25); + describe('clicking rate stepup', function() { + beforeEach(waitForCanplaythrough); + beforeEach(async function() { + await clickElementAtCenter(querySelectorDeep('#stepup')!); + }); + it('sets playback rate', function() { + expect(element?.playbackRate).to.equal(1.25); }); }); }); @@ -408,50 +422,66 @@ describe('', function() { describe('tabbable controls', function() { beforeEach(waitForCanplaythrough); beforeEach(seek(1)); - describe('tab 1', function() { - beforeEach(tab); + describe('Tab (1)', function() { + beforeEach(press('Tab')); it('has width', assertHasWidth); - it('focuses seek range', function() { - expect(element.shadowRoot?.activeElement?.getAttribute('aria-label')).to.equal('Seek'); + it('focuses seek range', async function() { + expect(await a11ySnapshot()) + .axTreeFocusedNode + .to.have.axName('Seek'); }); - describe('tab 2', function() { - beforeEach(tab); - it('focuses mute button', function() { - expect(element.shadowRoot?.activeElement?.getAttribute('aria-label')).to.equal('Mute'); + describe('Tab (2)', function() { + beforeEach(press('Tab')); + it('focuses mute button', async function() { + expect(await a11ySnapshot()) + .axTreeFocusedNode + .to.have.axName('Mute'); }); - describe('tab 3', function() { - beforeEach(tab); - it('focuses volume slider', function() { - expect(element.shadowRoot?.activeElement?.getAttribute('aria-label')).to.equal('Volume'); + describe('Tab (3)', function() { + beforeEach(press('Tab')); + it('focuses volume slider', async function() { + expect(await a11ySnapshot()) + .axTreeFocusedNode + .to.have.axName('Volume'); }); - describe('tab 4', function() { - beforeEach(tab); - it('focuses speed select', function() { - expect(element.shadowRoot?.activeElement?.getAttribute('aria-label')).to.equal('Speed'); + describe('Tab (4)', function() { + beforeEach(press('Tab')); + it('focuses speed select', async function() { + expect(await a11ySnapshot()) + .axTreeFocusedNode + .to.have.axName('Speed'); }); - describe('tab 5', function() { - beforeEach(tab); - it('focuses rewind button', function() { - expect(element.shadowRoot?.activeElement?.getAttribute('aria-label')).to.equal('Rewind 15 seconds'); + describe('Tab (5)', function() { + beforeEach(press('Tab')); + it('focuses rewind button', async function() { + expect(await a11ySnapshot()) + .axTreeFocusedNode + .to.have.axName('Rewind 15 seconds'); }); - describe('tab 6', function() { - beforeEach(tab); - it('focuses play button', function() { - expect(element.shadowRoot?.activeElement?.getAttribute('aria-label')).to.equal('Play'); + describe('Tab (6)', function() { + beforeEach(press('Tab')); + it('focuses play button', async function() { + expect(await a11ySnapshot()) + .axTreeFocusedNode + .to.have.axName('Play'); }); - describe('tab 7', function() { - beforeEach(tab); - it('focuses advance button', function() { - expect(element.shadowRoot?.activeElement?.getAttribute('aria-label')).to.equal('Advance 15 seconds'); + describe('Tab (7)', function() { + beforeEach(press('Tab')); + it('focuses advance button', async function() { + expect(await a11ySnapshot()) + .axTreeFocusedNode + .to.have.axName('Advance 15 seconds'); }); - describe('tab 8', function() { - beforeEach(tab); - it('focuses menu button', function() { - expect(element.shadowRoot?.activeElement?.getAttribute('aria-label')).to.equal('More options'); + describe('Tab (8)', function() { + beforeEach(press('Tab')); + it('focuses menu button', async function() { + expect(await a11ySnapshot()) + .axTreeFocusedNode + .to.have.axName('More options'); }); - describe('tab 9', function() { - beforeEach(tab); + describe('Tab (9)', function() { + beforeEach(press('Tab')); it('reaches the end of focusable elements', function() { expect(element.shadowRoot?.activeElement).to.be.null; }); @@ -466,24 +496,29 @@ describe('', function() { }); }); - it('displays the correct elements', function() { - expect(getShadowElementBySelector('#full-play'), 'Play').to.exist.and.to.be.visible; - expect(getShadowElementByAriaLabel('Seek'), 'Seek').to.exist.and.to.be.visible; - expect(getShadowElementByAriaLabel('Mute'), 'Mute').to.exist.and.to.be.visible; - expect(getShadowElementByAriaLabel('Speed'), 'Speed').to.exist.and.to.be.visible; - expect(getShadowElementByAriaLabel('Volume'), 'Volume').to.exist.and.to.be.visible; + it('displays the correct elements', async function() { + expect(await a11ySnapshot()) + .to.axContainName('Play') + .and.to.axContainName('Seek') + .and.to.axContainName('Mute') + .and.to.axContainName('Speed') + .and.to.axContainName('Volume') + .and.to.axContainName('More options'); }); // TODO: repeat this suite in mobile - it('rewind is disabled', function() { - const rw = getShadowElementBySelector('#rewind') as HTMLButtonElement; - expect(rw?.disabled).to.be.true; + it('rewind is disabled', async function() { + expect(await a11ySnapshot()).to.axContainQuery({ + name: 'Rewind 15 seconds', + disabled: true, + }); }); // TODO: repeat this suite in mobile - it('forward is not disabled', function() { - const fw = getShadowElementBySelector('#forward') as HTMLButtonElement; - expect(fw?.disabled).to.be.false; + it('forward is not disabled', async function() { + expect(await a11ySnapshot()) + .axQuery({ name: 'Advance 15 seconds' }) + .to.not.have.axProperty('disabled', true); }); describe('clicking the forward button', function() { @@ -496,9 +531,10 @@ describe('', function() { expect(currentTime > starttime).to.be.true; }); - it('enables rewind', function() { - const rw = getShadowElementBySelector('#rewind') as HTMLButtonElement; - expect(rw?.disabled).to.be.false; + it('enables rewind', async function() { + expect(await a11ySnapshot()) + .axQuery({ name: 'Rewind 15 seconds' }) + .to.not.have.axProperty('disabled', true); }); describe('then clicking the rewind button', function() { @@ -517,29 +553,38 @@ describe('', function() { describe('testing playback rate', function() { beforeEach(waitForCanplaythrough); - let startrate: number; - it('sets playback rate', async function() { - const pbr = getShadowElementBySelector('#full-playback-rate') as HTMLSelectElement; - pbr.selectedIndex = 0; - pbr.click(); - await element.updateComplete; - expect(element?.playbackRate).to.equal(0.25); + describe('clicking playback rate select', function() { + beforeEach(waitForCanplaythrough); + beforeEach(async function() { + await clickElementAtCenter(querySelectorDeep('rh-audio-player-rate-stepper:not([hidden]) select')!); + }); + describe('ArrowUp, Enter', function() { + beforeEach(press('ArrowUp')); + beforeEach(press('Enter')); + it('sets playback rate', function() { + expect(element?.playbackRate).to.equal(0.75); + }); + }); }); - it('increments playback rate', async function() { - const down = getShadowElementBySelector('#full-playback-rate-stepdown') as HTMLButtonElement; - startrate = element?.playbackRate; - down?.click(); - await element.updateComplete; - expect(element?.playbackRate).to.equal(startrate - 0.25); + describe('clicking rate stepdown', function() { + beforeEach(waitForCanplaythrough); + beforeEach(async function() { + await clickElementAtCenter(querySelectorDeep('rh-audio-player-rate-stepper:not([hidden]) #stepdown')!); + }); + it('sets playback rate', function() { + expect(element?.playbackRate).to.equal(0.75); + }); }); - it('decrements playback rate', async function() { - const up = getShadowElementBySelector('#full-playback-rate-stepup') as HTMLButtonElement; - startrate = element?.playbackRate; - up?.click(); - await element.updateComplete; - expect(element?.playbackRate).to.equal(startrate + 0.25); + describe('clicking rate stepup', function() { + beforeEach(waitForCanplaythrough); + beforeEach(async function() { + await clickElementAtCenter(querySelectorDeep('rh-audio-player-rate-stepper:not([hidden]) #stepup')!); + }); + it('sets playback rate', function() { + expect(element?.playbackRate).to.equal(1.25); + }); }); }); }); @@ -599,7 +644,7 @@ describe('', function() { expect(getShadowElementByAriaLabel('Mute'), 'Mute').to.exist.and.to.be.visible; }); it('has mute button enabled', function() { - const button = getShadowElementBySelector('#mute') as HTMLButtonElement; + const button = querySelectorDeep('#mute') as HTMLButtonElement; expect(button?.disabled, 'state').to.be.false; }); }); @@ -608,7 +653,7 @@ describe('', function() { beforeEach(setupForLayout('full')); it('has width', assertHasWidth); it('displays the correct elements', function() { - expect(getShadowElementBySelector('#play'), 'Play').to.exist.and.to.be.visible; + expect(querySelectorDeep('#play'), 'Play').to.exist.and.to.be.visible; expect(getShadowElementByAriaLabel('Seek'), 'Seek').to.exist.and.to.be.visible; expect(getShadowElementByAriaLabel('Mute'), 'Mute').to.exist.and.to.be.visible; }); diff --git a/elements/rh-avatar/docs/00-overview.md b/elements/rh-avatar/docs/00-overview.md index 4a55da0eaa..331980ff73 100644 --- a/elements/rh-avatar/docs/00-overview.md +++ b/elements/rh-avatar/docs/00-overview.md @@ -3,7 +3,7 @@ {{ tagName | getElementDescription }} - Image of an avatar group with a photo of a woman and text + Image of an avatar group with a photo of a woman and text {% repoStatusList repoStatus=repoStatus %} diff --git a/elements/rh-avatar/docs/10-style.md b/elements/rh-avatar/docs/10-style.md index 6b1df3b0d9..5f10d48c07 100644 --- a/elements/rh-avatar/docs/10-style.md +++ b/elements/rh-avatar/docs/10-style.md @@ -8,7 +8,7 @@ including their full name, job title, and company.
- Anatomy of an avatar group with numbered annotations + Anatomy of an avatar group with numbered annotations
    @@ -27,7 +27,7 @@ their name. A specific name is linked to the same pattern, so thumbnails can stay static without storing lots of generated images. - Image of all avatar groups including default, photo, green squares, purple squares, and blue triangles + Image of all avatar groups including default, photo, green squares, purple squares, and blue triangles ### Plain @@ -37,7 +37,7 @@ The avatar thumbnail can be used on its own in places like [cards](https://ux.redhat.com/elements/card/), navigations, tables, and more. - Image of a row of only avatar thumbnails + Image of a row of only avatar thumbnails ### Link @@ -50,7 +50,7 @@ Links can be applied to full name or job details text. - Image of two avatar groups; one has the full name linked and the other has the company name linked + Image of two avatar groups; one has the full name linked and the other has the company name linked ## Theme @@ -60,11 +60,11 @@ All avatar variants are available in both light and dark themes. ### Light and dark themes - Image of a light theme avatar group + Image of a light theme avatar group - Image of a dark theme avatar group + Image of a dark theme avatar group @@ -94,7 +94,7 @@ examples, go to the [Guidelines](https://ux.redhat.com/elements/avatar/guidelines/) page. - Image of two avatar groups showing specs like height, width, and centering/alignment + Image of two avatar groups showing specs like height, width, and centering/alignment ### Job details text @@ -102,7 +102,7 @@ examples, go to the Job details text has specific styles applied to it. - Image of two avatar groups showing only job details text left justified and center justified + Image of two avatar groups showing only job details text left justified and center justified @@ -135,7 +135,7 @@ Job details text has specific styles applied to it. Space values are the same for all variants and on all breakpoints. - Image of all avatar groups with spacing values in between + Image of all avatar groups with spacing values in between @@ -153,11 +153,11 @@ Interaction states are visual representations used to communicate the status of ### Hover - Image of light theme avatar group hover states + Image of light theme avatar group hover states - Image of dark theme avatar group hover states + Image of dark theme avatar group hover states @@ -207,11 +207,11 @@ Interaction states are visual representations used to communicate the status of - Image of light theme avatar group focus states + Image of light theme avatar group focus states - Image of dark theme avatar group focus states + Image of dark theme avatar group focus states @@ -242,11 +242,11 @@ Interaction states are visual representations used to communicate the status of - Image of light theme avatar group active states + Image of light theme avatar group active states - Image of dark theme avatar group active states + Image of dark theme avatar group active states diff --git a/elements/rh-avatar/docs/20-guidelines.md b/elements/rh-avatar/docs/20-guidelines.md index 6ce8d88bad..3ad5aa2fde 100644 --- a/elements/rh-avatar/docs/20-guidelines.md +++ b/elements/rh-avatar/docs/20-guidelines.md @@ -10,7 +10,7 @@ room for customization. The avatar thumbnail can be used at different sizes based on our design tokens. The default size is 64px. - Image of all avatar thumbnail sizes and their pixel values underneath + Image of all avatar thumbnail sizes and their pixel values underneath @@ -43,7 +43,7 @@ The avatar thumbnail can be used at different sizes based on our design tokens. Separate each part of the job title and company name with a comma. - Image of three job details text, ranging from short to long + Image of three job details text, ranging from short to long ## Layout @@ -54,7 +54,7 @@ The avatar thumbnail and job details text can be horizontally or vertically centered. - Image of two avatar groups; one is horizontally centered and the other is vertically centered + Image of two avatar groups; one is horizontally centered and the other is vertically centered @@ -63,7 +63,7 @@ centered. There is `48px` of space when avatar groups are stacked vertically. - Image of three avatar groups stacked vertically with 48 pixel of space in between + Image of three avatar groups stacked vertically with 48 pixel of space in between ## Responsive design @@ -71,13 +71,13 @@ There is `48px` of space when avatar groups are stacked vertically. ### Large breakpoints - Image of two avatar groups used on large breakpoints; one is aligned left and the other is aligned in the center + Image of two avatar groups used on large breakpoints; one is aligned left and the other is aligned in the center ### Small breakpoints - Image of four avatar groups used on small breakpoints; two are aligned left and the other two are aligned in the center + Image of four avatar groups used on small breakpoints; two are aligned left and the other two are aligned in the center ### Line breaks @@ -86,7 +86,7 @@ As breakpoints or containers get smaller, regardless if job details text will break to more lines, it is still anchored at the top. - Image of two avatar groups with specs on top; one has two lines and the other has five lines + Image of two avatar groups with specs on top; one has two lines and the other has five lines ## Best practices @@ -96,7 +96,7 @@ break to more lines, it is still anchored at the top. Do not change the shape of the avatar thumbnail. - Image of a square avatar thumbnail which is incorrect usage + Image of a square avatar thumbnail which is incorrect usage ### Light theme thumbnail @@ -104,7 +104,7 @@ Do not change the shape of the avatar thumbnail. Do not use a light theme avatar thumbnail in the dark theme. - Image of a light theme avatar thumbnail placed on a black background which is incorrect usage + Image of a light theme avatar thumbnail placed on a black background which is incorrect usage ### Icon vs. avatar thumbnail @@ -112,7 +112,7 @@ Do not use a light theme avatar thumbnail in the dark theme. Do not use an avatar thumbnail when an icon is more suitable. - Image of an icon and avatar thumbnail right next to each other which is incorrect usage + Image of an icon and avatar thumbnail right next to each other which is incorrect usage diff --git a/elements/rh-avatar/rh-avatar.css b/elements/rh-avatar/rh-avatar.css index d186557324..ec547bedc8 100644 --- a/elements/rh-avatar/rh-avatar.css +++ b/elements/rh-avatar/rh-avatar.css @@ -12,28 +12,26 @@ color: var(--rh-color-text-secondary-on-light, #4d4d4d); --_colors: - var( - --rh-avatar-colors, - var(--rh-color-blue-30, #92c5f9) - var(--rh-color-teal-50, #37a3a3) - var(--rh-color-green-60, #3d7317) - var(--rh-color-red-40, #f56e6e) - var(--rh-color-purple-60, #3d2785) - ); + var(--rh-avatar-colors, + var(--rh-color-blue-30, #92c5f9) + var(--rh-color-teal-50, #37a3a3) + var(--rh-color-green-60, #3d7317) + var(--rh-color-red-40, #f56e6e) + var(--rh-color-purple-60, #3d2785)); column-gap: var(--rh-space-lg, 16px); width: min-content; grid-template-columns: min-content minmax(max-content, 250px); grid-template-rows: min-content min-content; grid-template-areas: - "a t" - "a s"; + 'a t' + 'a s'; } #title { grid-area: t; align-self: end; - 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", Helvetica, Arial, sans-serif); + 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', Helvetica, Arial, sans-serif); font-weight: var(--rh-font-weight-heading-medium, 500); font-size: var(--rh-font-size-body-text-sm, 0.875rem); } @@ -45,20 +43,20 @@ font-size: var(--rh-font-size-body-text-sm, 0.875rem); } -:host([layout="block"]) #container, +:host([layout='block']) #container, #container.mobile { text-align: center; place-items: center; gap: 0; grid-template-columns: minmax(max-content, 250px); - grid-template-areas: "a" "t" "s"; + grid-template-areas: 'a' 't' 's'; grid-template-rows: minmax(var(--rh-avatar-size, var(--rh-size-icon-06, 64px)), var(--rh-size-icon-06, 64px)) min-content auto; } -:host([layout="block"]) :is(img, canvas, svg), +:host([layout='block']) :is(img, canvas, svg), #container.mobile :is(img, canvas, svg) { margin-block-end: var(--rh-space-lg, 16px); } @@ -69,33 +67,36 @@ slot { } ::slotted(a) { - color: var(--rh-color-interactive-blue-darker, #0066cc); + color: var(--rh-color-interactive-primary-default-on-light, #0066cc); text-decoration: none; } -::slotted(a:visited) { color: var(--rh-color-interactive-purple-darker, #5e40be); } +::slotted(a:visited) { + color: var(--rh-color-interactive-primary-visited-default-on-light, #5e40be); +} ::slotted(a:active), -::slotted(a:hover) { color: var(--rh-color-interactive-blue-darkest, #003366); } +::slotted(a:hover) { color: var(--rh-color-interactive-primary-hover-on-light, #003366); } + +.dark ::slotted(a) { color: var(--rh-color-interactive-primary-default-on-dark, #92c5f9); } -.dark ::slotted(a) { color: var(--rh-color-interactive-blue-lighter, #92c5f9); } -.dark ::slotted(a:visited) { color: var(--rh-color-interactive-purple-lighter, #b6a6e9); } +.dark ::slotted(a:visited) { + color: var(--rh-color-interactive-primary-visited-default-on-dark, #b6a6e9); +} .dark ::slotted(a:active), -.dark ::slotted(a:hover) { color: var(--rh-color-interactive-blue-lightest, #b9dafc); } +.dark ::slotted(a:hover) { color: var(--rh-color-interactive-primary-hover-on-dark, #b9dafc); } #container.dark { color: var(--rh-color-text-secondary-on-dark, #c7c7c7); --_colors: - var( - --rh-avatar-colors, - var(--rh-color-blue-50, #0066cc) - var(--rh-color-teal-70, #004d4d) - var(--rh-color-green-70, #204d00) - var(--rh-color-red-50, #ee0000) - var(--rh-color-purple-70, #21134d) - ); + var(--rh-avatar-colors, + var(--rh-color-blue-50, #0066cc) + var(--rh-color-teal-70, #004d4d) + var(--rh-color-green-70, #204d00) + var(--rh-color-red-50, #ee0000) + var(--rh-color-purple-70, #21134d)); } img, diff --git a/elements/rh-back-to-top/docs/00-overview.md b/elements/rh-back-to-top/docs/00-overview.md index 7971c676ad..183c179ab3 100644 --- a/elements/rh-back-to-top/docs/00-overview.md +++ b/elements/rh-back-to-top/docs/00-overview.md @@ -3,7 +3,7 @@ {{ tagName | getElementDescription }} - Example of a back to top button + Example of a back to top button diff --git a/elements/rh-back-to-top/docs/10-style.md b/elements/rh-back-to-top/docs/10-style.md index dd866e1537..cc45a71884 100644 --- a/elements/rh-back-to-top/docs/10-style.md +++ b/elements/rh-back-to-top/docs/10-style.md @@ -21,7 +21,7 @@ A back to top is a pill-shaped button that is anchored to the bottom right corne
    - Back to top button with numerical annotations + Back to top button with numerical annotations
      @@ -40,11 +40,11 @@ The back to top button looks the same in light and dark themes.
      - Back to top button with a blue background and white text against a white surface color + Back to top button with a blue background and white text against a white surface color - Back to top buttons that have a blue background and white text against a black surface color + Back to top buttons that have a blue background and white text against a black surface color
      @@ -55,7 +55,7 @@ The back to top button looks the same in light and dark themes. A back to top button has 4px of padding on the left and right, 8px of padding on the top and bottom, and a 4px gap between text and icon. The amount of space remains the same on all breakpoints. - Back to top button with block padding of 4px, inline padding of 8px, and a 4px gap between text and icon + Back to top button with block padding of 4px, inline padding of 8px, and a 4px gap between text and icon @@ -69,7 +69,7 @@ Interaction states are visual representations used to communicate the status of The background color of the button turns to a darker blue on hover. It also has a white border adjacent to the button and a dark blue outline adjacent to the border. This ensures contrast against all surface colors. - Back to top button with a dark blue background when a cursor hovers over it + Back to top button with a dark blue background when a cursor hovers over it @@ -81,7 +81,7 @@ The background color of the button turns to a darker blue on hover. It also has - A back to top button with a dark blue background and a blue focus ring around it + A back to top button with a dark blue background and a blue focus ring around it @@ -93,6 +93,6 @@ The background color of the button turns to a darker blue on hover. It also has - A back to top button with a dark blue background and a blue focus ring around it + A back to top button with a dark blue background and a blue focus ring around it diff --git a/elements/rh-back-to-top/docs/20-guidelines.md b/elements/rh-back-to-top/docs/20-guidelines.md index 6be2e9a557..0393a3698d 100644 --- a/elements/rh-back-to-top/docs/20-guidelines.md +++ b/elements/rh-back-to-top/docs/20-guidelines.md @@ -1,4 +1,4 @@ - + diff --git a/elements/rh-button/docs/00-overview.md b/elements/rh-button/docs/00-overview.md index b42a00a867..592071620d 100644 --- a/elements/rh-button/docs/00-overview.md +++ b/elements/rh-button/docs/00-overview.md @@ -3,7 +3,7 @@ {{ tagName | getElementDescription }} - Image of Danger, Primary, Secondary, Tertiary, and Link buttons in the first row and Play and Close buttons in the second row + Image of Danger, Primary, Secondary, Tertiary, and Link buttons in the first row and Play and Close buttons in the second row {% repoStatusList repoStatus=repoStatus %} diff --git a/elements/rh-button/docs/10-style.md b/elements/rh-button/docs/10-style.md index 3c1a7f6f52..a27973e0b6 100644 --- a/elements/rh-button/docs/10-style.md +++ b/elements/rh-button/docs/10-style.md @@ -8,7 +8,7 @@ used on its own or grouped with other buttons.
      - Anatomy image of buttons with numbered annotations + Anatomy image of buttons with numbered annotations
        @@ -30,11 +30,11 @@ Buttons are available in both light and dark themes. ### Light and dark themes - Image of light theme Danger, Primary, Secondary, Tertiary, Link, Play, and Close buttons + Image of light theme Danger, Primary, Secondary, Tertiary, Link, Play, and Close buttons - Image of dark theme Danger, Primary, Secondary, Tertiary, Link, Play, and Close buttons + Image of dark theme Danger, Primary, Secondary, Tertiary, Link, Play, and Close buttons @@ -120,7 +120,7 @@ horizontally and vertically centered and stays the same size no matter how big or small the image gets. - Image of buttons and various specs like border radius, height, icon size, width, alignment, placement, and more + Image of buttons and various specs like border radius, height, icon size, width, alignment, placement, and more ## Space @@ -134,7 +134,7 @@ space values when buttons are grouped, go to the [Guidelines](./guidelines) page - Image of Danger, Primary, Secondary, Tertiary, Link, and Close buttons with spacing values in between + Image of Danger, Primary, Secondary, Tertiary, Link, and Close buttons with spacing values in between @@ -154,11 +154,11 @@ an element or pattern. ### Hover - Image of light theme button hover states + Image of light theme button hover states - Image of dark theme button hover states + Image of dark theme button hover states @@ -223,11 +223,11 @@ an element or pattern. - Image of light theme button focus states + Image of light theme button focus states - Image of dark theme button focus states + Image of dark theme button focus states @@ -258,11 +258,11 @@ an element or pattern. - Image of light theme button active states + Image of light theme button active states - Image of dark theme button active states + Image of dark theme button active states diff --git a/elements/rh-button/docs/20-guidelines.md b/elements/rh-button/docs/20-guidelines.md index 73ff75eecb..12b690e673 100644 --- a/elements/rh-button/docs/20-guidelines.md +++ b/elements/rh-button/docs/20-guidelines.md @@ -23,7 +23,7 @@ function to users. Therefore, it is important that each variant is implemented consistently so they communicate the correct actions. - Image of the seven available button variant + Image of the seven available button variant @@ -77,7 +77,7 @@ Use a Play button to indicate that audio or video will play when selected. - Image of play button examples; a video thumbnail on the left and a text layout on the right + Image of play button examples; a video thumbnail on the left and a text layout on the right ### Close button @@ -86,9 +86,13 @@ Use a Close button to indicate that a window will close when selected. Close buttons are mostly found in [dialogs](/elements/dialog/). - Image of a dialog with a close button in the top right corner + Image of a dialog with a close button in the top right corner +### Other icons + +When adding icons, prefer to use the [microns](/icons/#micron-icons) as they fit +the button layout better. ### Disabled @@ -97,7 +101,7 @@ completed first, most buttons can become disabled. However, the Play and Close buttons do not include a disabled state. - Image of five disabled buttons not including play and close buttons, underneath is a dropdown with a disabled button + Image of five disabled buttons not including play and close buttons, underneath is a dropdown with a disabled button ## Writing content @@ -124,7 +128,7 @@ When writing link button text labels, use specific and action-focused language that matches what users will see when they arrive at their location. - Image of link button text labels + Image of link button text labels ### Button vs. call to action text labels @@ -133,7 +137,7 @@ Button text labels are written to be short and communicate an action whereas call to action text labels are written to entice users to select a link. - Image of two buttons on the left and two calls to action on the right + Image of two buttons on the left and two calls to action on the right ### Character and word count @@ -178,7 +182,7 @@ consistent across all contexts elements are stacked vertically - Image of buttons used in a dialog and a form + Image of buttons used in a dialog and a form ### Hierarchy @@ -187,7 +191,7 @@ Buttons are ordered by hierarchy from left to right. Do not use multiple Danger, Primary, or Close buttons in the same area. - Image of buttons grouped by hierarchy from left to right + Image of buttons grouped by hierarchy from left to right ### Grouping @@ -196,7 +200,7 @@ Grouping buttons is a useful way of aligning buttons that have a relationship. Group buttons logically into sets based on hierarchy and usage. - Image of button groups and their hierarchy from left to right + Image of button groups and their hierarchy from left to right ### Space in groups @@ -206,7 +210,7 @@ buttons. If buttons are stacked, the spacing between each button should be `8px`. - Image of button groups and their horizontal and vertical spacing in between each button + Image of button groups and their horizontal and vertical spacing in between each button ## Best practices @@ -216,7 +220,7 @@ buttons. If buttons are stacked, the spacing between each button should be Buttons should never have more than one line of text. - Image of a button with two lines of text which is incorrect usage + Image of a button with two lines of text which is incorrect usage ### Multiple buttons @@ -224,7 +228,7 @@ Buttons should never have more than one line of text. Do not use multiple Danger or Primary buttons in the same area. - Image of two danger and two primary button groups which is incorrect usage + Image of two danger and two primary button groups which is incorrect usage ### Text labels @@ -232,7 +236,7 @@ Do not use multiple Danger or Primary buttons in the same area. Do not write button text labels that are expressive or ambiguous. - Image of two buttons; one has expressive language and the other has ambiguous language which is incorrect usage + Image of two buttons; one has expressive language and the other has ambiguous language which is incorrect usage ### Danger button @@ -240,7 +244,7 @@ Do not write button text labels that are expressive or ambiguous. Do not use a Danger button for non-destructive purposes. - Image of a search bar using a danger button which is incorrect usage + Image of a search bar using a danger button which is incorrect usage ### Button as a call to action @@ -249,5 +253,5 @@ Do not use buttons as links or change the Primary button styling, use a link or call to action instead. - Image of text styles with a button underneath that resembles a call to action which is incorrect usage + Image of text styles with a button underneath that resembles a call to action which is incorrect usage diff --git a/elements/rh-button/docs/40-accessibility.md b/elements/rh-button/docs/40-accessibility.md index 380081d1a2..32249dddf4 100644 --- a/elements/rh-button/docs/40-accessibility.md +++ b/elements/rh-button/docs/40-accessibility.md @@ -13,7 +13,7 @@ link Users should have the ability to navigate to and interact with buttons using their keyboard. - Image of a button group showing focus indicators and tab key labels + Image of a button group showing focus indicators and tab key labels @@ -46,14 +46,14 @@ Users should have the ability to navigate to and interact with buttons using the {% include 'partials/accessibility/focusorder.md' %} For buttons in groups, the focus order is from left to right and top to bottom when stacked. Disabled buttons are not included in the focus order unless they include the `aria-disabled=“true”` attribute and display a [tooltip](/elements/tooltip) when focused. - Image of rows of button groups with numbers; one row has focus indicators only and the other has focus indicators and a tooltip + Image of rows of button groups with numbers; one row has focus indicators only and the other has focus indicators and a tooltip ## Touch targets Buttons in groups are adequately spaced for optimal touch targets. - Image of button group with touch targets on top of each button + Image of button group with touch targets on top of each button ## Screen reader guidelines diff --git a/elements/rh-button/rh-button.css b/elements/rh-button/rh-button.css index d908d303b8..2d4aa23bdc 100644 --- a/elements/rh-button/rh-button.css +++ b/elements/rh-button/rh-button.css @@ -3,10 +3,6 @@ height: max-content; } -:host([hidden]) { - display: none !important; -} - [hidden] { display: none !important; } @@ -36,7 +32,7 @@ button { button:after { position: absolute; inset: 0; - content: ""; + content: ''; border-style: solid; border-color: var(--_border-color); border-width: var(--_border-width); @@ -47,16 +43,16 @@ button > span { display: contents; } -:host(:is(:disabled, [aria-disabled="true"])), -:host(:is(:disabled, [aria-disabled="true"])) #container, -:host(:is(:disabled, [aria-disabled="true"])) button, -:host(:is(:disabled, [aria-disabled="true"])[danger]) button, -:host(:is(:disabled, [aria-disabled="true"])[variant="link"]) button { +:host(:is(:disabled, [aria-disabled='true'])), +:host(:is(:disabled, [aria-disabled='true'])) #container, +:host(:is(:disabled, [aria-disabled='true'])) button, +:host(:is(:disabled, [aria-disabled='true'])[danger]) button, +:host(:is(:disabled, [aria-disabled='true'])[variant='link']) button { pointer-events: none; cursor: default; } -[part="icon"] { +[part='icon'] { display: none; pointer-events: none; } @@ -64,42 +60,36 @@ button > span { .hasIcon { position: relative; display: flex; + gap: var(--rh-space-sm, 6px); align-items: center; -} + padding-inline-start: calc(var(--rh-space-lg, 16px) * 0.75); -.hasIcon [part="icon"] { - display: inline-flex; - align-items: center; - position: absolute; - width: 16px; + & [part='icon'] { + display: contents; + } } -[part="icon"] ::slotted(*) { +[part='icon'] ::slotted(*) { width: 16px; max-width: 16px; height: 16px; max-height: 16px; } -.hasIcon button { - position: absolute; - inset: 0; -} - .light { /* PRIMARY */ --_primary-color: var(--rh-color-text-primary-on-dark, #ffffff); - --_primary-background-color: var(--rh-color-interactive-blue-darker, #0066cc); + --_primary-background-color: var(--rh-color-interactive-primary-default-on-light, #0066cc); --_primary-border-color: transparent; --_primary-border-width: var(--rh-border-width-sm, 1px); --_primary-active-color: var(--rh-color-text-primary-on-dark, #ffffff); - --_primary-active-background-color: var(--rh-color-interactive-blue-darkest, #003366); + --_primary-active-background-color: var(--rh-color-interactive-primary-hover-on-light, #003366); --_primary-active-border-width: var(--rh-border-width-sm, 1px); --_primary-focus-color: var(--rh-color-text-primary-on-dark, #ffffff); - --_primary-focus-background-color: var(--rh-color-interactive-blue-darkest, #003366); + --_primary-focus-background-color: var(--rh-color-interactive-primary-hover-on-light, #003366); --_primary-focus-border-width: var(--rh-border-width-md, 2px); --_primary-hover-color: var(--rh-color-text-primary-on-dark, #ffffff); - --_primary-hover-background-color: var(--rh-color-interactive-blue-darkest, #003366); + --_primary-hover-background-color: var(--rh-color-interactive-primary-hover-on-light, #003366); --_primary-hover-border-width: var(--rh-border-width-sm, 1px); /* DANGER */ @@ -119,22 +109,22 @@ button > span { --_danger-hover-border-color: transparent; /* SECONDARY */ - --_secondary-color: var(--rh-color-interactive-blue-darker, #0066cc); + --_secondary-color: var(--rh-color-interactive-primary-default-on-light, #0066cc); --_secondary-danger-color: var(--rh-color-red-60, #a60000); --_secondary-background-color: transparent; - --_secondary-border-color: var(--rh-color-interactive-blue-darker, #0066cc); + --_secondary-border-color: var(--rh-color-interactive-primary-default-on-light, #0066cc); --_secondary-border-width: var(--rh-border-width-sm, 1px); - --_secondary-active-color: var(--rh-color-interactive-blue-darker, #0066cc); + --_secondary-active-color: var(--rh-color-interactive-primary-default-on-light, #0066cc); --_secondary-active-background-color: transparent; - --_secondary-active-border-color: var(--rh-color-interactive-blue-darker, #0066cc); + --_secondary-active-border-color: var(--rh-color-interactive-primary-default-on-light, #0066cc); --_secondary-active-border-width: var(--rh-border-width-md, 2px); - --_secondary-focus-color: var(--rh-color-interactive-blue-darker, #0066cc); + --_secondary-focus-color: var(--rh-color-interactive-primary-default-on-light, #0066cc); --_secondary-focus-background-color: transparent; - --_secondary-focus-border-color: var(--rh-color-interactive-blue-darker, #0066cc); + --_secondary-focus-border-color: var(--rh-color-interactive-primary-default-on-light, #0066cc); --_secondary-focus-border-width: var(--rh-border-width-md, 2px); - --_secondary-hover-color: var(--rh-color-interactive-blue-darker, #0066cc); + --_secondary-hover-color: var(--rh-color-interactive-primary-default-on-light, #0066cc); --_secondary-hover-background-color: transparent; - --_secondary-hover-border-color: var(--rh-color-interactive-blue-darker, #0066cc); + --_secondary-hover-border-color: var(--rh-color-interactive-primary-default-on-light, #0066cc); --_secondary-hover-border-width: var(--rh-border-width-md, 2px); /* TERTIARY */ @@ -156,13 +146,13 @@ button > span { --_tertiary-hover-border-width: var(--rh-border-width-md, 2px); /* LINK */ - --_link-color: var(--rh-color-interactive-blue-darker, #0066cc); + --_link-color: var(--rh-color-interactive-primary-default-on-light, #0066cc); --_link-background-color: transparent; --_link-active-color: var(--rh-color-blue-70, #003366); --_link-active-background-color: transparent; --_link-focus-color: var(--rh-color-blue-70, #003366); --_link-focus-background-color: transparent; - --_link-focus-outline-color: var(--rh-color-interactive-blue-darker, #0066cc); + --_link-focus-outline-color: var(--rh-color-interactive-primary-default-on-light, #0066cc); --_link-hover-color: var(--rh-color-blue-70, #003366); --_link-hover-background-color: transparent; @@ -173,7 +163,7 @@ button > span { --_close-active-background-color: transparent; --_close-focus-color: var(--rh-color-icon-secondary-on-light, #151515); --_close-focus-background-color: transparent; - --_close-focus-outline-color: var(--rh-color-interactive-blue-darker, #0066cc); + --_close-focus-outline-color: var(--rh-color-interactive-primary-default-on-light, #0066cc); --_close-hover-color: var(--rh-color-icon-secondary-on-light, #151515); --_close-hover-background-color: transparent; @@ -183,24 +173,24 @@ button > span { --_play-background-color: rgb(var(--_gray-90-rgb) / var(--rh-opacity-50, 50%)); --_play-active-background-color: rgb(var(--_gray-90-rgb) / var(--rh-opacity-80, 80%)); --_play-focus-background-color: rgb(var(--_gray-90-rgb) / var(--rh-opacity-80, 80%)); - --_play-focus-outline-color: var(--rh-color-interactive-blue-darker, #0066cc); + --_play-focus-outline-color: var(--rh-color-interactive-primary-default-on-light, #0066cc); --_play-hover-background-color: rgb(var(--_gray-90-rgb) / var(--rh-opacity-80, 80%)); } .dark { - --_focus-outline-color: var(--rh-color-interactive-blue-lighter, #92c5f9); + --_focus-outline-color: var(--rh-color-interactive-primary-default-on-dark, #92c5f9); /* PRIMARY */ --_primary-color: var(--rh-color-text-primary-on-dark, #ffffff); - --_primary-background-color: var(--rh-color-interactive-blue-darker, #0066cc); + --_primary-background-color: var(--rh-color-interactive-primary-default-on-light, #0066cc); --_primary-border-color: transparent; --_primary-border-width: var(--rh-border-width-sm, 1px); --_primary-active-color: var(--rh-color-text-primary-on-dark, #ffffff); - --_primary-active-background-color: var(--rh-color-interactive-blue-darkest, #003366); + --_primary-active-background-color: var(--rh-color-interactive-primary-hover-on-light, #003366); --_primary-focus-color: var(--rh-color-text-primary-on-dark, #ffffff); - --_primary-focus-background-color: var(--rh-color-interactive-blue-darkest, #003366); + --_primary-focus-background-color: var(--rh-color-interactive-primary-hover-on-light, #003366); --_primary-hover-color: var(--rh-color-text-primary-on-dark, #ffffff); - --_primary-hover-background-color: var(--rh-color-interactive-blue-darkest, #003366); + --_primary-hover-background-color: var(--rh-color-interactive-primary-hover-on-light, #003366); /* DANGER */ --_danger-color: var(--rh-color-text-primary-on-light, #151515); @@ -218,22 +208,22 @@ button > span { --_danger-hover-border-color: transparent; /* SECONDARY */ - --_secondary-color: var(--rh-color-interactive-blue-lighter, #92c5f9); + --_secondary-color: var(--rh-color-interactive-primary-default-on-dark, #92c5f9); --_secondary-danger-color: var(--rh-color-red-30, #f9a8a8); --_secondary-background-color: transparent; - --_secondary-border-color: var(--rh-color-interactive-blue-lighter, #92c5f9); + --_secondary-border-color: var(--rh-color-interactive-primary-default-on-dark, #92c5f9); --_secondary-border-width: var(--rh-border-width-sm, 1px); - --_secondary-active-color: var(--rh-color-interactive-blue-lighter, #92c5f9); + --_secondary-active-color: var(--rh-color-interactive-primary-default-on-dark, #92c5f9); --_secondary-active-background-color: transparent; - --_secondary-active-border-color: var(--rh-color-interactive-blue-lighter, #92c5f9); + --_secondary-active-border-color: var(--rh-color-interactive-primary-default-on-dark, #92c5f9); --_secondary-active-border-width: var(--rh-border-width-md, 2px); - --_secondary-focus-color: var(--rh-color-interactive-blue-lighter, #92c5f9); + --_secondary-focus-color: var(--rh-color-interactive-primary-default-on-dark, #92c5f9); --_secondary-focus-background-color: transparent; - --_secondary-focus-border-color: var(--rh-color-interactive-blue-lighter, #92c5f9); + --_secondary-focus-border-color: var(--rh-color-interactive-primary-default-on-dark, #92c5f9); --_secondary-focus-border-width: var(--rh-border-width-md, 2px); - --_secondary-hover-color: var(--rh-color-interactive-blue-lighter, #92c5f9); + --_secondary-hover-color: var(--rh-color-interactive-primary-default-on-dark, #92c5f9); --_secondary-hover-background-color: transparent; - --_secondary-hover-border-color: var(--rh-color-interactive-blue-lighter, #92c5f9); + --_secondary-hover-border-color: var(--rh-color-interactive-primary-default-on-dark, #92c5f9); --_secondary-hover-border-width: var(--rh-border-width-md, 2px); /* TERTIARY */ @@ -255,21 +245,21 @@ button > span { --_tertiary-hover-border-width: var(--rh-border-width-md, 2px); /* LINK */ - --_link-color: var(--rh-color-interactive-blue-lighter, #92c5f9); + --_link-color: var(--rh-color-interactive-primary-default-on-dark, #92c5f9); --_link-background-color: transparent; - --_link-active-color: var(--rh-color-interactive-blue-lightest, #b9dafc); + --_link-active-color: var(--rh-color-interactive-primary-hover-on-dark, #b9dafc); --_link-active-background-color: transparent; - --_link-focus-color: var(--rh-color-interactive-blue-lightest, #b9dafc); + --_link-focus-color: var(--rh-color-interactive-primary-hover-on-dark, #b9dafc); --_link-focus-background-color: transparent; - --_link-focus-outline-color: var(--rh-color-interactive-blue-lighter, #92c5f9); - --_link-hover-color: var(--rh-color-interactive-blue-lightest, #b9dafc); + --_link-focus-outline-color: var(--rh-color-interactive-primary-default-on-dark, #92c5f9); + --_link-hover-color: var(--rh-color-interactive-primary-hover-on-dark, #b9dafc); --_link-hover-background-color: transparent; /* CLOSE */ --_close-color: var(--rh-color-text-secondary-on-dark, #c7c7c7); --_close-background-color: transparent; --_close-focus-background-color: transparent; - --_close-focus-outline-color: var(--rh-color-interactive-blue-lighter, #92c5f9); + --_close-focus-outline-color: var(--rh-color-interactive-primary-default-on-dark, #92c5f9); /* PLAY */ --_white-rgb: 255 255 255; @@ -277,15 +267,10 @@ button > span { --_play-background-color: rgb(var(--_white-rgb) / var(--rh-opacity-50, 50%)); --_play-active-background-color: rgb(var(--_white-rgb) / var(--rh-opacity-80, 80%)); --_play-focus-background-color: rgb(var(--_white-rgb) / var(--rh-opacity-80, 80%)); - --_play-focus-outline-color: var(--rh-color-interactive-blue-lighter, #92c5f9); + --_play-focus-outline-color: var(--rh-color-interactive-primary-default-on-dark, #92c5f9); --_play-hover-background-color: rgb(var(--_white-rgb) / var(--rh-opacity-80, 80%)); } -:host([hidden]), -[hidden] { - display: none !important; -} - rh-icon { color: currentcolor; } @@ -317,7 +302,7 @@ button:focus { outline: var(--rh-border-width-md, 2px) solid - var(--_focus-outline-color, var(--rh-color-interactive-blue-darker, #0066cc)); + var(--_focus-outline-color, var(--rh-color-interactive-primary-default-on-light, #0066cc)); } button:hover { @@ -332,7 +317,7 @@ button:hover { * * ******************************/ -:host([danger]) button { +button.danger { --_default-color: var(--_danger-color); --_default-background-color: var(--_danger-background-color); --_default-border-color: var(--_danger-border-color); @@ -353,7 +338,7 @@ button:hover { * * ******************************/ -:host([variant="secondary" i]) button { +button.secondary { --_default-color: var(--_secondary-color); --_default-background-color: var(--_secondary-background-color); --_default-border-color: var(--_secondary-border-color); @@ -377,7 +362,7 @@ button:hover { * * ******************************/ -:host([variant="tertiary" i]) button { +button.tertiary { --_default-color: var(--_tertiary-color); --_default-background-color: var(--_tertiary-background-color); --_default-border-color: var(--_tertiary-border-color); @@ -400,8 +385,12 @@ button:hover { * * ******************************/ -:host([variant="link" i]) button { - display: inline; +button.link { + display: inline-flex; + + & rh-icon { + order: 1; + } --_default-color: var(--_link-color); --_default-background-color: var(--_link-background-color); @@ -424,7 +413,7 @@ button:hover { * * ******************************/ -:host([variant="close" i]) button { +button.close { --_default-color: var(--_close-color); --_default-background-color: var(--_close-background-color); --_active-color: var(--_close-active-color); @@ -448,10 +437,11 @@ button:hover { * * ******************************/ -:host([variant="play" i]) button { +button.play { border-radius: 100%; width: var(--rh-length-4xl, 64px); + --rh-icon-size: var(--rh-size-icon-02, 24px); --_default-color: var(--_play-color); --_default-background-color: var(--_play-background-color); --_default-background-opacity: var(--_play-background-opacity); @@ -466,44 +456,40 @@ button:hover { --_hover-background-color: var(--_play-hover-background-color); --_hover-background-opacity: var(--_play-hover-background-opacity); --_icon-size: var(--rh-size-icon-02, 24px); -} -:host(:is([variant="play"])) [part="icon"] { - position: relative; - inset-inline-start: 3px; + & [part='icon'] { + display: contents; + } + + & rh-icon { + translate: 10%; /* perceptually center play icon only */ + } } -:host(:is([variant="play" i], [variant="close" i])) button { +button:is(.play,.close) { aspect-ratio: 1; display: inline-flex; align-items: center; justify-content: center; padding: 0; -} - -:host(:is([variant="play" i], [variant="close" i])) [part="icon"] { - display: inline-block; - width: var(--_icon-size, var(--rh-size-icon-01, 16px)); - height: var(--_icon-size, var(--rh-size-icon-01, 16px)); -} -:host(:is([variant="play" i], [variant="close" i])) svg { - fill: currentcolor; - stroke: currentcolor; + /* visually hidden */ + & #text { + display: inline; + position: absolute !important; + width: 1px !important; + height: 1px !important; + padding: 0 !important; + margin: -1px !important; + overflow: hidden !important; + clip: rect(0, 0, 0, 0) !important; + white-space: nowrap !important; + border: 0 !important; + } } -/* visually hidden */ -:host(:is([variant="play" i], [variant="close" i])) #text { - display: inline; - position: absolute !important; - width: 1px !important; - height: 1px !important; - padding: 0 !important; - margin: -1px !important; - overflow: hidden !important; - clip: rect(0, 0, 0, 0) !important; - white-space: nowrap !important; - border: 0 !important; +:host(:is([variant='play' i], [variant='close' i])) { + line-height: 0; } /****************************** @@ -514,13 +500,18 @@ button:hover { :host(:disabled) button, :host(:disabled[danger]) button, -:host(:disabled[variant="link"]) button, +:host(:disabled[variant='link']) button, button[disabled] { pointer-events: none; cursor: default; --_color: var(--rh-color-text-secondary-on-light, #4d4d4d); --_background-color: var(--rh-color-surface-light, #e0e0e0); + + &.dark { + --_color: var(--rh-color-gray-40, #a3a3a3); + --_background-color: var(--rh-color-surface-dark, #383838); + } } :host(:disabled) button:after { @@ -533,7 +524,7 @@ button[disabled] { * * ******************************/ -:host([variant="secondary" i][danger]) button { +button.secondary.danger { --_default-color: var(--_secondary-danger-color); --_default-background-color: transparent; --_default-border-color: var(--_danger-background-color); @@ -548,6 +539,6 @@ button[disabled] { --_hover-border-color: var(--_danger-hover-border-color); } -:host(:not([disabled])) .hasIcon [part="icon"] { +:host(:not([disabled])) .hasIcon [part='icon'] { cursor: pointer; } diff --git a/elements/rh-button/rh-button.ts b/elements/rh-button/rh-button.ts index 2180887162..bec80811f2 100644 --- a/elements/rh-button/rh-button.ts +++ b/elements/rh-button/rh-button.ts @@ -1,3 +1,5 @@ +import type { IconNameFor, IconSetName } from '@rhds/icons'; + import { LitElement, html, type TemplateResult } from 'lit'; import { customElement } from 'lit/decorators/custom-element.js'; import { property } from 'lit/decorators/property.js'; @@ -35,6 +37,10 @@ export class RhButton extends LitElement { /** Disables the button */ @property({ reflect: true, type: Boolean }) disabled = false; + /** + * button type + * @see https://developer.mozilla.org/en-US/docs/Web/HTML/Element/button#type + */ @property({ reflect: true }) type?: 'button' | 'submit' | 'reset'; /** Accessible name for the button, use when the button does not have slotted text */ @@ -47,7 +53,10 @@ export class RhButton extends LitElement { @property() name?: string; /** Shorthand for the `icon` slot, the value is icon name */ - @property() icon?: string; + @property() icon?: IconNameFor; + + /** Icon set for the `icon` property - 'ui' by default */ + @property({ attribute: 'icon-set' }) iconSet?: IconSetName; @query('button') private _button!: HTMLButtonElement; @@ -78,34 +87,38 @@ export class RhButton extends LitElement { @colorContextConsumer() private on?: ColorTheme; get #hasIcon() { - return !!this.icon; + return this.variant === 'play' || this.variant === 'close' || !!this.icon; } #internals = InternalsController.of(this); override willUpdate() { - const variant = this.variant.toLowerCase(); - switch (variant) { - case 'close': - case 'play': - this.icon = variant; - break; + if (this.#hasIcon) { + import('@rhds/elements/rh-icon/rh-icon.js'); } } override render() { - const { on = 'light' } = this; + const { danger, variant, on = 'light' } = this; const hasIcon = this.#hasIcon; return html` @@ -133,24 +146,14 @@ export class RhButton extends LitElement { * * ``` */ - #renderDefaultIcon(): TemplateResult | string { + #renderIcon(): TemplateResult { switch (this.variant.toLowerCase()) { - // TODO: revisit when rh-icon is ready - // return html``; case 'close': - return html` - - - - `; + return html``; case 'play': - return html` - - - - `; + return html``; default: - return ''; + return html``; } } diff --git a/elements/rh-card/demo/color-context.html b/elements/rh-card/demo/color-context.html index 84a3ad5ff9..15b6cb0a11 100644 --- a/elements/rh-card/demo/color-context.html +++ b/elements/rh-card/demo/color-context.html @@ -16,7 +16,7 @@

        Slotted title, content, and footer

        + allow="darkest, lighter, lightest"> Call to action @@ -87,27 +87,21 @@

        Custom header

        } } &.bar { + --rh-card-header-background-on-light: var(--rh-color-surface-light, #e0e0e0); + --rh-card-header-background-on-dark: var(--rh-color-surface-dark, #383838); &::part(header) { margin: 0; - padding: var(--rh-space-lg, 16px) var(--rh-space-xl, 24px); - text-transform: uppercase; + padding: var(--rh-space-lg, 16px) var(--rh-space-2xl, 32px); + flex-direction: row; + gap: var(--rh-space-lg, 16px); font-weight: var(--rh-font-weight-heading-regular, 300); font-size: var(--rh-font-size-body-text-md, 1rem); - background-color: var(--bar-header-context-background-color); - } - &::part(body) { - /* margin: var(--rh-space-lg, 16px) var(--rh-space-xl, 24px); */ + 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); + text-transform: uppercase; /* deprecated? */ } } } - [color-palette^="light"] { - --bar-header-context-background-color: var(--rh-color-surface-light, #e0e0e0); - } - [color-palette^="dark"] { - --bar-header-context-background-color: var(--rh-color-surface-dark, #383838); - } - label[for="picker"] { display: block; } diff --git a/elements/rh-card/demo/logo-pattern.html b/elements/rh-card/demo/logo-pattern.html index 90fe602af2..197a1c10b0 100644 --- a/elements/rh-card/demo/logo-pattern.html +++ b/elements/rh-card/demo/logo-pattern.html @@ -76,7 +76,7 @@

        Heading, sm

        - 1 + 1 22
        1
        diff --git a/elements/rh-code-block/demo/client-side-highlighting.html b/elements/rh-code-block/demo/client-side-highlighting.html new file mode 100644 index 0000000000..676774f58d --- /dev/null +++ b/elements/rh-code-block/demo/client-side-highlighting.html @@ -0,0 +1,81 @@ + + + + + + + + + + + + + + + + + diff --git a/elements/rh-code-block/demo/prerendered-prism-highlighting.html b/elements/rh-code-block/demo/prerendered-prism-highlighting.html new file mode 100644 index 0000000000..9fa73818bb --- /dev/null +++ b/elements/rh-code-block/demo/prerendered-prism-highlighting.html @@ -0,0 +1,75 @@ + + +
        <!DOCTYPE html>
        +<html lang="en">
        +  <head>
        +    <meta charset="utf-8">
        +    <meta name="viewport" content="width=device-width">
        +    <title>Cards Galore!</title>
        +  </head>
        +  <body>
        +    <main>
        +      <rh-card>
        +        <h2 slot="header">Card</h2>
        +        <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit.
        +           Nullam eleifend elit sed est egestas, a sollicitudin mauris
        +           tincidunt. Pellentesque vel dapibus risus. Nullam aliquam
        +           felis orci, eget cursus mi lacinia quis. Vivamus at felis sem.</p>
        +        <rh-cta slot="footer" priority="primary">
        +          <a href="#">Call to action</a>
        +        </rh-cta>
        +      </rh-card>
        +    </main>
        +  </body>
        +</html>
        +
        + + +
        rh-card.avatar-card {
        +  width: 360px;
        +  &::part(body) {
        +    margin-block-start: var(--rh-space-lg, 16px);
        +  }
        +
        +  & p {
        +    margin-block-start: 0;
        +  }
        +
        +  & h4 {
        +    font-weight: var(--rh-font-weight-heading-regular, 300);
        +    font-size: var(--rh-font-size-body-text-md, 1rem);
        +    font-family: var(--rh-font-family-body-text);
        +    line-height: var(--rh-line-height-body-text, 1.5);
        +  }
        +}
        +
        + + +
        extends:
        +  - stylelint-config-standard
        +  - '@stylistic/stylelint-config'
        +
        +plugins:
        +  - ./node_modules/@rhds/tokens/plugins/stylelint.js
        +  - '@stylistic/stylelint-plugin'
        +
        +rules:
        +  rhds/token-values: true
        +  rhds/no-unknown-token-name:
        +    - true
        +    - allowed:
        +      - --rh-icon-size
        +
        +
        + + + + diff --git a/elements/rh-code-block/docs/10-overview.md b/elements/rh-code-block/docs/10-overview.md index 82a9b1710b..45dfd685e0 100644 --- a/elements/rh-code-block/docs/10-overview.md +++ b/elements/rh-code-block/docs/10-overview.md @@ -3,7 +3,7 @@ {{ tagName | getElementDescription }} - Image of a code block with black code text within a light gray container + Image of a code block with black code text within a light gray container {% repoStatusList repoStatus=repoStatus %} diff --git a/elements/rh-code-block/docs/20-style.md b/elements/rh-code-block/docs/20-style.md index d753c75502..3eaa16bbdd 100644 --- a/elements/rh-code-block/docs/20-style.md +++ b/elements/rh-code-block/docs/20-style.md @@ -7,7 +7,7 @@ container.
        - Image of code block anatomy showing two annotations + Image of code block anatomy showing two annotations
          @@ -24,14 +24,14 @@ A code block is available in both light and dark themes. ### Light theme - Image of light theme code block + Image of light theme code block ### Dark theme - Image of dark theme code block + Image of dark theme code block ### Configuration @@ -39,7 +39,7 @@ A code block is available in both light and dark themes. Code block text is always horizontally and vertically centered. - Image of a code block showing alignment and border radius specs + Image of a code block showing alignment and border radius specs ## Space @@ -47,7 +47,7 @@ Code block text is always horizontally and vertically centered. Container spacing reduces as breakpoints get smaller. - Image of a code block spacing for all breakpoints + Image of a code block spacing for all breakpoints diff --git a/elements/rh-code-block/docs/30-guidelines.md b/elements/rh-code-block/docs/30-guidelines.md index 9115669bdb..4355a9a7ac 100644 --- a/elements/rh-code-block/docs/30-guidelines.md +++ b/elements/rh-code-block/docs/30-guidelines.md @@ -13,7 +13,7 @@ A code block container can adhere to the width of content within or be fixed width. - Image of fluid width and fixed width code block sizes with text labels below + Image of fluid width and fixed width code block sizes with text labels below ## Content @@ -22,7 +22,7 @@ The length of code text and the number of lines can change the width and height of a code block. - Image of two code blocks; one code block is fluid width showing only one line and the other code block is fixed width showing 10 lines + Image of two code blocks; one code block is fluid width showing only one line and the other code block is fixed width showing 10 lines @@ -31,7 +31,7 @@ of a code block. ### Large breakpoints - Image of code blocks on desktop and tablet breakpoints + Image of code blocks on desktop and tablet breakpoints ### Small breakpoints @@ -39,7 +39,7 @@ of a code block. Container spacing and code text size reduces as breakpoints get smaller. - Image of code blocks on large and small mobile breakpoints + Image of code blocks on large and small mobile breakpoints @@ -50,7 +50,7 @@ Container spacing and code text size reduces as breakpoints get smaller. Do not use a different font than `--rh-font-family-code`. - Image of a code block showing the Red Hat Text font used for code text which is incorrect usage + Image of a code block showing the Red Hat Text font used for code text which is incorrect usage ### Different styling @@ -58,5 +58,5 @@ Do not use a different font than `--rh-font-family-code`. Do not change any of the code block styling. - Image of a code block showing different styles which is incorrect usage + Image of a code block showing different styles which is incorrect usage diff --git a/elements/rh-code-block/docs/40-code.md b/elements/rh-code-block/docs/40-code.md index 07321a14d8..38a49d87f5 100644 --- a/elements/rh-code-block/docs/40-code.md +++ b/elements/rh-code-block/docs/40-code.md @@ -1,5 +1,7 @@ {% renderInstall %}{% endrenderInstall %} +{% renderLightDom %}{% endrenderLightDom %} + ## Usage The content of code-block snippets must be contained within a non-executable diff --git a/elements/rh-code-block/prism.css.ts b/elements/rh-code-block/prism.css.ts new file mode 100644 index 0000000000..248bef9261 --- /dev/null +++ b/elements/rh-code-block/prism.css.ts @@ -0,0 +1,82 @@ +import { css } from 'lit'; + +const styles = css` + & code[class*="language-"], + & pre[class*="language-"] { + color: var(--_code-color); + font-family: var(--rh-font-family-code, RedHatMono, "Red Hat Mono", "Courier New", Courier, monospace); + text-align: left; + white-space: pre; + word-spacing: normal; + word-break: normal; + word-wrap: normal; + line-height: var(--rh-line-height-code, 1.5); + tab-size: 4; + hyphens: none; + background: transparent; + } + + & pre[class*="language-"]::selection, + & pre[class*="language-"] ::selection, + & code[class*="language-"]::selection, + & code[class*="language-"] ::selection { + text-shadow: none; + background: var(--_selected-text-background); + } + + @media print { + & code[class*="language-"], + & pre[class*="language-"] { + text-shadow: none; + } + } + + & .token.atrule { color: var(--_at-rule-color); } + & .token.attr-name { color: var(--_attr-name-color); } + & .token.attr-value { color: var(--_attr-value-color); } + & .token.bold { font-weight: var(--_important-color); } + & .token.boolean { color: var(--_boolean-color); } + & .token.builtin { color: var(--_built-in-color); } + & .token.cdata { color: var(--_cdata-color); } + & .token.char { color: var(--_character-color); } + & .token.class-name { color: var(--_class-name-color); } + & .token.comment { color: var(--_comment-color); } + & .token.constant { color: var(--_constant-color); } + & .token.deleted { color: var(--_deleted-color); } + & .token.function { color: var(--_function-name-color); } + & .token.important { color: var(--_important-color); } + & .token.inserted { color: var(--_inserted-color); } + & .token.keyword { color: var(--_keyword-color); } + & .token.namespace { color: var(--_namespace-color); } + & .token.number { color: var(--_number-color); } + & .token.operator { color: var(--_operator-color); } + & .token.property { color: var(--_property-color); } + & .token.punctuation { color: var(--_punctuation-color); } + & .token.regex { color: var(--_regex-color); } + & .token.selector { color: var(--_selector-color); } + & .token.string { color: var(--_string-color); } + & .token.symbol { color: var(--_symbol-color); } + & .token.tag { color: var(--_tag-color); } + & .token.url { color: var(--_url-color); } + & .token.variable { color: var(--_variable-color); } + + & .token.italic { font-style: italic; } + + & .token.entity { + color: var(--_entity-color); + cursor: help; + } + + & .token.prolog, + & .token.doctype { color: var(--_doctype-color); } + + & .language-css .token.string, + & .style .token.string { color: var(--_operator-color); } +`; + +export const prismStyles = css`#prism-output {${styles}}`; +export const preRenderedLightDomStyles = css`rh-code-block { +--_styles-applied: true; +${styles} +& > pre { opacity: 1; } +}`; diff --git a/elements/rh-code-block/prism.ts b/elements/rh-code-block/prism.ts new file mode 100644 index 0000000000..f4512eafeb --- /dev/null +++ b/elements/rh-code-block/prism.ts @@ -0,0 +1,43 @@ +import type { RhCodeBlock } from './rh-code-block.js'; +import { Prism } from 'prism-esm'; +import { unsafeHTML } from 'lit/directives/unsafe-html.js'; +import { html } from 'lit'; + +const prism = new Prism({ manual: true }); + +/** + * Autoload a supported language + * @param language a supported language + */ +async function autoloader(language: RhCodeBlock['language']) { + switch (language) { + case 'html': return import('prism-esm/components/prism-markup.js').then(m => m.loader(prism)); + case 'css': return import('prism-esm/components/prism-css.js').then(m => m.loader(prism)); + // @ts-expect-error: be liberal about what you accept + case 'js': + case 'javascript': return import('prism-esm/components/prism-javascript.js') + .then(m => m.loader(prism)); + // @ts-expect-error: be liberal about what you accept + case 'ts': + case 'typescript': return import('prism-esm/components/prism-typescript.js') + .then(m => m.loader(prism)); + case 'bash': return import('prism-esm/components/prism-bash.js').then(m => m.loader(prism)); + case 'ruby': return import('prism-esm/components/prism-ruby.js').then(m => m.loader(prism)); + case 'yaml': return import('prism-esm/components/prism-yaml.js').then(m => m.loader(prism)); + case 'json': return import('prism-esm/components/prism-json.js').then(m => m.loader(prism)); + } +} + +/** + * Highlight a string using prism.js + * @param textContent source code + * @param language a supported language + */ +export async function highlight(textContent: string, language: RhCodeBlock['language']) { + await autoloader(language); + const highlighted = prism.highlight(textContent, prism.languages[language!], language!); + return html`${unsafeHTML(highlighted)}`; +} + +export { prismStyles, preRenderedLightDomStyles } from './prism.css.js'; + diff --git a/elements/rh-code-block/rh-code-block.css b/elements/rh-code-block/rh-code-block.css index 2b6167bbd4..9127775359 100644 --- a/elements/rh-code-block/rh-code-block.css +++ b/elements/rh-code-block/rh-code-block.css @@ -2,6 +2,7 @@ --rh-code-block-callout-size: var(--rh-size-icon-02, 24px); --_aspect-ratio: 1; --_badge-size: var(--rh-code-block-callout-size); + --_badge-padding: 0; display: block; max-width: 1000px; @@ -39,54 +40,68 @@ .shadow-fab:is(:hover, :focus, :active) { background: - var( - --_code-action-hover-focus-active-background, - var(--rh-color-surface-light, #e0e0e0) - ); + var(--_code-action-hover-focus-active-background, + var(--rh-color-surface-light, #e0e0e0)); } .shadow-fab svg { width: var(--rh-size-icon-02, 24px); height: var(--rh-size-icon-02, 24px); - color: var(--_code-action-color, var(--rh-color-text-primary-on-light, #151515)); + color: var(--rh-color-text-primary); } .dark .shadow-fab { - --_code-action-color: var(--rh-color-text-primary-on-dark, #ffffff); --_code-action-hover-focus-active-background: var(--rh-color-surface-dark, #383838); } #container, #content-lines, #content, +#prism-output, #sizers { max-width: 100%; } +#prism-output { + margin: 0; + + & code { + font-size: inherit; + font-family: inherit; + font-weight: inherit; + line-height: inherit; + } +} + #container { + --_code-background-color: var(--rh-color-surface-lighter, #f2f2f2); --_code-main-spacer: var(--rh-space-xl, 24px); display: grid; place-items: center; grid-template-columns: auto min-content; grid-template-areas: - "code actions" - "expand expand"; + 'code actions' + 'expand expand'; column-gap: var(--_code-main-spacer); padding-inline-start: var(--_code-main-spacer); padding-block-end: var(--_code-main-spacer); border-radius: var(--rh-border-radius-default, 3px); - background-color: var(--_code-background-color, var(--rh-color-surface-lighter, #f2f2f2)); - color: var(--_code-color, var(--rh-color-text-primary-on-light, #151515)); - border: - var(--rh-border-width-sm, 1px) - solid - var(--_code-border-color, var(--rh-color-border-subtle-on-light, #c7c7c7)); + background-color: var(--_code-background-color); + color: var(--rh-color-text-primary); + border: var(--rh-border-width-sm, 1px) solid var(--rh-color-border-subtle); border-block-start-width: - var( - --rh-code-block-border-block-start-width, - var(--rh-border-width-sm, 1px) - ); + var(--rh-code-block-border-block-start-width, + var(--rh-border-width-sm, 1px)); + + --_gradient: + linear-gradient(var(--_gradient-angle, 0deg), + var(--_code-background-color) 0%, + transparent 100%); +} + +#container.dark { + --_code-background-color: var(--rh-color-surface-dark-alt, #292929); } #container.expandable { @@ -94,15 +109,17 @@ } #sizers, +#prism-output, #content { display: block; - font-family: var(--rh-font-family-code, RedHatMono, "Red Hat Mono", "Courier New", Courier, monospace); + font-family: var(--rh-font-family-code, RedHatMono, 'Red Hat Mono', 'Courier New', Courier, monospace); z-index: 1; place-self: start; grid-area: code; } #sizers, +#prism-output, #content::slotted(:is(script, pre)) { display: inline; white-space: var(--_code-white-space, pre); @@ -118,7 +135,7 @@ display: grid; column-gap: var(--rh-space-lg, 16px); grid-area: code; - grid-template-areas: "lines code"; + grid-template-areas: 'lines code'; grid-template-columns: min-content 1fr; grid-template-rows: 1fr; position: relative; @@ -134,6 +151,7 @@ opacity: 0; pointer-events: none; z-index: -10000; + line-height: var(--rh-line-height-code, 1.5); } #line-numbers { @@ -144,12 +162,15 @@ list-style-type: none; padding-inline: 0 var(--rh-space-md, 8px); text-align: end; - font-family: var(--rh-font-family-code, RedHatMono, "Red Hat Mono", "Courier New", Courier, monospace); - color: var(--_code-line-numbers-color, var(--rh-color-gray-60, #4d4d4d)); + font-family: var(--rh-font-family-code, RedHatMono, 'Red Hat Mono', 'Courier New', Courier, monospace); + color: var(--rh-color-text-secondary); font-weight: var(--rh-font-weight-code-regular, 400); - border-inline-end: - var(--rh-border-width-sm, 1px) solid - var(--_code-line-numbers-border-color, var(--rh-color-border-subtle-on-light, #c7c7c7)); + border-inline-end: var(--rh-border-width-sm, 1px) solid var(--rh-color-border-subtle); + + li { + line-height: var(--rh-line-height-code, 1.5); + display: block; + } } #actions { @@ -163,6 +184,8 @@ place-self: start center; height: 100%; position: relative; + + --_gradient-angle: 270deg; } #actions rh-tooltip { @@ -180,8 +203,8 @@ gap: var(--rh-space-md, 8px); inset-block-end: var(--_code-secondary-spacer); margin-block: var(--_code-secondary-spacer); - color: var(--_expand-toggle-color, var(--rh-color-text-primary-on-light, #151515)); - 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); + color: var(--rh-color-text-primary); + 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-sm, 0.875rem); font-weight: var(--rh-font-weight-body-text-regular, 400); line-height: var(--rh-line-height-body-text, 1.5); @@ -192,7 +215,7 @@ height: 7px; rotate: var(--_expand-toggle-rotate, 180deg); transform: rotate 0.2s ease-in-out; - color: var(--_expand-toggle-icon-color, var(--rh-color-icon-secondary-on-light, #151515)); + color: var(--rh-color-icon-secondary); } #container.compact { @@ -210,7 +233,7 @@ } .truncated #content-lines:before { - content: ""; + content: ''; display: block; position: sticky; z-index: 2; @@ -219,20 +242,11 @@ height: var(--rh-space-3xl, 48px); pointer-events: none; grid-column: -1/1; - background: - var( - --_block-end-overflow-gradient, - linear-gradient( - 0deg, - #f2f2f2 0%, - rgba(242, 242, 242, 0) - 100% - ) - ); + background: var(--_gradient); } :not(.wrap) #actions:before { - content: ""; + content: ''; display: block; position: absolute; z-index: 2; @@ -240,16 +254,7 @@ inset-inline-start: calc(-1 * var(--rh-space-4xl, 64px)); width: var(--rh-space-4xl, 64px); pointer-events: none; - background: - var( - --_inline-end-overflow-gradient, - linear-gradient( - 270deg, - #f2f2f2 0%, - rgba(242, 242, 242, 0) - 100% - ) - ); + background: var(--_gradient); } :not(.actions) #actions { @@ -261,21 +266,85 @@ --_code-word-wrap: anywhere; } -.dark { - --_code-background-color: var(--rh-color-surface-dark-alt, #292929); - --_code-border-color: var(--rh-color-border-subtle-on-dark, #707070); - --_code-color: var(--rh-color-text-primary-on-dark, #ffffff); - --_code-line-numbers-color: var(--rh-color-text-secondary-on-dark, #c7c7c7); - --_code-line-numbers-border-color: var(--rh-color-border-subtle-on-dark, #707070); - --_expand-toggle-color: var(--rh-color-text-primary-on-dark, #ffffff); - --_expand-toggle-icon-color: var(--rh-color-icon-secondary-on-dark, #ffffff); - --_inline-end-overflow-gradient: linear-gradient(270deg, #292929 0%, rgba(41, 41, 41, 0) 100%); - --_block-end-overflow-gradient: linear-gradient(0deg, #292929 0%, rgba(41, 41, 41, 0) 100%); -} - -[name="legend"]::slotted(dl) { +[name='legend']::slotted(dl) { display: grid; grid-template-columns: max-content auto; margin-block: var(--rh-space-lg, 16px); gap: var(--rh-space-md, 8px); } + +.on { + --_cdata-color: var(--rh-color-text-secondary); + --_comment-color: var(--rh-color-text-secondary); + --_comment-block-color: var(--rh-color-text-secondary); + --_doctype-color: var(--rh-color-text-secondary); +} + +.on, +.on.light { + --_default-color: var(--rh-color-gray-95, #151515); + --_selected-text-background: var(--rh-color-blue-10, #e0f0ff); + --_punctuation-color: var(--rh-color-gray-40, #a3a3a3); + --_namespace-color: var(--rh-color-gray-95, #151515); + --_property-color: var(--rh-color-purple-50, #5e40be); + --_tag-color: var(--rh-color-purple-50, #5e40be); + --_boolean-color: var(--rh-color-purple-50, #5e40be); + --_number-color: var(--rh-color-purple-50, #5e40be); + --_constant-color: var(--rh-color-purple-50, #5e40be); + --_symbol-color: var(--rh-color-purple-50, #5e40be); + --_deleted-color: var(--rh-color-purple-50, #5e40be); + --_function-name-color: var(--rh-color-purple-50, #5e40be); + --_selector-color: var(--rh-color-teal-60, #147878); + --_attr-name-color: var(--rh-color-teal-60, #147878); + --_string-color: var(--rh-color-teal-60, #147878); + --_character-color: var(--rh-color-teal-60, #147878); + --_built-in-color: var(--rh-color-teal-60, #147878); + --_inserted-color: var(--rh-color-teal-60, #147878); + --_operator-color: var(--rh-color-yellow-60, #96640f); + --_entity-color: var(--rh-color-yellow-60, #96640f); + --_url-color: var(--rh-color-yellow-60, #96640f); + --_at-rule-color: var(--rh-color-blue-60, #004d99); + --_attr-value-color: var(--rh-color-blue-60, #004d99); + --_keyword-color: var(--rh-color-blue-60, #004d99); + --_function-color: var(--rh-color-red-60, #a60000); + --_class-name-color: var(--rh-color-red-60, #a60000); + --_regex-color: var(--rh-color-orange-60, #9e4a06); + --_important-color: var(--rh-color-orange-60, #9e4a06); + --_variable-color: var(--rh-color-orange-60, #9e4a06); +} + +.on.dark { + --_default-color: var(--rh-color-gray-20, #e0e0e0); + --_selected-text-background: var(--rh-color-gray-95, #151515); + --_punctuation-color: var(--rh-color-gray-20, #e0e0e0); + --_namespace-color: var(--rh-color-red-40, #f56e6e); + --_property-color: var(--rh-color-yellow-40, #dca614); + --_tag-color: var(--rh-color-red-10, #fce3e3); + --_boolean-color: var(--rh-color-orange-40, #f5921b); + --_number-color: var(--rh-color-orange-40, #f5921b); + --_constant-color: var(--rh-color-yellow-40, #dca614); + --_symbol-color: var(--rh-color-yellow-40, #dca614); + --_deleted-color: var(--rh-color-red-40, #f56e6e); + --_function-name-color: var(--rh-color-teal-20, #b9e5e5); + --_selector-color: var(--rh-color-purple-30, #b6a6e9); + --_attr-name-color: var(--rh-color-red-40, #f56e6e); + --_string-color: var(--rh-color-green-40, #87bb62); + --_character-color: var(--rh-color-green-40, #87bb62); + --_built-in-color: var(--rh-color-purple-30, #b6a6e9); + --_inserted-color: var(--rh-color-green-40, #87bb62); + --_operator-color: var(--rh-color-blue-40, #4394e5); + --_entity-color: var(--rh-color-blue-40, #4394e5); + --_url-color: var(--rh-color-blue-40, #4394e5); + --_at-rule-color: var(--rh-color-purple-30, #b6a6e9); + --_attr-value-color: var(--rh-color-green-40, #87bb62); + --_keyword-color: var(--rh-color-purple-30, #b6a6e9); + --_function-color: var(--rh-color-orange-40, #f5921b); + --_class-name-color: var(--rh-color-yellow-40, #dca614); + --_regex-color: var(--rh-color-green-40, #87bb62); + --_important-color: var(--rh-color-purple-30, #b6a6e9); + --_variable-color: var(--rh-color-green-40, #87bb62); +} + +:host([highlighting='client']) #content::slotted(:is(script, pre)) { + display: none; +} diff --git a/elements/rh-code-block/rh-code-block.ts b/elements/rh-code-block/rh-code-block.ts index 47d727f63b..3469cc543c 100644 --- a/elements/rh-code-block/rh-code-block.ts +++ b/elements/rh-code-block/rh-code-block.ts @@ -1,8 +1,10 @@ -import { LitElement, html, type PropertyValues } from 'lit'; +import type { DirectiveResult } from 'lit-html/directive.js'; +import { CSSResult, LitElement, html, type PropertyValues } from 'lit'; import { customElement } from 'lit/decorators/custom-element.js'; import { classMap } from 'lit/directives/class-map.js'; import { styleMap } from 'lit/directives/style-map.js'; import { property } from 'lit/decorators/property.js'; +import { ifDefined } from 'lit-html/directives/if-defined.js'; import { SlotController } from '@patternfly/pfe-core/controllers/slot-controller.js'; @@ -15,6 +17,17 @@ import style from './rh-code-block.css'; * - manage state of copy and wrap, including if they are slotted. see actions.html */ +/** + * Returns a string with common indent stripped from each line. Useful for templating HTML + * @param str indented string + */ +function dedent(str: string) { + const stripped = str.replace(/^\n/, ''); + const match = stripped.match(/^\s+/); + const out = match ? stripped.replace(new RegExp(`^${match[0]}`, 'gm'), '') : str; + return out.trim(); +} + interface CodeLineHeightsInfo { lines: string[]; lineHeights: (number | undefined)[]; @@ -82,9 +95,30 @@ export class RhCodeBlock extends LitElement { }, }) actions: ('copy' | 'wrap')[] = []; + /** + * When set to "client", `` will automatically highlight the source using Prism.js + * When set to "Prerendered", `` will apply supported RHDS styles to children with + * prismjs classnames in the element's root. + */ + @property() highlighting?: 'client' | 'prerendered'; + + /** When set along with `highlighting="client"`, this grammar will be used to highlight source code */ + @property() language?: + | 'html' + | 'css' + | 'javascript' + | 'typescript' + | 'bash' + | 'ruby' + | 'yaml' + | 'json'; + /** When set, the code block displays with compact spacing */ @property({ type: Boolean, reflect: true }) compact = false; + /** When set, the code block source code will be dedented */ + @property({ type: Boolean, reflect: true }) dedent = false; + /** When set, the code block is resizable */ @property({ type: Boolean, reflect: true }) resizable = false; @@ -107,6 +141,8 @@ export class RhCodeBlock extends LitElement { 'legend', ); + #prismOutput?: DirectiveResult; + #ro = new ResizeObserver(() => this.#computeLineNumbers()); #lineHeights: `${string}px`[] = []; @@ -128,21 +164,26 @@ export class RhCodeBlock extends LitElement { const actions = !!this.actions.length; return html`
          -
          +
          - +
          ${this.#prismOutput}
          +
          Show more Show less @@ -172,6 +215,7 @@ export class RhCodeBlock extends LitElement {
          + `; } @@ -186,7 +230,47 @@ export class RhCodeBlock extends LitElement { } } - #wrapChanged() { + async #onSlotChange() { + switch (this.highlighting) { + case 'client': await this.#highlightWithPrism(); break; + // TODO: if we ever support other tokenizers e.g. highlightjs, + // dispatch here off of some supplemental attribute like `tokenizer="highlightjs"` + case 'prerendered': await this.#applyPrismPrerenderedStyles(); break; + } + this.#computeLineNumbers(); + } + + async #applyPrismPrerenderedStyles() { + if (getComputedStyle(this).getPropertyValue('--_styles-applied') !== 'true') { + const root = this.getRootNode(); + if (root instanceof Document || root instanceof ShadowRoot) { + const { preRenderedLightDomStyles: { styleSheet } } = await import('./prism.js'); + root.adoptedStyleSheets = [...root.adoptedStyleSheets, styleSheet!]; + } + } + } + + async #highlightWithPrism() { + const { highlight, prismStyles } = await import('./prism.js'); + const styleSheet = + prismStyles instanceof CSSStyleSheet ? prismStyles + : (prismStyles as CSSResult).styleSheet; + if (!this.shadowRoot!.adoptedStyleSheets.includes(styleSheet!)) { + this.shadowRoot!.adoptedStyleSheets = [ + ...this.shadowRoot!.adoptedStyleSheets as CSSStyleSheet[], + styleSheet!, + ]; + } + const scripts = this.querySelectorAll('script[type]:not([type="javascript"])'); + const preprocess = this.dedent ? dedent : (x: string) => x; + const textContent = preprocess(Array.from(scripts, x => x.textContent).join('')); + this.#prismOutput = await highlight(textContent, this.language); + this.requestUpdate('#prismOutput', {}); + await this.updateComplete; + } + + async #wrapChanged() { + await this.updateComplete; this.#computeLineNumbers(); // TODO: handle slotted fabs const slot = this.shadowRoot?.querySelector('slot[name="action-label-wrap"]'); @@ -198,32 +282,41 @@ export class RhCodeBlock extends LitElement { this.requestUpdate(); } + #getSlottedCodeElements() { + const slot = this.shadowRoot?.getElementById('content') as HTMLSlotElement; + return slot.assignedElements().flatMap(x => + x instanceof HTMLScriptElement + || x instanceof HTMLPreElement ? [x] + : []); + } + /** * Clone the text content and connect it to the document, in order to calculate the number of lines * @license MIT * Portions copyright prism.js authors (MIT license) */ - #computeLineNumbers() { - const slot = this.shadowRoot?.getElementById('content') as HTMLSlotElement; - - const codes: HTMLElement[] = slot.assignedElements().flatMap(x => - x instanceof HTMLScriptElement - || x instanceof HTMLPreElement ? [x] - : []); + async #computeLineNumbers() { + await this.updateComplete; + const codes = + this.#prismOutput ? [this.shadowRoot?.getElementById('prism-output')].filter(x => !!x) + : this.#getSlottedCodeElements(); const infos: CodeLineHeightsInfo[] = codes.map(element => { - const sizer = document.createElement('span'); - sizer.className = 'sizer'; - sizer.innerText = '0'; - sizer.style.display = 'block'; - this.shadowRoot?.getElementById('sizers')?.appendChild(sizer); - return { - lines: element.textContent?.split(/\n(?!$)/g) ?? [], - lineHeights: [], - sizer, - oneLinerHeight: sizer.getBoundingClientRect().height, - }; - }); + const codeElement = this.#prismOutput ? element.querySelector('code') : element; + if (codeElement) { + const sizer = document.createElement('span'); + sizer.className = 'sizer'; + sizer.innerText = '0'; + sizer.style.display = 'block'; + this.shadowRoot?.getElementById('sizers')?.appendChild(sizer); + return { + lines: element.textContent?.split(/\n(?!$)/g) ?? [], + lineHeights: [], + sizer, + oneLinerHeight: sizer.getBoundingClientRect().height, + }; + } + }).filter(x => !!x); for (const { lines, lineHeights, sizer, oneLinerHeight } of infos) { lineHeights[lines.length - 1] = undefined; // why? diff --git a/elements/rh-cta/docs/00-overview.md b/elements/rh-cta/docs/00-overview.md index 8708980268..e4ff1af54a 100644 --- a/elements/rh-cta/docs/00-overview.md +++ b/elements/rh-cta/docs/00-overview.md @@ -3,7 +3,7 @@ {{ tagName | getElementDescription }} - Image of variants including Primary (red background and white text), Secondary (black border and black text), Brick (light gray border and blue text), and Default (blue text and blue icon) + Image of variants including Primary (red background and white text), Secondary (black border and black text), Brick (light gray border and blue text), and Default (blue text and blue icon) {% repoStatusList repoStatus=repoStatus %} diff --git a/elements/rh-cta/docs/10-style.md b/elements/rh-cta/docs/10-style.md index 33ea27a3f5..32de4b0cb3 100644 --- a/elements/rh-cta/docs/10-style.md +++ b/elements/rh-cta/docs/10-style.md @@ -6,7 +6,7 @@ A call to action is text in a container or paired with an icon that directs user
          - Anatomy image showing calls to action with various annotation numbers + Anatomy image showing calls to action with various annotation numbers
            @@ -25,11 +25,11 @@ Calls to action are available in both light and dark themes. ### Light and dark themes - Image of light theme Primary, Secondary, Brick, Default, and Default video variants + Image of light theme Primary, Secondary, Brick, Default, and Default video variants - Image of dark theme Primary, Secondary, Brick, Default, and Default video variants + Image of dark theme Primary, Secondary, Brick, Default, and Default video variants @@ -106,11 +106,11 @@ Calls to action are available in both light and dark themes. The Brick variant includes a slot for an icon as well as an extra orientation. - Image of light theme Brick variants; one with text and no icon, one with an icon on the left of text, and one with an icon on top of text + Image of light theme Brick variants; one with text and no icon, one with an icon on the left of text, and one with an icon on top of text - Image of light theme Brick variants; one with text and no icon, one with an icon on the left of text, and one with an icon on top of text + Image of light theme Brick variants; one with text and no icon, one with an icon on the left of text, and one with an icon on top of text @@ -137,7 +137,7 @@ The Brick variant includes a slot for an icon as well as an extra orientation. Primary, Secondary, and Default variants include a slot for a video icon. The video icon is the same color as the text label. - Image of Primary, Secondary, and Default variants with video icons to the right of text + Image of Primary, Secondary, and Default variants with video icons to the right of text ### White variants @@ -145,7 +145,7 @@ Primary, Secondary, and Default variants include a slot for a video icon. The vi Dark theme includes white variants if other variants are duplicative or if they violate accessibility guidelines. - Image of Primary and Primary video variants with a white background and black text and Default and Default video variants with white text + Image of Primary and Primary video variants with a white background and black text and Default and Default video variants with white text @@ -182,7 +182,7 @@ Dark theme includes white variants if other variants are duplicative or if they All calls to action with a container have the same border radius, but the height and width vary based on the presence of icons and the amount of content. Calls to action in a row are horizontally centered. - Image of all variants with various specs like border radius, height, width, alignment, and more + Image of all variants with various specs like border radius, height, width, alignment, and more ## Space @@ -190,7 +190,7 @@ All calls to action with a container have the same border radius, but the height Space values are the same on all breakpoints for calls to action. To see space values when calls to action are grouped, go to the [Guidelines](/elements/call-to-action/guidelines/) page. - Image of Primary, Secondary, two Brick variants, and two Default variants with spacing values in between + Image of Primary, Secondary, two Brick variants, and two Default variants with spacing values in between @@ -208,15 +208,15 @@ Interaction states are visual representations used to communicate the status of ### Hover - Image of light theme hover states + Image of light theme hover states - Image of dark theme hover states + Image of dark theme hover states - Image of dark theme white variant hover states + Image of dark theme white variant hover states @@ -291,15 +291,15 @@ Interaction states are visual representations used to communicate the status of - Image of light theme focus states + Image of light theme focus states - Image of dark theme focus states + Image of dark theme focus states - Image of dark theme white variant focus states + Image of dark theme white variant focus states @@ -329,15 +329,15 @@ Interaction states are visual representations used to communicate the status of - Image of light theme active states + Image of light theme active states - Image of dark theme active states + Image of dark theme active states - Image of dark theme white variant active states + Image of dark theme white variant active states diff --git a/elements/rh-cta/docs/20-guidelines.md b/elements/rh-cta/docs/20-guidelines.md index dd15f201ae..ff9cda288a 100644 --- a/elements/rh-cta/docs/20-guidelines.md +++ b/elements/rh-cta/docs/20-guidelines.md @@ -28,7 +28,7 @@ signals that function to users. Therefore, it is important that each variant is implemented consistently so they communicate the correct actions. - Image of the Primary, 
+  <img src= @@ -77,7 +77,7 @@ To indicate that a link is currently unavailable, calls to action can become disabled. - Image of disabled Primary, 
+  <img src= @@ -89,7 +89,7 @@ communicate various topics, but the icons must be the same color, height, style, etc. - Image of Brick variants 
+  <img src= @@ -111,7 +111,7 @@ announce text to users - Do not use any other icons except for the ones that are included - Image of Default variants 
+  <img src= @@ -121,7 +121,7 @@ Text labels can be inviting as well as to the point, vague messaging does not help our users make informed decisions. - Image of how to 
+  <img src= @@ -131,7 +131,7 @@ Users do not want to spend more time reading than necessary, so write text labels with as few words as possible. - Image of comparing 
+  <img src= @@ -145,7 +145,7 @@ to certain languages. This can be avoided by writing less text. - Image of Primary, 
+  <img src= @@ -157,7 +157,7 @@ Call to action text labels are written to entice users to select a link whereas button text labels are written to be short and communicate an action. - Image of comparing text labels in calls to action versus text labels in 
     buttons @@ -205,7 +205,7 @@ important. Variants that are lower in hierarchy can be used more than one time per page. - Image of calls to 
+  <img src= @@ -217,12 +217,12 @@ lists, and more. It is commonly used as the last element in a group so users can read about something first and then proceed further if they are interested. - Image of calls 
+  <img src= - Image of calls 
+  <img src= @@ -233,7 +233,7 @@ Variants that are lower in hierarchy can be grouped with Primary as well as used more than once per page. - Image of call to 
+  <img src= @@ -248,7 +248,7 @@ Brick variants are flexible and can stretch to fit different column widths. - Image of Brick variants 
+  <img src= @@ -264,14 +264,14 @@ Horizontal and vertical spacing between Primary and Secondary variants is - Image of 
+  <img src= Horizontal and vertical spacing between the Default variant is `24px`. - Image of 
+  <img src= @@ -279,7 +279,7 @@ Horizontal and vertical spacing between Brick variants should be the same as grid gutters. - Image of a 
+  <img src= @@ -292,7 +292,7 @@ A Brick variant can hide and reveal a panel of content when selected like an selected at a time like [tabs](/elements/tabs/). - Image of Brick 
+  <img src= @@ -306,13 +306,13 @@ labels, a second row appears. -Image of calls to 
+<img src= -Image of calls to 
+<img src= @@ -325,7 +325,7 @@ alignment="left"> Do not change the styles of any variant. - Image of several 
+  <img src= @@ -334,7 +334,7 @@ Do not change the styles of any variant. Do not use more than one Primary variant on any page. - Image of two Primary 
+  <img src= @@ -343,7 +343,7 @@ Do not use more than one Primary variant on any page. Do not group different Brick variants together, use one variant per grid. - Image of Brick 
+  <img src= @@ -353,7 +353,7 @@ Do not group different Brick variants together, use one variant per grid. Do not group more than two different variants together. - Image of Primary, 
+  <img src= @@ -369,7 +369,7 @@ first on the left. - Image of the Primary 
+  <img src= @@ -379,7 +379,7 @@ Do not group more than three variants together otherwise the risk of [choice paralysis][paralysis]{target="_blank"} greatly increases. - Image of two rows of 
+  <img src= @@ -388,7 +388,7 @@ paralysis][paralysis]{target="_blank"} greatly increases. Do not add extra spacing or stretch the width of any variant except for Bricks. - Image of Primary and 
+  <img src= diff --git a/elements/rh-cta/docs/30-code.md b/elements/rh-cta/docs/30-code.md index 625569b684..e06d8b4db4 100644 --- a/elements/rh-cta/docs/30-code.md +++ b/elements/rh-cta/docs/30-code.md @@ -1,5 +1,7 @@ {% renderInstall lightdomcss=true %}{% endrenderInstall %} +{% renderLightDom shimcss=true %}{% endrenderLightDom %} + ## Usage ```html diff --git a/elements/rh-cta/docs/40-accessibility.md b/elements/rh-cta/docs/40-accessibility.md index 090c9bba91..30a18cb151 100644 --- a/elements/rh-cta/docs/40-accessibility.md +++ b/elements/rh-cta/docs/40-accessibility.md @@ -3,7 +3,7 @@ Users should have the ability to navigate to and interact with calls to action using their keyboard. - Image of three groups with different variants showing focus indicators and tab key labels + Image of three groups with different variants showing focus indicators and tab key labels @@ -41,7 +41,7 @@ Users should have the ability to navigate to and interact with calls to action u 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. For grouped calls to action, the focus order is from left to right and top to bottom. - Image of groups of three variants with numbers one through three moving from left to right and top to bottom + Image of groups of three variants with numbers one through three moving from left to right and top to bottom ## Touch targets @@ -49,7 +49,7 @@ A logical focus order helps keyboard users operate our websites. Elements need t Grouped calls to action are adequately spaced for optimal touch targets. - Image of groups of variants with touch targets on top of each + Image of groups of variants with touch targets on top of each ## Screen reader guidelines diff --git a/elements/rh-cta/rh-cta-lightdom-shim.css b/elements/rh-cta/rh-cta-lightdom-shim.css index dc83fda97a..2b921d15bb 100644 --- a/elements/rh-cta/rh-cta-lightdom-shim.css +++ b/elements/rh-cta/rh-cta-lightdom-shim.css @@ -2,7 +2,7 @@ rh-cta:not(:defined) { width: fit-content !important; display: inline-flex !important; color: var(--rh-cta-color); - 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", Helvetica, Arial, sans-serif); + 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', Helvetica, Arial, sans-serif); font-size: var(--rh-font-size-body-text-lg, 1.125rem); font-weight: 600; /* WARNING: not a token value */ line-height: var(--rh-line-height-body-text, 1.5); @@ -15,33 +15,33 @@ rh-cta:not(:defined) { rh-cta:not(:defined, [variant]) { --rh-cta-background-color: transparent; --rh-cta-border-color: transparent; - --rh-cta-color: var(--rh-color-interactive-blue-darker, #0066cc); + --rh-cta-color: var(--rh-color-interactive-primary-default-on-light, #0066cc); --rh-cta-hover-background-color: transparent; --rh-cta-hover-border-color: transparent; --rh-cta-hover-inner-border-color: transparent; - --rh-cta-hover-color: var(--rh-color-interactive-blue-darkest, #003366); + --rh-cta-hover-color: var(--rh-color-interactive-primary-hover-on-light, #003366); --rh-cta-hover-text-decoration: none; --rh-cta-focus-background-color: transparent; --rh-cta-focus-container-background-color: #0066cc1a; --rh-cta-focus-border-color: transparent; --rh-cta-focus-inner-border-color: transparent; - --rh-cta-focus-color: var(--rh-color-interactive-blue-darker, #0066cc); + --rh-cta-focus-color: var(--rh-color-interactive-primary-default-on-light, #0066cc); --rh-cta-focus-text-decoration: none; --rh-cta-active-container-background-color: #0066cc1a; --rh-cta-active-inner-border-color: transparent; --rh-cta-active-text-decoration: none; } -[data-rh-theme^="dark"] rh-cta:not(:defined, [variant]), -[color-palette^="dark"] rh-cta:not(:defined, [variant]), -rh-cta[color-palette^="dark"]:not(:defined, [variant]) { - --rh-cta-color: var(--rh-color-interactive-blue-lighter, #92c5f9); - --rh-cta-hover-color: var(--rh-color-interactive-blue-lightest, #b9dafc); +[data-rh-theme^='dark'] rh-cta:not(:defined, [variant]), +[color-palette^='dark'] rh-cta:not(:defined, [variant]), +rh-cta[color-palette^='dark']:not(:defined, [variant]) { + --rh-cta-color: var(--rh-color-interactive-primary-default-on-dark, #92c5f9); + --rh-cta-hover-color: var(--rh-color-interactive-primary-hover-on-dark, #b9dafc); /* --rh-color-interactive-blue-lighter with 25% opacity */ --rh-cta-focus-container-background-color: #73bcf740; --rh-cta-focus-border-color: transparent; - --rh-cta-focus-color: var(--rh-color-interactive-blue-lighter, #92c5f9); + --rh-cta-focus-color: var(--rh-color-interactive-primary-default-on-dark, #92c5f9); --rh-cta-focus-inner-border-color: transparent; --rh-cta-focus-text-decoration: none; @@ -53,10 +53,8 @@ rh-cta[color-palette^="dark"]:not(:defined, [variant]) { rh-cta:not(:defined):focus-within { border-color: var(--rh-cta-focus-border-color); background-color: - var( - --rh-cta-focus-container-background-color, - var(--rh-cta-focus-background-color) - ); + var(--rh-cta-focus-container-background-color, + var(--rh-cta-focus-background-color)); --rh-cta-color: var(--rh-cta-focus-color); --rh-cta-text-decoration: var(--rh-cta-focus-text-decoration); @@ -74,7 +72,7 @@ rh-cta:not(:defined):active { background-color: var(--rh-cta-active-background-color); } -rh-cta[variant="primary"]:not(:defined) { +rh-cta[variant='primary']:not(:defined) { border-style: solid; --rh-cta-background-color: var(--rh-color-brand-red-on-light, #ee0000); @@ -91,13 +89,13 @@ rh-cta[variant="primary"]:not(:defined) { --rh-cta-active-inner-border-color: var(--rh-color-text-primary-on-dark, #ffffff); } -[data-rh-theme^="dark"] rh-cta[variant="primary"]:not(:defined), -[color-palette^="dark"] rh-cta[variant="primary"]:not(:defined), -rh-cta[variant="primary"][color-palette^="dark"]:not(:defined) { +[data-rh-theme^='dark'] rh-cta[variant='primary']:not(:defined), +[color-palette^='dark'] rh-cta[variant='primary']:not(:defined), +rh-cta[variant='primary'][color-palette^='dark']:not(:defined) { --rh-cta-hover-border-color: var(--rh-color-brand-red-dark, #a60000); } -rh-cta[variant="secondary"]:not(:defined) { +rh-cta[variant='secondary']:not(:defined) { border-style: solid; --rh-cta-background-color: transparent; @@ -115,9 +113,9 @@ rh-cta[variant="secondary"]:not(:defined) { --rh-cta-active-inner-border-color: var(--rh-color-surface-light, #e0e0e0); } -[data-rh-them^="dark"] rh-cta[variant="secondary"]:not(:defined), -[color-palette^="dark"] rh-cta[variant="secondary"]:not(:defined), -rh-cta[variant="secondary"][color-palette^="dark"]:not(:defined) { +[data-rh-them^='dark'] rh-cta[variant='secondary']:not(:defined), +[color-palette^='dark'] rh-cta[variant='secondary']:not(:defined), +rh-cta[variant='secondary'][color-palette^='dark']:not(:defined) { --rh-cta-border-color: var(--rh-color-border-strong-on-dark, #ffffff); --rh-cta-color: var(--rh-color-text-primary-on-dark, #ffffff); --rh-cta-hover-background-color: var(--rh-color-surface-lightest, #ffffff); @@ -132,19 +130,19 @@ rh-cta[variant="secondary"][color-palette^="dark"]:not(:defined) { --rh-cta-active-inner-border-color: var(--rh-color-border-strong-on-light, #151515); } -rh-cta[variant="brick"]:not(:defined) { +rh-cta[variant='brick']:not(:defined) { border-style: solid; - 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-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-weight: var(--rh-font-weight-body-text-regular, 400); --rh-cta-background-color: transparent; --rh-cta-border-color: var(--rh-color-border-subtle-on-light, #c7c7c7); - --rh-cta-color: var(--rh-color-interactive-blue-darker, #0066cc); + --rh-cta-color: var(--rh-color-interactive-primary-default-on-light, #0066cc); --rh-cta-hover-background-color: var(--rh-color-surface-lighter, #f2f2f2); --rh-cta-hover-border-color: var(--rh-color-border-subtle-on-light, #c7c7c7); - --rh-cta-hover-color: var(--rh-color-interactive-blue-darkest, #003366); + --rh-cta-hover-color: var(--rh-color-interactive-primary-hover-on-light, #003366); --rh-cta-hover-text-decoration: underline; - --rh-cta-focus-color: var(--rh-color-interactive-blue-darker, #0066cc); + --rh-cta-focus-color: var(--rh-color-interactive-primary-default-on-light, #0066cc); --rh-cta-focus-border-color: var(--rh-color-border-subtle-on-light, #c7c7c7); --rh-cta-focus-inner-border-color: var(--rh-color-border-subtle-on-light, #c7c7c7); --rh-cta-focus-text-decoration: none; @@ -153,16 +151,16 @@ rh-cta[variant="brick"]:not(:defined) { --rh-cta-active-text-decoration: underline; } -[data-rh-theme^="dark"] rh-cta[variant="brick"]:not(:defined), -[color-palette^="dark"] rh-cta[variant="brick"]:not(:defined), -rh-cta[variant="brick"][color-palette^="dark"]:not(:defined) { +[data-rh-theme^='dark'] rh-cta[variant='brick']:not(:defined), +[color-palette^='dark'] rh-cta[variant='brick']:not(:defined), +rh-cta[variant='brick'][color-palette^='dark']:not(:defined) { --rh-cta-border-color: var(--rh-color-border-subtle-on-dark, #707070); - --rh-cta-color: var(--rh-color-interactive-blue-lighter, #92c5f9); + --rh-cta-color: var(--rh-color-interactive-primary-default-on-dark, #92c5f9); --rh-cta-hover-background-color: var(--rh-color-surface-darker, #1f1f1f); --rh-cta-hover-border-color: var(--rh-color-border-subtle-on-dark, #707070); - --rh-cta-hover-color: var(--rh-color-interactive-blue-lightest, #b9dafc); + --rh-cta-hover-color: var(--rh-color-interactive-primary-hover-on-dark, #b9dafc); --rh-cta-hover-text-decoration: underline; - --rh-cta-focus-color: var(--rh-color-interactive-blue-lighter, #92c5f9); + --rh-cta-focus-color: var(--rh-color-interactive-primary-default-on-dark, #92c5f9); --rh-cta-focus-border-color: var(--rh-color-border-subtle-on-dark, #707070); --rh-cta-focus-inner-border-color: var(--rh-color-border-subtle-on-dark, #707070); --rh-cta-focus-text-decoration: none; @@ -191,18 +189,14 @@ rh-cta[variant]:not(:defined) * { padding: var(--rh-space-lg, 16px) var(--rh-space-xl, 24px) !important; } -rh-cta[variant$="ary"]:not(:defined) * { +rh-cta[variant$='ary']:not(:defined) * { padding: var(--rh-space-lg, 16px) var(--rh-space-xl, 24px) !important; } -rh-cta[variant="primary"]:not(:defined) *:focus { +rh-cta[variant='primary']:not(:defined) *:focus { outline: - var( - --rh-border-width-sm, - 1px - ) solid var( - --rh-color-text-primary-on-dark, - #ffffff - ) !important; + var(--rh-border-width-sm, + 1px) solid var(--rh-color-text-primary-on-dark, + #ffffff) !important; outline-offset: -2px; } diff --git a/elements/rh-cta/rh-cta.css b/elements/rh-cta/rh-cta.css index a261771641..96dd0b4fcb 100644 --- a/elements/rh-cta/rh-cta.css +++ b/elements/rh-cta/rh-cta.css @@ -9,7 +9,6 @@ a, ::slotted(:is(a, button, input)) { vertical-align: middle !important; - white-space: break-spaces !important; word-break: break-word !important; display: inline !important; color: inherit !important; @@ -21,10 +20,14 @@ a, z-index: 2 !important; } +::slotted(:is(a, button, input)) { + white-space: break-spaces !important; +} + a:after, ::slotted(a):after { display: block; - content: ""; + content: ''; position: absolute; inset: 0; z-index: 3; @@ -43,7 +46,7 @@ a:after, position: relative; white-space: nowrap; color: var(--_color); - 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", Helvetica, Arial, sans-serif); + 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', Helvetica, Arial, sans-serif); font-size: var(--rh-font-size-body-text-lg, 1.125rem); font-weight: 600; /* WARNING: not a token value */ line-height: var(--rh-line-height-body-text, 1.5); @@ -52,14 +55,10 @@ a:after, border-radius: var(--rh-border-radius-default, 3px); border-width: var(--rh-border-width-sm, 1px); - --_context-background-color: var(--_background-color) !important; + --rh-color-surface: var(--_background-color) !important; --_arrow-size: 13px; - --_arrow-plus-padding: calc(var(--rh-space-md, 8px) + var(--_arrow-size)); --rh-icon-size: var(--rh-font-size-body-text-lg, 1.125rem); - --_rh-icon-plus-padding: - calc( - 5px + var(--rh-icon-size) /* stylelint-disable-line rhds/no-unknown-token-name */ - ); + --_rh-icon-plus-padding: calc(5px + var(--rh-icon-size)); } .rtl { @@ -70,7 +69,7 @@ a:after, #container:after { --_offset: 2px; - content: ""; + content: ''; display: block; height: calc(100% - var(--_offset) * 2); width: calc(100% - var(--_offset) * 2); @@ -114,17 +113,13 @@ a:focus-within, outline: none !important; } -:host(:is(:focus, :focus-within)) { +:host(:is(:focus, :focus-within)) #container { --_background-color: var(--rh-cta-focus-background-color); -} -:host(:is(:focus, :focus-within)) #container { border-color: var(--_focus-border-color); background-color: - var( - --_focus-container-background-color, - var(--_focus-background-color) - ); + var(--_focus-container-background-color, + var(--_focus-background-color)); color: var(--rh-cta-focus-color); outline: var(--rh-border-width-md, 2px) @@ -165,19 +160,13 @@ a:focus-within, * ACTIVE STATE * *****************************************************************************/ -:host(:active) { +:host(:active) #container { background-color: var(--_background-color); -} -:host(:active) #container { --_background-color: - var( - --rh-cta-background-color, - var( - --rh-cta-active-container-background-color, - var(--rh-cta-active-background-color) - ) - ); + var(--rh-cta-background-color, + var(--rh-cta-active-container-background-color, + var(--rh-cta-active-background-color))); } :host(:active) #container:after { @@ -195,51 +184,63 @@ a:focus-within, border-width: var(--rh-border-width-sm, 1px); padding-inline: var(--rh-space-2xl, 32px); padding-block: var(--rh-space-lg, 16px); -} -:host([variant]) #container a, -:host([variant]) #container ::slotted(:is(a, button, input)) { - display: inline-flex !important; - text-align: center !important; -} + & a, + & ::slotted(:is(a, button, input)) { + display: inline-flex !important; + text-align: center !important; + } -:host([variant$="ary"]) #container a, -:host([variant$="ary"]) #container ::slotted(:is(a, button, input)) { - font-size: var(--rh-cta-font-size-priority, var(--rh-font-size-body-text-md, 1rem)); -} + &.icon { + & a, + & ::slotted(:is(a, button, input)) { + display: inline !important; + } -:host([variant]) #container.icon a, -:host([variant]) #container.icon ::slotted(:is(a, button, input)) { - display: inline !important; -} + & rh-icon { + margin-inline-start: var(--rh-space-md, 8px); + } + } + + &.svg { + & a, + & ::slotted(:is(a, button, input)) { + --_arrow-plus-padding: calc(var(--rh-space-md, 8px) + var(--_arrow-size)); -:host([variant]) #container.svg a, -:host([variant]) #container.svg ::slotted(:is(a, button, input)) { - padding-inline-end: calc(var(--_arrow-plus-padding) + var(--rh-space-xl, 24px)) !important; + padding-inline-end: calc(var(--_arrow-plus-padding) + var(--rh-space-xl, 24px)) !important; + } + } } -:host([variant]) #container.icon rh-icon { - margin-inline-start: var(--rh-space-md, 8px); +:host([variant$='ary']) #container { + & a, + & ::slotted(:is(a, button, input)) { + font-size: var(--rh-cta-font-size-priority, var(--rh-font-size-body-text-md, 1rem)); + } } /***************************************************************************** * DEFAULT *****************************************************************************/ -:host(:not([variant])) { +:host(:not([variant])) #container { --_background-color: var(--rh-cta-background-color, transparent); --_border-color: var(--rh-cta-border-color, transparent); - --_color: var(--rh-cta-color, var(--rh-color-interactive-blue-darker, #0066cc)); + --_color: var(--rh-cta-color, var(--rh-color-interactive-primary-default)); --_hover-background-color: var(--rh-cta-hover-background-color, transparent); --_hover-border-color: var(--rh-cta-hover-border-color, transparent); - --_hover-color: var(--rh-cta-hover-color, var(--rh-color-interactive-blue-darkest, #003366)); + --_hover-color: + var(--rh-cta-hover-color, + var(--rh-color-interactive-primary-hover)); --_hover-text-decoration: var(--rh-cta-hover-text-decoration, none); --_focus-background-color: var(--rh-cta-focus-background-color, transparent); /* --rh-color-border-interactive-on-light with 10% opacity */ --_focus-container-background-color: var(--rh-cta-focus-container-background-color, #0066cc1a); --_focus-border-color: var(--rh-cta-focus-border-color, transparent); - --_focus-color: var(--rh-cta-focus-color, var(--rh-color-interactive-blue-darker, #0066cc)); + --_focus-color: + var(--rh-cta-focus-color, + var(--rh-color-interactive-primary-default)); --_focus-inner-border-color: var(--rh-cta-focus-inner-border-color, transparent); --_focus-text-decoration: var(--rh-cta-focus-text-decoration, none); @@ -247,406 +248,170 @@ a:focus-within, --_active-container-background-color: var(--rh-cta-active-container-background-color, #0066cc1a); --_active-inner-border-color: var(--rh-cta-active-inner-border-color, transparent); --_active-text-decoration: var(--rh-cta-active-text-decoration, none); -} - -:host(:not([variant])) .dark { - --_color: var(--rh-cta-color, var(--rh-color-interactive-blue-lighter, #92c5f9)); - --_hover-color: var(--rh-cta-hover-color, var(--rh-color-interactive-blue-lightest, #b9dafc)); - - /* --rh-color-interactive-blue-lighter with 25% opacity */ - --_focus-container-background-color: var(--rh-cta-focus-container-background-color, #73bcf740); - --_focus-border-color: var(--rh-cta-focus-border-color, transparent); - --_focus-color: var(--rh-cta-focus-color, var(--rh-color-interactive-blue-lighter, #92c5f9)); - --_focus-inner-border-color: var(--rh-cta-focus-inner-border-color, transparent); - --_focus-text-decoration: var(--rh-cta-focus-text-decoration, none); - /* --rh-color-interactive-blue-lighter with 25% opacity */ - --_active-container-background-color: var(--rh-cta-active-container-background-color, #73bcf740); - --_active-text-decoration: var(--rh-cta-active-text-decoration, none); + &.dark { + /* --rh-color-interactive-blue-lighter with 25% opacity */ + --_focus-container-background-color: var(--rh-cta-focus-container-background-color, #73bcf740); + --_focus-border-color: var(--rh-cta-focus-border-color, transparent); + --_focus-inner-border-color: var(--rh-cta-focus-inner-border-color, transparent); + --_focus-text-decoration: var(--rh-cta-focus-text-decoration, none); + + /* --rh-color-interactive-blue-lighter with 25% opacity */ + --_active-container-background-color: + var(--rh-cta-active-container-background-color, + #73bcf740); + --_active-text-decoration: var(--rh-cta-active-text-decoration, none); + } } /***************************************************************************** * PRIMARY *****************************************************************************/ -:host([variant="primary"]) #container { +:host([variant='primary']) #container { border-style: solid; - --_background-color: var(--rh-cta-background-color, var(--rh-color-brand-red-on-light, #ee0000)); - --_border-color: var(--rh-cta-border-color, var(--rh-color-brand-red-on-light, #ee0000)); + --_background-color: var(--rh-cta-background-color, var(--rh-color-brand-red)); + --_border-color: var(--rh-cta-border-color, var(--rh-color-brand-red)); --_color: var(--rh-cta-color, var(--rh-color-text-primary-on-dark, #ffffff)); --_hover-background-color: - var( - --rh-cta-hover-background-color, - var( - --rh-color-brand-red-dark, - #a60000 - ) - ); - --_hover-border-color: - var( - --rh-cta-hover-border-color, - var( - --rh-color-brand-red-dark, - #a60000 - ) - ); - --_hover-color: - var( - --rh-cta-hover-color, - var( - --rh-color-text-primary-on-dark, - #ffffff - ) - ); + var(--rh-cta-hover-background-color, + var(--rh-color-brand-red-dark, #a60000)); + --_hover-border-color: var(--rh-cta-hover-border-color, var(--rh-color-brand-red-dark, #a60000)); + --_hover-color: var(--rh-cta-hover-color, var(--rh-color-text-primary-on-dark, #ffffff)); --_focus-background-color: - var( - --rh-cta-focus-background-color, - var( - --rh-color-brand-red-on-light, - #ee0000 - ) - ); - --_focus-border-color: - var( - --rh-cta-focus-border-color, - var( - --rh-color-brand-red-on-light, - #ee0000 - ) - ); - --_focus-color: - var( - --rh-cta-focus-color, - var( - --rh-color-text-primary-on-dark, - #ffffff - ) - ); - --_focus-inner-border-color: - var( - --rh-cta-focus-inner-border-color, - var( - --rh-color-text-primary-on-dark, - #ffffff - ) - ); + var(--rh-cta-focus-background-color, + var(--rh-color-brand-red-dark, #a60000)); + --_focus-border-color: var(--rh-cta-focus-border-color, var(--rh-color-brand-red-dark, #a60000)); + --_focus-color: var(--rh-cta-focus-color, var(--rh-color-text-primary-on-dark, #ffffff)); + --_focus-inner-border-color: var(--rh-cta-focus-inner-border-color, var(--rh-color-text-primary)); --_active-background-color: - var( - --rh-cta-active-background-color, - var( - --rh-color-brand-red-dark, - #a60000 - ) - ); + var(--rh-cta-active-background-color, + var(--rh-color-brand-red-dark, #a60000)); --_active-inner-border-color: - var( - --rh-cta-active-inner-border-color, - var( - --rh-color-text-primary-on-dark, - #ffffff - ) - ); -} - -:host([variant="primary"]) #container.dark { - --_hover-border-color: var(--rh-cta-hover-border-color, var(--rh-color-brand-red-dark, #a60000)); + var(--rh-cta-active-inner-border-color, + var(--rh-color-text-primary)); } /***************************************************************************** * SECONDARY *****************************************************************************/ -:host([variant="secondary"]) #container { +:host([variant='secondary']) #container { border-style: solid; --_background-color: var(--rh-cta-background-color, transparent); - --_border-color: var(--rh-cta-border-color, var(--rh-color-text-primary-on-light, #151515)); - --_color: var(--rh-cta-color, var(--rh-color-text-primary-on-light, #151515)); + --_border-color: var(--rh-cta-border-color, var(--rh-color-border-strong)); + --_color: var(--rh-cta-color, var(--rh-color-text-primary)); --_hover-background-color: - var( - --rh-cta-hover-background-color, - var( - --rh-color-surface-darkest, - #151515 - ) - ); - --_hover-border-color: - var( - --rh-cta-hover-border-color, - var( - --rh-color-border-strong-on-light, - #151515 - ) - ); - --_hover-color: - var( - --rh-cta-hover-color, - var( - --rh-color-text-primary-on-dark, - #ffffff - ) - ); + var(--rh-cta-hover-background-color, + var(--rh-color-surface-darkest, + #151515)); + --_hover-border-color: var(--rh-cta-hover-border-color, var(--rh-color-border-strong)); + --_hover-color: var(--rh-cta-hover-color, var(--rh-color-text-primary-on-dark, #ffffff)); --_focus-background-color: - var( - --rh-cta-focus-background-color, - var( - --rh-color-surface-lighter, - #f2f2f2 - ) - ); - --_focus-border-color: - var( - --rh-cta-focus-border-color, - var( - --rh-color-border-strong-on-light, - #151515 - ) - ); + var(--rh-cta-focus-background-color, + var(--rh-color-surface-lighter, + #f2f2f2)); + --_focus-border-color: var(--rh-cta-focus-border-color, var(--rh-color-border-strong)); --_focus-color: - var( - --rh-cta-focus-color, - var( - --rh-color-surface-darkest, - #151515 - ) - ); + var(--rh-cta-focus-color, + var(--rh-color-surface-darkest, + #151515)); --_focus-inner-border-color: - var( - --rh-cta-focus-inner-border-color, - var( - --rh-color-border-strong-on-light, - #151515 - ) - ); - --_active-color: - var( - --rh-cta-active-color, - var( - --rh-color-text-primary-on-dark, - #ffffff - ) - ); - --_active-background-color: - var( - --rh-cta-active-background-color, - var( - --rh-color-border-strong-on-light, - #151515 - ) - ); + var(--rh-cta-focus-inner-border-color, + var(--rh-color-border-strong)); + --_active-color: var(--rh-cta-active-color, var(--rh-color-text-primary)); + --_active-background-color: var(--rh-cta-active-background-color, var(--rh-color-border-strong)); --_active-inner-border-color: - var( - --rh-cta-active-inner-border-color, - var( - --rh-color-surface-light, - #e0e0e0 - ) - ); -} - -:host([variant="secondary"]) #container.dark { - --_border-color: var(--rh-cta-border-color, var(--rh-color-border-strong-on-dark, #ffffff)); - --_color: var(--rh-cta-color, var(--rh-color-text-primary-on-dark, #ffffff)); - --_hover-background-color: - var( - --rh-cta-hover-background-color, - var( - --rh-color-surface-lightest, - #ffffff - ) - ); - --_hover-border-color: - var( - --rh-cta-hover-border-color, - var( - --rh-color-border-strong-on-dark, - #ffffff - ) - ); - --_hover-color: var(--rh-cta-hover-color, var(--rh-color-text-primary-on-light, #151515)); - --_focus-background-color: - var( - --rh-cta-focus-background-color, - var( - --rh-color-surface-dark, - #383838 - ) - ); - --_focus-border-color: - var( - --rh-cta-focus-border-color, - var( - --rh-color-border-strong-on-dark, - #ffffff - ) - ); - --_focus-inner-border-color: - var( - --rh-cta-focus-inner-border-color, - var( - --rh-color-border-strong-on-dark, - #ffffff - ) - ); - --_focus-color: var(--rh-cta-focus-color, var(--rh-color-text-primary-on-dark, #ffffff)); - --_active-color: var(--rh-cta-active-color, var(--rh-color-text-primary-on-light, #151515)); - --_active-background-color: - var( - --rh-cta-active-background-color, - var( - --rh-color-surface-lightest, - #ffffff - ) - ); - --_active-inner-border-color: - var( - --rh-cta-active-inner-border-color, - var( - --rh-color-border-strong-on-light, - #151515 - ) - ); + var(--rh-cta-active-inner-border-color, + var(--rh-color-surface-light, + #e0e0e0)); + + &.dark { + --_hover-background-color: + var(--rh-cta-hover-background-color, + var(--rh-color-surface-lightest, + #ffffff)); + --_focus-background-color: + var(--rh-cta-focus-background-color, + var(--rh-color-surface-dark, + #383838)); + --_hover-color: var(--rh-cta-hover-color, var(--rh-color-text-primary-on-light, #151515)); + --_focus-color: var(--rh-cta-focus-color, var(--rh-color-text-primary)); + --_active-background-color: + var(--rh-cta-active-background-color, + var(--rh-color-surface-lightest, + #ffffff)); + --_active-inner-border-color: + var(--rh-cta-active-inner-border-color, + var(--rh-color-border-strong-on-light, + #151515)); + } } /***************************************************************************** * BRICK *****************************************************************************/ -:host([variant="brick"]) { +:host([variant='brick']) { display: inline-block !important; max-width: 100%; width: 100%; -} - -:host([variant="brick"]) #container { - border-style: solid; - 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-weight: var(--rh-font-weight-body-text-regular, 400); - display: flex; - flex-flow: row wrap; - gap: var(--rh-space-md, 8px); - justify-content: center; - align-items: center; - --_background-color: var(--rh-cta-background-color, transparent); - --_border-color: var(--rh-cta-border-color, var(--rh-color-border-subtle-on-light, #c7c7c7)); - --_color: var(--rh-cta-color, var(--rh-color-interactive-blue-darker, #0066cc)); - --_hover-background-color: - var( - --rh-cta-hover-background-color, - var( - --rh-color-surface-lighter, - #f2f2f2 - ) - ); - --_hover-border-color: - var( - --rh-cta-hover-border-color, - var( - --rh-color-border-subtle-on-light, - #c7c7c7 - ) - ); - --_hover-color: var(--rh-cta-hover-color, var(--rh-color-interactive-blue-darkest, #003366)); - --_hover-text-decoration: var(--rh-cta-hover-text-decoration, none); - --_focus-color: var(--rh-cta-focus-color, var(--rh-color-interactive-blue-darker, #0066cc)); - --_focus-border-color: - var( - --rh-cta-focus-border-color, - var( - --rh-color-border-subtle-on-light, - #c7c7c7 - ) - ); - --_focus-inner-border-color: - var( - --rh-cta-focus-inner-border-color, - var( - --rh-color-border-subtle-on-light, - #c7c7c7 - ) - ); - --_focus-text-decoration: var(--rh-cta-focus-text-decoration, none); - --_active-background-color: - var( - --rh-cta-active-background-color, - var( - --rh-color-surface-lighter, - #f2f2f2 - ) - ); - --_active-inner-border-color: - var( - --rh-cta-active-inner-border-color, - var( - --rh-color-border-subtle-on-light, - #c7c7c7 - ) - ); - --_active-text-decoration: var(--rh-cta-active-text-decoration, none); -} - -:host([variant="brick"]) #container.dark { - --_border-color: var(--rh-cta-border-color, var(--rh-color-border-subtle-on-dark, #707070)); - --_color: var(--rh-cta-color, var(--rh-color-interactive-blue-lighter, #92c5f9)); - --_hover-background-color: - var( - --rh-cta-hover-background-color, - var( - --rh-color-surface-darker, - #1f1f1f - ) - ); - --_hover-border-color: - var( - --rh-cta-hover-border-color, - var( - --rh-color-border-subtle-on-dark, - #707070 - ) - ); - --_hover-color: var(--rh-cta-hover-color, var(--rh-color-interactive-blue-lightest, #b9dafc)); - --_hover-text-decoration: var(--rh-cta-hover-text-decoration, underline); - --_focus-color: var(--rh-cta-focus-color, var(--rh-color-interactive-blue-lighter, #92c5f9)); - --_focus-border-color: - var( - --rh-cta-focus-border-color, - var( - --rh-color-border-subtle-on-dark, - #707070 - ) - ); - --_focus-inner-border-color: - var( - --rh-cta-focus-inner-border-color, - var( - --rh-color-border-subtle-on-dark, - #707070 - ) - ); - --_focus-text-decoration: var(--rh-cta-focus-text-decoration, none); - --_active-background-color: - var( - --rh-cta-active-background-color, - var( - --rh-color-surface-darker, - #1f1f1f - ) - ); - --_active-inner-border-color: - var( - --rh-cta-active-inner-border-color, - var( - --rh-color-border-subtle-on-dark, - #707070 - ) - ); - --_active-text-decoration: var(--rh-cta-active-text-decoration, underline); -} - -:host([variant="brick"]) #container.icon rh-icon { - margin-inline: 0; + & #container { + border-style: solid; + 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-weight: var(--rh-font-weight-body-text-regular, 400); + display: flex; + flex-flow: row wrap; + gap: var(--rh-space-md, 8px); + justify-content: center; + align-items: center; + + --_background-color: var(--rh-cta-background-color, transparent); + --_border-color: var(--rh-cta-border-color, var(--rh-color-border-subtle)); + --_color: var(--rh-cta-color, var(--rh-color-interactive-primary-default)); + --_hover-background-color: + var(--rh-cta-hover-background-color, + var(--rh-color-surface-lighter, + #f2f2f2)); + --_hover-border-color: var(--rh-cta-hover-border-color, var(--rh-color-border-subtle)); + --_hover-color: var(--rh-cta-hover-color, var(--rh-color-interactive-primary-hover)); + --_hover-text-decoration: var(--rh-cta-hover-text-decoration, none); + --_focus-color: var(--rh-cta-focus-color, var(--rh-color-interactive-primary-default)); + --_focus-border-color: var(--rh-cta-focus-border-color, var(--rh-color-border-subtle)); + --_focus-inner-border-color: + var(--rh-cta-focus-inner-border-color, + var(--rh-color-border-subtle)); + --_focus-text-decoration: var(--rh-cta-focus-text-decoration, none); + --_active-background-color: + var(--rh-cta-active-background-color, + var(--rh-color-surface-lighter, + #f2f2f2)); + --_active-inner-border-color: + var(--rh-cta-active-inner-border-color, + var(--rh-color-border-subtle)); + --_active-text-decoration: var(--rh-cta-active-text-decoration, none); + + &.dark { + --_hover-background-color: + var(--rh-cta-hover-background-color, + var(--rh-color-surface-darker, + #1f1f1f)); + --_hover-text-decoration: var(--rh-cta-hover-text-decoration, underline); + --_focus-text-decoration: var(--rh-cta-focus-text-decoration, none); + --_active-background-color: + var(--rh-cta-active-background-color, + var(--rh-color-surface-darker, + #1f1f1f)); + --_active-text-decoration: var(--rh-cta-active-text-decoration, underline); + } + + &.icon rh-icon { + margin-inline: 0; + } + } } /* chrome <= 103 */ diff --git a/elements/rh-cta/rh-cta.ts b/elements/rh-cta/rh-cta.ts index b0540b9faa..8b6f3e5a34 100644 --- a/elements/rh-cta/rh-cta.ts +++ b/elements/rh-cta/rh-cta.ts @@ -138,7 +138,7 @@ export class RhCta extends LitElement { const { download, href, referrerpolicy, rel, target, icon, iconSet, - on = '', variant, + on = 'light', variant, } = this; const rtl = this.#dir.dir === 'rtl'; const isDefault = !variant; @@ -150,7 +150,7 @@ export class RhCta extends LitElement { return html` ${variant === 'brick' && icon ? html` ` : ''}${href ? html` diff --git a/elements/rh-dialog/docs/00-overview.md b/elements/rh-dialog/docs/00-overview.md index ec6f4a11db..779e35c5da 100644 --- a/elements/rh-dialog/docs/00-overview.md +++ b/elements/rh-dialog/docs/00-overview.md @@ -3,7 +3,7 @@ {{ tagName | getElementDescription }} - A dialog container with a black headline, black body text, two blue buttons, and a dark gray close button all on a white background on top of a slightly transparent black background + A dialog container with a black headline, black body text, two blue buttons, and a dark gray close button all on a white background on top of a slightly transparent black background {% repoStatusList repoStatus=repoStatus %} diff --git a/elements/rh-dialog/docs/10-style.md b/elements/rh-dialog/docs/10-style.md index 7934fe4d30..19cc714bd4 100644 --- a/elements/rh-dialog/docs/10-style.md +++ b/elements/rh-dialog/docs/10-style.md @@ -8,7 +8,7 @@ helps users focus on the dialog content.
            - Anatomy of a dialog with lots of annotations pointing to various parts + Anatomy of a dialog with lots of annotations pointing to various parts
              @@ -28,7 +28,7 @@ helps users focus on the dialog content. A dialog is available in the light theme only. - Light theme dialog + Light theme dialog ## Configuration @@ -37,7 +37,7 @@ The dialog container does not have a maximum height, but too much content in the body text section will cause scrolling. - How a dialog container is constructed showing border radius, region, and scrolling details + How a dialog container is constructed showing border radius, region, and scrolling details ## Space @@ -47,13 +47,13 @@ The amount of space in a dialog reduces as breakpoints get smaller. ### Large breakpoints - A dialog container on a large breakpoint with spacing between all elements + A dialog container on a large breakpoint with spacing between all elements ### Small breakpoints - A dialog container on a small breakpoint with spacing between all elements + A dialog container on a small breakpoint with spacing between all elements @@ -75,7 +75,7 @@ Control and inactive page number buttons have the same hover state. Truncation is not interactive so it has no hover state. - Light theme dialog hover state example + Light theme dialog hover state example @@ -99,7 +99,7 @@ is not interactive so it has no hover state. ### Focus - Light theme dialog focus state example + Light theme dialog focus state example @@ -126,7 +126,7 @@ is not interactive so it has no hover state. ### Active - Light theme dialog active state example + Light theme dialog active state example diff --git a/elements/rh-dialog/docs/20-guidelines.md b/elements/rh-dialog/docs/20-guidelines.md index dc3b228f81..28b2b814e1 100644 --- a/elements/rh-dialog/docs/20-guidelines.md +++ b/elements/rh-dialog/docs/20-guidelines.md @@ -30,7 +30,7 @@ The fixed-width dialog container works well for environments with a fixed grid, like marketing pages. - A dialog container spanning a 12-column grid that is fixed in the center of the page + A dialog container spanning a 12-column grid that is fixed in the center of the page @@ -40,7 +40,7 @@ The full-width dialog container works well for environments with a more fluid grid like apps or dashboards. - A dialog container spanning a 6-column fluid grid that takes up the whole screen + A dialog container spanning a 6-column fluid grid that takes up the whole screen @@ -59,7 +59,7 @@ actions. When confirming a non-destructive action, do the following: - Be specific about what will happen when an action is confirmed - Non-destructive confirmation dialog example with a blue primary button + Non-destructive confirmation dialog example with a blue primary button @@ -69,7 +69,7 @@ When confirming a destructive action, do the following. a [danger button](https://ux.redhat.com/elements/button/) instead - Destructive confirmation dialog example with a red primary button + Destructive confirmation dialog example with a red primary button @@ -80,7 +80,7 @@ expected behavior. Briefly contextualize the problem, explain why it happened, and then provide actionable steps toward a solution. - Error dialog example with a blue primary button + Error dialog example with a blue primary button ### Passive @@ -97,7 +97,7 @@ using a passive dialog, consider the following: alert](https://ux.redhat.com/elements/alert/) instead - Passive dialog example with a blue primary button + Passive dialog example with a blue primary button @@ -107,7 +107,7 @@ A video can replace a fixed-width dialog container, it should have the same width and include a close button. - A dialog video player spanning a 12-column grid with a white close button + A dialog video player spanning a 12-column grid with a white close button @@ -180,7 +180,7 @@ indicate there is additional content out of view. Dialog content should never scroll horizontally. - Dialog with a long amount of content showing visible gradient at the bottom of the body text section + Dialog with a long amount of content showing visible gradient at the bottom of the body text section @@ -192,14 +192,14 @@ By default, a dialog container is horizontally and vertically centered on top of the backdrop and viewport. - Dialog with container horizontally and vertically centered + Dialog with container horizontally and vertically centered By default, a dialog container is horizontally and vertically centered on top of the backdrop and viewport. - Dialog with container horizontally centered, but positioned at the top of the page + Dialog with container horizontally centered, but positioned at the top of the page @@ -211,7 +211,7 @@ Both the fixed-width and full-width dialog containers can be used on large breakpoints. - A dialog container on a large breakpoint + A dialog container on a large breakpoint ### Small breakpoints @@ -220,7 +220,7 @@ As breakpoints get smaller, the fixed-width dialog container will change to full-width and become taller. - Two dialog containers on small breakpoints, one tablet size and one mobile size + Two dialog containers on small breakpoints, one tablet size and one mobile size @@ -233,7 +233,7 @@ them to the main page instead. A dialog is disruptive, so it is important to bring users back to their original workflow as quickly as possible. - A dialog container with a three-panel accordion which is incorrect usage + A dialog container with a three-panel accordion which is incorrect usage @@ -243,7 +243,7 @@ Make sure to write clearly about what will happen when users confirm a specific action. - A dialog container with vague text which is incorrect usage + A dialog container with vague text which is incorrect usage @@ -253,5 +253,5 @@ Do not use more than two buttons in a dialog and do not add or change button variants. - A dialog container with three buttons which is incorrect usage + A dialog container with three buttons which is incorrect usage diff --git a/elements/rh-dialog/docs/40-accessibility.md b/elements/rh-dialog/docs/40-accessibility.md index b5028120a8..8a019cab2a 100644 --- a/elements/rh-dialog/docs/40-accessibility.md +++ b/elements/rh-dialog/docs/40-accessibility.md @@ -3,7 +3,7 @@ A dialog can be opened by pressing `Enter` when the dialog trigger has focus. When a dialog is open, moving focus using a keyboard is constrained or trapped within the dialog container. Keyboard navigation by pressing `Tab` will cycle focus through the interactive elements until the dialog is closed. - Flowchart of a dialog container outlining several keyboard interactions + Flowchart of a dialog container outlining several keyboard interactions @@ -51,7 +51,7 @@ When a dialog opens, the element that should receive focus depends on the conten Only the close button and any interactive elements are selectable. - A dialog container with three touch targets; one on the close button and one on each button + A dialog container with three touch targets; one on the close button and one on each button diff --git a/elements/rh-dialog/rh-dialog.css b/elements/rh-dialog/rh-dialog.css index 07fd42b523..f12ce32234 100644 --- a/elements/rh-dialog/rh-dialog.css +++ b/elements/rh-dialog/rh-dialog.css @@ -27,7 +27,7 @@ section { max-height: inherit; } -[part="overlay"] { +[part='overlay'] { position: fixed; height: 100%; width: 100%; @@ -36,7 +36,7 @@ section { background-color: rgba(3, 3, 3, 0.62); } -[part="dialog"] { +[part='dialog'] { position: relative; margin: 0 auto; width: var(--_box-width, calc(100% - var(--rh-space-2xl, 32px))); @@ -53,27 +53,27 @@ section { font-family: inherit; } -:host([width]) [part="dialog"], -:host([variant]) [part="dialog"] { +:host([width]) [part='dialog'], +:host([variant]) [part='dialog'] { margin-inline: 0; } -:host([width="small"]) [part="dialog"], -:host([variant="small"]) [part="dialog"] { +:host([width='small']) [part='dialog'], +:host([variant='small']) [part='dialog'] { --_box-width: 35rem; } -:host([width="medium"]) [part="dialog"], -:host([variant="medium"]) [part="dialog"] { +:host([width='medium']) [part='dialog'], +:host([variant='medium']) [part='dialog'] { --_box-width: 52.5rem; } -:host([width="large"]) [part="dialog"], -:host([variant="large"]) [part="dialog"] { +:host([width='large']) [part='dialog'], +:host([variant='large']) [part='dialog'] { --_box-width: 70rem; } -[part="content"] { +[part='content'] { overflow-y: auto; overscroll-behavior: contain; max-height: var(--_box-max-height, calc(100vh - var(--rh-space-3xl, 48px))); @@ -81,7 +81,7 @@ section { border-radius: var(--rh-border-radius-default, 3px); } -[part="content"] ::slotted([slot="header"]) { +[part='content'] ::slotted([slot='header']) { margin-top: 0 !important; } @@ -91,13 +91,13 @@ header { background-color: var(--rh-color-surface-lightest, #ffffff); } -header ::slotted(:is(h1,h2,h3,h4,h5,h6)[slot="header"]) { +header ::slotted(:is(h1,h2,h3,h4,h5,h6)[slot='header']) { font-size: var(--rh-font-size-heading-sm, 1.5rem); font-weight: var(--rh-font-weight-body-text-regular, 400); - font-family: "Red Hat Display", RedHatDisplay, Overpass, Helvetica, sans-serif; + font-family: 'Red Hat Display', RedHatDisplay, Overpass, Helvetica, sans-serif; } -[part="close-button"] { +[part='close-button'] { color: var(--rh-color-icon-subtle, #707070); background-color: transparent; border: none; @@ -113,17 +113,17 @@ header ::slotted(:is(h1,h2,h3,h4,h5,h6)[slot="header"]) { right: calc(var(--rh-space-xl, 24px) / -3); } -[part="close-button"] > svg { +[part='close-button'] > svg { font-size: 16px; width: var(--rh-space-lg, 16px); aspect-ratio: 1/1; } -[part="close-button"]:is(:hover, :focus-within, :focus-visible) svg:is(svg, :hover) { +[part='close-button']:is(:hover, :focus-within, :focus-visible) svg:is(svg, :hover) { fill: var(--rh-color-icon-secondary-on-light, #151515); } -:host([position="top"]) #dialog { +:host([position='top']) #dialog { align-self: start; margin-block: var(--rh-space-2xl, 32px); margin-inline: var(--rh-space-lg, 16px); @@ -140,35 +140,35 @@ footer { #rhds-wrapper { display: contents; - font-family: "Red Hat Text", RedHatText, Overpass, Helvetica, sans-serif; + font-family: 'Red Hat Text', RedHatText, Overpass, Helvetica, sans-serif; --offset: var(--rh-space-md, 8px); --offset-top: var(--offset); --offset-right: var(--offset); } -:host([type="video"]) { +:host([type='video']) { --rh-dialog-close-button-color: var(--rh-color-icon-secondary-on-dark, #ffffff); } -:host([type="video"]) [part="close-button"] { +:host([type='video']) [part='close-button'] { top: var(--offset-top); right: var(--offset-right); padding: var(--rh-space-sm, 6px); color: var(--rh-color-icon-secondary-on-dark, #ffffff); } -:host([type="video"]) [part="content"] { +:host([type='video']) [part='content'] { overflow: hidden; } -:host([type="video"][open]) [part="overlay"] { +:host([type='video'][open]) [part='overlay'] { --_gray-90-rgb: var(--rh-color-gray-90-rgb, 31 31 31); background-color: rgb(var(--_gray-90-rgb) / var(--rh-opacity-60, 60%)); } -:host([type="video"][open]) [part="dialog"] { +:host([type='video'][open]) [part='dialog'] { --_aspect-ratio: var(--rh-dialog-video-aspect-ratio, 16/9); aspect-ratio: var(--_aspect-ratio); @@ -177,13 +177,13 @@ footer { margin: 0; } -:host([type="video"]) #rhds-wrapper.mobile [part="close-button"] { +:host([type='video']) #rhds-wrapper.mobile [part='close-button'] { --offset-right: var(--rh-space-sm, 6px); } -:host([type="video"]) #container, -:host([type="video"]) [part="content"], -:host([type="video"]) ::slotted(:not([slot])) { +:host([type='video']) #container, +:host([type='video']) [part='content'], +:host([type='video']) ::slotted(:not([slot])) { aspect-ratio: var(--rh-dialog-video-aspect-ratio, 16/9); /* account for a 1px descrepency between dialog and container aspect ratio */ diff --git a/elements/rh-footer/docs/10-style.md b/elements/rh-footer/docs/10-style.md index 701fff208c..ceeb8adba3 100644 --- a/elements/rh-footer/docs/10-style.md +++ b/elements/rh-footer/docs/10-style.md @@ -11,7 +11,7 @@ websites.
              - Image of a footer showing lots of annotation numbers next to various styles and other elements + Image of a footer showing lots of annotation numbers next to various styles and other elements
                @@ -37,7 +37,7 @@ universal footer background color. This variant creates separation and helps distinguish both footers from each other. - Image of a footer with no elements except for backgrounds; the top background is dark gray and the bottom is black + Image of a footer with no elements except for backgrounds; the top background is dark gray and the bottom is black @@ -47,7 +47,7 @@ A footer only has one theme, but visually it could be considered in the dark theme. - Image of a large footer + Image of a large footer @@ -134,7 +134,7 @@ theme. ### Language selector - Image of a footer with the language selector menu open + Image of a footer with the language selector menu open @@ -174,26 +174,26 @@ Within these regions, position and alignment are somewhat rigid in order to maintain consistency. - Image of how a footer is architected showing lots of alignment examples + Image of how a footer is architected showing lots of alignment examples ## Space - Image of a desktop footer showing space values in between elements + Image of a desktop footer showing space values in between elements - Image of a tablet footer showing space values in between elements + Image of a tablet footer showing space values in between elements - Image of a mobile footer showing space values in between elements + Image of a mobile footer showing space values in between elements - Image of a footer showing space values in the language selector menu + Image of a footer showing space values in the language selector menu @@ -210,7 +210,7 @@ maintain consistency. ### Hover - Hover state examples within a footer + Hover state examples within a footer @@ -250,7 +250,7 @@ maintain consistency. ### Hover - language selector - Hover state example within the language selector menu + Hover state example within the language selector menu @@ -279,7 +279,7 @@ maintain consistency. - Focus state examples within a footer + Focus state examples within a footer @@ -307,7 +307,7 @@ maintain consistency. - Focus state example within the language selector menu + Focus state example within the language selector menu @@ -336,7 +336,7 @@ maintain consistency. - Active state examples within a footer + Active state examples within a footer @@ -364,7 +364,7 @@ maintain consistency. - Active state example within the language selector menu + Active state example within the language selector menu diff --git a/elements/rh-footer/docs/20-guidelines.md b/elements/rh-footer/docs/20-guidelines.md index ae269b3def..d51659eda6 100644 --- a/elements/rh-footer/docs/20-guidelines.md +++ b/elements/rh-footer/docs/20-guidelines.md @@ -15,7 +15,7 @@ A footer is divided into two parts, the **Website-specific** footer and the Most of the content in the website-specific footer can be customized. - Image of the website-specific footer showing regions that can and cannot be customized + Image of the website-specific footer showing regions that can and cannot be customized @@ -73,7 +73,7 @@ Most of the content in the website-specific footer can be customized. Content in the universal footer is always the same across all websites. - Image of the universal footer showing only one region that cannot be customized + Image of the universal footer showing only one region that cannot be customized @@ -102,7 +102,7 @@ Content in the universal footer is always the same across all websites. A footer spans the entire width of the browser window at all breakpoints. - Image of a footer in a layout spanning the width of the browser window + Image of a footer in a layout spanning the width of the browser window @@ -118,7 +118,7 @@ Red Hat fedora always links to redhat.com. - Image of the universal footer by itself + Image of the universal footer by itself ### Other web properties @@ -127,19 +127,19 @@ The footer was designed to be applied to all Red Hat web properties. The layout is flexible enough to accommodate grids, elements, text, and more. - Image of the footer on a Customer Portal website + Image of the footer on a Customer Portal website - Image of a footer on a Customer Portal website + Image of a footer on a Customer Portal website - Image of a footer on a Developer website + Image of a footer on a Developer website - Image of a footer on a Partner Connect website + Image of a footer on a Partner Connect website @@ -151,14 +151,14 @@ If the website-specific footer includes a lot of content, columns can be added below the first row of columns. - Image of a footer with four columns of links in one row and two columns in the second row + Image of a footer with four columns of links in one row and two columns in the second row If the website-specific footer includes less content, columns will stretch to fill the empty space. - Image of a footer with only two columns of links in one row + Image of a footer with only two columns of links in one row @@ -166,7 +166,7 @@ If the number of columns changes, social media links will shift position to remain aligned to the left edge of the last column. - Image of a footer with three columns of links showing an example of social media icons shifting + Image of a footer with three columns of links showing an example of social media icons shifting ## Responsive design @@ -174,7 +174,7 @@ remain aligned to the left edge of the last column. ### Large breakpoints - Image of a large breakpoint footer + Image of a large breakpoint footer @@ -189,11 +189,11 @@ content will also get rearranged. - Image of a tablet breakpoint footer + Image of a tablet breakpoint footer - Image of a mobile breakpoint footer + Image of a mobile breakpoint footer @@ -253,7 +253,7 @@ Do not reverse the order of footers, the website-specific footer should always be on top. - Image of the global footer on top of the website-specific footer which is incorrect usage + Image of the global footer on top of the website-specific footer which is incorrect usage @@ -262,7 +262,7 @@ be on top. Do not replace columns with an accordion if there is still adequate space. - Image of a desktop footer with an accordion replacing four columns of links which is incorrect usage + Image of a desktop footer with an accordion replacing four columns of links which is incorrect usage @@ -271,7 +271,7 @@ Do not replace columns with an accordion if there is still adequate space. Do not use the website-specific footer without the universal footer. - Image of a footer missing the universal footer which is incorrect usage + Image of a footer missing the universal footer which is incorrect usage @@ -281,5 +281,5 @@ Do not create your own custom universal footer by changing, deleting, or rearranging any elements. - Image of a universal footer with a new design which is incorrect usage + Image of a universal footer with a new design which is incorrect usage diff --git a/elements/rh-footer/docs/30-code.md b/elements/rh-footer/docs/30-code.md index abeb547cda..43fd9095e5 100644 --- a/elements/rh-footer/docs/30-code.md +++ b/elements/rh-footer/docs/30-code.md @@ -1,5 +1,7 @@ {% renderInstall lightdomcss=true %}{% endrenderInstall %} +{% renderLightDom %}{% endrenderLightDom %} + {% renderCodeDocs hideDescription=true %}{% endrenderCodeDocs %} {% renderCodeDocs for='rh-footer-universal' %}{% endrenderCodeDocs %} diff --git a/elements/rh-footer/docs/40-accessibility.md b/elements/rh-footer/docs/40-accessibility.md index b050f3bbbd..6e74b204a5 100644 --- a/elements/rh-footer/docs/40-accessibility.md +++ b/elements/rh-footer/docs/40-accessibility.md @@ -41,7 +41,7 @@ A logical focus order helps keyboard users operate our websites. Elements need t - Image of a footer showing groups of focus indicators in different regions with annotation numbers + Image of a footer showing groups of focus indicators in different regions with annotation numbers @@ -49,13 +49,13 @@ A logical focus order helps keyboard users operate our websites. Elements need t Users can open the language selector menu by pressing `Enter` if the trigger has focus. If they do, they can press `Tab` to move focus to the first language. Each language can receive focus from left to right and top to bottom. - Image of a footer with the language selector menu open showing the focus order of languages + Image of a footer with the language selector menu open showing the focus order of languages When the focus is moved outside of the menu, the menu closes. - Image of a footer with the language selector menu open showing the menu closing when focus is moved + Image of a footer with the language selector menu open showing the menu closing when focus is moved diff --git a/elements/rh-footer/rh-footer-block.css b/elements/rh-footer/rh-footer-block.css index 1ed99369bf..256edf8b2b 100644 --- a/elements/rh-footer/rh-footer-block.css +++ b/elements/rh-footer/rh-footer-block.css @@ -7,7 +7,7 @@ /** Add the separator to blocks in the middle */ :host(:not(:last-of-type, :first-of-type)):after { - content: ""; + content: ''; display: block; height: 1px; width: 100%; @@ -35,6 +35,6 @@ .content ::slotted(*) { color: var(--rh-color-text-secondary-on-dark, #c7c7c7); - 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-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-weight: var(--rh-font-weight-body-text-regular, 400); } diff --git a/elements/rh-footer/rh-footer-lightdom.css b/elements/rh-footer/rh-footer-lightdom.css index 2e082fe4c0..bdee8d3875 100644 --- a/elements/rh-footer/rh-footer-lightdom.css +++ b/elements/rh-footer/rh-footer-lightdom.css @@ -1,29 +1,29 @@ :is(rh-footer, rh-footer-universal) a { - color: var(--rh-color-interactive-blue-lighter, #92c5f9); + color: var(--rh-color-interactive-primary-default-on-dark, #92c5f9); text-decoration: none; } :is(rh-footer, rh-footer-universal) a:hover { - color: var(--rh-color-interactive-blue-lightest, #b9dafc); + color: var(--rh-color-interactive-primary-hover-on-dark, #b9dafc); text-decoration: underline; } :is(rh-footer, rh-footer-universal) a:is(:focus, :focus-within) { - color: var(--rh-color-interactive-blue-lightest, #b9dafc); + color: var(--rh-color-interactive-primary-hover-on-dark, #b9dafc); text-decoration: underline; } :is(rh-footer, rh-footer-universal) a:visited { - color: var(--rh-color-interactive-blue-lightest, #b9dafc); + color: var(--rh-color-interactive-primary-hover-on-dark, #b9dafc); text-decoration: none; } /* ensure links fully wrap img tags */ -:is(rh-footer, rh-footer-universal) a[slot^="logo"] { +:is(rh-footer, rh-footer-universal) a[slot^='logo'] { display: block; } -:is(rh-footer) a[slot^="logo"] > img { +:is(rh-footer) a[slot^='logo'] > img { display: block; width: auto; height: 100%; @@ -31,32 +31,32 @@ } :is(rh-footer, rh-footer-universal) :is(h1, h2, h3, h4, h5, h6) { - 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", Helvetica, Arial, sans-serif); + 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', Helvetica, Arial, sans-serif); line-height: var(--rh-line-height-heading, 1.3); } -rh-footer [slot="links"]:is(h1, h2, h3, h4, h5):nth-of-type(n+5) { +rh-footer [slot='links']:is(h1, h2, h3, h4, h5):nth-of-type(n+5) { --_link-header-margin: calc(var(--rh-space-2xl, 32px) - var(--rh-space-lg, 16px)); } -rh-footer [slot^="links"] a { +rh-footer [slot^='links'] a { gap: var(--rh-footer-links-gap, var(--rh-space-md, 8px)); } -:is(rh-footer, rh-footer-universal) [slot^="links"] li { +:is(rh-footer, rh-footer-universal) [slot^='links'] li { margin: 0; padding: 0; display: contents; } -:is(rh-footer, rh-footer-universal) [slot^="links"] a { +:is(rh-footer, rh-footer-universal) [slot^='links'] a { display: block; color: var(--rh-color-text-primary-on-dark, #ffffff) !important; font-size: var(--rh-footer-link-font-size, var(--rh-font-size-body-text-sm, 0.875rem)); width: fit-content; } -rh-footer-universal [slot^="links"] a { +rh-footer-universal [slot^='links'] a { font-size: inherit; } @@ -89,8 +89,8 @@ rh-footer:not(:defined) { width: 100%; display: grid; grid-template-areas: - "footer" - "global"; + 'footer' + 'global'; grid-template-rows: 1fr auto; min-height: var(--rh-footer-nojs-min-height, 750px); } @@ -100,12 +100,12 @@ rh-footer-universal:not(:defined):before { } /* Adding styles to logo */ -rh-footer:not(:defined) > [slot="logo"] { +rh-footer:not(:defined) > [slot='logo'] { padding: var(--rh-space-2xl, 32px) var(--_section-side-gap); } /* A11y hide child components */ -rh-footer:not(:defined) > :not([slot="logo"], rh-footer-universal), +rh-footer:not(:defined) > :not([slot='logo'], rh-footer-universal), rh-footer-universal:not(:defined) > * { border: 0; clip: rect(1px, 1px, 1px, 1px); diff --git a/elements/rh-footer/rh-footer-social-link.ts b/elements/rh-footer/rh-footer-social-link.ts index 55a64d6f6d..1e19863cb7 100644 --- a/elements/rh-footer/rh-footer-social-link.ts +++ b/elements/rh-footer/rh-footer-social-link.ts @@ -1,3 +1,5 @@ +import type { IconNameFor } from '@rhds/icons'; + import { LitElement, html } from 'lit'; import { customElement } from 'lit/decorators/custom-element.js'; import { property } from 'lit/decorators/property.js'; @@ -10,7 +12,8 @@ import style from './rh-footer-social-link.css'; export class RhFooterSocialLink extends LitElement { static readonly styles = style; - @property() icon?: string; + /** Icon for this social link e.g. `'facebook'` */ + @property() icon?: IconNameFor<'social'>; #logger = new Logger(this); @@ -31,9 +34,8 @@ export class RhFooterSocialLink extends LitElement { newDiv.querySelectorAll('[_rendered]').forEach(i => i.remove()); // NB: icons are restricted to social set, so as not to require a minor release // rh-icon is slated to deal with this problem in-house - newDiv.innerHTML = `${newDiv.innerHTML}`; + newDiv.innerHTML = + `${newDiv.innerHTML}`; // add a11y settings newDiv.setAttribute('aria-label', newDiv.textContent || ''); if (!newDiv.getAttribute('aria-label')) { diff --git a/elements/rh-footer/rh-footer.css b/elements/rh-footer/rh-footer.css index dd2bc5fa9b..5e364d2811 100644 --- a/elements/rh-footer/rh-footer.css +++ b/elements/rh-footer/rh-footer.css @@ -1,7 +1,7 @@ :host { /* apply sensible defaults based on redhat standards. */ color: var(--rh-color-white, #ffffff); - 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-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); line-height: var(--rh-line-height-body-text, 1.5); font-weight: var(--_font-weight); font-size: initial; @@ -26,7 +26,7 @@ footer, } ::slotted(:is(h1,h2,h3,h4,h5,h6)) { - 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", Helvetica, Arial, sans-serif) !important; + 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', Helvetica, Arial, sans-serif) !important; line-height: var(--rh-line-height-heading, 1.3) !important; } @@ -49,7 +49,7 @@ footer, padding: var(--rh-space-xs, 4px); top: 0; right: 0; - font-family: var(--rh-font-family-code, RedHatMono, "Red Hat Mono", "Courier New", Courier, monospace); + font-family: var(--rh-font-family-code, RedHatMono, 'Red Hat Mono', 'Courier New', Courier, monospace); font-size: var(--rh-font-size-code-xs, 0.75rem); } @@ -73,7 +73,7 @@ footer, .header:after { display: none; - content: ""; + content: ''; background-color: var(--_border-color); height: var(--rh-length-4xs, 1px); position: absolute; @@ -118,11 +118,11 @@ footer, display: grid; grid-template-columns: 1fr; grid-template-areas: - "logo" - "primary" - "spacer" - "secondary" - "tertiary"; + 'logo' + 'primary' + 'spacer' + 'secondary' + 'tertiary'; gap: var(--rh-space-2xl, 32px) var(--rh-space-xl, 24px); } @@ -222,7 +222,7 @@ footer, display: flex; } -[part="base"]:not(.isMobile) .links { +[part='base']:not(.isMobile) .links { display: grid; grid-template-columns: repeat(1fr, 25%); grid-template-rows: repeat(1, min-content auto); @@ -231,87 +231,87 @@ footer, grid-auto-flow: column; } -[part="base"]:not(.isMobile) .links ::slotted(:is(h2, h3, h4, h5, h6):nth-of-type(1)) { +[part='base']:not(.isMobile) .links ::slotted(:is(h2, h3, h4, h5, h6):nth-of-type(1)) { grid-column: 1/2; grid-row: 1/2; } -[part="base"]:not(.isMobile) .links ::slotted(:is(h2, h3, h4, h5, h6):nth-of-type(2)) { +[part='base']:not(.isMobile) .links ::slotted(:is(h2, h3, h4, h5, h6):nth-of-type(2)) { grid-column: 2/3; grid-row: 1/2; } -[part="base"]:not(.isMobile) .links ::slotted(:is(h2, h3, h4, h5, h6):nth-of-type(3)) { +[part='base']:not(.isMobile) .links ::slotted(:is(h2, h3, h4, h5, h6):nth-of-type(3)) { grid-column: 3/4; grid-row: 1/2; } -[part="base"]:not(.isMobile) .links ::slotted(:is(h2, h3, h4, h5, h6):nth-of-type(4)) { +[part='base']:not(.isMobile) .links ::slotted(:is(h2, h3, h4, h5, h6):nth-of-type(4)) { grid-column: 4/5; grid-row: 1/2; } -[part="base"]:not(.isMobile) .links ::slotted(:is(h2, h3, h4, h5, h6):nth-of-type(5)) { +[part='base']:not(.isMobile) .links ::slotted(:is(h2, h3, h4, h5, h6):nth-of-type(5)) { grid-column: 1/2; grid-row: 3/4; } -[part="base"]:not(.isMobile) .links ::slotted(:is(h2, h3, h4, h5, h6):nth-of-type(6)) { +[part='base']:not(.isMobile) .links ::slotted(:is(h2, h3, h4, h5, h6):nth-of-type(6)) { grid-column: 2/3; grid-row: 3/4; } -[part="base"]:not(.isMobile) .links ::slotted(:is(h2, h3, h4, h5, h6):nth-of-type(7)) { +[part='base']:not(.isMobile) .links ::slotted(:is(h2, h3, h4, h5, h6):nth-of-type(7)) { grid-column: 3/4; grid-row: 3/4; } -[part="base"]:not(.isMobile) .links ::slotted(:is(h2, h3, h4, h5, h6):nth-of-type(8)) { +[part='base']:not(.isMobile) .links ::slotted(:is(h2, h3, h4, h5, h6):nth-of-type(8)) { grid-column: 4/5; grid-row: 3/4; } -[part="base"]:not(.isMobile) .links ::slotted(:is(ul:nth-of-type(1))) { +[part='base']:not(.isMobile) .links ::slotted(:is(ul:nth-of-type(1))) { grid-column: 1/2; grid-row: 2/3; } -[part="base"]:not(.isMobile) .links ::slotted(:is(ul:nth-of-type(2))) { +[part='base']:not(.isMobile) .links ::slotted(:is(ul:nth-of-type(2))) { grid-column: 2/3; grid-row: 2/3; } -[part="base"]:not(.isMobile) .links ::slotted(:is(ul:nth-of-type(3))) { +[part='base']:not(.isMobile) .links ::slotted(:is(ul:nth-of-type(3))) { grid-column: 3/4; grid-row: 2/3; } -[part="base"]:not(.isMobile) .links ::slotted(:is(ul:nth-of-type(4))) { +[part='base']:not(.isMobile) .links ::slotted(:is(ul:nth-of-type(4))) { grid-column: 4/5; grid-row: 2/3; } -[part="base"]:not(.isMobile) .links ::slotted(:is(ul:nth-of-type(5))) { +[part='base']:not(.isMobile) .links ::slotted(:is(ul:nth-of-type(5))) { grid-column: 1/2; grid-row: 4/5; } -[part="base"]:not(.isMobile) .links ::slotted(:is(ul:nth-of-type(6))) { +[part='base']:not(.isMobile) .links ::slotted(:is(ul:nth-of-type(6))) { grid-column: 2/3; grid-row: 4/5; } -[part="base"]:not(.isMobile) .links ::slotted(:is(ul:nth-of-type(7))) { +[part='base']:not(.isMobile) .links ::slotted(:is(ul:nth-of-type(7))) { grid-column: 3/4; grid-row: 4/5; } -[part="base"]:not(.isMobile) .links ::slotted(:is(ul:nth-of-type(8))) { +[part='base']:not(.isMobile) .links ::slotted(:is(ul:nth-of-type(8))) { grid-column: 4/5; grid-row: 4/5; } -[part="base"]:not(.isMobile) .links ::slotted(ul) { +[part='base']:not(.isMobile) .links ::slotted(ul) { gap: var(--rh-footer-links-gap, var(--rh-space-lg, 16px)); display: flex; flex-direction: column; @@ -326,10 +326,8 @@ footer, margin-block: 0 !important; margin-block-start: var(--_link-header-margin, 0) !important; font-size: - var( - --rh-footer-link-header-font-size, - var(--rh-font-size-body-text-sm, 0.875rem) - ) !important; + var(--rh-footer-link-header-font-size, + var(--rh-font-size-body-text-sm, 0.875rem)) !important; color: var(--rh-color-text-primary-on-dark, #ffffff) !important; } @@ -355,19 +353,19 @@ rh-accordion-header:hover { .global-base { grid-template-columns: 4fr 4fr 4fr; grid-template-areas: - "logo logo logo" - "primary primary primary" - "spacer spacer spacer" - "secondary secondary secondary"; + 'logo logo logo' + 'primary primary primary' + 'spacer spacer spacer' + 'secondary secondary secondary'; } .global-base:is(.hasTertiary) { grid-template-columns: 4fr 4fr 4fr; grid-template-areas: - "logo logo logo" - "primary primary primary" - "spacer spacer spacer" - "secondary secondary tertiary"; + 'logo logo logo' + 'primary primary primary' + 'spacer spacer spacer' + 'secondary secondary tertiary'; } } @@ -377,8 +375,8 @@ rh-accordion-header:hover { grid-template-columns: auto 10fr 2fr; grid-template-rows: max-content max-content; grid-template-areas: - "logo primary tertiary" - "logo secondary tertiary"; + 'logo primary tertiary' + 'logo secondary tertiary'; gap: 24px 32px; } diff --git a/elements/rh-health-index/demo/color-context.html b/elements/rh-health-index/demo/color-context.html index 7ec85e1571..313892a21d 100644 --- a/elements/rh-health-index/demo/color-context.html +++ b/elements/rh-health-index/demo/color-context.html @@ -18,7 +18,6 @@

                Default

                E
                F
                -
              1. LG

                A
                @@ -28,7 +27,6 @@

                LG

                E
                F
              2. -
              3. XL

                A
                @@ -48,7 +46,7 @@

                XL

                \ No newline at end of file + } + diff --git a/elements/rh-health-index/docs/00-overview.md b/elements/rh-health-index/docs/00-overview.md index ad34a6f0f5..5da351bb1b 100644 --- a/elements/rh-health-index/docs/00-overview.md +++ b/elements/rh-health-index/docs/00-overview.md @@ -3,7 +3,7 @@ {{ tagName | getElementDescription }} - Four health index components. One is green with letter grade A, one is yellow with letter grade C, one is orange with letter grade D, and one is red with letter grade F. + Four health index components. One is green with letter grade A, one is yellow with letter grade C, one is orange with letter grade D, and one is red with letter grade F. diff --git a/elements/rh-health-index/docs/10-style.md b/elements/rh-health-index/docs/10-style.md index 25fa3d145a..ad00b34ae7 100644 --- a/elements/rh-health-index/docs/10-style.md +++ b/elements/rh-health-index/docs/10-style.md @@ -18,7 +18,7 @@ Health index is a combination of letter grades and severity colors. Severity col
                - Anatomy of 3 health index components. Annotation #1 is pointing to the letter grade and annotation #2 is pointing to the severity level. + Anatomy of 3 health index components. Annotation #1 is pointing to the letter grade and annotation #2 is pointing to the severity level.
                  @@ -34,7 +34,7 @@ Health index is a combination of letter grades and severity colors. Severity col There are four available variants: `Small`, `Default`, `Large`, and `Extra large`. The only difference between the Large and Extra large variants is the size. - 4 columns of health index components. Each column is a different size. Under each column, there is every letter grade and severity color. + 4 columns of health index components. Each column is a different size. Under each column, there is every letter grade and severity color. @@ -45,30 +45,30 @@ Health index is available in both light and dark themes. ### Light theme - Light theme health index component examples. + Light theme health index component examples. - Light theme health index component examples. + Light theme health index component examples. - Light theme health index component examples. + Light theme health index component examples. ### Dark theme - Dark theme health index component examples. + Dark theme health index component examples. - Dark theme health index component examples. + Dark theme health index component examples. - Dark theme health index component examples. + Dark theme health index component examples. @@ -77,7 +77,7 @@ Health index is available in both light and dark themes. Squares in the Default, Large, and Extra large variants are aligned horizontally. - 3 examples of health index component configurations. The small size is just 1 square, so it’s horizontally and vertically centered. The default, large, and extra large sizes are rows of squares, so they’re horizontally centered only. + 3 examples of health index component configurations. The small size is just 1 square, so it’s horizontally and vertically centered. The default, large, and extra large sizes are rows of squares, so they’re horizontally centered only. @@ -86,7 +86,7 @@ Squares in the Default, Large, and Extra large variants are aligned horizontally The spacer in the Default variant is the same for all viewport sizes. - Health index component with a 16px spacer box in between a C letter grade and a row of severity squares. The active severity square is yellow. + Health index component with a 16px spacer box in between a C letter grade and a row of severity squares. The active severity square is yellow. @@ -97,7 +97,7 @@ The spacer in the Default variant is the same for all viewport sizes. Depending on the theme and chosen variant, each severity level can have different colors and font styling. - Multiple light theme health index components at different sizes. Annotations 1 through 4 are pointing to various styling details as well as letter grades that have been enlarged. + Multiple light theme health index components at different sizes. Annotations 1 through 4 are pointing to various styling details as well as letter grades that have been enlarged. @@ -162,7 +162,7 @@ Depending on the theme and chosen variant, each severity level can have differen - Multiple dark theme health index components at different sizes. Annotations 1 through 4 are pointing to various styling details as well as letter grades that have been enlarged.. + Multiple dark theme health index components at different sizes. Annotations 1 through 4 are pointing to various styling details as well as letter grades that have been enlarged.. diff --git a/elements/rh-health-index/docs/20-guidelines.md b/elements/rh-health-index/docs/20-guidelines.md index 84e275984c..687ebe56f6 100644 --- a/elements/rh-health-index/docs/20-guidelines.md +++ b/elements/rh-health-index/docs/20-guidelines.md @@ -20,7 +20,7 @@ There are four available variants: `Small`, `Default`, `Large`, and `Extra large - A row of health index components with emphasis descriptions under each size. Small is low, default is medium, large is high, and extra large is highest. + A row of health index components with emphasis descriptions under each size. Small is low, default is medium, large is high, and extra large is highest. @@ -70,7 +70,7 @@ When health index shows a grade of “A” and the severity level color is green - A 3 by 3 grid of small size health index components. Each row has letter grades A, C, and F. Under each letter grade is text that describes a safe, at risk, or vulnerable state. + A 3 by 3 grid of small size health index components. Each row has letter grades A, C, and F. Under each letter grade is text that describes a safe, at risk, or vulnerable state. @@ -89,7 +89,7 @@ Health index should always be placed near helpful text or other content that exp Health index can be stacked with other content. In such cases, we recommend using the Small variant, as it does not take focus away from surrounding information. - A small size health index component with a letter grade A at the bottom of a stack of text. + A small size health index component with a letter grade A at the bottom of a stack of text. @@ -98,7 +98,7 @@ Health index can be stacked with other content. In such cases, we recommend usin Health index can also be inserted inline with text and components. In such cases, we recommend using the Large or Extra large variants to maintain equal hierarchy among elements. - An extra large size health index component with a letter grade F in between a heading, body text, and a call to action. + An extra large size health index component with a letter grade F in between a heading, body text, and a call to action. @@ -111,14 +111,14 @@ Letter grades and severity level colors are designed to work together. Mixing th
                  - Small, default, and large size health index components displaying correct letter grades and severity colors. + Small, default, and large size health index components displaying correct letter grades and severity colors.

                  Keep letter grades and severity level colors consistent.

                  - Small, default, and large size health index components displaying incorrect letter grades and severity colors. + Small, default, and large size health index components displaying incorrect letter grades and severity colors.

                  Do not mix up letter grades and severity level colors.

                  @@ -132,14 +132,14 @@ Light theme components are designed only to work in the light theme, and dark th
                  - Dark theme small, default, and large size health index components. + Dark theme small, default, and large size health index components.

                  Use the correct components in the correct theme.

                  - Light theme small, default, and large size health index components used incorrectly in the dark theme. + Light theme small, default, and large size health index components used incorrectly in the dark theme.

                  Do not use components from one theme in another theme.

                  @@ -153,14 +153,14 @@ Each variant is unique and designed to meet a specific user need.
                  - Small, default, and large size health index components displaying correct letter grades and severity colors. + Small, default, and large size health index components displaying correct letter grades and severity colors.

                  Use the available variants as intended.

                  - Large size health index component displaying extra text and an incorrect combination of styles. + Large size health index component displaying extra text and an incorrect combination of styles.

                  Do not combine variants or add other elements like text.

                  diff --git a/elements/rh-health-index/rh-health-index.css b/elements/rh-health-index/rh-health-index.css index 5b0fa8fb42..8528649f2f 100644 --- a/elements/rh-health-index/rh-health-index.css +++ b/elements/rh-health-index/rh-health-index.css @@ -11,7 +11,7 @@ align-items: center; width: max-content; font-size: var(--rh-font-size-body-text-md, 1rem); - font-family: var(--rh-font-family-code, RedHatMono, "Red Hat Mono", "Courier New", Courier, monospace); + font-family: var(--rh-font-family-code, RedHatMono, 'Red Hat Mono', 'Courier New', Courier, monospace); line-height: var(--_box-size); text-transform: uppercase; @@ -23,7 +23,7 @@ --_color-text-inactive: var(--rh-color-gray-70, #383838); --_color-text: var(--_color-text-inactive); --_color-fill: var(--rh-color-surface-lightest, #ffffff); - --_color-border: var(--rh-color-border-subtle-on-light, #c7c7c7); + --_color-border: var(--rh-color-border-subtle); } #grade { @@ -118,7 +118,7 @@ :is(.lg, .xl) .box:after { display: block; - content: ""; + content: ''; min-height: var(--rh-length-xs, 4px); z-index: 10; background-color: var(--_color-20); @@ -132,7 +132,7 @@ :is(.lg, .xl) .box.active:before { display: block; - content: ""; + content: ''; inset-inline: -1px; inset-block: -2px; z-index: -1; @@ -198,10 +198,6 @@ * Dark Color Theme *****************************************************************************/ -#container.dark { - --_color-border: var(--rh-color-border-subtle-on-dark, #707070); -} - #container.dark .box { --_color-text-active: var(--rh-color-white, #ffffff); --_color-fill: var(--rh-color-surface-darkest, #151515); @@ -243,7 +239,7 @@ } .dark .e { - --_color-10: var(--rh-color-red-orange-50, #f4784a); + --_color-10: var(--rh-color-red-orange-50, #f0561d); --_color-25: var(--rh-color-red-orange-10, #ffe3d9); --_color-30: var(--rh-color-red-orange-30, #f89b78); } diff --git a/elements/rh-icon/rh-icon.css b/elements/rh-icon/rh-icon.css index 0ec4afabee..44d42ef549 100644 --- a/elements/rh-icon/rh-icon.css +++ b/elements/rh-icon/rh-icon.css @@ -1,12 +1,18 @@ :host { - display: inline-block; line-height: 0; + aspect-ratio: 1/1; + display: inline-flex; + place-content: center; +} + +#container { + display: contents; } svg { width: var(--rh-icon-size, var(--rh-size-icon-01, 16px)); fill: currentcolor; - aspect-ratio: 1; + aspect-ratio: 1/1; } .standard svg { diff --git a/elements/rh-jump-links/docs/00-overview.md b/elements/rh-jump-links/docs/00-overview.md index 1eb534c50c..c903460af1 100644 --- a/elements/rh-jump-links/docs/00-overview.md +++ b/elements/rh-jump-links/docs/00-overview.md @@ -9,6 +9,6 @@ is visible in the browser window. ## Sample element - Jump links sample component + Jump links sample component diff --git a/elements/rh-jump-links/docs/10-style.md b/elements/rh-jump-links/docs/10-style.md index ddf5d2e8d6..1359cd1e20 100644 --- a/elements/rh-jump-links/docs/10-style.md +++ b/elements/rh-jump-links/docs/10-style.md @@ -3,22 +3,22 @@ Jump links are fixed on the page and follow a user as they scroll. It moves them to a section of content when the corresponding link is selected. It looks -visually similar to Open tabs, the only difference is +visually similar to Open tabs, the only difference is the uppercase label on top. - Jump links specs + Jump links specs ### Theme - Jump links theme light + Jump links theme light - Jump links theme dark + Jump links theme dark @@ -43,7 +43,7 @@ how many section links can be included, but no guidelines about how many nested section links can be included. - Jump links nested section + Jump links nested section @@ -53,7 +53,7 @@ A red indicator bar highlights what the active section is. It’s positioned on top of the anchor line, not adjacent. - Jump links active indicator bar + Jump links active indicator bar @@ -72,7 +72,7 @@ wrapped in a disclosure which is collapsed until a user expands the panel.
                  - Jump links on desktop + Jump links on desktop
                  On large screens, jump links are displayed in the layout
                  @@ -82,7 +82,7 @@ wrapped in a disclosure which is collapsed until a user expands the panel.
                  - Jump links on tablet + Jump links on tablet
                  Section links reduce in width as breakpoints get smaller
                  @@ -92,7 +92,7 @@ wrapped in a disclosure which is collapsed until a user expands the panel.
                  - Jump links on mobile + Jump links on mobile
                  On small screens, jump links are wrapped in a collapsed disclosure
                  @@ -101,11 +101,11 @@ wrapped in a disclosure which is collapsed until a user expands the panel. ## Spacing - Jump links spacing on desktop + Jump links spacing on desktop - Jump links spacing on mobile + Jump links spacing on mobile {% spacerTokensTable diff --git a/elements/rh-jump-links/docs/20-guidelines.md b/elements/rh-jump-links/docs/20-guidelines.md index de9c57d2bd..a5b4f10e76 100644 --- a/elements/rh-jump-links/docs/20-guidelines.md +++ b/elements/rh-jump-links/docs/20-guidelines.md @@ -44,7 +44,7 @@ can scroll freely on the right without interruption. Ensure there’s ample space between jump links and the content. - Jump links positioning + Jump links positioning @@ -53,14 +53,14 @@ space between jump links and the content. Jump links should contain at least two section links. - Jump links not enough links issue + Jump links not enough links issue Don’t include section links that are really long, they can be customized to be shorter when added to a group of jump links. - Jump links too long titles + Jump links too long titles @@ -68,14 +68,14 @@ Don’t overload jump links with too many section links, but including lots of nested section links is acceptable. - Jump links too many top level links issue + Jump links too many top level links issue Don’t nest section links within nested section links. - Jump links nesting issue + Jump links nesting issue @@ -109,7 +109,7 @@ use jump links in a mobile layout, so it’s wrapped in a [Disclosure]({{ becomes persistent when a user scrolls past the top edge of the content. - Jump links on mobile + Jump links on mobile @@ -127,7 +127,7 @@ top edge of content. Once jump links come into view and are persistent, the first section link is focused and the tab order becomes top to bottom. - Jump links tab order + Jump links tab order diff --git a/elements/rh-menu/rh-menu.css b/elements/rh-menu/rh-menu.css index d877df03e2..3ce85ab31a 100644 --- a/elements/rh-menu/rh-menu.css +++ b/elements/rh-menu/rh-menu.css @@ -14,17 +14,17 @@ slot { } .dark::slotted(a) { - color: var(--rh-color-interactive-blue-lightest, #b9dafc) !important; + color: var(--rh-color-interactive-primary-hover-on-dark, #b9dafc) !important; } .dark::slotted(a:hover) { - color: var(--rh-color-interactive-blue-lighter, #92c5f9); + color: var(--rh-color-interactive-primary-default-on-dark, #92c5f9); } .dark::slotted(a:visited) { - color: var(--rh-color-interactive-purple-lighter, #b6a6e9) !important; + color: var(--rh-color-interactive-primary-visited-default-on-dark, #b6a6e9) !important; } .dark::slotted(a:visited:hover) { - color: var(--rh-color-interactive-purple-lighter, #b6a6e9) !important; + color: var(--rh-color-interactive-primary-visited-default-on-dark, #b6a6e9) !important; } diff --git a/elements/rh-menu/rh-menu.ts b/elements/rh-menu/rh-menu.ts index c2e038d6eb..138b3e525d 100644 --- a/elements/rh-menu/rh-menu.ts +++ b/elements/rh-menu/rh-menu.ts @@ -34,9 +34,17 @@ export class RhMenu extends LitElement { @colorContextConsumer() private on?: ColorTheme; #tabindex = RovingTabindexController.of(this, { - getItems: () => this._menuItems ?? [], + getItems: () => this.getItems(this._menuItems), }); + /** + * override or set to add items to the roving tab index controller + * @param items original list of items + */ + getItems(items: HTMLElement[]): HTMLElement[] { + return items; + } + get activeItem() { return this.#tabindex.items.at(this.#tabindex.atFocusedItemIndex); } @@ -49,10 +57,10 @@ export class RhMenu extends LitElement { } render() { - const { on = '' } = this; + const { on = 'light' } = this; return html` `; } @@ -64,11 +72,11 @@ export class RhMenu extends LitElement { } activateItem(item: HTMLElement) { - this.#tabindex.atFocusedItemIndex = this._menuItems.indexOf(item); + this.#tabindex.atFocusedItemIndex = this.#tabindex.items.indexOf(item); } focus() { - this._menuItems[this.#tabindex.atFocusedItemIndex]?.focus(); + this.#tabindex.items[this.#tabindex.atFocusedItemIndex]?.focus(); } } diff --git a/elements/rh-navigation-secondary/demo/analytics.html b/elements/rh-navigation-secondary/demo/analytics.html index 0926c18d6c..94944425af 100644 --- a/elements/rh-navigation-secondary/demo/analytics.html +++ b/elements/rh-navigation-secondary/demo/analytics.html @@ -1,6 +1,7 @@ + data-analytics-region="secondary-navigation-Ansible" + accessible-label="ansible"> Red Hat Ansible Automation Platform diff --git a/elements/rh-navigation-secondary/docs/00-overview.md b/elements/rh-navigation-secondary/docs/00-overview.md index 73d627e685..bc8bed9af9 100644 --- a/elements/rh-navigation-secondary/docs/00-overview.md +++ b/elements/rh-navigation-secondary/docs/00-overview.md @@ -7,7 +7,7 @@ ## Sample element - Image of two stacked secondary navigations; one for large breakpoints and the other for small breakpoints + Image of two stacked secondary navigations; one for large breakpoints and the other for small breakpoints ## When to use diff --git a/elements/rh-navigation-secondary/docs/10-style.md b/elements/rh-navigation-secondary/docs/10-style.md index c6f5eb8242..938e0c1926 100644 --- a/elements/rh-navigation-secondary/docs/10-style.md +++ b/elements/rh-navigation-secondary/docs/10-style.md @@ -11,7 +11,7 @@ A secondary navigation is divided into three slots, it is not required to use al - Slot 3 - includes tertiary elements like a call to action (optional) - Image of a gray secondary navigation background with dotted line boxes that say slot 1, slot 2, and slot 3 from left to right + Image of a gray secondary navigation background with dotted line boxes that say slot 1, slot 2, and slot 3 from left to right @@ -50,7 +50,7 @@ Slots are defined areas where content can be inserted, each slot includes a spec On small breakpoints, navigation elements in Slot 2 will collapse into an accordion within a menu. Optional elements in Slot 3 will be placed below the accordion or hidden completely. - Image of four secondary navigations; two large ones and two small ones with dotted line boxes around each slot and labels that say slot 1, slot 2, and slot 3 + Image of four secondary navigations; two large ones and two small ones with dotted line boxes around each slot and labels that say slot 1, slot 2, and slot 3 ### Using the expandable menu @@ -88,7 +88,7 @@ A secondary navigation is available in both light and dark themes. The light the The light theme secondary navigation should be used in environments with a lighter look and feel. The box shadow is always visible unless covered by an expanded menu. - Image of a light theme secondary navigation + Image of a light theme secondary navigation @@ -122,7 +122,7 @@ The light theme secondary navigation should be used in environments with a light The dark theme secondary navigation should be used in environments with a darker look and feel. The gray bottom border is always visible unless covered by an expanded menu. - Image of a dark theme secondary navigation + Image of a dark theme secondary navigation @@ -156,7 +156,7 @@ The dark theme secondary navigation should be used in environments with a darker A secondary navigation spans the entire width of a browser window on all breakpoints. It has a fixed height of 86px on large breakpoints and a fixed height of 80px on small breakpoints even if Slot 1 text is only one line. Content in all slots is horizontally centered with the background. - Image of a secondary navigation construction; several examples showing details like spacing, alignment, height, width, and more + Image of a secondary navigation construction; several examples showing details like spacing, alignment, height, width, and more ### Expandable menu styles @@ -164,7 +164,7 @@ A secondary navigation spans the entire width of a browser window on all breakpo An expandable menu includes content like text, links, calls to action, and more. The menu tab, panel, and backdrop have the same styles on all breakpoints. - Image of two stacked secondary navigations with menus expanded; one for large breakpoints and the other for small breakpoints + Image of two stacked secondary navigations with menus expanded; one for large breakpoints and the other for small breakpoints ### Slot text labels @@ -173,11 +173,11 @@ Slot 1 and Slot 2 text elements have specific styles applied to them.

                  Helpful Tip

                  -

                  Slot 3 usually includes a Call to action. To see Call to action styles, visit the Call to action page.

                  +

                  Slot 3 usually includes a Call to action. To see Call to action styles, visit the Call to action page.

                  - Image of four stacked secondary navigations; two are light theme and two are dark theme, both with dotted line boxes and labels that say slot 1 and slot 2 + Image of four stacked secondary navigations; two are light theme and two are dark theme, both with dotted line boxes and labels that say slot 1 and slot 2 @@ -247,14 +247,14 @@ The amount of space in a secondary navigation remains about the same on all brea ### Large breakpoints - Image of secondary navigation spacing values on large breakpoints + Image of secondary navigation spacing values on large breakpoints ### Small breakpoints - Image of secondary navigation spacing values on small breakpoints + Image of secondary navigation spacing values on small breakpoints @@ -274,11 +274,11 @@ Interaction states are visual representations used to communicate the status of ### Hover - Image of light theme secondary navigation hover states + Image of light theme secondary navigation hover states - Image of dark theme secondary navigation hover states + Image of dark theme secondary navigation hover states @@ -331,11 +331,11 @@ Interaction states are visual representations used to communicate the status of - Image of light theme secondary navigation focus states + Image of light theme secondary navigation focus states - Image of dark theme secondary navigation focus states + Image of dark theme secondary navigation focus states @@ -366,11 +366,11 @@ Interaction states are visual representations used to communicate the status of - Image of light theme secondary navigation active states + Image of light theme secondary navigation active states - Image of dark theme secondary navigation active states + Image of dark theme secondary navigation active states diff --git a/elements/rh-navigation-secondary/docs/20-guidelines.md b/elements/rh-navigation-secondary/docs/20-guidelines.md index 5907a60ebf..5609cd6b9c 100644 --- a/elements/rh-navigation-secondary/docs/20-guidelines.md +++ b/elements/rh-navigation-secondary/docs/20-guidelines.md @@ -12,7 +12,7 @@ A secondary navigation offers a way to propagate content that relates to a speci The [primary navigation](../../navigation-primary) includes links to the most important pages across a domain. If content related to a specific topic needs to be organized somewhere, it should be added to a secondary navigation instead. This hierarchy can be demonstrated visually by the primary navigation being on top of a secondary navigation when a page loads. - Image of a primary navigation stacked on top of a secondary navigation + Image of a primary navigation stacked on top of a secondary navigation @@ -26,7 +26,7 @@ If a secondary navigation is used on a product page, Slot 1 should display the p - If product name text is short and there are fewer links and menus, it can remain on one line - Image of four secondary navigations showing how stacked product name text offers more space + Image of four secondary navigations showing how stacked product name text offers more space @@ -40,7 +40,7 @@ Slot 2 includes inline links, menus, and sometimes external links. The order of - Text will expand when translated to some languages - Image of two secondary navigations comparing an acceptable amount of links and menus + Image of two secondary navigations comparing an acceptable amount of links and menus @@ -54,7 +54,7 @@ Slot 3 is optional, but it can include interactive elements like a call to actio - Text will expand when translated to some languages - Image of two secondary navigations comparing the character counts of a call to action + Image of two secondary navigations comparing the character counts of a call to action @@ -101,13 +101,13 @@ Use the expandable menu to organize content in columns. - Image of a secondary navigation with four columns of links + Image of a secondary navigation with four columns of links If content is organized in two columns, they will stretch to fill the empty space. - Image of a secondary navigation with two columns of links + Image of a secondary navigation with two columns of links @@ -129,7 +129,7 @@ The expandable menu includes content like text, links, calls to action, and more When a user is viewing a page that is part of the secondary navigation information architecture, a red top border is visible. In the example below, a user is viewing both the *Overview* page and a page within the *Product variants* menu. External links do not display the red top border (except on hover) because they open links in a new tab or window instead. - Image of two secondary navigations with red bars on top of different menus + Image of two secondary navigations with red bars on top of different menus @@ -138,7 +138,7 @@ When a user is viewing a page that is part of the secondary navigation informati A secondary navigation is positioned below the primary navigation when the page loads. When a user scrolls down, the primary navigation disappears and the secondary navigation becomes fixed to the top of the browser window. When a user scrolls back up to the top, the secondary navigation is positioned under the primary navigation again. - Image of primary and secondary navigations and their behaviors when scrolling + Image of primary and secondary navigations and their behaviors when scrolling ### Navigating between menus @@ -151,7 +151,7 @@ Only one menu can be expanded at a time and there is no animation when navigatin - Image of three secondary navigations with different menus selected + Image of three secondary navigations with different menus selected @@ -160,13 +160,13 @@ Only one menu can be expanded at a time and there is no animation when navigatin If the height of the menu is **shorter** than the viewport height, content should scroll underneath the backdrop. - Image of secondary navigation showing the scrolling behavior when the menu panel is shorter than the viewport height + Image of secondary navigation showing the scrolling behavior when the menu panel is shorter than the viewport height If the height of the menu is **taller** than the viewport height, scroll is trapped within the panel until the menu is collapsed. - Image of secondary navigation showing the scrolling behavior when the menu panel is taller than the viewport height + Image of secondary navigation showing the scrolling behavior when the menu panel is taller than the viewport height @@ -178,14 +178,14 @@ As breakpoints get smaller, Slot 2 will collapse into an accordion within a menu ### Slot 2 visible - Image of secondary navigations; one has a menu collapsed and the other has a menu expanded, but both have slot 2 visible on large breakpoints + Image of secondary navigations; one has a menu collapsed and the other has a menu expanded, but both have slot 2 visible on large breakpoints ### Slot 2 hidden - Image of secondary navigations; slot 2 on small breakpoints is not visible unless the menu is expanded + Image of secondary navigations; slot 2 on small breakpoints is not visible unless the menu is expanded @@ -256,7 +256,7 @@ As breakpoints get smaller, Slot 2 will collapse into an accordion within a menu Do not position the secondary navigation above the primary navigation. - Image of a secondary navigation on top of a primary navigation which is incorrect usage + Image of a secondary navigation on top of a primary navigation which is incorrect usage @@ -265,7 +265,7 @@ Do not position the secondary navigation above the primary navigation. Do not use a dark theme secondary navigation in light environments and vice versa. - Image of a dark theme secondary navigation in a light theme environment which is incorrect usage + Image of a dark theme secondary navigation in a light theme environment which is incorrect usage @@ -274,7 +274,7 @@ Do not use a dark theme secondary navigation in light environments and vice vers Do not use too many links or menus in Slot 2. - Image of a secondary navigation with way more than five links and menus which is incorrect usage + Image of a secondary navigation with way more than five links and menus which is incorrect usage @@ -283,7 +283,7 @@ Do not use too many links or menus in Slot 2. Do not add more slots than provided, three is the maximum. - Image of a secondary navigation with four dotted line boxes for slots which is incorrect usage + Image of a secondary navigation with four dotted line boxes for slots which is incorrect usage @@ -292,7 +292,7 @@ Do not add more slots than provided, three is the maximum. Slot 1 text should never break to three lines. - Image of a secondary navigation, but the product name logo in slot 1 is three lines which is incorrect usage + Image of a secondary navigation, but the product name logo in slot 1 is three lines which is incorrect usage @@ -301,5 +301,5 @@ Slot 1 text should never break to three lines. At least one link or menu in Slot 2 must be visible. - Image of a secondary navigation with no links or menus in slot 2 which is incorrect usage + Image of a secondary navigation with no links or menus in slot 2 which is incorrect usage diff --git a/elements/rh-navigation-secondary/docs/30-code.md b/elements/rh-navigation-secondary/docs/30-code.md index 82fc7cff61..619cc31c56 100644 --- a/elements/rh-navigation-secondary/docs/30-code.md +++ b/elements/rh-navigation-secondary/docs/30-code.md @@ -1,5 +1,7 @@ {% renderInstall lightdomcss=true%}{% endrenderInstall %} +{% renderLightDom %}{% endrenderLightDom %} + ### System Integration #### Current page indicator diff --git a/elements/rh-navigation-secondary/docs/40-accessibility.md b/elements/rh-navigation-secondary/docs/40-accessibility.md index aea7018d12..a92df85325 100644 --- a/elements/rh-navigation-secondary/docs/40-accessibility.md +++ b/elements/rh-navigation-secondary/docs/40-accessibility.md @@ -5,7 +5,7 @@ All elements within a secondary navigation are focus stops. Pressing Enter when a menu has focus will expand or collapse it. Otherwise, users will be directed to a new page. If the height of the menu is taller than the viewport height due to lots of content, focus is trapped within the panel until the menu is collapsed. - Image of secondary navigations with diagrams of what happens when Tab or Enter keys are pressed + Image of secondary navigations with diagrams of what happens when Tab or Enter keys are pressed ### Keyboard events diff --git a/elements/rh-navigation-secondary/rh-navigation-secondary-dropdown.css b/elements/rh-navigation-secondary/rh-navigation-secondary-dropdown.css index 600b5d4d77..5a6d7a8d9c 100644 --- a/elements/rh-navigation-secondary/rh-navigation-secondary-dropdown.css +++ b/elements/rh-navigation-secondary/rh-navigation-secondary-dropdown.css @@ -15,23 +15,23 @@ box-shadow: var(--rh-box-shadow-sm, 0 2px 4px 0 rgba(21, 21, 21, 0.2)); } -::slotted([slot="link"]) { - --_chevron-color: var(--_context-text); +::slotted([slot='link']) { + --_chevron-color: var(--rh-color-text-primary); justify-content: space-between; position: relative; gap: calc(var(--rh-font-size-body-text-md, 1rem) / 2); - background-color: var(--_context-background-color); + background-color: var(--rh-color-surface); } -#container.highlight ::slotted([slot="link"]), -::slotted([slot="link"][aria-current="page"]) { +#container.highlight ::slotted([slot='link']), +::slotted([slot='link'][aria-current='page']) { border-block-start-color: var(--_current-active-child-border-color, #ee0000) !important; } -::slotted([slot="link"]):after { +::slotted([slot='link']):after { box-sizing: content-box !important; - content: ""; + content: ''; display: block; width: var(--_chevron-size); height: var(--_chevron-size); @@ -40,7 +40,7 @@ transform: var(--_chevron-transform-collapsed); } -#container.expanded ::slotted([slot="link"]):after { +#container.expanded ::slotted([slot='link']):after { transform: var(--_chevron-transform-expanded); } @@ -54,12 +54,12 @@ box-shadow: none; } - ::slotted([slot="link"][aria-expanded="true"]) { + ::slotted([slot='link'][aria-expanded='true']) { border-block-start-color: var(--rh-color-text-brand-on-light, #ee0000); background: var(--rh-color-surface-lightest, #ffffff) !important; } - ::slotted([slot="link"][aria-expanded="true"]):after { + ::slotted([slot='link'][aria-expanded='true']):after { --_chevron-color: var(--rh-color-text-primary-on-light, #151515) !important; } } diff --git a/elements/rh-navigation-secondary/rh-navigation-secondary-lightdom.css b/elements/rh-navigation-secondary/rh-navigation-secondary-lightdom.css index 097328e7ad..2b1903b745 100644 --- a/elements/rh-navigation-secondary/rh-navigation-secondary-lightdom.css +++ b/elements/rh-navigation-secondary/rh-navigation-secondary-lightdom.css @@ -13,7 +13,7 @@ rh-navigation-secondary { box-shadow: var(--rh-box-shadow-sm, 0 2px 4px 0 rgba(21, 21, 21, 0.2)); height: var(--_max-height); min-height: var(--_min-height); - 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-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); } rh-navigation-secondary:not(:defined) { @@ -23,12 +23,12 @@ rh-navigation-secondary:not(:defined) { grid-template-rows: minmax(var(--_min-height), var(--_max-height)) max-content max-content; grid-template-columns: 1fr max-content; grid-template-areas: - "logo logo" - "nav nav" - "cta cta"; + 'logo logo' + 'nav nav' + 'cta cta'; } -rh-navigation-secondary[color-palette="dark"] { +rh-navigation-secondary[color-palette='dark'] { --_nav-link-color: var(--rh-color-text-primary-on-light, #151515); --_logo-link-color: var(--rh-color-text-primary-on-dark, #ffffff); @@ -43,14 +43,14 @@ rh-navigation-secondary * { rh-navigation-secondary-menu a { text-decoration: underline !important; - color: var(--rh-color-interactive-blue-darker, #0066cc); + color: var(--rh-color-interactive-primary-default-on-light, #0066cc); } rh-navigation-secondary-menu a:hover { - color: var(--rh-color-interactive-blue-darkest, #003366) !important; + color: var(--rh-color-interactive-primary-hover-on-light, #003366) !important; } -rh-navigation-secondary > [slot="logo"] { +rh-navigation-secondary > [slot='logo'] { grid-area: logo; display: flex; align-items: center; @@ -64,27 +64,27 @@ rh-navigation-secondary > [slot="logo"] { font-size: var(--rh-font-size-body-text-md, 1rem); letter-spacing: 0.01125em; margin-inline-start: var(--rh-space-lg, 16px); - 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", Helvetica, Arial, sans-serif); + 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', Helvetica, Arial, sans-serif); font-weight: var(--rh-font-weight-heading-medium, 500); padding-block: var(--rh-space-lg, 16px); border-block-start: var(--rh-border-width-lg, 3px) solid transparent; width: max-content; } -rh-navigation-secondary > [slot="logo"][aria-current="page"] { +rh-navigation-secondary > [slot='logo'][aria-current='page'] { border-block-start-color: var(--rh-color-brand-red-on-light, #ee0000); } -rh-navigation-secondary > [slot="logo"]:hover { +rh-navigation-secondary > [slot='logo']:hover { text-decoration: none; color: var(--_nav-link-color); } -rh-navigation-secondary[color-palette="dark"] > [slot="logo"]:hover { +rh-navigation-secondary[color-palette='dark'] > [slot='logo']:hover { color: var(--_logo-link-color); } -rh-navigation-secondary > [slot="nav"] { +rh-navigation-secondary > [slot='nav'] { grid-area: nav; display: none; flex-direction: column; @@ -97,12 +97,12 @@ rh-navigation-secondary > [slot="nav"] { var(--rh-space-lg, 16px); } -rh-navigation-secondary > [slot="logo"], -rh-navigation-secondary > [slot="nav"] { +rh-navigation-secondary > [slot='logo'], +rh-navigation-secondary > [slot='nav'] { line-height: var(--rh-line-height-heading, 1.3); } -rh-navigation-secondary > [slot="cta"] { +rh-navigation-secondary > [slot='cta'] { grid-area: cta; display: none; height: 100%; @@ -117,8 +117,8 @@ rh-navigation-secondary > [slot="cta"] { } /* If the component isn't defined display top level links */ -rh-navigation-secondary:not(:defined) > [slot="nav"], -rh-navigation-secondary:not(:defined) > [slot="cta"] { +rh-navigation-secondary:not(:defined) > [slot='nav'], +rh-navigation-secondary:not(:defined) > [slot='cta'] { display: flex; } @@ -132,7 +132,7 @@ rh-navigation-secondary-menu:not(:defined) { } /* Top level links, styles are owned by lightdom elements */ -rh-navigation-secondary > [slot="nav"] > li > a, +rh-navigation-secondary > [slot='nav'] > li > a, rh-navigation-secondary-dropdown > a { display: flex; align-items: center; @@ -146,53 +146,53 @@ rh-navigation-secondary-dropdown > a { border-block-start: var(--rh-border-width-lg, 3px) solid transparent; } -rh-navigation-secondary [slot="nav"] > li > a[aria-current="page"] { +rh-navigation-secondary [slot='nav'] > li > a[aria-current='page'] { border-block-start-color: var(--rh-color-brand-red-on-light, #ee0000); } -rh-navigation-secondary[color-palette="dark"] [slot="nav"] li > a[aria-current="page"] { +rh-navigation-secondary[color-palette='dark'] [slot='nav'] li > a[aria-current='page'] { border-block-start-color: var(--rh-color-brand-red-on-dark, #ee0000); } -rh-navigation-secondary > [slot="nav"] > li > a:hover, +rh-navigation-secondary > [slot='nav'] > li > a:hover, rh-navigation-secondary-dropdown > a:hover { text-decoration: none !important; color: var(--_nav-link-color) !important; } -rh-navigation-secondary > [slot="nav"] > li > a:focus, +rh-navigation-secondary > [slot='nav'] > li > a:focus, rh-navigation-secondary-dropdown > a:focus { position: relative; z-index: 1; } -rh-navigation-secondary > [slot="nav"] > li { +rh-navigation-secondary > [slot='nav'] > li { border-block-start: var(--rh-border-width-sm, 1px) solid var(--rh-color-border-subtle-on-light, #c7c7c7); } -rh-navigation-secondary > [slot="nav"] > li:last-of-type { +rh-navigation-secondary > [slot='nav'] > li:last-of-type { border-block-end: var(--rh-border-width-sm, 1px) solid var(--rh-color-border-subtle-on-light, #c7c7c7); } -rh-navigation-secondary > [slot="nav"] a[aria-expanded="false"], -rh-navigation-secondary > [slot="nav"] > [slot="nav"] > li > a { +rh-navigation-secondary > [slot='nav'] a[aria-expanded='false'], +rh-navigation-secondary > [slot='nav'] > [slot='nav'] > li > a { color: var(--_nav-link-color); } -rh-navigation-secondary-menu-section > [slot="header"] { +rh-navigation-secondary-menu-section > [slot='header'] { font-size: var(--rh-font-size-body-text-md, 1rem); font-weight: 500; margin: 0 0 var(--rh-space-lg, 16px); } @media screen and (min-width: 768px) { - rh-navigation-secondary > [slot="logo"] { + rh-navigation-secondary > [slot='logo'] { margin-inline-start: var(--rh-space-2xl, 32px); } } @@ -204,34 +204,34 @@ rh-navigation-secondary-menu-section > [slot="header"] { rh-navigation-secondary:not(:defined) { display: grid; - grid-template-areas: "logo nav cta"; + grid-template-areas: 'logo nav cta'; grid-template-rows: minmax(var(--_min-height), var(--_max-height)) max-content max-content; grid-template-columns: max-content 1fr max-content; } - rh-navigation-secondary[color-palette="dark"] { + rh-navigation-secondary[color-palette='dark'] { --_nav-link-color: var(--rh-color-text-primary-on-dark, #ffffff); --_nav-chevron-color: var(--rh-color-text-primary-on-dark, #ffffff); } /* stylelint-disable-next-line @stylistic/max-line-length */ - rh-navigation-secondary[color-palette="dark"] rh-navigation-secondary-dropdown > a[aria-expanded="true"] { + rh-navigation-secondary[color-palette='dark'] rh-navigation-secondary-dropdown > a[aria-expanded='true'] { --_nav-link-color: var(--rh-color-text-primary-on-light, #151515); --_nav-chevron-color: var(--rh-color-text-primary-on-light, #151515); color: var(--_nav-link-color); } - rh-navigation-secondary > [slot="logo"] { + rh-navigation-secondary > [slot='logo'] { font-size: var(--rh-font-size-body-text-lg, 1.125rem); margin-inline-start: 2rem; } - rh-navigation-secondary > [slot="mobile-menu"] { + rh-navigation-secondary > [slot='mobile-menu'] { display: none; } - rh-navigation-secondary > [slot="nav"] { + rh-navigation-secondary > [slot='nav'] { grid-area: nav; display: flex; flex-direction: row; @@ -243,11 +243,11 @@ rh-navigation-secondary-menu-section > [slot="header"] { background-color: transparent; } - rh-navigation-secondary > [slot="nav"] > li { + rh-navigation-secondary > [slot='nav'] > li { border-block-start-width: 0; } - rh-navigation-secondary > [slot="nav"] > li:last-of-type { + rh-navigation-secondary > [slot='nav'] > li:last-of-type { border-bottom-width: 0; } @@ -256,22 +256,22 @@ rh-navigation-secondary-menu-section > [slot="header"] { height: 100%; } - rh-navigation-secondary > [slot="nav"] > li > a, + rh-navigation-secondary > [slot='nav'] > li > a, rh-navigation-secondary-dropdown > a { height: 100%; font-weight: 400; padding: 0 var(--rh-space-lg, 16px); } - rh-navigation-secondary > [slot="nav"] > li > a:focus, - rh-navigation-secondary > [slot="nav"] > li > a:hover, - rh-navigation-secondary-dropdown > a[aria-expanded="true"], + rh-navigation-secondary > [slot='nav'] > li > a:focus, + rh-navigation-secondary > [slot='nav'] > li > a:hover, + rh-navigation-secondary-dropdown > a[aria-expanded='true'], rh-navigation-secondary-dropdown > a:focus, rh-navigation-secondary-dropdown > a:hover { border-block-start-color: var(--rh-color-text-brand-on-light, #ee0000); } - rh-navigation-secondary > [slot="cta"] { + rh-navigation-secondary > [slot='cta'] { display: flex; flex-direction: row-reverse; background-color: transparent; @@ -280,13 +280,13 @@ rh-navigation-secondary-menu-section > [slot="header"] { } @media screen and (min-width: 1440px) { - rh-navigation-secondary:not(:defined) > [slot="logo"], - rh-navigation-secondary > [slot="logo"] { + rh-navigation-secondary:not(:defined) > [slot='logo'], + rh-navigation-secondary > [slot='logo'] { margin-inline-start: var(--rh-space-4xl, 64px); } - rh-navigation-secondary:not(:defined) > [slot="cta"], - rh-navigation-secondary > [slot="cta"] { + rh-navigation-secondary:not(:defined) > [slot='cta'], + rh-navigation-secondary > [slot='cta'] { margin-inline-end: var(--rh-space-4xl, 64px); } } diff --git a/elements/rh-navigation-secondary/rh-navigation-secondary-menu-section.css b/elements/rh-navigation-secondary/rh-navigation-secondary-menu-section.css index a88d4349de..730ea6c217 100644 --- a/elements/rh-navigation-secondary/rh-navigation-secondary-menu-section.css +++ b/elements/rh-navigation-secondary/rh-navigation-secondary-menu-section.css @@ -2,15 +2,15 @@ display: block; } -::slotted([slot="header"]) { +::slotted([slot='header']) { padding: 0; } ::slotted(:is(h1,h2,h3,h4,h5,h6)) { - 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", Helvetica, Arial, sans-serif); + 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', Helvetica, Arial, sans-serif); } -::slotted([slot="links"]:is(ul, ol)) { +::slotted([slot='links']:is(ul, ol)) { list-style: none; margin: 0; padding: 0; @@ -19,20 +19,20 @@ gap: var(--rh-font-size-body-text-md, 1rem); } -::slotted([slot="cta"]) { +::slotted([slot='cta']) { padding: var(--rh-space-xl, 24px) 0 0; } -::slotted([slot="cta"]:last-of-type) { +::slotted([slot='cta']:last-of-type) { padding: var(--rh-space-xl, 24px) 0; } @media screen and (min-width: 992px) { - ::slotted([slot="header"]) { + ::slotted([slot='header']) { padding: 0; } - ::slotted([slot="links"]) { + ::slotted([slot='links']) { padding: 0; margin: 0; } diff --git a/elements/rh-navigation-secondary/rh-navigation-secondary-menu.css b/elements/rh-navigation-secondary/rh-navigation-secondary-menu.css index ca357c6397..05a166c475 100644 --- a/elements/rh-navigation-secondary/rh-navigation-secondary-menu.css +++ b/elements/rh-navigation-secondary/rh-navigation-secondary-menu.css @@ -16,16 +16,12 @@ padding: var(--rh-space-xl, 24px); } -:host(:not([type="fixed-width"])) #sections { +:host(:not([type='fixed-width'])) #sections { display: grid; grid-template-columns: - var( - --rh-navigation-secondary-menu-section-grid, - repeat( - auto-fit, - minmax(15.5rem, 1fr) - ) - ); + var(--rh-navigation-secondary-menu-section-grid, + repeat(auto-fit, + minmax(15.5rem, 1fr))); grid-template-rows: auto; gap: var(--rh-navigation-secondary-menu-section-grid-gap, var(--rh-space-2xl, 32px)); } @@ -54,7 +50,7 @@ overflow-y: scroll; } - :host([layout="fixed-width"]) #container { + :host([layout='fixed-width']) #container { position: absolute; inset: var(--_nav-height) auto auto auto; margin-top: 0; @@ -67,7 +63,7 @@ margin: auto; } - :host([layout="fixed-width"]) #sections { + :host([layout='fixed-width']) #sections { padding: var(--rh-space-2xl, 32px); } } diff --git a/elements/rh-navigation-secondary/rh-navigation-secondary.css b/elements/rh-navigation-secondary/rh-navigation-secondary.css index 1ea7dcd81c..bdb20b2e30 100644 --- a/elements/rh-navigation-secondary/rh-navigation-secondary.css +++ b/elements/rh-navigation-secondary/rh-navigation-secondary.css @@ -5,14 +5,14 @@ --_chevron-down: -135deg; --_chevron-correction-x: calc(-1 * var(--rh-font-size-body-text-md, 1rem) / 16); --_chevron-correction-y: calc(-1 * var(--rh-font-size-body-text-md, 1rem) / 16); - --_chevron-color: var(--_context-text); + --_chevron-color: var(--rh-color-text-primary); --_chevron-transform-collapsed: rotate(var(--_chevron-up)) translate(var(--_chevron-correction-x), var(--_chevron-correction-x)); --_chevron-transform-expanded: rotate(var(--_chevron-down)) translate(var(--_chevron-correction-y), var(--_chevron-correction-y)); - --_button-font-color: var(--_context-text); + --_button-font-color: var(--rh-color-text-primary); --_nav-max-height: var(--_max-height, max-content); --_nav-min-height: var(--_min-height, 80px); --_current-active-child-border-color: var(--rh-color-brand-red-on-light, #ee0000); @@ -21,7 +21,7 @@ z-index: var(--rh-navigation-secondary-z-index, 102); } -:host([color-palette="dark"]) { +:host([color-palette='dark']) { --_current-active-child-border-color: var(--rh-color-brand-red-on-dark, #ee0000); --_border-color: var(--rh-color-border-subtle-on-dark, #707070); } @@ -44,7 +44,7 @@ nav.rtl { position: absolute; width: 100%; z-index: var(--rh-navigation-secondary-z-index, 102); - background-color: var(--_context-background-color); + background-color: var(--rh-color-surface); gap: 0 var(--rh-space-lg, 16px); grid-template-rows: minmax(var(--_nav-min-height), var(--_nav-max-height)) @@ -52,8 +52,8 @@ nav.rtl { max-content; grid-template-columns: 1fr max-content; grid-template-areas: - "logo menu" - "main main"; + 'logo menu' + 'main main'; height: fit-content; min-height: 100%; max-height: 100vh; @@ -69,17 +69,17 @@ rh-surface { width: 100%; } -::slotted([slot="nav"]), -::slotted([slot="cta"]) { +::slotted([slot='nav']), +::slotted([slot='cta']) { grid-area: unset !important; } -#container.expanded ::slotted([slot="nav"]), -#container.expanded ::slotted([slot="cta"]) { +#container.expanded ::slotted([slot='nav']), +#container.expanded ::slotted([slot='cta']) { display: flex !important; } -#container.expanded ::slotted([slot="nav"]) { +#container.expanded ::slotted([slot='nav']) { list-style: none; flex-direction: column; padding: 2rem 1rem 0; @@ -91,7 +91,7 @@ rh-surface { margin: 0 !important; } -#container.expanded ::slotted([slot="cta"]) { +#container.expanded ::slotted([slot='cta']) { padding: 2rem 1rem; } @@ -101,7 +101,7 @@ button { display: flex; height: 100%; align-items: center; - 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-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); padding: var(--rh-space-lg, 16px); border-block-start: var(--rh-border-width-lg, 3px) solid transparent; @@ -117,7 +117,7 @@ button:hover { button:after { box-sizing: content-box !important; - content: ""; + content: ''; display: block; width: var(--_chevron-size); height: var(--_chevron-size); @@ -126,7 +126,7 @@ button:after { transform: var(--_chevron-transform-collapsed); } -button[aria-expanded="true"]:after { +button[aria-expanded='true']:after { transform: var(--_chevron-transform-expanded); } @@ -134,13 +134,13 @@ button:focus { border-block-start-color: var(--rh-color-text-brand-on-light, #ee0000); } -:host([color-palette="dark"]) button { - background-color: var(--_context-background-color); +:host([color-palette='dark']) button { + background-color: var(--rh-color-surface); } button:active, -button[aria-expanded="true"], -:host([color-palette="dark"]) button[aria-expanded="true"] { +button[aria-expanded='true'], +:host([color-palette='dark']) button[aria-expanded='true'] { --_chevron-color: var(--rh-color-text-primary-on-light, #151515); color: var(--rh-color-text-primary-on-light, #151515); @@ -149,11 +149,11 @@ button[aria-expanded="true"], border-block-end: none; } -:host([color-palette="dark"]) button:active { +:host([color-palette='dark']) button:active { color: var(--rh-color-text-primary-on-dark, #ffffff); } -:host([color-palette="dark"]) button[aria-expanded="true"]:active { +:host([color-palette='dark']) button[aria-expanded='true']:active { color: var(--rh-color-text-primary-on-light, #151515); } @@ -162,14 +162,14 @@ button[aria-expanded="true"], margin-inline-end: var(--rh-space-2xl, 32px); } - #container.expanded ::slotted([slot="nav"]) { + #container.expanded ::slotted([slot='nav']) { padding: var(--rh-space-2xl, 32px) var(--rh-space-2xl, 32px) 0 !important; } - #container.expanded ::slotted([slot="cta"]) { + #container.expanded ::slotted([slot='cta']) { padding: var(--rh-space-2xl, 32px) !important; } } @@ -180,7 +180,7 @@ button[aria-expanded="true"], } #container { - grid-template-areas: "logo main"; + grid-template-areas: 'logo main'; grid-template-rows: auto; grid-template-columns: max-content 1fr; height: 100%; @@ -193,7 +193,7 @@ button[aria-expanded="true"], justify-content: space-between; } - #container.expanded ::slotted([slot="nav"]) { + #container.expanded ::slotted([slot='nav']) { max-height: calc(100vh - var(--_nav-min-height)); } diff --git a/elements/rh-navigation-secondary/rh-navigation-secondary.ts b/elements/rh-navigation-secondary/rh-navigation-secondary.ts index 12fd09552e..c2909f0f52 100644 --- a/elements/rh-navigation-secondary/rh-navigation-secondary.ts +++ b/elements/rh-navigation-secondary/rh-navigation-secondary.ts @@ -6,7 +6,6 @@ import { state } from 'lit/decorators/state.js'; import { queryAssignedElements } from 'lit/decorators/query-assigned-elements.js'; import { ComposedEvent } from '@patternfly/pfe-core'; -import { RovingTabindexController } from '@patternfly/pfe-core/controllers/roving-tabindex-controller.js'; import { InternalsController } from '@patternfly/pfe-core/controllers/internals-controller.js'; import { Logger } from '@patternfly/pfe-core/controllers/logger.js'; @@ -94,16 +93,6 @@ export class RhNavigationSecondary extends LitElement { /** Compact mode */ #compact = false; - get #items() { - return this._nav?.flatMap(slotted => - Array.from(slotted.querySelectorAll(`rh-navigation-secondary-dropdown > a, - [slot="nav"] > li > a`))) ?? []; - } - - #tabindex = RovingTabindexController.of(this, { - getItems: () => this.#items, - }); - #internals = InternalsController.of(this, { role: 'navigation' }); /** @@ -114,6 +103,11 @@ export class RhNavigationSecondary extends LitElement { @queryAssignedElements({ slot: 'nav' }) private _nav?: HTMLElement[]; + /** + * Customize the default `aria-label` on the `
                - Popover component, white variant + Popover component, white variant

                With heading

                Use for messages that require a heading.

                - Popover component, with heading variant + Popover component, with heading variant
                @@ -65,7 +65,7 @@ on the content and color of the background.

                Use for messages that do not require a heading.

              - Popover component, without heading variant + Popover component, without heading variant
              @@ -74,7 +74,7 @@ on the content and color of the background.

              A drop shadow gives a popover subtle elevation above light backgrounds.

            - Popover component, with drop shadow variant + Popover component, with drop shadow variant
            @@ -83,7 +83,7 @@ on the content and color of the background.

            A drop shadow cannot be seen on dark backgrounds, so it is not included.

          - Popover component, without drop shadow variant + Popover component, without drop shadow variant
          @@ -91,7 +91,7 @@ on the content and color of the background. ## Theme -For popovers and [tooltips]({{ '/elements/tooltip' | url }}), +For popovers and [tooltips](/elements/tooltip), the themes are inverted. For example, light theme popovers are **black* and should be used on light backgrounds; dark theme popovers are **white** and should be used on dark backgrounds. @@ -99,14 +99,14 @@ should be used on dark backgrounds. ### Black (light backgrounds) - Popover component, light theme + Popover component, light theme ### White (dark backgrounds) - Popover component, dark theme + Popover component, dark theme @@ -118,14 +118,14 @@ screens. ### Large screens - Popover component responsive design, large screens + Popover component responsive design, large screens ### Small screens - Popover component responsive design, small screens + Popover component responsive design, small screens @@ -134,7 +134,7 @@ screens. Each popover orientation contains the same amount of spacing in between the component and icon. - Popover component spacing + Popover component spacing diff --git a/elements/rh-popover/docs/20-guidelines.md b/elements/rh-popover/docs/20-guidelines.md index 04d85b3703..2b7236806a 100644 --- a/elements/rh-popover/docs/20-guidelines.md +++ b/elements/rh-popover/docs/20-guidelines.md @@ -43,7 +43,7 @@ well. - Popover component usage, content + Popover component usage, content @@ -96,7 +96,7 @@ content or is cut off by the edge of the screen when triggered, change the orientation. - Popover component usage, orientation + Popover component usage, orientation @@ -106,7 +106,7 @@ Avoid using a black popover on dark backgrounds, it will completely disappear into the background. - Popover component usage, black on black + Popover component usage, black on black @@ -116,7 +116,7 @@ Avoid using a white popover on light backgrounds, there is not enough contrast even with the subtle drop shadow. - Popover component usage, white on white + Popover component usage, white on white @@ -130,7 +130,7 @@ a popover, a user must select the close button, make a selection outside of the popover, or press the **Escape (esc)** key. - Popover component behavior, trigger + Popover component behavior, trigger @@ -141,7 +141,7 @@ trigger. However, an icon is not the only visual element that can trigger a popover. - Popover component behavior, form + Popover component behavior, form @@ -151,7 +151,7 @@ A popover and tooltip are triggered the same way on mobile, by a tap, but still have different use cases (see **Usage**). - Popover component behavior, mobile + Popover component behavior, mobile @@ -163,13 +163,13 @@ Both popover variants have interaction states.

          Default/Focus (black)

          - Popover component interaction state, default and focus + Popover component interaction state, default and focus

          Default/Focus (white)

          - Popover component interaction state, default and focus + Popover component interaction state, default and focus
          @@ -218,13 +218,13 @@ Both popover variants have interaction states.

          Hover/Active (black)

          - Popover component interaction state, hover and active + Popover component interaction state, hover and active

          Hover/Active (white)

          - Popover component interaction state, hover and active + Popover component interaction state, hover and active
@@ -276,7 +276,7 @@ the close button must have focus in order for a user to have control over the popover and be able to interact with the links or close it. - Popover component accessibility + Popover component accessibility @@ -316,7 +316,7 @@ popover and be able to interact with the links or close it. Do not embed a popover or tooltip within another popover. - Popover component best practice 1 + Popover component best practice 1 @@ -325,7 +325,7 @@ Do not embed a popover or tooltip within another popover. Do not overload a popover with too much content. - Popover component best practice 2 + Popover component best practice 2 @@ -334,5 +334,5 @@ Do not overload a popover with too much content. Do not remove the close button from a popover. - Popover component best practice 3 + Popover component best practice 3 diff --git a/elements/rh-progress-steps/docs/00-overview.md b/elements/rh-progress-steps/docs/00-overview.md index d76a4cb9a5..c63035cd14 100644 --- a/elements/rh-progress-steps/docs/00-overview.md +++ b/elements/rh-progress-steps/docs/00-overview.md @@ -12,7 +12,7 @@ toward the completion of a linear process. ## Sample element - Progress steps component sample + Progress steps component sample {% repoStatusChecklist repoStatus=repoStatus %} \ No newline at end of file diff --git a/elements/rh-progress-steps/docs/10-style.md b/elements/rh-progress-steps/docs/10-style.md index c892af144d..ac9705f50d 100644 --- a/elements/rh-progress-steps/docs/10-style.md +++ b/elements/rh-progress-steps/docs/10-style.md @@ -5,7 +5,7 @@ on a thin horizontal or vertical line and organized sequentially from left to right or top to bottom. - Progress steps component blueprint + Progress steps component blueprint @@ -27,7 +27,7 @@ through each step of the task. indicates how much progress a user has made. - Progress steps component visual elements + Progress steps component visual elements @@ -45,7 +45,7 @@ them in **Sentence case** only. - Progress steps component text labels + Progress steps component text labels @@ -64,7 +64,7 @@ steps with short text labels. - Progress steps component horizontal orientation + Progress steps component horizontal orientation @@ -82,7 +82,7 @@ with more words. - Progress steps component vertical orientation + Progress steps component vertical orientation @@ -95,28 +95,28 @@ orientation. ### Desktop - Progress steps component responsive design, desktop + Progress steps component responsive design, desktop ### Tablet - Progress steps component responsive design, tablet + Progress steps component responsive design, tablet ### Mobile - Progress steps component responsive design, mobile + Progress steps component responsive design, mobile ## Spacing - Progress steps component spacing + Progress steps component spacing diff --git a/elements/rh-progress-steps/docs/20-guidelines.md b/elements/rh-progress-steps/docs/20-guidelines.md index aafa65094a..3ac63f1bd2 100644 --- a/elements/rh-progress-steps/docs/20-guidelines.md +++ b/elements/rh-progress-steps/docs/20-guidelines.md @@ -16,7 +16,7 @@ labels, the vertical orientation should be used instead. - Progress steps component mobile usage + Progress steps component mobile usage @@ -34,11 +34,11 @@ before finishing and submitting. - Progress steps component progression, part 1 + Progress steps component progression, part 1 - Progress steps component progression, part 2 + Progress steps component progression, part 2 @@ -51,7 +51,7 @@ alert](https://ux.redhat.com/elements/alert/){target="_blank"} is displayed to inform them of what they should do. - Progress steps component validation + Progress steps component validation @@ -68,7 +68,7 @@ user **is not able** to go back to review or change anything. - Progress steps component completion + Progress steps component completion @@ -106,7 +106,7 @@ user is in the process will make them feel in control and encourage them to finish the task. - Progress steps component behavior + Progress steps component behavior @@ -117,28 +117,28 @@ The interaction states within both orientations are the same. ### Link - Progress steps component interaction state, link + Progress steps component interaction state, link ### Hover - Progress steps component interaction state, hover + Progress steps component interaction state, hover ### Focus - Progress steps component interaction state, focus + Progress steps component interaction state, focus ### Active - Progress steps component interaction state, active + Progress steps component interaction state, active @@ -149,7 +149,7 @@ and text label in order, from left to right in the horizontal component or from top to bottom in the vertical component. - Progress steps component tab order + Progress steps component tab order @@ -205,7 +205,7 @@ Do not use too many or too few steps, there should be between three and five steps visible. - Progress steps component best practice 1 + Progress steps component best practice 1 @@ -216,7 +216,7 @@ present or if text labels are too long, switch to the vertical orientation instead. - Progress steps component best practice 2 + Progress steps component best practice 2 @@ -227,7 +227,7 @@ proceed to the next step without resolving any errors first nor can they go back to resolve any errors and then continue. - Progress steps component best practice 3 + Progress steps component best practice 3 @@ -238,7 +238,7 @@ used to represent step position or validation if a user is colorblind or uses assistive technologies like a screen reader. - Progress steps component best practice 4 + Progress steps component best practice 4 @@ -248,7 +248,7 @@ Do not use Progress steps as an image carousel without including text labels and other types of content. - Progress steps component best practice 5 + Progress steps component best practice 5 @@ -258,5 +258,5 @@ Do not use Progress steps as Tabs. Progress steps are used for guiding a user through a task by displaying sequential steps and instructional content. - Progress steps component best practice 6 + Progress steps component best practice 6 diff --git a/elements/rh-site-status/docs/00-overview.md b/elements/rh-site-status/docs/00-overview.md index 69c11e010d..2f72502931 100644 --- a/elements/rh-site-status/docs/00-overview.md +++ b/elements/rh-site-status/docs/00-overview.md @@ -3,7 +3,7 @@ {{ tagName | getElementDescription }} - Image of a site status element with a green checkmark and the text 'All systems operational' + Image of a site status element with a green checkmark and the text 'All systems operational' diff --git a/elements/rh-site-status/docs/20-guidelines.md b/elements/rh-site-status/docs/20-guidelines.md index d160ded1d1..3fdc8a44a9 100644 --- a/elements/rh-site-status/docs/20-guidelines.md +++ b/elements/rh-site-status/docs/20-guidelines.md @@ -1,4 +1,4 @@ - + diff --git a/elements/rh-switch/demo/rh-switch.html b/elements/rh-switch/demo/rh-switch.html index baa48e3317..19924305d6 100644 --- a/elements/rh-switch/demo/rh-switch.html +++ b/elements/rh-switch/demo/rh-switch.html @@ -7,3 +7,10 @@ + + + diff --git a/elements/rh-switch/docs/00-overview.md b/elements/rh-switch/docs/00-overview.md index 9ad397bfd9..f70aae6cbe 100644 --- a/elements/rh-switch/docs/00-overview.md +++ b/elements/rh-switch/docs/00-overview.md @@ -3,7 +3,7 @@ {{ tagName | getElementDescription }} - example of switch that's on + example of switch that's on {% repoStatusList repoStatus=repoStatus %} diff --git a/elements/rh-switch/docs/10-style.md b/elements/rh-switch/docs/10-style.md index 1ca8280938..467e299cbb 100644 --- a/elements/rh-switch/docs/10-style.md +++ b/elements/rh-switch/docs/10-style.md @@ -7,7 +7,7 @@ A Switch resembles a slider and includes a status message. When activated, the t
- with numbers labeling the track, handle, and status message + with numbers labeling the track, handle, and status message
    @@ -25,11 +25,11 @@ A Switch is available in both light and dark themes.
    - Light theme switch with blue track, white handle, and black text + Light theme switch with blue track, white handle, and black text - Dark theme switch with light blue track, black handle, and white text + Dark theme switch with light blue track, black handle, and white text
    @@ -39,11 +39,11 @@ A Switch is the same height as the status message and both are horizontally alig
    - Switch and status message are 24px tall. Switch is 40px wide. + Switch and status message are 24px tall. Switch is 40px wide. - Horizontally aligned switch and status message + Horizontally aligned switch and status message
    @@ -53,7 +53,7 @@ A Switch is the same height as the status message and both are horizontally alig A status message can be positioned to the right or left of a Switch. - One switch with status message on the left and another with status message on the right + One switch with status message on the left and another with status message on the right @@ -62,11 +62,11 @@ A status message can be positioned to the right or left of a Switch. Space values remain the same at all viewport sizes. - 16px spacer between the switch and status message + 16px spacer between the switch and status message - 24px spacer between stacked switches with status messages + 24px spacer between stacked switches with status messages @@ -81,7 +81,7 @@ A Switch and the status message cx count as the same selectable object.
    - Switches that are on, off, disabled, hovered, active, and in focus + Switches that are on, off, disabled, hovered, active, and in focus
      diff --git a/elements/rh-switch/docs/20-guidelines.md b/elements/rh-switch/docs/20-guidelines.md index 9a6a0a8db1..c122d57a9c 100644 --- a/elements/rh-switch/docs/20-guidelines.md +++ b/elements/rh-switch/docs/20-guidelines.md @@ -69,7 +69,7 @@ A Switch displays a state through different methods and locations. - The Switch status message is used with a check icon to add clarity if necessary - four variants of switch + four variants of switch @@ -127,14 +127,14 @@ The status message and form label should be short and direct, not neutral or amb
      - Magenta button, brand red default call to action, green tooltip, and dark orange switch + Magenta button, brand red default call to action, green tooltip, and dark orange switch

      Ensure the message is clear when a Switch is toggled to the On or Off position and that the form label explains the switch's purpose.

      - Magenta button, brand red default call to action, green tooltip, and dark orange switch + Magenta button, brand red default call to action, green tooltip, and dark orange switch

      Do not use a status message that does not make the switch state clear, especially if the form label is hidden.

      @@ -174,7 +174,7 @@ The recommended maximum character count is listed below and includes spaces. Use a stack of Switches for situations where multiple independent options need to be turned on or off. - four switches, half of which are on, stacked in a column + four switches, half of which are on, stacked in a column @@ -183,7 +183,7 @@ Use a stack of Switches for situations where multiple independent options need t A Switch is successfully toggled when the handle slides to the other side of the track and the status message changes. When a user toggles a Switch, the effects should start immediately without needing to save. If immediate results are not achievable, another element should be used instead (see table above in Usage section). - One switch that is on, next to one that is off + One switch that is on, next to one that is off @@ -196,14 +196,14 @@ To avoid confusion as to what a Switch will do, always include some kind of stat
      - Switches with Bluetooth as a form label and/or a status message + Switches with Bluetooth as a form label and/or a status message

      Ensure the message is clear when a Switch is toggled to the On or Off position and that the form label explains the switch's purpose.

      - Two switches without a form label or status message + Two switches without a form label or status message

      Do not make it unknown to users what a Switch will do when toggled.

      @@ -239,14 +239,14 @@ Switches can be used in a list to toggle multiple independent options.
      - Four switches stacked vertically with half of them turned on + Four switches stacked vertically with half of them turned on

      Use Switches in a list only if the effects from toggling each Switch are immediate.

      - Four switches stacked vertically with a save button below them + Four switches stacked vertically with a save button below them

      Do not use Switches in a list if a user has to save to see the effects

      diff --git a/elements/rh-switch/docs/40-accessibility.md b/elements/rh-switch/docs/40-accessibility.md index f45d7463db..15510dd442 100644 --- a/elements/rh-switch/docs/40-accessibility.md +++ b/elements/rh-switch/docs/40-accessibility.md @@ -3,7 +3,7 @@ Users should have the ability to move focus to a Switch and toggle it on or off using their keyboard. - Diagram of switch with text and arrows that show what can be controlled by keyboard + Diagram of switch with text and arrows that show what can be controlled by keyboard @@ -32,7 +32,7 @@ Users should have the ability to move focus to a Switch and toggle it on or off 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. If Switches are stacked, focus lands on each as it moves from top to bottom. Each Switch should have the ability to be toggled. - Diagram with four switches and numbers 1 to 4 indicating focus order + Diagram with four switches and numbers 1 to 4 indicating focus order ## Touch targets @@ -40,7 +40,7 @@ A logical focus order helps keyboard users operate our websites. Elements need t Grouped Switches are adequately spaced for optimal touch targets. - group of four switches and red circles with low opacity over each switch + group of four switches and red circles with low opacity over each switch ## Using form labels diff --git a/elements/rh-switch/rh-switch.css b/elements/rh-switch/rh-switch.css index a5f2d8e8f1..cb782c9f86 100644 --- a/elements/rh-switch/rh-switch.css +++ b/elements/rh-switch/rh-switch.css @@ -3,150 +3,131 @@ outline: none; vertical-align: top; cursor: pointer; - - --_switch-width: 40px; - --_switch-height: 24px; - --_switch-handle-size: 14px; - --_switch-track-background-color: var(--rh-color-gray-60, #4d4d4d); - --_margin-inline: 5px; /* non standard spacer */ -} - -#container { - display: inline-flex; - align-items: center; - gap: var(--rh-space-lg, 16px); -} - -:host(:disabled) { - pointer-events: none; - cursor: not-allowed; - - --_switch-track-background-color: var(--rh-color-gray-30, #c7c7c7); } [hidden] { display: none !important; } -#switch { - align-items: center; +#container { display: inline-flex; - flex-shrink: 0; - position: relative; - width: var(--_switch-width); - height: var(--_switch-height); - border-radius: var(--rh-border-radius-pill, 64px); -} - -:host(:is(:focus, :focus-within)) #switch { - outline: - var(--rh-border-width-md, 2px) - solid - var(--_switch-focus-outline-color, var(--rh-color-border-interactive-on-light, #0066cc)); - outline-offset: var(--rh-space-sm, 6px); -} - -/* track */ -#switch:before { - content: ""; - display: flex; - position: absolute; - width: 100%; - height: 100%; - border-radius: inherit; - justify-content: center; align-items: center; - background-color: var(--_switch-track-background-color); -} - -/* handle */ -#switch:after { - content: ""; - height: var(--_switch-handle-size); - width: var(--_switch-handle-size); - border-radius: var(--rh-border-radius-pill, 64px); - transform-origin: center; - z-index: 0; - background-color: var(--_switch-handle-color, var(--rh-color-surface-lightest, #ffffff)); - margin-inline: var(--_margin-inline); - translate: 0%; - transition: translate 0.25s ease 0s; -} - -:host([checked]:not(:disabled)) { - --_switch-track-background-color: - var( - --_switch-checked, - var(--rh-color-accent-base-on-light, #0066cc) - ); -} - -:host([checked]) #switch:after { - translate: - calc( - var(--_switch-width) - (var(--_switch-handle-size) + - (var(--_margin-inline) * 2)) - ); -} - -:host([checked]) .rtl #switch:after { - translate: - calc( - -1 * ( - var(--_switch-width) - (var(--_switch-handle-size) + - (var(--_margin-inline) * 2)) - ) - ); -} + gap: var(--rh-space-lg, 16px); -svg { - fill: currentcolor; + --_margin-inline: 5px; /* non standard spacer */ + --_switch-width: 40px; + --_switch-height: 24px; + --_switch-handle-size: 14px; + --_switch-track-background-color: var(--rh-color-gray-60, #4d4d4d); + --_switch-handle-color: var(--rh-color-surface-lightest, #ffffff); + + #switch { + align-items: center; + display: inline-flex; + flex-shrink: 0; + position: relative; + width: var(--_switch-width); + height: var(--_switch-height); + border-radius: var(--rh-border-radius-pill, 64px); + + /* track */ + &:before { + content: ''; + display: flex; + position: absolute; + width: 100%; + height: 100%; + border-radius: inherit; + justify-content: center; + align-items: center; + background-color: var(--_switch-track-background-color); + } + + /* handle */ + &:after { + content: ''; + height: var(--_switch-handle-size); + width: var(--_switch-handle-size); + border-radius: var(--rh-border-radius-pill, 64px); + transform-origin: center; + z-index: 0; + background-color: var(--_switch-handle-color); + margin-inline: var(--_margin-inline); + translate: 0%; + transition: translate 0.25s ease 0s; + } + } + + & .message { + color: var(--rh-color-text-secondary); + } + + &.checked { + --_switch-track-background-color: var(--rh-color-accent-base); + + & .message { + color: var(--rh-color-text-primary); + } + + & #switch:after { + translate: + calc(var(--_switch-width) - (var(--_switch-handle-size) + + (var(--_margin-inline) * 2))); + } + + &.rtl #switch:after { + translate: + calc(-1 * ( + var(--_switch-width) - (var(--_switch-handle-size) + + (var(--_margin-inline) * 2)) + )); + } + } + + &.dark { + --_switch-track-background-color: var(--rh-color-gray-40, #a3a3a3); /* no disabled token yet */ + --_switch-handle-color: var(--rh-color-surface-dark-alt, #292929); + + &.checked { + --_switch-track-background-color: var(--rh-color-accent-base); + } + + &:after { + box-shadow: var(--rh-box-shadow-sm, 0 2px 4px 0 rgba(21, 21, 21, 0.2)); + } + } +} + +rh-icon { margin-inline: var(--_margin-inline); - font-size: var(--rh-font-size-body-text-xs, 0.75rem); - color: var(--_switch-handle-color, var(--rh-color-icon-secondary-on-dark, #ffffff)); + color: var(--_switch-handle-color); position: absolute; z-index: 1; } -:host(:not([checked])) ::slotted(*) { - color: var(--rh-color-text-secondary-on-light, #4d4d4d); -} - -:host(:disabled) ::slotted(*), -:host(:disabled) slot[name^="message"] span[aria-hidden] { - color: var(--rh-color-gray-50, #707070); -} - -.dark { - --_switch-track-background-color: var(--rh-color-gray-40, #a3a3a3); /* no disabled token yet */ - --_switch-handle-color: var(--rh-color-surface-dark-alt, #292929); -} - -.dark:after { - box-shadow: var(--rh-box-shadow-sm, 0 2px 4px 0 rgba(21, 21, 21, 0.2)); +:host(:is(:focus, :focus-within)) #container #switch { + outline: var(--rh-border-width-md, 2px) solid var(--rh-color-border-interactive); + outline-offset: var(--rh-space-sm, 6px); } -:host(:disabled) .dark { - --_switch-track-background-color: var(--rh-color-gray-60, #4d4d4d); -} +:host(:disabled) { + pointer-events: none; + cursor: not-allowed; -:host(:not([checked])) .dark ::slotted(*) { - color: var(--rh-color-text-secondary-on-dark, #c7c7c7); -} + --_switch-track-background-color: var(--rh-color-gray-30, #c7c7c7); -:host(:disabled) .dark ::slotted(*), -:host(:disabled) .dark slot[name^="message"] span[aria-hidden] { - color: var(--rh-color-gray-40, #a3a3a3); -} + & #container { + & .message { + color: var(--rh-color-gray-50, #707070); + } -:host(:is(:focus, :focus-within)) .dark { - --_switch-focus-outline-color: var(--rh-color-border-interactive-on-dark, #92c5f9); -} + &.dark { + --_switch-track-background-color: var(--rh-color-gray-60, #4d4d4d); -:host([checked]:not(:disabled)) .dark { - --_switch-track-background-color: - var( - --_switch-checked, - var(--rh-color-accent-base-on-dark, #92c5f9) - ); + & ::slotted(*), + & span { + color: var(--rh-color-gray-40, #a3a3a3); + } + } + } } diff --git a/elements/rh-switch/rh-switch.ts b/elements/rh-switch/rh-switch.ts index c1e83c8529..7d472f2a3d 100644 --- a/elements/rh-switch/rh-switch.ts +++ b/elements/rh-switch/rh-switch.ts @@ -5,13 +5,14 @@ import { classMap } from 'lit/directives/class-map.js'; import { InternalsController } from '@patternfly/pfe-core/controllers/internals-controller.js'; import { SlotController } from '@patternfly/pfe-core/controllers/slot-controller.js'; +import { getRandomId } from '@patternfly/pfe-core/functions/random.js'; import { DirController } from '../../lib/DirController.js'; import { colorContextConsumer, type ColorTheme } from '../../lib/context/color/consumer.js'; - import styles from './rh-switch.css'; -import { getRandomId } from '@patternfly/pfe-core/functions/random.js'; + +import '@rhds/elements/rh-icon/rh-icon.js'; /** * A switch toggles the state of a setting (between on and off). Switches and checkboxes can often be used interchangeably, but the switch provides a more explicit, visible representation on a setting. @@ -19,6 +20,8 @@ import { getRandomId } from '@patternfly/pfe-core/functions/random.js'; * @cssprop --rh-switch-unchecked - The background color of the switch when it is unchecked. * @cssprop --rh-switch-checked - The background color of the switch when it is checked. * @cssprop --rh-switch-disabled - The background color of the switch when it is disabled. + * @slot message-on - message content when checked. Overrides the `message-on` attribute. + * @slot message-off - message content when unchecked. Overrides the `message-off` attribute. */ @customElement('rh-switch') export class RhSwitch extends LitElement { @@ -26,25 +29,27 @@ export class RhSwitch extends LitElement { static readonly formAssociated = true; - @property({ reflect: true }) label?: string; + /** invisible, accessible label for screen readers */ + @property({ reflect: true, attribute: 'accessible-label' }) accessibleLabel?: string; + + /** Message to display when the switch is on (i.e. checked) */ + @property({ reflect: true, attribute: 'message-on' }) messageOn?: string; + /** Message to display when the switch is off (i.e. unchecked) */ + @property({ reflect: true, attribute: 'message-off' }) messageOff?: string; + + /** If the checkmark icon should be displayed when the switch is on */ @property({ reflect: true, type: Boolean, attribute: 'show-check-icon' }) showCheckIcon = false; + /** If the switch is on */ @property({ reflect: true, type: Boolean }) checked = false; + /** If the switch is disabled */ @property({ reflect: true, type: Boolean }) disabled = false; - @property({ reflect: true, attribute: 'accessible-label' }) accessibleLabel?: string; - - @property({ reflect: true, attribute: 'message-on' }) messageOn?: string; - - @property({ reflect: true, attribute: 'message-off' }) messageOff?: string; - + /** If the switch is reversed: message first, then control */ @property({ reflect: true, type: Boolean }) reversed = false; - /** - * Sets color theme based on parent context - */ @colorContextConsumer() private on?: ColorTheme; #internals = InternalsController.of(this, { role: 'switch' }); @@ -102,41 +107,27 @@ export class RhSwitch extends LitElement { render() { const rtl = this.#dir.dir === 'rtl'; - const { on = '' } = this; + const { on = 'light', reversed, checked } = this; + const slots = html` + + + + + + `; return html`
      - ${this.reversed ? html` - - ${this.#switchTemplate()} - ` : html` - ${this.#switchTemplate()} - - `} - - - - - - -
      - `; - } - - #switchTemplate() { - return html` -
      - ${this.showCheckIcon ? html` - - - - ` : ``} + class="${classMap({ checked, on: true, [on]: true, rtl })}"> + ${reversed ? slots : ''} +
      + +
      + ${reversed ? '' : slots}
      `; } diff --git a/elements/rh-switch/test/rh-switch.spec.ts b/elements/rh-switch/test/rh-switch.spec.ts index 19c61b9bdd..46172e6267 100644 --- a/elements/rh-switch/test/rh-switch.spec.ts +++ b/elements/rh-switch/test/rh-switch.spec.ts @@ -171,7 +171,7 @@ describe('', function() { }); it('should display a check icon', async function() { // TODO: can we test this without inspecting the private shadowRoot? - const svg = element.shadowRoot.querySelector('svg'); + const svg = element.shadowRoot?.querySelector('rh-icon'); expect(svg).to.be.ok; expect(svg?.hasAttribute('hidden')).to.be.false; }); diff --git a/elements/rh-table/demo/auto-data-labels.html b/elements/rh-table/demo/auto-data-labels.html new file mode 100644 index 0000000000..2d64ba715e --- /dev/null +++ b/elements/rh-table/demo/auto-data-labels.html @@ -0,0 +1,147 @@ +

      Basic table

      + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      DateEventVenue
      12 February + Waltz with Strauss + Main Hall
      24 MarchThe ObelisksWest Wing
      14 AprilThe WhatMain Hall
      +
      + +

      Table with rowspans

      + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      DateEventVenue
      12 February + Waltz with Strauss + Main Hall
      24 MarchWest Wing
      14 AprilThe WhatMain Hall
      +
      + +

      Table with colspans

      + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      DateEventVenue
      12 February + Waltz with Strauss + Main Hall
      24 MarchThe Obelisks in the West Wing
      14 AprilThe WhatMain Hall
      +
      + +

      Table with a complicated thead

      + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      When & where
      EventDateVenue
      + Waltz with Strauss + + 12 FebruaryMain Hall
      The Obelisks + 24 MarchWest Wing
      The What + 14 AprilMain Hall
      +
      + + + + diff --git a/elements/rh-table/demo/color-context.html b/elements/rh-table/demo/color-context.html index 82fb327e98..7e80a51963 100644 --- a/elements/rh-table/demo/color-context.html +++ b/elements/rh-table/demo/color-context.html @@ -1,9 +1,7 @@ - + @@ -11,28 +9,26 @@ - - - + + + - - - + + + - - - + + + - - - + + +
      - Concerts - Concerts
      DateEvent - Venue - DateEventVenue
      12 FebruaryWaltz with StraussMain Hall12 FebruaryWaltz with StraussMain Hall
      24 MarchThe ObelisksWest Wing24 MarchThe ObelisksWest Wing
      14 AprilThe WhatMain Hall14 AprilThe WhatMain Hall
      @@ -44,6 +40,5 @@ diff --git a/elements/rh-table/docs/00-overview.md b/elements/rh-table/docs/00-overview.md index 286a5a25bc..09dac524e5 100644 --- a/elements/rh-table/docs/00-overview.md +++ b/elements/rh-table/docs/00-overview.md @@ -3,7 +3,7 @@ {{ tagName | getElementDescription }} - Image of table with four columns and three row + Image of table with four columns and three row diff --git a/elements/rh-table/docs/10-style.md b/elements/rh-table/docs/10-style.md index 2dadefe4ac..39b950a539 100644 --- a/elements/rh-table/docs/10-style.md +++ b/elements/rh-table/docs/10-style.md @@ -4,7 +4,7 @@ Use a table to organize and display data efficiently in a grid with columns and
      - Image of table with numbers next to various parts + Image of table with numbers next to various parts
        @@ -25,7 +25,7 @@ Use a table to organize and display data efficiently in a grid with columns and Column and row titles should be a few words that describe the data in that column or row. - Image of various tables with no titles, column titles, row titles, and both + Image of various tables with no titles, column titles, row titles, and both @@ -35,7 +35,7 @@ The table title should make it clear to a user what the data is and what purpose - Image of table with a title on top and a caption underneath + Image of table with a title on top and a caption underneath @@ -46,14 +46,14 @@ A table is available in both light and dark themes. ### Light theme - Light theme table with black text on white surface + Light theme table with black text on white surface ### Dark theme - Dark theme table with white text on black surface + Dark theme table with white text on black surface @@ -62,7 +62,7 @@ A table is available in both light and dark themes. A scrollbar is visible if content exceeds the width or height of a table. Content can scroll horizontally, vertically, or both. - Image of various tables with a scrollbar on the right, on the bottom, and both + Image of various tables with a scrollbar on the right, on the bottom, and both @@ -71,7 +71,7 @@ A scrollbar is visible if content exceeds the width or height of a table. Conten A table has equal spacing within columns, rows, and in between divider lines. The same spacing is also maintained across large and small viewport sizes. - Image of table with spacers in between elements + Image of table with spacers in between elements @@ -93,19 +93,19 @@ On hover, cell rows and columns are highlighted with a semitransparent backgroun In light theme, a row is highlighted in light gray on white surface colors and white on light gray surface colors. The column highlight remains light blue. - Light theme tables with hover effects on a white surface + Light theme tables with hover effects on a white surface - Light theme tables with hover effects on a light gray surface + Light theme tables with hover effects on a light gray surface On all dark theme surface colors, the row highlight is white, and the column highlight uses a dark blue. - Dark theme tables with hover effects on a black surface + Dark theme tables with hover effects on a black surface @@ -117,9 +117,9 @@ On all dark theme surface colors, the row highlight is white, and the column hig - Light theme table cell in focus state + Light theme table cell in focus state - Dark theme table cell in focus state + Dark theme table cell in focus state diff --git a/elements/rh-table/docs/20-guidelines.md b/elements/rh-table/docs/20-guidelines.md index 75dc07ebc0..6f9faf6007 100644 --- a/elements/rh-table/docs/20-guidelines.md +++ b/elements/rh-table/docs/20-guidelines.md @@ -7,7 +7,7 @@ A table is a set of data that can be easily scanned and compared. Each row in a There is no maximum number of columns or rows. To reduce cognitive load and a cluttered user interface, set a `max-width` or `max-height` after five or six of each. - Image of table with a section of columns and rows highlighted + Image of table with a section of columns and rows highlighted @@ -16,7 +16,7 @@ There is no maximum number of columns or rows. To reduce cognitive load and a cl In some edge cases, table rows can have double padding if there are more element types than just text. - Image of two tables, one with default vertical padding and the other one with double vertical padding + Image of two tables, one with default vertical padding and the other one with double vertical padding @@ -27,7 +27,7 @@ In some edge cases, table rows can have double padding if there are more element Titles should be concise, scannable, and descriptive of content in the column or row. Header labels should have two or three words maximum. If more words are included, the label might break to a second line. - Image of two tables with examples of short and long column and row titles + Image of two tables with examples of short and long column and row titles @@ -72,7 +72,7 @@ In general, header labels should be as short as possible. However, if columns ha A table should be the same width as nearby blocks of content on the page. - Image of examples of placeholder content and a table having the same width, one is wide and one is narrow + Image of examples of placeholder content and a table having the same width, one is wide and one is narrow ### Scrolling @@ -80,7 +80,7 @@ A table should be the same width as nearby blocks of content on the page. A table will scroll horizontally or vertically if content exceeds the max-width or max-height. - Image of two tables, one with no scrolling and the other with scrolling columns and rows + Image of two tables, one with no scrolling and the other with scrolling columns and rows @@ -89,7 +89,7 @@ A table will scroll horizontally or vertically if content exceeds the max-width Logos can be used in cells along with text if necessary. - Image of table with logos and links among text + Image of table with logos and links among text @@ -104,7 +104,7 @@ Columns can be sorted in ascending or descending order. Sorting controls are loc - Sorted down (arrow pointing down) - Image of tables with various sorting options + Image of tables with various sorting options @@ -113,14 +113,14 @@ Columns can be sorted in ascending or descending order. Sorting controls are loc ### Large viewport sizes - Image of table on large viewport sizes + Image of table on large viewport sizes ### Small viewport sizes - Image of table on small viewport sizes + Image of table on small viewport sizes @@ -131,7 +131,7 @@ Columns can be sorted in ascending or descending order. Sorting controls are loc A table should display at least two columns. - Image of table with one column which is incorrect usage + Image of table with one column which is incorrect usage @@ -140,7 +140,7 @@ A table should display at least two columns. In some edge cases, a table can have large cell height if there are more element types than just text. - Image of table with lots of vertical padding which is incorrect usage + Image of table with lots of vertical padding which is incorrect usage @@ -149,5 +149,5 @@ In some edge cases, a table can have large cell height if there are more element Do not use the small viewport size table on large viewports. - Image of small viewport table used on a large viewport which is incorrect usage + Image of small viewport table used on a large viewport which is incorrect usage diff --git a/elements/rh-table/docs/30-code.md b/elements/rh-table/docs/30-code.md index eeea8593b8..3cd30a0d32 100644 --- a/elements/rh-table/docs/30-code.md +++ b/elements/rh-table/docs/30-code.md @@ -1,16 +1,18 @@ {% renderInstall lightdomcss=true %}{% endrenderInstall %} +{% renderLightDom %}{% endrenderLightDom %} + ## Usage

        Warning

        -

        Ensure that the table follows the recommendations on the accessibility tab so that the table works with assistive technology.

        +

        Ensure that the table follows the recommendations on the accessibility tab so that the table works with assistive technology.

        ### Title -Specify the title of the table using a `caption` element. +Specify the title of the table using a `` element. ```html @@ -23,9 +25,58 @@ Specify the title of the table using a `caption` element. ``` +### Responsive tables + +`` will automatically reformat to a "stacked" presentation in narrow +containers such as on small screens and mobile devices or in page sidebars. For simple table structures, each table cell heading will be auto-generated for its responsive layout. + +For complex tables (i.e., including `colspan` or `rowspan` attributes), or to customize or override individual table cell headings on mobile devices, use a `data-label` attribute on the `` elements to label them. + +```html + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        + Concerts +
        DateEventVenue
        12 FebruaryWaltz with StraussMain Hall
        24 MarchThe ObelisksWest Wing
        14 AprilThe WhatMain Hall
        + Dates and venues subject to change. +
        +``` + + ### Column highlighting -To enable column highlighting, the `table` element must also include a `col` element for each column in the table, typically wrapped with a `colgroup`. +To enable column highlighting, the `` element must also include a `` +element for each column in the table, typically wrapped with a ``. ```html @@ -45,7 +96,8 @@ To enable column highlighting, the `table` element must also include a `col` ele ### Sorting -To enable sorting on a column, add an `rh-sort-button` as the last child of the `th` cell. +To enable sorting on a column, add an `` as the last child of +the ` - - - + + + @@ -87,26 +139,26 @@ Additional information about the data in the table should be slotted into the `s - - - + + + - - - + + + - - - + + + - - - + + +
        ` cell. ```html @@ -60,9 +112,9 @@ To enable sorting on a column, add an `rh-sort-button` as the last child of the
        DateEventVenueDateEventVenue
        DateEventVenueDateEventVenue
        12 FebruaryWaltz with StraussMain Hall12 FebruaryWaltz with StraussMain Hall
        24 MarchThe ObelisksWest Wing24 MarchThe ObelisksWest Wing
        14 AprilThe WhatMain Hall14 AprilThe WhatMain Hall
        @@ -128,26 +180,26 @@ Additional information about the data in the table should be slotted into the `s - Date - Event - Venue + Date + Event + Venue - 12 February - Waltz with Strauss - Main Hall + 12 February + Waltz with Strauss + Main Hall - 24 March - The Obelisks - West Wing + 24 March + The Obelisks + West Wing - 14 April - The What - Main Hall + 14 April + The What + Main Hall diff --git a/elements/rh-table/docs/40-accessibility.md b/elements/rh-table/docs/40-accessibility.md index 3f98d580ff..bcc95c336e 100644 --- a/elements/rh-table/docs/40-accessibility.md +++ b/elements/rh-table/docs/40-accessibility.md @@ -65,7 +65,7 @@ Since tables are inherently complex HTML structures, they can create barriers fo If a table is in a container that can receive keyboard focus (e.g., with a `tabindex="0"` attribute), then a user can place focus on the container and scroll the table horizontally or vertically using the arrow keys. - Image of table with scrollbars and purple buttons showing keyboard navigation + Image of table with scrollbars and purple buttons showing keyboard navigation @@ -117,7 +117,7 @@ If a table is in a container that can receive keyboard focus (e.g., with a `tabi A logical focus order helps keyboard users operate our websites and apps. Elements need to receive focus in an order that preserves meaning, therefore the focus order should make sense and not jump around randomly. Focus within a table moves from top to bottom and left to right. - Image of table with links, focus indicators, and numbers showing the focus order + Image of table with links, focus indicators, and numbers showing the focus order @@ -126,7 +126,7 @@ A logical focus order helps keyboard users operate our websites and apps. Elemen Each cell includes enough spacing for selecting interactive elements. - Image of table with links and focus indicators showing touch target size + Image of table with links and focus indicators showing touch target size diff --git a/elements/rh-table/rh-sort-button.css b/elements/rh-table/rh-sort-button.css index 53bc24cd1e..7e2c6c7059 100644 --- a/elements/rh-table/rh-sort-button.css +++ b/elements/rh-table/rh-sort-button.css @@ -9,7 +9,7 @@ } #sort-button:after { - content: ""; + content: ''; position: absolute; inset: 0; cursor: pointer; diff --git a/elements/rh-table/rh-table-lightdom.css b/elements/rh-table/rh-table-lightdom.css index ffd1b8997c..088078147b 100644 --- a/elements/rh-table/rh-table-lightdom.css +++ b/elements/rh-table/rh-table-lightdom.css @@ -1,172 +1,150 @@ rh-table { - --_row-border: - var( - --rh-table-row-border, - var(--rh-border-width-sm, 1px) - solid - var(--rh-color-border-subtle-on-light, #c7c7c7) - ); - --_row-background-hover-color: - var( - --rh-table-row-background-hover-color, - rgb( - var(--rh-color-gray-20-rgb, 224 224 224) - / var(--rh-opacity-40, 40%) - ) - ); - --_column-background-hover-color: - var( - --rh-table-column-background-hover-color, - rgb( - var(--rh-color-blue-50-rgb, 0 102 204) - / var(--rh-opacity-10, 10%) - ) - ); -} - -rh-table table { - min-width: 100%; - margin: 0 auto; - table-layout: fixed; - border: 0; - border-collapse: collapse; -} - -rh-table thead th { - position: relative; - padding-top: var(--rh-space-lg, 16px); - padding-bottom: var(--rh-space-lg, 16px); - text-align: left; - font-weight: var(--rh-font-weight-heading-bold, 700); -} - -rh-table tr { - border-bottom: var(--_row-border); -} - -rh-table tr:hover { - background: var(--_row-background-hover-color); -} - -rh-table tr > * { - border: none; -} - -rh-table :is(tr, col) { - transition: background 0.3s ease-out; -} - -rh-table a { - color: var(--rh-color-interactive-blue-darker, #0066cc); - text-decoration: none; -} - -rh-table a:hover { - color: var(--rh-color-interactive-blue-darkest, #003366); - text-decoration: underline; -} - -rh-table caption { - 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-lg, 1.125rem); - font-weight: var(--rh-font-weight-heading-bold, 700); - line-height: var(--rh-line-height-body-text, 1.5); - margin-bottom: var(--rh-space-xl, 24px); - text-align: center; - font-style: normal; -} - -rh-table :is(th, td) { - padding-right: var(--rh-space-lg, 16px); - padding-left: var(--rh-space-lg, 16px); -} - -rh-table td { - padding-top: var(--rh-space-xl, 24px); - padding-bottom: var(--rh-space-xl, 24px); -} - -rh-table :is(col.active) { - background: var(--_column-background-hover-color); -} - -@media (max-width: 768px) { - rh-table table { - display: grid; + container: host / inline-size; + + & thead { + & th { + position: relative; + padding-block: var(--rh-space-lg, 16px); + text-align: start; + font-weight: var(--rh-font-weight-heading-bold, 700); + } } - rh-table thead { - display: none; - visibility: hidden; + & table { + min-width: 100%; + margin: 0 auto; + table-layout: fixed; + border: 0; + border-collapse: collapse; } - rh-table tbody { - display: block; - } - - rh-table :not(thead) ~ tbody tr { - display: grid; - grid-auto-columns: auto; - grid-auto-flow: column; + & :is(tr, col) { + transition: background 0.3s ease-out; } - rh-table thead ~ tbody tr { - border: none; - display: grid; - grid-template-columns: 1fr; - height: auto; - grid-auto-columns: max-content; - grid-auto-flow: unset; + & :is(th, td) { + padding-inline: var(--rh-space-lg, 16px); } - rh-table thead ~ tbody tr:first-child { - border-top: var(--_row-border); + & :is(col.active) { + background: var(--_column-background-hover-color); } - rh-table thead ~ tbody tr:last-child { - border-bottom: var(--_row-border); - } + & tr { + border-block-end: var(--_row-border); - rh-table thead ~ tbody tr:nth-child(even) { - background: var(--_row-background-hover-color); - } + &:hover { + background: var(--_row-background-hover-color); + } - rh-table thead ~ tbody tr:hover { - background: var(---_column-background-hover-color); + & > * { + border: none; + } } - rh-table thead ~ tbody tr > * { - padding: var(--rh-space-lg, 16px); + & td { + padding-block: var(--rh-space-xl, 24px); } - rh-table thead ~ tbody tr th { - text-align: center; - } + & a { + color: var(--rh-color-interactive-primary-default); + text-decoration: none; - rh-table thead ~ tbody tr :is(th, td) { - padding-top: calc(var(--rh-space-md, 8px) + var(--rh-space-xs, 4px)); - padding-bottom: calc(var(--rh-space-md, 8px) + var(--rh-space-xs, 4px)); - display: grid; - grid-column-gap: var(--rh-space-lg, 16px); - grid-template-columns: 1fr minmax(0, 1.5fr); - align-items: start; - white-space: normal; - word-wrap: break-word; - text-align: left; + &:hover { + color: var(--rh-color-interactive-primary-hover); + text-decoration: underline; + } } - rh-table thead ~ tbody tr :is(td,th):before { + & caption { + 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-lg, 1.125rem); font-weight: var(--rh-font-weight-heading-bold, 700); - text-align: left; - content: attr(data-label); - display: inline-block; + line-height: var(--rh-line-height-body-text, 1.5); + margin-block-end: var(--rh-space-xl, 24px); + text-align: center; + font-style: normal; } +} - rh-table thead ~ tbody tr:first-child td:first-child { - padding-top: var(--rh-space-lg, 16px); - } +@container host (max-width: 768px) { + table { + display: grid; - rh-table thead ~ tbody tr:last-child td:last-child { - padding-bottom: var(--rh-space-lg, 16px); + & *:not(thead) + tbody { + & tr { + display: grid; + grid-auto-columns: auto; + grid-auto-flow: column; + } + } + + & thead { + display: none; + visibility: hidden; + + & ~ tbody { + display: block; + + & tr { + border: none; + display: grid; + grid-template-columns: 1fr; + height: auto; + grid-auto-columns: max-content; + grid-auto-flow: unset; + + &:first-child { + border-block-start: var(--_row-border); + + & td:first-child { + padding-block-start: var(--rh-space-lg, 16px); + } + + & td:last-child { + padding-block-end: var(--rh-space-lg, 16px); + } + } + + &:nth-child(even) { + background: var(--_row-background-hover-color); + } + + &:last-child { + border-block-end: var(--_row-border); + } + + &:hover { + background: var(---_column-background-hover-color); + } + + & > * { + padding: var(--rh-space-lg, 16px); + } + + & :is(th, td) { + padding-block: calc(var(--rh-space-md, 8px) + var(--rh-space-xs, 4px)); + display: grid; + grid-column-gap: var(--rh-space-lg, 16px); + grid-template-columns: 1fr minmax(0, 1.5fr); + align-items: start; + white-space: normal; + word-wrap: break-word; + text-align: start; + } + + & :is(td,th):before { + font-weight: var(--rh-font-weight-heading-bold, 700); + text-align: start; + content: attr(data-label); + display: inline-block; + } + + & th { + text-align: center; + } + } + } + } } } diff --git a/elements/rh-table/rh-table.css b/elements/rh-table/rh-table.css index 4053419d51..0b079e412b 100644 --- a/elements/rh-table/rh-table.css +++ b/elements/rh-table/rh-table.css @@ -8,12 +8,23 @@ width: 100%; overflow: auto; scrollbar-color: var(--_scrollbar-track-color) var(--_scrollbar-thumb-color); - color: var(--_context-text); - background-color: var(--_context-background-color); + color: var(--rh-color-text-primary); + background-color: var(--rh-color-surface); --_scrollbar-size: calc(10 / 16 * 1rem); --_scrollbar-thumb-color: var(--rh-color-gray-50, #707070); - --_scrollbar-track-color: var(--rh-color-border-subtle-on-light, #c7c7c7); + --_scrollbar-track-color: var(--rh-color-border-subtle); + --_row-border: + var(--rh-table-row-border, + var(--rh-border-width-sm, 1px) + solid + var(--rh-color-border-subtle-on-light, #c7c7c7)); + --_row-background-hover-color: + var(--rh-table-row-background-hover-color, + rgba(from var(--rh-color-gray-40, #a3a3a3) r g b / 0.1)); + --_column-background-hover-color: + var(--rh-table-column-background-hover-color, + rgba(from var(--rh-color-blue-50, #0066cc) r g b / 0.1)); } :host::-webkit-scrollbar { @@ -34,48 +45,26 @@ display: block; } -:is(.color-palette-light, .color-palette-lighter) { - --rh-table-row-background-hover-color: - rgb( - var( - --_rh-color-white-rgb, /* making private as currently doesn't exist */ - 255 255 255 - ) - / var(--rh-opacity-50, 50%) - ); -} - +.color-palette-dark, +.color-palette-darker, +.color-palette-darkest, .dark { - --rh-table-row-background-hover-color: - rgb( - var( - --_rh-color-white-rgb, /* making private as currently doesn't exist */ - 255 255 255 - ) - / var(--rh-opacity-10, 10%) - ); - --rh-table-column-background-hover-color: - rgb( - var( - --rh-color-blue-70-rgb, - 0 51 102 - ) - / var(--rh-opacity-30, 30%) - ); + --_row-background-hover-color: rgba(from var(--rh-color-white, #ffffff) r g b / 0.1); + --_column-background-hover-color: rgba(from var(--rh-color-blue-70, #003366) r g b / 0.3); } /* @todo: should I move these styles to light dom css file? */ -::slotted([slot="summary"]) { +::slotted([slot='summary']) { display: block; padding: var(--rh-space-xl, 24px) var(--rh-space-lg, 16px) 0 var(--rh-space-lg, 16px); color: var(--rh-color-text-secondary-on-light, #4d4d4d); - 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-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-style: italic; font-weight: var(--rh-font-weight-body-text-regular, 400); line-height: var(--rh-line-height-body-text, 1.5); } -.dark ::slotted([slot="summary"]) { +.dark ::slotted([slot='summary']) { color: var(--rh-color-text-secondary-on-dark, #c7c7c7); } diff --git a/elements/rh-table/rh-table.ts b/elements/rh-table/rh-table.ts index 0b191f283e..88606fb13a 100644 --- a/elements/rh-table/rh-table.ts +++ b/elements/rh-table/rh-table.ts @@ -60,6 +60,10 @@ export class RhTable extends LitElement { return this.querySelectorAll('tbody > tr') as NodeListOf | undefined; } + get #colHeaders(): NodeListOf | undefined { + return this.querySelectorAll('thead > tr > th'); + } + get #summary(): HTMLElement | undefined { return this.querySelector('[slot="summary"]') as HTMLElement | undefined; } @@ -68,9 +72,12 @@ export class RhTable extends LitElement { #logger = new Logger(this); + #mo = new MutationObserver(() => this.#init); + connectedCallback() { super.connectedCallback(); this.#init(); + this.#mo.observe(this, { childList: true }); } protected willUpdate(): void { @@ -80,24 +87,46 @@ export class RhTable extends LitElement { * thats when the consumer requests an update. Switching between lighter -> light for example will * not trigger the component to update at this time. */ - this.#internalColorPalette = this.closest('[color-palette]')?.getAttribute('color-palette'); + const selector = '[color-palette]'; + function closestShadowRecurse(el: Element | Window | Document | null): Element | null { + if (!el || el === document || el === window) { + return null; + } + if ((el as Element).assignedSlot) { + el = (el as Element).assignedSlot; + } + const found = (el as Element).closest(selector); + return found ? + found + : closestShadowRecurse(((el as Element).getRootNode() as ShadowRoot).host); + } + this.#internalColorPalette = closestShadowRecurse(this)?.getAttribute('color-palette'); } render() { - const { on = '' } = this; + const { on = 'light' } = this; return html` -
        +
        `; } + disconnectedCallback() { + super.disconnectedCallback(); + this.#mo.disconnect(); + } + #onPointerleave() { if (!this.#cols) { return; @@ -138,6 +167,28 @@ export class RhTable extends LitElement { if (this.#table && this.#summary) { this.#table.setAttribute('aria-describedby', 'summary'); } + + /** + * Fail criteria: + * - If rowspan exists anywhere in the table, the auto-generated heading labels won't work + * - If colspan exists in the , the auto-generated heading labels won't work + * - If colspan exists in the , the auto-generated heading labels partially work (only assigning the first) + * + * So we bail for now... + */ + if (this.querySelector('[colspan], [rowspan]')) { + return; + } + + /* If responsive attribute set, auto-assign `data-label` attributes based on column headers */ + if (this.#table?.tHead && this.#colHeaders?.length && this.#rows) { + for (const row of this.#rows) { + row?.querySelectorAll(':is(td, th)') + .forEach((cell, index) => { + cell.dataset.label ||= this.#colHeaders?.[index]?.innerText || ''; + }); + } + } } #onSlotChange() { diff --git a/elements/rh-tabs/demo/color-context.html b/elements/rh-tabs/demo/color-context.html index 6fb18c5e19..2b1a0df340 100644 --- a/elements/rh-tabs/demo/color-context.html +++ b/elements/rh-tabs/demo/color-context.html @@ -71,3 +71,17 @@ }); + diff --git a/elements/rh-tabs/demo/icons-and-text.html b/elements/rh-tabs/demo/icons-and-text.html index 201bc617ec..230255eaba 100644 --- a/elements/rh-tabs/demo/icons-and-text.html +++ b/elements/rh-tabs/demo/icons-and-text.html @@ -1,16 +1,22 @@ - Users + Users Users - Containers + Containers Containers - Database + Database: Long SQL Statement Database - Server + Server Server - System + System System + + diff --git a/elements/rh-tabs/demo/long-tab-content.html b/elements/rh-tabs/demo/long-tab-content.html index 7e64c3319d..a8ecb5a0a2 100644 --- a/elements/rh-tabs/demo/long-tab-content.html +++ b/elements/rh-tabs/demo/long-tab-content.html @@ -24,7 +24,21 @@ Cloud - + + diff --git a/elements/rh-tabs/demo/nested.html b/elements/rh-tabs/demo/nested.html index 39a8fc124c..cdd7f678be 100644 --- a/elements/rh-tabs/demo/nested.html +++ b/elements/rh-tabs/demo/nested.html @@ -28,6 +28,19 @@ rh-tab-panel { padding: 0; } + + a { + color: var(--rh-color-interactive-primary-default); + &:hover { color: var(--rh-color-interactive-primary-hover); } + &:focus-within { color: var(--rh-color-interactive-primary-focus); } + &:active { color: var(--rh-color-interactive-primary-active); } + &:visited { + color: var(--rh-color-interactive-primary-visited); + &:hover { color: var(--rh-color-interactive-primary-visited-hover); } + &:focus-within { color: var(--rh-color-interactive-primary-visited-focus); } + &:active { color: var(--rh-color-interactive-primary-visited-active); } + } + } + + + diff --git a/elements/rh-tabs/demo/right-to-left.html b/elements/rh-tabs/demo/right-to-left.html index 56a96e4411..fbfdb0a50c 100644 --- a/elements/rh-tabs/demo/right-to-left.html +++ b/elements/rh-tabs/demo/right-to-left.html @@ -90,3 +90,19 @@ + + + diff --git a/elements/rh-tabs/demo/vertical.html b/elements/rh-tabs/demo/vertical.html index c2cf351497..ac77cbe3cf 100644 --- a/elements/rh-tabs/demo/vertical.html +++ b/elements/rh-tabs/demo/vertical.html @@ -14,3 +14,19 @@ + + + diff --git a/elements/rh-tabs/docs/00-overview.md b/elements/rh-tabs/docs/00-overview.md index e714955eba..ae6a105d64 100644 --- a/elements/rh-tabs/docs/00-overview.md +++ b/elements/rh-tabs/docs/00-overview.md @@ -3,7 +3,7 @@ {{ tagName | getElementDescription }} - Image of open tabs, box tabs, and tabs with overflow buttons + Image of open tabs, box tabs, and tabs with overflow buttons diff --git a/elements/rh-tabs/docs/10-style.md b/elements/rh-tabs/docs/10-style.md index 2890c02635..82b070d73e 100644 --- a/elements/rh-tabs/docs/10-style.md +++ b/elements/rh-tabs/docs/10-style.md @@ -7,7 +7,7 @@ Tabs are used to group related content allowing users to navigate a view without
        - Image of tabs anatomy showing horizontal and vertical open tabs and box tabs with lots of annotations + Image of tabs anatomy showing horizontal and vertical open tabs and box tabs with lots of annotations
          @@ -28,7 +28,7 @@ Tabs are used to group related content allowing users to navigate a view without There are two available variants. Open tabs has a more understated style whereas Box tabs has a more traditional style. - Image of open tabs on top and box tabs below + Image of open tabs on top and box tabs below @@ -37,7 +37,7 @@ There are two available variants. Open tabs has a more understated style whereas There are two available orientations and the only difference is padding. - Image of horizontal, vertical, and tabs with overflow buttons showing padding spacers + Image of horizontal, vertical, and tabs with overflow buttons showing padding spacers @@ -49,7 +49,7 @@ Both variants and orientations are available in both light and dark themes. ### Light theme - Image of light theme tabs + Image of light theme tabs @@ -109,7 +109,7 @@ Both variants and orientations are available in both light and dark themes. ### Dark theme - Image of dark theme tabs + Image of dark theme tabs @@ -171,7 +171,7 @@ Both variants and orientations are available in both light and dark themes. The panel for both orientations of tabs does not have a maximum height and should not scroll. - Image of horizontal and vertical tabs construction; several examples showing details like alignment, height, width, and more + Image of horizontal and vertical tabs construction; several examples showing details like alignment, height, width, and more @@ -180,7 +180,7 @@ The panel for both orientations of tabs does not have a maximum height and shoul Overflow buttons are containers with chevron icons that are added to tabs on small breakpoints. - Image of horizontal and vertical tabs with overflow buttons showing padding spacers + Image of horizontal and vertical tabs with overflow buttons showing padding spacers @@ -189,11 +189,11 @@ Overflow buttons are containers with chevron icons that are added to tabs on sma Box tabs are separated by a 1px divider. - Image of open tabs spacing for all sizes and orientations + Image of open tabs spacing for all sizes and orientations - Image of box tabs spacing for all sizes and orientations + Image of box tabs spacing for all sizes and orientations @@ -211,22 +211,22 @@ Interactive elements include inactive tabs and overflow buttons. Inactive tabs and overflow buttons have the same hover state. - Image of light theme open tabs hover states + Image of light theme open tabs hover states - Image of dark theme open tabs hover states + Image of dark theme open tabs hover states ### Hover - Box tabs - Image of light theme box tabs hover states + Image of light theme box tabs hover states - Image of dark theme box tabs hover states + Image of dark theme box tabs hover states @@ -262,11 +262,11 @@ Inactive tabs and overflow buttons have the same hover state. - Image of light theme open tabs focus states + Image of light theme open tabs focus states - Image of dark theme open tabs focus states + Image of dark theme open tabs focus states @@ -278,11 +278,11 @@ Inactive tabs and overflow buttons have the same hover state. - Image of light theme box tabs focus states + Image of light theme box tabs focus states - Image of dark theme box tabs focus states + Image of dark theme box tabs focus states @@ -312,11 +312,11 @@ Inactive tabs and overflow buttons have the same hover state. - Image of light theme open tabs active states + Image of light theme open tabs active states - Image of dark theme open tabs active states + Image of dark theme open tabs active states @@ -328,11 +328,11 @@ Inactive tabs and overflow buttons have the same hover state. - Image of light theme box tabs active states + Image of light theme box tabs active states - Image of dark theme box tabs active states + Image of dark theme box tabs active states diff --git a/elements/rh-tabs/docs/20-guidelines.md b/elements/rh-tabs/docs/20-guidelines.md index d0b481de3e..641bd2be78 100644 --- a/elements/rh-tabs/docs/20-guidelines.md +++ b/elements/rh-tabs/docs/20-guidelines.md @@ -13,7 +13,7 @@ Use tabs to organize lots of information into logical sections. Consider using a Tabs allow users to click through content one section at a time whereas an accordion allows users to view multiple sections of content simultaneously. - Image of tabs on top and an accordion below with two panels expanded + Image of tabs on top and an accordion below with two panels expanded @@ -22,7 +22,7 @@ Tabs allow users to click through content one section at a time whereas an accor To reduce cognitive load and a cluttered user interface, avoid using more than three or four tabs. - Image of open tabs with three tabs on top and box tabs with three tabs below + Image of open tabs with three tabs on top and box tabs with three tabs below @@ -33,7 +33,7 @@ When choosing one variation over the other, consider where it is being used. If Box tabs - use if your design includes a lot of boxes or you want to maintain the classic tabs look and feel - Image of open tabs on top and box tabs below + Image of open tabs on top and box tabs below @@ -44,7 +44,7 @@ When choosing one orientation over the other, consider the content in the panel, - Vertical tabs are placed on the left side of a container and offer users a left-to-right reading experience - Image of horizontal tabs on top and vertical tabs below + Image of horizontal tabs on top and vertical tabs below @@ -53,7 +53,7 @@ When choosing one orientation over the other, consider the content in the panel, If using horizontal tabs, the default orientation is left aligned, but center aligned is also an option. - Image of open tabs with left and center alignment and box tabs with left and center alignment + Image of open tabs with left and center alignment and box tabs with left and center alignment @@ -67,15 +67,15 @@ An inset is used to ensure consistent alignment and padding between text labels, - Image of open tabs showing detailed inset specs + Image of open tabs showing detailed inset specs - Image of box tabs showing detailed inset specs + Image of box tabs showing detailed inset specs - Image of vertical tabs showing detailed inset specs + Image of vertical tabs showing detailed inset specs Certain content layouts may require removing the inset. While this is not a default style, it is possible with custom CSS. @@ -85,7 +85,7 @@ Certain content layouts may require removing the inset. While this is not a defa In certain edge cases, logos can be used instead of text labels. - Image of open tabs with small logos in place of text labels + Image of open tabs with small logos in place of text labels @@ -99,15 +99,15 @@ The panel is below or to the right of tabs. Use this area to place other element - Image of open tabs with a text block and a card + Image of open tabs with a text block and a card - Image of open tabs with a title and a wide card + Image of open tabs with a title and a wide card - Image of open tabs with a text block and a blockquote + Image of open tabs with a text block and a blockquote @@ -118,7 +118,7 @@ The panel is below or to the right of tabs. Use this area to place other element Text labels should be concise, scannable, and descriptive of content in the panel. They should not exceed more than two or three short words. If they do, work with a content strategist to shorten them. - Image of open tabs with examples of adequate and long text labels + Image of open tabs with examples of adequate and long text labels @@ -153,7 +153,7 @@ Text labels should be short but descriptive. The divider line can be set to any width or be the same width as the list of tabs. - Image of open tabs with a stretched divider line on top and box tabs with a divider line constrained to the width of text labels below + Image of open tabs with a stretched divider line on top and box tabs with a divider line constrained to the width of text labels below @@ -162,7 +162,7 @@ The divider line can be set to any width or be the same width as the list of tab The divider line will become taller if the height of content in the panel exceeds the height of vertical tabs. - Image of vertical tabs with a short amount of content in the panel on top and vertical tabs with a long amount of content in the panel below + Image of vertical tabs with a short amount of content in the panel on top and vertical tabs with a long amount of content in the panel below @@ -171,7 +171,7 @@ The divider line will become taller if the height of content in the panel exceed Tabs can be used in a card if the layout is wide enough and there are fewer tabs. - Image of open tabs in a card with only two tabs + Image of open tabs in a card with only two tabs @@ -187,7 +187,7 @@ If the number of tabs exceeds the container width or breakpoint, overflow button - Image of open tabs at various widths showing overflow buttons on top and box tabs at various widths showing overflow buttons below + Image of open tabs at various widths showing overflow buttons on top and box tabs at various widths showing overflow buttons below @@ -196,7 +196,7 @@ If the number of tabs exceeds the container width or breakpoint, overflow button When the first tab is active, the left overflow button is disabled. When the last tab is active, the right overflow button is disabled. When a tab that is cut off is selected, the list of tabs shifts so the selected tab is in full view. - Image of selecting a cut off tab and the list of tabs shifting to reveal the selected tab in full view + Image of selecting a cut off tab and the list of tabs shifting to reveal the selected tab in full view @@ -205,7 +205,7 @@ When the first tab is active, the left overflow button is disabled. When the las ### Large breakpoints - Image of horizontal and vertical tabs on desktop and tablet breakpoints + Image of horizontal and vertical tabs on desktop and tablet breakpoints @@ -214,7 +214,7 @@ When the first tab is active, the left overflow button is disabled. When the las Vertical tabs switch to horizontal tabs with overflow buttons on small breakpoints. - Image of tabs with overflow buttons on small breakpoints + Image of tabs with overflow buttons on small breakpoints @@ -225,7 +225,7 @@ Vertical tabs switch to horizontal tabs with overflow buttons on small breakpoin There should be at least two tabs minimum. - Image of horizontal open and box tabs with one tab each which is incorrect usage + Image of horizontal open and box tabs with one tab each which is incorrect usage @@ -234,7 +234,7 @@ There should be at least two tabs minimum. Be careful about displaying too many tabs, some of them will become hidden even at large breakpoints. - Image of horizontal tabs with five tabs and overflow buttons which is incorrect usage + Image of horizontal tabs with five tabs and overflow buttons which is incorrect usage @@ -243,7 +243,7 @@ Be careful about displaying too many tabs, some of them will become hidden even Do not add extra spacing or stretch the width of tabs. - Image of horizontal tabs with three tabs that are stretched which is incorrect usage + Image of horizontal tabs with three tabs that are stretched which is incorrect usage @@ -252,5 +252,5 @@ Do not add extra spacing or stretch the width of tabs. Overflow buttons should not be visible if all tabs are visible. - Image of horizontal tabs with three visible tabs and overflow buttons which is incorrect usage + Image of horizontal tabs with three visible tabs and overflow buttons which is incorrect usage diff --git a/elements/rh-tabs/docs/40-accessibility.md b/elements/rh-tabs/docs/40-accessibility.md index e4db771091..39ffe08494 100644 --- a/elements/rh-tabs/docs/40-accessibility.md +++ b/elements/rh-tabs/docs/40-accessibility.md @@ -8,7 +8,7 @@ Each tab is a focus stop. Pressing the Arrow keys moves the focus a - Image of horizontal tabs with diagrams of what happens when Arrow or Tab keys are pressed + Image of horizontal tabs with diagrams of what happens when Arrow or Tab keys are pressed @@ -54,7 +54,7 @@ Each tab is a focus stop. Pressing the Arrow keys moves the focus a 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. For both sizes and orientations, the focus order is from left to right and top to bottom. Disabled buttons are not included in the focus order. - Image of horizontal, vertical, and tabs with overflow buttons showing the focus order from left to right and top to bottom + Image of horizontal, vertical, and tabs with overflow buttons showing the focus order from left to right and top to bottom @@ -63,7 +63,7 @@ A logical focus order helps keyboard users operate our websites. Elements need t Tabs are adequately spaced for optimal touch targets. - Image of open, box, and tabs with overflow buttons showing adequate touch target spacing + Image of open, box, and tabs with overflow buttons showing adequate touch target spacing diff --git a/elements/rh-tabs/rh-tab-panel.css b/elements/rh-tabs/rh-tab-panel.css index fcd7a87fb8..308334beb5 100644 --- a/elements/rh-tabs/rh-tab-panel.css +++ b/elements/rh-tabs/rh-tab-panel.css @@ -1,23 +1,12 @@ :host { display: block; - padding: var(--rh-space-2xl, 32px); + padding: var(--_panel-padding, var(--rh-space-2xl, 32px)); } -:host([box="inset"]) { - padding-inline: var(--_panels-overflow-padding, var(--rh-space-4xl, 64px)); -} - -:host([hidden]), -[hidden] { +:host([hidden]) { display: none !important; } -@media screen and (min-width: 768px) { - :host([vertical]) #rhds-container { - margin-inline: 0; - } - - :host([box][vertical]) { - padding: var(--rh-space-3xl, 48px); - } +#container { + display: contents; } diff --git a/elements/rh-tabs/rh-tab-panel.ts b/elements/rh-tabs/rh-tab-panel.ts index 2bdec511ab..19fd528628 100644 --- a/elements/rh-tabs/rh-tab-panel.ts +++ b/elements/rh-tabs/rh-tab-panel.ts @@ -1,7 +1,6 @@ import { LitElement, html } from 'lit'; import { customElement } from 'lit/decorators/custom-element.js'; import { classMap } from 'lit/directives/class-map.js'; - import { getRandomId } from '@patternfly/pfe-core/functions/random.js'; import { colorContextConsumer, type ColorTheme } from '../../lib/context/color/consumer.js'; @@ -16,8 +15,6 @@ import styles from './rh-tab-panel.css'; */ @customElement('rh-tab-panel') export class RhTabPanel extends LitElement { - static readonly version = '{{version}}'; - static readonly styles = [styles]; /** @@ -46,9 +43,9 @@ export class RhTabPanel extends LitElement { } render() { - const { on = '' } = this; + const { on = 'light' } = this; return html` -
          +
          `; diff --git a/elements/rh-tabs/rh-tab.css b/elements/rh-tabs/rh-tab.css index 94a2f199a0..fe57782f88 100644 --- a/elements/rh-tabs/rh-tab.css +++ b/elements/rh-tabs/rh-tab.css @@ -3,20 +3,22 @@ flex: none; --_active-tab-border: - var(--rh-border-width-lg, 3px) solid var( - --_active-tab-border-color, - var( - --rh-tabs-active-border-color, - var(--rh-color-accent-brand-on-light, #ee0000) - ) - ); + var(--rh-border-width-lg, 3px) solid var(--_active-tab-border-color, + var(--rh-tabs-active-border-color, + var(--rh-color-accent-brand))); --_active-tab-border-open: var(--rh-border-width-sm, 1px) solid - var(--_context-background-color, var(--rh-color-white, #ffffff)); + var(--rh-color-surface); } -.vertical [part="text"] { +[part='text'] { + display: inline; + line-height: var(--rh-line-height-heading, 1.3); + text-wrap: balance; +} + +.vertical [part='text'] { max-width: 100%; overflow-wrap: break-word; } @@ -25,17 +27,17 @@ display: none !important; } -slot[name="icon"] { +slot[name='icon'] { display: block; } +[part='icon'] { + margin-inline-end: var(--rh-space-md, 8px); +} + #button { - --_button-text-color: - var( - --rh-tabs-link-color, - var(--rh-color-text-secondary-on-light, #4d4d4d) - ); - --_button-focus-outline-color: var(--rh-color-border-interactive-on-light, #0066cc); + --_button-text-color: var(--rh-tabs-link-color, var(--rh-color-text-secondary)); + --_button-focus-outline-color: var(--rh-color-border-interactive); margin: 0; font-family: inherit; @@ -52,246 +54,367 @@ slot[name="icon"] { width: 100%; max-width: var(--_tab-max-width, 200px); max-height: 100%; + line-height: 0; padding: var(--rh-tabs-link-padding-block-start, var(--rh-space-lg, 16px)) var(--rh-tabs-link-padding-inline-end, var(--rh-space-2xl, 32px)) var(--rh-tabs-link-padding-block-end, var(--rh-space-lg, 16px)) var(--rh-tabs-link-padding-inline-start, var(--rh-space-2xl, 32px)); -} - -#button:before, -#button:after { - position: absolute; - inset: 0; - content: ""; - border-style: solid; - padding: 0; - margin: 0; - background-color: transparent; -} - -#button:before { - pointer-events: none; - border: 0 solid transparent; -} - -#button:focus-visible { - outline: var(--rh-border-width-md, 2px) solid var(--_button-focus-outline-color); - outline-offset: -8px; - border-radius: 10px; -} - -#button:after { - background-color: transparent; - border-inline: 0 solid transparent; - border-block-start: var(--rh-border-width-lg, 3px) solid transparent; - border-block-end: var(--rh-border-width-sm, 1px) solid transparent; -} - -:host([fill]) #button { - flex-basis: 100%; - justify-content: center; -} - -:host(:disabled) #button { - pointer-events: none; -} - -:host([aria-disabled="true"]) #button { - cursor: default; -} - -:host(:focus-visible) { - outline: none; -} - -:host(:is(:focus, :focus-visible)) #button { - outline: 1px auto var(--rh-color-interactive-blue-darker, #0066cc); - outline-offset: calc(var(--rh-space-md, 8px) * -1); -} - -#button.dark { - --_button-text-color: - var( - --rh-tabs-link-color, - var(--rh-color-text-secondary-on-dark, #c7c7c7) - ); - --_button-focus-outline-color: var(--rh-color-border-interactive-on-dark, #92c5f9); -} - -/* Context switch on attributes */ -#button.active { - --_button-text-color: - var( - --rh-tabs-link-color, - var(--rh-color-text-primary-on-light, #151515) - ); -} - -#button.active.dark { - --_button-text-color: - var( - --rh-tabs-link-color, - var(--rh-color-text-primary-on-dark, #ffffff) - ); -} - -/* Box context */ -#button.box { - --_inactive-tab-background-color: var(--rh-color-surface-lighter, #f2f2f2); -} - -#button.dark.box { - --_inactive-tab-background-color: var(--rh-color-surface-dark, #383838); -} - -#button.vertical { - text-align: start; -} - -[part="icon"] { - margin-inline-end: var(--rh-space-md, 8px); -} - -#button.active:not(.box, .vertical):after { - border-block-end: var(--_active-tab-border); -} - -#button.active.box:before { - border-inline-color: var(--_border-color); - border-inline-start-width: var(--rh-border-width-sm, 1px); -} - -#button.active.box:after { - border-block-start: var(--_active-tab-border); - border-block-end: var(--_active-tab-border-open); -} - -#button.box:not(.active) { - background-color: var(--_inactive-tab-background-color); -} - -#button.box:not(.active):before { - border-inline-color: var(--_border-color); - border-inline-start-width: var(--rh-border-width-sm, 1px); -} - -#button.box:not(.active):after { - border-block-end-color: var(--_border-color); -} - -#button.box.active.first:before { - border-inline-start-color: var(--_border-color); - border-inline-start-width: var(--rh-border-width-sm, 1px); -} -#button.first.box:not(.active):before { - border-inline-color: transparent; -} - -#button.last.box.active:before { - border-inline-end-color: var(--_border-color); - border-inline-end-width: var(--rh-border-width-sm, 1px); -} - -@media screen and (min-width: 768px) { - #button.vertical:not(.box) { - padding-block: - var(--rh-tabs-link-padding-block-start, var(--rh-space-md, 8px)) - var(--rh-tabs-link-padding-block-start, var(--rh-space-md, 8px)); + &:before, + &:after { + position: absolute; + inset: 0; + content: ''; + border-style: solid; + padding: 0; + margin: 0; + background-color: transparent; } - #button.vertical.active:after { - border-block-end: transparent; + &:before { + pointer-events: none; + border: 0 solid transparent; } - #button.box:not(.vertical, .active):before { - border-inline-color: var(--_border-color); - border-inline-start-width: var(--rh-border-width-sm, 1px); + &:after { + background-color: transparent; + border-inline: 0 solid transparent; + border-block-start: var(--rh-border-width-lg, 3px) solid transparent; + border-block-end: var(--rh-border-width-sm, 1px) solid transparent; } - #button.box.vertical:not(.active):before { - border-inline-start-color: transparent; - border-inline-end: - var(--rh-border-width-sm, 1px) - solid - var(--_border-color); - border-block-start: - var(--rh-border-width-sm, 1px) - solid - var(--_border-color); + /* When button is box */ + &.box { + --_inactive-tab-background-color: var(--rh-color-surface-lighter, #f2f2f2); } - #button.box:not(.active, .vertical):after { - border-block-end-color: var(--_border-color); + /* When button is vertical format */ + &.vertical { + text-align: start; + padding-inline: var(--rh-space-lg, 16px); + + &.box { + @container (min-width: 768px) { + &.first { + margin-block-start: var(--rh-space-2xl, 32px); + } + + &.last { + margin-block-end: var(--rh-space-2xl, 32px); + } + } + } + + &:not(.box) { + @container (min-width: 768px) { + padding-block: + var(--rh-tabs-link-padding-block-start, var(--rh-space-md, 8px)) + var(--rh-tabs-link-padding-block-end, var(--rh-space-md, 8px)); + + &.first { + margin-block-start: var(--rh-space-xl, 24px); + } + + &.last { + margin-block-end: var(--rh-space-xl, 24px); + } + } + } } - #button.active.box.vertical:after { - border-block-start: - var(--rh-border-width-sm, 1px) - solid - var(--_border-color); + /* When button is active */ + &.active { + --_button-text-color: var(--rh-tabs-link-color, var(--rh-color-text-primary)); + + &.box { + &:before { + border-inline-color: var(--_border-color); + border-inline-start-width: var(--rh-border-width-sm, 1px); + } + + &:after { + border-block-start: var(--_active-tab-border); + border-block-end: var(--_active-tab-border-open); + } + + &.first { + &:before { + border-inline-start-color: var(--_border-color); + border-inline-start-width: var(--rh-border-width-sm, 1px); + } + } + + &.last { + &:before { + border-inline-end-color: var(--_border-color); + border-inline-end-width: var(--rh-border-width-sm, 1px); + } + } + + &.vertical { + @container (min-width: 768px) { + &:before { + border-inline-start: var(--_active-tab-border); + border-inline-end: var(--_active-tab-border-open); + } + + &:after { + border-block-start: + var(--rh-border-width-sm, 1px) + solid + var(--_border-color); + } + } + + &.first { + @container (min-width: 768px) { + &:after { + border-block-start-color: var(--_border-color); + border-block-start-width: var(--rh-border-width-sm, 1px); + } + } + } + + &.last { + @container (min-width: 768px) { + &:before { + border-block-end-color: var(--_border-color); + border-block-end-width: var(--rh-border-width-sm, 1px); + } + } + } + } + + &:not(.vertical) { + &.first { + @container (min-width: 768px) { + &:before { + border-inline-start-color: var(--_border-color); + border-inline-start-width: var(--rh-border-width-sm, 1px); + } + } + } + + &.last { + @container (min-width: 768px) { + &:before { + border-inline-end-color: var(--_border-color); + border-inline-end-width: var(--rh-border-width-sm, 1px); + } + } + } + + @container (min-width: 768px) { + &:after { + border-block-start: var(--_active-tab-border); + border-block-end: var(--_active-tab-border-open); + } + } + } + } + + &.vertical { + @container (max-width: 767px) { + &:after { + border-block-start: var(--_active-tab-border); + } + } + + @container (min-width: 768px) { + &:after { + border-block-end: transparent; + } + } + } + + &:not(.box) { + &.vertical { + @container (max-width: 767px) { + &:after { + border-block-start: transparent; + border-block-end: var(--_active-tab-border); + } + } + + @container (min-width: 768px) { + &:before { + border-inline-start: var(--_active-tab-border); + } + + &:after { + border-block-end: transparent; + } + } + } + + &:not(.vertical) { + &:after { + border-block-end: var(--_active-tab-border); + } + } + } } - #button.box.vertical:not(.active):after { - border-block-end-color: transparent; + &:not(.active) { + &.box { + background-color: var(--_inactive-tab-background-color); + + &:before { + border-inline-color: var(--_border-color); + border-inline-start-width: var(--rh-border-width-sm, 1px); + } + + &:after { + border-block-end-color: var(--_border-color); + } + + &.vertical { + &:hover { + &:before { + border-block-start: + var(--rh-border-width-lg, 3px) + solid + var(--rh-color-interactive-secondary-default); + } + } + + @container (min-width: 768px) { + &:before { + border-inline-start-color: transparent; + border-inline-end: + var(--rh-border-width-sm, 1px) + solid + var(--_border-color); + border-block-start: + var(--rh-border-width-sm, 1px) + solid + var(--_border-color); + } + + &:after { + border-block-end-color: transparent; + } + + &:hover { + &:before { + border-inline-start: + var(--rh-border-width-lg, 3px) + solid + var(--rh-color-interactive-secondary-default); + border-block-start: + var(--rh-border-width-sm, 1px) + solid + var(--_border-color); + } + } + + &.first { + @container (min-width: 768px) { + &:before { + border-block-start-color: transparent; + border-inline-end-color: var(--_border-color); + } + } + } + + &.last { + @container (min-width: 768px) { + &:after { + border-block-end: none; + } + } + } + } + } + + &:not(.vertical) { + &:hover { + &:before { + border-block-start: + var(--rh-border-width-lg, 3px) + solid + var(--rh-color-interactive-secondary-default); + } + } + + @container (min-width: 768px) { + &:after { + border-block-end-color: var(--_border-color); + } + } + } + + &.first { + &:before { + border-inline-color: transparent; + } + } + } + + &:not(.box) { + &.vertical { + &:hover { + @container (max-width: 767px) { + &:after { + border-block-end: + var(--rh-border-width-lg, 3px) + solid + var(--rh-color-interactive-secondary-default); + } + } + + @container (min-width: 768px) { + &:after { + border-inline-start: + var(--rh-border-width-lg, 3px) + solid + var(--rh-color-interactive-secondary-default); + } + } + } + } + } + + &:not(.vertical, .box) { + &:hover { + &:before { + border-block-end: + var(--rh-border-width-lg, 3px) + solid + var(--rh-color-interactive-secondary-default); + } + } + } } - #button.vertical.box.first { - margin-block-start: var(--rh-space-2xl, 32px); - } + /* When button is in a dark context */ + &.dark { + --_button-text-color: var(--rh-tabs-link-color, var(--rh-color-text-secondary)); + --_button-focus-outline-color: var(--rh-color-border-interactive); + --_inactive-tab-background-color: var(--rh-color-surface-dark-alt, #292929); - #button.vertical.box.last { - margin-block-end: var(--rh-space-2xl, 32px); - } - - #button.first.vertical:not(.box) { - margin-block-start: var(--rh-space-xl, 24px); - } - - #button.last.vertical:not(.box) { - margin-block-end: var(--rh-space-xl, 24px); - } - - #button.active.box:not(.vertical):after { - border-block-start: var(--_active-tab-border); - border-block-end: var(--_active-tab-border-open); - } - - #button.first.box.vertical.active:after { - border-block-start-color: var(--_border-color); - border-block-start-width: var(--rh-border-width-sm, 1px); - } - - #button.box.vertical.active:before { - border-inline-start: var(--_active-tab-border); - border-inline-end: var(--_active-tab-border-open); - } - - #button.vertical.active:not(.box):before { - border-inline-start: var(--_active-tab-border); - } - - #button.first.vertical.box:not(.active):before { - border-block-start-color: transparent; - } - - #button.first.box.active:not(.vertical):before { - border-inline-start-color: var(--_border-color); - border-inline-start-width: var(--rh-border-width-sm, 1px); + &.active { + --_button-text-color: var(--rh-tabs-link-color, var(--rh-color-text-primary)); + } } +} - #button.last.box.active:not(.vertical):before { - border-inline-end-color: var(--_border-color); - border-inline-end-width: var(--rh-border-width-sm, 1px); +:host(:disabled) { + & #button { + pointer-events: none; } +} - #button.last.box.vertical.active:before { - border-block-end-color: var(--_border-color); - border-block-end-width: var(--rh-border-width-sm, 1px); +:host([aria-disabled='true']) { + & #button { + cursor: default; } +} - #button.last.box.vertical:not(.active):after { - border-block-end: none; +:host(:is(:focus, :focus-within)) { + & #button { + outline: 1px auto var(--rh-color-interactive-primary-default); + outline-offset: -3px; } } diff --git a/elements/rh-tabs/rh-tab.ts b/elements/rh-tabs/rh-tab.ts index 8da740d321..0257216b6e 100644 --- a/elements/rh-tabs/rh-tab.ts +++ b/elements/rh-tabs/rh-tab.ts @@ -44,8 +44,6 @@ export class TabExpandEvent extends Event { */ @customElement('rh-tab') export class RhTab extends LitElement { - static readonly version = '{{version}}'; - static readonly styles = [styles]; /** True when the tab is selected */ @@ -76,7 +74,7 @@ export class RhTab extends LitElement { } render() { - const { active, on = '' } = this; + const { active, on = 'light' } = this; const { box = false, vertical = false, firstTab, lastTab } = this.ctx ?? {}; const first = firstTab === this; const last = lastTab === this; @@ -84,7 +82,7 @@ export class RhTab extends LitElement {
          + class="${classMap({ active, box, vertical, first, last, on: true, [on]: true })}"> +
          ${!this.#overflow.showScrollButtons ? '' : html` -
          ${!this.#overflow.showScrollButtons ? '' : html` -
          @@ -240,6 +240,20 @@ export class RhTile extends LitElement { `; } + #renderLinkIcon() { + if (this.checkable) { + return ''; + } else if (this.disabled) { + return html``; + } else if (this.link === 'private') { + return html``; + } else if (this.link === 'external') { + return html``; + } else { + return html``; + } + } + async formDisabledCallback() { await this.updateComplete; this.requestUpdate(); diff --git a/elements/rh-timestamp/docs/10-style.md b/elements/rh-timestamp/docs/10-style.md index 37e190adc5..97182702b2 100644 --- a/elements/rh-timestamp/docs/10-style.md +++ b/elements/rh-timestamp/docs/10-style.md @@ -5,7 +5,7 @@ A timestamp is a simple line of text that displays date and time values.
          - Anatomy of a timestamp which is a simple line of text showing the date first and then the time after + Anatomy of a timestamp which is a simple line of text showing the date first and then the time after
            @@ -20,7 +20,7 @@ A timestamp is a simple line of text that displays date and time values. The size of a timestamp is determined by the text size it is applied to. - Two lines of text of various sizes with timestamps applied, one is 18px and the other is 24px + Two lines of text of various sizes with timestamps applied, one is 18px and the other is 24px @@ -28,7 +28,7 @@ The size of a timestamp is determined by the text size it is applied to. Two lines of text with timestamps applied, one is showing no styling and the other is showing a dashed underline. - Light theme badge + Light theme badge diff --git a/elements/rh-timestamp/docs/20-guidelines.md b/elements/rh-timestamp/docs/20-guidelines.md index c332b08143..378716f629 100644 --- a/elements/rh-timestamp/docs/20-guidelines.md +++ b/elements/rh-timestamp/docs/20-guidelines.md @@ -116,7 +116,7 @@ The format of the displayed content can be further customized by setting the cus To add a tooltip that displays the timestamp content as a UTC time, you can wrap `rh-timestamp` with `rh-tooltip` and set the `UTC` attribute on an additional `rh-timestamp`. - Timestamp with a tooltip on top showing the time with the UTC acronym at the end + Timestamp with a tooltip on top showing the time with the UTC acronym at the end @@ -128,7 +128,7 @@ To add a tooltip that displays the timestamp content as a UTC time, you can wrap - Timestamp with a tooltip on top showing the time and the words Coordinated Universal Time at the end + Timestamp with a tooltip on top showing the time and the words Coordinated Universal Time at the end @@ -169,7 +169,7 @@ To display relative time, set the `relative` attribute on `rh-timestamp`. To display relative time, set the `relative` attribute on `rh-timestamp`. - Timestamp with a tooltip on top showing what the date and time would be 11 months previous + Timestamp with a tooltip on top showing what the date and time would be 11 months previous @@ -181,7 +181,7 @@ To display relative time, set the `relative` attribute on `rh-timestamp`. - Timestamp with a tooltip on top showing what the date and time would be in one year + Timestamp with a tooltip on top showing what the date and time would be in one year @@ -239,14 +239,14 @@ Just like text, a timestamp will break to two lines as breakpoints get smaller. ### Large breakpoints - Timestamp text on desktop and tablet breakpoints + Timestamp text on desktop and tablet breakpoints ### Small breakpoints - Timestamp text on large and small mobile breakpoints with the smallest mobile example breaking to two lines + Timestamp text on large and small mobile breakpoints with the smallest mobile example breaking to two lines diff --git a/elements/rh-tooltip/docs/00-overview.md b/elements/rh-tooltip/docs/00-overview.md index 525d3ddd5c..ea1392f980 100644 --- a/elements/rh-tooltip/docs/00-overview.md +++ b/elements/rh-tooltip/docs/00-overview.md @@ -3,7 +3,7 @@ {{ tagName | getElementDescription }} - A black tooltip on top of a gray disabled button + A black tooltip on top of a gray disabled button {% repoStatusList repoStatus=repoStatus %} diff --git a/elements/rh-tooltip/docs/10-style.md b/elements/rh-tooltip/docs/10-style.md index 805345ab71..36ff06c836 100644 --- a/elements/rh-tooltip/docs/10-style.md +++ b/elements/rh-tooltip/docs/10-style.md @@ -6,7 +6,7 @@ A tooltip is a container with text that includes an arrow and sometimes a drop s ### Anatomy
            - Anatomy of a tooltip with annotations; number 1 is pointing to the container, number 2 is pointing to the text, number 3 is pointing to the arrow, and number 4 is pointing to the trigger + Anatomy of a tooltip with annotations; number 1 is pointing to the container, number 2 is pointing to the text, number 3 is pointing to the arrow, and number 4 is pointing to the trigger
              @@ -27,14 +27,14 @@ A tooltip is available in both light and dark themes. The dark theme tooltip con ### Light theme - Light theme tooltip which is black + Light theme tooltip which is black ### Dark theme - Dark theme tooltip which is white + Dark theme tooltip which is white @@ -43,14 +43,14 @@ A tooltip is available in both light and dark themes. The dark theme tooltip con All badges have the same height and border radius. - How a tooltip is constructed showing alignment, border radius, and arrow details + How a tooltip is constructed showing alignment, border radius, and arrow details ## Space - Tooltip spacing both within the element and in between the element and trigger + Tooltip spacing both within the element and in between the element and trigger @@ -73,5 +73,5 @@ A tooltip has a `300ms` entry delay on hover by default, but this can be customi A tooltip appears near an icon or element on hover, focus, or when tapped. A tooltip contains only text and is not interactive. - Tooltip trigger interaction states + Tooltip trigger interaction states diff --git a/elements/rh-tooltip/docs/20-guidelines.md b/elements/rh-tooltip/docs/20-guidelines.md index b6e30ee2f2..caa37b78d1 100644 --- a/elements/rh-tooltip/docs/20-guidelines.md +++ b/elements/rh-tooltip/docs/20-guidelines.md @@ -17,7 +17,7 @@ A tooltip and [Popover](/elements/popover) provide more information in context f Content in a tooltip is limited to text only. Consider the following when writing tooltip content. - Various text examples; from left to right, the text length starts very short, but gets longer and longer + Various text examples; from left to right, the text length starts very short, but gets longer and longer @@ -48,7 +48,7 @@ A tooltip's body text should be short and descriptive. The correct orientation of a tooltip depends on the amount of content and browser window. If a tooltip covers up important information or gets cut off, choose a different orientation. - Various orientation examples; from left to right and top to bottom, top, right, bottom, and left + Various orientation examples; from left to right and top to bottom, top, right, bottom, and left @@ -57,7 +57,7 @@ The correct orientation of a tooltip depends on the amount of content and browse When a cursor or focus is moved, the tooltip disappears. On mobile devices, users must tap to trigger a tooltip and then tap again to make it disappear. - Various behavior examples; from top to bottom, how a tooltip behaves when the trigger is hovered, focused, and tapped + Various behavior examples; from top to bottom, how a tooltip behaves when the trigger is hovered, focused, and tapped @@ -66,7 +66,7 @@ When a cursor or focus is moved, the tooltip disappears. On mobile devices, user A tooltip can generally be used on both large and small breakpoints if the content is not too long. - Examples of a tooltip used on large and small breakpoints + Examples of a tooltip used on large and small breakpoints @@ -77,7 +77,7 @@ A tooltip can generally be used on both large and small breakpoints if the conte Do not use a dark theme tooltip in light theme environments. - A dark theme or white tooltip used on a white background is incorrect usage + A dark theme or white tooltip used on a white background is incorrect usage @@ -86,7 +86,7 @@ Do not use a dark theme tooltip in light theme environments. A tooltip should not be cut off by the browser window. Change the orientation if it does. - If using the top orientation will cause the tooltip to get cut off, that is incorrect usage + If using the top orientation will cause the tooltip to get cut off, that is incorrect usage @@ -95,5 +95,5 @@ A tooltip should not be cut off by the browser window. Change the orientation if Do not add a tooltip to interface elements or actions that do not require further explanation. - Pairing a tooltip with an element that already has adequate descriptive text is incorrect usage + Pairing a tooltip with an element that already has adequate descriptive text is incorrect usage diff --git a/elements/rh-tooltip/docs/40-accessibility.md b/elements/rh-tooltip/docs/40-accessibility.md index 53937830d5..97a355a292 100644 --- a/elements/rh-tooltip/docs/40-accessibility.md +++ b/elements/rh-tooltip/docs/40-accessibility.md @@ -3,7 +3,7 @@ A tooltip will appear when the trigger receives focus and disappear when moving focus away from the trigger. - Tooltip keyboard interactions; pressing tab to focus the trigger will show the tooltip, but pressing tab again will hide the tooltip + Tooltip keyboard interactions; pressing tab to focus the trigger will show the tooltip, but pressing tab again will hide the tooltip diff --git a/elements/rh-tooltip/rh-tooltip.css b/elements/rh-tooltip/rh-tooltip.css index 2bd0e0e8e2..96abe54af2 100644 --- a/elements/rh-tooltip/rh-tooltip.css +++ b/elements/rh-tooltip/rh-tooltip.css @@ -9,10 +9,8 @@ /* WARNING: properties containing `__`are deprecated and will be removed */ --_floating-arrow-size: - var( - --rh-tooltip-arrow-size, - var(--rh-tooltip__arrow--Width, 11px) - ); + var(--rh-tooltip-arrow-size, + var(--rh-tooltip__arrow--Width, 11px)); } #tooltip, @@ -40,44 +38,27 @@ /* WARNING: properties containing `__`are deprecated and will be removed */ padding: - var( - --rh-tooltip-content-padding-block-start, - var(--rh-tooltip__content--PaddingTop, var(--rh-space-lg, 16px)) - ) - var( - --rh-tooltip-content-padding-inline-end, - var(--rh-tooltip__content--PaddingRight, var(--rh-space-lg, 16px)) - ) - var( - --rh-tooltip-content-padding-block-end, - var(--rh-tooltip__content--PaddingBottom, var(--rh-space-lg, 16px)) - ) - var( - --rh-tooltip-content-padding-inline-start, - var(--rh-tooltip__content--PaddingLeft, var(--rh-space-lg, 16px)) - ); + var(--rh-tooltip-content-padding-block-start, + var(--rh-tooltip__content--PaddingTop, var(--rh-space-lg, 16px))) + var(--rh-tooltip-content-padding-inline-end, + var(--rh-tooltip__content--PaddingRight, var(--rh-space-lg, 16px))) + var(--rh-tooltip-content-padding-block-end, + var(--rh-tooltip__content--PaddingBottom, var(--rh-space-lg, 16px))) + var(--rh-tooltip-content-padding-inline-start, + var(--rh-tooltip__content--PaddingLeft, var(--rh-space-lg, 16px))); /* WARNING: properties containing `__`are deprecated and will be removed */ font-size: - var( - --rh-tooltip-content-font-size, - var(--rh-tooltip__content--FontSize, var(--rh-font-size-body-text-sm, 0.875rem)) - ); + var(--rh-tooltip-content-font-size, + var(--rh-tooltip__content--FontSize, var(--rh-font-size-body-text-sm, 0.875rem))); /* WARNING: properties containing `__`are deprecated and will be removed */ color: - var( - --rh-tooltip-content-color, - var(--rh-tooltip__content--Color, var(--rh-color-text-primary-on-dark, #ffffff)) - ); + var(--rh-tooltip-content-color, + var(--rh-tooltip__content--Color, var(--rh-color-text-primary-on-dark, #ffffff))); background-color: - var( - --rh-tooltip-content-background-color, - var( - --rh-tooltip__content--BackgroundColor, - var(--rh-color-surface-darkest, #151515) - ) - ); + var(--rh-tooltip-content-background-color, + var(--rh-tooltip__content--BackgroundColor, var(--rh-color-surface-darkest, #151515))); } .initialized #tooltip { @@ -86,16 +67,14 @@ #tooltip:after { display: block; - content: ""; + content: ''; rotate: 45deg; width: var(--_floating-arrow-size); height: var(--_floating-arrow-size); will-change: left top right bottom; background-color: - var( - --rh-tooltip-content-background-color, - var(--rh-color-surface-darkest, #151515) - ); + var(--rh-tooltip-content-background-color, + var(--rh-tooltip__content--BackgroundColor, var(--rh-color-surface-darkest, #151515))); } .c { @@ -130,9 +109,9 @@ .right.end #tooltip:after { inset-block-end: var(--_floating-arrow-size); } .bottom.end #tooltip:after { inset-inline-end: var(--_floating-arrow-size); } -:host([position="left"]), -:host([position="right"]) { - --_text-alignment: "start"; +:host([position='left']), +:host([position='right']) { + --_text-alignment: 'start'; } .dark { diff --git a/elements/rh-video-embed/docs/00-overview.md b/elements/rh-video-embed/docs/00-overview.md index 1eaa828fe3..a384a7e5dd 100644 --- a/elements/rh-video-embed/docs/00-overview.md +++ b/elements/rh-video-embed/docs/00-overview.md @@ -5,7 +5,7 @@ A video embed element is a graphical preview of a video overlayed with a play button. When clicked, the YouTube video will begin playing. - Red Hat Logo on a gray background + Red Hat Logo on a gray background {% repoStatusList repoStatus=repoStatus %} @@ -14,7 +14,7 @@ A video embed element is a graphical preview of a video overlayed with a play bu
              - Red Hat Logo on a gray background + Red Hat Logo on a gray background diff --git a/elements/rh-video-embed/docs/10-style.md b/elements/rh-video-embed/docs/10-style.md index 0a75064962..e43324fa6c 100644 --- a/elements/rh-video-embed/docs/10-style.md +++ b/elements/rh-video-embed/docs/10-style.md @@ -6,7 +6,7 @@ The video embed element consists of a semitransparent play button with a video t
              - Anatomy of a video component with numbered annotations. + Anatomy of a video component with numbered annotations.
                @@ -23,11 +23,11 @@ The video embed element is available in both light and dark themes. It can inclu
                - Light theme video with the Red Hat logo and a play button on a light gray background + Light theme video with the Red Hat logo and a play button on a light gray background - Dark theme video with the Red Hat logo and a play button on a black background + Dark theme video with the Red Hat logo and a play button on a black background
                @@ -39,15 +39,15 @@ The caption can be left-, right-, or center-aligned, depending on how the video
                - Video with caption, below, left aligned + Video with caption, below, left aligned - Video with caption, below, center aligned + Video with caption, below, center aligned - Video with caption, below, right aligned + Video with caption, below, right aligned
                @@ -57,7 +57,7 @@ The caption can be left-, right-, or center-aligned, depending on how the video Space values remain the same at all viewport sizes. - Diagram of spacing for video + Diagram of spacing for video @@ -71,11 +71,11 @@ The play button’s opacity increases upon hover.
                - Light theme video on a gray background with a darker play button on hover + Light theme video on a gray background with a darker play button on hover - Dark theme video on a black background with a lighter play button on hover + Dark theme video on a black background with a lighter play button on hover
                @@ -85,11 +85,11 @@ On focus, the entire video embed element is outlined by a focus ring, and the pl
                - Light theme video with a focus ring outlining the video and a darker play button + Light theme video with a focus ring outlining the video and a darker play button - Dark theme video with a focus ring outlining the video and a lighter play button + Dark theme video with a focus ring outlining the video and a lighter play button
                @@ -99,10 +99,10 @@ The active state is the same as the focus state.
                - Light theme video with a focus ring outlining the video and a darker play button + Light theme video with a focus ring outlining the video and a darker play button - Dark theme video with a focus ring outlining the video and a lighter play button + Dark theme video with a focus ring outlining the video and a lighter play button
                diff --git a/elements/rh-video-embed/docs/20-guidelines.md b/elements/rh-video-embed/docs/20-guidelines.md index 146034e964..ab605c091b 100644 --- a/elements/rh-video-embed/docs/20-guidelines.md +++ b/elements/rh-video-embed/docs/20-guidelines.md @@ -9,7 +9,7 @@ For users that do not have advertising cookies enabled, the video embed element Check the [Code subpage](/elements/video-embed/code/) for information about [attributes](/elements/video-embed/code/#rh-video-embed) and [events](/elements/video-embed/code/#rh-video-embed) that will help you implement the cookie consent thumbnail and integrate it with the preferred cookie consent manager. View the [Require Consent demo](/elements/video-embed/demo/require-consent/) to see a standalone implementation of this functionality. - Video displaying the cookie consent which says, 'View this video by opting into Advertising Cookies.' It also has an 'Update Preferences button'. + Video displaying the cookie consent which says, 'View this video by opting into Advertising Cookies.' It also has an 'Update Preferences button'. ## Writing Content @@ -41,11 +41,11 @@ The video’s width will dynamically adjust with its parent container. The video ### Large Viewport Sizes -Video embed with a semitransparent grid in the background. The video embed only spans half the columns. +Video embed with a semitransparent grid in the background. The video embed only spans half the columns. ### Small Viewport sizes -Video embed with a semitransparent grid background on mobile. The video embed spans all columns on small viewports. +Video embed with a semitransparent grid background on mobile. The video embed spans all columns on small viewports. ## Best Practices @@ -56,14 +56,14 @@ Display the play button in a consistent, predictable spot for all videos.
                - Video with vertically and horizontally centered play button + Video with vertically and horizontally centered play button

                Keep the play button centered horizontally and vertically.

                - Video with play button in the bottom right + Video with play button in the bottom right

                Do not move the play button to another area of the video element.

                @@ -77,14 +77,14 @@ A video embed element and should have the same aspect ratio as the video it’s
                - Video embed with a correct, 16:9 aspect ratio + Video embed with a correct, 16:9 aspect ratio

                The video embed element should display a video using its original aspect ratio.

                - Video embed with a very narrow aspect ratio + Video embed with a very narrow aspect ratio

                Do not change the aspect ratio of the video within the video embed element.

                diff --git a/elements/rh-video-embed/docs/40-accessibility.md b/elements/rh-video-embed/docs/40-accessibility.md index eb9a1d105e..cf73b55f35 100644 --- a/elements/rh-video-embed/docs/40-accessibility.md +++ b/elements/rh-video-embed/docs/40-accessibility.md @@ -3,7 +3,7 @@ Users should have the ability to move focus to a video embed element and play the video using the keyboard. - Screenshots of a video embed showing a darkened play button on focus + Screenshots of a video embed showing a darkened play button on focus diff --git a/elements/rh-video-embed/rh-video-embed.css b/elements/rh-video-embed/rh-video-embed.css index 1a1dacce10..250546088b 100644 --- a/elements/rh-video-embed/rh-video-embed.css +++ b/elements/rh-video-embed/rh-video-embed.css @@ -20,12 +20,12 @@ } figure, -::slotted([slot="thumbnail"]), +::slotted([slot='thumbnail']), ::slotted(iframe) { max-width: 100%; } -::slotted([slot="thumbnail"]) { +::slotted([slot='thumbnail']) { display: block; } @@ -39,7 +39,7 @@ figure, } figure { - --_video-focus-border-color: var(--rh-color-border-interactive-on-light, #0066cc); + --_video-focus-border-color: var(--rh-color-border-interactive); --_video-play-btn-bkg-color: rgb(31 31 31 / var(--rh-opacity-50, 50%)); --_video-play-btn-interactive-bkg-color: rgb(21 21 21 / var(--rh-opacity-80, 80%)); @@ -49,10 +49,10 @@ figure { } figure.dark { - --_video-focus-border-color: var(--rh-color-border-interactive-on-dark, #92c5f9); + --_video-focus-border-color: var(--rh-color-border-interactive); --_video-play-btn-bkg-color: rgb(255 255 255 / var(--rh-opacity-20, 20%)); --_video-play-btn-interactive-bkg-color: rgb(255 255 255 / var(--rh-opacity-50, 50%)); - --_caption-text-color: var(--rh-color-text-secondary-on-dark, #c7c7c7); + --_caption-text-color: var(--rh-color-text-secondary); } figcaption { @@ -63,8 +63,8 @@ figcaption ::slotted(p) { margin-block-start: 0 !important; } -::slotted([slot="caption"]) { - color: var(--_caption-text-color, var(--rh-color-text-secondary-on-light, #4d4d4d)); +::slotted([slot='caption']) { + color: var(--_caption-text-color, var(--rh-color-text-secondary)); font-size: var(--rh-font-size-body-text-sm, 0.875rem) !important; line-height: var(--rh-line-height-body-text, 1.5); } @@ -90,20 +90,20 @@ figcaption ::slotted(p) { } #consent-message, -::slotted([slot="consent-message"]) { - 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", Helvetica, Arial, sans-serif); +::slotted([slot='consent-message']) { + 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', Helvetica, Arial, sans-serif); font-size: var(--rh-font-size-heading-xs, 1.25rem); line-height: var(--rh-line-height-heading, 1.3); } #consent-message, -::slotted([slot="consent-message"]:last-of-type) { +::slotted([slot='consent-message']:last-of-type) { margin-block-end: var(--rh-space-lg, 16px); } @container consent (min-width: 576px) { #consent-message, - ::slotted([slot="consent-message"]:last-of-type) { + ::slotted([slot='consent-message']:last-of-type) { margin-block-end: var(--rh-space-xl, 24px); } @@ -152,7 +152,7 @@ figcaption ::slotted(p) { } #play[hidden], -:is(.video, .consent) ::slotted([slot="thumbnail"]) { +:is(.video, .consent) ::slotted([slot='thumbnail']) { opacity: 0; pointer-events: none; } diff --git a/elements/rh-video-embed/rh-video-embed.ts b/elements/rh-video-embed/rh-video-embed.ts index 470548af8e..c4cb2dcb89 100644 --- a/elements/rh-video-embed/rh-video-embed.ts +++ b/elements/rh-video-embed/rh-video-embed.ts @@ -133,7 +133,7 @@ export class RhVideoEmbed extends LitElement { 'video' : 'thumbnail'; return html` -
                +
                diff --git a/eleventy.config.cjs b/eleventy.config.cjs index 64464613ec..cb04446a57 100644 --- a/eleventy.config.cjs +++ b/eleventy.config.cjs @@ -12,6 +12,7 @@ const DesignTokensPlugin = require('./docs/_plugins/tokens.cjs'); const RHDSMarkdownItPlugin = require('./docs/_plugins/markdown-it.cjs'); const ImportMapPlugin = require('./docs/_plugins/importMap.cjs'); const LitPlugin = require('@lit-labs/eleventy-plugin-lit'); +const HelmetPlugin = require('eleventy-plugin-helmet'); const util = require('node:util'); const exec = util.promisify(require('node:child_process').exec); @@ -21,7 +22,7 @@ const isWatch = const isLocal = !(process.env.CI || process.env.DEPLOY_URL); -/** @param {import('@11ty/eleventy/src/UserConfig')} eleventyConfig */ +/** @param {import('@11ty/eleventy').UserConfig} eleventyConfig */ module.exports = function(eleventyConfig) { eleventyConfig.setQuietMode(true); @@ -41,12 +42,15 @@ module.exports = function(eleventyConfig) { eleventyConfig.watchIgnores?.add('elements/*/test/'); eleventyConfig.watchIgnores?.add('lib/elements/*/test/'); eleventyConfig.addPassthroughCopy('docs/patterns/**/*.{svg,jpg,jpeg,png}'); + eleventyConfig.addPassthroughCopy('elements/*/demo/**/*.{svg,jpg,jpeg,png}'); eleventyConfig.addPassthroughCopy('docs/CNAME'); eleventyConfig.addPassthroughCopy('docs/.nojekyll'); eleventyConfig.addPassthroughCopy('docs/robots.txt'); eleventyConfig.addPassthroughCopy('docs/assets/**/*'); eleventyConfig.addPassthroughCopy('docs/styles/**/*'); eleventyConfig.addPassthroughCopy('docs/patterns/**/*.css'); + eleventyConfig.addPassthroughCopy('docs/theming/**/*.css'); + eleventyConfig.addPassthroughCopy('docs/foundations/**/*.{css,js}'); if (isLocal) { @@ -61,15 +65,17 @@ module.exports = function(eleventyConfig) { eleventyConfig.addGlobalData('isLocal', isLocal); eleventyConfig.addGlobalData('sideNavDropdowns', [ - { 'title': 'About', 'url': '/about', 'collection': 'about' }, - { 'title': 'Get started', 'url': '/get-started', 'collection': 'getstarted' }, - { 'title': 'Foundations', 'url': '/foundations', 'collection': 'foundations' }, - { 'title': 'Tokens', 'url': '/tokens', 'collection': 'token' }, - { 'title': 'Elements', 'url': '/elements', 'collection': 'elementDocs' }, - { 'title': 'Patterns', 'url': '/patterns', 'collection': 'pattern' }, - { 'title': 'Accessibility', 'url': '/accessibility', 'collection': 'accessibility' }, + { title: 'About', url: '/about', collection: 'about' }, + { title: 'Get started', url: '/get-started', collection: 'getstarted' }, + { title: 'Foundations', url: '/foundations', collection: 'foundations' }, + { title: 'Tokens', url: '/tokens', collection: 'tokenCategory' }, + { title: 'Elements', url: '/elements', collection: 'elementDocs' }, + { title: 'Theming', url: '/theming', collection: 'theming' }, + { title: 'Patterns', url: '/patterns', collection: 'pattern' }, + { title: 'Accessibility', url: '/accessibility', collection: 'accessibility' }, ]); + eleventyConfig.addPlugin(HelmetPlugin); eleventyConfig.addPlugin(RHDSMarkdownItPlugin); /** Table of Contents Shortcode */ @@ -90,12 +96,15 @@ module.exports = function(eleventyConfig) { nodemodulesPublicPath: '/assets/packages', manualImportMap: { imports: { + 'tinycolor2': '/assets/packages/tinycolor2/esm/tinycolor.js', 'lit/': '/assets/packages/lit/', 'lit-html': '/assets/packages/lit-html/lit-html.js', 'lit-html/': '/assets/packages/lit-html/', + 'prism-esm/': '/assets/packages/prism-esm/', '@lit-labs/ssr-client/lit-element-hydrate-support.js': '/assets/packages/@lit-labs/ssr-client/lit-element-hydrate-support.js', '@rhds/tokens': '/assets/packages/@rhds/tokens/js/tokens.js', + '@rhds/tokens/css/': '/assets/packages/@rhds/tokens/css/', '@rhds/tokens/': '/assets/packages/@rhds/tokens/js/', '@rhds/elements/lib/': '/assets/packages/@rhds/elements/lib/', '@rhds/elements/': '/assets/packages/@rhds/elements/elements/', @@ -110,6 +119,7 @@ module.exports = function(eleventyConfig) { localPackages: [ // ux-dot dependencies 'fuse.js', + 'tinycolor2', 'element-internals-polyfill', // RHDS dependencies @@ -119,6 +129,8 @@ module.exports = function(eleventyConfig) { '@rhds/tokens', '@rhds/tokens/media.js', '@rhds/tokens/meta.js', + '@rhds/tokens/css/color-context-provider.css.js', + '@rhds/tokens/css/color-context-consumer.css.js', '@rhds/icons/', '@rhds/icons/microns/', '@rhds/icons/social/', @@ -133,6 +145,8 @@ module.exports = function(eleventyConfig) { '@lit/context', '@lit/reactive-element', '@webcomponents/template-shadowroot/template-shadowroot.js', + 'prism-esm', + 'prism-esm/', 'lit', 'lit-element', 'lit-html', @@ -196,14 +210,17 @@ module.exports = function(eleventyConfig) { 'docs/assets/javascript/elements/uxdot-best-practice.js', 'docs/assets/javascript/elements/uxdot-search.js', 'docs/assets/javascript/elements/uxdot-toc.js', + // 'docs/assets/javascript/elements/uxdot-pattern.js', + // Uses context API need to work around issues + // 'docs/assets/javascript/elements/uxdot-example.js', + // extends RhTabs so cant DSD yet + // 'docs/assets/javascript/elements/uxdot-installation-tabs.js', 'elements/rh-button/rh-button.js', 'elements/rh-tag/rh-tag.js', + 'elements/rh-code-block/rh-code-block.js', 'elements/rh-icon/rh-icon.js', 'elements/rh-skip-link/rh-skip-link.js', 'elements/rh-footer/rh-footer-universal.js', - // 'docs/assets/javascript/elements/uxdot-pattern.js', - // 'docs/assets/javascript/elements/uxdot-example.js', // Uses context API need to work around issues - // 'docs/assets/javascript/elements/uxdot-installation-tabs.js', // extends RhTabs so cant DSD yet ], }); diff --git a/eslint.config.js b/eslint.config.js index 61d0aee4f2..97dee43457 100644 --- a/eslint.config.js +++ b/eslint.config.js @@ -26,6 +26,8 @@ export default tseslint.config( 'docs/core', 'docs/components', 'docs/assets/playgrounds', + 'docs/assets/javascript/elements/*.js.map', + 'docs/assets/javascript/elements/*.d.ts', 'docs/assets/javascript/elements/*.js', 'node_modules', @@ -45,6 +47,13 @@ export default tseslint.config( }, }, }, + { + name: 'local/docs/overrides', + files: ['docs/theming/code-samples/*.*'], + rules: { + '@stylistic/no-multi-spaces': ['off'], + }, + } ); diff --git a/lib/context/color/consumer.ts b/lib/context/color/consumer.ts index c6c4e07d37..201f25716c 100644 --- a/lib/context/color/consumer.ts +++ b/lib/context/color/consumer.ts @@ -8,6 +8,8 @@ import { import { ContextRequestEvent } from '../event.js'; +import styles from '@rhds/tokens/css/color-context-consumer.css.js'; + /** * A Color theme is a context-specific restriction on the available color palettes * @@ -52,7 +54,7 @@ export class ColorContextConsumer< #override: ColorTheme | null = null; constructor(host: T, private options?: ColorContextConsumerOptions) { - super(host); + super(host, styles); this.#propertyName = options?.propertyName ?? 'on' as keyof T; } @@ -74,7 +76,12 @@ export class ColorContextConsumer< contextEvents.delete(this.host); } - /** Register the dispose callback for hosts that requested multiple updates, then update the colour-context */ + /** + * Register the dispose callback for hosts that requested multiple updates, + * then update the colour-context + * @param value the color theme + * @param dispose cleanup callback + */ #contextCallback(value: ColorTheme | null, dispose?: () => void) { // protect against changing providers if (dispose && dispose !== this.#dispose) { @@ -84,7 +91,10 @@ export class ColorContextConsumer< this.update(value); } - /** Sets the `on` attribute on the host and any children that requested multiple updates */ + /** + * Sets the `on` attribute on the host and any children that requested multiple updates + * @param next the color theme + */ public update(next: ColorTheme | null) { const { last } = this; if (!this.#override && next !== last) { @@ -95,7 +105,13 @@ export class ColorContextConsumer< } } -export function colorContextConsumer(options?: ColorContextOptions) { +/** + * Makes this element a color context consumer + * @param options options + */ +export function colorContextConsumer< + T extends ReactiveElement +>(options?: ColorContextOptions) { return function(proto: T, _propertyName: string | keyof T) { const propertyName = _propertyName as keyof T; (proto.constructor as typeof ReactiveElement).addInitializer(instance => { diff --git a/lib/context/color/context-color.css b/lib/context/color/context-color.css deleted file mode 100644 index e7a9a67e02..0000000000 --- a/lib/context/color/context-color.css +++ /dev/null @@ -1,43 +0,0 @@ -/** - * It's important for `color-palette` to take precedence over `on` - * when setting `--context`, because a `dark` card that's on a `light` - * background must create a new `dark` context for its descendants - */ - -:host(:is([color-palette^="dark"])) { - --context: dark; - --_context-text: var(--rh-color-text-primary-on-dark, #ffffff); -} - -:host(:is([color-palette^="light"],[color-palette="base"])) { - --context: light; - --_context-text: var(--rh-color-text-primary-on-light, #151515); -} - -:host(:is([color-palette="lightest"])) { - --_context-background-color: var(--rh-color-surface-lightest, #ffffff); -} - -:host(:is([color-palette="lighter"])) { - --_context-background-color: var(--rh-color-surface-lighter, #f2f2f2); -} - -:host(:is([color-palette="light"])) { - --_context-background-color: var(--rh-color-surface-light, #e0e0e0); -} - -:host(:is([color-palette="base"])) { - --_context-background-color: var(--rh-color-surface-lightest, #ffffff); -} - -:host(:is([color-palette="dark"])) { - --_context-background-color: var(--rh-color-surface-dark, #383838); -} - -:host(:is([color-palette="darker"])) { - --_context-background-color: var(--rh-color-surface-darker, #1f1f1f); -} - -:host(:is([color-palette="darkest"])) { - --_context-background-color: var(--rh-color-surface-darkest, #151515); -} diff --git a/lib/context/color/controller.ts b/lib/context/color/controller.ts index 03889115b3..ad3c9063c5 100644 --- a/lib/context/color/controller.ts +++ b/lib/context/color/controller.ts @@ -1,17 +1,19 @@ import type { ColorTheme } from './consumer.js'; -import type { ReactiveController, ReactiveElement } from 'lit'; +import type { CSSResult, ReactiveController } from 'lit'; -import { StyleController } from '@patternfly/pfe-core/controllers/style-controller.js'; +import { ReactiveElement } from 'lit'; -import { createContext, type ContextRequestEvent } from '../event.js'; +import { StyleController } from '@patternfly/pfe-core/controllers/style-controller.js'; -import COLOR_CONTEXT_BASE_STYLES from './context-color.css'; +import { createContext, type ContextRequestEvent, type UnknownContext } from '../event.js'; export interface ColorContextOptions { prefix?: string; propertyName?: keyof T; } +type ColorContext = typeof ColorContextController.context; + /** * Maps from consumer host elements to already-fired request events * We hold these in memory in order to re-fire the events every time a new provider connects. @@ -30,9 +32,13 @@ export interface ColorContextOptions { */ export const contextEvents = new Map< ReactiveElement, - ContextRequestEvent + ContextRequestEvent >(); +export const isColorContextEvent = + (event: ContextRequestEvent): event is ContextRequestEvent => + event.context === ColorContextController.context; + /** * Color context is derived from the `--context` css custom property, * which *must* be set by the `color-palette` attribute @@ -48,9 +54,6 @@ export abstract class ColorContextController< /** The context object which acts as the key for providers and consumers */ public static readonly context = createContext(Symbol('rh-color-context')); - /** The style controller which provides the necessary CSS. */ - protected styleController: StyleController; - /** The last-known color context on the host */ protected last: ColorTheme | null = null; @@ -59,8 +62,12 @@ export abstract class ColorContextController< /** callback which updates the context value on consumers */ abstract update(next?: ColorTheme | null): void; - constructor(protected host: T) { - this.styleController = new StyleController(host, COLOR_CONTEXT_BASE_STYLES); + constructor(protected host: T, styles: CSSStyleSheet | CSSResult) { + new StyleController(host, styles); + if (this.host instanceof ReactiveElement) { + const Class = (this.host.constructor as typeof ReactiveElement); + Class.styles = [Class.styles].flat().filter(x => !!x).concat([styles]); + } host.addController(this); } } diff --git a/lib/context/color/provider.ts b/lib/context/color/provider.ts index df58dfcdb7..83f0469c6f 100644 --- a/lib/context/color/provider.ts +++ b/lib/context/color/provider.ts @@ -11,6 +11,8 @@ import { ColorContextConsumer, type ColorTheme } from './consumer.js'; import { Logger } from '@patternfly/pfe-core/controllers/logger.js'; +import styles from '@rhds/tokens/css/color-context-provider.css.js'; + /** * A `ColorPalette` is a collection of specific color values * Choosing a palette sets both color properties and, if the component is a context provider, @@ -89,7 +91,7 @@ export class ColorContextProvider< constructor(host: T, options?: ColorContextProviderOptions) { const { attribute = 'color-palette' } = options ?? {}; - super(host); + super(host, styles); this.#consumer = new ColorContextConsumer(host, { callback: value => this.update(value), }); @@ -132,22 +134,26 @@ export class ColorContextProvider< this.#mo.disconnect(); } - /** Was the context event fired requesting our colour-context context? */ + /** + * Was the context event fired requesting our colour-context context? + * @param event some event + */ #isColorContextEvent( event: ContextRequestEvent ): event is ContextRequestEvent { - return event.target !== this.host && event.context === ColorContextController.context; + return event.composedPath().at(0) !== this.host + && event.context === ColorContextController.context; } /** * Provider part of context API * When a child connects, claim its context-request event * and add its callback to the Set of children if it requests multiple updates + * @param event context-request event */ async #onChildContextRequestEvent(event: ContextRequestEvent) { // only handle ContextEvents relevant to colour context if (this.#isColorContextEvent(event)) { - // claim the context-request event for ourselves (required by context protocol) event.stopPropagation(); // Run the callback to initialize the child's colour-context @@ -160,7 +166,10 @@ export class ColorContextProvider< } } - /** Calls the context callback for all consumers */ + /** + * Calls the context callback for all consumers + * @param [force] override theme + */ public override async update(force?: ColorTheme) { const { value } = this; @@ -170,7 +179,10 @@ export class ColorContextProvider< } } -/** Makes this element a color context provider which updates its consumers when the decorated field changes */ +/** + * Makes this element a color context provider which updates its consumers when the decorated field changes + * @param options options + */ export function colorContextProvider(options?: ColorContextOptions) { return function(proto: T, _propertyName: string) { const propertyName = _propertyName as keyof T; diff --git a/lib/context/event.ts b/lib/context/event.ts index 7f0edff266..a8c2e18df3 100644 --- a/lib/context/event.ts +++ b/lib/context/event.ts @@ -28,6 +28,7 @@ export type ContextType = T extends Context( key: unknown, diff --git a/lib/elements/rh-context-demo/rh-context-demo.css b/lib/elements/rh-context-demo/rh-context-demo.css index afd290d92f..41513da610 100644 --- a/lib/elements/rh-context-demo/rh-context-demo.css +++ b/lib/elements/rh-context-demo/rh-context-demo.css @@ -5,8 +5,8 @@ position: relative; } -.light { color: var(--rh-color-text-primary-on-light, #151515); } -.dark { color: var(--rh-color-text-primary-on-dark, #ffffff); } +rh-surface, +.on { color: var(--rh-color-text-primary); } #picker-container { display: flex; diff --git a/lib/elements/rh-context-demo/rh-context-demo.ts b/lib/elements/rh-context-demo/rh-context-demo.ts index bf0ed51335..a859d945a3 100644 --- a/lib/elements/rh-context-demo/rh-context-demo.ts +++ b/lib/elements/rh-context-demo/rh-context-demo.ts @@ -1,18 +1,20 @@ import { LitElement, type PropertyValues, html } from 'lit'; import { customElement } from 'lit/decorators/custom-element.js'; import { property } from 'lit/decorators/property.js'; -import { classMap } from 'lit/directives/class-map.js'; +import { classMap } from 'lit-html/directives/class-map.js'; -import { type ColorPalette } from '../../context/color/provider.js'; +import { colorContextProvider, type ColorPalette } from '../../context/color/provider.js'; import { ContextChangeEvent } from '../rh-context-picker/rh-context-picker.js'; import '@rhds/elements/rh-surface/rh-surface.js'; import style from './rh-context-demo.css'; +import consumerStyles from '@rhds/tokens/css/color-context-consumer.css.js'; + @customElement('rh-context-demo') export class RhContextDemo extends LitElement { - static readonly styles = [style]; + static readonly styles = [style, consumerStyles]; static formAssociated = true; @@ -20,26 +22,27 @@ export class RhContextDemo extends LitElement { @property() label = 'Color Palette'; - @property({ attribute: 'color-palette', reflect: true }) colorPalette = this.value; + @colorContextProvider() + @property({ attribute: 'color-palette', reflect: true }) + colorPalette = this.value; #internals = this.attachInternals(); protected override render() { const { value = 'darkest' } = this; - const [on = 'dark'] = value.match(/dark|light/) ?? []; + const on = this.value.replace(/est|er/, ''); return html` -
                +
                - + `; } @@ -58,8 +61,13 @@ export class RhContextDemo extends LitElement { } #onChange(event: Event) { + const picker = this.shadowRoot?.getElementById('picker'); if (event instanceof ContextChangeEvent) { + if (event.target !== picker && event.provider && (event.provider !== this)) { + return; + } this.#setValue(event.colorPalette); + event.preventDefault(); } } diff --git a/lib/elements/rh-context-picker/rh-context-picker.css b/lib/elements/rh-context-picker/rh-context-picker.css index e3cc0b900b..e57c1d479b 100644 --- a/lib/elements/rh-context-picker/rh-context-picker.css +++ b/lib/elements/rh-context-picker/rh-context-picker.css @@ -1,8 +1,6 @@ :host { display: inline-flex; position: relative; - container-name: host; - container-type: inline-size; } * { @@ -10,11 +8,13 @@ } #container { - --thumb-color: var(--rh-color-interactive-blue-darker, #0066cc); + display: contents; + + --thumb-color: var(--rh-color-interactive-primary-default-on-light, #0066cc); } -#container.on-dark { - --thumb-color: var(--rh-color-interactive-blue-lighter, #92c5f9); +#container.on.dark { + --thumb-color: var(--rh-color-interactive-primary-default-on-dark, #92c5f9); } .darkest { --c: var(--rh-color-surface-darkest, #151515); } @@ -49,7 +49,7 @@ input { input:before { display: block; - content: ""; + content: ''; background: var(--c); border-radius: 50%; position: absolute; @@ -59,7 +59,7 @@ input:before { input:checked:after { display: block; - content: ""; + content: ''; background: var(--alt-color); border-radius: 50%; position: absolute; diff --git a/lib/elements/rh-context-picker/rh-context-picker.ts b/lib/elements/rh-context-picker/rh-context-picker.ts index a3810a0c88..112b25fca5 100644 --- a/lib/elements/rh-context-picker/rh-context-picker.ts +++ b/lib/elements/rh-context-picker/rh-context-picker.ts @@ -1,10 +1,11 @@ import type { ColorPalette } from '@rhds/elements/lib/context/color/provider.js'; -import type { Color } from '@rhds/tokens/js/types.js'; +import type { Color } from '@rhds/tokens'; import type { ColorTheme } from '@rhds/elements/lib/context/color/consumer.js'; -import { html, LitElement } from 'lit'; +import { html, LitElement, type ComplexAttributeConverter } from 'lit'; import { customElement } from 'lit/decorators/custom-element.js'; import { property } from 'lit/decorators/property.js'; +import { classMap } from 'lit/directives/class-map.js'; import { colorContextConsumer } from '@rhds/elements/lib/context/color/consumer.js'; import { InternalsController } from '@patternfly/pfe-core/controllers/internals-controller.js'; @@ -18,69 +19,72 @@ import { ColorSurfaceLightest as lightest, } from '@rhds/tokens/color.js'; -import { classMap } from 'lit/directives/class-map.js'; - import '@rhds/elements/rh-tooltip/rh-tooltip.js'; import style from './rh-context-picker.css'; export class ContextChangeEvent extends Event { - constructor(public colorPalette: ColorPalette) { + constructor( + public colorPalette: ColorPalette, + /** the context provider targeted by this element */ + public provider: HTMLElement | null, + ) { super('change', { bubbles: true, cancelable: true }); } } +export const ColorPaletteListConverter: ComplexAttributeConverter = { + fromAttribute(list: string) { + return list?.split(',') + ?.map(x => x.trim()) + ?.filter(x => paletteNames.includes(x as ColorPalette)) ?? []; + }, + toAttribute(list: ColorPalette[]) { + return list.join(','); + }, +}; + +export const paletteMap = new Map(Object.entries({ + lightest, + lighter, + light, + dark, + darker, + darkest, +}) as [ColorPalette, Color][]); + +export const paletteNames = Array.from(paletteMap, ([name]) => name); + @customElement('rh-context-picker') export class RhContextPicker extends LitElement { static formAssociated = true; static readonly styles = [style]; - static readonly palettes = new Map(Object.entries({ - darkest, - darker, - dark, - light, - lighter, - lightest, - }) as [ColorPalette, Color][]); - - private static paletteNames = Array.from(RhContextPicker.palettes, ([name]) => name); - declare shadowRoot: ShadowRoot; /** ID of context element to toggle (same root) */ - @property() target?: string; + @property() target?: string | HTMLElement; @property() value: ColorPalette = 'darkest'; @colorContextConsumer() private on?: ColorTheme; - @property({ - converter: { - fromAttribute(list: string) { - return list?.split(',') - ?.map(x => x.trim()) - ?.filter(x => RhContextPicker.paletteNames.includes(x as ColorPalette)) ?? []; - }, - toAttribute(list: ColorPalette[]) { - return list.join(','); - }, - }, - }) allow = RhContextPicker.paletteNames; + @property({ converter: ColorPaletteListConverter }) + allow = paletteNames; #internals = InternalsController.of(this); #target: HTMLElement | null = null; render() { - const { allow, on = 'dark', value = 'darkest' } = this; + const { allow, on = 'dark', value } = this; return html`
                ${this.#internals.computedLabelText}
                + class="on ${classMap({ [on]: true })}"> ${allow.map(palette => html` @@ -97,29 +101,25 @@ export class RhContextPicker extends LitElement { } formStateRestoreCallback(state: string) { - this.#setValue(state as this['value']); + if (state) { + this.#setValue(state as this['value']); + } } firstUpdated() { for (const label of this.#internals.labels) { label.addEventListener('click', () => this.focus()); } - const oldTarget = this.#target; - if (this.target) { + if (this.target instanceof HTMLElement) { + this.#target = this.target; + this.sync(); + } else if (this.target) { const root = this.getRootNode() as Document | ShadowRoot; this.#target = root.getElementById(this.target); this.sync(); } else { this.#target = this.closest('rh-surface'); } - oldTarget?.removeEventListener('change', this.#onChange); - this.#target?.addEventListener('change', this.#onChange); - } - - #onChange(event: Event) { - if (event instanceof ContextChangeEvent) { - event.stopPropagation(); - } } #onInput(event: Event) { @@ -134,7 +134,7 @@ export class RhContextPicker extends LitElement { #setValue(value: this['value']) { this.#internals.setFormValue(value); - if (value !== this.value && this.dispatchEvent(new ContextChangeEvent(value))) { + if (value !== this.value && this.dispatchEvent(new ContextChangeEvent(value, this.#target))) { this.value = value; this.sync(); } diff --git a/netlify.toml b/netlify.toml index 137d7761f6..681d0861e9 100644 --- a/netlify.toml +++ b/netlify.toml @@ -1,5 +1,7 @@ [build] command = "npm run docs" +[build.environment] + NODE_OPTIONS = "--max_old_space_size=8192" [[redirects]] from = '/components/get-started/*' diff --git a/package-lock.json b/package-lock.json index b763e66153..e655ee08c7 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,18 +10,20 @@ "license": "MIT", "dependencies": { "@lit/context": "^1.1.2", - "@patternfly/pfe-core": "^4.0.1", - "@rhds/icons": "^1.1.1", - "@rhds/tokens": "^2.0.1", + "@patternfly/pfe-core": "^4.0.2", + "@rhds/icons": "^1.1.2", + "@rhds/tokens": "^2.1.0", "lit": "^3.2.0", - "tslib": "^2.6.3" + "prism-esm": "^1.29.0-fix.6", + "tslib": "^2.7.0", + "web-dev-server-plugin-lit-css": "^3.0.1" }, "devDependencies": { "@11ty/eleventy": "^2.0.1", "@11ty/eleventy-img": "^4.0.2", "@11ty/eleventy-plugin-rss": "^2.0.2", - "@commitlint/cli": "^19.4.0", - "@commitlint/config-conventional": "^19.2.2", + "@commitlint/cli": "^19.5.0", + "@commitlint/config-conventional": "^19.5.0", "@lit-labs/eleventy-plugin-lit": "^1.0.3", "@lit/reactive-element": "^2.0.4", "@parse5/tools": "^0.5.0", @@ -30,46 +32,51 @@ "@patternfly/eslint-config-elements": "^4.0.0", "@patternfly/eslint-plugin-elements": "^2.0.0", "@patternfly/icons": "^1.0.3", - "@patternfly/pfe-tools": "^3.0.0", - "@playwright/test": "^1.46.1", - "@rollup/plugin-node-resolve": "^15.2.3", + "@patternfly/pfe-tools": "^3.0.1", + "@playwright/test": "^1.47.2", + "@rollup/plugin-node-resolve": "^15.3.0", "@rollup/plugin-typescript": "^11.1.6", "@stylistic/stylelint-config": "^2.0.0", - "@stylistic/stylelint-plugin": "^3.0.1", - "@types/mocha": "^10.0.7", + "@stylistic/stylelint-plugin": "^3.1.0", + "@types/mocha": "^10.0.8", "@web/rollup-plugin-import-meta-assets": "^2.2.1", "@webcomponents/template-shadowroot": "^0.2.1", "async-csv": "^2.1.3", "autoprefixer": "^10.4.20", - "cssnano": "^7.0.5", + "cssnano": "^7.0.6", "custom-elements-manifest": "^2.1.0", "element-internals-polyfill": "^1.3.11", "eleventy-plugin-dart-sass": "^1.0.3", + "eleventy-plugin-helmet": "^0.2.2", "eleventy-plugin-nesting-toc": "^1.3.0", "es-module-shims": "^1.10.0", - "eslint": "^9.9.0", + "eslint": "^9.11.1", "fuse.js": "^7.0.0", "git-branch": "^2.0.1", "image-size": "^1.1.1", "leasot": "^14.4.0", "lit-html": "^3.2.0", "markdown-it-attrs": "^4.2.0", - "markdownlint-cli2": "^0.13.0", + "markdown-it-footnote": "^4.0.0", + "markdownlint-cli2": "^0.14.0", "parse5": "^7.1.2", "patch-package": "^8.0.0", - "playground-elements": "^0.18.1", + "playground-elements": "^0.19.1", "postcss-pxtorem": "^6.1.0", + "query-selector-shadow-dom": "^1.0.1", "renamer": "^5.0.2", "spandx": "^3.0.0", "stylelint-config-standard": "^36.0.1", + "tinycolor2": "^1.6.0", "ts-patch": "^3.2.1", - "tsx": "^4.17.0", - "typescript": "^5.5.4", - "wireit": "^0.14.7" + "tsx": "^4.19.1", + "typescript": "^5.6.2", + "typescript-transform-lit-css": "^2.0.0", + "wireit": "^0.14.9" }, "optionalDependencies": { - "@esbuild/darwin-arm64": "^0.15.18", - "@esbuild/linux-x64": "^0.23.1", + "@esbuild/darwin-arm64": "^0.24.0", + "@esbuild/linux-x64": "^0.24.0", "@rollup/rollup-darwin-x64": "4.14.2" } }, @@ -231,9 +238,7 @@ }, "node_modules/@11ty/eleventy-plugin-syntaxhighlight": { "version": "5.0.0", - "dev": true, "license": "MIT", - "peer": true, "dependencies": { "prismjs": "^1.29.0" }, @@ -1408,9 +1413,8 @@ }, "node_modules/@commitlint/cli": { "version": "19.5.0", - "resolved": "https://registry.npmjs.org/@commitlint/cli/-/cli-19.5.0.tgz", - "integrity": "sha512-gaGqSliGwB86MDmAAKAtV9SV1SHdmN8pnGq4EJU4+hLisQ7IFfx4jvU4s+pk6tl0+9bv6yT+CaZkufOinkSJIQ==", "dev": true, + "license": "MIT", "dependencies": { "@commitlint/format": "^19.5.0", "@commitlint/lint": "^19.5.0", @@ -1428,11 +1432,11 @@ } }, "node_modules/@commitlint/config-conventional": { - "version": "19.2.2", + "version": "19.5.0", "dev": true, "license": "MIT", "dependencies": { - "@commitlint/types": "^19.0.3", + "@commitlint/types": "^19.5.0", "conventional-changelog-conventionalcommits": "^7.0.2" }, "engines": { @@ -1441,9 +1445,8 @@ }, "node_modules/@commitlint/config-validator": { "version": "19.5.0", - "resolved": "https://registry.npmjs.org/@commitlint/config-validator/-/config-validator-19.5.0.tgz", - "integrity": "sha512-CHtj92H5rdhKt17RmgALhfQt95VayrUo2tSqY9g2w+laAXyk7K/Ef6uPm9tn5qSIwSmrLjKaXK9eiNuxmQrDBw==", "dev": true, + "license": "MIT", "dependencies": { "@commitlint/types": "^19.5.0", "ajv": "^8.11.0" @@ -1454,9 +1457,8 @@ }, "node_modules/@commitlint/ensure": { "version": "19.5.0", - "resolved": "https://registry.npmjs.org/@commitlint/ensure/-/ensure-19.5.0.tgz", - "integrity": "sha512-Kv0pYZeMrdg48bHFEU5KKcccRfKmISSm9MvgIgkpI6m+ohFTB55qZlBW6eYqh/XDfRuIO0x4zSmvBjmOwWTwkg==", "dev": true, + "license": "MIT", "dependencies": { "@commitlint/types": "^19.5.0", "lodash.camelcase": "^4.3.0", @@ -1471,18 +1473,16 @@ }, "node_modules/@commitlint/execute-rule": { "version": "19.5.0", - "resolved": "https://registry.npmjs.org/@commitlint/execute-rule/-/execute-rule-19.5.0.tgz", - "integrity": "sha512-aqyGgytXhl2ejlk+/rfgtwpPexYyri4t8/n4ku6rRJoRhGZpLFMqrZ+YaubeGysCP6oz4mMA34YSTaSOKEeNrg==", "dev": true, + "license": "MIT", "engines": { "node": ">=v18" } }, "node_modules/@commitlint/format": { "version": "19.5.0", - "resolved": "https://registry.npmjs.org/@commitlint/format/-/format-19.5.0.tgz", - "integrity": "sha512-yNy088miE52stCI3dhG/vvxFo9e4jFkU1Mj3xECfzp/bIS/JUay4491huAlVcffOoMK1cd296q0W92NlER6r3A==", "dev": true, + "license": "MIT", "dependencies": { "@commitlint/types": "^19.5.0", "chalk": "^5.3.0" @@ -1493,9 +1493,8 @@ }, "node_modules/@commitlint/is-ignored": { "version": "19.5.0", - "resolved": "https://registry.npmjs.org/@commitlint/is-ignored/-/is-ignored-19.5.0.tgz", - "integrity": "sha512-0XQ7Llsf9iL/ANtwyZ6G0NGp5Y3EQ8eDQSxv/SRcfJ0awlBY4tHFAvwWbw66FVUaWICH7iE5en+FD9TQsokZ5w==", "dev": true, + "license": "MIT", "dependencies": { "@commitlint/types": "^19.5.0", "semver": "^7.6.0" @@ -1506,9 +1505,8 @@ }, "node_modules/@commitlint/lint": { "version": "19.5.0", - "resolved": "https://registry.npmjs.org/@commitlint/lint/-/lint-19.5.0.tgz", - "integrity": "sha512-cAAQwJcRtiBxQWO0eprrAbOurtJz8U6MgYqLz+p9kLElirzSCc0vGMcyCaA1O7AqBuxo11l1XsY3FhOFowLAAg==", "dev": true, + "license": "MIT", "dependencies": { "@commitlint/is-ignored": "^19.5.0", "@commitlint/parse": "^19.5.0", @@ -1521,9 +1519,8 @@ }, "node_modules/@commitlint/load": { "version": "19.5.0", - "resolved": "https://registry.npmjs.org/@commitlint/load/-/load-19.5.0.tgz", - "integrity": "sha512-INOUhkL/qaKqwcTUvCE8iIUf5XHsEPCLY9looJ/ipzi7jtGhgmtH7OOFiNvwYgH7mA8osUWOUDV8t4E2HAi4xA==", "dev": true, + "license": "MIT", "dependencies": { "@commitlint/config-validator": "^19.5.0", "@commitlint/execute-rule": "^19.5.0", @@ -1542,18 +1539,16 @@ }, "node_modules/@commitlint/message": { "version": "19.5.0", - "resolved": "https://registry.npmjs.org/@commitlint/message/-/message-19.5.0.tgz", - "integrity": "sha512-R7AM4YnbxN1Joj1tMfCyBryOC5aNJBdxadTZkuqtWi3Xj0kMdutq16XQwuoGbIzL2Pk62TALV1fZDCv36+JhTQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=v18" } }, "node_modules/@commitlint/parse": { "version": "19.5.0", - "resolved": "https://registry.npmjs.org/@commitlint/parse/-/parse-19.5.0.tgz", - "integrity": "sha512-cZ/IxfAlfWYhAQV0TwcbdR1Oc0/r0Ik1GEessDJ3Lbuma/MRO8FRQX76eurcXtmhJC//rj52ZSZuXUg0oIX0Fw==", "dev": true, + "license": "MIT", "dependencies": { "@commitlint/types": "^19.5.0", "conventional-changelog-angular": "^7.0.0", @@ -1565,9 +1560,8 @@ }, "node_modules/@commitlint/read": { "version": "19.5.0", - "resolved": "https://registry.npmjs.org/@commitlint/read/-/read-19.5.0.tgz", - "integrity": "sha512-TjS3HLPsLsxFPQj6jou8/CZFAmOP2y+6V4PGYt3ihbQKTY1Jnv0QG28WRKl/d1ha6zLODPZqsxLEov52dhR9BQ==", "dev": true, + "license": "MIT", "dependencies": { "@commitlint/top-level": "^19.5.0", "@commitlint/types": "^19.5.0", @@ -1581,9 +1575,8 @@ }, "node_modules/@commitlint/resolve-extends": { "version": "19.5.0", - "resolved": "https://registry.npmjs.org/@commitlint/resolve-extends/-/resolve-extends-19.5.0.tgz", - "integrity": "sha512-CU/GscZhCUsJwcKTJS9Ndh3AKGZTNFIOoQB2n8CmFnizE0VnEuJoum+COW+C1lNABEeqk6ssfc1Kkalm4bDklA==", "dev": true, + "license": "MIT", "dependencies": { "@commitlint/config-validator": "^19.5.0", "@commitlint/types": "^19.5.0", @@ -1598,9 +1591,8 @@ }, "node_modules/@commitlint/rules": { "version": "19.5.0", - "resolved": "https://registry.npmjs.org/@commitlint/rules/-/rules-19.5.0.tgz", - "integrity": "sha512-hDW5TPyf/h1/EufSHEKSp6Hs+YVsDMHazfJ2azIk9tHPXS6UqSz1dIRs1gpqS3eMXgtkT7JH6TW4IShdqOwhAw==", "dev": true, + "license": "MIT", "dependencies": { "@commitlint/ensure": "^19.5.0", "@commitlint/message": "^19.5.0", @@ -1613,18 +1605,16 @@ }, "node_modules/@commitlint/to-lines": { "version": "19.5.0", - "resolved": "https://registry.npmjs.org/@commitlint/to-lines/-/to-lines-19.5.0.tgz", - "integrity": "sha512-R772oj3NHPkodOSRZ9bBVNq224DOxQtNef5Pl8l2M8ZnkkzQfeSTr4uxawV2Sd3ui05dUVzvLNnzenDBO1KBeQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=v18" } }, "node_modules/@commitlint/top-level": { "version": "19.5.0", - "resolved": "https://registry.npmjs.org/@commitlint/top-level/-/top-level-19.5.0.tgz", - "integrity": "sha512-IP1YLmGAk0yWrImPRRc578I3dDUI5A2UBJx9FbSOjxe9sTlzFiwVJ+zeMLgAtHMtGZsC8LUnzmW1qRemkFU4ng==", "dev": true, + "license": "MIT", "dependencies": { "find-up": "^7.0.0" }, @@ -1634,9 +1624,8 @@ }, "node_modules/@commitlint/types": { "version": "19.5.0", - "resolved": "https://registry.npmjs.org/@commitlint/types/-/types-19.5.0.tgz", - "integrity": "sha512-DSHae2obMSMkAtTBSOulg5X7/z+rGLxcXQIkg3OmWvY6wifojge5uVMydfhUvs7yQj+V7jNmRZ2Xzl8GJyqRgg==", "dev": true, + "license": "MIT", "dependencies": { "@types/conventional-commits-parser": "^5.0.0", "chalk": "^5.3.0" @@ -1647,7 +1636,6 @@ }, "node_modules/@csstools/css-parser-algorithms": { "version": "3.0.1", - "dev": true, "funding": [ { "type": "github", @@ -1668,7 +1656,6 @@ }, "node_modules/@csstools/css-tokenizer": { "version": "3.0.1", - "dev": true, "funding": [ { "type": "github", @@ -1686,7 +1673,6 @@ }, "node_modules/@csstools/media-query-list-parser": { "version": "3.0.1", - "dev": true, "funding": [ { "type": "github", @@ -1706,9 +1692,30 @@ "@csstools/css-tokenizer": "^3.0.1" } }, + "node_modules/@csstools/selector-resolve-nested": { + "version": "1.1.0", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "peer": true, + "engines": { + "node": "^14 || ^16 || >=18" + }, + "peerDependencies": { + "postcss-selector-parser": "^6.0.13" + } + }, "node_modules/@csstools/selector-specificity": { "version": "4.0.0", - "dev": true, "funding": [ { "type": "github", @@ -1789,7 +1796,6 @@ }, "node_modules/@dual-bundle/import-meta-resolve": { "version": "4.1.0", - "dev": true, "license": "MIT", "funding": { "type": "github", @@ -1827,6 +1833,7 @@ "ppc64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "aix" @@ -1844,6 +1851,7 @@ "arm" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "android" @@ -1861,6 +1869,7 @@ "arm64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "android" @@ -1878,6 +1887,7 @@ "x64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "android" @@ -1888,18 +1898,19 @@ } }, "node_modules/@esbuild/darwin-arm64": { - "version": "0.15.18", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.15.18.tgz", - "integrity": "sha512-xoOZQRQJogDsoU6ZUq2irotU4N3BFDAvjEDPWXVWlrkZzZa17AidAf/r8wrjTbZqdZ0RDgV90o1ROrf2JZtVEQ==", + "version": "0.24.0", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.24.0.tgz", + "integrity": "sha512-CKyDpRbK1hXwv79soeTJNHb5EiG6ct3efd/FTPdzOWdbZZfGhpbcqIpiD0+vwmpu0wTIL97ZRPZu8vUt46nBSw==", "cpu": [ "arm64" ], + "license": "MIT", "optional": true, "os": [ "darwin" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/darwin-x64": { @@ -1910,6 +1921,7 @@ "x64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "darwin" @@ -1927,6 +1939,7 @@ "arm64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "freebsd" @@ -1944,6 +1957,7 @@ "x64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "freebsd" @@ -1961,6 +1975,7 @@ "arm" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" @@ -1978,6 +1993,7 @@ "arm64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" @@ -1995,6 +2011,7 @@ "ia32" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" @@ -2012,6 +2029,7 @@ "loong64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" @@ -2029,6 +2047,7 @@ "mips64el" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" @@ -2046,6 +2065,7 @@ "ppc64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" @@ -2063,6 +2083,7 @@ "riscv64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" @@ -2080,6 +2101,7 @@ "s390x" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" @@ -2090,7 +2112,7 @@ } }, "node_modules/@esbuild/linux-x64": { - "version": "0.23.1", + "version": "0.24.0", "cpu": [ "x64" ], @@ -2111,6 +2133,7 @@ "x64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "netbsd" @@ -2128,6 +2151,7 @@ "arm64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "openbsd" @@ -2144,6 +2168,7 @@ "x64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "openbsd" @@ -2161,6 +2186,7 @@ "x64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "sunos" @@ -2178,6 +2204,7 @@ "arm64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "win32" @@ -2195,6 +2222,7 @@ "ia32" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "win32" @@ -2212,6 +2240,7 @@ "x64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "win32" @@ -2263,7 +2292,7 @@ } }, "node_modules/@eslint/config-array": { - "version": "0.17.1", + "version": "0.18.0", "dev": true, "license": "Apache-2.0", "dependencies": { @@ -2275,6 +2304,14 @@ "node": "^18.18.0 || ^20.9.0 || >=21.1.0" } }, + "node_modules/@eslint/core": { + "version": "0.6.0", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, "node_modules/@eslint/eslintrc": { "version": "3.1.0", "dev": true, @@ -2334,7 +2371,7 @@ "license": "MIT" }, "node_modules/@eslint/js": { - "version": "9.9.0", + "version": "9.11.1", "dev": true, "license": "MIT", "engines": { @@ -2349,6 +2386,17 @@ "node": "^18.18.0 || ^20.9.0 || >=21.1.0" } }, + "node_modules/@eslint/plugin-kit": { + "version": "0.2.0", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "levn": "^0.4.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, "node_modules/@esm-bundle/chai": { "version": "4.3.4-fix.0", "dev": true, @@ -2360,16 +2408,14 @@ }, "node_modules/@floating-ui/core": { "version": "1.6.7", - "resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.6.7.tgz", - "integrity": "sha512-yDzVT/Lm101nQ5TCVeK65LtdN7Tj4Qpr9RTXJ2vPFLqtLxwOrpoxAHAJI8J3yYWUc40J0BDBheaitK5SJmno2g==", + "license": "MIT", "dependencies": { "@floating-ui/utils": "^0.2.7" } }, "node_modules/@floating-ui/dom": { "version": "1.6.10", - "resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.6.10.tgz", - "integrity": "sha512-fskgCFv8J8OamCmyun8MfjB1Olfn+uZKjOKZ0vhYF3gRmEUXcGOjxWL8bBr7i4kIuPZ2KD2S3EUIOxnjC8kl2A==", + "license": "MIT", "dependencies": { "@floating-ui/core": "^1.6.0", "@floating-ui/utils": "^0.2.7" @@ -2377,8 +2423,7 @@ }, "node_modules/@floating-ui/utils": { "version": "0.2.7", - "resolved": "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.2.7.tgz", - "integrity": "sha512-X8R8Oj771YRl/w+c1HqAC1szL8zWQRwFvgDwT129k9ACdBoud/+/rX9V0qiMl6LWUdP9voC2nDVZYPMQQsb6eA==" + "license": "MIT" }, "node_modules/@gar/promisify": { "version": "1.1.3", @@ -3937,9 +3982,8 @@ }, "node_modules/@patternfly/elements": { "version": "4.0.1", - "resolved": "https://registry.npmjs.org/@patternfly/elements/-/elements-4.0.1.tgz", - "integrity": "sha512-uYRfT6v3mPEJz/ty8XGIOqxaS7mr/UJT/uBTgcwAPFalTVmNnoVKMFlCEGxUnAQXS9FNeu2Ir4ycpLy6LFbApQ==", "dev": true, + "license": "MIT", "dependencies": { "@lit/context": "^1.1.2", "@patternfly/icons": "^1.0.3", @@ -3999,9 +4043,8 @@ "license": "MIT" }, "node_modules/@patternfly/pfe-core": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/@patternfly/pfe-core/-/pfe-core-4.0.1.tgz", - "integrity": "sha512-zBztsSRam2t2lWZGsgHxTWwsNhMQbq8R9vyyzEXTLdyvMF56gzKnUbhbNUQTimCuICuz3LynJ8XJ24Grx6iKdg==", + "version": "4.0.2", + "license": "MIT", "dependencies": { "@floating-ui/dom": "^1.6.10", "@lit/context": "^1.1.2", @@ -4009,7 +4052,7 @@ } }, "node_modules/@patternfly/pfe-tools": { - "version": "3.0.0", + "version": "3.0.1", "dev": true, "license": "MIT", "engines": { @@ -4089,11 +4132,11 @@ } }, "node_modules/@playwright/test": { - "version": "1.46.1", + "version": "1.47.2", "dev": true, "license": "Apache-2.0", "dependencies": { - "playwright": "1.46.1" + "playwright": "1.47.2" }, "bin": { "playwright": "cli.js" @@ -4126,18 +4169,14 @@ }, "node_modules/@pwrs/lit-css": { "version": "3.0.0", - "dev": true, "license": "ISC", - "peer": true, "dependencies": { "cssnano": "^6.1.2" } }, "node_modules/@pwrs/lit-css/node_modules/cssnano": { "version": "6.1.2", - "dev": true, "license": "MIT", - "peer": true, "dependencies": { "cssnano-preset-default": "^6.1.2", "lilconfig": "^3.1.1" @@ -4155,9 +4194,7 @@ }, "node_modules/@pwrs/lit-css/node_modules/cssnano-preset-default": { "version": "6.1.2", - "dev": true, "license": "MIT", - "peer": true, "dependencies": { "browserslist": "^4.23.0", "css-declaration-sorter": "^7.2.0", @@ -4199,9 +4236,7 @@ }, "node_modules/@pwrs/lit-css/node_modules/cssnano-utils": { "version": "4.0.2", - "dev": true, "license": "MIT", - "peer": true, "engines": { "node": "^14 || ^16 || >=18.0" }, @@ -4211,9 +4246,7 @@ }, "node_modules/@pwrs/lit-css/node_modules/postcss-calc": { "version": "9.0.1", - "dev": true, "license": "MIT", - "peer": true, "dependencies": { "postcss-selector-parser": "^6.0.11", "postcss-value-parser": "^4.2.0" @@ -4227,9 +4260,7 @@ }, "node_modules/@pwrs/lit-css/node_modules/postcss-colormin": { "version": "6.1.0", - "dev": true, "license": "MIT", - "peer": true, "dependencies": { "browserslist": "^4.23.0", "caniuse-api": "^3.0.0", @@ -4245,9 +4276,7 @@ }, "node_modules/@pwrs/lit-css/node_modules/postcss-convert-values": { "version": "6.1.0", - "dev": true, "license": "MIT", - "peer": true, "dependencies": { "browserslist": "^4.23.0", "postcss-value-parser": "^4.2.0" @@ -4261,9 +4290,7 @@ }, "node_modules/@pwrs/lit-css/node_modules/postcss-discard-comments": { "version": "6.0.2", - "dev": true, "license": "MIT", - "peer": true, "engines": { "node": "^14 || ^16 || >=18.0" }, @@ -4273,9 +4300,7 @@ }, "node_modules/@pwrs/lit-css/node_modules/postcss-discard-duplicates": { "version": "6.0.3", - "dev": true, "license": "MIT", - "peer": true, "engines": { "node": "^14 || ^16 || >=18.0" }, @@ -4285,9 +4310,7 @@ }, "node_modules/@pwrs/lit-css/node_modules/postcss-discard-empty": { "version": "6.0.3", - "dev": true, "license": "MIT", - "peer": true, "engines": { "node": "^14 || ^16 || >=18.0" }, @@ -4297,9 +4320,7 @@ }, "node_modules/@pwrs/lit-css/node_modules/postcss-discard-overridden": { "version": "6.0.2", - "dev": true, "license": "MIT", - "peer": true, "engines": { "node": "^14 || ^16 || >=18.0" }, @@ -4309,9 +4330,7 @@ }, "node_modules/@pwrs/lit-css/node_modules/postcss-merge-longhand": { "version": "6.0.5", - "dev": true, "license": "MIT", - "peer": true, "dependencies": { "postcss-value-parser": "^4.2.0", "stylehacks": "^6.1.1" @@ -4325,9 +4344,7 @@ }, "node_modules/@pwrs/lit-css/node_modules/postcss-merge-rules": { "version": "6.1.1", - "dev": true, "license": "MIT", - "peer": true, "dependencies": { "browserslist": "^4.23.0", "caniuse-api": "^3.0.0", @@ -4343,9 +4360,7 @@ }, "node_modules/@pwrs/lit-css/node_modules/postcss-minify-font-values": { "version": "6.1.0", - "dev": true, "license": "MIT", - "peer": true, "dependencies": { "postcss-value-parser": "^4.2.0" }, @@ -4358,9 +4373,7 @@ }, "node_modules/@pwrs/lit-css/node_modules/postcss-minify-gradients": { "version": "6.0.3", - "dev": true, "license": "MIT", - "peer": true, "dependencies": { "colord": "^2.9.3", "cssnano-utils": "^4.0.2", @@ -4375,9 +4388,7 @@ }, "node_modules/@pwrs/lit-css/node_modules/postcss-minify-params": { "version": "6.1.0", - "dev": true, "license": "MIT", - "peer": true, "dependencies": { "browserslist": "^4.23.0", "cssnano-utils": "^4.0.2", @@ -4392,9 +4403,7 @@ }, "node_modules/@pwrs/lit-css/node_modules/postcss-minify-selectors": { "version": "6.0.4", - "dev": true, "license": "MIT", - "peer": true, "dependencies": { "postcss-selector-parser": "^6.0.16" }, @@ -4407,9 +4416,7 @@ }, "node_modules/@pwrs/lit-css/node_modules/postcss-normalize-charset": { "version": "6.0.2", - "dev": true, "license": "MIT", - "peer": true, "engines": { "node": "^14 || ^16 || >=18.0" }, @@ -4419,9 +4426,7 @@ }, "node_modules/@pwrs/lit-css/node_modules/postcss-normalize-display-values": { "version": "6.0.2", - "dev": true, "license": "MIT", - "peer": true, "dependencies": { "postcss-value-parser": "^4.2.0" }, @@ -4434,9 +4439,7 @@ }, "node_modules/@pwrs/lit-css/node_modules/postcss-normalize-positions": { "version": "6.0.2", - "dev": true, "license": "MIT", - "peer": true, "dependencies": { "postcss-value-parser": "^4.2.0" }, @@ -4449,9 +4452,7 @@ }, "node_modules/@pwrs/lit-css/node_modules/postcss-normalize-repeat-style": { "version": "6.0.2", - "dev": true, "license": "MIT", - "peer": true, "dependencies": { "postcss-value-parser": "^4.2.0" }, @@ -4464,9 +4465,7 @@ }, "node_modules/@pwrs/lit-css/node_modules/postcss-normalize-string": { "version": "6.0.2", - "dev": true, "license": "MIT", - "peer": true, "dependencies": { "postcss-value-parser": "^4.2.0" }, @@ -4479,9 +4478,7 @@ }, "node_modules/@pwrs/lit-css/node_modules/postcss-normalize-timing-functions": { "version": "6.0.2", - "dev": true, "license": "MIT", - "peer": true, "dependencies": { "postcss-value-parser": "^4.2.0" }, @@ -4494,9 +4491,7 @@ }, "node_modules/@pwrs/lit-css/node_modules/postcss-normalize-unicode": { "version": "6.1.0", - "dev": true, "license": "MIT", - "peer": true, "dependencies": { "browserslist": "^4.23.0", "postcss-value-parser": "^4.2.0" @@ -4510,9 +4505,7 @@ }, "node_modules/@pwrs/lit-css/node_modules/postcss-normalize-url": { "version": "6.0.2", - "dev": true, "license": "MIT", - "peer": true, "dependencies": { "postcss-value-parser": "^4.2.0" }, @@ -4525,9 +4518,7 @@ }, "node_modules/@pwrs/lit-css/node_modules/postcss-normalize-whitespace": { "version": "6.0.2", - "dev": true, "license": "MIT", - "peer": true, "dependencies": { "postcss-value-parser": "^4.2.0" }, @@ -4540,9 +4531,7 @@ }, "node_modules/@pwrs/lit-css/node_modules/postcss-ordered-values": { "version": "6.0.2", - "dev": true, "license": "MIT", - "peer": true, "dependencies": { "cssnano-utils": "^4.0.2", "postcss-value-parser": "^4.2.0" @@ -4556,9 +4545,7 @@ }, "node_modules/@pwrs/lit-css/node_modules/postcss-reduce-initial": { "version": "6.1.0", - "dev": true, "license": "MIT", - "peer": true, "dependencies": { "browserslist": "^4.23.0", "caniuse-api": "^3.0.0" @@ -4572,9 +4559,7 @@ }, "node_modules/@pwrs/lit-css/node_modules/postcss-reduce-transforms": { "version": "6.0.2", - "dev": true, "license": "MIT", - "peer": true, "dependencies": { "postcss-value-parser": "^4.2.0" }, @@ -4587,9 +4572,7 @@ }, "node_modules/@pwrs/lit-css/node_modules/postcss-svgo": { "version": "6.0.3", - "dev": true, "license": "MIT", - "peer": true, "dependencies": { "postcss-value-parser": "^4.2.0", "svgo": "^3.2.0" @@ -4603,9 +4586,7 @@ }, "node_modules/@pwrs/lit-css/node_modules/postcss-unique-selectors": { "version": "6.0.4", - "dev": true, "license": "MIT", - "peer": true, "dependencies": { "postcss-selector-parser": "^6.0.16" }, @@ -4618,9 +4599,7 @@ }, "node_modules/@pwrs/lit-css/node_modules/stylehacks": { "version": "6.1.1", - "dev": true, "license": "MIT", - "peer": true, "dependencies": { "browserslist": "^4.23.0", "postcss-selector-parser": "^6.0.16" @@ -4633,592 +4612,64 @@ } }, "node_modules/@rhds/icons": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@rhds/icons/-/icons-1.1.1.tgz", - "integrity": "sha512-Cqpr9bmMbcSk/NMkp12qaOnSag7jEHU1zFKmsnJN/21BIYUAL6+mdyfsRe4dxzOkSSmjqCypiFJYcJ8KFNAMyA==" + "version": "1.1.2", + "license": "MIT" }, "node_modules/@rhds/tokens": { - "version": "2.0.1", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@rhds/tokens/-/tokens-2.1.0.tgz", + "integrity": "sha512-Lgjm1v9x2NB0UoyktA2vn3ijgXo5O3BiX5IQyTt1MpePSn2YWtUHtjSWyo+XmulPvPh/jfDdsoeN6VcZzzLuTA==", "dependencies": { - "@11ty/eleventy-plugin-syntaxhighlight": "^4.2.0", - "highlight.js": "^11.7.0", + "@11ty/eleventy-plugin-syntaxhighlight": "^5.0.0", + "highlight.js": "^11.10.0", "postcss-value-parser": "^4.2.0", - "stylelint": "^15.2.0" + "stylelint": "^16.9.0" } }, - "node_modules/@rhds/tokens/node_modules/@11ty/eleventy-plugin-syntaxhighlight": { - "version": "4.2.0", + "node_modules/@rollup/plugin-dynamic-import-vars": { + "version": "2.1.2", + "dev": true, "license": "MIT", "dependencies": { - "linkedom": "^0.14.19", - "prismjs": "^1.29.0" + "@rollup/pluginutils": "^5.0.1", + "astring": "^1.8.5", + "estree-walker": "^2.0.2", + "fast-glob": "^3.2.12", + "magic-string": "^0.30.3" }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/11ty" - } - }, - "node_modules/@rhds/tokens/node_modules/@csstools/css-parser-algorithms": { - "version": "2.7.1", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/csstools" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/csstools" - } - ], - "license": "MIT", "engines": { - "node": "^14 || ^16 || >=18" + "node": ">=14.0.0" }, "peerDependencies": { - "@csstools/css-tokenizer": "^2.4.1" - } - }, - "node_modules/@rhds/tokens/node_modules/@csstools/css-tokenizer": { - "version": "2.4.1", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/csstools" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/csstools" + "rollup": "^1.20.0||^2.0.0||^3.0.0||^4.0.0" + }, + "peerDependenciesMeta": { + "rollup": { + "optional": true } - ], - "license": "MIT", - "engines": { - "node": "^14 || ^16 || >=18" } }, - "node_modules/@rhds/tokens/node_modules/@csstools/media-query-list-parser": { - "version": "2.1.13", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/csstools" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/csstools" - } - ], + "node_modules/@rollup/plugin-node-resolve": { + "version": "15.3.0", + "dev": true, "license": "MIT", + "dependencies": { + "@rollup/pluginutils": "^5.0.1", + "@types/resolve": "1.20.2", + "deepmerge": "^4.2.2", + "is-module": "^1.0.0", + "resolve": "^1.22.1" + }, "engines": { - "node": "^14 || ^16 || >=18" + "node": ">=14.0.0" }, "peerDependencies": { - "@csstools/css-parser-algorithms": "^2.7.1", - "@csstools/css-tokenizer": "^2.4.1" - } - }, - "node_modules/@rhds/tokens/node_modules/@csstools/selector-specificity": { - "version": "3.1.1", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/csstools" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/csstools" - } - ], - "license": "MIT-0", - "engines": { - "node": "^14 || ^16 || >=18" - }, - "peerDependencies": { - "postcss-selector-parser": "^6.0.13" - } - }, - "node_modules/@rhds/tokens/node_modules/argparse": { - "version": "2.0.1", - "license": "Python-2.0" - }, - "node_modules/@rhds/tokens/node_modules/balanced-match": { - "version": "2.0.0", - "license": "MIT" - }, - "node_modules/@rhds/tokens/node_modules/camelcase-keys": { - "version": "7.0.2", - "license": "MIT", - "dependencies": { - "camelcase": "^6.3.0", - "map-obj": "^4.1.0", - "quick-lru": "^5.1.1", - "type-fest": "^1.2.1" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/@rhds/tokens/node_modules/cosmiconfig": { - "version": "8.3.6", - "license": "MIT", - "dependencies": { - "import-fresh": "^3.3.0", - "js-yaml": "^4.1.0", - "parse-json": "^5.2.0", - "path-type": "^4.0.0" - }, - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/sponsors/d-fischer" - }, - "peerDependencies": { - "typescript": ">=4.9.5" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/@rhds/tokens/node_modules/decamelize": { - "version": "5.0.1", - "license": "MIT", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/@rhds/tokens/node_modules/emoji-regex": { - "version": "8.0.0", - "license": "MIT" - }, - "node_modules/@rhds/tokens/node_modules/file-entry-cache": { - "version": "7.0.2", - "license": "MIT", - "dependencies": { - "flat-cache": "^3.2.0" - }, - "engines": { - "node": ">=12.0.0" - } - }, - "node_modules/@rhds/tokens/node_modules/find-up": { - "version": "5.0.0", - "license": "MIT", - "dependencies": { - "locate-path": "^6.0.0", - "path-exists": "^4.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/@rhds/tokens/node_modules/global-modules": { - "version": "2.0.0", - "license": "MIT", - "dependencies": { - "global-prefix": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/@rhds/tokens/node_modules/global-prefix": { - "version": "3.0.0", - "license": "MIT", - "dependencies": { - "ini": "^1.3.5", - "kind-of": "^6.0.2", - "which": "^1.3.1" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/@rhds/tokens/node_modules/globby": { - "version": "11.1.0", - "license": "MIT", - "dependencies": { - "array-union": "^2.1.0", - "dir-glob": "^3.0.1", - "fast-glob": "^3.2.9", - "ignore": "^5.2.0", - "merge2": "^1.4.1", - "slash": "^3.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/@rhds/tokens/node_modules/hosted-git-info": { - "version": "4.1.0", - "license": "ISC", - "dependencies": { - "lru-cache": "^6.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/@rhds/tokens/node_modules/indent-string": { - "version": "5.0.0", - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/@rhds/tokens/node_modules/ini": { - "version": "1.3.8", - "license": "ISC" - }, - "node_modules/@rhds/tokens/node_modules/js-yaml": { - "version": "4.1.0", - "license": "MIT", - "dependencies": { - "argparse": "^2.0.1" - }, - "bin": { - "js-yaml": "bin/js-yaml.js" - } - }, - "node_modules/@rhds/tokens/node_modules/known-css-properties": { - "version": "0.29.0", - "license": "MIT" - }, - "node_modules/@rhds/tokens/node_modules/locate-path": { - "version": "6.0.0", - "license": "MIT", - "dependencies": { - "p-locate": "^5.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/@rhds/tokens/node_modules/lru-cache": { - "version": "6.0.0", - "license": "ISC", - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/@rhds/tokens/node_modules/meow": { - "version": "10.1.5", - "license": "MIT", - "dependencies": { - "@types/minimist": "^1.2.2", - "camelcase-keys": "^7.0.0", - "decamelize": "^5.0.0", - "decamelize-keys": "^1.1.0", - "hard-rejection": "^2.1.0", - "minimist-options": "4.1.0", - "normalize-package-data": "^3.0.2", - "read-pkg-up": "^8.0.0", - "redent": "^4.0.0", - "trim-newlines": "^4.0.2", - "type-fest": "^1.2.2", - "yargs-parser": "^20.2.9" - }, - "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/@rhds/tokens/node_modules/normalize-package-data": { - "version": "3.0.3", - "license": "BSD-2-Clause", - "dependencies": { - "hosted-git-info": "^4.0.1", - "is-core-module": "^2.5.0", - "semver": "^7.3.4", - "validate-npm-package-license": "^3.0.1" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/@rhds/tokens/node_modules/p-limit": { - "version": "3.1.0", - "license": "MIT", - "dependencies": { - "yocto-queue": "^0.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/@rhds/tokens/node_modules/p-locate": { - "version": "5.0.0", - "license": "MIT", - "dependencies": { - "p-limit": "^3.0.2" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/@rhds/tokens/node_modules/path-exists": { - "version": "4.0.0", - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/@rhds/tokens/node_modules/postcss-safe-parser": { - "version": "6.0.0", - "license": "MIT", - "engines": { - "node": ">=12.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - }, - "peerDependencies": { - "postcss": "^8.3.3" - } - }, - "node_modules/@rhds/tokens/node_modules/read-pkg": { - "version": "6.0.0", - "license": "MIT", - "dependencies": { - "@types/normalize-package-data": "^2.4.0", - "normalize-package-data": "^3.0.2", - "parse-json": "^5.2.0", - "type-fest": "^1.0.1" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/@rhds/tokens/node_modules/read-pkg-up": { - "version": "8.0.0", - "license": "MIT", - "dependencies": { - "find-up": "^5.0.0", - "read-pkg": "^6.0.0", - "type-fest": "^1.0.1" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/@rhds/tokens/node_modules/redent": { - "version": "4.0.0", - "license": "MIT", - "dependencies": { - "indent-string": "^5.0.0", - "strip-indent": "^4.0.0" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/@rhds/tokens/node_modules/string-width": { - "version": "4.2.3", - "license": "MIT", - "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/@rhds/tokens/node_modules/strip-indent": { - "version": "4.0.0", - "license": "MIT", - "dependencies": { - "min-indent": "^1.0.1" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/@rhds/tokens/node_modules/stylelint": { - "version": "15.11.0", - "license": "MIT", - "dependencies": { - "@csstools/css-parser-algorithms": "^2.3.1", - "@csstools/css-tokenizer": "^2.2.0", - "@csstools/media-query-list-parser": "^2.1.4", - "@csstools/selector-specificity": "^3.0.0", - "balanced-match": "^2.0.0", - "colord": "^2.9.3", - "cosmiconfig": "^8.2.0", - "css-functions-list": "^3.2.1", - "css-tree": "^2.3.1", - "debug": "^4.3.4", - "fast-glob": "^3.3.1", - "fastest-levenshtein": "^1.0.16", - "file-entry-cache": "^7.0.0", - "global-modules": "^2.0.0", - "globby": "^11.1.0", - "globjoin": "^0.1.4", - "html-tags": "^3.3.1", - "ignore": "^5.2.4", - "import-lazy": "^4.0.0", - "imurmurhash": "^0.1.4", - "is-plain-object": "^5.0.0", - "known-css-properties": "^0.29.0", - "mathml-tag-names": "^2.1.3", - "meow": "^10.1.5", - "micromatch": "^4.0.5", - "normalize-path": "^3.0.0", - "picocolors": "^1.0.0", - "postcss": "^8.4.28", - "postcss-resolve-nested-selector": "^0.1.1", - "postcss-safe-parser": "^6.0.0", - "postcss-selector-parser": "^6.0.13", - "postcss-value-parser": "^4.2.0", - "resolve-from": "^5.0.0", - "string-width": "^4.2.3", - "strip-ansi": "^6.0.1", - "style-search": "^0.1.0", - "supports-hyperlinks": "^3.0.0", - "svg-tags": "^1.0.0", - "table": "^6.8.1", - "write-file-atomic": "^5.0.1" - }, - "bin": { - "stylelint": "bin/stylelint.mjs" - }, - "engines": { - "node": "^14.13.1 || >=16.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/stylelint" - } - }, - "node_modules/@rhds/tokens/node_modules/trim-newlines": { - "version": "4.1.1", - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/@rhds/tokens/node_modules/type-fest": { - "version": "1.4.0", - "license": "(MIT OR CC0-1.0)", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/@rhds/tokens/node_modules/which": { - "version": "1.3.1", - "license": "ISC", - "dependencies": { - "isexe": "^2.0.0" - }, - "bin": { - "which": "bin/which" - } - }, - "node_modules/@rhds/tokens/node_modules/yallist": { - "version": "4.0.0", - "license": "ISC" - }, - "node_modules/@rhds/tokens/node_modules/yargs-parser": { - "version": "20.2.9", - "license": "ISC", - "engines": { - "node": ">=10" - } - }, - "node_modules/@rollup/plugin-dynamic-import-vars": { - "version": "2.1.2", - "dev": true, - "license": "MIT", - "dependencies": { - "@rollup/pluginutils": "^5.0.1", - "astring": "^1.8.5", - "estree-walker": "^2.0.2", - "fast-glob": "^3.2.12", - "magic-string": "^0.30.3" - }, - "engines": { - "node": ">=14.0.0" - }, - "peerDependencies": { - "rollup": "^1.20.0||^2.0.0||^3.0.0||^4.0.0" - }, - "peerDependenciesMeta": { - "rollup": { - "optional": true - } - } - }, - "node_modules/@rollup/plugin-node-resolve": { - "version": "15.2.3", - "dev": true, - "license": "MIT", - "dependencies": { - "@rollup/pluginutils": "^5.0.1", - "@types/resolve": "1.20.2", - "deepmerge": "^4.2.2", - "is-builtin-module": "^3.2.1", - "is-module": "^1.0.0", - "resolve": "^1.22.1" - }, - "engines": { - "node": ">=14.0.0" - }, - "peerDependencies": { - "rollup": "^2.78.0||^3.0.0||^4.0.0" - }, - "peerDependenciesMeta": { - "rollup": { - "optional": true - } + "rollup": "^2.78.0||^3.0.0||^4.0.0" + }, + "peerDependenciesMeta": { + "rollup": { + "optional": true + } } }, "node_modules/@rollup/plugin-replace": { @@ -5269,7 +4720,6 @@ }, "node_modules/@rollup/pluginutils": { "version": "5.1.0", - "dev": true, "license": "MIT", "dependencies": { "@types/estree": "^1.0.0", @@ -5295,7 +4745,7 @@ "cpu": [ "arm" ], - "dev": true, + "license": "MIT", "optional": true, "os": [ "android" @@ -5309,7 +4759,7 @@ "cpu": [ "arm64" ], - "dev": true, + "license": "MIT", "optional": true, "os": [ "android" @@ -5323,7 +4773,7 @@ "cpu": [ "arm64" ], - "dev": true, + "license": "MIT", "optional": true, "os": [ "darwin" @@ -5337,6 +4787,7 @@ "cpu": [ "x64" ], + "license": "MIT", "optional": true, "os": [ "darwin" @@ -5349,7 +4800,7 @@ "cpu": [ "arm" ], - "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" @@ -5363,7 +4814,7 @@ "cpu": [ "arm" ], - "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" @@ -5377,7 +4828,7 @@ "cpu": [ "arm64" ], - "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" @@ -5391,7 +4842,7 @@ "cpu": [ "arm64" ], - "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" @@ -5405,7 +4856,7 @@ "cpu": [ "ppc64" ], - "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" @@ -5419,7 +4870,7 @@ "cpu": [ "riscv64" ], - "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" @@ -5433,7 +4884,7 @@ "cpu": [ "s390x" ], - "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" @@ -5445,7 +4896,6 @@ "cpu": [ "x64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -5458,7 +4908,6 @@ "cpu": [ "x64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -5473,7 +4922,7 @@ "cpu": [ "arm64" ], - "dev": true, + "license": "MIT", "optional": true, "os": [ "win32" @@ -5487,7 +4936,7 @@ "cpu": [ "ia32" ], - "dev": true, + "license": "MIT", "optional": true, "os": [ "win32" @@ -5501,7 +4950,7 @@ "cpu": [ "x64" ], - "dev": true, + "license": "MIT", "optional": true, "os": [ "win32" @@ -5790,13 +5239,13 @@ } }, "node_modules/@stylistic/stylelint-plugin": { - "version": "3.0.1", + "version": "3.1.0", "dev": true, "license": "MIT", "dependencies": { - "@csstools/css-parser-algorithms": "^3.0.0", - "@csstools/css-tokenizer": "^3.0.0", - "@csstools/media-query-list-parser": "^3.0.0", + "@csstools/css-parser-algorithms": "^3.0.1", + "@csstools/css-tokenizer": "^3.0.1", + "@csstools/media-query-list-parser": "^3.0.1", "is-plain-object": "^5.0.0", "postcss-selector-parser": "^6.1.2", "postcss-value-parser": "^4.2.0", @@ -5847,7 +5296,6 @@ }, "node_modules/@trysound/sax": { "version": "0.2.0", - "dev": true, "license": "ISC", "engines": { "node": ">=10.13.0" @@ -6006,7 +5454,6 @@ }, "node_modules/@types/estree": { "version": "1.0.5", - "dev": true, "license": "MIT" }, "node_modules/@types/express": { @@ -6088,8 +5535,7 @@ "node_modules/@types/json-schema": { "version": "7.0.15", "dev": true, - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/@types/keygrip": { "version": "1.0.6", @@ -6165,13 +5611,13 @@ }, "node_modules/@types/minimist": { "version": "1.2.5", + "dev": true, "license": "MIT" }, "node_modules/@types/mocha": { "version": "10.0.8", - "resolved": "https://registry.npmjs.org/@types/mocha/-/mocha-10.0.8.tgz", - "integrity": "sha512-HfMcUmy9hTMJh66VNcmeC9iVErIZJli2bszuXc6julh5YGuRb/W5OnkHjwLNYdFlMis0sY3If5SEAp+PktdJjw==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@types/node": { "version": "22.4.1", @@ -6183,6 +5629,7 @@ }, "node_modules/@types/normalize-package-data": { "version": "2.4.4", + "dev": true, "license": "MIT" }, "node_modules/@types/parse5": { @@ -6710,6 +6157,7 @@ "ppc64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "aix" @@ -6727,6 +6175,7 @@ "arm" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "android" @@ -6744,6 +6193,7 @@ "arm64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "android" @@ -6761,6 +6211,7 @@ "x64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "android" @@ -6778,6 +6229,7 @@ "arm64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "darwin" @@ -6795,6 +6247,7 @@ "x64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "darwin" @@ -6812,6 +6265,7 @@ "arm64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "freebsd" @@ -6829,6 +6283,7 @@ "x64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "freebsd" @@ -6846,6 +6301,7 @@ "arm" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" @@ -6863,6 +6319,7 @@ "arm64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" @@ -6880,6 +6337,7 @@ "ia32" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" @@ -6897,6 +6355,7 @@ "loong64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" @@ -6914,6 +6373,7 @@ "mips64el" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" @@ -6931,6 +6391,7 @@ "ppc64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" @@ -6948,6 +6409,7 @@ "riscv64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" @@ -6965,6 +6427,7 @@ "s390x" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" @@ -6998,6 +6461,7 @@ "x64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "netbsd" @@ -7015,6 +6479,7 @@ "x64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "openbsd" @@ -7032,6 +6497,7 @@ "x64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "sunos" @@ -7049,6 +6515,7 @@ "arm64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "win32" @@ -7066,6 +6533,7 @@ "ia32" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "win32" @@ -7083,6 +6551,7 @@ "x64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "win32" @@ -7428,9 +6897,8 @@ }, "node_modules/@webcomponents/template-shadowroot": { "version": "0.2.1", - "resolved": "https://registry.npmjs.org/@webcomponents/template-shadowroot/-/template-shadowroot-0.2.1.tgz", - "integrity": "sha512-fXL/vIUakyZL62hyvUh+EMwbVoTc0hksublmRz6ai6et8znHkJa6gtqMUZo1oc7dIz46exHSIImml9QTdknMHg==", - "dev": true + "dev": true, + "license": "BSD-3-Clause" }, "node_modules/@yarnpkg/lockfile": { "version": "1.1.0", @@ -7945,6 +7413,7 @@ }, "node_modules/balanced-match": { "version": "1.0.2", + "dev": true, "license": "MIT" }, "node_modules/bare-events": { @@ -8158,6 +7627,7 @@ "resolved": "https://registry.npmjs.org/bindings/-/bindings-1.5.0.tgz", "integrity": "sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==", "dev": true, + "license": "MIT", "optional": true, "dependencies": { "file-uri-to-path": "1.0.0" @@ -8184,6 +7654,7 @@ }, "node_modules/brace-expansion": { "version": "1.1.11", + "dev": true, "license": "MIT", "dependencies": { "balanced-match": "^1.0.0", @@ -8479,9 +7950,10 @@ "version": "1.2.13", "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.13.tgz", "integrity": "sha512-oWb1Z6mkHIskLzEJ/XWX0srkpkTQ7vaopMQkyaEIoq0fmtFVxOthb8cCxeT+p3ynTdkk/RZwbgG4brR5BeWECw==", - "deprecated": "The v1 package contains DANGEROUS / INSECURE binaries. Upgrade to safe fsevents v2", + "deprecated": "Upgrade to fsevents v2 to mitigate potential security issues", "dev": true, "hasInstallScript": true, + "license": "MIT", "optional": true, "os": [ "darwin" @@ -9135,7 +8607,6 @@ }, "node_modules/browserslist": { "version": "4.23.3", - "dev": true, "funding": [ { "type": "opencollective", @@ -9210,6 +8681,7 @@ "version": "3.3.0", "dev": true, "license": "MIT", + "peer": true, "engines": { "node": ">=6" }, @@ -9428,7 +8900,9 @@ }, "node_modules/camelcase": { "version": "6.3.0", + "dev": true, "license": "MIT", + "peer": true, "engines": { "node": ">=10" }, @@ -9470,7 +8944,6 @@ }, "node_modules/caniuse-api": { "version": "3.0.0", - "dev": true, "license": "MIT", "dependencies": { "browserslist": "^4.0.0", @@ -9481,7 +8954,6 @@ }, "node_modules/caniuse-lite": { "version": "1.0.30001651", - "dev": true, "funding": [ { "type": "opencollective", @@ -10009,7 +9481,7 @@ } }, "node_modules/comlink": { - "version": "4.3.1", + "version": "4.4.1", "dev": true, "license": "Apache-2.0" }, @@ -10136,6 +9608,7 @@ }, "node_modules/concat-map": { "version": "0.0.1", + "dev": true, "license": "MIT" }, "node_modules/connect": { @@ -10288,9 +9761,8 @@ }, "node_modules/conventional-changelog-angular": { "version": "7.0.0", - "resolved": "https://registry.npmjs.org/conventional-changelog-angular/-/conventional-changelog-angular-7.0.0.tgz", - "integrity": "sha512-ROjNchA9LgfNMTTFSIWPzebCwOGFdgkEq45EnvvrmSLvCtAw0HSmrCs7/ty+wAeYUZyNay0YMUNYFTRL72PkBQ==", "dev": true, + "license": "ISC", "dependencies": { "compare-func": "^2.0.0" }, @@ -11147,9 +10619,8 @@ }, "node_modules/conventional-commits-parser": { "version": "5.0.0", - "resolved": "https://registry.npmjs.org/conventional-commits-parser/-/conventional-commits-parser-5.0.0.tgz", - "integrity": "sha512-ZPMl0ZJbw74iS9LuX9YIAiW8pfM5p3yh2o/NbXHbkFuZzY5jvdi5jFycEOkmBW5H5I7nA+D6f3UcsCLP2vvSEA==", "dev": true, + "license": "MIT", "dependencies": { "is-text-path": "^2.0.0", "JSONStream": "^1.3.5", @@ -11218,7 +10689,6 @@ }, "node_modules/cosmiconfig": { "version": "9.0.0", - "dev": true, "license": "MIT", "dependencies": { "env-paths": "^2.2.1", @@ -11243,9 +10713,8 @@ }, "node_modules/cosmiconfig-typescript-loader": { "version": "5.0.0", - "resolved": "https://registry.npmjs.org/cosmiconfig-typescript-loader/-/cosmiconfig-typescript-loader-5.0.0.tgz", - "integrity": "sha512-+8cK7jRAReYkMwMiG+bxhcNKiHJDM6bR9FD/nGBXOWdMLuYawjF5cGrtLilJ+LGd3ZjCXnJjR5DkfWPoIVlqJA==", "dev": true, + "license": "MIT", "dependencies": { "jiti": "^1.19.1" }, @@ -11260,12 +10729,10 @@ }, "node_modules/cosmiconfig/node_modules/argparse": { "version": "2.0.1", - "dev": true, "license": "Python-2.0" }, "node_modules/cosmiconfig/node_modules/js-yaml": { "version": "4.1.0", - "dev": true, "license": "MIT", "dependencies": { "argparse": "^2.0.1" @@ -11289,7 +10756,6 @@ }, "node_modules/css-declaration-sorter": { "version": "7.2.0", - "dev": true, "license": "ISC", "engines": { "node": "^14 || ^16 || >=18" @@ -11351,11 +10817,11 @@ } }, "node_modules/cssnano": { - "version": "7.0.5", + "version": "7.0.6", "dev": true, "license": "MIT", "dependencies": { - "cssnano-preset-default": "^7.0.5", + "cssnano-preset-default": "^7.0.6", "lilconfig": "^3.1.2" }, "engines": { @@ -11370,26 +10836,26 @@ } }, "node_modules/cssnano-preset-default": { - "version": "7.0.5", + "version": "7.0.6", "dev": true, "license": "MIT", "dependencies": { "browserslist": "^4.23.3", "css-declaration-sorter": "^7.2.0", "cssnano-utils": "^5.0.0", - "postcss-calc": "^10.0.1", + "postcss-calc": "^10.0.2", "postcss-colormin": "^7.0.2", - "postcss-convert-values": "^7.0.3", - "postcss-discard-comments": "^7.0.2", + "postcss-convert-values": "^7.0.4", + "postcss-discard-comments": "^7.0.3", "postcss-discard-duplicates": "^7.0.1", "postcss-discard-empty": "^7.0.0", "postcss-discard-overridden": "^7.0.0", - "postcss-merge-longhand": "^7.0.3", - "postcss-merge-rules": "^7.0.3", + "postcss-merge-longhand": "^7.0.4", + "postcss-merge-rules": "^7.0.4", "postcss-minify-font-values": "^7.0.0", "postcss-minify-gradients": "^7.0.0", "postcss-minify-params": "^7.0.2", - "postcss-minify-selectors": "^7.0.3", + "postcss-minify-selectors": "^7.0.4", "postcss-normalize-charset": "^7.0.0", "postcss-normalize-display-values": "^7.0.0", "postcss-normalize-positions": "^7.0.0", @@ -11403,7 +10869,7 @@ "postcss-reduce-initial": "^7.0.2", "postcss-reduce-transforms": "^7.0.0", "postcss-svgo": "^7.0.1", - "postcss-unique-selectors": "^7.0.2" + "postcss-unique-selectors": "^7.0.3" }, "engines": { "node": "^18.12.0 || ^20.9.0 || >=22.0" @@ -11425,7 +10891,6 @@ }, "node_modules/csso": { "version": "5.0.5", - "dev": true, "license": "MIT", "dependencies": { "css-tree": "~2.2.0" @@ -11437,7 +10902,6 @@ }, "node_modules/csso/node_modules/css-tree": { "version": "2.2.1", - "dev": true, "license": "MIT", "dependencies": { "mdn-data": "2.0.28", @@ -11450,13 +10914,8 @@ }, "node_modules/csso/node_modules/mdn-data": { "version": "2.0.28", - "dev": true, "license": "CC0-1.0" }, - "node_modules/cssom": { - "version": "0.5.0", - "license": "MIT" - }, "node_modules/csv": { "version": "5.5.3", "dev": true, @@ -11501,9 +10960,8 @@ }, "node_modules/dargs": { "version": "8.1.0", - "resolved": "https://registry.npmjs.org/dargs/-/dargs-8.1.0.tgz", - "integrity": "sha512-wAV9QHOsNbwnWdNW2FYvE1P56wtgSbM+3SZcdGiWQILwVjACCXDCI3Ai8QlCjMDB8YK5zySiXZYBiwGmNY3lnw==", "dev": true, + "license": "MIT", "engines": { "node": ">=12" }, @@ -11561,6 +11019,7 @@ }, "node_modules/decamelize": { "version": "1.2.0", + "dev": true, "license": "MIT", "engines": { "node": ">=0.10.0" @@ -11568,6 +11027,7 @@ }, "node_modules/decamelize-keys": { "version": "1.1.1", + "dev": true, "license": "MIT", "dependencies": { "decamelize": "^1.1.0", @@ -11582,6 +11042,7 @@ }, "node_modules/decamelize-keys/node_modules/map-obj": { "version": "1.0.1", + "dev": true, "license": "MIT", "engines": { "node": ">=0.10.0" @@ -12118,7 +11579,6 @@ }, "node_modules/electron-to-chromium": { "version": "1.5.11", - "dev": true, "license": "ISC" }, "node_modules/element-internals-polyfill": { @@ -12137,6 +11597,123 @@ "@11ty/eleventy": "*" } }, + "node_modules/eleventy-plugin-helmet": { + "version": "0.2.2", + "dev": true, + "license": "MIT", + "dependencies": { + "posthtml": "^0.13.1" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "@11ty/eleventy": ">=0.7" + } + }, + "node_modules/eleventy-plugin-helmet/node_modules/dom-serializer": { + "version": "0.2.2", + "dev": true, + "license": "MIT", + "dependencies": { + "domelementtype": "^2.0.1", + "entities": "^2.0.0" + } + }, + "node_modules/eleventy-plugin-helmet/node_modules/dom-serializer/node_modules/domelementtype": { + "version": "2.3.0", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fb55" + } + ], + "license": "BSD-2-Clause" + }, + "node_modules/eleventy-plugin-helmet/node_modules/dom-serializer/node_modules/entities": { + "version": "2.2.0", + "dev": true, + "license": "BSD-2-Clause", + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/eleventy-plugin-helmet/node_modules/domelementtype": { + "version": "1.3.1", + "dev": true, + "license": "BSD-2-Clause" + }, + "node_modules/eleventy-plugin-helmet/node_modules/domhandler": { + "version": "2.4.2", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "domelementtype": "1" + } + }, + "node_modules/eleventy-plugin-helmet/node_modules/domutils": { + "version": "1.7.0", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "dom-serializer": "0", + "domelementtype": "1" + } + }, + "node_modules/eleventy-plugin-helmet/node_modules/entities": { + "version": "1.1.2", + "dev": true, + "license": "BSD-2-Clause" + }, + "node_modules/eleventy-plugin-helmet/node_modules/htmlparser2": { + "version": "3.10.1", + "dev": true, + "license": "MIT", + "dependencies": { + "domelementtype": "^1.3.1", + "domhandler": "^2.3.0", + "domutils": "^1.5.1", + "entities": "^1.1.1", + "inherits": "^2.0.1", + "readable-stream": "^3.1.1" + } + }, + "node_modules/eleventy-plugin-helmet/node_modules/posthtml": { + "version": "0.13.4", + "dev": true, + "license": "MIT", + "dependencies": { + "posthtml-parser": "^0.5.0", + "posthtml-render": "^1.2.3" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/eleventy-plugin-helmet/node_modules/posthtml-parser": { + "version": "0.5.3", + "dev": true, + "license": "MIT", + "dependencies": { + "htmlparser2": "^3.9.2" + }, + "engines": { + "node": ">=10.0.0" + }, + "funding": { + "type": "patreon", + "url": "https://opencollective.com/posthtml" + } + }, + "node_modules/eleventy-plugin-helmet/node_modules/posthtml-render": { + "version": "1.4.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + } + }, "node_modules/eleventy-plugin-nesting-toc": { "version": "1.3.0", "dev": true, @@ -12330,7 +11907,6 @@ }, "node_modules/env-paths": { "version": "2.2.1", - "dev": true, "license": "MIT", "engines": { "node": ">=6" @@ -12483,6 +12059,7 @@ "arm64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "darwin" @@ -12510,7 +12087,6 @@ }, "node_modules/escalade": { "version": "3.1.2", - "dev": true, "license": "MIT", "engines": { "node": ">=6" @@ -12564,18 +12140,22 @@ } }, "node_modules/eslint": { - "version": "9.9.0", + "version": "9.11.1", "dev": true, "license": "MIT", "dependencies": { "@eslint-community/eslint-utils": "^4.2.0", "@eslint-community/regexpp": "^4.11.0", - "@eslint/config-array": "^0.17.1", + "@eslint/config-array": "^0.18.0", + "@eslint/core": "^0.6.0", "@eslint/eslintrc": "^3.1.0", - "@eslint/js": "9.9.0", + "@eslint/js": "9.11.1", + "@eslint/plugin-kit": "^0.2.0", "@humanwhocodes/module-importer": "^1.0.1", "@humanwhocodes/retry": "^0.3.0", "@nodelib/fs.walk": "^1.2.8", + "@types/estree": "^1.0.6", + "@types/json-schema": "^7.0.15", "ajv": "^6.12.4", "chalk": "^4.0.0", "cross-spawn": "^7.0.2", @@ -12595,7 +12175,6 @@ "is-glob": "^4.0.0", "is-path-inside": "^3.0.3", "json-stable-stringify-without-jsonify": "^1.0.1", - "levn": "^0.4.1", "lodash.merge": "^4.6.2", "minimatch": "^3.1.2", "natural-compare": "^1.4.0", @@ -13107,6 +12686,11 @@ "url": "https://opencollective.com/eslint" } }, + "node_modules/eslint/node_modules/@types/estree": { + "version": "1.0.6", + "dev": true, + "license": "MIT" + }, "node_modules/eslint/node_modules/ajv": { "version": "6.12.6", "dev": true, @@ -13278,7 +12862,6 @@ }, "node_modules/estree-walker": { "version": "2.0.2", - "dev": true, "license": "MIT" }, "node_modules/esutils": { @@ -13700,6 +13283,7 @@ "resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz", "integrity": "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==", "dev": true, + "license": "MIT", "optional": true }, "node_modules/filelist": { @@ -13800,9 +13384,8 @@ }, "node_modules/find-up": { "version": "7.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-7.0.0.tgz", - "integrity": "sha512-YyZM99iHrqLKjmt4LJDj58KI+fYyufRLBSYcqycxf//KpBk9FoewoGX0450m9nB44qrZnovzC2oeP5hUibxc/g==", "dev": true, + "license": "MIT", "dependencies": { "locate-path": "^7.2.0", "path-exists": "^5.0.0", @@ -14091,6 +13674,7 @@ }, "node_modules/flat-cache": { "version": "3.2.0", + "dev": true, "license": "MIT", "dependencies": { "flatted": "^3.2.9", @@ -14267,14 +13851,15 @@ }, "node_modules/fs.realpath": { "version": "1.0.0", + "dev": true, "license": "ISC" }, "node_modules/fsevents": { "version": "2.3.3", "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", - "dev": true, "hasInstallScript": true, + "license": "MIT", "optional": true, "os": [ "darwin" @@ -14285,6 +13870,7 @@ }, "node_modules/function-bind": { "version": "1.1.2", + "dev": true, "license": "MIT", "funding": { "url": "https://github.com/sponsors/ljharb" @@ -14591,9 +14177,8 @@ }, "node_modules/git-raw-commits": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/git-raw-commits/-/git-raw-commits-4.0.0.tgz", - "integrity": "sha512-ICsMM1Wk8xSGMowkOmPrzo2Fgmfo4bMHLNX6ytHjajRJUqvHOw/TFapQ+QG75c3X/tTDDhOSRPGC52dDbNM8FQ==", "dev": true, + "license": "MIT", "dependencies": { "dargs": "^8.0.0", "meow": "^12.0.1", @@ -14849,9 +14434,8 @@ }, "node_modules/global-directory": { "version": "4.0.1", - "resolved": "https://registry.npmjs.org/global-directory/-/global-directory-4.0.1.tgz", - "integrity": "sha512-wHTUcDUoZ1H5/0iVqEudYW4/kAlN5cZ3j/bXn0Dpbizl9iaUVeWSHqiOjsgk6OW2bkLclbBjzewBz6weQ1zA2Q==", "dev": true, + "license": "MIT", "dependencies": { "ini": "4.1.1" }, @@ -15121,6 +14705,7 @@ }, "node_modules/hard-rejection": { "version": "2.1.0", + "dev": true, "license": "MIT", "engines": { "node": ">=6" @@ -15285,6 +14870,7 @@ }, "node_modules/hasown": { "version": "2.0.2", + "dev": true, "license": "MIT", "dependencies": { "function-bind": "^1.1.2" @@ -15691,18 +15277,10 @@ "node": ">=4" } }, - "node_modules/import-lazy": { - "version": "4.0.0", - "license": "MIT", - "engines": { - "node": ">=8" - } - }, "node_modules/import-meta-resolve": { "version": "4.1.0", - "resolved": "https://registry.npmjs.org/import-meta-resolve/-/import-meta-resolve-4.1.0.tgz", - "integrity": "sha512-I6fiaX09Xivtk+THaMfAwnA3MVA5Big1WHF1Dfx9hFuvNIWpXnorlkzhcQf6ehrqQiiZECRt1poOAkPmer3ruw==", "dev": true, + "license": "MIT", "funding": { "type": "github", "url": "https://github.com/sponsors/wooorm" @@ -15744,6 +15322,7 @@ }, "node_modules/inflight": { "version": "1.0.6", + "dev": true, "license": "ISC", "dependencies": { "once": "^1.3.0", @@ -15752,13 +15331,13 @@ }, "node_modules/inherits": { "version": "2.0.4", + "dev": true, "license": "ISC" }, "node_modules/ini": { "version": "4.1.1", - "resolved": "https://registry.npmjs.org/ini/-/ini-4.1.1.tgz", - "integrity": "sha512-QQnnxNyfvmHFIsj7gkPcYymR8Jdw/o7mp5ZFihxn6h8Ci6fh3Dx4E1gPjpQEpIuPo9XVNY/ZUwh4BPMjGyL01g==", "dev": true, + "license": "ISC", "engines": { "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } @@ -15979,6 +15558,7 @@ "version": "3.2.1", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "builtin-modules": "^3.3.0" }, @@ -15991,6 +15571,7 @@ }, "node_modules/is-core-module": { "version": "2.15.0", + "dev": true, "license": "MIT", "dependencies": { "hasown": "^2.0.2" @@ -16281,9 +15862,8 @@ }, "node_modules/is-text-path": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-text-path/-/is-text-path-2.0.0.tgz", - "integrity": "sha512-+oDTluR6WEjdXEJMnC2z6A4FRwFoYuvShVVEGsS7ewc0UTi2QtAKMDJuL4BDEVt+5T7MjFo12RP8ghOM75oKJw==", "dev": true, + "license": "MIT", "dependencies": { "text-extensions": "^2.0.0" }, @@ -16643,7 +16223,7 @@ } }, "node_modules/jsonc-parser": { - "version": "3.2.1", + "version": "3.3.1", "dev": true, "license": "MIT" }, @@ -16768,7 +16348,6 @@ }, "node_modules/known-css-properties": { "version": "0.34.0", - "dev": true, "license": "MIT" }, "node_modules/koa": { @@ -17093,7 +16672,6 @@ }, "node_modules/lilconfig": { "version": "3.1.2", - "dev": true, "license": "MIT", "engines": { "node": ">=14" @@ -17110,38 +16688,6 @@ "version": "1.2.4", "license": "MIT" }, - "node_modules/linkedom": { - "version": "0.14.26", - "license": "ISC", - "dependencies": { - "css-select": "^5.1.0", - "cssom": "^0.5.0", - "html-escaper": "^3.0.3", - "htmlparser2": "^8.0.1", - "uhyphen": "^0.2.0" - } - }, - "node_modules/linkedom/node_modules/html-escaper": { - "version": "3.0.3", - "license": "MIT" - }, - "node_modules/linkedom/node_modules/htmlparser2": { - "version": "8.0.2", - "funding": [ - "https://github.com/fb55/htmlparser2?sponsor=1", - { - "type": "github", - "url": "https://github.com/sponsors/fb55" - } - ], - "license": "MIT", - "dependencies": { - "domelementtype": "^2.3.0", - "domhandler": "^5.0.3", - "domutils": "^3.0.1", - "entities": "^4.4.0" - } - }, "node_modules/linkify-it": { "version": "5.0.0", "dev": true, @@ -17299,8 +16845,7 @@ }, "node_modules/lit-html": { "version": "3.2.0", - "resolved": "https://registry.npmjs.org/lit-html/-/lit-html-3.2.0.tgz", - "integrity": "sha512-pwT/HwoxqI9FggTrYVarkBKFN9MlTUpLrDHubTmW4SrkL3kkqW5gxwbxMMUnbbRHBC0WTZnYHcjDSCM559VyfA==", + "license": "BSD-3-Clause", "dependencies": { "@types/trusted-types": "^2.0.2" } @@ -17585,9 +17130,8 @@ }, "node_modules/locate-path": { "version": "7.2.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-7.2.0.tgz", - "integrity": "sha512-gvVijfZvn7R+2qyPX8mAuKcFGDf6Nc61GdvGafQsHL0sBIxfKzA+usWn4GFC/bk+QdwPUD4kWFJLhElipq+0VA==", "dev": true, + "license": "MIT", "dependencies": { "p-locate": "^6.0.0" }, @@ -17631,19 +17175,16 @@ }, "node_modules/lodash.isplainobject": { "version": "4.0.6", - "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz", - "integrity": "sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/lodash.kebabcase": { "version": "4.1.1", - "resolved": "https://registry.npmjs.org/lodash.kebabcase/-/lodash.kebabcase-4.1.1.tgz", - "integrity": "sha512-N8XRTIMMqqDgSy4VLKPnJ/+hpGZN+PHQiJnSenYqPaVV/NCqEogTnAdZLQiGKhxX+JCs8waWq2t1XHWKOmlY8g==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/lodash.memoize": { "version": "4.1.2", - "dev": true, "license": "MIT" }, "node_modules/lodash.merge": { @@ -17653,15 +17194,13 @@ }, "node_modules/lodash.mergewith": { "version": "4.6.2", - "resolved": "https://registry.npmjs.org/lodash.mergewith/-/lodash.mergewith-4.6.2.tgz", - "integrity": "sha512-GK3g5RPZWTRSeLSpgP8Xhra+pnjBC56q9FZYe1d5RN3TJ35dbkGy3YqBSMbyCrlbi+CM9Z3Jk5yTL7RCsqboyQ==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/lodash.snakecase": { "version": "4.1.1", - "resolved": "https://registry.npmjs.org/lodash.snakecase/-/lodash.snakecase-4.1.1.tgz", - "integrity": "sha512-QZ1d4xoBHYUeuouhEq3lk3Uq7ldgyFXGBhg04+oRLnIz8o9T65Eh+8YdroUwn846zchkA9yDsDl5CVVaV2nqYw==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/lodash.startcase": { "version": "4.4.0", @@ -17674,14 +17213,12 @@ }, "node_modules/lodash.uniq": { "version": "4.5.0", - "dev": true, "license": "MIT" }, "node_modules/lodash.upperfirst": { "version": "4.3.1", - "resolved": "https://registry.npmjs.org/lodash.upperfirst/-/lodash.upperfirst-4.3.1.tgz", - "integrity": "sha512-sReKOYJIJf74dhJONhU4e0/shzi1trVbSWDOhKYE5XV2O+H7Sb2Dihwuc7xWxVl+DgFPyTqIN3zMfT9cq5iWDg==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/log-symbols": { "version": "5.1.0", @@ -17881,6 +17418,7 @@ }, "node_modules/map-obj": { "version": "4.3.0", + "dev": true, "license": "MIT", "engines": { "node": ">=8" @@ -17937,18 +17475,23 @@ "markdown-it": ">= 9.0.0" } }, + "node_modules/markdown-it-footnote": { + "version": "4.0.0", + "dev": true, + "license": "MIT" + }, "node_modules/markdown-it/node_modules/argparse": { "version": "2.0.1", "dev": true, "license": "Python-2.0" }, "node_modules/markdownlint": { - "version": "0.34.0", + "version": "0.35.0", "dev": true, "license": "MIT", "dependencies": { "markdown-it": "14.1.0", - "markdownlint-micromark": "0.1.9" + "markdownlint-micromark": "0.1.10" }, "engines": { "node": ">=18" @@ -17958,16 +17501,16 @@ } }, "node_modules/markdownlint-cli2": { - "version": "0.13.0", + "version": "0.14.0", "dev": true, "license": "MIT", "dependencies": { - "globby": "14.0.1", + "globby": "14.0.2", "js-yaml": "4.1.0", - "jsonc-parser": "3.2.1", - "markdownlint": "0.34.0", - "markdownlint-cli2-formatter-default": "0.0.4", - "micromatch": "4.0.5" + "jsonc-parser": "3.3.1", + "markdownlint": "0.35.0", + "markdownlint-cli2-formatter-default": "0.0.5", + "micromatch": "4.0.8" }, "bin": { "markdownlint-cli2": "markdownlint-cli2.js" @@ -17980,9 +17523,12 @@ } }, "node_modules/markdownlint-cli2-formatter-default": { - "version": "0.0.4", + "version": "0.0.5", "dev": true, "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/DavidAnson" + }, "peerDependencies": { "markdownlint-cli2": ">=0.0.4" } @@ -18004,7 +17550,7 @@ "license": "Python-2.0" }, "node_modules/markdownlint-cli2/node_modules/globby": { - "version": "14.0.1", + "version": "14.0.2", "dev": true, "license": "MIT", "dependencies": { @@ -18033,18 +17579,6 @@ "js-yaml": "bin/js-yaml.js" } }, - "node_modules/markdownlint-cli2/node_modules/micromatch": { - "version": "4.0.5", - "dev": true, - "license": "MIT", - "dependencies": { - "braces": "^3.0.2", - "picomatch": "^2.3.1" - }, - "engines": { - "node": ">=8.6" - } - }, "node_modules/markdownlint-cli2/node_modules/path-type": { "version": "5.0.0", "dev": true, @@ -18068,7 +17602,7 @@ } }, "node_modules/markdownlint-micromark": { - "version": "0.1.9", + "version": "0.1.10", "dev": true, "license": "MIT", "engines": { @@ -18158,9 +17692,8 @@ }, "node_modules/meow": { "version": "12.1.1", - "resolved": "https://registry.npmjs.org/meow/-/meow-12.1.1.tgz", - "integrity": "sha512-BhXM0Au22RwUneMPwSCnyhTOizdWoIEPU9sp0Aqa1PnDMR5Wv2FGXYDjuzJEIX+Eo2Rb8xuYe5jrnm5QowQFkw==", "dev": true, + "license": "MIT", "engines": { "node": ">=16.10" }, @@ -18191,7 +17724,7 @@ } }, "node_modules/micromatch": { - "version": "4.0.7", + "version": "4.0.8", "license": "MIT", "dependencies": { "braces": "^3.0.3", @@ -18258,6 +17791,7 @@ }, "node_modules/min-indent": { "version": "1.0.1", + "dev": true, "license": "MIT", "engines": { "node": ">=4" @@ -18308,6 +17842,7 @@ }, "node_modules/minimatch": { "version": "3.1.2", + "dev": true, "license": "ISC", "dependencies": { "brace-expansion": "^1.1.7" @@ -18326,6 +17861,7 @@ }, "node_modules/minimist-options": { "version": "4.1.0", + "dev": true, "license": "MIT", "dependencies": { "arrify": "^1.0.1", @@ -18338,6 +17874,7 @@ }, "node_modules/minimist-options/node_modules/arrify": { "version": "1.0.1", + "dev": true, "license": "MIT", "engines": { "node": ">=0.10.0" @@ -18345,6 +17882,7 @@ }, "node_modules/minimist-options/node_modules/is-plain-obj": { "version": "1.1.0", + "dev": true, "license": "MIT", "engines": { "node": ">=0.10.0" @@ -18679,6 +18217,7 @@ "resolved": "https://registry.npmjs.org/nan/-/nan-2.20.0.tgz", "integrity": "sha512-bk3gXBZDGILuuo/6sKtr0DQmSThYHLtNCdSdXk9YkxD/jK6X2vmCyyXBBxyqZ4XcnzTyYEAThfX3DCEnLf6igw==", "dev": true, + "license": "MIT", "optional": true }, "node_modules/nanocolors": { @@ -18896,7 +18435,6 @@ }, "node_modules/node-releases": { "version": "2.0.18", - "dev": true, "license": "MIT" }, "node_modules/nodesi": { @@ -19212,6 +18750,7 @@ }, "node_modules/once": { "version": "1.4.0", + "dev": true, "license": "ISC", "dependencies": { "wrappy": "1" @@ -19449,9 +18988,8 @@ }, "node_modules/p-locate": { "version": "6.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-6.0.0.tgz", - "integrity": "sha512-wPrq66Llhl7/4AGC6I+cqxT07LhXvWL08LNXz1fENOw0Ap4sRZZ/gZpTTJ5jpurzzzfS2W/Ge9BY3LgLjCShcw==", "dev": true, + "license": "MIT", "dependencies": { "p-limit": "^4.0.0" }, @@ -19464,9 +19002,8 @@ }, "node_modules/p-locate/node_modules/p-limit": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-4.0.0.tgz", - "integrity": "sha512-5b0R4txpzjPWVw/cXXUResoD4hb6U/x9BH08L7nw+GN1sezDzPdxeRvpc9c433fZhBan/wusjbCsqwqm4EIBIQ==", "dev": true, + "license": "MIT", "dependencies": { "yocto-queue": "^1.0.0" }, @@ -19479,9 +19016,8 @@ }, "node_modules/p-locate/node_modules/yocto-queue": { "version": "1.1.1", - "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-1.1.1.tgz", - "integrity": "sha512-b4JR1PFR10y1mKjhHY9LaGo6tmrgjit7hxVIeAmyMw3jegXR4dhYqLaQF5zMXZxY7tLpMyJeLjr1C4rLmkVe8g==", "dev": true, + "license": "MIT", "engines": { "node": ">=12.20" }, @@ -19822,9 +19358,8 @@ }, "node_modules/patch-package": { "version": "8.0.0", - "resolved": "https://registry.npmjs.org/patch-package/-/patch-package-8.0.0.tgz", - "integrity": "sha512-da8BVIhzjtgScwDJ2TtKsfT5JFWz1hYoBl9rUQ1f38MC2HwnEIkK8VN3dKMKcP7P7bvvgzNDbfNHtx3MsQb5vA==", "dev": true, + "license": "MIT", "dependencies": { "@yarnpkg/lockfile": "^1.1.0", "chalk": "^4.1.2", @@ -19953,15 +19488,15 @@ }, "node_modules/path-exists": { "version": "5.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-5.0.0.tgz", - "integrity": "sha512-RjhtfwJOxzcFmNOi6ltcbcu4Iu+FL3zEj83dk4kAS+fVpTxXLO1b38RvJgT/0QwvV/L3aY9TAnyv0EOqW4GoMQ==", "dev": true, + "license": "MIT", "engines": { "node": "^12.20.0 || ^14.13.1 || >=16.0.0" } }, "node_modules/path-is-absolute": { "version": "1.0.1", + "dev": true, "license": "MIT", "engines": { "node": ">=0.10.0" @@ -20124,7 +19659,7 @@ } }, "node_modules/playground-elements": { - "version": "0.18.1", + "version": "0.19.1", "dev": true, "license": "BSD-3-Clause", "dependencies": { @@ -20135,63 +19670,19 @@ "@material/mwc-menu": "^0.27.0", "@material/mwc-textfield": "^0.27.0", "@types/codemirror": "^5.60.0", - "comlink": "=4.3.1", - "fuse.js": "^6.4.6", - "lit": "^2.0.0", - "tslib": "^2.0.3", + "comlink": "^4.4.1", + "fuse.js": "^7.0.0", + "lit": "^2.0.0 || ^3.0.0", + "tslib": "^2.6.3", "vscode-languageserver-protocol": "^3.17.2" } }, - "node_modules/playground-elements/node_modules/@lit/reactive-element": { - "version": "1.6.3", - "dev": true, - "license": "BSD-3-Clause", - "dependencies": { - "@lit-labs/ssr-dom-shim": "^1.0.0" - } - }, - "node_modules/playground-elements/node_modules/fuse.js": { - "version": "6.6.2", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": ">=10" - } - }, - "node_modules/playground-elements/node_modules/lit": { - "version": "2.8.0", - "dev": true, - "license": "BSD-3-Clause", - "dependencies": { - "@lit/reactive-element": "^1.6.0", - "lit-element": "^3.3.0", - "lit-html": "^2.8.0" - } - }, - "node_modules/playground-elements/node_modules/lit-element": { - "version": "3.3.3", - "dev": true, - "license": "BSD-3-Clause", - "dependencies": { - "@lit-labs/ssr-dom-shim": "^1.1.0", - "@lit/reactive-element": "^1.3.0", - "lit-html": "^2.8.0" - } - }, - "node_modules/playground-elements/node_modules/lit-html": { - "version": "2.8.0", - "dev": true, - "license": "BSD-3-Clause", - "dependencies": { - "@types/trusted-types": "^2.0.2" - } - }, "node_modules/playwright": { - "version": "1.46.1", + "version": "1.47.2", "dev": true, "license": "Apache-2.0", "dependencies": { - "playwright-core": "1.46.1" + "playwright-core": "1.47.2" }, "bin": { "playwright": "cli.js" @@ -20204,7 +19695,7 @@ } }, "node_modules/playwright-core": { - "version": "1.46.1", + "version": "1.47.2", "dev": true, "license": "Apache-2.0", "bin": { @@ -20220,6 +19711,7 @@ "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", "dev": true, "hasInstallScript": true, + "license": "MIT", "optional": true, "os": [ "darwin" @@ -20382,7 +19874,7 @@ } }, "node_modules/postcss-convert-values": { - "version": "7.0.3", + "version": "7.0.4", "dev": true, "license": "MIT", "dependencies": { @@ -20397,11 +19889,11 @@ } }, "node_modules/postcss-discard-comments": { - "version": "7.0.2", + "version": "7.0.3", "dev": true, "license": "MIT", "dependencies": { - "postcss-selector-parser": "^6.1.1" + "postcss-selector-parser": "^6.1.2" }, "engines": { "node": "^18.12.0 || ^20.9.0 || >=22.0" @@ -20444,12 +19936,12 @@ } }, "node_modules/postcss-merge-longhand": { - "version": "7.0.3", + "version": "7.0.4", "dev": true, "license": "MIT", "dependencies": { "postcss-value-parser": "^4.2.0", - "stylehacks": "^7.0.3" + "stylehacks": "^7.0.4" }, "engines": { "node": "^18.12.0 || ^20.9.0 || >=22.0" @@ -20459,14 +19951,14 @@ } }, "node_modules/postcss-merge-rules": { - "version": "7.0.3", + "version": "7.0.4", "dev": true, "license": "MIT", "dependencies": { "browserslist": "^4.23.3", "caniuse-api": "^3.0.0", "cssnano-utils": "^5.0.0", - "postcss-selector-parser": "^6.1.1" + "postcss-selector-parser": "^6.1.2" }, "engines": { "node": "^18.12.0 || ^20.9.0 || >=22.0" @@ -20522,12 +20014,12 @@ } }, "node_modules/postcss-minify-selectors": { - "version": "7.0.3", + "version": "7.0.4", "dev": true, "license": "MIT", "dependencies": { "cssesc": "^3.0.0", - "postcss-selector-parser": "^6.1.1" + "postcss-selector-parser": "^6.1.2" }, "engines": { "node": "^18.12.0 || ^20.9.0 || >=22.0" @@ -20536,6 +20028,55 @@ "postcss": "^8.4.31" } }, + "node_modules/postcss-nesting": { + "version": "12.1.5", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "peer": true, + "dependencies": { + "@csstools/selector-resolve-nested": "^1.1.0", + "@csstools/selector-specificity": "^3.1.1", + "postcss-selector-parser": "^6.1.0" + }, + "engines": { + "node": "^14 || ^16 || >=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/postcss-nesting/node_modules/@csstools/selector-specificity": { + "version": "3.1.1", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "peer": true, + "engines": { + "node": "^14 || ^16 || >=18" + }, + "peerDependencies": { + "postcss-selector-parser": "^6.0.13" + } + }, "node_modules/postcss-normalize-charset": { "version": "7.0.0", "dev": true, @@ -20718,7 +20259,6 @@ }, "node_modules/postcss-safe-parser": { "version": "7.0.0", - "dev": true, "funding": [ { "type": "opencollective", @@ -20768,11 +20308,11 @@ } }, "node_modules/postcss-unique-selectors": { - "version": "7.0.2", + "version": "7.0.3", "dev": true, "license": "MIT", "dependencies": { - "postcss-selector-parser": "^6.1.1" + "postcss-selector-parser": "^6.1.2" }, "engines": { "node": "^18.12.0 || ^20.9.0 || >=22.0" @@ -21064,6 +20604,13 @@ "node": ">=0.8" } }, + "node_modules/prism-esm": { + "version": "1.29.0-fix.6", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, "node_modules/prismjs": { "version": "1.29.0", "license": "MIT", @@ -21425,6 +20972,11 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/query-selector-shadow-dom": { + "version": "1.0.1", + "dev": true, + "license": "MIT" + }, "node_modules/queue": { "version": "6.0.2", "dev": true, @@ -21459,6 +21011,7 @@ }, "node_modules/quick-lru": { "version": "5.1.1", + "dev": true, "license": "MIT", "engines": { "node": ">=10" @@ -22190,6 +21743,7 @@ }, "node_modules/rimraf": { "version": "3.0.2", + "dev": true, "license": "ISC", "dependencies": { "glob": "^7.1.3" @@ -22203,6 +21757,7 @@ }, "node_modules/rimraf/node_modules/glob": { "version": "7.2.3", + "dev": true, "license": "ISC", "dependencies": { "fs.realpath": "^1.0.0", @@ -22221,7 +21776,7 @@ }, "node_modules/rollup": { "version": "4.21.0", - "dev": true, + "devOptional": true, "license": "MIT", "peer": true, "dependencies": { @@ -22271,7 +21826,7 @@ "cpu": [ "x64" ], - "dev": true, + "license": "MIT", "optional": true, "os": [ "darwin" @@ -22368,6 +21923,7 @@ }, "node_modules/semver": { "version": "7.6.3", + "dev": true, "license": "ISC", "bin": { "semver": "bin/semver.js" @@ -23439,6 +22995,7 @@ }, "node_modules/spdx-correct": { "version": "3.2.0", + "dev": true, "license": "Apache-2.0", "dependencies": { "spdx-expression-parse": "^3.0.0", @@ -23447,6 +23004,7 @@ }, "node_modules/spdx-correct/node_modules/spdx-expression-parse": { "version": "3.0.1", + "dev": true, "license": "MIT", "dependencies": { "spdx-exceptions": "^2.1.0", @@ -23455,6 +23013,7 @@ }, "node_modules/spdx-exceptions": { "version": "2.5.0", + "dev": true, "license": "CC-BY-3.0" }, "node_modules/spdx-expression-parse": { @@ -23469,6 +23028,7 @@ }, "node_modules/spdx-license-ids": { "version": "3.0.18", + "dev": true, "license": "CC0-1.0" }, "node_modules/split": { @@ -23537,9 +23097,8 @@ }, "node_modules/split2": { "version": "4.2.0", - "resolved": "https://registry.npmjs.org/split2/-/split2-4.2.0.tgz", - "integrity": "sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==", "dev": true, + "license": "ISC", "engines": { "node": ">= 10.x" } @@ -23880,15 +23439,16 @@ }, "node_modules/style-search": { "version": "0.1.0", + "dev": true, "license": "ISC" }, "node_modules/stylehacks": { - "version": "7.0.3", + "version": "7.0.4", "dev": true, "license": "MIT", "dependencies": { "browserslist": "^4.23.3", - "postcss-selector-parser": "^6.1.1" + "postcss-selector-parser": "^6.1.2" }, "engines": { "node": "^18.12.0 || ^20.9.0 || >=22.0" @@ -23898,8 +23458,7 @@ } }, "node_modules/stylelint": { - "version": "16.8.2", - "dev": true, + "version": "16.9.0", "funding": [ { "type": "opencollective", @@ -23912,9 +23471,9 @@ ], "license": "MIT", "dependencies": { - "@csstools/css-parser-algorithms": "^3.0.0", - "@csstools/css-tokenizer": "^3.0.0", - "@csstools/media-query-list-parser": "^3.0.0", + "@csstools/css-parser-algorithms": "^3.0.1", + "@csstools/css-tokenizer": "^3.0.1", + "@csstools/media-query-list-parser": "^3.0.1", "@csstools/selector-specificity": "^4.0.0", "@dual-bundle/import-meta-resolve": "^4.1.0", "balanced-match": "^2.0.0", @@ -23936,7 +23495,7 @@ "known-css-properties": "^0.34.0", "mathml-tag-names": "^2.1.3", "meow": "^13.2.0", - "micromatch": "^4.0.7", + "micromatch": "^4.0.8", "normalize-path": "^3.0.0", "picocolors": "^1.0.1", "postcss": "^8.4.41", @@ -23947,7 +23506,7 @@ "resolve-from": "^5.0.0", "string-width": "^4.2.3", "strip-ansi": "^7.1.0", - "supports-hyperlinks": "^3.0.0", + "supports-hyperlinks": "^3.1.0", "svg-tags": "^1.0.0", "table": "^6.8.2", "write-file-atomic": "^5.0.1" @@ -24006,17 +23565,14 @@ }, "node_modules/stylelint/node_modules/balanced-match": { "version": "2.0.0", - "dev": true, "license": "MIT" }, "node_modules/stylelint/node_modules/emoji-regex": { "version": "8.0.0", - "dev": true, "license": "MIT" }, "node_modules/stylelint/node_modules/file-entry-cache": { "version": "9.0.0", - "dev": true, "license": "MIT", "dependencies": { "flat-cache": "^5.0.0" @@ -24027,7 +23583,6 @@ }, "node_modules/stylelint/node_modules/flat-cache": { "version": "5.0.0", - "dev": true, "license": "MIT", "dependencies": { "flatted": "^3.3.1", @@ -24039,7 +23594,6 @@ }, "node_modules/stylelint/node_modules/global-modules": { "version": "2.0.0", - "dev": true, "license": "MIT", "dependencies": { "global-prefix": "^3.0.0" @@ -24050,7 +23604,6 @@ }, "node_modules/stylelint/node_modules/global-prefix": { "version": "3.0.0", - "dev": true, "license": "MIT", "dependencies": { "ini": "^1.3.5", @@ -24063,7 +23616,6 @@ }, "node_modules/stylelint/node_modules/globby": { "version": "11.1.0", - "dev": true, "license": "MIT", "dependencies": { "array-union": "^2.1.0", @@ -24082,12 +23634,10 @@ }, "node_modules/stylelint/node_modules/ini": { "version": "1.3.8", - "dev": true, "license": "ISC" }, "node_modules/stylelint/node_modules/meow": { "version": "13.2.0", - "dev": true, "license": "MIT", "engines": { "node": ">=18" @@ -24098,7 +23648,6 @@ }, "node_modules/stylelint/node_modules/string-width": { "version": "4.2.3", - "dev": true, "license": "MIT", "dependencies": { "emoji-regex": "^8.0.0", @@ -24111,7 +23660,6 @@ }, "node_modules/stylelint/node_modules/string-width/node_modules/strip-ansi": { "version": "6.0.1", - "dev": true, "license": "MIT", "dependencies": { "ansi-regex": "^5.0.1" @@ -24122,7 +23670,6 @@ }, "node_modules/stylelint/node_modules/strip-ansi": { "version": "7.1.0", - "dev": true, "license": "MIT", "dependencies": { "ansi-regex": "^6.0.1" @@ -24136,7 +23683,6 @@ }, "node_modules/stylelint/node_modules/strip-ansi/node_modules/ansi-regex": { "version": "6.0.1", - "dev": true, "license": "MIT", "engines": { "node": ">=12" @@ -24147,7 +23693,6 @@ }, "node_modules/stylelint/node_modules/which": { "version": "1.3.1", - "dev": true, "license": "ISC", "dependencies": { "isexe": "^2.0.0" @@ -24167,7 +23712,7 @@ } }, "node_modules/supports-hyperlinks": { - "version": "3.0.0", + "version": "3.1.0", "license": "MIT", "dependencies": { "has-flag": "^4.0.0", @@ -24175,6 +23720,9 @@ }, "engines": { "node": ">=14.18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/supports-preserve-symlinks-flag": { @@ -24212,7 +23760,6 @@ }, "node_modules/svgo": { "version": "3.3.2", - "dev": true, "license": "MIT", "dependencies": { "@trysound/sax": "0.2.0", @@ -24236,7 +23783,6 @@ }, "node_modules/svgo/node_modules/commander": { "version": "7.2.0", - "dev": true, "license": "MIT", "engines": { "node": ">= 10" @@ -24408,9 +23954,8 @@ }, "node_modules/text-extensions": { "version": "2.4.0", - "resolved": "https://registry.npmjs.org/text-extensions/-/text-extensions-2.4.0.tgz", - "integrity": "sha512-te/NtwBwfiNRLf9Ijqx3T0nlqZiQ2XrrtBvu+cLL8ZRrGkO0NHTug8MYFKyoSrv/sHTaSKfilUkizV6XhxMJ3g==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" }, @@ -24503,11 +24048,15 @@ "readable-stream": "3" } }, + "node_modules/tinycolor2": { + "version": "1.6.0", + "dev": true, + "license": "MIT" + }, "node_modules/tinyexec": { "version": "0.3.0", - "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-0.3.0.tgz", - "integrity": "sha512-tVGE0mVJPGb0chKhqmsoosjsS+qUnJVGJpZgsHYQcGoPlG3B51R3PouqTgEGH2Dc9jjFyOqOpix6ZHNMXp1FZg==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/tmp": { "version": "0.0.33", @@ -24800,7 +24349,7 @@ "peer": true }, "node_modules/tslib": { - "version": "2.6.3", + "version": "2.7.0", "license": "0BSD" }, "node_modules/tsscmp": { @@ -24814,9 +24363,8 @@ }, "node_modules/tsx": { "version": "4.19.1", - "resolved": "https://registry.npmjs.org/tsx/-/tsx-4.19.1.tgz", - "integrity": "sha512-0flMz1lh74BR4wOvBjuh9olbnwqCPc35OOlfyzHba0Dc+QNUeWX/Gq2YTbnwcWPO3BMd8fkzRVrHcsR+a7z7rA==", "dev": true, + "license": "MIT", "dependencies": { "esbuild": "~0.23.0", "get-tsconfig": "^4.7.5" @@ -24839,6 +24387,7 @@ "ppc64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "aix" @@ -24855,6 +24404,7 @@ "arm" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "android" @@ -24871,6 +24421,7 @@ "arm64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "android" @@ -24887,6 +24438,7 @@ "x64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "android" @@ -24903,6 +24455,7 @@ "arm64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "darwin" @@ -24919,6 +24472,7 @@ "x64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "darwin" @@ -24935,6 +24489,7 @@ "arm64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "freebsd" @@ -24951,6 +24506,7 @@ "x64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "freebsd" @@ -24967,6 +24523,7 @@ "arm" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" @@ -24983,6 +24540,7 @@ "arm64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" @@ -24999,6 +24557,7 @@ "ia32" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" @@ -25015,6 +24574,7 @@ "loong64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" @@ -25031,6 +24591,7 @@ "mips64el" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" @@ -25047,6 +24608,7 @@ "ppc64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" @@ -25063,6 +24625,7 @@ "riscv64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" @@ -25079,6 +24642,22 @@ "s390x" ], "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/linux-x64": { + "version": "0.23.1", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" @@ -25095,6 +24674,7 @@ "x64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "netbsd" @@ -25111,6 +24691,7 @@ "x64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "openbsd" @@ -25127,6 +24708,7 @@ "x64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "sunos" @@ -25143,6 +24725,7 @@ "arm64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "win32" @@ -25159,6 +24742,7 @@ "ia32" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "win32" @@ -25175,6 +24759,7 @@ "x64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "win32" @@ -25282,7 +24867,7 @@ } }, "node_modules/typescript": { - "version": "5.5.4", + "version": "5.6.2", "devOptional": true, "license": "Apache-2.0", "bin": { @@ -25316,6 +24901,22 @@ } } }, + "node_modules/typescript-transform-lit-css": { + "version": "2.0.0", + "dev": true, + "license": "ISC", + "dependencies": { + "@pwrs/lit-css": "^3.0.0" + }, + "peerDependencies": { + "clean-css": "^5", + "lit": "^2.7.2 || ^3.0.0", + "postcss": "^8", + "postcss-nesting": "^12", + "ts-patch": "^3.0", + "typescript": "^5" + } + }, "node_modules/typical": { "version": "4.0.0", "dev": true, @@ -25364,10 +24965,6 @@ "node": ">=0.8.0" } }, - "node_modules/uhyphen": { - "version": "0.2.0", - "license": "ISC" - }, "node_modules/ultron": { "version": "1.1.1", "dev": true, @@ -25519,7 +25116,6 @@ }, "node_modules/update-browserslist-db": { "version": "1.1.0", - "dev": true, "funding": [ { "type": "opencollective", @@ -25636,6 +25232,7 @@ }, "node_modules/validate-npm-package-license": { "version": "3.0.4", + "dev": true, "license": "Apache-2.0", "dependencies": { "spdx-correct": "^3.0.0", @@ -25644,6 +25241,7 @@ }, "node_modules/validate-npm-package-license/node_modules/spdx-expression-parse": { "version": "3.0.1", + "dev": true, "license": "MIT", "dependencies": { "spdx-exceptions": "^2.1.0", @@ -25803,10 +25401,8 @@ } }, "node_modules/web-dev-server-plugin-lit-css": { - "version": "3.0.0", - "dev": true, + "version": "3.0.1", "license": "ISC", - "peer": true, "dependencies": { "@pwrs/lit-css": "^3.0.0", "@rollup/pluginutils": "^5.1.0" @@ -25914,7 +25510,7 @@ } }, "node_modules/wireit": { - "version": "0.14.7", + "version": "0.14.9", "dev": true, "license": "Apache-2.0", "workspaces": [ @@ -26078,6 +25674,7 @@ }, "node_modules/wrappy": { "version": "1.0.2", + "dev": true, "license": "ISC" }, "node_modules/write-file-atomic": { @@ -26255,6 +25852,7 @@ }, "node_modules/yocto-queue": { "version": "0.1.0", + "dev": true, "license": "MIT", "engines": { "node": ">=10" diff --git a/package.json b/package.json index 9be6b50b8b..f4fc2757c7 100644 --- a/package.json +++ b/package.json @@ -86,6 +86,7 @@ "command": "web-dev-server --open --watch", "dependencies": [ "patch", + "compile", "analyze", "playgrounds", "watch:docs" @@ -104,8 +105,8 @@ "service": true, "command": "eleventy --serve --incremental", "dependencies": [ - "compile", "patch", + "compile", "analyze", "playgrounds" ] @@ -117,7 +118,7 @@ "analyze", "react-wrappers", "entrypoint", - "copy-css", + "copy-assets", "docs" ] }, @@ -181,7 +182,7 @@ "react/**/*" ] }, - "copy-css": { + "copy-assets": { "command": "npx tsx scripts/copy-assets.ts", "files": [ "elements/*/*.css", @@ -289,18 +290,20 @@ }, "dependencies": { "@lit/context": "^1.1.2", - "@patternfly/pfe-core": "^4.0.1", - "@rhds/icons": "^1.1.1", - "@rhds/tokens": "^2.0.1", + "@patternfly/pfe-core": "^4.0.2", + "@rhds/icons": "^1.1.2", + "@rhds/tokens": "^2.1.0", "lit": "^3.2.0", - "tslib": "^2.6.3" + "prism-esm": "^1.29.0-fix.6", + "tslib": "^2.7.0", + "web-dev-server-plugin-lit-css": "^3.0.1" }, "devDependencies": { "@11ty/eleventy": "^2.0.1", "@11ty/eleventy-img": "^4.0.2", "@11ty/eleventy-plugin-rss": "^2.0.2", - "@commitlint/cli": "^19.4.0", - "@commitlint/config-conventional": "^19.2.2", + "@commitlint/cli": "^19.5.0", + "@commitlint/config-conventional": "^19.5.0", "@lit-labs/eleventy-plugin-lit": "^1.0.3", "@lit/reactive-element": "^2.0.4", "@parse5/tools": "^0.5.0", @@ -309,46 +312,51 @@ "@patternfly/eslint-config-elements": "^4.0.0", "@patternfly/eslint-plugin-elements": "^2.0.0", "@patternfly/icons": "^1.0.3", - "@patternfly/pfe-tools": "^3.0.0", - "@playwright/test": "^1.46.1", - "@rollup/plugin-node-resolve": "^15.2.3", + "@patternfly/pfe-tools": "^3.0.1", + "@playwright/test": "^1.47.2", + "@rollup/plugin-node-resolve": "^15.3.0", "@rollup/plugin-typescript": "^11.1.6", "@stylistic/stylelint-config": "^2.0.0", - "@stylistic/stylelint-plugin": "^3.0.1", - "@types/mocha": "^10.0.7", + "@stylistic/stylelint-plugin": "^3.1.0", + "@types/mocha": "^10.0.8", "@web/rollup-plugin-import-meta-assets": "^2.2.1", "@webcomponents/template-shadowroot": "^0.2.1", "async-csv": "^2.1.3", "autoprefixer": "^10.4.20", - "cssnano": "^7.0.5", + "cssnano": "^7.0.6", "custom-elements-manifest": "^2.1.0", "element-internals-polyfill": "^1.3.11", "eleventy-plugin-dart-sass": "^1.0.3", + "eleventy-plugin-helmet": "^0.2.2", "eleventy-plugin-nesting-toc": "^1.3.0", "es-module-shims": "^1.10.0", - "eslint": "^9.9.0", + "eslint": "^9.11.1", "fuse.js": "^7.0.0", "git-branch": "^2.0.1", "image-size": "^1.1.1", "leasot": "^14.4.0", "lit-html": "^3.2.0", "markdown-it-attrs": "^4.2.0", - "markdownlint-cli2": "^0.13.0", + "markdown-it-footnote": "^4.0.0", + "markdownlint-cli2": "^0.14.0", "parse5": "^7.1.2", "patch-package": "^8.0.0", - "playground-elements": "^0.18.1", + "playground-elements": "^0.19.1", "postcss-pxtorem": "^6.1.0", + "query-selector-shadow-dom": "^1.0.1", "renamer": "^5.0.2", "spandx": "^3.0.0", "stylelint-config-standard": "^36.0.1", + "tinycolor2": "^1.6.0", "ts-patch": "^3.2.1", - "tsx": "^4.17.0", - "typescript": "^5.5.4", - "wireit": "^0.14.7" + "tsx": "^4.19.1", + "typescript": "^5.6.2", + "typescript-transform-lit-css": "^2.0.0", + "wireit": "^0.14.9" }, "optionalDependencies": { - "@esbuild/darwin-arm64": "^0.15.18", - "@esbuild/linux-x64": "^0.23.1", + "@esbuild/darwin-arm64": "^0.24.0", + "@esbuild/linux-x64": "^0.24.0", "@rollup/rollup-darwin-x64": "4.14.2" } } diff --git a/patches/@patternfly+pfe-core+4.0.2.patch b/patches/@patternfly+pfe-core+4.0.2.patch new file mode 100644 index 0000000000..0d147a66fc --- /dev/null +++ b/patches/@patternfly+pfe-core+4.0.2.patch @@ -0,0 +1,13 @@ +diff --git a/node_modules/@patternfly/pfe-core/ssr-shims.js b/node_modules/@patternfly/pfe-core/ssr-shims.js +index d432769..c7a30fb 100644 +--- a/node_modules/@patternfly/pfe-core/ssr-shims.js ++++ b/node_modules/@patternfly/pfe-core/ssr-shims.js +@@ -42,6 +42,8 @@ globalThis.IntersectionObserver ?? (globalThis.IntersectionObserver = ObserverSh + // @ts-expect-error: this runs in node + globalThis.MutationObserver ?? (globalThis.MutationObserver = ObserverShim); + // @ts-expect-error: this runs in node ++globalThis.ResizeObserver ?? (globalThis.ResizeObserver = ObserverShim); ++// @ts-expect-error: this runs in node + globalThis.getComputedStyle ?? (globalThis.getComputedStyle = function () { + return { + getPropertyPriority() { diff --git a/patches/@patternfly+pfe-tools+3.0.0.patch b/patches/@patternfly+pfe-tools+3.0.1.patch similarity index 100% rename from patches/@patternfly+pfe-tools+3.0.0.patch rename to patches/@patternfly+pfe-tools+3.0.1.patch diff --git a/scripts/bundle.js b/scripts/bundle.js index ba37f264e5..cdfc6ad794 100644 --- a/scripts/bundle.js +++ b/scripts/bundle.js @@ -1,12 +1,8 @@ #!/usr/bin/env node import { build } from 'esbuild'; -import { join, dirname } from 'node:path'; -import { fileURLToPath } from 'node:url'; import { litCssPlugin } from 'esbuild-plugin-lit-css'; import { minifyHTMLLiteralsPlugin } from 'esbuild-plugin-minify-html-literals'; -import { glob } from 'glob'; - import CleanCSS from 'clean-css'; const cleanCSS = new CleanCSS({ diff --git a/scripts/copy-assets.ts b/scripts/copy-assets.ts index 26d03e3bb0..02dfd974c5 100644 --- a/scripts/copy-assets.ts +++ b/scripts/copy-assets.ts @@ -1,10 +1,9 @@ /* eslint-disable no-console */ -import { cp, mkdir } from 'node:fs/promises'; +import { cp, mkdir, glob } from 'node:fs/promises'; import { dirname } from 'node:path'; -import { glob } from 'glob'; import chalk from 'chalk'; -for (const srcFile of await glob([ +for await (const srcFile of glob([ 'elements/*/*-lightdom.css', 'elements/*/*-shim.css', ])) { diff --git a/scripts/environment.js b/scripts/environment.js index 6e7795b67b..2fa31bf15c 100644 --- a/scripts/environment.js +++ b/scripts/environment.js @@ -1,29 +1,35 @@ import { join } from 'node:path'; -import { readdir, stat } from 'node:fs/promises'; +import { readdir } from 'node:fs/promises'; + +let iconSetsMap; + +/** + * create a javascript map containing icon names + */ +export async function getIconSetsMap() { + if (!iconSetsMap) { + // because the icon package exports DOM nodes, but this file runs in nodejs + await import('@patternfly/pfe-core/ssr-shims.js'); + const { standard, social, ui, microns } = await import('@rhds/icons'); + iconSetsMap = new Map([ + ['social', [...social.keys()]], + ['standard', [...standard.keys()]], + ['ui', [...ui.keys()]], + ['microns', [...microns.keys()]], + ]); + } + return iconSetsMap; +} /** * create a javascript module containing element and icon names */ export async function makeDemoEnv() { - const iconsDir = join(process.cwd(), 'node_modules', '@rhds', 'icons'); - const dirContents = await readdir(iconsDir); - const dirNamesOrNulls = await Promise.all(dirContents.map(async x => { - const stats = await stat(join(iconsDir, x)); - if (!x.startsWith('.') && stats.isDirectory()) { - return x; - } else { - return null; - } - })); - const iconSetNames = dirNamesOrNulls.filter(x => x != null); - const iconSets = await Promise.all(iconSetNames.reverse().map(async set => { - const files = await readdir(join(iconsDir, set)); - return [set, [...new Set(files.map(x => x.replace(/\..*$/, '')))]]; - })); + iconSetsMap ??= await getIconSetsMap(); const javascript = String.raw; // for editor highlighting const allElements = (await readdir(join(process.cwd(), 'elements'))) .filter(path => !path.includes('.')); return javascript` export const elements = ${JSON.stringify(allElements)}; -export const iconSets = new Map(${JSON.stringify(iconSets)});`; +export const iconSets = new Map(${JSON.stringify(Object.fromEntries(iconSetsMap.entries()))});`; } diff --git a/scripts/playgrounds.ts b/scripts/playgrounds.ts index f383baa688..e7bbc7d5ae 100644 --- a/scripts/playgrounds.ts +++ b/scripts/playgrounds.ts @@ -171,12 +171,7 @@ class PlaygroundDemo { } private addCommonCss() { - const cssPrefix = this.demo.filePath.match(DEMO_FILEPATH_IS_MAIN_DEMO_RE) ? '' : '../'; - this.append(this.createStyleLink(`${cssPrefix}reset.css`), - Tools.createTextNode('\n'), - this.createStyleLink(`${cssPrefix}fonts.css`), - Tools.createTextNode('\n'), - this.createStyleLink(`${cssPrefix}typography.css`)); + this.append(this.createStyleLink(`/styles/demo/styles.css`)); } private getFinalContent() { diff --git a/scripts/system-tokens.js b/scripts/system-tokens.js index 1ec5692e89..1b68c0a923 100644 --- a/scripts/system-tokens.js +++ b/scripts/system-tokens.js @@ -1,17 +1,15 @@ -import { readFile, writeFile, stat } from 'node:fs/promises'; +import { glob, readFile, writeFile, stat } from 'node:fs/promises'; import { tokens } from '@rhds/tokens/meta.js'; -import { dirname } from 'node:path'; +import { dirname, join } from 'node:path'; import { parse } from 'postcss'; -import { glob } from 'glob'; import valueParser from 'postcss-value-parser'; /** - * @typedef {object} Token - * @property {string} name token name - * @property {string} $description token description - * @property {string} $type token value type - * @property {string|unknown} $value token value + * name token name + * $description token description + * $type token value type + * $value token value */ /* eslint-disable no-console */ @@ -105,10 +103,11 @@ async function getSystemTokensForCEDecl(decl, modPath) { const dir = dirname(modPath); if (decl.tagName) { group('files:'); - for (const cssFilePath of await glob([ - `${dir}/${decl.tagName}.css`, - `${dir}/${decl.tagName}-lightdom.css`, - ], { absolute: true })) { + for await (const rel of glob([ + `elements/${dir}/${decl.tagName}.css`, + `elements/${dir}/${decl.tagName}-lightdom.css`, + ])) { + const cssFilePath = join(process.cwd(), rel); log(cssFilePath); if (await exists(cssFilePath)) { const css = await readFile(cssFilePath, 'utf8'); @@ -139,7 +138,6 @@ function tokensToCEMCssProperties(tokens) { /** file to modify */ const manifestUrl = new URL('../custom-elements.json', import.meta.url); -/** @type {import('custom-elements-manifest').Package} */ const manifest = JSON.parse(await readFile(manifestUrl, 'utf8')); for (const mod of manifest.modules) { diff --git a/tsconfig.json b/tsconfig.json index 113bd13a7c..8ca3584b76 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -28,14 +28,15 @@ "importHelpers": true, "incremental": true, "inlineSources": true, - "module": "es2022", - "moduleResolution": "node", + "module": "nodenext", + "moduleResolution": "nodenext", "verbatimModuleSyntax": true, "noEmitOnError": false, "rootDir": ".", "sourceMap": true, "strict": true, "target": "es2020", + "skipLibCheck": true, "useDefineForClassFields": false, "typeRoots": [ "./node_modules/@types", @@ -43,9 +44,9 @@ ], "plugins": [ { - "transform": "@patternfly/pfe-tools/typescript/transformers/css-imports.cjs", + "transform": "typescript-transform-lit-css", "inline": true, - "minify": true + "cssnano": true }, { "name": "typescript-lit-html-plugin" @@ -57,12 +58,14 @@ "lib": [ "DOM.iterable", "DOM", - "es2015.iterable", - "es2020", - "es2022", + "ES5", + "ES6", + "ES2020", + "ES2022", + "ES2015.Generator", + "ESNext.Collection", + "ESNext.AsyncIterable", "ESNext.Disposable", - "es5", - "es6", "ScriptHost" ], "paths": { @@ -74,6 +77,9 @@ ], "@rhds/tokens/color.*": [ "./node_modules/@rhds/tokens/js/color.*" + ], + "@rhds/tokens/css/*": [ + "./node_modules/@rhds/tokens/css/*" ] } } diff --git a/web-dev-server.config.js b/web-dev-server.config.js index e66311a015..9d1ec00b80 100644 --- a/web-dev-server.config.js +++ b/web-dev-server.config.js @@ -1,44 +1,137 @@ // @ts-check import { pfeDevServerConfig } from '@patternfly/pfe-tools/dev-server/config.js'; -import { glob } from 'glob'; -import { readdir, stat } from 'node:fs/promises'; +import { glob } from 'node:fs/promises'; +import { join } from 'node:path'; import { makeDemoEnv } from './scripts/environment.js'; +import { parse, serialize } from 'parse5'; +import { + createElement, + getAttribute, + getTextContent, + isElementNode, + query, + setAttribute, + setTextContent, + spliceChildren, +} from '@parse5/tools'; /** * Find all modules in a glob pattern, relative to the repo root, and resolve them as package paths * @param {string} pattern - * @param {(spec: string) => [string, string]} fn + * @param {string} [relativeTo='.'] */ -async function resolveLocal(pattern, fn) { - return glob(pattern, { ignore: ['**/test/**'] }) - .then(files => files.map(fn)) - .then(Object.fromEntries); +async function resolveLocal(pattern, relativeTo = './') { + const TEST_RE = /\/test\/|(\.d\.ts$)/; + // eslint-disable-next-line jsdoc/check-tag-names + /** @type [string, string][] */ + const files = []; + for await (const file of glob(pattern, { cwd: join(process.cwd(), relativeTo) })) { + if (!TEST_RE.test(file)) { + files.push([ + `@rhds/elements/${file.replace('.ts', '.js')}`, + join(relativeTo, file).replace('./', '/'), + ]); + } + } + return Object.fromEntries(files); +} + +/** + * manually inject icon import map with trailing slash. + * jspm generator doesn't yet support trailing slash + * @param {import('@parse5/tools').Document} document + */ +function injectManuallyResolvedModulesToImportMap(document) { + const importMapNode = query(document, node => + isElementNode(node) + && node.tagName === 'script' + && node.attrs.some(attr => + attr.name === 'type' + && attr.value === 'importmap')); + if (importMapNode && isElementNode(importMapNode)) { + const json = JSON.parse(getTextContent(importMapNode)); + Object.assign(json.imports, { + 'lit': '/node_modules/lit/index.js', + 'lit/': '/node_modules/lit/', + '@patternfly/pfe-core': '/node_modules/@patternfly/pfe-core/core.js', + '@patternfly/pfe-core/': '/node_modules/@patternfly/pfe-core/', + '@rhds/icons/': '/node_modules/@rhds/icons/', + '@rhds/tokens/': '/node_modules/@rhds/tokens/js/', + '@rhds/tokens/css/': '/node_modules/@rhds/tokens/css/', + '@floating-ui/dom': '/node_modules/@floating-ui/dom/dist/floating-ui.dom.browser.min.mjs', + '@floating-ui/core': '/node_modules/@floating-ui/core/dist/floating-ui.core.browser.min.mjs', + }); + setTextContent(importMapNode, JSON.stringify(json, null, 2)); + } } +/** + * add context picker to dev sserver chrome + * @param {import('@parse5/tools').Document} document + */ +function transformDevServerHTML(document) { + const surfaceId = 'rhds-dev-server-main'; + // replace the
                element with a surface + const main = query(document, x => + isElementNode(x) + && x.tagName === 'main'); + if (main && isElementNode(main)) { + main.tagName = 'rh-surface'; + setAttribute(main, 'color-palette', 'lightest'); + setAttribute(main, 'id', surfaceId); + setAttribute(main, 'role', 'main'); + } + // add a context picker to header, targeting main + const header = query(document, x => + isElementNode(x) + && getAttribute(x, 'id') === 'main-header'); + if (header && isElementNode(header)) { + const picker = createElement('rh-context-picker'); + setAttribute(picker, 'target', surfaceId); + setAttribute(picker, 'value', 'lightest'); + const logoBar = query(header, node => + isElementNode(node) + && getAttribute(node, 'class') === 'logo-bar'); + if (logoBar) { + spliceChildren(logoBar, 4, 0, picker); + } + } + // import surface and picker + const module = query(document, x => + isElementNode(x) + && x.tagName === 'script' + && getAttribute(x, 'type') === 'module'); + if (module) { + setTextContent(module, /* js */`${getTextContent(module)} + import '@rhds/elements/rh-surface/rh-surface.js'; + import '@rhds/elements/rh-tooltip/rh-tooltip.js'; + import '@rhds/elements/lib/elements/rh-context-picker/rh-context-picker.js'; + `); + } +} + + export const litcssOptions = { - include: (/** @type{string[]}*/(/** @type{unknown}*/([ + exclude: [ + /(lightdom)/, + /node_modules\/@rhds\/tokens\/css\/global\.css/, + ], + include: [ /elements\/rh-[\w-]+\/[\w-]+\.css$/, + /@rhds\/tokens\/css\/.*\.css$/, /lib\/.*\.css$/, - ]))), - exclude: /lightdom/, + ], }; export default pfeDevServerConfig({ tsconfig: 'tsconfig.json', litcssOptions, importMapOptions: { - providers: { - '@rhds/icons': 'nodemodules', - '@patternfly/elements': 'nodemodules', - '@patternfly/pfe-tools': 'nodemodules', - '@patternfly/pfe-core': 'nodemodules', - }, + typeScript: true, inputMap: { imports: { - '@rhds/icons': './node_modules/@rhds/icons/icons.js', - ...await resolveLocal('./lib/**/*.js', spec => [`@rhds/elements/${spec}`, `./${spec}`]), - ...await resolveLocal('./elements/**/*.js', x => [`@rhds/elements/${x.replace('elements/', '')}`, `./${x}`]), - ...await getRhdsIconNodemodulesImports(import.meta.url), + ...await resolveLocal('./lib/**/*.ts'), + ...await resolveLocal('./**/*.ts', './elements'), }, }, }, @@ -51,7 +144,11 @@ export default pfeDevServerConfig({ return next(); } }, - /** redirect requests for /assets/ css to /docs/assets/ */ + /** + * redirect requests for /assets/ css to /docs/assets/ + * @param ctx koa context + * @param next next koa middleware + */ function(ctx, next) { if (ctx.path.startsWith('/styles/')) { ctx.redirect(`/docs${ctx.path}`); @@ -59,10 +156,17 @@ export default pfeDevServerConfig({ return next(); } }, - /** redirect requests for /(lib|elements)/*.js to *.ts */ - function(ctx, next) { - if (!ctx.path.includes('node_modules') && ctx.path.match(/.*\/(lib|elements)\/.*\.js/)) { - ctx.redirect(ctx.path.replace('.js', '.ts')); + /** + * @param ctx koa context + * @param next next koa middleware + */ + async function(ctx, next) { + if (ctx.path.endsWith('/') && !ctx.path.includes('.')) { + await next(); + const document = parse(ctx.body); + injectManuallyResolvedModulesToImportMap(document); + transformDevServerHTML(document); + ctx.body = serialize(document); } else { return next(); } @@ -85,25 +189,4 @@ export default pfeDevServerConfig({ ], }); -// eslint-disable-next-line jsdoc/require-jsdoc -export async function getRhdsIconNodemodulesImports( - rootUrl, -) { - const files = await readdir(new URL('./node_modules/@rhds/icons/', rootUrl)); - const dirs = []; - - for (const dir of files) { - if (!dir.startsWith('.') && (await stat(new URL(`./node_modules/@rhds/icons/${dir}`, rootUrl))).isDirectory()) { - dirs.push(dir); - } - } - - const specs = await Promise.all(dirs.flatMap(dir => - readdir(new URL(`./node_modules/@rhds/icons/${dir}`, rootUrl)) - .then(files => files.filter(x => x.endsWith('.js'))) - .then(icons => icons.flatMap(icon => `@rhds/icons/${dir}/${icon}`)) - )); - - return Object.fromEntries(specs.flat().map(spec => [spec, `./node_modules/${spec}`])); -} diff --git a/web-test-runner.config.js b/web-test-runner.config.js index 8698c4d6ad..b9454b26bb 100644 --- a/web-test-runner.config.js +++ b/web-test-runner.config.js @@ -1,16 +1,23 @@ import { pfeTestRunnerConfig } from '@patternfly/pfe-tools/test/config.js'; import { litcssOptions } from './web-dev-server.config.js'; -export default pfeTestRunnerConfig({ +export default { ...pfeTestRunnerConfig({ litcssOptions, tsconfig: 'tsconfig.json', files: ['elements/**/*.spec.ts'], importMapOptions: { - providers: { - '@rhds/icons': 'nodemodules', - '@patternfly/pfe-tools': 'nodemodules', - '@patternfly/pfe-core': 'nodemodules', - }, }, -}); +}), + +middleware: [ + /** redirect requests for /(lib|elements)/*.js to *.ts */ + function(ctx, next) { + if (!ctx.path.includes('node_modules') && ctx.path.match(/(lib|elements)\/.*\.js$/)) { + ctx.redirect(ctx.path.replace('.js', '.ts')); + } else { + return next(); + } + }, +], +};