{"version":3,"file":"RangeScrollbar.mjs","names":[],"sources":["../../src/rangeScrollbar/RangeScrollbar.tsx"],"sourcesContent":["import { clamp } from '@techsquidtv/canvas-timeline-utils';\nimport React, { createContext, useCallback, useContext, useMemo, useRef, useState } from 'react';\nconst DEFAULT_KEYBOARD_STEP = 1;\nconst DEFAULT_KEYBOARD_PAGE_STEP = 10;\n\n/**\n * Controlled numeric range represented by a range scrollbar.\n *\n * `start` and `end` use the caller's domain units. For a timeline adapter those\n * units might be seconds; for a chart they might be indexes, prices, or pixels.\n */\nexport interface RangeScrollbarValue {\n  /** Inclusive start of the visible range. */\n  start: number;\n  /** Inclusive end of the visible range. */\n  end: number;\n}\n\n/**\n * Side of the range scrollbar thumb controlled by a resize handle.\n */\nexport type RangeScrollbarHandleSide = 'start' | 'end';\n\n/** Visual and interaction axis used by a range scrollbar. */\nexport type RangeScrollbarOrientation = 'horizontal' | 'vertical';\n\n/**\n * Reason a range scrollbar requested a controlled value change.\n */\nexport type RangeScrollbarChangeReason =\n  | 'set-value'\n  | 'thumb-drag'\n  | 'thumb-keyboard'\n  | 'handle-drag'\n  | 'handle-keyboard';\n\n/**\n * Details passed with a controlled range scrollbar value change.\n */\nexport interface RangeScrollbarValueChangeDetails {\n  /** Interaction or imperative action that produced the next value. */\n  reason: RangeScrollbarChangeReason;\n  /** Handle side when a resize handle produced the change. */\n  side?: RangeScrollbarHandleSide;\n  /** Stable identifier for a single pointer drag interaction. */\n  dragSessionId?: number;\n  /** Controlled value captured when the pointer drag interaction started. */\n  dragStartValue?: RangeScrollbarValue;\n}\n\n/**\n * Context passed to a range scrollbar `aria-valuetext` formatter.\n */\nexport interface RangeScrollbarAriaValueTextDetails {\n  /** Scrollbar part whose value is being described. */\n  part: 'thumb' | 'handle';\n  /** Handle side when `part` is `handle`. */\n  side?: RangeScrollbarHandleSide;\n  /** Full controlled range represented by the scrollbar. */\n  value: RangeScrollbarValue;\n  /** Current range span. */\n  rangeSpan: number;\n  /** Minimum value in the full domain. */\n  min: number;\n  /** Maximum value in the full domain. */\n  max: number;\n}\n\n/**\n * Options for deriving generic range scrollbar state and update helpers.\n */\nexport interface UseRangeScrollbarOptions {\n  /** Minimum value in the full scrollable domain. */\n  min: number;\n  /** Maximum value in the full scrollable domain. */\n  max: number;\n  /** Controlled visible range. */\n  value: RangeScrollbarValue;\n  /** Smallest allowed visible range span. Defaults to 0. */\n  minSpan?: number;\n  /** Called when range scrollbar interactions request a new controlled range. */\n  onValueChange?: (value: RangeScrollbarValue, details: RangeScrollbarValueChangeDetails) => void;\n}\n\n/**\n * Generic range scrollbar geometry and mutation helpers.\n */\nexport interface UseRangeScrollbarResult {\n  /** Minimum value in the full scrollable domain. */\n  min: number;\n  /** Maximum value in the full scrollable domain. */\n  max: number;\n  /** Controlled visible range after clamping to the domain. */\n  value: RangeScrollbarValue;\n  /** Smallest allowed visible range span after clamping to the domain span. */\n  minSpan: number;\n  /** Full domain span, equal to `max - min` when positive. */\n  domainSpan: number;\n  /** Visible range span, equal to `value.end - value.start`. */\n  rangeSpan: number;\n  /** CSS percent offset for the visible range thumb. */\n  /** CSS percent offset for the visible range thumb on the active axis. */\n  thumbOffsetPercent: number;\n  /** CSS percent width for the visible range thumb. */\n  /** CSS percent size for the visible range thumb on the active axis. */\n  thumbSizePercent: number;\n  /** Requests an explicit visible range. */\n  setValue: (value: RangeScrollbarValue, details?: RangeScrollbarValueChangeDetails) => void;\n  /** Requests a pan by a domain-unit delta while preserving the current span. */\n  panBy: (delta: number, details?: RangeScrollbarValueChangeDetails) => void;\n  /** Requests a resize by moving one side by a domain-unit delta. */\n  resizeBy: (\n    side: RangeScrollbarHandleSide,\n    delta: number,\n    details?: RangeScrollbarValueChangeDetails\n  ) => void;\n}\n\n/**\n * Props for the controlled range scrollbar root.\n */\nexport interface RangeScrollbarRootProps extends Omit<\n  React.HTMLAttributes<HTMLDivElement>,\n  'children' | 'onChange'\n> {\n  /** Minimum value in the full scrollable domain. */\n  min: number;\n  /** Maximum value in the full scrollable domain. */\n  max: number;\n  /** Controlled visible range. */\n  value: RangeScrollbarValue;\n  /** Visual and interaction axis. Defaults to `'horizontal'`. */\n  orientation?: RangeScrollbarOrientation;\n  /** Smallest allowed visible range span. Defaults to 0. */\n  minSpan?: number;\n  /** Domain-unit nudge used by arrow-key interactions. Defaults to 1. */\n  keyboardStep?: number;\n  /** Domain-unit nudge used by page-key interactions. Defaults to 10. */\n  keyboardPageStep?: number;\n  /** Disables pointer and keyboard interactions while keeping parts rendered. */\n  disabled?: boolean;\n  /** Formats `aria-valuetext` for the thumb and handles. */\n  getAriaValueText?: (value: number, details: RangeScrollbarAriaValueTextDetails) => string;\n  /** Called when range scrollbar interactions request a new controlled range. */\n  onValueChange?: (value: RangeScrollbarValue, details: RangeScrollbarValueChangeDetails) => void;\n  /** Thumb and handle components rendered within the measured track. */\n  children: React.ReactNode;\n}\n\n/**\n * Props for the draggable range scrollbar thumb.\n */\nexport interface RangeScrollbarThumbProps extends React.HTMLAttributes<HTMLDivElement> {\n  /** Optional custom content rendered inside the draggable visible-range thumb. */\n  children?: React.ReactNode;\n}\n\n/**\n * Props for a range scrollbar resize handle.\n */\nexport interface RangeScrollbarHandleProps extends React.HTMLAttributes<HTMLDivElement> {\n  /** Side of the visible range controlled by this handle. */\n  side: RangeScrollbarHandleSide;\n  /** Optional custom content rendered inside the resize handle. */\n  children?: React.ReactNode;\n}\n\ninterface RangeScrollbarContextValue extends UseRangeScrollbarResult {\n  rootRef: React.RefObject<HTMLDivElement | null>;\n  disabled: boolean;\n  getAriaValueText?: (value: number, details: RangeScrollbarAriaValueTextDetails) => string;\n  keyboardStep: number;\n  keyboardPageStep: number;\n  draggingPart: RangeScrollbarDragPart | null;\n  setDraggingPart: (part: RangeScrollbarDragPart | null) => void;\n  orientation: RangeScrollbarOrientation;\n}\n\ntype RangeScrollbarDragPart = 'thumb' | RangeScrollbarHandleSide;\n\nconst RangeScrollbarContext = createContext<RangeScrollbarContextValue | null>(null);\n\nfunction useRangeScrollbarContext() {\n  const ctx = useContext(RangeScrollbarContext);\n  if (!ctx) {\n    throw new Error('RangeScrollbar components must be used within RangeScrollbar.Root');\n  }\n  return ctx;\n}\n\nfunction normalizeDomain(min: number, max: number) {\n  return min <= max ? { min, max } : { min: max, max: min };\n}\n\nfunction normalizeMinSpan(minSpan: number | undefined, domainSpan: number) {\n  return clamp(Math.max(0, minSpan ?? 0), 0, Math.max(0, domainSpan));\n}\n\nfunction normalizeRange(\n  value: RangeScrollbarValue,\n  min: number,\n  max: number,\n  minSpan: number\n): RangeScrollbarValue {\n  if (max <= min) {\n    return { start: min, end: min };\n  }\n\n  let start = clamp(Math.min(value.start, value.end), min, max);\n  let end = clamp(Math.max(value.start, value.end), min, max);\n\n  if (end - start < minSpan) {\n    if (start + minSpan <= max) {\n      end = start + minSpan;\n    } else {\n      end = max;\n      start = max - minSpan;\n    }\n  }\n\n  return { start, end };\n}\n\nfunction panRange(value: RangeScrollbarValue, delta: number, min: number, max: number) {\n  const span = value.end - value.start;\n  const nextStart = clamp(value.start + delta, min, max - span);\n  return { start: nextStart, end: nextStart + span };\n}\n\nfunction resizeRange(\n  value: RangeScrollbarValue,\n  side: RangeScrollbarHandleSide,\n  delta: number,\n  min: number,\n  max: number,\n  minSpan: number\n) {\n  if (side === 'start') {\n    const start = clamp(value.start + delta, min, value.end - minSpan);\n    return { start, end: value.end };\n  }\n\n  const end = clamp(value.end + delta, value.start + minSpan, max);\n  return { start: value.start, end };\n}\n\nfunction keyboardDelta(\n  event: React.KeyboardEvent<HTMLElement>,\n  orientation: RangeScrollbarOrientation,\n  keyboardStep: number,\n  keyboardPageStep: number\n) {\n  switch (event.key) {\n    case 'ArrowLeft':\n      return orientation === 'horizontal' ? -keyboardStep : null;\n    case 'ArrowRight':\n      return orientation === 'horizontal' ? keyboardStep : null;\n    case 'ArrowUp':\n      return orientation === 'vertical' ? -keyboardStep : null;\n    case 'ArrowDown':\n      return orientation === 'vertical' ? keyboardStep : null;\n    case 'PageUp':\n      return -keyboardPageStep;\n    case 'PageDown':\n      return keyboardPageStep;\n    default:\n      return null;\n  }\n}\n\nfunction beginRangeScrollbarPointerDrag(\n  event: React.PointerEvent<HTMLElement>,\n  onPointerMove: (event: PointerEvent) => void,\n  onCleanup: () => void\n) {\n  if (event.button !== 0 && event.pointerType !== 'touch') {\n    return false;\n  }\n\n  event.stopPropagation();\n\n  const target = event.currentTarget;\n  const pointerId = event.pointerId;\n  try {\n    target.setPointerCapture?.(pointerId);\n  } catch {\n    // Continue the window-level drag fallback if pointer capture is unavailable.\n  }\n\n  const cleanup = () => {\n    try {\n      target.releasePointerCapture?.(pointerId);\n    } catch {\n      // Ignore pointer capture release failures.\n    }\n    window.removeEventListener('pointermove', onPointerMove);\n    window.removeEventListener('pointerup', cleanup);\n    window.removeEventListener('pointercancel', cleanup);\n    target.removeEventListener('lostpointercapture', cleanup);\n    onCleanup();\n  };\n\n  window.addEventListener('pointermove', onPointerMove);\n  window.addEventListener('pointerup', cleanup);\n  window.addEventListener('pointercancel', cleanup);\n  target.addEventListener('lostpointercapture', cleanup);\n\n  return true;\n}\n\nfunction scrollbarRoleProps(\n  props: React.HTMLAttributes<HTMLDivElement>,\n  orientation: RangeScrollbarOrientation,\n  ariaLabel: string,\n  ariaValueNow: number,\n  ariaValueMin: number,\n  ariaValueMax: number,\n  disabled: boolean,\n  ariaValueText?: string\n) {\n  return {\n    role: props.role ?? 'scrollbar',\n    tabIndex: disabled ? undefined : (props.tabIndex ?? 0),\n    'aria-disabled': props['aria-disabled'] ?? (disabled ? true : undefined),\n    'aria-orientation': props['aria-orientation'] ?? orientation,\n    'aria-label': props['aria-label'] ?? ariaLabel,\n    'aria-valuemin': props['aria-valuemin'] ?? ariaValueMin,\n    'aria-valuemax': props['aria-valuemax'] ?? ariaValueMax,\n    'aria-valuenow': props['aria-valuenow'] ?? ariaValueNow,\n    'aria-valuetext': props['aria-valuetext'] ?? ariaValueText,\n  };\n}\n\n/**\n * Derives geometry and controlled update helpers for a generic range scrollbar.\n *\n * @param options - Controlled range, domain, minimum span, and change handler.\n * @returns Clamped range state, thumb percentages, and range mutation helpers.\n *\n * @example\n * ```tsx\n * const scrollbar = useRangeScrollbar({\n *   min: 0,\n *   max: 100,\n *   value,\n *   minSpan: 5,\n *   onValueChange: setValue,\n * });\n *\n * return <span>{scrollbar.thumbSizePercent}% visible</span>;\n * ```\n */\n// oxlint-disable-next-line react-refresh/only-export-components\nexport function useRangeScrollbar(options: UseRangeScrollbarOptions): UseRangeScrollbarResult {\n  const { max: rawMax, min: rawMin, minSpan: rawMinSpan, onValueChange, value: rawValue } = options;\n  const domain = normalizeDomain(rawMin, rawMax);\n  const domainSpan = Math.max(0, domain.max - domain.min);\n  const minSpan = normalizeMinSpan(rawMinSpan, domainSpan);\n  const value = useMemo(\n    () => normalizeRange(rawValue, domain.min, domain.max, minSpan),\n    [domain.max, domain.min, minSpan, rawValue]\n  );\n\n  const setValue = useCallback(\n    (nextValue: RangeScrollbarValue, details?: RangeScrollbarValueChangeDetails) => {\n      const normalized = normalizeRange(nextValue, domain.min, domain.max, minSpan);\n      onValueChange?.(normalized, details ?? { reason: 'set-value' });\n    },\n    [domain.max, domain.min, minSpan, onValueChange]\n  );\n\n  const panBy = useCallback(\n    (delta: number, details?: RangeScrollbarValueChangeDetails) => {\n      setValue(panRange(value, delta, domain.min, domain.max), details);\n    },\n    [domain.max, domain.min, setValue, value]\n  );\n\n  const resizeBy = useCallback(\n    (side: RangeScrollbarHandleSide, delta: number, details?: RangeScrollbarValueChangeDetails) => {\n      setValue(resizeRange(value, side, delta, domain.min, domain.max, minSpan), details);\n    },\n    [domain.max, domain.min, minSpan, setValue, value]\n  );\n\n  const rangeSpan = value.end - value.start;\n  const thumbOffsetPercent = domainSpan > 0 ? ((value.start - domain.min) / domainSpan) * 100 : 0;\n  const thumbSizePercent = domainSpan > 0 ? (rangeSpan / domainSpan) * 100 : 100;\n\n  return useMemo(\n    () => ({\n      min: domain.min,\n      max: domain.max,\n      value,\n      minSpan,\n      domainSpan,\n      rangeSpan,\n      thumbOffsetPercent,\n      thumbSizePercent,\n      setValue,\n      panBy,\n      resizeBy,\n    }),\n    [\n      domain.min,\n      domain.max,\n      value,\n      minSpan,\n      domainSpan,\n      rangeSpan,\n      thumbOffsetPercent,\n      thumbSizePercent,\n      setValue,\n      panBy,\n      resizeBy,\n    ]\n  );\n}\n\n/**\n * Root element for a controlled generic range scrollbar.\n *\n * @param props - Controlled domain, visible range, keyboard options, and DOM props.\n * @returns A measured range scrollbar track that provides context to thumb and handles.\n *\n * @example\n * ```tsx\n * <RangeScrollbar.Root min={0} max={100} value={value} onValueChange={setValue}>\n *   <RangeScrollbar.Thumb>\n *     <RangeScrollbar.Handle side=\"start\" />\n *     <RangeScrollbar.Handle side=\"end\" />\n *   </RangeScrollbar.Thumb>\n * </RangeScrollbar.Root>\n * ```\n */\nexport const RangeScrollbarRoot = React.forwardRef<HTMLDivElement, RangeScrollbarRootProps>(\n  (\n    {\n      children,\n      className = '',\n      disabled = false,\n      keyboardPageStep = DEFAULT_KEYBOARD_PAGE_STEP,\n      keyboardStep = DEFAULT_KEYBOARD_STEP,\n      getAriaValueText,\n      max,\n      min,\n      minSpan,\n      onValueChange,\n      orientation = 'horizontal',\n      style,\n      value,\n      ...props\n    },\n    forwardedRef\n  ) => {\n    const internalRef = useRef<HTMLDivElement>(null);\n    const [draggingPart, setDraggingPart] = useState<RangeScrollbarDragPart | null>(null);\n    const controls = useRangeScrollbar({ min, max, value, minSpan, onValueChange });\n\n    const rootRef = React.useCallback(\n      (node: HTMLDivElement | null) => {\n        internalRef.current = node;\n        if (typeof forwardedRef === 'function') {\n          forwardedRef(node);\n        } else if (forwardedRef) {\n          forwardedRef.current = node;\n        }\n      },\n      [forwardedRef]\n    );\n\n    const contextValue = useMemo(\n      () => ({\n        ...controls,\n        rootRef: internalRef,\n        disabled,\n        getAriaValueText,\n        keyboardStep,\n        keyboardPageStep,\n        orientation,\n        draggingPart,\n        setDraggingPart,\n      }),\n      [\n        controls,\n        disabled,\n        getAriaValueText,\n        keyboardStep,\n        keyboardPageStep,\n        orientation,\n        draggingPart,\n      ]\n    );\n\n    return (\n      <RangeScrollbarContext.Provider value={contextValue}>\n        <div\n          ref={rootRef}\n          className={['range-scrollbar', className].filter(Boolean).join(' ')}\n          data-disabled={disabled ? '' : undefined}\n          data-orientation={orientation}\n          style={{ position: 'relative', ...style }}\n          {...props}\n        >\n          {children}\n        </div>\n      </RangeScrollbarContext.Provider>\n    );\n  }\n);\n\nRangeScrollbarRoot.displayName = 'RangeScrollbar.Root';\n\n/**\n * Draggable thumb representing the visible range within a larger domain.\n *\n * @param props - DOM props and optional content for the visible range thumb.\n * @returns An absolutely positioned thumb with pointer and keyboard pan behavior.\n */\nexport const RangeScrollbarThumb = React.forwardRef<HTMLDivElement, RangeScrollbarThumbProps>(\n  ({ children, className = '', style, ...props }, ref) => {\n    const {\n      disabled,\n      domainSpan,\n      getAriaValueText,\n      draggingPart,\n      keyboardPageStep,\n      keyboardStep,\n      max,\n      min,\n      orientation,\n      panBy,\n      rangeSpan,\n      rootRef,\n      setDraggingPart,\n      setValue,\n      thumbOffsetPercent,\n      thumbSizePercent,\n      value,\n    } = useRangeScrollbarContext();\n    const dragSessionIdRef = useRef(0);\n\n    const handlePointerDown = (event: React.PointerEvent<HTMLDivElement>) => {\n      props.onPointerDown?.(event);\n      if (event.defaultPrevented || disabled || domainSpan <= 0) {\n        return;\n      }\n\n      const startPointerPosition = orientation === 'vertical' ? event.clientY : event.clientX;\n      const initialValue = value;\n      const dragSessionId = (dragSessionIdRef.current += 1);\n      const rect = rootRef.current?.getBoundingClientRect();\n      const trackSize = (orientation === 'vertical' ? rect?.height : rect?.width) || 1;\n\n      const onPointerMove = (moveEvent: PointerEvent) => {\n        const pointerPosition = orientation === 'vertical' ? moveEvent.clientY : moveEvent.clientX;\n        const delta = ((pointerPosition - startPointerPosition) / trackSize) * domainSpan;\n        const nextValue = panRange(initialValue, delta, min, max);\n        setValue(nextValue, { reason: 'thumb-drag', dragSessionId, dragStartValue: initialValue });\n      };\n\n      if (beginRangeScrollbarPointerDrag(event, onPointerMove, () => setDraggingPart(null))) {\n        setDraggingPart('thumb');\n      }\n    };\n\n    const handleKeyDown = (event: React.KeyboardEvent<HTMLDivElement>) => {\n      props.onKeyDown?.(event);\n      if (event.defaultPrevented || disabled) {\n        return;\n      }\n\n      const delta = keyboardDelta(event, orientation, keyboardStep, keyboardPageStep);\n      if (delta === null) {\n        return;\n      }\n\n      event.preventDefault();\n      panBy(delta, { reason: 'thumb-keyboard' });\n    };\n\n    const roleProps = scrollbarRoleProps(\n      props,\n      orientation,\n      'Range window',\n      value.start,\n      min,\n      Math.max(min, max - rangeSpan),\n      disabled,\n      getAriaValueText?.(value.start, {\n        max,\n        min,\n        part: 'thumb',\n        rangeSpan,\n        value,\n      })\n    );\n\n    return (\n      <div\n        ref={ref}\n        className={['range-scrollbar-thumb', className].filter(Boolean).join(' ')}\n        data-disabled={disabled ? '' : undefined}\n        data-dragging={draggingPart === 'thumb' ? '' : undefined}\n        style={{\n          position: 'absolute',\n          ...(orientation === 'vertical'\n            ? {\n                bottom: 'auto',\n                left: 0,\n                right: 0,\n                top: `${thumbOffsetPercent}%`,\n                height: `${thumbSizePercent}%`,\n              }\n            : {\n                bottom: 0,\n                left: `${thumbOffsetPercent}%`,\n                right: 'auto',\n                top: 0,\n                width: `${thumbSizePercent}%`,\n              }),\n          ...style,\n        }}\n        {...props}\n        {...roleProps}\n        onPointerDown={handlePointerDown}\n        onKeyDown={handleKeyDown}\n      >\n        {children}\n      </div>\n    );\n  }\n);\n\nRangeScrollbarThumb.displayName = 'RangeScrollbar.Thumb';\n\n/**\n * Resize handle for moving one side of the visible range.\n *\n * @param props - Handle side, DOM props, and optional custom content.\n * @returns An absolutely positioned range resize handle.\n */\nexport const RangeScrollbarHandle = React.forwardRef<HTMLDivElement, RangeScrollbarHandleProps>(\n  ({ children, className = '', side, style, ...props }, ref) => {\n    const {\n      disabled,\n      domainSpan,\n      draggingPart,\n      getAriaValueText,\n      keyboardPageStep,\n      keyboardStep,\n      max,\n      min,\n      minSpan,\n      orientation,\n      resizeBy,\n      rootRef,\n      setDraggingPart,\n      setValue,\n      value,\n    } = useRangeScrollbarContext();\n    const dragSessionIdRef = useRef(0);\n\n    const handlePointerDown = (event: React.PointerEvent<HTMLDivElement>) => {\n      props.onPointerDown?.(event);\n      if (event.defaultPrevented || disabled || domainSpan <= 0) {\n        return;\n      }\n\n      const startPointerPosition = orientation === 'vertical' ? event.clientY : event.clientX;\n      const initialValue = value;\n      const dragSessionId = (dragSessionIdRef.current += 1);\n      const rect = rootRef.current?.getBoundingClientRect();\n      const trackSize = (orientation === 'vertical' ? rect?.height : rect?.width) || 1;\n\n      const onPointerMove = (moveEvent: PointerEvent) => {\n        const pointerPosition = orientation === 'vertical' ? moveEvent.clientY : moveEvent.clientX;\n        const delta = ((pointerPosition - startPointerPosition) / trackSize) * domainSpan;\n        const nextValue = resizeRange(initialValue, side, delta, min, max, minSpan);\n        setValue(nextValue, {\n          reason: 'handle-drag',\n          side,\n          dragSessionId,\n          dragStartValue: initialValue,\n        });\n      };\n\n      if (beginRangeScrollbarPointerDrag(event, onPointerMove, () => setDraggingPart(null))) {\n        setDraggingPart(side);\n      }\n    };\n\n    const handleKeyDown = (event: React.KeyboardEvent<HTMLDivElement>) => {\n      props.onKeyDown?.(event);\n      if (event.defaultPrevented || disabled) {\n        return;\n      }\n\n      const delta = keyboardDelta(event, orientation, keyboardStep, keyboardPageStep);\n      if (delta === null) {\n        return;\n      }\n\n      event.preventDefault();\n      resizeBy(side, delta, { reason: 'handle-keyboard', side });\n    };\n\n    const valueMin = side === 'start' ? min : value.start + minSpan;\n    const valueMax = side === 'start' ? value.end - minSpan : max;\n    const roleProps = scrollbarRoleProps(\n      props,\n      orientation,\n      side === 'start' ? 'Range start' : 'Range end',\n      value[side],\n      valueMin,\n      valueMax,\n      disabled,\n      getAriaValueText?.(value[side], {\n        max,\n        min,\n        part: 'handle',\n        rangeSpan: value.end - value.start,\n        side,\n        value,\n      })\n    );\n\n    return (\n      <div\n        ref={ref}\n        className={['range-scrollbar-handle', className].filter(Boolean).join(' ')}\n        data-disabled={disabled ? '' : undefined}\n        data-dragging={draggingPart === side ? '' : undefined}\n        style={{\n          position: 'absolute',\n          ...(orientation === 'vertical'\n            ? side === 'start'\n              ? {\n                  bottom: 'auto',\n                  height: '10px',\n                  left: 0,\n                  right: 0,\n                  top: 0,\n                }\n              : {\n                  bottom: 0,\n                  height: '10px',\n                  left: 0,\n                  right: 0,\n                  top: 'auto',\n                }\n            : side === 'start'\n              ? {\n                  bottom: 0,\n                  left: 0,\n                  right: 'auto',\n                  top: 0,\n                  width: '10px',\n                }\n              : {\n                  bottom: 0,\n                  left: 'auto',\n                  right: 0,\n                  top: 0,\n                  width: '10px',\n                }),\n          ...style,\n        }}\n        {...props}\n        data-side={side}\n        {...roleProps}\n        onPointerDown={handlePointerDown}\n        onKeyDown={handleKeyDown}\n      >\n        {children}\n      </div>\n    );\n  }\n);\n\nRangeScrollbarHandle.displayName = 'RangeScrollbar.Handle';\n\n/**\n * Namespace of generic controlled range scrollbar primitives.\n */\n// oxlint-disable-next-line react-refresh/only-export-components\nexport const RangeScrollbar = {\n  /** Root controlled range scrollbar track. */\n  Root: RangeScrollbarRoot,\n  /** Draggable visible range thumb. */\n  Thumb: RangeScrollbarThumb,\n  /** Resize handle for the start or end of the visible range. */\n  Handle: RangeScrollbarHandle,\n};\n"],"mappings":"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"}