@sigmela/router 0.3.6 → 0.4.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 (118) hide show
  1. package/CHANGELOG.md +23 -0
  2. package/LICENSE +2 -1
  3. package/README.md +108 -479
  4. package/dist/Router.d.ts +190 -0
  5. package/dist/Router.d.ts.map +1 -0
  6. package/dist/components/Modal.d.ts +56 -0
  7. package/dist/components/Modal.d.ts.map +1 -0
  8. package/dist/components/OverlayContentScope.d.ts +8 -0
  9. package/dist/components/OverlayContentScope.d.ts.map +1 -0
  10. package/dist/components/RouterCloseButton.d.ts +9 -0
  11. package/dist/components/RouterCloseButton.d.ts.map +1 -0
  12. package/dist/components/Sheet.d.ts +53 -0
  13. package/dist/components/Sheet.d.ts.map +1 -0
  14. package/dist/components/SheetSurface.d.ts +27 -0
  15. package/dist/components/SheetSurface.d.ts.map +1 -0
  16. package/dist/components/index.d.ts +4 -0
  17. package/dist/components/index.d.ts.map +1 -0
  18. package/dist/components/pageScrollLock.d.ts +3 -0
  19. package/dist/components/pageScrollLock.d.ts.map +1 -0
  20. package/dist/components/sheetDragEngine.d.ts +27 -0
  21. package/dist/components/sheetDragEngine.d.ts.map +1 -0
  22. package/dist/index.d.ts +5 -0
  23. package/dist/index.d.ts.map +1 -0
  24. package/dist/index.js +3649 -0
  25. package/dist/index.js.map +1 -0
  26. package/dist/navigationHistory.d.ts +17 -0
  27. package/dist/navigationHistory.d.ts.map +1 -0
  28. package/dist/router.css +971 -0
  29. package/dist/types.d.ts +3 -0
  30. package/dist/types.d.ts.map +1 -0
  31. package/dist/utils/id.d.ts +2 -0
  32. package/dist/utils/id.d.ts.map +1 -0
  33. package/package.json +69 -174
  34. package/lib/module/Drawer/Drawer.js +0 -250
  35. package/lib/module/Drawer/DrawerContext.js +0 -4
  36. package/lib/module/Drawer/DrawerIcon.web.js +0 -47
  37. package/lib/module/Drawer/RenderDrawer.native.js +0 -248
  38. package/lib/module/Drawer/RenderDrawer.web.js +0 -197
  39. package/lib/module/Drawer/useDrawer.js +0 -11
  40. package/lib/module/Navigation.js +0 -79
  41. package/lib/module/NavigationStack.js +0 -254
  42. package/lib/module/Router.js +0 -2171
  43. package/lib/module/RouterContext.js +0 -33
  44. package/lib/module/ScreenStack/ScreenStack.native.js +0 -3
  45. package/lib/module/ScreenStack/ScreenStack.web.js +0 -561
  46. package/lib/module/ScreenStack/ScreenStackContext.js +0 -21
  47. package/lib/module/ScreenStack/animationHelpers.js +0 -87
  48. package/lib/module/ScreenStack/index.js +0 -3
  49. package/lib/module/ScreenStackItem/ScreenStackItem.js +0 -70
  50. package/lib/module/ScreenStackItem/ScreenStackItem.types.js +0 -3
  51. package/lib/module/ScreenStackItem/ScreenStackItem.web.js +0 -171
  52. package/lib/module/ScreenStackItem/index.js +0 -3
  53. package/lib/module/ScreenStackSheetItem/ScreenStackSheetItem.native.js +0 -70
  54. package/lib/module/ScreenStackSheetItem/ScreenStackSheetItem.web.js +0 -5
  55. package/lib/module/ScreenStackSheetItem/index.js +0 -3
  56. package/lib/module/SplitView/RenderSplitView.native.js +0 -101
  57. package/lib/module/SplitView/RenderSplitView.web.js +0 -107
  58. package/lib/module/SplitView/SplitView.js +0 -97
  59. package/lib/module/SplitView/SplitViewContext.js +0 -4
  60. package/lib/module/SplitView/index.js +0 -5
  61. package/lib/module/SplitView/useSplitView.js +0 -11
  62. package/lib/module/StackRenderer.js +0 -42
  63. package/lib/module/TabBar/RenderTabBar.native.js +0 -418
  64. package/lib/module/TabBar/RenderTabBar.web.js +0 -218
  65. package/lib/module/TabBar/TabBar.js +0 -208
  66. package/lib/module/TabBar/TabBarContext.js +0 -4
  67. package/lib/module/TabBar/TabIcon.web.js +0 -47
  68. package/lib/module/TabBar/index.js +0 -6
  69. package/lib/module/TabBar/useTabBar.js +0 -11
  70. package/lib/module/TabBar/useTabBarHeight.js +0 -22
  71. package/lib/module/createController.js +0 -5
  72. package/lib/module/index.js +0 -15
  73. package/lib/module/navigationNode.js +0 -3
  74. package/lib/module/package.json +0 -1
  75. package/lib/module/styles.css +0 -1111
  76. package/lib/module/types.js +0 -13
  77. package/lib/typescript/package.json +0 -1
  78. package/lib/typescript/src/Drawer/Drawer.d.ts +0 -100
  79. package/lib/typescript/src/Drawer/DrawerContext.d.ts +0 -3
  80. package/lib/typescript/src/Drawer/DrawerIcon.web.d.ts +0 -7
  81. package/lib/typescript/src/Drawer/RenderDrawer.native.d.ts +0 -8
  82. package/lib/typescript/src/Drawer/RenderDrawer.web.d.ts +0 -8
  83. package/lib/typescript/src/Drawer/useDrawer.d.ts +0 -2
  84. package/lib/typescript/src/Navigation.d.ts +0 -17
  85. package/lib/typescript/src/NavigationStack.d.ts +0 -46
  86. package/lib/typescript/src/Router.d.ts +0 -232
  87. package/lib/typescript/src/RouterContext.d.ts +0 -18
  88. package/lib/typescript/src/ScreenStack/ScreenStack.native.d.ts +0 -2
  89. package/lib/typescript/src/ScreenStack/ScreenStack.web.d.ts +0 -9
  90. package/lib/typescript/src/ScreenStack/ScreenStackContext.d.ts +0 -31
  91. package/lib/typescript/src/ScreenStack/animationHelpers.d.ts +0 -6
  92. package/lib/typescript/src/ScreenStack/index.d.ts +0 -2
  93. package/lib/typescript/src/ScreenStackItem/ScreenStackItem.d.ts +0 -3
  94. package/lib/typescript/src/ScreenStackItem/ScreenStackItem.types.d.ts +0 -14
  95. package/lib/typescript/src/ScreenStackItem/ScreenStackItem.web.d.ts +0 -3
  96. package/lib/typescript/src/ScreenStackItem/index.d.ts +0 -3
  97. package/lib/typescript/src/ScreenStackSheetItem/ScreenStackSheetItem.native.d.ts +0 -11
  98. package/lib/typescript/src/ScreenStackSheetItem/ScreenStackSheetItem.web.d.ts +0 -2
  99. package/lib/typescript/src/ScreenStackSheetItem/index.d.ts +0 -2
  100. package/lib/typescript/src/SplitView/RenderSplitView.native.d.ts +0 -19
  101. package/lib/typescript/src/SplitView/RenderSplitView.web.d.ts +0 -8
  102. package/lib/typescript/src/SplitView/SplitView.d.ts +0 -33
  103. package/lib/typescript/src/SplitView/SplitViewContext.d.ts +0 -3
  104. package/lib/typescript/src/SplitView/index.d.ts +0 -5
  105. package/lib/typescript/src/SplitView/useSplitView.d.ts +0 -2
  106. package/lib/typescript/src/StackRenderer.d.ts +0 -8
  107. package/lib/typescript/src/TabBar/RenderTabBar.native.d.ts +0 -8
  108. package/lib/typescript/src/TabBar/RenderTabBar.web.d.ts +0 -8
  109. package/lib/typescript/src/TabBar/TabBar.d.ts +0 -112
  110. package/lib/typescript/src/TabBar/TabBarContext.d.ts +0 -3
  111. package/lib/typescript/src/TabBar/TabIcon.web.d.ts +0 -7
  112. package/lib/typescript/src/TabBar/index.d.ts +0 -5
  113. package/lib/typescript/src/TabBar/useTabBar.d.ts +0 -2
  114. package/lib/typescript/src/TabBar/useTabBarHeight.d.ts +0 -18
  115. package/lib/typescript/src/createController.d.ts +0 -15
  116. package/lib/typescript/src/index.d.ts +0 -21
  117. package/lib/typescript/src/navigationNode.d.ts +0 -41
  118. package/lib/typescript/src/types.d.ts +0 -140
@@ -1,1111 +0,0 @@
1
- .screen-stack {
2
- min-width: 100%;
3
- width: 100%;
4
- display: flex;
5
- position: relative;
6
- height: 100vh;
7
- height: 100dvh;
8
- overflow: hidden;
9
- }
10
-
11
- .screen-stack > .screen-stack-item {
12
- position: absolute;
13
- inset: 0;
14
- font-size: 24px;
15
- overflow: hidden;
16
- display: none;
17
- /* z-index is set inline in ScreenStack.web.tsx */
18
-
19
- /* Base transition for opening screen */
20
- transition:
21
- transform var(--stack-transition-time, 300ms)
22
- cubic-bezier(0.22, 0.61, 0.36, 1);
23
- }
24
-
25
- /* will-change hint for animating stacks */
26
- .screen-stack[data-animation="true"] > .screen-stack-item {
27
- will-change: transform;
28
- }
29
-
30
- /* Inner container for regular screen */
31
- .stack-screen-container {
32
- display: flex;
33
- flex: 1;
34
- height: 100%;
35
- }
36
-
37
- /* Inner container for modal (NOT flex: 1, to avoid stretching to full width) */
38
- .stack-modal-container {
39
- display: flex;
40
- height: 100%;
41
- }
42
-
43
- /* Overlay inside ScreenStackItem — always full-screen, only opacity animation */
44
- .stack-modal-overlay {
45
- position: absolute;
46
- inset: 0;
47
- background: rgba(0, 0, 0, 0);
48
- opacity: 0;
49
- pointer-events: none;
50
- z-index: 1;
51
- will-change: opacity;
52
- transition: opacity var(--stack-transition-time, 300ms)
53
- cubic-bezier(0.22, 0.61, 0.36, 1);
54
- }
55
-
56
- /* Show overlay only for modal-like presentations.
57
- IMPORTANT: use direct child (>) to avoid collapsing overlay from nested stacks,
58
- when modal ScreenStackItem is inside push ScreenStackItem container. */
59
- .screen-stack-item:not(.modal):not(.modal-right):not(.contained-modal):not(.fullscreen-modal):not(.formsheet):not(.pagesheet):not(.sheet)
60
- > .stack-modal-overlay {
61
- display: none;
62
- }
63
-
64
- /* Overlay in initial state — transparent */
65
- .screen-stack-item.modal.transition-preEnter > .stack-modal-overlay,
66
- .screen-stack-item.modal-right.transition-preEnter > .stack-modal-overlay,
67
- .screen-stack-item.contained-modal.transition-preEnter > .stack-modal-overlay,
68
- .screen-stack-item.fullscreen-modal.transition-preEnter > .stack-modal-overlay,
69
- .screen-stack-item.formsheet.transition-preEnter > .stack-modal-overlay,
70
- .screen-stack-item.pagesheet.transition-preEnter > .stack-modal-overlay,
71
- .screen-stack-item.sheet.transition-preEnter > .stack-modal-overlay {
72
- opacity: 0;
73
- background: rgba(0, 0, 0, 0.5);
74
- pointer-events: none;
75
- }
76
-
77
- /* Overlay on enter — fade in via transition */
78
- .screen-stack-item.modal.transition-entering > .stack-modal-overlay,
79
- .screen-stack-item.modal-right.transition-entering > .stack-modal-overlay,
80
- .screen-stack-item.contained-modal.transition-entering > .stack-modal-overlay,
81
- .screen-stack-item.fullscreen-modal.transition-entering > .stack-modal-overlay,
82
- .screen-stack-item.formsheet.transition-entering > .stack-modal-overlay,
83
- .screen-stack-item.pagesheet.transition-entering > .stack-modal-overlay,
84
- .screen-stack-item.sheet.transition-entering > .stack-modal-overlay {
85
- background: rgba(0, 0, 0, 0.5);
86
- pointer-events: none;
87
- opacity: 0.5;
88
- }
89
-
90
- /* For modal-like in active / entered states — fully visible */
91
- .screen-stack-item.modal.transition-entered > .stack-modal-overlay,
92
- .screen-stack-item.modal-right.transition-entered > .stack-modal-overlay,
93
- .screen-stack-item.contained-modal.transition-entered > .stack-modal-overlay,
94
- .screen-stack-item.fullscreen-modal.transition-entered > .stack-modal-overlay,
95
- .screen-stack-item.formsheet.transition-entered > .stack-modal-overlay,
96
- .screen-stack-item.pagesheet.transition-entered > .stack-modal-overlay,
97
- .screen-stack-item.sheet.transition-entered > .stack-modal-overlay {
98
- opacity: 0.5;
99
- background: rgba(0, 0, 0, 0.5);
100
- pointer-events: auto;
101
- }
102
-
103
- /* Overlay on modal-like close — fade out via transition */
104
- .screen-stack-item.modal.phase-exiting > .stack-modal-overlay,
105
- .screen-stack-item.modal.transition-exiting > .stack-modal-overlay,
106
- .screen-stack-item.modal-right.phase-exiting > .stack-modal-overlay,
107
- .screen-stack-item.modal-right.transition-exiting > .stack-modal-overlay,
108
- .screen-stack-item.contained-modal.phase-exiting > .stack-modal-overlay,
109
- .screen-stack-item.contained-modal.transition-exiting > .stack-modal-overlay,
110
- .screen-stack-item.fullscreen-modal.phase-exiting > .stack-modal-overlay,
111
- .screen-stack-item.fullscreen-modal.transition-exiting > .stack-modal-overlay,
112
- .screen-stack-item.formsheet.phase-exiting > .stack-modal-overlay,
113
- .screen-stack-item.formsheet.transition-exiting > .stack-modal-overlay,
114
- .screen-stack-item.pagesheet.phase-exiting > .stack-modal-overlay,
115
- .screen-stack-item.pagesheet.transition-exiting > .stack-modal-overlay,
116
- .screen-stack-item.sheet.phase-exiting > .stack-modal-overlay,
117
- .screen-stack-item.sheet.transition-exiting > .stack-modal-overlay {
118
- background: rgba(0, 0, 0, 0.5);
119
- pointer-events: none;
120
- opacity: 0;
121
- }
122
-
123
- /* Overlay for transparent-modal — transparent */
124
- .screen-stack-item.transparent-modal > .stack-modal-overlay {
125
- opacity: 0 !important;
126
- pointer-events: none !important;
127
- }
128
-
129
- /* Overlay for contained-transparent-modal — transparent */
130
- .screen-stack-item.contained-transparent-modal > .stack-modal-overlay {
131
- opacity: 0 !important;
132
- pointer-events: none !important;
133
- }
134
-
135
- /* Modal-like content container always above overlay */
136
- .screen-stack-item.modal .stack-modal-container,
137
- .screen-stack-item.modal-right .stack-modal-container,
138
- .screen-stack-item.contained-modal .stack-modal-container,
139
- .screen-stack-item.fullscreen-modal .stack-modal-container,
140
- .screen-stack-item.formsheet .stack-modal-container,
141
- .screen-stack-item.pagesheet .stack-modal-container,
142
- .screen-stack-item.sheet .stack-modal-container {
143
- position: relative;
144
- z-index: 2;
145
- }
146
-
147
- /* Show active / entering elements */
148
- .screen-stack > .screen-stack-item.phase-active,
149
- .screen-stack > .screen-stack-item.transition-entered,
150
- .screen-stack > .screen-stack-item.transition-entering,
151
- .screen-stack > .screen-stack-item.transition-preEnter {
152
- display: flex;
153
- }
154
-
155
- /* Base state for active elements after entry */
156
- /* Overridden via animation classes (push-enter, pop-enter, etc.) */
157
- .screen-stack > .screen-stack-item.phase-active.transition-entered:not(.push-enter):not(.pop-enter):not(.modal):not(.sheet) {
158
- transform: translateX(0);
159
- }
160
-
161
- /* Background (inactive) — visible, but without interactions */
162
- .screen-stack > .screen-stack-item.phase-inactive {
163
- display: flex;
164
- pointer-events: none; /* Don't intercept clicks */
165
- }
166
-
167
- /* Exiting elements are also shown during animation */
168
- /* Important: also show elements with pop-exit, even if they are still in transition-entered */
169
- .screen-stack > .screen-stack-item.phase-exiting,
170
- .screen-stack > .screen-stack-item.transition-exiting,
171
- .screen-stack > .screen-stack-item.transition-preExit,
172
- .screen-stack > .screen-stack-item.pop-exit {
173
- display: flex;
174
- }
175
-
176
- /* Fully exited — hide */
177
- .screen-stack > .screen-stack-item.transition-exited,
178
- .screen-stack > .screen-stack-item.transition-unmounted {
179
- display: none;
180
- }
181
-
182
- /* ==================== MODALS: base transform neutralization ==================== */
183
-
184
- /* IMPORTANT: modal elements should not move like regular screens */
185
- .screen-stack > .screen-stack-item.modal,
186
- .screen-stack > .screen-stack-item.modal-right,
187
- .screen-stack > .screen-stack-item.sheet {
188
- transform: translate3d(0, 0, 0) !important;
189
- }
190
-
191
- /* ==================== COMMON STYLES BY SCREEN TYPE ==================== */
192
-
193
- /* ==================== PUSH ANIMATIONS ==================== */
194
-
195
- /* Forward navigation (push) — opening screen */
196
- .screen-stack-item.push.push-enter {
197
- transition:
198
- transform var(--stack-transition-time, 300ms) cubic-bezier(0.22, 0.61, 0.36, 1);
199
- }
200
-
201
- /* PUSH ENTER - regular screen enters from right */
202
- .screen-stack-item.push.push-enter.transition-preEnter {
203
- transform: translateX(100%);
204
- }
205
-
206
- .screen-stack-item.push.push-enter.transition-entering,
207
- .screen-stack-item.push.push-enter.transition-entered {
208
- transform: translateX(0);
209
- }
210
-
211
- /* PUSH BACKGROUND - background screen shifts left */
212
- /* Important: use !important to override general rules for inactive */
213
- .screen-stack-item.push.push-background,
214
- .screen-stack-item.modal.push-background,
215
- .screen-stack-item.modal-right.push-background,
216
- .screen-stack-item.sheet.push-background,
217
- .screen-stack-item.formsheet.push-background,
218
- .screen-stack-item.pagesheet.push-background {
219
- transform: translateX(-25%) !important;
220
- transition:
221
- transform var(--stack-transition-time, 300ms) cubic-bezier(0.22, 0.61, 0.36, 1);
222
- }
223
-
224
- /* POP BACKGROUND - background screen on pop stays at -25% */
225
- /* Background elements on pop get pop-background instead of none, to preserve -25% position */
226
- .screen-stack-item.push.pop-background,
227
- .screen-stack-item.modal.pop-background,
228
- .screen-stack-item.modal-right.pop-background,
229
- .screen-stack-item.sheet.pop-background,
230
- .screen-stack-item.formsheet.pop-background,
231
- .screen-stack-item.pagesheet.pop-background {
232
- transform: translateX(-25%) !important;
233
- /* Don't set transition, so element stays in place without animation */
234
- }
235
-
236
- /* Backward navigation (pop) — closing screen */
237
- /* IMPORTANT: transition is set on element with pop-exit */
238
- .screen-stack-item.push.pop-exit {
239
- transition:
240
- transform var(--stack-transition-time, 300ms) cubic-bezier(0.22, 0.61, 0.36, 1);
241
- }
242
-
243
- /* POP EXIT - top screen exits to right */
244
- /* Key difference from old version: in old version selector .phase-exiting was applied WITHOUT dependency on transition-exiting */
245
- /* Here we do the same: if element has pop-exit and phase-exiting, it should exit to right */
246
- .screen-stack-item.push.pop-exit.phase-exiting,
247
- .screen-stack-item.push.pop-exit.transition-exiting {
248
- transform: translateX(100%);
249
- }
250
-
251
- /* POP ENTER - screen returns to center from -25% */
252
- /* Applied only to active (top) element on pop */
253
- /* In old version: element was at -25% (as background), then on pop becomes active and goes to 0 */
254
- /* Simplified approach as in old version: phase-active simply becomes 0 */
255
- .screen-stack-item.push.pop-enter {
256
- transition:
257
- transform var(--stack-transition-time, 300ms) cubic-bezier(0.22, 0.61, 0.36, 1);
258
- }
259
-
260
- /* Active element on pop simply in center (0) - final state */
261
- /* As in old version: .phase-active on pop -> transform: translateX(0) */
262
- .screen-stack-item.push.pop-enter.phase-active,
263
- .screen-stack-item.push.pop-enter.phase-active.transition-entered {
264
- transform: translateX(0);
265
- }
266
-
267
- /* ==================== MODAL STACK: don't move background ==================== */
268
-
269
- /* If there's a modal on top — don't move previous screen and don't dim it,
270
- overlay is responsible for dimming. */
271
- .screen-stack[data-has-active-modal="true"]
272
- > .screen-stack-item.push.phase-inactive,
273
- .screen-stack[data-has-active-modal="true"]
274
- > .screen-stack-item.push.phase-inactive.transition-entered {
275
- transform: translate3d(0, 0, 0) !important;
276
- }
277
-
278
- /* ==================== MOBILE MODAL (<= 639px) — bottom sheet ==================== */
279
- @media (max-width: 639px) {
280
- /* Inner container for modal — bottom sheet full width with top border radius */
281
- .screen-stack-item.modal .stack-modal-container,
282
- .screen-stack-item.modal-right .stack-modal-container {
283
- width: 100%;
284
- margin: 0;
285
- border-radius: 0;
286
- border-top-left-radius: 38px;
287
- border-top-right-radius: 38px;
288
- align-self: flex-end; /* align to bottom edge of parent */
289
- overflow: hidden;
290
- background: var(--modal-bg, #fff);
291
-
292
- transform: translateY(0);
293
- transition:
294
- transform var(--stack-transition-time, 300ms) cubic-bezier(0.22, 0.61, 0.36, 1);
295
- }
296
-
297
- /* MODAL ENTER - modal enters (bottom to top) */
298
- .screen-stack-item.modal.modal-enter.transition-preEnter .stack-modal-container,
299
- .screen-stack-item.modal-right.modal-right-enter.transition-preEnter .stack-modal-container {
300
- transform: translateY(100%);
301
- }
302
-
303
- .screen-stack-item.modal.modal-enter.transition-entering .stack-modal-container,
304
- .screen-stack-item.modal.modal-enter.transition-entered .stack-modal-container,
305
- .screen-stack-item.modal-right.modal-right-enter.transition-entering .stack-modal-container,
306
- .screen-stack-item.modal-right.modal-right-enter.transition-entered .stack-modal-container {
307
- transform: translateY(0);
308
- }
309
-
310
- /* MODAL EXIT - modal closes (exits downward) */
311
- .screen-stack-item.modal.modal-exit.transition-exiting .stack-modal-container,
312
- .screen-stack-item.modal-right.modal-right-exit.transition-exiting .stack-modal-container {
313
- transform: translateY(100%);
314
- transition:
315
- transform var(--stack-transition-time, 300ms) cubic-bezier(0.22, 0.61, 0.36, 1);
316
- }
317
-
318
- /* SHEET - sheet styles for mobile version */
319
- .screen-stack-item.sheet .stack-modal-container {
320
- width: 100%;
321
- margin: 0;
322
- border-radius: 0;
323
- border-top-left-radius: 38px;
324
- border-top-right-radius: 38px;
325
- align-self: flex-end;
326
- overflow: hidden;
327
- background: var(--modal-bg, #fff);
328
-
329
- transform: translateY(0);
330
- transition:
331
- transform var(--stack-transition-time, 300ms) cubic-bezier(0.22, 0.61, 0.36, 1);
332
- }
333
-
334
- /* SHEET ENTER - sheet enters (bottom to top) */
335
- .screen-stack-item.sheet.sheet-enter.transition-preEnter .stack-modal-container {
336
- transform: translateY(100%);
337
- }
338
-
339
- .screen-stack-item.sheet.sheet-enter.transition-entering .stack-modal-container,
340
- .screen-stack-item.sheet.sheet-enter.transition-entered .stack-modal-container {
341
- transform: translateY(0);
342
- }
343
-
344
- /* SHEET EXIT - sheet closes */
345
- .screen-stack-item.sheet.sheet-exit.transition-exiting .stack-modal-container {
346
- transform: translateY(100%);
347
- transition:
348
- transform var(--stack-transition-time, 300ms) cubic-bezier(0.22, 0.61, 0.36, 1);
349
- }
350
- }
351
-
352
- /* ==================== DESKTOP MODAL (>= 640px) — centered card ==================== */
353
- @media (min-width: 640px) {
354
- /* Inner container for modal — centered card 600px width, 75% height */
355
- .screen-stack-item.modal .stack-modal-container {
356
- width: 600px;
357
- max-width: calc(100% - 48px);
358
- height: 75vh;
359
- max-height: calc(100% - 48px);
360
- margin: auto; /* center in parent */
361
- border-radius: 38px;
362
- overflow: hidden;
363
- background: var(--modal-bg, #fff);
364
-
365
- transform: translateY(0);
366
- transition:
367
- transform var(--stack-transition-time, 300ms) cubic-bezier(0.22, 0.61, 0.36, 1);
368
- }
369
-
370
- /* Center the modal container using flexbox on parent */
371
- .screen-stack-item.modal {
372
- display: flex;
373
- align-items: center;
374
- justify-content: center;
375
- }
376
-
377
- /* MODAL ENTER - modal enters (bottom to center) */
378
- .screen-stack-item.modal.modal-enter.transition-preEnter .stack-modal-container {
379
- transform: translateY(100vh);
380
- }
381
-
382
- .screen-stack-item.modal.modal-enter.transition-entering .stack-modal-container,
383
- .screen-stack-item.modal.modal-enter.transition-entered .stack-modal-container {
384
- transform: translateY(0);
385
- }
386
-
387
- /* MODAL EXIT - modal closes (exits downward) */
388
- .screen-stack-item.modal.modal-exit.transition-exiting .stack-modal-container {
389
- transform: translateY(100vh);
390
- transition:
391
- transform var(--stack-transition-time, 300ms) cubic-bezier(0.22, 0.61, 0.36, 1);
392
- }
393
-
394
- /* ==================== MODAL-RIGHT — slide from right (previous modal behavior) ==================== */
395
-
396
- /* Inner container for modal-right — right sheet 393px */
397
- .screen-stack-item.modal-right .stack-modal-container {
398
- width: 393px;
399
- max-width: calc(100% - 36px);
400
- height: calc(100% - 36px);
401
- margin: 18px;
402
- margin-left: auto; /* align to right edge */
403
- border-radius: 16px;
404
- overflow: hidden;
405
- background: var(--modal-bg, #fff);
406
-
407
- transform: translateX(0);
408
- transition:
409
- transform var(--stack-transition-time, 300ms) cubic-bezier(0.22, 0.61, 0.36, 1);
410
- }
411
-
412
- /* MODAL-RIGHT ENTER - modal enters (right to left) */
413
- .screen-stack-item.modal-right.modal-right-enter.transition-preEnter .stack-modal-container {
414
- transform: translateX(100%);
415
- }
416
-
417
- .screen-stack-item.modal-right.modal-right-enter.transition-entering .stack-modal-container,
418
- .screen-stack-item.modal-right.modal-right-enter.transition-entered .stack-modal-container {
419
- transform: translateX(0);
420
- }
421
-
422
- /* MODAL-RIGHT EXIT - modal closes (exits to right) */
423
- .screen-stack-item.modal-right.modal-right-exit.transition-exiting .stack-modal-container {
424
- transform: translateX(100%);
425
- transition:
426
- transform var(--stack-transition-time, 300ms) cubic-bezier(0.22, 0.61, 0.36, 1);
427
- }
428
-
429
- /* SHEET ENTER - sheet enters (right to left) */
430
- .screen-stack-item.sheet.sheet-enter.transition-preEnter
431
- .stack-modal-container {
432
- transform: translateX(100%);
433
- }
434
-
435
- .screen-stack-item.sheet.sheet-enter.transition-entering
436
- .stack-modal-container,
437
- .screen-stack-item.sheet.sheet-enter.transition-entered
438
- .stack-modal-container {
439
- transform: translateX(0);
440
- }
441
-
442
- /* SHEET EXIT - sheet closes */
443
- .screen-stack-item.sheet.sheet-exit.transition-exiting
444
- .stack-modal-container {
445
- transform: translateX(100%);
446
- transition:
447
- transform var(--stack-transition-time, 300ms) cubic-bezier(0.22, 0.61, 0.36, 1);
448
- }
449
-
450
- /* Background screens under modal — don't move, don't dim (overlay does this) */
451
- .screen-stack[data-has-active-modal="true"]
452
- > .screen-stack-item.push.phase-inactive,
453
- .screen-stack[data-has-active-modal="true"]
454
- > .screen-stack-item.push.phase-inactive.transition-entered {
455
- transform: translate3d(0, 0, 0) !important;
456
- }
457
- }
458
-
459
- /* ==================== INACTIVE SCREENS (common settings) ==================== */
460
-
461
- /* Inactive screens (background stack elements)
462
- Background elements on pop get animationType: pop-background and stay at -25%
463
- (except modal case, there we override via data-has-active-modal) */
464
- .screen-stack > .screen-stack-item.phase-inactive:not(.push-background):not(.pop-background):not(.pop-enter):not(.pop-exit):not(.modal):not(.sheet) {
465
- /* Don't set transform explicitly - element will preserve previous position */
466
- }
467
-
468
- /* ==================== SPECIAL CASES ==================== */
469
-
470
- /* NO-ANIMATE - no animation (screenOptions.animated === false) */
471
- /* IMPORTANT: this rule should override all other animation rules */
472
- .screen-stack-item.no-animate,
473
- .screen-stack-item.no-animate.push-enter,
474
- .screen-stack-item.no-animate.push-exit,
475
- .screen-stack-item.no-animate.push-background,
476
- .screen-stack-item.no-animate.pop-enter,
477
- .screen-stack-item.no-animate.pop-exit,
478
- .screen-stack-item.no-animate.pop-background {
479
- transform: translate3d(0, 0, 0) !important;
480
- transition: none !important;
481
- }
482
-
483
- /* NONE - no animation (initial mount) */
484
- /* IMPORTANT: this rule should NOT be applied to pop-background elements */
485
- .screen-stack-item.none:not(.pop-background) {
486
- transform: translate3d(0, 0, 0) !important;
487
- transition: none !important;
488
- }
489
-
490
-
491
-
492
- .tab-stacks-container {
493
- display: flex;
494
- flex-direction: column;
495
- flex: 1 1 auto;
496
- min-height: 100vh;
497
- min-height: 100dvh;
498
- position: relative;
499
- }
500
-
501
- .tab-stacks-container > .screen-stack,
502
- .tab-stacks-container > .split-view-container {
503
- padding-bottom: calc(73px + env(safe-area-inset-bottom));
504
- }
505
-
506
- .tab-bar {
507
- /* CSS variables for theming / behavior */
508
- --tabbar-bg: #ffffff;
509
- --tabbar-gap: 4px;
510
- --tabbar-radius: 9999px;
511
- --tabbar-padding: 6px;
512
- --tabbar-item-radius: 9999px;
513
- --tabbar-height: 56px;
514
-
515
- /* Used by active indicator (set inline in RenderTabBar.web.tsx) */
516
- --tabbar-tabs-count: 1;
517
- --tabbar-active-index: 0;
518
-
519
- display: flex;
520
- flex-direction: row;
521
- align-items: center;
522
- justify-content: center;
523
- flex-shrink: 0;
524
- position: fixed;
525
- bottom: 0;
526
- left: 0;
527
- right: 0;
528
- padding: 10px 12px;
529
- padding-bottom: max(12px, env(safe-area-inset-bottom));
530
- background: transparent;
531
- z-index: 100;
532
- }
533
-
534
- .tab-bar-blur-overlay {
535
- position: fixed;
536
- bottom: 0;
537
- left: 0;
538
- right: 0;
539
- height: calc(73px + 16px + env(safe-area-inset-bottom));
540
- backdrop-filter: blur(20px) saturate(180%);
541
- background-color: rgba(255, 255, 255, 0.05);
542
- /* -webkit-backdrop-filter: blur(20px) saturate(180%); */
543
- pointer-events: none;
544
- z-index: 99;
545
- }
546
-
547
- .tab-bar-inner {
548
- position: relative;
549
- display: flex;
550
- width: 100%;
551
- max-width: 100%;
552
- border-radius: var(--tabbar-radius);
553
- overflow: hidden;
554
- isolation: isolate;
555
- }
556
-
557
- .tab-bar-glass {
558
- position: absolute;
559
- inset: 0;
560
- z-index: 0;
561
- pointer-events: none;
562
- }
563
-
564
- .tab-bar-content {
565
- position: relative;
566
- z-index: 1;
567
- display: flex;
568
- flex-direction: row;
569
- align-items: center;
570
- width: 100%;
571
- max-width: 100%;
572
- gap: var(--tabbar-gap);
573
- padding: var(--tabbar-padding);
574
- }
575
-
576
- .tab-bar-active-indicator {
577
- position: absolute;
578
- top: var(--tabbar-padding);
579
- bottom: var(--tabbar-padding);
580
- left: var(--tabbar-padding);
581
- border-radius: var(--tabbar-item-radius);
582
- z-index: 0;
583
- pointer-events: none;
584
- opacity: 0;
585
- transition:
586
- transform 220ms cubic-bezier(0.22, 0.61, 0.36, 1),
587
- opacity 180ms cubic-bezier(0.22, 0.61, 0.36, 1);
588
- }
589
-
590
- .tab-bar[data-tabs-count]:not([data-tabs-count="0"]) .tab-bar-active-indicator {
591
- opacity: 1;
592
- width: calc(
593
- (
594
- 100% -
595
- (var(--tabbar-padding) * 2) -
596
- (var(--tabbar-gap) * (var(--tabbar-tabs-count) - 1))
597
- ) / var(--tabbar-tabs-count)
598
- );
599
- transform: translateX(
600
- calc((var(--tabbar-active-index) * (100% + var(--tabbar-gap))))
601
- );
602
- }
603
-
604
- .tab-item {
605
- appearance: none;
606
- background: transparent;
607
- border: 0;
608
- margin: 0;
609
- padding: 6px 10px;
610
- height: var(--tabbar-height);
611
- color: inherit;
612
- display: flex;
613
- flex: 1 1 0;
614
- flex-direction: column;
615
- align-items: center;
616
- justify-content: center;
617
- gap: 4px;
618
- position: relative;
619
- cursor: pointer;
620
- border-radius: var(--tabbar-item-radius);
621
- transition:
622
- transform 120ms cubic-bezier(0.22, 0.61, 0.36, 1),
623
- background-color 200ms cubic-bezier(0.22, 0.61, 0.36, 1),
624
- color 200ms cubic-bezier(0.22, 0.61, 0.36, 1);
625
- }
626
-
627
- .tab-item.active {
628
- background: transparent;
629
- }
630
-
631
- .tab-item:hover:not(.active) {
632
- background: rgba(10, 10, 10, 0.06);
633
- background: color-mix(in srgb, #0a0a0a 6%, transparent);
634
- }
635
-
636
- .tab-item:active {
637
- transform: scale(0.98);
638
- }
639
-
640
- .tab-item:focus:not(:focus-visible) {
641
- outline: none;
642
- }
643
-
644
- .tab-item:focus-visible {
645
- box-shadow:
646
- 0 0 0 2px rgba(0, 0, 0, 0.4),
647
- 0 0 0 2px color-mix(in srgb, currentColor 40%, transparent),
648
- 0 10px 28px rgba(0, 0, 0, 0.12);
649
- }
650
-
651
- .tab-item-icon {
652
- width: 24px;
653
- height: 24px;
654
- display: flex;
655
- align-items: center;
656
- justify-content: center;
657
- flex-shrink: 0;
658
- }
659
-
660
- .tab-item-icon > * {
661
- width: 24px;
662
- height: 24px;
663
- display: block;
664
- object-fit: contain;
665
- }
666
-
667
- .tab-item-label {
668
- font-size: 12px;
669
- line-height: 16px;
670
- font-weight: 500;
671
- text-align: center;
672
- white-space: nowrap;
673
- pointer-events: none;
674
- }
675
-
676
- .tab-item-label-badge {
677
- position: absolute;
678
- top: 2px;
679
- right: 2px;
680
- min-width: 18px;
681
- height: 18px;
682
- padding: 0 6px;
683
- border-radius: 9999px;
684
- background-color: #dc3545;
685
- color: #fff;
686
- font-size: 11px;
687
- font-weight: 600;
688
- line-height: 18px;
689
- display: inline-flex;
690
- align-items: center;
691
- justify-content: center;
692
- box-shadow: 0 1px 3px rgba(0, 0, 0, 0.15);
693
- }
694
-
695
- /* ==================== MOBILE TAB BAR (<= 639px) — iOS-like floating glass pill ==================== */
696
- @media (max-width: 639px) {
697
- .tab-bar-inner {
698
- max-width: 560px;
699
- margin: 0 auto;
700
- }
701
-
702
- .tab-bar-glass {
703
- /* Fallbacks first (in case color-mix isn't supported) */
704
- background-color: rgba(255, 255, 255, 0.72);
705
- background: rgba(255, 255, 255, 0.72);
706
- /* Preferred (overrides when supported) */
707
- background: color-mix(in srgb, var(--tabbar-bg, #ffffff) 76%, transparent);
708
- backdrop-filter: blur(28px) saturate(180%);
709
- -webkit-backdrop-filter: blur(28px) saturate(180%);
710
- border: 1px solid rgba(255, 255, 255, 0.35);
711
- border: 0.5px solid color-mix(in srgb, #ffffff 55%, transparent);
712
- box-shadow:
713
- 0 8px 26px rgba(0, 0, 0, 0.18),
714
- 0 1px 0 rgba(255, 255, 255, 0.4) inset;
715
- }
716
-
717
- .tab-bar-active-indicator {
718
- background-color: rgba(255, 255, 255, 0.60);
719
- background: color-mix(in srgb, #ffffff 62%, transparent);
720
- box-shadow:
721
- 0 1px 0 rgba(255, 255, 255, 0.5) inset,
722
- 0 8px 20px rgba(0, 0, 0, 0.10);
723
- }
724
-
725
- .tab-item:hover:not(.active) {
726
- background: rgba(255, 255, 255, 0.22);
727
- background: color-mix(in srgb, #ffffff 22%, transparent);
728
- }
729
- }
730
-
731
- /* ==================== DESKTOP TAB BAR (>= 640px) ==================== */
732
- @media (min-width: 640px) {
733
- .tab-stacks-container {
734
- flex-direction: row;
735
- }
736
-
737
- .tab-stacks-container > .screen-stack,
738
- .tab-stacks-container > .split-view-container {
739
- padding-bottom: 0;
740
- margin-left: 260px;
741
- min-width: 0;
742
- width: calc(100% - 260px);
743
- }
744
-
745
- .tab-bar-blur-overlay {
746
- display: none;
747
- }
748
-
749
- .tab-bar {
750
- position: absolute;
751
- top: 0;
752
- left: 0;
753
- bottom: 0;
754
- width: 260px;
755
- height: 100%;
756
- flex-direction: column;
757
- align-items: stretch;
758
- justify-content: flex-start;
759
- padding: 0;
760
- flex-shrink: 0;
761
- order: 1;
762
- background: transparent;
763
- z-index: auto;
764
- }
765
-
766
- .tab-bar-inner {
767
- height: 100%;
768
- width: 100%;
769
- flex-direction: column;
770
- align-items: stretch;
771
- justify-content: flex-start;
772
- border-radius: 0;
773
- padding: 12px 0 0 0;
774
- gap: 0;
775
- background: var(--tabbar-bg, #ffffff);
776
- box-shadow: none;
777
- }
778
-
779
- .tab-bar-glass {
780
- display: none;
781
- }
782
-
783
- .tab-bar-content {
784
- flex-direction: column;
785
- align-items: stretch;
786
- justify-content: flex-start;
787
- padding: 0;
788
- gap: 0;
789
- }
790
-
791
- .tab-bar-active-indicator {
792
- display: none;
793
- }
794
-
795
- .tab-item {
796
- margin: 0 12px;
797
- margin-bottom: 4px;
798
- height: 44px;
799
- flex: 0 0 auto;
800
- flex-direction: row;
801
- align-items: center;
802
- justify-content: flex-start;
803
- padding: 0 12px;
804
- width: auto;
805
- border-radius: 10px;
806
- transition: background-color 200ms cubic-bezier(0.22, 0.61, 0.36, 1);
807
- }
808
-
809
- .tab-item.active {
810
- background: var(--backgroundTertiaryTrans, rgba(201, 204, 209, 0.32));
811
- }
812
-
813
- .tab-item:active {
814
- transform: none;
815
- }
816
-
817
- .tab-item-icon {
818
- width: 24px;
819
- height: 24px;
820
- padding-right: 12px;
821
- flex-shrink: 0;
822
- }
823
-
824
- .tab-item-label {
825
- flex: 1;
826
- font-size: 14px;
827
- line-height: 20px;
828
- font-weight: 600;
829
- text-align: left;
830
- padding-right: 3px;
831
- white-space: nowrap;
832
- }
833
-
834
- .tab-item-label-badge {
835
- position: static;
836
- transform: none;
837
- margin-left: auto;
838
- }
839
- }
840
-
841
- /* ==================== SPLIT VIEW (web) ==================== */
842
-
843
- .split-view-container {
844
- position: relative;
845
- display: block; /* narrow by default; wide enabled via injected @media rule */
846
- height: 100vh;
847
- height: 100dvh;
848
- min-height: 100vh;
849
- min-height: 100dvh;
850
- width: 100%;
851
- overflow: hidden;
852
- }
853
-
854
- .split-view-container .screen-stack {
855
- /* ScreenStack has min-width: 100%, which breaks side-by-side layouts */
856
- min-width: 0;
857
- }
858
-
859
- .split-view-primary {
860
- position: relative;
861
- width: 100%;
862
- height: 100%;
863
- min-width: 0;
864
- }
865
-
866
- .split-view-secondary {
867
- position: absolute;
868
- inset: 0;
869
- z-index: 2;
870
- width: 100%;
871
- height: 100%;
872
- min-width: 0;
873
- }
874
-
875
- /* In narrow mode, hide secondary completely if it has no active screen */
876
- .split-view-secondary:not(:has(.screen-stack-item.phase-active)):not(:has(.screen-stack-item.phase-exiting)):not(:has(.screen-stack-item.transition-entering)):not(:has(.screen-stack-item.transition-entered)):not(:has(.screen-stack-item.transition-preEnter)):not(:has(.screen-stack-item.transition-exiting)):not(:has(.screen-stack-item.transition-preExit)):not(:has(.screen-stack-item.pop-exit)) {
877
- display: none;
878
- }
879
-
880
-
881
- .split-view-container:has(.split-view-secondary:has(.screen-stack-item.phase-active)) .split-view-primary,
882
- .split-view-container:has(.split-view-secondary:has(.screen-stack-item.phase-exiting)) .split-view-primary,
883
- .split-view-container:has(.split-view-secondary:has(.screen-stack-item.transition-entering)) .split-view-primary,
884
- .split-view-container:has(.split-view-secondary:has(.screen-stack-item.transition-entered)) .split-view-primary,
885
- .split-view-container:has(.split-view-secondary:has(.screen-stack-item.transition-preEnter)) .split-view-primary,
886
- .split-view-container:has(.split-view-secondary:has(.screen-stack-item.transition-exiting)) .split-view-primary,
887
- .split-view-container:has(.split-view-secondary:has(.screen-stack-item.transition-preExit)) .split-view-primary,
888
- .split-view-container:has(.split-view-secondary:has(.screen-stack-item.pop-exit)) .split-view-primary {
889
- pointer-events: none;
890
- }
891
-
892
- /* Split view wide layout - applied when viewport width >= 640px */
893
- @media (min-width: 640px) {
894
- .split-view-container {
895
- display: flex;
896
- flex-direction: row;
897
- }
898
-
899
- .split-view-primary {
900
- position: relative;
901
- flex: 0 0 auto;
902
- max-width: var(--split-view-primary-max-width, 390px);
903
- border-right: 1px solid rgba(0, 0, 0, 0.08);
904
- }
905
-
906
- .split-view-secondary {
907
- display: flex;
908
- position: relative;
909
- inset: auto;
910
- z-index: auto;
911
- flex: 1 1 auto;
912
- }
913
- }
914
-
915
- /* ==================== DRAWER ==================== */
916
-
917
- .drawer-container {
918
- --drawer-bg: #ffffff;
919
- --drawer-width: 280px;
920
- --drawer-transition: 300ms cubic-bezier(0.22, 0.61, 0.36, 1);
921
-
922
- display: flex;
923
- flex-direction: row;
924
- flex: 1 1 auto;
925
- min-height: 100dvh;
926
- position: relative;
927
- overflow: hidden;
928
- }
929
-
930
- .drawer-sidebar {
931
- display: flex;
932
- flex-direction: column;
933
- width: var(--drawer-width);
934
- flex-shrink: 0;
935
- background: var(--drawer-bg);
936
- overflow-y: auto;
937
- overflow-x: hidden;
938
- padding: 12px 0 0 0;
939
- }
940
-
941
- .drawer-sidebar-content {
942
- display: flex;
943
- flex-direction: column;
944
- align-items: stretch;
945
- gap: 0;
946
- }
947
-
948
- .drawer-main {
949
- flex: 1 1 auto;
950
- min-width: 0;
951
- position: relative;
952
- }
953
-
954
- .drawer-overlay {
955
- display: none;
956
- }
957
-
958
- /* Drawer item — identical to desktop TabBar .tab-item */
959
- .drawer-item {
960
- appearance: none;
961
- background: transparent;
962
- border: 0;
963
- margin: 0 12px;
964
- margin-bottom: 4px;
965
- padding: 0 12px;
966
- height: 44px;
967
- color: inherit;
968
- display: flex;
969
- flex: 0 0 auto;
970
- flex-direction: row;
971
- align-items: center;
972
- justify-content: flex-start;
973
- cursor: pointer;
974
- border-radius: 10px;
975
- transition: background-color 200ms cubic-bezier(0.22, 0.61, 0.36, 1);
976
- }
977
-
978
- .drawer-item.active {
979
- background: var(--backgroundTertiaryTrans, rgba(201, 204, 209, 0.32));
980
- }
981
-
982
- .drawer-item:hover:not(.active) {
983
- background: color-mix(in srgb, #0a0a0a 6%, transparent);
984
- }
985
-
986
- .drawer-item:active {
987
- transform: none;
988
- }
989
-
990
- .drawer-item:focus {
991
- outline: none;
992
- }
993
-
994
- .drawer-item:focus-visible {
995
- box-shadow:
996
- 0 0 0 2px color-mix(in srgb, currentColor 40%, transparent),
997
- 0 10px 28px rgba(0, 0, 0, 0.12);
998
- }
999
-
1000
- .drawer-item-icon {
1001
- width: 24px;
1002
- height: 24px;
1003
- padding-right: 12px;
1004
- display: flex;
1005
- align-items: center;
1006
- justify-content: center;
1007
- flex-shrink: 0;
1008
- }
1009
-
1010
- .drawer-item-icon > * {
1011
- width: 24px;
1012
- height: 24px;
1013
- display: block;
1014
- object-fit: contain;
1015
- }
1016
-
1017
- .drawer-item-label {
1018
- flex: 1;
1019
- font-size: 14px;
1020
- line-height: 20px;
1021
- font-weight: 600;
1022
- text-align: left;
1023
- padding-right: 3px;
1024
- white-space: nowrap;
1025
- }
1026
-
1027
- .drawer-item-badge {
1028
- position: static;
1029
- transform: none;
1030
- margin-left: auto;
1031
- min-width: 18px;
1032
- height: 18px;
1033
- padding: 0 6px;
1034
- border-radius: 9999px;
1035
- background-color: #dc3545;
1036
- color: #fff;
1037
- font-size: 11px;
1038
- font-weight: 600;
1039
- line-height: 18px;
1040
- display: inline-flex;
1041
- align-items: center;
1042
- justify-content: center;
1043
- box-shadow: 0 1px 3px rgba(0, 0, 0, 0.15);
1044
- }
1045
-
1046
- /* ==================== MOBILE DRAWER (<= 640px) ==================== */
1047
- @media (max-width: 640px) {
1048
- .drawer-container {
1049
- overflow: hidden;
1050
- }
1051
-
1052
- .drawer-sidebar {
1053
- position: absolute;
1054
- top: 0;
1055
- left: 0;
1056
- bottom: 0;
1057
- z-index: 101;
1058
- transform: translateX(calc(-1 * var(--drawer-width)));
1059
- transition: transform var(--drawer-transition);
1060
- }
1061
-
1062
- .drawer-main {
1063
- width: 100%;
1064
- transition: transform var(--drawer-transition);
1065
- }
1066
-
1067
- .drawer-overlay {
1068
- display: block;
1069
- position: absolute;
1070
- inset: 0;
1071
- z-index: 100;
1072
- background: rgba(0, 0, 0, 0);
1073
- opacity: 0;
1074
- pointer-events: none;
1075
- transition:
1076
- opacity var(--drawer-transition),
1077
- background var(--drawer-transition);
1078
- }
1079
-
1080
- /* Open state */
1081
- .drawer-container[data-drawer-open='true'] .drawer-sidebar {
1082
- transform: translateX(0);
1083
- }
1084
-
1085
- .drawer-container[data-drawer-open='true'] .drawer-main {
1086
- transform: translateX(var(--drawer-width));
1087
- }
1088
-
1089
- .drawer-container[data-drawer-open='true'] .drawer-overlay {
1090
- opacity: 1;
1091
- background: rgba(0, 0, 0, 0.3);
1092
- pointer-events: auto;
1093
- }
1094
- }
1095
-
1096
- /* ==================== DESKTOP DRAWER (>= 641px) ==================== */
1097
- /* Inverted logic: sidebar is visible by default, data-drawer-open='true' hides it.
1098
- This way toggle() works on both viewports with a single boolean:
1099
- isOpen=false (default) → mobile: hidden, desktop: visible
1100
- isOpen=true (toggled) → mobile: visible, desktop: hidden */
1101
- @media (min-width: 641px) {
1102
- .drawer-sidebar {
1103
- border-right: 1px solid rgba(0, 0, 0, 0.08);
1104
- transition: margin-left var(--drawer-transition);
1105
- }
1106
-
1107
- .drawer-container[data-drawer-open='true'] .drawer-sidebar {
1108
- margin-left: calc(-1 * var(--drawer-width));
1109
- border-right: none;
1110
- }
1111
- }