diff --git a/.changeset/small-rice-arrive.md b/.changeset/small-rice-arrive.md
new file mode 100644
index 0000000000..a30bec6a82
--- /dev/null
+++ b/.changeset/small-rice-arrive.md
@@ -0,0 +1,14 @@
+---
+'@backstage/plugin-mui-to-bui': patch
+---
+
+Updated MUI to BUI theme converter to align with latest token changes
+
+**Changes:**
+
+- Removed generation of deprecated tokens: `--bui-fg-link`, `--bui-fg-link-hover`, `--bui-fg-tint`, `--bui-fg-tint-disabled`, `--bui-bg-tint` and all its variants
+- Added generation of new `info` status tokens: `--bui-fg-info`, `--bui-fg-info-on-bg`, `--bui-bg-info`, `--bui-border-info`
+- Updated status color mapping to generate both standalone and `-on-bg` variants for danger, warning, success, and info
+- Status colors now use `.main` for standalone variants and `.dark` for `-on-bg` variants, providing better visual hierarchy
+
+The converter now generates tokens that match the updated BUI design system structure, with clear distinction between status colors for standalone use vs. use on colored backgrounds.
diff --git a/.changeset/wicked-walls-accept.md b/.changeset/wicked-walls-accept.md
new file mode 100644
index 0000000000..dc5e86a0d4
--- /dev/null
+++ b/.changeset/wicked-walls-accept.md
@@ -0,0 +1,59 @@
+---
+'@backstage/ui': minor
+---
+
+**BREAKING**: Removed link and tint color tokens, added new status foreground tokens, and improved Link component styling
+
+The following color tokens have been removed:
+
+- `--bui-fg-link` (and all related tokens: `-hover`, `-pressed`, `-disabled`)
+- `--bui-fg-tint` (and all related tokens: `-hover`, `-pressed`, `-disabled`)
+- `--bui-bg-tint` (and all related tokens: `-hover`, `-pressed`, `-disabled`)
+- `--bui-border-tint` (and all related tokens)
+
+**New Status Tokens:**
+
+Added dedicated tokens for status colors that distinguish between usage on status backgrounds vs. standalone usage:
+
+- `--bui-fg-danger-on-bg` / `--bui-fg-danger`
+- `--bui-fg-warning-on-bg` / `--bui-fg-warning`
+- `--bui-fg-success-on-bg` / `--bui-fg-success`
+- `--bui-fg-info-on-bg` / `--bui-fg-info`
+
+The `-on-bg` variants are designed for text on colored backgrounds, while the base variants are for standalone status indicators with improved visibility and contrast.
+
+**Migration:**
+
+For link colors, migrate to one of the following alternatives:
+
+```diff
+.custom-link {
+- color: var(--bui-fg-link);
++ color: var(--bui-fg-info); /* For informational links */
++ /* or */
++ color: var(--bui-fg-primary); /* For standard text links */
+}
+```
+
+For tint colors (backgrounds, foregrounds, borders), migrate to appropriate status or neutral colors:
+
+```diff
+.info-section {
+- background: var(--bui-bg-tint);
++ background: var(--bui-bg-info); /* For informational sections */
++ /* or */
++ background: var(--bui-bg-neutral-on-surface-0); /* For neutral emphasis */
+}
+```
+
+If you're using status foreground colors on colored backgrounds, update to the new `-on-bg` tokens:
+
+```diff
+.error-badge {
+- color: var(--bui-fg-danger);
++ color: var(--bui-fg-danger-on-bg);
+ background: var(--bui-bg-danger);
+}
+```
+
+**Affected components:** Link
diff --git a/.storybook/themes/spotify.css b/.storybook/themes/spotify.css
index 352c633a15..4f8b1b137d 100644
--- a/.storybook/themes/spotify.css
+++ b/.storybook/themes/spotify.css
@@ -259,13 +259,9 @@
--bui-fg-primary: var(--bui-white);
--bui-fg-secondary: var(--bui-gray-7);
- --bui-fg-link: var(--bui-white);
- --bui-fg-link-hover: var(--bui-white);
--bui-fg-disabled: var(--bui-gray-5);
--bui-fg-solid: var(--bui-black);
--bui-fg-solid-disabled: #072f15;
- --bui-fg-tint: var(--bui-white);
- --bui-fg-tint-disabled: var(--bui-gray-5);
--bui-fg-danger: #e22b2b;
--bui-fg-warning: #e36d05;
--bui-fg-success: #1db954;
diff --git a/docs-ui/src/app/components/link/components.tsx b/docs-ui/src/app/components/link/components.tsx
index ac4bd05801..320dd52517 100644
--- a/docs-ui/src/app/components/link/components.tsx
+++ b/docs-ui/src/app/components/link/components.tsx
@@ -7,7 +7,9 @@ import { MemoryRouter } from 'react-router-dom';
export const Default = () => {
return (
- Sign up for Backstage
+
+ Sign up for Backstage
+
);
};
@@ -15,7 +17,7 @@ export const Default = () => {
export const ExternalLink = () => {
return (
-
+
Sign up for Backstage
@@ -58,22 +60,25 @@ export const AllVariants = () => {
export const AllColors = () => {
return (
-
-
+
+
Primary
-
+
Secondary
-
+
Danger
-
+
Warning
-
+
Success
+
+ Info
+
);
@@ -83,13 +88,28 @@ export const Weight = () => {
return (
-
+
Regular
-
+
Bold
);
};
+
+export const Standalone = () => {
+ return (
+
+
+
+ Default link
+
+
+ Standalone link
+
+
+
+ );
+};
diff --git a/docs-ui/src/app/components/link/page.mdx b/docs-ui/src/app/components/link/page.mdx
index 13710ee259..8715bb270b 100644
--- a/docs-ui/src/app/components/link/page.mdx
+++ b/docs-ui/src/app/components/link/page.mdx
@@ -10,6 +10,7 @@ import {
allVariantsSnippet,
allColorsSnippet,
weightSnippet,
+ standaloneSnippet,
} from './snippets';
import {
Default,
@@ -17,6 +18,7 @@ import {
AllVariants,
AllColors,
Weight,
+ Standalone,
} from './components';
import { PageTitle } from '@/components/PageTitle';
import { Theming } from '@/components/Theming';
@@ -55,6 +57,7 @@ Use `target="_blank"` to open links in a new tab.
py={4}
preview={}
code={externalLinkSnippet}
+ layout="side-by-side"
/>
### Variants
@@ -79,7 +82,25 @@ Status colors for contextual links.
### Weight
-} code={weightSnippet} />
+}
+ code={weightSnippet}
+ layout="side-by-side"
+/>
+
+### Standalone
+
+Use `standalone` to remove the underline by default. The underline will appear on hover.
+
+}
+ code={standaloneSnippet}
+ layout="side-by-side"
+/>
diff --git a/docs-ui/src/app/components/link/props-definition.tsx b/docs-ui/src/app/components/link/props-definition.tsx
index 7d3b762a24..f0aa95114e 100644
--- a/docs-ui/src/app/components/link/props-definition.tsx
+++ b/docs-ui/src/app/components/link/props-definition.tsx
@@ -66,6 +66,12 @@ export const linkPropDefs: Record = {
type: 'boolean',
description:
'Truncates text with ellipsis when it overflows its container.',
+ default: 'false',
+ },
+ standalone: {
+ type: 'boolean',
+ description: 'Removes underline by default. Underline appears on hover.',
+ default: 'false',
},
...childrenPropDefs,
...classNamePropDefs,
diff --git a/docs-ui/src/app/components/link/snippets.ts b/docs-ui/src/app/components/link/snippets.ts
index 234b3fe983..386ad9f1a0 100644
--- a/docs-ui/src/app/components/link/snippets.ts
+++ b/docs-ui/src/app/components/link/snippets.ts
@@ -4,7 +4,7 @@ export const linkUsageSnippet = `import { Link } from '@backstage/ui';
export const defaultSnippet = `Sign up for Backstage`;
-export const externalLinkSnippet = `
+export const externalLinkSnippet = `
Sign up for Backstage
`;
@@ -25,9 +25,15 @@ export const allColorsSnippet = `
Danger
Warning
Success
+ Info
`;
export const weightSnippet = `
Regular
Bold
`;
+
+export const standaloneSnippet = `
+ Default link
+ Standalone link
+`;
diff --git a/docs-ui/src/app/components/text/components.tsx b/docs-ui/src/app/components/text/components.tsx
index ef803ea2fb..8021a1dde6 100644
--- a/docs-ui/src/app/components/text/components.tsx
+++ b/docs-ui/src/app/components/text/components.tsx
@@ -30,6 +30,7 @@ export const Colors = () => {
Danger
Warning
Success
+ Info
);
};
diff --git a/docs-ui/src/app/components/text/snippets.ts b/docs-ui/src/app/components/text/snippets.ts
index 7f2c222186..b8cc26bd6b 100644
--- a/docs-ui/src/app/components/text/snippets.ts
+++ b/docs-ui/src/app/components/text/snippets.ts
@@ -21,6 +21,7 @@ export const colorsSnippet = `
Danger
Warning
Success
+ Info
`;
export const weightsSnippet = `
diff --git a/docs-ui/src/app/tokens/page.mdx b/docs-ui/src/app/tokens/page.mdx
index 97266afbf4..fdc8aa9a90 100644
--- a/docs-ui/src/app/tokens/page.mdx
+++ b/docs-ui/src/app/tokens/page.mdx
@@ -240,30 +240,6 @@ color of your app.
Used for solid background colors when disabled.
-
-
- --bui-bg-tint
-
- Used for tint background colors.
-
-
-
- --bui-bg-tint-hover
-
- Used for tint background colors when hovered.
-
-
-
- --bui-bg-tint-focus
-
- Used for tint background colors when active.
-
-
-
- --bui-bg-tint-disabled
-
- Used for tint background colors when disabled.
-
--bui-bg-danger
@@ -282,6 +258,12 @@ color of your app.
Used to show success information.
+
+
+ --bui-bg-info
+
+ Used to show informational content.
+
@@ -315,22 +297,6 @@ are prefixed with `fg` to make it easier to identify.
It should be used on top of main background surfaces.
-
-
- --bui-fg-link
-
-
- It should be used on top of main background surfaces.
-
-
-
-
- --bui-fg-link-hover
-
-
- It should be used on top of main background surfaces.
-
-
--bui-fg-disabled
@@ -347,33 +313,45 @@ are prefixed with `fg` to make it easier to identify.
It should be used on top of solid background colors.
-
-
- --bui-fg-tint
-
-
- It should be used on top of tint background colors.
-
-
-
-
- --bui-fg-tint-disabled
-
-
- It should be used on top of tint background colors when disabled.
-
-
--bui-fg-danger
+ Used for error states and destructive actions.
+
+
+
+ --bui-fg-warning
+
+
+ Used for warning states and cautionary information.
+
+
+
+
+ --bui-fg-success
+
+ Used for success states and positive feedback.
+
+
+
+ --bui-fg-info
+
+
+ Used for informational content and neutral status.
+
+
+
+
+ --bui-fg-danger-on-bg
+
It should be used on top of danger background colors.
- --bui-fg-warning
+ --bui-fg-warning-on-bg
It should be used on top of warning background colors.
@@ -381,12 +359,20 @@ are prefixed with `fg` to make it easier to identify.
- --bui-fg-success
+ --bui-fg-success-on-bg
It should be used on top of success background colors.
+
+
+ --bui-fg-info-on-bg
+
+
+ It should be used on top of info background colors.
+
+
@@ -449,6 +435,12 @@ low contrast to help as a separator with the different background colors.
It should be used on top of `--bui-bg-success`.
+
+
+ --bui-border-info
+
+ It should be used on top of `--bui-bg-info`.
+
diff --git a/docs-ui/src/css/theme-backstage.css b/docs-ui/src/css/theme-backstage.css
index f3bf8bf83a..e1ba6ba5b0 100644
--- a/docs-ui/src/css/theme-backstage.css
+++ b/docs-ui/src/css/theme-backstage.css
@@ -79,17 +79,17 @@
--bui-bg-info: #dbeafe;
--bui-fg-primary: var(--bui-black);
--bui-fg-secondary: var(--bui-gray-7);
- --bui-fg-link: #1f5493;
- --bui-fg-link-hover: #1f2d5c;
--bui-fg-disabled: #9e9e9e;
--bui-fg-solid: var(--bui-white);
--bui-fg-solid-disabled: #98a8bc;
- --bui-fg-tint: #1f5493;
- --bui-fg-tint-disabled: var(--bui-gray-5);
- --bui-fg-danger: #991919;
- --bui-fg-warning: #92310a;
- --bui-fg-success: #116932;
- --bui-fg-info: #173da6;
+ --bui-fg-danger-on-bg: #991919;
+ --bui-fg-warning-on-bg: #92310a;
+ --bui-fg-success-on-bg: #116932;
+ --bui-fg-info-on-bg: #173da6;
+ --bui-fg-danger: #ec3b18;
+ --bui-fg-warning: #ef7a32;
+ --bui-fg-success: #1ed760;
+ --bui-fg-info: #0d74ce;
--bui-border: #0000001a;
--bui-border-hover: #0003;
--bui-border-pressed: #0006;
@@ -143,17 +143,17 @@
--bui-bg-info: #132049;
--bui-fg-primary: var(--bui-white);
--bui-fg-secondary: var(--bui-gray-7);
- --bui-fg-link: #9cc9ff;
- --bui-fg-link-hover: #7eb5f7;
--bui-fg-disabled: var(--bui-gray-7);
--bui-fg-solid: #101821;
--bui-fg-solid-disabled: #6191cc;
- --bui-fg-tint: #9cc9ff;
- --bui-fg-tint-disabled: var(--bui-gray-5);
- --bui-fg-danger: #fca5a5;
- --bui-fg-warning: #fdba74;
- --bui-fg-success: #86efac;
- --bui-fg-info: #a3cfff;
+ --bui-fg-danger-on-bg: #fca5a5;
+ --bui-fg-warning-on-bg: #fdba74;
+ --bui-fg-success-on-bg: #86efac;
+ --bui-fg-info-on-bg: #a3cfff;
+ --bui-fg-danger: #ff5a30;
+ --bui-fg-warning: #ffa057;
+ --bui-fg-success: #1ed760;
+ --bui-fg-info: #70b8ff;
--bui-border: #ffffff1f;
--bui-border-hover: #fff6;
--bui-border-pressed: #ffffff80;
diff --git a/docs-ui/src/css/theme-spotify.css b/docs-ui/src/css/theme-spotify.css
index f8b18d6a31..dc660b5b5d 100644
--- a/docs-ui/src/css/theme-spotify.css
+++ b/docs-ui/src/css/theme-spotify.css
@@ -222,13 +222,9 @@
--bui-bg-success: #132d21;
--bui-fg-primary: var(--bui-white);
--bui-fg-secondary: var(--bui-gray-7);
- --bui-fg-link: var(--bui-white);
- --bui-fg-link-hover: var(--bui-white);
--bui-fg-disabled: var(--bui-gray-5);
--bui-fg-solid: var(--bui-black);
--bui-fg-solid-disabled: #072f15;
- --bui-fg-tint: var(--bui-white);
- --bui-fg-tint-disabled: var(--bui-gray-5);
--bui-fg-danger: #e22b2b;
--bui-fg-warning: #e36d05;
--bui-fg-success: #1db954;
diff --git a/docs/conf/user-interface/index.md b/docs/conf/user-interface/index.md
index e0fb645d78..002383c6f4 100644
--- a/docs/conf/user-interface/index.md
+++ b/docs/conf/user-interface/index.md
@@ -131,7 +131,10 @@ And if you’d like to go even further, you can target specific component class
| `--bui-fg-solid` | This is for texts or icons on top of a solid backgrounds. |
| `--bui-fg-primary` | Your primary text or icon colours. |
| `--bui-fg-secondary` | Your secondary text or icon colours. |
-| `--bui-fg-link` | Used for links. |
+| `--bui-fg-danger` | Used for error states and destructive actions. |
+| `--bui-fg-warning` | Used for warning states and cautionary information. |
+| `--bui-fg-success` | Used for success states and positive feedback. |
+| `--bui-fg-info` | Used for informational content and neutral status. |
| `--bui-border` | Main borders around surfaces like `Card`, `Dialog`, ... |
| `--bui-font-regular` | The main font of your app. |
@@ -169,31 +172,29 @@ These colors are used for the background of your application. We are mostly usin
| `--bui-bg-solid-hover` | Used for solid background colors when hovered. |
| `--bui-bg-solid-pressed` | Used for solid background colors when pressed. |
| `--bui-bg-solid-disabled` | Used for solid background colors when disabled. |
-| `--bui-bg-tint` | Used for tint background colors. |
-| `--bui-bg-tint-hover` | Used for tint background colors when hovered. |
-| `--bui-bg-tint-focus` | Used for tint background colors when active. |
-| `--bui-bg-tint-disabled` | Used for tint background colors when disabled. |
| `--bui-bg-danger` | Used to show errors information. |
| `--bui-bg-warning` | Used to show warnings information. |
| `--bui-bg-success` | Used to show success information. |
+| `--bui-bg-info` | Used to show informational content. |
#### Foreground colors
Foreground colours are meant to work in pair with a background colours. Typically this would work for icons, texts, shapes, ... Use a matching name to know what foreground color to use. These colors are prefixed with `fg` to make it easier to identify.
-| Token Name | Description |
-| ------------------------ | ----------------------------------------------------------------- |
-| `--bui-fg-primary` | It should be used on top of main background surfaces. |
-| `--bui-fg-secondary` | It should be used on top of main background surfaces. |
-| `--bui-fg-link` | It should be used on top of main background surfaces. |
-| `--bui-fg-link-hover` | It should be used on top of main background surfaces. |
-| `--bui-fg-disabled` | It should be used on top of main background surfaces. |
-| `--bui-fg-solid` | It should be used on top of solid background colors. |
-| `--bui-fg-tint` | It should be used on top of tint background colors. |
-| `--bui-fg-tint-disabled` | It should be used on top of tint background colors when disabled. |
-| `--bui-fg-danger` | It should be used on top of danger background colors. |
-| `--bui-fg-warning` | It should be used on top of warning background colors. |
-| `--bui-fg-success` | It should be used on top of success background colors. |
+| Token Name | Description |
+| ------------------------ | ------------------------------------------------------ |
+| `--bui-fg-primary` | It should be used on top of main background surfaces. |
+| `--bui-fg-secondary` | It should be used on top of main background surfaces. |
+| `--bui-fg-disabled` | It should be used on top of main background surfaces. |
+| `--bui-fg-solid` | It should be used on top of solid background colors. |
+| `--bui-fg-danger` | Used for error states and destructive actions. |
+| `--bui-fg-warning` | Used for warning states and cautionary information. |
+| `--bui-fg-success` | Used for success states and positive feedback. |
+| `--bui-fg-info` | Used for informational content and neutral status. |
+| `--bui-fg-danger-on-bg` | It should be used on top of danger background colors. |
+| `--bui-fg-warning-on-bg` | It should be used on top of warning background colors. |
+| `--bui-fg-success-on-bg` | It should be used on top of success background colors. |
+| `--bui-fg-info-on-bg` | It should be used on top of info background colors. |
#### Border colors
diff --git a/packages/ui/css/styles.css b/packages/ui/css/styles.css
index 1564855309..7538f53bbe 100644
--- a/packages/ui/css/styles.css
+++ b/packages/ui/css/styles.css
@@ -81,17 +81,17 @@
--bui-bg-info: #dbeafe;
--bui-fg-primary: var(--bui-black);
--bui-fg-secondary: var(--bui-gray-7);
- --bui-fg-link: #1f5493;
- --bui-fg-link-hover: #1f2d5c;
--bui-fg-disabled: #9e9e9e;
--bui-fg-solid: var(--bui-white);
--bui-fg-solid-disabled: #98a8bc;
- --bui-fg-tint: #1f5493;
- --bui-fg-tint-disabled: var(--bui-gray-5);
- --bui-fg-danger: #991919;
- --bui-fg-warning: #92310a;
- --bui-fg-success: #116932;
- --bui-fg-info: #173da6;
+ --bui-fg-danger-on-bg: #991919;
+ --bui-fg-warning-on-bg: #92310a;
+ --bui-fg-success-on-bg: #116932;
+ --bui-fg-info-on-bg: #173da6;
+ --bui-fg-danger: #ec3b18;
+ --bui-fg-warning: #ef7a32;
+ --bui-fg-success: #1ed760;
+ --bui-fg-info: #0d74ce;
--bui-border: #0000001a;
--bui-border-hover: #0003;
--bui-border-pressed: #0006;
@@ -146,17 +146,17 @@
--bui-bg-info: #132049;
--bui-fg-primary: var(--bui-white);
--bui-fg-secondary: var(--bui-gray-7);
- --bui-fg-link: #9cc9ff;
- --bui-fg-link-hover: #7eb5f7;
--bui-fg-disabled: var(--bui-gray-7);
--bui-fg-solid: #101821;
--bui-fg-solid-disabled: #6191cc;
- --bui-fg-tint: #9cc9ff;
- --bui-fg-tint-disabled: var(--bui-gray-5);
- --bui-fg-danger: #fca5a5;
- --bui-fg-warning: #fdba74;
- --bui-fg-success: #86efac;
- --bui-fg-info: #a3cfff;
+ --bui-fg-danger-on-bg: #fca5a5;
+ --bui-fg-warning-on-bg: #fdba74;
+ --bui-fg-success-on-bg: #86efac;
+ --bui-fg-info-on-bg: #a3cfff;
+ --bui-fg-danger: #ff5a30;
+ --bui-fg-warning: #ffa057;
+ --bui-fg-success: #1ed760;
+ --bui-fg-info: #70b8ff;
--bui-border: #ffffff1f;
--bui-border-hover: #fff6;
--bui-border-pressed: #ffffff80;
diff --git a/packages/ui/report.api.md b/packages/ui/report.api.md
index b4211d2499..ae76c8a8d0 100644
--- a/packages/ui/report.api.md
+++ b/packages/ui/report.api.md
@@ -1113,8 +1113,10 @@ export const LinkDefinition: {
'danger',
'warning',
'success',
+ 'info',
];
readonly truncate: readonly [true, false];
+ readonly standalone: readonly [true, false];
};
};
@@ -1128,6 +1130,8 @@ export interface LinkProps extends LinkProps_2 {
| TextColorStatus
| Partial>;
// (undocumented)
+ standalone?: boolean;
+ // (undocumented)
title?: string;
// (undocumented)
truncate?: boolean;
@@ -1906,7 +1910,7 @@ export { Text_2 as Text };
export type TextColors = 'primary' | 'secondary';
// @public (undocumented)
-export type TextColorStatus = 'danger' | 'warning' | 'success';
+export type TextColorStatus = 'danger' | 'warning' | 'success' | 'info';
// @public
export const TextDefinition: {
@@ -1922,6 +1926,7 @@ export const TextDefinition: {
'danger',
'warning',
'success',
+ 'info',
];
readonly truncate: readonly [true, false];
};
diff --git a/packages/ui/src/components/Alert/Alert.module.css b/packages/ui/src/components/Alert/Alert.module.css
index 643a7d09b0..9c2fc6a586 100644
--- a/packages/ui/src/components/Alert/Alert.module.css
+++ b/packages/ui/src/components/Alert/Alert.module.css
@@ -36,22 +36,22 @@
.bui-Alert[data-status='info'] {
--alert-bg: var(--bui-bg-info);
- --alert-fg: var(--bui-fg-info);
+ --alert-fg: var(--bui-fg-info-on-bg);
}
.bui-Alert[data-status='success'] {
--alert-bg: var(--bui-bg-success);
- --alert-fg: var(--bui-fg-success);
+ --alert-fg: var(--bui-fg-success-on-bg);
}
.bui-Alert[data-status='warning'] {
--alert-bg: var(--bui-bg-warning);
- --alert-fg: var(--bui-fg-warning);
+ --alert-fg: var(--bui-fg-warning-on-bg);
}
.bui-Alert[data-status='danger'] {
--alert-bg: var(--bui-bg-danger);
- --alert-fg: var(--bui-fg-danger);
+ --alert-fg: var(--bui-fg-danger-on-bg);
}
.bui-AlertIcon {
diff --git a/packages/ui/src/components/HeaderPage/HeaderPage.tsx b/packages/ui/src/components/HeaderPage/HeaderPage.tsx
index efa7ea8d58..8b1ef31874 100644
--- a/packages/ui/src/components/HeaderPage/HeaderPage.tsx
+++ b/packages/ui/src/components/HeaderPage/HeaderPage.tsx
@@ -56,6 +56,7 @@ export const HeaderPage = (props: HeaderPageProps) => {
color="secondary"
truncate
style={{ maxWidth: '240px' }}
+ standalone
>
{breadcrumb.label}
diff --git a/packages/ui/src/components/Link/Link.module.css b/packages/ui/src/components/Link/Link.module.css
index a319dfb66b..27ffe244fb 100644
--- a/packages/ui/src/components/Link/Link.module.css
+++ b/packages/ui/src/components/Link/Link.module.css
@@ -22,9 +22,14 @@
padding: 0;
margin: 0;
cursor: pointer;
- text-decoration-line: none;
display: inline-block;
+ text-decoration-line: underline;
+ text-decoration-style: solid;
+ text-decoration-thickness: min(2px, max(1px, 0.05em));
+ text-underline-offset: calc(0.025em + 2px);
+ text-decoration-color: color-mix(in srgb, currentColor 30%, transparent);
+
&:hover {
text-decoration-line: underline;
text-decoration-style: solid;
@@ -102,9 +107,25 @@
color: var(--bui-fg-success);
}
+ .bui-Link[data-color='info'] {
+ color: var(--bui-fg-info);
+ }
+
.bui-Link[data-truncate] {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
+
+ .bui-Link[data-standalone] {
+ text-decoration-line: none;
+
+ &:hover {
+ text-decoration-line: underline;
+ text-decoration-style: solid;
+ text-decoration-thickness: min(2px, max(1px, 0.05em));
+ text-underline-offset: calc(0.025em + 2px);
+ text-decoration-color: color-mix(in srgb, currentColor 30%, transparent);
+ }
+ }
}
diff --git a/packages/ui/src/components/Link/Link.stories.tsx b/packages/ui/src/components/Link/Link.stories.tsx
index 7d680e5616..fafb5948d9 100644
--- a/packages/ui/src/components/Link/Link.stories.tsx
+++ b/packages/ui/src/components/Link/Link.stories.tsx
@@ -102,6 +102,12 @@ export const AllColors = meta.story({
color="success"
children="I am success"
/>
+
),
});
@@ -235,6 +241,25 @@ export const Truncate = meta.story({
},
});
+export const Standalone = meta.story({
+ args: {
+ href: '/',
+ children: 'Standalone link (no underline by default)',
+ standalone: true,
+ },
+});
+
+export const StandaloneComparison = meta.story({
+ render: () => (
+
+ Default link (underline by default):
+
+ Standalone link (underline on hover only):
+
+
+ ),
+});
+
export const Responsive = meta.story({
args: {
...Default.input.args,
@@ -244,27 +269,3 @@ export const Responsive = meta.story({
},
},
});
-
-export const Playground = meta.story({
- args: {
- ...Default.input.args,
- },
- render: args => (
-
- Title X Small
-
- Body X Small
-
- Body Small
-
- Body Medium
-
- Body Large
-
- Title Small
-
- Title Medium
-
-
- ),
-});
diff --git a/packages/ui/src/components/Link/Link.tsx b/packages/ui/src/components/Link/Link.tsx
index fb9d25e805..efdca26750 100644
--- a/packages/ui/src/components/Link/Link.tsx
+++ b/packages/ui/src/components/Link/Link.tsx
@@ -44,6 +44,7 @@ const LinkInternal = forwardRef((props, ref) => {
weight,
color,
truncate,
+ standalone,
slot,
...restProps
} = cleanedProps;
diff --git a/packages/ui/src/components/Link/definition.ts b/packages/ui/src/components/Link/definition.ts
index cece929f11..58b780c812 100644
--- a/packages/ui/src/components/Link/definition.ts
+++ b/packages/ui/src/components/Link/definition.ts
@@ -27,7 +27,15 @@ export const LinkDefinition = {
dataAttributes: {
variant: ['subtitle', 'body', 'caption', 'label'] as const,
weight: ['regular', 'bold'] as const,
- color: ['primary', 'secondary', 'danger', 'warning', 'success'] as const,
+ color: [
+ 'primary',
+ 'secondary',
+ 'danger',
+ 'warning',
+ 'success',
+ 'info',
+ ] as const,
truncate: [true, false] as const,
+ standalone: [true, false] as const,
},
} as const satisfies ComponentDefinition;
diff --git a/packages/ui/src/components/Link/types.ts b/packages/ui/src/components/Link/types.ts
index 796676e593..9259a8a1d7 100644
--- a/packages/ui/src/components/Link/types.ts
+++ b/packages/ui/src/components/Link/types.ts
@@ -33,6 +33,7 @@ export interface LinkProps extends AriaLinkProps {
| TextColorStatus
| Partial>;
truncate?: boolean;
+ standalone?: boolean;
// This is used to set the title attribute on the link
title?: string;
diff --git a/packages/ui/src/components/Text/Text.module.css b/packages/ui/src/components/Text/Text.module.css
index 57de6f0ef8..b7b7b9f203 100644
--- a/packages/ui/src/components/Text/Text.module.css
+++ b/packages/ui/src/components/Text/Text.module.css
@@ -91,6 +91,10 @@
color: var(--bui-fg-success);
}
+ .bui-Text[data-color='info'] {
+ color: var(--bui-fg-info);
+ }
+
.bui-Text[data-truncate] {
overflow: hidden;
text-overflow: ellipsis;
diff --git a/packages/ui/src/components/Text/Text.stories.tsx b/packages/ui/src/components/Text/Text.stories.tsx
index 09a317716a..e8dff19318 100644
--- a/packages/ui/src/components/Text/Text.stories.tsx
+++ b/packages/ui/src/components/Text/Text.stories.tsx
@@ -101,6 +101,7 @@ export const AllColors = meta.story({
+
),
});
diff --git a/packages/ui/src/components/Text/definition.ts b/packages/ui/src/components/Text/definition.ts
index dbbfd6b72a..ad676405c7 100644
--- a/packages/ui/src/components/Text/definition.ts
+++ b/packages/ui/src/components/Text/definition.ts
@@ -27,7 +27,14 @@ export const TextDefinition = {
dataAttributes: {
variant: ['subtitle', 'body', 'caption', 'label'] as const,
weight: ['regular', 'bold'] as const,
- color: ['primary', 'secondary', 'danger', 'warning', 'success'] as const,
+ color: [
+ 'primary',
+ 'secondary',
+ 'danger',
+ 'warning',
+ 'success',
+ 'info',
+ ] as const,
truncate: [true, false] as const,
},
} as const satisfies ComponentDefinition;
diff --git a/packages/ui/src/css/tokens.css b/packages/ui/src/css/tokens.css
index 992a49b2f2..9cd6ea98e5 100644
--- a/packages/ui/src/css/tokens.css
+++ b/packages/ui/src/css/tokens.css
@@ -122,17 +122,19 @@
/* Foreground colors */
--bui-fg-primary: var(--bui-black);
--bui-fg-secondary: var(--bui-gray-7);
- --bui-fg-link: #1f5493;
- --bui-fg-link-hover: #1f2d5c;
--bui-fg-disabled: #9e9e9e;
--bui-fg-solid: var(--bui-white);
--bui-fg-solid-disabled: #98a8bc;
- --bui-fg-tint: #1f5493;
- --bui-fg-tint-disabled: var(--bui-gray-5);
- --bui-fg-danger: #991919;
- --bui-fg-warning: #92310a;
- --bui-fg-success: #116932;
- --bui-fg-info: #173da6;
+
+ /* Foreground Statuses */
+ --bui-fg-danger-on-bg: #991919;
+ --bui-fg-warning-on-bg: #92310a;
+ --bui-fg-success-on-bg: #116932;
+ --bui-fg-info-on-bg: #173da6;
+ --bui-fg-danger: #ec3b18;
+ --bui-fg-warning: #ef7a32;
+ --bui-fg-success: #1ed760;
+ --bui-fg-info: #0d74ce;
/* Border colors */
--bui-border: rgba(0, 0, 0, 0.1);
@@ -210,17 +212,19 @@
/* Foreground colors */
--bui-fg-primary: var(--bui-white);
--bui-fg-secondary: var(--bui-gray-7);
- --bui-fg-link: #9cc9ff;
- --bui-fg-link-hover: #7eb5f7;
--bui-fg-disabled: var(--bui-gray-7);
--bui-fg-solid: #101821;
--bui-fg-solid-disabled: #6191cc;
- --bui-fg-tint: #9cc9ff;
- --bui-fg-tint-disabled: var(--bui-gray-5);
- --bui-fg-danger: #fca5a5;
- --bui-fg-warning: #fdba74;
- --bui-fg-success: #86efac;
- --bui-fg-info: #a3cfff;
+
+ /* Foreground statuses */
+ --bui-fg-danger-on-bg: #fca5a5;
+ --bui-fg-warning-on-bg: #fdba74;
+ --bui-fg-success-on-bg: #86efac;
+ --bui-fg-info-on-bg: #a3cfff;
+ --bui-fg-danger: #ff5a30;
+ --bui-fg-warning: #ffa057;
+ --bui-fg-success: #1ed760;
+ --bui-fg-info: #70b8ff;
/* Border colors */
--bui-border: rgba(255, 255, 255, 0.12);
diff --git a/packages/ui/src/types.ts b/packages/ui/src/types.ts
index 0b23dfd10e..933e1d8aa9 100644
--- a/packages/ui/src/types.ts
+++ b/packages/ui/src/types.ts
@@ -131,7 +131,7 @@ export type TextVariants =
export type TextColors = 'primary' | 'secondary';
/** @public */
-export type TextColorStatus = 'danger' | 'warning' | 'success';
+export type TextColorStatus = 'danger' | 'warning' | 'success' | 'info';
/** @public */
export type TextWeights = 'regular' | 'bold';
diff --git a/plugins/mui-to-bui/src/components/BuiThemerPage/convertMuiToBuiTheme.test.ts b/plugins/mui-to-bui/src/components/BuiThemerPage/convertMuiToBuiTheme.test.ts
index 48bb318a71..a5f7cfd36f 100644
--- a/plugins/mui-to-bui/src/components/BuiThemerPage/convertMuiToBuiTheme.test.ts
+++ b/plugins/mui-to-bui/src/components/BuiThemerPage/convertMuiToBuiTheme.test.ts
@@ -151,6 +151,10 @@ describe('convertMuiToBuiTheme', () => {
expect(result.css).toContain('--bui-bg-danger: #ffcdd2;');
expect(result.css).toContain('--bui-bg-warning: #ffe0b2;');
expect(result.css).toContain('--bui-bg-success: #c8e6c9;');
+ // Info background may be hex or rgba depending on theme
+ expect(result.css).toMatch(
+ /--bui-bg-info:\s*(#[0-9a-f]{6}|rgba?\([^)]*\));/i,
+ );
});
it('should generate foreground colors correctly', () => {
@@ -178,10 +182,8 @@ describe('convertMuiToBuiTheme', () => {
const result = convertMuiToBuiTheme(theme);
- expect(result.css).toContain('--bui-fg-link: #1976d2;');
- expect(result.css).toContain('--bui-fg-link-hover: #115293;');
expect(result.css).toContain('--bui-fg-disabled: #cccccc;');
- // Foreground danger/warning/success may be hex or rgb depending on theme
+ // Foreground status colors (standalone)
expect(result.css).toMatch(
/--bui-fg-danger:\s*(#[0-9a-f]{6}|rgb\([^)]*\));/i,
);
@@ -191,6 +193,22 @@ describe('convertMuiToBuiTheme', () => {
expect(result.css).toMatch(
/--bui-fg-success:\s*(#[0-9a-f]{6}|rgb\([^)]*\));/i,
);
+ expect(result.css).toMatch(
+ /--bui-fg-info:\s*(#[0-9a-f]{6}|rgb\([^)]*\));/i,
+ );
+ // Foreground status colors (on background)
+ expect(result.css).toMatch(
+ /--bui-fg-danger-on-bg:\s*(#[0-9a-f]{6}|rgb\([^)]*\));/i,
+ );
+ expect(result.css).toMatch(
+ /--bui-fg-warning-on-bg:\s*(#[0-9a-f]{6}|rgb\([^)]*\));/i,
+ );
+ expect(result.css).toMatch(
+ /--bui-fg-success-on-bg:\s*(#[0-9a-f]{6}|rgb\([^)]*\));/i,
+ );
+ expect(result.css).toMatch(
+ /--bui-fg-info-on-bg:\s*(#[0-9a-f]{6}|rgb\([^)]*\));/i,
+ );
});
it('should generate border colors correctly', () => {
@@ -215,6 +233,10 @@ describe('convertMuiToBuiTheme', () => {
expect(result.css).toContain('--bui-border-danger: #f44336;');
expect(result.css).toContain('--bui-border-warning: #ff9800;');
expect(result.css).toContain('--bui-border-success: #4caf50;');
+ // Info border may be hex or rgb depending on theme
+ expect(result.css).toMatch(
+ /--bui-border-info:\s*(#[0-9a-f]{6}|rgb\([^)]*\));/i,
+ );
});
it('should handle function-based spacing', () => {
diff --git a/plugins/mui-to-bui/src/components/BuiThemerPage/convertMuiToBuiTheme.ts b/plugins/mui-to-bui/src/components/BuiThemerPage/convertMuiToBuiTheme.ts
index 029d70cec7..dc72e3d597 100644
--- a/plugins/mui-to-bui/src/components/BuiThemerPage/convertMuiToBuiTheme.ts
+++ b/plugins/mui-to-bui/src/components/BuiThemerPage/convertMuiToBuiTheme.ts
@@ -94,16 +94,17 @@ function generateBuiVariables(theme: Mui5Theme): Record {
Object.entries({
primary: palette.text.primary,
secondary: palette.textSubtle,
- link: palette.link ?? palette.primary.main,
- 'link-hover': palette.linkHover ?? palette.primary.dark,
disabled: palette.text.disabled,
solid: palette.primary.contrastText,
'solid-disabled': palette.text.disabled,
- tint: palette.textSubtle,
- 'tint-disabled': palette.textVerySubtle,
- danger: palette.error.dark,
- warning: palette.warning.dark,
- success: palette.success.dark,
+ danger: palette.error.main,
+ warning: palette.warning.main,
+ success: palette.success.main,
+ info: palette.info?.main ?? palette.primary.main,
+ 'danger-on-bg': palette.error.dark,
+ 'warning-on-bg': palette.warning.dark,
+ 'success-on-bg': palette.success.dark,
+ 'info-on-bg': palette.info?.dark ?? palette.primary.dark,
}).forEach(([key, value]) => {
styleObject[`--bui-fg-${key}`] = value;
});
@@ -118,13 +119,10 @@ function generateBuiVariables(theme: Mui5Theme): Record {
'solid-hover': blend(palette.primary.main, palette.primary.dark, 0.5),
'solid-pressed': palette.primary.dark,
'solid-disabled': palette.action.disabledBackground,
- tint: 'transparent',
- 'tint-hover': alpha(palette.primary.main, 0.4),
- 'tint-pressed': alpha(palette.primary.main, 0.6),
- 'tint-disabled': palette.action.disabledBackground,
danger: palette.error.light,
warning: palette.warning.light,
success: palette.success.light,
+ info: palette.info?.light ?? alpha(palette.primary.main, 0.1),
}).forEach(([key, value]) => {
styleObject[`--bui-bg-${key}`] = value;
});
@@ -134,6 +132,7 @@ function generateBuiVariables(theme: Mui5Theme): Record {
danger: palette.error.main,
warning: palette.warning.main,
success: palette.success.main,
+ info: palette.info?.main ?? palette.primary.main,
}).forEach(([key, value]) => {
styleObject[`--bui-border-${key}`] = value;
});
diff --git a/yarn.lock b/yarn.lock
index 9c6c9c034f..d5683239f0 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -27589,6 +27589,13 @@ __metadata:
languageName: node
linkType: hard
+"cookie-signature@npm:1.0.7, cookie-signature@npm:~1.0.6":
+ version: 1.0.7
+ resolution: "cookie-signature@npm:1.0.7"
+ checksum: 10/1a62808cd30d15fb43b70e19829b64d04b0802d8ef00275b57d152de4ae6a3208ca05c197b6668d104c4d9de389e53ccc2d3bc6bcaaffd9602461417d8c40710
+ languageName: node
+ linkType: hard
+
"cookie-signature@npm:^1.2.1, cookie-signature@npm:^1.2.2":
version: 1.2.2
resolution: "cookie-signature@npm:1.2.2"
@@ -27596,14 +27603,7 @@ __metadata:
languageName: node
linkType: hard
-"cookie-signature@npm:~1.0.6, cookie-signature@npm:~1.0.7":
- version: 1.0.7
- resolution: "cookie-signature@npm:1.0.7"
- checksum: 10/1a62808cd30d15fb43b70e19829b64d04b0802d8ef00275b57d152de4ae6a3208ca05c197b6668d104c4d9de389e53ccc2d3bc6bcaaffd9602461417d8c40710
- languageName: node
- linkType: hard
-
-"cookie@npm:0.7.2, cookie@npm:^0.7.0, cookie@npm:^0.7.1, cookie@npm:^0.7.2, cookie@npm:~0.7.1, cookie@npm:~0.7.2":
+"cookie@npm:0.7.2, cookie@npm:^0.7.0, cookie@npm:^0.7.1, cookie@npm:^0.7.2, cookie@npm:~0.7.1":
version: 0.7.2
resolution: "cookie@npm:0.7.2"
checksum: 10/24b286c556420d4ba4e9bc09120c9d3db7d28ace2bd0f8ccee82422ce42322f73c8312441271e5eefafbead725980e5996cc02766dbb89a90ac7f5636ede608f
@@ -28487,7 +28487,7 @@ __metadata:
languageName: node
linkType: hard
-"debug@npm:2.6.9, debug@npm:^2.6.0, debug@npm:~2.6.9":
+"debug@npm:2.6.9, debug@npm:^2.6.0":
version: 2.6.9
resolution: "debug@npm:2.6.9"
dependencies:
@@ -31059,18 +31059,18 @@ __metadata:
linkType: hard
"express-session@npm:^1.17.1, express-session@npm:^1.17.3":
- version: 1.19.0
- resolution: "express-session@npm:1.19.0"
+ version: 1.18.2
+ resolution: "express-session@npm:1.18.2"
dependencies:
- cookie: "npm:~0.7.2"
- cookie-signature: "npm:~1.0.7"
- debug: "npm:~2.6.9"
+ cookie: "npm:0.7.2"
+ cookie-signature: "npm:1.0.7"
+ debug: "npm:2.6.9"
depd: "npm:~2.0.0"
on-headers: "npm:~1.1.0"
parseurl: "npm:~1.3.3"
- safe-buffer: "npm:~5.2.1"
+ safe-buffer: "npm:5.2.1"
uid-safe: "npm:~2.1.5"
- checksum: 10/5f36b51d344ec40adb5b9cd8a915fd694cdaf64832632411d4f6e6de8e9a83d873a20389e9c3cce966fece76a18c0384c5f2763b3ac089f801e8d6e92cb543e6
+ checksum: 10/1a89a4d3e579e1d2a729dc604c254c3e942b24a279681371c2d8042b1080f9e6de4ca787a091ec1a9178c9f2cc5c19bcb9f3929632d44db8972263e26c2cc4b8
languageName: node
linkType: hard
@@ -45678,7 +45678,7 @@ __metadata:
languageName: node
linkType: hard
-"safe-buffer@npm:5.2.1, safe-buffer@npm:>=5.1.0, safe-buffer@npm:^5.0.1, safe-buffer@npm:^5.1.0, safe-buffer@npm:^5.1.1, safe-buffer@npm:^5.1.2, safe-buffer@npm:^5.2.1, safe-buffer@npm:~5.2.0, safe-buffer@npm:~5.2.1":
+"safe-buffer@npm:5.2.1, safe-buffer@npm:>=5.1.0, safe-buffer@npm:^5.0.1, safe-buffer@npm:^5.1.0, safe-buffer@npm:^5.1.1, safe-buffer@npm:^5.1.2, safe-buffer@npm:^5.2.1, safe-buffer@npm:~5.2.0":
version: 5.2.1
resolution: "safe-buffer@npm:5.2.1"
checksum: 10/32872cd0ff68a3ddade7a7617b8f4c2ae8764d8b7d884c651b74457967a9e0e886267d3ecc781220629c44a865167b61c375d2da6c720c840ecd73f45d5d9451