@seed-design/stackflow 0.0.0-alpha-20260414104312
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/lib/components/AppBar/AppBar.cjs +115 -0
- package/lib/components/AppBar/AppBar.d.ts +34 -0
- package/lib/components/AppBar/AppBar.js +103 -0
- package/lib/components/AppBar/AppBar.namespace.cjs +16 -0
- package/lib/components/AppBar/AppBar.namespace.d.ts +2 -0
- package/lib/components/AppBar/AppBar.namespace.js +1 -0
- package/lib/components/AppBar/index.cjs +18 -0
- package/lib/components/AppBar/index.d.ts +3 -0
- package/lib/components/AppBar/index.js +3 -0
- package/lib/components/AppScreen/AppScreen.cjs +68 -0
- package/lib/components/AppScreen/AppScreen.d.ts +23 -0
- package/lib/components/AppScreen/AppScreen.js +60 -0
- package/lib/components/AppScreen/AppScreen.namespace.cjs +13 -0
- package/lib/components/AppScreen/AppScreen.namespace.d.ts +2 -0
- package/lib/components/AppScreen/AppScreen.namespace.js +1 -0
- package/lib/components/AppScreen/index.cjs +15 -0
- package/lib/components/AppScreen/index.d.ts +3 -0
- package/lib/components/AppScreen/index.js +3 -0
- package/lib/components/index.cjs +26 -0
- package/lib/components/index.d.ts +2 -0
- package/lib/components/index.js +6 -0
- package/lib/hooks/index.cjs +9 -0
- package/lib/hooks/index.d.ts +1 -0
- package/lib/hooks/index.js +1 -0
- package/lib/hooks/useActivityZIndexBase.cjs +14 -0
- package/lib/hooks/useActivityZIndexBase.d.ts +18 -0
- package/lib/hooks/useActivityZIndexBase.js +10 -0
- package/lib/index.cjs +32 -0
- package/lib/index.d.ts +4 -0
- package/lib/index.js +10 -0
- package/lib/plugin.cjs +18 -0
- package/lib/plugin.d.ts +7 -0
- package/lib/plugin.js +14 -0
- package/lib/primitive/AppBar/AppBar.cjs +44 -0
- package/lib/primitive/AppBar/AppBar.d.ts +15 -0
- package/lib/primitive/AppBar/AppBar.js +37 -0
- package/lib/primitive/AppBar/AppBar.namespace.cjs +12 -0
- package/lib/primitive/AppBar/AppBar.namespace.d.ts +1 -0
- package/lib/primitive/AppBar/AppBar.namespace.js +1 -0
- package/lib/primitive/AppBar/index.cjs +14 -0
- package/lib/primitive/AppBar/index.d.ts +2 -0
- package/lib/primitive/AppBar/index.js +3 -0
- package/lib/primitive/AppBar/useAppBar.cjs +39 -0
- package/lib/primitive/AppBar/useAppBar.d.ts +294 -0
- package/lib/primitive/AppBar/useAppBar.js +35 -0
- package/lib/primitive/AppBar/useAppBarContext.cjs +21 -0
- package/lib/primitive/AppBar/useAppBarContext.d.ts +8 -0
- package/lib/primitive/AppBar/useAppBarContext.js +16 -0
- package/lib/primitive/AppScreen/AppScreen.cjs +64 -0
- package/lib/primitive/AppScreen/AppScreen.d.ts +15 -0
- package/lib/primitive/AppScreen/AppScreen.js +57 -0
- package/lib/primitive/AppScreen/AppScreen.namespace.cjs +12 -0
- package/lib/primitive/AppScreen/AppScreen.namespace.d.ts +1 -0
- package/lib/primitive/AppScreen/AppScreen.namespace.js +1 -0
- package/lib/primitive/AppScreen/index.cjs +16 -0
- package/lib/primitive/AppScreen/index.d.ts +3 -0
- package/lib/primitive/AppScreen/index.js +4 -0
- package/lib/primitive/AppScreen/useAppScreen.cjs +66 -0
- package/lib/primitive/AppScreen/useAppScreen.d.ts +1138 -0
- package/lib/primitive/AppScreen/useAppScreen.js +62 -0
- package/lib/primitive/AppScreen/useAppScreenContext.cjs +21 -0
- package/lib/primitive/AppScreen/useAppScreenContext.d.ts +8 -0
- package/lib/primitive/AppScreen/useAppScreenContext.js +16 -0
- package/lib/primitive/GlobalInteraction/GlobalInteraction.cjs +28 -0
- package/lib/primitive/GlobalInteraction/GlobalInteraction.d.ts +5 -0
- package/lib/primitive/GlobalInteraction/GlobalInteraction.js +24 -0
- package/lib/primitive/GlobalInteraction/index.cjs +11 -0
- package/lib/primitive/GlobalInteraction/index.d.ts +2 -0
- package/lib/primitive/GlobalInteraction/index.js +2 -0
- package/lib/primitive/GlobalInteraction/useGlobalInteraction.cjs +136 -0
- package/lib/primitive/GlobalInteraction/useGlobalInteraction.d.ts +54 -0
- package/lib/primitive/GlobalInteraction/useGlobalInteraction.js +132 -0
- package/lib/primitive/GlobalInteraction/useGlobalInteractionContext.cjs +21 -0
- package/lib/primitive/GlobalInteraction/useGlobalInteractionContext.d.ts +8 -0
- package/lib/primitive/GlobalInteraction/useGlobalInteractionContext.js +16 -0
- package/lib/primitive/GlobalInteraction/useSwipeBack.cjs +58 -0
- package/lib/primitive/GlobalInteraction/useSwipeBack.d.ts +8 -0
- package/lib/primitive/GlobalInteraction/useSwipeBack.js +54 -0
- package/lib/primitive/index.cjs +27 -0
- package/lib/primitive/index.d.ts +3 -0
- package/lib/primitive/index.js +9 -0
- package/lib/primitive/private/useElementOffset.cjs +54 -0
- package/lib/primitive/private/useElementOffset.d.ts +4 -0
- package/lib/primitive/private/useElementOffset.js +31 -0
- package/lib/primitive/private/useTopActivity.cjs +34 -0
- package/lib/primitive/private/useTopActivity.d.ts +5 -0
- package/lib/primitive/private/useTopActivity.js +30 -0
- package/lib/utils/createStyleContext.cjs +77 -0
- package/lib/utils/createStyleContext.d.ts +23 -0
- package/lib/utils/createStyleContext.js +73 -0
- package/lib/utils/createWithStateProps.d.ts +10 -0
- package/lib/utils/styled.cjs +25 -0
- package/lib/utils/styled.d.ts +16 -0
- package/lib/utils/styled.js +21 -0
- package/package.json +61 -0
- package/src/components/AppBar/AppBar.namespace.ts +21 -0
- package/src/components/AppBar/AppBar.tsx +146 -0
- package/src/components/AppBar/index.ts +23 -0
- package/src/components/AppScreen/AppScreen.namespace.ts +14 -0
- package/src/components/AppScreen/AppScreen.tsx +83 -0
- package/src/components/AppScreen/index.ts +16 -0
- package/src/components/index.ts +2 -0
- package/src/hooks/index.ts +1 -0
- package/src/hooks/useActivityZIndexBase.ts +26 -0
- package/src/index.ts +6 -0
- package/src/plugin.tsx +27 -0
- package/src/primitive/AppBar/AppBar.namespace.ts +10 -0
- package/src/primitive/AppBar/AppBar.tsx +52 -0
- package/src/primitive/AppBar/index.ts +12 -0
- package/src/primitive/AppBar/useAppBar.tsx +42 -0
- package/src/primitive/AppBar/useAppBarContext.ts +21 -0
- package/src/primitive/AppScreen/AppScreen.namespace.ts +10 -0
- package/src/primitive/AppScreen/AppScreen.tsx +72 -0
- package/src/primitive/AppScreen/index.ts +13 -0
- package/src/primitive/AppScreen/useAppScreen.tsx +69 -0
- package/src/primitive/AppScreen/useAppScreenContext.ts +21 -0
- package/src/primitive/GlobalInteraction/GlobalInteraction.tsx +25 -0
- package/src/primitive/GlobalInteraction/index.ts +6 -0
- package/src/primitive/GlobalInteraction/useGlobalInteraction.ts +188 -0
- package/src/primitive/GlobalInteraction/useGlobalInteractionContext.tsx +21 -0
- package/src/primitive/GlobalInteraction/useSwipeBack.ts +56 -0
- package/src/primitive/index.ts +3 -0
- package/src/primitive/private/useElementOffset.ts +37 -0
- package/src/primitive/private/useTopActivity.ts +33 -0
- package/src/utils/createStyleContext.tsx +128 -0
- package/src/utils/createWithStateProps.tsx +28 -0
- package/src/utils/styled.ts +41 -0
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
import { Slot } from "@radix-ui/react-slot";
|
|
2
|
+
import { appBar, type AppBarVariantProps } from "@seed-design/css/recipes/app-bar";
|
|
3
|
+
import { appBarMain, type AppBarMainVariantProps } from "@seed-design/css/recipes/app-bar-main";
|
|
4
|
+
import { mergeProps } from "@seed-design/dom-utils";
|
|
5
|
+
import { Primitive, type PrimitiveProps } from "@seed-design/react-primitive";
|
|
6
|
+
import clsx from "clsx";
|
|
7
|
+
import { forwardRef } from "react";
|
|
8
|
+
import { AppBar as AppBarPrimitive } from "../../primitive";
|
|
9
|
+
import { useAppBarContext } from "../../primitive/AppBar/useAppBarContext";
|
|
10
|
+
import { createStyleContext } from "../../utils/createStyleContext";
|
|
11
|
+
import { useTopActivity } from "../../primitive/private/useTopActivity";
|
|
12
|
+
import { useActivity } from "@stackflow/react";
|
|
13
|
+
import { useBoxBackgroundProps, type BoxBackgroundProps } from "../../utils/styled";
|
|
14
|
+
|
|
15
|
+
const { PropsProvider, ClassNamesProvider, useProps, withContext, useClassNames } =
|
|
16
|
+
createStyleContext(appBar);
|
|
17
|
+
const {
|
|
18
|
+
PropsProvider: MainPropsProvider,
|
|
19
|
+
withProvider: withMainProvider,
|
|
20
|
+
withContext: withMainContext,
|
|
21
|
+
} = createStyleContext(appBarMain);
|
|
22
|
+
|
|
23
|
+
export const AppBarPropsProvider = PropsProvider;
|
|
24
|
+
|
|
25
|
+
export interface AppBarProps
|
|
26
|
+
extends AppBarVariantProps,
|
|
27
|
+
AppBarPrimitive.RootProps,
|
|
28
|
+
BoxBackgroundProps {}
|
|
29
|
+
|
|
30
|
+
export const AppBarRoot = forwardRef<HTMLDivElement, AppBarProps>((props, ref) => {
|
|
31
|
+
const { style: boxStyle, restProps: propsWithoutBoxProps } = useBoxBackgroundProps(props);
|
|
32
|
+
|
|
33
|
+
const contextProps = useProps();
|
|
34
|
+
const [variantProps, otherProps] = appBar.splitVariantProps({
|
|
35
|
+
...contextProps,
|
|
36
|
+
...propsWithoutBoxProps,
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
const topActivityTransitionStyle = useTopActivity().transitionStyle;
|
|
40
|
+
|
|
41
|
+
const resolvedVariantProps: AppBarVariantProps = {
|
|
42
|
+
// this includes the default transitionStyle decided by theme, from contextProps or props
|
|
43
|
+
...variantProps,
|
|
44
|
+
...(useActivity().isTop === false && {
|
|
45
|
+
transitionStyle: topActivityTransitionStyle as NonNullable<
|
|
46
|
+
AppBarVariantProps["transitionStyle"]
|
|
47
|
+
>,
|
|
48
|
+
}),
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
const classNames = appBar(resolvedVariantProps);
|
|
52
|
+
|
|
53
|
+
return (
|
|
54
|
+
<ClassNamesProvider value={classNames}>
|
|
55
|
+
<MainPropsProvider value={resolvedVariantProps}>
|
|
56
|
+
<AppBarPrimitive.Root
|
|
57
|
+
ref={ref}
|
|
58
|
+
{...mergeProps({ className: classNames.root, style: boxStyle }, otherProps)}
|
|
59
|
+
/>
|
|
60
|
+
</MainPropsProvider>
|
|
61
|
+
</ClassNamesProvider>
|
|
62
|
+
);
|
|
63
|
+
});
|
|
64
|
+
AppBarRoot.displayName = "AppBarRoot";
|
|
65
|
+
|
|
66
|
+
export interface AppBarLeftProps extends AppBarPrimitive.LeftProps {}
|
|
67
|
+
|
|
68
|
+
export const AppBarLeft = withContext<HTMLDivElement, AppBarLeftProps>(
|
|
69
|
+
AppBarPrimitive.Left,
|
|
70
|
+
"left",
|
|
71
|
+
);
|
|
72
|
+
|
|
73
|
+
export interface AppBarRightProps extends AppBarPrimitive.RightProps {}
|
|
74
|
+
|
|
75
|
+
export const AppBarRight = withContext<HTMLDivElement, AppBarRightProps>(
|
|
76
|
+
AppBarPrimitive.Right,
|
|
77
|
+
"right",
|
|
78
|
+
);
|
|
79
|
+
|
|
80
|
+
export interface AppBarMainProps extends AppBarMainVariantProps, AppBarPrimitive.MainProps {}
|
|
81
|
+
|
|
82
|
+
export const AppBarMain = withMainProvider<HTMLDivElement, AppBarMainProps>(
|
|
83
|
+
AppBarPrimitive.Main,
|
|
84
|
+
"root",
|
|
85
|
+
);
|
|
86
|
+
|
|
87
|
+
export interface AppBarTitleProps extends PrimitiveProps, React.HTMLAttributes<HTMLSpanElement> {}
|
|
88
|
+
|
|
89
|
+
export const AppBarTitle = withMainContext<HTMLSpanElement, AppBarTitleProps>(
|
|
90
|
+
Primitive.span,
|
|
91
|
+
"title",
|
|
92
|
+
);
|
|
93
|
+
|
|
94
|
+
export interface AppBarSubtitleProps
|
|
95
|
+
extends PrimitiveProps,
|
|
96
|
+
React.HTMLAttributes<HTMLSpanElement> {}
|
|
97
|
+
|
|
98
|
+
export const AppBarSubtitle = withMainContext<HTMLSpanElement, AppBarSubtitleProps>(
|
|
99
|
+
Primitive.span,
|
|
100
|
+
"subtitle",
|
|
101
|
+
);
|
|
102
|
+
|
|
103
|
+
export interface AppBarIconButtonProps
|
|
104
|
+
extends PrimitiveProps,
|
|
105
|
+
React.ButtonHTMLAttributes<HTMLButtonElement> {}
|
|
106
|
+
|
|
107
|
+
export const AppBarIconButton = forwardRef<HTMLButtonElement, AppBarIconButtonProps>(
|
|
108
|
+
({ children, className, ...otherProps }, ref) => {
|
|
109
|
+
const { stateProps } = useAppBarContext();
|
|
110
|
+
const classNames = useClassNames();
|
|
111
|
+
|
|
112
|
+
return (
|
|
113
|
+
<Primitive.button
|
|
114
|
+
ref={ref}
|
|
115
|
+
type="button"
|
|
116
|
+
className={clsx(classNames.iconButton, className)}
|
|
117
|
+
{...mergeProps(stateProps, otherProps)}
|
|
118
|
+
>
|
|
119
|
+
<Slot className={classNames.icon} {...stateProps}>
|
|
120
|
+
{children}
|
|
121
|
+
</Slot>
|
|
122
|
+
</Primitive.button>
|
|
123
|
+
);
|
|
124
|
+
},
|
|
125
|
+
);
|
|
126
|
+
AppBarIconButton.displayName = "IconButton";
|
|
127
|
+
|
|
128
|
+
export interface AppBarSlotProps extends PrimitiveProps, React.HTMLAttributes<HTMLElement> {}
|
|
129
|
+
|
|
130
|
+
export const AppBarSlot = forwardRef<HTMLElement, AppBarSlotProps>(
|
|
131
|
+
({ children, className, ...otherProps }, ref) => {
|
|
132
|
+
const { stateProps } = useAppBarContext();
|
|
133
|
+
const classNames = useClassNames();
|
|
134
|
+
|
|
135
|
+
return (
|
|
136
|
+
<Slot
|
|
137
|
+
ref={ref}
|
|
138
|
+
className={clsx(classNames.custom, className)}
|
|
139
|
+
{...mergeProps(stateProps, otherProps)}
|
|
140
|
+
>
|
|
141
|
+
{children}
|
|
142
|
+
</Slot>
|
|
143
|
+
);
|
|
144
|
+
},
|
|
145
|
+
);
|
|
146
|
+
AppBarSlot.displayName = "AppBarSlot";
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
export {
|
|
2
|
+
AppBarIconButton,
|
|
3
|
+
AppBarLeft,
|
|
4
|
+
AppBarMain,
|
|
5
|
+
AppBarRight,
|
|
6
|
+
AppBarRoot,
|
|
7
|
+
AppBarSlot,
|
|
8
|
+
AppBarSubtitle,
|
|
9
|
+
AppBarTitle,
|
|
10
|
+
} from "./AppBar";
|
|
11
|
+
|
|
12
|
+
export type {
|
|
13
|
+
AppBarIconButtonProps,
|
|
14
|
+
AppBarLeftProps,
|
|
15
|
+
AppBarMainProps,
|
|
16
|
+
AppBarProps,
|
|
17
|
+
AppBarRightProps,
|
|
18
|
+
AppBarSlotProps,
|
|
19
|
+
AppBarSubtitleProps,
|
|
20
|
+
AppBarTitleProps,
|
|
21
|
+
} from "./AppBar";
|
|
22
|
+
|
|
23
|
+
export * as AppBar from "./AppBar.namespace";
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export {
|
|
2
|
+
AppScreenDim as Dim,
|
|
3
|
+
AppScreenEdge as Edge,
|
|
4
|
+
AppScreenLayer as Layer,
|
|
5
|
+
AppScreenRoot as Root,
|
|
6
|
+
AppScreenPropsProvider as PropsProvider,
|
|
7
|
+
} from "./AppScreen";
|
|
8
|
+
|
|
9
|
+
export type {
|
|
10
|
+
AppScreenDimProps as DimProps,
|
|
11
|
+
AppScreenEdgeProps as EdgeProps,
|
|
12
|
+
AppScreenLayerProps as LayerProps,
|
|
13
|
+
AppScreenRootProps as RootProps,
|
|
14
|
+
} from "./AppScreen";
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import { appScreen, type AppScreenVariantProps } from "@seed-design/css/recipes/app-screen";
|
|
2
|
+
import { mergeProps } from "@seed-design/dom-utils";
|
|
3
|
+
import { forwardRef, useMemo } from "react";
|
|
4
|
+
import { AppScreen as AppScreenPrimitive } from "../../primitive";
|
|
5
|
+
import { createStyleContext } from "../../utils/createStyleContext";
|
|
6
|
+
import { AppBarPropsProvider } from "../AppBar/AppBar";
|
|
7
|
+
import { useTopActivity } from "../../primitive/private/useTopActivity";
|
|
8
|
+
import { useActivity } from "@stackflow/react";
|
|
9
|
+
import { appBar } from "@seed-design/css/recipes/app-bar";
|
|
10
|
+
|
|
11
|
+
const { ClassNamesProvider, PropsProvider, withContext, useProps } = createStyleContext(appScreen);
|
|
12
|
+
|
|
13
|
+
export const AppScreenPropsProvider = PropsProvider;
|
|
14
|
+
|
|
15
|
+
export interface AppScreenRootProps extends AppScreenVariantProps, AppScreenPrimitive.RootProps {
|
|
16
|
+
/**
|
|
17
|
+
* @default "layer"
|
|
18
|
+
*/
|
|
19
|
+
tone?: "layer" | "transparent";
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export const AppScreenRoot = forwardRef<HTMLDivElement, AppScreenRootProps>((props, ref) => {
|
|
23
|
+
const contextProps = useProps();
|
|
24
|
+
const [variantProps, otherProps] = appScreen.splitVariantProps({ ...contextProps, ...props });
|
|
25
|
+
|
|
26
|
+
// TODO: we have to implement conditional default in recipe; this is temporal workaround.
|
|
27
|
+
const transitionStyle: NonNullable<AppScreenVariantProps["transitionStyle"]> =
|
|
28
|
+
variantProps.transitionStyle ??
|
|
29
|
+
(variantProps.theme === "cupertino" ? "slideFromRightIOS" : "fadeFromBottomAndroid");
|
|
30
|
+
|
|
31
|
+
const topActivityTransitionStyle = useTopActivity().transitionStyle;
|
|
32
|
+
|
|
33
|
+
const classNames = appScreen({
|
|
34
|
+
...variantProps,
|
|
35
|
+
transitionStyle: useActivity().isTop
|
|
36
|
+
? transitionStyle
|
|
37
|
+
: (topActivityTransitionStyle as NonNullable<AppScreenVariantProps["transitionStyle"]>),
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
const [appBarVariantProps] = useMemo(
|
|
41
|
+
() => appBar.splitVariantProps(variantProps),
|
|
42
|
+
[variantProps],
|
|
43
|
+
);
|
|
44
|
+
|
|
45
|
+
return (
|
|
46
|
+
<ClassNamesProvider value={classNames}>
|
|
47
|
+
<AppBarPropsProvider
|
|
48
|
+
value={useMemo(
|
|
49
|
+
() => ({ ...appBarVariantProps, transitionStyle }),
|
|
50
|
+
[appBarVariantProps, transitionStyle],
|
|
51
|
+
)}
|
|
52
|
+
>
|
|
53
|
+
<AppScreenPrimitive.Root
|
|
54
|
+
ref={ref}
|
|
55
|
+
data-transition-style={transitionStyle}
|
|
56
|
+
{...mergeProps({ className: classNames.root }, otherProps)}
|
|
57
|
+
/>
|
|
58
|
+
</AppBarPropsProvider>
|
|
59
|
+
</ClassNamesProvider>
|
|
60
|
+
);
|
|
61
|
+
});
|
|
62
|
+
AppScreenRoot.displayName = "AppScreenRoot";
|
|
63
|
+
|
|
64
|
+
export interface AppScreenDimProps extends AppScreenPrimitive.DimProps {}
|
|
65
|
+
|
|
66
|
+
export const AppScreenDim = withContext<HTMLDivElement, AppScreenDimProps>(
|
|
67
|
+
AppScreenPrimitive.Dim,
|
|
68
|
+
"dim",
|
|
69
|
+
);
|
|
70
|
+
|
|
71
|
+
export interface AppScreenEdgeProps extends AppScreenPrimitive.EdgeProps {}
|
|
72
|
+
|
|
73
|
+
export const AppScreenEdge = withContext<HTMLDivElement, AppScreenEdgeProps>(
|
|
74
|
+
AppScreenPrimitive.Edge,
|
|
75
|
+
"edge",
|
|
76
|
+
);
|
|
77
|
+
|
|
78
|
+
export interface AppScreenLayerProps extends AppScreenPrimitive.LayerProps {}
|
|
79
|
+
|
|
80
|
+
export const AppScreenLayer = withContext<HTMLDivElement, AppScreenLayerProps>(
|
|
81
|
+
AppScreenPrimitive.Layer,
|
|
82
|
+
"layer",
|
|
83
|
+
);
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
export {
|
|
2
|
+
AppScreenDim,
|
|
3
|
+
AppScreenEdge,
|
|
4
|
+
AppScreenLayer,
|
|
5
|
+
AppScreenRoot,
|
|
6
|
+
AppScreenPropsProvider,
|
|
7
|
+
} from "./AppScreen";
|
|
8
|
+
|
|
9
|
+
export type {
|
|
10
|
+
AppScreenDimProps,
|
|
11
|
+
AppScreenEdgeProps,
|
|
12
|
+
AppScreenLayerProps,
|
|
13
|
+
AppScreenRootProps,
|
|
14
|
+
} from "./AppScreen";
|
|
15
|
+
|
|
16
|
+
export * as AppScreen from "./AppScreen.namespace";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { useActivityZIndexBase } from "./useActivityZIndexBase";
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { useNullableActivity } from "@stackflow/react-ui-core";
|
|
2
|
+
|
|
3
|
+
interface UseActivityZIndexBaseParams {
|
|
4
|
+
/**
|
|
5
|
+
* Offset from the current activity's position in the stack.
|
|
6
|
+
*
|
|
7
|
+
* - `0` (default): Current activity's z-index base
|
|
8
|
+
* - `1`: Next activity's z-index base (common for overlay components)
|
|
9
|
+
*
|
|
10
|
+
* @default 0
|
|
11
|
+
*/
|
|
12
|
+
activityOffset?: number;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
const Z_INDEX_SPACING = 5;
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Returns the base z-index which is calculated by multiplying the activity's index by 5.
|
|
19
|
+
* This value is used to give proper z-index values to elements of AppScreen (e.g. app-bar, dim, edge, layer). See the stylesheet of AppScreen for more details.
|
|
20
|
+
* This value can be provided to layerIndex of various overlay components (e.g. AlertDialog, BottomSheet, MenuSheet) to ensure correct stacking order.
|
|
21
|
+
*/
|
|
22
|
+
export function useActivityZIndexBase(params?: UseActivityZIndexBaseParams): number {
|
|
23
|
+
const activity = useNullableActivity();
|
|
24
|
+
|
|
25
|
+
return ((activity?.zIndex ?? 0) + (params?.activityOffset ?? 0)) * Z_INDEX_SPACING;
|
|
26
|
+
}
|
package/src/index.ts
ADDED
package/src/plugin.tsx
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import type { StackflowReactPlugin } from "@stackflow/react";
|
|
2
|
+
import { AppScreenPropsProvider } from "./components";
|
|
3
|
+
import { GlobalInteraction } from "./primitive";
|
|
4
|
+
|
|
5
|
+
export interface SeedPluginOptions {
|
|
6
|
+
theme: "android" | "cupertino";
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export const seedPlugin =
|
|
10
|
+
(
|
|
11
|
+
options:
|
|
12
|
+
| SeedPluginOptions
|
|
13
|
+
// biome-ignore lint/suspicious/noExplicitAny: matches upstream @stackflow/react's `initialContext: any`
|
|
14
|
+
| ((args: { initialContext?: any }) => SeedPluginOptions),
|
|
15
|
+
): StackflowReactPlugin =>
|
|
16
|
+
() => ({
|
|
17
|
+
key: "seed-design",
|
|
18
|
+
wrapStack({ stack, initialContext }) {
|
|
19
|
+
const resolved = typeof options === "function" ? options({ initialContext }) : options;
|
|
20
|
+
|
|
21
|
+
return (
|
|
22
|
+
<AppScreenPropsProvider value={resolved}>
|
|
23
|
+
<GlobalInteraction>{stack.render()}</GlobalInteraction>
|
|
24
|
+
</AppScreenPropsProvider>
|
|
25
|
+
);
|
|
26
|
+
},
|
|
27
|
+
});
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export {
|
|
2
|
+
AppBarRoot as Root,
|
|
3
|
+
AppBarMain as Main,
|
|
4
|
+
AppBarLeft as Left,
|
|
5
|
+
AppBarRight as Right,
|
|
6
|
+
type AppBarRootProps as RootProps,
|
|
7
|
+
type AppBarMainProps as MainProps,
|
|
8
|
+
type AppBarLeftProps as LeftProps,
|
|
9
|
+
type AppBarRightProps as RightProps,
|
|
10
|
+
} from "./AppBar";
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { composeRefs } from "@radix-ui/react-compose-refs";
|
|
2
|
+
import { mergeProps } from "@seed-design/dom-utils";
|
|
3
|
+
import { Primitive, type PrimitiveProps } from "@seed-design/react-primitive";
|
|
4
|
+
import { forwardRef } from "react";
|
|
5
|
+
import { useAppBar, type UseAppBarProps } from "./useAppBar";
|
|
6
|
+
import { AppBarProvider, useAppBarContext } from "./useAppBarContext";
|
|
7
|
+
|
|
8
|
+
export interface AppBarRootProps
|
|
9
|
+
extends PrimitiveProps,
|
|
10
|
+
UseAppBarProps,
|
|
11
|
+
React.HTMLAttributes<HTMLDivElement> {}
|
|
12
|
+
|
|
13
|
+
export const AppBarRoot = forwardRef<HTMLDivElement, AppBarRootProps>((props, ref) => {
|
|
14
|
+
const { ...otherProps } = props;
|
|
15
|
+
const api = useAppBar({});
|
|
16
|
+
|
|
17
|
+
return (
|
|
18
|
+
<AppBarProvider value={api}>
|
|
19
|
+
<Primitive.div
|
|
20
|
+
ref={composeRefs(api.refs.root, ref)}
|
|
21
|
+
{...mergeProps(api.rootProps, otherProps)}
|
|
22
|
+
/>
|
|
23
|
+
</AppBarProvider>
|
|
24
|
+
);
|
|
25
|
+
});
|
|
26
|
+
AppBarRoot.displayName = "AppBarRoot";
|
|
27
|
+
|
|
28
|
+
export interface AppBarLeftProps extends PrimitiveProps, React.HTMLAttributes<HTMLDivElement> {}
|
|
29
|
+
|
|
30
|
+
export const AppBarLeft = forwardRef<HTMLDivElement, AppBarLeftProps>((props, ref) => {
|
|
31
|
+
const { refs, stateProps } = useAppBarContext();
|
|
32
|
+
|
|
33
|
+
return <Primitive.div ref={composeRefs(refs.left, ref)} {...mergeProps(stateProps, props)} />;
|
|
34
|
+
});
|
|
35
|
+
AppBarLeft.displayName = "AppBarLeft";
|
|
36
|
+
|
|
37
|
+
export interface AppBarRightProps extends PrimitiveProps, React.HTMLAttributes<HTMLDivElement> {}
|
|
38
|
+
|
|
39
|
+
export const AppBarRight = forwardRef<HTMLDivElement, AppBarRightProps>((props, ref) => {
|
|
40
|
+
const { refs, stateProps } = useAppBarContext();
|
|
41
|
+
|
|
42
|
+
return <Primitive.div ref={composeRefs(refs.right, ref)} {...mergeProps(stateProps, props)} />;
|
|
43
|
+
});
|
|
44
|
+
AppBarRight.displayName = "AppBarRight";
|
|
45
|
+
|
|
46
|
+
export interface AppBarMainProps extends PrimitiveProps, React.HTMLAttributes<HTMLDivElement> {}
|
|
47
|
+
|
|
48
|
+
export const AppBarMain = forwardRef<HTMLDivElement, AppBarMainProps>((props, ref) => {
|
|
49
|
+
const { stateProps } = useAppBarContext();
|
|
50
|
+
|
|
51
|
+
return <Primitive.div ref={ref} {...mergeProps(stateProps, props)} />;
|
|
52
|
+
});
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { elementProps } from "@seed-design/dom-utils";
|
|
2
|
+
import { useMemo, useState } from "react";
|
|
3
|
+
import { useAppScreenContext } from "../AppScreen";
|
|
4
|
+
import { useElementOffset } from "../private/useElementOffset";
|
|
5
|
+
|
|
6
|
+
// biome-ignore lint/suspicious/noEmptyInterface: intentionally empty for future extension
|
|
7
|
+
export interface UseAppBarProps {}
|
|
8
|
+
|
|
9
|
+
export type UseAppBarReturn = ReturnType<typeof useAppBar>;
|
|
10
|
+
|
|
11
|
+
export function useAppBar(_props: UseAppBarProps) {
|
|
12
|
+
const { stateProps } = useAppScreenContext();
|
|
13
|
+
|
|
14
|
+
const [root, rootRef] = useState<HTMLElement | null>(null);
|
|
15
|
+
const [left, leftRef] = useState<HTMLElement | null>(null);
|
|
16
|
+
const [right, rightRef] = useState<HTMLElement | null>(null);
|
|
17
|
+
|
|
18
|
+
const leftOffset = useElementOffset(left);
|
|
19
|
+
const rightOffset = useElementOffset(right);
|
|
20
|
+
const centeredTitlePaddingX = root
|
|
21
|
+
? `${Math.max(leftOffset?.fromLeft ?? 0, rightOffset?.fromRight ?? 0)}px`
|
|
22
|
+
: "initial";
|
|
23
|
+
|
|
24
|
+
return useMemo(
|
|
25
|
+
() => ({
|
|
26
|
+
refs: {
|
|
27
|
+
root: rootRef,
|
|
28
|
+
left: leftRef,
|
|
29
|
+
right: rightRef,
|
|
30
|
+
},
|
|
31
|
+
stateProps,
|
|
32
|
+
rootProps: elementProps({
|
|
33
|
+
"data-part": "appBar",
|
|
34
|
+
...stateProps,
|
|
35
|
+
style: {
|
|
36
|
+
"--centered-title-padding-x": centeredTitlePaddingX,
|
|
37
|
+
} as React.CSSProperties,
|
|
38
|
+
}),
|
|
39
|
+
}),
|
|
40
|
+
[stateProps, centeredTitlePaddingX],
|
|
41
|
+
);
|
|
42
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { createContext, useContext } from "react";
|
|
2
|
+
import type { UseAppBarReturn } from "./useAppBar";
|
|
3
|
+
|
|
4
|
+
export interface UseAppBarContext extends UseAppBarReturn {}
|
|
5
|
+
|
|
6
|
+
const AppBarContext = createContext<UseAppBarContext | null>(null);
|
|
7
|
+
|
|
8
|
+
export const AppBarProvider = AppBarContext.Provider;
|
|
9
|
+
|
|
10
|
+
export function useAppBarContext<T extends boolean | undefined = true>({
|
|
11
|
+
strict = true,
|
|
12
|
+
}: {
|
|
13
|
+
strict?: T;
|
|
14
|
+
} = {}): T extends false ? UseAppBarContext | null : UseAppBarContext {
|
|
15
|
+
const context = useContext(AppBarContext);
|
|
16
|
+
if (!context && strict) {
|
|
17
|
+
throw new Error("useAppBarContext must be used within a AppBar");
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
return context as UseAppBarContext;
|
|
21
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export {
|
|
2
|
+
AppScreenDim as Dim,
|
|
3
|
+
AppScreenEdge as Edge,
|
|
4
|
+
AppScreenLayer as Layer,
|
|
5
|
+
AppScreenRoot as Root,
|
|
6
|
+
type AppScreenDimProps as DimProps,
|
|
7
|
+
type AppScreenEdgeProps as EdgeProps,
|
|
8
|
+
type AppScreenLayerProps as LayerProps,
|
|
9
|
+
type AppScreenRootProps as RootProps,
|
|
10
|
+
} from "./AppScreen";
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import { composeRefs } from "@radix-ui/react-compose-refs";
|
|
2
|
+
import { mergeProps } from "@seed-design/dom-utils";
|
|
3
|
+
import { Primitive, type PrimitiveProps } from "@seed-design/react-primitive";
|
|
4
|
+
import { usePreventTouchDuringTransition } from "@stackflow/react-ui-core";
|
|
5
|
+
import { forwardRef, useRef } from "react";
|
|
6
|
+
import { useAppScreen, type UseAppScreenProps } from "./useAppScreen";
|
|
7
|
+
import { AppScreenProvider, useAppScreenContext } from "./useAppScreenContext";
|
|
8
|
+
|
|
9
|
+
export interface AppScreenRootProps
|
|
10
|
+
extends PrimitiveProps,
|
|
11
|
+
UseAppScreenProps,
|
|
12
|
+
React.HTMLAttributes<HTMLDivElement> {}
|
|
13
|
+
|
|
14
|
+
export const AppScreenRoot = forwardRef<HTMLDivElement, AppScreenRootProps>((props, ref) => {
|
|
15
|
+
const {
|
|
16
|
+
swipeBackDisplacementRatioThreshold,
|
|
17
|
+
swipeBackVelocityThreshold,
|
|
18
|
+
onSwipeBackEnd,
|
|
19
|
+
onSwipeBackMove,
|
|
20
|
+
onSwipeBackStart,
|
|
21
|
+
...otherProps
|
|
22
|
+
} = props;
|
|
23
|
+
const innerRef = useRef<HTMLDivElement>(null);
|
|
24
|
+
const api = useAppScreen({
|
|
25
|
+
swipeBackDisplacementRatioThreshold,
|
|
26
|
+
swipeBackVelocityThreshold,
|
|
27
|
+
onSwipeBackEnd,
|
|
28
|
+
onSwipeBackMove,
|
|
29
|
+
onSwipeBackStart,
|
|
30
|
+
});
|
|
31
|
+
usePreventTouchDuringTransition({
|
|
32
|
+
ref: innerRef as React.RefObject<HTMLDivElement>,
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
return (
|
|
36
|
+
<AppScreenProvider value={api}>
|
|
37
|
+
<Primitive.div
|
|
38
|
+
ref={composeRefs(innerRef, ref)}
|
|
39
|
+
data-stackflow-component-name="AppScreen"
|
|
40
|
+
{...mergeProps(api.activityProps, otherProps)}
|
|
41
|
+
/>
|
|
42
|
+
</AppScreenProvider>
|
|
43
|
+
);
|
|
44
|
+
});
|
|
45
|
+
AppScreenRoot.displayName = "AppScreenRoot";
|
|
46
|
+
|
|
47
|
+
export interface AppScreenDimProps extends PrimitiveProps, React.HTMLAttributes<HTMLDivElement> {}
|
|
48
|
+
|
|
49
|
+
export const AppScreenDim = forwardRef<HTMLDivElement, AppScreenDimProps>((props, ref) => {
|
|
50
|
+
const { dimProps } = useAppScreenContext();
|
|
51
|
+
|
|
52
|
+
return <Primitive.div ref={ref} {...mergeProps(dimProps, props)} />;
|
|
53
|
+
});
|
|
54
|
+
AppScreenDim.displayName = "AppScreenDim";
|
|
55
|
+
|
|
56
|
+
export interface AppScreenEdgeProps extends PrimitiveProps, React.HTMLAttributes<HTMLDivElement> {}
|
|
57
|
+
|
|
58
|
+
export const AppScreenEdge = forwardRef<HTMLDivElement, AppScreenEdgeProps>((props, ref) => {
|
|
59
|
+
const { edgeProps } = useAppScreenContext();
|
|
60
|
+
|
|
61
|
+
return <Primitive.div ref={ref} {...mergeProps(edgeProps, props)} />;
|
|
62
|
+
});
|
|
63
|
+
AppScreenEdge.displayName = "AppScreenEdge";
|
|
64
|
+
|
|
65
|
+
export interface AppScreenLayerProps extends PrimitiveProps, React.HTMLAttributes<HTMLDivElement> {}
|
|
66
|
+
|
|
67
|
+
export const AppScreenLayer = forwardRef<HTMLDivElement, AppScreenLayerProps>((props, ref) => {
|
|
68
|
+
const { layerProps } = useAppScreenContext();
|
|
69
|
+
|
|
70
|
+
return <Primitive.div ref={ref} {...mergeProps(layerProps, props)} />;
|
|
71
|
+
});
|
|
72
|
+
AppScreenLayer.displayName = "AppScreenLayer";
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export {
|
|
2
|
+
AppScreenDim,
|
|
3
|
+
AppScreenEdge,
|
|
4
|
+
AppScreenLayer,
|
|
5
|
+
AppScreenRoot,
|
|
6
|
+
type AppScreenDimProps,
|
|
7
|
+
type AppScreenEdgeProps,
|
|
8
|
+
type AppScreenLayerProps,
|
|
9
|
+
type AppScreenRootProps,
|
|
10
|
+
} from "./AppScreen";
|
|
11
|
+
|
|
12
|
+
export * as AppScreen from "./AppScreen.namespace";
|
|
13
|
+
export { useAppScreenContext, type UseAppScreenContext } from "./useAppScreenContext";
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { dataAttr, elementProps } from "@seed-design/dom-utils";
|
|
2
|
+
import { useNullableActivity } from "@stackflow/react-ui-core";
|
|
3
|
+
import { useMemo } from "react";
|
|
4
|
+
import { type UseSwipeBackProps, useSwipeBack } from "../GlobalInteraction/useSwipeBack";
|
|
5
|
+
import { useActivityZIndexBase } from "../../hooks";
|
|
6
|
+
|
|
7
|
+
export interface UseAppScreenProps extends UseSwipeBackProps {}
|
|
8
|
+
|
|
9
|
+
export type UseAppScreenReturn = ReturnType<typeof useAppScreen>;
|
|
10
|
+
|
|
11
|
+
export function useAppScreen(props: UseAppScreenProps) {
|
|
12
|
+
const activity = useNullableActivity();
|
|
13
|
+
|
|
14
|
+
const transitionState = activity?.transitionState ?? "enter-done";
|
|
15
|
+
|
|
16
|
+
const { activityProps, layerProps, edgeProps } = useSwipeBack(props);
|
|
17
|
+
|
|
18
|
+
const zIndexBase = useActivityZIndexBase();
|
|
19
|
+
const zIndexStyle = useMemo(
|
|
20
|
+
() =>
|
|
21
|
+
({
|
|
22
|
+
"--z-index-base": zIndexBase.toString(),
|
|
23
|
+
}) as React.CSSProperties,
|
|
24
|
+
[zIndexBase],
|
|
25
|
+
);
|
|
26
|
+
|
|
27
|
+
const stateProps = useMemo(
|
|
28
|
+
() => ({
|
|
29
|
+
"data-activity-is-top": dataAttr(activity?.isTop),
|
|
30
|
+
"data-activity-is-active": dataAttr(activity?.isActive),
|
|
31
|
+
"data-transition-state": transitionState,
|
|
32
|
+
}),
|
|
33
|
+
[transitionState, activity?.isActive, activity?.isTop],
|
|
34
|
+
) as React.HTMLAttributes<HTMLElement>;
|
|
35
|
+
|
|
36
|
+
return useMemo(
|
|
37
|
+
() => ({
|
|
38
|
+
activity,
|
|
39
|
+
stateProps,
|
|
40
|
+
activityProps: elementProps({
|
|
41
|
+
"data-part": "activity",
|
|
42
|
+
"data-activity-type": "full-screen",
|
|
43
|
+
...activityProps,
|
|
44
|
+
...stateProps,
|
|
45
|
+
"data-activity-id": activity?.id,
|
|
46
|
+
style: zIndexStyle,
|
|
47
|
+
// FIXME: @stackflow/react should prevent activity.id hydration mismatch; this is temporal fix.
|
|
48
|
+
suppressHydrationWarning: true,
|
|
49
|
+
}),
|
|
50
|
+
dimProps: elementProps({
|
|
51
|
+
"data-part": "dim",
|
|
52
|
+
...stateProps,
|
|
53
|
+
}),
|
|
54
|
+
layerProps: elementProps({
|
|
55
|
+
"data-part": "layer",
|
|
56
|
+
...stateProps,
|
|
57
|
+
...layerProps,
|
|
58
|
+
}),
|
|
59
|
+
edgeProps: elementProps({
|
|
60
|
+
"data-part": "edge",
|
|
61
|
+
"aria-hidden": true,
|
|
62
|
+
tabIndex: -1,
|
|
63
|
+
...edgeProps,
|
|
64
|
+
...stateProps,
|
|
65
|
+
}),
|
|
66
|
+
}),
|
|
67
|
+
[activity, zIndexStyle, stateProps, activityProps, edgeProps, layerProps],
|
|
68
|
+
);
|
|
69
|
+
}
|