1
0
mirror of https://github.com/LaCasemate/fab-manager.git synced 2025-01-18 07:52:23 +01:00

Add disabled style on text editor

This commit is contained in:
vincent 2022-05-10 15:22:01 +02:00
parent f18c4a2ecd
commit 3a8671edbd
9 changed files with 49 additions and 50 deletions

View File

@ -1,4 +1,4 @@
import React, { forwardRef, RefObject, useImperativeHandle, useRef } from 'react';
import React, { forwardRef, RefObject, useEffect, useImperativeHandle, useRef } from 'react';
import { useTranslation } from 'react-i18next';
import { useEditor, EditorContent, Editor } from '@tiptap/react';
import StarterKit from '@tiptap/starter-kit';
@ -12,7 +12,6 @@ import { MenuBar } from './menu-bar';
import { WarningOctagon } from 'phosphor-react';
interface FabTextEditorProps {
label?: string,
paragraphTools?: boolean,
content?: string,
limit?: number,
@ -21,7 +20,7 @@ interface FabTextEditorProps {
onChange?: (content: string) => void,
placeholder?: string,
error?: string,
readOnly?: boolean,
disabled?: boolean
}
export interface FabTextEditorRef {
@ -31,7 +30,7 @@ export interface FabTextEditorRef {
/**
* This component is a WYSIWYG text editor
*/
export const FabTextEditor: React.ForwardRefRenderFunction<FabTextEditorRef, FabTextEditorProps> = ({ label, paragraphTools, content, limit = 400, video, image, onChange, placeholder, error, readOnly = false }, ref: RefObject<FabTextEditorRef>) => {
export const FabTextEditor: React.ForwardRefRenderFunction<FabTextEditorRef, FabTextEditorProps> = ({ paragraphTools, content, limit = 400, video, image, onChange, placeholder, error, disabled = false }, ref: RefObject<FabTextEditorRef>) => {
const { t } = useTranslation('shared');
const placeholderText = placeholder || t('app.shared.text_editor.text_placeholder');
// TODO: Add ctrl+click on link to visit
@ -40,7 +39,7 @@ export const FabTextEditor: React.ForwardRefRenderFunction<FabTextEditorRef, Fab
// the methods in useImperativeHandle are exposed to the parent component
useImperativeHandle(ref, () => ({
focus () {
focusEditor();
editorRef.current?.commands?.focus();
}
}), []);
@ -71,41 +70,34 @@ export const FabTextEditor: React.ForwardRefRenderFunction<FabTextEditorRef, Fab
}
})
],
editable: !readOnly,
content,
onUpdate: ({ editor }) => {
onChange(editor.getHTML());
}
});
/**
* Callback triggered when the label is clicked: we want to focus the text edition zone
*/
const focusEditor = () => {
editorRef.current?.commands?.focus();
};
useEffect(() => {
editor?.setEditable(!disabled);
}, [disabled]);
// bind the editor to the ref, once it is ready
if (!editor) return null;
editorRef.current = editor;
return (
<>
{label && <label onClick={focusEditor} className="fab-textEditor-label">{label}</label>}
<div className="fab-textEditor">
<MenuBar editor={editor} paragraphTools={paragraphTools} video={video} image={image} disabled={readOnly} />
<EditorContent editor={editor} />
<div className="fab-textEditor-character-count">
{editor?.storage.characterCount.characters()} / {limit}
</div>
{error &&
<div className="fab-textEditor-error">
<WarningOctagon size={24} />
<p className="">{error}</p>
</div>
}
<div className={`fab-textEditor ${disabled && 'is-disabled'}`}>
<MenuBar editor={editor} paragraphTools={paragraphTools} video={video} image={image} disabled={disabled} />
<EditorContent editor={editor} />
<div className="fab-textEditor-character-count">
{editor?.storage.characterCount.characters()} / {limit}
</div>
</>
{error &&
<div className="fab-textEditor-error">
<WarningOctagon size={24} />
<p className="">{error}</p>
</div>
}
</div>
);
};

View File

@ -9,7 +9,6 @@ export interface AbstractFormItemProps<TFieldValues> extends PropsWithChildren<A
tooltip?: ReactNode,
className?: string,
disabled?: boolean|((id: string) => boolean),
readOnly?: boolean
onLabelClick?: (event: React.MouseEvent<HTMLLabelElement, MouseEvent>) => void,
}
@ -17,7 +16,7 @@ export interface AbstractFormItemProps<TFieldValues> extends PropsWithChildren<A
* This abstract component should not be used directly.
* Other forms components that are intended to be used with react-hook-form must extend this component.
*/
export const AbstractFormItem = <TFieldValues extends FieldValues>({ id, label, tooltip, className, disabled, readOnly, error, warning, rules, formState, onLabelClick, children }: AbstractFormItemProps<TFieldValues>) => {
export const AbstractFormItem = <TFieldValues extends FieldValues>({ id, label, tooltip, className, disabled, error, warning, rules, formState, onLabelClick, children }: AbstractFormItemProps<TFieldValues>) => {
const [isDirty, setIsDirty] = useState<boolean>(false);
const [fieldError, setFieldError] = useState<{ message: string }>(error);
const [isDisabled, setIsDisabled] = useState<boolean>(false);
@ -46,7 +45,6 @@ export const AbstractFormItem = <TFieldValues extends FieldValues>({ id, label,
`${isDirty && fieldError ? 'is-incorrect' : ''}`,
`${isDirty && warning ? 'is-warned' : ''}`,
`${rules && rules.required ? 'is-required' : ''}`,
`${readOnly ? 'is-readonly' : ''}`,
`${isDisabled ? 'is-disabled' : ''}`
].join(' ');

View File

@ -23,7 +23,7 @@ interface FormInputProps<TFieldValues, TInputType> extends FormComponent<TFieldV
/**
* This component is a template for an input component to use within React Hook Form
*/
export const FormInput = <TFieldValues extends FieldValues, TInputType>({ id, register, label, tooltip, defaultValue, icon, className, rules, readOnly, disabled, type, addOn, addOnAction, addOnClassName, placeholder, error, warning, formState, step, onChange, debounce, accept }: FormInputProps<TFieldValues, TInputType>) => {
export const FormInput = <TFieldValues extends FieldValues, TInputType>({ id, register, label, tooltip, defaultValue, icon, className, rules, disabled, type, addOn, addOnAction, addOnClassName, placeholder, error, warning, formState, step, onChange, debounce, accept }: FormInputProps<TFieldValues, TInputType>) => {
/**
* Debounced (ie. temporised) version of the 'on change' callback.
*/
@ -52,7 +52,7 @@ export const FormInput = <TFieldValues extends FieldValues, TInputType>({ id, re
return (
<AbstractFormItem id={id} formState={formState} label={label}
className={classNames} tooltip={tooltip}
disabled={disabled} readOnly={readOnly}
disabled={disabled}
rules={rules} error={error} warning={warning}>
{icon && <span className="icon">{icon}</span>}
<input id={id}
@ -66,7 +66,6 @@ export const FormInput = <TFieldValues extends FieldValues, TInputType>({ id, re
type={type}
step={step}
disabled={typeof disabled === 'function' ? disabled(id) : disabled}
readOnly={readOnly}
placeholder={placeholder}
accept={accept} />
{addOn && <span onClick={addOnAction} className={`addon ${addOnClassName || ''} ${addOnAction ? 'is-btn' : ''}`}>{addOn}</span>}

View File

@ -27,15 +27,15 @@ type selectOption<TOptionValue> = { value: TOptionValue, label: string };
* This component is a wrapper around react-select to use with react-hook-form.
* It is a multi-select component.
*/
export const FormMultiSelect = <TFieldValues extends FieldValues, TContext extends object, TOptionValue>({ id, label, tooltip, className, control, placeholder, options, valuesDefault, error, rules, disabled, onChange, formState, readOnly, warning, expectedResult, creatable }: FormSelectProps<TFieldValues, TContext, TOptionValue>) => {
export const FormMultiSelect = <TFieldValues extends FieldValues, TContext extends object, TOptionValue>({ id, label, tooltip, className, control, placeholder, options, valuesDefault, error, rules, disabled, onChange, formState, warning, expectedResult, creatable }: FormSelectProps<TFieldValues, TContext, TOptionValue>) => {
const [isDisabled, setIsDisabled] = React.useState<boolean>(false);
const [allOptions, setAllOptions] = React.useState<Array<selectOption<TOptionValue>>>(options);
useEffect(() => {
if (typeof disabled === 'function') {
setIsDisabled(disabled(id) || readOnly);
setIsDisabled(disabled(id));
} else {
setIsDisabled(disabled || readOnly);
setIsDisabled(disabled);
}
}, [disabled]);
@ -94,7 +94,7 @@ export const FormMultiSelect = <TFieldValues extends FieldValues, TContext exten
return (
<AbstractFormItem id={id} formState={formState} label={label}
className={`form-multi-select ${className || ''}`} tooltip={tooltip}
disabled={disabled} readOnly={readOnly}
disabled={disabled}
rules={rules} error={error} warning={warning}>
<Controller name={id as FieldPath<TFieldValues>}
control={control}
@ -122,6 +122,5 @@ export const FormMultiSelect = <TFieldValues extends FieldValues, TContext exten
FormMultiSelect.defaultProps = {
expectedResult: 'array',
creatable: false,
readOnly: false,
disabled: false
};

View File

@ -18,15 +18,15 @@ interface FormRichTextProps<TFieldValues, TContext extends object> extends FormC
/**
* This component is a rich-text editor to use with react-hook-form.
*/
export const FormRichText = <TFieldValues extends FieldValues, TContext extends object>({ id, label, tooltip, className, control, valueDefault, error, warning, rules, disabled = false, readOnly = false, formState, limit, paragraphTools, video, image }: FormRichTextProps<TFieldValues, TContext>) => {
export const FormRichText = <TFieldValues extends FieldValues, TContext extends object>({ id, label, tooltip, className, control, valueDefault, error, warning, rules, disabled = false, formState, limit, paragraphTools, video, image }: FormRichTextProps<TFieldValues, TContext>) => {
const textEditorRef = React.useRef<FabTextEditorRef>();
const [isDisabled, setIsDisabled] = React.useState<boolean>(false);
useEffect(() => {
if (typeof disabled === 'function') {
setIsDisabled(disabled(id) || readOnly);
setIsDisabled(disabled(id));
} else {
setIsDisabled(disabled || readOnly);
setIsDisabled(disabled);
}
}, [disabled]);
@ -56,7 +56,7 @@ export const FormRichText = <TFieldValues extends FieldValues, TContext extends
paragraphTools={paragraphTools}
video={video}
image={image}
readOnly={isDisabled}
disabled={isDisabled}
ref={textEditorRef} />
} />
</AbstractFormItem>

View File

@ -26,14 +26,14 @@ type selectOption<TOptionValue> = { value: TOptionValue, label: string };
/**
* This component is a wrapper for react-select to use with react-hook-form
*/
export const FormSelect = <TFieldValues extends FieldValues, TContext extends object, TOptionValue>({ id, label, tooltip, className, control, placeholder, options, valueDefault, error, warning, rules, disabled = false, onChange, readOnly = false, clearable = false, formState, creatable = false }: FormSelectProps<TFieldValues, TContext, TOptionValue>) => {
export const FormSelect = <TFieldValues extends FieldValues, TContext extends object, TOptionValue>({ id, label, tooltip, className, control, placeholder, options, valueDefault, error, warning, rules, disabled = false, onChange, clearable = false, formState, creatable = false }: FormSelectProps<TFieldValues, TContext, TOptionValue>) => {
const [isDisabled, setIsDisabled] = React.useState<boolean>(false);
useEffect(() => {
if (typeof disabled === 'function') {
setIsDisabled(disabled(id) || readOnly);
setIsDisabled(disabled(id));
} else {
setIsDisabled(disabled || readOnly);
setIsDisabled(disabled);
}
}, [disabled]);
@ -54,7 +54,7 @@ export const FormSelect = <TFieldValues extends FieldValues, TContext extends ob
<AbstractFormItem id={id} label={label} tooltip={tooltip}
className={`form-select ${className || ''}`} formState={formState}
error={error} warning={warning} rules={rules}
disabled={disabled} readOnly={readOnly}>
disabled={disabled}>
<Controller name={id as FieldPath<TFieldValues>}
control={control}
defaultValue={valueDefault as UnpackNestedValue<FieldPathValue<TFieldValues, Path<TFieldValues>>>}

View File

@ -14,7 +14,7 @@ interface FormSwitchProps<TFieldValues, TContext extends object> extends FormCon
/**
* This component is a wrapper for react-switch, to use with react-hook-form.
*/
export const FormSwitch = <TFieldValues, TContext extends object>({ id, label, tooltip, className, error, rules, disabled, control, defaultValue, formState, readOnly, warning, onChange }: FormSwitchProps<TFieldValues, TContext>) => {
export const FormSwitch = <TFieldValues, TContext extends object>({ id, label, tooltip, className, error, rules, disabled, control, defaultValue, formState, warning, onChange }: FormSwitchProps<TFieldValues, TContext>) => {
/**
* The following callback will trigger the onChange callback, if it was passed to this component,
* when the selected option changes.
@ -28,7 +28,7 @@ export const FormSwitch = <TFieldValues, TContext extends object>({ id, label, t
return (
<AbstractFormItem id={id} formState={formState} label={label}
className={`form-switch ${className || ''}`} tooltip={tooltip}
disabled={disabled} readOnly={readOnly}
disabled={disabled}
rules={rules} error={error} warning={warning}>
<Controller name={id as FieldPath<TFieldValues>}
control={control}
@ -43,8 +43,7 @@ export const FormSwitch = <TFieldValues, TContext extends object>({ id, label, t
height={19}
width={40}
ref={ref}
disabled={typeof disabled === 'function' ? disabled(id) : disabled}
readOnly={readOnly} />
disabled={typeof disabled === 'function' ? disabled(id) : disabled} />
} />
</AbstractFormItem>
);

View File

@ -212,4 +212,13 @@
}
p { margin: 0; }
}
&.is-disabled {
.ProseMirror {
resize: none;
}
button {
cursor: not-allowed;
}
}
}

View File

@ -3,4 +3,7 @@
border: 0;
display: block;
}
&.is-disabled {
opacity: 0.5;
}
}