From 3f9b3565b09e7beb112a96ecc5828c9c7dbd65bb Mon Sep 17 00:00:00 2001 From: Michael Marszalek Date: Mon, 27 Jun 2022 15:09:20 +0200 Subject: [PATCH 01/20] =?UTF-8?q?=F0=9F=9A=A7=20WIP?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../HelperText/HelperText.token.ts | 59 +++++++++++++++++ .../InputWrapper/HelperText/HelperText.tsx | 47 ++++++++++++++ .../InputWrapper/HelperText/index.ts | 1 + .../components/InputWrapper/InputWrapper.tsx | 64 +++++++++++++++++++ .../src/components/InputWrapper/index.tsx | 1 + 5 files changed, 172 insertions(+) create mode 100644 packages/eds-core-react/src/components/InputWrapper/HelperText/HelperText.token.ts create mode 100644 packages/eds-core-react/src/components/InputWrapper/HelperText/HelperText.tsx create mode 100644 packages/eds-core-react/src/components/InputWrapper/HelperText/index.ts create mode 100644 packages/eds-core-react/src/components/InputWrapper/InputWrapper.tsx create mode 100644 packages/eds-core-react/src/components/InputWrapper/index.tsx diff --git a/packages/eds-core-react/src/components/InputWrapper/HelperText/HelperText.token.ts b/packages/eds-core-react/src/components/InputWrapper/HelperText/HelperText.token.ts new file mode 100644 index 0000000000..72c8c314f4 --- /dev/null +++ b/packages/eds-core-react/src/components/InputWrapper/HelperText/HelperText.token.ts @@ -0,0 +1,59 @@ +import { tokens } from '@equinor/eds-tokens' +import type { Spacing, Typography } from '@equinor/eds-tokens' + +const { + colors, + spacings: { comfortable }, + typography, +} = tokens + +export type HelperTextProps = { + background: string + typography: Typography + spacings: { + comfortable: Spacing + compact: Spacing + } +} + +export const helperText: HelperTextProps = { + background: colors.ui.background__light.hex, + typography: typography.input.helper, + spacings: { + comfortable: { + left: comfortable.small, + right: comfortable.small, + top: comfortable.small, + bottom: '6px', + }, + compact: { + left: comfortable.small, + right: comfortable.small, + top: comfortable.xx_small, + bottom: '6px', + }, + }, +} + +const colorVariants = { + default: { + color: colors.text.static_icons__tertiary.hex, + disabledColor: colors.interactive.disabled__text.hex, + focusColor: colors.text.static_icons__tertiary.hex, + }, + error: { + color: colors.interactive.danger__text.hex, + disabledColor: colors.interactive.disabled__text.hex, + focusColor: colors.interactive.danger__hover.hex, + }, + warning: { + color: colors.interactive.warning__text.hex, + disabledColor: colors.interactive.disabled__text.hex, + focusColor: colors.interactive.warning__hover.hex, + }, + success: { + color: colors.interactive.success__text.hex, + disabledColor: colors.interactive.disabled__text.hex, + focusColor: colors.interactive.success__hover.hex, + }, +} diff --git a/packages/eds-core-react/src/components/InputWrapper/HelperText/HelperText.tsx b/packages/eds-core-react/src/components/InputWrapper/HelperText/HelperText.tsx new file mode 100644 index 0000000000..f740e14516 --- /dev/null +++ b/packages/eds-core-react/src/components/InputWrapper/HelperText/HelperText.tsx @@ -0,0 +1,47 @@ +import { ReactNode, forwardRef } from 'react' +import styled from 'styled-components' +import { typographyTemplate } from '@equinor/eds-utils' +import { helperText as tokens } from './HelperText.token' +import { Icon } from '../../Icon' +import type { Spacing } from '@equinor/eds-tokens' + +type VariationProps = { + isFocused?: boolean + isDisabled?: boolean +} + +type StyledProps = { + spacings?: Spacing +} + +const Container = styled.div` + display: flex; + align-items: flex-start; + margin-top: ${({ spacings }) => spacings.top}; +` +const Text = styled.p` + ${typographyTemplate(tokens.typography)} + margin: 0 0 0 ${({ spacings }) => spacings.left}; +` + +type HelperTextProps = { + /** Helper text */ + text?: string + /** Icon */ + icon?: ReactNode + /** Disabled */ + disabled?: boolean +} + +const TextfieldHelperText = forwardRef( + function TextfieldHelperText({ text, icon, ...rest }, ref) { + return ( + + {icon && {icon}} + {text} + + ) + }, +) + +export { TextfieldHelperText as HelperText } diff --git a/packages/eds-core-react/src/components/InputWrapper/HelperText/index.ts b/packages/eds-core-react/src/components/InputWrapper/HelperText/index.ts new file mode 100644 index 0000000000..23c77d008a --- /dev/null +++ b/packages/eds-core-react/src/components/InputWrapper/HelperText/index.ts @@ -0,0 +1 @@ +export { HelperText } from './HelperText' diff --git a/packages/eds-core-react/src/components/InputWrapper/InputWrapper.tsx b/packages/eds-core-react/src/components/InputWrapper/InputWrapper.tsx new file mode 100644 index 0000000000..49194a5325 --- /dev/null +++ b/packages/eds-core-react/src/components/InputWrapper/InputWrapper.tsx @@ -0,0 +1,64 @@ +import { ReactNode, forwardRef } from 'react' +import styled, { css } from 'styled-components' +import { Label } from '../Label' +import { useEds } from './../EdsProvider' + +type InputWrapperType = { + isFocused?: boolean + isDisabled?: boolean + isReadOnly?: boolean + variant?: string + inputIcon?: ReactNode + unit?: string + multiline?: boolean +} + +export const Box = styled.div`` + +type UnitType = { + isDisabled: boolean +} + +const Unit = styled.span` + // TODO Typography + /* Yes, we don't like magic numbers, but if you have both unit and icon, + the unit is slightly off due to line-height and font */ + display: inline-block; + margin-top: 3px; +` + +const Adornments = styled.div` + display: flex; + align-items: center; + justify-content: center; + height: 100%; + align-self: flex-start; +` + +type InputWrapperProps = { + /** Label */ + label: string + /** Meta */ + meta: string + /** Disabled state */ + disabled?: boolean + + /** Read Only */ + readOnly?: boolean +} + +export const InputWrapper = forwardRef( + function InputWrapper( + { disabled, readOnly, label, meta, children, ...other }, + ref, + ) { + const { density } = useEds() + + return ( + + + ) + }, +) diff --git a/packages/eds-core-react/src/components/InputWrapper/index.tsx b/packages/eds-core-react/src/components/InputWrapper/index.tsx new file mode 100644 index 0000000000..7472ad1d6e --- /dev/null +++ b/packages/eds-core-react/src/components/InputWrapper/index.tsx @@ -0,0 +1 @@ +export { InputWrapper } from './InputWrapper' From c96d13e92c66b6f4c342b0641207feeef4d7e5d1 Mon Sep 17 00:00:00 2001 From: Michael Marszalek Date: Tue, 28 Jun 2022 10:02:50 +0200 Subject: [PATCH 02/20] =?UTF-8?q?=F0=9F=93=9D=20Added=20story?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../InputWrapper/InputWrapper.stories.tsx | 14 +++++++++++ .../components/InputWrapper/InputWrapper.tsx | 24 +++++++------------ .../src/components/InputWrapper/index.tsx | 2 +- packages/eds-core-react/src/index.ts | 1 + 4 files changed, 25 insertions(+), 16 deletions(-) create mode 100644 packages/eds-core-react/src/components/InputWrapper/InputWrapper.stories.tsx diff --git a/packages/eds-core-react/src/components/InputWrapper/InputWrapper.stories.tsx b/packages/eds-core-react/src/components/InputWrapper/InputWrapper.stories.tsx new file mode 100644 index 0000000000..00d257bdc5 --- /dev/null +++ b/packages/eds-core-react/src/components/InputWrapper/InputWrapper.stories.tsx @@ -0,0 +1,14 @@ +import { InputWrapper, InputWrapperProps, Input } from '../..' +import { Story } from '@storybook/react/types-6-0' +import { ComponentMeta } from '@storybook/react' + +export default { + title: 'Inputs/InputWrapper', + component: InputWrapper, +} as ComponentMeta + +export const Introduction: Story = (args) => ( + + + +) diff --git a/packages/eds-core-react/src/components/InputWrapper/InputWrapper.tsx b/packages/eds-core-react/src/components/InputWrapper/InputWrapper.tsx index 49194a5325..02e2aafd21 100644 --- a/packages/eds-core-react/src/components/InputWrapper/InputWrapper.tsx +++ b/packages/eds-core-react/src/components/InputWrapper/InputWrapper.tsx @@ -1,19 +1,14 @@ -import { ReactNode, forwardRef } from 'react' +import { HTMLAttributes, forwardRef } from 'react' import styled, { css } from 'styled-components' import { Label } from '../Label' import { useEds } from './../EdsProvider' -type InputWrapperType = { - isFocused?: boolean - isDisabled?: boolean - isReadOnly?: boolean - variant?: string - inputIcon?: ReactNode - unit?: string - multiline?: boolean -} - -export const Box = styled.div`` +export const Box = styled.div` + display: grid; + gap: 8px; + grid-template-columns: auto; + align-items: center; +` type UnitType = { isDisabled: boolean @@ -29,13 +24,12 @@ const Unit = styled.span` const Adornments = styled.div` display: flex; - align-items: center; justify-content: center; height: 100%; align-self: flex-start; ` -type InputWrapperProps = { +export type InputWrapperProps = { /** Label */ label: string /** Meta */ @@ -45,7 +39,7 @@ type InputWrapperProps = { /** Read Only */ readOnly?: boolean -} +} & HTMLAttributes export const InputWrapper = forwardRef( function InputWrapper( diff --git a/packages/eds-core-react/src/components/InputWrapper/index.tsx b/packages/eds-core-react/src/components/InputWrapper/index.tsx index 7472ad1d6e..8099646987 100644 --- a/packages/eds-core-react/src/components/InputWrapper/index.tsx +++ b/packages/eds-core-react/src/components/InputWrapper/index.tsx @@ -1 +1 @@ -export { InputWrapper } from './InputWrapper' +export * from './InputWrapper' diff --git a/packages/eds-core-react/src/index.ts b/packages/eds-core-react/src/index.ts index 5ff66c4536..8e025e8aa9 100644 --- a/packages/eds-core-react/src/index.ts +++ b/packages/eds-core-react/src/index.ts @@ -35,4 +35,5 @@ export * from './components/Switch' export * from './components/EdsProvider' export * from './components/Paper' export * from './components/Autocomplete' +export * from './components/InputWrapper' /* eslint-enable */ From 5efa75b2fe4b3ecf119681eb70e51e67d39daf86 Mon Sep 17 00:00:00 2001 From: Michael Marszalek Date: Tue, 28 Jun 2022 15:51:19 +0200 Subject: [PATCH 03/20] wip --- .../InputWrapper/HelperText/HelperText.tsx | 4 ++++ .../components/InputWrapper/InputWrapper.tsx | 23 +++++++++++++++---- 2 files changed, 23 insertions(+), 4 deletions(-) diff --git a/packages/eds-core-react/src/components/InputWrapper/HelperText/HelperText.tsx b/packages/eds-core-react/src/components/InputWrapper/HelperText/HelperText.tsx index f740e14516..4c5d152f43 100644 --- a/packages/eds-core-react/src/components/InputWrapper/HelperText/HelperText.tsx +++ b/packages/eds-core-react/src/components/InputWrapper/HelperText/HelperText.tsx @@ -35,6 +35,10 @@ type HelperTextProps = { const TextfieldHelperText = forwardRef( function TextfieldHelperText({ text, icon, ...rest }, ref) { + if (!text) { + return null + } + return ( {icon && {icon}} diff --git a/packages/eds-core-react/src/components/InputWrapper/InputWrapper.tsx b/packages/eds-core-react/src/components/InputWrapper/InputWrapper.tsx index 02e2aafd21..80fc23fccb 100644 --- a/packages/eds-core-react/src/components/InputWrapper/InputWrapper.tsx +++ b/packages/eds-core-react/src/components/InputWrapper/InputWrapper.tsx @@ -1,6 +1,8 @@ -import { HTMLAttributes, forwardRef } from 'react' +import { HTMLAttributes, forwardRef, ReactNode } from 'react' import styled, { css } from 'styled-components' import { Label } from '../Label' +import { HelperText } from './HelperText' +import { Icon } from '../Icon' import { useEds } from './../EdsProvider' export const Box = styled.div` @@ -22,7 +24,7 @@ const Unit = styled.span` margin-top: 3px; ` -const Adornments = styled.div` +export const Adornments = styled.div` display: flex; justify-content: center; height: 100%; @@ -36,14 +38,26 @@ export type InputWrapperProps = { meta: string /** Disabled state */ disabled?: boolean - /** Read Only */ readOnly?: boolean + /** Helper text icon */ + helperIcon?: typeof Icon + /** Helper text */ + helperText?: string } & HTMLAttributes export const InputWrapper = forwardRef( function InputWrapper( - { disabled, readOnly, label, meta, children, ...other }, + { + disabled, + readOnly, + label, + meta, + children, + helperIcon, + helperText, + ...other + }, ref, ) { const { density } = useEds() @@ -52,6 +66,7 @@ export const InputWrapper = forwardRef( ) }, From dafcf19a3d95c3947eba17c8c3be40e8033983cb Mon Sep 17 00:00:00 2001 From: Michael Marszalek Date: Wed, 29 Jun 2022 14:18:28 +0200 Subject: [PATCH 04/20] =?UTF-8?q?=F0=9F=9A=A7=20WIP?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../HelperText/HelperText.token.ts | 5 +- .../InputWrapper/HelperText/HelperText.tsx | 26 +-- .../InputWrapper/InputWrapper.stories.tsx | 34 +++- .../InputWrapper/InputWrapper.tokens.ts | 180 ++++++++++++++++++ .../components/InputWrapper/InputWrapper.tsx | 83 +++++--- .../src/components/InputWrapper/index.tsx | 19 +- 6 files changed, 299 insertions(+), 48 deletions(-) create mode 100644 packages/eds-core-react/src/components/InputWrapper/InputWrapper.tokens.ts diff --git a/packages/eds-core-react/src/components/InputWrapper/HelperText/HelperText.token.ts b/packages/eds-core-react/src/components/InputWrapper/HelperText/HelperText.token.ts index 72c8c314f4..485c079ae4 100644 --- a/packages/eds-core-react/src/components/InputWrapper/HelperText/HelperText.token.ts +++ b/packages/eds-core-react/src/components/InputWrapper/HelperText/HelperText.token.ts @@ -18,7 +18,10 @@ export type HelperTextProps = { export const helperText: HelperTextProps = { background: colors.ui.background__light.hex, - typography: typography.input.helper, + typography: { + ...typography.input.helper, + color: colors.text.static_icons__tertiary.rgba, + }, spacings: { comfortable: { left: comfortable.small, diff --git a/packages/eds-core-react/src/components/InputWrapper/HelperText/HelperText.tsx b/packages/eds-core-react/src/components/InputWrapper/HelperText/HelperText.tsx index 4c5d152f43..19787ed40e 100644 --- a/packages/eds-core-react/src/components/InputWrapper/HelperText/HelperText.tsx +++ b/packages/eds-core-react/src/components/InputWrapper/HelperText/HelperText.tsx @@ -1,4 +1,4 @@ -import { ReactNode, forwardRef } from 'react' +import React, { forwardRef, useMemo, cloneElement, ReactElement } from 'react' import styled from 'styled-components' import { typographyTemplate } from '@equinor/eds-utils' import { helperText as tokens } from './HelperText.token' @@ -10,38 +10,38 @@ type VariationProps = { isDisabled?: boolean } -type StyledProps = { - spacings?: Spacing -} - -const Container = styled.div` - display: flex; - align-items: flex-start; - margin-top: ${({ spacings }) => spacings.top}; +const Container = styled.div` + display: grid; + gap: 8px; + grid-auto-flow: column; + align-items: start; + justify-content: start; + color: ${tokens.typography.color}; ` -const Text = styled.p` +const Text = styled.p` ${typographyTemplate(tokens.typography)} - margin: 0 0 0 ${({ spacings }) => spacings.left}; ` type HelperTextProps = { /** Helper text */ text?: string /** Icon */ - icon?: ReactNode + icon?: ReactElement /** Disabled */ disabled?: boolean } const TextfieldHelperText = forwardRef( function TextfieldHelperText({ text, icon, ...rest }, ref) { + const smallIcon = useMemo(() => cloneElement(icon, { size: 16 }), [icon]) + if (!text) { return null } return ( - {icon && {icon}} + {smallIcon} {text} ) diff --git a/packages/eds-core-react/src/components/InputWrapper/InputWrapper.stories.tsx b/packages/eds-core-react/src/components/InputWrapper/InputWrapper.stories.tsx index 00d257bdc5..35fa6b1649 100644 --- a/packages/eds-core-react/src/components/InputWrapper/InputWrapper.stories.tsx +++ b/packages/eds-core-react/src/components/InputWrapper/InputWrapper.stories.tsx @@ -1,14 +1,38 @@ -import { InputWrapper, InputWrapperProps, Input } from '../..' -import { Story } from '@storybook/react/types-6-0' -import { ComponentMeta } from '@storybook/react' +import { Story, ComponentMeta } from '@storybook/react' +import { accessible, dropper } from '@equinor/eds-icons' +import { InputWrapper, InputWrapperProps, Input, Icon } from '../..' +import styled from 'styled-components' export default { title: 'Inputs/InputWrapper', component: InputWrapper, } as ComponentMeta +const StrippedInput = styled(Input)` + box-shadow: none; + background: none; + padding: 0; + &:active, + &:focus { + outline: none; + } +` + export const Introduction: Story = (args) => ( - - + } + {...args} + > + left + + + right + + ) + +Introduction.args = { + helperText: 'Helper text', +} diff --git a/packages/eds-core-react/src/components/InputWrapper/InputWrapper.tokens.ts b/packages/eds-core-react/src/components/InputWrapper/InputWrapper.tokens.ts new file mode 100644 index 0000000000..28213f7eb3 --- /dev/null +++ b/packages/eds-core-react/src/components/InputWrapper/InputWrapper.tokens.ts @@ -0,0 +1,180 @@ +import { tokens } from '@equinor/eds-tokens' +import type { ComponentToken } from '@equinor/eds-tokens' +import { mergeDeepRight } from 'ramda' + +const { + colors: { + ui: { + background__light: { rgba: background }, + }, + text: { static_icons__default, static_icons__tertiary }, + interactive: { + disabled__text, + primary__resting, + danger__resting, + danger__hover, + warning__resting, + warning__hover, + success__resting, + success__hover, + }, + }, + spacings: { + comfortable: { small, x_small }, + }, + typography, + shape, +} = tokens + +export type InputToken = ComponentToken + +export const input: InputToken = { + minHeight: shape.straight.minHeight, + background, + spacings: { + left: small, + right: small, + top: '6px', + bottom: '6px', + }, + typography: { + ...typography.input.text, + color: static_icons__default.rgba, + }, + entities: { + placeholder: { + typography: { + color: static_icons__tertiary.rgba, + }, + }, + + adornment: { + typography: { + ...typography.input.label, + color: static_icons__tertiary.rgba, + }, + states: { + disabled: { + typography: { + color: disabled__text.rgba, + }, + }, + }, + }, + }, + states: { + disabled: { + typography: { + color: disabled__text.rgba, + }, + }, + readOnly: { + background: 'transparent', + boxShadow: 'none', + }, + active: { + outline: { + type: 'outline', + color: 'transparent', + width: '1px', + style: 'solid', + offset: '0px', + }, + }, + focus: { + outline: { + type: 'outline', + width: '2px', + color: primary__resting.rgba, + style: 'solid', + offset: '0px', + }, + }, + }, + boxShadow: 'inset 0px -1px 0px 0px ' + static_icons__tertiary.rgba, + modes: { + compact: { + minHeight: shape._modes.compact.straight.minHeight, + spacings: { + left: x_small, + right: x_small, + top: x_small, + bottom: x_small, + }, + }, + }, +} + +export const error: InputToken = mergeDeepRight(input, { + boxShadow: 'inset 0px -1px 0px 0px transparent', + states: { + active: { + outline: { + type: 'outline', + color: danger__resting.rgba, + width: '1px', + style: 'solid', + offset: '0px', + }, + }, + focus: { + outline: { + type: 'outline', + width: '2px', + color: danger__hover.rgba, + style: 'solid', + offset: '0px', + }, + }, + }, +}) + +export const warning: InputToken = mergeDeepRight(input, { + boxShadow: 'inset 0px -1px 0px 0px transparent', + states: { + active: { + outline: { + type: 'outline', + color: warning__resting.rgba, + width: '1px', + style: 'solid', + offset: '0px', + }, + }, + focus: { + outline: { + type: 'outline', + width: '2px', + color: warning__hover.rgba, + style: 'solid', + offset: '0px', + }, + }, + }, +}) + +export const success: InputToken = mergeDeepRight(input, { + boxShadow: 'inset 0px -1px 0px 0px transparent', + states: { + active: { + outline: { + type: 'outline', + color: success__resting.rgba, + width: '1px', + style: 'solid', + offset: '0px', + }, + }, + focus: { + outline: { + type: 'outline', + width: '2px', + color: success__hover.rgba, + style: 'solid', + offset: '0px', + }, + }, + }, +}) + +export const inputToken = { input, error, warning, success } diff --git a/packages/eds-core-react/src/components/InputWrapper/InputWrapper.tsx b/packages/eds-core-react/src/components/InputWrapper/InputWrapper.tsx index 80fc23fccb..219001f86f 100644 --- a/packages/eds-core-react/src/components/InputWrapper/InputWrapper.tsx +++ b/packages/eds-core-react/src/components/InputWrapper/InputWrapper.tsx @@ -1,35 +1,59 @@ -import { HTMLAttributes, forwardRef, ReactNode } from 'react' -import styled, { css } from 'styled-components' +import { HTMLAttributes, forwardRef, ReactElement } from 'react' +import styled, { css, ThemeProvider } from 'styled-components' import { Label } from '../Label' import { HelperText } from './HelperText' -import { Icon } from '../Icon' import { useEds } from './../EdsProvider' +import { inputToken } from './InputWrapper.tokens' +import { + outlineTemplate, + useToken, + spacingsTemplate, + typographyTemplate, +} from '@equinor/eds-utils' -export const Box = styled.div` +const Container = styled.div` display: grid; gap: 8px; - grid-template-columns: auto; - align-items: center; ` -type UnitType = { - isDisabled: boolean -} +const Field = styled.div(({ theme }) => { + const { + states: { + focus: { outline: focusOutline }, + active: { outline: activeOutline }, + disabled, + readOnly, + }, + boxShadow, + } = theme -const Unit = styled.span` - // TODO Typography - /* Yes, we don't like magic numbers, but if you have both unit and icon, - the unit is slightly off due to line-height and font */ - display: inline-block; - margin-top: 3px; -` + return css` + display: flex; + flex-direction: row; + column-gap: 8px; + background: ${theme.background}; + height: ${theme.minHeight}; + box-shadow: ${boxShadow}; -export const Adornments = styled.div` - display: flex; - justify-content: center; - height: 100%; - align-self: flex-start; -` + &:focus-within { + ${outlineTemplate(focusOutline)} + box-shadow: none; + } + ` +}) + +export const Adornments = styled.div(({ theme }) => { + return css` + display: flex; + column-gap: 8px; + justify-content: center; + align-items: center; + width: fit-content; + + ${spacingsTemplate(theme.spacings)} + ${typographyTemplate(theme.entities.adornment.typography)} + ` +}) export type InputWrapperProps = { /** Label */ @@ -41,7 +65,7 @@ export type InputWrapperProps = { /** Read Only */ readOnly?: boolean /** Helper text icon */ - helperIcon?: typeof Icon + helperIcon?: ReactElement /** Helper text */ helperText?: string } & HTMLAttributes @@ -61,13 +85,16 @@ export const InputWrapper = forwardRef( ref, ) { const { density } = useEds() + const token = inputToken.input return ( - - + + + + ) }, ) diff --git a/packages/eds-core-react/src/components/InputWrapper/index.tsx b/packages/eds-core-react/src/components/InputWrapper/index.tsx index 8099646987..cb1329bedb 100644 --- a/packages/eds-core-react/src/components/InputWrapper/index.tsx +++ b/packages/eds-core-react/src/components/InputWrapper/index.tsx @@ -1 +1,18 @@ -export * from './InputWrapper' +import { + InputWrapper as BaseComponent, + Adornments, + InputWrapperProps, +} from './InputWrapper' + +type InputWrapperCompoundProps = typeof BaseComponent & { + Adornments: typeof Adornments +} + +const InputWrapper = BaseComponent as InputWrapperCompoundProps + +InputWrapper.Adornments = Adornments + +InputWrapper.Adornments.displayName = 'InputWrapper.Adornments' + +export { InputWrapper } +export type { InputWrapperProps } From da22d9df2da156be3b4b4f0448e08571a461c175 Mon Sep 17 00:00:00 2001 From: Michael Marszalek Date: Wed, 29 Jun 2022 14:47:04 +0200 Subject: [PATCH 05/20] =?UTF-8?q?=F0=9F=9A=A7=20WIP?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../InputWrapper/HelperText/HelperText.tsx | 4 +--- .../InputWrapper/InputWrapper.stories.tsx | 21 ++++++++++++++----- .../components/InputWrapper/InputWrapper.tsx | 4 ++-- 3 files changed, 19 insertions(+), 10 deletions(-) diff --git a/packages/eds-core-react/src/components/InputWrapper/HelperText/HelperText.tsx b/packages/eds-core-react/src/components/InputWrapper/HelperText/HelperText.tsx index 19787ed40e..8becea925c 100644 --- a/packages/eds-core-react/src/components/InputWrapper/HelperText/HelperText.tsx +++ b/packages/eds-core-react/src/components/InputWrapper/HelperText/HelperText.tsx @@ -33,15 +33,13 @@ type HelperTextProps = { const TextfieldHelperText = forwardRef( function TextfieldHelperText({ text, icon, ...rest }, ref) { - const smallIcon = useMemo(() => cloneElement(icon, { size: 16 }), [icon]) - if (!text) { return null } return ( - {smallIcon} + {icon} {text} ) diff --git a/packages/eds-core-react/src/components/InputWrapper/InputWrapper.stories.tsx b/packages/eds-core-react/src/components/InputWrapper/InputWrapper.stories.tsx index 35fa6b1649..68b557c45c 100644 --- a/packages/eds-core-react/src/components/InputWrapper/InputWrapper.stories.tsx +++ b/packages/eds-core-react/src/components/InputWrapper/InputWrapper.stories.tsx @@ -1,6 +1,6 @@ import { Story, ComponentMeta } from '@storybook/react' -import { accessible, dropper } from '@equinor/eds-icons' -import { InputWrapper, InputWrapperProps, Input, Icon } from '../..' +import { accessible, dropper, clear, search } from '@equinor/eds-icons' +import { InputWrapper, InputWrapperProps, Input, Icon, Button } from '../..' import styled from 'styled-components' export default { @@ -18,17 +18,28 @@ const StrippedInput = styled(Input)` } ` +const SmallButton = styled(Button)` + height: 24px; + width: 24px; +` + export const Introduction: Story = (args) => ( } + meta="meta tag" + helperIcon={} {...args} > - left + + + right - + + + + ) diff --git a/packages/eds-core-react/src/components/InputWrapper/InputWrapper.tsx b/packages/eds-core-react/src/components/InputWrapper/InputWrapper.tsx index 219001f86f..5308f64ff4 100644 --- a/packages/eds-core-react/src/components/InputWrapper/InputWrapper.tsx +++ b/packages/eds-core-react/src/components/InputWrapper/InputWrapper.tsx @@ -57,9 +57,9 @@ export const Adornments = styled.div(({ theme }) => { export type InputWrapperProps = { /** Label */ - label: string + label?: string /** Meta */ - meta: string + meta?: string /** Disabled state */ disabled?: boolean /** Read Only */ From 411f134a18266af6f7fca95158fe1f68101c0bc7 Mon Sep 17 00:00:00 2001 From: Michael Marszalek Date: Thu, 30 Jun 2022 11:31:11 +0200 Subject: [PATCH 06/20] =?UTF-8?q?=F0=9F=9A=A7=20wip?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../InputWrapper/HelperText/HelperText.tsx | 12 ++++++++---- .../components/InputWrapper/InputWrapper.stories.tsx | 2 +- .../src/components/InputWrapper/InputWrapper.tsx | 9 +++------ 3 files changed, 12 insertions(+), 11 deletions(-) diff --git a/packages/eds-core-react/src/components/InputWrapper/HelperText/HelperText.tsx b/packages/eds-core-react/src/components/InputWrapper/HelperText/HelperText.tsx index 8becea925c..77513062ac 100644 --- a/packages/eds-core-react/src/components/InputWrapper/HelperText/HelperText.tsx +++ b/packages/eds-core-react/src/components/InputWrapper/HelperText/HelperText.tsx @@ -1,9 +1,13 @@ -import React, { forwardRef, useMemo, cloneElement, ReactElement } from 'react' +import { + forwardRef, + ReactNode, + useMemo, + cloneElement, + ReactElement, +} from 'react' import styled from 'styled-components' import { typographyTemplate } from '@equinor/eds-utils' import { helperText as tokens } from './HelperText.token' -import { Icon } from '../../Icon' -import type { Spacing } from '@equinor/eds-tokens' type VariationProps = { isFocused?: boolean @@ -26,7 +30,7 @@ type HelperTextProps = { /** Helper text */ text?: string /** Icon */ - icon?: ReactElement + icon?: ReactNode /** Disabled */ disabled?: boolean } diff --git a/packages/eds-core-react/src/components/InputWrapper/InputWrapper.stories.tsx b/packages/eds-core-react/src/components/InputWrapper/InputWrapper.stories.tsx index 68b557c45c..3b13ee3722 100644 --- a/packages/eds-core-react/src/components/InputWrapper/InputWrapper.stories.tsx +++ b/packages/eds-core-react/src/components/InputWrapper/InputWrapper.stories.tsx @@ -33,7 +33,7 @@ export const Introduction: Story = (args) => ( - + right diff --git a/packages/eds-core-react/src/components/InputWrapper/InputWrapper.tsx b/packages/eds-core-react/src/components/InputWrapper/InputWrapper.tsx index 5308f64ff4..93eab1d531 100644 --- a/packages/eds-core-react/src/components/InputWrapper/InputWrapper.tsx +++ b/packages/eds-core-react/src/components/InputWrapper/InputWrapper.tsx @@ -1,4 +1,4 @@ -import { HTMLAttributes, forwardRef, ReactElement } from 'react' +import { HTMLAttributes, forwardRef, ReactElement, ReactNode } from 'react' import styled, { css, ThemeProvider } from 'styled-components' import { Label } from '../Label' import { HelperText } from './HelperText' @@ -20,9 +20,6 @@ const Field = styled.div(({ theme }) => { const { states: { focus: { outline: focusOutline }, - active: { outline: activeOutline }, - disabled, - readOnly, }, boxShadow, } = theme @@ -65,7 +62,7 @@ export type InputWrapperProps = { /** Read Only */ readOnly?: boolean /** Helper text icon */ - helperIcon?: ReactElement + helperIcon?: ReactNode /** Helper text */ helperText?: string } & HTMLAttributes @@ -85,7 +82,7 @@ export const InputWrapper = forwardRef( ref, ) { const { density } = useEds() - const token = inputToken.input + const token = useToken({ density }, inputToken.input) return ( From f8a5603a14c34ed32dd2e8dae0f6a0767d8e4bcd Mon Sep 17 00:00:00 2001 From: Michael Marszalek Date: Wed, 6 Jul 2022 14:46:31 +0200 Subject: [PATCH 07/20] =?UTF-8?q?=F0=9F=9A=9A=20Moved=20over=20`Input`=20a?= =?UTF-8?q?dornment=20changes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/components/Input/Input.docs.mdx | 7 +- .../src/components/Input/Input.stories.tsx | 94 +++++++++++- .../src/components/Input/Input.tokens.ts | 131 ++++++++++------- .../src/components/Input/Input.tsx | 137 +++++++++++++----- packages/eds-tokens/src/types/component.ts | 7 +- 5 files changed, 281 insertions(+), 95 deletions(-) diff --git a/packages/eds-core-react/src/components/Input/Input.docs.mdx b/packages/eds-core-react/src/components/Input/Input.docs.mdx index 268f96ba62..0267ac8c02 100644 --- a/packages/eds-core-react/src/components/Input/Input.docs.mdx +++ b/packages/eds-core-react/src/components/Input/Input.docs.mdx @@ -52,4 +52,9 @@ It's important to link the `Input` to the corresponding label. Compact `Input` using `EdsProvider`. - \ No newline at end of file + + +### With Adornments + + + diff --git a/packages/eds-core-react/src/components/Input/Input.stories.tsx b/packages/eds-core-react/src/components/Input/Input.stories.tsx index 9bd943488a..3f34a7c23b 100644 --- a/packages/eds-core-react/src/components/Input/Input.stories.tsx +++ b/packages/eds-core-react/src/components/Input/Input.stories.tsx @@ -1,9 +1,12 @@ import { useState, useEffect } from 'react' +import { Story, ComponentMeta } from '@storybook/react' +import { anchor } from '@equinor/eds-icons' import { Input, InputProps, Label, EdsProvider, Density } from '../..' -import { Story } from '@storybook/react/types-6-0' -import { ComponentMeta } from '@storybook/react' +import styled from 'styled-components' import { Stack } from './../../../.storybook/components' import page from './Input.docs.mdx' +import { Button } from '../Button' +import { Icon } from '../Icon' export default { title: 'Inputs/Input', @@ -198,3 +201,90 @@ Compact.decorators = [ ) }, ] + +const SmallButton = styled(Button)` + height: 24px; + width: 24px; +` + +export const WithAdornments: Story = () => { + return ( + + + ) +} diff --git a/packages/eds-core-react/src/components/Input/Input.tokens.ts b/packages/eds-core-react/src/components/Input/Input.tokens.ts index f4958a82cf..80732915a5 100644 --- a/packages/eds-core-react/src/components/Input/Input.tokens.ts +++ b/packages/eds-core-react/src/components/Input/Input.tokens.ts @@ -29,7 +29,7 @@ const { export type InputToken = ComponentToken export const input: InputToken = { - minHeight: shape.straight.minHeight, + height: shape.straight.minHeight, background, spacings: { left: small, @@ -41,12 +41,32 @@ export const input: InputToken = { ...typography.input.text, color: static_icons__default.rgba, }, + outline: { + type: 'outline', + color: 'transparent', + width: '1px', + style: 'solid', + offset: '0px', + }, entities: { placeholder: { typography: { color: static_icons__tertiary.rgba, }, }, + adornment: { + typography: { + ...typography.input.label, + color: static_icons__tertiary.rgba, + }, + states: { + disabled: { + typography: { + color: disabled__text.rgba, + }, + }, + }, + }, }, states: { disabled: { @@ -58,15 +78,7 @@ export const input: InputToken = { background: 'transparent', boxShadow: 'none', }, - active: { - outline: { - type: 'outline', - color: 'transparent', - width: '1px', - style: 'solid', - offset: '0px', - }, - }, + active: {}, focus: { outline: { type: 'outline', @@ -92,72 +104,87 @@ export const input: InputToken = { } export const error: InputToken = mergeDeepRight(input, { - boxShadow: 'inset 0px -1px 0px 0px transparent', + boxShadow: 'none', + outline: { + color: danger__resting.rgba, + }, states: { - active: { - outline: { - type: 'outline', - color: danger__resting.rgba, - width: '1px', - style: 'solid', - offset: '0px', - }, - }, focus: { outline: { - type: 'outline', - width: '2px', color: danger__hover.rgba, - style: 'solid', - offset: '0px', + }, + }, + }, + entities: { + adornment: { + typography: { + ...typography.input.label, + color: danger__resting.rgba, + }, + states: { + focus: { + outline: { + color: danger__hover.rgba, + }, + }, }, }, }, }) export const warning: InputToken = mergeDeepRight(input, { - boxShadow: 'inset 0px -1px 0px 0px transparent', + boxShadow: 'none', + outline: { + color: warning__resting.rgba, + }, states: { - active: { - outline: { - type: 'outline', - color: warning__resting.rgba, - width: '1px', - style: 'solid', - offset: '0px', - }, - }, focus: { outline: { - type: 'outline', - width: '2px', color: warning__hover.rgba, - style: 'solid', - offset: '0px', + }, + }, + }, + entities: { + adornment: { + typography: { + ...typography.input.label, + color: warning__resting.rgba, + }, + states: { + focus: { + outline: { + color: warning__hover.rgba, + }, + }, }, }, }, }) export const success: InputToken = mergeDeepRight(input, { - boxShadow: 'inset 0px -1px 0px 0px transparent', + boxShadow: 'none', + outline: { + color: success__resting.rgba, + }, states: { - active: { - outline: { - type: 'outline', - color: success__resting.rgba, - width: '1px', - style: 'solid', - offset: '0px', - }, - }, focus: { outline: { - type: 'outline', - width: '2px', color: success__hover.rgba, - style: 'solid', - offset: '0px', + }, + }, + }, + entities: { + adornment: { + typography: { + ...typography.input.label, + color: success__resting.rgba, + }, + states: { + focus: { + outline: { + color: success__hover.rgba, + }, + }, }, }, }, diff --git a/packages/eds-core-react/src/components/Input/Input.tsx b/packages/eds-core-react/src/components/Input/Input.tsx index 848e329597..19e1daa51a 100644 --- a/packages/eds-core-react/src/components/Input/Input.tsx +++ b/packages/eds-core-react/src/components/Input/Input.tsx @@ -1,4 +1,4 @@ -import { InputHTMLAttributes, forwardRef } from 'react' +import { InputHTMLAttributes, forwardRef, ReactNode } from 'react' import styled, { css, ThemeProvider } from 'styled-components' import { inputToken as tokens } from './Input.tokens' import type { InputToken } from './Input.tokens' @@ -11,62 +11,90 @@ import { import type { Variants } from '../TextField/types' import { useEds } from '../EdsProvider' -const StyledInput = styled.input(({ theme }: StyledProps) => { - const { - states: { - focus: { outline: focusOutline }, - active: { outline: activeOutline }, - disabled, - readOnly, - }, - boxShadow, - } = theme +const Container = styled.div(({ theme, disabled, readOnly }: StyledProps) => { + const { states, entities } = theme return css` - width: 100%; + --eds-input-adornment-color: ${entities.adornment.typography.color}; + + display: flex; + flex-direction: row; + column-gap: 8px; + border: none; box-sizing: border-box; - margin: 0; - appearance: none; + height: ${theme.height}; + box-shadow: ${theme.boxShadow}; background: ${theme.background}; - border: none; - height: ${theme.minHeight}; - box-shadow: ${boxShadow}; - - ${outlineTemplate(activeOutline)} + ${outlineTemplate(theme.outline)} + ${spacingsTemplate(theme.spacings)} ${typographyTemplate(theme.typography)} - ${spacingsTemplate(theme.spacings)}; - &::placeholder { - color: ${theme.entities.placeholder.typography.color}; - } - &:active, - &:focus { - outline-offset: 0; + &:focus-within { + --eds-input-adornment-color: ${entities.adornment?.states.focus?.outline + .color}; + box-shadow: none; - ${outlineTemplate(focusOutline)} + ${outlineTemplate(states.focus.outline)} } - &:disabled { - color: ${disabled.typography.color}; + ${disabled && + css` + --eds-input-adornment-color: ${states.disabled.typography.color}; + color: ${states.disabled.typography.color}; cursor: not-allowed; box-shadow: none; outline: none; - &:focus, - &:active { + &:focus-within { outline: none; } + `} + ${readOnly && + css({ + background: states.readOnly.background, + boxShadow: states.readOnly.boxShadow, + })} + ` +}) + +const StyledInput = styled.input(({ theme }: StyledProps) => { + const { + states: { disabled }, + } = theme + + return css` + width: 100%; + border: none; + background: transparent; + ${typographyTemplate(theme.typography)} + outline: none; + + &::placeholder { + color: ${theme.entities.placeholder.typography.color}; } - &[readOnly] { - background: ${readOnly.background}; - box-shadow: ${readOnly.boxShadow}; + + &:disabled { + color: ${disabled.typography.color}; + cursor: not-allowed; } ` }) +export const Adornments = styled.div(({ theme }: StyledProps) => { + return css` + display: flex; + column-gap: 8px; + justify-content: center; + align-items: center; + width: fit-content; + ${typographyTemplate(theme.entities.adornment.typography)} + color: var(--eds-input-adornment-color); + ` +}) + type StyledProps = { theme: InputToken -} +} & Required> export type InputProps = { /** Placeholder */ @@ -79,10 +107,24 @@ export type InputProps = { type?: string /** Read Only */ readOnly?: boolean + /** Left adornments */ + leftAdornments?: ReactNode + /** Right adornments */ + rightAdornments?: ReactNode } & InputHTMLAttributes export const Input = forwardRef(function Input( - { variant = 'default', disabled = false, type = 'text', ...other }, + { + variant = 'default', + disabled = false, + type = 'text', + leftAdornments, + rightAdornments, + readOnly, + className, + style, + ...other + }, ref, ) { const actualVariant = variant === 'default' ? 'input' : variant @@ -94,12 +136,33 @@ export const Input = forwardRef(function Input( ref, type, disabled, + readOnly, ...other, } + const containerProps = { + disabled, + readOnly, + className, + style, + } + + const adornmentProps = { + disabled, + readOnly, + } + return ( - + + {leftAdornments ? ( + {leftAdornments} + ) : null} + + {rightAdornments ? ( + {rightAdornments} + ) : null} + ) }) diff --git a/packages/eds-tokens/src/types/component.ts b/packages/eds-tokens/src/types/component.ts index c4d14cc0e8..b4596a7d88 100644 --- a/packages/eds-tokens/src/types/component.ts +++ b/packages/eds-tokens/src/types/component.ts @@ -22,11 +22,12 @@ export type ComponentToken = { border?: Borders typography?: Partial clickbound?: Clickbound + outline?: Outline states?: { - active?: ComponentToken & { outline?: Outline } + active?: ComponentToken disabled?: ComponentToken - readOnly?: ComponentToken & { outline?: Outline } - focus?: ComponentToken & { outline?: Outline } + readOnly?: ComponentToken + focus?: ComponentToken hover?: ComponentToken pressed?: ComponentToken & { pressed?: Pressed } } From 050717bf361f26d102a7b2178a65127c3ce42ef2 Mon Sep 17 00:00:00 2001 From: Michael Marszalek Date: Wed, 6 Jul 2022 14:47:07 +0200 Subject: [PATCH 08/20] =?UTF-8?q?=E2=99=BB=EF=B8=8F=20Added=20`OldInput`?= =?UTF-8?q?=20for=20interim=20development?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/components/OldInput/Input.docs.mdx | 55 ++++++ .../src/components/OldInput/Input.stories.tsx | 141 +++++++++++++++ .../src/components/OldInput/Input.test.tsx | 124 +++++++++++++ .../src/components/OldInput/Input.tokens.ts | 166 ++++++++++++++++++ .../src/components/OldInput/Input.tsx | 105 +++++++++++ .../__snapshots__/Input.test.tsx.snap | 83 +++++++++ .../src/components/OldInput/index.ts | 1 + packages/eds-core-react/src/index.ts | 2 +- 8 files changed, 676 insertions(+), 1 deletion(-) create mode 100644 packages/eds-core-react/src/components/OldInput/Input.docs.mdx create mode 100644 packages/eds-core-react/src/components/OldInput/Input.stories.tsx create mode 100644 packages/eds-core-react/src/components/OldInput/Input.test.tsx create mode 100644 packages/eds-core-react/src/components/OldInput/Input.tokens.ts create mode 100644 packages/eds-core-react/src/components/OldInput/Input.tsx create mode 100644 packages/eds-core-react/src/components/OldInput/__snapshots__/Input.test.tsx.snap create mode 100644 packages/eds-core-react/src/components/OldInput/index.ts diff --git a/packages/eds-core-react/src/components/OldInput/Input.docs.mdx b/packages/eds-core-react/src/components/OldInput/Input.docs.mdx new file mode 100644 index 0000000000..268f96ba62 --- /dev/null +++ b/packages/eds-core-react/src/components/OldInput/Input.docs.mdx @@ -0,0 +1,55 @@ +import { Links, PropsTable, Story } from './../../../.storybook/components' +import { Input } from '.' + +# Input + +Is intended to use if you need to more flexibility than the wrapped TextField or select components give. + + + + + + +## Usage + +```tsx +import { Input } from '@equinor/eds-core-react' + + +``` + +## Examples + +### Types + +This is the native type property and here is a small selection of examples of all the possible types. + + + +### Variants + + + +### Disabled + + + +### Read only + + + +### Accessiblity + +It's important to link the `Input` to the corresponding label. + + + +### Compact + +Compact `Input` using `EdsProvider`. + + \ No newline at end of file diff --git a/packages/eds-core-react/src/components/OldInput/Input.stories.tsx b/packages/eds-core-react/src/components/OldInput/Input.stories.tsx new file mode 100644 index 0000000000..814e2516d4 --- /dev/null +++ b/packages/eds-core-react/src/components/OldInput/Input.stories.tsx @@ -0,0 +1,141 @@ +import { useState, useEffect } from 'react' +import { Input, InputProps, Label, EdsProvider, Density } from '../..' +import { Story } from '@storybook/react/types-6-0' +import { ComponentMeta } from '@storybook/react' +import { Stack } from '../../../.storybook/components' +import page from './Input.docs.mdx' + +export default { + title: 'Inputs/Input', + component: Input, + parameters: { + docs: { + page, + }, + }, +} as ComponentMeta + +export const Introduction: Story = (args) => + +export const Types: Story = () => ( + +
+
+
+
+
+
+
+
+
+
+
+) + +export const Variants: Story = () => ( + +
+
+
+
+
+
+
+
+
+) + +export const Disabled: Story = () => ( + <> +