From 0b22563a26c8da7ff941c3c031f82fa32bb9c5ec Mon Sep 17 00:00:00 2001 From: Szymon Graczyk Date: Wed, 27 Jul 2022 10:54:20 +0200 Subject: [PATCH 01/11] #339 Apply missing tokens to Input and TagInput components --- .../src/components/Input/Input.module.scss | 6 ++- .../src/components/Input/Input.stories.tsx | 53 ++++++++++++++----- .../src/components/Input/Input.tsx | 5 +- .../components/TagInput/TagInput.module.scss | 3 ++ .../components/TagInput/TagInput.stories.tsx | 51 ++++++++++++------ 5 files changed, 86 insertions(+), 32 deletions(-) diff --git a/packages/react-components/src/components/Input/Input.module.scss b/packages/react-components/src/components/Input/Input.module.scss index 379c65bc3..1897e0a0f 100644 --- a/packages/react-components/src/components/Input/Input.module.scss +++ b/packages/react-components/src/components/Input/Input.module.scss @@ -1,5 +1,5 @@ .input { - border: 1px solid #bdc7d1; + background: var(--surface-basic-default); border: 1px solid var(--border-default); border-radius: 4px; box-sizing: border-box; @@ -8,6 +8,10 @@ line-height: 22px; outline: none; + &::placeholder { + color: var(--content-disabled); + } + &:focus { border-color: var(--color-action-default); } diff --git a/packages/react-components/src/components/Input/Input.stories.tsx b/packages/react-components/src/components/Input/Input.stories.tsx index 41f1c2158..70f0b1aaa 100644 --- a/packages/react-components/src/components/Input/Input.stories.tsx +++ b/packages/react-components/src/components/Input/Input.stories.tsx @@ -1,24 +1,51 @@ import * as React from 'react'; -import { ComponentMeta } from '@storybook/react'; +import { ComponentMeta, Story } from '@storybook/react'; -import { Input as InputComponent, InputProps } from './Input'; +import { StoryDescriptor } from '../../stories/components/StoryDescriptor'; + +import { Input, InputProps } from './Input'; + +const placeholderText = 'Placeholder text'; export default { title: 'Forms/Input', - component: InputComponent, -} as ComponentMeta; + component: Input, +} as ComponentMeta; -export const Input = ({ ...args }): React.ReactElement => ( - +export const Default: Story = (args: InputProps) => ( + ); -Input.args = { +Default.storyName = 'Input'; +Default.args = { size: 'medium', placeholder: 'Placeholder text', - error: false, - disabled: false, -} as InputProps; +}; -export const WithIcon = () =>
TODO
; -export const WithArrow = () =>
TODO
; -export const WithIconAndArrow = () =>
TODO
; +export const Sizes = (): JSX.Element => ( + <> + + + + + + + + + + + + + +); + +export const States = (): JSX.Element => ( + <> + + + + + + + +); diff --git a/packages/react-components/src/components/Input/Input.tsx b/packages/react-components/src/components/Input/Input.tsx index ba886ee6e..db6cca22b 100644 --- a/packages/react-components/src/components/Input/Input.tsx +++ b/packages/react-components/src/components/Input/Input.tsx @@ -6,8 +6,9 @@ import styles from './Input.module.scss'; type InputSize = 'xsmall' | 'small' | 'medium' | 'large'; export interface InputProps extends React.HTMLAttributes { - size?: InputSize; - error?: boolean; + size?: InputSize | undefined; + error?: boolean | undefined; + disabled?: boolean | undefined; } const baseClass = 'input'; diff --git a/packages/react-components/src/components/TagInput/TagInput.module.scss b/packages/react-components/src/components/TagInput/TagInput.module.scss index 919a8c955..90745b34c 100644 --- a/packages/react-components/src/components/TagInput/TagInput.module.scss +++ b/packages/react-components/src/components/TagInput/TagInput.module.scss @@ -1,5 +1,6 @@ .tag-input { align-items: center; + background: var(--surface-basic-default); background-clip: padding-box; border: 1px solid var(--border-default); border-radius: 4px; @@ -34,6 +35,8 @@ } &:disabled { + background-color: var(--surface-basic-disabled); + border: 1px solid var(--border-disabled); color: var(--content-disabled); cursor: not-allowed; } diff --git a/packages/react-components/src/components/TagInput/TagInput.stories.tsx b/packages/react-components/src/components/TagInput/TagInput.stories.tsx index 37d89e80f..cbe06f380 100644 --- a/packages/react-components/src/components/TagInput/TagInput.stories.tsx +++ b/packages/react-components/src/components/TagInput/TagInput.stories.tsx @@ -1,16 +1,21 @@ import * as React from 'react'; -import { ComponentMeta } from '@storybook/react'; +import { ComponentMeta, Story } from '@storybook/react'; + +import noop from '../../utils/noop'; +import { StoryDescriptor } from '../../stories/components/StoryDescriptor'; import { - TagInput as TagInputComponent, + TagInput, TagInputProps, - EmailTagInput as EmailTagInputComponent, + EmailTagInput, EmailTagInputProps, } from './index'; +const placeholderText = 'Placeholder text'; + export default { title: 'Forms/Tag Input', - component: TagInputComponent, + component: TagInput, argTypes: { tags: { control: { @@ -18,32 +23,46 @@ export default { }, }, }, -} as ComponentMeta; +} as ComponentMeta; -export const TagInput = ({ ...args }: TagInputProps): React.ReactElement => { +export const DefaultTagInput: Story = ({ + ...args +}: TagInputProps) => { const [tags, setTags] = React.useState(['tag1', 'tag2']); return (
- +
); }; -TagInput.args = { - placeholder: 'Tag input placeholder', -} as TagInputProps; +DefaultTagInput.storyName = 'TagInput'; +DefaultTagInput.args = { + placeholder: placeholderText, +}; -export const EmailTagInput = ({ +export const DefaultEmailTagInput: Story = ({ ...args -}: EmailTagInputProps): React.ReactElement => { +}: EmailTagInputProps) => { const [tags, setTags] = React.useState(['one@test.com', 'two@test.com']); return (
- +
); }; - -EmailTagInput.args = { +DefaultEmailTagInput.storyName = 'EmailTagInput'; +DefaultEmailTagInput.args = { placeholder: 'name@company.com', -} as TagInputProps; +}; + +export const Sizes = (): JSX.Element => ( + <> + + + + + + + +); From 3ee38d13d14ad11db1f0601c124e6ca076d86e28 Mon Sep 17 00:00:00 2001 From: Marcin Sawicki Date: Thu, 28 Jul 2022 10:03:15 +0200 Subject: [PATCH 02/11] input styles update, added icon functionality, added kinds with password --- .../src/components/Input/Input.module.scss | 49 +++++++++-- .../src/components/Input/Input.stories.tsx | 34 ++++++-- .../src/components/Input/Input.tsx | 84 +++++++++++++++---- 3 files changed, 138 insertions(+), 29 deletions(-) diff --git a/packages/react-components/src/components/Input/Input.module.scss b/packages/react-components/src/components/Input/Input.module.scss index 1897e0a0f..7235a2085 100644 --- a/packages/react-components/src/components/Input/Input.module.scss +++ b/packages/react-components/src/components/Input/Input.module.scss @@ -1,12 +1,39 @@ .input { + align-items: center; background: var(--surface-basic-default); border: 1px solid var(--border-default); border-radius: 4px; box-sizing: border-box; color: var(--content-default); + display: flex; font-size: 15px; line-height: 22px; outline: none; + padding: 5px 12px; + + &:hover { + border-color: var(--border-hover); + } + + &--focused, + &--focused:hover { + border-color: var(--color-action-default); + } + + &--disabled, + &--disabled:hover { + background-color: var(--surface-basic-disabled); + border-color: var(--border-disabled); + } + + input { + background: none; + border: 0; + color: var(--content-default); + outline: none; + padding: 0; + width: 100%; + } &::placeholder { color: var(--content-disabled); @@ -22,24 +49,28 @@ color: var(--content-disabled); } - &--error { + &--error, + &--error:hover { border-color: var(--color-negative-default); } - &--xsmall { - height: 24px; - padding: 1px 4px; - } - &--small { + &--compact { height: 32px; - padding: 4px 8px; } + &--medium { height: 36px; - padding: 6px 8px; } + &--large { height: 40px; - padding: 8px; + } + + &__icon { + margin-right: 9px; + + &--disabled { + color: var(--content-disabled); + } } } diff --git a/packages/react-components/src/components/Input/Input.stories.tsx b/packages/react-components/src/components/Input/Input.stories.tsx index 70f0b1aaa..cfdf8147e 100644 --- a/packages/react-components/src/components/Input/Input.stories.tsx +++ b/packages/react-components/src/components/Input/Input.stories.tsx @@ -1,8 +1,10 @@ import * as React from 'react'; import { ComponentMeta, Story } from '@storybook/react'; -import { StoryDescriptor } from '../../stories/components/StoryDescriptor'; +import * as MaterialIcons from '@livechat/design-system-icons/react/material'; +import { StoryDescriptor } from '../../stories/components/StoryDescriptor'; +import { Icon } from '../Icon'; import { Input, InputProps } from './Input'; const placeholderText = 'Placeholder text'; @@ -10,6 +12,9 @@ const placeholderText = 'Placeholder text'; export default { title: 'Forms/Input', component: Input, + argTypes: { + onChange: { action: 'changed' }, + }, } as ComponentMeta; export const Default: Story = (args: InputProps) => ( @@ -24,11 +29,8 @@ Default.args = { export const Sizes = (): JSX.Element => ( <> - - - - - + + @@ -49,3 +51,23 @@ export const States = (): JSX.Element => ( ); + +export const Kinds = (): JSX.Element => ( + <> + + + + + + + +); + +export const WithIcon = (): JSX.Element => ( + <> + } + placeholder={placeholderText} + /> + +); diff --git a/packages/react-components/src/components/Input/Input.tsx b/packages/react-components/src/components/Input/Input.tsx index db6cca22b..55cc88400 100644 --- a/packages/react-components/src/components/Input/Input.tsx +++ b/packages/react-components/src/components/Input/Input.tsx @@ -1,34 +1,90 @@ import * as React from 'react'; import cx from 'clsx'; +import { + VisibilityOn as VisibilityOnIcon, + VisibilityOff as VisibilityOffIcon, +} from '@livechat/design-system-icons/react/material'; + import styles from './Input.module.scss'; +import { Button } from '../Button'; +import { Icon } from '../Icon'; -type InputSize = 'xsmall' | 'small' | 'medium' | 'large'; +type InputSize = 'compact' | 'medium' | 'large'; export interface InputProps extends React.HTMLAttributes { size?: InputSize | undefined; error?: boolean | undefined; disabled?: boolean | undefined; + kind?: 'text' | 'password'; + icon?: React.ReactElement; } const baseClass = 'input'; export const Input = React.forwardRef( - ({ size = 'medium', error = false, className, ...inputProps }, ref) => { + ( + { + size = 'medium', + error = false, + disabled, + kind = 'text', + icon = null, + className, + ...inputProps + }, + ref + ) => { + const [isFocused, setIsFocused] = React.useState(false); + const [isPasswordVisible, setIsPasswordVisible] = React.useState(false); + + const mergedClassNames = cx( + className, + styles[baseClass], + styles[`${baseClass}--${size}`], + { + [styles[`${baseClass}--disabled`]]: disabled, + [styles[`${baseClass}--focused`]]: isFocused, + [styles[`${baseClass}--error`]]: error, + } + ); + return ( - + {icon && + React.cloneElement(icon, { + className: cx(styles[`${baseClass}__icon`], { + [styles[`${baseClass}__icon--disabled`]]: disabled, + }), + })} + setIsFocused(true)} + onBlur={() => setIsFocused(false)} + disabled={disabled} + {...inputProps} + /> + {kind === 'password' && ( +