import { e as Context, j as jsxRuntimeExports, M as MathJax } from "./doenetml-cB_aZGJ5.js";
import { useState, useRef, useContext, useEffect } from "react";
import { u as useDoenetRenderer } from "./useDoenetRenderer-DN3Z9CW3.js";
import { s as sizeToCSS } from "./css-BJLDLYRJ.js";
import { BoardContext } from "./graph-DQks9OE0.js";
import { g as getPositionFromAnchorByCoordinate, P as POINTER_DRAG_THRESHOLD } from "./graph-FesVg1vs.js";
import { c as calculateValidationState, a as createCheckWorkComponent } from "./checkWork-D9syAFsW.js";
import { D as DescriptionPopover } from "./Description-kxNMQ7JQ.js";
import { a as addValidationStateToShortDescription } from "./description-CVwSJZpB.js";
function TextInput(props) {
  let { id, SVs, children, actions, ignoreUpdate, callAction } = useDoenetRenderer(props);
  let width = sizeToCSS(SVs.width);
  sizeToCSS(SVs.height);
  TextInput.baseStateVariable = "immediateValue";
  TextInput.ignoreActionsWithoutCore = (actionName) => actionName === "moveInput";
  const [rendererValue, setRendererValue] = useState(SVs.immediateValue);
  let rendererValueRef = useRef(null);
  rendererValueRef.current = rendererValue;
  let valueToRevertTo = useRef(SVs.immediateValue);
  let focused = useRef(null);
  let immediateValueWhenSetState = useRef(null);
  let inputJXG = useRef(null);
  let anchorPointJXG = useRef(null);
  let anchorRel = useRef(null);
  const board = useContext(BoardContext);
  let pointerAtDown = useRef(null);
  let pointAtDown = useRef(null);
  let dragged = useRef(false);
  let calculatedX = useRef(null);
  let calculatedY = useRef(null);
  let lastPositionFromCore = useRef(null);
  let previousPositionFromAnchor = useRef(null);
  let fixed = useRef(false);
  let fixLocation = useRef(false);
  fixed.current = SVs.fixed;
  fixLocation.current = !SVs.draggable || SVs.fixLocation || SVs.fixed;
  useEffect(() => {
    return () => {
      if (inputJXG.current !== null) {
        deleteInputJXG();
      }
    };
  }, []);
  if (!ignoreUpdate && immediateValueWhenSetState.current !== SVs.immediateValue) {
    setRendererValue(SVs.immediateValue);
    immediateValueWhenSetState.current = SVs.immediateValue;
    valueToRevertTo.current = SVs.immediateValue;
  } else {
    immediateValueWhenSetState.current = null;
  }
  const validationState = calculateValidationState(SVs);
  const submitAnswer = () => callAction({
    action: actions.submitAnswer
  });
  function handleKeyPress(e) {
    if (e.key === "Enter") {
      valueToRevertTo.current = rendererValueRef.current;
      callAction({
        action: actions.updateValue,
        baseVariableValue: rendererValueRef.current
      });
      if (SVs.showCheckWork && !SVs.expanded && validationState === "unvalidated") {
        submitAnswer();
      }
    }
  }
  function handleKeyDown(e) {
    if (e.key === "Escape") {
      let oldValue = valueToRevertTo.current;
      if (oldValue !== rendererValueRef.current) {
        setRendererValue(oldValue);
        immediateValueWhenSetState.current = SVs.immediateValue;
        callAction({
          action: actions.updateImmediateValue,
          args: {
            text: oldValue
          },
          baseVariableValue: oldValue
        });
      }
    }
  }
  function handleFocus() {
    focused.current = true;
  }
  function handleBlur() {
    focused.current = false;
    valueToRevertTo.current = rendererValueRef.current;
    callAction({
      action: actions.updateValue,
      baseVariableValue: rendererValueRef.current
    });
  }
  function onChangeHandler(e) {
    let newValue = e.target.value;
    if (newValue !== rendererValueRef.current) {
      setRendererValue(newValue);
      immediateValueWhenSetState.current = SVs.immediateValue;
      callAction({
        action: actions.updateImmediateValue,
        args: {
          text: newValue
        },
        baseVariableValue: newValue
      });
    }
  }
  function createInputJXG() {
    if (board === null) {
      return null;
    }
    let jsxInputAttributes = {
      visible: !SVs.hidden,
      fixed: fixed.current,
      disabled: SVs.disabled,
      useMathJax: SVs.labelHasLatex,
      strokeColor: "var(--canvasText)",
      highlightStrokeColor: "var(--canvasText)",
      highlight: !fixLocation.current,
      parse: false
    };
    let newAnchorPointJXG;
    try {
      let anchor = Context.fromAst(SVs.anchor);
      let anchorCoords = [
        anchor.get_component(0).evaluate_to_constant(),
        anchor.get_component(1).evaluate_to_constant()
      ];
      if (!Number.isFinite(anchorCoords[0])) {
        anchorCoords[0] = 0;
        jsxInputAttributes["visible"] = false;
      }
      if (!Number.isFinite(anchorCoords[1])) {
        anchorCoords[1] = 0;
        jsxInputAttributes["visible"] = false;
      }
      newAnchorPointJXG = board.create("point", anchorCoords, {
        visible: false
      });
    } catch (e) {
      jsxInputAttributes["visible"] = false;
      newAnchorPointJXG = board.create("point", [0, 0], {
        visible: false
      });
      return;
    }
    jsxInputAttributes.anchor = newAnchorPointJXG;
    let { anchorx, anchory } = getPositionFromAnchorByCoordinate(
      SVs.positionFromAnchor
    );
    jsxInputAttributes.anchorx = anchorx;
    jsxInputAttributes.anchory = anchory;
    anchorRel.current = [anchorx, anchory];
    let newInputJXG = board.create(
      "input",
      [0, 0, rendererValue, SVs.label],
      jsxInputAttributes
    );
    newInputJXG.isDraggable = !fixLocation.current;
    newInputJXG.rendNodeInput.addEventListener(
      "input",
      onChangeHandler
    );
    newInputJXG.rendNodeInput.addEventListener(
      "keypress",
      handleKeyPress
    );
    newInputJXG.rendNodeInput.addEventListener(
      "keydown",
      handleKeyDown
    );
    newInputJXG.rendNodeInput.addEventListener("blur", handleBlur);
    newInputJXG.rendNodeInput.addEventListener("focus", handleFocus);
    newInputJXG.rendNodeInput.style.width = width;
    newInputJXG.rendNodeInput.style.color = "var(--canvasText)";
    newInputJXG.rendNodeInput.style.background = "var(--canvas)";
    newInputJXG.rendNodeInput.style.borderColor = "var(--canvasText)";
    newInputJXG.rendNodeLabel.style.marginRight = "2px";
    newInputJXG.on("down", function(e) {
      document.activeElement?.blur();
      pointerAtDown.current = [e.x, e.y];
      pointAtDown.current = [...newAnchorPointJXG.coords.scrCoords];
      dragged.current = false;
    });
    newInputJXG.on("hit", function(e) {
      dragged.current = false;
    });
    newInputJXG.on("up", function(e) {
      if (dragged.current) {
        callAction({
          action: actions.moveInput,
          args: {
            x: calculatedX.current,
            y: calculatedY.current
          }
        });
        dragged.current = false;
      }
    });
    newInputJXG.on("keyfocusout", function(e) {
      if (dragged.current) {
        callAction({
          action: actions.moveInput,
          args: {
            x: calculatedX.current,
            y: calculatedY.current
          }
        });
        dragged.current = false;
      }
    });
    newInputJXG.on("drag", function(e) {
      let viaPointer = e.type === "pointermove";
      if (!viaPointer || Math.abs(e.x - pointerAtDown.current[0]) > POINTER_DRAG_THRESHOLD || Math.abs(e.y - pointerAtDown.current[1]) > POINTER_DRAG_THRESHOLD) {
        dragged.current = true;
      }
      let [xMin, yMax, xMax, yMin] = board.getBoundingBox();
      let width2 = newInputJXG.size[0] / board.unitX;
      let height2 = newInputJXG.size[1] / board.unitY;
      let anchorx2 = anchorRel.current?.[0] || 0;
      let anchory2 = anchorRel.current?.[1] || 0;
      let offsetx = 0;
      if (anchorx2 === "middle") {
        offsetx = -width2 / 2;
      } else if (anchorx2 === "right") {
        offsetx = -width2;
      }
      let offsety = 0;
      if (anchory2 === "middle") {
        offsety = -height2 / 2;
      } else if (anchory2 === "top") {
        offsety = -height2;
      }
      let xminAdjusted = xMin + 0.04 * (xMax - xMin) - offsetx - width2;
      let xmaxAdjusted = xMax - 0.04 * (xMax - xMin) - offsetx;
      let yminAdjusted = yMin + 0.04 * (yMax - yMin) - offsety - height2;
      let ymaxAdjusted = yMax - 0.04 * (yMax - yMin) - offsety;
      if (viaPointer && pointAtDown.current && pointerAtDown.current) {
        var o = board.origin.scrCoords;
        calculatedX.current = (pointAtDown.current[1] + e.x - pointerAtDown.current[0] - o[1]) / board.unitX;
        calculatedY.current = (o[2] - (pointAtDown.current[2] + e.y - pointerAtDown.current[1])) / board.unitY;
      } else {
        calculatedX.current = newAnchorPointJXG.X() + newInputJXG.relativeCoords.usrCoords[1];
        calculatedY.current = newAnchorPointJXG.Y() + newInputJXG.relativeCoords.usrCoords[2];
      }
      calculatedX.current = Math.min(
        xmaxAdjusted,
        Math.max(xminAdjusted, calculatedX.current)
      );
      calculatedY.current = Math.min(
        ymaxAdjusted,
        Math.max(yminAdjusted, calculatedY.current)
      );
      callAction({
        action: actions.moveInput,
        args: {
          x: calculatedX.current,
          y: calculatedY.current,
          transient: true,
          skippable: true
        }
      });
      newInputJXG.relativeCoords.setCoordinates(
        JXG.COORDS_BY_USER,
        [0, 0]
      );
      newAnchorPointJXG.coords.setCoordinates(
        JXG.COORDS_BY_USER,
        lastPositionFromCore.current
      );
    });
    newInputJXG.on("keydown", function(e) {
      if (e.key === "Enter") {
        if (dragged.current) {
          callAction({
            action: actions.moveInput,
            args: {
              x: calculatedX.current,
              y: calculatedY.current
            }
          });
          dragged.current = false;
        }
      }
    });
    inputJXG.current = newInputJXG;
    anchorPointJXG.current = newAnchorPointJXG;
    previousPositionFromAnchor.current = SVs.positionFromAnchor;
    if (SVs.labelHasLatex) {
      setTimeout(() => {
        if (inputJXG.current) {
          inputJXG.current.needsUpdate = true;
          inputJXG.current.setText(SVs.label);
          inputJXG.current.update();
          board?.updateRenderer();
        }
      }, 1e3);
    }
  }
  function deleteInputJXG() {
    if (!inputJXG.current) {
      return;
    }
    inputJXG.current.rendNodeInput.removeEventListener(
      "input",
      onChangeHandler
    );
    inputJXG.current.rendNodeInput.removeEventListener(
      "keypress",
      handleKeyPress
    );
    inputJXG.current.rendNodeInput.removeEventListener(
      "keydown",
      handleKeyDown
    );
    inputJXG.current.rendNodeInput.removeEventListener("blur", handleBlur);
    inputJXG.current.rendNodeInput.removeEventListener(
      "focus",
      handleFocus
    );
    inputJXG.current.off("drag");
    inputJXG.current.off("down");
    inputJXG.current.off("hit");
    inputJXG.current.off("up");
    inputJXG.current.off("keyfocusout");
    inputJXG.current.off("keydown");
    board?.removeObject(inputJXG.current);
    inputJXG.current = null;
  }
  if (board) {
    let anchorCoords;
    try {
      let anchor = Context.fromAst(SVs.anchor);
      anchorCoords = [
        anchor.get_component(0).evaluate_to_constant(),
        anchor.get_component(1).evaluate_to_constant()
      ];
    } catch (e) {
      anchorCoords = [NaN, NaN];
    }
    lastPositionFromCore.current = anchorCoords;
    if (inputJXG.current === null) {
      createInputJXG();
    } else if (anchorPointJXG.current) {
      if (inputJXG.current.Value() !== rendererValue) {
        inputJXG.current.set(rendererValue);
      }
      inputJXG.current.relativeCoords.setCoordinates(
        JXG.COORDS_BY_USER,
        [0, 0]
      );
      anchorPointJXG.current.coords.setCoordinates(
        JXG.COORDS_BY_USER,
        anchorCoords
      );
      inputJXG.current.setText(SVs.label);
      inputJXG.current.rendNodeInput.style.width = width;
      let visible = !SVs.hidden;
      if (Number.isFinite(anchorCoords[0]) && Number.isFinite(anchorCoords[1])) {
        let actuallyChangedVisibility = inputJXG.current.visProp["visible"] !== visible;
        inputJXG.current.visProp["visible"] = visible;
        inputJXG.current.visPropCalc["visible"] = visible;
        if (actuallyChangedVisibility) {
          inputJXG.current.setAttribute({ visible });
        }
      } else {
        inputJXG.current.visProp["visible"] = false;
        inputJXG.current.visPropCalc["visible"] = false;
      }
      if (inputJXG.current.visProp.disabled !== SVs.disabled) {
        inputJXG.current.visProp.disabled = SVs.disabled;
        inputJXG.current.setAttribute({ disabled: SVs.disabled });
      }
      inputJXG.current.visProp.highlight = !fixLocation.current;
      inputJXG.current.visProp.fixed = fixed.current;
      inputJXG.current.isDraggable = !fixLocation.current;
      inputJXG.current.needsUpdate = true;
      if (SVs.positionFromAnchor !== previousPositionFromAnchor.current) {
        let { anchorx, anchory } = getPositionFromAnchorByCoordinate(
          SVs.positionFromAnchor
        );
        inputJXG.current.visProp.anchorx = anchorx;
        inputJXG.current.visProp.anchory = anchory;
        anchorRel.current = [anchorx, anchory];
        previousPositionFromAnchor.current = SVs.positionFromAnchor;
        inputJXG.current.fullUpdate();
      } else {
        inputJXG.current.update();
      }
      anchorPointJXG.current.needsUpdate = true;
      anchorPointJXG.current.update();
      board.updateRenderer();
    }
    return /* @__PURE__ */ jsxRuntimeExports.jsx("span", { id });
  }
  if (SVs.hidden) {
    return null;
  }
  let disabled = SVs.disabled;
  const inputKey = id + "_input";
  const checkWorkComponent = createCheckWorkComponent(
    SVs,
    id,
    validationState,
    submitAnswer,
    false
  );
  let input;
  let label = SVs.label;
  if (SVs.labelHasLatex) {
    label = /* @__PURE__ */ jsxRuntimeExports.jsx(MathJax, { hideUntilTypeset: "first", inline: true, dynamic: true, children: label });
  }
  let shortDescription = SVs.shortDescription || void 0;
  const descriptionChild = children.find((child) => child);
  let descriptionId = void 0;
  let description = null;
  if (descriptionChild) {
    descriptionId = `${id}-description-content`;
    description = /* @__PURE__ */ jsxRuntimeExports.jsx(DescriptionPopover, { children: /* @__PURE__ */ jsxRuntimeExports.jsx("div", { id: descriptionId, children: descriptionChild }) });
  }
  let inputClass = "text-input" + (SVs.disabled ? " text-input-disabled" : "");
  if (SVs.colorCorrectness) {
    inputClass += ` text-input-${validationState}`;
    shortDescription = addValidationStateToShortDescription(
      validationState,
      shortDescription
    );
  }
  if (SVs.expanded) {
    input = /* @__PURE__ */ jsxRuntimeExports.jsxs("label", { style: { display: "inline-flex", maxWidth: "100%" }, children: [
      label,
      /* @__PURE__ */ jsxRuntimeExports.jsx(
        "textarea",
        {
          id: inputKey,
          value: rendererValue,
          disabled,
          onChange: onChangeHandler,
          onKeyPress: handleKeyPress,
          onKeyDown: handleKeyDown,
          onBlur: handleBlur,
          onFocus: handleFocus,
          className: inputClass,
          "aria-label": shortDescription,
          "aria-details": descriptionId,
          style: {
            margin: "0px 4px 4px 4px",
            color: "var(--canvasText)",
            background: "var(--canvas)"
          }
        },
        inputKey
      )
    ] });
  } else {
    input = /* @__PURE__ */ jsxRuntimeExports.jsxs("label", { style: { display: "inline-flex", maxWidth: "100%" }, children: [
      label,
      /* @__PURE__ */ jsxRuntimeExports.jsx(
        "input",
        {
          id: inputKey,
          value: rendererValue,
          disabled,
          onChange: onChangeHandler,
          onKeyPress: handleKeyPress,
          onKeyDown: handleKeyDown,
          onBlur: handleBlur,
          onFocus: handleFocus,
          className: inputClass,
          "aria-label": shortDescription,
          "aria-details": descriptionId,
          style: {
            margin: "0px 4px 4px 4px",
            color: "var(--canvasText)",
            background: "var(--canvas)",
            width,
            height: "20px"
          }
        },
        inputKey
      )
    ] });
  }
  return /* @__PURE__ */ jsxRuntimeExports.jsxs(
    "span",
    {
      id,
      style: {
        display: "inline-flex",
        maxWidth: "100%",
        alignItems: "start"
      },
      children: [
        input,
        checkWorkComponent,
        description
      ]
    }
  );
}
export {
  TextInput as default
};
