"use strict";

var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
exports.__esModule = true;
exports.DateTimeEdit = void 0;
var _extends2 = _interopRequireDefault(require("@babel/runtime/helpers/extends"));
var _react = _interopRequireWildcard(require("react"));
var _patternsFields = require("@wix/patterns-fields");
var _useCloseOnAncestorScroll = require("../../../../hooks/useCloseOnAncestorScroll");
var _mergeDateTime = require("./mergeDateTime");
var _formatters = require("./formatters");
var _helpers = require("./helpers");
var _subCellContext = require("./subCellContext");
var _EditStCss = require("./Edit.st.css.js");
var _jsxFileName = "/home/builduser/work/843658b9f44192f0/packages/cairo/dist/cjs/components/EditableTable/cellTypes/datetime/Edit.tsx";
function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function (e, t) { if (!t && e && e.__esModule) return e; var o, i, f = { __proto__: null, default: e }; if (null === e || "object" != typeof e && "function" != typeof e) return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f); } for (const t in e) "default" !== t && {}.hasOwnProperty.call(e, t) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, t)) && (i.get || i.set) ? o(f, t, i) : f[t] = e[t]); return f; })(e, t); }
/**
 * DateTimeEdit — 2-in-1 sub-cell editor.
 *
 * Single `Date | null` value rendered as two halves (date | time) with a
 * vertical divider. Each half has its own focus + edit lifecycle, but only
 * one sub-cell is in edit mode at a time. Commits merge the half-value back
 * into the full `Date` before calling onChange (so the other half is
 * preserved).
 *
 * The EditableTable framework has no sub-cell concept — `focusedCell` /
 * `editingCell` are `{rowKey, columnId}` only. So sub-cell focus, intra-cell
 * Tab interception, and date-popover focused-day capture all live here.
 */

const DateTimeEdit = ({
  value,
  onChange,
  onCommit,
  onCancel,
  inputRef,
  editTrigger
}) => {
  const {
    t
  } = (0, _patternsFields.useTranslations)();

  // Initial sub-cell. The View records the clicked half via
  // `onMouseDownCapture` (capture phase, before the framework's onClick
  // stopPropagation) into the wrapper-provided tracker; consume it once.
  const tracker = (0, _subCellContext.useSubCellClickTracker)();
  const [subEdit, setSubEdit] = (0, _react.useState)(() => {
    if (editTrigger === 'click' || editTrigger === 'doubleClick') {
      return tracker.consume() ?? 'date';
    }
    return 'date';
  });
  const dateWrapperRef = (0, _react.useRef)(null);
  const timeWrapperRef = (0, _react.useRef)(null);
  const datePickerRef = (0, _react.useRef)(null);
  const timeInputRef = (0, _react.useRef)(null);
  // Direct refs to the underlying <input> in each half. Populated by
  // CellDateInput / CellTimeInput via their object-ref `inputRef` prop.
  // Used for focus, programmatic typed-key forwarding, and the "is the
  // date input focused?" check — instead of querySelector'ing into WDS
  // internals.
  const dateInputElRef = (0, _react.useRef)(null);
  const timeInputElRef = (0, _react.useRef)(null);
  const isInsideCell = (0, _react.useCallback)(target => {
    var _dateWrapperRef$curre, _timeWrapperRef$curre;
    if (!(target instanceof Node)) {
      return false;
    }
    return Boolean(((_dateWrapperRef$curre = dateWrapperRef.current) == null ? void 0 : _dateWrapperRef$curre.contains(target)) || ((_timeWrapperRef$curre = timeWrapperRef.current) == null ? void 0 : _timeWrapperRef$curre.contains(target)));
  }, []);

  // Latest date from the date input (typed or picked), NOT yet committed to
  // editingValue. WDS DateInput's `componentDidUpdate` reformats the input
  // text on every props.value change, so calling onChange while the user is
  // still in the date half would overwrite mid-typing input. We stash here
  // and flush on focusout / intra-cell Tab / Escape.
  const typedDateRef = (0, _react.useRef)(null);
  const onChangeRef = (0, _react.useRef)(onChange);
  const onCommitRef = (0, _react.useRef)(onCommit);
  const valueRef = (0, _react.useRef)(value);
  const subEditRef = (0, _react.useRef)(subEdit);
  onChangeRef.current = onChange;
  onCommitRef.current = onCommit;
  valueRef.current = value;
  subEditRef.current = subEdit;

  // Type-to-edit trigger is consumed exactly once on mount. Without this
  // guard, both type-forwarding effects below would re-inject the typed
  // character every time `subEdit` changes (Tab between halves), because
  // `editTrigger` stays stable for the lifetime of the edit session.
  const typeTriggerConsumedRef = (0, _react.useRef)(false);
  const commitTypedDate = (0, _react.useCallback)(() => {
    if (typedDateRef.current) {
      onChangeRef.current(typedDateRef.current);
      typedDateRef.current = null;
    }
  }, []);
  const closeCalendar = (0, _react.useCallback)(() => {
    var _datePickerRef$curren;
    return (_datePickerRef$curren = datePickerRef.current) == null ? void 0 : _datePickerRef$curren.closeCalendar();
  }, []);
  (0, _useCloseOnAncestorScroll.useCloseOnAncestorScroll)(dateWrapperRef, closeCalendar, subEdit === 'date');
  const closeTimeDropdown = (0, _react.useCallback)(() => {
    var _timeInputRef$current;
    return (_timeInputRef$current = timeInputRef.current) == null ? void 0 : _timeInputRef$current.blur();
  }, []);
  (0, _useCloseOnAncestorScroll.useCloseOnAncestorScroll)(timeWrapperRef, closeTimeDropdown, subEdit === 'time');

  // Flush typed-but-not-committed date when focus leaves the date half. The
  // gesture paths (calendar day pick, Tab/Enter on focused day, intra-cell
  // Tab, Enter on input) flush via their own handlers; this covers external
  // exits — clicking another cell, the toolbar, or anything else outside
  // the date wrapper. Without it the framework's commitEdit (triggered by
  // the focus shift to another cell) would read the stale editingValue and
  // silently discard the user's typing.
  (0, _react.useEffect)(() => {
    if (subEdit !== 'date') {
      return;
    }
    const wrapper = dateWrapperRef.current;
    if (!wrapper) {
      return;
    }
    const onFocusOut = e => {
      const next = e.relatedTarget;
      if (next && wrapper.contains(next)) {
        return;
      }
      commitTypedDate();
    };
    wrapper.addEventListener('focusout', onFocusOut);
    return () => {
      wrapper.removeEventListener('focusout', onFocusOut);
    };
  }, [subEdit, commitTypedDate]);

  // Focus active sub-input on mount / sub-cell switch. Deferred via rAF so
  // any in-flight click chain finishes before WDS dropdown options mount —
  // otherwise a stray mousedown can land on a freshly-rendered option and
  // silently commit a value the user never picked.
  (0, _react.useEffect)(() => {
    if (subEdit === 'time') {
      const raf = requestAnimationFrame(() => {
        const input = timeInputElRef.current;
        if (input) {
          input.focus();
          input.click(); // auto-open WDS TimeInput dropdown
        }
      });
      return () => cancelAnimationFrame(raf);
    }
    const raf = requestAnimationFrame(() => {
      var _datePickerRef$curren2;
      (_datePickerRef$curren2 = datePickerRef.current) == null || _datePickerRef$curren2.focus();
    });
    return () => cancelAnimationFrame(raf);
  }, [subEdit]);

  // Type-to-edit: forward the typed character into the initial sub-cell's
  // input. Runs once via typeTriggerConsumedRef — re-running on sub-cell
  // switches would re-inject the digit every time the user Tabs between the
  // date and time halves (editTrigger stays stable for the whole session).
  (0, _react.useEffect)(() => {
    if (typeTriggerConsumedRef.current) {
      return;
    }
    if (!editTrigger || typeof editTrigger !== 'object' || editTrigger.kind !== 'type') {
      return;
    }
    typeTriggerConsumedRef.current = true;
    const key = editTrigger.key;
    if (key.length !== 1) {
      return;
    }
    const raf = requestAnimationFrame(() => {
      if (subEditRef.current === 'date') {
        var _datePickerRef$curren3;
        (_datePickerRef$curren3 = datePickerRef.current) == null || _datePickerRef$curren3.openCalendar();
        const dpInput = dateInputElRef.current;
        if (dpInput) {
          (0, _helpers.setNativeInputValue)(dpInput, key);
        }
        return;
      }
      const input = timeInputElRef.current;
      if (input) {
        (0, _helpers.setNativeInputValue)(input, key);
      }
    });
    return () => cancelAnimationFrame(raf);
  }, [editTrigger]);

  // Wire inputRef to whichever sub-input is currently active.
  (0, _react.useEffect)(() => {
    if (!inputRef) {
      return;
    }
    inputRef.current = (subEdit === 'time' ? timeInputElRef.current : dateInputElRef.current) ?? undefined;
  }, [subEdit, inputRef]);

  // Intra-cell Tab (date → time, Shift+Tab time → date). Document-capture
  // so we run BEFORE the table's useKeyboardNavigation Tab handler — the
  // framework only sees the Tab that should actually exit the cell.
  (0, _react.useEffect)(() => {
    const onKeyDownCapture = e => {
      if (e.key !== 'Tab') {
        return;
      }
      if (!isInsideCell(e.target)) {
        return;
      }
      if (!e.shiftKey && subEditRef.current === 'date') {
        e.preventDefault();
        e.stopImmediatePropagation();
        commitTypedDate();
        setSubEdit('time');
        return;
      }
      if (e.shiftKey && subEditRef.current === 'time') {
        e.preventDefault();
        e.stopImmediatePropagation();
        setSubEdit('date');
        return;
      }
    };
    document.addEventListener('keydown', onKeyDownCapture, true);
    return () => {
      document.removeEventListener('keydown', onKeyDownCapture, true);
    };
  }, [commitTypedDate, isInsideCell]);

  // Click on the inactive sub-cell switches sub-edit. pointerdown capture
  // only: calling preventDefault on a primary pointer's pointerdown
  // suppresses the synthesized mousedown / click that would otherwise let
  // WDS DropdownBase.onSelect commit whichever option happens to sit under
  // the click coords. Pair with the rAF defer on dropdown open above.
  (0, _react.useEffect)(() => {
    const onPointerDown = e => {
      var _target$closest;
      if (!isInsideCell(e.target)) {
        return;
      }
      const target = e.target;
      const sub = target == null || (_target$closest = target.closest('[data-sub-cell]')) == null ? void 0 : _target$closest.getAttribute('data-sub-cell');
      if (sub !== 'date' && sub !== 'time') {
        return;
      }
      if (sub === subEditRef.current) {
        return;
      }
      e.preventDefault();
      e.stopImmediatePropagation();
      setSubEdit(sub);
    };
    document.addEventListener('pointerdown', onPointerDown, true);
    return () => {
      document.removeEventListener('pointerdown', onPointerDown, true);
    };
  }, [isInsideCell]);
  const handleDateChange = (0, _react.useCallback)(newDate => {
    // Stash, don't commit — WDS DateInput reformats input text on every
    // props.value change, clobbering mid-typing input. The focusout effect
    // (and intra-cell Tab) flushes this to editingValue at the right moment.
    typedDateRef.current = (0, _mergeDateTime.mergeDate)(valueRef.current, newDate);
  }, []);
  const handleTimeChange = (0, _react.useCallback)(time => {
    if (!time) {
      // Per spec: no clear on the time half. CellTimeInput's clear button
      // is suppressed (no onClear prop). If WDS somehow emits null, no-op.
      return;
    }
    const asDate = (0, _patternsFields.timeToDate)(time);
    const merged = (0, _mergeDateTime.mergeTime)(valueRef.current, asDate);
    onChange(merged);
    onCommit();
  }, [onChange, onCommit]);

  // Clears the entire DateTime value. Wired to the date half's clear (X)
  // button — the single "remove this DateTime" affordance. Time half has no
  // clear button: there is no "date set, time null" state.
  const handleDateClear = (0, _react.useCallback)(() => {
    // Drop any stashed typed date so the focusout flush doesn't restore it
    // after we commit null.
    typedDateRef.current = null;
    onChange(null);
    onCommit();
  }, [onChange, onCommit]);
  const handleEscape = (0, _react.useCallback)(e => {
    if (e.key === 'Escape') {
      e.preventDefault();
      e.stopPropagation();
      // Cancellation drops any typed-but-stashed date. Without this, a
      // delayed focusout (browsers fire blur asynchronously when the
      // focused element is removed) could re-introduce the typed value
      // after the user already pressed Escape.
      typedDateRef.current = null;
      onCancel();
    }
  }, [onCancel]);
  const validDate = (0, _helpers.isValidDate)(value) ? value : null;
  const timeAsString = validDate ? (0, _patternsFields.dateToTime)(validDate) : null;
  const placeholderTokens = {
    day: t('CMS.cellDateTime.placeholder.day'),
    month: t('CMS.cellDateTime.placeholder.month'),
    year: t('CMS.cellDateTime.placeholder.year'),
    hour: t('CMS.cellDateTime.placeholder.hour'),
    minute: t('CMS.cellDateTime.placeholder.minute')
  };
  const datePh = (0, _formatters.datePlaceholder)(placeholderTokens);
  const timePh = (0, _formatters.timePlaceholder)(placeholderTokens);

  // Event-suppression layers in this component, by owner:
  //   1. halfHandlers.onClick / onMouseDown (React, below)
  //      → swallow the framework's "click inside cell during edit" handling
  //        so clicks on either half don't re-trigger an edit start.
  //   2. halfHandlers.onKeyDown = handleEscape (React, below)
  //      → cancels the edit before the framework's Escape behavior runs.
  //   3. document keydown capture for intra-cell Tab (useEffect above)
  //      → date↔time half switch runs BEFORE the framework's Tab handler
  //        would move focus to the next column.
  //   4. document pointerdown capture for sub-cell switch (useEffect above)
  //      → click on the inactive half switches subEdit without committing,
  //        and preventDefault suppresses the synthesized mousedown/click
  //        that would otherwise let WDS DropdownBase.onSelect commit a
  //        random option under the cursor.
  const halfHandlers = {
    onKeyDown: handleEscape,
    onClick: e => e.stopPropagation(),
    onMouseDown: e => e.stopPropagation()
  };
  return /*#__PURE__*/_react.default.createElement(_react.default.Fragment, null, /*#__PURE__*/_react.default.createElement("div", (0, _extends2.default)({
    ref: dateWrapperRef,
    "data-sub-cell": "date",
    className: _EditStCss.classes.dateHalf
  }, halfHandlers, {
    __self: void 0,
    __source: {
      fileName: _jsxFileName,
      lineNumber: 369,
      columnNumber: 7
    }
  }), subEdit === 'date' ? /*#__PURE__*/_react.default.createElement(_patternsFields.CellDateInput, {
    ref: datePickerRef,
    inputRef: dateInputElRef,
    value: validDate,
    onChange: handleDateChange,
    onClear: handleDateClear,
    placeholder: datePh,
    ariaLabel: t('CMS.cellDateTime.ariaLabel.date'),
    hidePrefix: true,
    dataHook: "datetime-date-edit",
    __self: void 0,
    __source: {
      fileName: _jsxFileName,
      lineNumber: 376,
      columnNumber: 11
    }
  }) : validDate ? /*#__PURE__*/_react.default.createElement("span", {
    className: _EditStCss.classes.passiveText,
    __self: void 0,
    __source: {
      fileName: _jsxFileName,
      lineNumber: 388,
      columnNumber: 11
    }
  }, (0, _formatters.formatDatePart)(validDate)) : /*#__PURE__*/_react.default.createElement("span", {
    className: _EditStCss.classes.placeholderText,
    __self: void 0,
    __source: {
      fileName: _jsxFileName,
      lineNumber: 392,
      columnNumber: 11
    }
  }, datePh)), /*#__PURE__*/_react.default.createElement("span", {
    "aria-hidden": true,
    className: _EditStCss.classes.divider,
    __self: void 0,
    __source: {
      fileName: _jsxFileName,
      lineNumber: 396,
      columnNumber: 7
    }
  }), /*#__PURE__*/_react.default.createElement("div", (0, _extends2.default)({
    ref: timeWrapperRef,
    "data-sub-cell": "time",
    className: _EditStCss.classes.timeHalf,
    "aria-label": t('CMS.cellDateTime.ariaLabel.time')
  }, halfHandlers, {
    __self: void 0,
    __source: {
      fileName: _jsxFileName,
      lineNumber: 398,
      columnNumber: 7
    }
  }), subEdit === 'time' ? /*#__PURE__*/_react.default.createElement(_patternsFields.CellTimeInput, {
    ref: timeInputRef,
    inputRef: timeInputElRef,
    value: timeAsString,
    onChange: handleTimeChange,
    placeholder: timePh,
    clearable: false,
    dataHook: "datetime-time-edit",
    __self: void 0,
    __source: {
      fileName: _jsxFileName,
      lineNumber: 406,
      columnNumber: 11
    }
  }) : validDate ? /*#__PURE__*/_react.default.createElement("span", {
    className: _EditStCss.classes.passiveText,
    __self: void 0,
    __source: {
      fileName: _jsxFileName,
      lineNumber: 416,
      columnNumber: 11
    }
  }, (0, _formatters.formatTimePart)(validDate)) : /*#__PURE__*/_react.default.createElement("span", {
    className: _EditStCss.classes.placeholderText,
    __self: void 0,
    __source: {
      fileName: _jsxFileName,
      lineNumber: 420,
      columnNumber: 11
    }
  }, timePh)));
};
exports.DateTimeEdit = DateTimeEdit;
//# sourceMappingURL=Edit.js.map