Merge branch 'batch-1' into topic-implement-quote

This commit is contained in:
Hossein Mehrabi 2023-02-23 15:30:11 +03:30
commit 5500d9131e
24 changed files with 533 additions and 91 deletions

View File

@ -6,6 +6,8 @@ export const buttonClasses = {
large: `${LSD_NAMESPACE}--large`,
medium: `${LSD_NAMESPACE}--medium`,
small: `${LSD_NAMESPACE}--small`,
withIcon: `${LSD_NAMESPACE}--with-icon`,
text: `${LSD_NAMESPACE}-button__text`,
icon: `${LSD_NAMESPACE}-button__icon`,
}

View File

@ -1,14 +1,42 @@
import { Meta, Story } from '@storybook/react'
import { useStorybookIconComponent } from '../../utils/storybook.utils'
import { Button, ButtonProps } from './Button'
export default {
title: 'Button',
component: Button,
argTypes: {
size: {
type: {
name: 'enum',
value: ['small', 'medium', 'large'],
},
defaultValue: 'large',
},
icon: {
type: {
name: 'enum',
value: useStorybookIconComponent.options,
},
},
},
} as Meta
export const Root: Story<ButtonProps> = (args) => (
<Button {...args}>Button</Button>
)
export const Root: Story<ButtonProps & { icon: string }> = ({
icon,
...args
}) => {
const IconComponent = useStorybookIconComponent(icon)
return (
<Button
{...args}
icon={IconComponent && <IconComponent color="primary"></IconComponent>}
>
Button
</Button>
)
}
Root.args = {
disabled: false,
}

View File

@ -22,6 +22,7 @@ export const ButtonStyles = css`
}
.${buttonClasses.medium} {
padding: 6px, 24px;
}
.${buttonClasses.small} {
@ -35,4 +36,33 @@ export const ButtonStyles = css`
}
}
}
.${buttonClasses.withIcon} {
display: flex;
}
.${buttonClasses.icon} {
display: flex;
}
.${buttonClasses.large}.${buttonClasses.withIcon} {
padding: 10px 14px 10px 18px;
.${buttonClasses.icon} {
margin-left: 18px;
}
}
.${buttonClasses.medium}.${buttonClasses.withIcon} {
padding: 6px 12px 6px 14px;
.${buttonClasses.icon} {
margin-left: 14px;
}
}
.${buttonClasses.small}.${buttonClasses.withIcon} {
padding: 6px 10px 6px 12px;
.${buttonClasses.icon} {
margin-left: 10px;
}
}
`

View File

@ -4,11 +4,12 @@ import { buttonClasses } from './Button.classes'
export type ButtonProps = React.ButtonHTMLAttributes<HTMLButtonElement> & {
size?: 'large' | 'medium' | 'small'
icon: React.ReactNode
}
export const Button: React.FC<ButtonProps> & {
classes: typeof buttonClasses
} = ({ size = 'medium', children, ...props }) => {
} = ({ size = 'medium', icon, children, ...props }) => {
return (
<>
<button
@ -18,9 +19,11 @@ export const Button: React.FC<ButtonProps> & {
buttonClasses.root,
buttonClasses[size],
props.disabled && buttonClasses.disabled,
icon && buttonClasses.withIcon,
)}
>
<span className={buttonClasses.text}>{children}</span>
{icon && <span className={buttonClasses.icon}>{icon}</span>}
</button>
</>
)

View File

@ -1,18 +1,20 @@
import { Global, SerializedStyles } from '@emotion/react'
import React, { useMemo } from 'react'
import { BreadcrumbStyles } from '../Breadcrumb/Breadcrumb.styles'
import { BreadcrumbItemStyles } from '../BreadcrumbItem/BreadcrumbItem.styles'
import { ButtonStyles } from '../Button/Button.styles'
import { CollapseStyles } from '../Collapse/Collapse.styles'
import { CollapseHeaderStyles } from '../CollapseHeader/CollapseHeader.styles'
import { DropdownStyles } from '../Dropdown/Dropdown.styles'
import { DropdownItemStyles } from '../DropdownItem/DropdownItem.styles'
import { LsdIconStyles } from '../Icons/LsdIcon/LsdIcon.styles'
import { IconTagStyles } from '../IconTag/IconTag.styles'
import { ListBoxStyles } from '../ListBox/ListBox.styles'
import { QuoteStyles } from '../Quote/Quote.styles'
import { TabItemStyles } from '../TabItem/TabItem.styles'
import { TabsStyles } from '../Tabs/Tabs.styles'
import { BreadcrumbStyles } from '../Breadcrumb/Breadcrumb.styles'
import { BreadcrumbItemStyles } from '../BreadcrumbItem/BreadcrumbItem.styles'
import { defaultThemes, Theme, withTheme } from '../Theme'
import { TypographyStyles } from '../Typography/Typography.styles'
import { QuoteStyles } from '../Quote/Quote.styles'
const componentStyles: Array<ReturnType<typeof withTheme> | SerializedStyles> =
[
@ -28,6 +30,8 @@ const componentStyles: Array<ReturnType<typeof withTheme> | SerializedStyles> =
BreadcrumbStyles,
BreadcrumbItemStyles,
QuoteStyles,
CollapseStyles,
CollapseHeaderStyles,
]
export const CSSBaseline: React.FC<{ theme?: Theme }> = ({

View File

@ -0,0 +1,8 @@
export const collapseClasses = {
root: `lsd-collapse`,
content: `lsd-collapse-content`,
open: 'lsd-collapse--open-item',
disabled: 'lsd-collapse--disabled',
}

View File

@ -0,0 +1,34 @@
import { Meta, Story } from '@storybook/react'
import { Typography } from '../Typography'
import { Collapse, CollapseProps } from './Collapse'
export default {
title: 'Collapse',
component: Collapse,
argTypes: {
size: {
type: {
name: 'enum',
value: ['small', 'medium', 'large'],
},
},
},
} as Meta
export const Root: Story<CollapseProps> = (args) => (
<div style={{ width: 'fit-content' }}>
<Collapse {...args}>
<div style={{ padding: '10px 18px' }}>
<Typography color="primary" component="label">
Slot component
</Typography>
</div>
</Collapse>
</div>
)
Root.args = {
size: 'large',
label: 'Title',
disabled: false,
}

View File

@ -0,0 +1,20 @@
import { css } from '@emotion/react'
import { collapseClasses } from './Collapse.classes'
export const CollapseStyles = css`
.${collapseClasses.root} {
box-sizing: border-box;
display: flex;
flex-direction: column;
}
.${collapseClasses.open} {
.${collapseClasses.content} {
border-top: 1px solid transparent;
}
}
.${collapseClasses.content} {
border: 1px solid rgb(var(--lsd-border-primary));
}
`

View File

@ -0,0 +1,58 @@
import clsx from 'clsx'
import React, { useEffect, useRef, useState } from 'react'
import { CollapseHeader } from '../CollapseHeader'
import { collapseClasses } from './Collapse.classes'
export type CollapseProps = Omit<
React.HTMLAttributes<HTMLDivElement>,
'label'
> & {
label: string
disabled?: boolean
size?: 'small' | 'medium' | 'large'
open?: boolean
onChange?: (open: boolean) => void
}
export const Collapse: React.FC<CollapseProps> & {
classes: typeof collapseClasses
} = ({ label, disabled = false, size = 'large', children, ...props }) => {
const ref = useRef<HTMLDivElement>(null)
const [open, setOpen] = useState(props.open ?? false)
const handleChange = (value: boolean) => {
if (typeof props.open === 'undefined') return setOpen(value)
props.onChange && props.onChange(value)
}
const onTrigger = () => !disabled && handleChange(!open)
useEffect(() => {
disabled && open && handleChange(false)
}, [disabled, open, handleChange])
return (
<div
{...props}
ref={ref}
className={clsx(
props.className,
collapseClasses.root,
disabled && collapseClasses.disabled,
open && collapseClasses.open,
)}
>
<CollapseHeader
label={label}
open={open}
setOpen={setOpen}
size={size}
onTrigger={onTrigger}
disabled={disabled}
/>
{open && <div className={collapseClasses.content}>{children}</div>}
</div>
)
}
Collapse.classes = collapseClasses

View File

@ -0,0 +1 @@
export * from './Collapse'

View File

@ -0,0 +1,16 @@
export const collapseHeaderClasses = {
root: `lsd-collapse-header`,
trigger: `lsd-collapse-header-trigger`,
triggerLabel: `lsd-collapse-header-trigger__label`,
triggerIcons: `lsd-collapse-header-trigger-icons`,
triggerIcon: `lsd-collapse-header-trigger-icons__icon`,
triggerMenuIcon: `lsd-collapse-header-trigger-icons__menu-icon`,
open: 'lsd-collapse-header--open',
disabled: 'lsd-collapse-header--disabled',
small: `lsd-collapse-header--small`,
medium: `lsd-collapse-header--medium`,
large: `lsd-collapse-header--large`,
}

View File

@ -0,0 +1,27 @@
import { Meta, Story } from '@storybook/react'
import { CollapseHeader, CollapseHeaderProps } from './CollapseHeader'
export default {
title: 'CollapseHeader',
component: CollapseHeader,
argTypes: {
size: {
type: {
name: 'enum',
value: ['small', 'medium', 'large'],
},
},
},
} as Meta
export const Root: Story<CollapseHeaderProps> = (args) => (
<div style={{ width: 'fit-content' }}>
<CollapseHeader {...args}></CollapseHeader>
</div>
)
Root.args = {
size: 'large',
label: 'title',
disabled: false,
}

View File

@ -0,0 +1,88 @@
import { css } from '@emotion/react'
import { collapseHeaderClasses } from './CollapseHeader.classes'
export const CollapseHeaderStyles = css`
.${collapseHeaderClasses.root} {
box-sizing: border-box;
}
.${collapseHeaderClasses.root}:not(.${collapseHeaderClasses.disabled}) {
.${collapseHeaderClasses.trigger} {
&:hover {
.${collapseHeaderClasses.triggerLabel} {
text-decoration: underline;
}
}
}
}
.${collapseHeaderClasses.trigger} {
width: 100%;
display: flex;
flex-direction: row;
align-items: center;
justify-content: space-between;
padding: 10px 14px 10px 18px;
cursor: pointer;
background: none;
border: 1px solid rgb(var(--lsd-border-primary));
&:focus {
outline: none;
}
}
.${collapseHeaderClasses.triggerLabel} {
cursor: inherit;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
margin: auto;
}
.${collapseHeaderClasses.triggerIcons} {
display: flex;
flex-direction: row;
align-items: center;
justify-content: flex-end;
}
.${collapseHeaderClasses.triggerIcon} {
margin-right: 8px;
}
.${collapseHeaderClasses.triggerMenuIcon} {
}
.${collapseHeaderClasses.disabled} {
.${collapseHeaderClasses.trigger} {
opacity: 0.34;
cursor: initial;
}
}
.${collapseHeaderClasses.large} {
.${collapseHeaderClasses.trigger} {
width: 299px;
height: 40px;
padding: 10px 18px;
}
}
.${collapseHeaderClasses.medium} {
.${collapseHeaderClasses.trigger} {
width: 270px;
height: 32px;
padding: 6px 14px;
}
}
.${collapseHeaderClasses.small} {
.${collapseHeaderClasses.trigger} {
width: 235px;
height: 28px;
padding: 6px 12px;
}
}
`

View File

@ -0,0 +1,71 @@
import clsx from 'clsx'
import React, { useEffect, useState } from 'react'
import { ArrowDownIcon, ArrowUpIcon } from '../Icons'
import { Typography } from '../Typography'
import { collapseHeaderClasses } from './CollapseHeader.classes'
export type CollapseHeaderProps = Omit<
React.HTMLAttributes<HTMLDivElement>,
'label' | 'disabled'
> & {
label: string
open: boolean
setOpen: React.Dispatch<React.SetStateAction<boolean>>
disabled?: boolean
onTrigger: () => void
size?: 'small' | 'medium' | 'large'
}
export const CollapseHeader: React.FC<CollapseHeaderProps> & {
classes: typeof collapseHeaderClasses
} = ({
label,
disabled = false,
open,
setOpen,
size = 'large',
onTrigger,
...props
}) => {
return (
<div
{...props}
className={clsx(
props.className,
collapseHeaderClasses.root,
collapseHeaderClasses[size],
disabled && collapseHeaderClasses.disabled,
open && collapseHeaderClasses.open,
)}
>
<button
className={clsx(collapseHeaderClasses.trigger)}
onClick={onTrigger}
>
<Typography
color="primary"
component="label"
variant={size === 'small' ? 'label2' : 'label1'}
className={collapseHeaderClasses.triggerLabel}
>
{label}
</Typography>
<div className={collapseHeaderClasses.triggerIcons}>
{open ? (
<ArrowUpIcon
color="primary"
className={collapseHeaderClasses.triggerMenuIcon}
/>
) : (
<ArrowDownIcon
color="primary"
className={collapseHeaderClasses.triggerMenuIcon}
/>
)}
</div>
</button>
</div>
)
}
CollapseHeader.classes = collapseHeaderClasses

View File

@ -0,0 +1 @@
export * from './CollapseHeader'

View File

@ -1,17 +1,22 @@
import { LsdIcon } from '../LsdIcon'
export const ArrowForwardIcon = LsdIcon((props) => (
<svg
width="14"
height="14"
viewBox="0 0 14 14"
fill="none"
xmlns="http://www.w3.org/2000/svg"
{...props}
>
<path
d="M6.99992 2.33334L6.17742 3.15584L9.43242 6.41668H2.33325V7.58334H9.43242L6.17742 10.8442L6.99992 11.6667L11.6666 7.00001L6.99992 2.33334Z"
fill="black"
/>
</svg>
))
export const ArrowForwardIcon = LsdIcon(
(props) => (
<svg
width="14"
height="14"
viewBox="0 0 14 14"
fill="none"
xmlns="http://www.w3.org/2000/svg"
{...props}
>
<path
d="M6.99992 2.33334L6.17742 3.15584L9.43242 6.41668H2.33325V7.58334H9.43242L6.17742 10.8442L6.99992 11.6667L11.6666 7.00001L6.99992 2.33334Z"
fill="black"
/>
</svg>
),
{
filled: true,
},
)

View File

@ -1,17 +1,22 @@
import { LsdIcon } from '../LsdIcon'
export const CloseIcon = LsdIcon((props) => (
<svg
width="14"
height="14"
viewBox="0 0 14 14"
fill="none"
xmlns="http://www.w3.org/2000/svg"
{...props}
>
<path
d="M11.0834 3.73916L10.2609 2.91666L7.00008 6.17749L3.73925 2.91666L2.91675 3.73916L6.17758 6.99999L2.91675 10.2608L3.73925 11.0833L7.00008 7.82249L10.2609 11.0833L11.0834 10.2608L7.82258 6.99999L11.0834 3.73916Z"
fill="black"
/>
</svg>
))
export const CloseIcon = LsdIcon(
(props) => (
<svg
width="14"
height="14"
viewBox="0 0 14 14"
fill="none"
xmlns="http://www.w3.org/2000/svg"
{...props}
>
<path
d="M11.0834 3.73916L10.2609 2.91666L7.00008 6.17749L3.73925 2.91666L2.91675 3.73916L6.17758 6.99999L2.91675 10.2608L3.73925 11.0833L7.00008 7.82249L10.2609 11.0833L11.0834 10.2608L7.82258 6.99999L11.0834 3.73916Z"
fill="black"
/>
</svg>
),
{
filled: true,
},
)

View File

@ -1,19 +1,24 @@
import { LsdIcon } from '../LsdIcon'
export const MoreIcon = LsdIcon((props) => (
<svg
width="14"
height="14"
viewBox="0 0 14 14"
fill="none"
xmlns="http://www.w3.org/2000/svg"
{...props}
>
<path
fillRule="evenodd"
clipRule="evenodd"
d="M3.49992 5.83334C2.85825 5.83334 2.33325 6.35834 2.33325 7.00001C2.33325 7.64168 2.85825 8.16668 3.49992 8.16668C4.14159 8.16668 4.66659 7.64168 4.66659 7.00001C4.66659 6.35834 4.14159 5.83334 3.49992 5.83334ZM10.4999 5.83334C9.85825 5.83334 9.33325 6.35834 9.33325 7.00001C9.33325 7.64168 9.85825 8.16668 10.4999 8.16668C11.1416 8.16668 11.6666 7.64168 11.6666 7.00001C11.6666 6.35834 11.1416 5.83334 10.4999 5.83334ZM5.83325 7.00001C5.83325 6.35834 6.35825 5.83334 6.99992 5.83334C7.64159 5.83334 8.16659 6.35834 8.16659 7.00001C8.16659 7.64168 7.64159 8.16668 6.99992 8.16668C6.35825 8.16668 5.83325 7.64168 5.83325 7.00001Z"
fill="black"
/>
</svg>
))
export const MoreIcon = LsdIcon(
(props) => (
<svg
width="14"
height="14"
viewBox="0 0 14 14"
fill="none"
xmlns="http://www.w3.org/2000/svg"
{...props}
>
<path
fillRule="evenodd"
clipRule="evenodd"
d="M3.49992 5.83334C2.85825 5.83334 2.33325 6.35834 2.33325 7.00001C2.33325 7.64168 2.85825 8.16668 3.49992 8.16668C4.14159 8.16668 4.66659 7.64168 4.66659 7.00001C4.66659 6.35834 4.14159 5.83334 3.49992 5.83334ZM10.4999 5.83334C9.85825 5.83334 9.33325 6.35834 9.33325 7.00001C9.33325 7.64168 9.85825 8.16668 10.4999 8.16668C11.1416 8.16668 11.6666 7.64168 11.6666 7.00001C11.6666 6.35834 11.1416 5.83334 10.4999 5.83334ZM5.83325 7.00001C5.83325 6.35834 6.35825 5.83334 6.99992 5.83334C7.64159 5.83334 8.16659 6.35834 8.16659 7.00001C8.16659 7.64168 7.64159 8.16668 6.99992 8.16668C6.35825 8.16668 5.83325 7.64168 5.83325 7.00001Z"
fill="black"
/>
</svg>
),
{
filled: true,
},
)

View File

@ -1,19 +1,24 @@
import { LsdIcon } from '../LsdIcon'
export const NewPageIcon = LsdIcon((props) => (
<svg
width="14"
height="14"
viewBox="0 0 14 14"
fill="none"
xmlns="http://www.w3.org/2000/svg"
{...props}
>
<path
fillRule="evenodd"
clipRule="evenodd"
d="M9.79293 3.5H3.00004V2.5H11.5V11H10.5V4.20711L3.35359 11.3536L2.64648 10.6464L9.79293 3.5Z"
fill="black"
/>
</svg>
))
export const NewPageIcon = LsdIcon(
(props) => (
<svg
width="14"
height="14"
viewBox="0 0 14 14"
fill="none"
xmlns="http://www.w3.org/2000/svg"
{...props}
>
<path
fillRule="evenodd"
clipRule="evenodd"
d="M9.79293 3.5H3.00004V2.5H11.5V11H10.5V4.20711L3.35359 11.3536L2.64648 10.6464L9.79293 3.5Z"
fill="black"
/>
</svg>
),
{
filled: true,
},
)

View File

@ -0,0 +1,22 @@
import { LsdIcon } from '../LsdIcon'
export const PickIcon = LsdIcon(
(props) => (
<svg
width="14"
height="14"
viewBox="0 0 14 14"
fill="none"
xmlns="http://www.w3.org/2000/svg"
{...props}
>
<path
fill-rule="evenodd"
clip-rule="evenodd"
d="M9.79287 3.5H2.99998V2.5H11.5V11H10.5V4.20711L3.35353 11.3536L2.64642 10.6464L9.79287 3.5Z"
fill="black"
/>
</svg>
),
{ filled: true },
)

View File

@ -0,0 +1 @@
export * from './PickIcon'

View File

@ -1,19 +1,24 @@
import { LsdIcon } from '../LsdIcon'
export const SearchIcon = LsdIcon((props) => (
<svg
width="14"
height="14"
viewBox="0 0 14 14"
fill="none"
xmlns="http://www.w3.org/2000/svg"
{...props}
>
<path
fillRule="evenodd"
clipRule="evenodd"
d="M8.61 7.74083L11.9525 11.0833L11.0833 11.9525L7.74083 8.61C7.11667 9.05917 6.36417 9.33333 5.54167 9.33333C3.4475 9.33333 1.75 7.63583 1.75 5.54167C1.75 3.4475 3.4475 1.75 5.54167 1.75C7.63583 1.75 9.33333 3.4475 9.33333 5.54167C9.33333 6.36417 9.05917 7.11667 8.61 7.74083ZM5.54167 2.91667C4.08917 2.91667 2.91667 4.08917 2.91667 5.54167C2.91667 6.99417 4.08917 8.16667 5.54167 8.16667C6.99417 8.16667 8.16667 6.99417 8.16667 5.54167C8.16667 4.08917 6.99417 2.91667 5.54167 2.91667Z"
fill="black"
/>
</svg>
))
export const SearchIcon = LsdIcon(
(props) => (
<svg
width="14"
height="14"
viewBox="0 0 14 14"
fill="none"
xmlns="http://www.w3.org/2000/svg"
{...props}
>
<path
fillRule="evenodd"
clipRule="evenodd"
d="M8.61 7.74083L11.9525 11.0833L11.0833 11.9525L7.74083 8.61C7.11667 9.05917 6.36417 9.33333 5.54167 9.33333C3.4475 9.33333 1.75 7.63583 1.75 5.54167C1.75 3.4475 3.4475 1.75 5.54167 1.75C7.63583 1.75 9.33333 3.4475 9.33333 5.54167C9.33333 6.36417 9.05917 7.11667 8.61 7.74083ZM5.54167 2.91667C4.08917 2.91667 2.91667 4.08917 2.91667 5.54167C2.91667 6.99417 4.08917 8.16667 5.54167 8.16667C6.99417 8.16667 8.16667 6.99417 8.16667 5.54167C8.16667 4.08917 6.99417 2.91667 5.54167 2.91667Z"
fill="black"
/>
</svg>
),
{
filled: true,
},
)

View File

@ -16,3 +16,4 @@ export * from './NavigateBeforeIcon'
export * from './NavigateNextIcon'
export * from './NewPageIcon'
export * from './SearchIcon'
export * from './PickIcon'

View File

@ -1,12 +1,14 @@
export * from './components/Breadcrumb'
export * from './components/BreadcrumbItem'
export * from './components/Button'
export * from './components/Collapse'
export * from './components/CollapseHeader'
export * from './components/Dropdown'
export * from './components/DropdownItem'
export * from './components/Icons'
export * from './components/IconTag'
export * from './components/ListBox'
export * from './components/Quote'
export * from './components/TabItem'
export * from './components/Tabs'
export * from './components/Theme'
export * from './components/Breadcrumb'
export * from './components/BreadcrumbItem'
export * from './components/Quote'