From cef00c7be2d88592dd65431217943c6b8cfa04a7 Mon Sep 17 00:00:00 2001 From: Tamas Kovacs Date: Wed, 11 Feb 2026 10:09:50 +0100 Subject: [PATCH] feat(ui-popover,ui-options,ui-menu): rework Menu and Options INSTUI-4796 --- docs/guides/upgrade-guide.md | 91 +++++++++++++++++++ packages/ui-menu/src/Menu/MenuItem/index.tsx | 71 ++++++++++++--- packages/ui-menu/src/Menu/MenuItem/props.ts | 4 +- packages/ui-menu/src/Menu/MenuItem/styles.ts | 41 ++++++--- packages/ui-menu/src/Menu/MenuItem/theme.ts | 72 --------------- .../ui-menu/src/Menu/MenuItemGroup/index.tsx | 5 +- .../ui-menu/src/Menu/MenuItemGroup/styles.ts | 8 +- .../ui-menu/src/Menu/MenuItemGroup/theme.ts | 56 ------------ .../src/Menu/MenuItemSeparator/index.tsx | 5 +- .../src/Menu/MenuItemSeparator/styles.ts | 6 +- .../src/Menu/MenuItemSeparator/theme.ts | 47 ---------- packages/ui-menu/src/Menu/index.tsx | 5 +- packages/ui-menu/src/Menu/styles.ts | 32 ++----- packages/ui-menu/src/Menu/theme.ts | 52 ----------- .../ui-options/src/Options/Item/index.tsx | 5 +- .../ui-options/src/Options/Item/styles.ts | 8 +- .../src/Options/Separator/index.tsx | 5 +- .../src/Options/Separator/styles.ts | 6 +- packages/ui-options/src/Options/index.tsx | 5 +- packages/ui-options/src/Options/styles.ts | 8 +- packages/ui-popover/src/Popover/index.tsx | 2 - 21 files changed, 217 insertions(+), 317 deletions(-) delete mode 100644 packages/ui-menu/src/Menu/MenuItem/theme.ts delete mode 100644 packages/ui-menu/src/Menu/MenuItemGroup/theme.ts delete mode 100644 packages/ui-menu/src/Menu/MenuItemSeparator/theme.ts delete mode 100644 packages/ui-menu/src/Menu/theme.ts diff --git a/docs/guides/upgrade-guide.md b/docs/guides/upgrade-guide.md index 54fde026e2..fef3ee78ad 100644 --- a/docs/guides/upgrade-guide.md +++ b/docs/guides/upgrade-guide.md @@ -391,6 +391,97 @@ type: embed ``` +### Menu + +Icons for checkbox and radio menu items are now positioned on the right side instead of the left. + +```js +--- +type: embed +--- + + +``` + +#### Menu.Item + +```js +--- +type: embed +--- + + +``` + +#### Menu.Group + +```js +--- +type: embed +--- + + +``` + +### Options + +```js +--- +type: embed +--- + + +``` + +#### Options.Item + +```js +--- +type: embed +--- + + +``` + +#### Options.Separator + +```js +--- +type: embed +--- + + +``` + ### NumberInput `error` or `success` messages are no longer displayed when the component is `readOnly` or `disabled`. diff --git a/packages/ui-menu/src/Menu/MenuItem/index.tsx b/packages/ui-menu/src/Menu/MenuItem/index.tsx index b66bead21f..a7c03094a7 100644 --- a/packages/ui-menu/src/Menu/MenuItem/index.tsx +++ b/packages/ui-menu/src/Menu/MenuItem/index.tsx @@ -25,7 +25,7 @@ import { Component } from 'react' import keycode from 'keycode' -import { IconCheckSolid, IconArrowOpenEndSolid } from '@instructure/ui-icons' +import { CheckInstUIIcon, ChevronRightInstUIIcon } from '@instructure/ui-icons' import { omitProps, getElementType, @@ -34,12 +34,11 @@ import { } from '@instructure/ui-react-utils' import { createChainedFunction } from '@instructure/ui-utils' import { isActiveElement, findDOMNode } from '@instructure/ui-dom-utils' -import { withStyleRework as withStyle } from '@instructure/emotion' +import { withStyle } from '@instructure/emotion' import { MenuContext } from '../../MenuContext' import generateStyle from './styles' -import generateComponentTheme from './theme' import { allowedProps } from './props' import type { MenuItemProps, MenuItemState } from './props' @@ -51,7 +50,7 @@ id: Menu.Item --- **/ @withDeterministicId() -@withStyle(generateStyle, generateComponentTheme) +@withStyle(generateStyle) class MenuItem extends Component { static readonly componentId = 'Menu.Item' @@ -67,12 +66,16 @@ class MenuItem extends Component { constructor(props: MenuItemProps) { super(props) + const state: MenuItemState = { + isHovered: false, + isFocused: false + } + if (typeof props.selected === 'undefined') { - this.state = { - selected: !!props.defaultSelected - } + state.selected = !!props.defaultSelected } + this.state = state this.labelId = props.deterministicId!('MenuItem__label') } @@ -176,6 +179,31 @@ class MenuItem extends Component { } } + handleMouseEnter = () => { + this.setState({ isHovered: true }) + } + + handleMouseLeave = () => { + this.setState({ isHovered: false }) + } + + handleFocusEvent = () => { + this.setState({ isFocused: true }) + } + + handleBlurEvent = () => { + this.setState({ isFocused: false }) + } + + getIconColor = () => { + const { type } = this.props + + if (type === 'flyout') { + return 'baseColor' + } + return this.selected ? 'inverseColor' : 'baseColor' + } + get elementType() { return getElementType(MenuItem, this.props) } @@ -211,17 +239,19 @@ class MenuItem extends Component { return ( + + {children} + {(type === 'checkbox' || type === 'radio') && ( - {this.selected && } + {this.selected && ( + + )} )} - - {children} - {type === 'flyout' && ( - + )} {renderLabelInfo && ( @@ -234,8 +264,17 @@ class MenuItem extends Component { } render() { - const { disabled, controls, onKeyDown, onKeyUp, type, href, target } = - this.props + const { + disabled, + controls, + onKeyDown, + onKeyUp, + onFocus, + onBlur, + type, + href, + target + } = this.props const props = omitProps(this.props, MenuItem.allowedProps) const ElementType = this.elementType @@ -263,6 +302,10 @@ class MenuItem extends Component { ref={this.handleRef} css={this.props.styles?.menuItem} onMouseOver={this.handleMouseOver} + onMouseEnter={this.handleMouseEnter} + onMouseLeave={this.handleMouseLeave} + onFocus={createChainedFunction(onFocus, this.handleFocusEvent)} + onBlur={createChainedFunction(onBlur, this.handleBlurEvent)} data-cid="MenuItem" > {this.renderContent()} diff --git a/packages/ui-menu/src/Menu/MenuItem/props.ts b/packages/ui-menu/src/Menu/MenuItem/props.ts index ab854a8314..61feb18c6a 100644 --- a/packages/ui-menu/src/Menu/MenuItem/props.ts +++ b/packages/ui-menu/src/Menu/MenuItem/props.ts @@ -124,7 +124,9 @@ const allowedProps: AllowedPropKeys = [ 'renderLabelInfo' ] type MenuItemState = { - selected: boolean + selected?: boolean + isHovered: boolean + isFocused: boolean } export type { MenuItemProps, MenuItemStyle, MenuItemState, OnMenuItemSelect } export { allowedProps } diff --git a/packages/ui-menu/src/Menu/MenuItem/styles.ts b/packages/ui-menu/src/Menu/MenuItem/styles.ts index 2a10c159df..637c1a2b91 100644 --- a/packages/ui-menu/src/Menu/MenuItem/styles.ts +++ b/packages/ui-menu/src/Menu/MenuItem/styles.ts @@ -22,7 +22,7 @@ * SOFTWARE. */ -import type { MenuItemTheme } from '@instructure/shared-types' +import type { NewComponentTypes } from '@instructure/ui-themes' import type { MenuItemProps, MenuItemStyle } from './props' /** @@ -36,10 +36,10 @@ import type { MenuItemProps, MenuItemStyle } from './props' * @return {Object} The final style object, which will be used in the component */ const generateStyle = ( - componentTheme: MenuItemTheme, + componentTheme: NewComponentTypes['MenuItem'], props: MenuItemProps ): MenuItemStyle => { - const { type, disabled } = props + const { type, disabled, selected } = props const isRadioOrCheckbox = type === 'checkbox' || type === 'radio' @@ -53,14 +53,14 @@ const generateStyle = ( const roleStyles = isRadioOrCheckbox ? { - paddingInlineStart: componentTheme.labelPadding + paddingInlineEnd: componentTheme.labelPadding } : {} const roleIconStyles = isRadioOrCheckbox ? { - insetInlineStart: componentTheme.iconPadding, - insetInlineEnd: 'auto' + insetInlineStart: 'auto', + insetInlineEnd: componentTheme.iconPadding } : {} @@ -72,6 +72,23 @@ const generateStyle = ( } : {} + const selectedStyles = selected + ? { + background: componentTheme.activeBackground, + '[class*="menuItem__label"]': { + color: componentTheme.activeLabelColor + } + } + : {} + + const selectedHighlightedStyles = selected + ? { + background: componentTheme.selectedHighlightedBackground + } + : { + background: componentTheme.highlightedBackground + } + const linkStyles = { textDecoration: 'none' } return { @@ -80,7 +97,7 @@ const generateStyle = ( position: 'relative', border: 'none', outline: 'none', - padding: componentTheme.padding, + padding: `${componentTheme.paddingVertical} ${componentTheme.paddingHorizontal}`, margin: '0', width: '100%', borderRadius: 'initial', @@ -101,13 +118,7 @@ const generateStyle = ( textDecoration: 'none', ...roleStyles, '&:focus, &:active, &:hover': { - background: componentTheme.activeBackground, - '[class*="menuItem__label"]': { - color: componentTheme.activeLabelColor - }, - '[class*="menuItem__icon"]': { - color: componentTheme.activeIconColor - } + ...selectedHighlightedStyles }, //removes extra ff button spacing '&::-moz-focus-inner': { @@ -116,6 +127,7 @@ const generateStyle = ( border: '0' }, ...disabledStyles, + ...selectedStyles, // NOTE: needs separate groups for `:is()` and `:-webkit-any()` because of css selector group validation (see https://www.w3.org/TR/selectors-3/#grouping) '&:is(a)': { @@ -133,7 +145,6 @@ const generateStyle = ( top: '0', width: '1em', height: '100%', - color: componentTheme.iconColor, ...roleIconStyles, ...flyoutIconStyles }, diff --git a/packages/ui-menu/src/Menu/MenuItem/theme.ts b/packages/ui-menu/src/Menu/MenuItem/theme.ts deleted file mode 100644 index 9bc6441f5d..0000000000 --- a/packages/ui-menu/src/Menu/MenuItem/theme.ts +++ /dev/null @@ -1,72 +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 { MenuItemTheme } 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): MenuItemTheme => { - const { colors, typography, spacing, key: themeName } = theme - - const themeSpecificStyle: ThemeSpecificStyle = { - canvas: { - labelColor: theme['ic-brand-font-color-dark'], - iconColor: theme['ic-brand-font-color-dark'], - activeBackground: theme['ic-brand-primary'] - } - } - - const componentVariables: MenuItemTheme = { - padding: `${spacing?.xSmall} ${spacing?.small}`, - - fontFamily: typography?.fontFamily, - fontWeight: typography?.fontWeightNormal, - lineHeight: typography?.lineHeightCondensed, - fontSize: typography?.fontSizeMedium, - labelPadding: spacing?.large, - - labelColor: colors?.contrasts?.grey125125, - background: colors?.contrasts?.white1010, - - iconColor: colors?.contrasts?.grey125125, - iconPadding: spacing?.small, - - activeBackground: colors?.contrasts?.blue4570, - activeLabelColor: colors?.contrasts?.white1010, - activeIconColor: colors?.contrasts?.white1010, - - labelInfoColor: colors?.contrasts?.grey5782 - } - - return { - ...componentVariables, - ...themeSpecificStyle[themeName] - } -} - -export default generateComponentTheme diff --git a/packages/ui-menu/src/Menu/MenuItemGroup/index.tsx b/packages/ui-menu/src/Menu/MenuItemGroup/index.tsx index ec0ca20de8..85a293a6bf 100644 --- a/packages/ui-menu/src/Menu/MenuItemGroup/index.tsx +++ b/packages/ui-menu/src/Menu/MenuItemGroup/index.tsx @@ -24,7 +24,7 @@ import { ComponentElement, Children, Component } from 'react' -import { withStyleRework as withStyle } from '@instructure/emotion' +import { withStyle } from '@instructure/emotion' import { omitProps, safeCloneElement, @@ -39,7 +39,6 @@ import { MenuItemSeparator } from '../MenuItemSeparator' import type { MenuSeparatorProps } from '../MenuItemSeparator/props' import generateStyle from './styles' -import generateComponentTheme from './theme' import { allowedProps } from './props' import type { MenuGroupProps, MenuGroupState } from './props' @@ -57,7 +56,7 @@ id: Menu.Group --- **/ @withDeterministicId() -@withStyle(generateStyle, generateComponentTheme) +@withStyle(generateStyle) class MenuItemGroup extends Component { static readonly componentId = 'Menu.Group' diff --git a/packages/ui-menu/src/Menu/MenuItemGroup/styles.ts b/packages/ui-menu/src/Menu/MenuItemGroup/styles.ts index 8bca9d7cbb..d1c0015ef6 100644 --- a/packages/ui-menu/src/Menu/MenuItemGroup/styles.ts +++ b/packages/ui-menu/src/Menu/MenuItemGroup/styles.ts @@ -22,7 +22,7 @@ * SOFTWARE. */ -import type { MenuGroupTheme } from '@instructure/shared-types' +import type { NewComponentTypes } from '@instructure/ui-themes' import type { MenuGroupStyle } from './props' /** @@ -35,7 +35,9 @@ import type { MenuGroupStyle } from './props' * @param {Object} state 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: MenuGroupTheme): MenuGroupStyle => { +const generateStyle = ( + componentTheme: NewComponentTypes['MenuGroup'] +): MenuGroupStyle => { return { menuItemGroup: { label: 'menuItemGroup', @@ -44,7 +46,7 @@ const generateStyle = (componentTheme: MenuGroupTheme): MenuGroupStyle => { label: { label: 'menuItemGroup__label', background: componentTheme.background, - padding: componentTheme.padding, + padding: `${componentTheme.paddingVertical} ${componentTheme.paddingHorizontal}`, display: 'block', fontSize: componentTheme.fontSize, fontFamily: componentTheme.fontFamily, diff --git a/packages/ui-menu/src/Menu/MenuItemGroup/theme.ts b/packages/ui-menu/src/Menu/MenuItemGroup/theme.ts deleted file mode 100644 index 6ceff78db8..0000000000 --- a/packages/ui-menu/src/Menu/MenuItemGroup/theme.ts +++ /dev/null @@ -1,56 +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 { MenuGroupTheme } 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): MenuGroupTheme => { - const { colors, spacing, typography, key: themeName } = theme - - const themeSpecificStyle: ThemeSpecificStyle = { - canvas: { - color: theme['ic-brand-font-color-dark'] - } - } - const componentVariables: MenuGroupTheme = { - fontSize: typography?.fontSizeMedium, - fontFamily: typography?.fontFamily, - fontWeight: typography?.fontWeightBold, - padding: `${spacing?.xSmall} ${spacing?.small}`, - color: colors?.contrasts?.grey125125, - background: colors?.contrasts?.white1010 - } - - return { - ...componentVariables, - ...themeSpecificStyle[themeName] - } -} - -export default generateComponentTheme diff --git a/packages/ui-menu/src/Menu/MenuItemSeparator/index.tsx b/packages/ui-menu/src/Menu/MenuItemSeparator/index.tsx index 39d3baa623..e38874e3a9 100644 --- a/packages/ui-menu/src/Menu/MenuItemSeparator/index.tsx +++ b/packages/ui-menu/src/Menu/MenuItemSeparator/index.tsx @@ -24,11 +24,10 @@ import { Component } from 'react' -import { withStyleRework as withStyle } from '@instructure/emotion' +import { withStyle } from '@instructure/emotion' import { omitProps } from '@instructure/ui-react-utils' import generateStyle from './styles' -import generateComponentTheme from './theme' import { allowedProps } from './props' import type { MenuSeparatorProps } from './props' @@ -40,7 +39,7 @@ id: Menu.Separator --- @module MenuItemSeparator **/ -@withStyle(generateStyle, generateComponentTheme) +@withStyle(generateStyle) class MenuItemSeparator extends Component { static readonly componentId = 'Menu.Separator' diff --git a/packages/ui-menu/src/Menu/MenuItemSeparator/styles.ts b/packages/ui-menu/src/Menu/MenuItemSeparator/styles.ts index 808329beab..e5fe1a5811 100644 --- a/packages/ui-menu/src/Menu/MenuItemSeparator/styles.ts +++ b/packages/ui-menu/src/Menu/MenuItemSeparator/styles.ts @@ -22,7 +22,7 @@ * SOFTWARE. */ -import type { MenuSeparatorTheme } from '@instructure/shared-types' +import type { NewComponentTypes } from '@instructure/ui-themes' import type { MenuSeparatorStyle } from './props' /** @@ -36,13 +36,13 @@ import type { MenuSeparatorStyle } from './props' * @return {Object} The final style object, which will be used in the component */ const generateStyle = ( - componentTheme: MenuSeparatorTheme + componentTheme: NewComponentTypes['MenuSeparator'] ): MenuSeparatorStyle => { return { menuItemSeparator: { label: 'menuItemSeparator', height: componentTheme.height, - margin: componentTheme.margin, + margin: `${componentTheme.marginVertical} ${componentTheme.marginHorizontal}`, overflow: 'hidden', background: componentTheme.background } diff --git a/packages/ui-menu/src/Menu/MenuItemSeparator/theme.ts b/packages/ui-menu/src/Menu/MenuItemSeparator/theme.ts deleted file mode 100644 index 635cb2459f..0000000000 --- a/packages/ui-menu/src/Menu/MenuItemSeparator/theme.ts +++ /dev/null @@ -1,47 +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 } from '@instructure/ui-themes' -import { MenuSeparatorTheme } 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): MenuSeparatorTheme => { - const { colors, spacing, borders } = theme - - const componentVariables: MenuSeparatorTheme = { - background: colors?.contrasts?.grey3045, - height: borders?.widthSmall, - margin: `0 ${spacing?.small}` - } - - return { - ...componentVariables - } -} - -export default generateComponentTheme diff --git a/packages/ui-menu/src/Menu/index.tsx b/packages/ui-menu/src/Menu/index.tsx index bb42dd2f02..3411e2bc63 100644 --- a/packages/ui-menu/src/Menu/index.tsx +++ b/packages/ui-menu/src/Menu/index.tsx @@ -41,10 +41,9 @@ import { MenuItemGroup } from './MenuItemGroup' import type { MenuGroupProps } from './MenuItemGroup/props' import { MenuItemSeparator } from './MenuItemSeparator' import type { MenuSeparatorProps } from './MenuItemSeparator/props' -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 { MenuProps } from './props' @@ -63,7 +62,7 @@ category: components --- **/ @withDeterministicId() -@withStyle(generateStyle, generateComponentTheme) +@withStyle(generateStyle) class Menu extends Component { static readonly componentId = 'Menu' static allowedProps = allowedProps diff --git a/packages/ui-menu/src/Menu/styles.ts b/packages/ui-menu/src/Menu/styles.ts index 200478f1a3..f2ac69bd0a 100644 --- a/packages/ui-menu/src/Menu/styles.ts +++ b/packages/ui-menu/src/Menu/styles.ts @@ -22,8 +22,9 @@ * SOFTWARE. */ -import type { MenuTheme } from '@instructure/shared-types' +import type { NewComponentTypes, SharedTokens } from '@instructure/ui-themes' import type { MenuStyle, MenuProps } from './props' +import { calcFocusOutlineStyles } from '@instructure/emotion' /** * --- @@ -36,8 +37,9 @@ import type { MenuStyle, MenuProps } from './props' * @return {Object} The final style object, which will be used in the component */ const generateStyle = ( - componentTheme: MenuTheme, - props: MenuProps + componentTheme: NewComponentTypes['Menu'], + props: MenuProps, + sharedTokens: SharedTokens ): MenuStyle => { const maxHeight = props.maxHeight ? { maxHeight: props.maxHeight, overflow: 'auto' } @@ -46,7 +48,6 @@ const generateStyle = ( return { menu: { label: 'menu', - ...maxHeight, minWidth: componentTheme.minWidth, maxWidth: componentTheme.maxWidth, listStyleType: 'none', @@ -56,26 +57,9 @@ const generateStyle = ( borderRadius: componentTheme.borderRadius, display: 'block', position: 'relative', - '&::before': { - content: '""', - position: 'absolute', - top: '-0.25rem', - left: '-0.25rem', - right: '-0.25rem', - bottom: '-0.25rem', - border: `${componentTheme.focusBorderWidth} ${componentTheme.focusBorderStyle} ${componentTheme.focusBorderColor}`, - borderRadius: componentTheme.focusBorderRadius, - opacity: 0, - transform: 'scale(0.9)', - pointerEvents: 'none' - }, - '&:focus': { - outline: 'none', - '&::before': { - opacity: 1, - transform: 'scale(1)' - } - } + overflow: 'hidden', + ...maxHeight, + ...calcFocusOutlineStyles(sharedTokens.focusOutline) } } } diff --git a/packages/ui-menu/src/Menu/theme.ts b/packages/ui-menu/src/Menu/theme.ts deleted file mode 100644 index 185e4e7851..0000000000 --- a/packages/ui-menu/src/Menu/theme.ts +++ /dev/null @@ -1,52 +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 } from '@instructure/ui-themes' -import { MenuTheme } 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): MenuTheme => { - const { colors, breakpoints, borders } = theme - - const componentVariables: MenuTheme = { - minWidth: breakpoints?.xxSmall, - maxWidth: breakpoints?.xSmall, - background: colors?.contrasts?.white1010, - borderRadius: borders?.radiusMedium, - focusBorderStyle: borders?.style, - focusBorderWidth: borders?.widthMedium, - focusBorderColor: colors?.contrasts?.blue4570, - focusBorderRadius: borders?.radiusMedium - } - - return { - ...componentVariables - } -} - -export default generateComponentTheme diff --git a/packages/ui-options/src/Options/Item/index.tsx b/packages/ui-options/src/Options/Item/index.tsx index 8ef744c974..6a9825055d 100644 --- a/packages/ui-options/src/Options/Item/index.tsx +++ b/packages/ui-options/src/Options/Item/index.tsx @@ -31,10 +31,9 @@ import { withDeterministicId } from '@instructure/ui-react-utils' -import { withStyleRework as withStyle } from '@instructure/emotion' +import { withStyle } from '@instructure/emotion' import generateStyles from './styles' -import generateComponentTheme from './theme' import type { OptionsItemProps, OptionsItemStyle } from './props' import { allowedProps } from './props' @@ -45,7 +44,7 @@ id: Options.Item --- **/ @withDeterministicId() -@withStyle(generateStyles, generateComponentTheme) +@withStyle(generateStyles) class Item extends Component { static readonly componentId = 'Options.Item' diff --git a/packages/ui-options/src/Options/Item/styles.ts b/packages/ui-options/src/Options/Item/styles.ts index 4b1eb379f0..b9db9de4ff 100644 --- a/packages/ui-options/src/Options/Item/styles.ts +++ b/packages/ui-options/src/Options/Item/styles.ts @@ -24,7 +24,7 @@ import { matchComponentTypes } from '@instructure/ui-react-utils' -import type { OptionsItemTheme } from '@instructure/shared-types' +import type { NewComponentTypes } from '@instructure/ui-themes' import type { OptionsItemProps, OptionsItemStyle } from './props' import { ReactNode } from 'react' @@ -39,7 +39,7 @@ import { ReactNode } from 'react' * @return {Object} The final style object, which will be used in the component */ const generateStyle = ( - componentTheme: OptionsItemTheme, + componentTheme: NewComponentTypes['OptionsItem'], props: OptionsItemProps ): OptionsItemStyle => { const { @@ -61,7 +61,7 @@ const generateStyle = ( }, selected: { background: componentTheme.selectedBackground, - color: componentTheme.highlightedLabelColor + color: componentTheme.selectedLabelColor }, disabled: { cursor: 'not-allowed', opacity: 0.68 }, 'highlighted-disabled': { @@ -142,7 +142,7 @@ const generateStyle = ( label: 'optionItem__container', display: 'block', outline: 'none', - padding: componentTheme.padding, + padding: `${componentTheme.paddingVertical} ${componentTheme.paddingHorizontal}`, ...(containsList && { padding: '0' }), ...(hasContentBeforeLabel && { paddingInlineEnd: componentTheme.iconPadding, diff --git a/packages/ui-options/src/Options/Separator/index.tsx b/packages/ui-options/src/Options/Separator/index.tsx index b204580be0..63deb306d4 100644 --- a/packages/ui-options/src/Options/Separator/index.tsx +++ b/packages/ui-options/src/Options/Separator/index.tsx @@ -26,10 +26,9 @@ import { Component } from 'react' import { getElementType, omitProps } from '@instructure/ui-react-utils' -import { withStyleRework as withStyle } from '@instructure/emotion' +import { withStyle } from '@instructure/emotion' import generateStyles from './styles' -import generateComponentTheme from './theme' import type { OptionsSeparatorProps } from './props' import { allowedProps } from './props' @@ -40,7 +39,7 @@ id: Options.Separator --- @module Separator **/ -@withStyle(generateStyles, generateComponentTheme) +@withStyle(generateStyles) class Separator extends Component { static readonly componentId = 'Options.Separator' diff --git a/packages/ui-options/src/Options/Separator/styles.ts b/packages/ui-options/src/Options/Separator/styles.ts index e0bdbca4e8..8cbd59a405 100644 --- a/packages/ui-options/src/Options/Separator/styles.ts +++ b/packages/ui-options/src/Options/Separator/styles.ts @@ -22,7 +22,7 @@ * SOFTWARE. */ -import type { OptionsSeparatorTheme } from '@instructure/shared-types' +import type { NewComponentTypes } from '@instructure/ui-themes' import type { OptionsSeparatorStyle } from './props' /** @@ -36,13 +36,13 @@ import type { OptionsSeparatorStyle } from './props' * @return {Object} The final style object, which will be used in the component */ const generateStyle = ( - componentTheme: OptionsSeparatorTheme + componentTheme: NewComponentTypes['OptionsSeparator'] ): OptionsSeparatorStyle => { return { separator: { label: 'separator', height: componentTheme.height, - margin: componentTheme.margin, + margin: `${componentTheme.marginVertical} ${componentTheme.marginHorizontal}`, overflow: 'hidden', background: componentTheme.background } diff --git a/packages/ui-options/src/Options/index.tsx b/packages/ui-options/src/Options/index.tsx index 8614bfc727..98fa3575e0 100644 --- a/packages/ui-options/src/Options/index.tsx +++ b/packages/ui-options/src/Options/index.tsx @@ -34,10 +34,9 @@ import { import { View } from '@instructure/ui-view' -import { withStyleRework as withStyle } from '@instructure/emotion' +import { withStyle } from '@instructure/emotion' import generateStyles from './styles' -import generateComponentTheme from './theme' import { Item } from './Item' import type { OptionsItemProps } from './Item/props' @@ -59,7 +58,7 @@ category: components/utilities --- **/ @withDeterministicId() -@withStyle(generateStyles, generateComponentTheme) +@withStyle(generateStyles) class Options extends Component { static readonly componentId = 'Options' diff --git a/packages/ui-options/src/Options/styles.ts b/packages/ui-options/src/Options/styles.ts index 3b5961d1f2..a0387e5faa 100644 --- a/packages/ui-options/src/Options/styles.ts +++ b/packages/ui-options/src/Options/styles.ts @@ -22,7 +22,7 @@ * SOFTWARE. */ -import type { OptionsTheme } from '@instructure/shared-types' +import type { NewComponentTypes } from '@instructure/ui-themes' import type { OptionsStyle } from './props' /** @@ -35,7 +35,9 @@ import type { OptionsStyle } from './props' * @param {Object} state 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: OptionsTheme): OptionsStyle => { +const generateStyle = ( + componentTheme: NewComponentTypes['Options'] +): OptionsStyle => { return { options: { label: 'options', @@ -53,7 +55,7 @@ const generateStyle = (componentTheme: OptionsTheme): OptionsStyle => { cursor: 'default', display: 'block', fontWeight: componentTheme.labelFontWeight, - padding: componentTheme.nestedLabelPadding + padding: `${componentTheme.nestedLabelPaddingVertical} ${componentTheme.nestedLabelPaddingHorizontal}` } } } diff --git a/packages/ui-popover/src/Popover/index.tsx b/packages/ui-popover/src/Popover/index.tsx index 73b85e4dab..c0d161fecd 100644 --- a/packages/ui-popover/src/Popover/index.tsx +++ b/packages/ui-popover/src/Popover/index.tsx @@ -601,8 +601,6 @@ class Popover extends Component { {...viewProps} borderColor={styles?.borderColor} borderRadius={styles?.borderRadius} - overflowX="hidden" - overflowY="hidden" > {content}