From 090f02fbfa61d0db87fe24a825136398ed2f95eb Mon Sep 17 00:00:00 2001 From: Sami Korpela Date: Mon, 9 Nov 2020 15:19:55 +0200 Subject: [PATCH 01/32] WIP: TextInput improvements Going to get rid of components level and using core from now on. Still in progress as creating internal components before deleting the files of the component level. --- .../Form/TextInput/TextInput.baseStyles.tsx | 17 +- src/core/Form/TextInput/TextInput.tsx | 200 ++++++++++++++---- 2 files changed, 161 insertions(+), 56 deletions(-) diff --git a/src/core/Form/TextInput/TextInput.baseStyles.tsx b/src/core/Form/TextInput/TextInput.baseStyles.tsx index d90488bf4..d635c8b24 100644 --- a/src/core/Form/TextInput/TextInput.baseStyles.tsx +++ b/src/core/Form/TextInput/TextInput.baseStyles.tsx @@ -1,24 +1,15 @@ import { css } from 'styled-components'; -import { TextInputProps } from './TextInput'; import { withSuomifiTheme, TokensAndTheme } from '../../theme'; import { input, containerIEFocus, font } from '../../theme/reset'; import { absoluteFocus } from '../../theme/utils'; import { math } from 'polished'; export const baseStyles = withSuomifiTheme( - ({ - theme, - inputContainerProps, - fullWidth, - }: TokensAndTheme & Omit) => css` + ({ theme }: TokensAndTheme) => css` &.fi-text-input { ${font({ theme })('bodyText')} display: inline-block; - width: ${fullWidth - ? '100%' - : inputContainerProps?.style?.width - ? inputContainerProps?.style.width - : inputContainerProps?.width || '290px'}; + width: 290px; } & .fi-text-input_label-p { @@ -43,6 +34,10 @@ export const baseStyles = withSuomifiTheme( } } + &.fi-text-input--full-width { + width: 100%; + } + & .fi-text-input_statusText_container { display: flex; flex-direction: column; diff --git a/src/core/Form/TextInput/TextInput.tsx b/src/core/Form/TextInput/TextInput.tsx index 1ba2257e8..df41d7560 100644 --- a/src/core/Form/TextInput/TextInput.tsx +++ b/src/core/Form/TextInput/TextInput.tsx @@ -1,74 +1,131 @@ -import React, { Component } from 'react'; +import React, { Component, ReactNode, ChangeEvent, FocusEvent } from 'react'; import { default as styled } from 'styled-components'; import { withSuomifiDefaultProps } from '../../theme/utils'; +import { + HtmlInput, + HtmlInputProps, + HtmlDiv, + HtmlDivProps, +} from '../../../reset'; +import { ParagraphProps } from '../../Paragraph/Paragraph'; import { TokensProp, InternalTokensProp } from '../../theme'; import { baseStyles } from './TextInput.baseStyles'; -import { - TextInput as CompTextInput, - TextInputProps as CompTextInputProps, -} from '../../../components/Form/TextInput'; +import { LabelText, LabelMode } from '../LabelText/LabelText'; +import { StatusText, InputStatus } from '../StatusText/StatusText'; +// import { +// TextInput as CompTextInput, +// TextInputProps as CompTextInputProps, +// } from '../../../components/Form/TextInput'; import classnames from 'classnames'; import { Icon, IconProps, BaseIconKeys } from '../../Icon/Icon'; import { Omit } from '../../../utils/typescript'; +import { idGenerator } from '../../../utils/uuid'; const baseClassName = 'fi-text-input'; export const textInputClassNames = { baseClassName, + fullWidth: `${baseClassName}--full-width`, labelParagraph: `${baseClassName}_label-p`, + disabled: `${baseClassName}--disabled`, error: `${baseClassName}--error`, success: `${baseClassName}--success`, icon: `${baseClassName}_with-icon`, + inputElementContainer: `${baseClassName}_input-element-container`, + inputElement: `${baseClassName}_input`, + functionalityContainer: `${baseClassName}_functionality-container`, }; -export interface TextInputProps extends CompTextInputProps, TokensProp { +export interface TextInputLabelProps extends HtmlDivProps {} + +export interface TextInputProps + extends Omit, + TokensProp { + /** TextInput container div class name for custom styling. */ + className?: string; + /** TextInput container div props */ + inputContainerProps?: Omit; + /** Disable input usage */ + disabled?: boolean; + /** Event handler to execute when clicked */ + onClick?: () => void; + /** Pass custom props to label container */ + labelProps?: TextInputLabelProps; + /** Pass custom props to Label text element */ + labelTextProps?: ParagraphProps; + /** To execute on input text change */ + onChange?: (event: ChangeEvent) => void; + /** To execute on input text onBlur */ + onBlur?: (event: FocusEvent) => void; + /** Label */ + labelText: string; + /** Hide or show label. Label element is always present, but can be visually hidden. + * @default visible + */ + labelMode?: LabelMode; + /** Placeholder text for input. Use only as visual aid, not for instructions. */ + visualPlaceholder?: string; + /** A custom element to be passed to the component. Will be rendered after the input */ + children?: ReactNode; + /** Hint text to be shown below the component */ + hintText?: string; + /** + * 'default' | 'error' | 'success' + * @default default + */ + status?: InputStatus; + /** Status text to be shown below the component and hint text. Use e.g. for validation error */ + statusText?: string; + /** 'text' | 'email' | 'number' | 'password' | 'tel' | 'url' + * @default text + */ + type?: 'text' | 'email' | 'number' | 'password' | 'tel' | 'url'; + /** Input name */ + name?: string; + /** Set components width to 100% */ + fullWidth?: boolean; + /** Optional text that is shown after labelText. Will be wrapped in parentheses. */ + optionalText?: string; icon?: BaseIconKeys; iconProps?: Omit; } -const StyledTextInput = styled( - ({ - tokens, - className, - status, - labelTextProps = { className: undefined }, - ...passProps - }: TextInputProps & InternalTokensProp) => { - return ( - - ); - }, -)` - ${(props) => baseStyles(props)} -`; - /** * * Use for user inputting text. * Props other than specified explicitly are passed on to underlying input element. */ -export class TextInput extends Component { +class BaseTextInput extends Component { + private id: string; + + private statusTextId: string; + + constructor(props: TextInputProps) { + super(props); + this.id = `${idGenerator(props.id)}`; + this.statusTextId = `${this.id}-statusText`; + } + render() { const { + className, + labelText, + labelMode, + labelProps, + labelTextProps = { className: undefined }, + inputContainerProps, + optionalText, + status, + statusText, + hintText, + visualPlaceholder, + id, + type = 'text', + fullWidth, children, icon, iconProps, - className, ...passProps - } = withSuomifiDefaultProps(this.props); + } = this.props; const resolvedIcon = icon || iconProps?.icon; @@ -78,15 +135,68 @@ export class TextInput extends Component { }; return ( - - {children} - {resolvedIcon && } - + + {labelText} + + + {/* + {hintText && ( + + {hintText} + + )} + */} + + + + {children} + {resolvedIcon && } + + + {statusText} + + + ); } } + +const StyledTextInput = styled( + ({ tokens, ...passProps }: TextInputProps & InternalTokensProp) => { + return ; + }, +)` + ${(props) => baseStyles(props)} +`; + +export class TextInput extends Component { + render() { + return ; + } +} From 2e52a77eb29f11cebad74eaa16a9bb3b2e24528d Mon Sep 17 00:00:00 2001 From: Sami Korpela Date: Tue, 10 Nov 2020 11:40:01 +0200 Subject: [PATCH 02/32] Drafting HintText internal component --- .../Form/HintText/HintText.baseStyles.tsx | 14 ++++++ src/core/Form/HintText/HintText.tsx | 47 +++++++++++++++++++ 2 files changed, 61 insertions(+) create mode 100644 src/core/Form/HintText/HintText.baseStyles.tsx create mode 100644 src/core/Form/HintText/HintText.tsx diff --git a/src/core/Form/HintText/HintText.baseStyles.tsx b/src/core/Form/HintText/HintText.baseStyles.tsx new file mode 100644 index 000000000..33f55f2d9 --- /dev/null +++ b/src/core/Form/HintText/HintText.baseStyles.tsx @@ -0,0 +1,14 @@ +import { css } from 'styled-components'; +import { withSuomifiTheme, TokensAndTheme } from '../../theme'; +import { font } from '../../theme/reset'; + +export const baseStyles = withSuomifiTheme( + ({ theme }: TokensAndTheme) => css` + &.fi-hint-text { + display: block; + color: ${theme.colors.blackBase}; + margin-bottom: ${theme.spacing.xs}; + ${font({ theme })('bodyTextSmall')}; + } + `, +); diff --git a/src/core/Form/HintText/HintText.tsx b/src/core/Form/HintText/HintText.tsx new file mode 100644 index 000000000..9ffdcd390 --- /dev/null +++ b/src/core/Form/HintText/HintText.tsx @@ -0,0 +1,47 @@ +import React, { Component, ReactNode } from 'react'; +import classnames from 'classnames'; +import { default as styled } from 'styled-components'; +import { baseStyles } from './HintText.baseStyles'; +import { HtmlSpan, HtmlSpanProps } from '../../../reset'; +import { TokensProp, InternalTokensProp } from 'core/theme'; +import { withSuomifiDefaultProps } from '../../theme/utils'; + +const baseClassName = 'fi-hint-text'; + +interface InternalHintTextProps extends HtmlSpanProps { + /** id */ + id?: string; + /** HintText element content */ + children?: ReactNode; + /** Custom class name for styling and customizing */ + className?: string; +} + +export interface HintTextProps extends InternalHintTextProps, TokensProp {} + +const StyledHintText = styled( + ({ + className, + children, + tokens, + ...passProps + }: HintTextProps & InternalTokensProp) => ( + + {children} + + ), +)` + ${(tokens) => baseStyles(withSuomifiDefaultProps(tokens))} +`; +export class HintText extends Component { + render() { + const { children, ...passProps } = withSuomifiDefaultProps(this.props); + if (!children) { + return null; + } + return {children}; + } +} From e081805325141d4a8cd681c9780be1e6c450efa7 Mon Sep 17 00:00:00 2001 From: Sami Korpela Date: Tue, 10 Nov 2020 11:55:34 +0200 Subject: [PATCH 03/32] Fix the place of JSDoc for TextInput --- src/core/Form/TextInput/TextInput.tsx | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/core/Form/TextInput/TextInput.tsx b/src/core/Form/TextInput/TextInput.tsx index df41d7560..f437f3588 100644 --- a/src/core/Form/TextInput/TextInput.tsx +++ b/src/core/Form/TextInput/TextInput.tsx @@ -89,11 +89,6 @@ export interface TextInputProps iconProps?: Omit; } -/** - * - * Use for user inputting text. - * Props other than specified explicitly are passed on to underlying input element. - */ class BaseTextInput extends Component { private id: string; @@ -195,6 +190,11 @@ const StyledTextInput = styled( ${(props) => baseStyles(props)} `; +/** + * + * Use for user inputting text. + * Props other than specified explicitly are passed on to underlying input element. + */ export class TextInput extends Component { render() { return ; From 1b5dc4fba7e8c5f0844ae8995c741e047625bdda Mon Sep 17 00:00:00 2001 From: Sami Korpela Date: Tue, 10 Nov 2020 11:58:23 +0200 Subject: [PATCH 04/32] Remove useless, commented imports --- src/core/Form/TextInput/TextInput.tsx | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/core/Form/TextInput/TextInput.tsx b/src/core/Form/TextInput/TextInput.tsx index f437f3588..8599ece34 100644 --- a/src/core/Form/TextInput/TextInput.tsx +++ b/src/core/Form/TextInput/TextInput.tsx @@ -12,10 +12,6 @@ import { TokensProp, InternalTokensProp } from '../../theme'; import { baseStyles } from './TextInput.baseStyles'; import { LabelText, LabelMode } from '../LabelText/LabelText'; import { StatusText, InputStatus } from '../StatusText/StatusText'; -// import { -// TextInput as CompTextInput, -// TextInputProps as CompTextInputProps, -// } from '../../../components/Form/TextInput'; import classnames from 'classnames'; import { Icon, IconProps, BaseIconKeys } from '../../Icon/Icon'; import { Omit } from '../../../utils/typescript'; From a883a2a4191f066763ffb3e6194056262e3da39f Mon Sep 17 00:00:00 2001 From: Sami Korpela Date: Tue, 10 Nov 2020 12:00:42 +0200 Subject: [PATCH 05/32] Add internal HintText in to use in TextInput --- src/core/Form/TextInput/TextInput.tsx | 16 +++++----------- 1 file changed, 5 insertions(+), 11 deletions(-) diff --git a/src/core/Form/TextInput/TextInput.tsx b/src/core/Form/TextInput/TextInput.tsx index 8599ece34..370a79843 100644 --- a/src/core/Form/TextInput/TextInput.tsx +++ b/src/core/Form/TextInput/TextInput.tsx @@ -12,6 +12,7 @@ import { TokensProp, InternalTokensProp } from '../../theme'; import { baseStyles } from './TextInput.baseStyles'; import { LabelText, LabelMode } from '../LabelText/LabelText'; import { StatusText, InputStatus } from '../StatusText/StatusText'; +import { HintText } from '../HintText/HintText'; import classnames from 'classnames'; import { Icon, IconProps, BaseIconKeys } from '../../Icon/Icon'; import { Omit } from '../../../utils/typescript'; @@ -88,11 +89,14 @@ export interface TextInputProps class BaseTextInput extends Component { private id: string; + private hintTextId: string; + private statusTextId: string; constructor(props: TextInputProps) { super(props); this.id = `${idGenerator(props.id)}`; + this.hintTextId = `${this.id}-hintText`; this.statusTextId = `${this.id}-statusText`; } @@ -145,17 +149,7 @@ class BaseTextInput extends Component { > {labelText} - - {/* - {hintText && ( - - {hintText} - - )} - */} + {hintText} Date: Tue, 10 Nov 2020 12:05:12 +0200 Subject: [PATCH 06/32] Fixed the description of InternalStatusTextProps JSDoc --- src/core/Form/StatusText/StatusText.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/core/Form/StatusText/StatusText.tsx b/src/core/Form/StatusText/StatusText.tsx index 79c9e83f3..d39651202 100644 --- a/src/core/Form/StatusText/StatusText.tsx +++ b/src/core/Form/StatusText/StatusText.tsx @@ -16,11 +16,11 @@ export type InputStatus = 'default' | 'error' | 'success'; interface InternalStatusTextProps extends HtmlSpanProps { /** id */ id?: string; - /** Chip element content */ + /** StatusText element content */ children?: ReactNode; /** Custom class name for styling and customizing */ className?: string; - /** Disable chip */ + /** Disable StatusText */ disabled?: boolean; /** Status */ status?: InputStatus; From 57bf24dfe97dff31ba9e1120bf388b951430f2b0 Mon Sep 17 00:00:00 2001 From: Sami Korpela Date: Tue, 10 Nov 2020 12:14:27 +0200 Subject: [PATCH 07/32] Update TextInput snapshots --- .../__snapshots__/TextInput.test.tsx.snap | 433 +++++++++--------- 1 file changed, 216 insertions(+), 217 deletions(-) diff --git a/src/core/Form/TextInput/__snapshots__/TextInput.test.tsx.snap b/src/core/Form/TextInput/__snapshots__/TextInput.test.tsx.snap index 085a010a7..f4b3c4c8c 100644 --- a/src/core/Form/TextInput/__snapshots__/TextInput.test.tsx.snap +++ b/src/core/Form/TextInput/__snapshots__/TextInput.test.tsx.snap @@ -25,7 +25,7 @@ exports[`snapshots match error status with statustext 1`] = ` white-space: normal; } -.c5 { +.c4 { line-height: 1.15; -ms-text-size-adjust: 100%; -webkit-text-size-adjust: 100%; @@ -48,32 +48,12 @@ exports[`snapshots match error status with statustext 1`] = ` max-width: 100%; } -.c5::-webkit-input-placeholder { +.c4::-webkit-input-placeholder { color: inherit; opacity: 0.54; } .c3 { - line-height: 1.15; - -ms-text-size-adjust: 100%; - -webkit-text-size-adjust: 100%; - margin: 0; - padding: 0; - border: 0; - box-sizing: border-box; - font: 100% inherit; - line-height: 1; - text-align: left; - -webkit-text-decoration: none; - text-decoration: none; - vertical-align: baseline; - color: inherit; - background: none; - cursor: inherit; - max-width: 100%; -} - -.c6 { line-height: 1.15; -ms-text-size-adjust: 100%; -webkit-text-size-adjust: 100%; @@ -97,35 +77,50 @@ exports[`snapshots match error status with statustext 1`] = ` white-space: normal; } -.c4 { - line-height: 1.15; - -ms-text-size-adjust: 100%; - -webkit-text-size-adjust: 100%; - margin: 0; - padding: 0; - border: 0; - box-sizing: border-box; - font: 100% inherit; - line-height: 1; - text-align: left; +.c2.fi-label-text .fi-label-text_label-span { + -webkit-letter-spacing: 0; + -moz-letter-spacing: 0; + -ms-letter-spacing: 0; + letter-spacing: 0; -webkit-text-decoration: none; text-decoration: none; - vertical-align: baseline; - color: inherit; - background: none; - cursor: inherit; + word-break: break-word; + overflow-wrap: break-word; + -webkit-font-smoothing: antialiased; + font-family: 'Source Sans Pro','Helvetica Neue','Arial',sans-serif; + font-size: 16px; + line-height: 1.5; + font-weight: 600; display: block; - max-width: 100%; - word-wrap: normal; - word-break: normal; - white-space: normal; + margin-bottom: 10px; + color: hsl(0,0%,16%); } -.c1.fi-text-input--disabled { - cursor: not-allowed; +.c5.fi-status-text { + margin-top: 5px; + -webkit-letter-spacing: 0; + -moz-letter-spacing: 0; + -ms-letter-spacing: 0; + letter-spacing: 0; + -webkit-text-decoration: none; + text-decoration: none; + word-break: break-word; + overflow-wrap: break-word; + -webkit-font-smoothing: antialiased; + font-family: 'Source Sans Pro','Helvetica Neue','Arial',sans-serif; + font-size: 16px; + line-height: 1.5; + font-weight: 600; + color: hsl(0,0%,16%); + font-size: 14px; + line-height: 20px; +} + +.c5.fi-status-text.fi-status-text--error { + color: hsl(3,59%,48%); } -.c2.fi-text-input { +.c1.fi-text-input { -webkit-letter-spacing: 0; -moz-letter-spacing: 0; -ms-letter-spacing: 0; @@ -143,7 +138,7 @@ exports[`snapshots match error status with statustext 1`] = ` width: 290px; } -.c2 .fi-text-input_label-p { +.c1 .fi-text-input_label-p { margin-bottom: 10px; -webkit-letter-spacing: 0; -moz-letter-spacing: 0; @@ -161,7 +156,7 @@ exports[`snapshots match error status with statustext 1`] = ` color: hsl(0,0%,16%); } -.c2 .fi-text-input_optionalText { +.c1 .fi-text-input_optionalText { font-family: 'Source Sans Pro','Helvetica Neue','Arial',sans-serif; font-size: 16px; line-height: 1.5; @@ -175,15 +170,15 @@ exports[`snapshots match error status with statustext 1`] = ` outline-style: solid; } -.c2 .fi-text-input_input-element-container:focus-within > input:focus { +.c1 .fi-text-input_input-element-container:focus-within > input:focus { outline: none; } -.c2 .fi-text-input_input-element-container:focus-within { +.c1 .fi-text-input_input-element-container:focus-within { position: relative; } -.c2 .fi-text-input_input-element-container:focus-within::after { +.c1 .fi-text-input_input-element-container:focus-within::after { content: ''; position: absolute; pointer-events: none; @@ -199,7 +194,11 @@ exports[`snapshots match error status with statustext 1`] = ` z-index: 9999; } -.c2 .fi-text-input_statusText_container { +.c1.fi-text-input--full-width { + width: 100%; +} + +.c1 .fi-text-input_statusText_container { display: -webkit-box; display: -webkit-flex; display: -ms-flexbox; @@ -209,7 +208,7 @@ exports[`snapshots match error status with statustext 1`] = ` flex-direction: column; } -.c2 .fi-text-input_statusText_container .fi-text-input_statusText { +.c1 .fi-text-input_statusText_container .fi-text-input_statusText { margin-top: 5px; -webkit-letter-spacing: 0; -moz-letter-spacing: 0; @@ -228,7 +227,7 @@ exports[`snapshots match error status with statustext 1`] = ` line-height: 20px; } -.c2 .fi-text-input_hintText { +.c1 .fi-text-input_hintText { display: block; color: hsl(0,0%,16%); margin-bottom: 10px; @@ -247,7 +246,7 @@ exports[`snapshots match error status with statustext 1`] = ` font-weight: 400; } -.c2 .fi-text-input_input { +.c1 .fi-text-input_input { color: hsl(0,0%,16%); -webkit-letter-spacing: 0; -moz-letter-spacing: 0; @@ -276,39 +275,39 @@ exports[`snapshots match error status with statustext 1`] = ` border-color: hsl(201,7%,58%); } -.c2 .fi-text-input_input::-webkit-input-placeholder { +.c1 .fi-text-input_input::-webkit-input-placeholder { font-style: italic; color: hsl(201,7%,46%); opacity: 1; } -.c2 .fi-text-input_input::-moz-placeholder { +.c1 .fi-text-input_input::-moz-placeholder { font-style: italic; color: hsl(201,7%,46%); opacity: 1; } -.c2 .fi-text-input_input:-ms-input-placeholder { +.c1 .fi-text-input_input:-ms-input-placeholder { font-style: italic; color: hsl(201,7%,46%); opacity: 1; } -.c2 .fi-text-input_input::placeholder { +.c1 .fi-text-input_input::placeholder { font-style: italic; color: hsl(201,7%,46%); opacity: 1; } -.c2.fi-text-input_with-icon .fi-text-input_input-element-container { +.c1.fi-text-input_with-icon .fi-text-input_input-element-container { position: relative; } -.c2.fi-text-input_with-icon .fi-text-input_input { +.c1.fi-text-input_with-icon .fi-text-input_input { padding-right: 40px; } -.c2.fi-text-input_with-icon .fi-icon { +.c1.fi-text-input_with-icon .fi-icon { position: absolute; width: 18px; height: 18px; @@ -316,11 +315,11 @@ exports[`snapshots match error status with statustext 1`] = ` right: 10px; } -.c2.fi-text-input--error .fi-text-input_input { +.c1.fi-text-input--error .fi-text-input_input { border-color: hsl(3,59%,48%); } -.c2.fi-text-input--error .fi-text-input_statusText { +.c1.fi-text-input--error .fi-text-input_statusText { color: hsl(3,59%,48%); } @@ -328,49 +327,50 @@ exports[`snapshots match error status with statustext 1`] = ` border-color: hsl(166,90%,34%); } -.c2.fi-text-input--disabled .fi-text-input_input { +.c1.fi-text-input--disabled .fi-text-input_input { color: hsl(202,7%,67%); background-color: hsl(202,7%,97%); } -.c2.fi-text-input--disabled .fi-icon { +.c1.fi-text-input--disabled .fi-icon { fill: hsl(202,7%,67%); }
+
-
- -
- - This is a status text - +
- + + This is a status text + +
`; @@ -399,7 +399,7 @@ exports[`snapshots match hidden label with placeholder 1`] = ` white-space: normal; } -.c6 { +.c5 { line-height: 1.15; -ms-text-size-adjust: 100%; -webkit-text-size-adjust: 100%; @@ -422,32 +422,12 @@ exports[`snapshots match hidden label with placeholder 1`] = ` max-width: 100%; } -.c6::-webkit-input-placeholder { +.c5::-webkit-input-placeholder { color: inherit; opacity: 0.54; } .c3 { - line-height: 1.15; - -ms-text-size-adjust: 100%; - -webkit-text-size-adjust: 100%; - margin: 0; - padding: 0; - border: 0; - box-sizing: border-box; - font: 100% inherit; - line-height: 1; - text-align: left; - -webkit-text-decoration: none; - text-decoration: none; - vertical-align: baseline; - color: inherit; - background: none; - cursor: inherit; - max-width: 100%; -} - -.c4 { line-height: 1.15; -ms-text-size-adjust: 100%; -webkit-text-size-adjust: 100%; @@ -471,7 +451,7 @@ exports[`snapshots match hidden label with placeholder 1`] = ` white-space: normal; } -.c5 { +.c4 { position: absolute; -webkit-clip: rect(0 0 0 0); clip: rect(0 0 0 0); @@ -483,11 +463,26 @@ exports[`snapshots match hidden label with placeholder 1`] = ` overflow: hidden; } -.c1.fi-text-input--disabled { - cursor: not-allowed; +.c2.fi-label-text .fi-label-text_label-span { + -webkit-letter-spacing: 0; + -moz-letter-spacing: 0; + -ms-letter-spacing: 0; + letter-spacing: 0; + -webkit-text-decoration: none; + text-decoration: none; + word-break: break-word; + overflow-wrap: break-word; + -webkit-font-smoothing: antialiased; + font-family: 'Source Sans Pro','Helvetica Neue','Arial',sans-serif; + font-size: 16px; + line-height: 1.5; + font-weight: 600; + display: block; + margin-bottom: 10px; + color: hsl(0,0%,16%); } -.c2.fi-text-input { +.c1.fi-text-input { -webkit-letter-spacing: 0; -moz-letter-spacing: 0; -ms-letter-spacing: 0; @@ -505,7 +500,7 @@ exports[`snapshots match hidden label with placeholder 1`] = ` width: 290px; } -.c2 .fi-text-input_label-p { +.c1 .fi-text-input_label-p { margin-bottom: 10px; -webkit-letter-spacing: 0; -moz-letter-spacing: 0; @@ -523,7 +518,7 @@ exports[`snapshots match hidden label with placeholder 1`] = ` color: hsl(0,0%,16%); } -.c2 .fi-text-input_optionalText { +.c1 .fi-text-input_optionalText { font-family: 'Source Sans Pro','Helvetica Neue','Arial',sans-serif; font-size: 16px; line-height: 1.5; @@ -531,21 +526,20 @@ exports[`snapshots match hidden label with placeholder 1`] = ` } .c2 .fi-text-input_input-element-container > input:focus { - outline-color: hsl(196,77%,44%); outline-width: 2px; outline-offset: 2px; outline-style: solid; } -.c2 .fi-text-input_input-element-container:focus-within > input:focus { +.c1 .fi-text-input_input-element-container:focus-within > input:focus { outline: none; } -.c2 .fi-text-input_input-element-container:focus-within { +.c1 .fi-text-input_input-element-container:focus-within { position: relative; } -.c2 .fi-text-input_input-element-container:focus-within::after { +.c1 .fi-text-input_input-element-container:focus-within::after { content: ''; position: absolute; pointer-events: none; @@ -561,7 +555,11 @@ exports[`snapshots match hidden label with placeholder 1`] = ` z-index: 9999; } -.c2 .fi-text-input_statusText_container { +.c1.fi-text-input--full-width { + width: 100%; +} + +.c1 .fi-text-input_statusText_container { display: -webkit-box; display: -webkit-flex; display: -ms-flexbox; @@ -571,7 +569,7 @@ exports[`snapshots match hidden label with placeholder 1`] = ` flex-direction: column; } -.c2 .fi-text-input_statusText_container .fi-text-input_statusText { +.c1 .fi-text-input_statusText_container .fi-text-input_statusText { margin-top: 5px; -webkit-letter-spacing: 0; -moz-letter-spacing: 0; @@ -590,7 +588,7 @@ exports[`snapshots match hidden label with placeholder 1`] = ` line-height: 20px; } -.c2 .fi-text-input_hintText { +.c1 .fi-text-input_hintText { display: block; color: hsl(0,0%,16%); margin-bottom: 10px; @@ -609,7 +607,7 @@ exports[`snapshots match hidden label with placeholder 1`] = ` font-weight: 400; } -.c2 .fi-text-input_input { +.c1 .fi-text-input_input { color: hsl(0,0%,16%); -webkit-letter-spacing: 0; -moz-letter-spacing: 0; @@ -638,39 +636,39 @@ exports[`snapshots match hidden label with placeholder 1`] = ` border-color: hsl(201,7%,58%); } -.c2 .fi-text-input_input::-webkit-input-placeholder { +.c1 .fi-text-input_input::-webkit-input-placeholder { font-style: italic; color: hsl(201,7%,46%); opacity: 1; } -.c2 .fi-text-input_input::-moz-placeholder { +.c1 .fi-text-input_input::-moz-placeholder { font-style: italic; color: hsl(201,7%,46%); opacity: 1; } -.c2 .fi-text-input_input:-ms-input-placeholder { +.c1 .fi-text-input_input:-ms-input-placeholder { font-style: italic; color: hsl(201,7%,46%); opacity: 1; } -.c2 .fi-text-input_input::placeholder { +.c1 .fi-text-input_input::placeholder { font-style: italic; color: hsl(201,7%,46%); opacity: 1; } -.c2.fi-text-input_with-icon .fi-text-input_input-element-container { +.c1.fi-text-input_with-icon .fi-text-input_input-element-container { position: relative; } -.c2.fi-text-input_with-icon .fi-text-input_input { +.c1.fi-text-input_with-icon .fi-text-input_input { padding-right: 40px; } -.c2.fi-text-input_with-icon .fi-icon { +.c1.fi-text-input_with-icon .fi-icon { position: absolute; width: 18px; height: 18px; @@ -678,11 +676,11 @@ exports[`snapshots match hidden label with placeholder 1`] = ` right: 10px; } -.c2.fi-text-input--error .fi-text-input_input { +.c1.fi-text-input--error .fi-text-input_input { border-color: hsl(3,59%,48%); } -.c2.fi-text-input--error .fi-text-input_statusText { +.c1.fi-text-input--error .fi-text-input_statusText { color: hsl(3,59%,48%); } @@ -690,43 +688,44 @@ exports[`snapshots match hidden label with placeholder 1`] = ` border-color: hsl(166,90%,34%); } -.c2.fi-text-input--disabled .fi-text-input_input { +.c1.fi-text-input--disabled .fi-text-input_input { color: hsl(202,7%,67%); background-color: hsl(202,7%,97%); } -.c2.fi-text-input--disabled .fi-icon { +.c1.fi-text-input--disabled .fi-icon { fill: hsl(202,7%,67%); }
+
-
- -
+
- +
`; @@ -755,7 +754,7 @@ exports[`snapshots match minimal implementation 1`] = ` white-space: normal; } -.c5 { +.c4 { line-height: 1.15; -ms-text-size-adjust: 100%; -webkit-text-size-adjust: 100%; @@ -778,7 +777,7 @@ exports[`snapshots match minimal implementation 1`] = ` max-width: 100%; } -.c5::-webkit-input-placeholder { +.c4::-webkit-input-placeholder { color: inherit; opacity: 0.54; } @@ -800,38 +799,33 @@ exports[`snapshots match minimal implementation 1`] = ` color: inherit; background: none; cursor: inherit; - max-width: 100%; -} - -.c4 { - line-height: 1.15; - -ms-text-size-adjust: 100%; - -webkit-text-size-adjust: 100%; - margin: 0; - padding: 0; - border: 0; - box-sizing: border-box; - font: 100% inherit; - line-height: 1; - text-align: left; - -webkit-text-decoration: none; - text-decoration: none; - vertical-align: baseline; - color: inherit; - background: none; - cursor: inherit; - display: block; + display: inline; max-width: 100%; word-wrap: normal; word-break: normal; white-space: normal; } -.c1.fi-text-input--disabled { - cursor: not-allowed; +.c2.fi-label-text .fi-label-text_label-span { + -webkit-letter-spacing: 0; + -moz-letter-spacing: 0; + -ms-letter-spacing: 0; + letter-spacing: 0; + -webkit-text-decoration: none; + text-decoration: none; + word-break: break-word; + overflow-wrap: break-word; + -webkit-font-smoothing: antialiased; + font-family: 'Source Sans Pro','Helvetica Neue','Arial',sans-serif; + font-size: 16px; + line-height: 1.5; + font-weight: 600; + display: block; + margin-bottom: 10px; + color: hsl(0,0%,16%); } -.c2.fi-text-input { +.c1.fi-text-input { -webkit-letter-spacing: 0; -moz-letter-spacing: 0; -ms-letter-spacing: 0; @@ -849,7 +843,7 @@ exports[`snapshots match minimal implementation 1`] = ` width: 290px; } -.c2 .fi-text-input_label-p { +.c1 .fi-text-input_label-p { margin-bottom: 10px; -webkit-letter-spacing: 0; -moz-letter-spacing: 0; @@ -867,7 +861,7 @@ exports[`snapshots match minimal implementation 1`] = ` color: hsl(0,0%,16%); } -.c2 .fi-text-input_optionalText { +.c1 .fi-text-input_optionalText { font-family: 'Source Sans Pro','Helvetica Neue','Arial',sans-serif; font-size: 16px; line-height: 1.5; @@ -881,15 +875,15 @@ exports[`snapshots match minimal implementation 1`] = ` outline-style: solid; } -.c2 .fi-text-input_input-element-container:focus-within > input:focus { +.c1 .fi-text-input_input-element-container:focus-within > input:focus { outline: none; } -.c2 .fi-text-input_input-element-container:focus-within { +.c1 .fi-text-input_input-element-container:focus-within { position: relative; } -.c2 .fi-text-input_input-element-container:focus-within::after { +.c1 .fi-text-input_input-element-container:focus-within::after { content: ''; position: absolute; pointer-events: none; @@ -905,7 +899,11 @@ exports[`snapshots match minimal implementation 1`] = ` z-index: 9999; } -.c2 .fi-text-input_statusText_container { +.c1.fi-text-input--full-width { + width: 100%; +} + +.c1 .fi-text-input_statusText_container { display: -webkit-box; display: -webkit-flex; display: -ms-flexbox; @@ -915,7 +913,7 @@ exports[`snapshots match minimal implementation 1`] = ` flex-direction: column; } -.c2 .fi-text-input_statusText_container .fi-text-input_statusText { +.c1 .fi-text-input_statusText_container .fi-text-input_statusText { margin-top: 5px; -webkit-letter-spacing: 0; -moz-letter-spacing: 0; @@ -934,7 +932,7 @@ exports[`snapshots match minimal implementation 1`] = ` line-height: 20px; } -.c2 .fi-text-input_hintText { +.c1 .fi-text-input_hintText { display: block; color: hsl(0,0%,16%); margin-bottom: 10px; @@ -953,7 +951,7 @@ exports[`snapshots match minimal implementation 1`] = ` font-weight: 400; } -.c2 .fi-text-input_input { +.c1 .fi-text-input_input { color: hsl(0,0%,16%); -webkit-letter-spacing: 0; -moz-letter-spacing: 0; @@ -982,39 +980,39 @@ exports[`snapshots match minimal implementation 1`] = ` border-color: hsl(201,7%,58%); } -.c2 .fi-text-input_input::-webkit-input-placeholder { +.c1 .fi-text-input_input::-webkit-input-placeholder { font-style: italic; color: hsl(201,7%,46%); opacity: 1; } -.c2 .fi-text-input_input::-moz-placeholder { +.c1 .fi-text-input_input::-moz-placeholder { font-style: italic; color: hsl(201,7%,46%); opacity: 1; } -.c2 .fi-text-input_input:-ms-input-placeholder { +.c1 .fi-text-input_input:-ms-input-placeholder { font-style: italic; color: hsl(201,7%,46%); opacity: 1; } -.c2 .fi-text-input_input::placeholder { +.c1 .fi-text-input_input::placeholder { font-style: italic; color: hsl(201,7%,46%); opacity: 1; } -.c2.fi-text-input_with-icon .fi-text-input_input-element-container { +.c1.fi-text-input_with-icon .fi-text-input_input-element-container { position: relative; } -.c2.fi-text-input_with-icon .fi-text-input_input { +.c1.fi-text-input_with-icon .fi-text-input_input { padding-right: 40px; } -.c2.fi-text-input_with-icon .fi-icon { +.c1.fi-text-input_with-icon .fi-icon { position: absolute; width: 18px; height: 18px; @@ -1022,11 +1020,11 @@ exports[`snapshots match minimal implementation 1`] = ` right: 10px; } -.c2.fi-text-input--error .fi-text-input_input { +.c1.fi-text-input--error .fi-text-input_input { border-color: hsl(3,59%,48%); } -.c2.fi-text-input--error .fi-text-input_statusText { +.c1.fi-text-input--error .fi-text-input_statusText { color: hsl(3,59%,48%); } @@ -1034,41 +1032,42 @@ exports[`snapshots match minimal implementation 1`] = ` border-color: hsl(166,90%,34%); } -.c2.fi-text-input--disabled .fi-text-input_input { +.c1.fi-text-input--disabled .fi-text-input_input { color: hsl(202,7%,67%); background-color: hsl(202,7%,97%); } -.c2.fi-text-input--disabled .fi-icon { +.c1.fi-text-input--disabled .fi-icon { fill: hsl(202,7%,67%); }
+
-
- -
+
- +
`; From 85a64dae7d2d012d4d96762db4f16cbddc7ae65a Mon Sep 17 00:00:00 2001 From: Sami Korpela Date: Tue, 10 Nov 2020 12:16:32 +0200 Subject: [PATCH 08/32] Remove unused className definition from TextInput --- src/core/Form/TextInput/TextInput.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/src/core/Form/TextInput/TextInput.tsx b/src/core/Form/TextInput/TextInput.tsx index 370a79843..588673d53 100644 --- a/src/core/Form/TextInput/TextInput.tsx +++ b/src/core/Form/TextInput/TextInput.tsx @@ -22,7 +22,6 @@ const baseClassName = 'fi-text-input'; export const textInputClassNames = { baseClassName, fullWidth: `${baseClassName}--full-width`, - labelParagraph: `${baseClassName}_label-p`, disabled: `${baseClassName}--disabled`, error: `${baseClassName}--error`, success: `${baseClassName}--success`, From c64a20856f89259cb4391b3ea4d9fb50cf76132a Mon Sep 17 00:00:00 2001 From: Sami Korpela Date: Tue, 10 Nov 2020 12:21:59 +0200 Subject: [PATCH 09/32] Fix the TextInput's hintText test --- src/core/Form/TextInput/TextInput.test.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/core/Form/TextInput/TextInput.test.tsx b/src/core/Form/TextInput/TextInput.test.tsx index bd2d1e817..beb7424b9 100644 --- a/src/core/Form/TextInput/TextInput.test.tsx +++ b/src/core/Form/TextInput/TextInput.test.tsx @@ -65,7 +65,7 @@ describe('props', () => { , ); const hintText = getByText('Example hint text'); - expect(hintText).toHaveClass('fi-text-input_hintText'); + expect(hintText).toHaveClass('fi-hint-text'); }); }); From b85e7c244f4da6526185774b691673a02431a87c Mon Sep 17 00:00:00 2001 From: Sami Korpela Date: Tue, 10 Nov 2020 12:23:57 +0200 Subject: [PATCH 10/32] Fix the TextInput's labelText test --- src/core/Form/TextInput/TextInput.test.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/core/Form/TextInput/TextInput.test.tsx b/src/core/Form/TextInput/TextInput.test.tsx index beb7424b9..9c2951d97 100644 --- a/src/core/Form/TextInput/TextInput.test.tsx +++ b/src/core/Form/TextInput/TextInput.test.tsx @@ -144,7 +144,7 @@ describe('props', () => { it('should be found ', () => { const { getByText } = render(); const label = getByText('Test input'); - expect(label).toHaveClass('fi-text-input_label-p'); + expect(label).toHaveClass('fi-label-text_label-span'); }); }); From 0c6a6692756ea74795d77da6bdeea3532c0d39fa Mon Sep 17 00:00:00 2001 From: Sami Korpela Date: Tue, 10 Nov 2020 12:25:48 +0200 Subject: [PATCH 11/32] Fix the TextInput's labelMode test --- src/core/Form/TextInput/TextInput.test.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/core/Form/TextInput/TextInput.test.tsx b/src/core/Form/TextInput/TextInput.test.tsx index 9c2951d97..204677cc7 100644 --- a/src/core/Form/TextInput/TextInput.test.tsx +++ b/src/core/Form/TextInput/TextInput.test.tsx @@ -162,7 +162,7 @@ describe('props', () => { it('should be visible by default', () => { const { getByText } = render(); const label = getByText('Test input'); - expect(label).toHaveClass('fi-text-input_label-p'); + expect(label).toHaveClass('fi-label-text_label-span'); }); it('should be hidden', () => { From f246055c696999adaca5965df19c0e6dab1ad551 Mon Sep 17 00:00:00 2001 From: Sami Korpela Date: Tue, 10 Nov 2020 14:11:49 +0200 Subject: [PATCH 12/32] Change internal LabelText to support optionalText No need to create separate component for the optional text as it is used with label anyway. --- src/core/Form/LabelText/LabelText.baseStyles.tsx | 4 ++++ src/core/Form/LabelText/LabelText.tsx | 14 +++++++++++++- src/core/Form/TextInput/TextInput.tsx | 1 + 3 files changed, 18 insertions(+), 1 deletion(-) diff --git a/src/core/Form/LabelText/LabelText.baseStyles.tsx b/src/core/Form/LabelText/LabelText.baseStyles.tsx index 53de0780f..c4da859d1 100644 --- a/src/core/Form/LabelText/LabelText.baseStyles.tsx +++ b/src/core/Form/LabelText/LabelText.baseStyles.tsx @@ -10,6 +10,10 @@ export const baseStyles = withSuomifiTheme( display: block; margin-bottom: ${theme.spacing.xs}; color: ${theme.colors.blackBase}; + + & .fi-label-text_optionalText { + ${theme.typography.bodyTextSmall}; + } } } `, diff --git a/src/core/Form/LabelText/LabelText.tsx b/src/core/Form/LabelText/LabelText.tsx index d553c9fa9..e44167be4 100644 --- a/src/core/Form/LabelText/LabelText.tsx +++ b/src/core/Form/LabelText/LabelText.tsx @@ -25,6 +25,8 @@ interface InternalLabelTextProps extends HtmlDivProps { labelSpanProps?: HtmlSpanProps; /** Render the wrapping element as another element */ asProp?: asPropType; + /** Optional text that is shown after labelText. Will be wrapped in parentheses. */ + optionalText?: string; } export interface LabelTextProps extends InternalLabelTextProps, TokensProp {} @@ -32,6 +34,7 @@ export interface LabelTextProps extends InternalLabelTextProps, TokensProp {} const baseClassName = 'fi-label-text'; const labelTextClassNames = { labelSpan: `${baseClassName}_label-span`, + optionalText: `${baseClassName}_optionalText`, }; const StyledLabelText = styled( @@ -42,6 +45,7 @@ const StyledLabelText = styled( children, tokens, asProp, + optionalText, ...passProps }: LabelTextProps & InternalTokensProp) => ( {labelMode === 'hidden' ? ( - {children} + + {children} + {optionalText && `(${optionalText})`} + ) : ( {children} + {optionalText && ( + + {` (${optionalText})`} + + )} )} diff --git a/src/core/Form/TextInput/TextInput.tsx b/src/core/Form/TextInput/TextInput.tsx index 588673d53..e398dafbb 100644 --- a/src/core/Form/TextInput/TextInput.tsx +++ b/src/core/Form/TextInput/TextInput.tsx @@ -144,6 +144,7 @@ class BaseTextInput extends Component { labelMode={labelMode} as="label" labelSpanProps={labelTextProps} + optionalText={optionalText} {...labelProps} > {labelText} From 24c673c5f4d288c640bcecf172cfed5bccf5d64e Mon Sep 17 00:00:00 2001 From: Sami Korpela Date: Tue, 10 Nov 2020 14:15:21 +0200 Subject: [PATCH 13/32] Remove the unnecessary styles from TextInput These are now done with internal components; StatusText, LabelText and HintText --- .../Form/TextInput/TextInput.baseStyles.tsx | 32 ------------------- 1 file changed, 32 deletions(-) diff --git a/src/core/Form/TextInput/TextInput.baseStyles.tsx b/src/core/Form/TextInput/TextInput.baseStyles.tsx index d635c8b24..ac0c81c18 100644 --- a/src/core/Form/TextInput/TextInput.baseStyles.tsx +++ b/src/core/Form/TextInput/TextInput.baseStyles.tsx @@ -12,16 +12,6 @@ export const baseStyles = withSuomifiTheme( width: 290px; } - & .fi-text-input_label-p { - margin-bottom: ${theme.spacing.xs}; - ${font({ theme })('actionElementInnerTextBold')}; - color: ${theme.colors.blackBase}; - } - - & .fi-text-input_optionalText { - ${theme.typography.bodyTextSmall}; - } - & .fi-text-input_input-element-container { ${containerIEFocus({ theme })} @@ -38,25 +28,6 @@ export const baseStyles = withSuomifiTheme( width: 100%; } - & .fi-text-input_statusText_container { - display: flex; - flex-direction: column; - - & .fi-text-input_statusText { - margin-top: ${theme.spacing.xxs}; - ${font({ theme })('bodySemiBoldSmall')}; - font-size: 14px; - line-height: 20px; - } - } - - & .fi-text-input_hintText { - display: block; - color: ${theme.colors.blackBase}; - margin-bottom: ${theme.spacing.xs}; - ${font({ theme })('bodyTextSmall')}; - } - & .fi-text-input_input { ${input({ theme })} background-color: ${theme.colors.whiteBase}; @@ -97,9 +68,6 @@ export const baseStyles = withSuomifiTheme( & .fi-text-input_input { border-color: ${theme.colors.alertBase}; } - & .fi-text-input_statusText { - color: ${theme.colors.alertBase}; - } } &.fi-text-input--success { & .fi-text-input_input { From c9ec083b12fc6d4a6fc7cd35e83661a2e11626c0 Mon Sep 17 00:00:00 2001 From: Sami Korpela Date: Tue, 10 Nov 2020 14:18:21 +0200 Subject: [PATCH 14/32] Update snapshots of TextInput and SearchInput SearchInput snapshot was changed because of the optionalText addition to internal LabelText component --- .../__snapshots__/SearchInput.test.tsx.snap | 7 + .../__snapshots__/TextInput.test.tsx.snap | 248 ++---------------- 2 files changed, 26 insertions(+), 229 deletions(-) diff --git a/src/core/Form/SearchInput/__snapshots__/SearchInput.test.tsx.snap b/src/core/Form/SearchInput/__snapshots__/SearchInput.test.tsx.snap index a7b866f36..8488f70db 100644 --- a/src/core/Form/SearchInput/__snapshots__/SearchInput.test.tsx.snap +++ b/src/core/Form/SearchInput/__snapshots__/SearchInput.test.tsx.snap @@ -156,6 +156,13 @@ exports[`snapshot should have matching default structure 1`] = ` color: hsl(0,0%,16%); } +.c2.fi-label-text .fi-label-text_label-span .fi-label-text_optionalText { + font-family: 'Source Sans Pro','Helvetica Neue','Arial',sans-serif; + font-size: 16px; + line-height: 1.5; + font-weight: 400; +} + .c7 { display: inline-block; vertical-align: baseline; diff --git a/src/core/Form/TextInput/__snapshots__/TextInput.test.tsx.snap b/src/core/Form/TextInput/__snapshots__/TextInput.test.tsx.snap index f4b3c4c8c..14278d33c 100644 --- a/src/core/Form/TextInput/__snapshots__/TextInput.test.tsx.snap +++ b/src/core/Form/TextInput/__snapshots__/TextInput.test.tsx.snap @@ -96,6 +96,13 @@ exports[`snapshots match error status with statustext 1`] = ` color: hsl(0,0%,16%); } +.c2.fi-label-text .fi-label-text_label-span .fi-label-text_optionalText { + font-family: 'Source Sans Pro','Helvetica Neue','Arial',sans-serif; + font-size: 16px; + line-height: 1.5; + font-weight: 400; +} + .c5.fi-status-text { margin-top: 5px; -webkit-letter-spacing: 0; @@ -138,31 +145,6 @@ exports[`snapshots match error status with statustext 1`] = ` width: 290px; } -.c1 .fi-text-input_label-p { - margin-bottom: 10px; - -webkit-letter-spacing: 0; - -moz-letter-spacing: 0; - -ms-letter-spacing: 0; - letter-spacing: 0; - -webkit-text-decoration: none; - text-decoration: none; - word-break: break-word; - overflow-wrap: break-word; - -webkit-font-smoothing: antialiased; - font-family: 'Source Sans Pro','Helvetica Neue','Arial',sans-serif; - font-size: 16px; - line-height: 1.5; - font-weight: 600; - color: hsl(0,0%,16%); -} - -.c1 .fi-text-input_optionalText { - font-family: 'Source Sans Pro','Helvetica Neue','Arial',sans-serif; - font-size: 16px; - line-height: 1.5; - font-weight: 400; -} - .c2 .fi-text-input_input-element-container > input:focus { outline-color: hsl(196,77%,44%); outline-width: 2px; @@ -198,54 +180,6 @@ exports[`snapshots match error status with statustext 1`] = ` width: 100%; } -.c1 .fi-text-input_statusText_container { - display: -webkit-box; - display: -webkit-flex; - display: -ms-flexbox; - display: flex; - -webkit-flex-direction: column; - -ms-flex-direction: column; - flex-direction: column; -} - -.c1 .fi-text-input_statusText_container .fi-text-input_statusText { - margin-top: 5px; - -webkit-letter-spacing: 0; - -moz-letter-spacing: 0; - -ms-letter-spacing: 0; - letter-spacing: 0; - -webkit-text-decoration: none; - text-decoration: none; - word-break: break-word; - overflow-wrap: break-word; - -webkit-font-smoothing: antialiased; - font-family: 'Source Sans Pro','Helvetica Neue','Arial',sans-serif; - font-size: 16px; - line-height: 1.5; - font-weight: 600; - font-size: 14px; - line-height: 20px; -} - -.c1 .fi-text-input_hintText { - display: block; - color: hsl(0,0%,16%); - margin-bottom: 10px; - -webkit-letter-spacing: 0; - -moz-letter-spacing: 0; - -ms-letter-spacing: 0; - letter-spacing: 0; - -webkit-text-decoration: none; - text-decoration: none; - word-break: break-word; - overflow-wrap: break-word; - -webkit-font-smoothing: antialiased; - font-family: 'Source Sans Pro','Helvetica Neue','Arial',sans-serif; - font-size: 16px; - line-height: 1.5; - font-weight: 400; -} - .c1 .fi-text-input_input { color: hsl(0,0%,16%); -webkit-letter-spacing: 0; @@ -319,10 +253,6 @@ exports[`snapshots match error status with statustext 1`] = ` border-color: hsl(3,59%,48%); } -.c1.fi-text-input--error .fi-text-input_statusText { - color: hsl(3,59%,48%); -} - .c2.fi-text-input--success .fi-text-input_input { border-color: hsl(166,90%,34%); } @@ -482,26 +412,14 @@ exports[`snapshots match hidden label with placeholder 1`] = ` color: hsl(0,0%,16%); } -.c1.fi-text-input { - -webkit-letter-spacing: 0; - -moz-letter-spacing: 0; - -ms-letter-spacing: 0; - letter-spacing: 0; - -webkit-text-decoration: none; - text-decoration: none; - word-break: break-word; - overflow-wrap: break-word; - -webkit-font-smoothing: antialiased; +.c2.fi-label-text .fi-label-text_label-span .fi-label-text_optionalText { font-family: 'Source Sans Pro','Helvetica Neue','Arial',sans-serif; - font-size: 18px; + font-size: 16px; line-height: 1.5; font-weight: 400; - display: inline-block; - width: 290px; } -.c1 .fi-text-input_label-p { - margin-bottom: 10px; +.c1.fi-text-input { -webkit-letter-spacing: 0; -moz-letter-spacing: 0; -ms-letter-spacing: 0; @@ -512,17 +430,11 @@ exports[`snapshots match hidden label with placeholder 1`] = ` overflow-wrap: break-word; -webkit-font-smoothing: antialiased; font-family: 'Source Sans Pro','Helvetica Neue','Arial',sans-serif; - font-size: 16px; - line-height: 1.5; - font-weight: 600; - color: hsl(0,0%,16%); -} - -.c1 .fi-text-input_optionalText { - font-family: 'Source Sans Pro','Helvetica Neue','Arial',sans-serif; - font-size: 16px; + font-size: 18px; line-height: 1.5; font-weight: 400; + display: inline-block; + width: 290px; } .c2 .fi-text-input_input-element-container > input:focus { @@ -559,54 +471,6 @@ exports[`snapshots match hidden label with placeholder 1`] = ` width: 100%; } -.c1 .fi-text-input_statusText_container { - display: -webkit-box; - display: -webkit-flex; - display: -ms-flexbox; - display: flex; - -webkit-flex-direction: column; - -ms-flex-direction: column; - flex-direction: column; -} - -.c1 .fi-text-input_statusText_container .fi-text-input_statusText { - margin-top: 5px; - -webkit-letter-spacing: 0; - -moz-letter-spacing: 0; - -ms-letter-spacing: 0; - letter-spacing: 0; - -webkit-text-decoration: none; - text-decoration: none; - word-break: break-word; - overflow-wrap: break-word; - -webkit-font-smoothing: antialiased; - font-family: 'Source Sans Pro','Helvetica Neue','Arial',sans-serif; - font-size: 16px; - line-height: 1.5; - font-weight: 600; - font-size: 14px; - line-height: 20px; -} - -.c1 .fi-text-input_hintText { - display: block; - color: hsl(0,0%,16%); - margin-bottom: 10px; - -webkit-letter-spacing: 0; - -moz-letter-spacing: 0; - -ms-letter-spacing: 0; - letter-spacing: 0; - -webkit-text-decoration: none; - text-decoration: none; - word-break: break-word; - overflow-wrap: break-word; - -webkit-font-smoothing: antialiased; - font-family: 'Source Sans Pro','Helvetica Neue','Arial',sans-serif; - font-size: 16px; - line-height: 1.5; - font-weight: 400; -} - .c1 .fi-text-input_input { color: hsl(0,0%,16%); -webkit-letter-spacing: 0; @@ -680,10 +544,6 @@ exports[`snapshots match hidden label with placeholder 1`] = ` border-color: hsl(3,59%,48%); } -.c1.fi-text-input--error .fi-text-input_statusText { - color: hsl(3,59%,48%); -} - .c2.fi-text-input--success .fi-text-input_input { border-color: hsl(166,90%,34%); } @@ -825,26 +685,14 @@ exports[`snapshots match minimal implementation 1`] = ` color: hsl(0,0%,16%); } -.c1.fi-text-input { - -webkit-letter-spacing: 0; - -moz-letter-spacing: 0; - -ms-letter-spacing: 0; - letter-spacing: 0; - -webkit-text-decoration: none; - text-decoration: none; - word-break: break-word; - overflow-wrap: break-word; - -webkit-font-smoothing: antialiased; +.c2.fi-label-text .fi-label-text_label-span .fi-label-text_optionalText { font-family: 'Source Sans Pro','Helvetica Neue','Arial',sans-serif; - font-size: 18px; + font-size: 16px; line-height: 1.5; font-weight: 400; - display: inline-block; - width: 290px; } -.c1 .fi-text-input_label-p { - margin-bottom: 10px; +.c1.fi-text-input { -webkit-letter-spacing: 0; -moz-letter-spacing: 0; -ms-letter-spacing: 0; @@ -855,17 +703,11 @@ exports[`snapshots match minimal implementation 1`] = ` overflow-wrap: break-word; -webkit-font-smoothing: antialiased; font-family: 'Source Sans Pro','Helvetica Neue','Arial',sans-serif; - font-size: 16px; - line-height: 1.5; - font-weight: 600; - color: hsl(0,0%,16%); -} - -.c1 .fi-text-input_optionalText { - font-family: 'Source Sans Pro','Helvetica Neue','Arial',sans-serif; - font-size: 16px; + font-size: 18px; line-height: 1.5; font-weight: 400; + display: inline-block; + width: 290px; } .c2 .fi-text-input_input-element-container > input:focus { @@ -903,54 +745,6 @@ exports[`snapshots match minimal implementation 1`] = ` width: 100%; } -.c1 .fi-text-input_statusText_container { - display: -webkit-box; - display: -webkit-flex; - display: -ms-flexbox; - display: flex; - -webkit-flex-direction: column; - -ms-flex-direction: column; - flex-direction: column; -} - -.c1 .fi-text-input_statusText_container .fi-text-input_statusText { - margin-top: 5px; - -webkit-letter-spacing: 0; - -moz-letter-spacing: 0; - -ms-letter-spacing: 0; - letter-spacing: 0; - -webkit-text-decoration: none; - text-decoration: none; - word-break: break-word; - overflow-wrap: break-word; - -webkit-font-smoothing: antialiased; - font-family: 'Source Sans Pro','Helvetica Neue','Arial',sans-serif; - font-size: 16px; - line-height: 1.5; - font-weight: 600; - font-size: 14px; - line-height: 20px; -} - -.c1 .fi-text-input_hintText { - display: block; - color: hsl(0,0%,16%); - margin-bottom: 10px; - -webkit-letter-spacing: 0; - -moz-letter-spacing: 0; - -ms-letter-spacing: 0; - letter-spacing: 0; - -webkit-text-decoration: none; - text-decoration: none; - word-break: break-word; - overflow-wrap: break-word; - -webkit-font-smoothing: antialiased; - font-family: 'Source Sans Pro','Helvetica Neue','Arial',sans-serif; - font-size: 16px; - line-height: 1.5; - font-weight: 400; -} - .c1 .fi-text-input_input { color: hsl(0,0%,16%); -webkit-letter-spacing: 0; @@ -1024,10 +818,6 @@ exports[`snapshots match minimal implementation 1`] = ` border-color: hsl(3,59%,48%); } -.c1.fi-text-input--error .fi-text-input_statusText { - color: hsl(3,59%,48%); -} - .c2.fi-text-input--success .fi-text-input_input { border-color: hsl(166,90%,34%); } From dc0444fad991cc27690870242fb3bc050462a0aa Mon Sep 17 00:00:00 2001 From: Sami Korpela Date: Tue, 10 Nov 2020 14:20:34 +0200 Subject: [PATCH 15/32] Fix the TextInput's optionalText test --- src/core/Form/TextInput/TextInput.test.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/core/Form/TextInput/TextInput.test.tsx b/src/core/Form/TextInput/TextInput.test.tsx index 204677cc7..b34368abc 100644 --- a/src/core/Form/TextInput/TextInput.test.tsx +++ b/src/core/Form/TextInput/TextInput.test.tsx @@ -154,7 +154,7 @@ describe('props', () => { , ); const optionalText = getByText('(Optional)'); - expect(optionalText).toHaveClass('fi-text-input_optionalText'); + expect(optionalText).toHaveClass('fi-label-text_optionalText'); }); }); From 9d94892e3c45f4d3848a9dd3c5709e9547d425a5 Mon Sep 17 00:00:00 2001 From: Sami Korpela Date: Tue, 10 Nov 2020 14:39:14 +0200 Subject: [PATCH 16/32] Removed the `labelProps` and `labelProps` props from TextInput --- src/core/Form/TextInput/TextInput.tsx | 9 --------- 1 file changed, 9 deletions(-) diff --git a/src/core/Form/TextInput/TextInput.tsx b/src/core/Form/TextInput/TextInput.tsx index e398dafbb..a25d24c1b 100644 --- a/src/core/Form/TextInput/TextInput.tsx +++ b/src/core/Form/TextInput/TextInput.tsx @@ -7,7 +7,6 @@ import { HtmlDiv, HtmlDivProps, } from '../../../reset'; -import { ParagraphProps } from '../../Paragraph/Paragraph'; import { TokensProp, InternalTokensProp } from '../../theme'; import { baseStyles } from './TextInput.baseStyles'; import { LabelText, LabelMode } from '../LabelText/LabelText'; @@ -44,10 +43,6 @@ export interface TextInputProps disabled?: boolean; /** Event handler to execute when clicked */ onClick?: () => void; - /** Pass custom props to label container */ - labelProps?: TextInputLabelProps; - /** Pass custom props to Label text element */ - labelTextProps?: ParagraphProps; /** To execute on input text change */ onChange?: (event: ChangeEvent) => void; /** To execute on input text onBlur */ @@ -104,8 +99,6 @@ class BaseTextInput extends Component { className, labelText, labelMode, - labelProps, - labelTextProps = { className: undefined }, inputContainerProps, optionalText, status, @@ -143,9 +136,7 @@ class BaseTextInput extends Component { htmlFor={this.id} labelMode={labelMode} as="label" - labelSpanProps={labelTextProps} optionalText={optionalText} - {...labelProps} > {labelText} From 604f09aa1b1eec1c4f26b72a4e90a3f903f05510 Mon Sep 17 00:00:00 2001 From: Sami Korpela Date: Tue, 10 Nov 2020 14:41:24 +0200 Subject: [PATCH 17/32] Add example use of optionalText prop of TextInput --- src/core/Form/TextInput/TextInput.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/core/Form/TextInput/TextInput.md b/src/core/Form/TextInput/TextInput.md index 015a9d5e0..b56098c27 100644 --- a/src/core/Form/TextInput/TextInput.md +++ b/src/core/Form/TextInput/TextInput.md @@ -16,6 +16,10 @@ import { TextInput } from 'suomifi-ui-components'; labelText="TextInput with hint text" hintText="An example hint text" /> + ; ``` From d91d16647df0f2d0370ec8a2d30c3794940849ac Mon Sep 17 00:00:00 2001 From: Sami Korpela Date: Tue, 10 Nov 2020 14:47:51 +0200 Subject: [PATCH 18/32] Remove the component level TextInput as it no longer user --- src/components/Form/TextInput.tsx | 188 ------------------------------ src/components/index.ts | 1 - 2 files changed, 189 deletions(-) delete mode 100644 src/components/Form/TextInput.tsx diff --git a/src/components/Form/TextInput.tsx b/src/components/Form/TextInput.tsx deleted file mode 100644 index 5875d4391..000000000 --- a/src/components/Form/TextInput.tsx +++ /dev/null @@ -1,188 +0,0 @@ -import React, { Component, ReactNode, ChangeEvent, FocusEvent } from 'react'; -import { Omit } from '../../utils/typescript'; -import { - HtmlLabel, - HtmlLabelProps, - HtmlInput, - HtmlInputProps, - HtmlDiv, - HtmlDivProps, - HtmlSpan, -} from '../../reset'; -import { VisuallyHidden } from '../Visually-hidden/Visually-hidden'; -import { Paragraph, ParagraphProps } from '../Paragraph/Paragraph'; -import classnames from 'classnames'; -import styled from 'styled-components'; -import { disabledCursor } from '../utils/css'; -import { idGenerator } from '../../utils/uuid'; - -const baseClassName = 'fi-text-input'; -const textInputClassNames = { - disabled: `${baseClassName}--disabled`, - label: `${baseClassName}_label`, - inputElement: `${baseClassName}_input`, - inputElementContainer: `${baseClassName}_input-element-container`, - statusText: `${baseClassName}_statusText`, - statusTextContainer: `${baseClassName}_statusText_container`, - hintText: `${baseClassName}_hintText`, - optionalText: `${baseClassName}_optionalText`, -}; - -export interface TextInputLabelProps extends HtmlLabelProps {} - -type Label = 'hidden' | 'visible'; - -type InputType = 'text' | 'email' | 'number' | 'password' | 'tel' | 'url'; - -type TextInputStatus = 'default' | 'error' | 'success'; - -export interface TextInputProps extends Omit { - /** TextInput container div class name for custom styling. */ - className?: string; - /** TextInput container div props */ - inputContainerProps?: Omit; - /** Disable input usage */ - disabled?: boolean; - /** Event handler to execute when clicked */ - onClick?: () => void; - /** Pass custom props to label container */ - labelProps?: TextInputLabelProps; - /** Pass custom props to Label text element */ - labelTextProps?: ParagraphProps; - /** To execute on input text change */ - onChange?: (event: ChangeEvent) => void; - /** To execute on input text onBlur */ - onBlur?: (event: FocusEvent) => void; - /** Label */ - labelText: string; - /** Hide or show label. Label element is always present, but can be visually hidden. - * @default visible - */ - labelMode?: Label; - /** Placeholder text for input. Use only as visual aid, not for instructions. */ - visualPlaceholder?: string; - /** A custom element to be passed to the component. Will be rendered after the input */ - children?: ReactNode; - /** Hint text to be shown below the component */ - hintText?: string; - /** - * 'default' | 'error' | 'success' - * @default default - */ - status?: TextInputStatus; - /** Status text to be shown below the component and hint text. Use e.g. for validation error */ - statusText?: string; - /** 'text' | 'email' | 'number' | 'password' | 'tel' | 'url' - * @default text - */ - type?: InputType; - /** Input name */ - name?: string; - /** Set components width to 100% */ - fullWidth?: boolean; - /** Optional text that is shown after labelText. Will be wrapped in parentheses. */ - optionalText?: string; -} - -class BaseTextInput extends Component { - render() { - const { - className, - labelText, - labelMode, - labelProps, - labelTextProps, - inputContainerProps, - children, - optionalText, - status, - statusText, - hintText, - visualPlaceholder, - id: propId, - type = 'text', - fullWidth, - ...passProps - } = this.props; - - const hideLabel = labelMode === 'hidden'; - const generatedStatusTextId = `${idGenerator(propId)}-statusText`; - const generatedHintTextId = `${idGenerator(propId)}-hintText`; - - return ( - - - {hideLabel ? ( - - {labelText} - {optionalText && `(${optionalText})`} - - ) : ( - - {labelText} - {optionalText && ( - - {` (${optionalText})`} - - )} - - )} - {hintText && ( - - {hintText} - - )} - - - - {children} - - {statusText && ( - - {statusText} - - )} - - - - ); - } -} - -export const StyledBaseTextInput = styled((props: TextInputProps) => ( - -))` - &.${textInputClassNames.disabled} { - ${disabledCursor} - } -`; - -export class TextInput extends Component { - render() { - return ; - } -} diff --git a/src/components/index.ts b/src/components/index.ts index ad47c534f..f00f9c1e6 100644 --- a/src/components/index.ts +++ b/src/components/index.ts @@ -7,7 +7,6 @@ export { DropdownItem, DropdownItemProps, } from './Dropdown/Dropdown'; -export { TextInput, TextInputProps } from './Form/TextInput'; export { Checkbox, CheckboxProps } from './Form/Checkbox'; export { Toggle, From 7bc4cee1ecdf0af03c87cdecac8a68350bc60b7c Mon Sep 17 00:00:00 2001 From: Sami Korpela Date: Tue, 10 Nov 2020 14:50:08 +0200 Subject: [PATCH 19/32] Fix the name to better describe that it is SearchInput SearchInput are not depending on the TextInput as it was before, so removed this to prevent confusion. --- src/core/Form/SearchInput/SearchInput.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/core/Form/SearchInput/SearchInput.tsx b/src/core/Form/SearchInput/SearchInput.tsx index 38b8977fd..816ea8e89 100644 --- a/src/core/Form/SearchInput/SearchInput.tsx +++ b/src/core/Form/SearchInput/SearchInput.tsx @@ -272,7 +272,7 @@ class BaseSearchInput extends Component { } } -const StyledTextInput = styled( +const StyledSearchInput = styled( ({ tokens, ...passProps }: SearchInputProps & InternalTokensProp) => { return ; }, @@ -287,6 +287,6 @@ const StyledTextInput = styled( */ export class SearchInput extends Component { render() { - return ; + return ; } } From 5d5ddca80a282080b5d82eea455d4e45d4120bc5 Mon Sep 17 00:00:00 2001 From: Sami Korpela Date: Tue, 10 Nov 2020 15:23:33 +0200 Subject: [PATCH 20/32] Change the location of InputStatus-type to be more reusable --- src/core/Form/SearchInput/SearchInput.tsx | 3 ++- src/core/Form/StatusText/StatusText.tsx | 3 +-- src/core/Form/TextInput/TextInput.tsx | 3 ++- src/core/Form/types.ts | 1 + 4 files changed, 6 insertions(+), 4 deletions(-) create mode 100644 src/core/Form/types.ts diff --git a/src/core/Form/SearchInput/SearchInput.tsx b/src/core/Form/SearchInput/SearchInput.tsx index 816ea8e89..cb9b0f1c4 100644 --- a/src/core/Form/SearchInput/SearchInput.tsx +++ b/src/core/Form/SearchInput/SearchInput.tsx @@ -18,10 +18,11 @@ import { StatusText } from '../StatusText/StatusText'; import { LabelText, LabelMode } from '../LabelText/LabelText'; import { Icon } from '../../Icon/Icon'; import { baseStyles } from './SearchInput.baseStyles'; +import { InputStatus } from '../types'; type SearchInputValue = string | number | undefined; -type SearchInputStatus = 'default' | 'error'; +type SearchInputStatus = Exclude; export interface SearchInputProps extends Omit< diff --git a/src/core/Form/StatusText/StatusText.tsx b/src/core/Form/StatusText/StatusText.tsx index d39651202..b6132b3cd 100644 --- a/src/core/Form/StatusText/StatusText.tsx +++ b/src/core/Form/StatusText/StatusText.tsx @@ -5,14 +5,13 @@ import { baseStyles } from './StatusText.baseStyles'; import { HtmlSpan, HtmlSpanProps } from '../../../reset'; import { TokensProp, InternalTokensProp } from 'core/theme'; import { withSuomifiDefaultProps } from '../../theme/utils'; +import { InputStatus } from '../types'; const baseClassName = 'fi-status-text'; const statusTextClassNames = { error: `${baseClassName}--error`, }; -export type InputStatus = 'default' | 'error' | 'success'; - interface InternalStatusTextProps extends HtmlSpanProps { /** id */ id?: string; diff --git a/src/core/Form/TextInput/TextInput.tsx b/src/core/Form/TextInput/TextInput.tsx index a25d24c1b..5142c4a3d 100644 --- a/src/core/Form/TextInput/TextInput.tsx +++ b/src/core/Form/TextInput/TextInput.tsx @@ -10,7 +10,8 @@ import { import { TokensProp, InternalTokensProp } from '../../theme'; import { baseStyles } from './TextInput.baseStyles'; import { LabelText, LabelMode } from '../LabelText/LabelText'; -import { StatusText, InputStatus } from '../StatusText/StatusText'; +import { StatusText } from '../StatusText/StatusText'; +import { InputStatus } from '../types'; import { HintText } from '../HintText/HintText'; import classnames from 'classnames'; import { Icon, IconProps, BaseIconKeys } from '../../Icon/Icon'; diff --git a/src/core/Form/types.ts b/src/core/Form/types.ts new file mode 100644 index 000000000..ebbc2b7b1 --- /dev/null +++ b/src/core/Form/types.ts @@ -0,0 +1 @@ +export type InputStatus = 'default' | 'error' | 'success'; From b3583da35546b5d776a1f68975c88b251e579284 Mon Sep 17 00:00:00 2001 From: Sami Korpela Date: Wed, 11 Nov 2020 10:40:59 +0200 Subject: [PATCH 21/32] Add tests for HintText component --- src/core/Form/HintText/HintText.test.tsx | 40 ++++++++++++++++++++++++ 1 file changed, 40 insertions(+) create mode 100644 src/core/Form/HintText/HintText.test.tsx diff --git a/src/core/Form/HintText/HintText.test.tsx b/src/core/Form/HintText/HintText.test.tsx new file mode 100644 index 000000000..c770db869 --- /dev/null +++ b/src/core/Form/HintText/HintText.test.tsx @@ -0,0 +1,40 @@ +import React from 'react'; +import { render } from '@testing-library/react'; +import { axeTest } from '../../../utils/test/axe'; + +import { HintText } from './HintText'; + +describe('props', () => { + describe('children', () => { + it('shows the given text', () => { + const { container } = render(Test text); + expect(container.firstChild).toHaveTextContent('Test text'); + }); + + it('is null when no children given', () => { + const { container } = render(); + expect(container.firstChild).toEqual(null); + }); + }); + + describe('id', () => { + it('has the given id', () => { + const { container } = render(Test text); + expect(container.firstChild).toHaveAttribute('id', 'test-id'); + }); + }); + + describe('className', () => { + it('has the given custom classname', () => { + const { container } = render( + Test text, + ); + expect(container.firstChild).toHaveClass('custom-style'); + }); + }); +}); + +test( + 'should not have basic accessibility issues', + axeTest(Test text), +); From 6de422268c2efb8e8406ec0ed2d8bb605621f828 Mon Sep 17 00:00:00 2001 From: Sami Korpela Date: Thu, 12 Nov 2020 13:30:04 +0200 Subject: [PATCH 22/32] Add tests for LabelText component --- src/core/Form/LabelText/LabelText.test.tsx | 75 ++++++++++++++++++++++ 1 file changed, 75 insertions(+) create mode 100644 src/core/Form/LabelText/LabelText.test.tsx diff --git a/src/core/Form/LabelText/LabelText.test.tsx b/src/core/Form/LabelText/LabelText.test.tsx new file mode 100644 index 000000000..64aae20ae --- /dev/null +++ b/src/core/Form/LabelText/LabelText.test.tsx @@ -0,0 +1,75 @@ +import React from 'react'; +import { render } from '@testing-library/react'; +import { axeTest } from '../../../utils/test/axe'; + +import { LabelText } from './LabelText'; + +describe('props', () => { + describe('children', () => { + it('shows the given text', () => { + const { container } = render(Test text); + expect(container.firstChild).toHaveTextContent('Test text'); + }); + }); + + describe('optionalText', () => { + it('has the optional text element', () => { + const { getByText } = render( + Test text, + ); + const optionalText = getByText('(optional)'); + expect(optionalText).toHaveClass('fi-label-text_optionalText'); + }); + }); + + describe('id', () => { + it('has the given id', () => { + const { container } = render( + Test text, + ); + expect(container.firstChild).toHaveAttribute('id', 'test-id'); + }); + }); + + describe('className', () => { + it('has the given custom classname', () => { + const { container } = render( + Test text, + ); + expect(container.firstChild).toHaveClass('custom-style'); + }); + }); + + describe('labelMode', () => { + it('should be visible by default', () => { + const { getByText } = render(Test text); + const label = getByText('Test text'); + expect(label).toHaveClass('fi-label-text_label-span'); + }); + + it('should be hidden', () => { + const { getByText } = render( + Test text, + ); + const label = getByText('Test text'); + expect(label).toHaveClass('fi-visually-hidden'); + }); + }); + + describe('asProp', () => { + it('has default of div as wrapping element', () => { + const { container } = render(Test text); + expect(container.firstChild).toBeInstanceOf(HTMLDivElement); + }); + + it('has the given wrapper element', () => { + const { container } = render(Test text); + expect(container.firstChild).toBeInstanceOf(HTMLLabelElement); + }); + }); +}); + +test( + 'should not have basic accessibility issues', + axeTest(Test text), +); From 8257df8538ce6e9881bc687d85ee659900f64e89 Mon Sep 17 00:00:00 2001 From: Sami Korpela Date: Fri, 13 Nov 2020 10:52:05 +0200 Subject: [PATCH 23/32] Add test for LabelText's labelSpanProps --- src/core/Form/LabelText/LabelText.test.tsx | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/core/Form/LabelText/LabelText.test.tsx b/src/core/Form/LabelText/LabelText.test.tsx index 64aae20ae..71da6291f 100644 --- a/src/core/Form/LabelText/LabelText.test.tsx +++ b/src/core/Form/LabelText/LabelText.test.tsx @@ -67,6 +67,18 @@ describe('props', () => { expect(container.firstChild).toBeInstanceOf(HTMLLabelElement); }); }); + + describe('labelSpanProps', () => { + it('has the given props', () => { + const { getByText } = render( + + Test text + , + ); + const textSpan = getByText('Test text'); + expect(textSpan).toHaveAttribute('style', 'font-size: 12px;'); + }); + }); }); test( From 2477f048df3c02105fe69b6d989b96cdf6d241cd Mon Sep 17 00:00:00 2001 From: Sami Korpela Date: Fri, 13 Nov 2020 13:21:18 +0200 Subject: [PATCH 24/32] Remove unused interface from TextInput --- src/core/Form/TextInput/TextInput.tsx | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/core/Form/TextInput/TextInput.tsx b/src/core/Form/TextInput/TextInput.tsx index 5142c4a3d..69b7edc4f 100644 --- a/src/core/Form/TextInput/TextInput.tsx +++ b/src/core/Form/TextInput/TextInput.tsx @@ -31,8 +31,6 @@ export const textInputClassNames = { functionalityContainer: `${baseClassName}_functionality-container`, }; -export interface TextInputLabelProps extends HtmlDivProps {} - export interface TextInputProps extends Omit, TokensProp { From fc624d5f16fceb646ee9f736eb22c418f18112c6 Mon Sep 17 00:00:00 2001 From: Sami Korpela Date: Fri, 13 Nov 2020 13:59:42 +0200 Subject: [PATCH 25/32] Add tests for StatusText --- src/core/Form/StatusText/StatusText.test.tsx | 58 ++++++++++++++++++++ 1 file changed, 58 insertions(+) create mode 100644 src/core/Form/StatusText/StatusText.test.tsx diff --git a/src/core/Form/StatusText/StatusText.test.tsx b/src/core/Form/StatusText/StatusText.test.tsx new file mode 100644 index 000000000..f174fa0c6 --- /dev/null +++ b/src/core/Form/StatusText/StatusText.test.tsx @@ -0,0 +1,58 @@ +import React from 'react'; +import { render } from '@testing-library/react'; +import { axeTest } from '../../../utils/test/axe'; + +import { StatusText } from './StatusText'; + +describe('props', () => { + describe('children', () => { + it('shows the given text', () => { + const { container } = render(Test text); + expect(container.firstChild).toHaveTextContent('Test text'); + }); + + it('is null when no children given', () => { + const { container } = render(); + expect(container.firstChild).toEqual(null); + }); + }); + + describe('id', () => { + it('has the given id', () => { + const { container } = render( + Test text, + ); + expect(container.firstChild).toHaveAttribute('id', 'test-id'); + }); + }); + + describe('className', () => { + it('has the given custom classname', () => { + const { container } = render( + Test text, + ); + expect(container.firstChild).toHaveClass('custom-style'); + }); + }); + + describe('status', () => { + it('has error style', () => { + const { container } = render( + Test text, + ); + expect(container.firstChild).toHaveClass('fi-status-text--error'); + }); + }); + + describe('disabled', () => { + it('is null when disabled', () => { + const { container } = render(Test text); + expect(container.firstChild).toEqual(null); + }); + }); +}); + +test( + 'should not have basic accessibility issues', + axeTest(Test text), +); From abcff553c4030aa7c29e0b070c24b3bde1293bd9 Mon Sep 17 00:00:00 2001 From: Sami Korpela Date: Mon, 16 Nov 2020 09:58:36 +0200 Subject: [PATCH 26/32] Update the TextInput snapshot tests after rebase --- .../TextInput/__snapshots__/TextInput.test.tsx.snap | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/src/core/Form/TextInput/__snapshots__/TextInput.test.tsx.snap b/src/core/Form/TextInput/__snapshots__/TextInput.test.tsx.snap index 14278d33c..27bc6cec8 100644 --- a/src/core/Form/TextInput/__snapshots__/TextInput.test.tsx.snap +++ b/src/core/Form/TextInput/__snapshots__/TextInput.test.tsx.snap @@ -145,7 +145,7 @@ exports[`snapshots match error status with statustext 1`] = ` width: 290px; } -.c2 .fi-text-input_input-element-container > input:focus { +.c1 .fi-text-input_input-element-container > input:focus { outline-color: hsl(196,77%,44%); outline-width: 2px; outline-offset: 2px; @@ -253,7 +253,7 @@ exports[`snapshots match error status with statustext 1`] = ` border-color: hsl(3,59%,48%); } -.c2.fi-text-input--success .fi-text-input_input { +.c1.fi-text-input--success .fi-text-input_input { border-color: hsl(166,90%,34%); } @@ -437,7 +437,8 @@ exports[`snapshots match hidden label with placeholder 1`] = ` width: 290px; } -.c2 .fi-text-input_input-element-container > input:focus { +.c1 .fi-text-input_input-element-container > input:focus { + outline-color: hsl(196,77%,44%); outline-width: 2px; outline-offset: 2px; outline-style: solid; @@ -544,7 +545,7 @@ exports[`snapshots match hidden label with placeholder 1`] = ` border-color: hsl(3,59%,48%); } -.c2.fi-text-input--success .fi-text-input_input { +.c1.fi-text-input--success .fi-text-input_input { border-color: hsl(166,90%,34%); } @@ -710,7 +711,7 @@ exports[`snapshots match minimal implementation 1`] = ` width: 290px; } -.c2 .fi-text-input_input-element-container > input:focus { +.c1 .fi-text-input_input-element-container > input:focus { outline-color: hsl(196,77%,44%); outline-width: 2px; outline-offset: 2px; @@ -818,7 +819,7 @@ exports[`snapshots match minimal implementation 1`] = ` border-color: hsl(3,59%,48%); } -.c2.fi-text-input--success .fi-text-input_input { +.c1.fi-text-input--success .fi-text-input_input { border-color: hsl(166,90%,34%); } From f9d40a1d83daec7f8bd6d2c354b7d70ea715d814 Mon Sep 17 00:00:00 2001 From: Sami Korpela Date: Wed, 18 Nov 2020 09:52:36 +0200 Subject: [PATCH 27/32] Change the JSDoc of the TextInput optionalText prop --- src/core/Form/TextInput/TextInput.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/core/Form/TextInput/TextInput.tsx b/src/core/Form/TextInput/TextInput.tsx index 69b7edc4f..9209331f5 100644 --- a/src/core/Form/TextInput/TextInput.tsx +++ b/src/core/Form/TextInput/TextInput.tsx @@ -73,7 +73,7 @@ export interface TextInputProps name?: string; /** Set components width to 100% */ fullWidth?: boolean; - /** Optional text that is shown after labelText. Will be wrapped in parentheses. */ + /** Text to mark a field optional. Will be wrapped in parentheses and shown after labelText. */ optionalText?: string; icon?: BaseIconKeys; iconProps?: Omit; From 525288704f521b51ac503249eaca09d68e92c9cf Mon Sep 17 00:00:00 2001 From: Sami Korpela Date: Wed, 18 Nov 2020 10:07:33 +0200 Subject: [PATCH 28/32] Remove unnecessary div from TextInput --- src/core/Form/TextInput/TextInput.tsx | 31 ++++---- .../__snapshots__/TextInput.test.tsx.snap | 76 ++++++++----------- 2 files changed, 46 insertions(+), 61 deletions(-) diff --git a/src/core/Form/TextInput/TextInput.tsx b/src/core/Form/TextInput/TextInput.tsx index 9209331f5..db076eaa5 100644 --- a/src/core/Form/TextInput/TextInput.tsx +++ b/src/core/Form/TextInput/TextInput.tsx @@ -28,7 +28,6 @@ export const textInputClassNames = { icon: `${baseClassName}_with-icon`, inputElementContainer: `${baseClassName}_input-element-container`, inputElement: `${baseClassName}_input`, - functionalityContainer: `${baseClassName}_functionality-container`, }; export interface TextInputProps @@ -140,23 +139,21 @@ class BaseTextInput extends Component { {labelText} {hintText} - - - - {children} - {resolvedIcon && } - - - {statusText} - + + + {children} + {resolvedIcon && } + + {statusText} + ); } diff --git a/src/core/Form/TextInput/__snapshots__/TextInput.test.tsx.snap b/src/core/Form/TextInput/__snapshots__/TextInput.test.tsx.snap index 27bc6cec8..6558f6c91 100644 --- a/src/core/Form/TextInput/__snapshots__/TextInput.test.tsx.snap +++ b/src/core/Form/TextInput/__snapshots__/TextInput.test.tsx.snap @@ -280,27 +280,23 @@ exports[`snapshots match error status with statustext 1`] = `
-
- -
- - This is a status text - +
+ + This is a status text + `; @@ -572,20 +568,16 @@ exports[`snapshots match hidden label with placeholder 1`] = `
-
- -
+
`; @@ -846,19 +838,15 @@ exports[`snapshots match minimal implementation 1`] = `
-
- -
+
`; From 00a532a4eaa321de677525c0ab7694991a8fd5cc Mon Sep 17 00:00:00 2001 From: Sami Korpela Date: Wed, 18 Nov 2020 10:35:26 +0200 Subject: [PATCH 29/32] Remove children prop from TextInput This seems unnecessary and high risk to break the layout when giving custom stuff. --- src/core/Form/TextInput/TextInput.tsx | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/core/Form/TextInput/TextInput.tsx b/src/core/Form/TextInput/TextInput.tsx index db076eaa5..eeb63b2b0 100644 --- a/src/core/Form/TextInput/TextInput.tsx +++ b/src/core/Form/TextInput/TextInput.tsx @@ -1,4 +1,4 @@ -import React, { Component, ReactNode, ChangeEvent, FocusEvent } from 'react'; +import React, { Component, ChangeEvent, FocusEvent } from 'react'; import { default as styled } from 'styled-components'; import { withSuomifiDefaultProps } from '../../theme/utils'; import { @@ -53,8 +53,6 @@ export interface TextInputProps labelMode?: LabelMode; /** Placeholder text for input. Use only as visual aid, not for instructions. */ visualPlaceholder?: string; - /** A custom element to be passed to the component. Will be rendered after the input */ - children?: ReactNode; /** Hint text to be shown below the component */ hintText?: string; /** @@ -106,7 +104,6 @@ class BaseTextInput extends Component { id, type = 'text', fullWidth, - children, icon, iconProps, ...passProps @@ -148,7 +145,6 @@ class BaseTextInput extends Component { placeholder={visualPlaceholder} {...{ 'aria-invalid': status === 'error' }} /> - {children} {resolvedIcon && }
From 12dec296e4551d2283b47dfd0a4a0bc05f497151 Mon Sep 17 00:00:00 2001 From: Sami Korpela Date: Thu, 19 Nov 2020 10:14:46 +0200 Subject: [PATCH 30/32] Fix TextInput to have aria-describedBy Previously it was inside label, so that functionality came automatically --- src/core/Form/TextInput/TextInput.tsx | 13 +++++++++++++ .../TextInput/__snapshots__/TextInput.test.tsx.snap | 1 + 2 files changed, 14 insertions(+) diff --git a/src/core/Form/TextInput/TextInput.tsx b/src/core/Form/TextInput/TextInput.tsx index eeb63b2b0..d4fe008d4 100644 --- a/src/core/Form/TextInput/TextInput.tsx +++ b/src/core/Form/TextInput/TextInput.tsx @@ -116,6 +116,18 @@ class BaseTextInput extends Component { icon: resolvedIcon, }; + const getDescribedBy = () => { + if (statusText || hintText) { + return { + 'aria-describedby': [ + ...(statusText ? [this.statusTextId] : []), + ...(hintText ? [this.hintTextId] : []), + ].join(' '), + }; + } + return {}; + }; + return ( { type={type} placeholder={visualPlaceholder} {...{ 'aria-invalid': status === 'error' }} + {...getDescribedBy()} /> {resolvedIcon && } diff --git a/src/core/Form/TextInput/__snapshots__/TextInput.test.tsx.snap b/src/core/Form/TextInput/__snapshots__/TextInput.test.tsx.snap index 6558f6c91..4948628ec 100644 --- a/src/core/Form/TextInput/__snapshots__/TextInput.test.tsx.snap +++ b/src/core/Form/TextInput/__snapshots__/TextInput.test.tsx.snap @@ -283,6 +283,7 @@ exports[`snapshots match error status with statustext 1`] = ` class="c0 fi-text-input_input-element-container" > Date: Thu, 19 Nov 2020 10:44:29 +0200 Subject: [PATCH 31/32] Add support for user given aria-describedby for TextInput --- src/core/Form/TextInput/TextInput.tsx | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/core/Form/TextInput/TextInput.tsx b/src/core/Form/TextInput/TextInput.tsx index d4fe008d4..3cbb0a8d7 100644 --- a/src/core/Form/TextInput/TextInput.tsx +++ b/src/core/Form/TextInput/TextInput.tsx @@ -106,6 +106,7 @@ class BaseTextInput extends Component { fullWidth, icon, iconProps, + 'aria-describedby': ariaDescribedBy, ...passProps } = this.props; @@ -117,11 +118,12 @@ class BaseTextInput extends Component { }; const getDescribedBy = () => { - if (statusText || hintText) { + if (statusText || hintText || ariaDescribedBy) { return { 'aria-describedby': [ ...(statusText ? [this.statusTextId] : []), ...(hintText ? [this.hintTextId] : []), + ...(ariaDescribedBy ? [ariaDescribedBy] : []), ].join(' '), }; } From f9f151141c33626f4d43c2c5459828921285eed4 Mon Sep 17 00:00:00 2001 From: Sami Korpela Date: Thu, 19 Nov 2020 11:39:40 +0200 Subject: [PATCH 32/32] Add more tests for TextInput Added test for statusText and hintText. Also testing that if user is giving aria-describedby it is also given to input --- src/core/Form/TextInput/TextInput.test.tsx | 53 ++++++++++++++++++++++ 1 file changed, 53 insertions(+) diff --git a/src/core/Form/TextInput/TextInput.test.tsx b/src/core/Form/TextInput/TextInput.test.tsx index b34368abc..f29563ef2 100644 --- a/src/core/Form/TextInput/TextInput.test.tsx +++ b/src/core/Form/TextInput/TextInput.test.tsx @@ -50,6 +50,21 @@ describe('snapshots match', () => { test('should not have basic accessibility issues', axeTest(TestTextInput)); describe('props', () => { + describe('with only minimum props', () => { + it('has user given aria-describedby on input', () => { + const { getByRole } = render( + , + ); + expect(getByRole('textbox')).toHaveAttribute( + 'aria-describedby', + 'external-component-id', + ); + }); + }); + describe('className', () => { it('has the given custom className', () => { const { container } = render( @@ -67,6 +82,44 @@ describe('props', () => { const hintText = getByText('Example hint text'); expect(hintText).toHaveClass('fi-hint-text'); }); + + it('will be added to input aria-describedby', () => { + const { getByRole } = render( + , + ); + expect(getByRole('textbox')).toHaveAttribute( + 'aria-describedby', + '123-hintText', + ); + }); + }); + + describe('statusText', () => { + it('has the status text element', () => { + const { getByText } = render( + , + ); + const statusText = getByText('Example status text'); + expect(statusText).toHaveClass('fi-status-text'); + }); + + it('will be added to input aria-describedby', () => { + const { getByRole } = render( + , + ); + expect(getByRole('textbox')).toHaveAttribute( + 'aria-describedby', + '123-statusText', + ); + }); }); describe('type', () => {