@seed-design/stackflow 1.1.24 → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/components/AppBar/AppBar.d.ts +0 -4
- package/lib/primitive/AppScreen/AppScreen.cjs +17 -6
- package/lib/primitive/AppScreen/AppScreen.js +18 -7
- package/lib/primitive/AppScreen/useAppScreen.cjs +2 -0
- package/lib/primitive/AppScreen/useAppScreen.d.ts +2 -1
- package/lib/primitive/AppScreen/useAppScreen.js +3 -1
- package/package.json +6 -5
- package/src/components/AppBar/AppBar.tsx +1 -6
- package/src/primitive/AppScreen/AppScreen.tsx +31 -8
- package/src/primitive/AppScreen/useAppScreen.tsx +3 -1
|
@@ -9,10 +9,6 @@ export declare const AppBarPropsProvider: ({ children, value }: {
|
|
|
9
9
|
value: Partial< AppBarVariant>;
|
|
10
10
|
}) => import("react/jsx-runtime").JSX.Element;
|
|
11
11
|
export interface AppBarProps extends AppBarVariantProps, AppBarPrimitive.RootProps, BoxBackgroundProps {
|
|
12
|
-
/**
|
|
13
|
-
* @deprecated SEED React 1.3에서 제거될 예정인 옵션입니다. 옵션 제거 이후에는 AppBar 하단 구분선이 표시되지 않습니다.
|
|
14
|
-
*/
|
|
15
|
-
divider?: AppBarVariantProps["divider"];
|
|
16
12
|
}
|
|
17
13
|
export declare const AppBarRoot: ForwardRefExoticComponent<AppBarProps & RefAttributes<HTMLDivElement>>;
|
|
18
14
|
export interface AppBarLeftProps extends AppBarPrimitive.LeftProps {
|
|
@@ -6,6 +6,7 @@ let _seed_design_dom_utils = require("@seed-design/dom-utils");
|
|
|
6
6
|
let _seed_design_react_primitive = require("@seed-design/react-primitive");
|
|
7
7
|
let react = require("react");
|
|
8
8
|
let _radix_ui_react_compose_refs = require("@radix-ui/react-compose-refs");
|
|
9
|
+
let _radix_ui_react_focus_scope = require("@radix-ui/react-focus-scope");
|
|
9
10
|
let _stackflow_react_ui_core = require("@stackflow/react-ui-core");
|
|
10
11
|
let react_jsx_runtime = require("react/jsx-runtime");
|
|
11
12
|
//#region src/primitive/AppScreen/AppScreen.tsx
|
|
@@ -20,12 +21,21 @@ var AppScreenRoot = (0, react.forwardRef)((props, ref) => {
|
|
|
20
21
|
onSwipeBackStart
|
|
21
22
|
});
|
|
22
23
|
(0, _stackflow_react_ui_core.usePreventTouchDuringTransition)({ ref: innerRef });
|
|
24
|
+
(0, react.useEffect)(() => {
|
|
25
|
+
if (api.activity?.transitionState === "enter-done") api.layerRef.current?.focus();
|
|
26
|
+
}, [api.activity?.transitionState, api.layerRef]);
|
|
23
27
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_useAppScreenContext.AppScreenProvider, {
|
|
24
28
|
value: api,
|
|
25
|
-
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_radix_ui_react_focus_scope.FocusScope, {
|
|
30
|
+
asChild: true,
|
|
31
|
+
trapped: true,
|
|
32
|
+
loop: true,
|
|
33
|
+
onMountAutoFocus: (e) => e.preventDefault(),
|
|
34
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_seed_design_react_primitive.Primitive.div, {
|
|
35
|
+
ref: (0, _radix_ui_react_compose_refs.composeRefs)(innerRef, ref),
|
|
36
|
+
"data-stackflow-component-name": "AppScreen",
|
|
37
|
+
...(0, _seed_design_dom_utils.mergeProps)(api.activityProps, otherProps)
|
|
38
|
+
})
|
|
29
39
|
})
|
|
30
40
|
});
|
|
31
41
|
});
|
|
@@ -47,9 +57,10 @@ var AppScreenEdge = (0, react.forwardRef)((props, ref) => {
|
|
|
47
57
|
});
|
|
48
58
|
AppScreenEdge.displayName = "AppScreenEdge";
|
|
49
59
|
var AppScreenLayer = (0, react.forwardRef)((props, ref) => {
|
|
50
|
-
const { layerProps } = require_useAppScreenContext.useAppScreenContext();
|
|
60
|
+
const { layerProps, layerRef } = require_useAppScreenContext.useAppScreenContext();
|
|
51
61
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_seed_design_react_primitive.Primitive.div, {
|
|
52
|
-
ref,
|
|
62
|
+
ref: (0, _radix_ui_react_compose_refs.composeRefs)(ref, layerRef),
|
|
63
|
+
tabIndex: -1,
|
|
53
64
|
...(0, _seed_design_dom_utils.mergeProps)(layerProps, props)
|
|
54
65
|
});
|
|
55
66
|
});
|
|
@@ -3,8 +3,9 @@ import { useAppScreen } from "./useAppScreen.js";
|
|
|
3
3
|
import { AppScreenProvider, useAppScreenContext } from "./useAppScreenContext.js";
|
|
4
4
|
import { mergeProps } from "@seed-design/dom-utils";
|
|
5
5
|
import { Primitive } from "@seed-design/react-primitive";
|
|
6
|
-
import { forwardRef, useRef } from "react";
|
|
6
|
+
import { forwardRef, useEffect, useRef } from "react";
|
|
7
7
|
import { composeRefs } from "@radix-ui/react-compose-refs";
|
|
8
|
+
import { FocusScope } from "@radix-ui/react-focus-scope";
|
|
8
9
|
import { usePreventTouchDuringTransition } from "@stackflow/react-ui-core";
|
|
9
10
|
import { jsx } from "react/jsx-runtime";
|
|
10
11
|
//#region src/primitive/AppScreen/AppScreen.tsx
|
|
@@ -19,12 +20,21 @@ var AppScreenRoot = forwardRef((props, ref) => {
|
|
|
19
20
|
onSwipeBackStart
|
|
20
21
|
});
|
|
21
22
|
usePreventTouchDuringTransition({ ref: innerRef });
|
|
23
|
+
useEffect(() => {
|
|
24
|
+
if (api.activity?.transitionState === "enter-done") api.layerRef.current?.focus();
|
|
25
|
+
}, [api.activity?.transitionState, api.layerRef]);
|
|
22
26
|
return /* @__PURE__ */ jsx(AppScreenProvider, {
|
|
23
27
|
value: api,
|
|
24
|
-
children: /* @__PURE__ */ jsx(
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
+
children: /* @__PURE__ */ jsx(FocusScope, {
|
|
29
|
+
asChild: true,
|
|
30
|
+
trapped: true,
|
|
31
|
+
loop: true,
|
|
32
|
+
onMountAutoFocus: (e) => e.preventDefault(),
|
|
33
|
+
children: /* @__PURE__ */ jsx(Primitive.div, {
|
|
34
|
+
ref: composeRefs(innerRef, ref),
|
|
35
|
+
"data-stackflow-component-name": "AppScreen",
|
|
36
|
+
...mergeProps(api.activityProps, otherProps)
|
|
37
|
+
})
|
|
28
38
|
})
|
|
29
39
|
});
|
|
30
40
|
});
|
|
@@ -46,9 +56,10 @@ var AppScreenEdge = forwardRef((props, ref) => {
|
|
|
46
56
|
});
|
|
47
57
|
AppScreenEdge.displayName = "AppScreenEdge";
|
|
48
58
|
var AppScreenLayer = forwardRef((props, ref) => {
|
|
49
|
-
const { layerProps } = useAppScreenContext();
|
|
59
|
+
const { layerProps, layerRef } = useAppScreenContext();
|
|
50
60
|
return /* @__PURE__ */ jsx(Primitive.div, {
|
|
51
|
-
ref,
|
|
61
|
+
ref: composeRefs(ref, layerRef),
|
|
62
|
+
tabIndex: -1,
|
|
52
63
|
...mergeProps(layerProps, props)
|
|
53
64
|
});
|
|
54
65
|
});
|
|
@@ -9,6 +9,7 @@ let _stackflow_react_ui_core = require("@stackflow/react-ui-core");
|
|
|
9
9
|
//#region src/primitive/AppScreen/useAppScreen.tsx
|
|
10
10
|
function useAppScreen(props) {
|
|
11
11
|
const activity = (0, _stackflow_react_ui_core.useNullableActivity)();
|
|
12
|
+
const layerRef = (0, react.useRef)(null);
|
|
12
13
|
const transitionState = activity?.transitionState ?? "enter-done";
|
|
13
14
|
const { activityProps, layerProps, edgeProps } = require_useSwipeBack.useSwipeBack(props);
|
|
14
15
|
const zIndexBase = require_useActivityZIndexBase.useActivityZIndexBase();
|
|
@@ -24,6 +25,7 @@ function useAppScreen(props) {
|
|
|
24
25
|
]);
|
|
25
26
|
return (0, react.useMemo)(() => ({
|
|
26
27
|
activity,
|
|
28
|
+
layerRef,
|
|
27
29
|
stateProps,
|
|
28
30
|
activityProps: (0, _seed_design_dom_utils.elementProps)({
|
|
29
31
|
"data-part": require_anatomy.appScreenAnatomy.activity,
|
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
import { UseSwipeBackProps } from '../GlobalInteraction/useSwipeBack';
|
|
2
2
|
import { Activity } from '@stackflow/core';
|
|
3
|
-
import { HTMLAttributes, CSSProperties, AriaRole, ReactNode, ClipboardEventHandler, CompositionEventHandler, FocusEventHandler, FormEventHandler, InputEventHandler, ReactEventHandler, KeyboardEventHandler, MouseEventHandler, DragEventHandler, TouchEventHandler, PointerEventHandler, UIEventHandler, WheelEventHandler, AnimationEventHandler, ToggleEventHandler, TransitionEventHandler } from 'react';
|
|
3
|
+
import { RefObject, HTMLAttributes, CSSProperties, AriaRole, ReactNode, ClipboardEventHandler, CompositionEventHandler, FocusEventHandler, FormEventHandler, InputEventHandler, ReactEventHandler, KeyboardEventHandler, MouseEventHandler, DragEventHandler, TouchEventHandler, PointerEventHandler, UIEventHandler, WheelEventHandler, AnimationEventHandler, ToggleEventHandler, TransitionEventHandler } from 'react';
|
|
4
4
|
export interface UseAppScreenProps extends UseSwipeBackProps {
|
|
5
5
|
}
|
|
6
6
|
export type UseAppScreenReturn = ReturnType<typeof useAppScreen>;
|
|
7
7
|
export declare function useAppScreen(props: UseAppScreenProps): {
|
|
8
8
|
activity: Activity | null;
|
|
9
|
+
layerRef: RefObject<HTMLDivElement | null>;
|
|
9
10
|
stateProps: HTMLAttributes<HTMLElement>;
|
|
10
11
|
activityProps: {
|
|
11
12
|
slot?: string | undefined | undefined;
|
|
@@ -3,11 +3,12 @@ import { useSwipeBack } from "../GlobalInteraction/useSwipeBack.js";
|
|
|
3
3
|
import { useActivityZIndexBase } from "../../hooks/useActivityZIndexBase.js";
|
|
4
4
|
import { appScreenAnatomy } from "./anatomy.js";
|
|
5
5
|
import { dataAttr, elementProps } from "@seed-design/dom-utils";
|
|
6
|
-
import { useMemo } from "react";
|
|
6
|
+
import { useMemo, useRef } from "react";
|
|
7
7
|
import { useNullableActivity } from "@stackflow/react-ui-core";
|
|
8
8
|
//#region src/primitive/AppScreen/useAppScreen.tsx
|
|
9
9
|
function useAppScreen(props) {
|
|
10
10
|
const activity = useNullableActivity();
|
|
11
|
+
const layerRef = useRef(null);
|
|
11
12
|
const transitionState = activity?.transitionState ?? "enter-done";
|
|
12
13
|
const { activityProps, layerProps, edgeProps } = useSwipeBack(props);
|
|
13
14
|
const zIndexBase = useActivityZIndexBase();
|
|
@@ -23,6 +24,7 @@ function useAppScreen(props) {
|
|
|
23
24
|
]);
|
|
24
25
|
return useMemo(() => ({
|
|
25
26
|
activity,
|
|
27
|
+
layerRef,
|
|
26
28
|
stateProps,
|
|
27
29
|
activityProps: elementProps({
|
|
28
30
|
"data-part": appScreenAnatomy.activity,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@seed-design/stackflow",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "2.0.0",
|
|
4
4
|
"repository": {
|
|
5
5
|
"type": "git",
|
|
6
6
|
"url": "git+https://github.com/daangn/seed-design.git",
|
|
@@ -28,15 +28,16 @@
|
|
|
28
28
|
},
|
|
29
29
|
"dependencies": {
|
|
30
30
|
"@radix-ui/react-compose-refs": "^1.1.2",
|
|
31
|
+
"@radix-ui/react-focus-scope": "^1.1.4",
|
|
31
32
|
"@radix-ui/react-slot": "^1.2.3",
|
|
32
33
|
"@radix-ui/react-use-callback-ref": "^1.1.1",
|
|
33
|
-
"@seed-design/dom-utils": "
|
|
34
|
-
"@seed-design/react-primitive": "
|
|
34
|
+
"@seed-design/dom-utils": "^2.0.0",
|
|
35
|
+
"@seed-design/react-primitive": "^2.0.0",
|
|
35
36
|
"@stackflow/react-ui-core": "^1.3.3",
|
|
36
37
|
"clsx": "^2.1.1"
|
|
37
38
|
},
|
|
38
39
|
"devDependencies": {
|
|
39
|
-
"@seed-design/css": "
|
|
40
|
+
"@seed-design/css": "2.0.0",
|
|
40
41
|
"@stackflow/core": "^1.2.0",
|
|
41
42
|
"@stackflow/react": "^1.5.1",
|
|
42
43
|
"@types/react": "^19.2.2",
|
|
@@ -49,7 +50,7 @@
|
|
|
49
50
|
"vite-plugin-dts": "^5.0.0"
|
|
50
51
|
},
|
|
51
52
|
"peerDependencies": {
|
|
52
|
-
"@seed-design/css": "
|
|
53
|
+
"@seed-design/css": "^2.0.0",
|
|
53
54
|
"@stackflow/core": ">=1.1.0",
|
|
54
55
|
"@stackflow/react": ">=1.4.1",
|
|
55
56
|
"react": ">=18.0.0",
|
|
@@ -26,12 +26,7 @@ export const AppBarPropsProvider = PropsProvider;
|
|
|
26
26
|
export interface AppBarProps
|
|
27
27
|
extends AppBarVariantProps,
|
|
28
28
|
AppBarPrimitive.RootProps,
|
|
29
|
-
BoxBackgroundProps {
|
|
30
|
-
/**
|
|
31
|
-
* @deprecated SEED React 1.3에서 제거될 예정인 옵션입니다. 옵션 제거 이후에는 AppBar 하단 구분선이 표시되지 않습니다.
|
|
32
|
-
*/
|
|
33
|
-
divider?: AppBarVariantProps["divider"];
|
|
34
|
-
}
|
|
29
|
+
BoxBackgroundProps {}
|
|
35
30
|
|
|
36
31
|
export const AppBarRoot = forwardRef<HTMLDivElement, AppBarProps>((props, ref) => {
|
|
37
32
|
const { style: boxStyle, restProps: propsWithoutBoxProps } = useBoxBackgroundProps(props);
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import { composeRefs } from "@radix-ui/react-compose-refs";
|
|
2
|
+
import { FocusScope } from "@radix-ui/react-focus-scope";
|
|
2
3
|
import { mergeProps } from "@seed-design/dom-utils";
|
|
3
4
|
import { Primitive, type PrimitiveProps } from "@seed-design/react-primitive";
|
|
4
5
|
import { usePreventTouchDuringTransition } from "@stackflow/react-ui-core";
|
|
5
|
-
import { forwardRef, useRef } from "react";
|
|
6
|
+
import { forwardRef, useEffect, useRef } from "react";
|
|
6
7
|
import { useAppScreen, type UseAppScreenProps } from "./useAppScreen";
|
|
7
8
|
import { AppScreenProvider, useAppScreenContext } from "./useAppScreenContext";
|
|
8
9
|
|
|
@@ -32,13 +33,29 @@ export const AppScreenRoot = forwardRef<HTMLDivElement, AppScreenRootProps>((pro
|
|
|
32
33
|
ref: innerRef as React.RefObject<HTMLDivElement>,
|
|
33
34
|
});
|
|
34
35
|
|
|
36
|
+
// Focus the layer once after the enter animation completes.
|
|
37
|
+
// onMountAutoFocus fires during enter-active and interrupts the CSS animation, so we
|
|
38
|
+
// defer until transitionState reaches "enter-done". This only happens once per activity
|
|
39
|
+
// lifecycle — subsequent isTop changes (e.g. upper activity pop) don't change
|
|
40
|
+
// transitionState, so the effect won't re-fire.
|
|
41
|
+
useEffect(() => {
|
|
42
|
+
if (api.activity?.transitionState === "enter-done") {
|
|
43
|
+
api.layerRef.current?.focus();
|
|
44
|
+
}
|
|
45
|
+
}, [api.activity?.transitionState, api.layerRef]);
|
|
46
|
+
|
|
35
47
|
return (
|
|
36
48
|
<AppScreenProvider value={api}>
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
49
|
+
{/* onMountAutoFocus is prevented because it fires during enter-active and
|
|
50
|
+
interrupts the CSS animation. Focus is handled by the useEffect above instead,
|
|
51
|
+
which defers until transitionState reaches "enter-done". */}
|
|
52
|
+
<FocusScope asChild trapped loop onMountAutoFocus={(e) => e.preventDefault()}>
|
|
53
|
+
<Primitive.div
|
|
54
|
+
ref={composeRefs(innerRef, ref)}
|
|
55
|
+
data-stackflow-component-name="AppScreen"
|
|
56
|
+
{...mergeProps(api.activityProps, otherProps)}
|
|
57
|
+
/>
|
|
58
|
+
</FocusScope>
|
|
42
59
|
</AppScreenProvider>
|
|
43
60
|
);
|
|
44
61
|
});
|
|
@@ -65,8 +82,14 @@ AppScreenEdge.displayName = "AppScreenEdge";
|
|
|
65
82
|
export interface AppScreenLayerProps extends PrimitiveProps, React.HTMLAttributes<HTMLDivElement> {}
|
|
66
83
|
|
|
67
84
|
export const AppScreenLayer = forwardRef<HTMLDivElement, AppScreenLayerProps>((props, ref) => {
|
|
68
|
-
const { layerProps } = useAppScreenContext();
|
|
85
|
+
const { layerProps, layerRef } = useAppScreenContext();
|
|
69
86
|
|
|
70
|
-
return
|
|
87
|
+
return (
|
|
88
|
+
<Primitive.div
|
|
89
|
+
ref={composeRefs(ref, layerRef)}
|
|
90
|
+
tabIndex={-1}
|
|
91
|
+
{...mergeProps(layerProps, props)}
|
|
92
|
+
/>
|
|
93
|
+
);
|
|
71
94
|
});
|
|
72
95
|
AppScreenLayer.displayName = "AppScreenLayer";
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { dataAttr, elementProps } from "@seed-design/dom-utils";
|
|
2
2
|
import { useNullableActivity } from "@stackflow/react-ui-core";
|
|
3
|
-
import { useMemo } from "react";
|
|
3
|
+
import { useMemo, useRef } from "react";
|
|
4
4
|
import { type UseSwipeBackProps, useSwipeBack } from "../GlobalInteraction/useSwipeBack";
|
|
5
5
|
import { useActivityZIndexBase } from "../../hooks";
|
|
6
6
|
import { appScreenAnatomy } from "./anatomy";
|
|
@@ -11,6 +11,7 @@ export type UseAppScreenReturn = ReturnType<typeof useAppScreen>;
|
|
|
11
11
|
|
|
12
12
|
export function useAppScreen(props: UseAppScreenProps) {
|
|
13
13
|
const activity = useNullableActivity();
|
|
14
|
+
const layerRef = useRef<HTMLDivElement>(null);
|
|
14
15
|
|
|
15
16
|
const transitionState = activity?.transitionState ?? "enter-done";
|
|
16
17
|
|
|
@@ -37,6 +38,7 @@ export function useAppScreen(props: UseAppScreenProps) {
|
|
|
37
38
|
return useMemo(
|
|
38
39
|
() => ({
|
|
39
40
|
activity,
|
|
41
|
+
layerRef,
|
|
40
42
|
stateProps,
|
|
41
43
|
activityProps: elementProps({
|
|
42
44
|
"data-part": appScreenAnatomy.activity,
|