All files / src/components index.js

100% Statements 21/21
100% Branches 15/15
100% Functions 10/10
100% Lines 20/20

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111                                                                                    58x 58x 58x       58x 10x   10x       58x 16x   16x     58x 5x 5x 5x     58x 1x 1x           58x                                 58x   1x                 58x              
import React, { useEffect, useRef, useState } from 'react';
import globals from './lib/globals';
import { InlineEditDisplay } from './lib/InlineEditDisplay/InlineEditDisplay';
import { InlineEditInputFactory } from './lib/InlineEditInputFactory/InlineEditInputFactory';
import { StyleWrapper } from './StyleWrapper';
 
// InlineEdit is a component that allows you to edit a value in place
// It consists of 2 sub-components: InlineEditDisplay and InlineEditInput
 
// inspired by Atlassian Inline Edit component
// https://atlassian.design/components/inline-edit/examples#default
 
// Also inspired by react-easy-edit
// https://github.com/giorgosart/react-easy-edit
 
// Tutorial for packages from:
// https://www.youtube.com/watch?v=hf6Z8OZanec
 
/**
 *
 * @callback onSave - callback function after onBlur or Enter
 * @callback displayRenderer - custom display render props
 * @param {String} initialValue - initial value to display / edit
 * @param {String} defaultValue - default value (will be used if user clicks Undo)
 * @param {Number} maxLength - max length of input
 * @param {String} inputComponent - 'input' or 'textarea'
 * @param {Boolean} startWithEditViewOpen - whether to start with edit view open (default: false)
 * @param {String} displayPlaceholder - placeholder for display view when value is empty
 * @param {Object} textAreaProps - props to override antd's Input.TextArea
 * @returns {ReactDOM}
 */
function InlineEdit({
  onSave = () => {},
  displayRenderer = () => {},
  initialValue = null,
  defaultValue = null,
  maxLength = globals.DEFAULT_INPUT_MAX_LENGTH,
  inputComponent = 'input', // 'input' | 'textarea'
  startWithEditViewOpen = false,
  displayPlaceholder = globals.DEFAULT_PLACEHOLDER,
  textAreaProps = {},
}) {
  const [isEditing, setIsEditing] = useState(startWithEditViewOpen);
  const [label, setLabel] = useState(initialValue);
  const inputRef = useRef();
  // const [form] = useForm();
 
  // to deal with i18n related changes in initialValue
  useEffect(() => {
    setLabel(initialValue);
 
    return () => {};
  }, [initialValue]);
 
  // to autofocus on input when first click
  useEffect(() => {
    if (isEditing && inputRef.current) { inputRef.current.focus({ cursor: 'all' }); }
 
    return () => {};
  }, [isEditing, inputRef]);
 
  const onSaveValue = (value) => {
    onSave(value);
    setLabel(value);
    setIsEditing(false);
  };
 
  const onUndoClick = (e) => {
    e.preventDefault();
    onSaveValue(defaultValue);
  };
 
  // INPUT: to save on enter / blur
  // Factory to create different input types (input / textarea)
  const editDOM = (
    <div className="inline-edit__input-wrapper">
      <InlineEditInputFactory
        label={label}
        initialLabel={initialValue}
        defaultLabel={defaultValue}
        onSave={onSaveValue}
        setLabel={setLabel}
        inputRef={inputRef}
        onUndoClick={onUndoClick}
        maxLength={maxLength}
        component={inputComponent}
        textAreaProps={textAreaProps}
      />
    </div>
  );
 
  const displayDOM = (
    <InlineEditDisplay
      onClick={() => {
        setIsEditing(true);
      }}
      label={label}
      placeholder={displayPlaceholder}
      displayRenderer={displayRenderer}
    />
  );
 
  // DISPLAY: to display the value
  return (
    <StyleWrapper>
      {isEditing ? editDOM : displayDOM}
    </StyleWrapper>
  );
}
export default InlineEdit;