SoapboxConfig: refactor Textarea
This commit is contained in:
parent
df714f1112
commit
874ae980e6
3 changed files with 23 additions and 18 deletions
|
@ -3,7 +3,7 @@ import { v4 as uuidv4 } from 'uuid';
|
||||||
|
|
||||||
interface IFormGroup {
|
interface IFormGroup {
|
||||||
/** Input label message. */
|
/** Input label message. */
|
||||||
labelText: React.ReactNode,
|
labelText?: React.ReactNode,
|
||||||
/** Input hint message. */
|
/** Input hint message. */
|
||||||
hintText?: React.ReactNode,
|
hintText?: React.ReactNode,
|
||||||
/** Input errors. */
|
/** Input errors. */
|
||||||
|
@ -26,13 +26,15 @@ const FormGroup: React.FC<IFormGroup> = (props) => {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<label
|
{labelText && (
|
||||||
htmlFor={formFieldId}
|
<label
|
||||||
data-testid='form-group-label'
|
htmlFor={formFieldId}
|
||||||
className='block text-sm font-medium text-gray-700 dark:text-gray-400'
|
data-testid='form-group-label'
|
||||||
>
|
className='block text-sm font-medium text-gray-700 dark:text-gray-400'
|
||||||
{labelText}
|
>
|
||||||
</label>
|
{labelText}
|
||||||
|
</label>
|
||||||
|
)}
|
||||||
|
|
||||||
<div className='mt-1 dark:text-white'>
|
<div className='mt-1 dark:text-white'>
|
||||||
{firstChild}
|
{firstChild}
|
||||||
|
@ -47,11 +49,11 @@ const FormGroup: React.FC<IFormGroup> = (props) => {
|
||||||
</p>
|
</p>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{hintText ? (
|
{hintText && (
|
||||||
<p data-testid='form-group-hint' className='mt-0.5 text-xs text-gray-400'>
|
<p data-testid='form-group-hint' className='mt-0.5 text-xs text-gray-400'>
|
||||||
{hintText}
|
{hintText}
|
||||||
</p>
|
</p>
|
||||||
) : null}
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import classNames from 'classnames';
|
import classNames from 'classnames';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
|
||||||
interface ITextarea extends Pick<React.TextareaHTMLAttributes<HTMLTextAreaElement>, 'maxLength' | 'onChange' | 'required' | 'disabled'> {
|
interface ITextarea extends Pick<React.TextareaHTMLAttributes<HTMLTextAreaElement>, 'maxLength' | 'onChange' | 'required' | 'disabled' | 'rows'> {
|
||||||
/** Put the cursor into the input on mount. */
|
/** Put the cursor into the input on mount. */
|
||||||
autoFocus?: boolean,
|
autoFocus?: boolean,
|
||||||
/** The initial text in the input. */
|
/** The initial text in the input. */
|
||||||
|
@ -16,11 +16,13 @@ interface ITextarea extends Pick<React.TextareaHTMLAttributes<HTMLTextAreaElemen
|
||||||
value?: string,
|
value?: string,
|
||||||
/** Whether the device should autocomplete text in this textarea. */
|
/** Whether the device should autocomplete text in this textarea. */
|
||||||
autoComplete?: string,
|
autoComplete?: string,
|
||||||
|
/** Whether to display the textarea in red. */
|
||||||
|
hasError?: boolean,
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Textarea with custom styles. */
|
/** Textarea with custom styles. */
|
||||||
const Textarea = React.forwardRef(
|
const Textarea = React.forwardRef(
|
||||||
({ isCodeEditor = false, ...props }: ITextarea, ref: React.ForwardedRef<HTMLTextAreaElement>) => {
|
({ isCodeEditor = false, hasError = false, ...props }: ITextarea, ref: React.ForwardedRef<HTMLTextAreaElement>) => {
|
||||||
return (
|
return (
|
||||||
<textarea
|
<textarea
|
||||||
{...props}
|
{...props}
|
||||||
|
@ -29,6 +31,7 @@ const Textarea = React.forwardRef(
|
||||||
'dark:bg-slate-800 shadow-sm focus:ring-indigo-500 focus:border-indigo-500 block w-full sm:text-sm border-gray-300 dark:border-gray-600 rounded-md':
|
'dark:bg-slate-800 shadow-sm focus:ring-indigo-500 focus:border-indigo-500 block w-full sm:text-sm border-gray-300 dark:border-gray-600 rounded-md':
|
||||||
true,
|
true,
|
||||||
'font-mono': isCodeEditor,
|
'font-mono': isCodeEditor,
|
||||||
|
'text-red-600 border-red-600': hasError,
|
||||||
})}
|
})}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
|
|
|
@ -5,12 +5,11 @@ import { defineMessages, useIntl, FormattedMessage } from 'react-intl';
|
||||||
import { updateConfig } from 'soapbox/actions/admin';
|
import { updateConfig } from 'soapbox/actions/admin';
|
||||||
import { uploadMedia } from 'soapbox/actions/media';
|
import { uploadMedia } from 'soapbox/actions/media';
|
||||||
import snackbar from 'soapbox/actions/snackbar';
|
import snackbar from 'soapbox/actions/snackbar';
|
||||||
import { Column, Form, FormActions, FormGroup, Input, Button } from 'soapbox/components/ui';
|
import { Column, Form, FormActions, FormGroup, Input, Textarea, Button } from 'soapbox/components/ui';
|
||||||
import HStack from 'soapbox/components/ui/hstack/hstack';
|
import HStack from 'soapbox/components/ui/hstack/hstack';
|
||||||
import Stack from 'soapbox/components/ui/stack/stack';
|
import Stack from 'soapbox/components/ui/stack/stack';
|
||||||
import Streamfield from 'soapbox/components/ui/streamfield/streamfield';
|
import Streamfield from 'soapbox/components/ui/streamfield/streamfield';
|
||||||
import {
|
import {
|
||||||
SimpleTextarea,
|
|
||||||
FileChooserLogo,
|
FileChooserLogo,
|
||||||
Checkbox,
|
Checkbox,
|
||||||
} from 'soapbox/features/forms';
|
} from 'soapbox/features/forms';
|
||||||
|
@ -320,14 +319,15 @@ const SoapboxConfig: React.FC = () => {
|
||||||
expanded={jsonEditorExpanded}
|
expanded={jsonEditorExpanded}
|
||||||
onToggle={toggleJSONEditor}
|
onToggle={toggleJSONEditor}
|
||||||
>
|
>
|
||||||
<div className={jsonValid ? 'code-editor' : 'code-editor code-editor--invalid'}>
|
<FormGroup hintText={intl.formatMessage(messages.rawJSONHint)}>
|
||||||
<SimpleTextarea
|
<Textarea
|
||||||
hint={intl.formatMessage(messages.rawJSONHint)}
|
|
||||||
value={rawJSON}
|
value={rawJSON}
|
||||||
onChange={handleEditJSON}
|
onChange={handleEditJSON}
|
||||||
|
hasError={!jsonValid}
|
||||||
|
isCodeEditor
|
||||||
rows={12}
|
rows={12}
|
||||||
/>
|
/>
|
||||||
</div>
|
</FormGroup>
|
||||||
</Accordion>
|
</Accordion>
|
||||||
</fieldset>
|
</fieldset>
|
||||||
<FormActions>
|
<FormActions>
|
||||||
|
|
Loading…
Reference in a new issue