diff --git a/docs/guides/upgrade-guide.md b/docs/guides/upgrade-guide.md index 4e542bd60b..ebef43e9f6 100644 --- a/docs/guides/upgrade-guide.md +++ b/docs/guides/upgrade-guide.md @@ -146,6 +146,18 @@ type: example - theme variable `topMargin` is now removed +### Tag + +- theme variable `defaultIconColor` is now removed +- theme variable `defaultIconHoverColor` is now removed +- theme variable `inlineIconColor` is now removed +- theme variable `inlineIconHoverColor` is now removed +- theme variable `focusOutlineColor` is now removed +- theme variable `focusOutlineStyle` is now removed +- theme variable `focusOutlineWidth` is now removed +- theme variable `padding` is now removed, `paddingHorizontal` can be used to set horizonal padding +- theme variable `paddingSmall` is now removed, `paddingHorizontalSmall` can be used to set horizonal padding + ### TextArea - theme variable `smallFontSize` is now renamed to `fontSizeSm` diff --git a/packages/ui-tag/package.json b/packages/ui-tag/package.json index 4c3eefa8fa..7dbf430e2a 100644 --- a/packages/ui-tag/package.json +++ b/packages/ui-tag/package.json @@ -30,6 +30,7 @@ "@instructure/ui-color-utils": "workspace:*", "@instructure/ui-dom-utils": "workspace:*", "@instructure/ui-icons": "workspace:*", + "@instructure/ui-icons-lucide": "workspace:*", "@instructure/ui-react-utils": "workspace:*", "@instructure/ui-view": "workspace:*" }, diff --git a/packages/ui-tag/src/Tag/__tests__/Tag.test.tsx b/packages/ui-tag/src/Tag/__tests__/Tag.test.tsx index 86ff5b8967..8a299a6d67 100644 --- a/packages/ui-tag/src/Tag/__tests__/Tag.test.tsx +++ b/packages/ui-tag/src/Tag/__tests__/Tag.test.tsx @@ -83,7 +83,7 @@ describe('', async () => { ) const icon = container.querySelector('svg') - expect(icon).toHaveAttribute('name', 'IconX') + expect(icon).toHaveAttribute('name', 'X') }) it('should meet a11y standards', async () => { diff --git a/packages/ui-tag/src/Tag/index.tsx b/packages/ui-tag/src/Tag/index.tsx index 802c36649d..c15be54021 100644 --- a/packages/ui-tag/src/Tag/index.tsx +++ b/packages/ui-tag/src/Tag/index.tsx @@ -24,15 +24,14 @@ import { Component } from 'react' -import { IconXLine } from '@instructure/ui-icons' +import { XInstUIIcon } from '@instructure/ui-icons-lucide' import { View } from '@instructure/ui-view' import type { ViewProps } from '@instructure/ui-view' import { omitProps } from '@instructure/ui-react-utils' import { isActiveElement } from '@instructure/ui-dom-utils' -import { withStyleRework as withStyle } from '@instructure/emotion' +import { withStyle } from '@instructure/emotion' import generateStyle from './styles' -import generateComponentTheme from './theme' import type { TagProps } from './props' import { allowedProps } from './props' @@ -42,7 +41,7 @@ category: components --- **/ -@withStyle(generateStyle, generateComponentTheme) +@withStyle(generateStyle) class Tag extends Component { static readonly componentId = 'Tag' @@ -55,6 +54,10 @@ class Tag extends Component { readOnly: false } + state = { + iconHovered: false + } + ref: Element | null = null componentDidMount() { @@ -73,6 +76,14 @@ class Tag extends Component { this.ref && (this.ref as HTMLElement).focus() } + handleIconMouseEnter = () => { + this.setState({ iconHovered: true }) + } + + handleIconMouseLeave = () => { + this.setState({ iconHovered: false }) + } + handleClick = (e: React.MouseEvent) => { const { disabled, readOnly, onClick } = this.props @@ -102,7 +113,8 @@ class Tag extends Component { title, onClick, margin, - styles + styles, + variant } = this.props const passthroughProps = View.omitViewProps( @@ -110,6 +122,18 @@ class Tag extends Component { Tag ) + const getIconColor = () => { + if (disabled) { + return 'mutedColor' + } + if (variant === 'inline') { + return this.state.iconHovered + ? 'actionSecondaryHoverColor' + : 'actionSecondaryBaseColor' + } + return this.state.iconHovered ? 'actionSecondaryHoverColor' : 'baseColor' + } + return ( { display={undefined} title={title || (typeof text === 'string' ? text : undefined)} data-cid="Tag" + onMouseEnter={this.handleIconMouseEnter} + onMouseLeave={this.handleIconMouseLeave} > {text} - {onClick && dismissible ? : null} + {onClick && dismissible ? ( + + ) : null} ) } diff --git a/packages/ui-tag/src/Tag/styles.ts b/packages/ui-tag/src/Tag/styles.ts index b65703e738..3080da008e 100644 --- a/packages/ui-tag/src/Tag/styles.ts +++ b/packages/ui-tag/src/Tag/styles.ts @@ -22,8 +22,9 @@ * SOFTWARE. */ -import type { TagTheme } from '@instructure/shared-types' +import type { NewComponentTypes, SharedTokens } from '@instructure/ui-themes' import type { TagProps, TagStyle } from './props' +import { calcFocusOutlineStyles } from '@instructure/emotion' /** * --- @@ -32,10 +33,14 @@ import type { TagProps, TagStyle } from './props' * Generates the style object from the theme and provided additional information * @param {Object} componentTheme The theme variable object. * @param {Object} props the props of the component, the style is applied to - * @param {Object} state the state of the component, the style is applied to + * @param {Object} sharedTokens the state of the component, the style is applied to * @return {Object} The final style object, which will be used in the component */ -const generateStyle = (componentTheme: TagTheme, props: TagProps): TagStyle => { +const generateStyle = ( + componentTheme: NewComponentTypes['Tag'], + props: TagProps, + sharedTokens: SharedTokens +): TagStyle => { const { variant, size, dismissible, onClick, disabled } = props const isButton = !!onClick @@ -43,7 +48,8 @@ const generateStyle = (componentTheme: TagTheme, props: TagProps): TagStyle => { const sizeVariants = { small: { tag: { - padding: componentTheme.paddingSmall, + paddingLeft: componentTheme.paddingHorizontalSmall, + paddingRight: componentTheme.paddingHorizontalSmall, fontSize: componentTheme.fontSizeSmall }, text: { @@ -53,7 +59,8 @@ const generateStyle = (componentTheme: TagTheme, props: TagProps): TagStyle => { }, medium: { tag: { - padding: componentTheme.padding, + paddingLeft: componentTheme.paddingHorizontal, + paddingRight: componentTheme.paddingHorizontal, fontSize: `calc(${componentTheme.fontSizeMedium} - 0.0625rem)` }, text: { @@ -63,7 +70,8 @@ const generateStyle = (componentTheme: TagTheme, props: TagProps): TagStyle => { }, large: { tag: { - padding: componentTheme.padding, + paddingLeft: componentTheme.paddingHorizontalSmall, + paddingRight: componentTheme.paddingHorizontal, fontSize: `calc(${componentTheme.fontSizeLarge} - 0.0625rem)` }, text: { @@ -99,7 +107,7 @@ const generateStyle = (componentTheme: TagTheme, props: TagProps): TagStyle => { tagBefore: { content: '""', boxSizing: 'border-box', - border: `${componentTheme.focusOutlineWidth} ${componentTheme.focusOutlineStyle} ${componentTheme.focusOutlineColor}`, + border: calcFocusOutlineStyles(sharedTokens.focusOutline), position: 'absolute', top: '-0.3125rem', bottom: '-0.3125rem', @@ -151,15 +159,7 @@ const generateStyle = (componentTheme: TagTheme, props: TagProps): TagStyle => { } const iconVariantVariants = { - default: { - ...(dismissible && { - color: componentTheme.defaultIconColor, - - '[class$="-tag"]:hover > &': { - color: componentTheme.defaultIconHoverColor - } - }) - }, + default: {}, inline: { ...(dismissible && { backgroundColor: componentTheme.inlineIconColor, diff --git a/packages/ui-tag/src/Tag/theme.ts b/packages/ui-tag/src/Tag/theme.ts deleted file mode 100644 index dbbda9ee8a..0000000000 --- a/packages/ui-tag/src/Tag/theme.ts +++ /dev/null @@ -1,92 +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 { Theme, ThemeSpecificStyle } from '@instructure/ui-themes' -import { TagTheme } from '@instructure/shared-types' - -/** - * 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): TagTheme => { - const { borders, colors, forms, spacing, typography, key: themeName } = theme - - const themeSpecificStyle: ThemeSpecificStyle = { - 'canvas-high-contrast': { - defaultBackground: colors?.contrasts?.white1010, - defaultBorderColor: colors?.contrasts?.grey125125 - }, - canvas: { - focusOutlineColor: theme['ic-brand-primary'], - defaultIconColor: theme['ic-brand-font-color-dark'], - defaultIconHoverColor: theme['ic-brand-primary'], - defaultColor: theme['ic-brand-font-color-dark'] - } - } - const componentVariables: TagTheme = { - fontFamily: typography.fontFamily, - heightSmall: '1.3125rem', // matches Pill component height - heightMedium: forms.inputHeightSmall, - heightLarge: forms.inputHeightMedium, - fontSizeSmall: typography.fontSizeXSmall, - fontSizeMedium: typography.fontSizeSmall, - fontSizeLarge: typography.fontSizeMedium, - padding: `0 ${spacing.xSmall}`, - paddingSmall: `0 ${spacing.xSmall}`, - focusOutlineColor: colors?.contrasts?.blue4570, - focusOutlineWidth: borders.widthMedium, - focusOutlineStyle: borders.style, - maxWidth: '10rem', - iconMargin: spacing.xSmall, - transitionTiming: '0.2s', - - defaultBackgroundHover: colors?.contrasts?.grey1214, - defaultBackground: colors?.contrasts?.grey1111, - defaultBorderColor: colors?.contrasts?.grey1424, - defaultBorderRadius: '999rem', - defaultBorderStyle: borders.style, - defaultBorderWidth: borders.widthSmall, - defaultColor: colors?.contrasts?.grey125125, - defaultIconColor: colors?.contrasts?.grey125125, - defaultIconHoverColor: colors?.contrasts?.blue4570, - - inlineBackgroundHover: colors?.contrasts?.grey1111, - inlineBackground: colors?.contrasts?.white1010, - inlineBorderColor: colors?.contrasts?.grey4570, - inlineBorderRadius: borders.radiusMedium, - inlineBorderStyle: borders.style, - inlineBorderWidth: borders.widthSmall, - inlineColor: colors?.contrasts?.grey125125, - inlineIconColor: colors?.contrasts?.grey4570, - inlineIconHoverColor: colors?.contrasts?.blue4570 - } - - return { - ...componentVariables, - ...themeSpecificStyle[themeName] - } -} - -export default generateComponentTheme diff --git a/packages/ui-tag/tsconfig.build.json b/packages/ui-tag/tsconfig.build.json index 6f772625d1..ce9e5dbf47 100644 --- a/packages/ui-tag/tsconfig.build.json +++ b/packages/ui-tag/tsconfig.build.json @@ -28,6 +28,9 @@ { "path": "../ui-icons/tsconfig.build.json" }, + { + "path": "../ui-icons-lucide/tsconfig.build.json" + }, { "path": "../ui-react-utils/tsconfig.build.json" }, diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 744c754577..c6e16675e9 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -4377,6 +4377,9 @@ importers: '@instructure/ui-icons': specifier: workspace:* version: link:../ui-icons + '@instructure/ui-icons-lucide': + specifier: workspace:* + version: link:../ui-icons-lucide '@instructure/ui-react-utils': specifier: workspace:* version: link:../ui-react-utils