@flemo/react 1.12.8 → 2.1.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/README.md +73 -9
- package/dist/Router.d.ts +3 -2
- package/dist/index.d.ts +4 -2
- package/dist/index.mjs +537 -394
- package/dist/navigate/useNavigate.d.ts +0 -1
- package/dist/screen/Layer.d.ts +40 -0
- package/dist/screen/LayerContext.d.ts +77 -0
- package/dist/screen/Morph.d.ts +14 -0
- package/dist/screen/MorphLayer/MorphLayer.d.ts +6 -0
- package/dist/screen/MorphLayer/index.d.ts +1 -0
- package/dist/screen/Screen.d.ts +6 -0
- package/dist/screen/ScreenFreeze.d.ts +13 -1
- package/dist/screen/ScreenMotion.d.ts +1 -1
- package/dist/screen/__tests__/Layer.test.d.ts +1 -0
- package/dist/screen/__tests__/Morph.test.d.ts +1 -0
- package/dist/screen/__tests__/ScreenFreeze.portal.test.d.ts +1 -0
- package/dist/screen/__tests__/ScreenMotion.swipeBack.test.d.ts +1 -0
- package/dist/transition/styles.d.ts +2 -2
- package/package.json +8 -8
|
@@ -9,7 +9,6 @@ export interface UseNavigateOptions {
|
|
|
9
9
|
router?: RouterTarget;
|
|
10
10
|
}
|
|
11
11
|
type RouteOptions = DistanceOptions & UseNavigateOptions & {
|
|
12
|
-
layoutId?: string | number;
|
|
13
12
|
transitionName?: TransitionName;
|
|
14
13
|
};
|
|
15
14
|
type PopRouteOptions = DistanceOptions & UseNavigateOptions & {
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { PropsWithChildren } from 'react';
|
|
2
|
+
export type LayerProps = PropsWithChildren;
|
|
3
|
+
/**
|
|
4
|
+
* Render an overlay beside the screen instead of inside it, so it can cover
|
|
5
|
+
* the shared bars.
|
|
6
|
+
*
|
|
7
|
+
* A screen that is moving carries a transform, and a transform is both a
|
|
8
|
+
* containing block for `position: fixed` descendants and a stacking context
|
|
9
|
+
* around all of them. The shared bars live outside the screen, as siblings. So
|
|
10
|
+
* a sheet written inside the screen is ONE atom with the screen's content as
|
|
11
|
+
* far as the bars are concerned, and a stacking context cannot be interleaved
|
|
12
|
+
* with an element outside it: "content under the bar, sheet over the bar" is
|
|
13
|
+
* not expressible from in there, at any z-index.
|
|
14
|
+
*
|
|
15
|
+
* ```tsx
|
|
16
|
+
* <Screen sharedBottomBar={<TabBar />}>
|
|
17
|
+
* <Content />
|
|
18
|
+
* <Layer>
|
|
19
|
+
* <BottomSheet open={open} />
|
|
20
|
+
* </Layer>
|
|
21
|
+
* </Screen>
|
|
22
|
+
* ```
|
|
23
|
+
*
|
|
24
|
+
* What leaves the screen is the PAINT ORDER, and only that. The slot keeps its
|
|
25
|
+
* owner's stack position, its status and transition (so it moves with the
|
|
26
|
+
* screen and leaves with it), its animation hold, and its paint-hidden state.
|
|
27
|
+
* It is rendered from inside the screen's own React subtree, so React freezes
|
|
28
|
+
* it with the screen and unmounts it with the screen without being asked.
|
|
29
|
+
*
|
|
30
|
+
* At rest none of this is needed: a screen at rest carries no transform, so a
|
|
31
|
+
* consumer's `position: fixed` overlay already resolves against the viewport
|
|
32
|
+
* and already outranks the bars with a z-index of its own. `<Layer>` is for
|
|
33
|
+
* the overlay that has to survive the screen MOVING under it, and for the one
|
|
34
|
+
* that has to clear chrome an ancestor screen declared.
|
|
35
|
+
*
|
|
36
|
+
* Children keep whatever positioning they had. On the server, and for the
|
|
37
|
+
* first render before the host mounts, this renders nothing.
|
|
38
|
+
*/
|
|
39
|
+
declare function Layer({ children }: LayerProps): import('react').ReactPortal | null;
|
|
40
|
+
export default Layer;
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The element a `<Layer>` portals into. Null before the outermost screen
|
|
3
|
+
* mounts and on the server, where no host element exists yet — a `<Layer>`
|
|
4
|
+
* renders nothing until it has a target.
|
|
5
|
+
*/
|
|
6
|
+
declare const LayerHostContext: import('react').Context<HTMLElement | null>;
|
|
7
|
+
export declare function useLayerHost(): HTMLElement | null;
|
|
8
|
+
/** Everything a slot needs to keep being its screen while sitting outside it. */
|
|
9
|
+
export interface LayerOwner {
|
|
10
|
+
/**
|
|
11
|
+
* The owning screen's stack position. Two screens' overlays then order the
|
|
12
|
+
* way their screens do, rather than by whichever portal mounted first.
|
|
13
|
+
*/
|
|
14
|
+
zIndex: number;
|
|
15
|
+
/**
|
|
16
|
+
* The owner's paint state. `visibility: hidden` on the screen container is
|
|
17
|
+
* plain CSS and stops at that container's own descendants, so a slot in
|
|
18
|
+
* another box has to be told. Without it a covered screen's overlay is the
|
|
19
|
+
* one thing still painting — for the whole debounce window before the freeze
|
|
20
|
+
* catches up (see ScreenFreeze.portal.test.tsx).
|
|
21
|
+
*/
|
|
22
|
+
paintHidden: boolean;
|
|
23
|
+
/** The transition, status and active flags the compiled slot rule selects on. */
|
|
24
|
+
transitionName: string;
|
|
25
|
+
status: string;
|
|
26
|
+
isActive: boolean;
|
|
27
|
+
/**
|
|
28
|
+
* The owner's animation hold. The slot pauses at the same from-pose as the
|
|
29
|
+
* screen, so a flight that is held opens with its overlay rather than after
|
|
30
|
+
* it.
|
|
31
|
+
*/
|
|
32
|
+
animHold: string;
|
|
33
|
+
/**
|
|
34
|
+
* Whether this owner is ALSO the screen that renders the host.
|
|
35
|
+
*
|
|
36
|
+
* An overlay has to travel with whatever is actually moving under it, and
|
|
37
|
+
* that is not always its owner. When an ancestor screen flies — a push on an
|
|
38
|
+
* outer Router, with the owner sitting inside it at rest — the thing that
|
|
39
|
+
* moves is the ancestor, and the host is inside the ancestor's container. So
|
|
40
|
+
* the HOST rides the screen that renders it, and a slot rides its owner only
|
|
41
|
+
* when the two are different screens. Otherwise the pair would both animate
|
|
42
|
+
* and the overlay would travel twice as far as its screen.
|
|
43
|
+
*
|
|
44
|
+
* Measured in a consumer app before this existed: a sheet in a nested screen
|
|
45
|
+
* sat perfectly still while the whole region slid out from under it, because
|
|
46
|
+
* its owner's status was IDLE for the entire flight and the compiled rule had
|
|
47
|
+
* nothing to match.
|
|
48
|
+
*/
|
|
49
|
+
rendersHost: boolean;
|
|
50
|
+
/**
|
|
51
|
+
* The owning screen's id, written onto the slot so the gesture driver can
|
|
52
|
+
* find it. A drag does not go through the compiled rules — it writes inline
|
|
53
|
+
* styles frame by frame — and it enumerates what rides along by walking the
|
|
54
|
+
* moving screen's container. A slot is not in that container, so it has to
|
|
55
|
+
* name its owner instead.
|
|
56
|
+
*/
|
|
57
|
+
screenId: string;
|
|
58
|
+
/**
|
|
59
|
+
* Register a slot element with its owner, for the lifetime of the slot.
|
|
60
|
+
*
|
|
61
|
+
* The owner needs to know it HAS an escaped overlay, because the dim has to
|
|
62
|
+
* follow the overlay out. A screen's decorator lives in that screen's
|
|
63
|
+
* container and covers everything inside it, so an overlay that left the
|
|
64
|
+
* container leaves the dim behind — measured: an inline sheet is covered by
|
|
65
|
+
* the dim, the same sheet through `<Layer>` is not. And a consumer writes
|
|
66
|
+
* that decorator with `createDecorator`, so it can be anything, including
|
|
67
|
+
* fully opaque. A screen that vanishes under its own decorator while its
|
|
68
|
+
* sheet floats untouched is not a cosmetic difference.
|
|
69
|
+
*
|
|
70
|
+
* The dim copy exists only while a slot does. Rendered unconditionally it
|
|
71
|
+
* would paint over the shared bars for every flight, overlay or not.
|
|
72
|
+
*/
|
|
73
|
+
registerSlot: (element: HTMLElement | null) => void;
|
|
74
|
+
}
|
|
75
|
+
declare const LayerOwnerContext: import('react').Context<LayerOwner | null>;
|
|
76
|
+
export declare function useLayerOwner(): LayerOwner | null;
|
|
77
|
+
export { LayerHostContext, LayerOwnerContext };
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { ComponentPropsWithRef, JSX, PropsWithChildren } from 'react';
|
|
2
|
+
import { MorphTransitionName } from '@flemo/core';
|
|
3
|
+
export interface MorphProps extends PropsWithChildren<ComponentPropsWithRef<"div">> {
|
|
4
|
+
layoutId: string | number;
|
|
5
|
+
name?: MorphTransitionName;
|
|
6
|
+
as?: keyof JSX.IntrinsicElements;
|
|
7
|
+
}
|
|
8
|
+
declare function Morph({ ref, layoutId, name, as, style, children, ...props }: MorphProps): import('react').ReactElement<{
|
|
9
|
+
"data-flemo-morph-slot": string;
|
|
10
|
+
style: {
|
|
11
|
+
display: string;
|
|
12
|
+
};
|
|
13
|
+
}, string | import('react').JSXElementConstructor<any>>;
|
|
14
|
+
export default Morph;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default, type MorphLayerProps } from './MorphLayer';
|
package/dist/screen/Screen.d.ts
CHANGED
|
@@ -1,6 +1,12 @@
|
|
|
1
1
|
import { ComponentPropsWithoutRef, PropsWithChildren, ReactNode } from 'react';
|
|
2
2
|
import { SharedBarId } from '@flemo/core';
|
|
3
3
|
export interface ScreenProps extends PropsWithChildren<Omit<ComponentPropsWithoutRef<"div">, "onPointerDown" | "onPointerMove" | "onPointerUp" | "onPointerCancel">> {
|
|
4
|
+
/**
|
|
5
|
+
* Covered: stop painting this screen, from this commit. Written by the
|
|
6
|
+
* binding, never by a consumer — the prop exists so <Screen> can hand the
|
|
7
|
+
* decision to the container ScreenMotion renders.
|
|
8
|
+
*/
|
|
9
|
+
paintHidden?: boolean;
|
|
4
10
|
statusBarHeight?: string;
|
|
5
11
|
statusBarColor?: string;
|
|
6
12
|
systemNavigationBarHeight?: string;
|
|
@@ -1,7 +1,19 @@
|
|
|
1
1
|
import { ReactNode } from 'react';
|
|
2
|
+
import { ScreenFreezeMode } from '@flemo/core';
|
|
2
3
|
interface ScreenFreezeProps {
|
|
3
4
|
freeze: boolean;
|
|
5
|
+
/**
|
|
6
|
+
* WHY this screen is freezing, which decides whether the hide may wait.
|
|
7
|
+
*
|
|
8
|
+
* Only the JUST-COVERED screen can be re-revealed by a pop, so only its hide
|
|
9
|
+
* can be the one a pop has to undo — and the debounce below exists for
|
|
10
|
+
* exactly that round trip. A DEEP screen is never what a pop wakes, so
|
|
11
|
+
* waiting buys it nothing and costs the thing the delay is invisible for
|
|
12
|
+
* right up until it is not: for the length of the wait it is still PAINTING,
|
|
13
|
+
* under whatever is on top of it.
|
|
14
|
+
*/
|
|
15
|
+
mode?: ScreenFreezeMode;
|
|
4
16
|
children: ReactNode;
|
|
5
17
|
}
|
|
6
|
-
declare function ScreenFreeze({ freeze, children }: ScreenFreezeProps): import("react").JSX.Element;
|
|
18
|
+
declare function ScreenFreeze({ freeze, mode, children }: ScreenFreezeProps): import("react").JSX.Element;
|
|
7
19
|
export default ScreenFreeze;
|
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
import { ScreenProps } from './Screen';
|
|
2
|
-
declare function ScreenMotion({ children, statusBarHeight, statusBarColor, systemNavigationBarHeight, systemNavigationBarColor, sharedTopBar, sharedTopBarId, sharedBottomBar, sharedBottomBarId, topBar, bottomBar, hideStatusBar, hideSystemNavigationBar, backgroundColor, contentScrollable, ...props }: ScreenProps): import("react").JSX.Element;
|
|
2
|
+
declare function ScreenMotion({ children, statusBarHeight, statusBarColor, systemNavigationBarHeight, systemNavigationBarColor, sharedTopBar, sharedTopBarId, sharedBottomBar, sharedBottomBarId, topBar, bottomBar, hideStatusBar, hideSystemNavigationBar, backgroundColor, contentScrollable, paintHidden, ...props }: ScreenProps): import("react").JSX.Element;
|
|
3
3
|
export default ScreenMotion;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { Decorator, PartTransition, Transition } from '@flemo/core';
|
|
2
|
-
export default function useTransitionStyles(transitions: Transition[], decorators: Decorator[], partTransitions?: PartTransition[]): void;
|
|
1
|
+
import { Decorator, MorphTransition, PartTransition, Transition } from '@flemo/core';
|
|
2
|
+
export default function useTransitionStyles(transitions: Transition[], decorators: Decorator[], partTransitions?: PartTransition[], morphTransitions?: MorphTransition[]): void;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@flemo/react",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "2.1.0",
|
|
4
4
|
"description": "React bindings for flemo: Router, Route, Screen, and the screen-transition runtime.",
|
|
5
5
|
"main": "./dist/index.mjs",
|
|
6
6
|
"module": "./dist/index.mjs",
|
|
@@ -34,28 +34,28 @@
|
|
|
34
34
|
"homepage": "https://flemo.dev",
|
|
35
35
|
"license": "MIT",
|
|
36
36
|
"dependencies": {
|
|
37
|
+
"@flemo/core": "2.1.0",
|
|
37
38
|
"path-to-regexp": "^8.4.2",
|
|
38
|
-
"zustand": "^5.0.
|
|
39
|
-
"@flemo/core": "1.30.0"
|
|
39
|
+
"zustand": "^5.0.15"
|
|
40
40
|
},
|
|
41
41
|
"devDependencies": {
|
|
42
|
+
"@flemo/eslint-config": "0.0.0",
|
|
43
|
+
"@flemo/tsconfig": "0.0.0",
|
|
42
44
|
"@testing-library/jest-dom": "^6.9.1",
|
|
43
45
|
"@testing-library/react": "^16.3.2",
|
|
44
46
|
"@types/node": "^24.13.1",
|
|
45
47
|
"@types/react": "^19.2.18",
|
|
46
48
|
"@types/react-dom": "^19.2.4",
|
|
47
49
|
"@vitejs/plugin-react-swc": "^4.3.3",
|
|
48
|
-
"@vitest/coverage-v8": "^4.1.
|
|
50
|
+
"@vitest/coverage-v8": "^4.1.11",
|
|
49
51
|
"eslint": "^9.39.5",
|
|
50
52
|
"jsdom": "^29.1.1",
|
|
51
53
|
"react": "^19.2.8",
|
|
52
54
|
"react-dom": "^19.2.8",
|
|
53
55
|
"typescript": "^6.0.3",
|
|
54
|
-
"vite": "^8.2.
|
|
56
|
+
"vite": "^8.2.2",
|
|
55
57
|
"vite-plugin-dts": "^5.0.3",
|
|
56
|
-
"vitest": "^4.1.
|
|
57
|
-
"@flemo/eslint-config": "0.0.0",
|
|
58
|
-
"@flemo/tsconfig": "0.0.0"
|
|
58
|
+
"vitest": "^4.1.11"
|
|
59
59
|
},
|
|
60
60
|
"peerDependencies": {
|
|
61
61
|
"react": "^19.2.8",
|