From e3a8dcc8dc8283b94a8d9e9adefb60442951916e Mon Sep 17 00:00:00 2001 From: kuzhelov Date: Tue, 5 Feb 2019 20:01:55 +0100 Subject: [PATCH] fix font icon sizes for avatar's image slot --- ...tarExampleImageCustomization.shorthand.tsx | 2 +- .../react/src/components/Avatar/Avatar.tsx | 9 +++++ packages/react/src/lib/callable.ts | 8 +++-- .../react/src/lib/createAnimationStyles.tsx | 4 +-- packages/react/src/lib/getClasses.ts | 5 ++- packages/react/src/lib/renderComponent.tsx | 4 +-- .../teams-high-contrast/componentVariables.ts | 1 + .../components/Icon/iconVariables.ts | 6 ++++ .../teams/components/Avatar/avatarStyles.ts | 4 +-- .../teams/components/Icon/avatarIconStyles.ts | 34 +++++++++++++++++++ .../teams/components/Icon/iconStyles.ts | 9 +++-- .../teams/components/Icon/iconVariables.ts | 8 ++++- packages/react/src/types.ts | 1 + 13 files changed, 82 insertions(+), 13 deletions(-) create mode 100644 packages/react/src/themes/teams-high-contrast/components/Icon/iconVariables.ts create mode 100644 packages/react/src/themes/teams/components/Icon/avatarIconStyles.ts diff --git a/docs/src/examples/components/Avatar/Variations/AvatarExampleImageCustomization.shorthand.tsx b/docs/src/examples/components/Avatar/Variations/AvatarExampleImageCustomization.shorthand.tsx index fce4870516..d268761d30 100644 --- a/docs/src/examples/components/Avatar/Variations/AvatarExampleImageCustomization.shorthand.tsx +++ b/docs/src/examples/components/Avatar/Variations/AvatarExampleImageCustomization.shorthand.tsx @@ -12,7 +12,7 @@ const AvatarExampleImageCustomizationShorthand = () => ( image={ // This example does not react to the avatar size variable // and otherwise produces bad results when border is applied compared to "normal" image - + } status={{ color: 'green', icon: 'check', title: 'Available' }} /> diff --git a/packages/react/src/components/Avatar/Avatar.tsx b/packages/react/src/components/Avatar/Avatar.tsx index c1d192fd87..e4e346a9d6 100644 --- a/packages/react/src/components/Avatar/Avatar.tsx +++ b/packages/react/src/components/Avatar/Avatar.tsx @@ -13,6 +13,10 @@ import { SizeValue, } from '../../lib' +export type AvatarSlotClassNames = { + image: string +} + export interface AvatarProps extends UIComponentProps { /** Shorthand for the image. */ image?: ShorthandValue @@ -43,6 +47,10 @@ class Avatar extends UIComponent, any> { static displayName = 'Avatar' + static slotClassNames = { + image: `${Avatar.className}__image`, + } + static propTypes = { ...commonPropTypes.createCommon({ children: false, @@ -92,6 +100,7 @@ class Avatar extends UIComponent, any> { avatar: true, title: name, styles: styles.image, + className: Avatar.slotClassNames.image, }, })} {!image && diff --git a/packages/react/src/lib/callable.ts b/packages/react/src/lib/callable.ts index 6e30c3179a..77fbc0a62a 100644 --- a/packages/react/src/lib/callable.ts +++ b/packages/react/src/lib/callable.ts @@ -1,6 +1,10 @@ +import { Func } from '../types' + // https://jsperf.com/startdust-callable -const callable = (possibleFunction: any) => (...args: any[]) => { - return typeof possibleFunction === 'function' ? possibleFunction(...args) : possibleFunction +const callable = (possibleFunction: T | Func) => (...args: any[]) => { + return typeof possibleFunction === 'function' + ? (possibleFunction as Func)(...args) + : possibleFunction } export default callable diff --git a/packages/react/src/lib/createAnimationStyles.tsx b/packages/react/src/lib/createAnimationStyles.tsx index 28da7ee6b4..ebfa156676 100644 --- a/packages/react/src/lib/createAnimationStyles.tsx +++ b/packages/react/src/lib/createAnimationStyles.tsx @@ -1,7 +1,7 @@ -import { ThemePrepared, AnimationProp } from '../themes/types' +import { AnimationProp, ICSSInJSStyle, ThemePrepared } from '../themes/types' import callable from './callable' -const createAnimationStyles = (animation: AnimationProp, theme: ThemePrepared) => { +const createAnimationStyles = (animation: AnimationProp, theme: ThemePrepared): ICSSInJSStyle => { let animationCSSProp = {} const { animations = {} } = theme diff --git a/packages/react/src/lib/getClasses.ts b/packages/react/src/lib/getClasses.ts index 894a65af05..9b1d19d870 100644 --- a/packages/react/src/lib/getClasses.ts +++ b/packages/react/src/lib/getClasses.ts @@ -19,7 +19,10 @@ const getClasses = ( const componentParts: string[] = Object.keys(componentStyles) return componentParts.reduce((classes, partName) => { - classes[partName] = renderer.renderRule(callable(componentStyles[partName]), styleParam) + // The reason for explicit cast is that Fela and Stardust use different interfaces for CSS styles + // - Fela: interface IStyle extends CSS.Properties + // - Stardust: interface ICSSInJSStyle extends React.CSSProperties + classes[partName] = renderer.renderRule(callable(componentStyles[partName]), styleParam) return classes }, {}) diff --git a/packages/react/src/lib/renderComponent.tsx b/packages/react/src/lib/renderComponent.tsx index de0e2d6f50..73f0216caa 100644 --- a/packages/react/src/lib/renderComponent.tsx +++ b/packages/react/src/lib/renderComponent.tsx @@ -211,10 +211,10 @@ const renderComponent =

(config: RenderConfig

): React.ReactElem colors, } - mergedStyles.root = { + mergedStyles.root = callable({ ...callable(mergedStyles.root)(styleParam), ...animationCSSProp, - } + }) const resolvedStyles: ComponentSlotStylesPrepared = Object.keys(mergedStyles).reduce( (acc, next) => ({ ...acc, [next]: callable(mergedStyles[next])(styleParam) }), diff --git a/packages/react/src/themes/teams-high-contrast/componentVariables.ts b/packages/react/src/themes/teams-high-contrast/componentVariables.ts index 5fe7ad8df0..ed9df02df4 100644 --- a/packages/react/src/themes/teams-high-contrast/componentVariables.ts +++ b/packages/react/src/themes/teams-high-contrast/componentVariables.ts @@ -4,6 +4,7 @@ export { default as Chat } from './components/Chat/chatVariables' export { default as ChatMessage } from './components/Chat/chatMessageVariables' export { default as Divider } from './components/Divider/dividerVariables' export { default as Header } from './components/Header/headerVariables' +export { default as Icon } from './components/Icon/iconVariables' export { default as Input } from './components/Input/inputVariables' export { default as Menu } from './components/Menu/menuVariables' export { default as Text } from './components/Text/textVariables' diff --git a/packages/react/src/themes/teams-high-contrast/components/Icon/iconVariables.ts b/packages/react/src/themes/teams-high-contrast/components/Icon/iconVariables.ts new file mode 100644 index 0000000000..c6483d4db9 --- /dev/null +++ b/packages/react/src/themes/teams-high-contrast/components/Icon/iconVariables.ts @@ -0,0 +1,6 @@ +import avatarVariables from '../Avatar/avatarVariables' +import { callable } from '../../../../lib' + +export default siteVars => ({ + avatarBorderWidth: callable(avatarVariables)(siteVars).avatarBorderWidth, +}) diff --git a/packages/react/src/themes/teams/components/Avatar/avatarStyles.ts b/packages/react/src/themes/teams/components/Avatar/avatarStyles.ts index 043fe3cb14..e5f27a2b39 100644 --- a/packages/react/src/themes/teams/components/Avatar/avatarStyles.ts +++ b/packages/react/src/themes/teams/components/Avatar/avatarStyles.ts @@ -1,8 +1,8 @@ import { pxToRem } from '../../../../lib' import { ComponentSlotStylesInput, ICSSInJSStyle } from '../../../types' -import { AvatarProps } from '../../../../components/Avatar/Avatar' +import { AvatarProps } from '../../../..' -const sizeToPxValue = { +export const sizeToPxValue = { smallest: 24, smaller: 24, small: 24, diff --git a/packages/react/src/themes/teams/components/Icon/avatarIconStyles.ts b/packages/react/src/themes/teams/components/Icon/avatarIconStyles.ts new file mode 100644 index 0000000000..a251dfe168 --- /dev/null +++ b/packages/react/src/themes/teams/components/Icon/avatarIconStyles.ts @@ -0,0 +1,34 @@ +import * as _ from 'lodash' + +import { pxToRem, SizeValue } from '../../../../lib' +import { IconVariables } from './iconVariables' + +import { sizeToPxValue as avatarSizeToPxValue } from '../Avatar/avatarStyles' + +const sizeToIconPaddingInPx: Record = { + smallest: 4, + smaller: 4, + small: 4, + medium: 6, + large: 8, + larger: 8, + largest: 10, +} + +export const getAvatarFontIconStyles = (size: SizeValue, v: IconVariables) => { + const slotSizeInPx = avatarSizeToPxValue[size] + const iconBorderWidthInPx = v.avatarBorderWidth || 0 + const iconPaddingSizeInPx = sizeToIconPaddingInPx[size] + + const iconSizeInRems = pxToRem(slotSizeInPx - 2 * iconPaddingSizeInPx - 2 * iconBorderWidthInPx) + + return { + fontSize: iconSizeInRems, + padding: pxToRem(iconPaddingSizeInPx), + + '::before': { + width: iconSizeInRems, + height: iconSizeInRems, + }, + } +} diff --git a/packages/react/src/themes/teams/components/Icon/iconStyles.ts b/packages/react/src/themes/teams/components/Icon/iconStyles.ts index 2dac6bdb2c..55ce03f295 100644 --- a/packages/react/src/themes/teams/components/Icon/iconStyles.ts +++ b/packages/react/src/themes/teams/components/Icon/iconStyles.ts @@ -4,9 +4,10 @@ import fontAwesomeIcons from './fontAwesomeIconStyles' import { callable, pxToRem, SizeValue } from '../../../../lib' import { ComponentSlotStylesInput, ICSSInJSStyle, FontIconSpec } from '../../../types' import { ResultOf } from '../../../../types' -import { IconXSpacing, IconProps } from '../../../../components/Icon/Icon' +import { Avatar, IconXSpacing, IconProps } from '../../../../' import { getStyle as getSvgStyle } from './svg' import { IconVariables, IconSizeModifier } from './iconVariables' +import { getAvatarFontIconStyles } from './avatarIconStyles' const sizes: Record = { smallest: 7, @@ -19,7 +20,7 @@ const sizes: Record = { } const getDefaultFontIcon = (iconName: string) => { - return callable(fontAwesomeIcons(iconName).icon)() + return callable(fontAwesomeIcons(iconName).icon as FontIconSpec)() } const getFontStyles = ( @@ -124,6 +125,10 @@ const iconStyles: ComponentSlotStylesInput = { ...(!rtl && { transform: `rotate(${rotate}deg)`, }), + + [`&.${Avatar.slotClassNames.image}`]: { + ...(isFontBased && getAvatarFontIconStyles(size, v)), + }, } }, diff --git a/packages/react/src/themes/teams/components/Icon/iconVariables.ts b/packages/react/src/themes/teams/components/Icon/iconVariables.ts index 139b735395..f53f950dc9 100644 --- a/packages/react/src/themes/teams/components/Icon/iconVariables.ts +++ b/packages/react/src/themes/teams/components/Icon/iconVariables.ts @@ -1,5 +1,7 @@ import { ColorValues } from '../../../types' -import { mapColorsToScheme, pxToRem } from '../../../../lib' +import { callable, mapColorsToScheme, pxToRem } from '../../../../lib' + +import avatarVariables from '../Avatar/avatarVariables' export type IconSizeModifier = 'x' | 'xx' @@ -19,6 +21,8 @@ export interface IconVariables { marginRight: string outline?: boolean sizeModifier?: IconSizeModifier + + avatarBorderWidth?: number } const colorVariant = 500 @@ -36,4 +40,6 @@ export default (siteVars): IconVariables => ({ horizontalSpace: pxToRem(10), marginRight: pxToRem(8), outline: undefined, + + avatarBorderWidth: callable(avatarVariables)(siteVars).avatarBorderWidth, }) diff --git a/packages/react/src/types.ts b/packages/react/src/types.ts index 27dd0e3f3b..e76be95bd5 100644 --- a/packages/react/src/types.ts +++ b/packages/react/src/types.ts @@ -17,6 +17,7 @@ export type ResultOf = T extends (...arg: any[]) => infer TResult ? TResult : export type OneOrArray = T | T[] export type ObjectOf = { [key: string]: T } +export type Func = (...args: any[]) => TResult export type ObjectOrFunc = ((arg: TArg) => TResult) | TResult // ========================================================