From eb12d63c147a437cdca2df1a9361fcc1f3882d42 Mon Sep 17 00:00:00 2001 From: Tamas Kovacs Date: Thu, 22 Jan 2026 15:25:59 +0100 Subject: [PATCH] feat(ui-alerts): rework Alert INSTUI-4782 --- docs/guides/upgrade-guide.md | 17 +++- .../src/Alert/__tests__/Alert.test.tsx | 20 +++-- packages/ui-alerts/src/Alert/index.tsx | 21 +++-- packages/ui-alerts/src/Alert/styles.ts | 16 ++-- packages/ui-alerts/src/Alert/theme.ts | 90 ------------------- 5 files changed, 48 insertions(+), 116 deletions(-) delete mode 100644 packages/ui-alerts/src/Alert/theme.ts diff --git a/docs/guides/upgrade-guide.md b/docs/guides/upgrade-guide.md index 87d94e1751..a49123ca9a 100644 --- a/docs/guides/upgrade-guide.md +++ b/docs/guides/upgrade-guide.md @@ -59,7 +59,20 @@ type: example ``` -## API Changes +### Alert + +```js +--- +type: embed +--- + + +``` ### Breadcrumb @@ -367,6 +380,7 @@ type: embed /> ``` + ### RadioInput - Setting `readonly` does not set the low level `` to disabled, but to `readonly`. This also means that the input is still focusable when `readonly` @@ -604,6 +618,7 @@ type: embed /> ``` + ### RangeInput ```js diff --git a/packages/ui-alerts/src/Alert/__tests__/Alert.test.tsx b/packages/ui-alerts/src/Alert/__tests__/Alert.test.tsx index 95129fab3e..0184e6d4fc 100644 --- a/packages/ui-alerts/src/Alert/__tests__/Alert.test.tsx +++ b/packages/ui-alerts/src/Alert/__tests__/Alert.test.tsx @@ -29,7 +29,7 @@ import '@testing-library/jest-dom' import userEvent from '@testing-library/user-event' import { Alert } from '../index' import type { AlertProps } from '../props' -import { IconGroupLine } from '@instructure/ui-icons' +import { GroupInstUIIcon } from '@instructure/ui-icons' describe('', () => { let srdiv: HTMLDivElement | null @@ -97,10 +97,10 @@ describe('', () => { NonNullable, string > = { - error: 'IconNo', - info: 'IconInfoBorderless', - success: 'IconCheckMark', - warning: 'IconWarningBorderless' + error: 'CircleX', + info: 'Info', + success: 'CircleCheck', + warning: 'TriangleAlert' } ;( @@ -115,7 +115,7 @@ describe('', () => { Success: Sample alert text. ) - const icon = container.querySelector('svg[class$="-svgIcon"]') + const icon = container.querySelector('svg[class^="lucide"]') expect(icon).toHaveAttribute('name', iconComponent) }) @@ -167,10 +167,12 @@ describe('', () => { }) it('should render an icon when provided as the `renderIcon` prop', () => { - const { container } = render(} />) - const icon = container.querySelector('svg[class$="-svgIcon"]') + const { container } = render( + } /> + ) + const icon = container.querySelector('svg[class^="lucide"]') - expect(icon).toHaveAttribute('name', 'IconGroup') + expect(icon).toHaveAttribute('name', 'Group') expect(icon).toBeInTheDocument() }) diff --git a/packages/ui-alerts/src/Alert/index.tsx b/packages/ui-alerts/src/Alert/index.tsx index 23a101354c..4c10d5a6ea 100644 --- a/packages/ui-alerts/src/Alert/index.tsx +++ b/packages/ui-alerts/src/Alert/index.tsx @@ -36,17 +36,16 @@ import { View } from '@instructure/ui-view' import type { ViewOwnProps } from '@instructure/ui-view' import { ScreenReaderContent } from '@instructure/ui-a11y-content' import { - IconCheckMarkSolid, - IconInfoBorderlessSolid, - IconWarningBorderlessSolid, - IconNoSolid + InfoInstUIIcon, + XCircleInstUIIcon, + CircleCheckInstUIIcon, + TriangleAlertInstUIIcon } from '@instructure/ui-icons' import { Transition } from '@instructure/ui-motion' import { logError as error } from '@instructure/console' -import { withStyleRework as withStyle } from '@instructure/emotion' +import { withStyle } from '@instructure/emotion' import generateStyle from './styles' -import generateComponentTheme from './theme' import { allowedProps } from './props' import type { AlertProps, AlertState } from './props' @@ -57,7 +56,7 @@ category: components --- **/ @withDeterministicId() -@withStyle(generateStyle, generateComponentTheme) +@withStyle(generateStyle) class Alert extends Component { static readonly componentId = 'Alert' @@ -88,10 +87,10 @@ class Alert extends Component { srid: string variantUI = { - error: IconNoSolid, - info: IconInfoBorderlessSolid, - success: IconCheckMarkSolid, - warning: IconWarningBorderlessSolid + error: XCircleInstUIIcon, + info: InfoInstUIIcon, + success: CircleCheckInstUIIcon, + warning: TriangleAlertInstUIIcon } ref: Element | null = null diff --git a/packages/ui-alerts/src/Alert/styles.ts b/packages/ui-alerts/src/Alert/styles.ts index 38a264fdb5..0aedd24159 100644 --- a/packages/ui-alerts/src/Alert/styles.ts +++ b/packages/ui-alerts/src/Alert/styles.ts @@ -22,7 +22,8 @@ * SOFTWARE. */ -import type { AlertTheme } from '@instructure/shared-types' +import type { NewComponentTypes, SharedTokens } from '@instructure/ui-themes' +import { boxShadowObjectsToCSSString } from '@instructure/ui-themes' import type { AlertProps, AlertStyle } from './props' /** @@ -36,8 +37,9 @@ import type { AlertProps, AlertStyle } from './props' * @return {Object} The final style object, which will be used in the component */ const generateStyle = ( - componentTheme: AlertTheme, - props: AlertProps + componentTheme: NewComponentTypes['Alert'], + props: AlertProps, + sharedTokens: SharedTokens ): AlertStyle => { const { variant, hasShadow } = props @@ -84,7 +86,11 @@ const generateStyle = ( borderStyle: componentTheme.borderStyle, borderRadius: componentTheme.borderRadius, ...variantStyles[variant!].alert, - ...(hasShadow && { boxShadow: componentTheme.boxShadow }) + ...(hasShadow && { + boxShadow: boxShadowObjectsToCSSString( + sharedTokens.boxShadow.elevation4 + ) + }) }, icon: { color: componentTheme.iconColor, @@ -116,7 +122,7 @@ const generateStyle = ( fontFamily: componentTheme.contentFontFamily, fontWeight: componentTheme.contentFontWeight, lineHeight: componentTheme.contentLineHeight, - padding: componentTheme.contentPadding + padding: `${componentTheme.contentPaddingVertical} ${componentTheme.contentPaddingHorizontal}` }, variantScreenReaderLabel: { position: 'absolute', diff --git a/packages/ui-alerts/src/Alert/theme.ts b/packages/ui-alerts/src/Alert/theme.ts deleted file mode 100644 index 09618b6e54..0000000000 --- a/packages/ui-alerts/src/Alert/theme.ts +++ /dev/null @@ -1,90 +0,0 @@ -/* - * The MIT License (MIT) - * - * Copyright (c) 2015 - present Instructure, Inc. - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -import type { AlertTheme } from '@instructure/shared-types' -import type { Theme, ThemeSpecificStyle } from '@instructure/ui-themes' - -/** - * Generates the theme object for the component from the theme and provided additional information - * @param {Object} theme The actual theme object. - * @return {Object} The final theme object with the overrides and component variables - */ -const generateComponentTheme = (theme: Theme): AlertTheme => { - const { - colors, - spacing, - borders, - typography, - shadows, - key: themeName - } = theme - - const themeSpecificStyle: ThemeSpecificStyle = { - canvas: { - color: theme['ic-brand-font-color-dark'] - } - } - - const componentVariables: AlertTheme = { - background: colors?.contrasts?.white1010, - color: colors?.contrasts?.grey125125, - marginTop: spacing?.small, - - borderRadius: borders?.radiusMedium, - borderWidth: borders?.widthMedium, - borderStyle: borders?.style, - - contentPadding: `${spacing?.small} ${spacing?.medium}`, - contentFontSize: typography?.fontSizeMedium, - contentFontFamily: typography?.fontFamily, - contentFontWeight: typography?.fontWeightNormal, - contentLineHeight: typography?.lineHeightCondensed, - - closeButtonMarginTop: spacing?.xSmall, - closeButtonMarginRight: spacing?.xxSmall, - - iconColor: colors?.contrasts?.white1010, - - successBorderColor: colors?.contrasts?.green4570, - successIconBackground: colors?.contrasts?.green4570, - - infoBorderColor: colors?.contrasts?.blue4570, - infoIconBackground: colors?.contrasts?.blue4570, - - warningBorderColor: colors?.contrasts?.orange4570, - warningIconBackground: colors?.contrasts?.orange4570, - - dangerBorderColor: colors?.contrasts?.red4570, - dangerIconBackground: colors?.contrasts?.red4570, - - boxShadow: shadows?.depth2 - } - - return { - ...componentVariables, - ...themeSpecificStyle[themeName] - } -} - -export default generateComponentTheme