Commit 758201e8 by Peter Holmberg Committed by GitHub

Forms: TextArea component (#20484)

* Adding component, story and documentation file

* forgot files

* Add label and formvalidation

* fix for error/invalid message

* fixing font color when input is disabled

* red border if invalid

* fixing props and label margin

* added support for icon in input

* support for button and loading state

* redoing some of the markup

* fixing height on addons

* Adding some basic documentation

* remove not used types file

* Add some more knobs

* move component to it's own directory, updated styling

* create component and  extract some shared styles

* update story name

* Adding focusstyle and knobs

* Sorting knobs, fix paddings

* accidentaly put in a line break

* use variable names in commonStyles

* add simple mdx docs

* Adding size to TextArea

* more shared styles

* remove unused import
parent e9f9912d
......@@ -9,6 +9,7 @@ import { Button } from './Button';
import { Form } from './Form';
import { Switch } from './Switch';
import { Icon } from '../Icon/Icon';
import { TextArea } from './TextArea/TextArea';
export default {
title: 'UI/Forms/Test forms/Server admin',
......@@ -82,12 +83,7 @@ export const users = () => {
label="Path to client cert"
description="Authentication against LDAP servers requiring client certificates if not required leave empty "
>
<Input
id="clientCert"
value={''}
// onChange={e => setPassword(e.currentTarget.value)}
size="lg"
/>
<TextArea id="clientCert" value={''} size="lg" />
</Field>
</fieldset>
<Button>Update</Button>
......
import React, { FC, HTMLProps, ReactNode } from 'react';
import { GrafanaTheme } from '@grafana/data';
import { css, cx } from 'emotion';
import { getFocusStyle } from '../commonStyles';
import { getFocusStyle, inputSizes, sharedInputStyle } from '../commonStyles';
import { stylesFactory, useTheme } from '../../../themes';
import { Icon } from '../../Icon/Icon';
import { useClientRect } from '../../../utils/useClientRect';
export type FormInputSize = 'sm' | 'md' | 'lg' | 'auto';
import { FormInputSize } from '../types';
export interface Props extends Omit<HTMLProps<HTMLInputElement>, 'prefix' | 'size'> {
/** Show an invalid state around the input */
......@@ -29,7 +28,6 @@ interface StyleDeps {
export const getInputStyles = stylesFactory(({ theme, invalid = false }: StyleDeps) => {
const colors = theme.colors;
const inputBorderColor = invalid ? colors.redBase : colors.formInputBorder;
const borderRadius = theme.border.radius.sm;
const height = theme.spacing.formInputHeight;
......@@ -117,25 +115,18 @@ export const getInputStyles = stylesFactory(({ theme, invalid = false }: StyleDe
input: cx(
getFocusStyle(theme),
sharedInputStyle(theme),
css`
label: input-input;
position: relative;
z-index: 0;
flex-grow: 1;
color: ${colors.formInputText};
background-color: ${colors.formInputBg};
border: 1px solid ${inputBorderColor};
border-radius: ${borderRadius};
height: 100%;
width: 100%;
padding: 0 ${theme.spacing.sm} 0 ${theme.spacing.sm};
font-size: ${theme.typography.size.md};
&:disabled {
background-color: ${colors.formInputBgDisabled};
color: ${colors.formInputDisabledText};
}
/*
Restoring increase/decrease spinner on number inputs. Overwriting rules implemented in
https://github.com/grafana/grafana/commit/488fe62f158a9e0a0bced2b678ada5d43cf3998e.
......@@ -208,20 +199,6 @@ export const getInputStyles = stylesFactory(({ theme, invalid = false }: StyleDe
right: 0;
`
),
inputSize: {
sm: css`
width: 200px;
`,
md: css`
width: 320px;
`,
lg: css`
width: 580px;
`,
auto: css`
width: 100%;
`,
},
};
});
......@@ -239,7 +216,7 @@ export const Input: FC<Props> = props => {
const styles = getInputStyles({ theme, invalid: !!invalid });
return (
<div className={cx(styles.wrapper, styles.inputSize[size])}>
<div className={cx(styles.wrapper, inputSizes()[size])}>
{!!addonBefore && <div className={styles.addon}>{addonBefore}</div>}
<div className={styles.inputWrapper}>
......
import { Props } from '@storybook/addon-docs/blocks';
import { TextArea } from './TextArea';
# TextArea
Use for multi line inputs like descriptions.
<Props of={TextArea} />
import React from 'react';
import { TextArea } from './TextArea';
import { withCenteredStory } from '../../../utils/storybook/withCenteredStory';
import { boolean, number, select, text } from '@storybook/addon-knobs';
import mdx from './TextArea.mdx';
export default {
title: 'UI/Forms/TextArea',
component: TextArea,
decorators: [withCenteredStory],
parameters: {
docs: {
page: mdx,
},
},
};
export const simple = () => {
const BEHAVIOUR_GROUP = 'Behaviour props';
// ---
const invalid = boolean('Invalid', false, BEHAVIOUR_GROUP);
const disabled = boolean('Disabled', false, BEHAVIOUR_GROUP);
const VISUAL_GROUP = 'Visual options';
// ---
const placeholder = text('Placeholder', 'This is just a placeholder', VISUAL_GROUP);
const cols = number('Cols', 30, { range: true, min: 5, max: 50, step: 5 }, VISUAL_GROUP);
const size = select('Size', ['sm', 'md', 'lg', 'auto'], undefined, VISUAL_GROUP);
const CONTAINER_GROUP = 'Container options';
// ---
const containerWidth = number(
'Container width',
300,
{
range: true,
min: 100,
max: 500,
step: 10,
},
CONTAINER_GROUP
);
return (
<div style={{ width: containerWidth }}>
<TextArea invalid={invalid} placeholder={placeholder} cols={cols} disabled={disabled} size={size} />
</div>
);
};
import React, { FC, HTMLProps } from 'react';
import { GrafanaTheme } from '@grafana/data';
import { css, cx } from 'emotion';
import { stylesFactory, useTheme } from '../../../themes';
import { getFocusStyle, inputSizes, sharedInputStyle } from '../commonStyles';
import { FormInputSize } from '../types';
export interface Props extends Omit<HTMLProps<HTMLTextAreaElement>, 'size'> {
/** Show an invalid state around the input */
invalid?: boolean;
/** Choose a predefined size */
size?: FormInputSize;
}
const getTextAreaStyle = stylesFactory((theme: GrafanaTheme, invalid = false) => {
return {
textarea: cx(
sharedInputStyle(theme),
getFocusStyle(theme),
css`
border-radius: ${theme.border.radius.sm};
padding: ${theme.spacing.formSpacingBase / 4}px ${theme.spacing.formSpacingBase}px;
width: 100%;
`
),
};
});
export const TextArea: FC<Props> = ({ invalid, size = 'auto', ...props }) => {
const theme = useTheme();
const styles = getTextAreaStyle(theme, invalid);
return (
<div className={inputSizes()[size]}>
<textarea className={styles.textarea} {...props} />
</div>
);
};
......@@ -9,3 +9,46 @@ export const getFocusStyle = (theme: GrafanaTheme) => css`
transition: all 0.2s cubic-bezier(0.19, 1, 0.22, 1);
}
`;
export const sharedInputStyle = (theme: GrafanaTheme, invalid = false) => {
const colors = theme.colors;
const borderColor = invalid ? colors.redBase : colors.formInputBorder;
return css`
background-color: ${colors.formInputBg};
line-height: ${theme.typography.lineHeight.lg};
font-size: ${theme.typography.size.md};
color: ${colors.formInputText};
border: 1px solid ${borderColor};
&:hover {
border-color: ${colors.formInputBorder};
}
&:focus {
outline: none;
}
&:disabled {
background-color: ${colors.formInputBgDisabled};
color: ${colors.formInputDisabledText};
}
`;
};
export const inputSizes = () => {
return {
sm: css`
width: 200px;
`,
md: css`
width: 320px;
`,
lg: css`
width: 580px;
`,
auto: css`
width: 100%;
`,
};
};
export type FormInputSize = 'sm' | 'md' | 'lg' | 'auto';
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment