Source: input/DrawOqt.js

import React, { createContext, useContext, useEffect, useRef, useState } from "react";
import CanvasDraw from "react-canvas-draw";
import { processOptions, FormContext, fakeEvent, useVariables, booleanString } from "../..";

/**
 * Componente que renderiza una pizarra donde el usuario puede dibujar libremente.
 * En la documentacion se pueden consultar las opciones que acepta options: https://github.com/embiem/react-canvas-draw
 * 
 * @name Reactor.Components.Input.DrawOqt
 * @param {ControlName!} name Identificacion del control
 * @param {DataURL} [value = ""] 
 *    El valor por defecto del componente
 * @param {BooleanString} [use_change = "true"] 
 *    Determina si se usara el evento de cambio
 * @param {string} [delay = "1000"] 
 *    El tiempo que demora en enviar el evento de cambio al form (en ms)
 * @param {DrawOqtOptions} [options = {...}] 
 *    Json string con las opciones de CanvasDraw. Default:
 *    <pre> {
 *      "loadTimeOffset": 5,
 *      "lazyRadius": 1,
 *      "brushRadius": 1,
 *      "brushColor": "#444",
 *      "catenaryColor": "#0a0302",
 *      "gridColor": "rgba(150,150,150,0.17)",
 *      "hideGrid": false,
 *      "canvasWidth": 400,
 *      "canvasHeight": 400,
 *      "disabled": false,
 *      "imgSrc": "",
 *      "immediateLoading": false,
 *      "hideInterface": false,
 *      "gridSizeX": 25,
 *      "gridSizeY": 25,
 *      "gridLineWidth": 0.5,
 *      "hideGridX": false,
 *      "hideGridY": false,
 *      "enablePanAndZoom": false,
 *      "mouseZoomFactor": 0.01,
 *      "zoomExtents": { "min": 0.33, "max": 3 }
 *    }</pre>
 * @param {string?} change_var Variable que tomarĂ¡ el valor del control cuando se modifique
 * @param {string} [context = "global"] Contexto donde se encuentra la variable
 * @class 
 * @returns {string} Data URL string
 * @example 
<draw name="firma" options='{"brushColor": "blue"}'></draw>
*/

export const DrawOqt = ({name, value = "", use_change = "true", delay = "1000", options, children, change_var, debug = "false", context = "global", ...otherProps}) => {

  const variables = useVariables({variable: change_var, context});
  const [state, setState] = useState({value: value || otherProps.defaultValue });
  const [props, setProps] = useState({...defaultProps, ...processOptions(options)});
  const formContext = useContext(FormContext);
  const inputRef = useRef();
  const saveableCanvas  = useRef();

  const handleChange = () => {
    const dataUrl = saveableCanvas.current.getDataURL()
    setState(state => ({...state, value: dataUrl}));
    if(change_var && context){
      variables.setData(dataUrl);
    }
  };

  useEffect(()=>{
    formContext?.change(fakeEvent({name, use_change, delay}));
  }, [state.value]);

  useEffect(()=>{
    setState(state => ({...state, value: null}))
  }, [value, props.defaultValue]);

  const setBrushColor = (newColor = "") => {
    booleanString(debug) && console.log({event: "DrawOqt setBrushColor", newColor});
    setProps(props => ({...props, brushColor: newColor}));
  }

  const undo = () => {
    saveableCanvas.current.undo();
  }

  const reset = () => {
    saveableCanvas.current.eraseAll();
  }

  return (
    <>
      <input 
        ref={inputRef}
        name={name}
        value={state.value}
        type="hidden"
      />
      <CanvasDraw ref={saveableCanvas} {...props} onChange={handleChange}  />
      <DrawOqtContext.Provider value={{props, setBrushColor, undo, reset}}>
        {children}
      </DrawOqtContext.Provider>     
    </>
  )
}

export const DrawOqtContext = createContext({
  undo: ()=>{},
  reset: ()=>{},
  setBrushColor: (newColor)=>{},
  props: defaultProps
});

const defaultProps = {
  onChange: null,
  saveData: null,
  loadTimeOffset: 5,
  lazyRadius: 1,
  brushRadius: 1,
  brushColor: "#444",
  catenaryColor: "#0a0302",
  gridColor: "rgba(150,150,150,0.17)",
  hideGrid: false,
  canvasWidth: 400,
  canvasHeight: 400,
  disabled: false,
  imgSrc: "",
  immediateLoading: false,
  hideInterface: false,
  gridSizeX: 25,
  gridSizeY: 25,
  gridLineWidth: 0.5,
  hideGridX: false,
  hideGridY: false,
  enablePanAndZoom: false,
  mouseZoomFactor: 0.01,
  zoomExtents: { min: 0.33, max: 3 }
};