@sigmela/router 0.1.3 → 0.2.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/README.md +177 -833
- package/lib/module/Navigation.js +1 -10
- package/lib/module/NavigationStack.js +168 -19
- package/lib/module/Router.js +1523 -501
- package/lib/module/RouterContext.js +1 -1
- package/lib/module/ScreenStack/ScreenStack.web.js +388 -117
- package/lib/module/ScreenStack/ScreenStackContext.js +21 -0
- package/lib/module/ScreenStack/animationHelpers.js +72 -0
- package/lib/module/ScreenStackItem/ScreenStackItem.js +2 -1
- package/lib/module/ScreenStackItem/ScreenStackItem.web.js +76 -16
- package/lib/module/ScreenStackSheetItem/ScreenStackSheetItem.native.js +2 -1
- package/lib/module/ScreenStackSheetItem/ScreenStackSheetItem.web.js +1 -1
- package/lib/module/SplitView/RenderSplitView.native.js +85 -0
- package/lib/module/SplitView/RenderSplitView.web.js +109 -0
- package/lib/module/SplitView/SplitView.js +89 -0
- package/lib/module/SplitView/SplitViewContext.js +4 -0
- package/lib/module/SplitView/index.js +5 -0
- package/lib/module/SplitView/useSplitView.js +11 -0
- package/lib/module/StackRenderer.js +4 -2
- package/lib/module/TabBar/RenderTabBar.native.js +118 -33
- package/lib/module/TabBar/RenderTabBar.web.js +52 -47
- package/lib/module/TabBar/TabBar.js +116 -3
- package/lib/module/TabBar/index.js +4 -1
- package/lib/module/TabBar/useTabBarHeight.js +22 -0
- package/lib/module/index.js +3 -4
- package/lib/module/navigationNode.js +3 -0
- package/lib/module/styles.css +693 -28
- package/lib/typescript/src/NavigationStack.d.ts +25 -13
- package/lib/typescript/src/Router.d.ts +147 -34
- package/lib/typescript/src/RouterContext.d.ts +1 -1
- package/lib/typescript/src/ScreenStack/ScreenStack.web.d.ts +0 -2
- package/lib/typescript/src/ScreenStack/ScreenStackContext.d.ts +31 -0
- package/lib/typescript/src/ScreenStack/animationHelpers.d.ts +6 -0
- package/lib/typescript/src/ScreenStackItem/ScreenStackItem.types.d.ts +5 -1
- package/lib/typescript/src/ScreenStackItem/ScreenStackItem.web.d.ts +1 -1
- package/lib/typescript/src/SplitView/RenderSplitView.native.d.ts +8 -0
- package/lib/typescript/src/SplitView/RenderSplitView.web.d.ts +8 -0
- package/lib/typescript/src/SplitView/SplitView.d.ts +31 -0
- package/lib/typescript/src/SplitView/SplitViewContext.d.ts +3 -0
- package/lib/typescript/src/SplitView/index.d.ts +5 -0
- package/lib/typescript/src/SplitView/useSplitView.d.ts +2 -0
- package/lib/typescript/src/StackRenderer.d.ts +2 -1
- package/lib/typescript/src/TabBar/TabBar.d.ts +27 -3
- package/lib/typescript/src/TabBar/index.d.ts +3 -0
- package/lib/typescript/src/TabBar/useTabBarHeight.d.ts +18 -0
- package/lib/typescript/src/createController.d.ts +1 -0
- package/lib/typescript/src/index.d.ts +4 -3
- package/lib/typescript/src/navigationNode.d.ts +41 -0
- package/lib/typescript/src/types.d.ts +29 -32
- package/package.json +6 -5
- package/lib/module/web/TransitionStack.js +0 -227
- package/lib/typescript/src/web/TransitionStack.d.ts +0 -21
package/lib/module/styles.css
CHANGED
|
@@ -10,37 +10,500 @@
|
|
|
10
10
|
.screen-stack > .screen-stack-item {
|
|
11
11
|
position: absolute;
|
|
12
12
|
inset: 0;
|
|
13
|
-
display: flex;
|
|
14
13
|
font-size: 24px;
|
|
15
|
-
display: none;
|
|
16
14
|
overflow: hidden;
|
|
15
|
+
display: none;
|
|
16
|
+
/* z-index is set inline in ScreenStack.web.tsx */
|
|
17
|
+
|
|
18
|
+
/* Base transition for opening screen */
|
|
19
|
+
transition:
|
|
20
|
+
transform 300ms cubic-bezier(0.22, 0.61, 0.36, 1),
|
|
21
|
+
filter 300ms cubic-bezier(0.22, 0.61, 0.36, 1);
|
|
17
22
|
}
|
|
18
23
|
|
|
19
|
-
|
|
24
|
+
/* Inner container for regular screen */
|
|
25
|
+
.stack-screen-container {
|
|
20
26
|
display: flex;
|
|
27
|
+
flex: 1;
|
|
28
|
+
height: 100%;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/* Inner container for modal (NOT flex: 1, to avoid stretching to full width) */
|
|
32
|
+
.stack-modal-container {
|
|
33
|
+
display: flex;
|
|
34
|
+
height: 100%;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/* Overlay inside ScreenStackItem — always full-screen, only opacity animation */
|
|
38
|
+
.stack-modal-overlay {
|
|
39
|
+
position: absolute;
|
|
40
|
+
inset: 0;
|
|
41
|
+
background: rgba(0, 0, 0, 0);
|
|
42
|
+
opacity: 0;
|
|
43
|
+
pointer-events: none;
|
|
44
|
+
z-index: 1;
|
|
45
|
+
will-change: opacity;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/* Show overlay only for modal-like presentations.
|
|
49
|
+
IMPORTANT: use direct child (>) to avoid collapsing overlay from nested stacks,
|
|
50
|
+
when modal ScreenStackItem is inside push ScreenStackItem container. */
|
|
51
|
+
.screen-stack-item:not(.modal):not(.contained-modal):not(.fullscreen-modal):not(.formsheet):not(.pagesheet):not(.sheet)
|
|
52
|
+
> .stack-modal-overlay {
|
|
53
|
+
display: none;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/* Keyframes for overlay appearance */
|
|
57
|
+
@keyframes modal-overlay-enter {
|
|
58
|
+
from {
|
|
59
|
+
opacity: 0;
|
|
60
|
+
}
|
|
61
|
+
to {
|
|
62
|
+
opacity: 0.5;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/* Keyframes for overlay disappearance */
|
|
67
|
+
@keyframes modal-overlay-exit {
|
|
68
|
+
from {
|
|
69
|
+
opacity: 0.5;
|
|
70
|
+
}
|
|
71
|
+
to {
|
|
72
|
+
opacity: 0;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/* Overlay in initial state — transparent */
|
|
77
|
+
.screen-stack-item.modal.transition-preEnter > .stack-modal-overlay,
|
|
78
|
+
.screen-stack-item.contained-modal.transition-preEnter > .stack-modal-overlay,
|
|
79
|
+
.screen-stack-item.fullscreen-modal.transition-preEnter > .stack-modal-overlay,
|
|
80
|
+
.screen-stack-item.formsheet.transition-preEnter > .stack-modal-overlay,
|
|
81
|
+
.screen-stack-item.pagesheet.transition-preEnter > .stack-modal-overlay,
|
|
82
|
+
.screen-stack-item.sheet.transition-preEnter > .stack-modal-overlay {
|
|
83
|
+
opacity: 0;
|
|
84
|
+
background: rgba(0, 0, 0, 0.5);
|
|
85
|
+
pointer-events: none;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/* Overlay on enter — start animation */
|
|
89
|
+
.screen-stack-item.modal.transition-entering > .stack-modal-overlay,
|
|
90
|
+
.screen-stack-item.modal.phase-active.transition-preEnter > .stack-modal-overlay,
|
|
91
|
+
.screen-stack-item.contained-modal.transition-entering > .stack-modal-overlay,
|
|
92
|
+
.screen-stack-item.contained-modal.phase-active.transition-preEnter > .stack-modal-overlay,
|
|
93
|
+
.screen-stack-item.fullscreen-modal.transition-entering > .stack-modal-overlay,
|
|
94
|
+
.screen-stack-item.fullscreen-modal.phase-active.transition-preEnter > .stack-modal-overlay,
|
|
95
|
+
.screen-stack-item.formsheet.transition-entering > .stack-modal-overlay,
|
|
96
|
+
.screen-stack-item.formsheet.phase-active.transition-preEnter > .stack-modal-overlay,
|
|
97
|
+
.screen-stack-item.pagesheet.transition-entering > .stack-modal-overlay,
|
|
98
|
+
.screen-stack-item.pagesheet.phase-active.transition-preEnter > .stack-modal-overlay,
|
|
99
|
+
.screen-stack-item.sheet.transition-entering > .stack-modal-overlay,
|
|
100
|
+
.screen-stack-item.sheet.phase-active.transition-preEnter > .stack-modal-overlay {
|
|
101
|
+
background: rgba(0, 0, 0, 0.5);
|
|
102
|
+
pointer-events: none;
|
|
103
|
+
animation: modal-overlay-enter 300ms cubic-bezier(0.22, 0.61, 0.36, 1) forwards;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
/* For modal-like in active / entered states — fully visible */
|
|
107
|
+
.screen-stack-item.modal.phase-active > .stack-modal-overlay,
|
|
108
|
+
.screen-stack-item.modal.transition-entered > .stack-modal-overlay,
|
|
109
|
+
.screen-stack-item.contained-modal.phase-active > .stack-modal-overlay,
|
|
110
|
+
.screen-stack-item.contained-modal.transition-entered > .stack-modal-overlay,
|
|
111
|
+
.screen-stack-item.fullscreen-modal.phase-active > .stack-modal-overlay,
|
|
112
|
+
.screen-stack-item.fullscreen-modal.transition-entered > .stack-modal-overlay,
|
|
113
|
+
.screen-stack-item.formsheet.phase-active > .stack-modal-overlay,
|
|
114
|
+
.screen-stack-item.formsheet.transition-entered > .stack-modal-overlay,
|
|
115
|
+
.screen-stack-item.pagesheet.phase-active > .stack-modal-overlay,
|
|
116
|
+
.screen-stack-item.pagesheet.transition-entered > .stack-modal-overlay,
|
|
117
|
+
.screen-stack-item.sheet.phase-active > .stack-modal-overlay,
|
|
118
|
+
.screen-stack-item.sheet.transition-entered > .stack-modal-overlay {
|
|
119
|
+
opacity: 0.5;
|
|
120
|
+
background: rgba(0, 0, 0, 0.5);
|
|
121
|
+
pointer-events: auto;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
/* Overlay on modal-like close — disappearance animation */
|
|
125
|
+
.screen-stack-item.modal.phase-exiting > .stack-modal-overlay,
|
|
126
|
+
.screen-stack-item.modal.transition-exiting > .stack-modal-overlay,
|
|
127
|
+
.screen-stack-item.contained-modal.phase-exiting > .stack-modal-overlay,
|
|
128
|
+
.screen-stack-item.contained-modal.transition-exiting > .stack-modal-overlay,
|
|
129
|
+
.screen-stack-item.fullscreen-modal.phase-exiting > .stack-modal-overlay,
|
|
130
|
+
.screen-stack-item.fullscreen-modal.transition-exiting > .stack-modal-overlay,
|
|
131
|
+
.screen-stack-item.formsheet.phase-exiting > .stack-modal-overlay,
|
|
132
|
+
.screen-stack-item.formsheet.transition-exiting > .stack-modal-overlay,
|
|
133
|
+
.screen-stack-item.pagesheet.phase-exiting > .stack-modal-overlay,
|
|
134
|
+
.screen-stack-item.pagesheet.transition-exiting > .stack-modal-overlay,
|
|
135
|
+
.screen-stack-item.sheet.phase-exiting > .stack-modal-overlay,
|
|
136
|
+
.screen-stack-item.sheet.transition-exiting > .stack-modal-overlay {
|
|
137
|
+
background: rgba(0, 0, 0, 0.5);
|
|
138
|
+
pointer-events: none;
|
|
139
|
+
animation: modal-overlay-exit 300ms cubic-bezier(0.22, 0.61, 0.36, 1) forwards;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
/* Overlay for transparent-modal — transparent */
|
|
143
|
+
.screen-stack-item.transparent-modal > .stack-modal-overlay {
|
|
144
|
+
opacity: 0 !important;
|
|
145
|
+
pointer-events: none !important;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
/* Overlay for contained-transparent-modal — transparent */
|
|
149
|
+
.screen-stack-item.contained-transparent-modal > .stack-modal-overlay {
|
|
150
|
+
opacity: 0 !important;
|
|
151
|
+
pointer-events: none !important;
|
|
21
152
|
}
|
|
22
153
|
|
|
23
|
-
|
|
24
|
-
|
|
154
|
+
/* Modal-like content container always above overlay */
|
|
155
|
+
.screen-stack-item.modal .stack-modal-container,
|
|
156
|
+
.screen-stack-item.contained-modal .stack-modal-container,
|
|
157
|
+
.screen-stack-item.fullscreen-modal .stack-modal-container,
|
|
158
|
+
.screen-stack-item.formsheet .stack-modal-container,
|
|
159
|
+
.screen-stack-item.pagesheet .stack-modal-container,
|
|
160
|
+
.screen-stack-item.sheet .stack-modal-container {
|
|
161
|
+
position: relative;
|
|
162
|
+
z-index: 2;
|
|
25
163
|
}
|
|
26
164
|
|
|
27
|
-
|
|
28
|
-
|
|
165
|
+
/* Show active / entering elements */
|
|
166
|
+
.screen-stack > .screen-stack-item.phase-active,
|
|
167
|
+
.screen-stack > .screen-stack-item.transition-entered,
|
|
168
|
+
.screen-stack > .screen-stack-item.transition-entering,
|
|
169
|
+
.screen-stack > .screen-stack-item.transition-preEnter {
|
|
170
|
+
display: flex;
|
|
29
171
|
}
|
|
30
172
|
|
|
31
|
-
|
|
32
|
-
|
|
173
|
+
/* Base state for active elements after entry */
|
|
174
|
+
/* Overridden via animation classes (push-enter, pop-enter, etc.) */
|
|
175
|
+
.screen-stack > .screen-stack-item.phase-active.transition-entered:not(.push-enter):not(.pop-enter):not(.modal):not(.sheet) {
|
|
176
|
+
transform: translateX(0);
|
|
177
|
+
filter: none;
|
|
33
178
|
}
|
|
34
179
|
|
|
35
|
-
|
|
36
|
-
|
|
180
|
+
/* Background (inactive) — visible, but without interactions */
|
|
181
|
+
.screen-stack > .screen-stack-item.phase-inactive {
|
|
182
|
+
display: flex;
|
|
183
|
+
pointer-events: none; /* Don't intercept clicks */
|
|
37
184
|
}
|
|
38
185
|
|
|
186
|
+
/* Exiting elements are also shown during animation */
|
|
187
|
+
/* Important: also show elements with pop-exit, even if they are still in transition-entered */
|
|
188
|
+
.screen-stack > .screen-stack-item.phase-exiting,
|
|
189
|
+
.screen-stack > .screen-stack-item.transition-exiting,
|
|
190
|
+
.screen-stack > .screen-stack-item.transition-preExit,
|
|
191
|
+
.screen-stack > .screen-stack-item.pop-exit {
|
|
192
|
+
display: flex;
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
/* Fully exited — hide */
|
|
196
|
+
.screen-stack > .screen-stack-item.transition-exited,
|
|
197
|
+
.screen-stack > .screen-stack-item.transition-unmounted {
|
|
198
|
+
display: none;
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
/* ==================== MODALS: base transform neutralization ==================== */
|
|
202
|
+
|
|
203
|
+
/* IMPORTANT: modal elements should not move like regular screens */
|
|
204
|
+
.screen-stack > .screen-stack-item.modal,
|
|
205
|
+
.screen-stack > .screen-stack-item.sheet {
|
|
206
|
+
transform: translate3d(0, 0, 0) !important;
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
/* ==================== COMMON STYLES BY SCREEN TYPE ==================== */
|
|
210
|
+
|
|
211
|
+
/* ==================== PUSH ANIMATIONS ==================== */
|
|
212
|
+
|
|
213
|
+
/* Forward navigation (push) — opening screen 300ms */
|
|
214
|
+
.screen-stack-item.push.push-enter {
|
|
215
|
+
transition:
|
|
216
|
+
transform 300ms cubic-bezier(0.22, 0.61, 0.36, 1),
|
|
217
|
+
filter 300ms cubic-bezier(0.22, 0.61, 0.36, 1);
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
/* PUSH ENTER - regular screen enters from right */
|
|
221
|
+
.screen-stack-item.push.push-enter.transition-preEnter {
|
|
222
|
+
transform: translateX(100%);
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
.screen-stack-item.push.push-enter.transition-entering,
|
|
226
|
+
.screen-stack-item.push.push-enter.transition-entered {
|
|
227
|
+
transform: translateX(0);
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
/* PUSH BACKGROUND - background screen shifts left */
|
|
231
|
+
/* Important: use !important to override general rules for inactive */
|
|
232
|
+
.screen-stack-item.push.push-background {
|
|
233
|
+
transform: translateX(-25%) !important;
|
|
234
|
+
transition:
|
|
235
|
+
transform 300ms cubic-bezier(0.22, 0.61, 0.36, 1),
|
|
236
|
+
filter 300ms cubic-bezier(0.22, 0.61, 0.36, 1);
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
/* POP BACKGROUND - background screen on pop stays at -25% */
|
|
240
|
+
/* Background elements on pop get pop-background instead of none, to preserve -25% position */
|
|
241
|
+
.screen-stack-item.push.pop-background {
|
|
242
|
+
transform: translateX(-25%) !important;
|
|
243
|
+
/* Don't set transition, so element stays in place without animation */
|
|
244
|
+
filter: none;
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
/* Backward navigation (pop) — closing screen 300ms */
|
|
248
|
+
/* IMPORTANT: transition is set on element with pop-exit */
|
|
249
|
+
.screen-stack-item.push.pop-exit {
|
|
250
|
+
transition:
|
|
251
|
+
transform 300ms cubic-bezier(0.22, 0.61, 0.36, 1),
|
|
252
|
+
filter 300ms cubic-bezier(0.22, 0.61, 0.36, 1);
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
/* POP EXIT - top screen exits to right */
|
|
256
|
+
/* Key difference from old version: in old version selector .phase-exiting was applied WITHOUT dependency on transition-exiting */
|
|
257
|
+
/* Here we do the same: if element has pop-exit and phase-exiting, it should exit to right */
|
|
258
|
+
.screen-stack-item.push.pop-exit.phase-exiting,
|
|
259
|
+
.screen-stack-item.push.pop-exit.transition-exiting {
|
|
260
|
+
transform: translateX(100%);
|
|
261
|
+
filter: none;
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
/* POP ENTER - screen returns to center from -25% */
|
|
265
|
+
/* Applied only to active (top) element on pop */
|
|
266
|
+
/* In old version: element was at -25% (as background), then on pop becomes active and goes to 0 */
|
|
267
|
+
/* Simplified approach as in old version: phase-active simply becomes 0 */
|
|
268
|
+
.screen-stack-item.push.pop-enter {
|
|
269
|
+
transition:
|
|
270
|
+
transform 300ms cubic-bezier(0.22, 0.61, 0.36, 1),
|
|
271
|
+
filter 300ms cubic-bezier(0.22, 0.61, 0.36, 1);
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
/* Active element on pop simply in center (0) - final state */
|
|
275
|
+
/* As in old version: .phase-active on pop → transform: translateX(0) */
|
|
276
|
+
.screen-stack-item.push.pop-enter.phase-active,
|
|
277
|
+
.screen-stack-item.push.pop-enter.phase-active.transition-entered {
|
|
278
|
+
transform: translateX(0);
|
|
279
|
+
filter: none;
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
/* ==================== MODAL STACK: don't move background ==================== */
|
|
283
|
+
|
|
284
|
+
/* If there's a modal on top — don't move previous screen and don't dim it,
|
|
285
|
+
overlay is responsible for dimming. */
|
|
286
|
+
.screen-stack:has(> .screen-stack-item.modal.phase-active)
|
|
287
|
+
> .screen-stack-item.push.phase-inactive,
|
|
288
|
+
.screen-stack:has(> .screen-stack-item.modal.phase-active)
|
|
289
|
+
> .screen-stack-item.push.phase-inactive.transition-entered {
|
|
290
|
+
transform: translate3d(0, 0, 0) !important;
|
|
291
|
+
filter: none;
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
/* ==================== MOBILE MODAL (<= 639px) — bottom sheet ==================== */
|
|
295
|
+
@media (max-width: 639px) {
|
|
296
|
+
/* Inner container for modal — bottom sheet full width with top border radius */
|
|
297
|
+
.screen-stack-item.modal .stack-modal-container {
|
|
298
|
+
width: 100%;
|
|
299
|
+
margin: 0;
|
|
300
|
+
border-radius: 0;
|
|
301
|
+
border-top-left-radius: 38px;
|
|
302
|
+
border-top-right-radius: 38px;
|
|
303
|
+
align-self: flex-end; /* align to bottom edge of parent */
|
|
304
|
+
overflow: hidden;
|
|
305
|
+
background: #fff; /* or var(--modal-bg) */
|
|
306
|
+
|
|
307
|
+
transform: translateY(0);
|
|
308
|
+
transition:
|
|
309
|
+
transform 300ms cubic-bezier(0.22, 0.61, 0.36, 1),
|
|
310
|
+
filter 300ms cubic-bezier(0.22, 0.61, 0.36, 1);
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
/* MODAL ENTER - modal enters (bottom to top) */
|
|
314
|
+
.screen-stack-item.modal.modal-enter.transition-preEnter .stack-modal-container {
|
|
315
|
+
transform: translateY(100%);
|
|
316
|
+
filter: none;
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
.screen-stack-item.modal.modal-enter.transition-entering .stack-modal-container,
|
|
320
|
+
.screen-stack-item.modal.modal-enter.transition-entered .stack-modal-container {
|
|
321
|
+
transform: translateY(0);
|
|
322
|
+
filter: none;
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
/* MODAL EXIT - modal closes (exits downward) */
|
|
326
|
+
.screen-stack-item.modal.modal-exit.transition-exiting .stack-modal-container {
|
|
327
|
+
transform: translateY(100%);
|
|
328
|
+
filter: none;
|
|
329
|
+
transition:
|
|
330
|
+
transform 300ms cubic-bezier(0.22, 0.61, 0.36, 1),
|
|
331
|
+
filter 300ms cubic-bezier(0.22, 0.61, 0.36, 1);
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
/* SHEET - sheet styles for mobile version */
|
|
335
|
+
.screen-stack-item.sheet .stack-modal-container {
|
|
336
|
+
width: 100%;
|
|
337
|
+
margin: 0;
|
|
338
|
+
border-radius: 0;
|
|
339
|
+
border-top-left-radius: 38px;
|
|
340
|
+
border-top-right-radius: 38px;
|
|
341
|
+
align-self: flex-end;
|
|
342
|
+
overflow: hidden;
|
|
343
|
+
background: #fff;
|
|
344
|
+
|
|
345
|
+
transform: translateY(0);
|
|
346
|
+
transition:
|
|
347
|
+
transform 300ms cubic-bezier(0.22, 0.61, 0.36, 1),
|
|
348
|
+
filter 300ms cubic-bezier(0.22, 0.61, 0.36, 1);
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
/* SHEET ENTER - sheet enters (bottom to top) */
|
|
352
|
+
.screen-stack-item.sheet.sheet-enter.transition-preEnter .stack-modal-container {
|
|
353
|
+
transform: translateY(100%);
|
|
354
|
+
filter: none;
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
.screen-stack-item.sheet.sheet-enter.transition-entering .stack-modal-container,
|
|
358
|
+
.screen-stack-item.sheet.sheet-enter.transition-entered .stack-modal-container {
|
|
359
|
+
transform: translateY(0);
|
|
360
|
+
filter: none;
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
/* SHEET EXIT - sheet closes */
|
|
364
|
+
.screen-stack-item.sheet.sheet-exit.transition-exiting .stack-modal-container {
|
|
365
|
+
transform: translateY(100%);
|
|
366
|
+
filter: none;
|
|
367
|
+
transition:
|
|
368
|
+
transform 300ms cubic-bezier(0.22, 0.61, 0.36, 1),
|
|
369
|
+
filter 300ms cubic-bezier(0.22, 0.61, 0.36, 1);
|
|
370
|
+
}
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
/* ==================== DESKTOP MODAL (>= 640px) — sheet on right ==================== */
|
|
374
|
+
@media (min-width: 640px) {
|
|
375
|
+
/* Inner container for modal — right sheet 393px, with margin and border radius */
|
|
376
|
+
.screen-stack-item.modal .stack-modal-container {
|
|
377
|
+
width: 393px;
|
|
378
|
+
max-width: calc(100% - 36px);
|
|
379
|
+
height: calc(100% - 36px);
|
|
380
|
+
margin: 18px;
|
|
381
|
+
margin-left: auto; /* align to right edge */
|
|
382
|
+
border-radius: 16px;
|
|
383
|
+
overflow: hidden;
|
|
384
|
+
background: #fff; /* or var(--modal-bg) */
|
|
385
|
+
|
|
386
|
+
transform: translateX(0);
|
|
387
|
+
transition:
|
|
388
|
+
transform 300ms cubic-bezier(0.22, 0.61, 0.36, 1),
|
|
389
|
+
filter 300ms cubic-bezier(0.22, 0.61, 0.36, 1);
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
/* MODAL ENTER - modal enters (right to left) */
|
|
393
|
+
.screen-stack-item.modal.modal-enter.transition-preEnter .stack-modal-container {
|
|
394
|
+
transform: translateX(100%);
|
|
395
|
+
filter: none;
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
.screen-stack-item.modal.modal-enter.transition-entering .stack-modal-container,
|
|
399
|
+
.screen-stack-item.modal.modal-enter.transition-entered .stack-modal-container {
|
|
400
|
+
transform: translateX(0);
|
|
401
|
+
filter: none;
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
/* MODAL EXIT - modal closes (exits to right) */
|
|
405
|
+
.screen-stack-item.modal.modal-exit.transition-exiting .stack-modal-container {
|
|
406
|
+
transform: translateX(100%);
|
|
407
|
+
filter: none;
|
|
408
|
+
transition:
|
|
409
|
+
transform 300ms cubic-bezier(0.22, 0.61, 0.36, 1),
|
|
410
|
+
filter 300ms cubic-bezier(0.22, 0.61, 0.36, 1);
|
|
411
|
+
}
|
|
412
|
+
|
|
413
|
+
/* SHEET ENTER - sheet enters (right to left) */
|
|
414
|
+
.screen-stack-item.sheet.sheet-enter.transition-preEnter
|
|
415
|
+
.stack-modal-container {
|
|
416
|
+
transform: translateX(100%);
|
|
417
|
+
filter: none;
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
.screen-stack-item.sheet.sheet-enter.transition-entering
|
|
421
|
+
.stack-modal-container,
|
|
422
|
+
.screen-stack-item.sheet.sheet-enter.transition-entered
|
|
423
|
+
.stack-modal-container {
|
|
424
|
+
transform: translateX(0);
|
|
425
|
+
filter: none;
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
/* SHEET EXIT - sheet closes */
|
|
429
|
+
.screen-stack-item.sheet.sheet-exit.transition-exiting
|
|
430
|
+
.stack-modal-container {
|
|
431
|
+
transform: translateX(100%);
|
|
432
|
+
filter: none;
|
|
433
|
+
transition:
|
|
434
|
+
transform 300ms cubic-bezier(0.22, 0.61, 0.36, 1),
|
|
435
|
+
filter 300ms cubic-bezier(0.22, 0.61, 0.36, 1);
|
|
436
|
+
}
|
|
437
|
+
|
|
438
|
+
/* Background screens under modal — don't move, don't dim (overlay does this) */
|
|
439
|
+
.screen-stack:has(> .screen-stack-item.modal.phase-active)
|
|
440
|
+
> .screen-stack-item.push.phase-inactive,
|
|
441
|
+
.screen-stack:has(> .screen-stack-item.modal.phase-active)
|
|
442
|
+
> .screen-stack-item.push.phase-inactive.transition-entered {
|
|
443
|
+
transform: translate3d(0, 0, 0) !important;
|
|
444
|
+
filter: none;
|
|
445
|
+
}
|
|
446
|
+
}
|
|
447
|
+
|
|
448
|
+
/* ==================== INACTIVE SCREENS (common settings) ==================== */
|
|
449
|
+
|
|
450
|
+
/* Inactive screens (background stack elements)
|
|
451
|
+
Background elements on pop get animationType: pop-background and stay at -25%
|
|
452
|
+
(except modal case, there we override via :has) */
|
|
453
|
+
.screen-stack > .screen-stack-item.phase-inactive:not(.push-background):not(.pop-background):not(.pop-enter):not(.pop-exit):not(.modal):not(.sheet) {
|
|
454
|
+
/* Don't set transform explicitly - element will preserve previous position */
|
|
455
|
+
filter: none;
|
|
456
|
+
}
|
|
457
|
+
|
|
458
|
+
/* ==================== SPECIAL CASES ==================== */
|
|
459
|
+
|
|
460
|
+
/* NO-ANIMATE - no animation (screenOptions.animated === false) */
|
|
461
|
+
/* IMPORTANT: this rule should override all other animation rules */
|
|
462
|
+
.screen-stack-item.no-animate,
|
|
463
|
+
.screen-stack-item.no-animate.push-enter,
|
|
464
|
+
.screen-stack-item.no-animate.push-exit,
|
|
465
|
+
.screen-stack-item.no-animate.push-background,
|
|
466
|
+
.screen-stack-item.no-animate.pop-enter,
|
|
467
|
+
.screen-stack-item.no-animate.pop-exit,
|
|
468
|
+
.screen-stack-item.no-animate.pop-background {
|
|
469
|
+
transform: translate3d(0, 0, 0) !important;
|
|
470
|
+
transition: none !important;
|
|
471
|
+
filter: none !important;
|
|
472
|
+
}
|
|
473
|
+
|
|
474
|
+
/* NONE - no animation (initial mount) */
|
|
475
|
+
/* IMPORTANT: this rule should NOT be applied to pop-background elements */
|
|
476
|
+
.screen-stack-item.none:not(.pop-background) {
|
|
477
|
+
transform: translate3d(0, 0, 0) !important;
|
|
478
|
+
transition: none !important;
|
|
479
|
+
filter: none !important;
|
|
480
|
+
}
|
|
481
|
+
|
|
482
|
+
|
|
483
|
+
|
|
39
484
|
.tab-stacks-container {
|
|
40
485
|
display: flex;
|
|
41
486
|
flex-direction: column;
|
|
42
487
|
flex: 1 1 auto;
|
|
43
|
-
min-height:
|
|
488
|
+
min-height: 100dvh;
|
|
489
|
+
position: relative;
|
|
490
|
+
}
|
|
491
|
+
|
|
492
|
+
.tab-stacks-container > .screen-stack {
|
|
493
|
+
padding-bottom: calc(73px + env(safe-area-inset-bottom));
|
|
494
|
+
}
|
|
495
|
+
|
|
496
|
+
.tab-bar-blur-overlay {
|
|
497
|
+
position: fixed;
|
|
498
|
+
bottom: 0;
|
|
499
|
+
left: 0;
|
|
500
|
+
right: 0;
|
|
501
|
+
height: calc(73px + 16px + env(safe-area-inset-bottom));
|
|
502
|
+
backdrop-filter: blur(20px) saturate(180%);
|
|
503
|
+
background-color: rgba(255, 255, 255, 0.05);
|
|
504
|
+
/* -webkit-backdrop-filter: blur(20px) saturate(180%); */
|
|
505
|
+
pointer-events: none;
|
|
506
|
+
z-index: 99;
|
|
44
507
|
}
|
|
45
508
|
|
|
46
509
|
.tab-bar {
|
|
@@ -49,8 +512,27 @@
|
|
|
49
512
|
align-items: center;
|
|
50
513
|
justify-content: center;
|
|
51
514
|
flex-shrink: 0;
|
|
52
|
-
position:
|
|
53
|
-
|
|
515
|
+
position: fixed;
|
|
516
|
+
bottom: 0;
|
|
517
|
+
left: 0;
|
|
518
|
+
right: 0;
|
|
519
|
+
padding: 8px 16px;
|
|
520
|
+
padding-bottom: max(16px, env(safe-area-inset-bottom));
|
|
521
|
+
background: transparent;
|
|
522
|
+
z-index: 100;
|
|
523
|
+
}
|
|
524
|
+
|
|
525
|
+
.tab-bar-inner {
|
|
526
|
+
display: flex;
|
|
527
|
+
flex-direction: row;
|
|
528
|
+
align-items: center;
|
|
529
|
+
background: #FFFFFF;
|
|
530
|
+
box-shadow: 0 2px 8px #00000014;
|
|
531
|
+
border-radius: 100px;
|
|
532
|
+
padding: 4px;
|
|
533
|
+
gap: 4px;
|
|
534
|
+
width: 100%;
|
|
535
|
+
max-width: 100%;
|
|
54
536
|
}
|
|
55
537
|
|
|
56
538
|
.tab-item {
|
|
@@ -58,28 +540,46 @@
|
|
|
58
540
|
background: transparent;
|
|
59
541
|
border: 0;
|
|
60
542
|
margin: 0;
|
|
61
|
-
padding:
|
|
62
|
-
height:
|
|
543
|
+
padding: 8px 16px;
|
|
544
|
+
height: 49px;
|
|
63
545
|
color: inherit;
|
|
64
546
|
display: flex;
|
|
65
|
-
flex: 1
|
|
547
|
+
flex: 1;
|
|
66
548
|
flex-direction: column;
|
|
67
549
|
align-items: center;
|
|
68
550
|
justify-content: center;
|
|
551
|
+
gap: 4px;
|
|
69
552
|
position: relative;
|
|
70
553
|
cursor: pointer;
|
|
554
|
+
border-radius: 100px;
|
|
555
|
+
transition: all 200ms cubic-bezier(0.22, 0.61, 0.36, 1);
|
|
71
556
|
}
|
|
72
557
|
|
|
558
|
+
.tab-item.active {
|
|
559
|
+
background: #EDEDED;
|
|
560
|
+
}
|
|
561
|
+
|
|
562
|
+
.tab-item:hover:not(.active) {
|
|
563
|
+
background: color-mix(in srgb, currentColor 8%, transparent);
|
|
564
|
+
}
|
|
565
|
+
|
|
566
|
+
|
|
73
567
|
.tab-item:focus {
|
|
74
568
|
outline: none;
|
|
75
569
|
}
|
|
76
570
|
|
|
571
|
+
.tab-item:focus-visible {
|
|
572
|
+
outline: 2px solid currentColor;
|
|
573
|
+
outline-offset: 2px;
|
|
574
|
+
}
|
|
575
|
+
|
|
77
576
|
.tab-item-icon {
|
|
78
577
|
width: 24px;
|
|
79
578
|
height: 24px;
|
|
80
579
|
display: flex;
|
|
81
580
|
align-items: center;
|
|
82
581
|
justify-content: center;
|
|
582
|
+
flex-shrink: 0;
|
|
83
583
|
}
|
|
84
584
|
|
|
85
585
|
.tab-item-icon > * {
|
|
@@ -90,28 +590,193 @@
|
|
|
90
590
|
}
|
|
91
591
|
|
|
92
592
|
.tab-item-label {
|
|
93
|
-
font-size:
|
|
94
|
-
line-height:
|
|
593
|
+
font-size: 12px;
|
|
594
|
+
line-height: 16px;
|
|
595
|
+
font-weight: 500;
|
|
95
596
|
text-align: center;
|
|
96
597
|
white-space: nowrap;
|
|
97
598
|
pointer-events: none;
|
|
98
|
-
margin-top: 2px;
|
|
99
599
|
}
|
|
100
600
|
|
|
101
601
|
.tab-item-label-badge {
|
|
102
602
|
position: absolute;
|
|
103
|
-
top:
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
padding: 0 5px;
|
|
603
|
+
top: 2px;
|
|
604
|
+
right: 2px;
|
|
605
|
+
min-width: 18px;
|
|
606
|
+
height: 18px;
|
|
607
|
+
padding: 0 6px;
|
|
109
608
|
border-radius: 9999px;
|
|
110
609
|
background-color: #dc3545;
|
|
111
610
|
color: #fff;
|
|
112
|
-
font-size:
|
|
113
|
-
|
|
611
|
+
font-size: 11px;
|
|
612
|
+
font-weight: 600;
|
|
613
|
+
line-height: 18px;
|
|
114
614
|
display: inline-flex;
|
|
115
615
|
align-items: center;
|
|
116
616
|
justify-content: center;
|
|
617
|
+
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.15);
|
|
618
|
+
}
|
|
619
|
+
|
|
620
|
+
/* ==================== DESKTOP TAB BAR (>= 641px) ==================== */
|
|
621
|
+
@media (min-width: 641px) {
|
|
622
|
+
.tab-stacks-container {
|
|
623
|
+
flex-direction: row;
|
|
624
|
+
}
|
|
625
|
+
|
|
626
|
+
.tab-stacks-container > .screen-stack {
|
|
627
|
+
padding-bottom: 0;
|
|
628
|
+
margin-left: 260px;
|
|
629
|
+
min-width: 0;
|
|
630
|
+
width: calc(100% - 260px);
|
|
631
|
+
}
|
|
632
|
+
|
|
633
|
+
.tab-bar-blur-overlay {
|
|
634
|
+
display: none;
|
|
635
|
+
}
|
|
636
|
+
|
|
637
|
+
.tab-bar {
|
|
638
|
+
position: absolute;
|
|
639
|
+
top: 0;
|
|
640
|
+
left: 0;
|
|
641
|
+
bottom: 0;
|
|
642
|
+
width: 260px;
|
|
643
|
+
height: 100%;
|
|
644
|
+
flex-direction: column;
|
|
645
|
+
align-items: stretch;
|
|
646
|
+
justify-content: flex-start;
|
|
647
|
+
padding: 0;
|
|
648
|
+
flex-shrink: 0;
|
|
649
|
+
order: 1;
|
|
650
|
+
background: transparent;
|
|
651
|
+
z-index: auto;
|
|
652
|
+
}
|
|
653
|
+
|
|
654
|
+
.tab-bar-inner {
|
|
655
|
+
height: 100%;
|
|
656
|
+
width: 100%;
|
|
657
|
+
flex-direction: column;
|
|
658
|
+
align-items: stretch;
|
|
659
|
+
justify-content: flex-start;
|
|
660
|
+
border-radius: 0;
|
|
661
|
+
padding: 12px 0 0 0;
|
|
662
|
+
gap: 0;
|
|
663
|
+
background: #FFFFFF;
|
|
664
|
+
box-shadow: none;
|
|
665
|
+
}
|
|
666
|
+
|
|
667
|
+
.tab-item {
|
|
668
|
+
margin: 0 12px;
|
|
669
|
+
margin-bottom: 4px;
|
|
670
|
+
height: 44px;
|
|
671
|
+
flex: 0 0 auto;
|
|
672
|
+
flex-direction: row;
|
|
673
|
+
align-items: center;
|
|
674
|
+
justify-content: flex-start;
|
|
675
|
+
padding: 0 12px;
|
|
676
|
+
width: auto;
|
|
677
|
+
border-radius: 10px;
|
|
678
|
+
transition: background-color 200ms cubic-bezier(0.22, 0.61, 0.36, 1);
|
|
679
|
+
}
|
|
680
|
+
|
|
681
|
+
.tab-item.active {
|
|
682
|
+
background: var(--backgroundTertiaryTrans, rgba(201, 204, 209, 0.32));
|
|
683
|
+
}
|
|
684
|
+
|
|
685
|
+
.tab-item:active {
|
|
686
|
+
transform: none;
|
|
687
|
+
}
|
|
688
|
+
|
|
689
|
+
.tab-item-icon {
|
|
690
|
+
width: 24px;
|
|
691
|
+
height: 24px;
|
|
692
|
+
padding-right: 12px;
|
|
693
|
+
flex-shrink: 0;
|
|
694
|
+
}
|
|
695
|
+
|
|
696
|
+
.tab-item-label {
|
|
697
|
+
flex: 1;
|
|
698
|
+
font-size: 14px;
|
|
699
|
+
line-height: 20px;
|
|
700
|
+
font-weight: 600;
|
|
701
|
+
text-align: left;
|
|
702
|
+
padding-right: 3px;
|
|
703
|
+
white-space: nowrap;
|
|
704
|
+
}
|
|
705
|
+
|
|
706
|
+
.tab-item-label-badge {
|
|
707
|
+
position: static;
|
|
708
|
+
transform: none;
|
|
709
|
+
margin-left: auto;
|
|
710
|
+
}
|
|
711
|
+
}
|
|
712
|
+
|
|
713
|
+
/* ==================== SPLIT VIEW (web) ==================== */
|
|
714
|
+
|
|
715
|
+
.split-view-container {
|
|
716
|
+
position: relative;
|
|
717
|
+
display: block; /* narrow by default; wide enabled via injected @media rule */
|
|
718
|
+
height: 100dvh;
|
|
719
|
+
min-height: 100dvh;
|
|
720
|
+
width: 100%;
|
|
721
|
+
overflow: hidden;
|
|
722
|
+
}
|
|
723
|
+
|
|
724
|
+
.split-view-container .screen-stack {
|
|
725
|
+
/* ScreenStack has min-width: 100%, which breaks side-by-side layouts */
|
|
726
|
+
min-width: 0;
|
|
727
|
+
}
|
|
728
|
+
|
|
729
|
+
.split-view-primary {
|
|
730
|
+
position: relative;
|
|
731
|
+
width: 100%;
|
|
732
|
+
height: 100%;
|
|
733
|
+
min-width: 0;
|
|
734
|
+
}
|
|
735
|
+
|
|
736
|
+
.split-view-secondary {
|
|
737
|
+
position: absolute;
|
|
738
|
+
inset: 0;
|
|
739
|
+
z-index: 2;
|
|
740
|
+
width: 100%;
|
|
741
|
+
height: 100%;
|
|
742
|
+
min-width: 0;
|
|
743
|
+
}
|
|
744
|
+
|
|
745
|
+
/* In narrow mode, hide secondary completely if it has no active screen */
|
|
746
|
+
.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)) {
|
|
747
|
+
display: none;
|
|
748
|
+
}
|
|
749
|
+
|
|
750
|
+
.split-view-container:has(.split-view-secondary:has(.screen-stack-item.phase-active)) .split-view-primary,
|
|
751
|
+
.split-view-container:has(.split-view-secondary:has(.screen-stack-item.phase-exiting)) .split-view-primary,
|
|
752
|
+
.split-view-container:has(.split-view-secondary:has(.screen-stack-item.transition-entering)) .split-view-primary,
|
|
753
|
+
.split-view-container:has(.split-view-secondary:has(.screen-stack-item.transition-entered)) .split-view-primary,
|
|
754
|
+
.split-view-container:has(.split-view-secondary:has(.screen-stack-item.transition-preEnter)) .split-view-primary,
|
|
755
|
+
.split-view-container:has(.split-view-secondary:has(.screen-stack-item.transition-exiting)) .split-view-primary,
|
|
756
|
+
.split-view-container:has(.split-view-secondary:has(.screen-stack-item.transition-preExit)) .split-view-primary,
|
|
757
|
+
.split-view-container:has(.split-view-secondary:has(.screen-stack-item.pop-exit)) .split-view-primary {
|
|
758
|
+
pointer-events: none;
|
|
759
|
+
}
|
|
760
|
+
|
|
761
|
+
/* Split view wide layout - applied when viewport width >= 640px */
|
|
762
|
+
@media (min-width: 640px) {
|
|
763
|
+
.split-view-container {
|
|
764
|
+
display: flex;
|
|
765
|
+
flex-direction: row;
|
|
766
|
+
}
|
|
767
|
+
|
|
768
|
+
.split-view-primary {
|
|
769
|
+
position: relative;
|
|
770
|
+
flex: 0 0 auto;
|
|
771
|
+
max-width: var(--split-view-primary-max-width, 390px);
|
|
772
|
+
border-right: 1px solid rgba(0, 0, 0, 0.08);
|
|
773
|
+
}
|
|
774
|
+
|
|
775
|
+
.split-view-secondary {
|
|
776
|
+
display: flex;
|
|
777
|
+
position: relative;
|
|
778
|
+
inset: auto;
|
|
779
|
+
z-index: auto;
|
|
780
|
+
flex: 1 1 auto;
|
|
781
|
+
}
|
|
117
782
|
}
|