Skip to content

Commit

Permalink
♻️ Textfield using InputWrapper (#2416)
Browse files Browse the repository at this point in the history
* ✨ Adornments support in `Input` component (#2354)

* 🚧 WIP

* 📝 Added story

* wip

* 🚧 WIP

* 🚧 WIP

* 🚧 wip

* 🚚 Moved over `Input` adornment changes

* ♻️ Added `OldInput` for interim development

* 🐛 Fixed textarea outline

* ♻️ back to new input

* 🔥 removed OldInput

* Testing something old

* updated snapshots

* its something

* ♻️ working version before testing styles

* ♻️ Further testing and tweaking

* 📸 ✅ Updated test & snapshots

* ♻️ working example

* 🚚 Moved typographymixin

* ♻️ Started cleaning up helpertext

* ♻️ Working with just input

* 🚧 WIP

* ♻️ Fixed helper text & colors

* ♻️ changed to usecallback

* ⚰️ Removed unused files

* ♻️ improvements to input

* ♻️ Simplified adornment width

* 🐛 Fixed new variant in Textarea

* ♻️ Textfield with discriminating union

* ♻️ re-introduced old proxy component

* Fiex typing

* 🗑️ Cleaning up files

* Added overridablecomponent to input

* 🏷️ Made as optional in overridableComponent

* 🐛 Fix aria-describedby when no helpertext is provided

* ♻️ Updated Textarea with input

* Cleaning up helpertext

* ♻️ Tweak adornments

* 📸 Update snapshots

* ♻️ Working textarea within Textfield

* ⏪ Reverted adornment styling changes

* Cleanup

* ♻️ Update Textfield rstories
  • Loading branch information
mimarz committed Sep 21, 2022
1 parent 850a61b commit 4e69e44
Show file tree
Hide file tree
Showing 28 changed files with 455 additions and 1,170 deletions.
5 changes: 5 additions & 0 deletions packages/eds-core-react/src/components/Input/Input.docs.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -58,3 +58,8 @@ Compact `Input` using `EdsProvider`.


<Story id="inputs-input--with-adornments" />

### Casted as textarea


<Story id="inputs-input--casted" />
16 changes: 4 additions & 12 deletions packages/eds-core-react/src/components/Input/Input.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -215,9 +215,7 @@ export const WithAdornments: Story<InputProps> = () => {
type="text"
id="adornments-default"
placeholder="Placeholder text Placeholder text"
leftAdornmentsWidth={40}
leftAdornments={<SmallButton variant="ghost_icon">IT</SmallButton>}
rightAdornmentsWidth={52}
rightAdornments={
<>
unit
Expand All @@ -230,9 +228,7 @@ export const WithAdornments: Story<InputProps> = () => {
type="text"
id="adornments-error"
variant="error"
leftAdornmentsWidth={40}
leftAdornments={<SmallButton variant="ghost_icon">IT</SmallButton>}
rightAdornmentsWidth={52}
rightAdornments={
<>
unit
Expand All @@ -245,9 +241,7 @@ export const WithAdornments: Story<InputProps> = () => {
type="text"
id="adornments-warning"
variant="warning"
leftAdornmentsWidth={40}
leftAdornments={<SmallButton variant="ghost_icon">IT</SmallButton>}
rightAdornmentsWidth={52}
rightAdornments={
<>
unit
Expand All @@ -260,9 +254,7 @@ export const WithAdornments: Story<InputProps> = () => {
type="text"
id="adornments-success"
variant="success"
leftAdornmentsWidth={40}
leftAdornments={<SmallButton variant="ghost_icon">IT</SmallButton>}
rightAdornmentsWidth={52}
rightAdornments={
<>
unit
Expand All @@ -277,15 +269,13 @@ export const WithAdornments: Story<InputProps> = () => {
disabled
placeholder="Placeholder text Placeholder text"
value="Some text Some textSome textSome text"
leftAdornmentsWidth={40}
leftAdornments={
<>
<SmallButton disabled variant="ghost_icon">
IT
</SmallButton>
</>
}
rightAdornmentsWidth={52}
rightAdornments={
<>
unit
Expand All @@ -298,13 +288,11 @@ export const WithAdornments: Story<InputProps> = () => {
type="text"
id="adornments-readonly"
readOnly
leftAdornmentsWidth={40}
leftAdornments={
<>
<SmallButton variant="ghost_icon">IT</SmallButton>
</>
}
rightAdornmentsWidth={52}
rightAdornments={
<>
unit
Expand All @@ -325,3 +313,7 @@ WithAdornments.decorators = [
)
},
]

export const casted: Story<InputProps> = (args) => {
return <Input as="textarea" {...args} />
}
252 changes: 143 additions & 109 deletions packages/eds-core-react/src/components/Input/Input.tsx
Original file line number Diff line number Diff line change
@@ -1,15 +1,24 @@
import { InputHTMLAttributes, forwardRef, ReactNode, useMemo } from 'react'
import {
forwardRef,
ReactNode,
useState,
useCallback,
CSSProperties,
ElementType,
ComponentPropsWithoutRef,
} from 'react'
import styled, { css } from 'styled-components'
import { ComponentToken } from '@equinor/eds-tokens'
import {
typographyMixin,
spacingsTemplate,
outlineTemplate,
useToken,
OverridableComponent,
} from '@equinor/eds-utils'
import { inputToken as tokens } from './Input.tokens'
import type { InputToken } from './Input.tokens'
import type { Variants } from '../TextField/types'
import type { Variants } from '../types'
import { useEds } from '../EdsProvider'

const Container = styled.div(({ token, disabled, readOnly }: StyledProps) => {
Expand All @@ -25,7 +34,6 @@ const Container = styled.div(({ token, disabled, readOnly }: StyledProps) => {
flex-direction: row;
border: none;
box-sizing: border-box;
height: ${token.height};
box-shadow: ${token.boxShadow};
background: ${token.background};
${outlineTemplate(token.outline)}
Expand Down Expand Up @@ -53,25 +61,30 @@ const Container = styled.div(({ token, disabled, readOnly }: StyledProps) => {
`
})

const StyledInput = styled.input(({ token }: StyledProps) => {
return css`
width: 100%;
border: none;
background: transparent;
${spacingsTemplate(token.spacings)}
${typographyMixin(token.typography)}
outline: none;
&::placeholder {
color: ${token.entities.placeholder.typography.color};
}
&:disabled {
color: var(--eds-input-color);
cursor: not-allowed;
}
`
})
const StyledInput = styled.input(
({ token, paddingLeft, paddingRight }: StyledProps) => {
return css`
width: 100%;
border: none;
background: transparent;
${spacingsTemplate(token.spacings)}
${typographyMixin(token.typography)}
outline: none;
padding-left: ${paddingLeft};
padding-right: ${paddingRight};
&::placeholder {
color: ${token.entities.placeholder.typography.color};
}
&:disabled {
color: var(--eds-input-color);
cursor: not-allowed;
}
`
},
)

type AdornmentProps = {
token: InputToken
Expand All @@ -80,8 +93,8 @@ type AdornmentProps = {
const Adornments = styled.div<AdornmentProps>(({ token }) => {
return css`
position: absolute;
top: 0;
bottom: 0;
top: ${token.spacings.top};
bottom: ${token.spacings.bottom};
display: flex;
align-items: center;
${typographyMixin(token.entities.adornment.typography)}
Expand All @@ -102,9 +115,10 @@ const RightAdornments = styled(Adornments)(
padding-right: ${token.entities.adornment.spacings.right};
`,
)

type StyledProps = {
token: InputToken
paddingLeft?: string
paddingRight?: string
} & Required<Pick<InputProps, 'readOnly' | 'disabled'>>

export type InputProps = {
Expand All @@ -120,90 +134,110 @@ export type InputProps = {
readOnly?: boolean
/** Left adornments */
leftAdornments?: ReactNode
/** Left adornments width */
leftAdornmentsWidth?: number
/** Right adornments */
rightAdornments?: ReactNode
/** Right adornments width */
rightAdornmentsWidth?: number
} & InputHTMLAttributes<HTMLInputElement>

export const Input = forwardRef<HTMLInputElement, InputProps>(function Input(
{
variant = 'default',
disabled = false,
type = 'text',
leftAdornments,
rightAdornments,
leftAdornmentsWidth,
rightAdornmentsWidth,
readOnly,
className,
style,
...other
},
ref,
) {
const actualVariant = variant === 'default' ? 'input' : variant
const inputVariant = tokens[actualVariant]
const { density } = useEds()
const token = useToken({ density }, inputVariant)()

const updatedToken = useMemo(
(): ComponentToken => ({
...token,
spacings: {
...token.spacings,
left:
typeof leftAdornmentsWidth !== 'undefined'
? `${leftAdornmentsWidth}px`
: token.spacings.left,
right:
typeof rightAdornmentsWidth !== 'undefined'
? `${rightAdornmentsWidth}px`
: token.spacings.right,
},
}),
[leftAdornmentsWidth, rightAdornmentsWidth, token],
)
const inputProps = {
/** Left adornments props */
leftAdornmentsProps?: ComponentPropsWithoutRef<'div'>
/** Right adornments props */
rightAdornmentsProps?: ComponentPropsWithoutRef<'div'>
/** Cast the input to another element */
as?: ElementType
/** */
className?: string
style?: CSSProperties
}

export const Input: OverridableComponent<InputProps, HTMLInputElement> =
forwardRef<HTMLInputElement, InputProps>(function Input(
{
variant,
disabled = false,
type = 'text',
leftAdornments,
rightAdornments,
readOnly,
className,
style,
leftAdornmentsProps,
rightAdornmentsProps,
...other
},
ref,
type,
disabled,
readOnly,
token: updatedToken,
...other,
}

const containerProps = {
disabled,
readOnly,
className,
style,
token: updatedToken,
}

const leftAdornmentProps = {
token: updatedToken,
}
const rightAdornmentProps = {
token: updatedToken,
}

return (
// Not using <ThemeProvider> because of cascading styling messing with adornments
<Container {...containerProps}>
{leftAdornments ? (
<LeftAdornments {...leftAdornmentProps}>
{leftAdornments}
</LeftAdornments>
) : null}
<StyledInput {...inputProps} />
{rightAdornments ? (
<RightAdornments {...rightAdornmentProps}>
{rightAdornments}
</RightAdornments>
) : null}
</Container>
)
})
) {
const inputVariant = tokens[variant] ? tokens[variant] : tokens.input
const { density } = useEds()
const _token = useToken({ density }, inputVariant)()

const [rightAdornmentsRef, setRightAdornmentsRef] =
useState<HTMLDivElement>()
const [leftAdornmentsRef, setLeftAdornmentsRef] = useState<HTMLDivElement>()

const token = useCallback((): ComponentToken => {
const leftAdornmentsWidth = leftAdornmentsRef
? leftAdornmentsRef.clientWidth
: 0
const rightAdornmentsWidth = rightAdornmentsRef
? rightAdornmentsRef.clientWidth
: 0
return {
..._token,
spacings: {
..._token.spacings,
left: `${leftAdornmentsWidth + parseInt(_token.spacings.left)}px`,
right: `${rightAdornmentsWidth + parseInt(_token.spacings.right)}px`,
},
}
}, [leftAdornmentsRef, rightAdornmentsRef, _token])()

const inputProps = {
ref,
type,
disabled,
readOnly,
token,
style: {
resize: 'none',
},
...other,
}

const containerProps = {
disabled,
readOnly,
className,
style,
token,
}

const _leftAdornmentProps = {
...leftAdornmentsProps,
ref: setLeftAdornmentsRef,
token,
}
const _rightAdornmentProps = {
...rightAdornmentsProps,
ref: setRightAdornmentsRef,
token,
}

return (
// Not using <ThemeProvider> because of cascading styling messing with adornments
<Container {...containerProps}>
{leftAdornments ? (
<LeftAdornments {..._leftAdornmentProps}>
{leftAdornments}
</LeftAdornments>
) : null}
<StyledInput
paddingLeft={token.spacings.left}
paddingRight={token.spacings.right}
{...inputProps}
/>
{rightAdornments ? (
<RightAdornments {..._rightAdornmentProps}>
{rightAdornments}
</RightAdornments>
) : null}
</Container>
)
})
Loading

0 comments on commit 4e69e44

Please sign in to comment.