From 87b6601f51eac65d02ff011f4ba5d5f0d6a4b020 Mon Sep 17 00:00:00 2001 From: Daria Alekhina Date: Wed, 29 May 2024 17:10:29 +0300 Subject: [PATCH 1/3] feat(StoreBadge): add new component --- .../components/StoreBadge/StoreBadge.api.mdx | 37 ++++++ .../StoreBadge/StoreBadge.classes.ts | 46 ++++++++ .../StoreBadge/StoreBadge.stories.tsx | 26 +++++ .../src/components/StoreBadge/StoreBadge.tsx | 109 ++++++++++++++++++ .../components/StoreBadge/StoreBadge.types.ts | 34 ++++++ .../react/src/components/StoreBadge/index.ts | 3 + packages/react/src/icons/IconAppStore.tsx | 45 ++++++++ packages/react/src/icons/IconAppStoreLogo.tsx | 12 ++ packages/react/src/icons/index.ts | 2 + 9 files changed, 314 insertions(+) create mode 100644 packages/react/src/components/StoreBadge/StoreBadge.api.mdx create mode 100644 packages/react/src/components/StoreBadge/StoreBadge.classes.ts create mode 100644 packages/react/src/components/StoreBadge/StoreBadge.stories.tsx create mode 100644 packages/react/src/components/StoreBadge/StoreBadge.tsx create mode 100644 packages/react/src/components/StoreBadge/StoreBadge.types.ts create mode 100644 packages/react/src/components/StoreBadge/index.ts create mode 100644 packages/react/src/icons/IconAppStore.tsx create mode 100644 packages/react/src/icons/IconAppStoreLogo.tsx diff --git a/packages/react/src/components/StoreBadge/StoreBadge.api.mdx b/packages/react/src/components/StoreBadge/StoreBadge.api.mdx new file mode 100644 index 000000000..db8204352 --- /dev/null +++ b/packages/react/src/components/StoreBadge/StoreBadge.api.mdx @@ -0,0 +1,37 @@ +import { Meta } from '@storybook/blocks'; +import LinkTo from '@storybook/addon-links/react'; +import { TableInterface } from '~storybook/components/TableInterface'; + + + +# Dropzone API + +```js +import { StoreBadge } from '@elonkit/react'; +``` + +## Component name + +The name `ESStoreBadge` can be used when providing default props or style overrides in the theme. + +## Props + + + +
+ +## CSS + + + +
+ +## Demos + +
    +
  • + + StoreBadge + +
  • +
diff --git a/packages/react/src/components/StoreBadge/StoreBadge.classes.ts b/packages/react/src/components/StoreBadge/StoreBadge.classes.ts new file mode 100644 index 000000000..160f83867 --- /dev/null +++ b/packages/react/src/components/StoreBadge/StoreBadge.classes.ts @@ -0,0 +1,46 @@ +import { generateUtilityClass, generateUtilityClasses } from '@mui/material'; + +export type StoreBadgeClasses = { + /** Styles applied to the root element. */ + root: string; + /** Styles applied to the root element if component checked. */ + checked: string; + /** Styles applied to the root element if component disabled. */ + disabled: string; + /** Styles applied to the root element if size='large'. */ + large: string; + /** Styles applied to the root element if size='medium'. */ + medium: string; + /** Styles applied to the root element if size='small'. */ + small: string; + /** Styles applied to the track element. */ + track: string; + /** Styles applied to the input element. */ + input: string; + /** Styles applied to the thumb element. */ + thumb: string; + /** Styles applied to the button element. */ + button: string; + + text: string; +}; + +export type StoreBadgeClassKey = keyof StoreBadgeClasses; + +export function getStoreBadgeUtilityClass(slot: string): string { + return generateUtilityClass('ESStoreBadge', slot); +} + +export const storeBadgeClasses: StoreBadgeClasses = generateUtilityClasses('ESStoreBadge', [ + 'root', + 'text', + 'checked', + 'track', + 'input', + 'thumb', + 'button', + 'disabled', + 'large', + 'medium', + 'small' +]); diff --git a/packages/react/src/components/StoreBadge/StoreBadge.stories.tsx b/packages/react/src/components/StoreBadge/StoreBadge.stories.tsx new file mode 100644 index 000000000..f337de334 --- /dev/null +++ b/packages/react/src/components/StoreBadge/StoreBadge.stories.tsx @@ -0,0 +1,26 @@ +import { Meta, StoryObj } from '@storybook/react'; + +import { StoreBadge } from '.'; + +import { IconAppStore, IconAppStoreLogo } from '../../icons'; + +const meta: Meta = { + tags: ['autodocs'], + component: StoreBadge, + parameters: { + references: ['StoreBadge'] + } +}; + +export default meta; +type Story = StoryObj; + +export const Demo: Story = { + render: (args) => { + return ( + } upperText="Загрузите в" {...args}> + + + ); + } +}; diff --git a/packages/react/src/components/StoreBadge/StoreBadge.tsx b/packages/react/src/components/StoreBadge/StoreBadge.tsx new file mode 100644 index 000000000..9a2f32ace --- /dev/null +++ b/packages/react/src/components/StoreBadge/StoreBadge.tsx @@ -0,0 +1,109 @@ +import React from 'react'; + +import { StoreBadgeProps } from './StoreBadge.types'; + +import clsx from 'clsx'; +import { getStoreBadgeUtilityClass, storeBadgeClasses } from './StoreBadge.classes'; + +import { unstable_composeClasses as composeClasses } from '@mui/base'; + +import { styled, useThemeProps } from '@mui/material/styles'; +import { Button, buttonBaseClasses, Typography } from '@mui/material'; + +type StoreBadgeOwnerState = { + classes?: StoreBadgeProps['classes']; + disabled?: StoreBadgeProps['disabled']; + color: NonNullable; + variant: NonNullable; +}; + +const useUtilityClasses = (ownerState: StoreBadgeOwnerState) => { + const { classes, disabled } = ownerState; + + const slots = { + root: ['root', disabled && 'disabled'], + text: ['text'] + }; + + return composeClasses(slots, getStoreBadgeUtilityClass, classes); +}; + +const StoreBadgeRoot = styled(Button, { + name: 'ESStoreBadge', + slot: 'Root', + overridesResolver: (props, styles) => { + const { + ownerState: { disabled, checked, size } + } = props; + return [styles.root, disabled && styles.disabled, checked && styles.checked, styles[size]]; + } +})<{ ownerState: StoreBadgeOwnerState }>(({ ownerState: { color, variant }, theme }) => ({ + ...theme.typography.body100, + border: `1px solid ${theme.vars.palette[color].A150}`, + color: theme.vars.palette[color][500], + textTransform: 'none', + [`&.${buttonBaseClasses.root}`]: { + ...(variant === 'filled' && { + backgroundColor: theme.vars.palette[`${color === 'monoA' ? 'monoB' : 'monoA'}`].A900 + }) + }, + + [`& .${storeBadgeClasses.text}`]: { + color: theme.vars.palette[color].A700 + } +})); + +const StoreBadgeText = styled(Typography, { + name: 'ESStoreBadge', + slot: 'Text', + overridesResolver: (props, styles) => styles.text +})(({ theme }) => ({ + ...theme.typography.micro, + textTransform: 'none' +})) as typeof Typography; + +const StoreBadgeContainer = styled('div', { + name: 'ESStoreBadge', + slot: 'Container', + overridesResolver: (props, styles) => styles.container +})(() => ({ + display: 'flex', + flexDirection: 'column', + alignItems: 'flex-start', + gap: '2px' +})); + +export const StoreBadge = (inProps: StoreBadgeProps) => { + const { + className, + disabled, + color = 'monoA', + variant = 'filled', + children, + startIcon, + upperText, + sx, + ...props + } = useThemeProps({ + props: inProps, + name: 'ESStoreBadge' + }); + + const ownerState = { ...props, disabled, color, variant }; + const classes = useUtilityClasses(ownerState); + + return ( + + + {upperText} + {children} + + + ); +}; diff --git a/packages/react/src/components/StoreBadge/StoreBadge.types.ts b/packages/react/src/components/StoreBadge/StoreBadge.types.ts new file mode 100644 index 000000000..b9396eb93 --- /dev/null +++ b/packages/react/src/components/StoreBadge/StoreBadge.types.ts @@ -0,0 +1,34 @@ +import { ReactNode } from 'react'; + +import { StoreBadgeClasses } from './StoreBadge.classes'; + +import { SxProps, Theme } from '@mui/material'; + +export interface StoreBadgeProps { + children: ReactNode; + + className?: string; + /** Override or extend the styles applied to the component. */ + classes?: Partial; + /** The system prop that allows defining system overrides as well as additional CSS styles. */ + sx?: SxProps; + /** If `true`, the component is checked. */ + checked?: boolean; + /** Callback fired when the state is changed. */ + onChange?: (e: React.ChangeEvent) => void; + + /** + * The color of the component. + * @default 'monoA' + */ + color?: 'monoA' | 'monoB'; + + startIcon?: ReactNode; + + variant?: 'filled' | 'outlined'; + + upperText?: string; + + /** If `true`, the component is disabled. */ + disabled?: boolean; +} diff --git a/packages/react/src/components/StoreBadge/index.ts b/packages/react/src/components/StoreBadge/index.ts new file mode 100644 index 000000000..19bda6836 --- /dev/null +++ b/packages/react/src/components/StoreBadge/index.ts @@ -0,0 +1,3 @@ +export { StoreBadge } from './StoreBadge'; +export { StoreBadgeClasses, storeBadgeClasses, StoreBadgeClassKey } from './StoreBadge.classes'; +export { StoreBadgeProps } from './StoreBadge.types'; diff --git a/packages/react/src/icons/IconAppStore.tsx b/packages/react/src/icons/IconAppStore.tsx new file mode 100644 index 000000000..8f60c9d53 --- /dev/null +++ b/packages/react/src/icons/IconAppStore.tsx @@ -0,0 +1,45 @@ +import { SvgIcon, SvgIconProps } from '../components/SvgIcon'; + +export const IconAppStore = (props: SvgIconProps) => { + return ( + + {/* */} + + + + + + + + + + + ); +}; diff --git a/packages/react/src/icons/IconAppStoreLogo.tsx b/packages/react/src/icons/IconAppStoreLogo.tsx new file mode 100644 index 000000000..061eb9488 --- /dev/null +++ b/packages/react/src/icons/IconAppStoreLogo.tsx @@ -0,0 +1,12 @@ +import { SvgIcon, SvgIconProps } from '../components/SvgIcon'; + +export const IconAppStoreLogo = (props: SvgIconProps) => { + return ( + + + + ); +}; diff --git a/packages/react/src/icons/index.ts b/packages/react/src/icons/index.ts index af5db3480..5c570e975 100644 --- a/packages/react/src/icons/index.ts +++ b/packages/react/src/icons/index.ts @@ -8,6 +8,8 @@ export { IconAlertLc } from './IconAlertLc'; export { IconAlertW300 } from './IconAlertW300'; export { IconAlertW500 } from './IconAlertW500'; export { IconApple } from './IconApple'; +export { IconAppStore } from './IconAppStore'; +export { IconAppStoreLogo } from './IconAppStoreLogo'; export { IconArchiveArrowDown } from './IconArchiveArrowDown'; export { IconArrowCollapse } from './IconArrowCollapse'; export { IconArrowDownW300 } from './IconArrowDownW300'; From d3188430e1052a8c92c549866963b556977cd048 Mon Sep 17 00:00:00 2001 From: Daria Alekhina Date: Wed, 29 May 2024 18:28:48 +0300 Subject: [PATCH 2/3] feat(StoreBadge): fix types --- .../StoreBadge/StoreBadge.classes.ts | 29 +++---------------- .../StoreBadge/StoreBadge.stories.tsx | 2 +- .../src/components/StoreBadge/StoreBadge.tsx | 7 +++-- .../components/StoreBadge/StoreBadge.types.ts | 21 +++++++------- packages/react/src/components/index.ts | 1 + packages/react/src/icons/IconAppStore.tsx | 7 +---- packages/react/src/icons/IconAppStoreLogo.tsx | 2 +- packages/react/src/overrides.d.ts | 7 +++++ 8 files changed, 30 insertions(+), 46 deletions(-) diff --git a/packages/react/src/components/StoreBadge/StoreBadge.classes.ts b/packages/react/src/components/StoreBadge/StoreBadge.classes.ts index 160f83867..5cc7c34a1 100644 --- a/packages/react/src/components/StoreBadge/StoreBadge.classes.ts +++ b/packages/react/src/components/StoreBadge/StoreBadge.classes.ts @@ -3,25 +3,11 @@ import { generateUtilityClass, generateUtilityClasses } from '@mui/material'; export type StoreBadgeClasses = { /** Styles applied to the root element. */ root: string; - /** Styles applied to the root element if component checked. */ - checked: string; /** Styles applied to the root element if component disabled. */ disabled: string; - /** Styles applied to the root element if size='large'. */ - large: string; - /** Styles applied to the root element if size='medium'. */ - medium: string; - /** Styles applied to the root element if size='small'. */ - small: string; - /** Styles applied to the track element. */ - track: string; - /** Styles applied to the input element. */ - input: string; - /** Styles applied to the thumb element. */ - thumb: string; - /** Styles applied to the button element. */ - button: string; - + /** Styles applied to the container element. */ + container: string; + /** Styles applied to the text element. */ text: string; }; @@ -34,13 +20,6 @@ export function getStoreBadgeUtilityClass(slot: string): string { export const storeBadgeClasses: StoreBadgeClasses = generateUtilityClasses('ESStoreBadge', [ 'root', 'text', - 'checked', - 'track', - 'input', - 'thumb', - 'button', 'disabled', - 'large', - 'medium', - 'small' + 'container' ]); diff --git a/packages/react/src/components/StoreBadge/StoreBadge.stories.tsx b/packages/react/src/components/StoreBadge/StoreBadge.stories.tsx index f337de334..eaa7644ad 100644 --- a/packages/react/src/components/StoreBadge/StoreBadge.stories.tsx +++ b/packages/react/src/components/StoreBadge/StoreBadge.stories.tsx @@ -19,7 +19,7 @@ export const Demo: Story = { render: (args) => { return ( } upperText="Загрузите в" {...args}> - + ); } diff --git a/packages/react/src/components/StoreBadge/StoreBadge.tsx b/packages/react/src/components/StoreBadge/StoreBadge.tsx index 9a2f32ace..3095ac53d 100644 --- a/packages/react/src/components/StoreBadge/StoreBadge.tsx +++ b/packages/react/src/components/StoreBadge/StoreBadge.tsx @@ -22,7 +22,8 @@ const useUtilityClasses = (ownerState: StoreBadgeOwnerState) => { const slots = { root: ['root', disabled && 'disabled'], - text: ['text'] + text: ['text'], + container: ['container'] }; return composeClasses(slots, getStoreBadgeUtilityClass, classes); @@ -82,6 +83,7 @@ export const StoreBadge = (inProps: StoreBadgeProps) => { children, startIcon, upperText, + href, sx, ...props } = useThemeProps({ @@ -96,11 +98,12 @@ export const StoreBadge = (inProps: StoreBadgeProps) => { - + {upperText} {children} diff --git a/packages/react/src/components/StoreBadge/StoreBadge.types.ts b/packages/react/src/components/StoreBadge/StoreBadge.types.ts index b9396eb93..b53e41204 100644 --- a/packages/react/src/components/StoreBadge/StoreBadge.types.ts +++ b/packages/react/src/components/StoreBadge/StoreBadge.types.ts @@ -6,29 +6,28 @@ import { SxProps, Theme } from '@mui/material'; export interface StoreBadgeProps { children: ReactNode; - + /** Class applied to the root element. */ className?: string; /** Override or extend the styles applied to the component. */ classes?: Partial; /** The system prop that allows defining system overrides as well as additional CSS styles. */ sx?: SxProps; - /** If `true`, the component is checked. */ - checked?: boolean; - /** Callback fired when the state is changed. */ - onChange?: (e: React.ChangeEvent) => void; - /** * The color of the component. * @default 'monoA' */ color?: 'monoA' | 'monoB'; - - startIcon?: ReactNode; - + /** + * The variant of the component. + * @default 'filled' + */ variant?: 'filled' | 'outlined'; - + /** Element placed before the children. */ + startIcon?: ReactNode; + /** Text placed up the children. */ upperText?: string; - + /** The URL to link to when the button is clicked. */ + href?: string; /** If `true`, the component is disabled. */ disabled?: boolean; } diff --git a/packages/react/src/components/index.ts b/packages/react/src/components/index.ts index c1da40d85..7f095fe7d 100644 --- a/packages/react/src/components/index.ts +++ b/packages/react/src/components/index.ts @@ -42,6 +42,7 @@ export * from './Sidenav'; export * from './SortingMenu'; export * from './Spinner'; export * from './Spinner'; +export * from './StoreBadge'; export * from './SvgIcon'; export * from './Swiper'; export * from './Swiper'; diff --git a/packages/react/src/icons/IconAppStore.tsx b/packages/react/src/icons/IconAppStore.tsx index 8f60c9d53..d263cfa05 100644 --- a/packages/react/src/icons/IconAppStore.tsx +++ b/packages/react/src/icons/IconAppStore.tsx @@ -2,12 +2,7 @@ import { SvgIcon, SvgIconProps } from '../components/SvgIcon'; export const IconAppStore = (props: SvgIconProps) => { return ( - - {/* */} - + { return ( - + Date: Wed, 5 Jun 2024 17:07:57 +0300 Subject: [PATCH 3/3] feat(StoreBadge): add new button --- .../StoreBadge/StoreBadge.classes.ts | 11 +++- .../StoreBadge/StoreBadge.stories.tsx | 10 ++++ .../src/components/StoreBadge/StoreBadge.tsx | 58 +++++++++---------- .../components/StoreBadge/StoreBadge.types.ts | 24 +++++++- 4 files changed, 69 insertions(+), 34 deletions(-) diff --git a/packages/react/src/components/StoreBadge/StoreBadge.classes.ts b/packages/react/src/components/StoreBadge/StoreBadge.classes.ts index 5cc7c34a1..10bb992a1 100644 --- a/packages/react/src/components/StoreBadge/StoreBadge.classes.ts +++ b/packages/react/src/components/StoreBadge/StoreBadge.classes.ts @@ -9,6 +9,11 @@ export type StoreBadgeClasses = { container: string; /** Styles applied to the text element. */ text: string; + + colorMonoA: string; + colorMonoB: string; + variantFilled: string; + variantOutlined: string; }; export type StoreBadgeClassKey = keyof StoreBadgeClasses; @@ -21,5 +26,9 @@ export const storeBadgeClasses: StoreBadgeClasses = generateUtilityClasses('ESSt 'root', 'text', 'disabled', - 'container' + 'container', + 'colorMonoA', + 'colorMonoB', + 'variantFilled', + 'variantOutlined' ]); diff --git a/packages/react/src/components/StoreBadge/StoreBadge.stories.tsx b/packages/react/src/components/StoreBadge/StoreBadge.stories.tsx index eaa7644ad..3a1288acd 100644 --- a/packages/react/src/components/StoreBadge/StoreBadge.stories.tsx +++ b/packages/react/src/components/StoreBadge/StoreBadge.stories.tsx @@ -9,6 +9,16 @@ const meta: Meta = { component: StoreBadge, parameters: { references: ['StoreBadge'] + }, + argTypes: { + variant: { + options: ['contained', 'outlined'], + control: { type: 'select' } + }, + color: { + options: ['monoA', 'monoB'], + control: { type: 'select' } + } } }; diff --git a/packages/react/src/components/StoreBadge/StoreBadge.tsx b/packages/react/src/components/StoreBadge/StoreBadge.tsx index 3095ac53d..a3e9f8ccf 100644 --- a/packages/react/src/components/StoreBadge/StoreBadge.tsx +++ b/packages/react/src/components/StoreBadge/StoreBadge.tsx @@ -1,27 +1,28 @@ -import React from 'react'; - -import { StoreBadgeProps } from './StoreBadge.types'; +import { StoreBadgeOwnProps, StoreBadgeProps, StoreBadgeTypeMap } from './StoreBadge.types'; import clsx from 'clsx'; -import { getStoreBadgeUtilityClass, storeBadgeClasses } from './StoreBadge.classes'; +import { getStoreBadgeUtilityClass } from './StoreBadge.classes'; import { unstable_composeClasses as composeClasses } from '@mui/base'; import { styled, useThemeProps } from '@mui/material/styles'; -import { Button, buttonBaseClasses, Typography } from '@mui/material'; +import { capitalize, Typography } from '@mui/material'; +import { OverridableComponent } from '@mui/material/OverridableComponent'; + +import { Button } from '../Button'; type StoreBadgeOwnerState = { - classes?: StoreBadgeProps['classes']; - disabled?: StoreBadgeProps['disabled']; - color: NonNullable; - variant: NonNullable; + classes?: StoreBadgeOwnProps['classes']; + disabled?: StoreBadgeOwnProps['disabled']; + color: NonNullable; + variant: NonNullable; }; const useUtilityClasses = (ownerState: StoreBadgeOwnerState) => { - const { classes, disabled } = ownerState; + const { classes, disabled, color, variant } = ownerState; const slots = { - root: ['root', disabled && 'disabled'], + root: ['root', disabled && 'disabled', `color${capitalize(color)}`, `variant${capitalize(variant)}`], text: ['text'], container: ['container'] }; @@ -34,25 +35,21 @@ const StoreBadgeRoot = styled(Button, { slot: 'Root', overridesResolver: (props, styles) => { const { - ownerState: { disabled, checked, size } + ownerState: { disabled, checked, size, variant, color } } = props; - return [styles.root, disabled && styles.disabled, checked && styles.checked, styles[size]]; + return [ + styles.root, + disabled && styles.disabled, + checked && styles.checked, + styles[size], + styles[`color${capitalize(color)}`], + styles[`variant${capitalize(variant)}`] + ]; } -})<{ ownerState: StoreBadgeOwnerState }>(({ ownerState: { color, variant }, theme }) => ({ +})(({ theme }) => ({ ...theme.typography.body100, - border: `1px solid ${theme.vars.palette[color].A150}`, - color: theme.vars.palette[color][500], - textTransform: 'none', - [`&.${buttonBaseClasses.root}`]: { - ...(variant === 'filled' && { - backgroundColor: theme.vars.palette[`${color === 'monoA' ? 'monoB' : 'monoA'}`].A900 - }) - }, - - [`& .${storeBadgeClasses.text}`]: { - color: theme.vars.palette[color].A700 - } -})); + textTransform: 'none' +})) as typeof Button; const StoreBadgeText = styled(Typography, { name: 'ESStoreBadge', @@ -74,12 +71,12 @@ const StoreBadgeContainer = styled('div', { gap: '2px' })); -export const StoreBadge = (inProps: StoreBadgeProps) => { +export const StoreBadge: OverridableComponent = (inProps: StoreBadgeProps) => { const { className, disabled, color = 'monoA', - variant = 'filled', + variant = 'contained', children, startIcon, upperText, @@ -98,10 +95,11 @@ export const StoreBadge = (inProps: StoreBadgeProps) => { {upperText} diff --git a/packages/react/src/components/StoreBadge/StoreBadge.types.ts b/packages/react/src/components/StoreBadge/StoreBadge.types.ts index b53e41204..dd875cfff 100644 --- a/packages/react/src/components/StoreBadge/StoreBadge.types.ts +++ b/packages/react/src/components/StoreBadge/StoreBadge.types.ts @@ -1,10 +1,15 @@ +/* eslint-disable @typescript-eslint/ban-types */ + import { ReactNode } from 'react'; import { StoreBadgeClasses } from './StoreBadge.classes'; import { SxProps, Theme } from '@mui/material'; +import { OverrideProps } from '@mui/material/OverridableComponent'; + +import { ExtendButtonTypeMap } from '../Button'; -export interface StoreBadgeProps { +export interface StoreBadgeOwnProps { children: ReactNode; /** Class applied to the root element. */ className?: string; @@ -19,9 +24,9 @@ export interface StoreBadgeProps { color?: 'monoA' | 'monoB'; /** * The variant of the component. - * @default 'filled' + * @default 'contained' */ - variant?: 'filled' | 'outlined'; + variant: 'contained' | 'outlined'; /** Element placed before the children. */ startIcon?: ReactNode; /** Text placed up the children. */ @@ -31,3 +36,16 @@ export interface StoreBadgeProps { /** If `true`, the component is disabled. */ disabled?: boolean; } + +export type StoreBadgeTypeMap< + AdditionalProps = {}, + RootComponent extends React.ElementType = 'button' +> = ExtendButtonTypeMap<{ + props: AdditionalProps & StoreBadgeOwnProps; + defaultComponent: RootComponent; +}>; + +export type StoreBadgeProps< + RootComponent extends React.ElementType = StoreBadgeTypeMap['defaultComponent'], + AdditionalProps = {} +> = OverrideProps, RootComponent>;