react-panel-layout 0.6.0 → 0.7.0

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.
Files changed (258) hide show
  1. package/dist/{FloatingPanelFrame-SgYLc6Ud.js → FloatingPanelFrame-3eU9AwPo.js} +2 -2
  2. package/dist/{FloatingPanelFrame-SgYLc6Ud.js.map → FloatingPanelFrame-3eU9AwPo.js.map} +1 -1
  3. package/dist/FloatingWindow-Bw2djgpz.js +1542 -0
  4. package/dist/FloatingWindow-Bw2djgpz.js.map +1 -0
  5. package/dist/FloatingWindow-Cvyokf0m.cjs +2 -0
  6. package/dist/FloatingWindow-Cvyokf0m.cjs.map +1 -0
  7. package/dist/GridLayout-B4aCqSyd.js +947 -0
  8. package/dist/{GridLayout-BltqeCPK.js.map → GridLayout-B4aCqSyd.js.map} +1 -1
  9. package/dist/GridLayout-DNOClFzz.cjs +2 -0
  10. package/dist/{GridLayout-B4VRsC0r.cjs.map → GridLayout-DNOClFzz.cjs.map} +1 -1
  11. package/dist/{HorizontalDivider-WF1k_qND.js → HorizontalDivider-DdxzfV0l.js} +3 -3
  12. package/dist/{HorizontalDivider-WF1k_qND.js.map → HorizontalDivider-DdxzfV0l.js.map} +1 -1
  13. package/dist/{HorizontalDivider-B5Z-KZLk.cjs → HorizontalDivider-_pgV4Mcv.cjs} +2 -2
  14. package/dist/{HorizontalDivider-B5Z-KZLk.cjs.map → HorizontalDivider-_pgV4Mcv.cjs.map} +1 -1
  15. package/dist/PanelSystem-B8Igvnb2.cjs +3 -0
  16. package/dist/PanelSystem-B8Igvnb2.cjs.map +1 -0
  17. package/dist/{PanelSystem-Dr1TBhxM.js → PanelSystem-DDUSFjXD.js} +209 -248
  18. package/dist/PanelSystem-DDUSFjXD.js.map +1 -0
  19. package/dist/ResizeHandle-CBcAS918.cjs +2 -0
  20. package/dist/{ResizeHandle-CScipO5l.cjs.map → ResizeHandle-CBcAS918.cjs.map} +1 -1
  21. package/dist/{ResizeHandle-CdA_JYfN.js → ResizeHandle-CXjc1meV.js} +28 -29
  22. package/dist/{ResizeHandle-CdA_JYfN.js.map → ResizeHandle-CXjc1meV.js.map} +1 -1
  23. package/dist/SwipePivotTabBar-DWrCuwEI.js +411 -0
  24. package/dist/SwipePivotTabBar-DWrCuwEI.js.map +1 -0
  25. package/dist/SwipePivotTabBar-fjjXkpj7.cjs +2 -0
  26. package/dist/SwipePivotTabBar-fjjXkpj7.cjs.map +1 -0
  27. package/dist/components/gesture/SwipeSafeZone.d.ts +40 -0
  28. package/dist/components/window/Drawer.d.ts +4 -1
  29. package/dist/components/window/DrawerLayers.d.ts +1 -1
  30. package/dist/components/window/DrawerRevealContext.d.ts +61 -0
  31. package/dist/components/window/drawerRevealAnimationUtils.d.ts +212 -0
  32. package/dist/components/window/drawerStyles.d.ts +74 -0
  33. package/dist/components/window/drawerSwipeConfig.d.ts +29 -0
  34. package/dist/components/window/useDrawerSwipeTransform.d.ts +29 -0
  35. package/dist/components/window/useDrawerTransform.d.ts +68 -0
  36. package/dist/components/window/useRevealDrawerTransform.d.ts +56 -0
  37. package/dist/config.cjs +1 -1
  38. package/dist/config.cjs.map +1 -1
  39. package/dist/config.js +9 -8
  40. package/dist/config.js.map +1 -1
  41. package/dist/constants/styles.d.ts +17 -0
  42. package/dist/dialog/index.d.ts +69 -0
  43. package/dist/floating.js +1 -1
  44. package/dist/grid.cjs +1 -1
  45. package/dist/grid.js +2 -2
  46. package/dist/hooks/gesture/testing/createGestureSimulator.d.ts +7 -0
  47. package/dist/hooks/gesture/types.d.ts +48 -5
  48. package/dist/hooks/gesture/utils.d.ts +19 -0
  49. package/dist/hooks/useAnimationFrame.d.ts +2 -0
  50. package/dist/hooks/useOperationContinuity.d.ts +64 -0
  51. package/dist/hooks/useResizeObserver.d.ts +33 -1
  52. package/dist/hooks/useSharedElementTransition.d.ts +112 -0
  53. package/dist/hooks/useSwipeContentTransform.d.ts +9 -2
  54. package/dist/index.cjs +1 -1
  55. package/dist/index.js +7 -7
  56. package/dist/modules/dialog/AlertDialog.d.ts +9 -0
  57. package/dist/modules/dialog/DialogContainer.d.ts +37 -0
  58. package/dist/modules/dialog/Modal.d.ts +26 -0
  59. package/dist/modules/dialog/SwipeDialogContainer.d.ts +16 -0
  60. package/dist/modules/dialog/dialogAnimationUtils.d.ts +113 -0
  61. package/dist/modules/dialog/types.d.ts +183 -0
  62. package/dist/modules/dialog/useDialog.d.ts +39 -0
  63. package/dist/modules/dialog/useDialogContainer.d.ts +47 -0
  64. package/dist/modules/dialog/useDialogSwipeInput.d.ts +70 -0
  65. package/dist/modules/dialog/useDialogTransform.d.ts +82 -0
  66. package/dist/modules/drawer/drawerStateMachine.d.ts +168 -0
  67. package/dist/modules/drawer/revealDrawerConstants.d.ts +33 -0
  68. package/dist/modules/drawer/revealDrawerStateMachine.d.ts +146 -0
  69. package/dist/modules/drawer/strategies/index.d.ts +8 -0
  70. package/dist/modules/drawer/strategies/overlayStrategy.d.ts +12 -0
  71. package/dist/modules/drawer/strategies/revealStrategy.d.ts +12 -0
  72. package/dist/modules/drawer/strategies/types.d.ts +116 -0
  73. package/dist/modules/drawer/types.d.ts +74 -0
  74. package/dist/modules/drawer/useDrawerSwipeInput.d.ts +24 -0
  75. package/dist/modules/pivot/SwipePivotTabBar.d.ts +3 -0
  76. package/dist/modules/stack/SwipeStackContent.d.ts +6 -3
  77. package/dist/modules/stack/SwipeStackOutlet.d.ts +4 -4
  78. package/dist/modules/stack/computeSwipeStackTransform.d.ts +1 -1
  79. package/dist/panels.cjs +1 -1
  80. package/dist/panels.js +1 -1
  81. package/dist/pivot.cjs +1 -1
  82. package/dist/pivot.js +1 -1
  83. package/dist/resizer.cjs +1 -1
  84. package/dist/resizer.js +2 -2
  85. package/dist/stack.cjs +1 -1
  86. package/dist/stack.cjs.map +1 -1
  87. package/dist/stack.js +480 -780
  88. package/dist/stack.js.map +1 -1
  89. package/dist/sticky-header/calculateStickyMetrics.d.ts +28 -0
  90. package/dist/sticky-header.cjs +1 -1
  91. package/dist/sticky-header.cjs.map +1 -1
  92. package/dist/sticky-header.js +59 -51
  93. package/dist/sticky-header.js.map +1 -1
  94. package/dist/{styles-DPPuJ0sf.js → styles-NkjuMOVS.js} +13 -13
  95. package/dist/{styles-DPPuJ0sf.js.map → styles-NkjuMOVS.js.map} +1 -1
  96. package/dist/styles-qf6ptVLD.cjs.map +1 -1
  97. package/dist/types.d.ts +30 -0
  98. package/dist/useAnimationFrame-BZ6D2lMq.cjs +2 -0
  99. package/dist/useAnimationFrame-BZ6D2lMq.cjs.map +1 -0
  100. package/dist/useAnimationFrame-Bg4e-H8O.js +394 -0
  101. package/dist/useAnimationFrame-Bg4e-H8O.js.map +1 -0
  102. package/dist/useDocumentPointerEvents-DXxw3qWj.js +54 -0
  103. package/dist/useDocumentPointerEvents-DXxw3qWj.js.map +1 -0
  104. package/dist/useDocumentPointerEvents-DxDSOtip.cjs +2 -0
  105. package/dist/useDocumentPointerEvents-DxDSOtip.cjs.map +1 -0
  106. package/dist/window/index.d.ts +2 -0
  107. package/dist/window.cjs +1 -1
  108. package/dist/window.cjs.map +1 -1
  109. package/dist/window.js +114 -103
  110. package/dist/window.js.map +1 -1
  111. package/package.json +6 -1
  112. package/src/components/gesture/SwipeSafeZone.tsx +70 -0
  113. package/src/components/grid/GridLayout.tsx +110 -38
  114. package/src/components/window/Drawer.tsx +353 -162
  115. package/src/components/window/DrawerLayers.tsx +54 -11
  116. package/src/components/window/DrawerRevealContext.spec.ts +20 -0
  117. package/src/components/window/DrawerRevealContext.tsx +99 -0
  118. package/src/components/window/drawerRevealAnimationUtils.spec.ts +375 -0
  119. package/src/components/window/drawerRevealAnimationUtils.ts +415 -0
  120. package/src/components/window/drawerStyles.spec.ts +302 -0
  121. package/src/components/window/drawerStyles.ts +252 -0
  122. package/src/components/window/drawerSwipeConfig.spec.ts +131 -0
  123. package/src/components/window/drawerSwipeConfig.ts +112 -0
  124. package/src/components/window/useDrawerSwipeTransform.ts +67 -0
  125. package/src/components/window/useDrawerTransform.ts +505 -0
  126. package/src/components/window/useRevealDrawerTransform.spec.ts +1936 -0
  127. package/src/components/window/useRevealDrawerTransform.ts +105 -0
  128. package/src/constants/styles.ts +19 -0
  129. package/src/demo/components/FullscreenDemoPage.tsx +47 -0
  130. package/src/demo/fullscreenRoutes.tsx +32 -0
  131. package/src/demo/index.tsx +5 -0
  132. package/src/demo/pages/Dialog/alerts/index.tsx +22 -0
  133. package/src/demo/pages/Dialog/card/index.tsx +22 -0
  134. package/src/demo/pages/Dialog/components/AlertDialogDemo.tsx +124 -0
  135. package/src/demo/pages/Dialog/components/CardExpandDemo.module.css +243 -0
  136. package/src/demo/pages/Dialog/components/CardExpandDemo.tsx +219 -0
  137. package/src/demo/pages/Dialog/components/CustomAlertDialogDemo.tsx +219 -0
  138. package/src/demo/pages/Dialog/components/DialogDemos.module.css +77 -0
  139. package/src/demo/pages/Dialog/components/ModalBasics.tsx +45 -0
  140. package/src/demo/pages/Dialog/components/SwipeDialogDemo.module.css +77 -0
  141. package/src/demo/pages/Dialog/components/SwipeDialogDemo.tsx +181 -0
  142. package/src/demo/pages/Dialog/custom-alert/index.tsx +22 -0
  143. package/src/demo/pages/Dialog/modal/index.tsx +17 -0
  144. package/src/demo/pages/Dialog/swipe/index.tsx +22 -0
  145. package/src/demo/pages/Drawer/components/DrawerBasics.module.css +6 -1
  146. package/src/demo/pages/Drawer/components/DrawerBasics.tsx +14 -4
  147. package/src/demo/pages/Drawer/components/DrawerReveal.module.css +157 -0
  148. package/src/demo/pages/Drawer/components/DrawerReveal.tsx +128 -0
  149. package/src/demo/pages/Drawer/components/DrawerSwipe.module.css +316 -0
  150. package/src/demo/pages/Drawer/components/DrawerSwipe.tsx +178 -0
  151. package/src/demo/pages/Drawer/reveal/index.tsx +17 -0
  152. package/src/demo/pages/Drawer/reveal-fullscreen/index.tsx +135 -0
  153. package/src/demo/pages/Drawer/reveal-fullscreen/styles.module.css +233 -0
  154. package/src/demo/pages/Drawer/swipe/index.tsx +17 -0
  155. package/src/demo/pages/Pivot/components/SwipeTabsPivot.tsx +54 -23
  156. package/src/demo/pages/Pivot/swipe-debug/index.tsx +1 -1
  157. package/src/demo/pages/Stack/components/StackBasics.spec.tsx +156 -0
  158. package/src/demo/pages/Stack/components/StackBasics.tsx +179 -95
  159. package/src/demo/pages/Stack/components/StackTablet.spec.tsx +110 -0
  160. package/src/demo/pages/Stack/components/StackTablet.tsx +42 -21
  161. package/src/demo/routes.tsx +24 -1
  162. package/src/dialog/index.ts +85 -0
  163. package/src/hooks/gesture/testing/createGestureSimulator.spec.ts +68 -64
  164. package/src/hooks/gesture/testing/createGestureSimulator.ts +113 -37
  165. package/src/hooks/gesture/types.ts +83 -6
  166. package/src/hooks/gesture/useEdgeSwipeInput.spec.ts +22 -14
  167. package/src/hooks/gesture/useNativeGestureGuard.spec.ts +99 -31
  168. package/src/hooks/gesture/useNativeGestureGuard.ts +3 -1
  169. package/src/hooks/gesture/utils.ts +102 -0
  170. package/src/hooks/useAnimatedVisibility.spec.ts +44 -24
  171. package/src/hooks/useAnimatedVisibility.ts +28 -2
  172. package/src/hooks/useAnimationFrame.ts +8 -0
  173. package/src/hooks/useOperationContinuity.spec.ts +394 -0
  174. package/src/hooks/useOperationContinuity.ts +135 -0
  175. package/src/hooks/useResizeObserver.spec.tsx +277 -0
  176. package/src/hooks/useResizeObserver.tsx +108 -39
  177. package/src/hooks/useScrollContainer.ts +4 -10
  178. package/src/hooks/useSharedElementTransition.ts +354 -0
  179. package/src/hooks/useSwipeContentTransform.spec.ts +18 -18
  180. package/src/hooks/useSwipeContentTransform.ts +166 -28
  181. package/src/modules/dialog/AlertDialog.spec.tsx +387 -0
  182. package/src/modules/dialog/AlertDialog.tsx +221 -0
  183. package/src/modules/dialog/DialogContainer.spec.tsx +228 -0
  184. package/src/modules/dialog/DialogContainer.tsx +188 -0
  185. package/src/modules/dialog/Modal.spec.tsx +220 -0
  186. package/src/modules/dialog/Modal.tsx +182 -0
  187. package/src/modules/dialog/SwipeDialogContainer.tsx +208 -0
  188. package/src/modules/dialog/dialogAnimationUtils.spec.ts +252 -0
  189. package/src/modules/dialog/dialogAnimationUtils.ts +297 -0
  190. package/src/modules/dialog/types.ts +186 -0
  191. package/src/modules/dialog/useDialog.spec.tsx +447 -0
  192. package/src/modules/dialog/useDialog.ts +214 -0
  193. package/src/modules/dialog/useDialogContainer.spec.ts +339 -0
  194. package/src/modules/dialog/useDialogContainer.ts +150 -0
  195. package/src/modules/dialog/useDialogSwipeInput.spec.ts +178 -0
  196. package/src/modules/dialog/useDialogSwipeInput.ts +350 -0
  197. package/src/modules/dialog/useDialogTransform.spec.ts +403 -0
  198. package/src/modules/dialog/useDialogTransform.ts +407 -0
  199. package/src/modules/drawer/drawerStateMachine.ts +500 -0
  200. package/src/modules/drawer/revealDrawerConstants.ts +38 -0
  201. package/src/modules/drawer/revealDrawerStateMachine.spec.ts +558 -0
  202. package/src/modules/drawer/revealDrawerStateMachine.ts +197 -0
  203. package/src/modules/drawer/strategies/index.ts +9 -0
  204. package/src/modules/drawer/strategies/overlayStrategy.ts +133 -0
  205. package/src/modules/drawer/strategies/revealStrategy.ts +111 -0
  206. package/src/modules/drawer/strategies/types.ts +160 -0
  207. package/src/modules/drawer/types.ts +102 -0
  208. package/src/modules/drawer/useDrawerSwipeInput.spec.ts +566 -0
  209. package/src/modules/drawer/useDrawerSwipeInput.ts +402 -0
  210. package/src/modules/panels/rendering/ContentRegistry.spec.tsx +21 -14
  211. package/src/modules/pivot/SwipePivotContent.position.spec.tsx +12 -8
  212. package/src/modules/pivot/SwipePivotContent.spec.tsx +66 -25
  213. package/src/modules/pivot/SwipePivotContent.tsx +2 -2
  214. package/src/modules/pivot/SwipePivotTabBar.spec.tsx +85 -68
  215. package/src/modules/pivot/SwipePivotTabBar.tsx +75 -15
  216. package/src/modules/pivot/scaleInputState.spec.ts +11 -2
  217. package/src/modules/pivot/usePivot.spec.ts +17 -3
  218. package/src/modules/pivot/usePivotSwipeInput.spec.ts +182 -123
  219. package/src/modules/stack/SwipeStackContent.spec.tsx +387 -100
  220. package/src/modules/stack/SwipeStackContent.tsx +43 -33
  221. package/src/modules/stack/SwipeStackOutlet.spec.tsx +14 -16
  222. package/src/modules/stack/SwipeStackOutlet.tsx +6 -6
  223. package/src/modules/stack/computeSwipeStackTransform.spec.ts +5 -5
  224. package/src/modules/stack/computeSwipeStackTransform.ts +3 -3
  225. package/src/modules/stack/swipeTransitionContinuity.spec.tsx +1133 -0
  226. package/src/modules/stack/useStackAnimationState.spec.ts +3 -1
  227. package/src/modules/stack/useStackAnimationState.ts +18 -13
  228. package/src/modules/stack/useStackNavigation.spec.ts +198 -3
  229. package/src/modules/stack/useStackNavigation.tsx +113 -56
  230. package/src/modules/stack/useStackSwipeInput.spec.ts +65 -32
  231. package/src/modules/stack/useStackSwipeInput.ts +1 -1
  232. package/src/sticky-header/StickyArea.tsx +29 -57
  233. package/src/sticky-header/calculateStickyMetrics.spec.ts +105 -0
  234. package/src/sticky-header/calculateStickyMetrics.ts +50 -0
  235. package/src/types.ts +33 -0
  236. package/src/window/index.ts +2 -0
  237. package/dist/FloatingWindow-BpdOpg_L.js +0 -400
  238. package/dist/FloatingWindow-BpdOpg_L.js.map +0 -1
  239. package/dist/FloatingWindow-TCDNY5gE.cjs +0 -2
  240. package/dist/FloatingWindow-TCDNY5gE.cjs.map +0 -1
  241. package/dist/GridLayout-B4VRsC0r.cjs +0 -2
  242. package/dist/GridLayout-BltqeCPK.js +0 -927
  243. package/dist/PanelSystem-Bs8bQwQF.cjs +0 -3
  244. package/dist/PanelSystem-Bs8bQwQF.cjs.map +0 -1
  245. package/dist/PanelSystem-Dr1TBhxM.js.map +0 -1
  246. package/dist/ResizeHandle-CScipO5l.cjs +0 -2
  247. package/dist/SwipePivotTabBar-BGO9X94m.js +0 -407
  248. package/dist/SwipePivotTabBar-BGO9X94m.js.map +0 -1
  249. package/dist/SwipePivotTabBar-BrQismcZ.cjs +0 -2
  250. package/dist/SwipePivotTabBar-BrQismcZ.cjs.map +0 -1
  251. package/dist/useDocumentPointerEvents-CKdhGXd0.js +0 -46
  252. package/dist/useDocumentPointerEvents-CKdhGXd0.js.map +0 -1
  253. package/dist/useDocumentPointerEvents-ChqrKXDk.cjs +0 -2
  254. package/dist/useDocumentPointerEvents-ChqrKXDk.cjs.map +0 -1
  255. package/dist/useEffectEvent-Dp7HLCf0.js +0 -13
  256. package/dist/useEffectEvent-Dp7HLCf0.js.map +0 -1
  257. package/dist/useEffectEvent-huSsGUnl.cjs +0 -2
  258. package/dist/useEffectEvent-huSsGUnl.cjs.map +0 -1
@@ -0,0 +1,233 @@
1
+ /**
2
+ * @file Styles for Reveal Mode Fullscreen Demo
3
+ */
4
+
5
+ .container {
6
+ display: flex;
7
+ flex-direction: column;
8
+ height: 100vh;
9
+ height: 100dvh;
10
+ overflow-y: auto;
11
+ background: #fff;
12
+ color: #0f1419;
13
+ }
14
+
15
+ .header {
16
+ display: flex;
17
+ align-items: center;
18
+ gap: 16px;
19
+ padding: 12px 16px;
20
+ border-bottom: 1px solid #eff3f4;
21
+ position: sticky;
22
+ top: 0;
23
+ background: #fff;
24
+ z-index: 100;
25
+ }
26
+
27
+ .menuButton {
28
+ display: flex;
29
+ align-items: center;
30
+ justify-content: center;
31
+ width: 40px;
32
+ height: 40px;
33
+ border: none;
34
+ background: transparent;
35
+ border-radius: 50%;
36
+ cursor: pointer;
37
+ transition: background 0.15s ease;
38
+ }
39
+
40
+ .menuButton:hover {
41
+ background: rgba(15, 20, 25, 0.1);
42
+ }
43
+
44
+ .menuIcon {
45
+ position: relative;
46
+ width: 18px;
47
+ height: 2px;
48
+ background: #0f1419;
49
+ border-radius: 1px;
50
+ }
51
+
52
+ .menuIcon::before,
53
+ .menuIcon::after {
54
+ content: "";
55
+ position: absolute;
56
+ left: 0;
57
+ width: 100%;
58
+ height: 2px;
59
+ background: #0f1419;
60
+ border-radius: 1px;
61
+ }
62
+
63
+ .menuIcon::before {
64
+ top: -6px;
65
+ }
66
+
67
+ .menuIcon::after {
68
+ top: 6px;
69
+ }
70
+
71
+ .title {
72
+ font-size: 20px;
73
+ font-weight: 700;
74
+ margin: 0;
75
+ }
76
+
77
+ .main {
78
+ flex: 1;
79
+ padding: 20px 16px;
80
+ display: flex;
81
+ flex-direction: column;
82
+ gap: 16px;
83
+ }
84
+
85
+ .card {
86
+ padding: 20px;
87
+ background: #f7f9f9;
88
+ border-radius: 16px;
89
+ }
90
+
91
+ .card h2 {
92
+ margin: 0 0 12px;
93
+ font-size: 18px;
94
+ font-weight: 700;
95
+ }
96
+
97
+ .card h3 {
98
+ margin: 0 0 12px;
99
+ font-size: 16px;
100
+ font-weight: 600;
101
+ }
102
+
103
+ .card p {
104
+ margin: 0 0 12px;
105
+ color: #536471;
106
+ line-height: 1.5;
107
+ }
108
+
109
+ .card p:last-child {
110
+ margin-bottom: 0;
111
+ }
112
+
113
+ .list {
114
+ margin: 0;
115
+ padding-left: 20px;
116
+ color: #536471;
117
+ line-height: 1.8;
118
+ }
119
+
120
+ .backLink {
121
+ display: inline-flex;
122
+ align-items: center;
123
+ gap: 8px;
124
+ margin-top: auto;
125
+ padding: 12px 20px;
126
+ background: #1d9bf0;
127
+ color: #fff;
128
+ border-radius: 9999px;
129
+ text-decoration: none;
130
+ font-weight: 600;
131
+ transition: background 0.15s ease;
132
+ }
133
+
134
+ .backLink:hover {
135
+ background: #1a8cd8;
136
+ }
137
+
138
+ /* Drawer content */
139
+ .drawerContent {
140
+ display: flex;
141
+ flex-direction: column;
142
+ height: 100%;
143
+ padding: 16px;
144
+ background: #fff;
145
+ border-right: 1px solid #eff3f4;
146
+ overflow-y: auto;
147
+ -webkit-overflow-scrolling: touch;
148
+ }
149
+
150
+ .profile {
151
+ display: flex;
152
+ align-items: center;
153
+ gap: 12px;
154
+ padding: 12px 0;
155
+ border-bottom: 1px solid #eff3f4;
156
+ margin-bottom: 8px;
157
+ }
158
+
159
+ .avatar {
160
+ display: flex;
161
+ align-items: center;
162
+ justify-content: center;
163
+ width: 40px;
164
+ height: 40px;
165
+ background: #1d9bf0;
166
+ border-radius: 50%;
167
+ color: #fff;
168
+ font-size: 18px;
169
+ font-weight: 700;
170
+ }
171
+
172
+ .profileInfo {
173
+ display: flex;
174
+ flex-direction: column;
175
+ gap: 2px;
176
+ }
177
+
178
+ .profileName {
179
+ font-size: 15px;
180
+ font-weight: 700;
181
+ color: #0f1419;
182
+ }
183
+
184
+ .profileHandle {
185
+ font-size: 13px;
186
+ color: #536471;
187
+ }
188
+
189
+ .nav {
190
+ display: flex;
191
+ flex-direction: column;
192
+ gap: 4px;
193
+ flex: 1;
194
+ padding: 8px 0;
195
+ }
196
+
197
+ .navItem {
198
+ display: flex;
199
+ align-items: center;
200
+ gap: 16px;
201
+ padding: 12px;
202
+ border-radius: 9999px;
203
+ color: #0f1419;
204
+ font-size: 20px;
205
+ font-weight: 500;
206
+ text-decoration: none;
207
+ transition: background 0.2s ease;
208
+ }
209
+
210
+ .navItem:hover {
211
+ background: #e7e7e8;
212
+ }
213
+
214
+ .navIcon {
215
+ width: 26px;
216
+ height: 26px;
217
+ }
218
+
219
+ .closeButton {
220
+ padding: 14px;
221
+ background: #eff3f4;
222
+ border: none;
223
+ border-radius: 9999px;
224
+ font-size: 15px;
225
+ font-weight: 700;
226
+ color: #0f1419;
227
+ cursor: pointer;
228
+ transition: background 0.15s ease;
229
+ }
230
+
231
+ .closeButton:hover {
232
+ background: #d7dbdc;
233
+ }
@@ -0,0 +1,17 @@
1
+ /**
2
+ * @file Drawer - Swipe Gestures page
3
+ */
4
+ import * as React from "react";
5
+ import { DrawerSwipe } from "../components/DrawerSwipe";
6
+ import DrawerSwipeSource from "../components/DrawerSwipe.tsx?raw";
7
+ import { SingleSamplePage } from "../../../components/layout";
8
+
9
+ const Page: React.FC = () => {
10
+ return (
11
+ <SingleSamplePage title="Drawer / Swipe Gestures" code={DrawerSwipeSource} codeTitle="DrawerSwipe.tsx" previewHeight={600}>
12
+ <DrawerSwipe />
13
+ </SingleSamplePage>
14
+ );
15
+ };
16
+
17
+ export default Page;
@@ -22,6 +22,15 @@ type ContentItemsProps = {
22
22
  containerWidth: number;
23
23
  };
24
24
 
25
+ type TabBarProps = {
26
+ contentContainerWidth: number;
27
+ items: PivotItem[];
28
+ pivot: UsePivotResult;
29
+ tabInputState: SwipeInputState;
30
+ tabWidth: number;
31
+ indicatorStyle: IndicatorStyle;
32
+ };
33
+
25
34
  /** Renders content items */
26
35
  const ContentItems: React.FC<ContentItemsProps> = ({ items, pivot, inputState, containerWidth }) => {
27
36
  if (containerWidth <= 0) {
@@ -55,6 +64,43 @@ const ContentItems: React.FC<ContentItemsProps> = ({ items, pivot, inputState, c
55
64
  );
56
65
  };
57
66
 
67
+ const TabBar: React.FC<TabBarProps> = ({
68
+ contentContainerWidth,
69
+ items,
70
+ pivot,
71
+ tabInputState,
72
+ tabWidth,
73
+ indicatorStyle,
74
+ }) => {
75
+ if (contentContainerWidth <= 0) {
76
+ return null;
77
+ }
78
+
79
+ return (
80
+ <SwipePivotTabBar
81
+ items={items}
82
+ activeId={pivot.activeId}
83
+ activeIndex={pivot.activeIndex}
84
+ itemCount={pivot.itemCount}
85
+ inputState={tabInputState}
86
+ tabWidth={tabWidth}
87
+ viewportWidth={contentContainerWidth}
88
+ navigationMode={pivot.navigationMode}
89
+ fixedTabs={indicatorStyle === "sliding"}
90
+ renderTab={(item, isActive) => (
91
+ <button
92
+ className={indicatorStyle === "sliding" ? styles.tabIos : styles.tab}
93
+ data-active={isActive}
94
+ onClick={() => pivot.setActiveId(item.id)}
95
+ >
96
+ {item.label}
97
+ </button>
98
+ )}
99
+ renderIndicator={indicatorStyle === "sliding" ? SlidingIndicator : undefined}
100
+ />
101
+ );
102
+ };
103
+
58
104
  const pageColors = ["#ffe0e0", "#e0ffe0", "#e0e0ff", "#fff0e0", "#f0e0ff"];
59
105
 
60
106
  const items: PivotItem[] = [
@@ -225,29 +271,14 @@ export const SwipeTabsPivot: React.FC = () => {
225
271
  className={styles.tabsContainer}
226
272
  data-style={indicatorStyle === "sliding" ? "ios" : undefined}
227
273
  >
228
- {contentContainerWidth > 0 && (
229
- <SwipePivotTabBar
230
- items={items}
231
- activeId={pivot.activeId}
232
- activeIndex={pivot.activeIndex}
233
- itemCount={pivot.itemCount}
234
- inputState={tabInputState}
235
- tabWidth={tabWidth}
236
- viewportWidth={contentContainerWidth}
237
- navigationMode={pivot.navigationMode}
238
- fixedTabs={indicatorStyle === "sliding"}
239
- renderTab={(item, isActive) => (
240
- <button
241
- className={indicatorStyle === "sliding" ? styles.tabIos : styles.tab}
242
- data-active={isActive}
243
- onClick={() => pivot.setActiveId(item.id)}
244
- >
245
- {item.label}
246
- </button>
247
- )}
248
- renderIndicator={indicatorStyle === "sliding" ? SlidingIndicator : undefined}
249
- />
250
- )}
274
+ <TabBar
275
+ contentContainerWidth={contentContainerWidth}
276
+ items={items}
277
+ pivot={pivot}
278
+ tabInputState={tabInputState}
279
+ tabWidth={tabWidth}
280
+ indicatorStyle={indicatorStyle}
281
+ />
251
282
  </div>
252
283
 
253
284
  {/* Content area - uses original inputState */}
@@ -261,7 +261,7 @@ const SwipeDebugPage: React.FC = () => {
261
261
  [{log.time}] {log.message}
262
262
  </div>
263
263
  ))}
264
- {logs.length === 0 && <div>No logs yet. Start swiping...</div>}
264
+ {logs.length === 0 ? <div>No logs yet. Start swiping...</div> : null}
265
265
  </div>
266
266
 
267
267
  {/* Manual navigation */}
@@ -0,0 +1,156 @@
1
+ /**
2
+ * @file Tests for StackBasics component logic.
3
+ *
4
+ * These tests focus on the panel visibility and depth calculation logic,
5
+ * particularly around the exitingPanelId handling during rapid navigation.
6
+ */
7
+
8
+ // Empty export to make this file a module (prevents global scope pollution)
9
+ export {};
10
+
11
+ /**
12
+ * Pure function version of the isExiting logic for testing.
13
+ * This matches the logic in StackBasics.tsx.
14
+ */
15
+ function computeIsExiting(
16
+ panelId: string,
17
+ exitingPanelId: string | null,
18
+ stack: readonly string[],
19
+ ): boolean {
20
+ // FIX: Check if panel is in current stack - if so, it's not exiting
21
+ const isInCurrentStack = stack.includes(panelId);
22
+ return panelId === exitingPanelId && !isInCurrentStack;
23
+ }
24
+
25
+ /**
26
+ * Pure function version of panelDepth calculation.
27
+ */
28
+ function computePanelDepth(
29
+ panelId: string,
30
+ isExiting: boolean,
31
+ stack: readonly string[],
32
+ depth: number,
33
+ ): number {
34
+ return isExiting ? depth + 1 : stack.indexOf(panelId);
35
+ }
36
+
37
+ describe("StackBasics panel calculation logic", () => {
38
+ describe("isExiting calculation", () => {
39
+ it("returns true when panel is exitingPanelId and not in stack", () => {
40
+ // Back navigation: detail was removed from stack but exitingPanelId is set
41
+ const result = computeIsExiting("detail", "detail", ["list"]);
42
+ expect(result).toBe(true);
43
+ });
44
+
45
+ it("returns false when panel is in current stack even if it matches exitingPanelId", () => {
46
+ // Bug scenario: user pushed detail again before exitingPanelId timeout cleared
47
+ // detail is in stack but exitingPanelId is still "detail"
48
+ const result = computeIsExiting("detail", "detail", ["list", "detail"]);
49
+ expect(result).toBe(false);
50
+ });
51
+
52
+ it("returns false when panel does not match exitingPanelId", () => {
53
+ const result = computeIsExiting("list", "detail", ["list"]);
54
+ expect(result).toBe(false);
55
+ });
56
+
57
+ it("returns false when exitingPanelId is null", () => {
58
+ const result = computeIsExiting("detail", null, ["list", "detail"]);
59
+ expect(result).toBe(false);
60
+ });
61
+ });
62
+
63
+ describe("panelDepth calculation", () => {
64
+ it("returns correct depth for active panel in stack", () => {
65
+ const isExiting = computeIsExiting("detail", null, ["list", "detail"]);
66
+ const depth = computePanelDepth("detail", isExiting, ["list", "detail"], 1);
67
+ expect(depth).toBe(1);
68
+ });
69
+
70
+ it("returns depth + 1 for exiting panel", () => {
71
+ const isExiting = computeIsExiting("detail", "detail", ["list"]);
72
+ const depth = computePanelDepth("detail", isExiting, ["list"], 0);
73
+ expect(depth).toBe(1); // 0 + 1
74
+ });
75
+
76
+ it("returns correct depth for re-pushed panel (not exiting)", () => {
77
+ // Bug scenario: detail was exiting but got re-pushed
78
+ // Should use stack.indexOf, not depth + 1
79
+ const stack = ["list", "detail"];
80
+ const isExiting = computeIsExiting("detail", "detail", stack);
81
+ const depth = computePanelDepth("detail", isExiting, stack, 1);
82
+ expect(depth).toBe(1); // stack.indexOf("detail") = 1, NOT depth + 1 = 2
83
+ });
84
+ });
85
+
86
+ describe("rapid navigation scenarios", () => {
87
+ it("handles push → back → push sequence correctly", () => {
88
+ // Helper function to compute stack state for each step
89
+ const computeStackState = (step: number) => {
90
+ if (step === 0) {
91
+ // Initial: list active
92
+ return { stack: ["list"] as readonly string[], depth: 0, exitingPanelId: null as string | null };
93
+ }
94
+ if (step === 1) {
95
+ // Push detail
96
+ return { stack: ["list", "detail"] as readonly string[], depth: 1, exitingPanelId: null as string | null };
97
+ }
98
+ if (step === 2) {
99
+ // Back to list (detail becomes exiting)
100
+ return { stack: ["list"] as readonly string[], depth: 0, exitingPanelId: "detail" };
101
+ }
102
+ // step === 3: Push detail again BEFORE exitingPanelId clears
103
+ return { stack: ["list", "detail"] as readonly string[], depth: 1, exitingPanelId: "detail" };
104
+ };
105
+
106
+ // Verify detail is exiting at step 2
107
+ const step2 = computeStackState(2);
108
+ const isExitingStep2 = computeIsExiting("detail", step2.exitingPanelId, step2.stack);
109
+ expect(isExitingStep2).toBe(true);
110
+
111
+ // Now detail should NOT be exiting because it's in the stack at step 3
112
+ const step3 = computeStackState(3);
113
+ const isExitingStep3 = computeIsExiting("detail", step3.exitingPanelId, step3.stack);
114
+ expect(isExitingStep3).toBe(false);
115
+
116
+ // Panel depth should be correct
117
+ const panelDepth = computePanelDepth("detail", isExitingStep3, step3.stack, step3.depth);
118
+ expect(panelDepth).toBe(1); // Not 2!
119
+ });
120
+
121
+ it("handles deep navigation with rapid back operations", () => {
122
+ // Helper function to compute stack state for each step
123
+ const computeDeepNavState = (step: number) => {
124
+ if (step === 0) {
125
+ // Initial: list → detail → edit
126
+ return { stack: ["list", "detail", "edit"] as readonly string[], depth: 2, exitingPanelId: null as string | null };
127
+ }
128
+ if (step === 1) {
129
+ // Back to detail (edit becomes exiting)
130
+ return { stack: ["list", "detail"] as readonly string[], depth: 1, exitingPanelId: "edit" };
131
+ }
132
+ if (step === 2) {
133
+ // Back to list immediately (detail becomes exiting)
134
+ return { stack: ["list"] as readonly string[], depth: 0, exitingPanelId: "detail" };
135
+ }
136
+ // step === 3: Push to detail again
137
+ return { stack: ["list", "detail"] as readonly string[], depth: 1, exitingPanelId: "detail" };
138
+ };
139
+
140
+ const step1 = computeDeepNavState(1);
141
+ const editIsExiting = computeIsExiting("edit", step1.exitingPanelId, step1.stack);
142
+ expect(editIsExiting).toBe(true);
143
+
144
+ const step2 = computeDeepNavState(2);
145
+ const detailIsExiting = computeIsExiting("detail", step2.exitingPanelId, step2.stack);
146
+ expect(detailIsExiting).toBe(true);
147
+
148
+ const step3 = computeDeepNavState(3);
149
+ const detailIsExitingAfterPush = computeIsExiting("detail", step3.exitingPanelId, step3.stack);
150
+ expect(detailIsExitingAfterPush).toBe(false);
151
+
152
+ const detailDepth = computePanelDepth("detail", detailIsExitingAfterPush, step3.stack, step3.depth);
153
+ expect(detailDepth).toBe(1);
154
+ });
155
+ });
156
+ });