diff --git a/packages/react-ui/.styleguide/components/StyleGuideWrapper/StyleGuideWrapper.styles.ts b/packages/react-ui/.styleguide/components/StyleGuideWrapper/StyleGuideWrapper.styles.ts index 8f3715c1251..82063abe2e4 100644 --- a/packages/react-ui/.styleguide/components/StyleGuideWrapper/StyleGuideWrapper.styles.ts +++ b/packages/react-ui/.styleguide/components/StyleGuideWrapper/StyleGuideWrapper.styles.ts @@ -1,9 +1,11 @@ -import { css, memoizeStyle } from '../../../lib/theming/Emotion'; +import { memoizeStyle } from '../../../lib/theming/Emotion'; import { Theme } from '../../../lib/theming/Theme'; +import type { Emotion } from '@emotion/css/create-instance'; -export const styles = memoizeStyle({ - root() { - return css` +export const getStyles = (emotion: Emotion) => + memoizeStyle({ + root() { + return emotion.css` font-weight: 400; font-size: 14px; padding-left: 300px; @@ -41,15 +43,15 @@ export const styles = memoizeStyle({ } } `; - }, - darkRoot(t: Theme) { - return css` + }, + darkRoot(t: Theme) { + return emotion.css` background: ${t.bgDefault}; color: ${t.textColorDefault}; `; - }, - wrapper() { - return css` + }, + wrapper() { + return emotion.css` padding: 30px 40px; margin: 0 auto; max-width: 1000px; @@ -59,12 +61,12 @@ export const styles = memoizeStyle({ padding: 16px; } `; - }, - content() { - return css``; - }, - darkContent(t: Theme) { - return css` + }, + content() { + return emotion.css``; + }, + darkContent(t: Theme) { + return emotion.css` h1, h2, h3, @@ -126,14 +128,14 @@ export const styles = memoizeStyle({ border: 1px solid #444; } `; - }, - header() { - return css` + }, + header() { + return emotion.css` padding: 40px 40px 0 !important; `; - }, - sidebar() { - return css` + }, + sidebar() { + return emotion.css` width: 300px; background: #41464e; font-size: 16px; @@ -165,9 +167,9 @@ export const styles = memoizeStyle({ font-weight: normal; } `; - }, - footer() { - return css` + }, + footer() { + return emotion.css` position: fixed; top: 0; right: 0; @@ -175,9 +177,9 @@ export const styles = memoizeStyle({ height: 149px; z-index: 999; `; - }, - footerLink() { - return css` + }, + footerLink() { + return emotion.css` position: relative; right: -37px; top: -22px; @@ -194,5 +196,5 @@ export const styles = memoizeStyle({ transform: rotate(45deg); cursor: pointer; `; - }, -}); + }, + }); diff --git a/packages/react-ui/.styleguide/components/StyleGuideWrapper/StyleGuideWrapper.tsx b/packages/react-ui/.styleguide/components/StyleGuideWrapper/StyleGuideWrapper.tsx index ad7826ab05b..9c02eddf0e6 100644 --- a/packages/react-ui/.styleguide/components/StyleGuideWrapper/StyleGuideWrapper.tsx +++ b/packages/react-ui/.styleguide/components/StyleGuideWrapper/StyleGuideWrapper.tsx @@ -2,8 +2,8 @@ import React, { useState } from 'react'; import ThemeSwitcher from '../ThemeSwitcher/ThemeSwitcher'; import Context from 'react-styleguidist/lib/client/rsg-components/Context'; import { useStyleGuideContext } from 'react-styleguidist/lib/client/rsg-components/Context/Context'; -import { cx } from '../../../lib/theming/Emotion'; -import { styles } from './StyleGuideWrapper.styles'; +import { useEmotion } from '../../../lib/theming/Emotion'; +import { getStyles } from './StyleGuideWrapper.styles'; import { DARK_THEME } from '../../../lib/theming/themes/DarkTheme'; import { DEFAULT_THEME_WRAPPER } from '../ThemeSwitcher/constants'; @@ -16,6 +16,7 @@ interface StyleGuideRendererProps { } function StyleGuideRenderer({ children, hasSidebar, toc, title, version }: StyleGuideRendererProps) { + const emotion = useEmotion(); const { codeRevision, config, slots, displayMode, cssRevision } = useStyleGuideContext(); const [theme, setTheme] = useState(DEFAULT_THEME_WRAPPER); document.body.style.fontFamily = 'Lab Grotesque, Roboto, Helvetica Neue, Arial, sans-serif'; @@ -31,11 +32,15 @@ function StyleGuideRenderer({ children, hasSidebar, toc, title, version }: Style root.style.height = '100%'; } } + + const styles = getStyles(emotion); return ( -
+
-
{children}
+
+ {children} +
{hasSidebar && (
diff --git a/packages/react-ui/components/Autocomplete/Autocomplete.styles.ts b/packages/react-ui/components/Autocomplete/Autocomplete.styles.ts index 3d0469c9f82..9c4e8e8ee32 100644 --- a/packages/react-ui/components/Autocomplete/Autocomplete.styles.ts +++ b/packages/react-ui/components/Autocomplete/Autocomplete.styles.ts @@ -1,11 +1,14 @@ -import { css, memoizeStyle } from '../../lib/theming/Emotion'; +import type { Emotion } from '@emotion/css/create-instance'; + +import { memoizeStyle } from '../../lib/theming/Emotion'; import { Theme } from '../../lib/theming/Theme'; -export const styles = memoizeStyle({ - root(t: Theme) { - return css` - display: inline-block; - width: ${t.inputWidth}; - `; - }, -}); +export const getStyles = (emotion: Emotion) => + memoizeStyle({ + root(t: Theme) { + return emotion.css` + display: inline-block; + width: ${t.inputWidth}; + `; + }, + }); diff --git a/packages/react-ui/components/Autocomplete/Autocomplete.tsx b/packages/react-ui/components/Autocomplete/Autocomplete.tsx index e62302594f0..06feb5cbb7b 100644 --- a/packages/react-ui/components/Autocomplete/Autocomplete.tsx +++ b/packages/react-ui/components/Autocomplete/Autocomplete.tsx @@ -2,11 +2,11 @@ /* eslint-disable @typescript-eslint/no-unused-vars */ import React, { AriaAttributes, KeyboardEvent } from 'react'; import PropTypes from 'prop-types'; +import type { Emotion } from '@emotion/css/create-instance'; import { MenuMessage } from '../../internal/MenuMessage'; import { locale } from '../../lib/locale/decorators'; import { getRandomID, isNullable } from '../../lib/utils'; -import { ThemeContext } from '../../lib/theming/ThemeContext'; import { Theme } from '../../lib/theming/Theme'; import { isKeyArrowDown, isKeyArrowUp, isKeyEnter, isKeyEscape } from '../../lib/events/keyboard/identifiers'; import { Input, InputProps } from '../Input'; @@ -23,10 +23,12 @@ import { responsiveLayout } from '../ResponsiveLayout/decorator'; import { getRootNode, rootNode, TSetRootNode } from '../../lib/rootNode'; import { getDOMRect } from '../../lib/dom/getDOMRect'; import { SizeProp } from '../../lib/types/props'; +import { EmotionConsumer } from '../../lib/theming/Emotion'; +import { ThemeContext } from '../../lib/theming/ThemeContext'; -import { styles } from './Autocomplete.styles'; import { AutocompleteLocale, AutocompleteLocaleHelper } from './locale'; import { getAutocompleteTheme } from './getAutocompleteTheme'; +import { getStyles } from './Autocomplete.styles'; function match(pattern: string, items: string[]) { if (!pattern || !items) { @@ -159,6 +161,7 @@ export class Autocomplete extends React.Component - {(theme) => { - this.theme = getAutocompleteTheme(theme); + + {(emotion) => { + this.emotion = emotion; return ( - - - {this.renderMain} - - + + {(theme) => { + this.theme = getAutocompleteTheme(theme); + return ( + + + {this.renderMain} + + + ); + }} + ); }} - + ); } public renderMain = (props: CommonWrapperRestProps) => { @@ -243,6 +253,7 @@ export class Autocomplete extends React.Component { - const hasGradient = btnBackgroundStart !== btnBackgroundEnd; - return css` +export const buttonUseMixin = + (emotion: Emotion) => + ( + btnBackground: string, + btnBackgroundStart: string, + btnBackgroundEnd: string, + color: string, + borderColor: string, + borderBottomColor: string, + borderWidth: string, + ) => { + const hasGradient = btnBackgroundStart !== btnBackgroundEnd; + return emotion.css` background-color: ${hasGradient ? `initial` : btnBackground}; background-image: ${hasGradient ? `linear-gradient(${btnBackgroundStart}, ${btnBackgroundEnd})` : `none`}; color: ${color}; - box-shadow: 0 0 0 ${borderWidth} ${borderColor}${borderBottomColor ? `, 0 ${borderWidth} 0 0 ${borderBottomColor}` : ``}; + box-shadow: 0 0 0 ${borderWidth} ${borderColor}${ + borderBottomColor ? `, 0 ${borderWidth} 0 0 ${borderBottomColor}` : `` + }; .${globalClasses.arrowHelper} { box-shadow: ${borderWidth} 0 0 0 ${borderColor}; @@ -55,44 +60,52 @@ export const buttonUseMixin = ( } } `; -}; + }; -export const buttonHoverMixin = ( - btnBackground: string, - btnBackgroundStart: string, - btnBackgroundEnd: string, - color: string, - borderColor: string, - borderBottomColor: string, - borderWidth: string, -) => { - const hasGradient = btnBackgroundStart !== btnBackgroundEnd; - return css` +export const buttonHoverMixin = + (emotion: Emotion) => + ( + btnBackground: string, + btnBackgroundStart: string, + btnBackgroundEnd: string, + color: string, + borderColor: string, + borderBottomColor: string, + borderWidth: string, + ) => { + const hasGradient = btnBackgroundStart !== btnBackgroundEnd; + return emotion.css` background-color: ${hasGradient ? `initial` : btnBackground}; background-image: ${hasGradient ? `linear-gradient(${btnBackgroundStart}, ${btnBackgroundEnd})` : `none`}; - box-shadow: 0 0 0 ${borderWidth} ${borderColor}${borderBottomColor ? `, 0 ${borderWidth} 0 0 ${borderBottomColor}` : ``}; + box-shadow: 0 0 0 ${borderWidth} ${borderColor}${ + borderBottomColor ? `, 0 ${borderWidth} 0 0 ${borderBottomColor}` : `` + }; color: ${color}; .${globalClasses.arrowHelper} { box-shadow: ${borderWidth} 0 0 ${borderColor}; } `; -}; + }; -export const buttonActiveMixin = ( - btnBackground: string, - btnShadow: string, - borderColor: string, - borderTopColor: string, - borderWidth: string, - arrowBgImage: string, -) => { - return css` +export const buttonActiveMixin = + (emotion: Emotion) => + ( + btnBackground: string, + btnShadow: string, + borderColor: string, + borderTopColor: string, + borderWidth: string, + arrowBgImage: string, + ) => { + return emotion.css` &, &:hover { background-image: none !important; // override :hover styles background-color: ${btnBackground} !important; // override :hover styles - box-shadow: 0 0 0 ${borderWidth} ${borderColor}${borderTopColor ? `, 0 -${borderWidth} 0 0 ${borderTopColor}` : ``} !important; // override :hover styles + box-shadow: 0 0 0 ${borderWidth} ${borderColor}${ + borderTopColor ? `, 0 -${borderWidth} 0 0 ${borderTopColor}` : `` + } !important; // override :hover styles .${globalClasses.innerShadow} { box-shadow: ${btnShadow}; @@ -107,42 +120,30 @@ export const buttonActiveMixin = ( } } `; -}; + }; -export const buttonSizeMixin = ( - fontSize: string, - lineHeight: string, - paddingX: string, - paddingY: string, - fontFamilyCompensation: string, -) => { - return css` +export const buttonSizeMixin = + (emotion: Emotion) => + (fontSize: string, lineHeight: string, paddingX: string, paddingY: string, fontFamilyCompensation: string) => { + return emotion.css` font-size: ${fontSize}; box-sizing: border-box; padding: ${getBtnPadding(fontSize, paddingY, paddingX, fontFamilyCompensation)}; line-height: ${lineHeight}; `; -}; + }; -export const buttonSizeMixinIE11 = ( - fontSize: string, - paddingX: string, - paddingY: string, - fontFamilyCompensation: string, -) => { - return css` +export const buttonSizeMixinIE11 = + (emotion: Emotion) => (fontSize: string, paddingX: string, paddingY: string, fontFamilyCompensation: string) => { + return emotion.css` padding: ${getBtnPadding(fontSize, paddingY, paddingX, fontFamilyCompensation, 1)}; line-height: normal; `; -}; + }; -export const arrowOutlineMixin = ( - insetWidth: string, - outlineColor: string, - outlineWidth: string, - insetColor: string, -) => { - return css` +export const arrowOutlineMixin = + (emotion: Emotion) => (insetWidth: string, outlineColor: string, outlineWidth: string, insetColor: string) => { + return emotion.css` .${globalClasses.arrowHelper} { &.${globalClasses.arrowHelperTop} { box-shadow: inset -${insetWidth} ${insetWidth} 0 0 ${insetColor}, ${outlineWidth} 0 0 0 ${outlineColor} !important; // override :active styles @@ -164,4 +165,4 @@ export const arrowOutlineMixin = ( } } `; -}; + }; diff --git a/packages/react-ui/components/Button/Button.styles.ts b/packages/react-ui/components/Button/Button.styles.ts index 6ce07792a3a..0518cea7762 100644 --- a/packages/react-ui/components/Button/Button.styles.ts +++ b/packages/react-ui/components/Button/Button.styles.ts @@ -1,15 +1,17 @@ -import { css, memoizeStyle, prefix } from '../../lib/theming/Emotion'; +import type { Emotion } from '@emotion/css/create-instance'; + +import { memoizeStyle, prefix } from '../../lib/theming/Emotion'; import { Theme } from '../../lib/theming/Theme'; import { resetButton, resetText } from '../../lib/styles/Mixins'; import { isFirefox } from '../../lib/client'; import { - buttonUseMixin, - buttonHoverMixin, + arrowOutlineMixin, buttonActiveMixin, + buttonHoverMixin, buttonSizeMixin, - arrowOutlineMixin, buttonSizeMixinIE11, + buttonUseMixin, } from './Button.mixins'; export const globalClasses = prefix('button')({ @@ -23,11 +25,12 @@ export const globalClasses = prefix('button')({ innerShadow: 'inner-shadow', }); -export const styles = memoizeStyle({ - root(t: Theme) { - return css` - ${resetButton()}; - ${resetText()}; +export const getStyles = (emotion: Emotion) => + memoizeStyle({ + root(t: Theme) { + return emotion.css` + ${resetButton(emotion)}; + ${resetText(emotion)}; transition: background-color ${t.transitionDuration} ${t.transitionTimingFunction} ${t.btnBorderColorTransition ? `, ${t.btnBorderColorTransition}` : ''}; @@ -74,58 +77,58 @@ export const styles = memoizeStyle({ color: ${t.btnIconColor}; } `; - }, + }, - withArrowIconRightSmall(t: Theme) { - return css` + withArrowIconRightSmall(t: Theme) { + return emotion.css` padding-right: calc(${t.btnIconSizeSmall} + ${t.btnWithIconPaddingLeftSmall} + ${t.btnWithIconPaddingLeftSmall}); `; - }, + }, - withArrowIconRightMedium(t: Theme) { - return css` + withArrowIconRightMedium(t: Theme) { + return emotion.css` padding-right: calc( ${t.btnIconSizeMedium} + ${t.btnWithIconPaddingLeftMedium} + ${t.btnWithIconPaddingLeftMedium} ); `; - }, + }, - withArrowIconRightLarge(t: Theme) { - return css` + withArrowIconRightLarge(t: Theme) { + return emotion.css` padding-right: calc(${t.btnIconSizeLarge} + ${t.btnWithIconPaddingLeftLarge} + ${t.btnWithIconPaddingLeftLarge}); `; - }, + }, - withArrowIconLeftSmall(t: Theme) { - return css` + withArrowIconLeftSmall(t: Theme) { + return emotion.css` padding-left: calc(${t.btnIconSizeSmall} + ${t.btnWithIconPaddingLeftSmall} + ${t.btnWithIconPaddingLeftSmall}); `; - }, + }, - withArrowIconLeftMedium(t: Theme) { - return css` + withArrowIconLeftMedium(t: Theme) { + return emotion.css` padding-left: calc( ${t.btnIconSizeMedium} + ${t.btnWithIconPaddingLeftMedium} + ${t.btnWithIconPaddingLeftMedium} ); `; - }, + }, - withArrowIconLeftLarge(t: Theme) { - return css` + withArrowIconLeftLarge(t: Theme) { + return emotion.css` padding-left: calc(${t.btnIconSizeLarge} + ${t.btnWithIconPaddingLeftLarge} + ${t.btnWithIconPaddingLeftLarge}); `; - }, + }, - simulatedPress() { - return css` + simulatedPress() { + return emotion.css` &:active .${globalClasses.caption} { transform: translateY(1px); } `; - }, + }, - outline() { - return css` + outline() { + return emotion.css` border-radius: inherit; position: absolute; top: 0; @@ -133,48 +136,48 @@ export const styles = memoizeStyle({ left: 0; right: 0; `; - }, + }, - outlineWarning(t: Theme) { - return css` + outlineWarning(t: Theme) { + return emotion.css` box-shadow: 0 0 0 ${t.btnOutlineWidth} ${t.btnBorderColorWarning}, inset 0 0 0 ${t.btnInsetWidth} ${t.btnInsetColor}; `; - }, + }, - outlineError(t: Theme) { - return css` + outlineError(t: Theme) { + return emotion.css` box-shadow: 0 0 0 ${t.btnOutlineWidth} ${t.btnBorderColorError}, inset 0 0 0 ${t.btnInsetWidth} ${t.btnInsetColor}; `; - }, + }, - outlineLink() { - return css` + outlineLink() { + return emotion.css` box-shadow: none; left: -2px; right: -2px; bottom: -2px; top: -2px; `; - }, + }, - outlineLinkWarning(t: Theme) { - return css` + outlineLinkWarning(t: Theme) { + return emotion.css` background-color: ${t.btnWarningSecondary}; `; - }, + }, - outlineLinkError(t: Theme) { - return css` + outlineLinkError(t: Theme) { + return emotion.css` background-color: ${t.btnErrorSecondary}; `; - }, + }, - sizeSmall(t: Theme) { - return css` + sizeSmall(t: Theme) { + return emotion.css` border-radius: ${t.btnBorderRadiusSmall}; - ${buttonSizeMixin( + ${buttonSizeMixin(emotion)( t.btnFontSizeSmall, t.btnLineHeightSmall, t.btnPaddingXSmall, @@ -182,24 +185,24 @@ export const styles = memoizeStyle({ t.fontFamilyCompensationBaseline, )}; `; - }, + }, - sizeSmallIE11(t: Theme) { - return css` - ${buttonSizeMixinIE11( + sizeSmallIE11(t: Theme) { + return emotion.css` + ${buttonSizeMixinIE11(emotion)( t.btnFontSizeSmall, t.btnPaddingXSmall, t.btnPaddingYSmall, t.fontFamilyCompensationBaseline, )}; `; - }, + }, - sizeMedium(t: Theme) { - return css` + sizeMedium(t: Theme) { + return emotion.css` border-radius: ${t.btnBorderRadiusMedium}; - ${buttonSizeMixin( + ${buttonSizeMixin(emotion)( t.btnFontSizeMedium, t.btnLineHeightMedium, t.btnPaddingXMedium, @@ -207,24 +210,24 @@ export const styles = memoizeStyle({ t.fontFamilyCompensationBaseline, )}; `; - }, + }, - sizeMediumIE11(t: Theme) { - return css` - ${buttonSizeMixinIE11( + sizeMediumIE11(t: Theme) { + return emotion.css` + ${buttonSizeMixinIE11(emotion)( t.btnFontSizeMedium, t.btnPaddingXMedium, t.btnPaddingYMedium, t.fontFamilyCompensationBaseline, )}; `; - }, + }, - sizeLarge(t: Theme) { - return css` + sizeLarge(t: Theme) { + return emotion.css` border-radius: ${t.btnBorderRadiusLarge}; - ${buttonSizeMixin( + ${buttonSizeMixin(emotion)( t.btnFontSizeLarge, t.btnLineHeightLarge, t.btnPaddingXLarge, @@ -232,57 +235,57 @@ export const styles = memoizeStyle({ t.fontFamilyCompensationBaseline, )}; `; - }, + }, - sizeLargeIE11(t: Theme) { - return css` - ${buttonSizeMixinIE11( + sizeLargeIE11(t: Theme) { + return emotion.css` + ${buttonSizeMixinIE11(emotion)( t.btnFontSizeLarge, t.btnPaddingXLarge, t.btnPaddingYLarge, t.fontFamilyCompensationBaseline, )}; `; - }, + }, - sizeSmallWithIcon(t: Theme) { - return css` + sizeSmallWithIcon(t: Theme) { + return emotion.css` padding-left: ${t.btnWithIconPaddingLeftSmall}; `; - }, + }, - sizeMediumWithIcon(t: Theme) { - return css` + sizeMediumWithIcon(t: Theme) { + return emotion.css` padding-left: ${t.btnWithIconPaddingLeftMedium}; `; - }, + }, - sizeLargeWithIcon(t: Theme) { - return css` + sizeLargeWithIcon(t: Theme) { + return emotion.css` padding-left: ${t.btnWithIconPaddingLeftLarge}; `; - }, + }, - sizeSmallWithIconWithoutText(t: Theme) { - return css` + sizeSmallWithIconWithoutText(t: Theme) { + return emotion.css` padding-right: ${t.btnWithIconPaddingLeftSmall}; `; - }, + }, - sizeMediumWithIconWithoutText(t: Theme) { - return css` + sizeMediumWithIconWithoutText(t: Theme) { + return emotion.css` padding-right: ${t.btnWithIconPaddingLeftMedium}; `; - }, + }, - sizeLargeWithIconWithoutText(t: Theme) { - return css` + sizeLargeWithIconWithoutText(t: Theme) { + return emotion.css` padding-right: ${t.btnWithIconPaddingLeftLarge}; `; - }, + }, - link(t: Theme) { - return css` + link(t: Theme) { + return emotion.css` background: none; border-radius: ${t.btnLinkBorderRadius}; border: none; @@ -301,35 +304,35 @@ export const styles = memoizeStyle({ } &:active:enabled { - ${activeStyles.link(t)} + ${getActiveStyles(emotion).link(t)} } `; - }, + }, - linkLineHeight() { - return css` + linkLineHeight() { + return emotion.css` line-height: inherit !important; // override size mixin `; - }, + }, - linkLineHeightSafariFallback() { - return css` + linkLineHeightSafariFallback() { + return emotion.css` /* Safari overrides 'underline' and 'border' if 'line-height' is used */ margin: -1px 0 -2px; `; - }, + }, - linkFocus(t: Theme) { - return css` + linkFocus(t: Theme) { + return emotion.css` & { color: ${t.btnLinkColor}; text-decoration: ${t.btnLinkHoverTextDecoration}; } `; - }, + }, - linkDisabled(t: Theme) { - return css` + linkDisabled(t: Theme) { + return emotion.css` cursor: default; &, @@ -338,10 +341,10 @@ export const styles = memoizeStyle({ color: ${t.btnLinkDisabledColor}; } `; - }, + }, - focus(t: Theme) { - return css` + focus(t: Theme) { + return emotion.css` position: relative; z-index: 2; @@ -353,10 +356,10 @@ export const styles = memoizeStyle({ 0 0 0 ${t.btnFocusShadowWidth} ${t.btnBorderColorFocus} !important; // override root:hover style } `; - }, + }, - disabled(t: Theme) { - return css` + disabled(t: Theme) { + return emotion.css` cursor: default; box-shadow: 0 0 0 ${t.btnBorderWidth} ${t.btnDisabledBorderColor}; @@ -368,40 +371,40 @@ export const styles = memoizeStyle({ box-shadow: ${t.btnBorderWidth} 0 0 0 ${t.btnDisabledBorderColor}; } `; - }, + }, - disabledWithoutOutline(t: Theme) { - return css` + disabledWithoutOutline(t: Theme) { + return emotion.css` box-shadow: 0 0 0 ${t.btnBorderWidth} ${t.btnDisabledBg}; `; - }, + }, - arrowWarning(t: Theme) { - return css` + arrowWarning(t: Theme) { + return emotion.css` box-shadow: inset 0 0 0 ${t.btnInsetWidth} ${t.btnInsetColor}; - ${arrowOutlineMixin(t.btnInsetWidth, t.btnBorderColorWarning, t.btnOutlineWidth, t.btnInsetColor)} + ${arrowOutlineMixin(emotion)(t.btnInsetWidth, t.btnBorderColorWarning, t.btnOutlineWidth, t.btnInsetColor)} `; - }, + }, - arrowError(t: Theme) { - return css` + arrowError(t: Theme) { + return emotion.css` box-shadow: inset 0 0 0 ${t.btnInsetWidth} ${t.btnInsetColor}; - ${arrowOutlineMixin(t.btnInsetWidth, t.btnBorderColorError, t.btnOutlineWidth, t.btnInsetColor)} + ${arrowOutlineMixin(emotion)(t.btnInsetWidth, t.btnBorderColorError, t.btnOutlineWidth, t.btnInsetColor)} `; - }, + }, - arrowFocus(t: Theme) { - return css` + arrowFocus(t: Theme) { + return emotion.css` box-shadow: inset 0 0 0 ${t.btnInsetWidth} ${t.btnOutlineColorFocus}; - ${arrowOutlineMixin(t.btnInsetWidth, t.btnBorderColorFocus, t.btnOutlineWidth, t.btnOutlineColorFocus)} + ${arrowOutlineMixin(emotion)(t.btnInsetWidth, t.btnBorderColorFocus, t.btnOutlineWidth, t.btnOutlineColorFocus)} `; - }, + }, - arrow() { - return css` + arrow() { + return emotion.css` background: inherit; border-radius: inherit; position: absolute; @@ -463,16 +466,16 @@ export const styles = memoizeStyle({ } } `; - }, + }, - arrowLeft() { - return css` + arrowLeft() { + return emotion.css` transform: scaleX(-1); `; - }, + }, - arrowIconRoot() { - return css` + arrowIconRoot() { + return emotion.css` position: absolute; height: 100%; top: 0; @@ -482,38 +485,38 @@ export const styles = memoizeStyle({ justify-content: center; box-sizing: content-box; `; - }, + }, - arrowIconRootSmall(t: Theme) { - return css` + arrowIconRootSmall(t: Theme) { + return emotion.css` padding: 0 ${t.btnWithIconPaddingLeftSmall} 0 ${t.btnWithIconPaddingLeftSmall}; width: ${t.btnIconSizeSmall}; `; - }, + }, - arrowIconRootMedium(t: Theme) { - return css` + arrowIconRootMedium(t: Theme) { + return emotion.css` padding: 0 ${t.btnWithIconPaddingLeftMedium} 0 ${t.btnWithIconPaddingLeftMedium}; width: ${t.btnIconSizeMedium}; `; - }, + }, - arrowIconRootLarge(t: Theme) { - return css` + arrowIconRootLarge(t: Theme) { + return emotion.css` padding: 0 ${t.btnWithIconPaddingLeftLarge} 0 ${t.btnWithIconPaddingLeftLarge}; width: ${t.btnIconSizeLarge}; `; - }, + }, - arrowIconLeft() { - return css` + arrowIconLeft() { + return emotion.css` left: 0; `; - }, + }, - default(t: Theme) { - return css` - ${buttonUseMixin( + default(t: Theme) { + return emotion.css` + ${buttonUseMixin(emotion)( t.btnDefaultBg, t.btnDefaultBgStart, t.btnDefaultBgEnd, @@ -524,7 +527,7 @@ export const styles = memoizeStyle({ )}; &:hover:enabled { - ${buttonHoverMixin( + ${buttonHoverMixin(emotion)( t.btnDefaultHoverBg, t.btnDefaultHoverBgStart, t.btnDefaultHoverBgEnd, @@ -536,14 +539,14 @@ export const styles = memoizeStyle({ } &:active:enabled { - ${activeStyles.default(t)}; + ${getActiveStyles(emotion).default(t)}; } `; - }, + }, - primary(t: Theme) { - return css` - ${buttonUseMixin( + primary(t: Theme) { + return emotion.css` + ${buttonUseMixin(emotion)( t.btnPrimaryBg, t.btnPrimaryBgStart, t.btnPrimaryBgEnd, @@ -554,7 +557,7 @@ export const styles = memoizeStyle({ )}; &:hover:enabled { - ${buttonHoverMixin( + ${buttonHoverMixin(emotion)( t.btnPrimaryHoverBg, t.btnPrimaryHoverBgStart, t.btnPrimaryHoverBgEnd, @@ -566,14 +569,14 @@ export const styles = memoizeStyle({ } &:active:enabled { - ${activeStyles.primary(t)} + ${getActiveStyles(emotion).primary(t)} } `; - }, + }, - success(t: Theme) { - return css` - ${buttonUseMixin( + success(t: Theme) { + return emotion.css` + ${buttonUseMixin(emotion)( t.btnSuccessBg, t.btnSuccessBgStart, t.btnSuccessBgEnd, @@ -584,7 +587,7 @@ export const styles = memoizeStyle({ )}; &:hover:enabled { - ${buttonHoverMixin( + ${buttonHoverMixin(emotion)( t.btnSuccessHoverBg, t.btnSuccessHoverBgStart, t.btnSuccessHoverBgEnd, @@ -596,14 +599,14 @@ export const styles = memoizeStyle({ } &:active:enabled { - ${activeStyles.success(t)} + ${getActiveStyles(emotion).success(t)} } `; - }, + }, - danger(t: Theme) { - return css` - ${buttonUseMixin( + danger(t: Theme) { + return emotion.css` + ${buttonUseMixin(emotion)( t.btnDangerBg, t.btnDangerBgStart, t.btnDangerBgEnd, @@ -614,7 +617,7 @@ export const styles = memoizeStyle({ )}; &:hover:enabled { - ${buttonHoverMixin( + ${buttonHoverMixin(emotion)( t.btnDangerHoverBg, t.btnDangerHoverBgStart, t.btnDangerHoverBgEnd, @@ -626,14 +629,14 @@ export const styles = memoizeStyle({ } &:active:enabled { - ${activeStyles.danger(t)} + ${getActiveStyles(emotion).danger(t)} } `; - }, + }, - pay(t: Theme) { - return css` - ${buttonUseMixin( + pay(t: Theme) { + return emotion.css` + ${buttonUseMixin(emotion)( t.btnPayBg, t.btnPayBgStart, t.btnPayBgEnd, @@ -644,7 +647,7 @@ export const styles = memoizeStyle({ )}; &:hover:enabled { - ${buttonHoverMixin( + ${buttonHoverMixin(emotion)( t.btnPayHoverBg, t.btnPayHoverBgStart, t.btnPayHoverBgEnd, @@ -656,13 +659,13 @@ export const styles = memoizeStyle({ } &:active:enabled { - ${activeStyles.pay(t)} + ${getActiveStyles(emotion).pay(t)} } `; - }, + }, - text(t: Theme) { - return css` + text(t: Theme) { + return emotion.css` &, &:enabled, &:hover:enabled { @@ -672,10 +675,10 @@ export const styles = memoizeStyle({ } } - ${buttonUseMixin(t.btnTextBg, '', '', t.btnTextTextColor, t.btnTextBorderColor, '', t.btnBorderWidth)}; + ${buttonUseMixin(emotion)(t.btnTextBg, '', '', t.btnTextTextColor, t.btnTextBorderColor, '', t.btnBorderWidth)}; &:hover:enabled { - ${buttonHoverMixin( + ${buttonHoverMixin(emotion)( t.btnTextHoverBg, '', '', @@ -687,14 +690,14 @@ export const styles = memoizeStyle({ } &:active:enabled { - ${activeStyles.text(t)} + ${getActiveStyles(emotion).text(t)} } `; - }, + }, - backless(t: Theme) { - return css` - ${buttonUseMixin( + backless(t: Theme) { + return emotion.css` + ${buttonUseMixin(emotion)( t.btnBacklessBg, '', '', @@ -708,7 +711,7 @@ export const styles = memoizeStyle({ background: transparent; &:hover:enabled { - ${buttonHoverMixin( + ${buttonHoverMixin(emotion)( t.btnBacklessHoverBg, '', '', @@ -720,13 +723,13 @@ export const styles = memoizeStyle({ } &:active:enabled { - ${activeStyles.backless(t)} + ${getActiveStyles(emotion).backless(t)} } `; - }, + }, - checked(t: Theme) { - const checkedStyles = ` + checked(t: Theme) { + const checkedStyles = ` background-image: none; box-shadow: 0 0 0 ${t.btnBorderWidth} ${t.btnDefaultCheckedBorderColor}; background-color: ${t.btnCheckedBg}; @@ -745,7 +748,7 @@ export const styles = memoizeStyle({ } `; - return css` + return emotion.css` ${checkedStyles} &:hover:enabled, @@ -754,10 +757,10 @@ export const styles = memoizeStyle({ ${checkedStyles} } `; - }, + }, - checked2022(t: Theme) { - const checkedStyles = ` + checked2022(t: Theme) { + const checkedStyles = ` background-image: none; box-shadow: 0 0 0 ${t.btnBorderWidth} ${t.btnDefaultCheckedBorderColor} !important; background-color: ${t.btnCheckedBg} !important; @@ -783,7 +786,7 @@ export const styles = memoizeStyle({ } `; - return css` + return emotion.css` ${checkedStyles} &:hover:enabled, @@ -792,10 +795,10 @@ export const styles = memoizeStyle({ ${checkedStyles} } `; - }, + }, - checkedFocused(t: Theme) { - return css` + checkedFocused(t: Theme) { + return emotion.css` &:hover:enabled, &:hover:active:enabled { box-shadow: inset 0 0 0 ${t.btnInsetWidth} ${t.btnOutlineColorFocus}, @@ -803,10 +806,10 @@ export const styles = memoizeStyle({ border-color: ${t.btnBorderColorFocus} !important; } `; - }, + }, - checkedDisabled(t: Theme) { - return css` + checkedDisabled(t: Theme) { + return emotion.css` box-shadow: 0 0 0 ${t.btnBorderWidth} ${t.btnCheckedDisabledBorderColor}; background-color: ${t.btnCheckedDisabledBg}; color: ${t.btnCheckedDisabledColor}; @@ -823,113 +826,113 @@ export const styles = memoizeStyle({ } } `; - }, + }, - checkedDisabled2022(t: Theme) { - return css` + checkedDisabled2022(t: Theme) { + return emotion.css` svg { color: ${t.btnCheckedDisabledColor} !important; } `; - }, + }, - caption() { - return css` + caption() { + return emotion.css` position: relative; white-space: nowrap; display: inline-block; width: 100%; vertical-align: top; `; - }, + }, - captionLink() { - return css` + captionLink() { + return emotion.css` display: inline; transform: none !important; // override root:active style `; - }, + }, - captionTranslated() { - return css` + captionTranslated() { + return emotion.css` transform: translateY(1px); `; - }, + }, - captionDisabled() { - return css` + captionDisabled() { + return emotion.css` transform: none !important; // override root:active style `; - }, + }, - wrap(t: Theme) { - return css` + wrap(t: Theme) { + return emotion.css` box-sizing: border-box; display: inline-block; line-height: normal; padding: ${t.btnBorderWidth}; `; - }, + }, - wrapSmall(t: Theme) { - return css` + wrapSmall(t: Theme) { + return emotion.css` height: ${t.btnHeightSmall}; `; - }, + }, - wrapMedium(t: Theme) { - return css` + wrapMedium(t: Theme) { + return emotion.css` height: ${t.btnHeightMedium}; `; - }, + }, - wrapLarge(t: Theme) { - return css` + wrapLarge(t: Theme) { + return emotion.css` height: ${t.btnHeightLarge}; `; - }, + }, - narrow() { - return css` + narrow() { + return emotion.css` padding-left: 5px; padding-right: 5px; `; - }, + }, - noPadding() { - return css` + noPadding() { + return emotion.css` padding-left: 0; padding-right: 0; `; - }, + }, - noRightPadding() { - return css` + noRightPadding() { + return emotion.css` padding-right: 0; `; - }, + }, - wrapLink() { - return css` + wrapLink() { + return emotion.css` padding: 0; `; - }, + }, - wrapArrow() { - return css` + wrapArrow() { + return emotion.css` margin-right: 10px; `; - }, + }, - wrapArrowLeft() { - return css` + wrapArrowLeft() { + return emotion.css` margin-right: 0; margin-left: 10px; `; - }, + }, - borderless() { - return css` + borderless() { + return emotion.css` &:enabled, &:active:hover:enabled, &:hover:enabled { @@ -939,32 +942,32 @@ export const styles = memoizeStyle({ } } `; - }, + }, - borderless2022() { - return css` + borderless2022() { + return emotion.css` &, &:active:hover, &:hover { box-shadow: none !important; // override root:hover style } `; - }, + }, - backlessDisabled2022(t: Theme) { - return css` + backlessDisabled2022(t: Theme) { + return emotion.css` box-shadow: 0 0 0 1px ${t.btnBacklessDisabledBorderColor}; `; - }, + }, - textDisabled2022() { - return css` + textDisabled2022() { + return emotion.css` background-color: transparent; `; - }, + }, - loading() { - return css` + loading() { + return emotion.css` position: absolute; top: 0; bottom: 0; @@ -976,20 +979,21 @@ export const styles = memoizeStyle({ justify-content: center; z-index: 10; `; - }, + }, - visibilityHidden() { - return css` + visibilityHidden() { + return emotion.css` visibility: hidden; `; - }, -}); + }, + }); -export const activeStyles = memoizeStyle({ - default(t: Theme) { - return css` +export const getActiveStyles = (emotion: Emotion) => + memoizeStyle({ + default(t: Theme) { + return emotion.css` & { - ${buttonActiveMixin( + ${buttonActiveMixin(emotion)( t.btnDefaultActiveBg, t.btnDefaultActiveShadow, t.btnDefaultActiveBorderColor, @@ -999,12 +1003,12 @@ export const activeStyles = memoizeStyle({ )}; } `; - }, + }, - primary(t: Theme) { - return css` + primary(t: Theme) { + return emotion.css` & { - ${buttonActiveMixin( + ${buttonActiveMixin(emotion)( t.btnPrimaryActiveBg, t.btnPrimaryActiveShadow, t.btnPrimaryActiveBorderColor, @@ -1014,12 +1018,12 @@ export const activeStyles = memoizeStyle({ )}; } `; - }, + }, - success(t: Theme) { - return css` + success(t: Theme) { + return emotion.css` & { - ${buttonActiveMixin( + ${buttonActiveMixin(emotion)( t.btnSuccessActiveBg, t.btnSuccessActiveShadow, t.btnSuccessActiveBorderColor, @@ -1029,12 +1033,12 @@ export const activeStyles = memoizeStyle({ )}; } `; - }, + }, - danger(t: Theme) { - return css` + danger(t: Theme) { + return emotion.css` & { - ${buttonActiveMixin( + ${buttonActiveMixin(emotion)( t.btnDangerActiveBg, t.btnDangerActiveShadow, t.btnDangerActiveBorderColor, @@ -1044,12 +1048,12 @@ export const activeStyles = memoizeStyle({ )}; } `; - }, + }, - pay(t: Theme) { - return css` + pay(t: Theme) { + return emotion.css` & { - ${buttonActiveMixin( + ${buttonActiveMixin(emotion)( t.btnPayActiveBg, t.btnPayActiveShadow, t.btnPayActiveBorderColor, @@ -1059,30 +1063,37 @@ export const activeStyles = memoizeStyle({ )}; } `; - }, + }, - link(t: Theme) { - return css` + link(t: Theme) { + return emotion.css` & { color: ${t.btnLinkActiveColor}; } `; - }, + }, - text(t: Theme) { - return css` + text(t: Theme) { + return emotion.css` & { - ${buttonActiveMixin(t.btnTextActiveBg, '', t.btnTextActiveBg, '', t.btnBorderWidth, t.btnArrowBgImageActive)}; + ${buttonActiveMixin(emotion)( + t.btnTextActiveBg, + '', + t.btnTextActiveBg, + '', + t.btnBorderWidth, + t.btnArrowBgImageActive, + )}; } `; - }, + }, - backless(t: Theme) { - return css` + backless(t: Theme) { + return emotion.css` &, &:hover { background: ${t.btnBacklessActiveBg}; } `; - }, -}); + }, + }); diff --git a/packages/react-ui/components/Button/Button.tsx b/packages/react-ui/components/Button/Button.tsx index b5c9181f05a..8984229f036 100644 --- a/packages/react-ui/components/Button/Button.tsx +++ b/packages/react-ui/components/Button/Button.tsx @@ -1,22 +1,23 @@ import React, { AriaAttributes, HTMLAttributes } from 'react'; import { globalObject } from '@skbkontur/global-object'; +import type { Emotion } from '@emotion/css/create-instance'; import { HTMLProps } from '../../typings/html'; import { isKonturIcon, isReactUIComponent } from '../../lib/utils'; -import { isIE11, isEdge, isSafari } from '../../lib/client'; +import { isEdge, isIE11, isSafari } from '../../lib/client'; import { keyListener } from '../../lib/events/keyListener'; import { Theme, ThemeIn } from '../../lib/theming/Theme'; import { ThemeContext } from '../../lib/theming/ThemeContext'; -import { CommonWrapper, CommonProps } from '../../internal/CommonWrapper'; -import { cx } from '../../lib/theming/Emotion'; +import { CommonProps, CommonWrapper } from '../../internal/CommonWrapper'; import { rootNode, TSetRootNode } from '../../lib/rootNode'; import { ThemeFactory } from '../../lib/theming/ThemeFactory'; import { createPropsGetter } from '../../lib/createPropsGetter'; import { isTheme2022 } from '../../lib/theming/ThemeHelpers'; import { Link, LinkProps } from '../Link'; import { SizeProp } from '../../lib/types/props'; +import { EmotionConsumer } from '../../lib/theming/Emotion'; -import { styles, activeStyles, globalClasses } from './Button.styles'; +import { getActiveStyles, getStyles, globalClasses } from './Button.styles'; import { ButtonIcon, ButtonIconProps, getButtonIconSizes } from './ButtonIcon'; import { useButtonArrow } from './ButtonArrow'; import { getInnerLinkTheme } from './getInnerLinkTheme'; @@ -221,6 +222,7 @@ export class Button extends React.Component { }; private theme!: Theme; + private emotion!: Emotion; private node: HTMLButtonElement | null = null; private setRootNode!: TSetRootNode; @@ -254,12 +256,19 @@ export class Button extends React.Component { public render(): JSX.Element { return ( - - {(theme) => { - this.theme = this.props.theme ? ThemeFactory.create(this.props.theme as Theme, theme) : theme; - return this.renderMain(); + + {(emotion) => { + this.emotion = emotion; + return ( + + {(theme) => { + this.theme = this.props.theme ? ThemeFactory.create(this.props.theme as Theme, theme) : theme; + return this.renderMain(); + }} + + ); }} - + ); } @@ -315,12 +324,15 @@ export class Button extends React.Component { const [wrapClassNameWithArrow, rootClassNameWithArrow, arrowNode] = useButtonArrow( { ...this.props, isFocused: Boolean(isFocused) }, this.theme, + this.emotion, ); const isUseStateWithoutOutlineInDisabledState = !['default', 'backless'].includes(use); let rootClassName = ''; + const styles = getStyles(this.emotion); + const activeStyles = getActiveStyles(this.emotion); if (_isTheme2022) { const trueDisabled = disabled || loading; - rootClassName = cx( + rootClassName = this.emotion.cx( styles.root(this.theme), styles[use](this.theme), sizeClass, @@ -347,7 +359,7 @@ export class Button extends React.Component { ]), ); } else { - rootClassName = cx({ + rootClassName = this.emotion.cx({ [styles.root(this.theme)]: true, [styles.simulatedPress()]: true, [styles[use](this.theme)]: true, @@ -398,7 +410,7 @@ export class Button extends React.Component { }; const wrapProps = { - className: cx(globalClasses.root, { + className: this.emotion.cx(globalClasses.root, { [styles.wrap(this.theme)]: true, [wrapClassNameWithArrow]: true, [this.getSizeWrapClassName()]: true, @@ -416,7 +428,7 @@ export class Button extends React.Component { outlineNode = (
{ // Force disable all props and features, that cannot be use with Link if (isLink) { - rootProps.className = cx({ + rootProps.className = this.emotion.cx({ [styles.root(this.theme)]: true, [sizeClass]: true, [styles.link(this.theme)]: true, @@ -450,7 +462,7 @@ export class Button extends React.Component { [styles.linkDisabled(this.theme)]: disabled || loading, }); Object.assign(wrapProps, { - className: cx(styles.wrap(this.theme), styles.wrapLink()), + className: this.emotion.cx(styles.wrap(this.theme), styles.wrapLink()), style: { width: wrapProps.style.width }, }); rootProps.style.textAlign = undefined; @@ -461,7 +473,7 @@ export class Button extends React.Component { let captionNode = (
{ {loadingNode} {leftIconNode} @@ -520,23 +532,24 @@ export class Button extends React.Component { } private getSizeClassName() { + const styles = getStyles(this.emotion); const _isTheme2022 = isTheme2022(this.theme); switch (this.getProps().size) { case 'large': - return cx(styles.sizeLarge(this.theme), { + return this.emotion.cx(styles.sizeLarge(this.theme), { [styles.sizeLargeIE11(this.theme)]: isIE11 || isEdge, [styles.sizeLargeWithIcon(this.theme)]: !!this.props.icon, [styles.sizeLargeWithIconWithoutText(this.theme)]: _isTheme2022 && !!this.props.icon && !this.props.children, }); case 'medium': - return cx(styles.sizeMedium(this.theme), { + return this.emotion.cx(styles.sizeMedium(this.theme), { [styles.sizeMediumIE11(this.theme)]: isIE11 || isEdge, [styles.sizeMediumWithIcon(this.theme)]: !!this.props.icon, [styles.sizeMediumWithIconWithoutText(this.theme)]: _isTheme2022 && !!this.props.icon && !this.props.children, }); case 'small': default: - return cx(styles.sizeSmall(this.theme), { + return this.emotion.cx(styles.sizeSmall(this.theme), { [styles.sizeSmallIE11(this.theme)]: isIE11 || isEdge, [styles.sizeSmallWithIcon(this.theme)]: !!this.props.icon, [styles.sizeSmallWithIconWithoutText(this.theme)]: _isTheme2022 && !!this.props.icon && !this.props.children, @@ -545,6 +558,8 @@ export class Button extends React.Component { } private getSizeWrapClassName() { + const styles = getStyles(this.emotion); + switch (this.getProps().size) { case 'large': return styles.wrapLarge(this.theme); diff --git a/packages/react-ui/components/Button/ButtonArrow.tsx b/packages/react-ui/components/Button/ButtonArrow.tsx index 8326f70b38c..199921a066a 100644 --- a/packages/react-ui/components/Button/ButtonArrow.tsx +++ b/packages/react-ui/components/Button/ButtonArrow.tsx @@ -1,14 +1,15 @@ -import React, { useContext } from 'react'; +import React from 'react'; +import type { Emotion } from '@emotion/css/create-instance'; -import { cx } from '../../lib/theming/Emotion'; -import { ThemeContext } from '../../lib/theming/ThemeContext'; +import { useEmotion } from '../../lib/theming/Emotion'; import { isTheme2022 } from '../../lib/theming/ThemeHelpers'; import { Theme } from '../../lib/theming/Theme'; +import { useTheme } from '../../lib/theming/useTheme'; import { ArrowRightIcon } from './ArrowRightIcon'; import { ArrowLeftIcon } from './ArrowLeftIcon'; import { Button, ButtonProps } from './Button'; -import { globalClasses, styles } from './Button.styles'; +import { getStyles, globalClasses } from './Button.styles'; type ButtonArrowProps = Pick & { isFocused: boolean; @@ -23,11 +24,13 @@ const ButtonArrow: React.FunctionComponent = ({ warning, isFocused, }) => { - const theme = useContext(ThemeContext); + const emotion = useEmotion(); + const theme = useTheme(); const _isTheme2022 = isTheme2022(theme); + const styles = getStyles(emotion); const getArrowIconRootClassName = () => { - return cx(styles.arrowIconRoot(), globalClasses.arrow, { + return emotion.cx(styles.arrowIconRoot(), globalClasses.arrow, { [styles.arrowIconRootSmall(theme)]: size === 'small', [styles.arrowIconRootMedium(theme)]: size === 'medium', [styles.arrowIconRootLarge(theme)]: size === 'large', @@ -52,7 +55,7 @@ const ButtonArrow: React.FunctionComponent = ({ } else { arrowNode = (
= ({ [styles.arrowLeft()]: arrow === 'left', })} > -
-
+
+
); } @@ -69,7 +72,13 @@ const ButtonArrow: React.FunctionComponent = ({ return arrowNode; }; -export function useButtonArrow(props: ButtonArrowProps, theme: Theme): [string, string, React.ReactNode] { +export function useButtonArrow( + props: ButtonArrowProps, + theme: Theme, + emotion: Emotion, +): [string, string, React.ReactNode] { + const styles = getStyles(emotion); + const { arrow, size, use } = props; const _isTheme2022 = isTheme2022(theme); const canRender = use !== 'link' && (arrow === true || arrow === 'left'); @@ -77,7 +86,7 @@ export function useButtonArrow(props: ButtonArrowProps, theme: Theme): [string, const rootClassName = !_isTheme2022 && canRender ? '' - : cx( + : emotion.cx( arrow === true && size === 'small' && styles.withArrowIconRightSmall(theme), arrow === true && size === 'medium' && styles.withArrowIconRightMedium(theme), arrow === true && size === 'large' && styles.withArrowIconRightLarge(theme), @@ -89,7 +98,7 @@ export function useButtonArrow(props: ButtonArrowProps, theme: Theme): [string, const wrapClassName = _isTheme2022 && canRender ? '' - : cx({ + : emotion.cx({ [styles.wrapArrow()]: arrow === true, [styles.wrapArrowLeft()]: arrow === 'left', }); diff --git a/packages/react-ui/components/Button/ButtonIcon.styles.ts b/packages/react-ui/components/Button/ButtonIcon.styles.ts index 6560d2ba33f..ec1f71389e3 100644 --- a/packages/react-ui/components/Button/ButtonIcon.styles.ts +++ b/packages/react-ui/components/Button/ButtonIcon.styles.ts @@ -1,90 +1,93 @@ +import type { Emotion } from '@emotion/css/create-instance'; + import { isTheme2022 } from '../../lib/theming/ThemeHelpers'; import { ZERO_WIDTH_SPACE_CSS } from '../../lib/chars'; -import { css, memoizeStyle } from '../../lib/theming/Emotion'; +import { memoizeStyle } from '../../lib/theming/Emotion'; import { Theme } from '../../lib/theming/Theme'; -export const styles = memoizeStyle({ - icon(t: Theme) { - const space = isTheme2022(t) ? `'${ZERO_WIDTH_SPACE_CSS}'` : null; - return css` - display: inline-block; +export const getStyles = (emotion: Emotion) => + memoizeStyle({ + icon(t: Theme) { + const space = isTheme2022(t) ? `'${ZERO_WIDTH_SPACE_CSS}'` : null; + return emotion.css` + display: inline-block; - &::before { - content: ${space}; - } - `; - }, + &::before { + content: ${space}; + } + `; + }, - iconSmall(t: Theme) { - return css` - width: ${t.btnIconSizeSmall}; - `; - }, + iconSmall(t: Theme) { + return emotion.css` + width: ${t.btnIconSizeSmall}; + `; + }, - iconSmallLeft(t: Theme) { - return css` - margin-right: ${t.btnIconGapSmall}; - `; - }, + iconSmallLeft(t: Theme) { + return emotion.css` + margin-right: ${t.btnIconGapSmall}; + `; + }, - iconSmallRight(t: Theme) { - return css` - margin-left: ${t.btnIconGapSmallRight}; - `; - }, + iconSmallRight(t: Theme) { + return emotion.css` + margin-left: ${t.btnIconGapSmallRight}; + `; + }, - iconMedium(t: Theme) { - return css` - width: ${t.btnIconSizeMedium}; - `; - }, + iconMedium(t: Theme) { + return emotion.css` + width: ${t.btnIconSizeMedium}; + `; + }, - iconMediumLeft(t: Theme) { - return css` - margin-right: ${t.btnIconGapMediumRight}; - `; - }, + iconMediumLeft(t: Theme) { + return emotion.css` + margin-right: ${t.btnIconGapMediumRight}; + `; + }, - iconMediumRight(t: Theme) { - return css` - margin-left: ${t.btnIconGapMedium}; - `; - }, + iconMediumRight(t: Theme) { + return emotion.css` + margin-left: ${t.btnIconGapMedium}; + `; + }, - iconLarge(t: Theme) { - return css` - width: ${t.btnIconSizeLarge}; - `; - }, + iconLarge(t: Theme) { + return emotion.css` + width: ${t.btnIconSizeLarge}; + `; + }, - iconLargeLeft(t: Theme) { - return css` - margin-right: ${t.btnIconGapLarge}; - `; - }, + iconLargeLeft(t: Theme) { + return emotion.css` + margin-right: ${t.btnIconGapLarge}; + `; + }, - iconLargeRight(t: Theme) { - return css` - margin-left: ${t.btnIconGapLargeRight}; - `; - }, + iconLargeRight(t: Theme) { + return emotion.css` + margin-left: ${t.btnIconGapLargeRight}; + `; + }, - iconLeftLink(t: Theme) { - return css` - margin-right: ${t.btnLinkIconMarginRight}; - `; - }, + iconLeftLink(t: Theme) { + return emotion.css` + margin-right: ${t.btnLinkIconMarginRight}; + `; + }, - iconRightLink(t: Theme) { - return css` - margin-left: ${t.btnLinkIconMarginLeft}; - `; - }, + iconRightLink(t: Theme) { + return emotion.css` + margin-left: ${t.btnLinkIconMarginLeft}; + `; + }, - iconNoMargin() { - return css` - margin-right: 0; - margin-left: 0; - `; - }, -}); + iconNoMargin() { + return emotion.css` + margin-right: 0; + margin-left: 0; + `; + }, + }); diff --git a/packages/react-ui/components/Button/ButtonIcon.tsx b/packages/react-ui/components/Button/ButtonIcon.tsx index cecec34485c..d2d1f22162b 100644 --- a/packages/react-ui/components/Button/ButtonIcon.tsx +++ b/packages/react-ui/components/Button/ButtonIcon.tsx @@ -1,14 +1,14 @@ -import React, { useContext } from 'react'; +import React from 'react'; import { Theme } from '../../lib/theming/Theme'; import { isKonturIcon } from '../../lib/utils'; -import { cx } from '../../lib/theming/Emotion'; -import { ThemeContext } from '../../lib/theming/ThemeContext'; +import { useEmotion } from '../../lib/theming/Emotion'; import { isTheme2022 } from '../../lib/theming/ThemeHelpers'; import { SizeProp } from '../../lib/types/props'; +import { useTheme } from '../../lib/theming/useTheme'; import { ButtonProps } from './Button'; -import { styles } from './ButtonIcon.styles'; +import { getStyles } from './ButtonIcon.styles'; import { LoadingButtonIcon } from './LoadingButtonIcon'; export interface ButtonIconProps extends Pick { @@ -26,7 +26,7 @@ export const getButtonIconSizes = (theme: Theme): Record => { }; const useIcon = (icon: any, size: SizeProp) => { - const theme = useContext(ThemeContext); + const theme = useTheme(); if (icon && isTheme2022(theme) && isKonturIcon(icon)) { const sizes = getButtonIconSizes(theme); return React.cloneElement(icon, { size: icon.props.size ?? sizes[size] }); @@ -44,7 +44,10 @@ export const ButtonIcon: React.FunctionComponent = ({ hasBothIcons = false, size = 'small', }) => { - const theme = useContext(ThemeContext); + const theme = useTheme(); + const emotion = useEmotion(); + const styles = getStyles(emotion); + const isLink = use === 'link'; const getSizeIconClassName = () => { @@ -80,7 +83,7 @@ export const ButtonIcon: React.FunctionComponent = ({ return ( { - const theme = useContext(ThemeContext); + const theme = useTheme(); + const emotion = useEmotion(); + const styles = getStyles(emotion); return (
diff --git a/packages/react-ui/components/Calendar/Calendar.styles.ts b/packages/react-ui/components/Calendar/Calendar.styles.ts index cf49e9c2810..b1744c02911 100644 --- a/packages/react-ui/components/Calendar/Calendar.styles.ts +++ b/packages/react-ui/components/Calendar/Calendar.styles.ts @@ -1,33 +1,36 @@ -import { css, memoizeStyle } from '../../lib/theming/Emotion'; +import type { Emotion } from '@emotion/css/create-instance'; + +import { memoizeStyle } from '../../lib/theming/Emotion'; import { Theme } from '../../lib/theming/Theme'; -export const styles = memoizeStyle({ - root(t: Theme) { - const width = parseInt(t.calendarCellSize) * 7; - return css` - background: ${t.calendarBg}; - box-sizing: content-box; - border-radius: ${t.pickerBorderRadius}; - color: ${t.textColorDefault}; - display: block; - padding: 0 ${t.calendarPaddingX}; - width: ${width}px; - touch-action: none; - `; - }, +export const getStyles = (emotion: Emotion) => + memoizeStyle({ + root(t: Theme) { + const width = parseInt(t.calendarCellSize) * 7; + return emotion.css` + background: ${t.calendarBg}; + box-sizing: content-box; + border-radius: ${t.pickerBorderRadius}; + color: ${t.textColorDefault}; + display: block; + padding: 0 ${t.calendarPaddingX}; + width: ${width}px; + touch-action: none; + `; + }, - wrapper() { - return css` - font-size: 14px; - position: relative; - overflow: hidden; - `; - }, + wrapper() { + return emotion.css` + font-size: 14px; + position: relative; + overflow: hidden; + `; + }, - separator(t: Theme) { - return css` - border-bottom: ${t.calendarBottomSeparatorBorder}; - margin: 0 ${t.calendarMonthTitleMarginX}; - `; - }, -}); + separator(t: Theme) { + return emotion.css` + border-bottom: ${t.calendarBottomSeparatorBorder}; + margin: 0 ${t.calendarMonthTitleMarginX}; + `; + }, + }); diff --git a/packages/react-ui/components/Calendar/Calendar.tsx b/packages/react-ui/components/Calendar/Calendar.tsx index 3fc8fe3cf5e..e88ea2d2e85 100644 --- a/packages/react-ui/components/Calendar/Calendar.tsx +++ b/packages/react-ui/components/Calendar/Calendar.tsx @@ -3,28 +3,29 @@ import normalizeWheel from 'normalize-wheel'; import throttle from 'lodash.throttle'; import shallowEqual from 'shallowequal'; import { globalObject, SafeTimer } from '@skbkontur/global-object'; +import type { Emotion } from '@emotion/css/create-instance'; import { isInstanceOf } from '../../lib/isInstanceOf'; import { InternalDate } from '../../lib/date/InternalDate'; import { InternalDateTransformer } from '../../lib/date/InternalDateTransformer'; import { rootNode, TSetRootNode } from '../../lib/rootNode'; -import { cx } from '../../lib/theming/Emotion'; +import { EmotionConsumer } from '../../lib/theming/Emotion'; import { CommonProps, CommonWrapper } from '../../internal/CommonWrapper'; import { MAX_DATE, MAX_MONTH, MAX_YEAR, MIN_DATE, MIN_MONTH, MIN_YEAR } from '../../lib/date/constants'; import { Nullable, Range } from '../../typings/utility-types'; import { Theme } from '../../lib/theming/Theme'; -import { ThemeContext } from '../../lib/theming/ThemeContext'; import { animation } from '../../lib/animation'; import { isMobile } from '../../lib/client'; import { createPropsGetter } from '../../lib/createPropsGetter'; +import { ThemeContext } from '../../lib/theming/ThemeContext'; import { themeConfig } from './config'; import { MonthViewModel } from './MonthViewModel'; import * as CalendarScrollEvents from './CalendarScrollEvents'; import { Month } from './Month'; -import { styles } from './Calendar.styles'; import { CalendarDateShape, create, isGreater, isLess } from './CalendarDateShape'; import * as CalendarUtils from './CalendarUtils'; +import { getStyles } from './Calendar.styles'; export interface CalendarProps extends CommonProps { /** @@ -109,6 +110,7 @@ export class Calendar extends React.Component { private getProps = createPropsGetter(Calendar.defaultProps); private theme!: Theme; + private emotion!: Emotion; private wheelEndTimeout: SafeTimer; private root: Nullable; private animation = animation(); @@ -160,12 +162,19 @@ export class Calendar extends React.Component { public render() { return ( - - {(theme) => { - this.theme = theme; - return this.renderMain(); + + {(emotion) => { + this.emotion = emotion; + return ( + + {(theme) => { + this.theme = theme; + return this.renderMain(); + }} + + ); }} - + ); } @@ -284,10 +293,11 @@ export class Calendar extends React.Component { const wrapperStyle = { height: themeConfig(this.theme).WRAPPER_HEIGHT }; const props = this.getProps(); + const styles = getStyles(this.emotion); return ( -
+
{this.state.months .map<[number, MonthViewModel]>((x, i) => [positions[i], x]) diff --git a/packages/react-ui/components/Calendar/DayCellView.styles.ts b/packages/react-ui/components/Calendar/DayCellView.styles.ts index 97f90ff98f6..c25a5a5c945 100644 --- a/packages/react-ui/components/Calendar/DayCellView.styles.ts +++ b/packages/react-ui/components/Calendar/DayCellView.styles.ts @@ -1,4 +1,6 @@ -import { css, memoizeStyle, prefix } from '../../lib/theming/Emotion'; +import type { Emotion } from '@emotion/css/create-instance'; + +import { memoizeStyle, prefix } from '../../lib/theming/Emotion'; import { Theme } from '../../lib/theming/Theme'; import { resetButton } from '../../lib/styles/Mixins'; @@ -6,70 +8,71 @@ export const globalClasses = prefix('day-cell-view')({ todayCaption: 'today-caption', }); -export const styles = memoizeStyle({ - cell(t: Theme) { - return css` - ${resetButton()}; +export const getStyles = (emotion: Emotion) => + memoizeStyle({ + cell(t: Theme) { + return emotion.css` + ${resetButton(emotion)}; - background: ${t.calendarCellBg}; - border: 1px solid transparent; - display: inline-block; - font-size: 14px; - padding: 0; - text-align: center; - user-select: none; - position: relative; + background: ${t.calendarCellBg}; + border: 1px solid transparent; + display: inline-block; + font-size: 14px; + padding: 0; + text-align: center; + user-select: none; + position: relative; - width: ${t.calendarCellSize}; - height: ${t.calendarCellSize}; - line-height: ${t.calendarCellLineHeight}; - border-radius: 50%; + width: ${t.calendarCellSize}; + height: ${t.calendarCellSize}; + line-height: ${t.calendarCellLineHeight}; + border-radius: 50%; - &:hover { - background-color: ${t.calendarCellHoverBgColor}; - color: ${t.calendarCellHoverColor}; - cursor: pointer; - } - &:disabled { - opacity: 0.5; - pointer-events: none; - } - &:active:hover:enabled { - color: ${t.calendarCellActiveHoverColor}; - } - `; - }, + &:hover { + background-color: ${t.calendarCellHoverBgColor}; + color: ${t.calendarCellHoverColor}; + cursor: pointer; + } + &:disabled { + opacity: 0.5; + pointer-events: none; + } + &:active:hover:enabled { + color: ${t.calendarCellActiveHoverColor}; + } + `; + }, - selected(t: Theme) { - return css` - background-color: ${t.calendarCellSelectedBgColor}; - color: ${t.calendarCellSelectedFontColor}; - `; - }, + selected(t: Theme) { + return emotion.css` + background-color: ${t.calendarCellSelectedBgColor}; + color: ${t.calendarCellSelectedFontColor}; + `; + }, - weekend(t: Theme) { - return css` - color: ${t.calendarCellWeekendColor}; - `; - }, + weekend(t: Theme) { + return emotion.css` + color: ${t.calendarCellWeekendColor}; + `; + }, - today(t: Theme) { - return css` - border: ${t.calendarCellTodayBorder}; - `; - }, + today(t: Theme) { + return emotion.css` + border: ${t.calendarCellTodayBorder}; + `; + }, - today2022(t: Theme) { - return css` - .${globalClasses.todayCaption} { - border-bottom: ${t.calendarCellTodayBorder}; - } - `; - }, + today2022(t: Theme) { + return emotion.css` + .${globalClasses.todayCaption} { + border-bottom: ${t.calendarCellTodayBorder}; + } + `; + }, - todayCaption() { - return css` - padding-bottom: 2px; - `; - }, -}); + todayCaption() { + return emotion.css` + padding-bottom: 2px; + `; + }, + }); diff --git a/packages/react-ui/components/Calendar/DayCellView.tsx b/packages/react-ui/components/Calendar/DayCellView.tsx index dff852a8729..1fb7fb25ad9 100644 --- a/packages/react-ui/components/Calendar/DayCellView.tsx +++ b/packages/react-ui/components/Calendar/DayCellView.tsx @@ -1,15 +1,15 @@ -import React, { useContext } from 'react'; +import React from 'react'; import { useLocaleForControl } from '../../lib/locale/useLocaleForControl'; import { Nullable } from '../../typings/utility-types'; -import { ThemeContext } from '../../lib/theming/ThemeContext'; -import { cx } from '../../lib/theming/Emotion'; +import { useEmotion } from '../../lib/theming/Emotion'; import { isTheme2022 } from '../../lib/theming/ThemeHelpers'; import { DatePickerLocaleHelper } from '../DatePicker/locale'; import { getVisualStateDataAttributes } from '../../internal/CommonWrapper/getVisualStateDataAttributes'; +import { useTheme } from '../../lib/theming/useTheme'; import * as CDS from './CalendarDateShape'; -import { globalClasses, styles } from './DayCellView.styles'; +import { getStyles, globalClasses } from './DayCellView.styles'; import { CalendarDataTids } from './Calendar'; interface DayCellViewProps { @@ -24,7 +24,8 @@ interface DayCellViewProps { export function DayCellView(props: DayCellViewProps) { const { date, minDate, maxDate, today, value, isWeekend, onDateClick } = props; - const theme = useContext(ThemeContext); + const emotion = useEmotion(); + const theme = useTheme(); const _isTheme2022 = isTheme2022(theme); const handleClick = () => { @@ -32,8 +33,9 @@ export function DayCellView(props: DayCellViewProps) { onDateClick?.({ date, month, year }); }; + const styles = getStyles(emotion); const child = _isTheme2022 ? ( - {date.date} + {date.date} ) : ( date.date ); @@ -49,7 +51,7 @@ export function DayCellView(props: DayCellViewProps) { tabIndex={-1} aria-label={`${locale.dayCellChooseDateAriaLabel} ${value?.date}.${value && value.month + 1}.${value?.year}`} disabled={!CDS.isBetween(date, minDate, maxDate)} - className={cx({ + className={emotion.cx({ [styles.cell(theme)]: true, [styles.today(theme)]: isToday && !_isTheme2022, [styles.today2022(theme)]: isToday && _isTheme2022, diff --git a/packages/react-ui/components/Calendar/Month.tsx b/packages/react-ui/components/Calendar/Month.tsx index a358f15882f..d55db4991cc 100644 --- a/packages/react-ui/components/Calendar/Month.tsx +++ b/packages/react-ui/components/Calendar/Month.tsx @@ -1,10 +1,12 @@ import React from 'react'; +import type { Emotion } from '@emotion/css/create-instance'; -import { ThemeContext } from '../../lib/theming/ThemeContext'; import { Theme } from '../../lib/theming/Theme'; import { DateSelect } from '../../internal/DateSelect'; import { Nullable } from '../../typings/utility-types'; import { createPropsGetter } from '../../lib/createPropsGetter'; +import { EmotionConsumer } from '../../lib/theming/Emotion'; +import { ThemeContext } from '../../lib/theming/ThemeContext'; import { themeConfig } from './config'; import * as CDS from './CalendarDateShape'; @@ -13,7 +15,7 @@ import { DayCellViewModel } from './DayCellViewModel'; import { MonthView } from './MonthView'; import { DayCellView } from './DayCellView'; import * as CalendarScrollEvents from './CalendarScrollEvents'; -import { styles } from './MonthView.styles'; +import { getStyles } from './MonthView.styles'; interface MonthProps { top: number; @@ -31,7 +33,6 @@ type DefaultProps = Required>; export class Month extends React.Component { private theme!: Theme; - private monthSelect: DateSelect | null = null; private yearSelect: DateSelect | null = null; @@ -146,6 +147,7 @@ interface MonthDayGridProps { class MonthDayGrid extends React.Component { private theme!: Theme; + private emotion!: Emotion; public static defaultProps: DefaultProps = { isHoliday: (day: CDS.CalendarDateShape & { isWeekend: boolean }) => day.isWeekend, @@ -171,16 +173,24 @@ class MonthDayGrid extends React.Component { public render() { return ( - - {(theme) => { - this.theme = theme; - return this.renderMain(); + + {(emotion) => { + this.emotion = emotion; + return ( + + {(theme) => { + this.theme = theme; + return this.renderMain(); + }} + + ); }} - + ); } public renderMain() { + const styles = getStyles(this.emotion); return (
+ memoizeStyle({ + headerMonth(t: Theme) { + return emotion.css` + display: inline-block; + padding: ${t.calendarMonthTitlePaddingTop} 0 ${t.calendarMonthTitlePaddingBottom}; + `; + }, + + headerYear(t: Theme) { + return emotion.css` + display: inline-block; + position: absolute; + right: 0; + padding: ${t.calendarMonthTitlePaddingTop} 0 ${t.calendarMonthTitlePaddingBottom}; + `; + }, + + month(t: Theme) { + const width = parseInt(t.calendarCellSize) * 7; + return emotion.css` + position: absolute; + width: ${width}px; + `; + }, + + header() { + return emotion.css` + position: relative; + `; + }, + + headerSticky(t: Theme) { + return emotion.css` + background-color: ${t.calendarMonthHeaderStickedBgColor}; + z-index: 2; + `; + }, + + monthTitle(t: Theme) { + return emotion.css` + border-bottom: 1px solid ${t.calendarMonthTitleBorderBottomColor}; + font-weight: ${t.dateSelectFontWeight}; + margin: 0 ${t.calendarMonthTitleMarginX} ${t.calendarMonthTitleMarginBottom}; + line-height: ${t.calendarMonthTitleLineHeight}; + `; + }, + + monthDayGrid(t: Theme) { + return emotion.css` + line-height: ${t.calendarCellLineHeight}; + `; + }, + }); diff --git a/packages/react-ui/components/Calendar/MonthView.tsx b/packages/react-ui/components/Calendar/MonthView.tsx index 8ace10918fa..4612389b13c 100644 --- a/packages/react-ui/components/Calendar/MonthView.tsx +++ b/packages/react-ui/components/Calendar/MonthView.tsx @@ -1,11 +1,11 @@ -import React, { useContext } from 'react'; +import React from 'react'; import { DateSelect } from '../../internal/DateSelect'; -import { ThemeContext } from '../../lib/theming/ThemeContext'; import * as ColorFunctions from '../../lib/styles/ColorFunctions'; -import { cx } from '../../lib/theming/Emotion'; +import { useEmotion } from '../../lib/theming/Emotion'; +import { useTheme } from '../../lib/theming/useTheme'; -import { styles } from './MonthView.styles'; +import { getStyles } from './MonthView.styles'; import { themeConfig } from './config'; import * as CDS from './CalendarDateShape'; import { CalendarDataTids } from './Calendar'; @@ -28,7 +28,8 @@ interface MonthViewProps { } export function MonthView(props: MonthViewProps) { - const theme = useContext(ThemeContext); + const theme = useTheme(); + const emotion = useEmotion(); const { children, @@ -77,12 +78,13 @@ export function MonthView(props: MonthViewProps) { } return max; }; + const styles = getStyles(emotion); return (
+ memoizeStyle({ + root() { + return emotion.css` + height: 100%; + text-align: center; + `; + }, - rootAlignRight() { - return css` - text-align: right; - `; - }, + rootAlignLeft() { + return emotion.css` + text-align: left; + `; + }, - spring() { - return css` - display: inline-block; - height: 100%; - vertical-align: middle; - `; - }, + rootAlignRight() { + return emotion.css` + text-align: right; + `; + }, - container() { - return css` - display: inline-block; - text-align: left; - vertical-align: middle; - `; - }, -}); + spring() { + return emotion.css` + display: inline-block; + height: 100%; + vertical-align: middle; + `; + }, + + container() { + return emotion.css` + display: inline-block; + text-align: left; + vertical-align: middle; + `; + }, + }); diff --git a/packages/react-ui/components/Center/Center.tsx b/packages/react-ui/components/Center/Center.tsx index b14701260ce..5ad63355c44 100644 --- a/packages/react-ui/components/Center/Center.tsx +++ b/packages/react-ui/components/Center/Center.tsx @@ -1,12 +1,13 @@ import React from 'react'; +import type { Emotion } from '@emotion/css/create-instance'; import { Override } from '../../typings/utility-types'; import { CommonProps, CommonWrapper, CommonWrapperRestProps } from '../../internal/CommonWrapper'; -import { cx } from '../../lib/theming/Emotion'; import { rootNode, TSetRootNode } from '../../lib/rootNode'; import { createPropsGetter, DefaultizedProps } from '../../lib/createPropsGetter'; +import { EmotionConsumer } from '../../lib/theming/Emotion'; -import { styles } from './Center.styles'; +import { getStyles } from './Center.styles'; export type HorizontalAlign = 'left' | 'center' | 'right'; @@ -44,23 +45,31 @@ export class Center extends React.Component { }; private getProps = createPropsGetter(Center.defaultProps); + private emotion!: Emotion; private setRootNode!: TSetRootNode; public render() { return ( - - {this.renderMain} - + + {(emotion) => { + this.emotion = emotion; + return ( + + {this.renderMain} + + ); + }} + ); } private renderMain = (props: CommonWrapperRestProps) => { const { align, ...rest } = props; - + const styles = getStyles(this.emotion); return (
{ - return css` +export const checkboxSizeMixin = + (emotion: Emotion) => (fontSize: string, lineHeight: string, paddingY: string, checkboxBoxSize: string) => { + return emotion.css` line-height: ${lineHeight}; font-size: ${fontSize}; padding: ${paddingY} 0; @@ -12,26 +14,23 @@ export const checkboxSizeMixin = (fontSize: string, lineHeight: string, paddingY width: ${checkboxBoxSize}; } `; -}; + }; -export const boxWrapperSizeMixin = ( - labGrotesqueBaselineCompensation: string, - fontSize: string, - checkboxBoxSize: string, - checkboxBoxOffsetY: string, -) => { - const labGrotesqueCompenstation = parseInt(labGrotesqueBaselineCompensation); - const boxFontSize = parseInt(fontSize); - const baselineCompensation = getLabGrotesqueBaselineCompensation( - boxFontSize, - labGrotesqueCompenstation, - isChrome, - isFirefox, - ); +export const boxWrapperSizeMixin = + (emotion: Emotion) => + (labGrotesqueBaselineCompensation: string, fontSize: string, checkboxBoxSize: string, checkboxBoxOffsetY: string) => { + const labGrotesqueCompenstation = parseInt(labGrotesqueBaselineCompensation); + const boxFontSize = parseInt(fontSize); + const baselineCompensation = getLabGrotesqueBaselineCompensation( + boxFontSize, + labGrotesqueCompenstation, + isChrome, + isFirefox, + ); - return css` + return emotion.css` width: ${checkboxBoxSize}; height: ${checkboxBoxSize}; margin-top: calc(${checkboxBoxOffsetY} + ${baselineCompensation}px); `; -}; + }; diff --git a/packages/react-ui/components/Checkbox/Checkbox.styles.ts b/packages/react-ui/components/Checkbox/Checkbox.styles.ts index dc165d0bf18..581e047ee6e 100644 --- a/packages/react-ui/components/Checkbox/Checkbox.styles.ts +++ b/packages/react-ui/components/Checkbox/Checkbox.styles.ts @@ -1,4 +1,6 @@ -import { css, memoizeStyle, prefix } from '../../lib/theming/Emotion'; +import type { Emotion } from '@emotion/css/create-instance'; + +import { memoizeStyle, prefix } from '../../lib/theming/Emotion'; import { Theme } from '../../lib/theming/Theme'; import { boxWrapperSizeMixin, checkboxSizeMixin } from './Checkbox.mixins'; @@ -7,112 +9,113 @@ export const globalClasses = prefix('checkbox')({ box: 'box', }); -export const styles = memoizeStyle({ - root(t: Theme) { - return css` - display: inline-flex; - align-items: baseline; - cursor: pointer; - position: relative; - - &::before { - // non-breaking space. - // makes a correct space for absolutely positioned box, - // and also height and baseline for checkbox without caption. - content: '\\00A0'; - display: inline-block; - flex: 0 0 auto; - } - - .${globalClasses.box} { - transition: background ${t.transitionDuration} ${t.transitionTimingFunction}, - box-shadow ${t.transitionDuration} ${t.transitionTimingFunction}; - } - - &:hover .${globalClasses.box} { - background: ${t.checkboxHoverBg}; - box-shadow: ${t.checkboxShadowHover}; - } - - &:active .${globalClasses.box} { - box-shadow: ${t.checkboxShadowActive}; - background: ${t.checkboxActiveBg}; - } - `; - }, - - rootSmall(t: Theme) { - return css` - ${checkboxSizeMixin( - t.checkboxFontSizeSmall, - t.checkboxLineHeightSmall, - t.checkboxPaddingYSmall, - t.checkboxBoxSizeSmall, - )}; - `; - }, - - rootMedium(t: Theme) { - return css` - ${checkboxSizeMixin( - t.checkboxFontSizeMedium, - t.checkboxLineHeightMedium, - t.checkboxPaddingYMedium, - t.checkboxBoxSizeMedium, - )}; - `; - }, - - rootLarge(t: Theme) { - return css` - ${checkboxSizeMixin( - t.checkboxFontSizeLarge, - t.checkboxLineHeightLarge, - t.checkboxPaddingYLarge, - t.checkboxBoxSizeLarge, - )}; - `; - }, - - rootDisableTextSelect() { - return css` - user-select: none; - `; - }, - - rootChecked(t: Theme) { - return css` - &:hover .${globalClasses.box} { - box-shadow: ${t.checkboxCheckedHoverShadow}; - background: ${t.checkboxCheckedHoverBg}; - } - - &:active .${globalClasses.box} { - background: ${t.checkboxCheckedActiveBg}; - box-shadow: ${t.checkboxCheckedActiveShadow}; - } - `; - }, - - rootFallback() { - return css` - display: inline-table; - - & > * { - // fix root's :active state in IE11 that gets blocked by nested elements - pointer-events: none; - } - `; - }, - - rootWrapperIE11() { - return css` - display: inline; - `; - }, - - boxWrapper(t: Theme) { - return css` +export const getStyles = (emotion: Emotion) => + memoizeStyle({ + root(t: Theme) { + return emotion.css` + display: inline-flex; + align-items: baseline; + cursor: pointer; + position: relative; + + &::before { + // non-breaking space. + // makes a correct space for absolutely positioned box, + // and also height and baseline for checkbox without caption. + content: '\\00A0'; + display: inline-block; + flex: 0 0 auto; + } + + .${globalClasses.box} { + transition: background ${t.transitionDuration} ${t.transitionTimingFunction}, + box-shadow ${t.transitionDuration} ${t.transitionTimingFunction}; + } + + &:hover .${globalClasses.box} { + background: ${t.checkboxHoverBg}; + box-shadow: ${t.checkboxShadowHover}; + } + + &:active .${globalClasses.box} { + box-shadow: ${t.checkboxShadowActive}; + background: ${t.checkboxActiveBg}; + } + `; + }, + + rootSmall(t: Theme) { + return emotion.css` + ${checkboxSizeMixin(emotion)( + t.checkboxFontSizeSmall, + t.checkboxLineHeightSmall, + t.checkboxPaddingYSmall, + t.checkboxBoxSizeSmall, + )}; + `; + }, + + rootMedium(t: Theme) { + return emotion.css` + ${checkboxSizeMixin(emotion)( + t.checkboxFontSizeMedium, + t.checkboxLineHeightMedium, + t.checkboxPaddingYMedium, + t.checkboxBoxSizeMedium, + )}; + `; + }, + + rootLarge(t: Theme) { + return emotion.css` + ${checkboxSizeMixin(emotion)( + t.checkboxFontSizeLarge, + t.checkboxLineHeightLarge, + t.checkboxPaddingYLarge, + t.checkboxBoxSizeLarge, + )}; + `; + }, + + rootDisableTextSelect() { + return emotion.css` + user-select: none; + `; + }, + + rootChecked(t: Theme) { + return emotion.css` + &:hover .${globalClasses.box} { + box-shadow: ${t.checkboxCheckedHoverShadow}; + background: ${t.checkboxCheckedHoverBg}; + } + + &:active .${globalClasses.box} { + background: ${t.checkboxCheckedActiveBg}; + box-shadow: ${t.checkboxCheckedActiveShadow}; + } + `; + }, + + rootFallback() { + return emotion.css` + display: inline-table; + + & > * { + // fix root's :active state in IE11 that gets blocked by nested elements + pointer-events: none; + } + `; + }, + + rootWrapperIE11() { + return emotion.css` + display: inline; + `; + }, + + boxWrapper(t: Theme) { + return emotion.css` position: absolute; box-sizing: border-box; padding: ${t.checkboxBorderWidth}; @@ -122,143 +125,143 @@ export const styles = memoizeStyle({ left: 0; )}; `; - }, - - boxWrapperSmall(t: Theme) { - return css` - ${boxWrapperSizeMixin( - t.labGrotesqueBaselineCompensation, - t.checkboxFontSizeSmall, - t.checkboxBoxSizeSmall, - t.checkboxBoxOffsetY, - )}; - `; - }, - - boxWrapperMedium(t: Theme) { - return css` - ${boxWrapperSizeMixin( - t.labGrotesqueBaselineCompensation, - t.checkboxFontSizeMedium, - t.checkboxBoxSizeMedium, - t.checkboxBoxOffsetY, - )}; - `; - }, - - boxWrapperLarge(t: Theme) { - return css` - ${boxWrapperSizeMixin( - t.labGrotesqueBaselineCompensation, - t.checkboxFontSizeLarge, - t.checkboxBoxSizeLarge, - t.checkboxBoxOffsetY, - )}; - `; - }, - - box(t: Theme) { - return css` - color: ${t.checkboxTextColorDefault}; - box-shadow: ${t.checkboxShadow}; - background: ${t.checkboxBg}; - border-radius: ${t.checkboxBorderRadius}; - height: 100%; - `; - }, - - input() { - return css` - display: inline-block; - height: 0; - opacity: 0; - position: absolute; - width: 0; - z-index: -1; - `; - }, - - boxWarning(t: Theme) { - return css` - box-shadow: inset 0 0 0 1px ${t.checkboxOutlineColorFocus}, - 0 0 0 ${t.checkboxOutlineWidth} ${t.checkboxBorderColorWarning} !important; // override hover and active - `; - }, - - boxError(t: Theme) { - return css` - box-shadow: inset 0 0 0 1px ${t.checkboxOutlineColorFocus}, - 0 0 0 ${t.checkboxOutlineWidth} ${t.checkboxBorderColorError} !important; // override hover and active - `; - }, - - boxChecked(t: Theme) { - return css` - background: ${t.checkboxCheckedBg}; - color: ${t.checkboxCheckedColor}; - box-shadow: ${t.checkboxCheckedShadow}; - `; - }, - - boxFocus(t: Theme) { - return css` - box-shadow: inset 0 0 0 1px ${t.checkboxOutlineColorFocus}, - 0 0 0 ${t.checkboxOutlineWidth} ${t.checkboxBorderColorFocus} !important; // override hover and active - `; - }, - - boxDisabled(t: Theme) { - return css` - box-shadow: ${t.checkboxShadowDisabled} !important; // override hover and active - background: ${t.checkboxBgDisabled} !important; // override hover and active - color: ${t.checkboxTextColorDisabled}; - `; - }, - - disabled(t: Theme) { - return css` - color: ${t.checkboxTextColorDisabled}; - cursor: default; - `; - }, - - icon() { - return css` - position: absolute; - top: 0; - bottom: 0; - right: 0; - left: 0; - display: flex; - justify-content: center; - align-items: center; - `; - }, - - iconFixPosition() { - return css` - svg { - margin: -12.5% 0 0 0; - } - `; - }, - - iconUnchecked() { - return css` - color: transparent; - `; - }, - - caption(t: Theme) { - return css` - color: ${t.checkboxTextColorDefault}; - padding-left: ${t.checkboxCaptionGap}; - `; - }, - - captionIE11() { - return css` - display: table-cell; - `; - }, -}); + }, + + boxWrapperSmall(t: Theme) { + return emotion.css` + ${boxWrapperSizeMixin(emotion)( + t.labGrotesqueBaselineCompensation, + t.checkboxFontSizeSmall, + t.checkboxBoxSizeSmall, + t.checkboxBoxOffsetY, + )}; + `; + }, + + boxWrapperMedium(t: Theme) { + return emotion.css` + ${boxWrapperSizeMixin(emotion)( + t.labGrotesqueBaselineCompensation, + t.checkboxFontSizeMedium, + t.checkboxBoxSizeMedium, + t.checkboxBoxOffsetY, + )}; + `; + }, + + boxWrapperLarge(t: Theme) { + return emotion.css` + ${boxWrapperSizeMixin(emotion)( + t.labGrotesqueBaselineCompensation, + t.checkboxFontSizeLarge, + t.checkboxBoxSizeLarge, + t.checkboxBoxOffsetY, + )}; + `; + }, + + box(t: Theme) { + return emotion.css` + color: ${t.checkboxTextColorDefault}; + box-shadow: ${t.checkboxShadow}; + background: ${t.checkboxBg}; + border-radius: ${t.checkboxBorderRadius}; + height: 100%; + `; + }, + + input() { + return emotion.css` + display: inline-block; + height: 0; + opacity: 0; + position: absolute; + width: 0; + z-index: -1; + `; + }, + + boxWarning(t: Theme) { + return emotion.css` + box-shadow: inset 0 0 0 1px ${t.checkboxOutlineColorFocus}, + 0 0 0 ${t.checkboxOutlineWidth} ${t.checkboxBorderColorWarning} !important; // override hover and active + `; + }, + + boxError(t: Theme) { + return emotion.css` + box-shadow: inset 0 0 0 1px ${t.checkboxOutlineColorFocus}, + 0 0 0 ${t.checkboxOutlineWidth} ${t.checkboxBorderColorError} !important; // override hover and active + `; + }, + + boxChecked(t: Theme) { + return emotion.css` + background: ${t.checkboxCheckedBg}; + color: ${t.checkboxCheckedColor}; + box-shadow: ${t.checkboxCheckedShadow}; + `; + }, + + boxFocus(t: Theme) { + return emotion.css` + box-shadow: inset 0 0 0 1px ${t.checkboxOutlineColorFocus}, + 0 0 0 ${t.checkboxOutlineWidth} ${t.checkboxBorderColorFocus} !important; // override hover and active + `; + }, + + boxDisabled(t: Theme) { + return emotion.css` + box-shadow: ${t.checkboxShadowDisabled} !important; // override hover and active + background: ${t.checkboxBgDisabled} !important; // override hover and active + color: ${t.checkboxTextColorDisabled}; + `; + }, + + disabled(t: Theme) { + return emotion.css` + color: ${t.checkboxTextColorDisabled}; + cursor: default; + `; + }, + + icon() { + return emotion.css` + position: absolute; + top: 0; + bottom: 0; + right: 0; + left: 0; + display: flex; + justify-content: center; + align-items: center; + `; + }, + + iconFixPosition() { + return emotion.css` + svg { + margin: -12.5% 0 0 0; + } + `; + }, + + iconUnchecked() { + return emotion.css` + color: transparent; + `; + }, + + caption(t: Theme) { + return emotion.css` + color: ${t.checkboxTextColorDefault}; + padding-left: ${t.checkboxCaptionGap}; + `; + }, + + captionIE11() { + return emotion.css` + display: table-cell; + `; + }, + }); diff --git a/packages/react-ui/components/Checkbox/Checkbox.tsx b/packages/react-ui/components/Checkbox/Checkbox.tsx index 85f161efa94..c5101dd6548 100644 --- a/packages/react-ui/components/Checkbox/Checkbox.tsx +++ b/packages/react-ui/components/Checkbox/Checkbox.tsx @@ -3,23 +3,24 @@ import React, { AriaAttributes } from 'react'; import PropTypes from 'prop-types'; import { globalObject } from '@skbkontur/global-object'; +import type { Emotion } from '@emotion/css/create-instance'; import { Override } from '../../typings/utility-types'; import { keyListener } from '../../lib/events/keyListener'; import { Theme } from '../../lib/theming/Theme'; -import { ThemeContext } from '../../lib/theming/ThemeContext'; import { OkIcon, SquareIcon } from '../../internal/icons/16px'; import { isEdge, isIE11 } from '../../lib/client'; -import { CommonWrapper, CommonProps, CommonWrapperRestProps } from '../../internal/CommonWrapper'; -import { cx } from '../../lib/theming/Emotion'; +import { CommonProps, CommonWrapper, CommonWrapperRestProps } from '../../internal/CommonWrapper'; +import { EmotionConsumer } from '../../lib/theming/Emotion'; import { rootNode, TSetRootNode } from '../../lib/rootNode'; import { fixFirefoxModifiedClickOnLabel } from '../../lib/events/fixFirefoxModifiedClickOnLabel'; import { isTheme2022 } from '../../lib/theming/ThemeHelpers'; import { createPropsGetter } from '../../lib/createPropsGetter'; import { SizeProp } from '../../lib/types/props'; import { FocusControlWrapper } from '../../internal/FocusControlWrapper'; +import { ThemeContext } from '../../lib/theming/ThemeContext'; -import { styles, globalClasses } from './Checkbox.styles'; +import { getStyles, globalClasses } from './Checkbox.styles'; import { CheckedIcon } from './CheckedIcon'; import { IndeterminateIcon } from './IndeterminateIcon'; @@ -99,6 +100,7 @@ export class Checkbox extends React.PureComponent private getProps = createPropsGetter(Checkbox.defaultProps); private getRootSizeClassName() { + const styles = getStyles(this.emotion); switch (this.getProps().size) { case 'large': return styles.rootLarge(this.theme); @@ -111,6 +113,7 @@ export class Checkbox extends React.PureComponent } private getBoxWrapperSizeClassName() { + const styles = getStyles(this.emotion); switch (this.getProps().size) { case 'large': return styles.boxWrapperLarge(this.theme); @@ -153,6 +156,7 @@ export class Checkbox extends React.PureComponent }; private theme!: Theme; + private emotion!: Emotion; private input = React.createRef(); private handleShiftPress = (e: KeyboardEvent) => { @@ -195,16 +199,23 @@ export class Checkbox extends React.PureComponent public render() { return ( - - {(theme) => { - this.theme = theme; + + {(emotion) => { + this.emotion = emotion; return ( - - {this.renderMain} - + + {(theme) => { + this.theme = theme; + return ( + + {this.renderMain} + + ); + }} + ); }} - + ); } @@ -269,8 +280,8 @@ export class Checkbox extends React.PureComponent const isIndeterminate = this.state.indeterminate; const _isTheme2022 = isTheme2022(this.theme); - - const iconClass = cx( + const styles = getStyles(this.emotion); + const iconClass = this.emotion.cx( styles.icon(), !_isTheme2022 && styles.iconFixPosition(), !props.checked && !isIndeterminate && styles.iconUnchecked(), @@ -292,7 +303,7 @@ export class Checkbox extends React.PureComponent ); - const rootClass = cx(this.getRootSizeClassName(), { + const rootClass = this.emotion.cx(this.getRootSizeClassName(), { [styles.root(this.theme)]: true, [styles.rootFallback()]: isIE11 || isEdge, [styles.rootChecked(this.theme)]: props.checked || isIndeterminate, @@ -313,7 +324,7 @@ export class Checkbox extends React.PureComponent let caption = null; if (this.props.children) { - const captionClass = cx({ + const captionClass = this.emotion.cx({ [styles.caption(this.theme)]: true, [styles.captionIE11()]: isIE11 || isEdge, [styles.disabled(this.theme)]: Boolean(props.disabled), @@ -323,12 +334,12 @@ export class Checkbox extends React.PureComponent const box = (
- (background || color) && - `& ::selection { +export const getStyles = (emotion: Emotion) => + memoizeStyle({ + root() { + return emotion.css` + cursor: text; + `; + }, + + selected(t: Theme) { + return emotion.css` + & ::selection { + background: ${t.dateInputComponentSelectedBgColor}; + } + & ::-moz-selection { + background: ${t.dateInputComponentSelectedBgColor}; + } + `; + }, + + selectedFor22Themes(t: Theme) { + const getSelection = (background: string, color: string) => + (background || color) && + `& ::selection { background: ${background}; color: ${color}; }`; - return css` - cursor: text; - - ${getSelection(t.dateInputComponentSelectedBgColor, t.dateInputComponentSelectedTextColor)} - `; - }, - - mask(t: Theme) { - return css` - color: ${t.dateInputMaskColor}; - `; - }, - - delimiterFilled() { - return css` - color: inherit; - `; - }, -}); + return emotion.css` + cursor: text; + + ${getSelection(t.dateInputComponentSelectedBgColor, t.dateInputComponentSelectedTextColor)} + `; + }, + + mask(t: Theme) { + return emotion.css` + color: ${t.dateInputMaskColor}; + `; + }, + + delimiterFilled() { + return emotion.css` + color: inherit; + `; + }, + }); diff --git a/packages/react-ui/components/DateInput/DateFragmentsView.tsx b/packages/react-ui/components/DateInput/DateFragmentsView.tsx index 1bcc41bea95..0106364fd36 100644 --- a/packages/react-ui/components/DateInput/DateFragmentsView.tsx +++ b/packages/react-ui/components/DateInput/DateFragmentsView.tsx @@ -1,15 +1,16 @@ import React from 'react'; import { globalObject } from '@skbkontur/global-object'; +import type { Emotion } from '@emotion/css/create-instance'; import { MaskCharLowLine } from '../../internal/MaskCharLowLine'; import { InternalDateValidator } from '../../lib/date/InternalDateValidator'; import { InternalDateComponentType, InternalDateFragment } from '../../lib/date/types'; import { Theme } from '../../lib/theming/Theme'; -import { ThemeContext } from '../../lib/theming/ThemeContext'; -import { cx } from '../../lib/theming/Emotion'; +import { EmotionConsumer } from '../../lib/theming/Emotion'; import { isTheme2022 } from '../../lib/theming/ThemeHelpers'; +import { ThemeContext } from '../../lib/theming/ThemeContext'; -import { styles } from './DateFragmentsView.styles'; +import { getStyles } from './DateFragmentsView.styles'; interface DateFragmentViewProps { selected: InternalDateComponentType | null; @@ -20,6 +21,7 @@ interface DateFragmentViewProps { export class DateFragmentsView extends React.Component { private theme!: Theme; + private emotion!: Emotion; private rootNode: HTMLSpanElement | null = null; public isFragment = (el: HTMLElement | EventTarget): boolean => { @@ -35,22 +37,30 @@ export class DateFragmentsView extends React.Component { public render() { return ( - - {(theme) => { - this.theme = theme; - return this.renderMain(); + + {(emotion) => { + this.emotion = emotion; + return ( + + {(theme) => { + this.theme = theme; + return this.renderMain(); + }} + + ); }} - + ); } private renderMain() { const _isTheme2022 = isTheme2022(this.theme); + const styles = getStyles(this.emotion); return ( { } private renderSeparator(fragment: InternalDateFragment, index: number): JSX.Element { - const separatorClassName = cx({ + const styles = getStyles(this.emotion); + const separatorClassName = this.emotion.cx({ [styles.mask(this.theme)]: true, [styles.delimiterFilled()]: this.props.fragments[index + 1].value !== null, }); @@ -101,6 +112,7 @@ export class DateFragmentsView extends React.Component { onSelectDateComponent(type, e); } }; + const styles = getStyles(this.emotion); return ( diff --git a/packages/react-ui/components/DateInput/DateInput.styles.ts b/packages/react-ui/components/DateInput/DateInput.styles.ts index a350d0544b3..2f07e9d685e 100644 --- a/packages/react-ui/components/DateInput/DateInput.styles.ts +++ b/packages/react-ui/components/DateInput/DateInput.styles.ts @@ -1,48 +1,49 @@ -import { css } from '../../lib/theming/Emotion'; +import type { Emotion } from '@emotion/css/create-instance'; + import { Theme } from '../../lib/theming/Theme'; -export const styles = { +export const getStyles = (emotion: Emotion) => ({ icon(t: Theme) { - return css` + return emotion.css` cursor: pointer; color: ${t.dateInputIconColor}; `; }, iconSmall(t: Theme) { - return css` + return emotion.css` font-size: ${t.inputFontSizeSmall}; `; }, iconMedium(t: Theme) { - return css` + return emotion.css` font-size: ${t.inputFontSizeMedium}; `; }, iconLarge(t: Theme) { - return css` + return emotion.css` font-size: ${t.inputFontSizeLarge}; `; }, iconDisabled(t: Theme) { - return css` + return emotion.css` cursor: default; color: ${t.textColorDisabled}; `; }, value() { - return css` + return emotion.css` visibility: hidden; `; }, valueVisible() { - return css` + return emotion.css` visibility: visible; `; }, -}; +}); diff --git a/packages/react-ui/components/DateInput/DateInput.tsx b/packages/react-ui/components/DateInput/DateInput.tsx index 639ea3e1994..887dc163632 100644 --- a/packages/react-ui/components/DateInput/DateInput.tsx +++ b/packages/react-ui/components/DateInput/DateInput.tsx @@ -1,6 +1,7 @@ import React from 'react'; import ReactDOM from 'react-dom'; import { globalObject } from '@skbkontur/global-object'; +import type { Emotion } from '@emotion/css/create-instance'; import { ConditionalHandler } from '../../lib/ConditionalHandler'; import { LENGTH_FULLDATE, MAX_FULLDATE, MIN_FULLDATE } from '../../lib/date/constants'; @@ -9,19 +10,19 @@ import { Theme } from '../../lib/theming/Theme'; import { DatePickerLocale, DatePickerLocaleHelper } from '../DatePicker/locale'; import { InputLikeText } from '../../internal/InputLikeText'; import { locale } from '../../lib/locale/decorators'; -import { ThemeContext } from '../../lib/theming/ThemeContext'; import { CalendarIcon } from '../../internal/icons/16px'; -import { CommonWrapper, CommonProps } from '../../internal/CommonWrapper'; -import { cx } from '../../lib/theming/Emotion'; +import { CommonProps, CommonWrapper } from '../../internal/CommonWrapper'; import { rootNode, TSetRootNode } from '../../lib/rootNode'; import { createPropsGetter } from '../../lib/createPropsGetter'; import { isTheme2022 } from '../../lib/theming/ThemeHelpers'; import { SizeProp } from '../../lib/types/props'; import { FocusControlWrapper } from '../../internal/FocusControlWrapper'; +import { ThemeContext } from '../../lib/theming/ThemeContext'; +import { EmotionConsumer } from '../../lib/theming/Emotion'; import { CalendarIcon as CalendarIcon2022 } from './CalendarIcon'; import { DateFragmentsView } from './DateFragmentsView'; -import { styles } from './DateInput.styles'; +import { getStyles } from './DateInput.styles'; import { Actions, extractAction } from './helpers/DateInputKeyboardActions'; import { InternalDateMediator } from './helpers/InternalDateMediator'; @@ -109,6 +110,7 @@ export class DateInput extends React.Component { private locale!: DatePickerLocale; private blurEvent: React.FocusEvent | null = null; private theme!: Theme; + private emotion!: Emotion; private setRootNode!: TSetRootNode; private conditionalHandler = new ConditionalHandler]>() .add(Actions.MoveSelectionLeft, () => this.shiftSelection(-1)) @@ -193,12 +195,19 @@ export class DateInput extends React.Component { public render() { return ( - - {(theme) => { - this.theme = theme; - return this.renderMain(); + + {(emotion) => { + this.emotion = emotion; + return ( + + {(theme) => { + this.theme = theme; + return this.renderMain(); + }} + + ); }} - + ); } @@ -206,7 +215,7 @@ export class DateInput extends React.Component { const { focused, selected, inputMode, valueFormatted } = this.state; const showValue = Boolean(focused || valueFormatted); const { width, size } = this.getProps(); - + const styles = getStyles(this.emotion); return ( @@ -231,7 +240,7 @@ export class DateInput extends React.Component { inputMode={'numeric'} takeContentWidth > - + { private renderIcon = () => { const { withIcon, disabled = false } = this.props; const size = this.getProps().size; - + const styles = getStyles(this.emotion); if (withIcon) { const theme = this.theme; const icon = isTheme2022(theme) ? : ; - const iconStyles = cx({ + const iconStyles = this.emotion.cx({ [styles.icon(theme)]: true, [styles.iconSmall(theme)]: size === 'small', [styles.iconMedium(theme)]: size === 'medium', diff --git a/packages/react-ui/components/DatePicker/DatePicker.styles.ts b/packages/react-ui/components/DatePicker/DatePicker.styles.ts index c7fc992e15c..bbcb12b042c 100644 --- a/packages/react-ui/components/DatePicker/DatePicker.styles.ts +++ b/packages/react-ui/components/DatePicker/DatePicker.styles.ts @@ -1,47 +1,50 @@ +import type { Emotion } from '@emotion/css/create-instance'; + import { Theme } from '../../lib/theming/Theme'; -import { css, memoizeStyle } from '../../lib/theming/Emotion'; +import { memoizeStyle } from '../../lib/theming/Emotion'; -export const styles = memoizeStyle({ - root() { - return css` - display: inline-block; - position: relative; - touch-action: none; - line-height: normal; - `; - }, - calendarWrapper(t: Theme) { - return css` - background: ${t.pickerBg}; - box-shadow: ${t.pickerShadow}; - display: inline-block; - font-size: 0; - z-index: 1000; - touch-action: none; - border-radius: ${t.pickerBorderRadius}; - `; - }, - todayLinkWrapper(t: Theme) { - return css` - background-color: ${t.pickerTodayWrapperBgColor}; - border: none; - border-top: ${t.pickerTodayWrapperBorderTop}; - color: ${t.linkColor}; - display: block; - font-size: ${t.pickerTodayWrapperFontSize}; - padding-bottom: ${t.pickerTodayWrapperPaddingBottom}; - padding-top: ${t.pickerTodayWrapperPaddingTop}; - line-height: ${t.pickerTodayWrapperLineHeight}; - width: 100%; +export const getStyles = (emotion: Emotion) => + memoizeStyle({ + root() { + return emotion.css` + display: inline-block; + position: relative; + touch-action: none; + line-height: normal; + `; + }, + calendarWrapper(t: Theme) { + return emotion.css` + background: ${t.pickerBg}; + box-shadow: ${t.pickerShadow}; + display: inline-block; + font-size: 0; + z-index: 1000; + touch-action: none; + border-radius: ${t.pickerBorderRadius}; + `; + }, + todayLinkWrapper(t: Theme) { + return emotion.css` + background-color: ${t.pickerTodayWrapperBgColor}; + border: none; + border-top: ${t.pickerTodayWrapperBorderTop}; + color: ${t.linkColor}; + display: block; + font-size: ${t.pickerTodayWrapperFontSize}; + padding-bottom: ${t.pickerTodayWrapperPaddingBottom}; + padding-top: ${t.pickerTodayWrapperPaddingTop}; + line-height: ${t.pickerTodayWrapperLineHeight}; + width: 100%; - &:hover { - background-color: ${t.pickerTodayWrapperHoverBgColor}; - cursor: pointer; - } + &:hover { + background-color: ${t.pickerTodayWrapperHoverBgColor}; + cursor: pointer; + } - &:active { - color: ${t.linkActiveColor}; - } - `; - }, -}); + &:active { + color: ${t.linkActiveColor}; + } + `; + }, + }); diff --git a/packages/react-ui/components/DatePicker/DatePicker.tsx b/packages/react-ui/components/DatePicker/DatePicker.tsx index b78268186e0..4c62649ddb6 100644 --- a/packages/react-ui/components/DatePicker/DatePicker.tsx +++ b/packages/react-ui/components/DatePicker/DatePicker.tsx @@ -1,12 +1,12 @@ import PropTypes from 'prop-types'; import React from 'react'; +import type { Emotion } from '@emotion/css/create-instance'; import { LocaleContext } from '../../lib/locale'; import { locale } from '../../lib/locale/decorators'; import { InternalDateGetter } from '../../lib/date/InternalDateGetter'; import { ArrowAUpIcon16Light } from '../../internal/icons2022/ArrowAUpIcon/ArrowAUp16Light'; import { isTheme2022 } from '../../lib/theming/ThemeHelpers'; -import { cx } from '../../lib/theming/Emotion'; import { ThemeFactory } from '../../lib/theming/ThemeFactory'; import { InternalDate } from '../../lib/date/InternalDate'; import { MAX_FULLDATE, MIN_FULLDATE } from '../../lib/date/constants'; @@ -15,20 +15,21 @@ import { Nullable } from '../../typings/utility-types'; import { DateInput } from '../DateInput'; import { DropdownContainer, DropdownContainerProps } from '../../internal/DropdownContainer'; import { filterProps } from '../../lib/filterProps'; -import { CommonWrapper, CommonProps, CommonWrapperRestProps } from '../../internal/CommonWrapper'; +import { CommonProps, CommonWrapper, CommonWrapperRestProps } from '../../internal/CommonWrapper'; import { isMobile } from '../../lib/client'; import { NativeDateInput } from '../../internal/NativeDateInput'; import { getRootNode, rootNode, TSetRootNode } from '../../lib/rootNode'; import { isNonNullable } from '../../lib/utils'; import { createPropsGetter } from '../../lib/createPropsGetter'; import { Calendar, CalendarDateShape, CalendarProps } from '../Calendar'; -import { ThemeContext } from '../../lib/theming/ThemeContext'; import { Theme } from '../../lib/theming/Theme'; import { Button } from '../Button'; import { getTodayDate } from '../Calendar/CalendarUtils'; import { SizeProp } from '../../lib/types/props'; +import { ThemeContext } from '../../lib/theming/ThemeContext'; +import { EmotionConsumer } from '../../lib/theming/Emotion'; -import { styles } from './DatePicker.styles'; +import { getStyles } from './DatePicker.styles'; import { DatePickerLocale, DatePickerLocaleHelper } from './locale'; const INPUT_PASS_PROPS = { @@ -163,6 +164,7 @@ export class DatePicker extends React.PureComponent - {(theme) => { - this.theme = theme; - + + {(emotion) => { + this.emotion = emotion; return ( - - - {this.renderMain} - - + + {(theme) => { + this.theme = theme; + + return ( + + + {this.renderMain} + + + ); + }} + ); }} - + ); } @@ -269,6 +278,7 @@ export class DatePicker extends React.PureComponent ); } + const styles = getStyles(this.emotion); return (