@stackflow/plugin-basic-ui 0.19.3-alpha.1 → 0.20.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.
Files changed (40) hide show
  1. package/dist/basicUIPlugin.d.ts +1 -0
  2. package/dist/components/AppBar.css.d.ts +3 -1
  3. package/dist/components/AppBar.d.ts +3 -2
  4. package/dist/components/AppScreen.css.d.ts +2 -2
  5. package/dist/components/AppScreen.d.ts +7 -3
  6. package/dist/components/BottomSheet.d.ts +1 -1
  7. package/dist/components/Modal.d.ts +1 -1
  8. package/dist/hooks/index.d.ts +1 -0
  9. package/dist/hooks/useNullableActivity.d.ts +2 -0
  10. package/dist/index.css +409 -1
  11. package/dist/index.css.map +3 -3
  12. package/dist/index.d.ts +3 -4
  13. package/dist/index.js +1009 -1
  14. package/dist/index.js.map +4 -4
  15. package/dist/index.mjs +987 -1
  16. package/dist/index.mjs.map +4 -4
  17. package/dist/styles/f.css.d.ts +1 -0
  18. package/dist/theme.css.d.ts +2 -1
  19. package/dist/utils/compact.d.ts +1 -0
  20. package/dist/utils/index.d.ts +1 -0
  21. package/package.json +6 -7
  22. package/src/basicUIPlugin.tsx +5 -2
  23. package/src/components/AppBar.css.ts +29 -21
  24. package/src/components/AppBar.tsx +41 -33
  25. package/src/components/AppScreen.css.ts +11 -10
  26. package/src/components/AppScreen.tsx +72 -50
  27. package/src/components/BottomSheet.css.ts +5 -4
  28. package/src/components/BottomSheet.tsx +12 -9
  29. package/src/components/Modal.css.ts +2 -1
  30. package/src/components/Modal.tsx +12 -9
  31. package/src/hooks/index.ts +1 -0
  32. package/src/hooks/useNullableActivity.ts +6 -0
  33. package/src/hooks/useStyleEffect.ts +11 -4
  34. package/src/hooks/useStyleEffectOffset.ts +2 -2
  35. package/src/hooks/useStyleEffectSwipeBack.ts +5 -5
  36. package/src/index.ts +10 -8
  37. package/src/styles/f.css.ts +4 -0
  38. package/src/theme.css.ts +5 -2
  39. package/src/utils/compact.ts +6 -0
  40. package/src/utils/index.ts +1 -0
@@ -1,10 +1,10 @@
1
- import { useActions, useActivity } from "@stackflow/react";
1
+ import { useActions } from "@stackflow/react";
2
2
  import { assignInlineVars } from "@vanilla-extract/dynamic";
3
3
  import React, { useRef } from "react";
4
4
 
5
5
  import { IconBack, IconClose } from "../assets";
6
6
  import { useGlobalOptions } from "../basicUIPlugin";
7
- import { useMaxWidth } from "../hooks";
7
+ import { useMaxWidth, useNullableActivity } from "../hooks";
8
8
  import type { GlobalVars } from "../theme.css";
9
9
  import { globalVars } from "../theme.css";
10
10
  import { compactMap, noop } from "../utils";
@@ -17,6 +17,7 @@ type AppBarProps = Partial<
17
17
  | "borderColor"
18
18
  | "borderSize"
19
19
  | "height"
20
+ | "heightTransitionDuration"
20
21
  | "iconColor"
21
22
  | "textColor"
22
23
  | "backgroundColor"
@@ -66,7 +67,7 @@ const AppBar = React.forwardRef<HTMLDivElement, AppBarProps>(
66
67
  ref,
67
68
  ) => {
68
69
  const actions = useActions();
69
- const activity = useActivity();
70
+ const activity = useNullableActivity();
70
71
 
71
72
  const globalOptions = useGlobalOptions();
72
73
  const globalCloseButton = globalOptions.appBar?.closeButton;
@@ -90,6 +91,9 @@ const AppBar = React.forwardRef<HTMLDivElement, AppBarProps>(
90
91
  };
91
92
 
92
93
  const renderBackButton = () => {
94
+ if (!activity) {
95
+ return null;
96
+ }
93
97
  if (activity.isRoot) {
94
98
  return null;
95
99
  }
@@ -136,10 +140,9 @@ const AppBar = React.forwardRef<HTMLDivElement, AppBarProps>(
136
140
  };
137
141
 
138
142
  const renderCloseButton = () => {
139
- if (
140
- (!closeButton && !globalOptions.appBar?.closeButton) ||
141
- !activity.isRoot
142
- ) {
143
+ const isRoot = !activity || activity.isRoot;
144
+
145
+ if ((!closeButton && !globalOptions.appBar?.closeButton) || !isRoot) {
143
146
  return null;
144
147
  }
145
148
  if (closeButton && "render" in closeButton && closeButton.render) {
@@ -206,37 +209,42 @@ const AppBar = React.forwardRef<HTMLDivElement, AppBarProps>(
206
209
  }),
207
210
  )}
208
211
  >
209
- <div className={css.left}>
210
- {closeButtonLocation === "left" && renderCloseButton()}
211
- {renderBackButton()}
212
- {appendLeft?.()}
213
- </div>
214
- <div ref={centerRef} className={css.center}>
215
- <div
216
- className={css.centerMain({
217
- hasLeft,
218
- })}
219
- >
220
- {typeof title === "string" ? (
221
- <div className={css.centerText}>{title}</div>
222
- ) : (
223
- title
224
- )}
225
- <button
226
- className={css.centerMainEdge}
227
- type="button"
228
- aria-hidden="true"
229
- onClick={onTopClick}
230
- />
212
+ <div className={css.safeArea} />
213
+ <div className={css.container}>
214
+ <div className={css.left}>
215
+ {closeButtonLocation === "left" && renderCloseButton()}
216
+ {renderBackButton()}
217
+ {appendLeft?.()}
218
+ </div>
219
+ <div ref={centerRef} className={css.center}>
220
+ <div
221
+ className={css.centerMain({
222
+ hasLeft,
223
+ })}
224
+ >
225
+ {typeof title === "string" ? (
226
+ <div className={css.centerText}>{title}</div>
227
+ ) : (
228
+ title
229
+ )}
230
+ <button
231
+ className={css.centerMainEdge}
232
+ type="button"
233
+ aria-hidden="true"
234
+ onClick={onTopClick}
235
+ />
236
+ </div>
237
+ </div>
238
+ <div className={css.right}>
239
+ {appendRight?.()}
240
+ {closeButtonLocation === "right" && renderCloseButton()}
231
241
  </div>
232
- </div>
233
- <div className={css.right}>
234
- {appendRight?.()}
235
- {closeButtonLocation === "right" && renderCloseButton()}
236
242
  </div>
237
243
  </div>
238
244
  );
239
245
  },
240
246
  );
241
247
 
248
+ AppBar.displayName = "AppBar";
249
+
242
250
  export default AppBar;
@@ -1,5 +1,4 @@
1
1
  import { createThemeContract, style } from "@vanilla-extract/css";
2
- import { calc } from "@vanilla-extract/css-utils";
3
2
  import { recipe } from "@vanilla-extract/recipes";
4
3
 
5
4
  import { f } from "../styles";
@@ -42,7 +41,7 @@ export const enterActive = style({});
42
41
  export const enterDone = style({});
43
42
  export const exitActive = style({});
44
43
  export const exitDone = style({
45
- transform: "translateX(100%)",
44
+ transform: "translate3d(100%, 0, 0)",
46
45
  });
47
46
 
48
47
  export const appScreen = recipe({
@@ -64,6 +63,7 @@ export const dim = style([
64
63
  {
65
64
  opacity: 0,
66
65
  zIndex: vars.zIndexes.dim,
66
+ willChange: "opacity",
67
67
  selectors: {
68
68
  [`${android} &, ${rootAndroid} &`]: {
69
69
  height: "10rem",
@@ -97,27 +97,28 @@ export const paper = recipe({
97
97
  display: "none",
98
98
  },
99
99
  zIndex: vars.zIndexes.paper,
100
+ willChange: "transform",
100
101
  selectors: {
101
102
  [`${cupertino} &, ${rootCupertino} &`]: {
102
- transform: "translateX(100%)",
103
+ transform: "translate3d(100%, 0, 0)",
103
104
  },
104
105
  [`${cupertino} ${enterActive} &, ${rootCupertino} ${enterActive} &`]: {
105
- transform: "translateX(0)",
106
+ transform: "translate3d(0, 0, 0)",
106
107
  },
107
108
  [`${cupertino} ${enterDone} &, ${rootCupertino} ${enterDone} &`]: {
108
- transform: "translateX(0)",
109
+ transform: "translate3d(0, 0, 0)",
109
110
  },
110
111
  [`${android} &, ${rootAndroid} &`]: {
111
112
  opacity: 0,
112
- transform: "translateY(10rem)",
113
+ transform: "translate3d(0, 10rem, 0)",
113
114
  },
114
115
  [`${android} ${enterActive} &, ${rootAndroid} ${enterActive} &`]: {
115
116
  opacity: 1,
116
- transform: "translateY(0)",
117
+ transform: "translate3d(0, 0, 0)",
117
118
  },
118
119
  [`${android} ${enterDone} &, ${rootAndroid} ${enterDone} &`]: {
119
120
  opacity: 1,
120
- transform: "translateY(0)",
121
+ transform: "translate3d(0, 0, 0)",
121
122
  },
122
123
  },
123
124
  },
@@ -127,7 +128,7 @@ export const paper = recipe({
127
128
  true: [
128
129
  f.borderBox,
129
130
  {
130
- transition: `transform ${vars.transitionDuration}, opacity ${vars.transitionDuration}, height ${globalVars.appBar.showTransitionDuration}`,
131
+ transition: `transform ${vars.transitionDuration}, opacity ${vars.transitionDuration}, padding-top ${globalVars.appBar.heightTransitionDuration}`,
131
132
  paddingTop: [
132
133
  `calc(${globalVars.appBar.height} + constant(safe-area-inset-top))`,
133
134
  `calc(${globalVars.appBar.height} + env(safe-area-inset-top))`,
@@ -153,7 +154,7 @@ export const edge = recipe({
153
154
  hasAppBar: {
154
155
  true: {
155
156
  top: globalVars.appBar.height,
156
- height: calc("100%").subtract(globalVars.appBar.height).toString(),
157
+ height: `calc(100% - ${globalVars.appBar.height})`,
157
158
  },
158
159
  },
159
160
  },
@@ -1,12 +1,13 @@
1
1
  /* eslint-disable no-param-reassign */
2
2
 
3
- import { useActions, useActivity } from "@stackflow/react";
3
+ import { useActions } from "@stackflow/react";
4
4
  import { assignInlineVars } from "@vanilla-extract/dynamic";
5
- import React, { useRef } from "react";
5
+ import React, { createContext, useContext, useMemo, useRef } from "react";
6
6
 
7
7
  import { useGlobalOptions } from "../basicUIPlugin";
8
8
  import {
9
9
  useLazy,
10
+ useNullableActivity,
10
11
  useStyleEffectHide,
11
12
  useStyleEffectOffset,
12
13
  useStyleEffectSwipeBack,
@@ -18,12 +19,19 @@ import { compactMap } from "../utils";
18
19
  import AppBar from "./AppBar";
19
20
  import * as css from "./AppScreen.css";
20
21
 
21
- type AppScreenProps = Partial<
22
+ export type AppScreenContext = {
23
+ scroll: (args: { top: number }) => void;
24
+ };
25
+ const Context = createContext<AppScreenContext>(null as any);
26
+
27
+ export function useAppScreen() {
28
+ return useContext(Context);
29
+ }
30
+
31
+ export type AppScreenProps = Partial<
22
32
  Pick<GlobalVars, "backgroundColor" | "dimBackgroundColor">
23
33
  > & {
24
34
  appBar?: Omit<PropOf<typeof AppBar>, "theme" | "ref" | "key">;
25
- showAppBar?: boolean;
26
- showAppBarTransitionDuration?: string;
27
35
  preventSwipeBack?: boolean;
28
36
  children: React.ReactNode;
29
37
  };
@@ -31,13 +39,11 @@ const AppScreen: React.FC<AppScreenProps> = ({
31
39
  backgroundColor,
32
40
  dimBackgroundColor,
33
41
  appBar,
34
- showAppBar = !!appBar,
35
- showAppBarTransitionDuration,
36
42
  preventSwipeBack,
37
43
  children,
38
44
  }) => {
39
45
  const globalOptions = useGlobalOptions();
40
- const activity = useActivity();
46
+ const activity = useNullableActivity();
41
47
  const { pop } = useActions();
42
48
 
43
49
  const appScreenRef = useRef<HTMLDivElement>(null);
@@ -67,16 +73,16 @@ const AppScreen: React.FC<AppScreenProps> = ({
67
73
  },
68
74
  });
69
75
 
70
- const hasAppBar = !!appBar && showAppBar;
76
+ const hasAppBar = !!appBar;
71
77
 
72
- const zIndexBase = activity.zIndex * 5;
78
+ const zIndexBase = (activity?.zIndex ?? 0) * 5;
73
79
  const zIndexDim = zIndexBase;
74
80
  const zIndexPaper =
75
81
  zIndexBase + (globalOptions.theme === "cupertino" && hasAppBar ? 1 : 3);
76
82
  const zIndexEdge = zIndexBase + 4;
77
83
  const zIndexAppBar = zIndexBase + 7;
78
84
 
79
- const { transitionState } = activity;
85
+ const transitionState = activity?.transitionState ?? "enter-done";
80
86
  const lazyTransitionState = useLazy(transitionState);
81
87
 
82
88
  const onAppBarTopClick: React.MouseEventHandler = (e) => {
@@ -91,53 +97,69 @@ const AppScreen: React.FC<AppScreenProps> = ({
91
97
  };
92
98
 
93
99
  return (
94
- <div
95
- ref={appScreenRef}
96
- className={css.appScreen({
97
- transitionState:
98
- transitionState === "enter-done" || transitionState === "exit-done"
99
- ? transitionState
100
- : lazyTransitionState,
101
- })}
102
- style={assignInlineVars(
103
- compactMap({
104
- [globalVars.backgroundColor]: backgroundColor,
105
- [globalVars.dimBackgroundColor]: dimBackgroundColor,
106
- [globalVars.appBar.height]: showAppBar ? appBar?.height : "0",
107
- [globalVars.appBar.showTransitionDuration]:
108
- showAppBarTransitionDuration,
109
- [css.vars.zIndexes.dim]: `${zIndexDim}`,
110
- [css.vars.zIndexes.paper]: `${zIndexPaper}`,
111
- [css.vars.zIndexes.edge]: `${zIndexEdge}`,
112
- [css.vars.zIndexes.appBar]: `${zIndexAppBar}`,
113
- [css.vars.transitionDuration]:
114
- activity.transitionState === "enter-active" ||
115
- activity.transitionState === "exit-active"
116
- ? `var(--stackflow-transition-duration)`
117
- : "0ms",
100
+ <Context.Provider
101
+ value={useMemo(
102
+ () => ({
103
+ scroll({ top }) {
104
+ paperRef?.current?.scroll({
105
+ top,
106
+ behavior: "smooth",
107
+ });
108
+ },
118
109
  }),
110
+ [paperRef],
119
111
  )}
120
112
  >
121
- <div className={css.dim} ref={dimRef} />
122
113
  <div
123
- key={activity.id}
124
- className={css.paper({
125
- hasAppBar,
114
+ ref={appScreenRef}
115
+ className={css.appScreen({
116
+ transitionState:
117
+ transitionState === "enter-done" || transitionState === "exit-done"
118
+ ? transitionState
119
+ : lazyTransitionState,
126
120
  })}
127
- ref={paperRef}
121
+ style={assignInlineVars(
122
+ compactMap({
123
+ [globalVars.backgroundColor]: backgroundColor,
124
+ [globalVars.dimBackgroundColor]: dimBackgroundColor,
125
+ [globalVars.appBar.height]: appBar?.height,
126
+ [globalVars.appBar.heightTransitionDuration]:
127
+ appBar?.heightTransitionDuration,
128
+ [css.vars.zIndexes.dim]: `${zIndexDim}`,
129
+ [css.vars.zIndexes.paper]: `${zIndexPaper}`,
130
+ [css.vars.zIndexes.edge]: `${zIndexEdge}`,
131
+ [css.vars.zIndexes.appBar]: `${zIndexAppBar}`,
132
+ [css.vars.transitionDuration]:
133
+ transitionState === "enter-active" ||
134
+ transitionState === "exit-active"
135
+ ? `var(--stackflow-transition-duration)`
136
+ : "0ms",
137
+ }),
138
+ )}
128
139
  >
129
- {children}
130
- </div>
131
- {!activity.isRoot &&
132
- globalOptions.theme === "cupertino" &&
133
- !preventSwipeBack && (
134
- <div className={css.edge({ hasAppBar })} ref={edgeRef} />
140
+ <div className={css.dim} ref={dimRef} />
141
+ <div
142
+ key={activity?.id}
143
+ className={css.paper({
144
+ hasAppBar,
145
+ })}
146
+ ref={paperRef}
147
+ >
148
+ {children}
149
+ </div>
150
+ {!activity?.isRoot &&
151
+ globalOptions.theme === "cupertino" &&
152
+ !preventSwipeBack && (
153
+ <div className={css.edge({ hasAppBar })} ref={edgeRef} />
154
+ )}
155
+ {appBar && (
156
+ <AppBar {...appBar} ref={appBarRef} onTopClick={onAppBarTopClick} />
135
157
  )}
136
- {appBar && (
137
- <AppBar {...appBar} ref={appBarRef} onTopClick={onAppBarTopClick} />
138
- )}
139
- </div>
158
+ </div>
159
+ </Context.Provider>
140
160
  );
141
161
  };
142
162
 
163
+ AppScreen.displayName = "AppScreen";
164
+
143
165
  export default AppScreen;
@@ -20,7 +20,7 @@ export const enterActive = style({});
20
20
  export const enterDone = style({});
21
21
  export const exitActive = style({});
22
22
  export const exitDone = style({
23
- transform: "translateX(100%)",
23
+ transform: "translate3d(100%, 0, 0)",
24
24
  });
25
25
 
26
26
  export const container = recipe({
@@ -62,15 +62,16 @@ export const paper = style([
62
62
  backgroundColor: globalVars.backgroundColor,
63
63
  width: "100%",
64
64
  borderRadius: `${globalVars.bottomSheet.borderRadius} ${globalVars.bottomSheet.borderRadius} 0 0`,
65
- transform: "translateY(100%)",
65
+ willChange: "transform, opacity",
66
+ transform: "translate3d(0, 100%, 0)",
66
67
  opacity: 0,
67
68
  selectors: {
68
69
  [`${enterActive} &, ${enterDone} &`]: {
69
- transform: "translateY(0)",
70
+ transform: "translate3d(0, 0, 0)",
70
71
  opacity: 1,
71
72
  },
72
73
  [`${exitActive} &, ${exitDone} &`]: {
73
- transform: "translateY(100%)",
74
+ transform: "translate3d(0, 100%, 0)",
74
75
  opacity: 0,
75
76
  },
76
77
  },
@@ -1,16 +1,16 @@
1
1
  /* eslint-disable jsx-a11y/no-static-element-interactions, jsx-a11y/click-events-have-key-events */
2
2
 
3
- import { useActions, useActivity } from "@stackflow/react";
3
+ import { useActions } from "@stackflow/react";
4
4
  import { assignInlineVars } from "@vanilla-extract/dynamic";
5
5
  import React, { useRef } from "react";
6
6
 
7
- import { useLazy, useStyleEffect } from "../hooks";
7
+ import { useLazy, useNullableActivity, useStyleEffect } from "../hooks";
8
8
  import type { GlobalVars } from "../theme.css";
9
9
  import { globalVars } from "../theme.css";
10
10
  import { compactMap } from "../utils";
11
11
  import * as css from "./BottomSheet.css";
12
12
 
13
- type BottomSheetProps = Partial<
13
+ export type BottomSheetProps = Partial<
14
14
  Pick<GlobalVars, "backgroundColor" | "dimBackgroundColor">
15
15
  > &
16
16
  Partial<GlobalVars["bottomSheet"]> & {
@@ -24,7 +24,7 @@ const BottomSheet: React.FC<BottomSheetProps> = ({
24
24
  onOutsideClick,
25
25
  children,
26
26
  }) => {
27
- const activity = useActivity();
27
+ const activity = useNullableActivity();
28
28
  const { pop } = useActions();
29
29
 
30
30
  const containerRef = useRef<HTMLDivElement>(null);
@@ -63,13 +63,14 @@ const BottomSheet: React.FC<BottomSheetProps> = ({
63
63
  e.stopPropagation();
64
64
  };
65
65
 
66
- const zIndexBase = activity.zIndex * 5 + 3;
67
- const zIndexPaper = activity.zIndex * 5 + 4;
66
+ const zIndexBase = (activity?.zIndex ?? 0) * 5 + 3;
67
+ const zIndexPaper = (activity?.zIndex ?? 0) * 5 + 4;
68
+ const transitionState = activity?.transitionState ?? "enter-done";
68
69
 
69
70
  return (
70
71
  <div
71
72
  className={css.container({
72
- transitionState: useLazy(activity.transitionState),
73
+ transitionState: useLazy(transitionState),
73
74
  })}
74
75
  ref={containerRef}
75
76
  style={assignInlineVars(
@@ -80,8 +81,8 @@ const BottomSheet: React.FC<BottomSheetProps> = ({
80
81
  [css.vars.zIndexes.dim]: `${zIndexBase}`,
81
82
  [css.vars.zIndexes.paper]: `${zIndexPaper}`,
82
83
  [css.vars.transitionDuration]:
83
- activity.transitionState === "enter-active" ||
84
- activity.transitionState === "exit-active"
84
+ transitionState === "enter-active" ||
85
+ transitionState === "exit-active"
85
86
  ? `var(--stackflow-transition-duration)`
86
87
  : "0ms",
87
88
  }),
@@ -96,4 +97,6 @@ const BottomSheet: React.FC<BottomSheetProps> = ({
96
97
  );
97
98
  };
98
99
 
100
+ BottomSheet.displayName = "BottomSheet";
101
+
99
102
  export default BottomSheet;
@@ -20,7 +20,7 @@ export const enterActive = style({});
20
20
  export const enterDone = style({});
21
21
  export const exitActive = style({});
22
22
  export const exitDone = style({
23
- transform: "translateX(100%)",
23
+ transform: "translate3d(100%, 0, 0)",
24
24
  });
25
25
 
26
26
  export const container = recipe({
@@ -66,6 +66,7 @@ export const paper = style([
66
66
  boxShadow:
67
67
  "0px 0.625rem 2.375rem rgba(0, 0, 0, 0.15), 0px .5625rem 2.875rem rgba(0, 0, 0, 0.12), 0px .3125rem .9375rem rgba(0, 0, 0, 0.1)",
68
68
  borderRadius: globalVars.modal.borderRadius,
69
+ willChange: "transform, opacity",
69
70
  transform: "scale(1.1)",
70
71
  opacity: 0,
71
72
  selectors: {
@@ -1,16 +1,16 @@
1
1
  /* eslint-disable jsx-a11y/no-static-element-interactions, jsx-a11y/click-events-have-key-events */
2
2
 
3
- import { useActions, useActivity } from "@stackflow/react";
3
+ import { useActions } from "@stackflow/react";
4
4
  import { assignInlineVars } from "@vanilla-extract/dynamic";
5
5
  import React, { useRef } from "react";
6
6
 
7
- import { useLazy, useStyleEffect } from "../hooks";
7
+ import { useLazy, useNullableActivity, useStyleEffect } from "../hooks";
8
8
  import type { GlobalVars } from "../theme.css";
9
9
  import { globalVars } from "../theme.css";
10
10
  import { compactMap } from "../utils";
11
11
  import * as css from "./Modal.css";
12
12
 
13
- type ModalProps = Partial<
13
+ export type ModalProps = Partial<
14
14
  Pick<GlobalVars, "backgroundColor" | "dimBackgroundColor">
15
15
  > &
16
16
  Partial<GlobalVars["modal"]> & {
@@ -24,7 +24,7 @@ const Modal: React.FC<ModalProps> = ({
24
24
  onOutsideClick,
25
25
  children,
26
26
  }) => {
27
- const activity = useActivity();
27
+ const activity = useNullableActivity();
28
28
  const { pop } = useActions();
29
29
 
30
30
  const containerRef = useRef<HTMLDivElement>(null);
@@ -63,13 +63,14 @@ const Modal: React.FC<ModalProps> = ({
63
63
  e.stopPropagation();
64
64
  };
65
65
 
66
- const zIndexBase = activity.zIndex * 5 + 3;
67
- const zIndexPaper = activity.zIndex * 5 + 4;
66
+ const zIndexBase = (activity?.zIndex ?? 0) * 5 + 3;
67
+ const zIndexPaper = (activity?.zIndex ?? 0) * 5 + 4;
68
+ const transitionState = activity?.transitionState ?? "enter-done";
68
69
 
69
70
  return (
70
71
  <div
71
72
  className={css.container({
72
- transitionState: useLazy(activity.transitionState),
73
+ transitionState: useLazy(transitionState),
73
74
  })}
74
75
  ref={containerRef}
75
76
  style={assignInlineVars(
@@ -80,8 +81,8 @@ const Modal: React.FC<ModalProps> = ({
80
81
  [css.vars.zIndexes.dim]: `${zIndexBase}`,
81
82
  [css.vars.zIndexes.paper]: `${zIndexPaper}`,
82
83
  [css.vars.transitionDuration]:
83
- activity.transitionState === "enter-active" ||
84
- activity.transitionState === "exit-active"
84
+ transitionState === "enter-active" ||
85
+ transitionState === "exit-active"
85
86
  ? `var(--stackflow-transition-duration)`
86
87
  : "0ms",
87
88
  }),
@@ -96,4 +97,6 @@ const Modal: React.FC<ModalProps> = ({
96
97
  );
97
98
  };
98
99
 
100
+ Modal.displayName = "Modal";
101
+
99
102
  export default Modal;
@@ -1,5 +1,6 @@
1
1
  export * from "./useLazy";
2
2
  export * from "./useMaxWidth";
3
+ export * from "./useNullableActivity";
3
4
  export * from "./useStyleEffect";
4
5
  export * from "./useStyleEffectHide";
5
6
  export * from "./useStyleEffectOffset";
@@ -0,0 +1,6 @@
1
+ import type { Activity } from "@stackflow/core";
2
+ import { useActivity } from "@stackflow/react";
3
+
4
+ export function useNullableActivity() {
5
+ return useActivity() as Activity | null;
6
+ }
@@ -1,8 +1,9 @@
1
1
  import type { ActivityTransitionState } from "@stackflow/core";
2
- import { useActivity } from "@stackflow/react";
3
2
  import type React from "react";
4
3
  import { useEffect } from "react";
5
4
 
5
+ import { useNullableActivity } from "./useNullableActivity";
6
+
6
7
  const connections: {
7
8
  [styleName: string]: Map<
8
9
  number,
@@ -25,9 +26,12 @@ export function useStyleEffect({
25
26
  refs: Array<React.RefObject<HTMLElement>>;
26
27
  }) => (() => void) | void;
27
28
  }) {
28
- const activity = useActivity();
29
+ const activity = useNullableActivity();
29
30
 
30
31
  useEffect(() => {
32
+ if (!activity) {
33
+ return () => {};
34
+ }
31
35
  if (!connections[styleName]) {
32
36
  connections[styleName] = new Map();
33
37
  }
@@ -40,9 +44,12 @@ export function useStyleEffect({
40
44
  return () => {
41
45
  connections[styleName].delete(activity.zIndex);
42
46
  };
43
- }, [activity.id, refs, effect]);
47
+ }, [activity?.id, refs, effect]);
44
48
 
45
49
  useEffect(() => {
50
+ if (!activity) {
51
+ return () => {};
52
+ }
46
53
  if (!effect) {
47
54
  return () => {};
48
55
  }
@@ -72,5 +79,5 @@ export function useStyleEffect({
72
79
  return () => {
73
80
  cleanup?.();
74
81
  };
75
- }, [activity.transitionState]);
82
+ }, [activity?.transitionState]);
76
83
  }
@@ -22,8 +22,8 @@ export function useStyleEffectOffset({
22
22
  ? ({ activityTransitionState, refs }) => {
23
23
  const transform =
24
24
  theme === "cupertino"
25
- ? `translateX(-${OFFSET_PX_CUPERTINO / 16}rem)`
26
- : `translateY(-${OFFSET_PX_ANDROID / 16}rem)`;
25
+ ? `translate3d(-${OFFSET_PX_CUPERTINO / 16}rem, 0, 0)`
26
+ : `translate3d(0, -${OFFSET_PX_ANDROID / 16}rem, 0)`;
27
27
 
28
28
  const cleanup = () => {
29
29
  requestNextFrame(() => {
@@ -72,7 +72,7 @@ export function useStyleEffectSwipeBack({
72
72
  $dim.style.transition = "0s";
73
73
 
74
74
  $paper.style.overflowY = "hidden";
75
- $paper.style.transform = `translateX(${dx}px)`;
75
+ $paper.style.transform = `translate3d(${dx}px, 0, 0)`;
76
76
  $paper.style.transition = "0s";
77
77
 
78
78
  refs.forEach((ref) => {
@@ -80,9 +80,9 @@ export function useStyleEffectSwipeBack({
80
80
  return;
81
81
  }
82
82
 
83
- ref.current.style.transform = `translateX(${
83
+ ref.current.style.transform = `translate3d(${
84
84
  -1 * (1 - p) * OFFSET_PX_CUPERTINO
85
- }px)`;
85
+ }px, 0, 0)`;
86
86
  ref.current.style.transition = "0s";
87
87
 
88
88
  if (ref.current.parentElement?.style.display === "none") {
@@ -112,9 +112,9 @@ export function useStyleEffectSwipeBack({
112
112
  }
113
113
 
114
114
  ref.current.style.transition = `var(--stackflow-transition-duration)`;
115
- ref.current.style.transform = `translateX(${
115
+ ref.current.style.transform = `translate3d(${
116
116
  swiped ? "0" : `-${OFFSET_PX_CUPERTINO / 16}rem`
117
- })`;
117
+ }, 0, 0)`;
118
118
  });
119
119
 
120
120
  const _cachedRefs = [...cachedRefs];