tmp/webapp-docs/frontend/components/DplAskCorner.js

/**
 * The free-text AI control pinned to the top-right **corner** of the Manage block editor's DPL box: a
 * joined **Modify / Draft** combo that opens a small popover with one input. **Modify** re-processes the
 * current template with a typed instruction; **Draft** builds a fresh template from a description. It's
 * a compact corner affordance (like the composer's eye/gear) rather than a slab under the toolbar.
 *
 * Presentational: it reports the typed text up via `onCustom(instruction)` / `onCreate(description)`;
 * the parent ({@link module:gui/components/ManageBlockEditor}) owns the provider call + apply + busy.
 * @module gui/components/DplAskCorner
 */
import { useEffect, useRef, useState } from "react";
import { useIntl } from "react-intl";
import { m } from "../lib/dpl/dplRefineMessages.js";

/**
 * @param {object} props
 * @param {string} [props.busyMode] The mode string currently running (`""`/undefined when idle).
 * @param {boolean} [props.disabled] Hard-disable the control (e.g. while saving).
 * @param {Function} props.onCreate `(description)` — draft a new template.
 * @param {Function} props.onCustom `(instruction)` — apply a change to the current template.
 * @returns {JSX.Element}
 */
import { jsxDEV as _jsxDEV, Fragment as _Fragment } from "react/jsx-dev-runtime";
export default function DplAskCorner({
  busyMode = "",
  disabled = false,
  onCreate,
  onCustom
}) {
  const intl = useIntl();
  const busy = Boolean(busyMode);
  const [open, setOpen] = useState(false);
  const [intent, setIntent] = useState("modify");
  const [text, setText] = useState("");
  const inputRef = useRef(null);
  const running = busyMode === "dpl-custom" || busyMode === "dpl-create";
  useEffect(() => {
    if (open) inputRef.current?.focus();
  }, [open, intent]);
  // Keep the popover open while a request runs; close it once it settles.
  const wasBusy = useRef(false);
  useEffect(() => {
    if (wasBusy.current && !busy) setOpen(false);
    wasBusy.current = busy;
  }, [busy]);
  useEffect(() => {
    if (!open) return undefined;
    const onKey = e => e.key === "Escape" && !busy && setOpen(false);
    window.addEventListener("keydown", onKey);
    return () => window.removeEventListener("keydown", onKey);
  }, [open, busy]);
  const pick = next => {
    if (open && intent === next) {
      setOpen(false);
      return;
    }
    setIntent(next);
    setOpen(true);
  };
  const submit = () => {
    const t = text.trim();
    if (!t) {
      inputRef.current?.focus();
      return;
    }
    if (intent === "create") onCreate?.(t);else onCustom?.(t);
    // Text is kept: modify is iterative, and a validation bounce shouldn't wipe it.
  };
  const isCreate = intent === "create";
  const sendLabel = running ? isCreate ? m.drafting : m.modifying : isCreate ? m.createSubmit : m.send;
  return /*#__PURE__*/_jsxDEV("div", {
    className: "dpl-ask-corner",
    children: [/*#__PURE__*/_jsxDEV("div", {
      className: "dpl-ask-combo",
      role: "group",
      "aria-label": intl.formatMessage(m.toolbarAsk),
      children: [/*#__PURE__*/_jsxDEV("button", {
        type: "button",
        className: `dpl-ask-seg${open && intent === "modify" ? " on" : ""}`,
        onClick: () => pick("modify"),
        disabled: disabled || busy,
        "aria-haspopup": "dialog",
        "aria-expanded": open && intent === "modify",
        title: intl.formatMessage(m.askModifyHint),
        children: intl.formatMessage(m.askModify)
      }, void 0, false), /*#__PURE__*/_jsxDEV("button", {
        type: "button",
        className: `dpl-ask-seg${open && intent === "create" ? " on" : ""}`,
        onClick: () => pick("create"),
        disabled: disabled || busy,
        "aria-haspopup": "dialog",
        "aria-expanded": open && intent === "create",
        title: intl.formatMessage(m.askCreateHint),
        children: intl.formatMessage(m.askCreate)
      }, void 0, false)]
    }, void 0, true), open && /*#__PURE__*/_jsxDEV(_Fragment, {
      children: [/*#__PURE__*/_jsxDEV("div", {
        className: "dpl-ask-scrim",
        onClick: () => !busy && setOpen(false),
        "aria-hidden": "true"
      }, void 0, false), /*#__PURE__*/_jsxDEV("div", {
        className: "dpl-ask-pop",
        role: "dialog",
        "aria-label": intl.formatMessage(isCreate ? m.askCreateTitle : m.askModifyTitle),
        children: [/*#__PURE__*/_jsxDEV("div", {
          className: "dpl-ask-pop-title",
          children: intl.formatMessage(isCreate ? m.askCreateTitle : m.askModifyTitle)
        }, void 0, false), /*#__PURE__*/_jsxDEV("textarea", {
          ref: inputRef,
          className: "dpl-ask-input",
          rows: 3,
          value: text,
          onChange: e => setText(e.target.value),
          onKeyDown: e => {
            if (e.key === "Enter" && (e.metaKey || e.ctrlKey)) {
              e.preventDefault();
              submit();
            }
          },
          placeholder: intl.formatMessage(isCreate ? m.createPlaceholder : m.modifyPlaceholder),
          "aria-label": intl.formatMessage(isCreate ? m.createAria : m.modifyAria),
          disabled: busy
        }, void 0, false), /*#__PURE__*/_jsxDEV("div", {
          className: "dpl-ask-pop-foot",
          children: [/*#__PURE__*/_jsxDEV("span", {
            className: "dpl-ask-hint",
            children: intl.formatMessage(m.askEnterHint)
          }, void 0, false), /*#__PURE__*/_jsxDEV("button", {
            type: "button",
            className: "primary dpl-ask-send",
            onClick: submit,
            disabled: busy || !text.trim(),
            children: intl.formatMessage(sendLabel)
          }, void 0, false)]
        }, void 0, true)]
      }, void 0, true)]
    }, void 0, true)]
  }, void 0, true);
}