Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support for unit in TextField #1152

Merged
merged 32 commits into from
Mar 16, 2021
Merged
Show file tree
Hide file tree
Changes from 22 commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
5a83307
📝 Add a story for text field with unit
wenche Mar 9, 2021
a3c3eda
🚧 Begin work on unit
wenche Mar 9, 2021
29aa142
🚧 Approach with absolute positioning, doesn't work very well
wenche Mar 9, 2021
f69dd99
🚧 Some work for extended input approach
wenche Mar 9, 2021
61bca8c
🚧 Lot's of playing around with the logic
wenche Mar 11, 2021
7eed6d2
📝 Add more stories for testing the different variants
wenche Mar 12, 2021
50cf1c0
📝 Add even more stories to hightlight missing default text color
wenche Mar 12, 2021
29f6199
✨ Temporary fix of the missing default color
wenche Mar 12, 2021
f7f728a
🐛 Fix positioning of icon in textarea. Resize none to make things loo…
wenche Mar 12, 2021
3dda844
⬇️ Add guidelines for using multiline
wenche Mar 12, 2021
3b89e93
♻️ Use the term adornment for unit and icon
wenche Mar 12, 2021
d375252
♻️ Use outline template
wenche Mar 12, 2021
901ebb8
🔥 Delete comments and unused vars
wenche Mar 12, 2021
f1a44c6
📝 Use defaultValue as it's no need for the examples to be controlled
wenche Mar 12, 2021
b3672fb
🔥 More clean up. Remove unnecessary wrappers and prop
wenche Mar 12, 2021
f6fc6b2
💄 Add a tiny top margin to the unit
wenche Mar 12, 2021
ed97957
📝 Add variants for text field
wenche Mar 12, 2021
60af987
📝 More clarifications in the stories
wenche Mar 12, 2021
16e69a5
✨ Separate disabled color for unit
wenche Mar 12, 2021
a61567c
📝 Add a more complete TextField as default
wenche Mar 12, 2021
2eef265
📝 Better textfield in demo
wenche Mar 12, 2021
73851cb
📝 Change helperIcon and inputIcon by selecting from defined options. …
wenche Mar 12, 2021
43e705d
🏷️ Remove unused type
wenche Mar 15, 2021
1bb0c41
✏️ Fix typo
wenche Mar 15, 2021
ef5072f
♻️ Let InputWrapper extend Input and remove outline and box shadow
wenche Mar 15, 2021
a48db28
🏷️ Use TextFieldType to type the use of entities
wenche Mar 15, 2021
7ff8489
♻️ Easier to read with this Mickey-invented syntax :heart:
wenche Mar 15, 2021
3c9a85c
🏷️ Unit optional as well
wenche Mar 15, 2021
4c574c3
♿️ Remove duplicate ids
wenche Mar 15, 2021
5e4db76
✏️ Fix the rest of the multline typos
wenche Mar 16, 2021
92a9d0c
🏷️ Use correct type name.
wenche Mar 16, 2021
e5b4019
♻️ Remove func
wenche Mar 16, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions libraries/core-react/src/components/Input/Input.tokens.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ type InputProps = {
background: string
typography: Typography
placeholderColor: string
disabledColor: string
spacings: {
comfortable: Spacing
compact: Spacing
Expand All @@ -59,6 +60,7 @@ export const input: InputProps = {
color: colors.text.static_icons__default.hex,
},
placeholderColor: colors.text.static_icons__tertiary.hex,
disabledColor: colors.interactive.disabled__text.hex,
spacings,
default: {
border: {
Expand Down
33 changes: 27 additions & 6 deletions libraries/core-react/src/components/Input/Input.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,35 +3,50 @@ import { ElementType, InputHTMLAttributes } from 'react'
import styled, { css } from 'styled-components'
import { InputVariantProps, input as tokens } from './Input.tokens'
import { typographyTemplate, spacingsTemplate } from '@utils'
import { InputWithAdornments } from '../TextField/InputWrapper'
wenche marked this conversation as resolved.
Show resolved Hide resolved
import type { Variants } from '../TextField/types'
import type { Spacing } from '@equinor/eds-tokens'

const Variation = ({ variant }: { variant: InputVariantProps }) => {
const Variation = ({
variant,
token,
}: {
variant: string
token: InputVariantProps
}) => {
if (!variant) {
return ``
}

const {
focus: { border: focusBorderOutline },
border: { outline: borderOutline, bottom: borderBottom },
} = variant
} = token

return css`
border: none;
outline: ${borderOutline.width} solid ${borderOutline.color};
box-shadow: inset 0 -${borderBottom.width} 0 0 ${borderBottom.color};
${InputWithAdornments} & {
outline: none;
}
&:active,
&:focus {
outline-offset: 0;
box-shadow: none;
outline: ${focusBorderOutline.width} solid ${focusBorderOutline.color};
}

${InputWithAdornments} &:active,
${InputWithAdornments} &:focus {
outline: none;
box-shadow: none;
}

&:disabled {
cursor: not-allowed;
box-shadow: none;
outline: none;

&:focus,
&:active {
outline: none;
Expand All @@ -42,7 +57,8 @@ const Variation = ({ variant }: { variant: InputVariantProps }) => {

type StyledProps = {
spacings: Spacing
variant: InputVariantProps
token: InputVariantProps
variant: string
}

const StyledInput = styled.input<StyledProps>`
Expand All @@ -51,7 +67,6 @@ const StyledInput = styled.input<StyledProps>`
margin: 0;
border: none;
appearance: none;

background: ${tokens.background};

${({ spacings }) => spacingsTemplate(spacings)}
Expand All @@ -61,6 +76,9 @@ const StyledInput = styled.input<StyledProps>`
&::placeholder {
color: ${tokens.placeholderColor};
}
&:disabled {
color: ${tokens.disabledColor};
}
`

export type InputProps = {
Expand All @@ -76,6 +94,8 @@ export type InputProps = {
type?: string
/** Read Only */
readonly?: boolean
/* By default Input will handle focus*/
handleFocus?: boolean
wenche marked this conversation as resolved.
Show resolved Hide resolved
} & InputHTMLAttributes<HTMLInputElement>

export const Input = React.forwardRef<HTMLInputElement, InputProps>(
Expand All @@ -98,7 +118,8 @@ export const Input = React.forwardRef<HTMLInputElement, InputProps>(
ref,
type,
disabled,
variant: inputVariant,
variant: variant,
token: inputVariant,
spacings: spacings,
...other,
}
Expand Down
22 changes: 3 additions & 19 deletions libraries/core-react/src/components/TextField/Icon/Icon.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -49,13 +49,6 @@ const StyledIcon = styled.div<StyledIconProps>`
${Variation}
`

const StyledIputIcon = styled(StyledIcon)`
position: absolute;
right: ${({ spacings }) => spacings.right};
top: ${({ spacings }) => spacings.top};
bottom: ${({ spacings }) => spacings.bottom};
`

type TextfieldIconProps = {
/** isDisabled */
isDisabled?: boolean
Expand All @@ -74,7 +67,6 @@ const InputIcon = React.forwardRef<HTMLDivElement, TextfieldIconProps>(
{
variant = 'default',
isDisabled = false,
isInputIcon = true,
spacings = tokens.spacings.comfortable,
colors = {
color: tokens[variant].color,
Expand All @@ -96,17 +88,9 @@ const InputIcon = React.forwardRef<HTMLDivElement, TextfieldIconProps>(
}

return (
<>
{isInputIcon ? (
<StyledIputIcon ref={ref} {...iconProps} {...other}>
{children}
</StyledIputIcon>
) : (
<StyledIcon ref={ref} {...iconProps} {...other}>
{children}
</StyledIcon>
)}
</>
<StyledIcon ref={ref} {...iconProps} {...other}>
{children}
</StyledIcon>
)
},
)
Expand Down
131 changes: 127 additions & 4 deletions libraries/core-react/src/components/TextField/InputWrapper.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,101 @@
import * as React from 'react'
import { InputHTMLAttributes } from 'react'
import { InputHTMLAttributes, ReactNode } from 'react'
import { useTextField } from './context'
import { Input } from '../Input'
import { Icon } from './Icon'
import type { Variants } from './types'
import type { ComponentToken } from '@equinor/eds-tokens'
wenche marked this conversation as resolved.
Show resolved Hide resolved
import styled, { css } from 'styled-components'
import { typographyTemplate, outlineTemplate } from '@utils'
import * as tokens from './TextField.tokens'

const { textfield } = tokens

const Variation = ({
variant,
isFocused,
token,
}: {
variant: string
token: ComponentToken
isFocused: boolean
}) => {
if (!variant) {
return ``
}

return css`
box-shadow: ${() =>
isFocused
? `none`
: variant === 'default'
? `inset 0 -1px 0 0 ${
token.border?.type === 'border' && token.border?.color
}`
: `0 0 0 1px ${
token.border?.type === 'border' && token.border?.color
}`};
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don't think this needs to be inside an anonymous function.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Struggled a lot to find the easiest syntax for this 🔥 styled-components. Couldn't make it work without the func Might be a user error, but I gave up. 😓

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I just tested, and I couldn't not see any difference without the removed func, so I suggest we remove it to avoid unintended consequences in the future

${isFocused && outlineTemplate(token.states.focus.outline)}
`
}

type InputWithAdornmentsType = {
isFocused: boolean
isDisabled: boolean
variant: string
token: ComponentToken
}

export const InputWithAdornments = styled.div<InputWithAdornmentsType>`
display: flex;
align-items: center;
background: ${textfield.background};
padding-right: ${textfield.spacings.right};
${Variation}
${({ isDisabled }) =>
isDisabled && {
boxShadow: 'none',
cursor: 'not-allowed',
outline: 'none',
}}
wenche marked this conversation as resolved.
Show resolved Hide resolved
`

type UnitType = {
isDisabled: boolean
}

const Unit = styled.span<UnitType>`
${typographyTemplate(textfield.entities.unit.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;
${({ isDisabled }) =>
isDisabled && {
color: textfield.entities.unit.states.disabled.typography.color,
}}
`

type AdornmentsType = {
multiline: boolean
}

const Adornments = styled.div<AdornmentsType>`
display: flex;
align-items: center;
justify-content: center;

height: 100%;
margin-left: ${textfield.spacings.left};
& div:nth-child(2) {
margin-left: ${textfield.spacings.left};
}
mimarz marked this conversation as resolved.
Show resolved Hide resolved
${({ multiline }) =>
multiline && {
alignSelf: 'start',
marginTop: `${textfield.spacings.top}`,
}}
`

type TextfieldInputProps = {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggest changing this props names for component to match

pomfrida marked this conversation as resolved.
Show resolved Hide resolved
/** Specifies if text should be bold */
Expand All @@ -17,14 +110,21 @@ type TextfieldInputProps = {
type?: string
/** Read Only */
readonly?: boolean
unit?: string
inputIcon?: ReactNode
} & InputHTMLAttributes<HTMLInputElement>

export const InputWrapper = React.forwardRef<
HTMLInputElement,
TextfieldInputProps
pomfrida marked this conversation as resolved.
Show resolved Hide resolved
>(function InputWrapper({ multiline, variant, disabled, type, ...other }, ref) {
const { handleFocus, handleBlur } = useTextField()
>(function InputWrapper(
{ multiline, variant, disabled, type, unit, inputIcon, ...other },
ref,
) {
const { handleFocus, handleBlur, isFocused } = useTextField()

const actualVariant = variant === 'default' ? 'textfield' : variant
const inputVariant = tokens[actualVariant]
const inputProps = {
multiline,
ref,
Expand All @@ -34,5 +134,28 @@ export const InputWrapper = React.forwardRef<
...other,
}

return <Input onBlur={handleBlur} onFocus={handleFocus} {...inputProps} />
return (
<>
{inputIcon || unit ? (
<InputWithAdornments
isFocused={isFocused}
isDisabled={disabled}
variant={variant}
token={inputVariant}
>
<Input onBlur={handleBlur} onFocus={handleFocus} {...inputProps} />
<Adornments multiline={multiline}>
{unit && <Unit isDisabled={disabled}>{unit}</Unit>}
{inputIcon && (
<Icon isDisabled={disabled} variant={variant}>
{inputIcon}
</Icon>
)}
</Adornments>
</InputWithAdornments>
) : (
<Input onBlur={handleBlur} onFocus={handleFocus} {...inputProps} />
)}
</>
)
})
Loading