diff --git a/.changeset/breezy-scissors-approve.md b/.changeset/breezy-scissors-approve.md deleted file mode 100644 index 42892d86ec..0000000000 --- a/.changeset/breezy-scissors-approve.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@rhds/elements": patch ---- - -``: outline variant should now get the correct background styles added. diff --git a/.changeset/curly-jobs-eat.md b/.changeset/curly-jobs-eat.md new file mode 100644 index 0000000000..66186ca786 --- /dev/null +++ b/.changeset/curly-jobs-eat.md @@ -0,0 +1,5 @@ +--- +"@rhds/elements": patch +--- + +``: added support for rtl language overflow scroll buttons diff --git a/.changeset/curly-ways-march.md b/.changeset/curly-ways-march.md new file mode 100644 index 0000000000..c81ecdc195 --- /dev/null +++ b/.changeset/curly-ways-march.md @@ -0,0 +1,4 @@ +--- +"@rhds/elements": patch +--- +React: add generated react wrappers to NPM package diff --git a/.changeset/eager-dolls-wear.md b/.changeset/eager-dolls-wear.md new file mode 100644 index 0000000000..cec9f5da7b --- /dev/null +++ b/.changeset/eager-dolls-wear.md @@ -0,0 +1,4 @@ +--- +"@rhds/elements": patch +--- +``: automatically fetch status for the current domain diff --git a/.changeset/eighty-flowers-sell.md b/.changeset/eighty-flowers-sell.md deleted file mode 100644 index 3d778dfd92..0000000000 --- a/.changeset/eighty-flowers-sell.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@rhds/elements": patch ---- - -``: uses SVG for default images instead of much larger base-64 PNG images diff --git a/.changeset/forty-candles-train.md b/.changeset/forty-candles-train.md deleted file mode 100644 index c1e90d54aa..0000000000 --- a/.changeset/forty-candles-train.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@rhds/elements": patch ---- - -``: Added @csspart docs. diff --git a/.changeset/plenty-rabbits-scream.md b/.changeset/plenty-rabbits-scream.md new file mode 100644 index 0000000000..c75425db2a --- /dev/null +++ b/.changeset/plenty-rabbits-scream.md @@ -0,0 +1,4 @@ +--- +"@rhds/elements": patch +--- +``: hide header, body, or footer regions when they have no content diff --git a/.changeset/popular-crews-relate.md b/.changeset/popular-crews-relate.md deleted file mode 100644 index 77be7f4e93..0000000000 --- a/.changeset/popular-crews-relate.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@rhds/elements": patch ---- - -``: corrected subscribe slot documentation. diff --git a/.changeset/shy-houses-arrive.md b/.changeset/shy-houses-arrive.md new file mode 100644 index 0000000000..3cf7b3bed1 --- /dev/null +++ b/.changeset/shy-houses-arrive.md @@ -0,0 +1,4 @@ +--- +"@rhds/elements": patch +--- +``: applied heading font to card headings diff --git a/.changeset/spicy-planes-lead.md b/.changeset/spicy-planes-lead.md new file mode 100644 index 0000000000..9c47cff405 --- /dev/null +++ b/.changeset/spicy-planes-lead.md @@ -0,0 +1,4 @@ +--- +"@rhds/elements": patch +--- +``: corrected 'show more' button styles diff --git a/.changeset/tough-pens-brake.md b/.changeset/tough-pens-brake.md new file mode 100644 index 0000000000..5838b51fd5 --- /dev/null +++ b/.changeset/tough-pens-brake.md @@ -0,0 +1,5 @@ +--- +"@rhds/elements": patch +--- + +``: ensure correct font-family is used diff --git a/.changeset/wet-feet-pull.md b/.changeset/wet-feet-pull.md new file mode 100644 index 0000000000..1c351913b7 --- /dev/null +++ b/.changeset/wet-feet-pull.md @@ -0,0 +1,4 @@ +--- +"@rhds/elements": patch +--- +``: removes landmark semantics from card, simplifying page navigation for screen reader users diff --git a/.eslintignore b/.eslintignore deleted file mode 100644 index 611f16b0ef..0000000000 --- a/.eslintignore +++ /dev/null @@ -1,54 +0,0 @@ -!.eleventy.cjs - -*.mp3 -*.vtt -*.css -*.woff -*.d.ts -*.ico -*.jpeg -*.jpg -*.map -*.md -*.njk -*.patch -*.png -*.scss -*.sh -*.spec.js -*.svg -*.toml -*.tsbuildinfo -*.txt -*.yml -*.yaml -*.min.js -*.tgz -*.csv -CNAME - -custom-elements.json -package-lock.json - -_site -docs/_data/todos.json -docs/demo.js -docs/pfe.min.js -docs/bundle.js -docs/core -docs/components -node_modules - -core/pfe-sass/docs/index.html -core/**/*.js -elements/**/*.js -lib/**/*.js -tools/**/*.js - -!core/*/demo/*.js -!elements/*/demo/*.js - -tools/create-element/templates/**/* -node_modules -node_modules/**/* - diff --git a/.eslintrc.json b/.eslintrc.json deleted file mode 100644 index cfe32ac8bb..0000000000 --- a/.eslintrc.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "extends": "@patternfly/elements", - "rules": { - "brace-style": [ - "error", - "1tbs", - { - "allowSingleLine": true - } - ] - } -} diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 0002ca1850..0dd76658c1 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -35,7 +35,8 @@ jobs: - name: Install dependencies run: npm ci --prefer-offline - + - name: Install Playwright Browsers + run: npx playwright install --with-deps - name: Lint id: lint run: npm run lint diff --git a/.github/workflows/validate-pr.yml b/.github/workflows/validate-pr.yml new file mode 100644 index 0000000000..3bb682f067 --- /dev/null +++ b/.github/workflows/validate-pr.yml @@ -0,0 +1,25 @@ +name: Validate PRs + +on: + pull_request: + types: + - opened + - reopened + - synchronize + - edited + +jobs: + validate: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-node@v4 + with: + node-version: '20' + cache: 'npm' + - run: npm i semantic-release @changesets/read --prefer-offline + - uses: actions/github-script@v7 + with: + script: | + const { validate } = await import('${{ github.workspace }}/scripts/validate-prs.js'); + await validate({ context }); diff --git a/.gitignore b/.gitignore index 2efdad53af..1216e5e6df 100644 --- a/.gitignore +++ b/.gitignore @@ -1,14 +1,18 @@ # Dependencies node_modules .wireit +.rollup.cache +.cache # Ignore compiled files in webroot _site docs/pfe.min* +docs/assets/playgrounds/ # Build artifacts elements/*/*.js elements/*/test/*.js +react lib/**/*.js !elements/**/demo/*.css *.map @@ -92,3 +96,4 @@ $RECYCLE.BIN/ *.lnk !declaration.d.ts +docs/assets/playgrounds/rh-playground.js diff --git a/.markdownlint-cli2.mjs b/.markdownlint-cli2.mjs index f0c5b6719a..1e459cf2d5 100644 --- a/.markdownlint-cli2.mjs +++ b/.markdownlint-cli2.mjs @@ -5,23 +5,23 @@ export default { description: 'Require changesets to use the correct package name', tags: ['frontmatter'], function({ name, frontMatterLines, ...rest }, onError) { - const yaml = YAML.load(frontMatterLines.filter(Boolean).filter(x => x !== '---')) + const yaml = YAML.load(frontMatterLines.filter(Boolean).filter(x => x !== '---')); for (const [key, value] of Object.entries(yaml)) { - if (['patch','minor','major'].includes(value)) { + if (['patch', 'minor', 'major'].includes(value)) { if (key !== '@rhds/elements') { onError({ lineNumber: 2, detail: `incorrect package name ${key}`, - }) + }); } } } - } + }, }], dot: true, files: './changeset/*.md', config: { - default: false, + 'default': false, 'markdownlint-changeset-packagename': true, - } -} + }, +}; diff --git a/.nvmrc b/.nvmrc index e44a38e080..790e1105f2 100644 --- a/.nvmrc +++ b/.nvmrc @@ -1 +1 @@ -v18.12.1 +v20.10.0 diff --git a/.stylelintrc.yml b/.stylelintrc.yml index 117f356772..9d7dbb09f3 100644 --- a/.stylelintrc.yml +++ b/.stylelintrc.yml @@ -1,4 +1,7 @@ -extends: stylelint-config-standard +extends: + - stylelint-config-standard + - stylelint-stylistic/config + ignoreFiles: - node_modules/**/* @@ -16,18 +19,6 @@ rules: - ignoreShorthands: - /grid/ - # TODO: migrate the following paragraph to stylelint-stylistic - # see https://github.com/elirasza/stylelint-stylistic/tree/main/lib/rules/indentation - string-quotes: double - selector-combinator-space-after: always - selector-combinator-space-before: always - indentation: - - 2 - - indentInsideParens: 'once-at-root-twice-in-block' - max-line-length: - - 100 - - ignorePattern: /--rh-font-family-/ - number-max-precision: 6 no-descending-specificity: - true @@ -49,10 +40,84 @@ rules: - ignorePseudoElements: - /part(.*)/ + stylistic/string-quotes: double + stylistic/selector-combinator-space-after: always + stylistic/selector-combinator-space-before: always + stylistic/indentation: + - 2 + - indentInsideParens: 'once-at-root-twice-in-block' + stylistic/max-line-length: + - 100 + - ignorePattern: /--rh-font-family-/ + 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 + - stylelint-stylistic overrides: - files: @@ -60,7 +125,9 @@ overrides: defaultSeverity: warning extends: stylelint-config-standard-scss rules: - max-line-length: + stylistic/block-closing-brace-newline-after: null + scss/at-if-closing-brace-newline-after: always-last-in-chain + stylistic/max-line-length: - 120 - ignorePattern: /--rh-font-family-/ diff --git a/CHANGELOG.md b/CHANGELOG.md index 362bf447c3..c474c257fc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,401 @@ # @rhds/elements +## 1.4.1 + +### Patch Changes + +- 862380b: corrected `@patternfly/elements` dependency to be included with the package + +## 1.4.0 + +### Minor Changes + +- fecdcbf: ``: added line numbers +- fecdcbf: ✨ Added `` + + 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. + + ```html + + ``` + +- fecdcbf: ✨ Added ``. + + Back to top component is a fragment link that allows users to quickly navigate to the top of a lengthy content. + + ```html + Back to top + ``` + +- fecdcbf: ✨ Added ``. + + 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. + + ```html + + Skip to main content + + ``` + +- fecdcbf: ⚛️ Added React wrapper components + + You can now more easily integrate RHDS elements into your React apps by importing our wrapper components + + First, make sure that you list `@lit/react` as a dependency in your project + + ```sh + npm install --save @lit/react + ``` + + Then import the element components you need and treat them like any other react component + + ```js + import { Tabs } from '@rhds/elements/react/rh-tabs/rh-tabs.js'; + import { Tab } from '@rhds/elements/react/rh-tabs/rh-tab.js'; + import { TabPanel } from '@rhds/elements/react/rh-tabs/rh-tab-panel.js'; + + import { useState } from 'react'; + + const tabs = [ + { heading: 'Hello Red Hat', content: 'Let\'s break down silos' }, + { heading: 'Web components', content: 'They work everywhere' } + ]; + + function App() { + const [index, setExpanded] = useState(-1); + return ( + expanded {expanded} + {tabs.map(({ heading, content }, i) => ( + setExpanded(i)}>{heading} + {content}))} + + ); + } + ``` + +- fecdcbf: ``: added `Show more` toggle +- fecdcbf: ``: added copy and wrap actions, with localizable slots for the button labels + + ```html + + Copy to Clipboard + + Toggle word wrap + + + + ``` + +### Patch Changes + +- fecdcbf: ``: improved focus accessibility for keyboard navigation users on firefox + ``: improved focus accessibility on firefox +- fecdcbf: ``: added a accents slot with placement options as inline and bottom +- fecdcbf: Context: aligned context implementation with updated [protocol defintions](https://github.com/webcomponents-cg/community-protocols/blob/main/proposals/context.md#definitions) +- fecdcbf: Update dependencies, including Lit version 3 +- fecdcbf: ``: make sure alerts always have to correct (lightest) colour palette +- fecdcbf: ``: allow tabs with long text content to fit into different-sized containers + +## 1.3.2 + +### Patch Changes + +- 1d1640705: ``: corrected icon slot visibility with a slotted icon +- d61b8dc71: ``: ensure that `cancel`, `open`, and `closed` events fire + +## 1.3.1 + +### Patch Changes + +- d87dfb94a: ``: fixed issue that stop tabs from correctly resizing on mobile +- 01f100cf8: ``: fixed issue with click target area of tile +- 08722dd71: ``: corrected custom background hover color tokens. +- 4259ba0ed: ``: improved documentation + +## 1.3.0 + +### Minor Changes + +- 5e64235d5: ``: added Hebrew translations +- 0829fa2c4: ✨ Added ``. + + Surface is a container which sets background color and text color and provides that theme context to its child elements. Surface supports `darkest`, `darker`, `dark`, `light`, `lighter`, `lightest` color palettes. + + ```html + + Call to Action + + ``` + +- c9b81875e: ``: adds ability to override panel margin and padding +- 31b28dcc6: ``: add `numeric` CSS shadow part, corresponding to the numeric page input + + Example: hiding the numeric paginator + + ```css + rh-pagination::part(numeric) { + display: none; + } + ``` + +- 05fbc275a: ``: add `accessible-label` attribute to override form control label + + Accessible labels are visually hidden labels for form controls. In the case of + ``, they are optional, so long as the text content of the tile is + already an accessible label for the control. + + Use `accessible-label` when you would like to label the form control with + something other than the tile's text content, or when the tile has no text + content. + + ```html +
+ + Tile 1 + Tile 2 + + + + +
+ ``` + +- 58ab8e60b: Uses `@rhds/tokens` - Red Hat Design Tokens - version 2! + + ⚠️ if your pages directly override "crayon" colour values, (e.g. `--rh-color-red-50`) + then this is a breaking change, since the token names have changed. + + However, if your project follows the theming guidelines and only overrides the + semantic tokens, then you should automatically receive the new colour values. + +- 05fbc275a: ``: radio and checkbox tiles now submit their values in `
` elements + +### Patch Changes + +- b123092da: ``: removed dependency on `@patternfly/elements` package. +- 5e64235d5: ``: fix `` as slotted action +- 976981b0d: ``: fix inline variant's styles +- 6a87885e8: ``: remove dependency on `@patternfly/elements` +- 719873947: ``: remove user-agent margin from blockquote, in accordance with [design guidelines][design] + + [design]: https://ux.redhat.com/elements/blockquote/style/ + +- fcf22f028: ``: remove dependency on `@patternfly/elements` +- 18f802f7f: ``: added color palette and theme support +- c0af10745: ``: improved styles for first body paragraph when there is other content displayed first +- 4f6ff65e7: ``: ensure footer is always on the bottom of the card +- 6e8fad64b: ``: adjust whitespace of card parts to suit design +- bf7c96ca4: ``: allow for pre-rendered (via prism.js) code blocks +- f969ff1f2: ``: fixed layout of non-vertical box variant tabs +- 54264f37c: ``: deprecates the `color-palette` attribute. +- 8cb9790e2: ``: fixed cursor when arrow is hovered +- 976981b0d: ``: remove padding for alerts which have only header content +- 976981b0d: ``: make variants case-insensitive +- a6510e224: ``: adds default value for tab font-size +- eefc04cb9: ``: fixes issue where content would take up unwanted space before the element fully upgraded +- 2137702b3: ``: updated twitter logo with X +- 0254749cb: ``: removed unused color-palette attribute +- 8c5559cee: ``: remove the dependency on `@patternfly/elements`. + _NOTE_: The `open`, `close`, and `cancel` events are no longer the same object constructor type as ``, so `instanceof` checks may fail. +- 2eb82a822: ``: removed non-existent `name` slot from the element manifest. + This doesn't change the element, only the documentation. Instead of `name`, use + the anonymous slot: + + ```html + + Title + Subtitle + + ``` + +- 5e64235d5: ``: support color context +- 6a134b5f4: ``: remove dependency on `@patternfly/elements` +- 369d5b7cf: ``: collapses margins between header, body, and footer + + NOTE that this changes the default styling of the `header`, `body`, and `footer` + CSS Shadow Parts. They previously used `padding` for layout, and now use `margin`. + If you modified their padding via the `::part` selector, you will need to update your CSS + + Before: + + ```css + .special-card::part(header) { + padding: var(--rh-space-sm); + } + ``` + + After: + + ```css + .special-card::part(header) { + margin-block-start: var(--rh-space-sm); + margin-inline: var(--rh-space-sm); + } + ``` + +- 5e64235d5: ``: ensure dialog content is always on light theme +- 42c167f9e: ``: improved color palette styles +- 0d2d349d7: `rh-table`: corrected table height +- a1c587d1b: ``: adds current page indicator to logo slot +- c68165b4e: ``: adds deprecation notice on `theme` attribute +- 54264f37c: ``: remove dependency on `@patternfly/elements` +- baa382063: ``: fixed border color for dark color palettes +- fb9e3eac0: ``: remove dependency on `@patternfly/elements` +- d4e1ebd4b: ``: while tag should not be used on dark contexts unless it has the + `white` colour, this change ensures that tags that are used on dark context will + be legible. +- 422d6279b: ``: ensure that tiles in a flex container grow along the cross axis +- 61ca7202d: ``: remove dependency on `@patternfly/elements` +- b3f7b1877: ``: added arrow animation on hover +- 9f1249474: ``: fixed initialization of current page indicator + +## 1.2.0 + +### Minor Changes + +- 35c28e72: Added ``. + + Tile creates a component that can be used in place of a link, checkbox, or radio button selection. + + ```html + + +
Title
+

Link

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

Link

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

Link

+ Lorem ipsum dolor sit amet, consectetur adipiscing elit. +
Suspendisse eu turpis elementum
+
+
+ ``` + +- 9d3c7b09: ✨ Added ``. + + A table is a container for displaying information. It allows a user to scan, examine, and compare large amounts of data. + + ```html + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ Concerts +
Date + Event + + Venue +
12 FebruaryWaltz with StraussMain Hall
24 MarchThe ObelisksWest Wing
14 AprilThe WhatMain Hall
+ Dates and venues subject to change. +
+ ``` + +- 39e76fc6: `rh-card`: `header` slot now displays items vertically instead of stacked, allowing for more than one item to display in the header. + + Example: + + ```html + + +

Headline, sm

+

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.

+ + Call to action + +
+ ``` + +- c9780fc2: ✨ Added ``. + + Provides consistent formats for displaying date and time values. + + ```html + Tue Aug 09 2006 14:57:00 GMT-0400 + ``` + +### Patch Changes + +- f4fcb1f3: ``: improved keyboard navigation +- 681519b5: ``: + ``: + ``: Updated custom elements manifest summaries +- ed6ff92e: ``: corrected and updated support for current page indicator +- a6ca3987: ``: `brick` variants are now full width. + + `` should only be used within grids. Check your layouts to make sure they adhere to the guidelines. + +- 0c2d42b1: ``: corrects the custom element manifest's event name for the `expand` event +- 7e2c9bb6: ``: adds `color-palette` attribute back with deprecation notice + +## 1.1.1 + +### Patch Changes + +- ab339ac6: ``: outline variant should now get the correct background styles added. +- f79543b7: ``: uses SVG for default images instead of much larger base-64 PNG images +- 77fa329a: ``: Added @csspart docs. +- f0f66ec2: ``: fixed vertical tabs text alignment +- 716b52d1: `` and other elements: color context support +- cf8ee6cb: ``: corrected subscribe slot documentation. +- d709896f: ``: corrected layout of icon brick variant +- d709896f: ``: ensured entire CTA is clickable +- d709896f: ``: fix a style bug which affects CTA links at narrow widths +- ff90f4d6: ``: prevent an error when using footer and react in certain chrome versions +- 44a444a5: ``: corrected navigation bar height for small and large viewports' + ## 1.1.0 ### Minor Changes diff --git a/README.md b/README.md index 054683526d..2da44a6201 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,6 @@ # Red Hat Design System -[Documentation](https://ux.redhat.com), [design tokens](https://red-hat-design-tokens.netlify.app), -and [web components](https://ux.redhat.com/elements/) for building uniform -experiences with the Red Hat brand. +[Documentation][docs], [design tokens][tokens], and [web components][elements] for building uniform experiences with the Red Hat brand. ## 🎨 For Designers @@ -10,8 +8,7 @@ RHDS provides Adobe XD libraries and design kits to aid in your design work. ## 💻 For Developers -RHDS provides a collection of ready-made, framework-agnostic web components with Red Hat branding, -user experience, accessibility, and style guidelines built in. +RHDS provides a collection of ready-made, framework-agnostic web components with Red Hat branding, user experience, accessibility, and style guidelines built in. ```html @@ -25,5 +22,11 @@ user experience, accessibility, and style guidelines built in. ## Contributions are Welcome -Would you like to contribute to the **documentation** or **design specs**? Read [the site contributing guide](https://github.com/RedHat-UX/red-hat-design-system/tree/main/CONTRIBUTING_DESIGN.md). -Would you like to contribute to **component development**? Read [the developer contributing guide](https://github.com/RedHat-UX/red-hat-design-system/tree/main/CONTRIBUTING_DEV.md). +Would you like to contribute to the **documentation** or **design specs**? Read [the site contributing guide][contributing]. +Would you like to contribute to **component development**? Read [the developer contributing guide][development]. + +[docs]: https://ux.redhat.com +[tokens]: https://red-hat-design-tokens.netlify.app +[elements]: https://ux.redhat.com/elements/ +[contributing]: https://github.com/RedHat-UX/red-hat-design-system/tree/main/CONTRIBUTING_DESIGN.md +[development]: https://github.com/RedHat-UX/red-hat-design-system/tree/main/CONTRIBUTING_DEV.md diff --git a/declaration.d.ts b/declaration.d.ts index ce9a0440cf..8fb49f9bc2 100644 --- a/declaration.d.ts +++ b/declaration.d.ts @@ -1,8 +1,5 @@ declare module '*.css' { - import type { CSSResult } from 'lit'; - - // import style from './some-styles.css'; - const style: CSSResult; + const style: CSSStyleSheet export default style; } diff --git a/docs/_data/playgrounds.cjs b/docs/_data/playgrounds.cjs index 478efaa859..b4d7b5c9fc 100644 --- a/docs/_data/playgrounds.cjs +++ b/docs/_data/playgrounds.cjs @@ -8,8 +8,8 @@ function groupBy(prop, xs) { function getDemoFilename(x) { return `demo/${(x.url.split('/demo/').pop() || `${x.primaryElementName}.html`).replace(/\/$/, '.html')}` - .replace('.html', '/index.html') - .replace(`${x.primaryElementName}/index.html`, 'index.html'); + .replace('.html', '/index.html') + .replace(`${x.primaryElementName}/index.html`, 'index.html'); } /** @@ -26,7 +26,8 @@ function getDemoFilename(x) { * > One of `.`, or **WORD** (_>= 1x_) * `"` */ -const DEMO_SUBRESOURCE_RE = /(?href|src)="\/elements\/rh-(?.*)\/(?.*)\.(?[.\w]+)"/g; +const DEMO_SUBRESOURCE_RE = + /(?href|src)="\/elements\/rh-(?.*)\/(?.*)\.(?[.\w]+)"/g; /** * `/elements/` @@ -38,6 +39,14 @@ const DEMO_SUBRESOURCE_RE = /(?href|src)="\/elements\/rh-(?.*) */ const DEMO_FILEPATH_IS_MAIN_DEMO_RE = /\/elements\/(.*)\/demo\/\1\.html/; +/** + * Elements which can support a `src=""` attribute which points to a subresource + */ +const SRC_SUBRESOURCE_TAGNAMES = new Set([ + 'img', + 'rh-avatar', +]); + /** * Replace paths in demo files from the dev SPA's format to 11ty's format * @param {string} content @@ -53,9 +62,48 @@ function demoPaths(content, pathname) { } } +function isModuleScript(node) { + return ( + node.tagName === 'script' + && node.attrs.some(x => x.name === 'type' && x.value === 'module') + ); +} + +function isStyleLink(node) { + return ( + node.tagName === 'link' + && node.attrs.some(x => x.name === 'rel' && x.value === 'stylesheet') + && node.attrs.some(x => x.name === 'href') + ); +} + +function hasLocalSrcAttr(node) { + return ( + node.attrs.some(({ name, value }) => name === 'src' && !value.startsWith('http')) + ); +} + +function getAttrMap(node) { + return Object.fromEntries(node.attrs.map(({ name, value }) => + [name, value])); +} + +class SubresourceError extends Error { + constructor(message, originalError, subresourceFileURL) { + super(message); + this.originalError = originalError; + this.subresourceFileURL = subresourceFileURL; + } +} + module.exports = async function(data) { performance.mark('playgrounds-start'); - const { parseHTML } = await import('linkedom'); + const { parseFragment, serialize } = await import('parse5'); + const Tools = await import('@parse5/tools'); + + function append(node, ...nodes) { + Tools.spliceChildren(node, Infinity, 0, ...nodes); + } const demoManifests = groupBy('primaryElementName', data.demos); @@ -74,61 +122,142 @@ module.exports = async function(data) { const demoSource = await fs.readFile(demo.filePath, 'utf8'); - const { document } = parseHTML(demoSource); + const fragment = parseFragment(demoSource); const baseCssPathPrefix = demo.filePath.match(DEMO_FILEPATH_IS_MAIN_DEMO_RE) ? '' : '../'; - const baseCssLink = document.createElement('link'); - baseCssLink.rel = 'stylesheet'; - baseCssLink.href = `${baseCssPathPrefix}rhds-demo-base.css`; - document.head.append(baseCssLink); + + append( + fragment, + Tools.createCommentNode('playground-fold'), + Tools.createElement('link', { + rel: 'stylesheet', + href: 'https://static.redhat.com/libs/redhat/redhat-font/4/webfonts/red-hat-font.min.css', + }), + Tools.createElement('link', { + rel: 'stylesheet', + href: 'https://static.redhat.com/libs/redhat/redhat-theme/6/advanced-theme.css', + }), + Tools.createElement('link', { + rel: 'stylesheet', + href: `${baseCssPathPrefix}rhds-demo-base.css`, + }), + Tools.createTextNode('\n\n'), + Tools.createCommentNode('playground-fold-end'), + ); const filename = getDemoFilename(demo); /** @see docs/_plugins/rhds.cjs demoPaths transform */ - const base = url.pathToFileURL(path.join(process.cwd(), 'elements', primaryElementName, 'demo/')); + const base = url.pathToFileURL(path.join(process.cwd(), + 'elements', + primaryElementName, + 'demo/')); const docsDir = url.pathToFileURL(path.join(process.cwd(), 'docs/')); const isMainDemo = filename === 'demo/index.html'; const demoSlug = filename.split('/').at(1); + const addSubresourceURL = async subresourceURL => { + if (subresourceURL && !subresourceURL.startsWith('http')) { + const subresourceFileURL = !subresourceURL.startsWith('/') ? + // non-tabular ternary + new URL(subresourceURL, base) + : new URL(subresourceURL.replace('/', './'), docsDir); + try { + const resourceName = + path.normalize(`demo${isMainDemo ? '' : `/${demoSlug}`}/${subresourceURL}`); + if (!fileMap.has(resourceName)) { + const content = + demoPaths( + await fs.readFile(subresourceFileURL, 'utf8'), + subresourceFileURL.pathname, + ); + fileMap.set(resourceName, { content, hidden: true }); + } + } catch (e) { + throw new SubresourceError( + `Error generating playground for ${demo.slug}.\nCould not find subresource ${subresourceURL} at ${subresourceFileURL?.href ?? 'unknown'}`, + e, + subresourceFileURL, + ); + } + } + }; + fileMap.set('demo/rhds-demo-base.css', { contentType: 'text/css', content: baseCssSource, hidden: true, }); - fileMap.set(filename, { - contentType: 'text/html', - selected: isMainDemo, - content: demoPaths(document.toString(), demo.filePath), - label: demo.title, - }); + const hrefSubresourceElements = Tools.queryAll(fragment, node => + Tools.isElementNode(node) + && isStyleLink(node)); - // register demo script and css resources - for (const el of document.querySelectorAll('script[type=module][src], link[rel=stylesheet][href]')) { - const isLink = el.localName === 'link'; - const subresourceURL = isLink ? el.href : el.src; - if (!subresourceURL.startsWith('http')) { - const subresourceFileURL = !subresourceURL.startsWith('/') - // non-tabular tern - // eslint-disable-next-line operator-linebreak - ? new URL(subresourceURL, base) - : new URL(subresourceURL.replace('/', './'), docsDir); - try { - const content = demoPaths(await fs.readFile(subresourceFileURL, 'utf8'), subresourceFileURL.pathname); - const resourceName = path.normalize(`demo${isMainDemo ? '' : `/${demoSlug}`}/${subresourceURL}`); - fileMap.set(resourceName, { content, hidden: true }); - } catch (e) { - // we can swallow the error for the demo base file because we wrote it ourselves above. - // maybe not the most elegant solution, but it works - if (subresourceFileURL?.href?.endsWith('rhds-demo-base.css')) { continue; } + const srcSubresourceElements = Tools.queryAll(fragment, node => + Tools.isElementNode(node) + && SRC_SUBRESOURCE_TAGNAMES.has(node.tagName) + && hasLocalSrcAttr(node)); + + // register demo css resources + for (const el of hrefSubresourceElements) { + try { + const attrs = getAttrMap(el); + await addSubresourceURL(attrs.href); + } catch (e) { + // we can swallow the error for the demo base file because we wrote it ourselves above. + // maybe not the most elegant solution, but it works + if (e.subresourceFileURL?.href?.endsWith('rhds-demo-base.css')) { + continue; + } else { // In order to surface the error to the user, let's enable console logging // eslint-disable-next-line no-console - console.log(`Error generating playground for ${demo.slug}.\nCould not find subresource ${subresourceURL} at ${subresourceFileURL?.href ?? 'unknown'}`); + console.log(e.message); throw e; } } } + // register demo script and image resources + for (const el of srcSubresourceElements) { + const attrs = getAttrMap(el); + await addSubresourceURL(attrs.src); + } + + // HACK: https://github.com/google/playground-elements/issues/93#issuecomment-1775247123 + const inlineModules = + Tools.queryAll(fragment, node => + Tools.isElementNode(node) + && isModuleScript(node) + && !node.attrs.some(({ name }) => name === 'src')); + + Array.from(inlineModules).forEach((el, i) => { + const moduleName = `${primaryElementName}-${demoSlug.replace('.html', '')}-inline-script-${i++}.js`; + append( + fragment, + Tools.createCommentNode('playground-hide'), + Tools.createElement('script', { + type: 'module', + src: `./${demoSlug === 'index.html' ? '' : '../'}${moduleName}`, + }), + Tools.createTextNode('\n\n'), + Tools.createCommentNode('playground-hide-end'), + ); + + fileMap.set(`demo/${moduleName}`, { + contentType: 'application/javascript', + content: el.childNodes.map(x => x.value).join('\n'), + hidden: true, + }); + }); + // ENDHACK + + fileMap.set(filename, { + contentType: 'text/html', + selected: isMainDemo, + content: demoPaths(serialize(fragment), demo.filePath), + label: demo.title, + }); + const files = Object.fromEntries(fileMap.entries()); playgroundConfigsMap.set(primaryElementName, { files }); } diff --git a/docs/_data/relatedItems.yaml b/docs/_data/relatedItems.yaml index 953047d9f7..08ae0dc52d 100644 --- a/docs/_data/relatedItems.yaml +++ b/docs/_data/relatedItems.yaml @@ -40,6 +40,7 @@ rh-footer: - rh-accordion - rh-popover - rh-tooltip + - rh-site-status rh-jump-links: - rh-pagination - rh-progress-steps @@ -64,6 +65,13 @@ rh-progress-steps: - rh-jump-links - rh-pagination - rh-tabs +rh-skip-link: + - rh-navigation + - rh-navigation-secondary + - rh-subnav +rh-site-status: + - rh-card + - rh-footer rh-spinner: - form - search-bar @@ -74,6 +82,8 @@ rh-subnav: - rh-navigation - rh-navigation-secondary - skip-navigation +rh-table: + - rh-code-block rh-tabs: - rh-jump-links - rh-pagination @@ -82,6 +92,13 @@ rh-tag: - rh-avatar - rh-badge - rh-button +rh-tile: + - rh-cta + - rh-card + - form +rh-timestamp: + - rh-blockquote + - rh-statistic rh-tooltip: - rh-footer - form @@ -93,7 +110,7 @@ announcement: disclosure: - rh-accordion - filter - - form + - rh-form filter: - rh-accordion - disclosure diff --git a/docs/_data/repoStatus.csv b/docs/_data/repoStatus.csv deleted file mode 100644 index 34c2051104..0000000000 --- a/docs/_data/repoStatus.csv +++ /dev/null @@ -1,84 +0,0 @@ -id,Element/Pattern,RHDS,WebRH,WebDMS,Adobe Target, -Accordion,Small size,x,x,,, -Accordion,Large size,x,x,,, -Alert,Inline,x,,,, -Alert,Inline variation,x,,,, -Alert,Toast,x,,,, -Avatar,Avatar,x,,,, -Badge,Badge,x,,,, -Blockquote,Default size,x,,,, -Blockquote,Large size,x,,,, -Button,Danger,x,,,, -Button,Primary,x,,,, -Button,Secondary,x,,,, -Button,Tertiary,x,,,, -Button,Link,x,,,, -Button,Play,x,,,, -Button,Close,x,,,, -Card,Basic,,x,,, -Card,Lists,,x,,, -Card,Data/fast facts,,,x,, -Card,Logo,,x,,, -Card,Bar/with hat,,x,,, -Card,Icon,,x,,, -Card,Image,,x,,, -Card,Asset,,,x,, -Card,Quote,,x,,, -Card,Avatars,,,x,, -Card,Video,,,x,, -Card,Pricing,,,x,, -Card,Logo slider,,,x,, -Card,Name slider,,,x,, -Code Block,Code Block,x,,,, -Cta,Primary,x,,,, -Cta,"Primary, video",x,,,, -Cta,Secondary,x,,,, -Cta,"Secondary, video",,,,, -Cta,Brick,x,,,, -Cta,"Brick, icon",x,,,, -Cta,Default,x,,,, -Cta,"Default, video",x,,,, -Dialog,Dialog,x,,,, -Footer,Footer,x,,,, -Navigation Secondary,Secondary navigation,x,,,, -Pagination,Compact size,x,,,, -Pagination,Full size,x,,,, -Spinner,Small size,x,,,, -Spinner,Medium size,x,,,, -Spinner,Large size,x,,,, -Stat,Default size,x,,,, -Stat,Large size,x,,,, -Tabs,Open,x,,,, -Tabs,Boxed,x,,,, -Tag,Red - filled and unfilled,x,,,, -Tag,Orange - filled and unfilled,x,,,, -Tag,Green - filled and unfilled,x,,,, -Tag,Cyan - filled and unfilled,x,,,, -Tag,Blue - filled and unfilled,x,,,, -Tag,Purple - filled and unfilled,x,,,, -Tag,Gray - filled and unfilled,x,,,, -Tooltip,Tooltip,x,,,, -,12-column grid,,x,x,, -,Audio player,,,x,, -,Announcement bar,,,x,x, -,Cookie banner,,,,, -,Filter box,,x,,, -,Fixed bottom banner,,,x,x, -,Footer group,,,,, -,Form - full,,x,,, -,Form - input group - money,,,,, -,Form - input group - email,,,,, -,Form - input group - username,,,,, -,Form - input group - date,,,,, -,Form - input group - search,,,,, -,Form - input group - help,,,,, -,Jump links - horizontal,,,,, -,Jump links - vertical,,,,, -,Link with icon,,,,, -,Logo bar,,,x,, -,Navigation,,x,,, -,Quote,x,x,x,, -,Search bar,,,,, -,Search combo,,,,, -,Skip to main content,,,,, -,Video with thumbnail,,,x,, diff --git a/docs/_data/repoStatus.yaml b/docs/_data/repoStatus.yaml new file mode 100644 index 0000000000..baa46d1e5c --- /dev/null +++ b/docs/_data/repoStatus.yaml @@ -0,0 +1,406 @@ +- name: "Accordion" + type: "Element" + overallStatus: "Available" + libraries: + - name: Figma library + status: Ready + - name: Responsive + status: Ready + - name: RH Elements + status: Ready + - name: webRH + status: Ready + - name: Documentation + status: Ready +- name: "Alert" + type: "Element" + overallStatus: "Available" + libraries: + - name: Figma library + status: Ready + - name: Responsive + status: Ready + - name: RH Elements + status: Ready + - name: webRH + status: Ready + - name: Documentation + status: Ready +- name: "Audio Player" + type: "Element" + overallStatus: "Available" + libraries: + - name: Figma library + status: Ready + - name: Responsive + status: Ready + - name: RH Elements + status: Ready + - name: webRH + status: Ready + - name: Documentation + status: Ready +- name: "Avatar" + type: "Element" + overallStatus: "Available" + libraries: + - name: Figma library + status: Ready + - name: Responsive + status: Ready + - name: RH Elements + status: Ready + - name: webRH + status: Ready + - name: Documentation + status: Ready +- name: "Back To Top" + type: "Element" + overallStatus: "Available" + libraries: + - name: Figma library + status: Ready + - name: Responsive + status: Ready + - name: RH Elements + status: Ready + - name: webRH + status: Planned + - name: Documentation + status: In Progress +- name: "Badge" + type: "Element" + overallStatus: "Available" + libraries: + - name: Figma library + status: Ready + - name: Responsive + status: Ready + - name: RH Elements + status: Ready + - name: webRH + status: Ready + - name: Documentation + status: Ready +- name: "Blockquote" + type: "Element" + overallStatus: "Available" + libraries: + - name: Figma library + status: Ready + - name: Responsive + status: Ready + - name: RH Elements + status: Ready + - name: webRH + status: Ready + - name: Documentation + status: Ready +- name: "Button" + type: "Element" + overallStatus: "Available" + libraries: + - name: Figma library + status: Ready + - name: Responsive + status: Ready + - name: RH Elements + status: Ready + - name: webRH + status: Ready + - name: Documentation + status: Ready +- name: "Cta" + type: "Element" + overallStatus: "Available" + libraries: + - name: Figma library + status: Ready + - name: Responsive + status: Ready + - name: RH Elements + status: Ready + - name: webRH + status: Ready + - name: Documentation + status: Ready +- name: "Card" + type: "Element" + overallStatus: "Available" + libraries: + - name: Figma library + status: Ready + - name: Responsive + status: Ready + - name: RH Elements + status: Ready + - name: webRH + status: Ready + - name: Documentation + status: Ready +- name: "Code Block" + type: "Element" + overallStatus: "Available" + libraries: + - name: Figma library + status: Ready + - name: Responsive + status: Ready + - name: RH Elements + status: Ready + - name: webRH + status: Ready + - name: Documentation + status: Ready +- name: "Dialog" + type: "Element" + overallStatus: "Available" + libraries: + - name: Figma library + status: Ready + - name: Responsive + status: Ready + - name: RH Elements + status: Ready + - name: webRH + status: Ready + - name: Documentation + status: Ready +- name: "Footer" + type: "Element" + overallStatus: "Available" + libraries: + - name: Figma library + status: Ready + - name: Responsive + status: Ready + - name: RH Elements + status: Ready + - name: webRH + status: Ready + - name: Documentation + status: Ready +- name: "Jumplinks" + type: "Element" + overallStatus: "Available" + libraries: + - name: Figma library + status: N/A + - name: Responsive + status: N/A + - name: RH Elements + status: N/A + - name: webRH + status: N/A + - name: Documentation + status: Ready +- name: "Navigation Secondary" + type: "Element" + overallStatus: "Available" + libraries: + - name: Figma library + status: Ready + - name: Responsive + status: Ready + - name: RH Elements + status: Ready + - name: webRH + status: Ready + - name: Documentation + status: Ready +- name: "Pagination" + type: "Element" + overallStatus: "Available" + libraries: + - name: Figma library + status: Ready + - name: Responsive + status: Ready + - name: RH Elements + status: Ready + - name: webRH + status: Ready + - name: Documentation + status: Ready +- name: "Popover" + type: "Element" + overallStatus: "Available" + libraries: + - name: Figma library + status: Ready + - name: Responsive + status: Ready + - name: RH Elements + status: Ready + - name: webRH + status: Ready + - name: Documentation + status: Ready +- name: "Skip Link" + type: "Element" + overallStatus: "New" + libraries: + - name: Figma library + status: Ready + - name: Responsive + status: Ready + - name: RH Elements + status: Ready + - name: webRH + status: Planned + - name: Documentation + status: Ready +- name: "Site Status" + type: "Element" + overallStatus: "New" + libraries: + - name: Figma library + status: Ready + - name: Responsive + status: Ready + - name: RH Elements + status: Ready + - name: webRH + status: Planned + - name: Documentation + status: Ready +- name: "Spinner" + type: "Element" + overallStatus: "Available" + libraries: + - name: Figma library + status: Ready + - name: Responsive + status: Ready + - name: RH Elements + status: Ready + - name: webRH + status: Ready + - name: Documentation + status: Ready +- name: "Stat" + type: "Element" + overallStatus: "Available" + libraries: + - name: Figma library + status: Ready + - name: Responsive + status: Ready + - name: RH Elements + status: Ready + - name: webRH + status: Ready + - name: Documentation + status: Ready +- name: "Subnav" + type: "Element" + overallStatus: "Available" + libraries: + - name: Figma library + status: Ready + - name: Responsive + status: Ready + - name: RH Elements + status: Ready + - name: webRH + status: Ready + - name: Documentation + status: Ready +- name: "Surface" + type: "Element" + overallStatus: "New" + libraries: + - name: Figma library + status: Ready + - name: Responsive + status: Ready + - name: RH Elements + status: Ready + - name: webRH + status: Ready + - name: Documentation + status: Ready +- name: "Table" + type: "Element" + overallStatus: "New" + libraries: + - name: Figma library + status: Ready + - name: Responsive + status: Ready + - name: RH Elements + status: Ready + - name: webRH + status: Ready + - name: Documentation + status: Ready +- name: "Tabs" + type: "Element" + overallStatus: "Available" + libraries: + - name: Figma library + status: Ready + - name: Responsive + status: Ready + - name: RH Elements + status: Ready + - name: webRH + status: Ready + - name: Documentation + status: Ready +- name: "Tag" + type: "Element" + overallStatus: "Available" + libraries: + - name: Figma library + status: Ready + - name: Responsive + status: Ready + - name: RH Elements + status: Ready + - name: webRH + status: Ready + - name: Documentation + status: Ready +- name: "Tile" + type: "Element" + overallStatus: "New" + libraries: + - name: Figma library + status: Ready + - name: Responsive + status: Ready + - name: RH Elements + status: Ready + - name: webRH + status: Ready + - name: Documentation + status: Ready +- name: "Timestamp" + type: "Element" + overallStatus: "Available" + libraries: + - name: Figma library + status: Ready + - name: Responsive + status: Ready + - name: RH Elements + status: Ready + - name: webRH + status: Ready + - name: Documentation + status: Ready +- name: "Tooltip" + type: "Element" + overallStatus: "Available" + libraries: + - name: Figma library + status: Ready + - name: Responsive + status: Ready + - name: RH Elements + status: Ready + - name: webRH + status: Ready + - name: Documentation + status: Ready \ No newline at end of file diff --git a/docs/_data/tokens.cjs b/docs/_data/tokens.cjs deleted file mode 100644 index bcdfe550cd..0000000000 --- a/docs/_data/tokens.cjs +++ /dev/null @@ -1 +0,0 @@ -module.exports = require('@rhds/tokens/json/rhds.tokens.json'); diff --git a/docs/_includes/accessibility/1.3.1-A.md b/docs/_includes/accessibility/1.3.1-A.md new file mode 100644 index 0000000000..a485c54f06 --- /dev/null +++ b/docs/_includes/accessibility/1.3.1-A.md @@ -0,0 +1 @@ +- [SC 1.3.1 Info and Relationships](https://www.w3.org/WAI/WCAG21/Understanding/info-and-relationships.html) (Level A) diff --git a/docs/_includes/component/footer.njk b/docs/_includes/component/footer.njk index 5e471d7795..d86a5119ab 100755 --- a/docs/_includes/component/footer.njk +++ b/docs/_includes/component/footer.njk @@ -1,18 +1,3 @@ - {#
-
-
- Info -
-
-

Viewing experience

-

This website is best viewed on large screens. Images are reduced in size to fit a smaller layout.

-
-
-
- -
-
#} -
    diff --git a/docs/_includes/component/header.njk b/docs/_includes/component/header.njk index cb752f1071..e0180926e3 100755 --- a/docs/_includes/component/header.njk +++ b/docs/_includes/component/header.njk @@ -1,86 +1,68 @@ -{% macro menuLink (text, linkUrl, className) %} - {% set classes = className %} - {% if page.url == linkUrl %} - {% set classes = classes + " " + className + "--active" %} - {% endif %} - - {{ text }} - -{% endmacro %} - - - -