From d34cb52c1209e1a33bbcbcc5899dbc03299970c5 Mon Sep 17 00:00:00 2001 From: Cee Chen Date: Wed, 3 Apr 2024 13:46:47 -0700 Subject: [PATCH 1/7] [EuiTabs] Memoize styles - note: conditional JSX not touched here because 'link or button' logic will be a separate future refactor --- src/components/tabs/tab.tsx | 8 ++++---- src/components/tabs/tabs.tsx | 7 ++----- 2 files changed, 6 insertions(+), 9 deletions(-) diff --git a/src/components/tabs/tab.tsx b/src/components/tabs/tab.tsx index 7ae9ac2adcf..98281510769 100644 --- a/src/components/tabs/tab.tsx +++ b/src/components/tabs/tab.tsx @@ -15,8 +15,9 @@ import React, { useContext, } from 'react'; import classNames from 'classnames'; + +import { getSecureRelForTarget, useEuiMemoizedStyles } from '../../services'; import { CommonProps, ExclusiveUnion } from '../common'; -import { getSecureRelForTarget, useEuiTheme } from '../../services'; import { validateHref } from '../../services/security/href_validator'; import { euiTabStyles, euiTabContentStyles } from './tab.styles'; @@ -63,7 +64,6 @@ export const EuiTab: FunctionComponent = ({ ...rest }) => { const { size, expand } = useContext(EuiTabsContext); - const euiTheme = useEuiTheme(); const isHrefValid = !href || validateHref(href); const disabled = _disabled || !isHrefValid; @@ -72,7 +72,7 @@ export const EuiTab: FunctionComponent = ({ 'euiTab-isSelected': isSelected, }); - const tabStyles = euiTabStyles(euiTheme); + const tabStyles = useEuiMemoizedStyles(euiTabStyles); const cssTabStyles = [ tabStyles.euiTab, expand && tabStyles.expanded, @@ -80,7 +80,7 @@ export const EuiTab: FunctionComponent = ({ isSelected && (disabled ? tabStyles.disabled.selected : tabStyles.selected), ]; - const tabContentStyles = euiTabContentStyles(euiTheme); + const tabContentStyles = useEuiMemoizedStyles(euiTabContentStyles); const cssTabContentStyles = [ tabContentStyles.euiTab__content, size && tabContentStyles[size], diff --git a/src/components/tabs/tabs.tsx b/src/components/tabs/tabs.tsx index adeaae1a597..ae9cb409ffb 100644 --- a/src/components/tabs/tabs.tsx +++ b/src/components/tabs/tabs.tsx @@ -13,8 +13,8 @@ import React, { ReactNode, } from 'react'; import classNames from 'classnames'; +import { useEuiMemoizedStyles } from '../../services'; import { CommonProps } from '../common'; -import { useEuiTheme } from '../../services'; import { euiTabsStyles } from './tabs.styles'; import { EuiTabsContext } from './tabs_context'; @@ -58,12 +58,9 @@ export const EuiTabs = forwardRef( }: EuiTabsProps, ref ) => { - const euiTheme = useEuiTheme(); - const classes = classNames('euiTabs', className); - const styles = euiTabsStyles(euiTheme); - + const styles = useEuiMemoizedStyles(euiTabsStyles); const cssStyles = [ styles.euiTabs, styles[size], From 63be19567171d55c647b08c43806258048b6cc34 Mon Sep 17 00:00:00 2001 From: Cee Chen Date: Wed, 3 Apr 2024 14:04:18 -0700 Subject: [PATCH 2/7] [EuiBadge] Memoize styles - note: conditional JSX not touched here because 'link or button' logic will be a separate future refactor --- src/components/badge/badge.tsx | 11 ++++++----- src/components/badge/badge_group/badge_group.tsx | 9 ++++----- src/components/badge/beta_badge/beta_badge.tsx | 10 +++------- .../badge/notification_badge/badge_notification.tsx | 9 ++++----- 4 files changed, 17 insertions(+), 22 deletions(-) diff --git a/src/components/badge/badge.tsx b/src/components/badge/badge.tsx index 03cfcc0f9f2..3e3bac321f2 100644 --- a/src/components/badge/badge.tsx +++ b/src/components/badge/badge.tsx @@ -16,15 +16,17 @@ import React, { useMemo, } from 'react'; import classNames from 'classnames'; -import { CommonProps, ExclusiveUnion, PropsOf } from '../common'; + import { useEuiTheme, + useEuiMemoizedStyles, getSecureRelForTarget, wcagContrastMin, } from '../../services'; +import { validateHref } from '../../services/security/href_validator'; +import { CommonProps, ExclusiveUnion, PropsOf } from '../common'; import { EuiInnerText } from '../inner_text'; import { EuiIcon, IconType } from '../icon'; -import { validateHref } from '../../services/security/href_validator'; import { getTextColor, getColorContrast, getIsValidColor } from './color_utils'; import { euiBadgeStyles } from './badge.styles'; @@ -124,12 +126,11 @@ export const EuiBadge: FunctionComponent = ({ style, ...rest }) => { - const euiTheme = useEuiTheme(); - const isHrefValid = !href || validateHref(href); const isDisabled = _isDisabled || !isHrefValid; const isNamedColor = COLORS.includes(color as BadgeColor); + const euiTheme = useEuiTheme(); const customColorStyles = useMemo(() => { // Named colors set their styles via Emotion CSS and not inline styles if (isNamedColor) return style; @@ -165,7 +166,7 @@ export const EuiBadge: FunctionComponent = ({ } }, [color, isNamedColor, style, euiTheme]); - const styles = euiBadgeStyles(euiTheme); + const styles = useEuiMemoizedStyles(euiBadgeStyles); const cssStyles = [ styles.euiBadge, isNamedColor && styles[color as BadgeColor], diff --git a/src/components/badge/badge_group/badge_group.tsx b/src/components/badge/badge_group/badge_group.tsx index 83099b899ce..9a5c03e1bac 100644 --- a/src/components/badge/badge_group/badge_group.tsx +++ b/src/components/badge/badge_group/badge_group.tsx @@ -8,8 +8,9 @@ import React, { forwardRef, HTMLAttributes, Ref, ReactNode } from 'react'; import classNames from 'classnames'; + +import { useEuiMemoizedStyles } from '../../../services'; import { CommonProps } from '../../common'; -import { useEuiTheme } from '../../../services'; import { euiBadgeGroupStyles } from './badge_group.styles'; @@ -35,13 +36,11 @@ export const EuiBadgeGroup = forwardRef< { children, className, gutterSize = 'xs', ...rest }, ref: Ref ) => { - const euiTheme = useEuiTheme(); + const classes = classNames('euiBadgeGroup', className); - const styles = euiBadgeGroupStyles(euiTheme); + const styles = useEuiMemoizedStyles(euiBadgeGroupStyles); const cssStyles = [styles.euiBadgeGroup, styles[gutterSize]]; - const classes = classNames('euiBadgeGroup', className); - return (
{children} diff --git a/src/components/badge/beta_badge/beta_badge.tsx b/src/components/badge/beta_badge/beta_badge.tsx index 89f60ccce68..6cf6484be6c 100644 --- a/src/components/badge/beta_badge/beta_badge.tsx +++ b/src/components/badge/beta_badge/beta_badge.tsx @@ -14,12 +14,10 @@ import React, { ReactNode, } from 'react'; import classNames from 'classnames'; -import { CommonProps, ExclusiveUnion } from '../../common'; - -import { getSecureRelForTarget, useEuiTheme } from '../../../services'; +import { getSecureRelForTarget, useEuiMemoizedStyles } from '../../../services'; +import { CommonProps, ExclusiveUnion } from '../../common'; import { EuiToolTip, EuiToolTipProps, ToolTipPositions } from '../../tool_tip'; - import { EuiIcon, IconType } from '../../icon'; import { euiBetaBadgeStyles } from './beta_badge.styles'; @@ -146,14 +144,12 @@ export const EuiBetaBadge: FunctionComponent = ({ alignment = 'baseline', ...rest }) => { - const euiTheme = useEuiTheme(); - const singleLetter = !!(typeof label === 'string' && label.length === 1); const isCircular = iconType || singleLetter; const classes = classNames('euiBetaBadge', className); - const styles = euiBetaBadgeStyles(euiTheme); + const styles = useEuiMemoizedStyles(euiBetaBadgeStyles); const cssStyles = [ styles.euiBetaBadge, styles[color], diff --git a/src/components/badge/notification_badge/badge_notification.tsx b/src/components/badge/notification_badge/badge_notification.tsx index 7a1ea13b684..c68cfa21510 100644 --- a/src/components/badge/notification_badge/badge_notification.tsx +++ b/src/components/badge/notification_badge/badge_notification.tsx @@ -8,8 +8,9 @@ import React, { HTMLAttributes, ReactNode, FunctionComponent } from 'react'; import classNames from 'classnames'; + +import { useEuiMemoizedStyles } from '../../../services'; import { CommonProps } from '../../common'; -import { useEuiTheme } from '../../../services'; import { euiNotificationBadgeStyles } from './badge_notification.styles'; @@ -33,13 +34,11 @@ export interface EuiNotificationBadgeProps export const EuiNotificationBadge: FunctionComponent< EuiNotificationBadgeProps > = ({ children, className, size = 's', color = 'accent', ...rest }) => { - const euiTheme = useEuiTheme(); + const classes = classNames('euiNotificationBadge', className); - const styles = euiNotificationBadgeStyles(euiTheme); + const styles = useEuiMemoizedStyles(euiNotificationBadgeStyles); const cssStyles = [styles.euiNotificationBadge, styles[size], styles[color]]; - const classes = classNames('euiNotificationBadge', className); - return ( {children} From 0f9a6c0a986de2fe7c6bbcb567d979c829de98d7 Mon Sep 17 00:00:00 2001 From: Cee Chen Date: Wed, 3 Apr 2024 14:24:34 -0700 Subject: [PATCH 3/7] [EuiContextMenu] Memoize class styles - not going to try anything fancy here, class components are a headache --- src/components/context_menu/context_menu.tsx | 18 ++++++++++-------- .../context_menu/context_menu_panel.tsx | 19 +++++++++++-------- 2 files changed, 21 insertions(+), 16 deletions(-) diff --git a/src/components/context_menu/context_menu.tsx b/src/components/context_menu/context_menu.tsx index 4a23f32a9ea..02d292d6647 100644 --- a/src/components/context_menu/context_menu.tsx +++ b/src/components/context_menu/context_menu.tsx @@ -16,7 +16,10 @@ import React, { } from 'react'; import classNames from 'classnames'; -import { withEuiTheme, WithEuiThemeProps } from '../../services'; +import { + withEuiStylesMemoizer, + WithEuiStylesMemoizerProps, +} from '../../services'; import { CommonProps, ExclusiveUnion } from '../common'; import { EuiHorizontalRule, EuiHorizontalRuleProps } from '../horizontal_rule'; @@ -173,7 +176,7 @@ interface State { } export class EuiContextMenuClass extends Component< - WithEuiThemeProps & EuiContextMenuProps, + WithEuiStylesMemoizerProps & EuiContextMenuProps, State > { static defaultProps: Partial = { @@ -199,7 +202,7 @@ export class EuiContextMenuClass extends Component< return null; } - constructor(props: WithEuiThemeProps & EuiContextMenuProps) { + constructor(props: WithEuiStylesMemoizerProps & EuiContextMenuProps) { super(props); this.state = { @@ -429,7 +432,7 @@ export class EuiContextMenuClass extends Component< render() { const { - theme, + stylesMemoizer, panels, onPanelChange, className, @@ -453,12 +456,11 @@ export class EuiContextMenuClass extends Component< const classes = classNames('euiContextMenu', className); - const styles = euiContextMenuStyles(theme); - const cssStyles = [styles.euiContextMenu]; + const styles = stylesMemoizer(euiContextMenuStyles); return (
(EuiContextMenuClass); + withEuiStylesMemoizer(EuiContextMenuClass); diff --git a/src/components/context_menu/context_menu_panel.tsx b/src/components/context_menu/context_menu_panel.tsx index bf928459f59..578d42cd49c 100644 --- a/src/components/context_menu/context_menu_panel.tsx +++ b/src/components/context_menu/context_menu_panel.tsx @@ -17,7 +17,11 @@ import React, { import classNames from 'classnames'; import { tabbable, FocusableElement } from 'tabbable'; -import { withEuiTheme, WithEuiThemeProps, keys } from '../../services'; +import { + withEuiStylesMemoizer, + WithEuiStylesMemoizerProps, + keys, +} from '../../services'; import { CommonProps, NoArgCallback } from '../common'; import { EuiResizeObserver } from '../observer/resize_observer'; @@ -74,7 +78,7 @@ interface State { } export class EuiContextMenuPanelClass extends Component< - WithEuiThemeProps & Props, + WithEuiStylesMemoizerProps & Props, State > { static defaultProps: Partial = { @@ -86,7 +90,7 @@ export class EuiContextMenuPanelClass extends Component< private panel?: HTMLElement | null = null; private initialPopoverParent?: HTMLElement | null = null; - constructor(props: WithEuiThemeProps & Props) { + constructor(props: WithEuiStylesMemoizerProps & Props) { super(props); this.state = { @@ -394,7 +398,7 @@ export class EuiContextMenuPanelClass extends Component< render() { const { - theme, + stylesMemoizer, children, className, onClose, @@ -414,7 +418,7 @@ export class EuiContextMenuPanelClass extends Component< const classes = classNames('euiContextMenuPanel', className); - const styles = euiContextMenuPanelStyles(theme); + const styles = stylesMemoizer(euiContextMenuPanelStyles); const cssStyles = [ styles.euiContextMenuPanel, transitionDirection && @@ -472,6 +476,5 @@ export class EuiContextMenuPanelClass extends Component< } } -export const EuiContextMenuPanel = withEuiTheme( - EuiContextMenuPanelClass -); +export const EuiContextMenuPanel = + withEuiStylesMemoizer(EuiContextMenuPanelClass); From 0d49adbe9686e0bdc9708b487008770fd8cb80c1 Mon Sep 17 00:00:00 2001 From: Cee Chen Date: Fri, 29 Mar 2024 10:43:28 -0700 Subject: [PATCH 4/7] [EuiDescriptionList] Memoize styles + array `.map()` --- .../description_list/description_list.tsx | 43 +++++++++---------- .../description_list_description.tsx | 5 +-- .../description_list_title.tsx | 5 +-- 3 files changed, 24 insertions(+), 29 deletions(-) diff --git a/src/components/description_list/description_list.tsx b/src/components/description_list/description_list.tsx index 1b0ebba7edb..579fd198c44 100644 --- a/src/components/description_list/description_list.tsx +++ b/src/components/description_list/description_list.tsx @@ -9,7 +9,7 @@ import React, { HTMLAttributes, FunctionComponent, useMemo } from 'react'; import classNames from 'classnames'; -import { useEuiTheme, useIsWithinBreakpoints } from '../../services'; +import { useEuiMemoizedStyles, useIsWithinBreakpoints } from '../../services'; import { CommonProps } from '../common'; import { EuiDescriptionListProps } from './description_list_types'; @@ -45,8 +45,7 @@ export const EuiDescriptionList: FunctionComponent< } }, [_type, showResponsiveColumns]); - const euiTheme = useEuiTheme(); - const styles = euiDescriptionListStyles(euiTheme); + const styles = useEuiMemoizedStyles(euiDescriptionListStyles); const cssStyles = [ styles.euiDescriptionList, @@ -74,26 +73,24 @@ export const EuiDescriptionList: FunctionComponent< const classes = classNames('euiDescriptionList', className); - let childrenOrListItems = null; + const renderedListItems = useMemo(() => { + if (listItems) { + return listItems.map((item, index) => { + return [ + + {item.title} + , - if (listItems) { - childrenOrListItems = listItems.map((item, index) => { - return [ - - {item.title} - , - - - {item.description} - , - ]; - }); - } else { - childrenOrListItems = children; - } + + {item.description} + , + ]; + }); + } + }, [listItems, descriptionProps, titleProps]); return ( - {childrenOrListItems} + {listItems ? renderedListItems : children} ); diff --git a/src/components/description_list/description_list_description.tsx b/src/components/description_list/description_list_description.tsx index e39881d1978..747d2264ed0 100644 --- a/src/components/description_list/description_list_description.tsx +++ b/src/components/description_list/description_list_description.tsx @@ -9,8 +9,8 @@ import React, { HTMLAttributes, FunctionComponent, useContext } from 'react'; import classNames from 'classnames'; +import { useEuiMemoizedStyles } from '../../services'; import { CommonProps } from '../common'; -import { useEuiTheme } from '../../services'; import { EuiDescriptionListContext } from './description_list_context'; import { euiDescriptionListDescriptionStyles } from './description_list_description.styles'; @@ -27,8 +27,7 @@ export const EuiDescriptionListDescription: FunctionComponent< EuiDescriptionListContext ); - const theme = useEuiTheme(); - const styles = euiDescriptionListDescriptionStyles(theme); + const styles = useEuiMemoizedStyles(euiDescriptionListDescriptionStyles); let conditionalStyles = compressed && textStyle === 'reverse' diff --git a/src/components/description_list/description_list_title.tsx b/src/components/description_list/description_list_title.tsx index 7f5167693c9..a69d2a4d2c2 100644 --- a/src/components/description_list/description_list_title.tsx +++ b/src/components/description_list/description_list_title.tsx @@ -9,8 +9,8 @@ import React, { HTMLAttributes, FunctionComponent, useContext } from 'react'; import classNames from 'classnames'; +import { useEuiMemoizedStyles } from '../../services'; import { CommonProps } from '../common'; -import { useEuiTheme } from '../../services'; import { EuiDescriptionListContext } from './description_list_context'; import { euiDescriptionListTitleStyles } from './description_list_title.styles'; @@ -27,8 +27,7 @@ export const EuiDescriptionListTitle: FunctionComponent< EuiDescriptionListContext ); - const theme = useEuiTheme(); - const styles = euiDescriptionListTitleStyles(theme); + const styles = useEuiMemoizedStyles(euiDescriptionListTitleStyles); let conditionalStyles = compressed && textStyle !== 'reverse' From 6e394f1d9ec073231cd017f446e91c50ffb118e0 Mon Sep 17 00:00:00 2001 From: Cee Chen Date: Fri, 29 Mar 2024 10:52:01 -0700 Subject: [PATCH 5/7] [EuiEmptyPrompt] Memoize styles - a neat example of DRYing out existing perf attempts! --- src/components/empty_prompt/empty_prompt.tsx | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/components/empty_prompt/empty_prompt.tsx b/src/components/empty_prompt/empty_prompt.tsx index fb919eecbf7..d16fe9539fc 100644 --- a/src/components/empty_prompt/empty_prompt.tsx +++ b/src/components/empty_prompt/empty_prompt.tsx @@ -14,7 +14,7 @@ import React, { } from 'react'; import classNames from 'classnames'; -import { useEuiTheme } from '../../services'; +import { useEuiMemoizedStyles } from '../../services'; import { CommonProps } from '../common'; import { EuiTitle, EuiTitleSize } from '../title'; import { EuiFlexGroup, EuiFlexItem } from '../flex'; @@ -97,8 +97,7 @@ export const EuiEmptyPrompt: FunctionComponent = ({ ...rest }) => { const classes = classNames('euiEmptyPrompt', className); - const euiTheme = useEuiTheme(); - const styles = useMemo(() => euiEmptyPromptStyles(euiTheme), [euiTheme]); + const styles = useEuiMemoizedStyles(euiEmptyPromptStyles); const cssStyles = [styles.euiEmptyPrompt, styles[layout]]; const mainStyles = [ styles.main.euiEmptyPrompt__main, From d94ecfb7d97f954a27c93ae3cf1f7735eb125ff4 Mon Sep 17 00:00:00 2001 From: Cee Chen Date: Fri, 29 Mar 2024 14:45:33 -0700 Subject: [PATCH 6/7] [EuiHorizontalRule] Memoize styles + remove modifier classes - no usages in Kibana --- .../__snapshots__/context_menu.test.tsx.snap | 4 +-- .../horizontal_rule.test.tsx.snap | 2 +- .../horizontal_rule/horizontal_rule.tsx | 28 ++----------------- 3 files changed, 6 insertions(+), 28 deletions(-) diff --git a/src/components/context_menu/__snapshots__/context_menu.test.tsx.snap b/src/components/context_menu/__snapshots__/context_menu.test.tsx.snap index 87edd6a8653..3feacd2cb68 100644 --- a/src/components/context_menu/__snapshots__/context_menu.test.tsx.snap +++ b/src/components/context_menu/__snapshots__/context_menu.test.tsx.snap @@ -21,7 +21,7 @@ exports[`EuiContextMenu can pass-through horizontal rule props 1`] = `

@@ -168,7 +168,7 @@ exports[`EuiContextMenu renders isSeparator items 1`] = `
`; diff --git a/src/components/horizontal_rule/horizontal_rule.tsx b/src/components/horizontal_rule/horizontal_rule.tsx index 297af7d8378..9313d960911 100644 --- a/src/components/horizontal_rule/horizontal_rule.tsx +++ b/src/components/horizontal_rule/horizontal_rule.tsx @@ -10,7 +10,7 @@ import React, { FunctionComponent, HTMLAttributes } from 'react'; import classNames from 'classnames'; import { CommonProps } from '../common'; -import { useEuiTheme } from '../../services'; +import { useEuiMemoizedStyles } from '../../services'; import { euiHorizontalRuleStyles } from './horizontal_rule.styles'; export const SIZES = ['full', 'half', 'quarter'] as const; @@ -29,37 +29,15 @@ export interface EuiHorizontalRuleProps margin?: EuiHorizontalRuleMargin; } -const marginToClassNameMap: { - [value in EuiHorizontalRuleMargin]: string | null; -} = { - none: null, - xs: 'marginXSmall', - s: 'marginSmall', - m: 'marginMedium', - l: 'marginLarge', - xl: 'marginXLarge', - xxl: 'marginXXLarge', -}; - export const EuiHorizontalRule: FunctionComponent = ({ className, size = 'full', margin = 'l', ...rest }) => { - const euiTheme = useEuiTheme(); - const styles = euiHorizontalRuleStyles(euiTheme); - - const classes = classNames( - 'euiHorizontalRule', - { - [`euiHorizontalRule--${size}`]: size, - [`euiHorizontalRule--${marginToClassNameMap[margin]}`]: - margin && margin !== 'none', - }, - className - ); + const classes = classNames('euiHorizontalRule', className); + const styles = useEuiMemoizedStyles(euiHorizontalRuleStyles); const cssStyles = [styles.euiHorizontalRule, styles[size], styles[margin]]; return
; From 8a4c58f8ece8ba2974777f15085c6cfc22dd1209 Mon Sep 17 00:00:00 2001 From: Cee Chen Date: Fri, 29 Mar 2024 14:48:35 -0700 Subject: [PATCH 7/7] [EuiCallOut] Memoize styles + `useMemo` + inline JSX - `optionalChildren` isn't worth memoizing because children rerenders too often + move `.euiCallOut__icon` to header styles since it's only used in that DOM --- src/components/call_out/call_out.styles.ts | 12 +- src/components/call_out/call_out.tsx | 143 +++++++++++---------- 2 files changed, 79 insertions(+), 76 deletions(-) diff --git a/src/components/call_out/call_out.styles.ts b/src/components/call_out/call_out.styles.ts index a6164f8d951..59e4cd4cc04 100644 --- a/src/components/call_out/call_out.styles.ts +++ b/src/components/call_out/call_out.styles.ts @@ -45,15 +45,10 @@ export const euiCallOutStyles = ({ euiTheme }: UseEuiTheme) => { ${logicalCSS('right', euiTheme.size.s)} `, }, - euiCallOut__icon: css` - position: relative; - ${logicalCSS('top', '-1px')} - ${logicalCSS('margin-right', euiTheme.size.s)} - `, }; }; -export const euiCallOutHeadingStyles = ({ euiTheme }: UseEuiTheme) => { +export const euiCallOutHeaderStyles = ({ euiTheme }: UseEuiTheme) => { return { euiCallOutHeader: css` font-weight: ${euiTheme.font.weight.medium}; @@ -75,5 +70,10 @@ export const euiCallOutHeadingStyles = ({ euiTheme }: UseEuiTheme) => { danger: css` color: ${euiTheme.colors.dangerText}; `, + euiCallOut__icon: css` + position: relative; + ${logicalCSS('top', '-1px')} + ${logicalCSS('margin-right', euiTheme.size.s)} + `, }; }; diff --git a/src/components/call_out/call_out.tsx b/src/components/call_out/call_out.tsx index 728848b099f..4abcacb253d 100644 --- a/src/components/call_out/call_out.tsx +++ b/src/components/call_out/call_out.tsx @@ -6,22 +6,21 @@ * Side Public License, v 1. */ -import React, { forwardRef, HTMLAttributes, ReactNode } from 'react'; +import React, { forwardRef, HTMLAttributes, ReactNode, useMemo } from 'react'; import classNames from 'classnames'; +import { useEuiMemoizedStyles } from '../../services'; import { CommonProps } from '../common'; import { IconType, EuiIcon } from '../icon'; - import { EuiButtonIcon } from '../button'; import { EuiText } from '../text'; -import { useEuiTheme } from '../../services'; import { EuiPanel } from '../panel'; import { EuiSpacer } from '../spacer'; import { EuiTitle } from '../title'; import { EuiI18n } from '../i18n'; -import { euiCallOutStyles, euiCallOutHeadingStyles } from './call_out.styles'; +import { euiCallOutStyles, euiCallOutHeaderStyles } from './call_out.styles'; export const COLORS = ['primary', 'success', 'warning', 'danger'] as const; export type Color = (typeof COLORS)[number]; @@ -63,22 +62,12 @@ export const EuiCallOut = forwardRef( }, ref ) => { - const theme = useEuiTheme(); - const styles = euiCallOutStyles(theme); + const styles = useEuiMemoizedStyles(euiCallOutStyles); const cssStyles = [ styles.euiCallOut, onDismiss && styles.hasDismissButton.hasDimissButton, onDismiss && styles.hasDismissButton[size], ]; - const cssDismissButtonStyles = [ - styles.dismissButton.euiCallOut__dismissButton, - styles.dismissButton[size], - ]; - const headerStyles = euiCallOutHeadingStyles(theme); - const cssHeaderStyles = [ - headerStyles.euiCallOutHeader, - headerStyles[color], - ]; const classes = classNames( 'euiCallOut', @@ -88,42 +77,57 @@ export const EuiCallOut = forwardRef( className ); - const dismissButton = onDismiss && ( - - {(dismissAriaLabel: string) => ( - - )} - - ); - - const headerIcon = iconType && ( -