@trackunit/react-drawer 1.21.0 → 1.21.2

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.
package/index.cjs.js CHANGED
@@ -5,7 +5,6 @@ var i18nLibraryTranslation = require('@trackunit/i18n-library-translation');
5
5
  var reactComponents = require('@trackunit/react-components');
6
6
  var react = require('react');
7
7
  var cssClassVarianceUtilities = require('@trackunit/css-class-variance-utilities');
8
- var reactSwipeable = require('react-swipeable');
9
8
 
10
9
  var defaultTranslations = {
11
10
 
@@ -362,276 +361,6 @@ const cvaToggleContainer = cssClassVarianceUtilities.cvaMerge(["z-8", "absolute"
362
361
  },
363
362
  });
364
363
 
365
- /**
366
- * Retrieves the Y-axis translation value of a given HTML element.
367
- *
368
- * @param element - The HTML element for which to get the Y translation. If not provided or null, returns 0.
369
- * @returns {number} - The Y translation value of the element. Returns 0 if the element is not provided or if the transform style is "none".
370
- */
371
- const getElementYTranslation = (element) => {
372
- if (!element) {
373
- return 0;
374
- }
375
- const style = window.getComputedStyle(element);
376
- const transform = style.transform;
377
- if (transform === "none") {
378
- return 0;
379
- }
380
- const matrix = new DOMMatrix(transform);
381
- return matrix.m42;
382
- };
383
- const isPassedThreshold = (dragDistance, threshold) => {
384
- return dragDistance >= threshold;
385
- };
386
- /**
387
- * Hook for handling swipe events on the drawer.
388
- *
389
- * @param options - The hook options.
390
- * @param options.closingThreshold - The fraction (0-1) of the drawer's height needed to trigger open/close.
391
- * @param options.onCloseGesture - Callback when a close gesture is detected (optional).
392
- * @param options.onOpenGesture - Callback when an open gesture is detected (optional).
393
- * @param options.onDragEnd - Callback when the drag/swipe gesture ends. Receives drag distance and velocity (optional).
394
- * @param options.constrainDrag - Function to constrain/deny drag. Receives drag distance, returns boolean (optional).
395
- */
396
- const useSwipeHandlers = ({ closingThreshold, onCloseGesture, onOpenGesture, onDragEnd, constrainDrag, }) => {
397
- const [isDragging, setIsDragging] = react.useState(false);
398
- const [dragDistance, setDragDistance] = react.useState(0);
399
- const currentY = react.useRef(0);
400
- const [currentHeight, setCurrentHeight] = react.useState(0);
401
- const { geometry, ref, element } = reactComponents.useMeasure();
402
- const [threshold, setThreshold] = react.useState(0);
403
- react.useEffect(() => {
404
- setThreshold(currentHeight * closingThreshold);
405
- }, [currentHeight, closingThreshold]);
406
- const handleTouchStartOrMouseDown = react.useCallback(() => {
407
- const y = getElementYTranslation(element);
408
- const height = geometry?.height ?? 0;
409
- currentY.current = y;
410
- setCurrentHeight(height);
411
- setDragDistance(y);
412
- setIsDragging(true);
413
- }, [element, geometry]);
414
- const handleSwiping = react.useCallback((e) => {
415
- const newY = currentY.current + e.deltaY;
416
- if (constrainDrag && constrainDrag(e.deltaY)) {
417
- return;
418
- }
419
- if (newY >= 0) {
420
- setDragDistance(newY);
421
- }
422
- }, [constrainDrag]);
423
- const handleSwipedDown = react.useCallback((e) => {
424
- if (isPassedThreshold(e.absY, threshold) && onCloseGesture) {
425
- onCloseGesture();
426
- }
427
- setIsDragging(false);
428
- setDragDistance(0);
429
- }, [threshold, onCloseGesture]);
430
- const handleSwipedUp = react.useCallback((e) => {
431
- if (isPassedThreshold(e.absY, threshold) && onOpenGesture) {
432
- onOpenGesture();
433
- }
434
- setIsDragging(false);
435
- setDragDistance(0);
436
- }, [threshold, onOpenGesture]);
437
- const handleSwiped = react.useCallback((e) => {
438
- if (onDragEnd) {
439
- onDragEnd(e.deltaY, e.velocity);
440
- }
441
- }, [onDragEnd]);
442
- const handlers = reactSwipeable.useSwipeable({
443
- onTouchStartOrOnMouseDown: handleTouchStartOrMouseDown,
444
- onSwiping: handleSwiping,
445
- onSwipedDown: handleSwipedDown,
446
- onSwipedUp: handleSwipedUp,
447
- onSwiped: handleSwiped,
448
- trackMouse: true,
449
- trackTouch: true,
450
- preventScrollOnSwipe: true,
451
- });
452
- return react.useMemo(() => ({ handlers, isDragging, dragDistance, ref, element }), [handlers, isDragging, dragDistance, ref, element]);
453
- };
454
-
455
- /**
456
- * DrawerPuller is a React component that renders a puller element for a swipeable drawer.
457
- *
458
- * @param props - The props for the DrawerPuller component.
459
- * @param props.className - Additional class names to apply to the puller element.
460
- * @param props.ref - The ref to be forwarded to the root div element.
461
- * @returns {ReactElement} The drawer puller element.
462
- */
463
- const DrawerPuller = ({ className, ref, ...props }) => {
464
- return (jsxRuntime.jsx("div", { className: cvaPuller({ className }), "data-testid": "drawer-puller", ...props, ref: ref, children: jsxRuntime.jsx("div", { className: cvaPullerIcon() }) }));
465
- };
466
- DrawerPuller.displayName = "DrawerPuller";
467
- const cvaPuller = cssClassVarianceUtilities.cvaMerge(["pt-1", "pb-4", "flex", "items-center", "justify-center"]);
468
- const cvaPullerIcon = cssClassVarianceUtilities.cvaMerge(["block", "h-1", "w-8", "rounded-full", "bg-neutral-400"]);
469
-
470
- const CLOSING_THRESHOLD = 0.15;
471
- const VELOCITY_THRESHOLD = 0.3;
472
- const SNAP_POINT_TRANSITION = "transform 500ms cubic-bezier(0.32,0.72,0,1)";
473
- /**
474
- *
475
- * SwipeableDrawer is a component that wraps the Drawer component to add swipeable functionality.
476
- * It uses swipe handlers to detect swipe gestures for opening and closing the drawer.
477
- * The component manages its docked state based on the open prop and keepMountedWhenClosed prop.
478
- * It also applies styles dynamically based on whether the drawer is being dragged.
479
- */
480
- const SwipeableDrawer = ({ open = false, onClose, onOpen, onOpenGesture, onSnapPointChange, children, keepMountedWhenClosed, className, position = "bottom", snapPoints, activeSnapPoint: activeSnapPointProp = null, container, ref, ...others }) => {
481
- const drawerRef = react.useRef(null);
482
- const { geometry: containerGeometry, ref: containerMeasureRef } = reactComponents.useMeasure();
483
- react.useImperativeHandle(ref, () => drawerRef.current);
484
- const [activeSnapPoint, setActiveSnapPoint] = react.useState(activeSnapPointProp);
485
- const [snapPointOffsets, setSnapPointOffsets] = react.useState([]);
486
- const isLastSnapPoint = react.useMemo(() => {
487
- return activeSnapPoint === snapPoints?.[snapPoints.length - 1];
488
- }, [activeSnapPoint, snapPoints]);
489
- const isFirstSnapPoint = react.useMemo(() => {
490
- return activeSnapPoint === snapPoints?.[0];
491
- }, [activeSnapPoint, snapPoints]);
492
- const activeSnapPointIndex = react.useMemo(() => snapPoints?.findIndex(snapPoint => snapPoint === activeSnapPoint) ?? -1, [snapPoints, activeSnapPoint]);
493
- const onHandleDragEnd = react.useCallback((draggedBy, velocity) => {
494
- if (!snapPoints || !snapPoints.length) {
495
- return;
496
- }
497
- const direction = draggedBy > 0 ? -1 : 1;
498
- // If the velocity is greater than the threshold and the dragged distance is less than 40% of the container height, snap to the next snap point
499
- if (velocity > VELOCITY_THRESHOLD && Math.abs(draggedBy) < (containerGeometry?.height ?? 0) * 0.4) {
500
- const newSnapPoint = snapPoints[activeSnapPointIndex + direction] ?? null;
501
- if (newSnapPoint !== null) {
502
- setActiveSnapPoint(newSnapPoint);
503
- onSnapPointChange?.(newSnapPoint);
504
- }
505
- return;
506
- }
507
- // Otherwise, find the closest snap point
508
- // This is when the user is dragging but not swiping.
509
- // For example, when the user is dragging the drawer to the bottom but not fast enough to trigger a swipe.
510
- const currentPosition = (snapPointOffsets[activeSnapPointIndex] ?? 0) + draggedBy;
511
- const closestSnapPoint = snapPointOffsets.reduce((prev, curr) => {
512
- if (typeof prev !== "number" || typeof curr !== "number") {
513
- return prev;
514
- }
515
- return Math.abs(curr - currentPosition) < Math.abs(prev - currentPosition) ? curr : prev;
516
- });
517
- const snapPointIndex = snapPointOffsets.findIndex(offset => offset === closestSnapPoint);
518
- const nextSnapPoint = snapPoints[snapPointIndex] ?? null;
519
- if (nextSnapPoint === null) {
520
- return;
521
- }
522
- setActiveSnapPoint(nextSnapPoint);
523
- onSnapPointChange?.(nextSnapPoint);
524
- }, [snapPoints, snapPointOffsets, activeSnapPointIndex, containerGeometry, onSnapPointChange]);
525
- const { handlers, isDragging, dragDistance, ref: swipeHandlersRef, } = useSwipeHandlers({
526
- closingThreshold: CLOSING_THRESHOLD,
527
- onCloseGesture: () => {
528
- if (!snapPoints) {
529
- onClose?.();
530
- }
531
- },
532
- onOpenGesture: () => {
533
- if (!snapPoints) {
534
- onOpenGesture?.();
535
- }
536
- },
537
- onDragEnd: onHandleDragEnd,
538
- constrainDrag: (y) => {
539
- if (isLastSnapPoint) {
540
- return y <= 0;
541
- }
542
- if (isFirstSnapPoint) {
543
- return y >= 0;
544
- }
545
- return false;
546
- },
547
- });
548
- const mergedRef = reactComponents.useMergeRefs([drawerRef, swipeHandlersRef]);
549
- const { blockScroll, restoreScroll } = reactComponents.useScrollBlock();
550
- const { blockScroll: blockScrollContent, restoreScroll: restoreScrollContent } = reactComponents.useScrollBlock(document.getElementById("host-layout-content"));
551
- react.useEffect(() => {
552
- if (!snapPoints || !drawerRef.current) {
553
- return;
554
- }
555
- const containerSize = containerGeometry && containerGeometry.height > 0 ? containerGeometry.height : window.innerHeight;
556
- const newSnapPointOffsets = snapPoints.map(snapPoint => {
557
- // If snapPoint is a number, it is a percentage of the container size
558
- if (typeof snapPoint === "number") {
559
- const height = Math.floor(containerSize * snapPoint);
560
- return containerSize - height;
561
- }
562
- // If snapPoint is a string, it is a pixel value
563
- if (snapPoint.endsWith("px")) {
564
- return containerSize - parseInt(snapPoint.slice(0, -1), 10);
565
- }
566
- return 0;
567
- });
568
- setSnapPointOffsets(newSnapPointOffsets);
569
- }, [snapPoints, drawerRef, containerGeometry]);
570
- react.useEffect(() => {
571
- if (container) {
572
- containerMeasureRef(container);
573
- }
574
- }, [container, containerMeasureRef]);
575
- react.useEffect(() => {
576
- if (!snapPoints || snapPoints.length === 0) {
577
- return;
578
- }
579
- const snapPointIndex = snapPoints.findIndex(offset => offset === activeSnapPointProp);
580
- const nextSnapPoint = snapPoints[snapPointIndex > -1 ? snapPointIndex : 0] ?? null;
581
- if (nextSnapPoint === null) {
582
- return;
583
- }
584
- setActiveSnapPoint(nextSnapPoint);
585
- onSnapPointChange?.(nextSnapPoint);
586
- }, [snapPoints, activeSnapPointProp, onSnapPointChange]);
587
- const drawerStyle = react.useMemo(() => {
588
- if (isDragging) {
589
- return {
590
- transform: `translateY(${dragDistance}px)`,
591
- transition: "none",
592
- };
593
- }
594
- if (snapPoints && snapPointOffsets.length > 0 && activeSnapPointIndex !== -1) {
595
- return {
596
- transform: `translateY(${snapPointOffsets[activeSnapPointIndex]}px)`,
597
- transition: SNAP_POINT_TRANSITION,
598
- };
599
- }
600
- return {};
601
- }, [isDragging, dragDistance, snapPointOffsets, activeSnapPointIndex, snapPoints]);
602
- const applyDrawerStyles = react.useCallback(() => {
603
- if (!drawerRef.current) {
604
- return;
605
- }
606
- if (open) {
607
- drawerRef.current.style.transform = drawerStyle.transform ?? "";
608
- drawerRef.current.style.transition = drawerStyle.transition ?? "";
609
- }
610
- else {
611
- drawerRef.current.style.transform = "";
612
- drawerRef.current.style.transition = "";
613
- }
614
- }, [open, drawerStyle]);
615
- react.useEffect(() => {
616
- applyDrawerStyles();
617
- }, [applyDrawerStyles]);
618
- const onOpenHandler = react.useCallback(() => {
619
- onOpen?.();
620
- blockScroll();
621
- blockScrollContent();
622
- applyDrawerStyles();
623
- }, [onOpen, blockScroll, blockScrollContent, applyDrawerStyles]);
624
- const onCloseHandler = react.useCallback(() => {
625
- onClose?.();
626
- restoreScroll();
627
- restoreScrollContent();
628
- applyDrawerStyles();
629
- }, [onClose, restoreScroll, restoreScrollContent, applyDrawerStyles]);
630
- return (jsxRuntime.jsxs(Drawer, { className: cvaSwipeableDrawer({ className }), keepMountedWhenClosed: keepMountedWhenClosed, onClose: onCloseHandler, onOpen: onOpenHandler, open: open, position: position, ref: mergedRef, ...others, children: [jsxRuntime.jsx(DrawerPuller, { ...handlers }), children] }));
631
- };
632
- SwipeableDrawer.displayName = "SwipeableDrawer";
633
- const cvaSwipeableDrawer = cssClassVarianceUtilities.cvaMerge([]);
634
-
635
364
  /*
636
365
  * ----------------------------
637
366
  * | SETUP TRANSLATIONS START |
@@ -643,6 +372,4 @@ setupLibraryTranslations();
643
372
 
644
373
  exports.Drawer = Drawer;
645
374
  exports.DrawerToggle = DrawerToggle;
646
- exports.SwipeableDrawer = SwipeableDrawer;
647
375
  exports.TRANSITION_DURATION = TRANSITION_DURATION;
648
- exports.cvaSwipeableDrawer = cvaSwipeableDrawer;
package/index.esm.js CHANGED
@@ -1,9 +1,8 @@
1
1
  import { jsx, jsxs } from 'react/jsx-runtime';
2
2
  import { registerTranslations } from '@trackunit/i18n-library-translation';
3
- import { useViewportBreakpoints, Portal, Icon, useMeasure, useMergeRefs, useScrollBlock } from '@trackunit/react-components';
4
- import { useEffect, useReducer, useRef, useCallback, useState, useMemo, useImperativeHandle } from 'react';
3
+ import { useViewportBreakpoints, Portal, Icon } from '@trackunit/react-components';
4
+ import { useEffect, useReducer, useRef, useCallback } from 'react';
5
5
  import { cvaMerge } from '@trackunit/css-class-variance-utilities';
6
- import { useSwipeable } from 'react-swipeable';
7
6
 
8
7
  var defaultTranslations = {
9
8
 
@@ -360,276 +359,6 @@ const cvaToggleContainer = cvaMerge(["z-8", "absolute"], {
360
359
  },
361
360
  });
362
361
 
363
- /**
364
- * Retrieves the Y-axis translation value of a given HTML element.
365
- *
366
- * @param element - The HTML element for which to get the Y translation. If not provided or null, returns 0.
367
- * @returns {number} - The Y translation value of the element. Returns 0 if the element is not provided or if the transform style is "none".
368
- */
369
- const getElementYTranslation = (element) => {
370
- if (!element) {
371
- return 0;
372
- }
373
- const style = window.getComputedStyle(element);
374
- const transform = style.transform;
375
- if (transform === "none") {
376
- return 0;
377
- }
378
- const matrix = new DOMMatrix(transform);
379
- return matrix.m42;
380
- };
381
- const isPassedThreshold = (dragDistance, threshold) => {
382
- return dragDistance >= threshold;
383
- };
384
- /**
385
- * Hook for handling swipe events on the drawer.
386
- *
387
- * @param options - The hook options.
388
- * @param options.closingThreshold - The fraction (0-1) of the drawer's height needed to trigger open/close.
389
- * @param options.onCloseGesture - Callback when a close gesture is detected (optional).
390
- * @param options.onOpenGesture - Callback when an open gesture is detected (optional).
391
- * @param options.onDragEnd - Callback when the drag/swipe gesture ends. Receives drag distance and velocity (optional).
392
- * @param options.constrainDrag - Function to constrain/deny drag. Receives drag distance, returns boolean (optional).
393
- */
394
- const useSwipeHandlers = ({ closingThreshold, onCloseGesture, onOpenGesture, onDragEnd, constrainDrag, }) => {
395
- const [isDragging, setIsDragging] = useState(false);
396
- const [dragDistance, setDragDistance] = useState(0);
397
- const currentY = useRef(0);
398
- const [currentHeight, setCurrentHeight] = useState(0);
399
- const { geometry, ref, element } = useMeasure();
400
- const [threshold, setThreshold] = useState(0);
401
- useEffect(() => {
402
- setThreshold(currentHeight * closingThreshold);
403
- }, [currentHeight, closingThreshold]);
404
- const handleTouchStartOrMouseDown = useCallback(() => {
405
- const y = getElementYTranslation(element);
406
- const height = geometry?.height ?? 0;
407
- currentY.current = y;
408
- setCurrentHeight(height);
409
- setDragDistance(y);
410
- setIsDragging(true);
411
- }, [element, geometry]);
412
- const handleSwiping = useCallback((e) => {
413
- const newY = currentY.current + e.deltaY;
414
- if (constrainDrag && constrainDrag(e.deltaY)) {
415
- return;
416
- }
417
- if (newY >= 0) {
418
- setDragDistance(newY);
419
- }
420
- }, [constrainDrag]);
421
- const handleSwipedDown = useCallback((e) => {
422
- if (isPassedThreshold(e.absY, threshold) && onCloseGesture) {
423
- onCloseGesture();
424
- }
425
- setIsDragging(false);
426
- setDragDistance(0);
427
- }, [threshold, onCloseGesture]);
428
- const handleSwipedUp = useCallback((e) => {
429
- if (isPassedThreshold(e.absY, threshold) && onOpenGesture) {
430
- onOpenGesture();
431
- }
432
- setIsDragging(false);
433
- setDragDistance(0);
434
- }, [threshold, onOpenGesture]);
435
- const handleSwiped = useCallback((e) => {
436
- if (onDragEnd) {
437
- onDragEnd(e.deltaY, e.velocity);
438
- }
439
- }, [onDragEnd]);
440
- const handlers = useSwipeable({
441
- onTouchStartOrOnMouseDown: handleTouchStartOrMouseDown,
442
- onSwiping: handleSwiping,
443
- onSwipedDown: handleSwipedDown,
444
- onSwipedUp: handleSwipedUp,
445
- onSwiped: handleSwiped,
446
- trackMouse: true,
447
- trackTouch: true,
448
- preventScrollOnSwipe: true,
449
- });
450
- return useMemo(() => ({ handlers, isDragging, dragDistance, ref, element }), [handlers, isDragging, dragDistance, ref, element]);
451
- };
452
-
453
- /**
454
- * DrawerPuller is a React component that renders a puller element for a swipeable drawer.
455
- *
456
- * @param props - The props for the DrawerPuller component.
457
- * @param props.className - Additional class names to apply to the puller element.
458
- * @param props.ref - The ref to be forwarded to the root div element.
459
- * @returns {ReactElement} The drawer puller element.
460
- */
461
- const DrawerPuller = ({ className, ref, ...props }) => {
462
- return (jsx("div", { className: cvaPuller({ className }), "data-testid": "drawer-puller", ...props, ref: ref, children: jsx("div", { className: cvaPullerIcon() }) }));
463
- };
464
- DrawerPuller.displayName = "DrawerPuller";
465
- const cvaPuller = cvaMerge(["pt-1", "pb-4", "flex", "items-center", "justify-center"]);
466
- const cvaPullerIcon = cvaMerge(["block", "h-1", "w-8", "rounded-full", "bg-neutral-400"]);
467
-
468
- const CLOSING_THRESHOLD = 0.15;
469
- const VELOCITY_THRESHOLD = 0.3;
470
- const SNAP_POINT_TRANSITION = "transform 500ms cubic-bezier(0.32,0.72,0,1)";
471
- /**
472
- *
473
- * SwipeableDrawer is a component that wraps the Drawer component to add swipeable functionality.
474
- * It uses swipe handlers to detect swipe gestures for opening and closing the drawer.
475
- * The component manages its docked state based on the open prop and keepMountedWhenClosed prop.
476
- * It also applies styles dynamically based on whether the drawer is being dragged.
477
- */
478
- const SwipeableDrawer = ({ open = false, onClose, onOpen, onOpenGesture, onSnapPointChange, children, keepMountedWhenClosed, className, position = "bottom", snapPoints, activeSnapPoint: activeSnapPointProp = null, container, ref, ...others }) => {
479
- const drawerRef = useRef(null);
480
- const { geometry: containerGeometry, ref: containerMeasureRef } = useMeasure();
481
- useImperativeHandle(ref, () => drawerRef.current);
482
- const [activeSnapPoint, setActiveSnapPoint] = useState(activeSnapPointProp);
483
- const [snapPointOffsets, setSnapPointOffsets] = useState([]);
484
- const isLastSnapPoint = useMemo(() => {
485
- return activeSnapPoint === snapPoints?.[snapPoints.length - 1];
486
- }, [activeSnapPoint, snapPoints]);
487
- const isFirstSnapPoint = useMemo(() => {
488
- return activeSnapPoint === snapPoints?.[0];
489
- }, [activeSnapPoint, snapPoints]);
490
- const activeSnapPointIndex = useMemo(() => snapPoints?.findIndex(snapPoint => snapPoint === activeSnapPoint) ?? -1, [snapPoints, activeSnapPoint]);
491
- const onHandleDragEnd = useCallback((draggedBy, velocity) => {
492
- if (!snapPoints || !snapPoints.length) {
493
- return;
494
- }
495
- const direction = draggedBy > 0 ? -1 : 1;
496
- // If the velocity is greater than the threshold and the dragged distance is less than 40% of the container height, snap to the next snap point
497
- if (velocity > VELOCITY_THRESHOLD && Math.abs(draggedBy) < (containerGeometry?.height ?? 0) * 0.4) {
498
- const newSnapPoint = snapPoints[activeSnapPointIndex + direction] ?? null;
499
- if (newSnapPoint !== null) {
500
- setActiveSnapPoint(newSnapPoint);
501
- onSnapPointChange?.(newSnapPoint);
502
- }
503
- return;
504
- }
505
- // Otherwise, find the closest snap point
506
- // This is when the user is dragging but not swiping.
507
- // For example, when the user is dragging the drawer to the bottom but not fast enough to trigger a swipe.
508
- const currentPosition = (snapPointOffsets[activeSnapPointIndex] ?? 0) + draggedBy;
509
- const closestSnapPoint = snapPointOffsets.reduce((prev, curr) => {
510
- if (typeof prev !== "number" || typeof curr !== "number") {
511
- return prev;
512
- }
513
- return Math.abs(curr - currentPosition) < Math.abs(prev - currentPosition) ? curr : prev;
514
- });
515
- const snapPointIndex = snapPointOffsets.findIndex(offset => offset === closestSnapPoint);
516
- const nextSnapPoint = snapPoints[snapPointIndex] ?? null;
517
- if (nextSnapPoint === null) {
518
- return;
519
- }
520
- setActiveSnapPoint(nextSnapPoint);
521
- onSnapPointChange?.(nextSnapPoint);
522
- }, [snapPoints, snapPointOffsets, activeSnapPointIndex, containerGeometry, onSnapPointChange]);
523
- const { handlers, isDragging, dragDistance, ref: swipeHandlersRef, } = useSwipeHandlers({
524
- closingThreshold: CLOSING_THRESHOLD,
525
- onCloseGesture: () => {
526
- if (!snapPoints) {
527
- onClose?.();
528
- }
529
- },
530
- onOpenGesture: () => {
531
- if (!snapPoints) {
532
- onOpenGesture?.();
533
- }
534
- },
535
- onDragEnd: onHandleDragEnd,
536
- constrainDrag: (y) => {
537
- if (isLastSnapPoint) {
538
- return y <= 0;
539
- }
540
- if (isFirstSnapPoint) {
541
- return y >= 0;
542
- }
543
- return false;
544
- },
545
- });
546
- const mergedRef = useMergeRefs([drawerRef, swipeHandlersRef]);
547
- const { blockScroll, restoreScroll } = useScrollBlock();
548
- const { blockScroll: blockScrollContent, restoreScroll: restoreScrollContent } = useScrollBlock(document.getElementById("host-layout-content"));
549
- useEffect(() => {
550
- if (!snapPoints || !drawerRef.current) {
551
- return;
552
- }
553
- const containerSize = containerGeometry && containerGeometry.height > 0 ? containerGeometry.height : window.innerHeight;
554
- const newSnapPointOffsets = snapPoints.map(snapPoint => {
555
- // If snapPoint is a number, it is a percentage of the container size
556
- if (typeof snapPoint === "number") {
557
- const height = Math.floor(containerSize * snapPoint);
558
- return containerSize - height;
559
- }
560
- // If snapPoint is a string, it is a pixel value
561
- if (snapPoint.endsWith("px")) {
562
- return containerSize - parseInt(snapPoint.slice(0, -1), 10);
563
- }
564
- return 0;
565
- });
566
- setSnapPointOffsets(newSnapPointOffsets);
567
- }, [snapPoints, drawerRef, containerGeometry]);
568
- useEffect(() => {
569
- if (container) {
570
- containerMeasureRef(container);
571
- }
572
- }, [container, containerMeasureRef]);
573
- useEffect(() => {
574
- if (!snapPoints || snapPoints.length === 0) {
575
- return;
576
- }
577
- const snapPointIndex = snapPoints.findIndex(offset => offset === activeSnapPointProp);
578
- const nextSnapPoint = snapPoints[snapPointIndex > -1 ? snapPointIndex : 0] ?? null;
579
- if (nextSnapPoint === null) {
580
- return;
581
- }
582
- setActiveSnapPoint(nextSnapPoint);
583
- onSnapPointChange?.(nextSnapPoint);
584
- }, [snapPoints, activeSnapPointProp, onSnapPointChange]);
585
- const drawerStyle = useMemo(() => {
586
- if (isDragging) {
587
- return {
588
- transform: `translateY(${dragDistance}px)`,
589
- transition: "none",
590
- };
591
- }
592
- if (snapPoints && snapPointOffsets.length > 0 && activeSnapPointIndex !== -1) {
593
- return {
594
- transform: `translateY(${snapPointOffsets[activeSnapPointIndex]}px)`,
595
- transition: SNAP_POINT_TRANSITION,
596
- };
597
- }
598
- return {};
599
- }, [isDragging, dragDistance, snapPointOffsets, activeSnapPointIndex, snapPoints]);
600
- const applyDrawerStyles = useCallback(() => {
601
- if (!drawerRef.current) {
602
- return;
603
- }
604
- if (open) {
605
- drawerRef.current.style.transform = drawerStyle.transform ?? "";
606
- drawerRef.current.style.transition = drawerStyle.transition ?? "";
607
- }
608
- else {
609
- drawerRef.current.style.transform = "";
610
- drawerRef.current.style.transition = "";
611
- }
612
- }, [open, drawerStyle]);
613
- useEffect(() => {
614
- applyDrawerStyles();
615
- }, [applyDrawerStyles]);
616
- const onOpenHandler = useCallback(() => {
617
- onOpen?.();
618
- blockScroll();
619
- blockScrollContent();
620
- applyDrawerStyles();
621
- }, [onOpen, blockScroll, blockScrollContent, applyDrawerStyles]);
622
- const onCloseHandler = useCallback(() => {
623
- onClose?.();
624
- restoreScroll();
625
- restoreScrollContent();
626
- applyDrawerStyles();
627
- }, [onClose, restoreScroll, restoreScrollContent, applyDrawerStyles]);
628
- return (jsxs(Drawer, { className: cvaSwipeableDrawer({ className }), keepMountedWhenClosed: keepMountedWhenClosed, onClose: onCloseHandler, onOpen: onOpenHandler, open: open, position: position, ref: mergedRef, ...others, children: [jsx(DrawerPuller, { ...handlers }), children] }));
629
- };
630
- SwipeableDrawer.displayName = "SwipeableDrawer";
631
- const cvaSwipeableDrawer = cvaMerge([]);
632
-
633
362
  /*
634
363
  * ----------------------------
635
364
  * | SETUP TRANSLATIONS START |
@@ -639,4 +368,4 @@ const cvaSwipeableDrawer = cvaMerge([]);
639
368
  */
640
369
  setupLibraryTranslations();
641
370
 
642
- export { Drawer, DrawerToggle, SwipeableDrawer, TRANSITION_DURATION, cvaSwipeableDrawer };
371
+ export { Drawer, DrawerToggle, TRANSITION_DURATION };
package/package.json CHANGED
@@ -1,17 +1,16 @@
1
1
  {
2
2
  "name": "@trackunit/react-drawer",
3
- "version": "1.21.0",
3
+ "version": "1.21.2",
4
4
  "repository": "https://github.com/Trackunit/manager",
5
5
  "license": "SEE LICENSE IN LICENSE.txt",
6
6
  "engines": {
7
7
  "node": ">=24.x"
8
8
  },
9
9
  "dependencies": {
10
- "react-swipeable": "^7.0.1",
11
- "@trackunit/react-components": "1.22.0",
12
- "@trackunit/css-class-variance-utilities": "1.11.97",
13
- "@trackunit/ui-icons": "1.11.93",
14
- "@trackunit/i18n-library-translation": "1.18.3"
10
+ "@trackunit/react-components": "1.22.2",
11
+ "@trackunit/css-class-variance-utilities": "1.11.99",
12
+ "@trackunit/ui-icons": "1.11.95",
13
+ "@trackunit/i18n-library-translation": "1.18.5"
15
14
  },
16
15
  "peerDependencies": {
17
16
  "@tanstack/react-router": "^1.114.29",
package/src/index.d.ts CHANGED
@@ -1,3 +1,2 @@
1
1
  export * from "./components/Drawer/Drawer";
2
2
  export * from "./components/DrawerToggle/DrawerToggle";
3
- export * from "./components/SwipeableDrawer/SwipeableDrawer";
@@ -1,16 +0,0 @@
1
- import { CommonProps } from "@trackunit/react-components";
2
- import { ReactElement, type Ref } from "react";
3
- /**
4
- * DrawerPuller is a React component that renders a puller element for a swipeable drawer.
5
- *
6
- * @param props - The props for the DrawerPuller component.
7
- * @param props.className - Additional class names to apply to the puller element.
8
- * @param props.ref - The ref to be forwarded to the root div element.
9
- * @returns {ReactElement} The drawer puller element.
10
- */
11
- export declare const DrawerPuller: {
12
- ({ className, ref, ...props }: CommonProps & {
13
- ref?: Ref<HTMLDivElement>;
14
- }): ReactElement;
15
- displayName: string;
16
- };
@@ -1,25 +0,0 @@
1
- import { ReactElement, Ref } from "react";
2
- import { type DrawerProps } from "../Drawer/Drawer";
3
- export interface SwipeableDrawerProps extends DrawerProps {
4
- onOpenGesture?: () => void;
5
- onSnapPointChange?: (snapPoint: number | string) => void;
6
- snapPoints?: Array<number | string>;
7
- activeSnapPoint?: number | string | null;
8
- container?: HTMLElement | null;
9
- /**
10
- * A ref for the component
11
- */
12
- ref?: Ref<HTMLDivElement>;
13
- }
14
- /**
15
- *
16
- * SwipeableDrawer is a component that wraps the Drawer component to add swipeable functionality.
17
- * It uses swipe handlers to detect swipe gestures for opening and closing the drawer.
18
- * The component manages its docked state based on the open prop and keepMountedWhenClosed prop.
19
- * It also applies styles dynamically based on whether the drawer is being dragged.
20
- */
21
- export declare const SwipeableDrawer: {
22
- ({ open, onClose, onOpen, onOpenGesture, onSnapPointChange, children, keepMountedWhenClosed, className, position, snapPoints, activeSnapPoint: activeSnapPointProp, container, ref, ...others }: SwipeableDrawerProps): ReactElement;
23
- displayName: string;
24
- };
25
- export declare const cvaSwipeableDrawer: (props?: import("class-variance-authority/types").ClassProp | undefined) => string;
@@ -1,25 +0,0 @@
1
- interface UseSwipeHandlersProps {
2
- closingThreshold: number;
3
- onCloseGesture?: () => void;
4
- onOpenGesture?: () => void;
5
- onDragEnd?: (dragDistance: number, velocity: number) => void;
6
- constrainDrag?: (dragDistance: number) => boolean;
7
- }
8
- /**
9
- * Hook for handling swipe events on the drawer.
10
- *
11
- * @param options - The hook options.
12
- * @param options.closingThreshold - The fraction (0-1) of the drawer's height needed to trigger open/close.
13
- * @param options.onCloseGesture - Callback when a close gesture is detected (optional).
14
- * @param options.onOpenGesture - Callback when an open gesture is detected (optional).
15
- * @param options.onDragEnd - Callback when the drag/swipe gesture ends. Receives drag distance and velocity (optional).
16
- * @param options.constrainDrag - Function to constrain/deny drag. Receives drag distance, returns boolean (optional).
17
- */
18
- export declare const useSwipeHandlers: ({ closingThreshold, onCloseGesture, onOpenGesture, onDragEnd, constrainDrag, }: UseSwipeHandlersProps) => {
19
- handlers: import("react-swipeable").SwipeableHandlers;
20
- isDragging: boolean;
21
- dragDistance: number;
22
- ref: import("react").RefCallback<HTMLDivElement>;
23
- element: HTMLDivElement | null;
24
- };
25
- export {};