@lodev09/react-native-true-sheet 4.0.0-beta.21 → 4.0.0-beta.22

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -299,6 +299,7 @@ export function Root({
299
299
  const dismissAttempted = React.useRef(false);
300
300
  const keyboardIsOpen = React.useRef(false);
301
301
  const shouldAnimate = React.useRef(!defaultOpen);
302
+ const hasPresented = React.useRef(false);
302
303
  const previousDiffFromInitial = React.useRef(0);
303
304
  const drawerRef = React.useRef<HTMLDivElement>(null);
304
305
  const drawerHeightRef = React.useRef(drawerRef.current?.getBoundingClientRect().height || 0);
@@ -315,10 +316,14 @@ export function Root({
315
316
  onContentHeightChangeRef.current?.(measuredContentHeight);
316
317
  }, [measuredContentHeight]);
317
318
 
318
- const onSnapPointChange = React.useCallback((activeSnapPointIndex: number) => {
319
+ const onSnapPointChange = React.useCallback((activeSnapPointIndex: number, animated: boolean) => {
319
320
  // Change openTime ref when we reach the last snap point to prevent dragging for 500ms incase it's scrollable.
320
321
  if (snapPoints && activeSnapPointIndex === snapPointsOffset.length - 1)
321
322
  openTime.current = new Date();
323
+ // Instant snaps do not emit transition events for position tracking.
324
+ if (!animated && drawerRef.current) {
325
+ onPositionChangeRef.current?.(drawerRef.current.getBoundingClientRect().top);
326
+ }
322
327
  }, []);
323
328
 
324
329
  const {
@@ -1017,6 +1022,8 @@ export function Root({
1017
1022
  dismissible,
1018
1023
  onDismissAttempt,
1019
1024
  shouldAnimate,
1025
+ initialAnimated,
1026
+ hasPresented,
1020
1027
  handleOnly,
1021
1028
  isOpen,
1022
1029
  isDragging,
@@ -1175,6 +1182,8 @@ export const Content = React.forwardRef<HTMLDivElement, ContentProps>(
1175
1182
  container,
1176
1183
  handleOnly,
1177
1184
  shouldAnimate,
1185
+ initialAnimated,
1186
+ hasPresented,
1178
1187
  autoFocus,
1179
1188
  onPositionChangeRef,
1180
1189
  setContentHeight,
@@ -1423,15 +1432,18 @@ export const Content = React.forwardRef<HTMLDivElement, ContentProps>(
1423
1432
  wrapper.style.transform = `translate3d(0, ${viewportH}px, 0)`;
1424
1433
  } else if (isOpen && !wasOpenRef.current) {
1425
1434
  wrapper.style.transition = 'none';
1426
- wrapper.style.transform = `translate3d(0, ${viewportH}px, 0)`;
1427
- // eslint-disable-next-line no-void
1428
- void wrapper.offsetHeight;
1429
- wrapper.style.transition = transition;
1435
+ if (hasPresented.current || initialAnimated) {
1436
+ wrapper.style.transform = `translate3d(0, ${viewportH}px, 0)`;
1437
+ // eslint-disable-next-line no-void
1438
+ void wrapper.offsetHeight;
1439
+ wrapper.style.transition = transition;
1440
+ }
1430
1441
  wrapper.style.transform = 'translate3d(0, 0, 0)';
1442
+ hasPresented.current = true;
1431
1443
  }
1432
1444
  }
1433
1445
  wasOpenRef.current = isOpen;
1434
- }, [isOpen, detached, drawerRef]);
1446
+ }, [isOpen, detached, drawerRef, initialAnimated, hasPresented]);
1435
1447
 
1436
1448
  // Subsequent snap writes belong to useSnapPoints. A React style update on
1437
1449
  // release would overwrite the live drag value before its transition starts.
@@ -35,7 +35,7 @@ export function useSnapPoints({
35
35
  fadeFromIndex?: number;
36
36
  drawerRef: React.RefObject<HTMLDivElement | null>;
37
37
  overlayRef: React.RefObject<HTMLDivElement | null>;
38
- onSnapPointChange(activeSnapPointIndex: number): void;
38
+ onSnapPointChange(activeSnapPointIndex: number, animated: boolean): void;
39
39
  direction?: DrawerDirection;
40
40
  container?: HTMLElement | null | undefined;
41
41
  snapToSequentialPoint?: boolean;
@@ -193,17 +193,31 @@ export function useSnapPoints({
193
193
  });
194
194
  };
195
195
 
196
- // Skip the transition on the very first snap when the consumer opts out of
197
- // the initial presentation animation. All subsequent snaps still animate.
196
+ // Initial measurements can take several commits before the first paint.
197
+ // Keep all of them unanimated when initial presentation animation is disabled.
198
198
  const hasSnappedRef = React.useRef(false);
199
+ const initialSnapFrameRef = React.useRef<number | null>(null);
200
+ React.useEffect(
201
+ () => () => {
202
+ if (initialSnapFrameRef.current !== null) {
203
+ window.cancelAnimationFrame(initialSnapFrameRef.current);
204
+ initialSnapFrameRef.current = null;
205
+ }
206
+ },
207
+ []
208
+ );
199
209
  const snapToPoint = React.useCallback(
200
210
  (dimension: number) => {
211
+ if (!drawerRef.current) return;
201
212
  const newSnapPointIndex =
202
213
  snapPointsOffset?.findIndex((snapPointDim) => snapPointDim === dimension) ?? null;
203
- onSnapPointChange(newSnapPointIndex);
204
214
 
205
215
  const animateThisSnap = hasSnappedRef.current || initialAnimated;
206
- hasSnappedRef.current = true;
216
+ if (initialSnapFrameRef.current === null) {
217
+ initialSnapFrameRef.current = window.requestAnimationFrame(() => {
218
+ hasSnappedRef.current = true;
219
+ });
220
+ }
207
221
  // One animated value drives both the translation and the visible height.
208
222
  set(drawerRef.current, {
209
223
  'transition': animateThisSnap
@@ -216,6 +230,9 @@ export function useSnapPoints({
216
230
  // Snapping implies drag overshoot (if any) should be undone.
217
231
  setDetachedWrapperTransform(0, animateThisSnap);
218
232
 
233
+ const overlayTransition = animateThisSnap
234
+ ? `opacity ${TRANSITIONS.DURATION}s cubic-bezier(${TRANSITIONS.EASE.join(',')})`
235
+ : 'none';
219
236
  if (
220
237
  snapPointsOffset &&
221
238
  newSnapPointIndex !== snapPointsOffset.length - 1 &&
@@ -224,24 +241,33 @@ export function useSnapPoints({
224
241
  newSnapPointIndex < fadeFromIndex
225
242
  ) {
226
243
  set(overlayRef.current, {
227
- transition: `opacity ${TRANSITIONS.DURATION}s cubic-bezier(${TRANSITIONS.EASE.join(',')})`,
244
+ transition: overlayTransition,
228
245
  opacity: '0',
229
246
  pointerEvents: 'none',
230
247
  });
231
248
  } else {
232
249
  set(overlayRef.current, {
233
- transition: `opacity ${TRANSITIONS.DURATION}s cubic-bezier(${TRANSITIONS.EASE.join(',')})`,
250
+ transition: overlayTransition,
234
251
  opacity: '1',
235
252
  pointerEvents: 'auto',
236
253
  });
237
254
  }
238
255
 
256
+ onSnapPointChange(newSnapPointIndex, animateThisSnap);
239
257
  setActiveSnapPoint(snapPoints?.[Math.max(newSnapPointIndex, 0)]);
240
258
  },
241
- [drawerRef.current, snapPoints, snapPointsOffset, fadeFromIndex, overlayRef, setActiveSnapPoint]
259
+ [
260
+ drawerRef.current,
261
+ snapPoints,
262
+ snapPointsOffset,
263
+ fadeFromIndex,
264
+ overlayRef,
265
+ setActiveSnapPoint,
266
+ initialAnimated,
267
+ ]
242
268
  );
243
269
 
244
- React.useEffect(() => {
270
+ React.useLayoutEffect(() => {
245
271
  if (!isOpen) return;
246
272
  if (activeSnapPoint || activeSnapPointProp) {
247
273
  const newIndex =