@react-ui-org/react-ui 0.57.0 → 0.59.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (118) hide show
  1. package/.nvmrc +1 -1
  2. package/README.md +2 -11
  3. package/dist/react-ui.css +19 -19
  4. package/dist/react-ui.development.css +1351 -963
  5. package/dist/react-ui.development.js +187 -87
  6. package/dist/react-ui.js +1 -1
  7. package/package.json +16 -5
  8. package/src/components/Alert/Alert.jsx +7 -9
  9. package/src/components/Alert/Alert.module.scss +3 -3
  10. package/src/components/Alert/README.md +18 -32
  11. package/src/components/Alert/_settings.scss +1 -2
  12. package/src/components/Badge/Badge.jsx +3 -3
  13. package/src/components/Button/Button.jsx +3 -3
  14. package/src/components/ButtonGroup/ButtonGroup.jsx +3 -3
  15. package/src/components/Card/Card.jsx +7 -7
  16. package/src/components/Card/Card.module.scss +8 -7
  17. package/src/components/Card/CardBody.jsx +2 -2
  18. package/src/components/Card/CardFooter.jsx +2 -2
  19. package/src/components/Card/README.md +20 -17
  20. package/src/components/Card/_settings.scss +1 -2
  21. package/src/components/Card/_theme.scss +1 -0
  22. package/src/components/CheckboxField/CheckboxField.jsx +11 -5
  23. package/src/components/CheckboxField/README.md +110 -5
  24. package/src/components/FileInputField/FileInputField.jsx +148 -22
  25. package/src/components/FileInputField/FileInputField.module.scss +87 -1
  26. package/src/components/FileInputField/README.md +83 -2
  27. package/src/components/FileInputField/_settings.scss +15 -0
  28. package/src/components/FormLayout/FormLayout.jsx +3 -3
  29. package/src/components/FormLayout/FormLayoutCustomField.jsx +3 -3
  30. package/src/components/FormLayout/README.md +1 -0
  31. package/src/components/Grid/Grid.jsx +2 -2
  32. package/src/components/Grid/Grid.module.scss +2 -2
  33. package/src/components/Grid/GridSpan.jsx +2 -2
  34. package/src/components/InputGroup/InputGroup.jsx +4 -4
  35. package/src/components/InputGroup/InputGroup.module.scss +12 -8
  36. package/src/components/InputGroup/README.md +1 -1
  37. package/src/components/Modal/Modal.jsx +118 -46
  38. package/src/components/Modal/Modal.module.scss +34 -18
  39. package/src/components/Modal/ModalBody.jsx +3 -3
  40. package/src/components/Modal/ModalBody.module.scss +18 -0
  41. package/src/components/Modal/ModalCloseButton.jsx +4 -6
  42. package/src/components/Modal/ModalContent.jsx +2 -2
  43. package/src/components/Modal/ModalFooter.jsx +3 -3
  44. package/src/components/Modal/ModalFooter.module.scss +6 -2
  45. package/src/components/Modal/ModalHeader.jsx +3 -3
  46. package/src/components/Modal/ModalHeader.module.scss +8 -1
  47. package/src/components/Modal/ModalTitle.jsx +2 -2
  48. package/src/components/Modal/README.md +407 -187
  49. package/src/components/Modal/_animations.scss +9 -0
  50. package/src/components/Modal/_helpers/dialogOnCancelHandler.js +28 -0
  51. package/src/components/Modal/_helpers/dialogOnClickHandler.js +46 -0
  52. package/src/components/Modal/_helpers/dialogOnCloseHandler.js +28 -0
  53. package/src/components/Modal/_helpers/dialogOnKeyDownHandler.js +62 -0
  54. package/src/components/Modal/_helpers/getPositionClassName.js +1 -1
  55. package/src/components/Modal/_hooks/useModalFocus.js +24 -91
  56. package/src/components/Modal/_settings.scss +4 -3
  57. package/src/components/Modal/_theme.scss +1 -0
  58. package/src/components/Paper/Paper.jsx +3 -3
  59. package/src/components/Popover/Popover.jsx +60 -15
  60. package/src/components/Popover/Popover.module.scss +37 -9
  61. package/src/components/Popover/PopoverWrapper.jsx +2 -2
  62. package/src/components/Popover/README.md +60 -3
  63. package/src/components/Popover/_helpers/cleanPlacementStyle.js +20 -0
  64. package/src/components/Radio/README.md +103 -0
  65. package/src/components/Radio/Radio.jsx +11 -5
  66. package/src/components/Radio/Radio.module.scss +4 -0
  67. package/src/components/ScrollView/ScrollView.jsx +5 -7
  68. package/src/components/SelectField/README.md +103 -0
  69. package/src/components/SelectField/SelectField.jsx +11 -5
  70. package/src/components/Table/Table.jsx +2 -2
  71. package/src/components/Tabs/Tabs.jsx +2 -2
  72. package/src/components/Tabs/TabsItem.jsx +3 -3
  73. package/src/components/Text/Text.jsx +3 -3
  74. package/src/components/TextArea/TextArea.jsx +3 -3
  75. package/src/components/TextField/README.md +14 -2
  76. package/src/components/TextField/TextField.jsx +3 -3
  77. package/src/components/TextLink/README.md +10 -3
  78. package/src/components/TextLink/TextLink.jsx +2 -2
  79. package/src/components/TextLink/_theme.scss +3 -3
  80. package/src/components/Toggle/README.md +83 -1
  81. package/src/components/Toggle/Toggle.jsx +11 -5
  82. package/src/components/Toolbar/Toolbar.jsx +3 -3
  83. package/src/components/Toolbar/ToolbarGroup.jsx +3 -3
  84. package/src/components/Toolbar/ToolbarItem.jsx +3 -3
  85. package/src/components/_helpers/resolveContextOrProp.js +6 -3
  86. package/src/helpers/classNames/README.md +65 -0
  87. package/src/helpers/classNames/classNames.js +11 -0
  88. package/src/helpers/classNames/index.js +1 -0
  89. package/src/helpers/transferProps/README.md +46 -0
  90. package/src/helpers/transferProps/index.js +1 -0
  91. package/src/index.js +6 -5
  92. package/src/providers/globalProps/GlobalPropsContext.jsx +5 -0
  93. package/src/providers/globalProps/GlobalPropsProvider.jsx +33 -0
  94. package/src/providers/globalProps/index.js +3 -0
  95. package/src/{provider → providers/globalProps}/withGlobalProps.jsx +16 -16
  96. package/src/providers/translations/TranslationsContext.jsx +6 -0
  97. package/src/providers/translations/TranslationsProvider.jsx +33 -0
  98. package/src/providers/translations/index.js +2 -0
  99. package/src/styles/elements/_links.scss +2 -9
  100. package/src/styles/generic/_focus.scss +1 -1
  101. package/src/styles/theme/_form-fields.scss +19 -0
  102. package/src/styles/theme/_links.scss +4 -3
  103. package/src/styles/tools/_accessibility.scss +3 -5
  104. package/src/styles/tools/_collections.scss +62 -5
  105. package/src/styles/tools/_links.scss +17 -0
  106. package/src/styles/tools/form-fields/_box-field-elements.scss +21 -9
  107. package/src/styles/tools/form-fields/_box-field-layout.scss +2 -2
  108. package/src/styles/tools/form-fields/_box-field-sizes.scss +6 -10
  109. package/src/styles/tools/form-fields/_foundation.scss +6 -4
  110. package/src/styles/tools/form-fields/_variants.scss +12 -8
  111. package/src/theme.scss +53 -2
  112. package/src/translations/en.js +5 -0
  113. package/src/provider/RUIContext.jsx +0 -9
  114. package/src/provider/RUIProvider.jsx +0 -42
  115. package/src/provider/index.js +0 -3
  116. package/src/styles/settings/_z-indexes.scss +0 -2
  117. package/src/utils/classNames.js +0 -8
  118. /package/src/{utils → helpers/transferProps}/transferProps.js +0 -0
@@ -1,8 +1,8 @@
1
1
  import PropTypes from 'prop-types';
2
2
  import React from 'react';
3
- import { withGlobalProps } from '../../provider';
4
- import { classNames } from '../../utils/classNames';
5
- import { transferProps } from '../../utils/transferProps';
3
+ import { withGlobalProps } from '../../providers/globalProps';
4
+ import { classNames } from '../../helpers/classNames/classNames';
5
+ import { transferProps } from '../../helpers/transferProps';
6
6
  import { isChildrenEmpty } from '../_helpers/isChildrenEmpty';
7
7
  import { getAlignClassName } from './_helpers/getAlignClassName';
8
8
  import { getJustifyClassName } from './_helpers/getJustifyClassName';
@@ -1,8 +1,8 @@
1
1
  import PropTypes from 'prop-types';
2
2
  import React from 'react';
3
- import { withGlobalProps } from '../../provider';
4
- import { classNames } from '../../utils/classNames';
5
- import { transferProps } from '../../utils/transferProps';
3
+ import { withGlobalProps } from '../../providers/globalProps';
4
+ import { classNames } from '../../helpers/classNames/classNames';
5
+ import { transferProps } from '../../helpers/transferProps';
6
6
  import { isChildrenEmpty } from '../_helpers/isChildrenEmpty';
7
7
  import { getAlignClassName } from './_helpers/getAlignClassName';
8
8
  import styles from './Toolbar.module.scss';
@@ -1,8 +1,8 @@
1
1
  import PropTypes from 'prop-types';
2
2
  import React from 'react';
3
- import { classNames } from '../../utils/classNames';
4
- import { transferProps } from '../../utils/transferProps';
5
- import { withGlobalProps } from '../../provider';
3
+ import { classNames } from '../../helpers/classNames/classNames';
4
+ import { transferProps } from '../../helpers/transferProps';
5
+ import { withGlobalProps } from '../../providers/globalProps';
6
6
  import { isChildrenEmpty } from '../_helpers/isChildrenEmpty';
7
7
  import styles from './Toolbar.module.scss';
8
8
 
@@ -1,7 +1,10 @@
1
1
  export const resolveContextOrProp = (contextValue, propValue) => {
2
- if (contextValue != null) {
3
- return contextValue;
2
+ // We need to test:
3
+ // * `false` - for when the `contextValue` is boolean
4
+ // * `null` - for when the `contextValue` is non-boolean
5
+ if (contextValue === false || contextValue === null) {
6
+ return propValue;
4
7
  }
5
8
 
6
- return propValue;
9
+ return contextValue;
7
10
  };
@@ -0,0 +1,65 @@
1
+ # classNames
2
+
3
+ The `classNames` helper function simplifies creating a string passable to
4
+ the `class` / `className` attribute.
5
+
6
+ It accepts multiple arguments, filters out invalid values, and returns a single
7
+ string where the remaining parameters are joined by a space.
8
+
9
+ ## Usage
10
+
11
+ To use `classNames` helper, you need to import it first:
12
+
13
+ ```js
14
+ import { classNames } from '@react-ui-org/react-ui';
15
+ ```
16
+
17
+ And use it:
18
+
19
+ ```docoff-react-preview
20
+ <>
21
+ <div
22
+ className={classNames(
23
+ 'd-block',
24
+ new Date('2025-01-01T00:00:00') < new Date() && 'text-danger',
25
+ )}
26
+ >
27
+ {(new Date()).toLocaleDateString()}
28
+ </div>
29
+ <div
30
+ className={classNames(
31
+ 'd-block',
32
+ new Date('3000-01-01T00:00:00') < new Date() && 'text-danger',
33
+ )}
34
+ >
35
+ {(new Date()).toLocaleDateString()}
36
+ </div>
37
+ </>
38
+ ```
39
+
40
+ ## Parameter Filtering
41
+
42
+ The `classNames` function:
43
+
44
+ * filters out all values that are not strings
45
+ * filters out empty strings
46
+ * filters out whitespace only strings
47
+
48
+ <!-- markdownlint-disable MD010 -->
49
+ ```docoff-react-preview
50
+ {classNames(
51
+ 'class-1',
52
+ 'class-2 class-3',
53
+ ' ',
54
+ ' ', // non-breakable space
55
+ ' ', // tab
56
+ '',
57
+ 0,
58
+ 1,
59
+ null,
60
+ undefined,
61
+ true,
62
+ false,
63
+ )}
64
+ ```
65
+ <!-- markdownlint-enable MD010 -->
@@ -0,0 +1,11 @@
1
+ export const classNames = (...classes) => {
2
+ const filteredClassNames = classes.filter(
3
+ (className) => typeof className === 'string'
4
+ && className.trim().length > 0,
5
+ );
6
+
7
+ return filteredClassNames.length > 0
8
+ ? filteredClassNames.join(' ')
9
+ // React does not render attributes whose value is `undefined` and we do not want an empty `class` attribute in HTML
10
+ : undefined;
11
+ };
@@ -0,0 +1 @@
1
+ export { classNames } from './classNames';
@@ -0,0 +1,46 @@
1
+ # transferProps
2
+
3
+ The `transferProps` helper controls passing of props from the React component
4
+ to the HTML element.
5
+
6
+ It enables making the component interactive and helps to improve its
7
+ accessibility. However some props should never be passed to the HTML element
8
+ as it would break things. This function is used to filter them out. Among these
9
+ props are:
10
+
11
+ - `children`
12
+ - `className`
13
+ - `contentEditable`
14
+ - `dangerouslySetInnerHtml`
15
+ - `ref`
16
+ - `staticContext`
17
+ - `style`
18
+ - `suppressContentEditableWarning`
19
+
20
+ 👉 When run in development mode, the function will log the error to the console
21
+ if any invalid props are passed.
22
+
23
+ ## Basic Usage
24
+
25
+ To use `transferProps` helper, you need to import it first:
26
+
27
+ ```js
28
+ import { transferProps } from "@react-ui-org/react-ui";
29
+ ```
30
+
31
+ And use it:
32
+
33
+ ```jsx
34
+ const CustomComponent = ({
35
+ children,
36
+ id,
37
+ ...restProps
38
+ }) => (
39
+ <div
40
+ {...transferProps(restProps)}
41
+ id={id && `${id}__customComponent`}
42
+ >
43
+ {children}
44
+ </div>
45
+ );
46
+ ```
@@ -0,0 +1 @@
1
+ export { transferProps } from './transferProps';
package/src/index.js CHANGED
@@ -57,9 +57,10 @@ export {
57
57
  ToolbarItem,
58
58
  } from './components/Toolbar';
59
59
 
60
- // Provider
61
- export { RUIProvider } from './provider';
60
+ // Providers
61
+ export { GlobalPropsProvider } from './providers/globalProps';
62
+ export { TranslationsProvider } from './providers/translations';
62
63
 
63
- // Utils
64
- export { classNames } from './utils/classNames';
65
- export { transferProps } from './utils/transferProps';
64
+ // Helpers
65
+ export { classNames } from './helpers/classNames';
66
+ export { transferProps } from './helpers/transferProps';
@@ -0,0 +1,5 @@
1
+ import React from 'react';
2
+
3
+ const GlobalPropsContext = React.createContext({});
4
+
5
+ export default GlobalPropsContext;
@@ -0,0 +1,33 @@
1
+ import PropTypes from 'prop-types';
2
+ import React, {
3
+ useContext,
4
+ } from 'react';
5
+ import { mergeDeep } from '../../utils/mergeDeep';
6
+ import GlobalPropsContext from './GlobalPropsContext';
7
+
8
+ const GlobalPropsProvider = ({
9
+ children,
10
+ globalProps,
11
+ }) => {
12
+ const contextGlobalProps = useContext(GlobalPropsContext);
13
+
14
+ return (
15
+ <GlobalPropsContext.Provider
16
+ value={mergeDeep(contextGlobalProps, globalProps)}
17
+ >
18
+ {children}
19
+ </GlobalPropsContext.Provider>
20
+ );
21
+ };
22
+
23
+ GlobalPropsProvider.defaultProps = {
24
+ children: null,
25
+ globalProps: {},
26
+ };
27
+
28
+ GlobalPropsProvider.propTypes = {
29
+ children: PropTypes.node,
30
+ globalProps: PropTypes.shape({}),
31
+ };
32
+
33
+ export default GlobalPropsProvider;
@@ -0,0 +1,3 @@
1
+ export { default as GlobalPropsContext } from './GlobalPropsContext';
2
+ export { default as GlobalPropsProvider } from './GlobalPropsProvider';
3
+ export { default as withGlobalProps } from './withGlobalProps';
@@ -1,26 +1,24 @@
1
1
  import PropTypes from 'prop-types';
2
- import React from 'react';
3
- import RUIContext from './RUIContext';
2
+ import React, {
3
+ useContext,
4
+ } from 'react';
5
+ import GlobalPropsContext from './GlobalPropsContext';
4
6
 
5
7
  export default (Component, componentName) => {
6
8
  const WithGlobalPropsComponent = ({
7
9
  forwardedRef,
8
10
  ...rest
9
- }) => (
10
- <RUIContext.Consumer>
11
- {({ globalProps }) => {
12
- const contextGlobalProps = globalProps ? globalProps[componentName] : null;
11
+ }) => {
12
+ const contextGlobalProps = useContext(GlobalPropsContext);
13
13
 
14
- return (
15
- <Component
16
- {...contextGlobalProps}
17
- {...rest}
18
- ref={forwardedRef}
19
- />
20
- );
21
- }}
22
- </RUIContext.Consumer>
23
- );
14
+ return (
15
+ <Component
16
+ {...contextGlobalProps[componentName] || {}}
17
+ {...rest}
18
+ ref={forwardedRef}
19
+ />
20
+ );
21
+ };
24
22
 
25
23
  WithGlobalPropsComponent.defaultProps = {
26
24
  forwardedRef: undefined,
@@ -29,6 +27,8 @@ export default (Component, componentName) => {
29
27
  WithGlobalPropsComponent.propTypes = {
30
28
  forwardedRef: PropTypes.oneOfType([
31
29
  PropTypes.func,
30
+
31
+ // The props can be of any type and here we need to support them all
32
32
  // eslint-disable-next-line react/forbid-prop-types
33
33
  PropTypes.shape({ current: PropTypes.any }),
34
34
  ]),
@@ -0,0 +1,6 @@
1
+ import React from 'react';
2
+ import defaultTranslations from '../../translations/en';
3
+
4
+ const RUIContext = React.createContext(defaultTranslations);
5
+
6
+ export default RUIContext;
@@ -0,0 +1,33 @@
1
+ import PropTypes from 'prop-types';
2
+ import React, {
3
+ useContext,
4
+ } from 'react';
5
+ import { mergeDeep } from '../../utils/mergeDeep';
6
+ import TranslationsContext from './TranslationsContext';
7
+
8
+ const TranslationsProvider = ({
9
+ children,
10
+ translations,
11
+ }) => {
12
+ const contextTranslations = useContext(TranslationsContext);
13
+
14
+ return (
15
+ <TranslationsContext.Provider
16
+ value={mergeDeep(contextTranslations, translations)}
17
+ >
18
+ {children}
19
+ </TranslationsContext.Provider>
20
+ );
21
+ };
22
+
23
+ TranslationsProvider.defaultProps = {
24
+ children: null,
25
+ translations: {},
26
+ };
27
+
28
+ TranslationsProvider.propTypes = {
29
+ children: PropTypes.node,
30
+ translations: PropTypes.shape({}),
31
+ };
32
+
33
+ export default TranslationsProvider;
@@ -0,0 +1,2 @@
1
+ export { default as TranslationsContext } from './TranslationsContext';
2
+ export { default as TranslationsProvider } from './TranslationsProvider';
@@ -1,12 +1,5 @@
1
- @use "../theme/links";
1
+ @use "../tools/links";
2
2
 
3
3
  a {
4
- text-decoration: links.$decoration;
5
- color: links.$color;
6
-
7
- &:hover,
8
- &:focus {
9
- text-decoration: links.$hover-decoration;
10
- color: links.$hover-color;
11
- }
4
+ @include links.base();
12
5
  }
@@ -6,6 +6,6 @@
6
6
  outline: none;
7
7
  }
8
8
 
9
- :is(a, button, input, select, textarea, [type="button"], [type="submit"]) {
9
+ :is(a, button, input, select, textarea, [type="button"], [type="submit"]):focus-visible {
10
10
  @include accessibility.focus-ring();
11
11
  }
@@ -30,6 +30,25 @@ $horizontal-label-vertical-alignment: var(--rui-FormField--horizontal__label__ve
30
30
  $horizontal-field-vertical-alignment: var(--rui-FormField--horizontal__field__vertical-alignment);
31
31
  $horizontal-full-width-label-width: var(--rui-FormField--horizontal--full-width__label__width);
32
32
 
33
+ // Form fields: links in validation states
34
+ $link-validation-colors: (
35
+ invalid: (
36
+ default: var(--rui-color-feedback-danger),
37
+ hover: var(--rui-color-feedback-danger-hover),
38
+ active: var(--rui-color-feedback-danger-active),
39
+ ),
40
+ valid: (
41
+ default: var(--rui-color-feedback-success),
42
+ hover: var(--rui-color-feedback-success-hover),
43
+ active: var(--rui-color-feedback-success-active),
44
+ ),
45
+ warning: (
46
+ default: var(--rui-color-feedback-warning),
47
+ hover: var(--rui-color-feedback-warning-hover),
48
+ active: var(--rui-color-feedback-warning-active),
49
+ ),
50
+ );
51
+
33
52
  // Form fields: disabled state
34
53
  $disabled-cursor: var(--rui-FormField--disabled__cursor);
35
54
  $disabled-opacity: var(--rui-FormField--disabled__opacity);
@@ -1,6 +1,7 @@
1
- $color: var(--rui-color-text-link);
1
+ $color: var(--rui-local-link-color, var(--rui-color-text-link));
2
2
  $decoration: var(--rui-text-decoration-link);
3
- $hover-color: var(--rui-color-text-link-hover);
3
+ $underline-offset: var(--rui-underline-offset-link);
4
+ $hover-color: var(--rui-local-link-color-hover, var(--rui-color-text-link-hover));
4
5
  $hover-decoration: var(--rui-text-decoration-link-hover);
5
- $active-color: var(--rui-color-text-link-active);
6
+ $active-color: var(--rui-local-link-color-active, var(--rui-color-text-link-active));
6
7
  $active-decoration: var(--rui-text-decoration-link-active);
@@ -45,9 +45,7 @@
45
45
  }
46
46
 
47
47
  @mixin focus-ring() {
48
- &:focus-visible {
49
- outline: theme.$focus-outline;
50
- outline-offset: theme.$focus-outline-offset;
51
- box-shadow: theme.$focus-box-shadow;
52
- }
48
+ outline: theme.$focus-outline;
49
+ outline-offset: theme.$focus-outline-offset;
50
+ box-shadow: theme.$focus-box-shadow;
53
51
  }
@@ -1,6 +1,31 @@
1
+ @use "sass:list";
2
+ @use "sass:map";
3
+ @use "../settings/collections";
1
4
  @use "string" as rui-string;
2
5
 
3
- // Mixin to generate CSS custom properties for a set of visual properties.
6
+ // Function to get the parent collection category by value.
7
+ //
8
+ // 1. Returns **only the first** matching collection category.
9
+ //
10
+ // @param {String} $value - The value to get the category for.
11
+ // @param {Map} $collections - The collections map to search in.
12
+
13
+ @function _get-category-by-value($value, $collections) {
14
+ @each $category, $values in $collections {
15
+ @if list.index($values, $value) {
16
+ @return $category; // 1.
17
+ }
18
+ }
19
+
20
+ @error
21
+ "Supplied value \""
22
+ + $value
23
+ + "\" not found in any category ("
24
+ + map.keys($collections)
25
+ + ")";
26
+ }
27
+
28
+ // Mixin to generate CSS custom properties for a component theme.
4
29
  //
5
30
  // 1. Generates a CSS custom property for each property in the `$properties` list.
6
31
  // 2. Theming of the disabled state is optional, so the `default` theme options are used (via CSS custom property
@@ -15,7 +40,7 @@
15
40
  //
16
41
  // Example:
17
42
  //
18
- // @include generate-properties(
43
+ // @include generate-component-properties(
19
44
  // $prefix: "rui-",
20
45
  // $component-name: "Card",
21
46
  // $variant-name: "color",
@@ -29,7 +54,7 @@
29
54
  // --rui-local-border-color: var(--rui-Card--success__border-color);
30
55
  // --rui-local-background-color: var(--rui-Card--success__background-color);
31
56
 
32
- @mixin generate-properties(
57
+ @mixin generate-component-properties(
33
58
  $prefix,
34
59
  $component-name,
35
60
  $modifier-value: null,
@@ -72,6 +97,32 @@
72
97
  }
73
98
  }
74
99
 
100
+ // Mixin to generate CSS custom properties for links theme.
101
+ //
102
+ // @param {String} $prefix - The prefix for the CSS custom properties.
103
+ // @param {String} $variant-value - The value of the variant.
104
+ //
105
+ // Example:
106
+ //
107
+ // @include generate-link-properties(
108
+ // $prefix: "rui-",
109
+ // $variant-value: "success",
110
+ // );
111
+ //
112
+ // … will output:
113
+ //
114
+ // --rui-local-link-color: var(--rui-color-feedback-success);
115
+ // --rui-local-link-color-hover: var(--rui-color-feedback-success-hover);
116
+ // --rui-local-link-color-active: var(--rui-color-feedback-success-active);
117
+
118
+ @mixin generate-link-properties($prefix, $variant-value) {
119
+ $color-category: _get-category-by-value($value: $variant-value, $collections: collections.$colors);
120
+
121
+ --#{$prefix}local-link-color: var(--rui-color-#{$color-category}-#{$variant-value});
122
+ --#{$prefix}local-link-color-hover: var(--rui-color-#{$color-category}-#{$variant-value}-hover);
123
+ --#{$prefix}local-link-color-active: var(--rui-color-#{$color-category}-#{$variant-value}-active);
124
+ }
125
+
75
126
  // Mixin to generate CSS classes for a component variant.
76
127
  //
77
128
  // @param {String} $prefix - The prefix for the CSS custom properties.
@@ -81,6 +132,7 @@
81
132
  // @param {String} $variant-name - The name of the variant.
82
133
  // @param {String} $variant-value - The value of the variant.
83
134
  // @param {Boolean} $generate-interaction-states - Whether to generate interaction states (disabled, hover, active).
135
+ // @param {Boolean} $inherit-link-color - Whether to inherit link color from the component variant.
84
136
  // @param {List} $properties - The list of properties to generate CSS custom properties for.
85
137
  //
86
138
  // Examples:
@@ -147,6 +199,7 @@
147
199
  $variant-name,
148
200
  $variant-value,
149
201
  $generate-interaction-states: false,
202
+ $inherit-link-color: false,
150
203
  $properties,
151
204
  ) {
152
205
  $modifier-class-name:
@@ -168,7 +221,7 @@
168
221
 
169
222
  @each $interaction-state, $interaction-state-selector in $interaction-state-selector-map {
170
223
  #{$interaction-state-selector} {
171
- @include generate-properties(
224
+ @include generate-component-properties(
172
225
  $prefix: $prefix,
173
226
  $component-name: $component-name,
174
227
  $modifier-value: $modifier-value,
@@ -179,7 +232,7 @@
179
232
  }
180
233
  }
181
234
  } @else {
182
- @include generate-properties(
235
+ @include generate-component-properties(
183
236
  $prefix: $prefix,
184
237
  $component-name: $component-name,
185
238
  $modifier-value: $modifier-value,
@@ -187,5 +240,9 @@
187
240
  $properties: $properties,
188
241
  );
189
242
  }
243
+
244
+ @if $inherit-link-color {
245
+ @include generate-link-properties($prefix: $prefix, $variant-value: $variant-value);
246
+ }
190
247
  }
191
248
  }
@@ -0,0 +1,17 @@
1
+ @use "../theme/links";
2
+
3
+ @mixin base() {
4
+ text-decoration: links.$decoration;
5
+ text-underline-offset: links.$underline-offset;
6
+ color: links.$color;
7
+
8
+ &:hover {
9
+ text-decoration: links.$hover-decoration;
10
+ color: links.$hover-color;
11
+ }
12
+
13
+ &:active {
14
+ text-decoration: links.$active-decoration;
15
+ color: links.$active-color;
16
+ }
17
+ }
@@ -4,6 +4,7 @@
4
4
  // 3. Let inputs properly fit various layout scenarios.
5
5
  // 4. Leave out space for SelectField caret.
6
6
  // 5. Use a block-level display mode to prevent extra white space below grouped inputs in Safari.
7
+ // 6. Pull out the focused input from the group.
7
8
 
8
9
  @use "../../settings/form-fields" as settings;
9
10
  @use "../../theme/form-fields" as theme;
@@ -18,24 +19,29 @@
18
19
  max-width: 100%; // 3.
19
20
  }
20
21
 
21
- @mixin input() {
22
+ @mixin base() {
22
23
  @include transition.add((opacity, color, border-color, background-color, box-shadow));
23
24
 
24
- appearance: none;
25
25
  width: theme.$box-input-width;
26
26
  min-width: theme.$box-input-min-width;
27
27
  max-width: 100%; // 3.
28
28
  height: var(--rui-local-height);
29
29
  padding: var(--rui-local-padding-y) var(--rui-local-padding-x);
30
+ color: var(--rui-local-color);
31
+ border: theme.$box-border-width solid var(--rui-local-border-color);
32
+ border-radius: theme.$box-border-radius;
33
+ background: var(--rui-local-background);
34
+ }
35
+
36
+ @mixin input() {
37
+ @include base();
38
+
39
+ appearance: none;
30
40
  font-weight: settings.$box-input-font-weight;
31
41
  font-size: var(--rui-local-font-size);
32
42
  line-height: settings.$box-input-line-height;
33
43
  font-family: settings.$box-input-font-family;
34
44
  vertical-align: middle;
35
- color: var(--rui-local-color);
36
- border: theme.$box-border-width solid var(--rui-local-border-color);
37
- border-radius: theme.$box-border-radius;
38
- background: var(--rui-local-background);
39
45
  box-shadow: var(--rui-local-box-shadow);
40
46
 
41
47
  &::placeholder {
@@ -124,17 +130,23 @@
124
130
  }
125
131
  }
126
132
 
127
- @mixin in-group-layout() {
133
+ @mixin in-group-layout($input-element-selector: ".input") {
134
+ // 6.
135
+ &:focus-within {
136
+ isolation: isolate;
137
+ z-index: 1;
138
+ }
139
+
128
140
  .inputContainer {
129
141
  display: block; // 5.
130
142
  }
131
143
 
132
- &:not(:first-child) .input {
144
+ &:not(:first-child) #{$input-element-selector} {
133
145
  border-start-start-radius: var(--rui-local-inner-border-radius);
134
146
  border-end-start-radius: var(--rui-local-inner-border-radius);
135
147
  }
136
148
 
137
- &:not(:last-child) .input {
149
+ &:not(:last-child) #{$input-element-selector} {
138
150
  border-start-end-radius: var(--rui-local-inner-border-radius);
139
151
  border-end-end-radius: var(--rui-local-inner-border-radius);
140
152
  }
@@ -166,14 +166,14 @@
166
166
  }
167
167
  }
168
168
 
169
- @mixin full-width() {
169
+ @mixin full-width($input-element-selector: ".input") {
170
170
  display: flex;
171
171
  flex-direction: column;
172
172
  width: 100%;
173
173
 
174
174
  .field,
175
175
  .inputContainer,
176
- .input {
176
+ #{$input-element-selector} {
177
177
  width: 100%;
178
178
  }
179
179