diff --git a/src/components/Avatar/Avatar.styles.ts b/src/components/Avatar/Avatar.styles.ts index 97219011..d4b802c8 100644 --- a/src/components/Avatar/Avatar.styles.ts +++ b/src/components/Avatar/Avatar.styles.ts @@ -1,11 +1,18 @@ -import type { AvatarAppearance, AvatarShape } from './types'; +import type { AvatarAppearance, AvatarShape, AvatarSize } from './types'; import type { BaseProps } from '@/types/BaseProps'; import { Emphasis } from '@/types/Emphasis'; import { Size } from '@/types/Size'; export type AvatarConfig = { - shape?: Partial>; + shape?: Partial< + Record< + AvatarShape, + BaseProps & { + size?: Partial>; + } + > + >; size?: Partial>; appearance?: Partial< Record< @@ -31,7 +38,11 @@ export const defaultConfig = { borderRadius: '$border-radius-full', }, square: { - borderRadius: '$border-radius-large', + borderRadius: { + _: '$border-radius-large', + '&[data-size="xSmall"]': '$border-radius-medium', + '&[data-size="2xSmall"]': '$border-radius-medium', + }, }, }, size: { diff --git a/src/components/Avatar/Avatar.tsx b/src/components/Avatar/Avatar.tsx index 8eeabe13..251100ad 100644 --- a/src/components/Avatar/Avatar.tsx +++ b/src/components/Avatar/Avatar.tsx @@ -26,7 +26,14 @@ export const Avatar: FC = ({ ); return ( - + {img ? ( ) : ( diff --git a/src/components/Button/Button.styles.ts b/src/components/Button/Button.styles.ts index ea288cee..9c04ef19 100644 --- a/src/components/Button/Button.styles.ts +++ b/src/components/Button/Button.styles.ts @@ -1,5 +1,9 @@ +import { LoaderProps } from '../Loader'; + import { BaseProps } from '@/types/BaseProps'; +type LoaderAppearance = Pick; + export type DefaultButtonConfig = { appearance?: { primary?: { @@ -39,6 +43,37 @@ export type DefaultButtonConfig = { hasAfterIcon?: BaseProps; } & BaseProps; }; + innerElements?: { + loader?: { + appearance?: { + primary?: + | LoaderAppearance + | { + intent?: { + none?: LoaderAppearance; + success?: LoaderAppearance; + destructive?: LoaderAppearance; + }; + }; + secondary?: + | LoaderAppearance + | { + intent?: { + none?: LoaderAppearance; + success?: LoaderAppearance; + destructive?: LoaderAppearance; + }; + }; + inverted?: + | LoaderAppearance + | { + intent?: { + none?: LoaderAppearance; + }; + }; + }; + }; + }; } & BaseProps; export type GhostButtonConfig = { @@ -83,6 +118,42 @@ export type GhostButtonConfig = { hasAfterIcon?: BaseProps; } & BaseProps; }; + innerElements?: { + loader?: { + appearance?: { + primary?: + | LoaderAppearance + | { + intent?: { + none?: LoaderAppearance; + success?: LoaderAppearance; + destructive?: LoaderAppearance; + }; + }; + secondary?: + | LoaderAppearance + | { + intent?: { + none?: LoaderAppearance; + }; + }; + inverted?: + | LoaderAppearance + | { + intent?: { + none?: LoaderAppearance; + }; + }; + reverseInverted?: + | LoaderAppearance + | { + intent?: { + none?: LoaderAppearance; + }; + }; + }; + }; + }; } & BaseProps; export type BareButtonConfig = { @@ -122,6 +193,42 @@ export type BareButtonConfig = { hasAfterIcon?: BaseProps; } & BaseProps; }; + innerElements?: { + loader?: { + appearance?: { + primary?: + | LoaderAppearance + | { + intent?: { + none?: LoaderAppearance; + success?: LoaderAppearance; + destructive?: LoaderAppearance; + }; + }; + secondary?: + | LoaderAppearance + | { + intent?: { + none?: LoaderAppearance; + }; + }; + inverted?: + | LoaderAppearance + | { + intent?: { + none?: LoaderAppearance; + }; + }; + reverseInverted?: + | LoaderAppearance + | { + intent?: { + none?: LoaderAppearance; + }; + }; + }; + }; + }; } & BaseProps; const size = { @@ -178,7 +285,8 @@ const size = { const commonConfig = { display: 'inline-flex', - gap: '$space-component-gap-xSmall', + borderRadius: '$border-radius-large', + gap: '$space-component-gap-small', w: 'fit-content', justifyContent: 'center', alignItems: 'center', @@ -207,7 +315,6 @@ const commonConfig = { const defaultButtonConfig = { ...commonConfig, - borderRadius: '$border-radius-medium', boxShadow: '$elevation-bottom-100', appearance: { primary: { @@ -300,11 +407,25 @@ const defaultButtonConfig = { }, }, size, + innerElements: { + loader: { + appearance: { + primary: { + appearance: 'white', + }, + secondary: { + appearance: 'greyscale', + }, + inverted: { + appearance: 'greyscale', + }, + }, + }, + }, } satisfies DefaultButtonConfig; const ghostButtonConfig = { ...commonConfig, - borderRadius: '$border-radius-large', backgroundColor: { _: 'transparent', hover: '$color-action-ghost-hover', @@ -384,6 +505,26 @@ const ghostButtonConfig = { }, }, size, + innerElements: { + loader: { + appearance: { + primary: { + appearance: 'greyscale', + intent: { + none: { + appearance: 'primary', + }, + }, + }, + secondary: { + appearance: 'greyscale', + }, + inverted: { + appearance: 'greyscale', + }, + }, + }, + }, } satisfies GhostButtonConfig; const bareButtonConfig = { @@ -473,6 +614,26 @@ const bareButtonConfig = { hasAfterIcon: {}, }, }, + innerElements: { + loader: { + appearance: { + primary: { + appearance: 'greyscale', + intent: { + none: { + appearance: 'primary', + }, + }, + }, + secondary: { + appearance: 'greyscale', + }, + inverted: { + appearance: 'greyscale', + }, + }, + }, + }, } satisfies BareButtonConfig; export type ButtonConfig = { diff --git a/src/components/Button/Button.tsx b/src/components/Button/Button.tsx index b6abe707..626ab9fb 100644 --- a/src/components/Button/Button.tsx +++ b/src/components/Button/Button.tsx @@ -57,13 +57,13 @@ export const Button: FC = ({ {state === 'loading' && ( - + )} {beforeIcon && state !== 'loading' && } {children} diff --git a/src/components/Button/stylesBuilder/stylesBuilder.test.ts b/src/components/Button/stylesBuilder/stylesBuilder.test.ts index bbfdc889..1c358923 100644 --- a/src/components/Button/stylesBuilder/stylesBuilder.test.ts +++ b/src/components/Button/stylesBuilder/stylesBuilder.test.ts @@ -23,11 +23,11 @@ describe('stylesBuilder', () => { loading: '$color-action-primary-loading', selected: '$color-action-primary-selected', }, - borderRadius: '$border-radius-medium', + borderRadius: '$border-radius-large', boxShadow: '$elevation-bottom-100', color: '$color-action-inverted-normal', display: 'inline-flex', - gap: '$space-component-gap-xSmall', + gap: '$space-component-gap-small', justifyContent: 'center', opacity: { disabled: '$opacity-disabled', @@ -56,6 +56,9 @@ describe('stylesBuilder', () => { w: 'fit-content', whiteSpace: 'nowrap', }, + loader: { + appearance: 'white', + }, }); }); }); diff --git a/src/components/Button/stylesBuilder/stylesBuilder.ts b/src/components/Button/stylesBuilder/stylesBuilder.ts index c0bda5e3..934aa644 100644 --- a/src/components/Button/stylesBuilder/stylesBuilder.ts +++ b/src/components/Button/stylesBuilder/stylesBuilder.ts @@ -1,3 +1,4 @@ +import { LoaderProps } from '../../Loader'; import { ButtonProps } from '../Button.props'; import { defaultConfig } from '../Button.styles'; @@ -17,6 +18,32 @@ type ButtonStylesBulderInput = { type ButtonStylesBuilder = { container: BaseProps; + loader: Pick; +}; + +const getLoaderProps = ( + loader: object, + props: Pick, +) => { + let loaderProps: Pick = {}; + + if (!('appearance' in loader)) return loader; + + const loaderAppearance = + loader?.appearance?.[props.appearance as keyof typeof loader.appearance]; + + if (loaderAppearance) { + if ('intent' in loaderAppearance) { + const { intent: loaderIntent } = loaderAppearance; + + loaderProps = + loaderIntent?.[props.intent as keyof typeof loaderIntent] || {}; + } else { + loaderProps = loaderAppearance; + } + } + + return loaderProps; }; export const stylesBuilder = ( @@ -26,7 +53,13 @@ export const stylesBuilder = ( defaultConfig, custom: props.custom, }); - const { appearance, size, ...container } = variants[props.variant]; + + const { + appearance, + size, + innerElements: { loader }, + ...container + } = variants[props.variant]; const { hasDropdownIndicator, hasBeforeIcon, hasAfterIcon, ...sizeStyles } = fallbackKey( @@ -68,5 +101,9 @@ export const stylesBuilder = ( ...appearanceStyles, ...intentStyles, }, + loader: getLoaderProps(loader, { + appearance: props.appearance, + intent: props.intent, + }), }; }; diff --git a/src/components/Checkbox/Checkbox.styles.ts b/src/components/Checkbox/Checkbox.styles.ts index b874de84..931f6b9d 100644 --- a/src/components/Checkbox/Checkbox.styles.ts +++ b/src/components/Checkbox/Checkbox.styles.ts @@ -63,6 +63,7 @@ export const defaultConfig = { alert: { _: '$color-interaction-border-alert', hover: '$color-interaction-border-alert', + checked: '$color-interaction-ghost-normal', }, indeterminate: 'transparent', }, diff --git a/src/components/InlineBanner/InlineBanner.styles.ts b/src/components/InlineBanner/InlineBanner.styles.ts index a764502b..d40b135b 100644 --- a/src/components/InlineBanner/InlineBanner.styles.ts +++ b/src/components/InlineBanner/InlineBanner.styles.ts @@ -18,11 +18,12 @@ export type InlineBannerConfig = { closeButton?: BaseProps; }; spacing?: { - closeButton?: BaseProps; + container?: BaseProps; }; } & BaseProps; export const defaultConfig = { + position: 'relative', display: 'flex', p: '$space-component-padding-xLarge', gap: '$space-component-gap-large', @@ -53,7 +54,7 @@ export const defaultConfig = { }, innerElements: { iconContainer: { - h: 'xSmall', + h: '$size-xSmall', display: 'flex', alignItems: 'center', intent: { @@ -110,12 +111,14 @@ export const defaultConfig = { }, }, closeButton: { - ml: 'auto', + position: 'absolute', + top: '$space-component-padding-large', + right: '$space-component-padding-large', }, }, spacing: { - closeButton: { - pr: '$space-component-padding-large', + container: { + pr: '$space-component-padding-6xLarge', }, }, } satisfies InlineBannerConfig; diff --git a/src/components/InlineBanner/stylesBuilder/stylesBuilder.ts b/src/components/InlineBanner/stylesBuilder/stylesBuilder.ts index 747fedd0..d7d9484a 100644 --- a/src/components/InlineBanner/stylesBuilder/stylesBuilder.ts +++ b/src/components/InlineBanner/stylesBuilder/stylesBuilder.ts @@ -57,7 +57,7 @@ export const stylesBuilder = ({ container: { ...restProps, ...intentStyles[intent], - ...(hasCloseButton && spacing.closeButton), + ...(hasCloseButton && spacing.container), }, iconContainer: iconContainerStyles, contentContainer, diff --git a/src/components/InlineSearchInput/InlineSearchInput.styles.ts b/src/components/InlineSearchInput/InlineSearchInput.styles.ts index cec3a197..1bc194b6 100644 --- a/src/components/InlineSearchInput/InlineSearchInput.styles.ts +++ b/src/components/InlineSearchInput/InlineSearchInput.styles.ts @@ -1,11 +1,16 @@ import { SearchInputProps } from '../SearchInput'; export const defaultConfig: SearchInputProps['custom'] = { + position: 'relative', display: 'inline-flex', + w: 'auto', h: '$size-small', padding: '$space-component-padding-xSmall $space-component-padding-small', backgroundColor: { - hover: '$color-interaction-ghost-hover', + hover: { + _: '$color-interaction-ghost-hover', + focusWithin: '$color-interaction-background-formField', + }, }, ring: { _: 'unset', @@ -18,10 +23,15 @@ export const defaultConfig: SearchInputProps['custom'] = { w: 'unset', h: 'unset', minWidth: '50px', - backgroundColor: 'unset', - padding: 'unset', + backgroundColor: 'transparent', + padding: 0, + paddingRight: '36px', display: 'inline-block', }, + clearButton: { + position: 'absolute', + right: '$space-component-padding-small', + }, beforeComponent: { spacing: { Icon: { diff --git a/src/components/Popover/Popover.stories.tsx b/src/components/Popover/Popover.stories.tsx index c6e499ad..7c4bdad9 100644 --- a/src/components/Popover/Popover.stories.tsx +++ b/src/components/Popover/Popover.stories.tsx @@ -15,7 +15,7 @@ const meta = { tags: ['autodocs'], args: { content: ( - + ), diff --git a/src/components/Popover/Popover.styles.ts b/src/components/Popover/Popover.styles.ts index 3e82b502..ad0894b6 100644 --- a/src/components/Popover/Popover.styles.ts +++ b/src/components/Popover/Popover.styles.ts @@ -18,15 +18,15 @@ export const defaultConfig = { top: { align: { start: { - transform: 'translate(0%, -100%)', + transform: 'translate(0%, -100%) translateZ(0)', left: '50%', }, center: { - transform: 'translate(-50%, -100%)', + transform: 'translate(-50%, -100%) translateZ(0)', left: '50%', }, end: { - transform: 'translate(-100%, -100%)', + transform: 'translate(-100%, -100%) translateZ(0)', left: '50%', }, }, @@ -34,15 +34,15 @@ export const defaultConfig = { bottom: { align: { start: { - transform: 'translate(0%, 100%)', + transform: 'translate(0%, 100%) translateZ(0)', left: '50%', }, center: { - transform: 'translate(-50%, 100%)', + transform: 'translate(-50%, 100%) translateZ(0)', left: '50%', }, end: { - transform: 'translate(-100%, 100%)', + transform: 'translate(-100%, 100%) translateZ(0)', left: '50%', }, }, @@ -50,15 +50,15 @@ export const defaultConfig = { left: { align: { start: { - transform: 'translate(-100%, 0%)', + transform: 'translate(-100%, 0%) translateZ(0)', top: '50%', }, center: { - transform: 'translate(-100%, -50%)', + transform: 'translate(-100%, -50%) translateZ(0)', top: '50%', }, end: { - transform: 'translate(-100%, -100%)', + transform: 'translate(-100%, -100%) translateZ(0)', top: '50%', }, }, @@ -66,15 +66,15 @@ export const defaultConfig = { right: { align: { start: { - transform: 'translate(100%, 0%)', + transform: 'translate(100%, 0%) translateZ(0)', top: '50%', }, center: { - transform: 'translate(100%, -50%)', + transform: 'translate(100%, -50%) translateZ(0)', top: '50%', }, end: { - transform: 'translate(100%, -100%)', + transform: 'translate(100%, -100%) translateZ(0)', top: '50%', }, }, diff --git a/src/components/Popover/Popover.test.tsx b/src/components/Popover/Popover.test.tsx index 4e3cc7c1..0e720bd1 100644 --- a/src/components/Popover/Popover.test.tsx +++ b/src/components/Popover/Popover.test.tsx @@ -33,78 +33,94 @@ describe('Popover', () => { it('should render content on the top centered', () => { const { content } = getPopover(); - expect(content).toHaveStyle('transform: translate(-50%,-100%)'); + expect(content).toHaveStyle( + 'transform: translate(-50%,-100%) translateZ(0)', + ); }); it('should render content on the top start', () => { const { content } = getPopover(); - expect(content).toHaveStyle('transform: translate(0%,-100%)'); + expect(content).toHaveStyle('transform: translate(0%,-100%) translateZ(0)'); }); it('should render content on the top end', () => { const { content } = getPopover(); - expect(content).toHaveStyle('transform: translate(-100%,-100%)'); + expect(content).toHaveStyle( + 'transform: translate(-100%,-100%) translateZ(0)', + ); }); it('should render content on the bottom centered', () => { const { content } = getPopover( , ); - expect(content).toHaveStyle('transform: translate(-50%,100%)'); + expect(content).toHaveStyle( + 'transform: translate(-50%,100%) translateZ(0)', + ); }); it('should render content on the bottom start', () => { const { content } = getPopover( , ); - expect(content).toHaveStyle('transform: translate(0%,100%)'); + expect(content).toHaveStyle('transform: translate(0%,100%) translateZ(0)'); }); it('should render content on the bottom end', () => { const { content } = getPopover( , ); - expect(content).toHaveStyle('transform: translate(-100%,100%)'); + expect(content).toHaveStyle( + 'transform: translate(-100%,100%) translateZ(0)', + ); }); it('should render content on the left centered', () => { const { content } = getPopover(); - expect(content).toHaveStyle('transform: translate(-100%,-50%)'); + expect(content).toHaveStyle( + 'transform: translate(-100%,-50%) translateZ(0)', + ); }); it('should render content on the left start', () => { const { content } = getPopover( , ); - expect(content).toHaveStyle('transform: translate(-100%,0%)'); + expect(content).toHaveStyle('transform: translate(-100%,0%) translateZ(0)'); }); it('should render content on the left end', () => { const { content } = getPopover( , ); - expect(content).toHaveStyle('transform: translate(-100%,-100%)'); + expect(content).toHaveStyle( + 'transform: translate(-100%,-100%) translateZ(0)', + ); }); it('should render content on the right centered', () => { const { content } = getPopover( , ); - expect(content).toHaveStyle('transform: translate(100%,-50%)'); + expect(content).toHaveStyle( + 'transform: translate(100%,-50%) translateZ(0)', + ); }); it('should render content on the right start', () => { const { content } = getPopover( , ); - expect(content).toHaveStyle('transform: translate(100%,0%)'); + expect(content).toHaveStyle('transform: translate(100%,0%) translateZ(0)'); }); it('should render content on the right end', () => { const { content } = getPopover( , ); - expect(content).toHaveStyle('transform: translate(100%,-100%)'); + expect(content).toHaveStyle( + 'transform: translate(100%,-100%) translateZ(0)', + ); }); it('should render correct offset (top)', () => { diff --git a/src/components/RadioButton/RadioButton.styles.ts b/src/components/RadioButton/RadioButton.styles.ts index f1742700..577dfd29 100644 --- a/src/components/RadioButton/RadioButton.styles.ts +++ b/src/components/RadioButton/RadioButton.styles.ts @@ -52,6 +52,7 @@ export const defaultConfig = { alert: { _: '$color-interaction-border-alert', hover: '$color-interaction-border-alert', + checked: '$color-interaction-default-normal', }, }, outlineStyle: { diff --git a/src/components/SearchInput/SearchInput.stories.tsx b/src/components/SearchInput/SearchInput.stories.tsx index 9912a33b..6349023f 100644 --- a/src/components/SearchInput/SearchInput.stories.tsx +++ b/src/components/SearchInput/SearchInput.stories.tsx @@ -60,7 +60,7 @@ export const Dropdown: Story = { }, }; -export const Icon: Story = { +export const IconButton: Story = { args: { afterComponent: { type: 'IconButton', diff --git a/src/components/Select/Select.styles.ts b/src/components/Select/Select.styles.ts new file mode 100644 index 00000000..89ba8cc3 --- /dev/null +++ b/src/components/Select/Select.styles.ts @@ -0,0 +1,13 @@ +import type { TextInputProps } from '../TextInput'; + +export const defaultConfig: TextInputProps['custom'] = { + innerElements: { + afterComponent: { + spacing: { + IconButton: { + marginRight: '$space-component-padding-medium', + }, + }, + }, + }, +}; diff --git a/src/components/Select/Select.tsx b/src/components/Select/Select.tsx index 0870600e..4a9a73b5 100644 --- a/src/components/Select/Select.tsx +++ b/src/components/Select/Select.tsx @@ -2,11 +2,13 @@ import { Icon } from '@virtuslab/tetrisly-icons'; import type { FC } from 'react'; import type { SelectProps } from './Select.props'; +import { defaultConfig } from './Select.styles'; import { Avatar } from '../Avatar'; import { IconButton } from '../IconButton'; import type { TextInputProps } from '../TextInput'; import { useTextInput } from '../TextInput/useTextInput'; +import { mergeConfigWithCustom } from '@/services/mergeConfigWithCustom/mergeConfigWithCutom'; import { tet } from '@/tetrisly'; import type { MarginProps } from '@/types'; @@ -22,9 +24,13 @@ export const Select: FC = ({ beforeComponent, hasClearButton, value, + custom: customProps, ...props }) => { const afterComponent = DROPDOWN_INDICATOR_COMPONENT; + + const custom = mergeConfigWithCustom({ defaultConfig, custom: customProps }); + const { containerRef, handleContainerClick, @@ -37,8 +43,10 @@ export const Select: FC = ({ } = useTextInput({ beforeComponent, afterComponent, + custom, ...props, }); + return ( = ({ > - >; + emphasis: Partial>; + intent: Partial>; } & BaseProps; closeButton?: BaseProps; }; @@ -136,6 +134,15 @@ export const defaultConfig = { color: '$color-content-tertiary', }, }, + intent: { + neutral: {}, + informative: {}, + success: {}, + warning: { + color: '$color-content-secondary', + }, + negative: {}, + }, }, closeButton: { ml: '$space-component-padding-large', diff --git a/src/components/Toast/Toast.tsx b/src/components/Toast/Toast.tsx index 41c344dd..09129d89 100644 --- a/src/components/Toast/Toast.tsx +++ b/src/components/Toast/Toast.tsx @@ -57,9 +57,9 @@ export const Toast: FC = ({