var __create = Object.create;
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __getProtoOf = Object.getPrototypeOf;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
  for (var name in all)
    __defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
  if (from && typeof from === "object" || typeof from === "function") {
    for (let key of __getOwnPropNames(from))
      if (!__hasOwnProp.call(to, key) && key !== except)
        __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
  }
  return to;
};
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
  // If the importer is in node compatibility mode or this is not an ESM
  // file that has been converted to a CommonJS file using a Babel-
  // compatible transform (i.e. "__esModule" has not been set), then set
  // "default" to the CommonJS "module.exports" for node compatibility.
  isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
  mod
));
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);

// src/components/pisellTimeNavigator/PisellTimeNavigator.tsx
var PisellTimeNavigator_exports = {};
__export(PisellTimeNavigator_exports, {
  PisellTimeNavigator: () => PisellTimeNavigator
});
module.exports = __toCommonJS(PisellTimeNavigator_exports);
var import_react = __toESM(require("react"));
var import_dayjs = __toESM(require("dayjs"));
var import_classnames = __toESM(require("classnames"));
var import_PisellScrollView = __toESM(require("../PisellScrollView"));
var import_utils = require("./utils");
var import_hooks = require("./hooks");
var import_components = require("./components");
var import_utils2 = require("@pisell/utils");
var import_locales = __toESM(require("./locales"));
var import_PisellTimeNavigator = require("./PisellTimeNavigator.less");
var import_useEngineContext = __toESM(require("../../hooks/useEngineContext"));
var import_timeNavigatorConstants = require("./timeNavigatorConstants");
var DEFAULT_HORIZONTAL_TRACK_HEIGHT_PX = 48;
var horizontalCurrentTimeGradientWidthPx = (cellPx) => Math.round(cellPx * 1.7);
function PisellTimeNavigator(props) {
  var _a, _b;
  const {
    value: valueProp,
    onChange,
    defaultValue,
    referenceDate: referenceDateProp,
    realtime = false,
    range,
    stepMinutes = 15,
    majorStepMinutes = 60,
    cursorMode = "axis-moves",
    orientation = "horizontal",
    horizontalAxisCellSizePx,
    horizontalTrackHeightPx,
    disabledRanges,
    showNowButton = true,
    userInteractionLocked = false,
    snapToStep = false,
    inertia = false,
    businessHours,
    pastTimeFade,
    containerStyle,
    scaleStyle,
    cursorStyle,
    nowButtonStyle,
    className,
    style,
    locale,
    timeFormat = "HH:mm",
    formatTimeLabel,
    renderNowButton,
    onUserInteraction,
    densitySeries: densitySeriesProp,
    loadDensity: loadDensityProp
  } = props;
  const context = (0, import_useEngineContext.default)();
  import_utils2.locales.init(
    import_locales.default,
    ((_b = (_a = context == null ? void 0 : context.engine) == null ? void 0 : _a.props) == null ? void 0 : _b.locale) || "en"
  );
  const referenceDateFromProp = (0, import_react.useMemo)(() => {
    if (referenceDateProp == null) return void 0;
    const d = (0, import_utils.parseValue)(referenceDateProp, (0, import_dayjs.default)());
    return (d ?? (0, import_dayjs.default)()).startOf("day");
  }, [referenceDateProp]);
  const referenceDate = referenceDateFromProp ?? (0, import_utils.pickReferenceDateContainingNow)(range, (0, import_dayjs.default)());
  const isHorizontal = orientation === "horizontal";
  const trackHeightPx = (0, import_react.useMemo)(() => {
    const raw = horizontalTrackHeightPx;
    if (raw == null || !Number.isFinite(Number(raw))) {
      return DEFAULT_HORIZONTAL_TRACK_HEIGHT_PX;
    }
    const n = Math.round(Number(raw));
    return Math.max(28, Math.min(96, n));
  }, [horizontalTrackHeightPx]);
  const referenceDayKey = referenceDate.format("YYYY-MM-DD");
  const [densityLoaded, setDensityLoaded] = (0, import_react.useState)();
  const densityReqId = (0, import_react.useRef)(0);
  const densityAxisKeyRef = (0, import_react.useRef)(null);
  const densityGradientId = (0, import_react.useMemo)(
    () => `pisell-time-density-fill-${Math.random().toString(36).slice(2, 8)}`,
    []
  );
  (0, import_react.useEffect)(() => {
    const axisKey = `${referenceDayKey}|${stepMinutes}`;
    const axisKeyChanged = densityAxisKeyRef.current === null || densityAxisKeyRef.current !== axisKey;
    if (densitySeriesProp !== void 0) {
      densityAxisKeyRef.current = null;
      setDensityLoaded(void 0);
      return;
    }
    if (!loadDensityProp) {
      densityAxisKeyRef.current = null;
      setDensityLoaded(void 0);
      return;
    }
    densityAxisKeyRef.current = axisKey;
    const req = ++densityReqId.current;
    let cancelled = false;
    if (axisKeyChanged) {
      setDensityLoaded(void 0);
    }
    const refDay = (0, import_dayjs.default)(referenceDayKey).startOf("day");
    void loadDensityProp({ referenceDate: refDay, stepMinutes }).then((arr) => {
      if (cancelled || req !== densityReqId.current) return;
      setDensityLoaded(Array.isArray(arr) ? arr : []);
    }).catch(() => {
      if (cancelled || req !== densityReqId.current) return;
      setDensityLoaded(void 0);
    });
    return () => {
      cancelled = true;
    };
  }, [referenceDayKey, stepMinutes, loadDensityProp, densitySeriesProp]);
  const resolvedDensity = densitySeriesProp !== void 0 ? densitySeriesProp : densityLoaded;
  const isAxisMoves = cursorMode === "axis-moves";
  const [viewportSize, setViewportSize] = (0, import_react.useState)({ w: 0, h: 0 });
  const viewportWrapRef = (0, import_react.useRef)(null);
  (0, import_react.useEffect)(() => {
    const el = viewportWrapRef.current;
    if (!el) return;
    const setSize = () => {
      const w = el.clientWidth;
      const h = el.clientHeight;
      setViewportSize(
        (prev) => prev.w === w && prev.h === h ? prev : { w, h }
      );
    };
    setSize();
    const ro = new ResizeObserver(setSize);
    ro.observe(el);
    return () => ro.disconnect();
  }, []);
  const horizontalSlotCount = (0, import_react.useMemo)(
    () => isHorizontal ? (0, import_utils.getHorizontalAxisSlotCount)(range, referenceDate, stepMinutes) : 0,
    [isHorizontal, range == null ? void 0 : range.start, range == null ? void 0 : range.end, referenceDate, stepMinutes]
  );
  const cellSizePx = (0, import_react.useMemo)(() => {
    if (!isHorizontal) return import_timeNavigatorConstants.CELL_SIZE_V;
    if (isAxisMoves) {
      const custom = horizontalAxisCellSizePx;
      if (custom != null && Number.isFinite(custom)) {
        const n2 = Number(custom);
        if (n2 > 0) return Math.max(32, Math.min(n2, 200));
      }
      return import_timeNavigatorConstants.CELL_SIZE_H;
    }
    const n = horizontalSlotCount;
    if (n <= 0) return import_timeNavigatorConstants.CELL_SIZE_H;
    const vpW = Math.max(1, viewportSize.w || 400);
    const reserve = showNowButton ? import_timeNavigatorConstants.CURSOR_MOVES_NOW_RESERVE_PX : 0;
    const usable = Math.max(40, vpW - reserve - import_timeNavigatorConstants.CURSOR_MOVES_H_PADDING_PX * 2);
    const raw = Math.floor(usable / n);
    return Math.max(import_timeNavigatorConstants.CURSOR_MOVES_MIN_CELL_PX, Math.min(import_timeNavigatorConstants.CELL_SIZE_H, raw));
  }, [
    isHorizontal,
    isAxisMoves,
    horizontalAxisCellSizePx,
    horizontalSlotCount,
    viewportSize.w,
    showNowButton
  ]);
  const axis = (0, import_hooks.useTimeAxis)({
    range,
    stepMinutes,
    referenceDate,
    orientation,
    cellSizePx
  });
  const horizontalDensityCurve = (0, import_react.useMemo)(() => {
    if (!isHorizontal || !(resolvedDensity == null ? void 0 : resolvedDensity.length)) return null;
    const ticksN = axis.ticks.length;
    const n = Math.min(resolvedDensity.length, ticksN);
    if (n < 2) return null;
    const slice = resolvedDensity.slice(0, n);
    const maxV = Math.max(...slice, 0);
    const minV = Math.min(...slice, 0);
    const span = Math.max(1, maxV - minV);
    const h = Math.max(12, trackHeightPx - 2);
    const points = slice.map((v, i) => {
      const x = axis.timeToOffset(axis.ticks[i]);
      const t = (v - minV) / span;
      const y = h - 1 - t * (h - 3);
      return { x, y };
    });
    const first = points[0];
    const last = points[points.length - 1];
    let linePath = `M ${first.x} ${first.y}`;
    for (let i = 0; i < points.length - 1; i += 1) {
      const p0 = points[i];
      const p1 = points[i + 1];
      const cx = (p0.x + p1.x) / 2;
      const cy = (p0.y + p1.y) / 2;
      linePath += ` Q ${p0.x} ${p0.y} ${cx} ${cy}`;
    }
    linePath += ` T ${last.x} ${last.y}`;
    const areaPath = `${linePath} L ${last.x} ${h} L ${first.x} ${h} Z`;
    return {
      points,
      linePath,
      areaPath,
      h,
      w: axis.totalLengthPx
    };
  }, [
    isHorizontal,
    resolvedDensity,
    axis.ticks,
    axis.timeToOffset,
    axis.totalLengthPx,
    cellSizePx,
    trackHeightPx
  ]);
  const isControlled = valueProp !== void 0;
  const [internalValue, setInternalValue] = (0, import_react.useState)(() => {
    const v = valueProp ?? defaultValue;
    return (0, import_utils.parseValue)(v, referenceDate);
  });
  const value = isControlled ? valueProp != null ? (0, import_utils.parseValue)(valueProp, referenceDate) : null : internalValue;
  const effectiveValue = value ?? axis.rangeStart;
  const scrollRef = (0, import_react.useRef)(null);
  const scrollToCenterInProgressRef = (0, import_react.useRef)(false);
  const valueUpdatedByScrollRef = (0, import_react.useRef)(false);
  const isPointerDownRef = (0, import_react.useRef)(false);
  const [scrollPosition, setScrollPosition] = (0, import_react.useState)({
    scrollLeft: 0,
    scrollTop: 0
  });
  const [, setNowTick] = (0, import_react.useState)(0);
  (0, import_react.useEffect)(() => {
    const id = setInterval(() => setNowTick((n) => n + 1), 60 * 1e3);
    return () => clearInterval(id);
  }, []);
  const cursorDragActiveRef = (0, import_react.useRef)(false);
  const cursorDragBaseRef = (0, import_react.useRef)({
    startClient: 0,
    startOffset: 0,
    pxPerClient: 1
  });
  const measureWrapPxPerClient = (0, import_react.useCallback)(() => {
    const el = viewportWrapRef.current;
    if (!el) return 1;
    const rect = el.getBoundingClientRect();
    const layout = isHorizontal ? el.offsetWidth : el.offsetHeight;
    const rendered = isHorizontal ? rect.width : rect.height;
    if (!layout || !rendered) return 1;
    const scale = rendered / layout;
    if (!Number.isFinite(scale) || scale <= 0.01) return 1;
    return 1 / scale;
  }, [isHorizontal]);
  const [isCursorDragging, setIsCursorDragging] = (0, import_react.useState)(false);
  const [dragVisualOffsetPx, setDragVisualOffsetPx] = (0, import_react.useState)(
    null
  );
  const pendingDragOffsetRef = (0, import_react.useRef)(null);
  const dragRafIdRef = (0, import_react.useRef)(null);
  const cancelPendingDragFrame = (0, import_react.useCallback)(() => {
    if (dragRafIdRef.current != null) {
      cancelAnimationFrame(dragRafIdRef.current);
      dragRafIdRef.current = null;
    }
    pendingDragOffsetRef.current = null;
  }, []);
  (0, import_react.useEffect)(() => cancelPendingDragFrame, [cancelPendingDragFrame]);
  const getScrollContainer = (0, import_react.useCallback)(
    () => {
      var _a2, _b2;
      return ((_b2 = (_a2 = scrollRef.current) == null ? void 0 : _a2.getScrollContainer) == null ? void 0 : _b2.call(_a2)) ?? null;
    },
    []
  );
  const inertiaHandlers = (0, import_hooks.useDragInertia)({
    enabled: inertia && !userInteractionLocked,
    orientation,
    getScrollContainer
  });
  const effectiveViewportW = viewportSize.w || 400;
  const effectiveViewportH = viewportSize.h || 300;
  const halfViewportW = effectiveViewportW / 2;
  const halfViewportH = effectiveViewportH / 2;
  const dotOffsetPx = isHorizontal ? cellSizePx / 2 : 0;
  const axisStartMarginW = isHorizontal && !isAxisMoves ? import_timeNavigatorConstants.CURSOR_MOVES_H_PADDING_PX : Math.max(0, halfViewportW - dotOffsetPx);
  const axisStartMarginH = Math.max(0, halfViewportH - dotOffsetPx);
  const horizontalAxisWrapStyle = (0, import_react.useMemo)(() => {
    if (!isHorizontal) return null;
    const minHeight = trackHeightPx;
    if (isAxisMoves) {
      const natural2 = axis.totalLengthPx + (effectiveViewportW - cellSizePx);
      if (!showNowButton) {
        return {
          width: "100%",
          minWidth: natural2,
          minHeight,
          boxSizing: "border-box"
        };
      }
      return { width: natural2, minHeight };
    }
    const natural = import_timeNavigatorConstants.CURSOR_MOVES_H_PADDING_PX + axis.totalLengthPx + import_timeNavigatorConstants.CURSOR_MOVES_H_PADDING_PX;
    if (!showNowButton) {
      return {
        width: "100%",
        minWidth: natural,
        minHeight,
        boxSizing: "border-box"
      };
    }
    return { width: natural, minHeight };
  }, [
    isHorizontal,
    isAxisMoves,
    axis.totalLengthPx,
    effectiveViewportW,
    cellSizePx,
    showNowButton,
    trackHeightPx
  ]);
  const handleScroll = (0, import_react.useCallback)(
    (data) => {
      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;
      const halfW = data.clientWidth / 2;
      const halfH = data.clientHeight / 2;
      const hasPadding = isHorizontal ? effectiveViewportW > 0 : effectiveViewportH > 0;
      const centerOffset = isHorizontal ? hasPadding ? data.scrollLeft + dotOffsetPx : data.scrollLeft + halfW : hasPadding ? data.scrollTop + dotOffsetPx : data.scrollTop + halfH;
      const t = axis.offsetToTimeContinuous(centerOffset);
      if (!t) return;
      const tMinute = t.startOf("minute");
      if ((0, import_utils.isInDisabledRanges)(tMinute, disabledRanges)) return;
      valueUpdatedByScrollRef.current = true;
      if (!isControlled) setInternalValue(tMinute);
      onChange == null ? void 0 : onChange(tMinute);
    },
    [
      isAxisMoves,
      isHorizontal,
      isControlled,
      axis.offsetToTimeContinuous,
      disabledRanges,
      onChange,
      effectiveViewportW,
      effectiveViewportH,
      dotOffsetPx,
      userInteractionLocked
    ]
  );
  const performSnapFromScrollPosition = (0, import_react.useCallback)(
    (scrollLeft, scrollTop, clientWidth, clientHeight) => {
      if (!isAxisMoves || clientWidth <= 0 && clientHeight <= 0) return;
      valueUpdatedByScrollRef.current = false;
      const hasPadding = isHorizontal ? effectiveViewportW > 0 : effectiveViewportH > 0;
      const centerOffset = isHorizontal ? hasPadding ? scrollLeft + dotOffsetPx : scrollLeft + clientWidth / 2 : hasPadding ? scrollTop + dotOffsetPx : scrollTop + clientHeight / 2;
      const t = axis.offsetToTimeContinuous(centerOffset);
      if (!t) return;
      const snapped = snapToStep ? (0, import_utils.snapToStepMinutes)(t, stepMinutes) : t;
      if ((0, import_utils.isInDisabledRanges)(snapped, disabledRanges)) return;
      if (!isControlled) setInternalValue(snapped);
      onChange == null ? void 0 : onChange(snapped);
    },
    [
      isAxisMoves,
      isHorizontal,
      isControlled,
      axis.offsetToTimeContinuous,
      snapToStep,
      stepMinutes,
      disabledRanges,
      onChange,
      effectiveViewportW,
      effectiveViewportH,
      dotOffsetPx
    ]
  );
  const scrollEndClearTimeoutRef = (0, import_react.useRef)(
    null
  );
  const handleScrollEnd = (0, import_react.useCallback)(
    (data) => {
      if (userInteractionLocked) return;
      if (scrollToCenterInProgressRef.current) {
        if (scrollEndClearTimeoutRef.current)
          clearTimeout(scrollEndClearTimeoutRef.current);
        scrollEndClearTimeoutRef.current = setTimeout(() => {
          scrollToCenterInProgressRef.current = false;
          scrollEndClearTimeoutRef.current = null;
        }, 500);
        return;
      }
      if (isPointerDownRef.current) return;
      performSnapFromScrollPosition(
        data.scrollLeft,
        data.scrollTop,
        data.clientWidth,
        data.clientHeight
      );
    },
    [performSnapFromScrollPosition, userInteractionLocked]
  );
  const handlePointerUp = (0, import_react.useCallback)(
    (e) => {
      var _a2, _b2, _c, _d;
      isPointerDownRef.current = false;
      if (userInteractionLocked) return;
      if ((_b2 = (_a2 = e.target) == null ? void 0 : _a2.closest) == null ? void 0 : _b2.call(_a2, ".pisell-time-navigator-now"))
        return;
      if (!isAxisMoves) return;
      const container = (_d = (_c = scrollRef.current) == null ? void 0 : _c.getScrollContainer) == null ? void 0 : _d.call(_c);
      if (!container) return;
      performSnapFromScrollPosition(
        container.scrollLeft,
        container.scrollTop,
        container.clientWidth,
        container.clientHeight
      );
    },
    [isAxisMoves, performSnapFromScrollPosition, userInteractionLocked]
  );
  const snapFn = (0, import_react.useCallback)(
    (t) => (0, import_utils.snapToStepMinutes)(t, stepMinutes),
    [stepMinutes]
  );
  const isInDisabled = (0, import_react.useCallback)(
    (t) => (0, import_utils.isInDisabledRanges)(t, disabledRanges),
    [disabledRanges]
  );
  const handleChange = (0, import_react.useCallback)(
    (next) => {
      if (isInDisabled(next)) return;
      if (!isControlled) setInternalValue(next);
      onChange == null ? void 0 : onChange(next);
    },
    [isControlled, onChange, isInDisabled]
  );
  (0, import_hooks.useRealtime)(realtime, () => {
    const wall = (0, import_dayjs.default)().startOf("minute");
    const [rangeStart, rangeEnd] = (0, import_utils.getRangeBounds)(range, referenceDate);
    const clamped = wall.isBefore(rangeStart) ? rangeStart : wall.isAfter(rangeEnd) ? rangeEnd : wall;
    const snapped = snapToStep ? snapFn(clamped) : clamped;
    if (!isInDisabled(snapped)) handleChange(snapped);
  });
  (0, import_react.useEffect)(() => {
    if (!isControlled && valueProp !== void 0) {
      setInternalValue((0, import_utils.parseValue)(valueProp, referenceDate));
    }
  }, [isControlled, valueProp, referenceDate]);
  const referenceDayMs = referenceDate.valueOf();
  (0, import_react.useEffect)(() => {
    if (isControlled) return;
    setInternalValue((prev) => {
      if (!prev) {
        return (0, import_utils.parseValue)(defaultValue, referenceDate);
      }
      return referenceDate.hour(prev.hour()).minute(prev.minute()).second(0).millisecond(0);
    });
  }, [referenceDayMs, isControlled, defaultValue]);
  const cursorOffsetPx = axis.timeToOffset(effectiveValue);
  const visualCursorOffsetPx = dragVisualOffsetPx ?? cursorOffsetPx;
  const visualValue = (0, import_react.useMemo)(() => {
    if (dragVisualOffsetPx == null) return effectiveValue;
    return axis.offsetToTimeContinuous(dragVisualOffsetPx) ?? effectiveValue;
  }, [dragVisualOffsetPx, axis.offsetToTimeContinuous, effectiveValue]);
  const wallAligned = (0, import_dayjs.default)().startOf("minute");
  const currentTimeInRange = !wallAligned.isBefore(axis.rangeStart) && !wallAligned.isAfter(axis.rangeEnd);
  const currentTimeOffsetPx = currentTimeInRange ? axis.timeToOffset(wallAligned) : void 0;
  const resolveTimeLabel = (0, import_react.useCallback)(
    (t) => {
      if (formatTimeLabel) return formatTimeLabel(t);
      return locale ? t.locale(locale).format(timeFormat) : t.format(timeFormat);
    },
    [formatTimeLabel, locale, timeFormat]
  );
  const horizontalCurrentTimeHighlightStyle = (0, import_react.useMemo)(() => {
    if (!isHorizontal || currentTimeOffsetPx == null || currentTimeOffsetPx < 0) {
      return null;
    }
    const gradW = horizontalCurrentTimeGradientWidthPx(cellSizePx);
    const w = Math.min(gradW, currentTimeOffsetPx);
    return {
      left: axisStartMarginW + Math.max(0, currentTimeOffsetPx - w),
      top: 0,
      width: w,
      height: trackHeightPx
    };
  }, [
    isHorizontal,
    currentTimeOffsetPx,
    axisStartMarginW,
    cellSizePx,
    trackHeightPx
  ]);
  const SCROLL_SYNC_THRESHOLD_PX = 2;
  const hasScrollPadding = isHorizontal ? effectiveViewportW > 0 : effectiveViewportH > 0;
  const verticalTailPx = effectiveViewportH / 2;
  const verticalWrapHeight = axisStartMarginH + axis.totalLengthPx + verticalTailPx;
  const maxScrollPx = isHorizontal ? Math.max(0, axis.totalLengthPx - cellSizePx) : Math.max(0, verticalWrapHeight - effectiveViewportH);
  (0, import_react.useEffect)(() => {
    var _a2, _b2, _c, _d;
    if (!isAxisMoves && isHorizontal) {
      const container2 = (_b2 = (_a2 = scrollRef.current) == null ? void 0 : _a2.getScrollContainer) == null ? void 0 : _b2.call(_a2);
      if (container2 && container2.scrollLeft !== 0) {
        container2.scrollTo({ left: 0, behavior: "auto" });
      }
      return;
    }
    if (!isAxisMoves && cursorDragActiveRef.current) return;
    if (valueUpdatedByScrollRef.current) {
      valueUpdatedByScrollRef.current = false;
      return;
    }
    const container = (_d = (_c = scrollRef.current) == null ? void 0 : _c.getScrollContainer) == null ? void 0 : _d.call(_c);
    if (!container) return;
    const viewportPx = isHorizontal ? container.clientWidth : container.clientHeight;
    const targetScroll = hasScrollPadding ? Math.max(0, Math.min(cursorOffsetPx - dotOffsetPx, maxScrollPx)) : Math.max(
      0,
      Math.min(
        cursorOffsetPx - viewportPx / 2,
        Math.max(0, axis.totalLengthPx - viewportPx)
      )
    );
    const 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
  ]);
  const scrollToCenterTime = (0, import_react.useCallback)(
    (t) => {
      const container = getScrollContainer();
      if (!container) return;
      const offset = axis.timeToOffset(t);
      const viewportPx = isHorizontal ? container.clientWidth : container.clientHeight;
      const maxScroll = hasScrollPadding ? maxScrollPx : Math.max(0, axis.totalLengthPx - viewportPx);
      const 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
    ]
  );
  const handleSelectTime = (0, import_react.useCallback)(
    (t) => {
      handleChange(t);
      if (isAxisMoves) scrollToCenterTime(t);
    },
    [handleChange, isAxisMoves, scrollToCenterTime]
  );
  const handleNow = (0, import_react.useCallback)(() => {
    valueUpdatedByScrollRef.current = false;
    const wall = (0, import_dayjs.default)().startOf("minute");
    const [rangeStart, rangeEnd] = (0, import_utils.getRangeBounds)(range, referenceDate);
    const clamped = wall.isBefore(rangeStart) ? rangeStart : wall.isAfter(rangeEnd) ? rangeEnd : wall;
    handleChange(clamped);
  }, [range, referenceDate, handleChange]);
  const applyOffsetToNavigatorValue = (0, import_react.useCallback)(
    (offsetPx, snap) => {
      const maxO = Math.max(0, axis.totalLengthPx - 1e-3);
      const nextOff = Math.max(0, Math.min(offsetPx, maxO));
      const t = axis.offsetToTimeContinuous(nextOff);
      if (!t) return;
      const out = snapToStep ? snap ? (0, import_utils.snapToStepMinutes)(t, stepMinutes) : t.startOf("minute") : t;
      if ((0, import_utils.isInDisabledRanges)(out, disabledRanges)) return;
      if (!isControlled) setInternalValue(out);
      onChange == null ? void 0 : onChange(out);
    },
    [
      axis.totalLengthPx,
      axis.offsetToTimeContinuous,
      snapToStep,
      stepMinutes,
      disabledRanges,
      isControlled,
      onChange
    ]
  );
  const handleCursorDragPointerDown = (0, import_react.useCallback)(
    (e) => {
      if (userInteractionLocked || isAxisMoves) return;
      e.preventDefault();
      e.stopPropagation();
      onUserInteraction == null ? void 0 : onUserInteraction();
      cursorDragActiveRef.current = true;
      cursorDragBaseRef.current = {
        startClient: isHorizontal ? e.clientX : e.clientY,
        startOffset: cursorOffsetPx,
        pxPerClient: measureWrapPxPerClient()
      };
      valueUpdatedByScrollRef.current = true;
      setIsCursorDragging(true);
      e.currentTarget.setPointerCapture(e.pointerId);
    },
    [
      userInteractionLocked,
      isAxisMoves,
      isHorizontal,
      cursorOffsetPx,
      onUserInteraction,
      measureWrapPxPerClient
    ]
  );
  const handleCursorDragPointerMove = (0, import_react.useCallback)(
    (e) => {
      if (!cursorDragActiveRef.current) return;
      const client = isHorizontal ? e.clientX : e.clientY;
      const screenDelta = client - cursorDragBaseRef.current.startClient;
      const delta = screenDelta * (cursorDragBaseRef.current.pxPerClient || 1);
      const nextOff = cursorDragBaseRef.current.startOffset + delta;
      pendingDragOffsetRef.current = nextOff;
      if (dragRafIdRef.current != null) return;
      dragRafIdRef.current = requestAnimationFrame(() => {
        dragRafIdRef.current = null;
        const pending = pendingDragOffsetRef.current;
        pendingDragOffsetRef.current = null;
        if (pending == null) return;
        if (!cursorDragActiveRef.current) return;
        const maxO = Math.max(0, axis.totalLengthPx - 1e-3);
        const clamped = Math.max(0, Math.min(pending, maxO));
        setDragVisualOffsetPx(clamped);
      });
    },
    [isHorizontal, axis.totalLengthPx]
  );
  const handleCursorDragPointerUp = (0, import_react.useCallback)(
    (e) => {
      if (!cursorDragActiveRef.current) return;
      cursorDragActiveRef.current = false;
      setIsCursorDragging(false);
      try {
        e.currentTarget.releasePointerCapture(e.pointerId);
      } catch {
      }
      const client = isHorizontal ? e.clientX : e.clientY;
      const screenDelta = client - cursorDragBaseRef.current.startClient;
      const delta = screenDelta * (cursorDragBaseRef.current.pxPerClient || 1);
      const nextOff = cursorDragBaseRef.current.startOffset + delta;
      valueUpdatedByScrollRef.current = false;
      cancelPendingDragFrame();
      setDragVisualOffsetPx(null);
      applyOffsetToNavigatorValue(nextOff, true);
    },
    [isHorizontal, applyOffsetToNavigatorValue, cancelPendingDragFrame]
  );
  const businessHoursPx = (0, import_react.useMemo)(() => {
    if (!businessHours) return void 0;
    const [s, e] = (0, import_utils.getRangeBounds)(businessHours, referenceDate);
    return [axis.timeToOffset(s), axis.timeToOffset(e)];
  }, [businessHours, referenceDate, axis.timeToOffset]);
  const scrollConfig = (0, import_react.useMemo)(
    () => ({
      show: false,
      type: isHorizontal ? "lrArrows" : "tbArrows",
      scrollDistance: cellSizePx
    }),
    [isHorizontal, cellSizePx]
  );
  return /* @__PURE__ */ import_react.default.createElement(
    "div",
    {
      className: (0, import_classnames.default)(
        "pisell-time-navigator",
        `pisell-time-navigator--${orientation}`,
        userInteractionLocked && "pisell-time-navigator--interaction-locked",
        className
      ),
      style: isHorizontal ? {
        ...style ?? {},
        ["--pisell-time-nav-track-h"]: `${trackHeightPx}px`
      } : { height: "100%", minHeight: 200, ...style ?? {} }
    },
    /* @__PURE__ */ import_react.default.createElement(
      "div",
      {
        ref: viewportWrapRef,
        className: "pisell-time-navigator-viewport-wrap",
        style: isHorizontal ? void 0 : { height: "100%", minHeight: 200, maxHeight: 800 },
        onPointerDownCapture: () => {
          isPointerDownRef.current = true;
        },
        onPointerUpCapture: handlePointerUp,
        onPointerLeaveCapture: handlePointerUp
      },
      /* @__PURE__ */ import_react.default.createElement(
        "div",
        {
          className: (0, import_classnames.default)(
            "pisell-time-navigator-scroll-host",
            userInteractionLocked && "pisell-time-navigator-scroll-host--interaction-locked"
          )
        },
        /* @__PURE__ */ import_react.default.createElement(
          import_PisellScrollView.default,
          {
            ref: scrollRef,
            width: "100%",
            height: "100%",
            overflow: isHorizontal ? "x" : "y",
            showScrollButtons: false,
            scrollbarStyle: "none",
            scrollActionsConfig: scrollConfig,
            onScroll: handleScroll,
            onScrollEnd: handleScrollEnd,
            style: {
              ...isHorizontal ? { height: trackHeightPx } : {
                width: 54,
                minHeight: 200,
                height: "100%",
                maxHeight: 800
              },
              ...containerStyle
            }
          },
          /* @__PURE__ */ import_react.default.createElement(
            import_components.GestureLayer,
            {
              orientation,
              cellSizePx,
              axisStartMarginPx: isHorizontal ? axisStartMarginW : axisStartMarginH,
              offsetToTime: axis.offsetToTime,
              offsetToTimeContinuous: axis.offsetToTimeContinuous,
              onSelectTime: handleSelectTime,
              isInDisabledRanges: isInDisabled,
              snapToStep,
              stepMinutes,
              snapFn,
              scrollPosition,
              viewportSize,
              onUserInteraction,
              onPointerDown: inertiaHandlers.onPointerDown,
              onPointerMove: inertiaHandlers.onPointerMove,
              onPointerUp: inertiaHandlers.onPointerUp,
              onPointerLeave: inertiaHandlers.onPointerUp
            },
            /* @__PURE__ */ import_react.default.createElement(
              "div",
              {
                className: "pisell-time-navigator-axis-wrap",
                style: isHorizontal ? horizontalAxisWrapStyle ?? { minHeight: trackHeightPx } : {
                  width: "100%"
                  /* 不设 height，由轴（marginTop + 内容 + marginBottom）自然撑开，避免固定高度与 margin 的 CSS 盒模型歧义 */
                }
              },
              horizontalCurrentTimeHighlightStyle && /* @__PURE__ */ import_react.default.createElement(
                "div",
                {
                  className: "pisell-time-navigator-current-gradient pisell-time-navigator-current-gradient--horizontal",
                  style: horizontalCurrentTimeHighlightStyle,
                  "aria-hidden": true
                }
              ),
              /* @__PURE__ */ import_react.default.createElement(
                "div",
                {
                  className: (0, import_classnames.default)(
                    "pisell-time-navigator-axis",
                    `pisell-time-navigator-axis--${orientation}`
                  ),
                  "data-time-navigator-axis": true,
                  style: isHorizontal ? {
                    width: axis.totalLengthPx,
                    height: trackHeightPx,
                    marginLeft: axisStartMarginW
                  } : {
                    height: axis.totalLengthPx,
                    width: "100%",
                    marginTop: axisStartMarginH,
                    marginBottom: verticalTailPx
                  }
                },
                /* @__PURE__ */ import_react.default.createElement(
                  import_components.BackgroundLayer,
                  {
                    orientation,
                    pastTimeFade,
                    businessHoursPx
                  }
                ),
                horizontalDensityCurve ? /* @__PURE__ */ import_react.default.createElement(
                  "svg",
                  {
                    className: "pisell-time-navigator-density-layer",
                    width: horizontalDensityCurve.w,
                    height: horizontalDensityCurve.h,
                    viewBox: `0 0 ${horizontalDensityCurve.w} ${horizontalDensityCurve.h}`,
                    preserveAspectRatio: "none",
                    "aria-hidden": true
                  },
                  /* @__PURE__ */ import_react.default.createElement("defs", null, /* @__PURE__ */ import_react.default.createElement(
                    "linearGradient",
                    {
                      id: densityGradientId,
                      x1: "0",
                      y1: "0",
                      x2: "0",
                      y2: "1"
                    },
                    /* @__PURE__ */ import_react.default.createElement(
                      "stop",
                      {
                        offset: "0%",
                        stopColor: "#ff9c66",
                        stopOpacity: "0.32"
                      }
                    ),
                    /* @__PURE__ */ import_react.default.createElement(
                      "stop",
                      {
                        offset: "100%",
                        stopColor: "#ff9c66",
                        stopOpacity: "0.02"
                      }
                    )
                  )),
                  /* @__PURE__ */ import_react.default.createElement(
                    "path",
                    {
                      d: horizontalDensityCurve.areaPath,
                      fill: `url(#${densityGradientId})`
                    }
                  ),
                  /* @__PURE__ */ import_react.default.createElement(
                    "path",
                    {
                      d: horizontalDensityCurve.linePath,
                      fill: "none",
                      stroke: "#ff8a4a",
                      strokeWidth: 1.8,
                      vectorEffect: "non-scaling-stroke"
                    }
                  ),
                  horizontalDensityCurve.points.map((p, i) => /* @__PURE__ */ import_react.default.createElement(
                    "circle",
                    {
                      key: i,
                      cx: p.x,
                      cy: p.y,
                      r: 1.4,
                      fill: "#ff8a4a"
                    }
                  ))
                ) : null,
                /* @__PURE__ */ import_react.default.createElement(
                  import_components.ScaleLayer,
                  {
                    orientation,
                    ticks: axis.ticks,
                    stepMinutes,
                    majorStepMinutes,
                    timeFormat,
                    locale,
                    style: scaleStyle,
                    horizontalCellSizePx: isHorizontal ? cellSizePx : void 0,
                    cellWidthsPx: isHorizontal ? axis.cellWidthsPx : void 0,
                    leadingPaddingPx: isHorizontal ? dotOffsetPx : void 0,
                    trailingPaddingPx: isHorizontal ? dotOffsetPx : void 0
                  }
                ),
                isHorizontal && currentTimeOffsetPx != null && currentTimeOffsetPx >= 0 && /* @__PURE__ */ import_react.default.createElement(
                  "span",
                  {
                    className: "pisell-time-navigator-current-time-bubble",
                    style: { left: currentTimeOffsetPx },
                    "aria-hidden": true
                  },
                  resolveTimeLabel(wallAligned)
                ),
                !isHorizontal && currentTimeOffsetPx != null && currentTimeOffsetPx >= 0 && /* @__PURE__ */ import_react.default.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__ */ import_react.default.createElement(
                  import_components.CursorLayer,
                  {
                    orientation,
                    value: visualValue,
                    timeFormat,
                    formatTimeLabel,
                    locale,
                    isRealtime: realtime,
                    offsetPx: visualCursorOffsetPx,
                    style: cursorStyle,
                    dragInteractive: !userInteractionLocked,
                    isDragging: isCursorDragging,
                    onDragPointerDown: handleCursorDragPointerDown,
                    onDragPointerMove: handleCursorDragPointerMove,
                    onDragPointerUp: handleCursorDragPointerUp,
                    onDragPointerCancel: handleCursorDragPointerUp
                  }
                )
              )
            )
          )
        )
      ),
      !isAxisMoves && isHorizontal && isCursorDragging && visualValue != null && /* @__PURE__ */ import_react.default.createElement(
        "div",
        {
          className: "pisell-time-navigator-drag-bubble-overlay",
          "aria-hidden": true
        },
        /* @__PURE__ */ import_react.default.createElement(
          "span",
          {
            className: (0, import_classnames.default)(
              "pisell-time-navigator-drag-bubble",
              realtime && "pisell-time-navigator-drag-bubble--realtime"
            ),
            style: {
              left: axisStartMarginW + visualCursorOffsetPx - scrollPosition.scrollLeft
            }
          },
          resolveTimeLabel(visualValue)
        )
      ),
      isAxisMoves && /* @__PURE__ */ import_react.default.createElement(
        "div",
        {
          className: (0, import_classnames.default)(
            "pisell-time-navigator-cursor-fixed",
            `pisell-time-navigator-cursor-fixed--${orientation}`
          ),
          "aria-hidden": true
        },
        /* @__PURE__ */ import_react.default.createElement(
          import_components.CursorLayer,
          {
            orientation,
            value: effectiveValue,
            timeFormat,
            formatTimeLabel,
            locale,
            isRealtime: realtime,
            offsetPx: 0,
            fixedCenter: true,
            style: cursorStyle
          }
        )
      ),
      showNowButton && /* @__PURE__ */ import_react.default.createElement(
        import_components.NowButton,
        {
          orientation,
          onClick: handleNow,
          style: nowButtonStyle,
          renderCustom: renderNowButton
        }
      )
    )
  );
}
PisellTimeNavigator.displayName = "PisellTimeNavigator";
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
  PisellTimeNavigator
});
