From 8d44fa54210b12ceddc043b68ce5e17f710d2019 Mon Sep 17 00:00:00 2001 From: Adam Kudrna Date: Fri, 9 Aug 2024 20:58:12 +0200 Subject: [PATCH 01/15] Fix MkDocs deployment to GitHub pages (#556) --- .github/workflows/release-management.yml | 2 -- 1 file changed, 2 deletions(-) diff --git a/.github/workflows/release-management.yml b/.github/workflows/release-management.yml index 29c58f2c7..6edea6eaa 100644 --- a/.github/workflows/release-management.yml +++ b/.github/workflows/release-management.yml @@ -116,8 +116,6 @@ jobs: steps: - name: Clone repository uses: actions/checkout@v4 - with: - persist-credentials: false # Hard-coded username and email for the GitHub bot user # https://api.github.com/users/github-actions%5Bbot%5D From 94a4a36087adb36cdd6caceaafc15e5f66567319 Mon Sep 17 00:00:00 2001 From: Adam Kudrna Date: Fri, 16 Aug 2024 13:49:50 +0200 Subject: [PATCH 02/15] Create CNAME file to enable custom domain for docs --- src/CNAME | 1 + 1 file changed, 1 insertion(+) create mode 100644 src/CNAME diff --git a/src/CNAME b/src/CNAME new file mode 100644 index 000000000..937aa23de --- /dev/null +++ b/src/CNAME @@ -0,0 +1 @@ +react-ui.io From 02a83f7ae8fc95829a490a28386b4a721676752b Mon Sep 17 00:00:00 2001 From: Adam Kudrna Date: Thu, 22 Aug 2024 12:19:19 +0200 Subject: [PATCH 03/15] Switch `@visionappscz/stylelint-config` to v4 --- package-lock.json | 8 ++++---- package.json | 2 +- stylelint.config.js | 21 --------------------- 3 files changed, 5 insertions(+), 26 deletions(-) diff --git a/package-lock.json b/package-lock.json index a8df1a8b8..6cc618219 100644 --- a/package-lock.json +++ b/package-lock.json @@ -27,7 +27,7 @@ "@testing-library/react": "^16.0.0", "@testing-library/user-event": "^14.5.2", "@visionappscz/eslint-config-visionapps": "^1.7.0", - "@visionappscz/stylelint-config": "^4.0.0-beta1", + "@visionappscz/stylelint-config": "^4.0.0", "autoprefixer": "^10.4.19", "babel-jest": "^29.7.0", "babel-loader": "^9.1.3", @@ -3932,9 +3932,9 @@ } }, "node_modules/@visionappscz/stylelint-config": { - "version": "4.0.0-beta1", - "resolved": "https://registry.npmjs.org/@visionappscz/stylelint-config/-/stylelint-config-4.0.0-beta1.tgz", - "integrity": "sha512-SE2dcvhcwL2lsgylz1krlfpLLovdk+Up9jN9ANVMSh4IOAtrNcJPNB4Oxc3WAx4F3w7Z7ZEhDeluevLo5F2lqw==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@visionappscz/stylelint-config/-/stylelint-config-4.0.0.tgz", + "integrity": "sha512-dCh1oQxgzpg3ML4zeYqzo8XYPDUx4xXJ7Nx7mF2NU4dDvsuJZXee32U5Z9tUnTxL1kimRpraVIPzHmOI5wN0WQ==", "dev": true, "dependencies": { "stylelint-config-standard": "^36.0.0", diff --git a/package.json b/package.json index b604286b4..ba6c86042 100644 --- a/package.json +++ b/package.json @@ -71,7 +71,7 @@ "@testing-library/react": "^16.0.0", "@testing-library/user-event": "^14.5.2", "@visionappscz/eslint-config-visionapps": "^1.7.0", - "@visionappscz/stylelint-config": "^4.0.0-beta1", + "@visionappscz/stylelint-config": "^4.0.0", "autoprefixer": "^10.4.19", "babel-jest": "^29.7.0", "babel-loader": "^9.1.3", diff --git a/stylelint.config.js b/stylelint.config.js index ef0546115..a9acf4f22 100644 --- a/stylelint.config.js +++ b/stylelint.config.js @@ -28,27 +28,6 @@ module.exports = { }, ], - // Override `@visionappscz/stylelint-config/order` rules to ignore all block at rules: - 'order/order': [ - 'dollar-variables', - 'custom-properties', - { - name: 'extend', - type: 'at-rule', - }, - { - hasBlock: false, - name: 'include', - type: 'at-rule', - }, - 'declarations', - 'rules', - // { - // hasBlock: true, - // type: 'at-rule', - // }, - ], - // Require camelCase pattern for class names as they are picked up by dot notation in JS. // Also allow kebab-case class names for global helper and utility classes. // From b2ed7cd83ec499a94e2d5effabe47d159e955c3e Mon Sep 17 00:00:00 2001 From: Adam Kudrna Date: Mon, 26 Aug 2024 18:56:41 +0200 Subject: [PATCH 04/15] Introduce color collections for generative styling of components --- mkdocs.yml | 1 + src/docs/foundation/collections.md | 24 ++++++++++++++++++++++++ src/docs/foundation/colors.md | 20 ++++++++------------ src/docs/foundation/design-tokens.md | 8 +++----- src/styles/settings/_collections.scss | 9 +++++++++ 5 files changed, 45 insertions(+), 17 deletions(-) create mode 100644 src/docs/foundation/collections.md create mode 100644 src/styles/settings/_collections.scss diff --git a/mkdocs.yml b/mkdocs.yml index 651715eaa..e07315fd2 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -84,6 +84,7 @@ nav: - 'Browsers & Devices': 'docs/getting-started/browsers-and-devices.md' - Foundation: - 'Design Tokens': 'docs/foundation/design-tokens.md' + - 'Collections': 'docs/foundation/collections.md' - 'Colors': 'docs/foundation/colors.md' - 'Typography': 'docs/foundation/typography.md' - 'Spacing': 'docs/foundation/spacing.md' diff --git a/src/docs/foundation/collections.md b/src/docs/foundation/collections.md new file mode 100644 index 000000000..62a6e08bf --- /dev/null +++ b/src/docs/foundation/collections.md @@ -0,0 +1,24 @@ +# Collections + +Collections are lists of available values that can be used to customize the +appearance of components, such as colors, sizes, and placement. Collections are +used to ensure consistency across the design system. + +## General Guidelines + +- Components can support one or more collections from a collection category. + Refer to the documentation for each component to see which collections are + available. +- If an option from a collection is used in a component, all other options from + the same collection must be available for use in that component too. + +## Colors + +The following color names are designed for use in components that support the +`color` prop: + +| Collection | Available values | +|------------|--------------------------------------------------------| +| Action | `primary`, `secondary`, `selected` | +| Feedback | `success`, `warning`, `danger`, `info`, `help`, `note` | +| Neutral | `light`, `dark` | diff --git a/src/docs/foundation/colors.md b/src/docs/foundation/colors.md index 32d6c9ed7..3fa1358fa 100644 --- a/src/docs/foundation/colors.md +++ b/src/docs/foundation/colors.md @@ -227,23 +227,17 @@ primary border. ## Applying Colors -Components can apply colors above using one or more following color groups. +Components can apply colors above using one or more following approaches. -### Component Colors +### Color Collections Some components ([Alert](/components/Alert), [Badge](/components/Badge), [Button](/components/Button), and more) come in more color variants to help you better reflect their place in content hierarchy or the meaning of their content. -Following colors are available in such cases: - -- **action colors (actionable components only):** `primary`, `secondary`, and - `selected`, -- **feedback colors:** `success`, `warning`, `danger`, `help`, `info`, and - `note`, -- **neutral colors:** `light` and `dark`. - -There is always a reasonable default for the component in question that can be -changed to any of supported values above through the `color` prop. +In such cases, one or more [Color Collections][collection-colors] are always +used. There is always a reasonable default color for the component in question +that can be changed to any of supported collection values through the `color` +prop. ### Validation States @@ -258,3 +252,5 @@ apply selected [feedback colors](#feedback-colors) for individual states: Validation state is always optional. Default styling is applied for the given component when its `validationState` prop is not specified. + +[collection-colors]: /docs/foundation/collections#colors diff --git a/src/docs/foundation/design-tokens.md b/src/docs/foundation/design-tokens.md index 21b939236..07e2f7281 100644 --- a/src/docs/foundation/design-tokens.md +++ b/src/docs/foundation/design-tokens.md @@ -10,9 +10,7 @@ organizations. design system needs. React UI uses CSS custom properties as a primary storage format for design tokens. -## Design Token Types - -### Global Tokens +## Global Tokens Global tokens represent the basic, context-agnostic values in your design language. They define color palettes, typography scales, or spacing values, @@ -24,7 +22,7 @@ without binding them to any semantic meaning. } ``` -### Semantic Tokens +## Semantic Tokens Semantic tokens define roles and decisions that give the design system its character. They communicate the intended purpose of a global token and are often @@ -36,7 +34,7 @@ reused by component tokens. } ``` -### Component Tokens +## Component Tokens Component tokens represent the values associated with a component. They often inherit from semantic tokens, but are named in a way that narrows down their diff --git a/src/styles/settings/_collections.scss b/src/styles/settings/_collections.scss new file mode 100644 index 000000000..64b718d85 --- /dev/null +++ b/src/styles/settings/_collections.scss @@ -0,0 +1,9 @@ +$action-colors: primary, secondary, selected; +$feedback-colors: success, warning, danger, info, help, note; +$neutral-colors: light, dark; + +$colors: ( + action: $action-colors, + feedback: $feedback-colors, + neutral: $neutral-colors, +); From 96642278f2f8caa15dec460cdefc1d7d85ee2c8c Mon Sep 17 00:00:00 2001 From: Adam Kudrna Date: Mon, 2 Sep 2024 21:11:12 +0200 Subject: [PATCH 05/15] Include `refactor/*` branch name for the `refactoring` label --- .github/pr-labeler.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/pr-labeler.yml b/.github/pr-labeler.yml index 4927c6b6f..10f3a566f 100644 --- a/.github/pr-labeler.yml +++ b/.github/pr-labeler.yml @@ -1,7 +1,7 @@ BC: bc/* feature: [feature/*, task/*] fix: [fix/*, bug/*, bugfix/*] -refactoring: refactoring/* +refactoring: [refactor/*, refactoring/*] documentation: [docs/*, documentation/*] maintenance: maintenance/* 'skip changelog': release/* From 5bcecab3c335b44ca7c08437bbbf689a7f04823d Mon Sep 17 00:00:00 2001 From: Adam Kudrna Date: Sat, 31 Aug 2024 15:12:57 +0200 Subject: [PATCH 06/15] Make `Badge` priority class always present like in all other components This change affects output HTML and may break downstream snapshot tests. --- src/components/Badge/Badge.jsx | 3 ++- src/components/Badge/Badge.module.scss | 6 +++--- src/components/Badge/__tests__/Badge.test.jsx | 2 +- src/components/Button/Button.jsx | 2 +- src/components/ButtonGroup/ButtonGroup.jsx | 2 +- src/components/_helpers/getRootPriorityClassName.js | 2 +- 6 files changed, 9 insertions(+), 8 deletions(-) diff --git a/src/components/Badge/Badge.jsx b/src/components/Badge/Badge.jsx index 56215029b..ef841489c 100644 --- a/src/components/Badge/Badge.jsx +++ b/src/components/Badge/Badge.jsx @@ -4,6 +4,7 @@ import { withGlobalProps } from '../../provider'; import { classNames } from '../../utils/classNames'; import { transferProps } from '../../utils/transferProps'; import { getRootColorClassName } from '../_helpers/getRootColorClassName'; +import { getRootPriorityClassName } from '../_helpers/getRootPriorityClassName'; import styles from './Badge.module.scss'; export const Badge = ({ @@ -16,7 +17,7 @@ export const Badge = ({ {...transferProps(restProps)} className={classNames( styles.root, - priority === 'outline' && styles.isRootPriorityOutline, + getRootPriorityClassName(priority, styles), getRootColorClassName(color, styles), )} > diff --git a/src/components/Badge/Badge.module.scss b/src/components/Badge/Badge.module.scss index a78c70227..1949d9378 100644 --- a/src/components/Badge/Badge.module.scss +++ b/src/components/Badge/Badge.module.scss @@ -20,6 +20,9 @@ $_badge-size: 1.25rem; vertical-align: baseline; color: var(--rui-local-color); border-radius: math.div($_badge-size, 2); + } + + .isRootPriorityFilled { background-color: var(--rui-local-background-color); box-shadow: var(--rui-local-box-shadow, #{0 0 0 2px rgb(255 255 255 / 80%)}); } @@ -67,9 +70,6 @@ $_badge-size: 1.25rem; } .isRootPriorityOutline { - --rui-local-background-color: transparent; - --rui-local-box-shadow: none; - padding-top: 0.1875rem; padding-bottom: 0.1875rem; border: borders.$width solid currentcolor; diff --git a/src/components/Badge/__tests__/Badge.test.jsx b/src/components/Badge/__tests__/Badge.test.jsx index 87e14c916..6e40cec27 100644 --- a/src/components/Badge/__tests__/Badge.test.jsx +++ b/src/components/Badge/__tests__/Badge.test.jsx @@ -19,7 +19,7 @@ describe('rendering', () => { ], [ { priority: 'filled' }, - (rootElement) => expect(rootElement).not.toHaveClass('isRootPriorityOutline'), + (rootElement) => expect(rootElement).toHaveClass('isRootPriorityFilled'), ], [ { priority: 'outline' }, diff --git a/src/components/Button/Button.jsx b/src/components/Button/Button.jsx index cf9488943..3fa732fcb 100644 --- a/src/components/Button/Button.jsx +++ b/src/components/Button/Button.jsx @@ -4,11 +4,11 @@ import { withGlobalProps } from '../../provider'; import { classNames } from '../../utils/classNames'; import { transferProps } from '../../utils/transferProps'; import { getRootColorClassName } from '../_helpers/getRootColorClassName'; +import { getRootPriorityClassName } from '../_helpers/getRootPriorityClassName'; import { getRootSizeClassName } from '../_helpers/getRootSizeClassName'; import { resolveContextOrProp } from '../_helpers/resolveContextOrProp'; import { ButtonGroupContext } from '../ButtonGroup'; import { InputGroupContext } from '../InputGroup/InputGroupContext'; -import getRootPriorityClassName from '../_helpers/getRootPriorityClassName'; import getRootLabelVisibilityClassName from './helpers/getRootLabelVisibilityClassName'; import styles from './Button.module.scss'; diff --git a/src/components/ButtonGroup/ButtonGroup.jsx b/src/components/ButtonGroup/ButtonGroup.jsx index d863a4e14..e894fb92a 100644 --- a/src/components/ButtonGroup/ButtonGroup.jsx +++ b/src/components/ButtonGroup/ButtonGroup.jsx @@ -5,7 +5,7 @@ import React, { import { withGlobalProps } from '../../provider'; import { classNames } from '../../utils/classNames'; import { transferProps } from '../../utils/transferProps'; -import getRootPriorityClassName from '../_helpers/getRootPriorityClassName'; +import { getRootPriorityClassName } from '../_helpers/getRootPriorityClassName'; import { isChildrenEmpty } from '../_helpers/isChildrenEmpty'; import styles from './ButtonGroup.module.scss'; import { ButtonGroupContext } from './ButtonGroupContext'; diff --git a/src/components/_helpers/getRootPriorityClassName.js b/src/components/_helpers/getRootPriorityClassName.js index 410176577..9cdb17c31 100644 --- a/src/components/_helpers/getRootPriorityClassName.js +++ b/src/components/_helpers/getRootPriorityClassName.js @@ -1,4 +1,4 @@ -export default (priority, styles) => { +export const getRootPriorityClassName = (priority, styles) => { if (priority === 'filled') { return styles.isRootPriorityFilled; } From 4f7c6dca44430efc1da39ed915b40752e7f3c90a Mon Sep 17 00:00:00 2001 From: Adam Kudrna Date: Sat, 31 Aug 2024 15:29:31 +0200 Subject: [PATCH 07/15] Split color prop test by collections --- src/components/Alert/__tests__/Alert.test.jsx | 6 ++++-- src/components/Badge/__tests__/Badge.test.jsx | 6 ++++-- src/components/Button/__tests__/Button.test.jsx | 6 ++++-- src/components/Card/__tests__/Card.test.jsx | 6 ++++-- .../{colorPropTest.js => feedbackColorPropTest.js} | 10 +--------- tests/propTests/neutralColorPropTest.js | 10 ++++++++++ 6 files changed, 27 insertions(+), 17 deletions(-) rename tests/propTests/{colorPropTest.js => feedbackColorPropTest.js} (72%) create mode 100644 tests/propTests/neutralColorPropTest.js diff --git a/src/components/Alert/__tests__/Alert.test.jsx b/src/components/Alert/__tests__/Alert.test.jsx index a846d99aa..591cca145 100644 --- a/src/components/Alert/__tests__/Alert.test.jsx +++ b/src/components/Alert/__tests__/Alert.test.jsx @@ -5,7 +5,8 @@ import { within, } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; -import { colorPropTest } from '../../../../tests/propTests/colorPropTest'; +import { feedbackColorPropTest } from '../../../../tests/propTests/feedbackColorPropTest'; +import { neutralColorPropTest } from '../../../../tests/propTests/neutralColorPropTest'; import defaultTranslations from '../../../translations/en'; import { Alert } from '../Alert'; @@ -20,7 +21,8 @@ describe('rendering', () => { { children:
content text
}, (rootElement) => expect(within(rootElement).getByText('content text')), ], - ...colorPropTest, + ...feedbackColorPropTest, + ...neutralColorPropTest, [ { icon: (
icon
) }, (rootElement) => expect(within(rootElement).getByText('icon')), diff --git a/src/components/Badge/__tests__/Badge.test.jsx b/src/components/Badge/__tests__/Badge.test.jsx index 6e40cec27..37531b990 100644 --- a/src/components/Badge/__tests__/Badge.test.jsx +++ b/src/components/Badge/__tests__/Badge.test.jsx @@ -3,7 +3,8 @@ import { render, within, } from '@testing-library/react'; -import { colorPropTest } from '../../../../tests/propTests/colorPropTest'; +import { feedbackColorPropTest } from '../../../../tests/propTests/feedbackColorPropTest'; +import { neutralColorPropTest } from '../../../../tests/propTests/neutralColorPropTest'; import { Badge } from '../Badge'; const mandatoryProps = { @@ -12,7 +13,8 @@ const mandatoryProps = { describe('rendering', () => { it.each([ - ...colorPropTest, + ...feedbackColorPropTest, + ...neutralColorPropTest, [ { label: 'label text' }, (rootElement) => expect(within(rootElement).getByText('label text')), diff --git a/src/components/Button/__tests__/Button.test.jsx b/src/components/Button/__tests__/Button.test.jsx index 17a174912..0a5ee0a08 100644 --- a/src/components/Button/__tests__/Button.test.jsx +++ b/src/components/Button/__tests__/Button.test.jsx @@ -7,7 +7,8 @@ import { import userEvent from '@testing-library/user-event'; import { actionColorPropTest } from '../../../../tests/propTests/actionColorPropTest'; import { blockPropTest } from '../../../../tests/propTests/blockPropTest'; -import { colorPropTest } from '../../../../tests/propTests/colorPropTest'; +import { feedbackColorPropTest } from '../../../../tests/propTests/feedbackColorPropTest'; +import { neutralColorPropTest } from '../../../../tests/propTests/neutralColorPropTest'; import { refPropTest } from '../../../../tests/propTests/refPropTest'; import { labelPropTest } from '../../../../tests/propTests/labelPropTest'; import { sizePropTest } from '../../../../tests/propTests/sizePropTest'; @@ -67,7 +68,8 @@ describe('rendering', () => { ], ...actionColorPropTest, ...blockPropTest, - ...colorPropTest, + ...feedbackColorPropTest, + ...neutralColorPropTest, [ { disabled: true }, (rootElement) => expect(rootElement).toBeDisabled(), diff --git a/src/components/Card/__tests__/Card.test.jsx b/src/components/Card/__tests__/Card.test.jsx index bee505efa..3b9029932 100644 --- a/src/components/Card/__tests__/Card.test.jsx +++ b/src/components/Card/__tests__/Card.test.jsx @@ -3,7 +3,8 @@ import { render, within, } from '@testing-library/react'; -import { colorPropTest } from '../../../../tests/propTests/colorPropTest'; +import { feedbackColorPropTest } from '../../../../tests/propTests/feedbackColorPropTest'; +import { neutralColorPropTest } from '../../../../tests/propTests/neutralColorPropTest'; import { raisedPropTest } from '../../../../tests/propTests/raisedPropTest'; import { ScrollView } from '../../ScrollView'; import { Card } from '../Card'; @@ -33,7 +34,8 @@ describe('rendering', () => { { children: scroll view content }, (rootElement) => expect(within(rootElement).getByText('scroll view content')), ], - ...colorPropTest, + ...feedbackColorPropTest, + ...neutralColorPropTest, ...densePropTest('Root'), [ { disabled: true }, diff --git a/tests/propTests/colorPropTest.js b/tests/propTests/feedbackColorPropTest.js similarity index 72% rename from tests/propTests/colorPropTest.js rename to tests/propTests/feedbackColorPropTest.js index 0c47eec4a..ff8662ee6 100644 --- a/tests/propTests/colorPropTest.js +++ b/tests/propTests/feedbackColorPropTest.js @@ -1,8 +1,4 @@ -export const colorPropTest = [ - [ - { color: 'dark' }, - (rootElement) => expect(rootElement).toHaveClass('isRootColorDark'), - ], +export const feedbackColorPropTest = [ [ { color: 'danger' }, (rootElement) => expect(rootElement).toHaveClass('isRootColorDanger'), @@ -15,10 +11,6 @@ export const colorPropTest = [ { color: 'info' }, (rootElement) => expect(rootElement).toHaveClass('isRootColorInfo'), ], - [ - { color: 'light' }, - (rootElement) => expect(rootElement).toHaveClass('isRootColorLight'), - ], [ { color: 'note' }, (rootElement) => expect(rootElement).toHaveClass('isRootColorNote'), diff --git a/tests/propTests/neutralColorPropTest.js b/tests/propTests/neutralColorPropTest.js new file mode 100644 index 000000000..3d5d294fc --- /dev/null +++ b/tests/propTests/neutralColorPropTest.js @@ -0,0 +1,10 @@ +export const neutralColorPropTest = [ + [ + { color: 'dark' }, + (rootElement) => expect(rootElement).toHaveClass('isRootColorDark'), + ], + [ + { color: 'light' }, + (rootElement) => expect(rootElement).toHaveClass('isRootColorLight'), + ], +]; From 7412ff5bd721641aa12be3ba298a85f7d4ffc28e Mon Sep 17 00:00:00 2001 From: Adam Kudrna Date: Sat, 31 Aug 2024 16:34:28 +0200 Subject: [PATCH 08/15] Introduce theming of `Badge` color variants `Badge` color variants are now generated using color collections. Other components to be styled the same way already support theming, so `Badge` needs to support theming too. New theming options: `--rui-Badge----__` See `theme.scss` for all available options. --- src/components/Badge/Badge.jsx | 3 +- src/components/Badge/Badge.module.scss | 97 +++++++------------------- src/components/Badge/README.md | 21 +++++- src/components/Badge/_settings.scss | 8 +++ src/styles/tools/_collections.scss | 36 ++++++++++ src/styles/tools/_string.scss | 7 +- src/theme.scss | 64 +++++++++++++++++ 7 files changed, 160 insertions(+), 76 deletions(-) create mode 100644 src/components/Badge/_settings.scss create mode 100644 src/styles/tools/_collections.scss diff --git a/src/components/Badge/Badge.jsx b/src/components/Badge/Badge.jsx index ef841489c..653938fff 100644 --- a/src/components/Badge/Badge.jsx +++ b/src/components/Badge/Badge.jsx @@ -32,7 +32,8 @@ Badge.defaultProps = { Badge.propTypes = { /** - * [Color variant](/docs/foundation/colors#component-colors) to clarify importance and meaning of the badge. + * Color to clarify importance and meaning of the badge. Implements + * [Feedback and Neutral color collections](/docs/foundation/collections#colors). */ color: PropTypes.oneOf(['success', 'warning', 'danger', 'help', 'info', 'note', 'light', 'dark']), /** diff --git a/src/components/Badge/Badge.module.scss b/src/components/Badge/Badge.module.scss index 1949d9378..7e57d903d 100644 --- a/src/components/Badge/Badge.module.scss +++ b/src/components/Badge/Badge.module.scss @@ -2,14 +2,14 @@ @use "sass:math"; @use "../../styles/theme/borders"; @use "../../styles/theme/typography"; - -$_badge-size: 1.25rem; +@use "../../styles/tools/collections"; +@use "settings"; @layer components.badge { .root { display: inline-block; - min-width: $_badge-size; - height: $_badge-size; + min-width: settings.$badge-size; + height: settings.$badge-size; padding: 0.25rem 0.35rem; overflow: hidden; font-weight: map.get(typography.$font-weight-values, bold); @@ -19,7 +19,7 @@ $_badge-size: 1.25rem; white-space: nowrap; vertical-align: baseline; color: var(--rui-local-color); - border-radius: math.div($_badge-size, 2); + border-radius: math.div(settings.$badge-size, 2); } .isRootPriorityFilled { @@ -27,45 +27,20 @@ $_badge-size: 1.25rem; box-shadow: var(--rui-local-box-shadow, #{0 0 0 2px rgb(255 255 255 / 80%)}); } - .isRootColorSuccess { - --rui-local-color: var(--rui-color-feedback-on-success); - --rui-local-background-color: var(--rui-color-feedback-success); - } - - .isRootColorWarning { - --rui-local-color: var(--rui-color-feedback-on-warning); - --rui-local-background-color: var(--rui-color-feedback-warning); - } - - .isRootColorDanger { - --rui-local-color: var(--rui-color-feedback-on-danger); - --rui-local-background-color: var(--rui-color-feedback-danger); - } - - .isRootColorHelp { - --rui-local-color: var(--rui-color-feedback-on-help); - --rui-local-background-color: var(--rui-color-feedback-help); - } - - .isRootColorInfo { - --rui-local-color: var(--rui-color-feedback-on-info); - --rui-local-background-color: var(--rui-color-feedback-info); - } - - .isRootColorNote { - --rui-local-color: var(--rui-color-feedback-on-note); - --rui-local-background-color: var(--rui-color-feedback-note); - } - - .isRootColorLight { - --rui-local-color: var(--rui-color-neutral-on-light); - --rui-local-background-color: var(--rui-color-neutral-light); - --rui-local-box-shadow: none; + @each $color in settings.$colors { + @include collections.generate-properties( + $prefix: "rui-", + $component-name: "Badge", + $modifier-name: "priority", + $modifier-value: "filled", + $variant-name: "color", + $variant-value: $color, + $properties: settings.$themeable-properties-filled, + ); } + .isRootColorLight, .isRootColorDark { - --rui-local-color: var(--rui-color-neutral-on-dark); - --rui-local-background-color: var(--rui-color-neutral-dark); --rui-local-box-shadow: none; } @@ -75,35 +50,15 @@ $_badge-size: 1.25rem; border: borders.$width solid currentcolor; } - .isRootPriorityOutline.isRootColorSuccess { - --rui-local-color: var(--rui-color-feedback-success); - } - - .isRootPriorityOutline.isRootColorWarning { - --rui-local-color: var(--rui-color-feedback-warning); - } - - .isRootPriorityOutline.isRootColorDanger { - --rui-local-color: var(--rui-color-feedback-danger); - } - - .isRootPriorityOutline.isRootColorHelp { - --rui-local-color: var(--rui-color-feedback-help); - } - - .isRootPriorityOutline.isRootColorInfo { - --rui-local-color: var(--rui-color-feedback-info); - } - - .isRootPriorityOutline.isRootColorNote { - --rui-local-color: var(--rui-color-feedback-note); - } - - .isRootPriorityOutline.isRootColorLight { - --rui-local-color: var(--rui-color-neutral-light); - } - - .isRootPriorityOutline.isRootColorDark { - --rui-local-color: var(--rui-color-neutral-dark); + @each $color in settings.$colors { + @include collections.generate-properties( + $prefix: "rui-", + $component-name: "Badge", + $modifier-name: "priority", + $modifier-value: "outline", + $variant-name: "color", + $variant-value: $color, + $properties: settings.$themeable-properties-outline, + ); } } diff --git a/src/components/Badge/README.md b/src/components/Badge/README.md index 84f343d25..ceec6fed9 100644 --- a/src/components/Badge/README.md +++ b/src/components/Badge/README.md @@ -29,8 +29,9 @@ lowest: 1. filled 2. outline -All priorities come in supported -[component colors](/docs/foundation/colors#component-colors). +All priorities are available in colors from supported +[color collections](/docs/foundation/collections#colors). +Check [API](#api) to see which collections are supported. ### Filled @@ -102,5 +103,21 @@ helps to improve its accessibility. +## Theming + +It's possible to adjust the theme of specific badge color variant. Naming +convention looks as follows: + +`--rui-Badge----__` + +Where: + +- `` is one of `filled` or `outline`, +- `` is a value from supported + [color collections](/docs/foundation/collections#colors) + (check [API](#api) to see which collections are supported), +- `` is one of `color` (color of text) or `background-color` for the + filled priority, or just `color` for the outline priority. + [div-attributes]: https://developer.mozilla.org/en-US/docs/Web/HTML/Element/div#attributes [React common props]: https://react.dev/reference/react-dom/components/common#common-props diff --git a/src/components/Badge/_settings.scss b/src/components/Badge/_settings.scss new file mode 100644 index 000000000..294181de4 --- /dev/null +++ b/src/components/Badge/_settings.scss @@ -0,0 +1,8 @@ +@use "sass:list"; +@use "../../styles/settings/collections"; + +$badge-size: 1.25rem; + +$colors: list.join(collections.$feedback-colors, collections.$neutral-colors); +$themeable-properties-filled: color, background-color; +$themeable-properties-outline: color; diff --git a/src/styles/tools/_collections.scss b/src/styles/tools/_collections.scss new file mode 100644 index 000000000..2d5573986 --- /dev/null +++ b/src/styles/tools/_collections.scss @@ -0,0 +1,36 @@ +@use "string" as rui-string; + +@mixin generate-properties( + $prefix, + $component-name, + $modifier-name: null, + $modifier-value: null, + $variant-name, + $variant-value, + $properties, +) { + $combined-class-name: + if( + $modifier-name and $modifier-value, + ".isRoot#{rui-string.capitalize($modifier-name)}#{rui-string.capitalize($modifier-value)}", + "" + ); + + #{$combined-class-name}.isRoot#{rui-string.capitalize($variant-name)}#{rui-string.capitalize($variant-value)} { + @each $property in $properties { + --#{$prefix}local-#{$property}: + var( + #{ + "--" + + $prefix + + $component-name + + if($modifier-value, "--" + $modifier-value, "") + + "--" + + $variant-value + + "__" + + $property + } + ); + } + } +} diff --git a/src/styles/tools/_string.scss b/src/styles/tools/_string.scss index f0dde40c1..b8dc32b9a 100644 --- a/src/styles/tools/_string.scss +++ b/src/styles/tools/_string.scss @@ -1,7 +1,10 @@ -// Author: Hugo Giraudel - @use "sass:string"; +@function capitalize($string) { + @return string.to-upper-case(string.slice($string, 1, 1)) + string.slice($string, 2); +} + +// Author: Hugo Giraudel @function replace($string, $search, $replace: "") { $index: string.index($string, $search); diff --git a/src/theme.scss b/src/theme.scss index ae0ebb513..d7537a63f 100644 --- a/src/theme.scss +++ b/src/theme.scss @@ -306,6 +306,70 @@ --rui-Alert--dark__foreground-color: var(--rui-color-neutral-on-dark); --rui-Alert--dark__background-color: var(--rui-color-background-dark); + // + // Badge + // ===== + + // Badge: filled priority + + // Badge: filled priority: success variant + --rui-Badge--filled--success__color: var(--rui-color-feedback-on-success); + --rui-Badge--filled--success__background-color: var(--rui-color-feedback-success); + + // Badge: filled priority: warning variant + --rui-Badge--filled--warning__color: var(--rui-color-feedback-on-warning); + --rui-Badge--filled--warning__background-color: var(--rui-color-feedback-warning); + + // Badge: filled priority: danger variant + --rui-Badge--filled--danger__color: var(--rui-color-feedback-on-danger); + --rui-Badge--filled--danger__background-color: var(--rui-color-feedback-danger); + + // Badge: filled priority: help variant + --rui-Badge--filled--help__color: var(--rui-color-feedback-on-help); + --rui-Badge--filled--help__background-color: var(--rui-color-feedback-help); + + // Badge: filled priority: info variant + --rui-Badge--filled--info__color: var(--rui-color-feedback-on-info); + --rui-Badge--filled--info__background-color: var(--rui-color-feedback-info); + + // Badge: filled priority: note variant + --rui-Badge--filled--note__color: var(--rui-color-feedback-on-note); + --rui-Badge--filled--note__background-color: var(--rui-color-feedback-note); + + // Badge: filled priority: light variant + --rui-Badge--filled--light__color: var(--rui-color-neutral-on-light); + --rui-Badge--filled--light__background-color: var(--rui-color-neutral-light); + + // Badge: filled priority: dark variant + --rui-Badge--filled--dark__color: var(--rui-color-neutral-on-dark); + --rui-Badge--filled--dark__background-color: var(--rui-color-neutral-dark); + + // Badge: outline priority + + // Badge: outline priority: success variant + --rui-Badge--outline--success__color: var(--rui-color-feedback-success); + + // Badge: outline priority: warning variant + --rui-Badge--outline--warning__color: var(--rui-color-feedback-warning); + + // Badge: outline priority: danger variant + --rui-Badge--outline--danger__color: var(--rui-color-feedback-danger); + + // Badge: outline priority: help variant + --rui-Badge--outline--help__color: var(--rui-color-feedback-help); + + // Badge: outline priority: info variant + --rui-Badge--outline--info__color: var(--rui-color-feedback-info); + + // Badge: outline priority: note variant + --rui-Badge--outline--note__color: var(--rui-color-feedback-note); + + // Badge: outline priority: light variant + --rui-Badge--outline--light__color: var(--rui-color-neutral-light); + + // Badge: outline priority: dark variant + --rui-Badge--outline--dark__color: var(--rui-color-neutral-dark); + // // Button // ====== From 42a72838702ccb78b179a7e87057b62c543317b6 Mon Sep 17 00:00:00 2001 From: Adam Kudrna Date: Sat, 31 Aug 2024 17:15:55 +0200 Subject: [PATCH 09/15] Use collections to generate styles of `Alert` color variants --- src/components/Alert/Alert.jsx | 3 +- src/components/Alert/Alert.module.scss | 40 ++++++------------------ src/components/Alert/README.md | 11 ++++--- src/components/Alert/_settings.scss | 5 +++ src/components/Alert/_theme.scss | 43 -------------------------- src/components/Alert/_tools.scss | 10 ------ 6 files changed, 22 insertions(+), 90 deletions(-) delete mode 100644 src/components/Alert/_tools.scss diff --git a/src/components/Alert/Alert.jsx b/src/components/Alert/Alert.jsx index d07852e23..34bf8623c 100644 --- a/src/components/Alert/Alert.jsx +++ b/src/components/Alert/Alert.jsx @@ -70,7 +70,8 @@ Alert.propTypes = { */ children: PropTypes.node.isRequired, /** - * [Color variant](/docs/foundation/colors#component-colors) to clarify importance and meaning of the alert. + * Color variant to clarify importance and meaning of the alert. Implements + * [Feedback and Neutral color collections](/docs/foundation/collections#colors). */ color: PropTypes.oneOf(['success', 'warning', 'danger', 'help', 'info', 'note', 'light', 'dark']), /** diff --git a/src/components/Alert/Alert.module.scss b/src/components/Alert/Alert.module.scss index 285e7476d..b2a8f9b95 100644 --- a/src/components/Alert/Alert.module.scss +++ b/src/components/Alert/Alert.module.scss @@ -1,10 +1,10 @@ @use "sass:map"; @use "../../styles/theme/typography"; @use "../../styles/tools/accessibility"; +@use "../../styles/tools/collections"; @use "../../styles/tools/reset"; @use "settings"; @use "theme"; -@use "tools"; @layer components.alert { .root { @@ -66,35 +66,13 @@ top: -0.1em; } - .isRootColorSuccess { - @include tools.color(success); - } - - .isRootColorWarning { - @include tools.color(warning); - } - - .isRootColorDanger { - @include tools.color(danger); - } - - .isRootColorHelp { - @include tools.color(help); - } - - .isRootColorInfo { - @include tools.color(info); - } - - .isRootColorNote { - @include tools.color(note); - } - - .isRootColorLight { - @include tools.color(light); - } - - .isRootColorDark { - @include tools.color(dark); + @each $color in settings.$colors { + @include collections.generate-properties( + $prefix: "rui-", + $component-name: "Alert", + $variant-name: "color", + $variant-value: $color, + $properties: settings.$themeable-properties, + ); } } diff --git a/src/components/Alert/README.md b/src/components/Alert/README.md index 5abf8452b..befc886e3 100644 --- a/src/components/Alert/README.md +++ b/src/components/Alert/README.md @@ -31,8 +31,8 @@ See [API](#api) for all available options. ## Color Variants -All [component colors](/docs/foundation/colors#component-colors) are supported by -alert to cover all possible needs of your project. +To cover all possible needs of your project, Alert is available in colors from +[Feedback and Neutral color collections](/docs/foundation/collections#colors). ### Success @@ -208,9 +208,10 @@ convention looks as follows: Where: -- `` is one of supported - [component colors](/docs/foundation/colors#component-colors) - (see alert [color variants](#color-variants) and [API](#api)), +- `` is a value from supported + [color collections](/docs/foundation/collections#colors) + (check [color variants](#color-variants) and [API](#api) to see which + collections are supported), - `` is one of `color` (color of text), `foreground-color` (color of border, icon, links, and emphasis), or `background-color`. diff --git a/src/components/Alert/_settings.scss b/src/components/Alert/_settings.scss index 036e8a37b..b7ab4487e 100644 --- a/src/components/Alert/_settings.scss +++ b/src/components/Alert/_settings.scss @@ -1,7 +1,12 @@ +@use "sass:list"; @use "sass:map"; +@use "../../styles/settings/collections"; @use "../../styles/theme/typography"; @use "theme"; $font-size: map.get(typography.$font-size-values, 1); $line-height: typography.$line-height-base; $min-height: calc(#{$font-size} * #{$line-height} + 2 * #{theme.$padding}); + +$colors: list.join(collections.$feedback-colors, collections.$neutral-colors); +$themeable-properties: color, foreground-color, background-color; diff --git a/src/components/Alert/_theme.scss b/src/components/Alert/_theme.scss index 208ed6fce..8dc449e4f 100644 --- a/src/components/Alert/_theme.scss +++ b/src/components/Alert/_theme.scss @@ -4,46 +4,3 @@ $border-width: var(--rui-Alert__border-width); $border-radius: var(--rui-Alert__border-radius); $emphasis-font-weight: var(--rui-Alert__emphasis__font-weight); $stripe-width: var(--rui-Alert__stripe__width); - -$colors: ( - success: ( - color: var(--rui-Alert--success__color), - foreground-color: var(--rui-Alert--success__foreground-color), - background-color: var(--rui-Alert--success__background-color), - ), - warning: ( - color: var(--rui-Alert--warning__color), - foreground-color: var(--rui-Alert--warning__foreground-color), - background-color: var(--rui-Alert--warning__background-color), - ), - danger: ( - color: var(--rui-Alert--danger__color), - foreground-color: var(--rui-Alert--danger__foreground-color), - background-color: var(--rui-Alert--danger__background-color), - ), - info: ( - color: var(--rui-Alert--info__color), - foreground-color: var(--rui-Alert--info__foreground-color), - background-color: var(--rui-Alert--info__background-color), - ), - help: ( - color: var(--rui-Alert--help__color), - foreground-color: var(--rui-Alert--help__foreground-color), - background-color: var(--rui-Alert--help__background-color), - ), - note: ( - color: var(--rui-Alert--note__color), - foreground-color: var(--rui-Alert--note__foreground-color), - background-color: var(--rui-Alert--note__background-color), - ), - light: ( - color: var(--rui-Alert--light__color), - foreground-color: var(--rui-Alert--light__foreground-color), - background-color: var(--rui-Alert--light__background-color), - ), - dark: ( - color: var(--rui-Alert--dark__color), - foreground-color: var(--rui-Alert--dark__foreground-color), - background-color: var(--rui-Alert--dark__background-color), - ), -); diff --git a/src/components/Alert/_tools.scss b/src/components/Alert/_tools.scss deleted file mode 100644 index 0608c9624..000000000 --- a/src/components/Alert/_tools.scss +++ /dev/null @@ -1,10 +0,0 @@ -@use "sass:map"; -@use "theme"; - -@mixin color($color) { - $color-variant-properties: map.get(theme.$colors, $color); - - --rui-local-color: #{map.get($color-variant-properties, color)}; - --rui-local-foreground-color: #{map.get($color-variant-properties, foreground-color)}; - --rui-local-background-color: #{map.get($color-variant-properties, background-color)}; -} From 57f136eb826d450a0fec68d941a5c57eea2a84a5 Mon Sep 17 00:00:00 2001 From: Adam Kudrna Date: Sat, 31 Aug 2024 17:35:03 +0200 Subject: [PATCH 10/15] Use collections to generate styles of `Card` color variants --- src/components/Card/Card.jsx | 3 +- src/components/Card/Card.module.scss | 41 +++++++------------------- src/components/Card/README.md | 12 ++++---- src/components/Card/_settings.scss | 5 ++++ src/components/Card/_theme.scss | 43 ---------------------------- src/components/Card/_tools.scss | 10 ------- 6 files changed, 23 insertions(+), 91 deletions(-) create mode 100644 src/components/Card/_settings.scss delete mode 100644 src/components/Card/_tools.scss diff --git a/src/components/Card/Card.jsx b/src/components/Card/Card.jsx index 074ade486..8616ee555 100644 --- a/src/components/Card/Card.jsx +++ b/src/components/Card/Card.jsx @@ -44,7 +44,8 @@ Card.propTypes = { */ children: PropTypes.node.isRequired, /** - * [Color variant](/docs/foundation/colors#component-colors) to clarify importance and meaning of the card. + * Color to clarify importance and meaning of the card. Implements + * [Feedback and Neutral color collections](/docs/foundation/collections#colors). */ color: PropTypes.oneOf(['success', 'warning', 'danger', 'help', 'info', 'note', 'light', 'dark']), /** diff --git a/src/components/Card/Card.module.scss b/src/components/Card/Card.module.scss index 046c9be34..da432403c 100644 --- a/src/components/Card/Card.module.scss +++ b/src/components/Card/Card.module.scss @@ -1,7 +1,8 @@ // 1. Retain equal card widths in flex and grid layouts independently on their content. +@use "../../styles/tools/collections"; +@use "settings"; @use "theme"; -@use "tools"; @layer components.card { .root { @@ -33,36 +34,14 @@ box-shadow: theme.$raised-box-shadow; } - .isRootColorSuccess { - @include tools.color(success); - } - - .isRootColorWarning { - @include tools.color(warning); - } - - .isRootColorDanger { - @include tools.color(danger); - } - - .isRootColorHelp { - @include tools.color(help); - } - - .isRootColorInfo { - @include tools.color(info); - } - - .isRootColorNote { - @include tools.color(note); - } - - .isRootColorLight { - @include tools.color(light); - } - - .isRootColorDark { - @include tools.color(dark); + @each $color in settings.$colors { + @include collections.generate-properties( + $prefix: "rui-", + $component-name: "Card", + $variant-name: "color", + $variant-value: $color, + $properties: settings.$themeable-properties, + ); } .isRootDisabled { diff --git a/src/components/Card/README.md b/src/components/Card/README.md index b77aac764..1604f5199 100644 --- a/src/components/Card/README.md +++ b/src/components/Card/README.md @@ -147,9 +147,8 @@ for card content. ## Color Variants -Card supports all -[component colors](/docs/foundation/colors#component-colors) to cover different needs -of your app. +To cover all possible needs of your project, Card is available in colors from +[Feedback and Neutral color collections](/docs/foundation/collections#colors). ```docoff-react-preview @@ -307,9 +306,10 @@ looks as follows: Where: -- `` is one of supported - [component colors](/docs/foundation/colors#component-colors) - (see [color variants](#color-variants) and [API](#api)), +- `` is a value from supported + [color collections](/docs/foundation/collections#colors) + (check [color variants](#color-variants) and [API](#api) to see which + collections are supported), - `` is one of `color` (color of text), `border-color`, or `background-color`. diff --git a/src/components/Card/_settings.scss b/src/components/Card/_settings.scss new file mode 100644 index 000000000..c055c8b49 --- /dev/null +++ b/src/components/Card/_settings.scss @@ -0,0 +1,5 @@ +@use "sass:list"; +@use "../../styles/settings/collections"; + +$colors: list.join(collections.$feedback-colors, collections.$neutral-colors); +$themeable-properties: color, border-color, background-color; diff --git a/src/components/Card/_theme.scss b/src/components/Card/_theme.scss index a5f08b1c3..819da99fb 100644 --- a/src/components/Card/_theme.scss +++ b/src/components/Card/_theme.scss @@ -7,46 +7,3 @@ $raised-box-shadow: var(--rui-Card--raised__box-shadow); $disabled-background-color: var(--rui-Card--disabled__background-color); $disabled-opacity: var(--rui-Card--disabled__opacity); - -$colors: ( - success: ( - color: var(--rui-Card--success__color), - border-color: var(--rui-Card--success__border-color), - background-color: var(--rui-Card--success__background-color), - ), - warning: ( - color: var(--rui-Card--warning__color), - border-color: var(--rui-Card--warning__border-color), - background-color: var(--rui-Card--warning__background-color), - ), - danger: ( - color: var(--rui-Card--danger__color), - border-color: var(--rui-Card--danger__border-color), - background-color: var(--rui-Card--danger__background-color), - ), - info: ( - color: var(--rui-Card--info__color), - border-color: var(--rui-Card--info__border-color), - background-color: var(--rui-Card--info__background-color), - ), - help: ( - color: var(--rui-Card--help__color), - border-color: var(--rui-Card--help__border-color), - background-color: var(--rui-Card--help__background-color), - ), - note: ( - color: var(--rui-Card--note__color), - border-color: var(--rui-Card--note__border-color), - background-color: var(--rui-Card--note__background-color), - ), - light: ( - color: var(--rui-Card--light__color), - border-color: var(--rui-Card--light__border-color), - background-color: var(--rui-Card--light__background-color), - ), - dark: ( - color: var(--rui-Card--dark__color), - border-color: var(--rui-Card--dark__border-color), - background-color: var(--rui-Card--dark__background-color), - ), -); diff --git a/src/components/Card/_tools.scss b/src/components/Card/_tools.scss deleted file mode 100644 index ee155fc9a..000000000 --- a/src/components/Card/_tools.scss +++ /dev/null @@ -1,10 +0,0 @@ -@use "sass:map"; -@use "theme"; - -@mixin color($color) { - $color-variant-properties: map.get(theme.$colors, $color); - - --rui-local-color: #{map.get($color-variant-properties, color)}; - --rui-local-border-color: #{map.get($color-variant-properties, border-color)}; - --rui-local-background-color: #{map.get($color-variant-properties, background-color)}; -} From c104d823ce67b6ad59e0b9da1353cd0f8b099ea2 Mon Sep 17 00:00:00 2001 From: Adam Kudrna Date: Sat, 31 Aug 2024 23:30:33 +0200 Subject: [PATCH 11/15] Use collections to generate styles of `Button` color variants --- src/components/Alert/Alert.module.scss | 2 +- src/components/Badge/Badge.module.scss | 4 +- src/components/Button/Button.jsx | 3 +- src/components/Button/Button.module.scss | 185 +++++++++++++++++++++- src/components/Button/README.md | 14 +- src/components/Button/_base.scss | 156 ------------------- src/components/Button/_priorities.scss | 149 ------------------ src/components/Button/_settings.scss | 11 +- src/components/Button/_theme.scss | 3 - src/components/Button/_tools.scss | 78 +--------- src/components/Card/Card.module.scss | 2 +- src/styles/tools/_collections.scss | 187 +++++++++++++++++++++-- 12 files changed, 383 insertions(+), 411 deletions(-) delete mode 100644 src/components/Button/_base.scss delete mode 100644 src/components/Button/_priorities.scss diff --git a/src/components/Alert/Alert.module.scss b/src/components/Alert/Alert.module.scss index b2a8f9b95..cd8c2b725 100644 --- a/src/components/Alert/Alert.module.scss +++ b/src/components/Alert/Alert.module.scss @@ -67,7 +67,7 @@ } @each $color in settings.$colors { - @include collections.generate-properties( + @include collections.generate-class( $prefix: "rui-", $component-name: "Alert", $variant-name: "color", diff --git a/src/components/Badge/Badge.module.scss b/src/components/Badge/Badge.module.scss index 7e57d903d..d63d1ec6c 100644 --- a/src/components/Badge/Badge.module.scss +++ b/src/components/Badge/Badge.module.scss @@ -28,7 +28,7 @@ } @each $color in settings.$colors { - @include collections.generate-properties( + @include collections.generate-class( $prefix: "rui-", $component-name: "Badge", $modifier-name: "priority", @@ -51,7 +51,7 @@ } @each $color in settings.$colors { - @include collections.generate-properties( + @include collections.generate-class( $prefix: "rui-", $component-name: "Badge", $modifier-name: "priority", diff --git a/src/components/Button/Button.jsx b/src/components/Button/Button.jsx index 3fa732fcb..c934f13e1 100644 --- a/src/components/Button/Button.jsx +++ b/src/components/Button/Button.jsx @@ -133,7 +133,8 @@ Button.propTypes = { */ block: PropTypes.bool, /** - * [Color variant](/docs/foundation/colors#component-colors) to clarify importance and meaning of the button. + * Color variant to clarify importance and meaning of the alert. Implements + * [Action, Feedback and Neutral color collections](/docs/foundation/collections#colors). */ color: PropTypes.oneOf( ['primary', 'secondary', 'selected', 'success', 'warning', 'danger', 'help', 'info', 'note', 'light', 'dark'], diff --git a/src/components/Button/Button.module.scss b/src/components/Button/Button.module.scss index 91d5b61f3..7eb9b06b2 100644 --- a/src/components/Button/Button.module.scss +++ b/src/components/Button/Button.module.scss @@ -1,2 +1,183 @@ -@use "base"; -@use "priorities"; +// 1. ButtonGroup gap is implemented using the `margin` property so the buttons can overlap and reduce duplicate +// borders. + +@use "sass:map"; +@use "../../styles/tools/breakpoint"; +@use "../../styles/tools/collections"; +@use "settings"; +@use "theme"; +@use "tools"; + +@layer components.button { + .root { + @include tools.button(); + } + + .label { + display: block; + } + + .beforeLabel, + .afterLabel, + .startCorner, + .endCorner, + .feedbackIcon { + display: flex; + align-items: baseline; + justify-content: center; + } + + .startCorner, + .endCorner { + position: absolute; + top: -0.35rem; + z-index: 2; + } + + .startCorner { + left: 0; + margin-left: -0.35rem; + } + + .endCorner { + right: 0; + margin-right: -0.35rem; + } + + .feedbackIcon { + position: absolute; + inset: 0; + z-index: 1; + align-items: center; + } + + .isRootSizeSmall { + @include tools.button-size(small); + } + + .isRootSizeMedium { + @include tools.button-size(medium); + } + + .isRootSizeLarge { + @include tools.button-size(large); + } + + .isRootBlock { + width: 100%; + } + + .hasRootFeedback:disabled { + opacity: theme.$feedback-opacity; + cursor: theme.$feedback-cursor; + } + + .hasRootFeedback .label, + .hasRootFeedback .beforeLabel, + .hasRootFeedback .afterLabel { + color: transparent; + } + + .isRootInButtonGroup, + .isRootInInputGroup { + z-index: map.get(settings.$group-z-indexes, button); + + &:not(:first-child) { + border-start-start-radius: var(--rui-local-inner-border-radius); + border-end-start-radius: var(--rui-local-inner-border-radius); + } + + &:not(:last-child) { + border-start-end-radius: var(--rui-local-inner-border-radius); + border-end-end-radius: var(--rui-local-inner-border-radius); + } + } + + .isRootInButtonGroup:not(:first-child) { + margin-inline-start: var(--rui-local-gap); // 1. + + &::before { + content: ""; + position: absolute; + top: calc(-1 * #{theme.$border-width}); + bottom: calc(-1 * #{theme.$border-width}); + left: calc(-1 * #{theme.$border-width}); + z-index: map.get(settings.$group-z-indexes, separator); + border-left: var(--rui-local-separator-width) solid var(--rui-local-separator-color); + transform: translateX(calc(-0.5 * var(--rui-local-gap) - 50%)); + } + } + + .isRootInButtonGroup:focus, + .isRootInButtonGroup:not(:disabled):hover { + z-index: map.get(settings.$group-z-indexes, button-hover); + } + + .isRootInButtonGroup .startCorner, + .isRootInInputGroup .startCorner, + .isRootInButtonGroup .endCorner, + .isRootInInputGroup .endCorner { + z-index: map.get(settings.$group-z-indexes, button-overflowing-elements); + } + + .hasLabelHidden, + .hasLabelVisibleSm, + .hasLabelVisibleMd, + .hasLabelVisibleLg, + .hasLabelVisibleXl, + .hasLabelVisibleX2l, + .hasLabelVisibleX3l { + @include tools.hide-label(); + } + + .hasLabelVisibleSm { + @include breakpoint.up(sm) { + @include tools.show-label(); + } + } + + .hasLabelVisibleMd { + @include breakpoint.up(md) { + @include tools.show-label(); + } + } + + .hasLabelVisibleLg { + @include breakpoint.up(lg) { + @include tools.show-label(); + } + } + + .hasLabelVisibleXl { + @include breakpoint.up(xl) { + @include tools.show-label(); + } + } + + .hasLabelVisibleX2l { + @include breakpoint.up(x2l) { + @include tools.show-label(); + } + } + + .hasLabelVisibleX3l { + @include breakpoint.up(x3l) { + @include tools.show-label(); + } + } + + @each $priority in map.keys(settings.$themeable-properties) { + @each $color in settings.$colors { + @include collections.generate-class( + $prefix: "rui-", + $component-name: "Button", + $modifier-name: "priority", + $modifier-value: $priority, + $variant-name: "color", + $variant-value: $color, + $generate-interaction-states: true, + $properties: map.get(settings.$themeable-properties, $priority), + ); + } + } +} diff --git a/src/components/Button/README.md b/src/components/Button/README.md index 7e43d5096..be732e6a7 100644 --- a/src/components/Button/README.md +++ b/src/components/Button/README.md @@ -40,8 +40,9 @@ lowest: 2. outline 3. flat -All priorities come in supported -[component colors](/docs/foundation/colors#component-colors). +All priorities are available in colors from supported +[color collections](/docs/foundation/collections#colors). +Check [API](#api) to see which collections are supported. ### Filled @@ -257,7 +258,7 @@ Disabled state makes the action unavailable. When user's action triggers an asynchronous process on background, the button's feedback state (not to be mistaken with -[feedback colors](/docs/foundation/colors#component-colors)) can be indicated by +[feedback colors](/docs/foundation/colors#feedback-colors)) can be indicated by showing an icon. The icon replaces button's label while retaining original dimensions of the button. Buttons in feedback state are automatically disabled to prevent unwanted interaction. @@ -431,9 +432,10 @@ Where: - `` is one of `filled`, `outline`, or `flat` (see [Priorities](#priorities) and [API](#api)), -- `` is one of supported - [component colors](/docs/foundation/colors#component-colors) - (see color variants of [each priority](#priorities) and [API](#api)), +- `` is a value from supported + [color collections](/docs/foundation/collections#colors) + (check color variants of [each priority](#priorities) and [API](#api) to see + which collections are supported), - `` is one of `default`, `hover`, `active`, or `disabled` (the last one being optional), - `` is one of: diff --git a/src/components/Button/_base.scss b/src/components/Button/_base.scss deleted file mode 100644 index 7c2648ac4..000000000 --- a/src/components/Button/_base.scss +++ /dev/null @@ -1,156 +0,0 @@ -// 1. ButtonGroup gap is implemented using the `margin` property so the buttons can overlap and reduce duplicate -// borders. - -@use "sass:map"; -@use "../../styles/tools/breakpoint"; -@use "settings"; -@use "theme"; -@use "tools"; - -@layer components.button { - .root { - @include tools.button(); - } - - .label { - display: block; - } - - .beforeLabel, - .afterLabel, - .startCorner, - .endCorner, - .feedbackIcon { - display: flex; - align-items: baseline; - justify-content: center; - } - - .startCorner, - .endCorner { - position: absolute; - top: -0.35rem; - z-index: 2; - } - - .startCorner { - left: 0; - margin-left: -0.35rem; - } - - .endCorner { - right: 0; - margin-right: -0.35rem; - } - - .feedbackIcon { - position: absolute; - inset: 0; - z-index: 1; - align-items: center; - } - - .isRootSizeSmall { - @include tools.button-size(small); - } - - .isRootSizeMedium { - @include tools.button-size(medium); - } - - .isRootSizeLarge { - @include tools.button-size(large); - } - - .isRootBlock { - width: 100%; - } - - .hasRootFeedback:disabled { - opacity: theme.$feedback-opacity; - cursor: theme.$feedback-cursor; - } - - .hasRootFeedback .label, - .hasRootFeedback .beforeLabel, - .hasRootFeedback .afterLabel { - color: transparent; - } - - .isRootInButtonGroup, - .isRootInInputGroup { - z-index: map.get(settings.$group-z-indexes, button); - - &:not(:first-child) { - border-start-start-radius: var(--rui-local-inner-border-radius); - border-end-start-radius: var(--rui-local-inner-border-radius); - } - - &:not(:last-child) { - border-start-end-radius: var(--rui-local-inner-border-radius); - border-end-end-radius: var(--rui-local-inner-border-radius); - } - } - - .isRootInButtonGroup:not(:first-child) { - margin-inline-start: var(--rui-local-gap); // 1. - } - - .isRootInButtonGroup:focus, - .isRootInButtonGroup:not(:disabled):hover { - z-index: map.get(settings.$group-z-indexes, button-hover); - } - - .isRootInButtonGroup .startCorner, - .isRootInInputGroup .startCorner, - .isRootInButtonGroup .endCorner, - .isRootInInputGroup .endCorner { - z-index: map.get(settings.$group-z-indexes, button-overflowing-elements); - } - - .hasLabelHidden, - .hasLabelVisibleSm, - .hasLabelVisibleMd, - .hasLabelVisibleLg, - .hasLabelVisibleXl, - .hasLabelVisibleX2l, - .hasLabelVisibleX3l { - @include tools.hide-label(); - } - - .hasLabelVisibleSm { - @include breakpoint.up(sm) { - @include tools.show-label(); - } - } - - .hasLabelVisibleMd { - @include breakpoint.up(md) { - @include tools.show-label(); - } - } - - .hasLabelVisibleLg { - @include breakpoint.up(lg) { - @include tools.show-label(); - } - } - - .hasLabelVisibleXl { - @include breakpoint.up(xl) { - @include tools.show-label(); - } - } - - .hasLabelVisibleX2l { - @include breakpoint.up(x2l) { - @include tools.show-label(); - } - } - - .hasLabelVisibleX3l { - @include breakpoint.up(x3l) { - @include tools.show-label(); - } - } -} diff --git a/src/components/Button/_priorities.scss b/src/components/Button/_priorities.scss deleted file mode 100644 index eb94ce6a7..000000000 --- a/src/components/Button/_priorities.scss +++ /dev/null @@ -1,149 +0,0 @@ -@use "sass:map"; -@use "settings"; -@use "theme"; -@use "tools"; - -@layer components.button { - .isRootPriorityFilled.isRootColorPrimary { - @include tools.button-color(filled, primary); - } - - .isRootPriorityFilled.isRootColorSecondary { - @include tools.button-color(filled, secondary); - } - - .isRootPriorityFilled.isRootColorSelected { - @include tools.button-color(filled, selected); - } - - .isRootPriorityFilled.isRootColorSuccess { - @include tools.button-color(filled, success); - } - - .isRootPriorityFilled.isRootColorWarning { - @include tools.button-color(filled, warning); - } - - .isRootPriorityFilled.isRootColorDanger { - @include tools.button-color(filled, danger); - } - - .isRootPriorityFilled.isRootColorHelp { - @include tools.button-color(filled, help); - } - - .isRootPriorityFilled.isRootColorInfo { - @include tools.button-color(filled, info); - } - - .isRootPriorityFilled.isRootColorNote { - @include tools.button-color(filled, note); - } - - .isRootPriorityFilled.isRootColorLight { - @include tools.button-color(filled, light); - } - - .isRootPriorityFilled.isRootColorDark { - @include tools.button-color(filled, dark); - } - - .isRootPriorityOutline.isRootColorPrimary { - @include tools.button-color(outline, primary); - } - - .isRootPriorityOutline.isRootColorSecondary { - @include tools.button-color(outline, secondary); - } - - .isRootPriorityOutline.isRootColorSelected { - @include tools.button-color(outline, selected); - } - - .isRootPriorityOutline.isRootColorSuccess { - @include tools.button-color(outline, success); - } - - .isRootPriorityOutline.isRootColorWarning { - @include tools.button-color(outline, warning); - } - - .isRootPriorityOutline.isRootColorDanger { - @include tools.button-color(outline, danger); - } - - .isRootPriorityOutline.isRootColorHelp { - @include tools.button-color(outline, help); - } - - .isRootPriorityOutline.isRootColorInfo { - @include tools.button-color(outline, info); - } - - .isRootPriorityOutline.isRootColorNote { - @include tools.button-color(outline, note); - } - - .isRootPriorityOutline.isRootColorLight { - @include tools.button-color(outline, light); - } - - .isRootPriorityOutline.isRootColorDark { - @include tools.button-color(outline, dark); - } - - .isRootPriorityFlat.isRootColorPrimary { - @include tools.button-color(flat, primary); - } - - .isRootPriorityFlat.isRootColorSecondary { - @include tools.button-color(flat, secondary); - } - - .isRootPriorityFlat.isRootColorSelected { - @include tools.button-color(flat, selected); - } - - .isRootPriorityFlat.isRootColorSuccess { - @include tools.button-color(flat, success); - } - - .isRootPriorityFlat.isRootColorWarning { - @include tools.button-color(flat, warning); - } - - .isRootPriorityFlat.isRootColorDanger { - @include tools.button-color(flat, danger); - } - - .isRootPriorityFlat.isRootColorHelp { - @include tools.button-color(flat, help); - } - - .isRootPriorityFlat.isRootColorInfo { - @include tools.button-color(flat, info); - } - - .isRootPriorityFlat.isRootColorNote { - @include tools.button-color(flat, note); - } - - .isRootPriorityFlat.isRootColorLight { - @include tools.button-color(flat, light); - } - - .isRootPriorityFlat.isRootColorDark { - @include tools.button-color(flat, dark); - } - - .isRootInButtonGroup:not(:first-child)::before { - content: ""; - position: absolute; - top: calc(-1 * #{theme.$border-width}); - bottom: calc(-1 * #{theme.$border-width}); - left: calc(-1 * #{theme.$border-width}); - z-index: map.get(settings.$group-z-indexes, separator); - border-left: var(--rui-local-separator-width) solid var(--rui-local-separator-color); - transform: translateX(calc(-0.5 * var(--rui-local-gap) - 50%)); - } -} diff --git a/src/components/Button/_settings.scss b/src/components/Button/_settings.scss index 9065491f3..71f3908b3 100644 --- a/src/components/Button/_settings.scss +++ b/src/components/Button/_settings.scss @@ -1,3 +1,5 @@ +@use "sass:list"; +@use "../../styles/settings/collections"; @use "../../styles/theme/typography"; @use "../../styles/tools/spacing"; @@ -12,9 +14,12 @@ $group-z-indexes: ( button-overflowing-elements: 3, ); -$themeable-variants: (primary, secondary, selected, success, warning, danger, help, info, note, light, dark); -$themeable-states: (default, hover, active, disabled); -$themeable-priority-properties: ( +$colors: + list.join( + list.join(collections.$action-colors, collections.$feedback-colors), + collections.$neutral-colors + ); +$themeable-properties: ( filled: (color, border-color, background, box-shadow), outline: (color, border-color, background), flat: (color, background), diff --git a/src/components/Button/_theme.scss b/src/components/Button/_theme.scss index ec62d574d..c5814f954 100644 --- a/src/components/Button/_theme.scss +++ b/src/components/Button/_theme.scss @@ -1,6 +1,3 @@ -// Priority and variant specific theme options are obtained dynamically because there is way too -// many of them to maintain manually. See `_tools.scss` for details. - $font-weight: var(--rui-Button__font-weight); $letter-spacing: var(--rui-Button__letter-spacing); $text-transform: var(--rui-Button__text-transform); diff --git a/src/components/Button/_tools.scss b/src/components/Button/_tools.scss index 4d1932578..70796fabd 100644 --- a/src/components/Button/_tools.scss +++ b/src/components/Button/_tools.scss @@ -1,71 +1,23 @@ -// 1. Due to complexity, it's easier and safer to resolve variant custom properties dynamically with -// a mixin. This way it's also easier to make theming adjustments to all supported modifications -// in one place. This applies to the following button priorities: +// 1. Get ready for position of corner elements and group separator. // -// - filled -// - outline -// - flat +// 2. Icon buttons should appear as squares, that's why width and height is equal here. // -// 2. Disabled state theming is optional so `default` theme options are used if no `disabled` -// styling is provided for specific variant. -// -// 3. Get ready for position of corner elements and group separator. -// -// 4. Icon buttons should appear as squares, that's why width and height is equal here. -// -// 5. Use original padding to restore square buttons back to their size. +// 3. Use original padding to restore square buttons back to their size. @use "sass:list"; @use "sass:map"; -@use "sass:math"; @use "../../styles/tools/accessibility"; -@use "../../styles/tools/breakpoint"; @use "../../styles/tools/transition"; @use "settings"; @use "theme"; -// 1. -@mixin _get-themeable-properties($priority, $color, $state) { - @if not list.index(map.keys(settings.$themeable-priority-properties), $priority) { - @error "Invalid priority specified! #{$priority} doesn't exist. " - + "Choose one of #{settings.$themeable-priority-properties}."; - } - - @if not list.index(settings.$themeable-variants, $color) { - @error "Invalid variant specified! #{$color} doesn't exist. " - + "Choose one of #{settings.$themeable-variants}."; - } - - @if not list.index(settings.$themeable-states, $state) { - @error "Invalid state specified! #{$state} doesn't exist. " - + "Choose one of #{settings.$themeable-states}."; - } - - $properties: map.get(settings.$themeable-priority-properties, $priority); - - // 2. - @if $state == "disabled" { - @each $property in $properties { - --rui-local-#{$property}: - var( - --rui-Button--#{$priority}--#{$color}--#{$state}__#{$property}, - var(--rui-Button--#{$priority}--#{$color}--default__#{$property}) - ); - } - } @else { - @each $property in $properties { - --rui-local-#{$property}: var(--rui-Button--#{$priority}--#{$color}--#{$state}__#{$property}); - } - } -} - -// 4. +// 2. @mixin _button-square() { --rui-local-padding: 0; --rui-local-width: var(--rui-local-height); } -// 5. +// 3. @mixin _button-size-restore() { --rui-local-padding: var(--rui-local-padding-original); --rui-local-width: unset; @@ -74,7 +26,7 @@ @mixin button() { @include transition.add((opacity, color, border-color, background-color, box-shadow)); - position: relative; // 3. + position: relative; // 1. display: inline-flex; column-gap: settings.$icon-spacing; align-items: center; @@ -112,26 +64,10 @@ --rui-local-height: #{map.get($properties, height)}; --rui-local-padding: #{map.get($properties, padding-y)} #{map.get($properties, padding-x)}; - --rui-local-padding-original: #{map.get($properties, padding-y)} #{map.get($properties, padding-x)}; // 5. + --rui-local-padding-original: #{map.get($properties, padding-y)} #{map.get($properties, padding-x)}; // 3. --rui-local-font-size: #{map.get($properties, font-size)}; } -@mixin button-color($priority, $color) { - @include _get-themeable-properties($priority, $color, default); - - &:disabled { - @include _get-themeable-properties($priority, $color, disabled); - } - - &:not(:disabled):hover { - @include _get-themeable-properties($priority, $color, hover); - } - - &:not(:disabled):active { - @include _get-themeable-properties($priority, $color, active); - } -} - @mixin hide-label() { @include _button-square(); diff --git a/src/components/Card/Card.module.scss b/src/components/Card/Card.module.scss index da432403c..03befec54 100644 --- a/src/components/Card/Card.module.scss +++ b/src/components/Card/Card.module.scss @@ -35,7 +35,7 @@ } @each $color in settings.$colors { - @include collections.generate-properties( + @include collections.generate-class( $prefix: "rui-", $component-name: "Card", $variant-name: "color", diff --git a/src/styles/tools/_collections.scss b/src/styles/tools/_collections.scss index 2d5573986..f506a08fd 100644 --- a/src/styles/tools/_collections.scss +++ b/src/styles/tools/_collections.scss @@ -1,36 +1,191 @@ @use "string" as rui-string; +// Mixin to generate CSS custom properties for a set of visual properties. +// +// 1. Generates a CSS custom property for each property in the `$properties` list. +// 2. Theming of the disabled state is optional, so the `default` theme options are used (via CSS custom property +// fallback) if no `disabled` styling for the specific variant is provided by user. +// +// @param {String} $prefix - The prefix for the CSS custom properties. +// @param {String} $component-name - The name of the component. +// @param {String} $modifier-value - The value of the modifier. +// @param {String} $variant-value - The value of the variant. +// @param {String} $interaction-state - The interaction state. +// @param {List} $properties - The list of properties to generate CSS custom properties for. +// +// Example: +// +// @include generate-properties( +// $prefix: "rui-", +// $component-name: "Card", +// $variant-name: "color", +// $variant-value: "success", +// $properties: color, border-color, background-color, +// ); +// +// … will output: +// +// --rui-local-color: var(--rui-Card--success__color); +// --rui-local-border-color: var(--rui-Card--success__border-color); +// --rui-local-background-color: var(--rui-Card--success__background-color); + @mixin generate-properties( + $prefix, + $component-name, + $modifier-value: null, + $variant-value, + $interaction-state: null, + $properties, +) { + @each $property in $properties { + $modifier: if($modifier-value, "--" + $modifier-value, ""); + $state: if($interaction-state, "--" + $interaction-state, ""); + + // 1. + --#{$prefix}local-#{$property}: + var( + #{ + "--" + + $prefix + + $component-name + + $modifier + + "--" + + $variant-value + + $state + + "__" + + $property + } + #{if( + $interaction-state and $interaction-state == "disabled", + ", var(--" + + $prefix + + $component-name + + $modifier + + "--" + + $variant-value + + "--default__" + + $property + + ")", + "" + )} + ); // 2. + } +} + +// Mixin to generate CSS classes for a component variant. +// +// @param {String} $prefix - The prefix for the CSS custom properties. +// @param {String} $component-name - The name of the component. +// @param {String} $modifier-name - Optional name of the class name modifier. +// @param {String} $modifier-name - Optional value of the class name modifier. +// @param {String} $variant-name - The name of the variant. +// @param {String} $variant-value - The value of the variant. +// @param {Boolean} $generate-interaction-states - Whether to generate interaction states (disabled, hover, active). +// @param {List} $properties - The list of properties to generate CSS custom properties for. +// +// Examples: +// +// @include collections.generate-class( +// $prefix: "rui-", +// $component-name: "Card", +// $variant-name: "color", +// $variant-value: "success", +// $properties: color, border-color, background-color, +// ); +// +// … will output: +// +// .isRootColorSuccess { +// --rui-local-color: var(--rui-Card--success__color); +// --rui-local-border-color: var(--rui-Card--success__border-color); +// --rui-local-background-color: var(--rui-Card--success__background-color); +// } +// +// @include collections.generate-class( +// $prefix: "rui-", +// $component-name: "Button", +// $modifier-name: "priority", +// $modifier-value: "flat", +// $variant-name: "color", +// $variant-value: "success", +// $generate-interaction-states: true, +// $properties: color, background, +// ); +// +// … will output: +// +// .isRootPriorityFlat.isRootColorSuccess { +// --rui-local-color: var(--rui-Button--flat--success--default__color); +// --rui-local-background: var(--rui-Button--flat--success--default__background); +// } +// .isRootPriorityFlat.isRootColorSuccess:disabled { +// --rui-local-color: +// var( +// --rui-Button--flat--success--disabled__color, +// var(--rui-Button--flat--success--default__color) +// ); +// --rui-local-background: +// var( +// --rui-Button--flat--success--disabled__background, +// var(--rui-Button--flat--success--default__background) +// ); +// } +// .isRootPriorityFlat.isRootColorSuccess:not(:disabled):hover { +// --rui-local-color: var(--rui-Button--flat--success--hover__color); +// --rui-local-background: var(--rui-Button--flat--success--hover__background); +// } +// .isRootPriorityFlat.isRootColorSuccess:not(:disabled):active { +// --rui-local-color: var(--rui-Button--flat--success--active__color); +// --rui-local-background: var(--rui-Button--flat--success--active__background); +// } + +@mixin generate-class( $prefix, $component-name, $modifier-name: null, $modifier-value: null, $variant-name, $variant-value, + $generate-interaction-states: false, $properties, ) { - $combined-class-name: + $modifier-class-name: if( $modifier-name and $modifier-value, ".isRoot#{rui-string.capitalize($modifier-name)}#{rui-string.capitalize($modifier-value)}", "" ); + $variant-class-name: ".isRoot#{rui-string.capitalize($variant-name)}#{rui-string.capitalize($variant-value)}"; + + #{$modifier-class-name}#{$variant-class-name} { + @if $generate-interaction-states { + $interaction-state-selector-map: ( + default: "&", + disabled: "&:disabled", + hover: "&:not(:disabled):hover", + active: "&:not(:disabled):active", + ); - #{$combined-class-name}.isRoot#{rui-string.capitalize($variant-name)}#{rui-string.capitalize($variant-value)} { - @each $property in $properties { - --#{$prefix}local-#{$property}: - var( - #{ - "--" - + $prefix - + $component-name - + if($modifier-value, "--" + $modifier-value, "") - + "--" - + $variant-value - + "__" - + $property - } - ); + @each $interaction-state, $interaction-state-selector in $interaction-state-selector-map { + #{$interaction-state-selector} { + @include generate-properties( + $prefix: $prefix, + $component-name: $component-name, + $modifier-value: $modifier-value, + $variant-value: $variant-value, + $interaction-state: $interaction-state, + $properties: $properties, + ); + } + } + } @else { + @include generate-properties( + $prefix: $prefix, + $component-name: $component-name, + $modifier-value: $modifier-value, + $variant-value: $variant-value, + $properties: $properties, + ); } } } From d532592001380c4c88a0f92d637e1b6bfbead5ce Mon Sep 17 00:00:00 2001 From: David Menc Date: Fri, 23 Aug 2024 09:51:57 +0200 Subject: [PATCH 12/15] Remove line between popover and arrow --- src/components/Popover/Popover.module.scss | 32 +++++++++++----------- src/components/Popover/_theme.scss | 6 ++-- webpack.config.babel.js | 2 +- 3 files changed, 21 insertions(+), 19 deletions(-) diff --git a/src/components/Popover/Popover.module.scss b/src/components/Popover/Popover.module.scss index b4a746bb7..1c3d18737 100644 --- a/src/components/Popover/Popover.module.scss +++ b/src/components/Popover/Popover.module.scss @@ -51,52 +51,52 @@ // Sides .isRootAtTop { - bottom: 100%; + bottom: calc(100% + #{theme.$arrow-gap} - #{theme.$arrow-safe-rendering-overlap}); } .isRootAtBottom { - top: 100%; + top: calc(100% + #{theme.$arrow-gap} - #{theme.$arrow-safe-rendering-overlap}); } .isRootAtLeft { - right: 100%; + right: calc(100% + #{theme.$arrow-gap} - #{theme.$arrow-safe-rendering-overlap}); } .isRootAtRight { - left: 100%; + left: calc(100% + #{theme.$arrow-gap} - #{theme.$arrow-safe-rendering-overlap}); } // Arrows .isRootAtTop > .arrow { - top: 100%; + top: calc(100% - #{theme.$arrow-safe-rendering-overlap}); } .isRootAtBottom > .arrow { - bottom: 100%; + bottom: calc(100% - #{theme.$arrow-safe-rendering-overlap}); } .isRootAtLeft > .arrow { - left: 100%; + left: calc(100% - #{theme.$arrow-safe-rendering-overlap}); } .isRootAtRight > .arrow { - right: 100%; + right: calc(100% - #{theme.$arrow-safe-rendering-overlap}); } // Side alignments: top .isRootAtTop.isRootAtCenter { left: 50%; - transform: translate(-50%, #{-1 * theme.$arrow-height}); + transform: translate(-50%, calc(-1 * #{theme.$arrow-height})); } .isRootAtTop.isRootAtStart { left: 0; - transform: translate(0, #{-1 * theme.$arrow-height}); + transform: translate(0, calc(-1 * #{theme.$arrow-height})); } .isRootAtTop.isRootAtEnd { right: 0; - transform: translate(0, #{-1 * theme.$arrow-height}); + transform: translate(0, calc(-1 * #{theme.$arrow-height})); } .isRootAtTop.isRootAtCenter > .arrow { @@ -148,17 +148,17 @@ // Side alignments: left .isRootAtLeft.isRootAtCenter { top: 50%; - transform: translate(#{-1 * theme.$arrow-height}, -50%); + transform: translate(calc(-1 * #{theme.$arrow-height}), -50%); } .isRootAtLeft.isRootAtStart { top: 0; - transform: translate(#{-1 * theme.$arrow-height}, 0); + transform: translate(calc(-1 * #{theme.$arrow-height}), 0); } .isRootAtLeft.isRootAtEnd { bottom: 0; - transform: translate(#{-1 * theme.$arrow-height}, 0); + transform: translate(calc(-1 * #{theme.$arrow-height}), 0); } .isRootAtLeft.isRootAtCenter > .arrow { @@ -216,7 +216,7 @@ } .isRootControlled.isRootAtTop { - transform: translate(0, #{-1 * theme.$arrow-height}); // 2. + transform: translate(0, calc(-1 * #{theme.$arrow-height})); // 2. } .isRootControlled.isRootAtBottom { @@ -224,7 +224,7 @@ } .isRootControlled.isRootAtLeft { - transform: translate(#{-1 * theme.$arrow-height}, 0); // 2. + transform: translate(calc(-1 * #{theme.$arrow-height}), 0); // 2. } .isRootControlled.isRootAtRight { diff --git a/src/components/Popover/_theme.scss b/src/components/Popover/_theme.scss index bb3523cb9..59b40e545 100644 --- a/src/components/Popover/_theme.scss +++ b/src/components/Popover/_theme.scss @@ -11,6 +11,8 @@ $color: var(--rui-Popover__color); $background-color: var(--rui-Popover__background-color); $box-shadow: var(--rui-Popover__box-shadow); -$arrow-width: 1rem; -$arrow-height: math.div($arrow-width, 2); // 1. +$arrow-safe-rendering-overlap: 1px; +$arrow-gap: 1px; +$arrow-width: calc(1rem + #{$arrow-safe-rendering-overlap * 2}); +$arrow-height: calc($arrow-width / 2); // 1. $arrow-corner-offset: 0.75rem; diff --git a/webpack.config.babel.js b/webpack.config.babel.js index 1dfbed3d7..db9839b28 100644 --- a/webpack.config.babel.js +++ b/webpack.config.babel.js @@ -5,7 +5,7 @@ const TerserPlugin = require('terser-webpack-plugin'); const VisualizerPlugin = require('webpack-visualizer-plugin2'); const MAX_DEVELOPMENT_OUTPUT_SIZE = 3300000; -const MAX_PRODUCTION_OUTPUT_SIZE = 420000; +const MAX_PRODUCTION_OUTPUT_SIZE = 430000; module.exports = (env, argv) => ({ devtool: argv.mode === 'production' From 637e64d8cc2f42149ffe1533ad4c23fb7820c9dc Mon Sep 17 00:00:00 2001 From: Adam Kudrna Date: Fri, 4 Oct 2024 12:03:53 +0200 Subject: [PATCH 13/15] Fix `Grid` items/content alignment when just a single value is set (#569) Intentionally use longhand properties because the custom property fallback mechanism evaluates `initial` values as empty. That makes the other value of the shorthand property unexpectedly used for both axes. --- src/components/Grid/Grid.module.scss | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/components/Grid/Grid.module.scss b/src/components/Grid/Grid.module.scss index 3ce33ae22..e8a520d2b 100644 --- a/src/components/Grid/Grid.module.scss +++ b/src/components/Grid/Grid.module.scss @@ -19,6 +19,9 @@ // `--rui-local-: var(--rui-local--sm, var(--rui-local--xs, ))` // // 2. Apply custom property value that is defined within current breakpoint, see 1. +// +// 3. Intentionally use longhand properties because the custom property fallback mechanism evaluates `initial` values as +// empty. That makes the other value of the shorthand property unexpectedly used for both axes. @use "sass:map"; @use "../../styles/tools/spacing"; @@ -35,8 +38,12 @@ grid-template-rows: var(--rui-local-rows); // 2. grid-auto-flow: var(--rui-local-auto-flow); // 2. grid-gap: var(--rui-local-row-gap) var(--rui-local-column-gap); // 2. - place-content: var(--rui-local-align-content) var(--rui-local-justify-content); // 2. - place-items: var(--rui-local-align-items) var(--rui-local-justify-items); // 2. + // stylelint-disable declaration-block-no-redundant-longhand-properties -- 3. + align-content: var(--rui-local-align-content); // 2. + align-items: var(--rui-local-align-items); // 2. + justify-content: var(--rui-local-justify-content); // 2. + justify-items: var(--rui-local-justify-items); // 2. + // stylelint-enable declaration-block-no-redundant-longhand-properties } // stylelint-disable-next-line selector-max-universal -- Reset any previously added margins. From 7898915131255ba74ecbc9f0bb4a01e4bf54d2c2 Mon Sep 17 00:00:00 2001 From: Adam Kudrna Date: Fri, 4 Oct 2024 18:01:22 +0200 Subject: [PATCH 14/15] Fix placement of form fields when just a single value is set Intentionally use longhand properties because the custom property fallback mechanism evaluates `initial` values as empty. That makes the other value of the shorthand property unexpectedly used for both axes. --- src/styles/tools/form-fields/_box-field-layout.scss | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/styles/tools/form-fields/_box-field-layout.scss b/src/styles/tools/form-fields/_box-field-layout.scss index 79d836360..e76386730 100644 --- a/src/styles/tools/form-fields/_box-field-layout.scss +++ b/src/styles/tools/form-fields/_box-field-layout.scss @@ -55,6 +55,9 @@ // // 13. Label and field are vertically aligned to top (start) by default (see 10.). Vertical // alignment of each block can be changed by theme configuration. +// +// 14. Intentionally use longhand properties because the custom property fallback mechanism evaluates `initial` values +// as empty. That makes the other value of the shorthand property unexpectedly used for both axes. @use "../../settings/forms"; @use "../../settings/form-fields" as settings; @@ -125,7 +128,10 @@ .field { grid-area: field; - place-self: theme.$horizontal-field-vertical-alignment start; // 13. / 7. + // stylelint-disable declaration-block-no-redundant-longhand-properties -- 14. + align-self: theme.$horizontal-field-vertical-alignment; // 13. + justify-self: start; // 7. + // stylelint-enable declaration-block-no-redundant-longhand-properties } } } From 783a2a7bb33f87277174e0ba270821ecf3473d87 Mon Sep 17 00:00:00 2001 From: Adam Kudrna Date: Fri, 11 Oct 2024 15:00:02 +0200 Subject: [PATCH 15/15] Bump version to v0.57.0 --- package-lock.json | 4 ++-- package.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index 6cc618219..944482c6c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@react-ui-org/react-ui", - "version": "0.56.0", + "version": "0.57.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@react-ui-org/react-ui", - "version": "0.56.0", + "version": "0.57.0", "hasInstallScript": true, "license": "MIT", "dependencies": { diff --git a/package.json b/package.json index ba6c86042..ae5961119 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "@react-ui-org/react-ui", "description": "React UI is a themeable UI library for React apps.", - "version": "0.56.0", + "version": "0.57.0", "keywords": [ "react", "ui",