react-modal-sheet 5.0.0 → 5.1.1

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.
@@ -0,0 +1,52 @@
1
+ import { motion, useTransform } from 'motion/react';
2
+ import React from 'react';
3
+
4
+ import { useSheetContext } from './context';
5
+ import { styles } from './styles';
6
+ import type { SheetDragIndicatorProps } from './types';
7
+ import { applyStyles } from './utils';
8
+
9
+ export function SheetDragIndicator({
10
+ style,
11
+ className = '',
12
+ unstyled,
13
+ ...rest
14
+ }: SheetDragIndicatorProps) {
15
+ const sheetContext = useSheetContext();
16
+
17
+ const indicator1Transform = useTransform(
18
+ sheetContext.indicatorRotation,
19
+ (r) => `translateX(2px) rotate(${r}deg)`
20
+ );
21
+
22
+ const indicator2Transform = useTransform(
23
+ sheetContext.indicatorRotation,
24
+ (r) => `translateX(-2px) rotate(${-1 * r}deg)`
25
+ );
26
+
27
+ const isUnstyled = unstyled ?? sheetContext.unstyled;
28
+
29
+ const indicatorWrapperStyle = {
30
+ ...applyStyles(styles.indicatorWrapper, isUnstyled),
31
+ ...style,
32
+ };
33
+
34
+ const indicatorStyle = applyStyles(styles.indicator, isUnstyled);
35
+
36
+ return (
37
+ <div
38
+ className={`react-modal-sheet-drag-indicator-container ${className}`}
39
+ style={indicatorWrapperStyle}
40
+ {...rest}
41
+ >
42
+ <motion.span
43
+ className="react-modal-sheet-drag-indicator"
44
+ style={{ ...indicatorStyle, transform: indicator1Transform }}
45
+ />
46
+ <motion.span
47
+ className="react-modal-sheet-drag-indicator"
48
+ style={{ ...indicatorStyle, transform: indicator2Transform }}
49
+ />
50
+ </div>
51
+ );
52
+ }
@@ -1,14 +1,18 @@
1
- import { motion, useTransform } from 'motion/react';
1
+ import { motion } from 'motion/react';
2
2
  import React, { forwardRef } from 'react';
3
3
 
4
+ import { SheetDragIndicator } from './SheetDragIndicator';
4
5
  import { useSheetContext } from './context';
5
6
  import { useDragConstraints } from './hooks/use-drag-constraints';
6
7
  import { styles } from './styles';
7
- import { type SheetDraggableProps } from './types';
8
- import { mergeRefs } from './utils';
8
+ import { type SheetHeaderProps } from './types';
9
+ import { applyStyles, mergeRefs } from './utils';
9
10
 
10
- export const SheetHeader = forwardRef<any, SheetDraggableProps>(
11
- ({ children, style, disableDrag, ...rest }, ref) => {
11
+ export const SheetHeader = forwardRef<any, SheetHeaderProps>(
12
+ (
13
+ { children, style, disableDrag, unstyled, className = '', ...rest },
14
+ ref
15
+ ) => {
12
16
  const sheetContext = useSheetContext();
13
17
  const dragConstraints = useDragConstraints();
14
18
  const dragProps =
@@ -16,35 +20,28 @@ export const SheetHeader = forwardRef<any, SheetDraggableProps>(
16
20
  ? undefined
17
21
  : sheetContext.dragProps;
18
22
 
19
- const indicator1Transform = useTransform(
20
- sheetContext.indicatorRotation,
21
- (r) => `translateX(2px) rotate(${r}deg)`
22
- );
23
+ const isUnstyled = unstyled ?? sheetContext.unstyled;
23
24
 
24
- const indicator2Transform = useTransform(
25
- sheetContext.indicatorRotation,
26
- (r) => `translateX(-2px) rotate(${-1 * r}deg)`
27
- );
25
+ const headerWrapperStyle = {
26
+ ...applyStyles(styles.headerWrapper, isUnstyled),
27
+ ...style,
28
+ };
29
+
30
+ const headerStyle = applyStyles(styles.header, isUnstyled);
28
31
 
29
32
  return (
30
33
  <motion.div
31
34
  {...rest}
32
35
  ref={mergeRefs([ref, dragConstraints.ref])}
33
- style={{ ...styles.headerWrapper, ...style }}
36
+ style={headerWrapperStyle}
37
+ className={`react-modal-sheet-header-container ${className}`}
34
38
  {...dragProps}
35
39
  dragConstraints={dragConstraints.ref}
36
40
  onMeasureDragConstraints={dragConstraints.onMeasure}
37
41
  >
38
42
  {children || (
39
- <div className="react-modal-sheet-header" style={styles.header}>
40
- <motion.span
41
- className="react-modal-sheet-drag-indicator"
42
- style={{ ...styles.indicator, transform: indicator1Transform }}
43
- />
44
- <motion.span
45
- className="react-modal-sheet-drag-indicator"
46
- style={{ ...styles.indicator, transform: indicator2Transform }}
47
- />
43
+ <div className="react-modal-sheet-header" style={headerStyle}>
44
+ <SheetDragIndicator />
48
45
  </div>
49
46
  )}
50
47
  </motion.div>
package/src/index.tsx CHANGED
@@ -1,12 +1,12 @@
1
1
  import type { MotionValue } from 'motion/react';
2
- import type { RefObject } from 'react';
3
2
 
4
3
  import { SheetBackdrop } from './SheetBackdrop';
5
4
  import { SheetContainer } from './SheetContainer';
6
5
  import { SheetContent } from './SheetContent';
6
+ import { SheetDragIndicator } from './SheetDragIndicator';
7
7
  import { SheetHeader } from './SheetHeader';
8
8
  import { Sheet as SheetBase } from './sheet';
9
- import type { SheetCompound, SheetDraggableProps } from './types';
9
+ import type { SheetCompound } from './types';
10
10
 
11
11
  export interface SheetRef {
12
12
  y: MotionValue<number>;
@@ -18,17 +18,21 @@ export interface SheetRef {
18
18
  export const Sheet: SheetCompound = Object.assign(SheetBase, {
19
19
  Container: SheetContainer,
20
20
  Header: SheetHeader,
21
+ DragIndicator: SheetDragIndicator,
21
22
  Content: SheetContent,
22
23
  Backdrop: SheetBackdrop,
23
24
  });
24
25
 
25
26
  // Export types
26
- export type SheetHeaderProps = SheetDraggableProps;
27
- export type SheetContentProps = SheetDraggableProps;
28
27
  export type {
29
28
  SheetBackdropProps,
30
29
  SheetContainerProps,
30
+ SheetContentProps,
31
+ SheetDetent,
32
+ SheetDragIndicatorProps,
33
+ SheetHeaderProps,
31
34
  SheetProps,
32
35
  SheetSnapPoint,
33
36
  SheetStateInfo,
37
+ SheetTweenConfig,
34
38
  } from './types';
package/src/sheet.tsx CHANGED
@@ -37,6 +37,7 @@ import {
37
37
  } from './snap';
38
38
  import { styles } from './styles';
39
39
  import { type SheetContextType, type SheetProps } from './types';
40
+ import { applyStyles } from './utils';
40
41
 
41
42
  export const Sheet = forwardRef<any, SheetProps>(
42
43
  (
@@ -45,20 +46,21 @@ export const Sheet = forwardRef<any, SheetProps>(
45
46
  children,
46
47
  className = '',
47
48
  detent = 'default',
49
+ disableDismiss = false,
48
50
  disableDrag: disableDragProp = false,
49
51
  disableScrollLocking = false,
50
- disableDismiss = false,
51
52
  dragCloseThreshold = DEFAULT_DRAG_CLOSE_THRESHOLD,
52
53
  dragVelocityThreshold = DEFAULT_DRAG_VELOCITY_THRESHOLD,
54
+ initialSnap,
53
55
  isOpen,
54
56
  modalEffectRootId,
55
57
  modalEffectThreshold,
56
58
  mountPoint,
57
59
  prefersReducedMotion = false,
58
60
  snapPoints: snapPointsProp,
59
- initialSnap,
60
61
  style,
61
62
  tweenConfig = DEFAULT_TWEEN_CONFIG,
63
+ unstyled = false,
62
64
  onOpenStart,
63
65
  onOpenEnd,
64
66
  onClose,
@@ -337,6 +339,7 @@ export const Sheet = forwardRef<any, SheetProps>(
337
339
  avoidKeyboard,
338
340
  sheetBoundsRef,
339
341
  sheetRef,
342
+ unstyled,
340
343
  y,
341
344
  };
342
345
 
@@ -347,7 +350,12 @@ export const Sheet = forwardRef<any, SheetProps>(
347
350
  ref={ref}
348
351
  data-sheet-state={state}
349
352
  className={`react-modal-sheet-root ${className}`}
350
- style={{ ...styles.root, zIndex, visibility, ...style }}
353
+ style={{
354
+ ...applyStyles(styles.root, unstyled),
355
+ zIndex,
356
+ visibility,
357
+ ...style,
358
+ }}
351
359
  >
352
360
  {state !== 'closed' ? children : null}
353
361
  </motion.div>
package/src/styles.ts CHANGED
@@ -1,69 +1,110 @@
1
- import { type Properties } from 'csstype';
1
+ import type { CSSProperties } from 'react';
2
2
 
3
3
  export const styles = {
4
4
  root: {
5
- position: 'fixed',
6
- top: 0,
7
- bottom: 0,
8
- left: 0,
9
- right: 0,
10
- overflow: 'hidden',
11
- pointerEvents: 'none',
5
+ base: {
6
+ position: 'fixed',
7
+ top: 0,
8
+ bottom: 0,
9
+ left: 0,
10
+ right: 0,
11
+ overflow: 'hidden',
12
+ pointerEvents: 'none',
13
+ },
14
+ decorative: {},
12
15
  },
13
16
  backdrop: {
14
- zIndex: 1,
15
- position: 'fixed',
16
- top: 0,
17
- left: 0,
18
- width: '100%',
19
- height: '100%',
20
- backgroundColor: 'rgba(0, 0, 0, 0.2)',
21
- touchAction: 'none',
22
- border: 'none',
23
- userSelect: 'none',
24
- WebkitTapHighlightColor: 'transparent',
17
+ base: {
18
+ zIndex: 1,
19
+ position: 'fixed',
20
+ top: 0,
21
+ left: 0,
22
+ width: '100%',
23
+ height: '100%',
24
+ touchAction: 'none',
25
+ userSelect: 'none',
26
+ },
27
+ decorative: {
28
+ backgroundColor: 'rgba(0, 0, 0, 0.2)',
29
+ border: 'none',
30
+ WebkitTapHighlightColor: 'transparent',
31
+ },
25
32
  },
26
33
  container: {
27
- zIndex: 2,
28
- position: 'absolute',
29
- left: 0,
30
- bottom: 0,
31
- width: '100%',
32
- backgroundColor: '#fff',
33
- borderTopRightRadius: '8px',
34
- borderTopLeftRadius: '8px',
35
- boxShadow: '0px -2px 16px rgba(0, 0, 0, 0.3)',
36
- display: 'flex',
37
- flexDirection: 'column',
38
- pointerEvents: 'auto',
34
+ base: {
35
+ zIndex: 2,
36
+ position: 'absolute',
37
+ left: 0,
38
+ bottom: 0,
39
+ width: '100%',
40
+ pointerEvents: 'auto',
41
+ display: 'flex',
42
+ flexDirection: 'column',
43
+ },
44
+ decorative: {
45
+ backgroundColor: '#fff',
46
+ borderTopRightRadius: '8px',
47
+ borderTopLeftRadius: '8px',
48
+ boxShadow: '0px -2px 16px rgba(0, 0, 0, 0.3)',
49
+ },
39
50
  },
40
51
  headerWrapper: {
41
- width: '100%',
52
+ base: {
53
+ width: '100%',
54
+ },
55
+ decorative: {},
42
56
  },
43
57
  header: {
44
- height: '40px',
45
- width: '100%',
46
- position: 'relative',
47
- display: 'flex',
48
- alignItems: 'center',
49
- justifyContent: 'center',
58
+ base: {
59
+ width: '100%',
60
+ position: 'relative',
61
+ },
62
+ decorative: {
63
+ height: '40px',
64
+ display: 'flex',
65
+ alignItems: 'center',
66
+ justifyContent: 'center',
67
+ },
68
+ },
69
+ indicatorWrapper: {
70
+ base: {
71
+ display: 'flex',
72
+ },
73
+ decorative: {},
50
74
  },
51
75
  indicator: {
52
- width: '18px',
53
- height: '4px',
54
- borderRadius: '99px',
55
- backgroundColor: '#ddd',
76
+ base: {
77
+ display: 'inline-block',
78
+ },
79
+ decorative: {
80
+ width: '18px',
81
+ height: '4px',
82
+ borderRadius: '99px',
83
+ backgroundColor: '#ddd',
84
+ },
56
85
  },
57
86
  content: {
58
- flexGrow: 1,
59
- display: 'flex',
60
- flexDirection: 'column',
61
- minHeight: '0px',
62
- position: 'relative',
87
+ base: {
88
+ minHeight: '0px',
89
+ position: 'relative',
90
+ flexGrow: 1,
91
+ display: 'flex',
92
+ flexDirection: 'column',
93
+ },
94
+ decorative: {},
63
95
  },
64
96
  scroller: {
65
- height: '100%',
66
- overflowY: 'auto',
67
- overscrollBehaviorY: 'none',
97
+ base: {
98
+ height: '100%',
99
+ overflowY: 'auto',
100
+ overscrollBehaviorY: 'none',
101
+ },
102
+ decorative: {},
68
103
  },
69
- } satisfies Record<string, Properties>;
104
+ } satisfies Record<
105
+ string,
106
+ {
107
+ base: CSSProperties;
108
+ decorative: CSSProperties;
109
+ }
110
+ >;
package/src/types.tsx CHANGED
@@ -1,6 +1,9 @@
1
1
  import {
2
+ type CSSProperties,
2
3
  type ComponentPropsWithoutRef,
3
4
  type ForwardRefExoticComponent,
5
+ type FunctionComponent,
6
+ type HTMLAttributes,
4
7
  type ReactNode,
5
8
  type RefAttributes,
6
9
  type RefObject,
@@ -11,18 +14,20 @@ import {
11
14
  type EasingDefinition,
12
15
  type MotionProps,
13
16
  type MotionValue,
14
- type Transition,
15
17
  type motion,
16
18
  } from 'motion/react';
17
- import type { RectReadOnly } from 'react-use-measure';
18
19
 
19
20
  export type SheetDetent = 'default' | 'full' | 'content';
20
21
 
21
- type CommonProps = MotionProps & {
22
+ type CommonProps = {
22
23
  className?: string;
24
+ unstyled?: boolean;
23
25
  };
24
26
 
25
- type MotionDivProps = ComponentPropsWithoutRef<typeof motion.div>;
27
+ type MotionCommonProps = Omit<
28
+ ComponentPropsWithoutRef<typeof motion.div>,
29
+ 'initial' | 'animate' | 'exit'
30
+ >;
26
31
 
27
32
  export interface SheetTweenConfig {
28
33
  ease: EasingDefinition;
@@ -30,6 +35,7 @@ export interface SheetTweenConfig {
30
35
  }
31
36
 
32
37
  export type SheetProps = {
38
+ unstyled?: boolean;
33
39
  avoidKeyboard?: boolean;
34
40
  children: ReactNode;
35
41
  detent?: SheetDetent;
@@ -52,24 +58,30 @@ export type SheetProps = {
52
58
  onOpenEnd?: () => void;
53
59
  onOpenStart?: () => void;
54
60
  onSnap?: (index: number) => void;
55
- } & MotionDivProps;
61
+ } & MotionCommonProps;
56
62
 
57
- export type SheetContainerProps = Omit<
58
- CommonProps,
59
- 'initial' | 'animate' | 'exit' | 'onAnimationComplete'
60
- > & {
61
- children: ReactNode;
62
- };
63
+ export type SheetContainerProps = MotionCommonProps &
64
+ CommonProps & {
65
+ children: ReactNode;
66
+ };
63
67
 
64
- export type SheetDraggableProps = MotionDivProps & {
65
- children?: ReactNode;
66
- disableDrag?: boolean;
67
- };
68
+ export type SheetHeaderProps = MotionCommonProps &
69
+ CommonProps & {
70
+ children?: ReactNode;
71
+ disableDrag?: boolean;
72
+ };
68
73
 
69
- export type SheetBackdropProps = Omit<
70
- CommonProps,
71
- 'initial' | 'animate' | 'exit'
72
- >;
74
+ export type SheetContentProps = MotionCommonProps &
75
+ CommonProps & {
76
+ disableDrag?: boolean | ((args: SheetStateInfo) => boolean);
77
+ disableScroll?: boolean | ((args: SheetStateInfo) => boolean);
78
+ scrollRef?: RefObject<HTMLDivElement | null>;
79
+ };
80
+
81
+ export type SheetBackdropProps = MotionCommonProps & CommonProps;
82
+
83
+ export type SheetDragIndicatorProps = HTMLAttributes<HTMLDivElement> &
84
+ CommonProps;
73
85
 
74
86
  export interface SheetDragProps {
75
87
  drag: 'y';
@@ -86,12 +98,6 @@ export type SheetStateInfo = {
86
98
  currentSnap?: number;
87
99
  };
88
100
 
89
- export type SheetContentScrollableProps = MotionDivProps & {
90
- disableDrag?: boolean | ((args: SheetStateInfo) => boolean);
91
- disableScroll?: boolean | ((args: SheetStateInfo) => boolean);
92
- scrollRef?: RefObject<HTMLDivElement | null>;
93
- };
94
-
95
101
  export type SheetSnapPoint = {
96
102
  snapIndex: number;
97
103
  snapValue: number; // Absolute value from the bottom of the sheet
@@ -107,6 +113,7 @@ export interface SheetContextType {
107
113
  avoidKeyboard: boolean;
108
114
  sheetBoundsRef: (node: HTMLDivElement | null) => void;
109
115
  sheetRef: RefObject<any>;
116
+ unstyled: boolean;
110
117
  y: MotionValue<any>;
111
118
  }
112
119
 
@@ -116,30 +123,31 @@ export interface SheetScrollerContextType {
116
123
  setDragEnabled: () => void;
117
124
  }
118
125
 
126
+ type SheetComponent = ForwardRefExoticComponent<
127
+ SheetProps & RefAttributes<any>
128
+ >;
129
+
119
130
  type ContainerComponent = ForwardRefExoticComponent<
120
131
  SheetContainerProps & RefAttributes<any>
121
132
  >;
122
133
 
123
- type DraggableComponent = ForwardRefExoticComponent<
124
- SheetDraggableProps & RefAttributes<any>
134
+ type HeaderComponent = ForwardRefExoticComponent<
135
+ SheetHeaderProps & RefAttributes<any>
125
136
  >;
126
137
 
127
138
  type BackdropComponent = ForwardRefExoticComponent<
128
139
  SheetBackdropProps & RefAttributes<any>
129
140
  >;
130
141
 
131
- type SheetComponent = ForwardRefExoticComponent<
132
- SheetProps & RefAttributes<any>
133
- >;
134
-
135
- type ContentScrollableComponent = ForwardRefExoticComponent<
136
- SheetContentScrollableProps & RefAttributes<any>
142
+ type ContentComponent = ForwardRefExoticComponent<
143
+ SheetContentProps & RefAttributes<any>
137
144
  >;
138
145
 
139
146
  interface SheetCompoundComponent {
140
147
  Container: ContainerComponent;
141
- Header: DraggableComponent;
142
- Content: ContentScrollableComponent;
148
+ Header: HeaderComponent;
149
+ DragIndicator: FunctionComponent<SheetDragIndicatorProps>;
150
+ Content: ContentComponent;
143
151
  Backdrop: BackdropComponent;
144
152
  }
145
153
 
package/src/utils.ts CHANGED
@@ -1,6 +1,13 @@
1
- import { type ForwardedRef, type RefCallback, type RefObject } from 'react';
1
+ import { type CSSProperties, type ForwardedRef, type RefCallback } from 'react';
2
2
  import { IS_SSR } from './constants';
3
3
 
4
+ export function applyStyles(
5
+ styles: { base: CSSProperties; decorative: CSSProperties },
6
+ unstyled: boolean
7
+ ) {
8
+ return unstyled ? styles.base : { ...styles.base, ...styles.decorative };
9
+ }
10
+
4
11
  export function isAscendingOrder(arr: number[]) {
5
12
  for (let i = 0; i < arr.length; i++) {
6
13
  if (arr[i + 1] < arr[i]) return false;