{"version":3,"file":"useSnapPoints.mjs","names":[],"sources":["../../../src/base-ui/FloatingSheet/useSnapPoints.ts"],"sourcesContent":["import { type RefObject, useMemo } from 'react';\n\nimport { clamp, resolveSize } from './helpers';\n\nconst VELOCITY_THRESHOLD = 0.4;\nconst DRAG_DISTANCE_RATIO = 0.4;\n\ninterface UseSnapPointsOptions {\n  closeThreshold: number;\n  containerHeight: number;\n  containerRef: RefObject<HTMLElement | null>;\n  maxHeightPx: number;\n  minHeightPx: number;\n  snapPoints: number[];\n}\n\ninterface SnapReleaseParams {\n  activeIndex: number;\n  currentHeight: number;\n  dismissible: boolean;\n  draggedDistance: number; // positive = upward (growing), negative = downward (shrinking)\n  velocity: number;\n}\n\ntype SnapReleaseResult = { type: 'snap'; height: number } | { type: 'dismiss' };\n\nexport function useSnapPoints({\n  closeThreshold,\n  snapPoints,\n  containerHeight,\n  minHeightPx,\n  maxHeightPx,\n}: UseSnapPointsOptions) {\n  const snapPointHeights = useMemo(() => {\n    if (!containerHeight) return [];\n\n    const resolved = snapPoints\n      .map((sp) => clamp(resolveSize(sp, containerHeight), minHeightPx, maxHeightPx))\n      .sort((a, b) => a - b);\n\n    // Remove duplicates\n    return [...new Set(resolved)];\n  }, [snapPoints, containerHeight, minHeightPx, maxHeightPx]);\n\n  function findClosestSnapPoint(height: number): number {\n    if (snapPointHeights.length === 0) return clamp(height, minHeightPx, maxHeightPx);\n\n    return snapPointHeights.reduce((prev, curr) =>\n      Math.abs(curr - height) < Math.abs(prev - height) ? curr : prev,\n    );\n  }\n\n  function findActiveIndex(height: number): number {\n    const closest = findClosestSnapPoint(height);\n    return snapPointHeights.indexOf(closest);\n  }\n\n  function getSnapRelease({\n    currentHeight,\n    activeIndex,\n    draggedDistance,\n    velocity,\n    dismissible,\n  }: SnapReleaseParams): SnapReleaseResult {\n    const isFirst = activeIndex === 0;\n    const isLast = activeIndex === snapPointHeights.length - 1;\n    const isDraggingUp = draggedDistance > 0;\n    const highestSnapPoint = snapPointHeights.at(-1) ?? maxHeightPx;\n    const lowestSnapPoint = snapPointHeights[0] ?? minHeightPx;\n    const nextHigherSnapPoint =\n      snapPointHeights[Math.min(activeIndex + 1, snapPointHeights.length - 1)] ?? highestSnapPoint;\n    const nextLowerSnapPoint = snapPointHeights[Math.max(activeIndex - 1, 0)] ?? lowestSnapPoint;\n    const sheetHeight = snapPointHeights[activeIndex] ?? currentHeight;\n\n    // High velocity handling\n    if (\n      velocity > VELOCITY_THRESHOLD &&\n      Math.abs(draggedDistance) < sheetHeight * DRAG_DISTANCE_RATIO\n    ) {\n      if (isDraggingUp) {\n        // Fling upward: go to next higher snap, cap at highest\n        if (isLast) return { type: 'snap', height: highestSnapPoint };\n\n        return { type: 'snap', height: nextHigherSnapPoint };\n      } else {\n        // Fling downward: go to next lower snap, or dismiss if at lowest\n        if (isFirst) {\n          return dismissible ? { type: 'dismiss' } : { type: 'snap', height: lowestSnapPoint };\n        }\n\n        return { type: 'snap', height: nextLowerSnapPoint };\n      }\n    }\n\n    if (\n      dismissible &&\n      isFirst &&\n      !isDraggingUp &&\n      currentHeight < lowestSnapPoint * closeThreshold\n    ) {\n      return { type: 'dismiss' };\n    }\n\n    // Low velocity: snap to closest\n    const closest = findClosestSnapPoint(currentHeight);\n    return { type: 'snap', height: closest };\n  }\n\n  return {\n    snapPointHeights,\n    findClosestSnapPoint,\n    findActiveIndex,\n    getSnapRelease,\n  };\n}\n"],"mappings":";;;AAIA,MAAM,qBAAqB;AAC3B,MAAM,sBAAsB;AAqB5B,SAAgB,cAAc,EAC5B,gBACA,YACA,iBACA,aACA,eACuB;CACvB,MAAM,mBAAmB,cAAc;AACrC,MAAI,CAAC,gBAAiB,QAAO,EAAE;EAE/B,MAAM,WAAW,WACd,KAAK,OAAO,MAAM,YAAY,IAAI,gBAAgB,EAAE,aAAa,YAAY,CAAC,CAC9E,MAAM,GAAG,MAAM,IAAI,EAAE;AAGxB,SAAO,CAAC,GAAG,IAAI,IAAI,SAAS,CAAC;IAC5B;EAAC;EAAY;EAAiB;EAAa;EAAY,CAAC;CAE3D,SAAS,qBAAqB,QAAwB;AACpD,MAAI,iBAAiB,WAAW,EAAG,QAAO,MAAM,QAAQ,aAAa,YAAY;AAEjF,SAAO,iBAAiB,QAAQ,MAAM,SACpC,KAAK,IAAI,OAAO,OAAO,GAAG,KAAK,IAAI,OAAO,OAAO,GAAG,OAAO,KAC5D;;CAGH,SAAS,gBAAgB,QAAwB;EAC/C,MAAM,UAAU,qBAAqB,OAAO;AAC5C,SAAO,iBAAiB,QAAQ,QAAQ;;CAG1C,SAAS,eAAe,EACtB,eACA,aACA,iBACA,UACA,eACuC;EACvC,MAAM,UAAU,gBAAgB;EAChC,MAAM,SAAS,gBAAgB,iBAAiB,SAAS;EACzD,MAAM,eAAe,kBAAkB;EACvC,MAAM,mBAAmB,iBAAiB,GAAG,GAAG,IAAI;EACpD,MAAM,kBAAkB,iBAAiB,MAAM;EAC/C,MAAM,sBACJ,iBAAiB,KAAK,IAAI,cAAc,GAAG,iBAAiB,SAAS,EAAE,KAAK;EAC9E,MAAM,qBAAqB,iBAAiB,KAAK,IAAI,cAAc,GAAG,EAAE,KAAK;EAC7E,MAAM,cAAc,iBAAiB,gBAAgB;AAGrD,MACE,WAAW,sBACX,KAAK,IAAI,gBAAgB,GAAG,cAAc,oBAE1C,KAAI,cAAc;AAEhB,OAAI,OAAQ,QAAO;IAAE,MAAM;IAAQ,QAAQ;IAAkB;AAE7D,UAAO;IAAE,MAAM;IAAQ,QAAQ;IAAqB;SAC/C;AAEL,OAAI,QACF,QAAO,cAAc,EAAE,MAAM,WAAW,GAAG;IAAE,MAAM;IAAQ,QAAQ;IAAiB;AAGtF,UAAO;IAAE,MAAM;IAAQ,QAAQ;IAAoB;;AAIvD,MACE,eACA,WACA,CAAC,gBACD,gBAAgB,kBAAkB,eAElC,QAAO,EAAE,MAAM,WAAW;AAK5B,SAAO;GAAE,MAAM;GAAQ,QADP,qBAAqB,cAAc;GACX;;AAG1C,QAAO;EACL;EACA;EACA;EACA;EACD"}