tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

commit 57cb207db55a9625adbe937b2f43ca55cb95929d
parent 90ce611386b0d35a769d6835957e1e0bdb42ed8c
Author: Osmond Arnesto <oarnesto@mozilla.com>
Date:   Wed, 22 Oct 2025 02:48:37 +0000

Bug 1979978 - stylelint rule for non-semantic usage of design tokens r=frontend-codestyle-reviewers,tgiles

Differential Revision: https://phabricator.services.mozilla.com/D266532

Diffstat:
M.stylelintrc.js | 3+++
Adocs/code-quality/lint/linters/stylelint-plugin-mozilla/rules/no-non-semantic-token-usage.rst | 79+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mstylelint-rollouts.config.js | 83+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Atools/lint/stylelint/stylelint-plugin-mozilla/data.mjs | 205+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mtools/lint/stylelint/stylelint-plugin-mozilla/helpers.mjs | 4+---
Mtools/lint/stylelint/stylelint-plugin-mozilla/rules/index.mjs | 2++
Atools/lint/stylelint/stylelint-plugin-mozilla/rules/no-non-semantic-token-usage.mjs | 177+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Atools/lint/stylelint/stylelint-plugin-mozilla/tests/no-non-semantic-token-usage.mjs | 179+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
8 files changed, 729 insertions(+), 3 deletions(-)

diff --git a/.stylelintrc.js b/.stylelintrc.js @@ -278,6 +278,7 @@ module.exports = { "stylelint-plugin-mozilla/use-space-tokens": true, "stylelint-plugin-mozilla/use-text-color-tokens": true, "stylelint-plugin-mozilla/use-box-shadow-tokens": true, + "stylelint-plugin-mozilla/no-non-semantic-token-usage": true, }, overrides: [ @@ -426,6 +427,7 @@ module.exports = { "stylelint-plugin-mozilla/use-space-tokens": false, "stylelint-plugin-mozilla/use-text-color-tokens": false, "stylelint-plugin-mozilla/use-box-shadow-tokens": false, + "stylelint-plugin-mozilla/no-non-semantic-token-usage": false, }, }, { @@ -440,6 +442,7 @@ module.exports = { "stylelint-plugin-mozilla/use-border-radius-tokens": true, "stylelint-plugin-mozilla/use-space-tokens": false, "stylelint-plugin-mozilla/use-text-color-tokens": false, + "stylelint-plugin-mozilla/no-non-semantic-token-usage": false, }, }, { diff --git a/docs/code-quality/lint/linters/stylelint-plugin-mozilla/rules/no-non-semantic-token-usage.rst b/docs/code-quality/lint/linters/stylelint-plugin-mozilla/rules/no-non-semantic-token-usage.rst @@ -0,0 +1,79 @@ +=========================== +no-non-semantic-token-usage +=========================== + +This rule checks that design tokens are only used with the appropriate CSS +properties. This ensures that that design tokens are not used with +unexpected properties, such as a font-size token to set a border-width. +This rule allows for variables used with fallback values and variables +used in shorthand properties. + +Examples of incorrect token usage for this rule: +------------------------------------------------ + +.. code-block:: css + + .card { + background-color: var(--border-color); + } + +.. code-block:: css + + .card { + padding: var(--size-item-small); + } + +.. code-block:: css + + .card { + width: var(--space-small); + } + +.. code-block:: css + + .button { + border: var(--border-width) solid var(--text-color); + } + +.. code-block:: css + + :root { + --local-background-color: var(--text-color); + } + + .button { + background-color: var(--local-background-color); + } + +Examples of correct code for this rule: +--------------------------------------- + +.. code-block:: css + + .card { + background-color: var(--background-color-canvas); + } + +.. code-block:: css + + .card { + background-color: var(--background-color-canvas, #fff); + } + +.. code-block:: css + + .card { + background: repeat cover var(--background-color-canvas); + } + +.. code-block:: css + + .card { + background: var(--background-color-canvas), #fff; + } + +.. code-block:: css + + .button { + border: var(--border-width) solid var(--border-color); + } diff --git a/stylelint-rollouts.config.js b/stylelint-rollouts.config.js @@ -1468,4 +1468,87 @@ module.exports = [ "toolkit/themes/shared/tree/tree.css", ], }, + { + // stylelint fixes for this rule will be addressed in Bug 1992749 + name: "rollout-no-non-semantic-token-usage", + rules: { + "stylelint-plugin-mozilla/no-non-semantic-token-usage": "null", + }, + files: [ + "browser/components/aboutlogins/content/components/input-field/input-field.css", + "browser/components/aboutlogins/content/components/login-list.css", + "browser/components/aboutlogins/content/components/login-message-popup.css", + "browser/components/aboutlogins/content/components/login-timeline.css", + "browser/components/aboutlogins/content/components/menu-button.css", + "browser/components/aboutwelcome/content-src/aboutwelcome.scss", + "browser/components/backup/content/backup-common.css", + "browser/components/backup/content/restore-from-backup.css", + "browser/components/genai/chat.css", + "browser/components/genai/content/link-preview-card.css", + "browser/components/profiles/content/profile-avatar-selector.css", + "browser/components/profiles/content/profile-card.css", + "browser/components/protections/content/protections.css", + "browser/components/sidebar/sidebar-main.css", + "browser/components/textrecognition/textrecognition.css", + "browser/extensions/newtab/content-src/components/Base/_Base.scss", + "browser/extensions/newtab/content-src/components/Card/_Card.scss", + "browser/extensions/newtab/content-src/components/CustomizeMenu/_CustomizeMenu.scss", + "browser/extensions/newtab/content-src/components/DiscoveryStreamComponents/CardGrid/_CardGrid.scss", + "browser/extensions/newtab/content-src/components/DiscoveryStreamComponents/CardSections/_CardSections.scss", + "browser/extensions/newtab/content-src/components/DiscoveryStreamComponents/DSCard/_DSCard.scss", + "browser/extensions/newtab/content-src/components/DiscoveryStreamComponents/InterestPicker/_InterestPicker.scss", + "browser/extensions/newtab/content-src/components/DiscoveryStreamComponents/Navigation/_Navigation.scss", + "browser/extensions/newtab/content-src/components/DiscoveryStreamComponents/PromoCard/_PromoCard.scss", + "browser/extensions/newtab/content-src/components/DiscoveryStreamComponents/TopicSelection/_TopicSelection.scss", + "browser/extensions/newtab/content-src/components/DiscoveryStreamComponents/TopicsWidget/_TopicsWidget.scss", + "browser/extensions/newtab/content-src/components/DiscoveryStreamComponents/TrendingSearches/_TrendingSearches.scss", + "browser/extensions/newtab/content-src/components/Search/_Search.scss", + "browser/extensions/newtab/content-src/components/Sections/_Sections.scss", + "browser/extensions/newtab/content-src/components/TopSites/_TopSites.scss", + "browser/extensions/newtab/content-src/components/WallpaperCategories/_WallpaperCategories.scss", + "browser/extensions/newtab/content-src/components/Weather/_Weather.scss", + "browser/extensions/newtab/content-src/components/Widgets/FocusTimer/_FocusTimer.scss", + "browser/extensions/newtab/content-src/components/Widgets/Lists/_Lists.scss", + "browser/extensions/newtab/content-src/styles/_variables.scss", + "browser/themes/linux/browser.css", + "browser/themes/shared/addons/unified-extensions.css", + "browser/themes/shared/controlcenter/panel.css", + "browser/themes/shared/customizableui/panelUI-shared.css", + "browser/themes/shared/downloads/downloads.inc.css", + "browser/themes/shared/formautofill-notification.css", + "browser/themes/shared/identity-block/identity-block.css", + "browser/themes/shared/notification-icons.css", + "browser/themes/shared/pageInfo.css", + "browser/themes/shared/places/editBookmarkPanel.css", + "browser/themes/shared/preferences/containers-dialog.css", + "browser/themes/shared/sidebar.css", + "browser/themes/shared/tabbrowser/tabs.css", + "browser/themes/shared/toolbarbuttons.css", + "browser/themes/shared/translations/panel.css", + "browser/themes/shared/urlbar-dynamic-results.css", + "browser/themes/shared/urlbar-searchbar.css", + "browser/themes/shared/urlbarView.css", + "browser/themes/windows/browser.css", + "toolkit/components/printing/content/toggle-group.css", + "toolkit/components/satchel/megalist/content/megalist.css", + "toolkit/content/aboutGlean.css", + "toolkit/content/widgets/moz-box-common.css", + "toolkit/content/widgets/moz-button/moz-button.css", + "toolkit/content/widgets/moz-input-color/moz-input-color.css", + "toolkit/content/widgets/moz-input-text/moz-input-text.css", + "toolkit/content/widgets/moz-message-bar/moz-message-bar.css", + "toolkit/content/widgets/moz-page-nav/moz-page-nav.css", + "toolkit/content/widgets/moz-select/moz-select.css", + "toolkit/content/widgets/moz-toggle/moz-toggle.css", + "toolkit/content/widgets/moz-visual-picker/moz-visual-picker-item.css", + "toolkit/content/widgets/panel-list/panel-item.css", + "toolkit/content/widgets/panel-list/panel-list.css", + "toolkit/themes/shared/aboutReader.css", + "toolkit/themes/shared/design-system/tokens-table.css", + "toolkit/themes/shared/findbar.css", + "toolkit/themes/shared/global-shared.css", + "toolkit/themes/shared/in-content/common-shared.css", + "toolkit/themes/shared/menulist.css", + ], + }, ]; diff --git a/tools/lint/stylelint/stylelint-plugin-mozilla/data.mjs b/tools/lint/stylelint/stylelint-plugin-mozilla/data.mjs @@ -0,0 +1,205 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +export const BACKGROUND_COLOR = { + CATEGORIES: ["background-color"], + PROPERTIES: ["background", "background-color"], +}; + +export const BORDER_COLOR = { + CATEGORIES: ["border-color", "border", "outline"], + PROPERTIES: [ + "border", + "border-color", + "outline", + "outline-color", + "border-top", + "border-right", + "border-bottom", + "border-left", + "border-top-color", + "border-right-color", + "border-bottom-color", + "border-left-color", + "border-block", + "border-block-color", + "border-block-start", + "border-block-start-color", + "border-block-end", + "border-block-end-color", + "border-inline", + "border-inline-color", + "border-inline-start", + "border-inline-start-color", + "border-inline-end", + "border-inline-end-color", + ], +}; + +export const BORDER_RADIUS = { + CATEGORIES: ["border-radius"], + PROPERTIES: [ + "border-radius", + "border-top-left-radius", + "border-top-right-radius", + "border-bottom-right-radius", + "border-bottom-left-radius", + "border-start-start-radius", + "border-start-end-radius", + "border-end-start-radius", + "border-end-end-radius", + ], +}; + +export const BORDER_WIDTH = { + CATEGORIES: ["border-width"], + PROPERTIES: [ + "border", + "border-width", + "border-top", + "border-top-width", + "border-block-start", + "border-block-start-width", + "border-right", + "border-right-width", + "border-inline-end", + "border-inline-width", + "border-bottom", + "border-bottom-width", + "border-block-end", + "border-block-end-width", + "border-left", + "border-left-width", + "border-inline-start", + "border-inline-start-width", + "outline", + "outline-width", + ], +}; + +export const FONT_SIZE = { + CATEGORIES: ["font-size", "heading-font"], + PROPERTIES: ["font-size", "font"], +}; + +export const FONT_WEIGHT = { + CATEGORIES: ["font-weight"], + PROPERTIES: ["font-weight", "font"], +}; + +export const ICON_COLOR = { + CATEGORIES: ["icon-color"], + PROPERTIES: ["color", "fill", "stroke"], +}; + +export const SIZE = { + CATEGORIES: ["size", "icon-size"], + PROPERTIES: [ + "width", + "min-width", + "max-width", + "height", + "min-height", + "max-height", + "inline-size", + "min-inline-size", + "max-inline-size", + "block-size", + "min-block-size", + "max-block-size", + "inset", + "inset-block", + "inset-block-end", + "inset-block-start", + "inset-inline", + "inset-inline-end", + "inset-inline-start", + "flex", + "flex-basis", + "grid", + "grid-template-rows", + "grid-template-columns", + "grid-auto-rows", + "grid-auto-columns", + "background-size", + "transform", + ], +}; + +export const OPACITY = { + CATEGORIES: ["opacity"], + PROPERTIES: ["opacity"], +}; + +export const SPACE = { + CATEGORIES: ["space"], + PROPERTIES: [ + "margin", + "margin-top", + "margin-right", + "margin-bottom", + "margin-left", + "margin-block", + "margin-block-start", + "margin-block-end", + "margin-inline", + "margin-inline-start", + "margin-inline-end", + "padding", + "padding-top", + "padding-right", + "padding-bottom", + "padding-left", + "padding-block", + "padding-block-start", + "padding-block-end", + "padding-inline", + "padding-inline-start", + "padding-inline-end", + "inset", + "inset-block", + "inset-block-end", + "inset-block-start", + "inset-inline", + "inset-inline-end", + "inset-inline-start", + "gap", + "row-gap", + "column-gap", + "scroll-margin", + "scroll-margin-top", + "scroll-margin-right", + "scroll-margin-bottom", + "scroll-margin-left", + "scroll-margin-block", + "scroll-margin-block-start", + "scroll-margin-block-end", + "scroll-margin-inline", + "scroll-margin-inline-start", + "scroll-margin-inline-end", + "scroll-padding", + "scroll-padding-top", + "scroll-padding-right", + "scroll-padding-bottom", + "scroll-padding-left", + "scroll-padding-block", + "scroll-padding-block-start", + "scroll-padding-block-end", + "scroll-padding-inline", + "scroll-padding-inline-start", + "scroll-padding-inline-end", + "border-spacing", + ], +}; + +export const TEXT_COLOR = { + CATEGORIES: ["text-color", "link"], + PROPERTIES: ["color", "fill", "stroke"], +}; + +export const BOX_SHADOW = { + CATEGORIES: ["box-shadow"], + PROPERTIES: ["box-shadow", "filter", "backdrop-filter"], +}; diff --git a/tools/lint/stylelint/stylelint-plugin-mozilla/helpers.mjs b/tools/lint/stylelint/stylelint-plugin-mozilla/helpers.mjs @@ -52,7 +52,6 @@ export const ALLOW_LIST = [ * @param {string[]} additionalAllows to be appended to our list * @returns {string[]} */ - export const createAllowList = (additionalAllows = []) => { return [...ALLOW_LIST, ...additionalAllows]; }; @@ -67,7 +66,7 @@ export const createTokenNamesArray = tokenCategoriesArray => tokenCategoriesArray .flatMap(category => tokensTable[category]) .reduce((acc, token) => { - if (token.name) { + if (token?.name) { return [...acc, `var(${token.name})`]; } return acc; @@ -356,7 +355,6 @@ export const isValidLocalProperty = (value, cssCustomProperties, tokenCSS) => { * @param {string} value some CSS declaration to match * @returns {string} */ - export const trimValue = value => String(value).trim(); /** diff --git a/tools/lint/stylelint/stylelint-plugin-mozilla/rules/index.mjs b/tools/lint/stylelint/stylelint-plugin-mozilla/rules/index.mjs @@ -14,6 +14,7 @@ import useSpaceTokens from "./use-space-tokens.mjs"; import useBackgroundColorTokens from "./use-background-color-tokens.mjs"; import useTextColorTokens from "./use-text-color-tokens.mjs"; import useBoxShadowTokens from "./use-box-shadow-tokens.mjs"; +import noNonSemanticTokenUsage from "./no-non-semantic-token-usage.mjs"; export default { "no-base-design-tokens": noBaseDesignTokens, @@ -26,4 +27,5 @@ export default { "use-background-color-tokens": useBackgroundColorTokens, "use-text-color-tokens": useTextColorTokens, "use-box-shadow-tokens": useBoxShadowTokens, + "no-non-semantic-token-usage": noNonSemanticTokenUsage, }; diff --git a/tools/lint/stylelint/stylelint-plugin-mozilla/rules/no-non-semantic-token-usage.mjs b/tools/lint/stylelint/stylelint-plugin-mozilla/rules/no-non-semantic-token-usage.mjs @@ -0,0 +1,177 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +import stylelint from "stylelint"; +import valueParser from "postcss-value-parser"; +import { + getLocalCustomProperties, + namespace, + createTokenNamesArray, + isWord, + isVariableFunction, +} from "../helpers.mjs"; +import { + BACKGROUND_COLOR, + BORDER_COLOR, + BORDER_RADIUS, + BORDER_WIDTH, + FONT_SIZE, + FONT_WEIGHT, + ICON_COLOR, + SIZE, + OPACITY, + SPACE, + TEXT_COLOR, + BOX_SHADOW, +} from "../data.mjs"; + +const { + utils: { report, ruleMessages, validateOptions }, +} = stylelint; + +const ruleName = namespace("no-non-semantic-token-usage"); + +const messages = ruleMessages(ruleName, { + rejected: token => + `Unexpected usage of \`${token}\`. Design tokens should only be used with properties matching their semantic meaning.`, +}); + +const meta = { + url: "https://firefox-source-docs.mozilla.org/code-quality/lint/linters/stylelint-plugin-mozilla/rules/no-non-semantic-token-usage.html", + fixable: false, +}; + +const backgroundColorTokens = createTokenNamesArray( + BACKGROUND_COLOR.CATEGORIES +); +const borderColorTokens = createTokenNamesArray(BORDER_COLOR.CATEGORIES); +const borderRadiusTokens = createTokenNamesArray(BORDER_RADIUS.CATEGORIES); +const borderWidthTokens = createTokenNamesArray(BORDER_WIDTH.CATEGORIES); +const fontSizeTokens = createTokenNamesArray(FONT_SIZE.CATEGORIES); +const fontWeightTokens = createTokenNamesArray(FONT_WEIGHT.CATEGORIES); +const iconColorTokens = createTokenNamesArray(ICON_COLOR.CATEGORIES); +const sizeTokens = createTokenNamesArray(SIZE.CATEGORIES); +const opacityTokens = createTokenNamesArray(OPACITY.CATEGORIES); +const spaceTokens = createTokenNamesArray(SPACE.CATEGORIES); +const textColorTokens = createTokenNamesArray(TEXT_COLOR.CATEGORIES); +const boxShadowTokens = createTokenNamesArray(BOX_SHADOW.CATEGORIES); + +// Get allowed properties by token category +const getAllowedProps = token => { + let tokenProperties = null; + switch (true) { + case backgroundColorTokens.includes(token): + tokenProperties = BACKGROUND_COLOR.PROPERTIES; + break; + case borderColorTokens.includes(token): + tokenProperties = BORDER_COLOR.PROPERTIES; + break; + case borderRadiusTokens.includes(token): + tokenProperties = BORDER_RADIUS.PROPERTIES; + break; + case borderWidthTokens.includes(token): + tokenProperties = BORDER_WIDTH.PROPERTIES; + break; + case fontSizeTokens.includes(token): + tokenProperties = FONT_SIZE.PROPERTIES; + break; + case fontWeightTokens.includes(token): + tokenProperties = FONT_WEIGHT.PROPERTIES; + break; + case iconColorTokens.includes(token): + tokenProperties = ICON_COLOR.PROPERTIES; + break; + case sizeTokens.includes(token): + tokenProperties = SIZE.PROPERTIES; + break; + case opacityTokens.includes(token): + tokenProperties = OPACITY.PROPERTIES; + break; + case spaceTokens.includes(token): + tokenProperties = SPACE.PROPERTIES; + break; + case textColorTokens.includes(token): + tokenProperties = TEXT_COLOR.PROPERTIES; + break; + case boxShadowTokens.includes(token): + tokenProperties = BOX_SHADOW.PROPERTIES; + break; + default: + break; + } + + return tokenProperties; +}; + +// Get all design tokens in CSS declaration value +const getAllTokensInValue = value => { + const parsedValue = valueParser(value).nodes; + + const allTokens = parsedValue + .filter(node => isVariableFunction(node)) + .map(functionNode => { + const variableNode = functionNode.nodes.find( + node => isWord(node) && node.value.startsWith("--") + ); + return variableNode ? variableNode.value : null; + }) + .filter(Boolean); + + return allTokens; +}; + +const ruleFunction = primaryOption => { + return (root, result) => { + const validOptions = validateOptions(result, ruleName, { + actual: primaryOption, + possible: [true], + }); + if (!validOptions) { + return; + } + + const cssCustomProperties = getLocalCustomProperties(root); + + root.walkDecls(declaration => { + const { prop, value } = declaration; + + const tokens = getAllTokensInValue(value); + + tokens.forEach(token => { + // If local CSS custom variable declaration, skip + if (prop in cssCustomProperties) { + return; + } + + // `var(--token-name)` mirrors shape received from `createTokenNamesArray()` + let varifiedToken = `var(${token})`; + let allowedProps = null; + + if (cssCustomProperties[token]) { + // `cssCustomProperties[token]` already in desired shape + varifiedToken = cssCustomProperties[token]; + allowedProps = getAllowedProps(cssCustomProperties[token]); + } else { + allowedProps = getAllowedProps(varifiedToken); + } + + if (allowedProps && !allowedProps.includes(prop)) { + report({ + message: messages.rejected(varifiedToken), + node: declaration, + result, + ruleName, + }); + } + }); + }); + }; +}; + +ruleFunction.ruleName = ruleName; +ruleFunction.messages = messages; +ruleFunction.meta = meta; + +export default ruleFunction; diff --git a/tools/lint/stylelint/stylelint-plugin-mozilla/tests/no-non-semantic-token-usage.mjs b/tools/lint/stylelint/stylelint-plugin-mozilla/tests/no-non-semantic-token-usage.mjs @@ -0,0 +1,179 @@ +/** + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ +// eslint-disable-next-line import/no-unresolved +import { testRule } from "stylelint-test-rule-node"; +import stylelint from "stylelint"; +import noNonSemanticTokenUsage from "../rules/no-non-semantic-token-usage.mjs"; + +let plugin = stylelint.createPlugin( + noNonSemanticTokenUsage.ruleName, + noNonSemanticTokenUsage +); +let { + ruleName, + rule: { messages }, +} = plugin; + +testRule({ + plugins: [plugin], + ruleName, + config: true, + fix: false, + accept: [ + // * allowed token usage + { + code: ".a { background-color: var(--background-color-canvas); }", + description: + "Using the canvas background color token with the background-color property is valid.", + }, + { + code: ".a { background-color: var(--background-color-canvas, #fff); }", + description: + "Using the canvas background color token with the background-color property is valid.", + }, + { + code: ".a { background-color: var(--background-color-canvas), #fff; }", + description: + "Using the canvas background color token with the background-color property is valid.", + }, + { + code: ".a { background: repeat cover var(--background-color-canvas); }", + description: + "Using the canvas background color token with the background property is valid.", + }, + { + code: ".a { border-color: var(--border-color); }", + description: + "Using the border color token with the border-color property is valid.", + }, + { + code: ".a { border: 2px solid var(--border-color); }", + description: + "Using the border color token with the border shorthand property is valid.", + }, + { + code: ".a { border: var(--border-width) solid var(--border-color); }", + description: + "Using the border width and border color tokens with the border shorthand property are valid.", + }, + { + code: ".a { border-radius: var(--border-radius-small, 0.25rem); }", + description: + "Using the small border radius token with the border-radius property is valid.", + }, + { + code: ".a { font-size: var(--font-size-small); }", + description: + "Using the small font size token with the font-size property is valid.", + }, + { + code: ".a { font: bold var(--font-size-small) 'Open Sans' sans-serif; }", + description: + "Using the small font size token with the font shorthand property is valid.", + }, + { + code: ".a { font-weight: var(--font-weight-bold); }", + description: + "Using the bold font size token with the font-weight property is valid.", + }, + { + code: ".a { font: var(--font-weight-bold) 16px 'Open Sans' sans-serif; }", + description: + "Using the bold font weight token with the font shorthand property is valid.", + }, + { + code: ".a { fill: var(--icon-color); }", + description: + "Using the icon color token with the fill property is valid.", + }, + { + code: ".a { height: var(--input-text-min-height); }", + description: + "Using the input text minimum height token with the height property is valid.", + }, + { + code: ".a { inset: var(--size-item-small) var(--size-item-small) var(--size-item-large) var(--size-item-xlarge); }", + description: + "Using the small, large, and xlarge size tokens with the inset property is valid.", + }, + { + code: ".a { opacity: var(--button-opacity-disabled); }", + description: + "Using the disabled button opacity token with the opacity property is valid.", + }, + { + code: ".a { padding: var(--space-small) 4px; }", + description: + "Using the small space token with the padding property is valid.", + }, + { + code: ".a { color: var(--text-color); }", + description: + "Using the text color token with the color property is valid.", + }, + { + code: ".a { color: var(--button-text-color); }", + description: + "Using the button text color token with the color property is valid.", + }, + { + code: ".a { box-shadow: var(--box-shadow-level-3); }", + description: + "Using the 3rd-level box shadow token with the box-shadow property is valid.", + }, + { + code: ".a { box-shadow: var(--box-shadow-level-2), var(--box-shadow-level-4); }", + description: + "Using the 2nd-level and 4th-level box shadow tokens with the box-shadow property is valid.", + }, + { + code: ` + button { + background-color: var(--background-color-canvas); + color: var(--text-color); + border: 2px solid var(--border-color); + } + `, + description: + "Using the canvas background color token with the background-color property, the text color token with the color property, and the border color token with the border shorthand property are valid.", + }, + ], + reject: [ + { + code: ".a { background: var(--border-color); }", + message: messages.rejected("var(--border-color)"), + description: + "Unexpected usage of `var(--border-color)`. Design tokens should only be used with properties matching their semantic meaning.", + }, + { + code: ".a { border: var(--font-size-xsmall) solid var(--border-color); }", + message: messages.rejected("var(--font-size-xsmall)"), + description: + "Unexpected usage of `var(--font-size-xsmall)`. Design tokens should only be used with properties matching their semantic meaning.", + }, + { + code: ".a { border: var(--border-width) solid var(--background-color-canvas); }", + message: messages.rejected("var(--background-color-canvas)"), + description: + "Unexpected usage of `var(--background-color-canvas)`. Design tokens should only be used with properties matching their semantic meaning.", + }, + { + code: ` + :root { --local-background-color: var(--border-color); } + .a { background: var(--local-background-color); } + `, + message: messages.rejected("var(--border-color)"), + description: + "Unexpected usage of `var(--border-color)`. Design tokens should only be used with properties matching their semantic meaning.", + }, + { + code: ".a { padding: var(--space-small) 4px var(--size-item-large) var(--space-small); }", + message: messages.rejected("var(--size-item-large)"), + description: + "Unexpected usage of `var(--size-item-large)`. Design tokens should only be used with properties matching their semantic meaning.", + }, + ], +});