@flightdev/transitions 0.2.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/LICENSE +21 -0
- package/README.md +86 -0
- package/dist/adapters/react/index.d.ts +210 -0
- package/dist/adapters/react/index.js +261 -0
- package/dist/adapters/react/index.js.map +1 -0
- package/dist/adapters/solid/index.d.ts +5 -0
- package/dist/adapters/solid/index.js +9 -0
- package/dist/adapters/solid/index.js.map +1 -0
- package/dist/adapters/svelte/index.d.ts +5 -0
- package/dist/adapters/svelte/index.js +9 -0
- package/dist/adapters/svelte/index.js.map +1 -0
- package/dist/adapters/vue/index.d.ts +5 -0
- package/dist/adapters/vue/index.js +9 -0
- package/dist/adapters/vue/index.js.map +1 -0
- package/dist/chunk-DZC3OLDU.js +121 -0
- package/dist/chunk-DZC3OLDU.js.map +1 -0
- package/dist/chunk-GEYKSLH6.js +190 -0
- package/dist/chunk-GEYKSLH6.js.map +1 -0
- package/dist/chunk-N7U5LD4Z.js +70 -0
- package/dist/chunk-N7U5LD4Z.js.map +1 -0
- package/dist/chunk-OV3U5STU.js +252 -0
- package/dist/chunk-OV3U5STU.js.map +1 -0
- package/dist/chunk-QSB65CTV.js +438 -0
- package/dist/chunk-QSB65CTV.js.map +1 -0
- package/dist/chunk-SPUGO5I5.js +138 -0
- package/dist/chunk-SPUGO5I5.js.map +1 -0
- package/dist/chunk-W7HSR35B.js +3 -0
- package/dist/chunk-W7HSR35B.js.map +1 -0
- package/dist/chunk-X2A7XWYR.js +442 -0
- package/dist/chunk-X2A7XWYR.js.map +1 -0
- package/dist/chunk-XLVYHPII.js +3 -0
- package/dist/chunk-XLVYHPII.js.map +1 -0
- package/dist/chunk-ZI6E7GNQ.js +136 -0
- package/dist/chunk-ZI6E7GNQ.js.map +1 -0
- package/dist/component/index.d.ts +87 -0
- package/dist/component/index.js +5 -0
- package/dist/component/index.js.map +1 -0
- package/dist/config/index.d.ts +93 -0
- package/dist/config/index.js +5 -0
- package/dist/config/index.js.map +1 -0
- package/dist/core/index.d.ts +107 -0
- package/dist/core/index.js +5 -0
- package/dist/core/index.js.map +1 -0
- package/dist/index.d.ts +10 -0
- package/dist/index.js +11 -0
- package/dist/index.js.map +1 -0
- package/dist/layout/index.d.ts +112 -0
- package/dist/layout/index.js +4 -0
- package/dist/layout/index.js.map +1 -0
- package/dist/page/index.d.ts +87 -0
- package/dist/page/index.js +7 -0
- package/dist/page/index.js.map +1 -0
- package/dist/presets/index.d.ts +192 -0
- package/dist/presets/index.js +3 -0
- package/dist/presets/index.js.map +1 -0
- package/dist/router/index.d.ts +104 -0
- package/dist/router/index.js +7 -0
- package/dist/router/index.js.map +1 -0
- package/dist/transition-manager-QWm4OSFw.d.ts +62 -0
- package/dist/types-BA4L37s4.d.ts +272 -0
- package/dist/view-transition-LSN_PSbm.d.ts +97 -0
- package/package.json +148 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2024-2026 Flight Contributors
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
# @flight-framework/transitions
|
|
2
|
+
|
|
3
|
+
View transition utilities for Flight Framework. Smooth page transitions with the View Transitions API.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install @flight-framework/transitions
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Quick Start
|
|
12
|
+
|
|
13
|
+
```typescript
|
|
14
|
+
import { createTransition } from '@flight-framework/transitions';
|
|
15
|
+
|
|
16
|
+
const transition = createTransition();
|
|
17
|
+
|
|
18
|
+
// Wrap navigation with transition
|
|
19
|
+
await transition.navigate('/new-page', async () => {
|
|
20
|
+
await router.push('/new-page');
|
|
21
|
+
});
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
## React Integration
|
|
25
|
+
|
|
26
|
+
```tsx
|
|
27
|
+
import { TransitionProvider, useTransition } from '@flight-framework/transitions/react';
|
|
28
|
+
|
|
29
|
+
function App() {
|
|
30
|
+
return (
|
|
31
|
+
<TransitionProvider>
|
|
32
|
+
<Routes />
|
|
33
|
+
</TransitionProvider>
|
|
34
|
+
);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
function Navigation() {
|
|
38
|
+
const { navigate, isPending } = useTransition();
|
|
39
|
+
|
|
40
|
+
return (
|
|
41
|
+
<nav>
|
|
42
|
+
<button
|
|
43
|
+
onClick={() => navigate('/about')}
|
|
44
|
+
disabled={isPending}
|
|
45
|
+
>
|
|
46
|
+
About
|
|
47
|
+
</button>
|
|
48
|
+
</nav>
|
|
49
|
+
);
|
|
50
|
+
}
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
## Named Transitions
|
|
54
|
+
|
|
55
|
+
```css
|
|
56
|
+
/* Shared element transitions */
|
|
57
|
+
.hero-image {
|
|
58
|
+
view-transition-name: hero;
|
|
59
|
+
}
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
```tsx
|
|
63
|
+
<img
|
|
64
|
+
src="/hero.jpg"
|
|
65
|
+
style={{ viewTransitionName: 'hero' }}
|
|
66
|
+
/>
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
## Configuration
|
|
70
|
+
|
|
71
|
+
```typescript
|
|
72
|
+
createTransition({
|
|
73
|
+
// Fallback for browsers without View Transitions
|
|
74
|
+
fallback: 'fade',
|
|
75
|
+
|
|
76
|
+
// Transition duration
|
|
77
|
+
duration: 300,
|
|
78
|
+
|
|
79
|
+
// Easing function
|
|
80
|
+
easing: 'ease-out',
|
|
81
|
+
});
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
## License
|
|
85
|
+
|
|
86
|
+
MIT
|
|
@@ -0,0 +1,210 @@
|
|
|
1
|
+
import React, { FC, ReactNode, CSSProperties } from 'react';
|
|
2
|
+
import { i as TransitionsConfig, j as TransitionState, P as PageTransitionConfig, T as TransitionPreset, C as CustomTransition } from '../../types-BA4L37s4.js';
|
|
3
|
+
import { T as TransitionManager } from '../../transition-manager-QWm4OSFw.js';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* @flightdev/transitions - React Adapter
|
|
7
|
+
*
|
|
8
|
+
* React components and hooks for Flight Transitions.
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
interface TransitionContextValue {
|
|
12
|
+
/** Current transition state */
|
|
13
|
+
state: TransitionState;
|
|
14
|
+
/** Transition manager instance */
|
|
15
|
+
manager: TransitionManager;
|
|
16
|
+
/** Whether transitions are enabled */
|
|
17
|
+
isEnabled: boolean;
|
|
18
|
+
/** Whether View Transitions API is supported */
|
|
19
|
+
isViewTransitionSupported: boolean;
|
|
20
|
+
/** Start a page transition programmatically */
|
|
21
|
+
startTransition: (to: string, config?: PageTransitionConfig) => Promise<void>;
|
|
22
|
+
/** Skip the current transition */
|
|
23
|
+
skipTransition: () => void;
|
|
24
|
+
}
|
|
25
|
+
interface TransitionProviderProps {
|
|
26
|
+
children: ReactNode;
|
|
27
|
+
/** Initial transition configuration */
|
|
28
|
+
config?: TransitionsConfig;
|
|
29
|
+
/** Use a custom transition manager */
|
|
30
|
+
manager?: TransitionManager;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* TransitionProvider - Provides transition context to the app
|
|
34
|
+
*
|
|
35
|
+
* @example
|
|
36
|
+
* ```tsx
|
|
37
|
+
* // In your root layout
|
|
38
|
+
* import { TransitionProvider } from '@flightdev/transitions/react';
|
|
39
|
+
*
|
|
40
|
+
* export default function RootLayout({ children }) {
|
|
41
|
+
* return (
|
|
42
|
+
* <TransitionProvider config={{ pageTransition: 'fade' }}>
|
|
43
|
+
* {children}
|
|
44
|
+
* </TransitionProvider>
|
|
45
|
+
* );
|
|
46
|
+
* }
|
|
47
|
+
* ```
|
|
48
|
+
*/
|
|
49
|
+
declare const TransitionProvider: FC<TransitionProviderProps>;
|
|
50
|
+
/**
|
|
51
|
+
* useTransition - Access the transition context
|
|
52
|
+
*
|
|
53
|
+
* @example
|
|
54
|
+
* ```tsx
|
|
55
|
+
* function MyComponent() {
|
|
56
|
+
* const { state, startTransition } = useTransition();
|
|
57
|
+
*
|
|
58
|
+
* return (
|
|
59
|
+
* <div>
|
|
60
|
+
* {state.isTransitioning && <LoadingSpinner />}
|
|
61
|
+
* <button onClick={() => startTransition('/about')}>
|
|
62
|
+
* Go to About
|
|
63
|
+
* </button>
|
|
64
|
+
* </div>
|
|
65
|
+
* );
|
|
66
|
+
* }
|
|
67
|
+
* ```
|
|
68
|
+
*/
|
|
69
|
+
declare function useTransition(): TransitionContextValue;
|
|
70
|
+
/**
|
|
71
|
+
* useTransitionState - Get just the transition state
|
|
72
|
+
*/
|
|
73
|
+
declare function useTransitionState(): TransitionState;
|
|
74
|
+
/**
|
|
75
|
+
* useIsTransitioning - Check if a transition is in progress
|
|
76
|
+
*/
|
|
77
|
+
declare function useIsTransitioning(): boolean;
|
|
78
|
+
/**
|
|
79
|
+
* useTransitionDirection - Get the current transition direction
|
|
80
|
+
*/
|
|
81
|
+
declare function useTransitionDirection(): 'forward' | 'back' | 'auto';
|
|
82
|
+
/**
|
|
83
|
+
* useReducedMotion - Check if user prefers reduced motion
|
|
84
|
+
*/
|
|
85
|
+
declare function useReducedMotion(): boolean;
|
|
86
|
+
interface PageTransitionProps {
|
|
87
|
+
children: ReactNode;
|
|
88
|
+
/** Transition type (overrides context config) */
|
|
89
|
+
type?: TransitionPreset | CustomTransition;
|
|
90
|
+
/** Duration override */
|
|
91
|
+
duration?: number;
|
|
92
|
+
/** Mode for sequencing enter/leave */
|
|
93
|
+
mode?: 'in-out' | 'out-in' | 'simultaneous';
|
|
94
|
+
/** Callback when transition starts */
|
|
95
|
+
onStart?: () => void;
|
|
96
|
+
/** Callback when transition ends */
|
|
97
|
+
onEnd?: () => void;
|
|
98
|
+
/** CSS class for the wrapper */
|
|
99
|
+
className?: string;
|
|
100
|
+
/** Inline styles for the wrapper */
|
|
101
|
+
style?: CSSProperties;
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* PageTransition - Wraps page content with transition animations
|
|
105
|
+
*
|
|
106
|
+
* @example
|
|
107
|
+
* ```tsx
|
|
108
|
+
* // In a layout
|
|
109
|
+
* export default function Layout({ children }) {
|
|
110
|
+
* return (
|
|
111
|
+
* <PageTransition type="slide-left">
|
|
112
|
+
* {children}
|
|
113
|
+
* </PageTransition>
|
|
114
|
+
* );
|
|
115
|
+
* }
|
|
116
|
+
* ```
|
|
117
|
+
*/
|
|
118
|
+
declare const PageTransition: FC<PageTransitionProps>;
|
|
119
|
+
interface TransitionElementProps {
|
|
120
|
+
children: ReactNode;
|
|
121
|
+
/** Show or hide the element */
|
|
122
|
+
show: boolean;
|
|
123
|
+
/** Transition type */
|
|
124
|
+
type?: TransitionPreset | CustomTransition;
|
|
125
|
+
/** Duration override */
|
|
126
|
+
duration?: number;
|
|
127
|
+
/** Animate on initial mount */
|
|
128
|
+
appear?: boolean;
|
|
129
|
+
/** Unmount when hidden */
|
|
130
|
+
unmountOnHide?: boolean;
|
|
131
|
+
/** Callbacks */
|
|
132
|
+
onEnter?: () => void;
|
|
133
|
+
onEnterComplete?: () => void;
|
|
134
|
+
onLeave?: () => void;
|
|
135
|
+
onLeaveComplete?: () => void;
|
|
136
|
+
/** Wrapper element tag name */
|
|
137
|
+
as?: 'div' | 'span' | 'section' | 'article' | 'main' | 'aside' | 'header' | 'footer' | 'nav';
|
|
138
|
+
/** CSS class */
|
|
139
|
+
className?: string;
|
|
140
|
+
/** Inline styles */
|
|
141
|
+
style?: CSSProperties;
|
|
142
|
+
}
|
|
143
|
+
/**
|
|
144
|
+
* Transition - Animate element enter/leave
|
|
145
|
+
*
|
|
146
|
+
* @example
|
|
147
|
+
* ```tsx
|
|
148
|
+
* function Modal({ isOpen, onClose, children }) {
|
|
149
|
+
* return (
|
|
150
|
+
* <Transition show={isOpen} type="fade-scale">
|
|
151
|
+
* <div className="modal">
|
|
152
|
+
* {children}
|
|
153
|
+
* </div>
|
|
154
|
+
* </Transition>
|
|
155
|
+
* );
|
|
156
|
+
* }
|
|
157
|
+
* ```
|
|
158
|
+
*/
|
|
159
|
+
declare const Transition: FC<TransitionElementProps>;
|
|
160
|
+
interface SharedElementProps {
|
|
161
|
+
children: ReactNode;
|
|
162
|
+
/** Unique name for matching across pages */
|
|
163
|
+
name: string;
|
|
164
|
+
/** Wrapper element tag name */
|
|
165
|
+
as?: 'div' | 'span' | 'section' | 'article' | 'main' | 'aside' | 'header' | 'footer' | 'img';
|
|
166
|
+
/** CSS class */
|
|
167
|
+
className?: string;
|
|
168
|
+
/** Inline styles */
|
|
169
|
+
style?: CSSProperties;
|
|
170
|
+
}
|
|
171
|
+
/**
|
|
172
|
+
* SharedElement - Mark an element for shared element transitions
|
|
173
|
+
*
|
|
174
|
+
* @example
|
|
175
|
+
* ```tsx
|
|
176
|
+
* // On list page
|
|
177
|
+
* <SharedElement name={`product-${product.id}`}>
|
|
178
|
+
* <img src={product.image} />
|
|
179
|
+
* </SharedElement>
|
|
180
|
+
*
|
|
181
|
+
* // On detail page
|
|
182
|
+
* <SharedElement name={`product-${product.id}`}>
|
|
183
|
+
* <img src={product.image} />
|
|
184
|
+
* </SharedElement>
|
|
185
|
+
* ```
|
|
186
|
+
*/
|
|
187
|
+
declare const SharedElement: FC<SharedElementProps>;
|
|
188
|
+
interface TransitionLinkProps extends React.AnchorHTMLAttributes<HTMLAnchorElement> {
|
|
189
|
+
/** Transition type for this navigation */
|
|
190
|
+
transition?: TransitionPreset | CustomTransition | false;
|
|
191
|
+
/** Replace instead of push */
|
|
192
|
+
replace?: boolean;
|
|
193
|
+
/** Prefetch on hover */
|
|
194
|
+
prefetch?: boolean;
|
|
195
|
+
}
|
|
196
|
+
/**
|
|
197
|
+
* TransitionLink - Link component with transition support
|
|
198
|
+
*
|
|
199
|
+
* Use with @flightdev/router or wrap your router's Link component.
|
|
200
|
+
*
|
|
201
|
+
* @example
|
|
202
|
+
* ```tsx
|
|
203
|
+
* <TransitionLink href="/about" transition="slide-left">
|
|
204
|
+
* About Us
|
|
205
|
+
* </TransitionLink>
|
|
206
|
+
* ```
|
|
207
|
+
*/
|
|
208
|
+
declare const TransitionLink: FC<TransitionLinkProps>;
|
|
209
|
+
|
|
210
|
+
export { PageTransition, type PageTransitionProps, SharedElement, type SharedElementProps, Transition, type TransitionElementProps, TransitionLink, type TransitionLinkProps, TransitionProvider, type TransitionProviderProps, useIsTransitioning, useReducedMotion, useTransition, useTransitionDirection, useTransitionState };
|
|
@@ -0,0 +1,261 @@
|
|
|
1
|
+
import { createTransitionManager, getTransitionManager } from '../../chunk-X2A7XWYR.js';
|
|
2
|
+
import { prefersReducedMotion } from '../../chunk-OV3U5STU.js';
|
|
3
|
+
import { createContext, useRef, useState, useEffect, useMemo, useContext, createElement, useCallback } from 'react';
|
|
4
|
+
import { jsx } from 'react/jsx-runtime';
|
|
5
|
+
|
|
6
|
+
var TransitionContext = createContext(null);
|
|
7
|
+
var TransitionProvider = ({
|
|
8
|
+
children,
|
|
9
|
+
config,
|
|
10
|
+
manager: customManager
|
|
11
|
+
}) => {
|
|
12
|
+
const managerRef = useRef(null);
|
|
13
|
+
if (!managerRef.current) {
|
|
14
|
+
managerRef.current = customManager ?? createTransitionManager(config);
|
|
15
|
+
}
|
|
16
|
+
const manager = managerRef.current;
|
|
17
|
+
const [state, setState] = useState(manager.getState());
|
|
18
|
+
useEffect(() => {
|
|
19
|
+
const unsubscribe = manager.subscribe((newState) => {
|
|
20
|
+
setState(newState);
|
|
21
|
+
});
|
|
22
|
+
return unsubscribe;
|
|
23
|
+
}, [manager]);
|
|
24
|
+
useEffect(() => {
|
|
25
|
+
if (config) {
|
|
26
|
+
manager.configure(config);
|
|
27
|
+
}
|
|
28
|
+
}, [config, manager]);
|
|
29
|
+
useEffect(() => {
|
|
30
|
+
return () => {
|
|
31
|
+
if (!customManager) {
|
|
32
|
+
manager.destroy();
|
|
33
|
+
}
|
|
34
|
+
};
|
|
35
|
+
}, [manager, customManager]);
|
|
36
|
+
const value = useMemo(() => ({
|
|
37
|
+
state,
|
|
38
|
+
manager,
|
|
39
|
+
isEnabled: manager.isEnabled(),
|
|
40
|
+
isViewTransitionSupported: manager.isViewTransitionSupported(),
|
|
41
|
+
startTransition: (to, pageConfig) => manager.startPageTransition(to, pageConfig),
|
|
42
|
+
skipTransition: () => manager.skipTransition()
|
|
43
|
+
}), [state, manager]);
|
|
44
|
+
return /* @__PURE__ */ jsx(TransitionContext.Provider, { value, children });
|
|
45
|
+
};
|
|
46
|
+
function useTransition() {
|
|
47
|
+
const context = useContext(TransitionContext);
|
|
48
|
+
if (!context) {
|
|
49
|
+
const manager = getTransitionManager();
|
|
50
|
+
return {
|
|
51
|
+
state: manager.getState(),
|
|
52
|
+
manager,
|
|
53
|
+
isEnabled: manager.isEnabled(),
|
|
54
|
+
isViewTransitionSupported: manager.isViewTransitionSupported(),
|
|
55
|
+
startTransition: (to, config) => manager.startPageTransition(to, config),
|
|
56
|
+
skipTransition: () => manager.skipTransition()
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
return context;
|
|
60
|
+
}
|
|
61
|
+
function useTransitionState() {
|
|
62
|
+
const { state } = useTransition();
|
|
63
|
+
return state;
|
|
64
|
+
}
|
|
65
|
+
function useIsTransitioning() {
|
|
66
|
+
const { state } = useTransition();
|
|
67
|
+
return state.isTransitioning;
|
|
68
|
+
}
|
|
69
|
+
function useTransitionDirection() {
|
|
70
|
+
const { state } = useTransition();
|
|
71
|
+
return state.direction;
|
|
72
|
+
}
|
|
73
|
+
function useReducedMotion() {
|
|
74
|
+
const [reduced, setReduced] = useState(() => prefersReducedMotion());
|
|
75
|
+
useEffect(() => {
|
|
76
|
+
const mediaQuery = window.matchMedia("(prefers-reduced-motion: reduce)");
|
|
77
|
+
const handler = (event) => {
|
|
78
|
+
setReduced(event.matches);
|
|
79
|
+
};
|
|
80
|
+
mediaQuery.addEventListener("change", handler);
|
|
81
|
+
return () => mediaQuery.removeEventListener("change", handler);
|
|
82
|
+
}, []);
|
|
83
|
+
return reduced;
|
|
84
|
+
}
|
|
85
|
+
var PageTransition = ({
|
|
86
|
+
children,
|
|
87
|
+
type,
|
|
88
|
+
duration,
|
|
89
|
+
mode = "out-in",
|
|
90
|
+
onStart,
|
|
91
|
+
onEnd,
|
|
92
|
+
className,
|
|
93
|
+
style
|
|
94
|
+
}) => {
|
|
95
|
+
const { state } = useTransition();
|
|
96
|
+
const containerRef = useRef(null);
|
|
97
|
+
useEffect(() => {
|
|
98
|
+
if (state.isTransitioning && state.phase === "leaving") {
|
|
99
|
+
onStart?.();
|
|
100
|
+
}
|
|
101
|
+
if (!state.isTransitioning && state.phase === "idle") {
|
|
102
|
+
onEnd?.();
|
|
103
|
+
}
|
|
104
|
+
}, [state.isTransitioning, state.phase, onStart, onEnd]);
|
|
105
|
+
const transitionClass = useMemo(() => {
|
|
106
|
+
const classes = ["flight-page-transition"];
|
|
107
|
+
if (className) {
|
|
108
|
+
classes.push(className);
|
|
109
|
+
}
|
|
110
|
+
if (state.isTransitioning) {
|
|
111
|
+
classes.push("flight-transitioning");
|
|
112
|
+
classes.push(`flight-transition-${state.phase}`);
|
|
113
|
+
classes.push(`flight-direction-${state.direction}`);
|
|
114
|
+
}
|
|
115
|
+
return classes.join(" ");
|
|
116
|
+
}, [className, state.isTransitioning, state.phase, state.direction]);
|
|
117
|
+
const inlineStyle = useMemo(() => {
|
|
118
|
+
const styles = { ...style };
|
|
119
|
+
if (duration !== void 0) {
|
|
120
|
+
styles["--flight-transition-duration"] = `${duration}ms`;
|
|
121
|
+
}
|
|
122
|
+
if (type && typeof type === "string") {
|
|
123
|
+
styles["--flight-transition-type"] = type;
|
|
124
|
+
}
|
|
125
|
+
return styles;
|
|
126
|
+
}, [style, duration, type]);
|
|
127
|
+
return /* @__PURE__ */ jsx("div", { ref: containerRef, className: transitionClass, style: inlineStyle, children });
|
|
128
|
+
};
|
|
129
|
+
var Transition = ({
|
|
130
|
+
children,
|
|
131
|
+
show,
|
|
132
|
+
type = "fade",
|
|
133
|
+
duration,
|
|
134
|
+
appear = false,
|
|
135
|
+
unmountOnHide = true,
|
|
136
|
+
onEnter,
|
|
137
|
+
onEnterComplete,
|
|
138
|
+
onLeave,
|
|
139
|
+
onLeaveComplete,
|
|
140
|
+
as: Component = "div",
|
|
141
|
+
className,
|
|
142
|
+
style
|
|
143
|
+
}) => {
|
|
144
|
+
const [shouldRender, setShouldRender] = useState(show);
|
|
145
|
+
const [phase, setPhase] = useState(
|
|
146
|
+
show ? "entered" : "left"
|
|
147
|
+
);
|
|
148
|
+
const isInitialMount = useRef(true);
|
|
149
|
+
useEffect(() => {
|
|
150
|
+
const isMount = isInitialMount.current;
|
|
151
|
+
isInitialMount.current = false;
|
|
152
|
+
if (show) {
|
|
153
|
+
setShouldRender(true);
|
|
154
|
+
if (!isMount || appear) {
|
|
155
|
+
setPhase("entering");
|
|
156
|
+
onEnter?.();
|
|
157
|
+
const timer = setTimeout(() => {
|
|
158
|
+
setPhase("entered");
|
|
159
|
+
onEnterComplete?.();
|
|
160
|
+
}, duration ?? 200);
|
|
161
|
+
return () => clearTimeout(timer);
|
|
162
|
+
} else {
|
|
163
|
+
setPhase("entered");
|
|
164
|
+
}
|
|
165
|
+
} else {
|
|
166
|
+
setPhase("leaving");
|
|
167
|
+
onLeave?.();
|
|
168
|
+
const timer = setTimeout(() => {
|
|
169
|
+
setPhase("left");
|
|
170
|
+
onLeaveComplete?.();
|
|
171
|
+
if (unmountOnHide) {
|
|
172
|
+
setShouldRender(false);
|
|
173
|
+
}
|
|
174
|
+
}, duration ?? 200);
|
|
175
|
+
return () => clearTimeout(timer);
|
|
176
|
+
}
|
|
177
|
+
}, [show, appear, duration, unmountOnHide, onEnter, onEnterComplete, onLeave, onLeaveComplete]);
|
|
178
|
+
if (!shouldRender) {
|
|
179
|
+
return null;
|
|
180
|
+
}
|
|
181
|
+
const transitionClass = [
|
|
182
|
+
"flight-transition",
|
|
183
|
+
`flight-transition-${phase}`,
|
|
184
|
+
typeof type === "string" ? `flight-transition-${type}` : void 0,
|
|
185
|
+
className
|
|
186
|
+
].filter(Boolean).join(" ");
|
|
187
|
+
const inlineStyle = {
|
|
188
|
+
...style
|
|
189
|
+
};
|
|
190
|
+
if (duration !== void 0) {
|
|
191
|
+
inlineStyle["--flight-transition-duration"] = `${duration}ms`;
|
|
192
|
+
}
|
|
193
|
+
return createElement(
|
|
194
|
+
Component,
|
|
195
|
+
{ className: transitionClass, style: inlineStyle },
|
|
196
|
+
children
|
|
197
|
+
);
|
|
198
|
+
};
|
|
199
|
+
var SharedElement = ({
|
|
200
|
+
children,
|
|
201
|
+
name,
|
|
202
|
+
as: Component = "div",
|
|
203
|
+
className,
|
|
204
|
+
style
|
|
205
|
+
}) => {
|
|
206
|
+
const ref = useRef(null);
|
|
207
|
+
useEffect(() => {
|
|
208
|
+
const element = ref.current;
|
|
209
|
+
if (element) {
|
|
210
|
+
element.style.viewTransitionName = name;
|
|
211
|
+
return () => {
|
|
212
|
+
element.style.viewTransitionName = "";
|
|
213
|
+
};
|
|
214
|
+
}
|
|
215
|
+
}, [name]);
|
|
216
|
+
return createElement(
|
|
217
|
+
Component,
|
|
218
|
+
{
|
|
219
|
+
ref,
|
|
220
|
+
className,
|
|
221
|
+
style,
|
|
222
|
+
"data-transition-name": name
|
|
223
|
+
},
|
|
224
|
+
children
|
|
225
|
+
);
|
|
226
|
+
};
|
|
227
|
+
var TransitionLink = ({
|
|
228
|
+
children,
|
|
229
|
+
href,
|
|
230
|
+
transition,
|
|
231
|
+
replace = false,
|
|
232
|
+
prefetch = false,
|
|
233
|
+
onClick,
|
|
234
|
+
...props
|
|
235
|
+
}) => {
|
|
236
|
+
const { startTransition, manager } = useTransition();
|
|
237
|
+
const handleClick = useCallback(async (e) => {
|
|
238
|
+
onClick?.(e);
|
|
239
|
+
if (e.defaultPrevented) return;
|
|
240
|
+
if (e.button !== 0 || e.metaKey || e.ctrlKey || e.shiftKey || e.altKey) {
|
|
241
|
+
return;
|
|
242
|
+
}
|
|
243
|
+
if (href && !href.startsWith("/") && !href.startsWith(window.location.origin)) {
|
|
244
|
+
return;
|
|
245
|
+
}
|
|
246
|
+
e.preventDefault();
|
|
247
|
+
const targetPath = href?.startsWith("/") ? href : new URL(href ?? "", window.location.origin).pathname;
|
|
248
|
+
await startTransition(targetPath, transition !== void 0 ? { default: transition } : void 0);
|
|
249
|
+
if (replace) {
|
|
250
|
+
window.history.replaceState({}, "", targetPath);
|
|
251
|
+
} else {
|
|
252
|
+
window.history.pushState({}, "", targetPath);
|
|
253
|
+
}
|
|
254
|
+
window.dispatchEvent(new PopStateEvent("popstate"));
|
|
255
|
+
}, [href, transition, replace, onClick, startTransition]);
|
|
256
|
+
return /* @__PURE__ */ jsx("a", { href, onClick: handleClick, ...props, children });
|
|
257
|
+
};
|
|
258
|
+
|
|
259
|
+
export { PageTransition, SharedElement, Transition, TransitionLink, TransitionProvider, useIsTransitioning, useReducedMotion, useTransition, useTransitionDirection, useTransitionState };
|
|
260
|
+
//# sourceMappingURL=index.js.map
|
|
261
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../src/adapters/react/components.tsx"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["/**\r\n * @flightdev/transitions - React Adapter\r\n * \r\n * React components and hooks for Flight Transitions.\r\n */\r\n\r\n'use client';\r\n\r\nimport React, {\r\n createContext,\r\n useContext,\r\n useState,\r\n useEffect,\r\n useCallback,\r\n useRef,\r\n useMemo,\r\n createElement,\r\n type ReactNode,\r\n type FC,\r\n type CSSProperties,\r\n type ElementType,\r\n} from 'react';\r\n\r\nimport type {\r\n TransitionsConfig,\r\n TransitionState,\r\n TransitionPreset,\r\n CustomTransition,\r\n PageTransitionConfig,\r\n} from '../../core/types';\r\nimport {\r\n createTransitionManager,\r\n getTransitionManager,\r\n type TransitionManager,\r\n} from '../../core/transition-manager';\r\nimport { prefersReducedMotion } from '../../core/animation-engine';\r\n\r\n// =============================================================================\r\n// CONTEXT\r\n// =============================================================================\r\n\r\ninterface TransitionContextValue {\r\n /** Current transition state */\r\n state: TransitionState;\r\n /** Transition manager instance */\r\n manager: TransitionManager;\r\n /** Whether transitions are enabled */\r\n isEnabled: boolean;\r\n /** Whether View Transitions API is supported */\r\n isViewTransitionSupported: boolean;\r\n /** Start a page transition programmatically */\r\n startTransition: (to: string, config?: PageTransitionConfig) => Promise<void>;\r\n /** Skip the current transition */\r\n skipTransition: () => void;\r\n}\r\n\r\nconst TransitionContext = createContext<TransitionContextValue | null>(null);\r\n\r\n// =============================================================================\r\n// PROVIDER\r\n// =============================================================================\r\n\r\nexport interface TransitionProviderProps {\r\n children: ReactNode;\r\n /** Initial transition configuration */\r\n config?: TransitionsConfig;\r\n /** Use a custom transition manager */\r\n manager?: TransitionManager;\r\n}\r\n\r\n/**\r\n * TransitionProvider - Provides transition context to the app\r\n * \r\n * @example\r\n * ```tsx\r\n * // In your root layout\r\n * import { TransitionProvider } from '@flightdev/transitions/react';\r\n * \r\n * export default function RootLayout({ children }) {\r\n * return (\r\n * <TransitionProvider config={{ pageTransition: 'fade' }}>\r\n * {children}\r\n * </TransitionProvider>\r\n * );\r\n * }\r\n * ```\r\n */\r\nexport const TransitionProvider: FC<TransitionProviderProps> = ({\r\n children,\r\n config,\r\n manager: customManager,\r\n}) => {\r\n // Create or use provided manager\r\n const managerRef = useRef<TransitionManager | null>(null);\r\n\r\n if (!managerRef.current) {\r\n managerRef.current = customManager ?? createTransitionManager(config);\r\n }\r\n\r\n const manager = managerRef.current;\r\n\r\n // Track transition state\r\n const [state, setState] = useState<TransitionState>(manager.getState());\r\n\r\n // Subscribe to state changes\r\n useEffect(() => {\r\n const unsubscribe = manager.subscribe((newState) => {\r\n setState(newState);\r\n });\r\n return unsubscribe;\r\n }, [manager]);\r\n\r\n // Update config when it changes\r\n useEffect(() => {\r\n if (config) {\r\n manager.configure(config);\r\n }\r\n }, [config, manager]);\r\n\r\n // Cleanup on unmount\r\n useEffect(() => {\r\n return () => {\r\n if (!customManager) {\r\n manager.destroy();\r\n }\r\n };\r\n }, [manager, customManager]);\r\n\r\n const value = useMemo<TransitionContextValue>(() => ({\r\n state,\r\n manager,\r\n isEnabled: manager.isEnabled(),\r\n isViewTransitionSupported: manager.isViewTransitionSupported(),\r\n startTransition: (to, pageConfig) => manager.startPageTransition(to, pageConfig),\r\n skipTransition: () => manager.skipTransition(),\r\n }), [state, manager]);\r\n\r\n return (\r\n <TransitionContext.Provider value={value}>\r\n {children}\r\n </TransitionContext.Provider>\r\n );\r\n};\r\n\r\n// =============================================================================\r\n// HOOKS\r\n// =============================================================================\r\n\r\n/**\r\n * useTransition - Access the transition context\r\n * \r\n * @example\r\n * ```tsx\r\n * function MyComponent() {\r\n * const { state, startTransition } = useTransition();\r\n * \r\n * return (\r\n * <div>\r\n * {state.isTransitioning && <LoadingSpinner />}\r\n * <button onClick={() => startTransition('/about')}>\r\n * Go to About\r\n * </button>\r\n * </div>\r\n * );\r\n * }\r\n * ```\r\n */\r\nexport function useTransition(): TransitionContextValue {\r\n const context = useContext(TransitionContext);\r\n\r\n if (!context) {\r\n // Return a fallback for components outside provider\r\n const manager = getTransitionManager();\r\n return {\r\n state: manager.getState(),\r\n manager,\r\n isEnabled: manager.isEnabled(),\r\n isViewTransitionSupported: manager.isViewTransitionSupported(),\r\n startTransition: (to, config) => manager.startPageTransition(to, config),\r\n skipTransition: () => manager.skipTransition(),\r\n };\r\n }\r\n\r\n return context;\r\n}\r\n\r\n/**\r\n * useTransitionState - Get just the transition state\r\n */\r\nexport function useTransitionState(): TransitionState {\r\n const { state } = useTransition();\r\n return state;\r\n}\r\n\r\n/**\r\n * useIsTransitioning - Check if a transition is in progress\r\n */\r\nexport function useIsTransitioning(): boolean {\r\n const { state } = useTransition();\r\n return state.isTransitioning;\r\n}\r\n\r\n/**\r\n * useTransitionDirection - Get the current transition direction\r\n */\r\nexport function useTransitionDirection(): 'forward' | 'back' | 'auto' {\r\n const { state } = useTransition();\r\n return state.direction;\r\n}\r\n\r\n/**\r\n * useReducedMotion - Check if user prefers reduced motion\r\n */\r\nexport function useReducedMotion(): boolean {\r\n const [reduced, setReduced] = useState(() => prefersReducedMotion());\r\n\r\n useEffect(() => {\r\n const mediaQuery = window.matchMedia('(prefers-reduced-motion: reduce)');\r\n\r\n const handler = (event: MediaQueryListEvent) => {\r\n setReduced(event.matches);\r\n };\r\n\r\n mediaQuery.addEventListener('change', handler);\r\n return () => mediaQuery.removeEventListener('change', handler);\r\n }, []);\r\n\r\n return reduced;\r\n}\r\n\r\n// =============================================================================\r\n// PAGE TRANSITION COMPONENT\r\n// =============================================================================\r\n\r\nexport interface PageTransitionProps {\r\n children: ReactNode;\r\n /** Transition type (overrides context config) */\r\n type?: TransitionPreset | CustomTransition;\r\n /** Duration override */\r\n duration?: number;\r\n /** Mode for sequencing enter/leave */\r\n mode?: 'in-out' | 'out-in' | 'simultaneous';\r\n /** Callback when transition starts */\r\n onStart?: () => void;\r\n /** Callback when transition ends */\r\n onEnd?: () => void;\r\n /** CSS class for the wrapper */\r\n className?: string;\r\n /** Inline styles for the wrapper */\r\n style?: CSSProperties;\r\n}\r\n\r\n/**\r\n * PageTransition - Wraps page content with transition animations\r\n * \r\n * @example\r\n * ```tsx\r\n * // In a layout\r\n * export default function Layout({ children }) {\r\n * return (\r\n * <PageTransition type=\"slide-left\">\r\n * {children}\r\n * </PageTransition>\r\n * );\r\n * }\r\n * ```\r\n */\r\nexport const PageTransition: FC<PageTransitionProps> = ({\r\n children,\r\n type,\r\n duration,\r\n mode = 'out-in',\r\n onStart,\r\n onEnd,\r\n className,\r\n style,\r\n}) => {\r\n const { state } = useTransition();\r\n const containerRef = useRef<HTMLDivElement>(null);\r\n\r\n // Call callbacks\r\n useEffect(() => {\r\n if (state.isTransitioning && state.phase === 'leaving') {\r\n onStart?.();\r\n }\r\n if (!state.isTransitioning && state.phase === 'idle') {\r\n onEnd?.();\r\n }\r\n }, [state.isTransitioning, state.phase, onStart, onEnd]);\r\n\r\n // Build transition class\r\n const transitionClass = useMemo(() => {\r\n const classes = ['flight-page-transition'];\r\n\r\n if (className) {\r\n classes.push(className);\r\n }\r\n\r\n if (state.isTransitioning) {\r\n classes.push('flight-transitioning');\r\n classes.push(`flight-transition-${state.phase}`);\r\n classes.push(`flight-direction-${state.direction}`);\r\n }\r\n\r\n return classes.join(' ');\r\n }, [className, state.isTransitioning, state.phase, state.direction]);\r\n\r\n // Build inline styles with CSS custom properties\r\n const inlineStyle = useMemo<CSSProperties>(() => {\r\n const styles: CSSProperties = { ...style };\r\n\r\n if (duration !== undefined) {\r\n (styles as Record<string, unknown>)['--flight-transition-duration'] = `${duration}ms`;\r\n }\r\n\r\n if (type && typeof type === 'string') {\r\n (styles as Record<string, unknown>)['--flight-transition-type'] = type;\r\n }\r\n\r\n return styles;\r\n }, [style, duration, type]);\r\n\r\n return (\r\n <div ref={containerRef} className={transitionClass} style={inlineStyle}>\r\n {children}\r\n </div>\r\n );\r\n};\r\n\r\n// =============================================================================\r\n// TRANSITION COMPONENT (for elements)\r\n// =============================================================================\r\n\r\nexport interface TransitionElementProps {\r\n children: ReactNode;\r\n /** Show or hide the element */\r\n show: boolean;\r\n /** Transition type */\r\n type?: TransitionPreset | CustomTransition;\r\n /** Duration override */\r\n duration?: number;\r\n /** Animate on initial mount */\r\n appear?: boolean;\r\n /** Unmount when hidden */\r\n unmountOnHide?: boolean;\r\n /** Callbacks */\r\n onEnter?: () => void;\r\n onEnterComplete?: () => void;\r\n onLeave?: () => void;\r\n onLeaveComplete?: () => void;\r\n /** Wrapper element tag name */\r\n as?: 'div' | 'span' | 'section' | 'article' | 'main' | 'aside' | 'header' | 'footer' | 'nav';\r\n /** CSS class */\r\n className?: string;\r\n /** Inline styles */\r\n style?: CSSProperties;\r\n}\r\n\r\n/**\r\n * Transition - Animate element enter/leave\r\n * \r\n * @example\r\n * ```tsx\r\n * function Modal({ isOpen, onClose, children }) {\r\n * return (\r\n * <Transition show={isOpen} type=\"fade-scale\">\r\n * <div className=\"modal\">\r\n * {children}\r\n * </div>\r\n * </Transition>\r\n * );\r\n * }\r\n * ```\r\n */\r\nexport const Transition: FC<TransitionElementProps> = ({\r\n children,\r\n show,\r\n type = 'fade',\r\n duration,\r\n appear = false,\r\n unmountOnHide = true,\r\n onEnter,\r\n onEnterComplete,\r\n onLeave,\r\n onLeaveComplete,\r\n as: Component = 'div',\r\n className,\r\n style,\r\n}) => {\r\n const [shouldRender, setShouldRender] = useState(show);\r\n const [phase, setPhase] = useState<'entering' | 'entered' | 'leaving' | 'left'>(\r\n show ? 'entered' : 'left'\r\n );\r\n const isInitialMount = useRef(true);\r\n\r\n useEffect(() => {\r\n const isMount = isInitialMount.current;\r\n isInitialMount.current = false;\r\n\r\n if (show) {\r\n setShouldRender(true);\r\n\r\n if (!isMount || appear) {\r\n setPhase('entering');\r\n onEnter?.();\r\n\r\n const timer = setTimeout(() => {\r\n setPhase('entered');\r\n onEnterComplete?.();\r\n }, duration ?? 200);\r\n\r\n return () => clearTimeout(timer);\r\n } else {\r\n setPhase('entered');\r\n }\r\n } else {\r\n setPhase('leaving');\r\n onLeave?.();\r\n\r\n const timer = setTimeout(() => {\r\n setPhase('left');\r\n onLeaveComplete?.();\r\n if (unmountOnHide) {\r\n setShouldRender(false);\r\n }\r\n }, duration ?? 200);\r\n\r\n return () => clearTimeout(timer);\r\n }\r\n }, [show, appear, duration, unmountOnHide, onEnter, onEnterComplete, onLeave, onLeaveComplete]);\r\n\r\n if (!shouldRender) {\r\n return null;\r\n }\r\n\r\n const transitionClass = [\r\n 'flight-transition',\r\n `flight-transition-${phase}`,\r\n typeof type === 'string' ? `flight-transition-${type}` : undefined,\r\n className,\r\n ].filter(Boolean).join(' ');\r\n\r\n const inlineStyle: CSSProperties = {\r\n ...style,\r\n };\r\n\r\n if (duration !== undefined) {\r\n (inlineStyle as Record<string, unknown>)['--flight-transition-duration'] = `${duration}ms`;\r\n }\r\n\r\n return createElement(\r\n Component,\r\n { className: transitionClass, style: inlineStyle },\r\n children\r\n );\r\n};\r\n\r\n// =============================================================================\r\n// SHARED ELEMENT\r\n// =============================================================================\r\n\r\nexport interface SharedElementProps {\r\n children: ReactNode;\r\n /** Unique name for matching across pages */\r\n name: string;\r\n /** Wrapper element tag name */\r\n as?: 'div' | 'span' | 'section' | 'article' | 'main' | 'aside' | 'header' | 'footer' | 'img';\r\n /** CSS class */\r\n className?: string;\r\n /** Inline styles */\r\n style?: CSSProperties;\r\n}\r\n\r\n/**\r\n * SharedElement - Mark an element for shared element transitions\r\n * \r\n * @example\r\n * ```tsx\r\n * // On list page\r\n * <SharedElement name={`product-${product.id}`}>\r\n * <img src={product.image} />\r\n * </SharedElement>\r\n * \r\n * // On detail page\r\n * <SharedElement name={`product-${product.id}`}>\r\n * <img src={product.image} />\r\n * </SharedElement>\r\n * ```\r\n */\r\nexport const SharedElement: FC<SharedElementProps> = ({\r\n children,\r\n name,\r\n as: Component = 'div',\r\n className,\r\n style,\r\n}) => {\r\n const ref = useRef<HTMLElement>(null);\r\n\r\n useEffect(() => {\r\n const element = ref.current;\r\n if (element) {\r\n // Set view-transition-name for native View Transitions API\r\n element.style.viewTransitionName = name;\r\n\r\n return () => {\r\n element.style.viewTransitionName = '';\r\n };\r\n }\r\n }, [name]);\r\n\r\n return createElement(\r\n Component,\r\n {\r\n ref: ref as React.Ref<HTMLDivElement>,\r\n className,\r\n style,\r\n 'data-transition-name': name,\r\n },\r\n children\r\n );\r\n};\r\n\r\n// =============================================================================\r\n// ANIMATED LINK\r\n// =============================================================================\r\n\r\nexport interface TransitionLinkProps extends React.AnchorHTMLAttributes<HTMLAnchorElement> {\r\n /** Transition type for this navigation */\r\n transition?: TransitionPreset | CustomTransition | false;\r\n /** Replace instead of push */\r\n replace?: boolean;\r\n /** Prefetch on hover */\r\n prefetch?: boolean;\r\n}\r\n\r\n/**\r\n * TransitionLink - Link component with transition support\r\n * \r\n * Use with @flightdev/router or wrap your router's Link component.\r\n * \r\n * @example\r\n * ```tsx\r\n * <TransitionLink href=\"/about\" transition=\"slide-left\">\r\n * About Us\r\n * </TransitionLink>\r\n * ```\r\n */\r\nexport const TransitionLink: FC<TransitionLinkProps> = ({\r\n children,\r\n href,\r\n transition,\r\n replace = false,\r\n prefetch = false,\r\n onClick,\r\n ...props\r\n}) => {\r\n const { startTransition, manager } = useTransition();\r\n\r\n const handleClick = useCallback(async (e: React.MouseEvent<HTMLAnchorElement>) => {\r\n // Call original onClick if provided\r\n onClick?.(e);\r\n\r\n // If default prevented, don't handle\r\n if (e.defaultPrevented) return;\r\n\r\n // Only handle left clicks without modifiers\r\n if (e.button !== 0 || e.metaKey || e.ctrlKey || e.shiftKey || e.altKey) {\r\n return;\r\n }\r\n\r\n // Only handle same-origin links\r\n if (href && !href.startsWith('/') && !href.startsWith(window.location.origin)) {\r\n return;\r\n }\r\n\r\n // Prevent default navigation\r\n e.preventDefault();\r\n\r\n const targetPath = href?.startsWith('/')\r\n ? href\r\n : new URL(href ?? '', window.location.origin).pathname;\r\n\r\n // Start transition\r\n await startTransition(targetPath, transition !== undefined ? { default: transition } : undefined);\r\n\r\n // Perform actual navigation\r\n if (replace) {\r\n window.history.replaceState({}, '', targetPath);\r\n } else {\r\n window.history.pushState({}, '', targetPath);\r\n }\r\n\r\n // Dispatch popstate for router to pick up\r\n window.dispatchEvent(new PopStateEvent('popstate'));\r\n }, [href, transition, replace, onClick, startTransition]);\r\n\r\n return (\r\n <a href={href} onClick={handleClick} {...props}>\r\n {children}\r\n </a>\r\n );\r\n};\r\n"]}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export { i as isViewTransitionSupported, s as startViewTransition } from '../../view-transition-LSN_PSbm.js';
|
|
2
|
+
export { c as createTransitionManager, g as getTransitionManager } from '../../transition-manager-QWm4OSFw.js';
|
|
3
|
+
export { definePageTransition, executePageTransition } from '../../page/index.js';
|
|
4
|
+
export { registerSharedElement, unregisterSharedElement } from '../../layout/index.js';
|
|
5
|
+
import '../../types-BA4L37s4.js';
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import '../../chunk-W7HSR35B.js';
|
|
2
|
+
import '../../chunk-XLVYHPII.js';
|
|
3
|
+
export { definePageTransition, executePageTransition } from '../../chunk-SPUGO5I5.js';
|
|
4
|
+
export { registerSharedElement, unregisterSharedElement } from '../../chunk-ZI6E7GNQ.js';
|
|
5
|
+
import '../../chunk-QSB65CTV.js';
|
|
6
|
+
export { createTransitionManager, getTransitionManager, isViewTransitionSupported, startViewTransition } from '../../chunk-X2A7XWYR.js';
|
|
7
|
+
import '../../chunk-OV3U5STU.js';
|
|
8
|
+
//# sourceMappingURL=index.js.map
|
|
9
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":[],"names":[],"mappings":"","file":"index.js"}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export { i as isViewTransitionSupported, s as startViewTransition } from '../../view-transition-LSN_PSbm.js';
|
|
2
|
+
export { c as createTransitionManager, g as getTransitionManager } from '../../transition-manager-QWm4OSFw.js';
|
|
3
|
+
export { definePageTransition, executePageTransition } from '../../page/index.js';
|
|
4
|
+
export { registerSharedElement, unregisterSharedElement } from '../../layout/index.js';
|
|
5
|
+
import '../../types-BA4L37s4.js';
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import '../../chunk-W7HSR35B.js';
|
|
2
|
+
import '../../chunk-XLVYHPII.js';
|
|
3
|
+
export { definePageTransition, executePageTransition } from '../../chunk-SPUGO5I5.js';
|
|
4
|
+
export { registerSharedElement, unregisterSharedElement } from '../../chunk-ZI6E7GNQ.js';
|
|
5
|
+
import '../../chunk-QSB65CTV.js';
|
|
6
|
+
export { createTransitionManager, getTransitionManager, isViewTransitionSupported, startViewTransition } from '../../chunk-X2A7XWYR.js';
|
|
7
|
+
import '../../chunk-OV3U5STU.js';
|
|
8
|
+
//# sourceMappingURL=index.js.map
|
|
9
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":[],"names":[],"mappings":"","file":"index.js"}
|