function _typeof(o) { "@babel/helpers - typeof"; return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) { return typeof o; } : function (o) { return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o; }, _typeof(o); }
function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
function _defineProperty(obj, key, value) { key = _toPropertyKey(key); if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == _typeof(i) ? i : String(i); }
function _toPrimitive(t, r) { if ("object" != _typeof(t) || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != _typeof(i)) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); }
function _toConsumableArray(arr) { return _arrayWithoutHoles(arr) || _iterableToArray(arr) || _unsupportedIterableToArray(arr) || _nonIterableSpread(); }
function _nonIterableSpread() { throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); }
function _iterableToArray(iter) { if (typeof Symbol !== "undefined" && iter[Symbol.iterator] != null || iter["@@iterator"] != null) return Array.from(iter); }
function _arrayWithoutHoles(arr) { if (Array.isArray(arr)) return _arrayLikeToArray(arr); }
function _slicedToArray(arr, i) { return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _unsupportedIterableToArray(arr, i) || _nonIterableRest(); }
function _nonIterableRest() { throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); }
function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o === "string") return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return Array.from(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); }
function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) arr2[i] = arr[i]; return arr2; }
function _iterableToArrayLimit(r, l) { var t = null == r ? null : "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"]; if (null != t) { var e, n, i, u, a = [], f = !0, o = !1; try { if (i = (t = t.call(r)).next, 0 === l) { if (Object(t) !== t) return; f = !1; } else for (; !(f = (e = i.call(t)).done) && (a.push(e.value), a.length !== l); f = !0); } catch (r) { o = !0, n = r; } finally { try { if (!f && null != t.return && (u = t.return(), Object(u) !== u)) return; } finally { if (o) throw n; } } return a; } }
function _arrayWithHoles(arr) { if (Array.isArray(arr)) return arr; }
import React, { useState, useEffect, useRef, useCallback, useMemo } from 'react';
import dayjs from 'dayjs';
import classNames from 'classnames';
import PisellScrollView from "../PisellScrollView";
import { parseValue, getRangeBounds, snapToStepMinutes, isInDisabledRanges as checkDisabledRanges, getHorizontalAxisSlotCount } from "./utils";
import { useTimeAxis, useRealtime, useDragInertia } from "./hooks";
import { BackgroundLayer, CursorLayer, GestureLayer, NowButton, ScaleLayer } from "./components";
import { locales } from '@pisell/utils';
import pisellTimeNavigatorLocales from "./locales";
import "./PisellTimeNavigator.less";
import useEngineContext from "../../hooks/useEngineContext";

/** 横向每格宽度（px），Figma 约 82；axis-moves 固定用此值，cursor-moves 时按视口压缩以看全 range */
var CELL_SIZE_H = 82;
/**
 * 横向「此刻」橙区目标宽度（px）：按 axis-moves 下一格多的比例换算，滚动轴与 cursor-moves 压格时同宽；
 * 不用压缩后的 cellSizePx，避免指针模式下渐变过窄。
 */
var CURRENT_TIME_GRADIENT_WIDTH_H_PX = Math.round(CELL_SIZE_H * 1.7);
/** 竖向每格高度（px） */
var CELL_SIZE_V = 20;
/** 横向「Now」按钮占位，避免刻度被挡 */
var CURSOR_MOVES_NOW_RESERVE_PX = 56;
/** cursor-moves 横向：轴与视口左右边距 */
var CURSOR_MOVES_H_PADDING_PX = 8;
/** cursor-moves 横向：每格最小宽度（再小刻度不可读） */
var CURSOR_MOVES_MIN_CELL_PX = 8;
/** 密度层高度：时间轴 48px 内留少量上下边距 */
var DENSITY_LAYER_HEIGHT = 46;

/**
 * PisellTimeNavigator：可拖动的时间导航轴，时间范围内浏览、选择、控制
 */
export function PisellTimeNavigator(props) {
  var _context$engine;
  var valueProp = props.value,
    onChange = props.onChange,
    defaultValue = props.defaultValue,
    referenceDateProp = props.referenceDate,
    _props$realtime = props.realtime,
    realtime = _props$realtime === void 0 ? false : _props$realtime,
    range = props.range,
    _props$stepMinutes = props.stepMinutes,
    stepMinutes = _props$stepMinutes === void 0 ? 15 : _props$stepMinutes,
    _props$majorStepMinut = props.majorStepMinutes,
    majorStepMinutes = _props$majorStepMinut === void 0 ? 60 : _props$majorStepMinut,
    _props$cursorMode = props.cursorMode,
    cursorMode = _props$cursorMode === void 0 ? 'axis-moves' : _props$cursorMode,
    _props$orientation = props.orientation,
    orientation = _props$orientation === void 0 ? 'horizontal' : _props$orientation,
    disabledRanges = props.disabledRanges,
    _props$showNowButton = props.showNowButton,
    showNowButton = _props$showNowButton === void 0 ? true : _props$showNowButton,
    _props$userInteractio = props.userInteractionLocked,
    userInteractionLocked = _props$userInteractio === void 0 ? false : _props$userInteractio,
    _props$snapToStep = props.snapToStep,
    snapToStep = _props$snapToStep === void 0 ? false : _props$snapToStep,
    _props$inertia = props.inertia,
    inertia = _props$inertia === void 0 ? false : _props$inertia,
    businessHours = props.businessHours,
    pastTimeFade = props.pastTimeFade,
    containerStyle = props.containerStyle,
    scaleStyle = props.scaleStyle,
    cursorStyle = props.cursorStyle,
    nowButtonStyle = props.nowButtonStyle,
    className = props.className,
    style = props.style,
    locale = props.locale,
    _props$timeFormat = props.timeFormat,
    timeFormat = _props$timeFormat === void 0 ? 'HH:mm' : _props$timeFormat,
    renderNowButton = props.renderNowButton,
    onUserInteraction = props.onUserInteraction,
    densitySeriesProp = props.densitySeries,
    loadDensityProp = props.loadDensity;
  var context = useEngineContext();
  locales.init(pisellTimeNavigatorLocales, (context === null || context === void 0 || (_context$engine = context.engine) === null || _context$engine === void 0 || (_context$engine = _context$engine.props) === null || _context$engine === void 0 ? void 0 : _context$engine.locale) || 'en');

  /**
   * 锚定日历日：传入 prop 时以 prop 为准；不传则每帧取当天 0 点（与历史行为一致，便于跨自然日）
   */
  var referenceDateFromProp = useMemo(function () {
    if (referenceDateProp == null) return undefined;
    var d = parseValue(referenceDateProp, dayjs());
    return (d !== null && d !== void 0 ? d : dayjs()).startOf('day');
  }, [referenceDateProp]);
  var referenceDate = referenceDateFromProp !== null && referenceDateFromProp !== void 0 ? referenceDateFromProp : dayjs().startOf('day');
  var isHorizontal = orientation === 'horizontal';

  /** 按自然日稳定依赖，避免无 referenceDate prop 时每次 render 新建 dayjs 触发重复 loadDensity */
  var referenceDayKey = referenceDateFromProp != null ? referenceDateFromProp.format('YYYY-MM-DD') : dayjs().format('YYYY-MM-DD');
  var _useState = useState(),
    _useState2 = _slicedToArray(_useState, 2),
    densityLoaded = _useState2[0],
    setDensityLoaded = _useState2[1];
  var densityReqId = useRef(0);
  var densityGradientId = useMemo(function () {
    return "pisell-time-density-fill-".concat(Math.random().toString(36).slice(2, 8));
  }, []);
  useEffect(function () {
    if (densitySeriesProp !== undefined) {
      setDensityLoaded(undefined);
      return;
    }
    if (!loadDensityProp) {
      setDensityLoaded(undefined);
      return;
    }
    var req = ++densityReqId.current;
    var cancelled = false;
    setDensityLoaded(undefined);
    var refDay = dayjs(referenceDayKey).startOf('day');
    void loadDensityProp({
      referenceDate: refDay,
      stepMinutes: stepMinutes
    }).then(function (arr) {
      if (cancelled || req !== densityReqId.current) return;
      setDensityLoaded(Array.isArray(arr) ? arr : []);
    }).catch(function () {
      if (cancelled || req !== densityReqId.current) return;
      setDensityLoaded(undefined);
    });
    return function () {
      cancelled = true;
    };
  }, [referenceDayKey, stepMinutes, loadDensityProp, densitySeriesProp]);
  var resolvedDensity = densitySeriesProp !== undefined ? densitySeriesProp : densityLoaded;
  var isAxisMoves = cursorMode === 'axis-moves';
  var _useState3 = useState({
      w: 0,
      h: 0
    }),
    _useState4 = _slicedToArray(_useState3, 2),
    viewportSize = _useState4[0],
    setViewportSize = _useState4[1];

  /** 挂载和视口变化时同步尺寸（需在 cellSize 计算之前声明 state） */
  var viewportWrapRef = useRef(null);
  useEffect(function () {
    var el = viewportWrapRef.current;
    if (!el) return;
    var setSize = function setSize() {
      var w = el.clientWidth;
      var h = el.clientHeight;
      setViewportSize(function (prev) {
        return prev.w === w && prev.h === h ? prev : {
          w: w,
          h: h
        };
      });
    };
    setSize();
    var ro = new ResizeObserver(setSize);
    ro.observe(el);
    return function () {
      return ro.disconnect();
    };
  }, []);
  var horizontalSlotCount = useMemo(function () {
    return isHorizontal ? getHorizontalAxisSlotCount(range, referenceDate, stepMinutes) : 0;
  }, [isHorizontal, range === null || range === void 0 ? void 0 : range.start, range === null || range === void 0 ? void 0 : range.end, referenceDate, stepMinutes]);

  /** cursor-moves + 横向：整段 range 压进一条可视区域，等比例缩小格宽 */
  var cellSizePx = useMemo(function () {
    if (!isHorizontal) return CELL_SIZE_V;
    if (isAxisMoves) return CELL_SIZE_H;
    var n = horizontalSlotCount;
    if (n <= 0) return CELL_SIZE_H;
    var vpW = Math.max(1, viewportSize.w || 400);
    var reserve = showNowButton ? CURSOR_MOVES_NOW_RESERVE_PX : 0;
    var usable = Math.max(40, vpW - reserve - CURSOR_MOVES_H_PADDING_PX * 2);
    var raw = Math.floor(usable / n);
    return Math.max(CURSOR_MOVES_MIN_CELL_PX, Math.min(CELL_SIZE_H, raw));
  }, [isHorizontal, isAxisMoves, horizontalSlotCount, viewportSize.w, showNowButton]);
  var axis = useTimeAxis({
    range: range,
    stepMinutes: stepMinutes,
    referenceDate: referenceDate,
    orientation: orientation,
    cellSizePx: cellSizePx
  });
  var horizontalDensityCurve = useMemo(function () {
    if (!isHorizontal || !(resolvedDensity !== null && resolvedDensity !== void 0 && resolvedDensity.length)) return null;
    var ticksN = axis.ticks.length;
    var n = Math.min(resolvedDensity.length, ticksN);
    if (n < 2) return null;
    var slice = resolvedDensity.slice(0, n);
    var maxV = Math.max.apply(Math, _toConsumableArray(slice).concat([0]));
    var minV = Math.min.apply(Math, _toConsumableArray(slice).concat([0]));
    var span = Math.max(1, maxV - minV);
    var h = DENSITY_LAYER_HEIGHT;
    var points = slice.map(function (v, i) {
      var x = i * cellSizePx + cellSizePx / 2;
      /** 映射到 [0,1]：最低值贴底，最高值接近顶部，基本吃满密度层高度 */
      var t = (v - minV) / span;
      var y = h - 1 - t * (h - 3);
      return {
        x: x,
        y: y
      };
    });
    var first = points[0];
    var last = points[points.length - 1];
    var linePath = "M ".concat(first.x, " ").concat(first.y);
    for (var i = 0; i < points.length - 1; i += 1) {
      var p0 = points[i];
      var p1 = points[i + 1];
      var cx = (p0.x + p1.x) / 2;
      var cy = (p0.y + p1.y) / 2;
      linePath += " Q ".concat(p0.x, " ").concat(p0.y, " ").concat(cx, " ").concat(cy);
    }
    linePath += " T ".concat(last.x, " ").concat(last.y);
    var areaPath = "".concat(linePath, " L ").concat(last.x, " ").concat(h, " L ").concat(first.x, " ").concat(h, " Z");
    return {
      points: points,
      linePath: linePath,
      areaPath: areaPath,
      h: h,
      w: axis.totalLengthPx
    };
  }, [isHorizontal, resolvedDensity, axis.ticks, axis.totalLengthPx, cellSizePx]);
  var isControlled = valueProp !== undefined;
  var _useState5 = useState(function () {
      var v = valueProp !== null && valueProp !== void 0 ? valueProp : defaultValue;
      return parseValue(v, referenceDate);
    }),
    _useState6 = _slicedToArray(_useState5, 2),
    internalValue = _useState6[0],
    setInternalValue = _useState6[1];
  var value = isControlled ? valueProp != null ? parseValue(valueProp, referenceDate) : null : internalValue;
  var effectiveValue = value !== null && value !== void 0 ? value : axis.rangeStart;
  var scrollRef = useRef(null);
  /** 标记当前是否为「程序性滚动到中心」：其触发的 onScrollEnd 不再做时间判定 */
  var scrollToCenterInProgressRef = useRef(false);
  /** 标记 value 是否由滚动/松手更新：若是则不再根据 value 做「滚动到中心」 */
  var valueUpdatedByScrollRef = useRef(false);
  /** 手指是否仍按在滚动区域上；仅当完全松手后才执行吸附 */
  var isPointerDownRef = useRef(false);
  var _useState7 = useState({
      scrollLeft: 0,
      scrollTop: 0
    }),
    _useState8 = _slicedToArray(_useState7, 2),
    scrollPosition = _useState8[0],
    setScrollPosition = _useState8[1];
  /** 每分钟更新一次，使当前时间线/渐变块随真实时间移动 */
  var _useState9 = useState(0),
    _useState10 = _slicedToArray(_useState9, 2),
    setNowTick = _useState10[1];
  useEffect(function () {
    var id = setInterval(function () {
      return setNowTick(function (n) {
        return n + 1;
      });
    }, 60 * 1000);
    return function () {
      return clearInterval(id);
    };
  }, []);

  /** cursor-moves：拖指针时禁止程序性滚动抢焦点 */
  var cursorDragActiveRef = useRef(false);
  var cursorDragBaseRef = useRef({
    startClient: 0,
    startOffset: 0
  });
  var getScrollContainer = useCallback(function () {
    var _scrollRef$current$ge, _scrollRef$current, _scrollRef$current$ge2;
    return (_scrollRef$current$ge = (_scrollRef$current = scrollRef.current) === null || _scrollRef$current === void 0 || (_scrollRef$current$ge2 = _scrollRef$current.getScrollContainer) === null || _scrollRef$current$ge2 === void 0 ? void 0 : _scrollRef$current$ge2.call(_scrollRef$current)) !== null && _scrollRef$current$ge !== void 0 ? _scrollRef$current$ge : null;
  }, []);
  var inertiaHandlers = useDragInertia({
    enabled: inertia && !userInteractionLocked,
    orientation: orientation,
    getScrollContainer: getScrollContainer
  });

  /** 横向：点位于每格中心 cellSizePx/2；竖向：对齐整点上面的粗线（格顶），dotOffsetPx=0 */
  /** 视口未量到前用默认值，避免首帧 axisStartMargin 为 0 导致错位 */
  var effectiveViewportW = viewportSize.w || 400;
  var effectiveViewportH = viewportSize.h || 300;
  var halfViewportW = effectiveViewportW / 2;
  var halfViewportH = effectiveViewportH / 2;
  var dotOffsetPx = isHorizontal ? cellSizePx / 2 : 0;
  /** cursor-moves 横向：左右小边距，整轴落在视口内；axis-moves 保持半屏留白可滚动 */
  var axisStartMarginW = isHorizontal && !isAxisMoves ? CURSOR_MOVES_H_PADDING_PX : Math.max(0, halfViewportW - dotOffsetPx);
  var axisStartMarginH = Math.max(0, halfViewportH - dotOffsetPx);

  /**
   * 横向 axis-wrap：无 Now 时用 width:100% + minWidth:自然内容宽，铺满滚动视口；内容更长时仍可横向滚动。
   * 依赖 effectiveViewportW（须在 viewportSize 之后计算）。
   */
  var horizontalAxisWrapStyle = useMemo(function () {
    if (!isHorizontal) return null;
    var minHeight = 48;
    if (isAxisMoves) {
      var _natural = axis.totalLengthPx + (effectiveViewportW - cellSizePx);
      if (!showNowButton) {
        return {
          width: '100%',
          minWidth: _natural,
          minHeight: minHeight,
          boxSizing: 'border-box'
        };
      }
      return {
        width: _natural,
        minHeight: minHeight
      };
    }
    var natural = CURSOR_MOVES_H_PADDING_PX + axis.totalLengthPx + CURSOR_MOVES_H_PADDING_PX;
    if (!showNowButton) {
      return {
        width: '100%',
        minWidth: natural,
        minHeight: minHeight,
        boxSizing: 'border-box'
      };
    }
    return {
      width: natural,
      minHeight: minHeight
    };
  }, [isHorizontal, isAxisMoves, axis.totalLengthPx, effectiveViewportW, cellSizePx, showNowButton]);

  /** 拖动中：用连续映射按 1 分钟步长显示时间（不吸附到 stepMinutes） */
  var handleScroll = useCallback(function (data) {
    /** 程序性滚动到中心（如点 Now）过程中不更新任何状态，避免时间轴再动、value 被覆盖 */
    if (scrollToCenterInProgressRef.current) return;
    setScrollPosition({
      scrollLeft: data.scrollLeft,
      scrollTop: data.scrollTop
    });
    setViewportSize({
      w: data.clientWidth,
      h: data.clientHeight
    });
    if (userInteractionLocked) return;
    if (!isAxisMoves || data.clientWidth <= 0 && data.clientHeight <= 0) return;
    var halfW = data.clientWidth / 2;
    var halfH = data.clientHeight / 2;
    var hasPadding = isHorizontal ? effectiveViewportW > 0 : effectiveViewportH > 0;
    var centerOffset = isHorizontal ? hasPadding ? data.scrollLeft + dotOffsetPx : data.scrollLeft + halfW : hasPadding ? data.scrollTop + dotOffsetPx : data.scrollTop + halfH;
    var t = axis.offsetToTimeContinuous(centerOffset);
    if (!t) return;
    var tMinute = t.startOf('minute');
    if (checkDisabledRanges(tMinute, disabledRanges)) return;
    valueUpdatedByScrollRef.current = true;
    if (!isControlled) setInternalValue(tMinute);
    onChange === null || onChange === void 0 || onChange(tMinute);
  }, [isAxisMoves, isHorizontal, isControlled, axis.offsetToTimeContinuous, disabledRanges, onChange, effectiveViewportW, effectiveViewportH, dotOffsetPx, userInteractionLocked]);

  /** 根据当前视口中心吸附到 0/15/30/45 分钟并更新 value；由松手后的 scrollEnd 或 pointerUp 调用 */
  var performSnapFromScrollPosition = useCallback(function (scrollLeft, scrollTop, clientWidth, clientHeight) {
    if (!isAxisMoves || clientWidth <= 0 && clientHeight <= 0) return;
    valueUpdatedByScrollRef.current = false;
    var hasPadding = isHorizontal ? effectiveViewportW > 0 : effectiveViewportH > 0;
    var centerOffset = isHorizontal ? hasPadding ? scrollLeft + dotOffsetPx : scrollLeft + clientWidth / 2 : hasPadding ? scrollTop + dotOffsetPx : scrollTop + clientHeight / 2;
    var t = axis.offsetToTimeContinuous(centerOffset);
    if (!t) return;
    var snapped = snapToStep ? snapToStepMinutes(t, stepMinutes) : t;
    if (checkDisabledRanges(snapped, disabledRanges)) return;
    if (!isControlled) setInternalValue(snapped);
    onChange === null || onChange === void 0 || onChange(snapped);
  }, [isAxisMoves, isHorizontal, isControlled, axis.offsetToTimeContinuous, snapToStep, stepMinutes, disabledRanges, onChange, effectiveViewportW, effectiveViewportH, dotOffsetPx]);

  /** 程序性滚动结束后延迟清除标记，避免同一次滚动触发的后续 scrollEnd 误走吸附（导致轴动、值被改） */
  var scrollEndClearTimeoutRef = useRef(null);

  /** 滚动结束：仅当手指已松开时才吸附（避免拖动中停顿就吸附）；若仍按着则等 pointerUp 再吸附 */
  var handleScrollEnd = useCallback(function (data) {
    if (userInteractionLocked) return;
    if (scrollToCenterInProgressRef.current) {
      if (scrollEndClearTimeoutRef.current) clearTimeout(scrollEndClearTimeoutRef.current);
      /** 不立即清除：程序性滚动的 scrollEnd 会在动画结束时才触发（可能数百 ms 后），延迟清除才能跳过那次吸附 */
      scrollEndClearTimeoutRef.current = setTimeout(function () {
        scrollToCenterInProgressRef.current = false;
        scrollEndClearTimeoutRef.current = null;
      }, 500);
      return;
    }
    if (isPointerDownRef.current) return;
    performSnapFromScrollPosition(data.scrollLeft, data.scrollTop, data.clientWidth, data.clientHeight);
  }, [performSnapFromScrollPosition, userInteractionLocked]);

  /** 手指松开时若尚未吸附（例如按住不动再松手），用当前滚动位置做一次吸附；点 Now 按钮松手不吸附 */
  var handlePointerUp = useCallback(function (e) {
    var _e$target, _e$target$closest, _scrollRef$current2, _scrollRef$current2$g;
    isPointerDownRef.current = false;
    if (userInteractionLocked) return;
    if ((_e$target = e.target) !== null && _e$target !== void 0 && (_e$target$closest = _e$target.closest) !== null && _e$target$closest !== void 0 && _e$target$closest.call(_e$target, '.pisell-time-navigator-now')) return;
    if (!isAxisMoves) return;
    var container = (_scrollRef$current2 = scrollRef.current) === null || _scrollRef$current2 === void 0 || (_scrollRef$current2$g = _scrollRef$current2.getScrollContainer) === null || _scrollRef$current2$g === void 0 ? void 0 : _scrollRef$current2$g.call(_scrollRef$current2);
    if (!container) return;
    performSnapFromScrollPosition(container.scrollLeft, container.scrollTop, container.clientWidth, container.clientHeight);
  }, [isAxisMoves, performSnapFromScrollPosition, userInteractionLocked]);
  var snapFn = useCallback(function (t) {
    return snapToStepMinutes(t, stepMinutes);
  }, [stepMinutes]);
  var isInDisabled = useCallback(function (t) {
    return checkDisabledRanges(t, disabledRanges);
  }, [disabledRanges]);
  var handleChange = useCallback(function (next) {
    if (isInDisabled(next)) return;
    if (!isControlled) setInternalValue(next);
    onChange === null || onChange === void 0 || onChange(next);
  }, [isControlled, onChange, isInDisabled]);
  useRealtime(realtime, function () {
    var wall = dayjs().startOf('minute');
    var _getRangeBounds = getRangeBounds(range, referenceDate),
      _getRangeBounds2 = _slicedToArray(_getRangeBounds, 2),
      rangeStart = _getRangeBounds2[0],
      rangeEnd = _getRangeBounds2[1];
    /** 跨日营业：用真实此刻落在 [rangeStart, rangeEnd] 内，而非仅 reference 当日钟面 */
    var clamped = wall.isBefore(rangeStart) ? rangeStart : wall.isAfter(rangeEnd) ? rangeEnd : wall;
    var snapped = snapToStep ? snapFn(clamped) : clamped;
    if (!isInDisabled(snapped)) handleChange(snapped);
  });
  useEffect(function () {
    if (!isControlled && valueProp !== undefined) {
      setInternalValue(parseValue(valueProp, referenceDate));
    }
  }, [isControlled, valueProp, referenceDate]);

  /** 锚定日切换时保留非受控下的时分，落到新日上 */
  var referenceDayMs = referenceDate.valueOf();
  useEffect(function () {
    if (isControlled) return;
    setInternalValue(function (prev) {
      if (!prev) {
        return parseValue(defaultValue, referenceDate);
      }
      return referenceDate.hour(prev.hour()).minute(prev.minute()).second(0).millisecond(0);
    });
  }, [referenceDayMs, isControlled, defaultValue]);
  var cursorOffsetPx = axis.timeToOffset(effectiveValue);
  /** 刻度「现在线」：真实系统时刻落在轴区间内时绘制（含跨日营业次日凌晨） */
  var wallAligned = dayjs().startOf('minute');
  var currentTimeInRange = !wallAligned.isBefore(axis.rangeStart) && !wallAligned.isAfter(axis.rangeEnd);
  var currentTimeOffsetPx = currentTimeInRange ? axis.timeToOffset(wallAligned) : undefined;

  /** 横向轴「此刻」橙区：固定像素宽（见 CURRENT_TIME_GRADIENT_WIDTH_H_PX），右缘对齐当前时刻 */
  var horizontalCurrentTimeHighlightStyle = useMemo(function () {
    if (!isHorizontal || currentTimeOffsetPx == null || currentTimeOffsetPx < 0) {
      return null;
    }
    var w = Math.min(CURRENT_TIME_GRADIENT_WIDTH_H_PX, currentTimeOffsetPx);
    return {
      left: axisStartMarginW + Math.max(0, currentTimeOffsetPx - w),
      top: 0,
      width: w,
      height: 48
    };
  }, [isHorizontal, currentTimeOffsetPx, axisStartMarginW]);

  // 以点为基准：有留白时 targetScroll = cursorOffsetPx - dotOffsetPx（使该点对准视口中心）
  var SCROLL_SYNC_THRESHOLD_PX = 2;
  var hasScrollPadding = isHorizontal ? effectiveViewportW > 0 : effectiveViewportH > 0;
  /**
   * 竖向：上留白用 axis marginTop，下留白用 axis marginBottom（均为半屏）
   * axis-wrap 高度 = marginTop + 轴内容 + marginBottom
   */
  var verticalTailPx = effectiveViewportH / 2;
  var verticalWrapHeight = axisStartMarginH + axis.totalLengthPx + verticalTailPx;
  var maxScrollPx = isHorizontal ? Math.max(0, axis.totalLengthPx - cellSizePx) : Math.max(0, verticalWrapHeight - effectiveViewportH);
  useEffect(function () {
    var _scrollRef$current4, _scrollRef$current4$g;
    /** 横向 cursor-moves：整段 range 已压进视口，禁止程序性横滚 */
    if (!isAxisMoves && isHorizontal) {
      var _scrollRef$current3, _scrollRef$current3$g;
      var _container = (_scrollRef$current3 = scrollRef.current) === null || _scrollRef$current3 === void 0 || (_scrollRef$current3$g = _scrollRef$current3.getScrollContainer) === null || _scrollRef$current3$g === void 0 ? void 0 : _scrollRef$current3$g.call(_scrollRef$current3);
      if (_container && _container.scrollLeft !== 0) {
        _container.scrollTo({
          left: 0,
          behavior: 'auto'
        });
      }
      return;
    }
    if (!isAxisMoves && cursorDragActiveRef.current) return;
    if (valueUpdatedByScrollRef.current) {
      valueUpdatedByScrollRef.current = false;
      return;
    }
    var container = (_scrollRef$current4 = scrollRef.current) === null || _scrollRef$current4 === void 0 || (_scrollRef$current4$g = _scrollRef$current4.getScrollContainer) === null || _scrollRef$current4$g === void 0 ? void 0 : _scrollRef$current4$g.call(_scrollRef$current4);
    if (!container) return;
    var viewportPx = isHorizontal ? container.clientWidth : container.clientHeight;
    var targetScroll = hasScrollPadding ? Math.max(0, Math.min(cursorOffsetPx - dotOffsetPx, maxScrollPx)) : Math.max(0, Math.min(cursorOffsetPx - viewportPx / 2, Math.max(0, axis.totalLengthPx - viewportPx)));
    var currentScroll = isHorizontal ? container.scrollLeft : container.scrollTop;
    if (Math.abs(currentScroll - targetScroll) <= SCROLL_SYNC_THRESHOLD_PX) return;
    scrollToCenterInProgressRef.current = true;
    if (isHorizontal) {
      container.scrollTo({
        left: targetScroll,
        behavior: 'smooth'
      });
    } else {
      container.scrollTo({
        top: targetScroll,
        behavior: 'smooth'
      });
    }
  }, [effectiveValue.valueOf(), isHorizontal, cursorOffsetPx, maxScrollPx, hasScrollPadding, dotOffsetPx, cellSizePx, axis.totalLengthPx, isAxisMoves]);
  var scrollToCenterTime = useCallback(function (t) {
    var container = getScrollContainer();
    if (!container) return;
    var offset = axis.timeToOffset(t);
    var viewportPx = isHorizontal ? container.clientWidth : container.clientHeight;
    var maxScroll = hasScrollPadding ? maxScrollPx : Math.max(0, axis.totalLengthPx - viewportPx);
    var target = hasScrollPadding ? Math.max(0, Math.min(offset - dotOffsetPx, maxScrollPx)) : Math.max(0, Math.min(offset - viewportPx / 2, maxScroll));
    scrollToCenterInProgressRef.current = true;
    container.scrollTo({
      left: isHorizontal ? target : 0,
      top: isHorizontal ? 0 : target,
      behavior: 'smooth'
    });
  }, [getScrollContainer, axis.timeToOffset, axis.totalLengthPx, isHorizontal, hasScrollPadding, dotOffsetPx, maxScrollPx]);
  var handleSelectTime = useCallback(function (t) {
    handleChange(t);
    if (isAxisMoves) scrollToCenterTime(t);
  }, [handleChange, isAxisMoves, scrollToCenterTime]);

  /** 点 Now：系统当前时刻映射到锚定日，再 clamp 到 range */
  var handleNow = useCallback(function () {
    valueUpdatedByScrollRef.current = false;
    var wall = dayjs().startOf('minute');
    var _getRangeBounds3 = getRangeBounds(range, referenceDate),
      _getRangeBounds4 = _slicedToArray(_getRangeBounds3, 2),
      rangeStart = _getRangeBounds4[0],
      rangeEnd = _getRangeBounds4[1];
    var clamped = wall.isBefore(rangeStart) ? rangeStart : wall.isAfter(rangeEnd) ? rangeEnd : wall;
    handleChange(clamped);
  }, [range, referenceDate, handleChange]);
  var applyOffsetToNavigatorValue = useCallback(function (offsetPx, snap) {
    var maxO = Math.max(0, axis.totalLengthPx - 0.001);
    var nextOff = Math.max(0, Math.min(offsetPx, maxO));
    var t = axis.offsetToTimeContinuous(nextOff);
    if (!t) return;
    var out = snapToStep ? snap ? snapToStepMinutes(t, stepMinutes) : t.startOf('minute') : t;
    if (checkDisabledRanges(out, disabledRanges)) return;
    if (!isControlled) setInternalValue(out);
    onChange === null || onChange === void 0 || onChange(out);
  }, [axis.totalLengthPx, axis.offsetToTimeContinuous, snapToStep, stepMinutes, disabledRanges, isControlled, onChange]);
  var handleCursorDragPointerDown = useCallback(function (e) {
    if (userInteractionLocked || isAxisMoves) return;
    e.preventDefault();
    e.stopPropagation();
    onUserInteraction === null || onUserInteraction === void 0 || onUserInteraction();
    cursorDragActiveRef.current = true;
    cursorDragBaseRef.current = {
      startClient: isHorizontal ? e.clientX : e.clientY,
      startOffset: cursorOffsetPx
    };
    valueUpdatedByScrollRef.current = true;
    e.currentTarget.setPointerCapture(e.pointerId);
  }, [userInteractionLocked, isAxisMoves, isHorizontal, cursorOffsetPx, onUserInteraction]);
  var handleCursorDragPointerMove = useCallback(function (e) {
    if (!cursorDragActiveRef.current) return;
    var client = isHorizontal ? e.clientX : e.clientY;
    var delta = client - cursorDragBaseRef.current.startClient;
    var nextOff = cursorDragBaseRef.current.startOffset + delta;
    applyOffsetToNavigatorValue(nextOff, false);
  }, [isHorizontal, applyOffsetToNavigatorValue]);
  var handleCursorDragPointerUp = useCallback(function (e) {
    if (!cursorDragActiveRef.current) return;
    cursorDragActiveRef.current = false;
    try {
      e.currentTarget.releasePointerCapture(e.pointerId);
    } catch (_unused) {
      /* already released */
    }
    var client = isHorizontal ? e.clientX : e.clientY;
    var delta = client - cursorDragBaseRef.current.startClient;
    var nextOff = cursorDragBaseRef.current.startOffset + delta;
    valueUpdatedByScrollRef.current = false;
    applyOffsetToNavigatorValue(nextOff, true);
  }, [isHorizontal, applyOffsetToNavigatorValue]);
  var businessHoursPx = useMemo(function () {
    if (!businessHours) return undefined;
    var _getRangeBounds5 = getRangeBounds(businessHours, referenceDate),
      _getRangeBounds6 = _slicedToArray(_getRangeBounds5, 2),
      s = _getRangeBounds6[0],
      e = _getRangeBounds6[1];
    return [axis.timeToOffset(s), axis.timeToOffset(e)];
  }, [businessHours, referenceDate, axis.timeToOffset]);
  var scrollConfig = useMemo(function () {
    return {
      show: false,
      type: isHorizontal ? 'lrArrows' : 'tbArrows',
      scrollDistance: cellSizePx
    };
  }, [isHorizontal, cellSizePx]);
  return /*#__PURE__*/React.createElement("div", {
    className: classNames('pisell-time-navigator', "pisell-time-navigator--".concat(orientation), userInteractionLocked && 'pisell-time-navigator--interaction-locked', className),
    style: isHorizontal ? style : _objectSpread({
      height: '100%',
      minHeight: 200
    }, style)
  }, /*#__PURE__*/React.createElement("div", {
    ref: viewportWrapRef,
    className: "pisell-time-navigator-viewport-wrap",
    style: isHorizontal ? undefined : {
      height: '100%',
      minHeight: 200,
      maxHeight: 800
    },
    onPointerDownCapture: function onPointerDownCapture() {
      isPointerDownRef.current = true;
    },
    onPointerUpCapture: handlePointerUp,
    onPointerLeaveCapture: handlePointerUp
  }, /*#__PURE__*/React.createElement("div", {
    className: classNames('pisell-time-navigator-scroll-host', userInteractionLocked && 'pisell-time-navigator-scroll-host--interaction-locked')
  }, /*#__PURE__*/React.createElement(PisellScrollView, {
    ref: scrollRef,
    width: '100%',
    height: '100%',
    overflow: isHorizontal ? 'x' : 'y',
    showScrollButtons: false,
    scrollbarStyle: "none",
    scrollActionsConfig: scrollConfig,
    onScroll: handleScroll,
    onScrollEnd: handleScrollEnd,
    style: _objectSpread(_objectSpread({}, isHorizontal ? {
      height: 48
    } : {
      width: 54,
      minHeight: 200,
      height: '100%',
      maxHeight: 800
    }), containerStyle)
  }, /*#__PURE__*/React.createElement(GestureLayer, {
    orientation: orientation,
    cellSizePx: cellSizePx,
    axisStartMarginPx: isHorizontal ? axisStartMarginW : axisStartMarginH,
    offsetToTime: axis.offsetToTime,
    onSelectTime: handleSelectTime,
    isInDisabledRanges: isInDisabled,
    snapToStep: snapToStep,
    stepMinutes: stepMinutes,
    snapFn: snapFn,
    scrollPosition: scrollPosition,
    viewportSize: viewportSize,
    onUserInteraction: onUserInteraction,
    onPointerDown: inertiaHandlers.onPointerDown,
    onPointerMove: inertiaHandlers.onPointerMove,
    onPointerUp: inertiaHandlers.onPointerUp,
    onPointerLeave: inertiaHandlers.onPointerUp
  }, /*#__PURE__*/React.createElement("div", {
    className: "pisell-time-navigator-axis-wrap",
    style: isHorizontal ? horizontalAxisWrapStyle !== null && horizontalAxisWrapStyle !== void 0 ? horizontalAxisWrapStyle : {
      minHeight: 48
    } : {
      width: '100%'
      /* 不设 height，由轴（marginTop + 内容 + marginBottom）自然撑开，避免固定高度与 margin 的 CSS 盒模型歧义 */
    }
  }, horizontalCurrentTimeHighlightStyle && /*#__PURE__*/React.createElement("div", {
    className: "pisell-time-navigator-current-gradient pisell-time-navigator-current-gradient--horizontal",
    style: horizontalCurrentTimeHighlightStyle,
    "aria-hidden": true
  }), /*#__PURE__*/React.createElement("div", {
    className: classNames('pisell-time-navigator-axis', "pisell-time-navigator-axis--".concat(orientation)),
    "data-time-navigator-axis": true,
    style: isHorizontal ? {
      width: axis.totalLengthPx,
      height: 48,
      marginLeft: axisStartMarginW
    } : {
      height: axis.totalLengthPx,
      width: '100%',
      marginTop: axisStartMarginH,
      marginBottom: verticalTailPx
    }
  }, /*#__PURE__*/React.createElement(BackgroundLayer, {
    orientation: orientation,
    pastTimeFade: pastTimeFade,
    businessHoursPx: businessHoursPx
  }), horizontalDensityCurve ? /*#__PURE__*/React.createElement("svg", {
    className: "pisell-time-navigator-density-layer",
    width: horizontalDensityCurve.w,
    height: horizontalDensityCurve.h,
    viewBox: "0 0 ".concat(horizontalDensityCurve.w, " ").concat(horizontalDensityCurve.h),
    preserveAspectRatio: "none",
    "aria-hidden": true
  }, /*#__PURE__*/React.createElement("defs", null, /*#__PURE__*/React.createElement("linearGradient", {
    id: densityGradientId,
    x1: "0",
    y1: "0",
    x2: "0",
    y2: "1"
  }, /*#__PURE__*/React.createElement("stop", {
    offset: "0%",
    stopColor: "#ff9c66",
    stopOpacity: "0.32"
  }), /*#__PURE__*/React.createElement("stop", {
    offset: "100%",
    stopColor: "#ff9c66",
    stopOpacity: "0.02"
  }))), /*#__PURE__*/React.createElement("path", {
    d: horizontalDensityCurve.areaPath,
    fill: "url(#".concat(densityGradientId, ")")
  }), /*#__PURE__*/React.createElement("path", {
    d: horizontalDensityCurve.linePath,
    fill: "none",
    stroke: "#ff8a4a",
    strokeWidth: 1.8,
    vectorEffect: "non-scaling-stroke"
  }), horizontalDensityCurve.points.map(function (p, i) {
    return /*#__PURE__*/React.createElement("circle", {
      key: i,
      cx: p.x,
      cy: p.y,
      r: 1.4,
      fill: "#ff8a4a"
    });
  })) : null, /*#__PURE__*/React.createElement(ScaleLayer, {
    orientation: orientation,
    ticks: axis.ticks,
    stepMinutes: stepMinutes,
    majorStepMinutes: majorStepMinutes,
    timeFormat: timeFormat,
    locale: locale,
    style: scaleStyle,
    horizontalCellSizePx: isHorizontal ? cellSizePx : undefined
  }), isHorizontal && currentTimeOffsetPx != null && currentTimeOffsetPx >= 0 && /*#__PURE__*/React.createElement("span", {
    className: "pisell-time-navigator-current-time-bubble",
    style: {
      left: currentTimeOffsetPx
    },
    "aria-hidden": true
  }, locale ? wallAligned.locale(locale).format(timeFormat) : wallAligned.format(timeFormat)), !isHorizontal && currentTimeOffsetPx != null && currentTimeOffsetPx >= 0 && /*#__PURE__*/React.createElement("div", {
    className: "pisell-time-navigator-current-line",
    style: {
      left: 0,
      top: currentTimeOffsetPx - 1,
      width: '100%',
      height: 2,
      background: '#FF692E'
    },
    "aria-hidden": true
  }), !isAxisMoves && /*#__PURE__*/React.createElement(CursorLayer, {
    orientation: orientation,
    value: effectiveValue,
    timeFormat: timeFormat,
    locale: locale,
    isRealtime: realtime,
    offsetPx: cursorOffsetPx,
    style: cursorStyle,
    dragInteractive: !userInteractionLocked,
    onDragPointerDown: handleCursorDragPointerDown,
    onDragPointerMove: handleCursorDragPointerMove,
    onDragPointerUp: handleCursorDragPointerUp,
    onDragPointerCancel: handleCursorDragPointerUp
  })))))), isAxisMoves && /*#__PURE__*/React.createElement("div", {
    className: classNames('pisell-time-navigator-cursor-fixed', "pisell-time-navigator-cursor-fixed--".concat(orientation)),
    "aria-hidden": true
  }, /*#__PURE__*/React.createElement(CursorLayer, {
    orientation: orientation,
    value: effectiveValue,
    timeFormat: timeFormat,
    locale: locale,
    isRealtime: realtime,
    offsetPx: 0,
    fixedCenter: true,
    style: cursorStyle
  })), showNowButton && /*#__PURE__*/React.createElement(NowButton, {
    orientation: orientation,
    onClick: handleNow,
    style: nowButtonStyle,
    renderCustom: renderNowButton
  })));
}
PisellTimeNavigator.displayName = 'PisellTimeNavigator';