react-panel-layout 0.6.0 → 0.6.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.
- package/dist/{FloatingPanelFrame-SgYLc6Ud.js → FloatingPanelFrame-3eU9AwPo.js} +2 -2
- package/dist/{FloatingPanelFrame-SgYLc6Ud.js.map → FloatingPanelFrame-3eU9AwPo.js.map} +1 -1
- package/dist/FloatingWindow-CUXnEtrb.js +827 -0
- package/dist/FloatingWindow-CUXnEtrb.js.map +1 -0
- package/dist/FloatingWindow-DMwyK0eK.cjs +2 -0
- package/dist/FloatingWindow-DMwyK0eK.cjs.map +1 -0
- package/dist/GridLayout-DKTg_N61.cjs +2 -0
- package/dist/{GridLayout-B4VRsC0r.cjs.map → GridLayout-DKTg_N61.cjs.map} +1 -1
- package/dist/{GridLayout-BltqeCPK.js → GridLayout-UWNxXw77.js} +34 -35
- package/dist/{GridLayout-BltqeCPK.js.map → GridLayout-UWNxXw77.js.map} +1 -1
- package/dist/{HorizontalDivider-WF1k_qND.js → HorizontalDivider-DdxzfV0l.js} +3 -3
- package/dist/{HorizontalDivider-WF1k_qND.js.map → HorizontalDivider-DdxzfV0l.js.map} +1 -1
- package/dist/{HorizontalDivider-B5Z-KZLk.cjs → HorizontalDivider-_pgV4Mcv.cjs} +2 -2
- package/dist/{HorizontalDivider-B5Z-KZLk.cjs.map → HorizontalDivider-_pgV4Mcv.cjs.map} +1 -1
- package/dist/{PanelSystem-Dr1TBhxM.js → PanelSystem-BqUzNtf2.js} +5 -5
- package/dist/{PanelSystem-Dr1TBhxM.js.map → PanelSystem-BqUzNtf2.js.map} +1 -1
- package/dist/{PanelSystem-Bs8bQwQF.cjs → PanelSystem-D603LKKv.cjs} +2 -2
- package/dist/{PanelSystem-Bs8bQwQF.cjs.map → PanelSystem-D603LKKv.cjs.map} +1 -1
- package/dist/ResizeHandle-CBcAS918.cjs +2 -0
- package/dist/{ResizeHandle-CScipO5l.cjs.map → ResizeHandle-CBcAS918.cjs.map} +1 -1
- package/dist/{ResizeHandle-CdA_JYfN.js → ResizeHandle-CXjc1meV.js} +28 -29
- package/dist/{ResizeHandle-CdA_JYfN.js.map → ResizeHandle-CXjc1meV.js.map} +1 -1
- package/dist/SwipePivotTabBar-DWrCuwEI.js +411 -0
- package/dist/SwipePivotTabBar-DWrCuwEI.js.map +1 -0
- package/dist/SwipePivotTabBar-fjjXkpj7.cjs +2 -0
- package/dist/SwipePivotTabBar-fjjXkpj7.cjs.map +1 -0
- package/dist/components/gesture/SwipeSafeZone.d.ts +40 -0
- package/dist/components/window/Drawer.d.ts +3 -1
- package/dist/components/window/DrawerLayers.d.ts +1 -1
- package/dist/components/window/drawerStyles.d.ts +69 -0
- package/dist/components/window/drawerSwipeConfig.d.ts +29 -0
- package/dist/components/window/useDrawerSwipeTransform.d.ts +23 -0
- package/dist/config.cjs +1 -1
- package/dist/config.js +3 -3
- package/dist/constants/styles.d.ts +17 -0
- package/dist/dialog/index.d.ts +69 -0
- package/dist/floating.js +1 -1
- package/dist/grid.cjs +1 -1
- package/dist/grid.js +2 -2
- package/dist/hooks/gesture/testing/createGestureSimulator.d.ts +7 -0
- package/dist/hooks/gesture/types.d.ts +48 -5
- package/dist/hooks/gesture/utils.d.ts +19 -0
- package/dist/hooks/useAnimationFrame.d.ts +2 -0
- package/dist/hooks/useOperationContinuity.d.ts +64 -0
- package/dist/hooks/useResizeObserver.d.ts +33 -1
- package/dist/hooks/useSharedElementTransition.d.ts +112 -0
- package/dist/hooks/useSwipeContentTransform.d.ts +9 -2
- package/dist/index.cjs +1 -1
- package/dist/index.js +7 -7
- package/dist/modules/dialog/AlertDialog.d.ts +9 -0
- package/dist/modules/dialog/DialogContainer.d.ts +37 -0
- package/dist/modules/dialog/Modal.d.ts +26 -0
- package/dist/modules/dialog/SwipeDialogContainer.d.ts +16 -0
- package/dist/modules/dialog/dialogAnimationUtils.d.ts +113 -0
- package/dist/modules/dialog/types.d.ts +183 -0
- package/dist/modules/dialog/useDialog.d.ts +39 -0
- package/dist/modules/dialog/useDialogContainer.d.ts +47 -0
- package/dist/modules/dialog/useDialogSwipeInput.d.ts +70 -0
- package/dist/modules/dialog/useDialogTransform.d.ts +82 -0
- package/dist/modules/drawer/types.d.ts +74 -0
- package/dist/modules/drawer/useDrawerSwipeInput.d.ts +24 -0
- package/dist/modules/pivot/SwipePivotTabBar.d.ts +3 -0
- package/dist/modules/stack/SwipeStackContent.d.ts +6 -3
- package/dist/modules/stack/SwipeStackOutlet.d.ts +4 -4
- package/dist/modules/stack/computeSwipeStackTransform.d.ts +1 -1
- package/dist/panels.cjs +1 -1
- package/dist/panels.js +1 -1
- package/dist/pivot.cjs +1 -1
- package/dist/pivot.js +1 -1
- package/dist/resizer.cjs +1 -1
- package/dist/resizer.js +2 -2
- package/dist/stack.cjs +1 -1
- package/dist/stack.cjs.map +1 -1
- package/dist/stack.js +503 -762
- package/dist/stack.js.map +1 -1
- package/dist/sticky-header/calculateStickyMetrics.d.ts +28 -0
- package/dist/sticky-header.cjs +1 -1
- package/dist/sticky-header.cjs.map +1 -1
- package/dist/sticky-header.js +59 -51
- package/dist/sticky-header.js.map +1 -1
- package/dist/{styles-DPPuJ0sf.js → styles-NkjuMOVS.js} +13 -13
- package/dist/{styles-DPPuJ0sf.js.map → styles-NkjuMOVS.js.map} +1 -1
- package/dist/styles-qf6ptVLD.cjs.map +1 -1
- package/dist/types.d.ts +16 -0
- package/dist/useDocumentPointerEvents-DXxw3qWj.js +54 -0
- package/dist/useDocumentPointerEvents-DXxw3qWj.js.map +1 -0
- package/dist/useDocumentPointerEvents-DxDSOtip.cjs +2 -0
- package/dist/useDocumentPointerEvents-DxDSOtip.cjs.map +1 -0
- package/dist/useNativeGestureGuard-C7TSqEkr.cjs +2 -0
- package/dist/useNativeGestureGuard-C7TSqEkr.cjs.map +1 -0
- package/dist/useNativeGestureGuard-CGYo6O0r.js +347 -0
- package/dist/useNativeGestureGuard-CGYo6O0r.js.map +1 -0
- package/dist/window/index.d.ts +2 -0
- package/dist/window.cjs +1 -1
- package/dist/window.cjs.map +1 -1
- package/dist/window.js +114 -103
- package/dist/window.js.map +1 -1
- package/package.json +6 -1
- package/src/components/gesture/SwipeSafeZone.tsx +69 -0
- package/src/components/window/Drawer.tsx +249 -162
- package/src/components/window/DrawerLayers.tsx +13 -3
- package/src/components/window/drawerStyles.spec.ts +263 -0
- package/src/components/window/drawerStyles.ts +228 -0
- package/src/components/window/drawerSwipeConfig.spec.ts +131 -0
- package/src/components/window/drawerSwipeConfig.ts +112 -0
- package/src/components/window/useDrawerSwipeTransform.spec.ts +234 -0
- package/src/components/window/useDrawerSwipeTransform.ts +129 -0
- package/src/constants/styles.ts +19 -0
- package/src/demo/pages/Dialog/alerts/index.tsx +22 -0
- package/src/demo/pages/Dialog/card/index.tsx +22 -0
- package/src/demo/pages/Dialog/components/AlertDialogDemo.tsx +124 -0
- package/src/demo/pages/Dialog/components/CardExpandDemo.module.css +243 -0
- package/src/demo/pages/Dialog/components/CardExpandDemo.tsx +204 -0
- package/src/demo/pages/Dialog/components/CustomAlertDialogDemo.tsx +219 -0
- package/src/demo/pages/Dialog/components/DialogDemos.module.css +77 -0
- package/src/demo/pages/Dialog/components/ModalBasics.tsx +45 -0
- package/src/demo/pages/Dialog/components/SwipeDialogDemo.module.css +77 -0
- package/src/demo/pages/Dialog/components/SwipeDialogDemo.tsx +181 -0
- package/src/demo/pages/Dialog/custom-alert/index.tsx +22 -0
- package/src/demo/pages/Dialog/modal/index.tsx +17 -0
- package/src/demo/pages/Dialog/swipe/index.tsx +22 -0
- package/src/demo/pages/Drawer/components/DrawerSwipe.module.css +316 -0
- package/src/demo/pages/Drawer/components/DrawerSwipe.tsx +178 -0
- package/src/demo/pages/Drawer/swipe/index.tsx +17 -0
- package/src/demo/pages/Pivot/components/SwipeTabsPivot.tsx +54 -23
- package/src/demo/pages/Pivot/swipe-debug/index.tsx +1 -1
- package/src/demo/pages/Stack/components/StackBasics.spec.tsx +152 -0
- package/src/demo/pages/Stack/components/StackBasics.tsx +179 -95
- package/src/demo/pages/Stack/components/StackTablet.spec.tsx +120 -0
- package/src/demo/pages/Stack/components/StackTablet.tsx +42 -21
- package/src/demo/routes.tsx +22 -1
- package/src/dialog/index.ts +85 -0
- package/src/hooks/gesture/testing/createGestureSimulator.spec.ts +68 -64
- package/src/hooks/gesture/testing/createGestureSimulator.ts +112 -37
- package/src/hooks/gesture/types.ts +83 -6
- package/src/hooks/gesture/useEdgeSwipeInput.spec.ts +22 -14
- package/src/hooks/gesture/useNativeGestureGuard.spec.ts +91 -31
- package/src/hooks/gesture/useNativeGestureGuard.ts +3 -1
- package/src/hooks/gesture/utils.ts +91 -0
- package/src/hooks/useAnimatedVisibility.spec.ts +44 -24
- package/src/hooks/useAnimatedVisibility.ts +28 -2
- package/src/hooks/useAnimationFrame.ts +8 -0
- package/src/hooks/useOperationContinuity.spec.ts +387 -0
- package/src/hooks/useOperationContinuity.ts +135 -0
- package/src/hooks/useResizeObserver.spec.tsx +277 -0
- package/src/hooks/useResizeObserver.tsx +108 -39
- package/src/hooks/useScrollContainer.ts +4 -10
- package/src/hooks/useSharedElementTransition.ts +333 -0
- package/src/hooks/useSwipeContentTransform.spec.ts +18 -18
- package/src/hooks/useSwipeContentTransform.ts +166 -28
- package/src/modules/dialog/AlertDialog.spec.tsx +387 -0
- package/src/modules/dialog/AlertDialog.tsx +221 -0
- package/src/modules/dialog/DialogContainer.spec.tsx +228 -0
- package/src/modules/dialog/DialogContainer.tsx +188 -0
- package/src/modules/dialog/Modal.spec.tsx +220 -0
- package/src/modules/dialog/Modal.tsx +182 -0
- package/src/modules/dialog/SwipeDialogContainer.tsx +208 -0
- package/src/modules/dialog/dialogAnimationUtils.spec.ts +253 -0
- package/src/modules/dialog/dialogAnimationUtils.ts +297 -0
- package/src/modules/dialog/types.ts +186 -0
- package/src/modules/dialog/useDialog.spec.tsx +447 -0
- package/src/modules/dialog/useDialog.ts +214 -0
- package/src/modules/dialog/useDialogContainer.spec.ts +331 -0
- package/src/modules/dialog/useDialogContainer.ts +150 -0
- package/src/modules/dialog/useDialogSwipeInput.spec.ts +157 -0
- package/src/modules/dialog/useDialogSwipeInput.ts +319 -0
- package/src/modules/dialog/useDialogTransform.spec.ts +370 -0
- package/src/modules/dialog/useDialogTransform.ts +407 -0
- package/src/modules/drawer/types.ts +102 -0
- package/src/modules/drawer/useDrawerSwipeInput.spec.ts +566 -0
- package/src/modules/drawer/useDrawerSwipeInput.ts +399 -0
- package/src/modules/panels/rendering/ContentRegistry.spec.tsx +21 -14
- package/src/modules/pivot/SwipePivotContent.position.spec.tsx +12 -8
- package/src/modules/pivot/SwipePivotContent.spec.tsx +55 -25
- package/src/modules/pivot/SwipePivotContent.tsx +2 -2
- package/src/modules/pivot/SwipePivotTabBar.spec.tsx +85 -68
- package/src/modules/pivot/SwipePivotTabBar.tsx +75 -15
- package/src/modules/pivot/scaleInputState.spec.ts +11 -2
- package/src/modules/pivot/usePivot.spec.ts +17 -3
- package/src/modules/pivot/usePivotSwipeInput.spec.ts +182 -123
- package/src/modules/stack/SwipeStackContent.spec.tsx +387 -100
- package/src/modules/stack/SwipeStackContent.tsx +43 -33
- package/src/modules/stack/SwipeStackOutlet.spec.tsx +14 -16
- package/src/modules/stack/SwipeStackOutlet.tsx +6 -6
- package/src/modules/stack/computeSwipeStackTransform.spec.ts +5 -5
- package/src/modules/stack/computeSwipeStackTransform.ts +3 -3
- package/src/modules/stack/swipeTransitionContinuity.spec.tsx +1133 -0
- package/src/modules/stack/useStackAnimationState.spec.ts +3 -1
- package/src/modules/stack/useStackAnimationState.ts +18 -13
- package/src/modules/stack/useStackNavigation.spec.ts +198 -3
- package/src/modules/stack/useStackNavigation.tsx +113 -56
- package/src/modules/stack/useStackSwipeInput.spec.ts +65 -32
- package/src/modules/stack/useStackSwipeInput.ts +1 -1
- package/src/sticky-header/StickyArea.tsx +29 -57
- package/src/sticky-header/calculateStickyMetrics.spec.ts +105 -0
- package/src/sticky-header/calculateStickyMetrics.ts +50 -0
- package/src/types.ts +18 -0
- package/src/window/index.ts +2 -0
- package/dist/FloatingWindow-BpdOpg_L.js +0 -400
- package/dist/FloatingWindow-BpdOpg_L.js.map +0 -1
- package/dist/FloatingWindow-TCDNY5gE.cjs +0 -2
- package/dist/FloatingWindow-TCDNY5gE.cjs.map +0 -1
- package/dist/GridLayout-B4VRsC0r.cjs +0 -2
- package/dist/ResizeHandle-CScipO5l.cjs +0 -2
- package/dist/SwipePivotTabBar-BGO9X94m.js +0 -407
- package/dist/SwipePivotTabBar-BGO9X94m.js.map +0 -1
- package/dist/SwipePivotTabBar-BrQismcZ.cjs +0 -2
- package/dist/SwipePivotTabBar-BrQismcZ.cjs.map +0 -1
- package/dist/useDocumentPointerEvents-CKdhGXd0.js +0 -46
- package/dist/useDocumentPointerEvents-CKdhGXd0.js.map +0 -1
- package/dist/useDocumentPointerEvents-ChqrKXDk.cjs +0 -2
- package/dist/useDocumentPointerEvents-ChqrKXDk.cjs.map +0 -1
- package/dist/useEffectEvent-Dp7HLCf0.js +0 -13
- package/dist/useEffectEvent-Dp7HLCf0.js.map +0 -1
- package/dist/useEffectEvent-huSsGUnl.cjs +0 -2
- package/dist/useEffectEvent-huSsGUnl.cjs.map +0 -1
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file SwipeSafeZone component
|
|
3
|
+
*
|
|
4
|
+
* A wrapper component that marks an area as exempt from swipe gesture detection.
|
|
5
|
+
* Content inside this zone will not trigger swipe-to-close or other swipe gestures.
|
|
6
|
+
*
|
|
7
|
+
* Use this for:
|
|
8
|
+
* - Scrollable content areas
|
|
9
|
+
* - Input fields and text areas
|
|
10
|
+
* - Interactive elements that need drag/swipe for their own purposes
|
|
11
|
+
*/
|
|
12
|
+
import * as React from "react";
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Data attribute used to identify swipe-safe zones.
|
|
16
|
+
* Swipe gesture handlers should check for this attribute on target elements.
|
|
17
|
+
*/
|
|
18
|
+
export const SWIPE_SAFE_ZONE_ATTR = "data-swipe-safe-zone";
|
|
19
|
+
|
|
20
|
+
export type SwipeSafeZoneProps = {
|
|
21
|
+
/** Content to render inside the safe zone */
|
|
22
|
+
children: React.ReactNode;
|
|
23
|
+
/** Additional CSS class name */
|
|
24
|
+
className?: string;
|
|
25
|
+
/** Additional inline styles */
|
|
26
|
+
style?: React.CSSProperties;
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* SwipeSafeZone marks an area where swipe gestures should not be triggered.
|
|
31
|
+
*
|
|
32
|
+
* @example
|
|
33
|
+
* ```tsx
|
|
34
|
+
* <SwipeSafeZone>
|
|
35
|
+
* <ScrollableList items={items} />
|
|
36
|
+
* </SwipeSafeZone>
|
|
37
|
+
* ```
|
|
38
|
+
*/
|
|
39
|
+
export const SwipeSafeZone: React.FC<SwipeSafeZoneProps> = ({
|
|
40
|
+
children,
|
|
41
|
+
className,
|
|
42
|
+
style,
|
|
43
|
+
}) => {
|
|
44
|
+
return (
|
|
45
|
+
<div
|
|
46
|
+
className={className}
|
|
47
|
+
style={style}
|
|
48
|
+
data-swipe-safe-zone="true"
|
|
49
|
+
>
|
|
50
|
+
{children}
|
|
51
|
+
</div>
|
|
52
|
+
);
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Check if an element is inside a SwipeSafeZone.
|
|
57
|
+
*/
|
|
58
|
+
export function isInSwipeSafeZone(element: HTMLElement, container: HTMLElement): boolean {
|
|
59
|
+
let current: HTMLElement | null = element;
|
|
60
|
+
|
|
61
|
+
while (current && current !== container) {
|
|
62
|
+
if (current.hasAttribute(SWIPE_SAFE_ZONE_ATTR)) {
|
|
63
|
+
return true;
|
|
64
|
+
}
|
|
65
|
+
current = current.parentElement;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
return false;
|
|
69
|
+
}
|
|
@@ -2,83 +2,53 @@
|
|
|
2
2
|
* @file Drawer component
|
|
3
3
|
*
|
|
4
4
|
* Mobile-friendly slide-in panel with backdrop support.
|
|
5
|
+
* Supports swipe gestures for opening/closing.
|
|
5
6
|
*/
|
|
6
7
|
import * as React from "react";
|
|
7
|
-
import type { DrawerBehavior, WindowPosition } from "../../types";
|
|
8
|
+
import type { DrawerBehavior, WindowPosition } from "../../types.js";
|
|
8
9
|
import {
|
|
9
10
|
FloatingPanelCloseButton,
|
|
10
11
|
FloatingPanelContent,
|
|
11
12
|
FloatingPanelFrame,
|
|
12
13
|
FloatingPanelHeader,
|
|
13
14
|
FloatingPanelTitle,
|
|
14
|
-
} from "../paneling/FloatingPanelFrame";
|
|
15
|
+
} from "../paneling/FloatingPanelFrame.js";
|
|
15
16
|
import {
|
|
16
17
|
DRAWER_HEADER_PADDING_Y,
|
|
17
18
|
DRAWER_HEADER_PADDING_X,
|
|
18
19
|
DRAWER_HEADER_GAP,
|
|
19
20
|
DRAWER_CONTENT_PADDING,
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
};
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
transform: "translateX(-100%)",
|
|
41
|
-
},
|
|
42
|
-
right: {
|
|
43
|
-
top: 0,
|
|
44
|
-
bottom: 0,
|
|
45
|
-
right: 0,
|
|
46
|
-
transform: "translateX(100%)",
|
|
47
|
-
},
|
|
48
|
-
top: {
|
|
49
|
-
top: 0,
|
|
50
|
-
left: 0,
|
|
51
|
-
right: 0,
|
|
52
|
-
transform: "translateY(-100%)",
|
|
53
|
-
},
|
|
54
|
-
bottom: {
|
|
55
|
-
bottom: 0,
|
|
56
|
-
left: 0,
|
|
57
|
-
right: 0,
|
|
58
|
-
transform: "translateY(100%)",
|
|
59
|
-
},
|
|
60
|
-
};
|
|
61
|
-
|
|
62
|
-
const computeTransitionValue = (
|
|
63
|
-
mode: DrawerBehavior["transitionMode"] | undefined,
|
|
64
|
-
duration: DrawerBehavior["transitionDuration"],
|
|
65
|
-
easing: DrawerBehavior["transitionEasing"],
|
|
66
|
-
): string | undefined => {
|
|
67
|
-
if (mode === "none") {
|
|
68
|
-
return undefined;
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
const durationValue = duration ?? DRAWER_TRANSITION_DURATION;
|
|
72
|
-
const easingValue = easing ?? DRAWER_TRANSITION_EASING;
|
|
21
|
+
} from "../../constants/styles.js";
|
|
22
|
+
import { useDrawerSwipeInput } from "../../modules/drawer/useDrawerSwipeInput.js";
|
|
23
|
+
import type { DrawerSwipeDirection } from "../../modules/drawer/types.js";
|
|
24
|
+
import {
|
|
25
|
+
DRAWER_BACKDROP_BASE_STYLE,
|
|
26
|
+
DRAWER_PANEL_BASE_STYLE,
|
|
27
|
+
getPlacementStyle,
|
|
28
|
+
getOpenTransform,
|
|
29
|
+
computeTransitionValue,
|
|
30
|
+
computeBackdropTransition,
|
|
31
|
+
formatDimension,
|
|
32
|
+
computeEdgeZoneStyle,
|
|
33
|
+
} from "./drawerStyles.js";
|
|
34
|
+
import type { DrawerPlacement } from "./drawerStyles.js";
|
|
35
|
+
import {
|
|
36
|
+
parseSwipeGesturesConfig,
|
|
37
|
+
resolvePlacement,
|
|
38
|
+
shouldShowEdgeZone,
|
|
39
|
+
} from "./drawerSwipeConfig.js";
|
|
40
|
+
import { useDrawerSwipeTransform } from "./useDrawerSwipeTransform.js";
|
|
73
41
|
|
|
74
|
-
|
|
75
|
-
|
|
42
|
+
// ============================================================================
|
|
43
|
+
// Types
|
|
44
|
+
// ============================================================================
|
|
76
45
|
|
|
77
46
|
export type DrawerProps = {
|
|
78
47
|
id: string;
|
|
79
48
|
config: DrawerBehavior;
|
|
80
49
|
isOpen: boolean;
|
|
81
50
|
onClose: () => void;
|
|
51
|
+
onOpen?: () => void;
|
|
82
52
|
children: React.ReactNode;
|
|
83
53
|
zIndex?: number;
|
|
84
54
|
width?: string | number;
|
|
@@ -86,12 +56,9 @@ export type DrawerProps = {
|
|
|
86
56
|
position?: WindowPosition;
|
|
87
57
|
};
|
|
88
58
|
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
}
|
|
93
|
-
return showClose;
|
|
94
|
-
};
|
|
59
|
+
// ============================================================================
|
|
60
|
+
// Sub-components
|
|
61
|
+
// ============================================================================
|
|
95
62
|
|
|
96
63
|
type DrawerContentProps = {
|
|
97
64
|
chrome: boolean;
|
|
@@ -102,7 +69,14 @@ type DrawerContentProps = {
|
|
|
102
69
|
children: React.ReactNode;
|
|
103
70
|
};
|
|
104
71
|
|
|
105
|
-
const DrawerContent: React.FC<DrawerContentProps> = ({
|
|
72
|
+
const DrawerContent: React.FC<DrawerContentProps> = ({
|
|
73
|
+
chrome,
|
|
74
|
+
frameStyle,
|
|
75
|
+
header,
|
|
76
|
+
dismissible,
|
|
77
|
+
onClose,
|
|
78
|
+
children,
|
|
79
|
+
}) => {
|
|
106
80
|
if (!chrome) {
|
|
107
81
|
return <>{children}</>;
|
|
108
82
|
}
|
|
@@ -118,43 +92,152 @@ const DrawerContent: React.FC<DrawerContentProps> = ({ chrome, frameStyle, heade
|
|
|
118
92
|
);
|
|
119
93
|
};
|
|
120
94
|
|
|
121
|
-
|
|
95
|
+
type DrawerHeaderViewProps = {
|
|
122
96
|
header?: DrawerBehavior["header"];
|
|
123
97
|
dismissible: boolean;
|
|
124
98
|
onClose: () => void;
|
|
125
|
-
}
|
|
99
|
+
};
|
|
100
|
+
|
|
101
|
+
function shouldShowCloseButton(dismissible: boolean, showCloseButton: boolean): boolean {
|
|
102
|
+
if (!dismissible) {
|
|
103
|
+
return false;
|
|
104
|
+
}
|
|
105
|
+
return showCloseButton;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
function renderCloseButton(
|
|
109
|
+
shouldShow: boolean,
|
|
110
|
+
onClose: () => void,
|
|
111
|
+
): React.ReactNode {
|
|
112
|
+
if (!shouldShow) {
|
|
113
|
+
return null;
|
|
114
|
+
}
|
|
115
|
+
return (
|
|
116
|
+
<FloatingPanelCloseButton
|
|
117
|
+
onClick={onClose}
|
|
118
|
+
aria-label="Close drawer"
|
|
119
|
+
style={{ marginLeft: "auto" }}
|
|
120
|
+
/>
|
|
121
|
+
);
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
function renderEdgeZone(
|
|
125
|
+
showEdgeZone: boolean,
|
|
126
|
+
edgeZoneRef: React.RefObject<HTMLDivElement | null>,
|
|
127
|
+
edgeZoneStyle: React.CSSProperties,
|
|
128
|
+
onPointerDown: ((e: React.PointerEvent<HTMLElement>) => void) | undefined,
|
|
129
|
+
placement: string,
|
|
130
|
+
): React.ReactNode {
|
|
131
|
+
if (!showEdgeZone) {
|
|
132
|
+
return null;
|
|
133
|
+
}
|
|
134
|
+
return (
|
|
135
|
+
<div
|
|
136
|
+
ref={edgeZoneRef}
|
|
137
|
+
style={edgeZoneStyle}
|
|
138
|
+
onPointerDown={onPointerDown}
|
|
139
|
+
data-drawer-edge-zone={placement}
|
|
140
|
+
/>
|
|
141
|
+
);
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
const DrawerHeaderView: React.FC<DrawerHeaderViewProps> = ({ header, dismissible, onClose }) => {
|
|
126
145
|
if (!header) {
|
|
127
146
|
return null;
|
|
128
147
|
}
|
|
129
148
|
|
|
130
149
|
const showCloseButton = header.showCloseButton ?? true;
|
|
131
|
-
const
|
|
150
|
+
const shouldShow = shouldShowCloseButton(dismissible, showCloseButton);
|
|
132
151
|
|
|
133
152
|
return (
|
|
134
|
-
<
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
>
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
</React.Activity>
|
|
141
|
-
<React.Activity mode={shouldShowClose ? "visible" : "hidden"}>
|
|
142
|
-
<FloatingPanelCloseButton
|
|
143
|
-
onClick={onClose}
|
|
144
|
-
aria-label="Close drawer"
|
|
145
|
-
style={{ marginLeft: "auto" }}
|
|
146
|
-
/>
|
|
147
|
-
</React.Activity>
|
|
148
|
-
</FloatingPanelHeader>
|
|
149
|
-
</React.Activity>
|
|
153
|
+
<FloatingPanelHeader
|
|
154
|
+
style={{ padding: `${DRAWER_HEADER_PADDING_Y} ${DRAWER_HEADER_PADDING_X}`, gap: DRAWER_HEADER_GAP }}
|
|
155
|
+
>
|
|
156
|
+
<FloatingPanelTitle>{header.title}</FloatingPanelTitle>
|
|
157
|
+
{renderCloseButton(shouldShow, onClose)}
|
|
158
|
+
</FloatingPanelHeader>
|
|
150
159
|
);
|
|
151
160
|
};
|
|
152
161
|
|
|
162
|
+
// ============================================================================
|
|
163
|
+
// Style computation hooks
|
|
164
|
+
// ============================================================================
|
|
165
|
+
|
|
166
|
+
function useDrawerPanelStyle(
|
|
167
|
+
placement: DrawerPlacement,
|
|
168
|
+
isOpen: boolean,
|
|
169
|
+
isSwipeOperating: boolean,
|
|
170
|
+
config: DrawerBehavior,
|
|
171
|
+
dimensions: { width?: string | number; height?: string | number; zIndex?: number },
|
|
172
|
+
): React.CSSProperties {
|
|
173
|
+
return React.useMemo((): React.CSSProperties => {
|
|
174
|
+
const effectiveMode = isSwipeOperating ? "none" : config.transitionMode;
|
|
175
|
+
const transitionValue = computeTransitionValue(
|
|
176
|
+
effectiveMode,
|
|
177
|
+
config.transitionDuration,
|
|
178
|
+
config.transitionEasing,
|
|
179
|
+
);
|
|
180
|
+
|
|
181
|
+
const placementStyle = getPlacementStyle(placement);
|
|
182
|
+
const transform = isOpen ? getOpenTransform(placement) : placementStyle.transform;
|
|
183
|
+
const position = config.inline ? "absolute" : "fixed";
|
|
184
|
+
|
|
185
|
+
return {
|
|
186
|
+
...DRAWER_PANEL_BASE_STYLE,
|
|
187
|
+
position,
|
|
188
|
+
...placementStyle,
|
|
189
|
+
transform,
|
|
190
|
+
transition: transitionValue,
|
|
191
|
+
zIndex: dimensions.zIndex,
|
|
192
|
+
width: formatDimension(dimensions.width),
|
|
193
|
+
height: formatDimension(dimensions.height),
|
|
194
|
+
};
|
|
195
|
+
}, [placement, isOpen, isSwipeOperating, config, dimensions]);
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
function useBackdropStyle(
|
|
199
|
+
placement: DrawerPlacement,
|
|
200
|
+
isOpen: boolean,
|
|
201
|
+
isSwipeOperating: boolean,
|
|
202
|
+
config: DrawerBehavior,
|
|
203
|
+
zIndex: number | undefined,
|
|
204
|
+
): React.CSSProperties {
|
|
205
|
+
return React.useMemo((): React.CSSProperties => {
|
|
206
|
+
const effectiveMode = isSwipeOperating ? "none" : config.transitionMode;
|
|
207
|
+
const transitionValue = computeBackdropTransition(effectiveMode, config.transitionDuration);
|
|
208
|
+
const position = config.inline ? "absolute" as const : "fixed" as const;
|
|
209
|
+
|
|
210
|
+
return {
|
|
211
|
+
...DRAWER_BACKDROP_BASE_STYLE,
|
|
212
|
+
position,
|
|
213
|
+
opacity: isOpen ? 1 : 0,
|
|
214
|
+
pointerEvents: isOpen ? "auto" : "none",
|
|
215
|
+
transition: transitionValue,
|
|
216
|
+
zIndex: zIndex !== undefined ? zIndex - 1 : undefined,
|
|
217
|
+
};
|
|
218
|
+
}, [isOpen, isSwipeOperating, config, zIndex]);
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
function useFrameStyle(placement: DrawerPlacement): React.CSSProperties {
|
|
222
|
+
return React.useMemo((): React.CSSProperties => {
|
|
223
|
+
const style: React.CSSProperties = { borderRadius: 0 };
|
|
224
|
+
if (placement === "left" || placement === "right") {
|
|
225
|
+
style.height = "100%";
|
|
226
|
+
}
|
|
227
|
+
return style;
|
|
228
|
+
}, [placement]);
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
// ============================================================================
|
|
232
|
+
// Main Component
|
|
233
|
+
// ============================================================================
|
|
234
|
+
|
|
153
235
|
export const Drawer: React.FC<DrawerProps> = ({
|
|
154
236
|
id,
|
|
155
237
|
config,
|
|
156
238
|
isOpen,
|
|
157
239
|
onClose,
|
|
240
|
+
onOpen,
|
|
158
241
|
children,
|
|
159
242
|
zIndex,
|
|
160
243
|
width,
|
|
@@ -166,106 +249,110 @@ export const Drawer: React.FC<DrawerProps> = ({
|
|
|
166
249
|
header,
|
|
167
250
|
chrome = true,
|
|
168
251
|
inline = false,
|
|
169
|
-
transitionMode = "css",
|
|
170
|
-
transitionDuration,
|
|
171
|
-
transitionEasing,
|
|
172
252
|
} = config;
|
|
173
253
|
|
|
174
|
-
const
|
|
175
|
-
(anchor?: DrawerBehavior["anchor"], pos?: WindowPosition): "left" | "right" | "top" | "bottom" => {
|
|
176
|
-
// Prefer explicit anchor from config
|
|
177
|
-
if (anchor) {
|
|
178
|
-
return anchor;
|
|
179
|
-
}
|
|
180
|
-
// Fall back to inferring from position
|
|
181
|
-
if (!pos) {
|
|
182
|
-
return "right";
|
|
183
|
-
}
|
|
184
|
-
if (pos.left !== undefined) {
|
|
185
|
-
return "left";
|
|
186
|
-
}
|
|
187
|
-
if (pos.right !== undefined) {
|
|
188
|
-
return "right";
|
|
189
|
-
}
|
|
190
|
-
if (pos.top !== undefined) {
|
|
191
|
-
return "top";
|
|
192
|
-
}
|
|
193
|
-
if (pos.bottom !== undefined) {
|
|
194
|
-
return "bottom";
|
|
195
|
-
}
|
|
196
|
-
return "right";
|
|
197
|
-
},
|
|
198
|
-
[],
|
|
199
|
-
);
|
|
200
|
-
|
|
254
|
+
const swipeConfig = parseSwipeGesturesConfig(config.swipeGestures);
|
|
201
255
|
const placement = resolvePlacement(config.anchor, position);
|
|
202
256
|
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
bottom: "translateY(0)",
|
|
208
|
-
};
|
|
209
|
-
|
|
210
|
-
const drawerStyle = React.useMemo((): React.CSSProperties => {
|
|
211
|
-
const transitionValue = computeTransitionValue(transitionMode, transitionDuration, transitionEasing);
|
|
212
|
-
|
|
213
|
-
const style: React.CSSProperties = {
|
|
214
|
-
...drawerBaseStyle,
|
|
215
|
-
...(inline ? { position: "absolute" } : { position: "fixed" }),
|
|
216
|
-
...drawerPlacementStyles[placement],
|
|
217
|
-
transform: isOpen ? openTransforms[placement] : drawerPlacementStyles[placement].transform,
|
|
218
|
-
transition: transitionValue,
|
|
219
|
-
};
|
|
257
|
+
// Refs
|
|
258
|
+
const drawerRef = React.useRef<HTMLDivElement>(null);
|
|
259
|
+
const backdropRef = React.useRef<HTMLDivElement>(null);
|
|
260
|
+
const edgeZoneRef = React.useRef<HTMLDivElement>(null);
|
|
220
261
|
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
262
|
+
// Swipe callbacks
|
|
263
|
+
const handleSwipeOpen = React.useCallback(() => {
|
|
264
|
+
onOpen?.();
|
|
265
|
+
config.onStateChange?.(true);
|
|
266
|
+
}, [onOpen, config]);
|
|
224
267
|
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
if (height !== undefined) {
|
|
229
|
-
style.height = typeof height === "number" ? `${height}px` : height;
|
|
230
|
-
}
|
|
268
|
+
const handleSwipeClose = React.useCallback(() => {
|
|
269
|
+
onClose();
|
|
270
|
+
}, [onClose]);
|
|
231
271
|
|
|
232
|
-
|
|
233
|
-
|
|
272
|
+
// Swipe input handling
|
|
273
|
+
const {
|
|
274
|
+
state: swipeState,
|
|
275
|
+
displacement,
|
|
276
|
+
edgeContainerProps,
|
|
277
|
+
drawerContentProps,
|
|
278
|
+
isOpening,
|
|
279
|
+
isClosing,
|
|
280
|
+
} = useDrawerSwipeInput({
|
|
281
|
+
edgeContainerRef: edgeZoneRef,
|
|
282
|
+
drawerContentRef: drawerRef,
|
|
283
|
+
direction: placement as DrawerSwipeDirection,
|
|
284
|
+
isOpen,
|
|
285
|
+
onSwipeOpen: handleSwipeOpen,
|
|
286
|
+
onSwipeClose: handleSwipeClose,
|
|
287
|
+
enableEdgeSwipeOpen: swipeConfig.edgeSwipeOpen,
|
|
288
|
+
enableSwipeClose: swipeConfig.swipeClose,
|
|
289
|
+
edgeWidth: swipeConfig.edgeWidth,
|
|
290
|
+
dismissThreshold: swipeConfig.dismissThreshold,
|
|
291
|
+
});
|
|
234
292
|
|
|
235
|
-
const
|
|
293
|
+
const isSwipeOperating = swipeState.phase === "operating";
|
|
236
294
|
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
}
|
|
295
|
+
// Apply swipe transform
|
|
296
|
+
useDrawerSwipeTransform({
|
|
297
|
+
drawerRef,
|
|
298
|
+
backdropRef,
|
|
299
|
+
placement: placement as DrawerSwipeDirection,
|
|
300
|
+
swipeState,
|
|
301
|
+
displacement,
|
|
302
|
+
isOpening,
|
|
303
|
+
isClosing,
|
|
304
|
+
enabled: swipeConfig.enabled,
|
|
305
|
+
});
|
|
248
306
|
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
307
|
+
// Computed styles
|
|
308
|
+
const drawerStyle = useDrawerPanelStyle(placement, isOpen, isSwipeOperating, config, { width, height, zIndex });
|
|
309
|
+
const backdropStyle = useBackdropStyle(placement, isOpen, isSwipeOperating, config, zIndex);
|
|
310
|
+
const frameStyle = useFrameStyle(placement);
|
|
311
|
+
|
|
312
|
+
// Edge zone style: merge positioning style with gesture handlers' style
|
|
313
|
+
const edgeZoneStyle = React.useMemo((): React.CSSProperties => {
|
|
314
|
+
const positioningStyle = computeEdgeZoneStyle({
|
|
315
|
+
placement,
|
|
316
|
+
inline,
|
|
317
|
+
edgeWidth: swipeConfig.edgeWidth,
|
|
318
|
+
zIndex,
|
|
319
|
+
});
|
|
320
|
+
// Merge with gesture container styles (touchAction, etc.)
|
|
321
|
+
return { ...positioningStyle, ...edgeContainerProps.style };
|
|
322
|
+
}, [placement, inline, swipeConfig.edgeWidth, zIndex, edgeContainerProps.style]);
|
|
323
|
+
|
|
324
|
+
// Merged drawer style with swipe props
|
|
325
|
+
const mergedDrawerStyle = React.useMemo((): React.CSSProperties => {
|
|
326
|
+
if (!swipeConfig.enabled) {
|
|
327
|
+
return drawerStyle;
|
|
254
328
|
}
|
|
255
|
-
return style;
|
|
256
|
-
}, [
|
|
329
|
+
return { ...drawerStyle, ...drawerContentProps.style };
|
|
330
|
+
}, [swipeConfig.enabled, drawerStyle, drawerContentProps.style]);
|
|
331
|
+
|
|
332
|
+
// Visibility flags
|
|
333
|
+
const showEdgeZone = shouldShowEdgeZone(swipeConfig, isOpen, isOpening);
|
|
334
|
+
const ariaLabel = header?.title ?? config.ariaLabel ?? "Drawer";
|
|
335
|
+
|
|
336
|
+
const edgeZoneElement = renderEdgeZone(showEdgeZone, edgeZoneRef, edgeZoneStyle, edgeContainerProps.onPointerDown, placement);
|
|
257
337
|
|
|
258
338
|
return (
|
|
259
339
|
<>
|
|
260
|
-
|
|
340
|
+
{edgeZoneElement}
|
|
341
|
+
<div
|
|
342
|
+
ref={backdropRef}
|
|
343
|
+
style={backdropStyle}
|
|
344
|
+
onClick={dismissible ? onClose : undefined}
|
|
345
|
+
/>
|
|
261
346
|
<div
|
|
347
|
+
ref={drawerRef}
|
|
262
348
|
data-layer-id={id}
|
|
263
349
|
data-placement={placement}
|
|
264
|
-
style={
|
|
350
|
+
style={mergedDrawerStyle}
|
|
265
351
|
role="dialog"
|
|
266
352
|
aria-modal={dismissible ? true : undefined}
|
|
267
353
|
aria-hidden={isOpen ? undefined : true}
|
|
268
354
|
aria-label={ariaLabel}
|
|
355
|
+
onPointerDown={swipeConfig.enabled ? drawerContentProps.onPointerDown : undefined}
|
|
269
356
|
>
|
|
270
357
|
<DrawerContent
|
|
271
358
|
chrome={chrome}
|
|
@@ -2,9 +2,9 @@
|
|
|
2
2
|
* @file DrawerLayers component
|
|
3
3
|
*/
|
|
4
4
|
import * as React from "react";
|
|
5
|
-
import type { LayerDefinition } from "../../types";
|
|
6
|
-
import { Drawer } from "./Drawer";
|
|
7
|
-
import { useDrawerState } from "../../modules/window/useDrawerState";
|
|
5
|
+
import type { LayerDefinition } from "../../types.js";
|
|
6
|
+
import { Drawer } from "./Drawer.js";
|
|
7
|
+
import { useDrawerState } from "../../modules/window/useDrawerState.js";
|
|
8
8
|
|
|
9
9
|
export type DrawerLayersProps = {
|
|
10
10
|
layers: LayerDefinition[];
|
|
@@ -23,6 +23,14 @@ export const DrawerLayers: React.FC<DrawerLayersProps> = ({ layers }) => {
|
|
|
23
23
|
return handlers;
|
|
24
24
|
}, [drawerLayers, drawer.close]);
|
|
25
25
|
|
|
26
|
+
const openHandlers = React.useMemo(() => {
|
|
27
|
+
const handlers = new Map<string, () => void>();
|
|
28
|
+
drawerLayers.forEach((layer) => {
|
|
29
|
+
handlers.set(layer.id, () => drawer.open(layer.id));
|
|
30
|
+
});
|
|
31
|
+
return handlers;
|
|
32
|
+
}, [drawerLayers, drawer.open]);
|
|
33
|
+
|
|
26
34
|
return (
|
|
27
35
|
<>
|
|
28
36
|
{drawerLayers.map((layer) => {
|
|
@@ -32,6 +40,7 @@ export const DrawerLayers: React.FC<DrawerLayersProps> = ({ layers }) => {
|
|
|
32
40
|
|
|
33
41
|
const isOpen = drawer.state(layer.id);
|
|
34
42
|
const onClose = closeHandlers.get(layer.id);
|
|
43
|
+
const onOpen = openHandlers.get(layer.id);
|
|
35
44
|
|
|
36
45
|
if (!onClose) {
|
|
37
46
|
return null;
|
|
@@ -44,6 +53,7 @@ export const DrawerLayers: React.FC<DrawerLayersProps> = ({ layers }) => {
|
|
|
44
53
|
config={layer.drawer}
|
|
45
54
|
isOpen={isOpen}
|
|
46
55
|
onClose={onClose}
|
|
56
|
+
onOpen={onOpen}
|
|
47
57
|
zIndex={layer.zIndex}
|
|
48
58
|
width={layer.width}
|
|
49
59
|
height={layer.height}
|