@neveranyart/weaver 1.0.7 → 1.0.9
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 +144 -8
- package/dist/hooks.js +0 -2
- package/dist/hooks.js.map +1 -1
- package/dist/hooks.mjs +0 -2
- package/dist/hooks.mjs.map +1 -1
- package/dist/routing.d.mts +5 -12
- package/dist/routing.d.ts +5 -12
- package/dist/routing.js +18 -6
- package/dist/routing.js.map +1 -1
- package/dist/routing.mjs +19 -7
- package/dist/routing.mjs.map +1 -1
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -1,16 +1,152 @@
|
|
|
1
|
-
#
|
|
1
|
+
# `@neveranyart/weaver`
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
**WIP DOCS**
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
This is `@neveranyart/weaver`, an in-house package for making interactive React CSR.
|
|
5
|
+
An in-house core package by neveranyart for making performant, interactive React CSR.
|
|
7
6
|
|
|
8
|
-
|
|
7
|
+

|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
## Introduction
|
|
11
|
+
This package is published as an in-depth on `neverany` technicals. This package is not intended for broad usage so it has a strict choice of dependencies and a specific way of use.
|
|
12
|
+
|
|
13
|
+
## Usage
|
|
14
|
+
|
|
15
|
+
### Routing
|
|
16
|
+
The package wraps around `react-router` as a base for working with routing because it provides us a way to postpone parent components mounting.
|
|
17
|
+
|
|
18
|
+
There are 2 components for composing delayed routing for animations: `DelayedOutlet`, `Pipeline`.
|
|
19
|
+
|
|
20
|
+
- `DelayedOutlet`:
|
|
21
|
+
- Drop-in replacement for `Outlet` component from `react-router`.
|
|
22
|
+
- `Pipeline`:
|
|
23
|
+
- Declare parent for an endpoint, handle route changes and communicates with `DelayedOutlet`.
|
|
24
|
+
- As long as it's the ONLY instance on the route endpoint, it should works just fine.
|
|
25
|
+
- Can be placed anywhere, but please put it as a parent for all of your endpoint's components.
|
|
26
|
+
- It can't nest itself.
|
|
27
|
+
|
|
28
|
+
> [!CAUTION]
|
|
29
|
+
> There can only be ONE `DelayedOutlet` per app and ONE `Pipeline` per parent path.
|
|
30
|
+
|
|
31
|
+
Other than that, just use `react-router` like intended. `weaver/routing` has especially tested against going back and forth rapidly and works flawlessly in strict mode, so you don't have to think about the logic behind it!
|
|
32
|
+
|
|
33
|
+
While the route is delayed, the previous route is still displayed to ensure a smooth tranition to your likings.
|
|
34
|
+
|
|
35
|
+
Example usage with 2 endpoints, router delayed for `500ms`:
|
|
36
|
+
|
|
37
|
+
```tsx
|
|
38
|
+
import { DelayedOutlet, Pipeline } from '@neveranyart/weaver/routing';
|
|
39
|
+
import { StrictMode, Suspense } from 'react';
|
|
40
|
+
import { createRoot } from 'react-dom/client';
|
|
41
|
+
import { createBrowserRouter, Link, RouterProvider } from 'react-router';
|
|
42
|
+
|
|
43
|
+
function Root() {
|
|
44
|
+
return (
|
|
45
|
+
<main>
|
|
46
|
+
<DelayedOutlet delay={500} />
|
|
47
|
+
</main>
|
|
48
|
+
);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
function Home() {
|
|
52
|
+
return (
|
|
53
|
+
<Pipeline title={'Home'} debugName={'Home'} parentPath={'/'}>
|
|
54
|
+
<p>Home</p>
|
|
55
|
+
<Link to="/projects">Navigate</Link>
|
|
56
|
+
</Pipeline>
|
|
57
|
+
);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
const router = createBrowserRouter([
|
|
61
|
+
{
|
|
62
|
+
path: '/',
|
|
63
|
+
element: <Root />,
|
|
64
|
+
children: [
|
|
65
|
+
{
|
|
66
|
+
index: true,
|
|
67
|
+
element: (
|
|
68
|
+
<Suspense>
|
|
69
|
+
<Home />
|
|
70
|
+
</Suspense>
|
|
71
|
+
),
|
|
72
|
+
},
|
|
73
|
+
{
|
|
74
|
+
path: '/projects/*',
|
|
75
|
+
element: (
|
|
76
|
+
<Suspense>
|
|
77
|
+
<Pipeline
|
|
78
|
+
title={'Projects'}
|
|
79
|
+
debugName={'Projects'}
|
|
80
|
+
{/* The `parentPath` is required and must match the actual route path */}
|
|
81
|
+
parentPath={'/projects'}
|
|
82
|
+
>
|
|
83
|
+
<p>Projects</p>
|
|
84
|
+
<Link to="/">Navigate</Link>
|
|
85
|
+
</Pipeline>
|
|
86
|
+
</Suspense>
|
|
87
|
+
),
|
|
88
|
+
},
|
|
89
|
+
],
|
|
90
|
+
},
|
|
91
|
+
]);
|
|
92
|
+
|
|
93
|
+
createRoot(document.getElementById('root')!).render(
|
|
94
|
+
<StrictMode>
|
|
95
|
+
<RouterProvider router={router} />
|
|
96
|
+
</StrictMode>
|
|
97
|
+
);
|
|
9
98
|
```
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
99
|
+
|
|
100
|
+
`weaver/routing` also provides a quick way to react to state changes with a cool hook called `useWeaverState`. Containing 4 states for you to play with:
|
|
101
|
+
|
|
102
|
+
```ts
|
|
103
|
+
const pageRendered = useWeaverState('pageRendered');
|
|
104
|
+
const activePipeline = useWeaverState('activePipeline');
|
|
105
|
+
const activeParent = useWeaverState('activeParent');
|
|
106
|
+
const navigating = useWeaverState('navigating');
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
When a route change happens, this is how states in `weaver/routing` changes when a route change is successful:
|
|
110
|
+
|
|
111
|
+
`+`: Other events/information.
|
|
112
|
+
`!`: State changes.
|
|
113
|
+
|
|
13
114
|
```
|
|
115
|
+
+ Current `Pipeline` path: "/""
|
|
116
|
+
! pageRendered -> false, navigating -> true.
|
|
117
|
+
+ Receives new parent.
|
|
118
|
+
+ Delay route change.
|
|
119
|
+
+ Set new `Pipeline`.
|
|
120
|
+
+ `Pipeline` path "/" start unmounting process.
|
|
121
|
+
+ New `Pipeline` path: "/projects".
|
|
122
|
+
! activePipeline -> "/projects".
|
|
123
|
+
! navigating -> false.
|
|
124
|
+
+ New `Pipeline` start mounting process.
|
|
125
|
+
! pageRendered -> true, activeParent -> "/projects".
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
When a route change is cancelled by user going back mid delay:
|
|
129
|
+
|
|
130
|
+
```
|
|
131
|
+
+ Current `Pipeline` path: "/""
|
|
132
|
+
! pageRendered -> false, navigating -> true.
|
|
133
|
+
+ Receives new parent.
|
|
134
|
+
+ Delay route change.
|
|
135
|
+
+ User cancelled.
|
|
136
|
+
! pageRendered -> true, navigating -> false.
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
Overall:
|
|
140
|
+
- `pageRendered` covers the whole routing process. It is the recommended way of knowing if the content is ready to be displayed or not.
|
|
141
|
+
- `activePipeline` is for knowing which Pipeline has taken over previous one.
|
|
142
|
+
- `activeParent` tells which Pipeline has delivered its components on screen.
|
|
143
|
+
- `navigating` tells when `DelayedOutlet` handles routing.
|
|
144
|
+
|
|
145
|
+
### Hooks
|
|
146
|
+
`weaver` provides a reasonable amount of DOM hooks, intensive hooks will only allow callbacks usage to avoid React re-render.
|
|
147
|
+
|
|
148
|
+
### Scene
|
|
149
|
+
|
|
14
150
|
|
|
15
151
|
The package comes packed with:
|
|
16
152
|
- `Pipeline`, `DelayedOutlet`: CSR router handler built for transition animation, hiding initialization lags behind a wall while allowing SEO to work.
|
package/dist/hooks.js
CHANGED
package/dist/hooks.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/hooks/index.ts","../src/hooks/breakpoints.ts","../src/hooks/screenCallback.ts","../src/hooks/effectOnce.ts","../src/hooks/lenisCallback.ts","../src/setup.ts","../src/hooks/orbit.ts","../src/hooks/mouseCallback.ts","../src/hooks/navigateAnchor.ts","../src/hooks/rawParams.ts","../src/hooks/routeNormalizer.ts","../src/hooks/screen.ts","../src/hooks/viewport.ts"],"sourcesContent":["import { useBreakpoints } from './breakpoints';\nimport { useEffectOnce, useLayoutEffectOnce } from './effectOnce';\nimport { useLenisCallback } from './lenisCallback';\nimport { useMouseCallback } from './mouseCallback';\nimport { useNavigateAnchor } from './navigateAnchor';\nimport { useOrbit } from './orbit';\nimport { useRawParams } from './rawParams';\nimport { useRouteNormalizer } from './routeNormalizer';\nimport { useScreen } from './screen';\nimport { useScreenCallback } from './screenCallback';\nimport { useViewport } from './viewport';\n\nexport {\n useBreakpoints,\n useEffectOnce,\n useLayoutEffectOnce,\n useLenisCallback,\n useMouseCallback,\n useNavigateAnchor,\n useOrbit,\n useRawParams,\n useRouteNormalizer,\n useScreen,\n useScreenCallback,\n useViewport,\n};\n","import { useCallback, useState } from 'react';\nimport { useScreenCallback } from './screenCallback';\n\nexport function useBreakpoints(breakpoints?: number[] | null) {\n const getBreakpoint = useCallback(\n (width: number) => {\n const processingBreakpoints = !breakpoints\n ? [640, 768, 1024, 1280, 1536]\n : breakpoints;\n\n if (!processingBreakpoints) {\n throw Error(\"Uhhh... so you don't want a breakpoint? Just say it.\");\n }\n\n let result = processingBreakpoints!.length;\n for (let index = 0; index < processingBreakpoints!.length; index++) {\n if (width < processingBreakpoints![index]) {\n result = index;\n break;\n }\n }\n\n return result;\n },\n [breakpoints]\n );\n\n const [breakAt, setBreakAt] = useState<number>(\n getBreakpoint(document.body.clientWidth)\n );\n\n const breakpointCheck = useCallback(\n (latest: { width: number; height: number }) => {\n const result = getBreakpoint(latest.width);\n if (result !== breakAt) {\n setBreakAt(result);\n }\n },\n [breakAt, getBreakpoint]\n );\n useScreenCallback(breakpointCheck);\n\n return breakAt;\n}\n","import { useLayoutEffect } from 'react';\n\nexport interface ScreenCallbackValues {\n width: number;\n height: number;\n}\n\ntype Callback = (props: ScreenCallbackValues) => void;\n\nexport function useScreenCallback(\n callback: Callback,\n options?: { initialCall?: boolean }\n) {\n useLayoutEffect(() => {\n const reportScreen = () =>\n callback({\n width: document.body.clientWidth,\n height: document.documentElement.clientHeight,\n });\n\n // Call it first time when the hook was initialized.\n if (options?.initialCall) {\n reportScreen();\n }\n\n window.addEventListener('resize', reportScreen, { passive: true });\n\n return () => {\n window.removeEventListener('resize', reportScreen);\n };\n }, [callback, options?.initialCall]);\n}\n","import { useEffect, useLayoutEffect } from 'react';\n\nexport function useEffectOnce(callback: React.EffectCallback) {\n // eslint-disable-next-line react-hooks/exhaustive-deps\n useEffect(callback, []);\n}\n\nexport function useLayoutEffectOnce(callback: React.EffectCallback) {\n // eslint-disable-next-line react-hooks/exhaustive-deps\n useLayoutEffect(callback, []);\n}\n","import { type RefObject, useCallback, useLayoutEffect, useMemo } from 'react';\nimport { weaverSetup } from '../setup';\nimport { useOrbit } from './orbit';\n\ninterface HookOptions {\n /**\n * Hook will report when first initialized without waiting for scroll event to actually happens.\n */\n initialCall?: boolean;\n /**\n * Set an element to only call when the element is actually entering the viewport (with 25% `rootMargin`).\n */\n intersectOn?: RefObject<HTMLOrSVGElement | null>;\n}\n\nexport const scrollCallbackReason = {\n Resize: 'resize',\n Scroll: 'scroll',\n Initialize: 'initialize',\n} as const;\nexport type ScrollCallbackReason =\n (typeof scrollCallbackReason)[keyof typeof scrollCallbackReason];\n\ntype Callback = (latest: number, reason: ScrollCallbackReason) => void;\n\nexport function useLenisCallback(callback: Callback, options?: HookOptions) {\n const callbackWrapScroll = useCallback(\n () =>\n callback(\n weaverSetup._lenisInstance!.actualScroll,\n scrollCallbackReason.Scroll\n ),\n [callback]\n );\n const callbackWrapResize = useCallback(\n () =>\n callback(\n weaverSetup._lenisInstance!.actualScroll,\n scrollCallbackReason.Resize\n ),\n [callback]\n );\n\n const intersectOn = useMemo(\n () => options?.intersectOn,\n [options?.intersectOn]\n );\n const initialCall = useMemo(\n () => options?.initialCall,\n [options?.initialCall]\n );\n\n useOrbit({\n target: intersectOn as RefObject<HTMLElement | null> | undefined,\n events: {\n onIntersect(entry) {\n if (entry.isIntersecting) {\n weaverSetup._lenisInstance!.on('scroll', callbackWrapScroll);\n window.addEventListener('resize', callbackWrapResize);\n } else {\n weaverSetup._lenisInstance!.off('scroll', callbackWrapScroll);\n window.removeEventListener('resize', callbackWrapResize);\n }\n },\n },\n rootMargin: '50% 0px 50% 0px',\n });\n\n useLayoutEffect(() => {\n if (!intersectOn) {\n weaverSetup._lenisInstance!.on('scroll', callbackWrapScroll);\n window.addEventListener('resize', callbackWrapResize);\n }\n\n if (initialCall) {\n callback(\n weaverSetup._lenisInstance!.actualScroll,\n scrollCallbackReason.Initialize\n );\n }\n\n return () => {\n weaverSetup._lenisInstance!.off('scroll', callbackWrapScroll);\n window.removeEventListener('resize', callbackWrapResize);\n };\n }, [\n callback,\n callbackWrapResize,\n callbackWrapScroll,\n initialCall,\n intersectOn,\n ]);\n}\n","import Lenis from 'lenis';\nimport { ReactNode } from 'react';\n\nexport type BasicTunnelIn = ({ children }: { children: ReactNode }) => null;\n\nclass WeaverSetup {\n /**\n * This variable is handled internally by weaver. **Do not use**.\n */\n get _lenisInstance(): Lenis | undefined {\n return (globalThis as any).__weaverLenis;\n }\n set _lenisInstance(val: Lenis | undefined) {\n (globalThis as any).__weaverLenis = val;\n }\n\n /**\n * This variable is handled internally by weaver. **Do not use**.\n */\n get _Default3DTunnelIn(): BasicTunnelIn | undefined {\n return (globalThis as any).__weaver3DTunnel;\n }\n set _Default3DTunnelIn(val: BasicTunnelIn | undefined) {\n (globalThis as any).__weaver3DTunnel = val;\n }\n\n setLenisInstance(instance: Lenis) {\n this._lenisInstance = instance;\n }\n set3DTunnel(tunnelIn: BasicTunnelIn) {\n this._Default3DTunnelIn = tunnelIn;\n }\n}\n\nexport const weaverSetup = new WeaverSetup();\n","import { type RefObject, useLayoutEffect } from 'react';\n\n/**\n * A simple Orbit hook.\n *\n * @param target HTML element ref to attach to.\n * @param events Specify which events should the orbit tracks.\n */\nexport function useOrbit(options: {\n target?: RefObject<HTMLElement | null>;\n events: {\n onResize?: (entry: ResizeObserverEntry) => void;\n onIntersect?: (entry: IntersectionObserverEntry) => void;\n };\n rootMargin?: string;\n}) {\n const { onResize, onIntersect } = options.events;\n const { rootMargin = '25% 0px 25% 0px' } = options;\n\n useLayoutEffect(() => {\n if (!options.target) return;\n if (!options.target.current) return;\n\n let orbitResize = undefined;\n if (onResize) {\n orbitResize = new ResizeObserver((entries) => onResize(entries[0]));\n orbitResize.observe(options.target.current);\n }\n let orbitIntersect = undefined;\n if (onIntersect) {\n orbitIntersect = new IntersectionObserver(\n (entries) => onIntersect(entries[0]),\n { rootMargin }\n );\n orbitIntersect.observe(options.target.current);\n }\n\n return () => {\n orbitResize?.disconnect();\n orbitIntersect?.disconnect();\n };\n }, [onIntersect, onResize, rootMargin, options.target]);\n}\n","import { useId, useLayoutEffect } from 'react';\n\nexport interface MousePositionValues {\n x: number;\n y: number;\n}\n\ninterface MouseCallback {\n callback: (latest: MousePositionValues) => void;\n options: HookOptions;\n}\n\ninterface HookOptions {\n normalized?: boolean;\n}\n\ntype Callback = (latest: MousePositionValues) => void;\n\nclass MouseEventDistributor {\n private callbacks = new Map<string, MouseCallback>();\n private eventRegistered = false;\n\n constructor() {\n if (this.eventRegistered) return;\n\n window.addEventListener('pointermove', this.callbackLoop.bind(this), {\n passive: true,\n });\n\n this.eventRegistered = true;\n }\n\n addCallbackLoop(\n id: string,\n callback: (latest: MousePositionValues) => void,\n options: HookOptions\n ) {\n this.callbacks.set(id, { callback, options });\n }\n\n removeCallbackLoop(id: string) {\n this.callbacks.delete(id);\n }\n\n private processEvent(event: PointerEvent) {\n const mouse = {\n x: event.clientX,\n y: event.clientY,\n };\n const mouseNormalized = {\n x: mouse.x / (document.body.clientWidth / 2) - 1,\n y: mouse.y / (document.documentElement.clientHeight / 2) - 1,\n };\n\n return [mouse, mouseNormalized];\n }\n\n private callbackLoop(event: PointerEvent) {\n if (event.pointerType !== 'mouse') return;\n\n const callbacks = this.callbacks.entries();\n const [mouse, mouseNormalized] = this.processEvent(event);\n\n let inspecting = callbacks.next().value;\n while (inspecting) {\n if (inspecting[1].options.normalized) {\n inspecting[1].callback(mouseNormalized);\n } else {\n inspecting[1].callback(mouse);\n }\n\n inspecting = callbacks.next().value;\n }\n }\n}\n\nconst distributor = new MouseEventDistributor();\n\nexport function useMouseCallback(\n callback: Callback,\n options: HookOptions = {\n normalized: true,\n }\n) {\n const id = useId();\n\n useLayoutEffect(() => {\n distributor.addCallbackLoop(id, callback, options);\n\n return () => {\n distributor.removeCallbackLoop(id);\n };\n }, [callback, id, options]);\n}\n","import { useCallback } from 'react';\nimport { useNavigate } from 'react-router';\nimport { weaverSetup } from '../setup';\n\nexport function useNavigateAnchor(onNavigate?: () => void) {\n const navigate = useNavigate();\n\n return useCallback(\n (event: React.MouseEvent<HTMLAnchorElement, MouseEvent>) => {\n event.preventDefault();\n const href = event.currentTarget.getAttribute('href');\n if (href) {\n if (onNavigate) {\n onNavigate();\n }\n\n if (href !== window.location.pathname) {\n navigate(event.currentTarget.getAttribute('href') ?? '');\n } else {\n weaverSetup._lenisInstance!.scrollTo(0, { duration: 2 });\n }\n }\n },\n [onNavigate, navigate]\n );\n}\n","import { useLocation } from 'react-router';\n\nexport function useRawParams(\n prefix: string,\n limit?: number\n): (string | undefined)[] {\n const { pathname } = useLocation();\n\n const prefixedPath = pathname.replace(new RegExp(prefix), '');\n if (prefixedPath === pathname) {\n return [];\n }\n\n return prefixedPath\n .split('/')\n .filter((param) => param !== '')\n .slice(limit);\n}\n","import { useCallback, useLayoutEffect } from 'react';\nimport { useLocation, useNavigate } from 'react-router';\n\nexport function useRouteNormalizer(options: { autoReplace: boolean }) {\n const { pathname } = useLocation();\n const navigate = useNavigate();\n\n const normalizer = useCallback(\n (input: string) => input.replace(/\\/+\\//g, () => '/'),\n []\n );\n\n useLayoutEffect(() => {\n const result = normalizer(pathname);\n if (options.autoReplace && result !== pathname) {\n window.location.replace(result);\n }\n }, [options.autoReplace, pathname, navigate, normalizer]);\n\n return {\n pathname,\n normalizer,\n };\n}\n","import { useCallback, useLayoutEffect, useState } from 'react';\n\nexport function useScreen() {\n const [width, setWidth] = useState(document.body.clientWidth);\n const [height, setHeight] = useState(document.documentElement.clientHeight);\n\n const setScreen = useCallback(() => {\n setWidth(document.body.clientWidth);\n setHeight(document.documentElement.clientHeight);\n }, []);\n\n useLayoutEffect(() => {\n window.addEventListener('resize', setScreen, { passive: true });\n\n return () => {\n window.removeEventListener('resize', setScreen);\n };\n }, [setScreen]);\n\n return { width: width, height: height };\n}\n","import { useThree } from '@react-three/fiber';\nimport { useCallback, useState } from 'react';\nimport { OrthographicCamera, PerspectiveCamera } from 'three';\nimport { useScreenCallback } from './screenCallback';\n\nexport function useViewport(\n customCamera?: OrthographicCamera | PerspectiveCamera\n) {\n const { viewport, camera } = useThree();\n\n const [width, setWidth] = useState(viewport.getCurrentViewport().width);\n const [height, setHeight] = useState(viewport.getCurrentViewport().height);\n\n const viewportUpdate = useCallback(() => {\n const actualViewport = viewport.getCurrentViewport(customCamera ?? camera);\n setWidth(actualViewport.width);\n setHeight(actualViewport.height);\n }, [camera, customCamera, viewport]);\n useScreenCallback(viewportUpdate);\n\n return { width: width, height: height };\n}\n"],"mappings":"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","names":["import_react","import_react","import_react","import_react","import_react","import_react","import_react_router","import_react","import_react_router","import_react","import_react"]}
|
|
1
|
+
{"version":3,"sources":["../src/hooks/index.ts","../src/hooks/breakpoints.ts","../src/hooks/screenCallback.ts","../src/hooks/effectOnce.ts","../src/hooks/lenisCallback.ts","../src/setup.ts","../src/hooks/orbit.ts","../src/hooks/mouseCallback.ts","../src/hooks/navigateAnchor.ts","../src/hooks/rawParams.ts","../src/hooks/routeNormalizer.ts","../src/hooks/screen.ts","../src/hooks/viewport.ts"],"sourcesContent":["import { useBreakpoints } from './breakpoints';\nimport { useEffectOnce, useLayoutEffectOnce } from './effectOnce';\nimport { useLenisCallback } from './lenisCallback';\nimport { useMouseCallback } from './mouseCallback';\nimport { useNavigateAnchor } from './navigateAnchor';\nimport { useOrbit } from './orbit';\nimport { useRawParams } from './rawParams';\nimport { useRouteNormalizer } from './routeNormalizer';\nimport { useScreen } from './screen';\nimport { useScreenCallback } from './screenCallback';\nimport { useViewport } from './viewport';\n\nexport {\n useBreakpoints,\n useEffectOnce,\n useLayoutEffectOnce,\n useLenisCallback,\n useMouseCallback,\n useNavigateAnchor,\n useOrbit,\n useRawParams,\n useRouteNormalizer,\n useScreen,\n useScreenCallback,\n useViewport,\n};\n","import { useCallback, useState } from 'react';\nimport { useScreenCallback } from './screenCallback';\n\nexport function useBreakpoints(breakpoints?: number[] | null) {\n const getBreakpoint = useCallback(\n (width: number) => {\n const processingBreakpoints = !breakpoints\n ? [640, 768, 1024, 1280, 1536]\n : breakpoints;\n\n if (!processingBreakpoints) {\n throw Error(\"Uhhh... so you don't want a breakpoint? Just say it.\");\n }\n\n let result = processingBreakpoints!.length;\n for (let index = 0; index < processingBreakpoints!.length; index++) {\n if (width < processingBreakpoints![index]) {\n result = index;\n break;\n }\n }\n\n return result;\n },\n [breakpoints]\n );\n\n const [breakAt, setBreakAt] = useState<number>(\n getBreakpoint(document.body.clientWidth)\n );\n\n const breakpointCheck = useCallback(\n (latest: { width: number; height: number }) => {\n const result = getBreakpoint(latest.width);\n if (result !== breakAt) {\n setBreakAt(result);\n }\n },\n [breakAt, getBreakpoint]\n );\n useScreenCallback(breakpointCheck);\n\n return breakAt;\n}\n","import { useLayoutEffect } from 'react';\n\nexport interface ScreenCallbackValues {\n width: number;\n height: number;\n}\n\ntype Callback = (props: ScreenCallbackValues) => void;\n\nexport function useScreenCallback(\n callback: Callback,\n options?: { initialCall?: boolean }\n) {\n useLayoutEffect(() => {\n const reportScreen = () =>\n callback({\n width: document.body.clientWidth,\n height: document.documentElement.clientHeight,\n });\n\n // Call it first time when the hook was initialized.\n if (options?.initialCall) {\n reportScreen();\n }\n\n window.addEventListener('resize', reportScreen, { passive: true });\n\n return () => {\n window.removeEventListener('resize', reportScreen);\n };\n }, [callback, options?.initialCall]);\n}\n","import { useEffect, useLayoutEffect } from 'react';\n\nexport function useEffectOnce(callback: React.EffectCallback) {\n // eslint-disable-next-line react-hooks/exhaustive-deps\n useEffect(callback, []);\n}\n\nexport function useLayoutEffectOnce(callback: React.EffectCallback) {\n // eslint-disable-next-line react-hooks/exhaustive-deps\n useLayoutEffect(callback, []);\n}\n","import { type RefObject, useCallback, useLayoutEffect, useMemo } from 'react';\nimport { weaverSetup } from '../setup';\nimport { useOrbit } from './orbit';\n\ninterface HookOptions {\n /**\n * Hook will report when first initialized without waiting for scroll event to actually happens.\n */\n initialCall?: boolean;\n /**\n * Set an element to only call when the element is actually entering the viewport (with 25% `rootMargin`).\n */\n intersectOn?: RefObject<HTMLOrSVGElement | null>;\n}\n\nexport const scrollCallbackReason = {\n Resize: 'resize',\n Scroll: 'scroll',\n Initialize: 'initialize',\n} as const;\nexport type ScrollCallbackReason =\n (typeof scrollCallbackReason)[keyof typeof scrollCallbackReason];\n\ntype Callback = (latest: number, reason: ScrollCallbackReason) => void;\n\nexport function useLenisCallback(callback: Callback, options?: HookOptions) {\n const callbackWrapScroll = useCallback(\n () =>\n callback(\n weaverSetup._lenisInstance!.actualScroll,\n scrollCallbackReason.Scroll\n ),\n [callback]\n );\n const callbackWrapResize = useCallback(\n () =>\n callback(\n weaverSetup._lenisInstance!.actualScroll,\n scrollCallbackReason.Resize\n ),\n [callback]\n );\n\n const intersectOn = useMemo(\n () => options?.intersectOn,\n [options?.intersectOn]\n );\n const initialCall = useMemo(\n () => options?.initialCall,\n [options?.initialCall]\n );\n\n useOrbit({\n target: intersectOn as RefObject<HTMLElement | null> | undefined,\n events: {\n onIntersect(entry) {\n if (entry.isIntersecting) {\n weaverSetup._lenisInstance!.on('scroll', callbackWrapScroll);\n window.addEventListener('resize', callbackWrapResize);\n } else {\n weaverSetup._lenisInstance!.off('scroll', callbackWrapScroll);\n window.removeEventListener('resize', callbackWrapResize);\n }\n },\n },\n rootMargin: '50% 0px 50% 0px',\n });\n\n useLayoutEffect(() => {\n if (!intersectOn) {\n weaverSetup._lenisInstance!.on('scroll', callbackWrapScroll);\n window.addEventListener('resize', callbackWrapResize);\n }\n\n if (initialCall) {\n callback(\n weaverSetup._lenisInstance!.actualScroll,\n scrollCallbackReason.Initialize\n );\n }\n\n return () => {\n weaverSetup._lenisInstance!.off('scroll', callbackWrapScroll);\n window.removeEventListener('resize', callbackWrapResize);\n };\n }, [\n callback,\n callbackWrapResize,\n callbackWrapScroll,\n initialCall,\n intersectOn,\n ]);\n}\n","import Lenis from 'lenis';\nimport { ReactNode } from 'react';\n\nexport type BasicTunnelIn = ({ children }: { children: ReactNode }) => null;\n\nclass WeaverSetup {\n /**\n * This variable is handled internally by weaver. **Do not use**.\n */\n get _lenisInstance(): Lenis | undefined {\n return (globalThis as any).__weaverLenis;\n }\n set _lenisInstance(val: Lenis | undefined) {\n (globalThis as any).__weaverLenis = val;\n }\n\n /**\n * This variable is handled internally by weaver. **Do not use**.\n */\n get _Default3DTunnelIn(): BasicTunnelIn | undefined {\n return (globalThis as any).__weaver3DTunnel;\n }\n set _Default3DTunnelIn(val: BasicTunnelIn | undefined) {\n (globalThis as any).__weaver3DTunnel = val;\n }\n\n setLenisInstance(instance: Lenis) {\n this._lenisInstance = instance;\n }\n set3DTunnel(tunnelIn: BasicTunnelIn) {\n this._Default3DTunnelIn = tunnelIn;\n }\n}\n\nexport const weaverSetup = new WeaverSetup();\n","import { type RefObject, useLayoutEffect } from 'react';\n\n/**\n * A simple Orbit hook.\n *\n * @param target HTML element ref to attach to.\n * @param events Specify which events should the orbit tracks.\n */\nexport function useOrbit(options: {\n target?: RefObject<HTMLElement | null>;\n events: {\n onResize?: (entry: ResizeObserverEntry) => void;\n onIntersect?: (entry: IntersectionObserverEntry) => void;\n };\n rootMargin?: string;\n}) {\n const { onResize, onIntersect } = options.events;\n const { rootMargin = '25% 0px 25% 0px' } = options;\n\n useLayoutEffect(() => {\n if (!options.target) return;\n if (!options.target.current) return;\n\n let orbitResize = undefined;\n if (onResize) {\n orbitResize = new ResizeObserver((entries) => onResize(entries[0]));\n orbitResize.observe(options.target.current);\n }\n let orbitIntersect = undefined;\n if (onIntersect) {\n orbitIntersect = new IntersectionObserver(\n (entries) => onIntersect(entries[0]),\n { rootMargin }\n );\n orbitIntersect.observe(options.target.current);\n }\n\n return () => {\n orbitResize?.disconnect();\n orbitIntersect?.disconnect();\n };\n }, [onIntersect, onResize, rootMargin, options.target]);\n}\n","import { useId, useLayoutEffect } from 'react';\n\nexport interface MousePositionValues {\n x: number;\n y: number;\n}\n\ninterface MouseCallback {\n callback: (latest: MousePositionValues) => void;\n options: HookOptions;\n}\n\ninterface HookOptions {\n normalized?: boolean;\n}\n\ntype Callback = (latest: MousePositionValues) => void;\n\nclass MouseEventDistributor {\n private callbacks = new Map<string, MouseCallback>();\n private eventRegistered = false;\n\n constructor() {\n if (this.eventRegistered) return;\n\n window.addEventListener('pointermove', this.callbackLoop.bind(this), {\n passive: true,\n });\n\n this.eventRegistered = true;\n }\n\n addCallbackLoop(\n id: string,\n callback: (latest: MousePositionValues) => void,\n options: HookOptions\n ) {\n this.callbacks.set(id, { callback, options });\n }\n\n removeCallbackLoop(id: string) {\n this.callbacks.delete(id);\n }\n\n private processEvent(event: PointerEvent) {\n const mouse = {\n x: event.clientX,\n y: event.clientY,\n };\n const mouseNormalized = {\n x: mouse.x / (document.body.clientWidth / 2) - 1,\n y: mouse.y / (document.documentElement.clientHeight / 2) - 1,\n };\n\n return [mouse, mouseNormalized];\n }\n\n private callbackLoop(event: PointerEvent) {\n if (event.pointerType !== 'mouse') return;\n\n const callbacks = this.callbacks.entries();\n const [mouse, mouseNormalized] = this.processEvent(event);\n\n let inspecting = callbacks.next().value;\n while (inspecting) {\n if (inspecting[1].options.normalized) {\n inspecting[1].callback(mouseNormalized);\n } else {\n inspecting[1].callback(mouse);\n }\n\n inspecting = callbacks.next().value;\n }\n }\n}\n\nconst distributor = new MouseEventDistributor();\n\nexport function useMouseCallback(\n callback: Callback,\n options: HookOptions = {\n normalized: true,\n }\n) {\n const id = useId();\n\n useLayoutEffect(() => {\n distributor.addCallbackLoop(id, callback, options);\n\n return () => {\n distributor.removeCallbackLoop(id);\n };\n }, [callback, id, options]);\n}\n","import { useCallback } from 'react';\nimport { useNavigate } from 'react-router';\n\nexport function useNavigateAnchor(onNavigate?: () => void) {\n const navigate = useNavigate();\n\n return useCallback(\n (event: React.MouseEvent<HTMLAnchorElement, MouseEvent>) => {\n event.preventDefault();\n const href = event.currentTarget.getAttribute('href');\n if (href) {\n if (onNavigate) {\n onNavigate();\n }\n\n if (href !== window.location.pathname) {\n navigate(event.currentTarget.getAttribute('href') ?? '');\n }\n }\n },\n [onNavigate, navigate]\n );\n}\n","import { useLocation } from 'react-router';\n\nexport function useRawParams(\n prefix: string,\n limit?: number\n): (string | undefined)[] {\n const { pathname } = useLocation();\n\n const prefixedPath = pathname.replace(new RegExp(prefix), '');\n if (prefixedPath === pathname) {\n return [];\n }\n\n return prefixedPath\n .split('/')\n .filter((param) => param !== '')\n .slice(limit);\n}\n","import { useCallback, useLayoutEffect } from 'react';\nimport { useLocation, useNavigate } from 'react-router';\n\nexport function useRouteNormalizer(options: { autoReplace: boolean }) {\n const { pathname } = useLocation();\n const navigate = useNavigate();\n\n const normalizer = useCallback(\n (input: string) => input.replace(/\\/+\\//g, () => '/'),\n []\n );\n\n useLayoutEffect(() => {\n const result = normalizer(pathname);\n if (options.autoReplace && result !== pathname) {\n window.location.replace(result);\n }\n }, [options.autoReplace, pathname, navigate, normalizer]);\n\n return {\n pathname,\n normalizer,\n };\n}\n","import { useCallback, useLayoutEffect, useState } from 'react';\n\nexport function useScreen() {\n const [width, setWidth] = useState(document.body.clientWidth);\n const [height, setHeight] = useState(document.documentElement.clientHeight);\n\n const setScreen = useCallback(() => {\n setWidth(document.body.clientWidth);\n setHeight(document.documentElement.clientHeight);\n }, []);\n\n useLayoutEffect(() => {\n window.addEventListener('resize', setScreen, { passive: true });\n\n return () => {\n window.removeEventListener('resize', setScreen);\n };\n }, [setScreen]);\n\n return { width: width, height: height };\n}\n","import { useThree } from '@react-three/fiber';\nimport { useCallback, useState } from 'react';\nimport { OrthographicCamera, PerspectiveCamera } from 'three';\nimport { useScreenCallback } from './screenCallback';\n\nexport function useViewport(\n customCamera?: OrthographicCamera | PerspectiveCamera\n) {\n const { viewport, camera } = useThree();\n\n const [width, setWidth] = useState(viewport.getCurrentViewport().width);\n const [height, setHeight] = useState(viewport.getCurrentViewport().height);\n\n const viewportUpdate = useCallback(() => {\n const actualViewport = viewport.getCurrentViewport(customCamera ?? camera);\n setWidth(actualViewport.width);\n setHeight(actualViewport.height);\n }, [camera, customCamera, viewport]);\n useScreenCallback(viewportUpdate);\n\n return { width: width, height: height };\n}\n"],"mappings":"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","names":["import_react","import_react","import_react","import_react","import_react","import_react","import_react_router","import_react","import_react_router","import_react","import_react"]}
|
package/dist/hooks.mjs
CHANGED
package/dist/hooks.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/hooks/breakpoints.ts","../src/hooks/screenCallback.ts","../src/hooks/effectOnce.ts","../src/hooks/lenisCallback.ts","../src/setup.ts","../src/hooks/orbit.ts","../src/hooks/mouseCallback.ts","../src/hooks/navigateAnchor.ts","../src/hooks/rawParams.ts","../src/hooks/routeNormalizer.ts","../src/hooks/screen.ts","../src/hooks/viewport.ts"],"sourcesContent":["import { useCallback, useState } from 'react';\nimport { useScreenCallback } from './screenCallback';\n\nexport function useBreakpoints(breakpoints?: number[] | null) {\n const getBreakpoint = useCallback(\n (width: number) => {\n const processingBreakpoints = !breakpoints\n ? [640, 768, 1024, 1280, 1536]\n : breakpoints;\n\n if (!processingBreakpoints) {\n throw Error(\"Uhhh... so you don't want a breakpoint? Just say it.\");\n }\n\n let result = processingBreakpoints!.length;\n for (let index = 0; index < processingBreakpoints!.length; index++) {\n if (width < processingBreakpoints![index]) {\n result = index;\n break;\n }\n }\n\n return result;\n },\n [breakpoints]\n );\n\n const [breakAt, setBreakAt] = useState<number>(\n getBreakpoint(document.body.clientWidth)\n );\n\n const breakpointCheck = useCallback(\n (latest: { width: number; height: number }) => {\n const result = getBreakpoint(latest.width);\n if (result !== breakAt) {\n setBreakAt(result);\n }\n },\n [breakAt, getBreakpoint]\n );\n useScreenCallback(breakpointCheck);\n\n return breakAt;\n}\n","import { useLayoutEffect } from 'react';\n\nexport interface ScreenCallbackValues {\n width: number;\n height: number;\n}\n\ntype Callback = (props: ScreenCallbackValues) => void;\n\nexport function useScreenCallback(\n callback: Callback,\n options?: { initialCall?: boolean }\n) {\n useLayoutEffect(() => {\n const reportScreen = () =>\n callback({\n width: document.body.clientWidth,\n height: document.documentElement.clientHeight,\n });\n\n // Call it first time when the hook was initialized.\n if (options?.initialCall) {\n reportScreen();\n }\n\n window.addEventListener('resize', reportScreen, { passive: true });\n\n return () => {\n window.removeEventListener('resize', reportScreen);\n };\n }, [callback, options?.initialCall]);\n}\n","import { useEffect, useLayoutEffect } from 'react';\n\nexport function useEffectOnce(callback: React.EffectCallback) {\n // eslint-disable-next-line react-hooks/exhaustive-deps\n useEffect(callback, []);\n}\n\nexport function useLayoutEffectOnce(callback: React.EffectCallback) {\n // eslint-disable-next-line react-hooks/exhaustive-deps\n useLayoutEffect(callback, []);\n}\n","import { type RefObject, useCallback, useLayoutEffect, useMemo } from 'react';\nimport { weaverSetup } from '../setup';\nimport { useOrbit } from './orbit';\n\ninterface HookOptions {\n /**\n * Hook will report when first initialized without waiting for scroll event to actually happens.\n */\n initialCall?: boolean;\n /**\n * Set an element to only call when the element is actually entering the viewport (with 25% `rootMargin`).\n */\n intersectOn?: RefObject<HTMLOrSVGElement | null>;\n}\n\nexport const scrollCallbackReason = {\n Resize: 'resize',\n Scroll: 'scroll',\n Initialize: 'initialize',\n} as const;\nexport type ScrollCallbackReason =\n (typeof scrollCallbackReason)[keyof typeof scrollCallbackReason];\n\ntype Callback = (latest: number, reason: ScrollCallbackReason) => void;\n\nexport function useLenisCallback(callback: Callback, options?: HookOptions) {\n const callbackWrapScroll = useCallback(\n () =>\n callback(\n weaverSetup._lenisInstance!.actualScroll,\n scrollCallbackReason.Scroll\n ),\n [callback]\n );\n const callbackWrapResize = useCallback(\n () =>\n callback(\n weaverSetup._lenisInstance!.actualScroll,\n scrollCallbackReason.Resize\n ),\n [callback]\n );\n\n const intersectOn = useMemo(\n () => options?.intersectOn,\n [options?.intersectOn]\n );\n const initialCall = useMemo(\n () => options?.initialCall,\n [options?.initialCall]\n );\n\n useOrbit({\n target: intersectOn as RefObject<HTMLElement | null> | undefined,\n events: {\n onIntersect(entry) {\n if (entry.isIntersecting) {\n weaverSetup._lenisInstance!.on('scroll', callbackWrapScroll);\n window.addEventListener('resize', callbackWrapResize);\n } else {\n weaverSetup._lenisInstance!.off('scroll', callbackWrapScroll);\n window.removeEventListener('resize', callbackWrapResize);\n }\n },\n },\n rootMargin: '50% 0px 50% 0px',\n });\n\n useLayoutEffect(() => {\n if (!intersectOn) {\n weaverSetup._lenisInstance!.on('scroll', callbackWrapScroll);\n window.addEventListener('resize', callbackWrapResize);\n }\n\n if (initialCall) {\n callback(\n weaverSetup._lenisInstance!.actualScroll,\n scrollCallbackReason.Initialize\n );\n }\n\n return () => {\n weaverSetup._lenisInstance!.off('scroll', callbackWrapScroll);\n window.removeEventListener('resize', callbackWrapResize);\n };\n }, [\n callback,\n callbackWrapResize,\n callbackWrapScroll,\n initialCall,\n intersectOn,\n ]);\n}\n","import Lenis from 'lenis';\nimport { ReactNode } from 'react';\n\nexport type BasicTunnelIn = ({ children }: { children: ReactNode }) => null;\n\nclass WeaverSetup {\n /**\n * This variable is handled internally by weaver. **Do not use**.\n */\n get _lenisInstance(): Lenis | undefined {\n return (globalThis as any).__weaverLenis;\n }\n set _lenisInstance(val: Lenis | undefined) {\n (globalThis as any).__weaverLenis = val;\n }\n\n /**\n * This variable is handled internally by weaver. **Do not use**.\n */\n get _Default3DTunnelIn(): BasicTunnelIn | undefined {\n return (globalThis as any).__weaver3DTunnel;\n }\n set _Default3DTunnelIn(val: BasicTunnelIn | undefined) {\n (globalThis as any).__weaver3DTunnel = val;\n }\n\n setLenisInstance(instance: Lenis) {\n this._lenisInstance = instance;\n }\n set3DTunnel(tunnelIn: BasicTunnelIn) {\n this._Default3DTunnelIn = tunnelIn;\n }\n}\n\nexport const weaverSetup = new WeaverSetup();\n","import { type RefObject, useLayoutEffect } from 'react';\n\n/**\n * A simple Orbit hook.\n *\n * @param target HTML element ref to attach to.\n * @param events Specify which events should the orbit tracks.\n */\nexport function useOrbit(options: {\n target?: RefObject<HTMLElement | null>;\n events: {\n onResize?: (entry: ResizeObserverEntry) => void;\n onIntersect?: (entry: IntersectionObserverEntry) => void;\n };\n rootMargin?: string;\n}) {\n const { onResize, onIntersect } = options.events;\n const { rootMargin = '25% 0px 25% 0px' } = options;\n\n useLayoutEffect(() => {\n if (!options.target) return;\n if (!options.target.current) return;\n\n let orbitResize = undefined;\n if (onResize) {\n orbitResize = new ResizeObserver((entries) => onResize(entries[0]));\n orbitResize.observe(options.target.current);\n }\n let orbitIntersect = undefined;\n if (onIntersect) {\n orbitIntersect = new IntersectionObserver(\n (entries) => onIntersect(entries[0]),\n { rootMargin }\n );\n orbitIntersect.observe(options.target.current);\n }\n\n return () => {\n orbitResize?.disconnect();\n orbitIntersect?.disconnect();\n };\n }, [onIntersect, onResize, rootMargin, options.target]);\n}\n","import { useId, useLayoutEffect } from 'react';\n\nexport interface MousePositionValues {\n x: number;\n y: number;\n}\n\ninterface MouseCallback {\n callback: (latest: MousePositionValues) => void;\n options: HookOptions;\n}\n\ninterface HookOptions {\n normalized?: boolean;\n}\n\ntype Callback = (latest: MousePositionValues) => void;\n\nclass MouseEventDistributor {\n private callbacks = new Map<string, MouseCallback>();\n private eventRegistered = false;\n\n constructor() {\n if (this.eventRegistered) return;\n\n window.addEventListener('pointermove', this.callbackLoop.bind(this), {\n passive: true,\n });\n\n this.eventRegistered = true;\n }\n\n addCallbackLoop(\n id: string,\n callback: (latest: MousePositionValues) => void,\n options: HookOptions\n ) {\n this.callbacks.set(id, { callback, options });\n }\n\n removeCallbackLoop(id: string) {\n this.callbacks.delete(id);\n }\n\n private processEvent(event: PointerEvent) {\n const mouse = {\n x: event.clientX,\n y: event.clientY,\n };\n const mouseNormalized = {\n x: mouse.x / (document.body.clientWidth / 2) - 1,\n y: mouse.y / (document.documentElement.clientHeight / 2) - 1,\n };\n\n return [mouse, mouseNormalized];\n }\n\n private callbackLoop(event: PointerEvent) {\n if (event.pointerType !== 'mouse') return;\n\n const callbacks = this.callbacks.entries();\n const [mouse, mouseNormalized] = this.processEvent(event);\n\n let inspecting = callbacks.next().value;\n while (inspecting) {\n if (inspecting[1].options.normalized) {\n inspecting[1].callback(mouseNormalized);\n } else {\n inspecting[1].callback(mouse);\n }\n\n inspecting = callbacks.next().value;\n }\n }\n}\n\nconst distributor = new MouseEventDistributor();\n\nexport function useMouseCallback(\n callback: Callback,\n options: HookOptions = {\n normalized: true,\n }\n) {\n const id = useId();\n\n useLayoutEffect(() => {\n distributor.addCallbackLoop(id, callback, options);\n\n return () => {\n distributor.removeCallbackLoop(id);\n };\n }, [callback, id, options]);\n}\n","import { useCallback } from 'react';\nimport { useNavigate } from 'react-router';\nimport { weaverSetup } from '../setup';\n\nexport function useNavigateAnchor(onNavigate?: () => void) {\n const navigate = useNavigate();\n\n return useCallback(\n (event: React.MouseEvent<HTMLAnchorElement, MouseEvent>) => {\n event.preventDefault();\n const href = event.currentTarget.getAttribute('href');\n if (href) {\n if (onNavigate) {\n onNavigate();\n }\n\n if (href !== window.location.pathname) {\n navigate(event.currentTarget.getAttribute('href') ?? '');\n } else {\n weaverSetup._lenisInstance!.scrollTo(0, { duration: 2 });\n }\n }\n },\n [onNavigate, navigate]\n );\n}\n","import { useLocation } from 'react-router';\n\nexport function useRawParams(\n prefix: string,\n limit?: number\n): (string | undefined)[] {\n const { pathname } = useLocation();\n\n const prefixedPath = pathname.replace(new RegExp(prefix), '');\n if (prefixedPath === pathname) {\n return [];\n }\n\n return prefixedPath\n .split('/')\n .filter((param) => param !== '')\n .slice(limit);\n}\n","import { useCallback, useLayoutEffect } from 'react';\nimport { useLocation, useNavigate } from 'react-router';\n\nexport function useRouteNormalizer(options: { autoReplace: boolean }) {\n const { pathname } = useLocation();\n const navigate = useNavigate();\n\n const normalizer = useCallback(\n (input: string) => input.replace(/\\/+\\//g, () => '/'),\n []\n );\n\n useLayoutEffect(() => {\n const result = normalizer(pathname);\n if (options.autoReplace && result !== pathname) {\n window.location.replace(result);\n }\n }, [options.autoReplace, pathname, navigate, normalizer]);\n\n return {\n pathname,\n normalizer,\n };\n}\n","import { useCallback, useLayoutEffect, useState } from 'react';\n\nexport function useScreen() {\n const [width, setWidth] = useState(document.body.clientWidth);\n const [height, setHeight] = useState(document.documentElement.clientHeight);\n\n const setScreen = useCallback(() => {\n setWidth(document.body.clientWidth);\n setHeight(document.documentElement.clientHeight);\n }, []);\n\n useLayoutEffect(() => {\n window.addEventListener('resize', setScreen, { passive: true });\n\n return () => {\n window.removeEventListener('resize', setScreen);\n };\n }, [setScreen]);\n\n return { width: width, height: height };\n}\n","import { useThree } from '@react-three/fiber';\nimport { useCallback, useState } from 'react';\nimport { OrthographicCamera, PerspectiveCamera } from 'three';\nimport { useScreenCallback } from './screenCallback';\n\nexport function useViewport(\n customCamera?: OrthographicCamera | PerspectiveCamera\n) {\n const { viewport, camera } = useThree();\n\n const [width, setWidth] = useState(viewport.getCurrentViewport().width);\n const [height, setHeight] = useState(viewport.getCurrentViewport().height);\n\n const viewportUpdate = useCallback(() => {\n const actualViewport = viewport.getCurrentViewport(customCamera ?? camera);\n setWidth(actualViewport.width);\n setHeight(actualViewport.height);\n }, [camera, customCamera, viewport]);\n useScreenCallback(viewportUpdate);\n\n return { width: width, height: height };\n}\n"],"mappings":"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","names":["useLayoutEffect","useCallback","useLayoutEffect","useLayoutEffect","useCallback","useLayoutEffect","useLayoutEffect","useCallback","useCallback","useCallback","useLayoutEffect","useLocation","useNavigate","useCallback","useLayoutEffect","useState","useCallback","useState","useState","useCallback"]}
|
|
1
|
+
{"version":3,"sources":["../src/hooks/breakpoints.ts","../src/hooks/screenCallback.ts","../src/hooks/effectOnce.ts","../src/hooks/lenisCallback.ts","../src/setup.ts","../src/hooks/orbit.ts","../src/hooks/mouseCallback.ts","../src/hooks/navigateAnchor.ts","../src/hooks/rawParams.ts","../src/hooks/routeNormalizer.ts","../src/hooks/screen.ts","../src/hooks/viewport.ts"],"sourcesContent":["import { useCallback, useState } from 'react';\nimport { useScreenCallback } from './screenCallback';\n\nexport function useBreakpoints(breakpoints?: number[] | null) {\n const getBreakpoint = useCallback(\n (width: number) => {\n const processingBreakpoints = !breakpoints\n ? [640, 768, 1024, 1280, 1536]\n : breakpoints;\n\n if (!processingBreakpoints) {\n throw Error(\"Uhhh... so you don't want a breakpoint? Just say it.\");\n }\n\n let result = processingBreakpoints!.length;\n for (let index = 0; index < processingBreakpoints!.length; index++) {\n if (width < processingBreakpoints![index]) {\n result = index;\n break;\n }\n }\n\n return result;\n },\n [breakpoints]\n );\n\n const [breakAt, setBreakAt] = useState<number>(\n getBreakpoint(document.body.clientWidth)\n );\n\n const breakpointCheck = useCallback(\n (latest: { width: number; height: number }) => {\n const result = getBreakpoint(latest.width);\n if (result !== breakAt) {\n setBreakAt(result);\n }\n },\n [breakAt, getBreakpoint]\n );\n useScreenCallback(breakpointCheck);\n\n return breakAt;\n}\n","import { useLayoutEffect } from 'react';\n\nexport interface ScreenCallbackValues {\n width: number;\n height: number;\n}\n\ntype Callback = (props: ScreenCallbackValues) => void;\n\nexport function useScreenCallback(\n callback: Callback,\n options?: { initialCall?: boolean }\n) {\n useLayoutEffect(() => {\n const reportScreen = () =>\n callback({\n width: document.body.clientWidth,\n height: document.documentElement.clientHeight,\n });\n\n // Call it first time when the hook was initialized.\n if (options?.initialCall) {\n reportScreen();\n }\n\n window.addEventListener('resize', reportScreen, { passive: true });\n\n return () => {\n window.removeEventListener('resize', reportScreen);\n };\n }, [callback, options?.initialCall]);\n}\n","import { useEffect, useLayoutEffect } from 'react';\n\nexport function useEffectOnce(callback: React.EffectCallback) {\n // eslint-disable-next-line react-hooks/exhaustive-deps\n useEffect(callback, []);\n}\n\nexport function useLayoutEffectOnce(callback: React.EffectCallback) {\n // eslint-disable-next-line react-hooks/exhaustive-deps\n useLayoutEffect(callback, []);\n}\n","import { type RefObject, useCallback, useLayoutEffect, useMemo } from 'react';\nimport { weaverSetup } from '../setup';\nimport { useOrbit } from './orbit';\n\ninterface HookOptions {\n /**\n * Hook will report when first initialized without waiting for scroll event to actually happens.\n */\n initialCall?: boolean;\n /**\n * Set an element to only call when the element is actually entering the viewport (with 25% `rootMargin`).\n */\n intersectOn?: RefObject<HTMLOrSVGElement | null>;\n}\n\nexport const scrollCallbackReason = {\n Resize: 'resize',\n Scroll: 'scroll',\n Initialize: 'initialize',\n} as const;\nexport type ScrollCallbackReason =\n (typeof scrollCallbackReason)[keyof typeof scrollCallbackReason];\n\ntype Callback = (latest: number, reason: ScrollCallbackReason) => void;\n\nexport function useLenisCallback(callback: Callback, options?: HookOptions) {\n const callbackWrapScroll = useCallback(\n () =>\n callback(\n weaverSetup._lenisInstance!.actualScroll,\n scrollCallbackReason.Scroll\n ),\n [callback]\n );\n const callbackWrapResize = useCallback(\n () =>\n callback(\n weaverSetup._lenisInstance!.actualScroll,\n scrollCallbackReason.Resize\n ),\n [callback]\n );\n\n const intersectOn = useMemo(\n () => options?.intersectOn,\n [options?.intersectOn]\n );\n const initialCall = useMemo(\n () => options?.initialCall,\n [options?.initialCall]\n );\n\n useOrbit({\n target: intersectOn as RefObject<HTMLElement | null> | undefined,\n events: {\n onIntersect(entry) {\n if (entry.isIntersecting) {\n weaverSetup._lenisInstance!.on('scroll', callbackWrapScroll);\n window.addEventListener('resize', callbackWrapResize);\n } else {\n weaverSetup._lenisInstance!.off('scroll', callbackWrapScroll);\n window.removeEventListener('resize', callbackWrapResize);\n }\n },\n },\n rootMargin: '50% 0px 50% 0px',\n });\n\n useLayoutEffect(() => {\n if (!intersectOn) {\n weaverSetup._lenisInstance!.on('scroll', callbackWrapScroll);\n window.addEventListener('resize', callbackWrapResize);\n }\n\n if (initialCall) {\n callback(\n weaverSetup._lenisInstance!.actualScroll,\n scrollCallbackReason.Initialize\n );\n }\n\n return () => {\n weaverSetup._lenisInstance!.off('scroll', callbackWrapScroll);\n window.removeEventListener('resize', callbackWrapResize);\n };\n }, [\n callback,\n callbackWrapResize,\n callbackWrapScroll,\n initialCall,\n intersectOn,\n ]);\n}\n","import Lenis from 'lenis';\nimport { ReactNode } from 'react';\n\nexport type BasicTunnelIn = ({ children }: { children: ReactNode }) => null;\n\nclass WeaverSetup {\n /**\n * This variable is handled internally by weaver. **Do not use**.\n */\n get _lenisInstance(): Lenis | undefined {\n return (globalThis as any).__weaverLenis;\n }\n set _lenisInstance(val: Lenis | undefined) {\n (globalThis as any).__weaverLenis = val;\n }\n\n /**\n * This variable is handled internally by weaver. **Do not use**.\n */\n get _Default3DTunnelIn(): BasicTunnelIn | undefined {\n return (globalThis as any).__weaver3DTunnel;\n }\n set _Default3DTunnelIn(val: BasicTunnelIn | undefined) {\n (globalThis as any).__weaver3DTunnel = val;\n }\n\n setLenisInstance(instance: Lenis) {\n this._lenisInstance = instance;\n }\n set3DTunnel(tunnelIn: BasicTunnelIn) {\n this._Default3DTunnelIn = tunnelIn;\n }\n}\n\nexport const weaverSetup = new WeaverSetup();\n","import { type RefObject, useLayoutEffect } from 'react';\n\n/**\n * A simple Orbit hook.\n *\n * @param target HTML element ref to attach to.\n * @param events Specify which events should the orbit tracks.\n */\nexport function useOrbit(options: {\n target?: RefObject<HTMLElement | null>;\n events: {\n onResize?: (entry: ResizeObserverEntry) => void;\n onIntersect?: (entry: IntersectionObserverEntry) => void;\n };\n rootMargin?: string;\n}) {\n const { onResize, onIntersect } = options.events;\n const { rootMargin = '25% 0px 25% 0px' } = options;\n\n useLayoutEffect(() => {\n if (!options.target) return;\n if (!options.target.current) return;\n\n let orbitResize = undefined;\n if (onResize) {\n orbitResize = new ResizeObserver((entries) => onResize(entries[0]));\n orbitResize.observe(options.target.current);\n }\n let orbitIntersect = undefined;\n if (onIntersect) {\n orbitIntersect = new IntersectionObserver(\n (entries) => onIntersect(entries[0]),\n { rootMargin }\n );\n orbitIntersect.observe(options.target.current);\n }\n\n return () => {\n orbitResize?.disconnect();\n orbitIntersect?.disconnect();\n };\n }, [onIntersect, onResize, rootMargin, options.target]);\n}\n","import { useId, useLayoutEffect } from 'react';\n\nexport interface MousePositionValues {\n x: number;\n y: number;\n}\n\ninterface MouseCallback {\n callback: (latest: MousePositionValues) => void;\n options: HookOptions;\n}\n\ninterface HookOptions {\n normalized?: boolean;\n}\n\ntype Callback = (latest: MousePositionValues) => void;\n\nclass MouseEventDistributor {\n private callbacks = new Map<string, MouseCallback>();\n private eventRegistered = false;\n\n constructor() {\n if (this.eventRegistered) return;\n\n window.addEventListener('pointermove', this.callbackLoop.bind(this), {\n passive: true,\n });\n\n this.eventRegistered = true;\n }\n\n addCallbackLoop(\n id: string,\n callback: (latest: MousePositionValues) => void,\n options: HookOptions\n ) {\n this.callbacks.set(id, { callback, options });\n }\n\n removeCallbackLoop(id: string) {\n this.callbacks.delete(id);\n }\n\n private processEvent(event: PointerEvent) {\n const mouse = {\n x: event.clientX,\n y: event.clientY,\n };\n const mouseNormalized = {\n x: mouse.x / (document.body.clientWidth / 2) - 1,\n y: mouse.y / (document.documentElement.clientHeight / 2) - 1,\n };\n\n return [mouse, mouseNormalized];\n }\n\n private callbackLoop(event: PointerEvent) {\n if (event.pointerType !== 'mouse') return;\n\n const callbacks = this.callbacks.entries();\n const [mouse, mouseNormalized] = this.processEvent(event);\n\n let inspecting = callbacks.next().value;\n while (inspecting) {\n if (inspecting[1].options.normalized) {\n inspecting[1].callback(mouseNormalized);\n } else {\n inspecting[1].callback(mouse);\n }\n\n inspecting = callbacks.next().value;\n }\n }\n}\n\nconst distributor = new MouseEventDistributor();\n\nexport function useMouseCallback(\n callback: Callback,\n options: HookOptions = {\n normalized: true,\n }\n) {\n const id = useId();\n\n useLayoutEffect(() => {\n distributor.addCallbackLoop(id, callback, options);\n\n return () => {\n distributor.removeCallbackLoop(id);\n };\n }, [callback, id, options]);\n}\n","import { useCallback } from 'react';\nimport { useNavigate } from 'react-router';\n\nexport function useNavigateAnchor(onNavigate?: () => void) {\n const navigate = useNavigate();\n\n return useCallback(\n (event: React.MouseEvent<HTMLAnchorElement, MouseEvent>) => {\n event.preventDefault();\n const href = event.currentTarget.getAttribute('href');\n if (href) {\n if (onNavigate) {\n onNavigate();\n }\n\n if (href !== window.location.pathname) {\n navigate(event.currentTarget.getAttribute('href') ?? '');\n }\n }\n },\n [onNavigate, navigate]\n );\n}\n","import { useLocation } from 'react-router';\n\nexport function useRawParams(\n prefix: string,\n limit?: number\n): (string | undefined)[] {\n const { pathname } = useLocation();\n\n const prefixedPath = pathname.replace(new RegExp(prefix), '');\n if (prefixedPath === pathname) {\n return [];\n }\n\n return prefixedPath\n .split('/')\n .filter((param) => param !== '')\n .slice(limit);\n}\n","import { useCallback, useLayoutEffect } from 'react';\nimport { useLocation, useNavigate } from 'react-router';\n\nexport function useRouteNormalizer(options: { autoReplace: boolean }) {\n const { pathname } = useLocation();\n const navigate = useNavigate();\n\n const normalizer = useCallback(\n (input: string) => input.replace(/\\/+\\//g, () => '/'),\n []\n );\n\n useLayoutEffect(() => {\n const result = normalizer(pathname);\n if (options.autoReplace && result !== pathname) {\n window.location.replace(result);\n }\n }, [options.autoReplace, pathname, navigate, normalizer]);\n\n return {\n pathname,\n normalizer,\n };\n}\n","import { useCallback, useLayoutEffect, useState } from 'react';\n\nexport function useScreen() {\n const [width, setWidth] = useState(document.body.clientWidth);\n const [height, setHeight] = useState(document.documentElement.clientHeight);\n\n const setScreen = useCallback(() => {\n setWidth(document.body.clientWidth);\n setHeight(document.documentElement.clientHeight);\n }, []);\n\n useLayoutEffect(() => {\n window.addEventListener('resize', setScreen, { passive: true });\n\n return () => {\n window.removeEventListener('resize', setScreen);\n };\n }, [setScreen]);\n\n return { width: width, height: height };\n}\n","import { useThree } from '@react-three/fiber';\nimport { useCallback, useState } from 'react';\nimport { OrthographicCamera, PerspectiveCamera } from 'three';\nimport { useScreenCallback } from './screenCallback';\n\nexport function useViewport(\n customCamera?: OrthographicCamera | PerspectiveCamera\n) {\n const { viewport, camera } = useThree();\n\n const [width, setWidth] = useState(viewport.getCurrentViewport().width);\n const [height, setHeight] = useState(viewport.getCurrentViewport().height);\n\n const viewportUpdate = useCallback(() => {\n const actualViewport = viewport.getCurrentViewport(customCamera ?? camera);\n setWidth(actualViewport.width);\n setHeight(actualViewport.height);\n }, [camera, customCamera, viewport]);\n useScreenCallback(viewportUpdate);\n\n return { width: width, height: height };\n}\n"],"mappings":";AAAA,SAAS,aAAa,gBAAgB;;;ACAtC,SAAS,uBAAuB;AASzB,SAAS,kBACd,UACA,SACA;AACA,kBAAgB,MAAM;AACpB,UAAM,eAAe,MACnB,SAAS;AAAA,MACP,OAAO,SAAS,KAAK;AAAA,MACrB,QAAQ,SAAS,gBAAgB;AAAA,IACnC,CAAC;AAGH,QAAI,SAAS,aAAa;AACxB,mBAAa;AAAA,IACf;AAEA,WAAO,iBAAiB,UAAU,cAAc,EAAE,SAAS,KAAK,CAAC;AAEjE,WAAO,MAAM;AACX,aAAO,oBAAoB,UAAU,YAAY;AAAA,IACnD;AAAA,EACF,GAAG,CAAC,UAAU,SAAS,WAAW,CAAC;AACrC;;;AD5BO,SAAS,eAAe,aAA+B;AAC5D,QAAM,gBAAgB;AAAA,IACpB,CAAC,UAAkB;AACjB,YAAM,wBAAwB,CAAC,cAC3B,CAAC,KAAK,KAAK,MAAM,MAAM,IAAI,IAC3B;AAEJ,UAAI,CAAC,uBAAuB;AAC1B,cAAM,MAAM,sDAAsD;AAAA,MACpE;AAEA,UAAI,SAAS,sBAAuB;AACpC,eAAS,QAAQ,GAAG,QAAQ,sBAAuB,QAAQ,SAAS;AAClE,YAAI,QAAQ,sBAAuB,KAAK,GAAG;AACzC,mBAAS;AACT;AAAA,QACF;AAAA,MACF;AAEA,aAAO;AAAA,IACT;AAAA,IACA,CAAC,WAAW;AAAA,EACd;AAEA,QAAM,CAAC,SAAS,UAAU,IAAI;AAAA,IAC5B,cAAc,SAAS,KAAK,WAAW;AAAA,EACzC;AAEA,QAAM,kBAAkB;AAAA,IACtB,CAAC,WAA8C;AAC7C,YAAM,SAAS,cAAc,OAAO,KAAK;AACzC,UAAI,WAAW,SAAS;AACtB,mBAAW,MAAM;AAAA,MACnB;AAAA,IACF;AAAA,IACA,CAAC,SAAS,aAAa;AAAA,EACzB;AACA,oBAAkB,eAAe;AAEjC,SAAO;AACT;;;AE3CA,SAAS,WAAW,mBAAAA,wBAAuB;AAEpC,SAAS,cAAc,UAAgC;AAE5D,YAAU,UAAU,CAAC,CAAC;AACxB;AAEO,SAAS,oBAAoB,UAAgC;AAElE,EAAAA,iBAAgB,UAAU,CAAC,CAAC;AAC9B;;;ACVA,SAAyB,eAAAC,cAAa,mBAAAC,kBAAiB,eAAe;;;ACKtE,IAAM,cAAN,MAAkB;AAAA;AAAA;AAAA;AAAA,EAIhB,IAAI,iBAAoC;AACtC,WAAQ,WAAmB;AAAA,EAC7B;AAAA,EACA,IAAI,eAAe,KAAwB;AACzC,IAAC,WAAmB,gBAAgB;AAAA,EACtC;AAAA;AAAA;AAAA;AAAA,EAKA,IAAI,qBAAgD;AAClD,WAAQ,WAAmB;AAAA,EAC7B;AAAA,EACA,IAAI,mBAAmB,KAAgC;AACrD,IAAC,WAAmB,mBAAmB;AAAA,EACzC;AAAA,EAEA,iBAAiB,UAAiB;AAChC,SAAK,iBAAiB;AAAA,EACxB;AAAA,EACA,YAAY,UAAyB;AACnC,SAAK,qBAAqB;AAAA,EAC5B;AACF;AAEO,IAAM,cAAc,IAAI,YAAY;;;AClC3C,SAAyB,mBAAAC,wBAAuB;AAQzC,SAAS,SAAS,SAOtB;AACD,QAAM,EAAE,UAAU,YAAY,IAAI,QAAQ;AAC1C,QAAM,EAAE,aAAa,kBAAkB,IAAI;AAE3C,EAAAA,iBAAgB,MAAM;AACpB,QAAI,CAAC,QAAQ,OAAQ;AACrB,QAAI,CAAC,QAAQ,OAAO,QAAS;AAE7B,QAAI,cAAc;AAClB,QAAI,UAAU;AACZ,oBAAc,IAAI,eAAe,CAAC,YAAY,SAAS,QAAQ,CAAC,CAAC,CAAC;AAClE,kBAAY,QAAQ,QAAQ,OAAO,OAAO;AAAA,IAC5C;AACA,QAAI,iBAAiB;AACrB,QAAI,aAAa;AACf,uBAAiB,IAAI;AAAA,QACnB,CAAC,YAAY,YAAY,QAAQ,CAAC,CAAC;AAAA,QACnC,EAAE,WAAW;AAAA,MACf;AACA,qBAAe,QAAQ,QAAQ,OAAO,OAAO;AAAA,IAC/C;AAEA,WAAO,MAAM;AACX,mBAAa,WAAW;AACxB,sBAAgB,WAAW;AAAA,IAC7B;AAAA,EACF,GAAG,CAAC,aAAa,UAAU,YAAY,QAAQ,MAAM,CAAC;AACxD;;;AF3BO,IAAM,uBAAuB;AAAA,EAClC,QAAQ;AAAA,EACR,QAAQ;AAAA,EACR,YAAY;AACd;AAMO,SAAS,iBAAiB,UAAoB,SAAuB;AAC1E,QAAM,qBAAqBC;AAAA,IACzB,MACE;AAAA,MACE,YAAY,eAAgB;AAAA,MAC5B,qBAAqB;AAAA,IACvB;AAAA,IACF,CAAC,QAAQ;AAAA,EACX;AACA,QAAM,qBAAqBA;AAAA,IACzB,MACE;AAAA,MACE,YAAY,eAAgB;AAAA,MAC5B,qBAAqB;AAAA,IACvB;AAAA,IACF,CAAC,QAAQ;AAAA,EACX;AAEA,QAAM,cAAc;AAAA,IAClB,MAAM,SAAS;AAAA,IACf,CAAC,SAAS,WAAW;AAAA,EACvB;AACA,QAAM,cAAc;AAAA,IAClB,MAAM,SAAS;AAAA,IACf,CAAC,SAAS,WAAW;AAAA,EACvB;AAEA,WAAS;AAAA,IACP,QAAQ;AAAA,IACR,QAAQ;AAAA,MACN,YAAY,OAAO;AACjB,YAAI,MAAM,gBAAgB;AACxB,sBAAY,eAAgB,GAAG,UAAU,kBAAkB;AAC3D,iBAAO,iBAAiB,UAAU,kBAAkB;AAAA,QACtD,OAAO;AACL,sBAAY,eAAgB,IAAI,UAAU,kBAAkB;AAC5D,iBAAO,oBAAoB,UAAU,kBAAkB;AAAA,QACzD;AAAA,MACF;AAAA,IACF;AAAA,IACA,YAAY;AAAA,EACd,CAAC;AAED,EAAAC,iBAAgB,MAAM;AACpB,QAAI,CAAC,aAAa;AAChB,kBAAY,eAAgB,GAAG,UAAU,kBAAkB;AAC3D,aAAO,iBAAiB,UAAU,kBAAkB;AAAA,IACtD;AAEA,QAAI,aAAa;AACf;AAAA,QACE,YAAY,eAAgB;AAAA,QAC5B,qBAAqB;AAAA,MACvB;AAAA,IACF;AAEA,WAAO,MAAM;AACX,kBAAY,eAAgB,IAAI,UAAU,kBAAkB;AAC5D,aAAO,oBAAoB,UAAU,kBAAkB;AAAA,IACzD;AAAA,EACF,GAAG;AAAA,IACD;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF,CAAC;AACH;;;AG5FA,SAAS,OAAO,mBAAAC,wBAAuB;AAkBvC,IAAM,wBAAN,MAA4B;AAAA,EAClB,YAAY,oBAAI,IAA2B;AAAA,EAC3C,kBAAkB;AAAA,EAE1B,cAAc;AACZ,QAAI,KAAK,gBAAiB;AAE1B,WAAO,iBAAiB,eAAe,KAAK,aAAa,KAAK,IAAI,GAAG;AAAA,MACnE,SAAS;AAAA,IACX,CAAC;AAED,SAAK,kBAAkB;AAAA,EACzB;AAAA,EAEA,gBACE,IACA,UACA,SACA;AACA,SAAK,UAAU,IAAI,IAAI,EAAE,UAAU,QAAQ,CAAC;AAAA,EAC9C;AAAA,EAEA,mBAAmB,IAAY;AAC7B,SAAK,UAAU,OAAO,EAAE;AAAA,EAC1B;AAAA,EAEQ,aAAa,OAAqB;AACxC,UAAM,QAAQ;AAAA,MACZ,GAAG,MAAM;AAAA,MACT,GAAG,MAAM;AAAA,IACX;AACA,UAAM,kBAAkB;AAAA,MACtB,GAAG,MAAM,KAAK,SAAS,KAAK,cAAc,KAAK;AAAA,MAC/C,GAAG,MAAM,KAAK,SAAS,gBAAgB,eAAe,KAAK;AAAA,IAC7D;AAEA,WAAO,CAAC,OAAO,eAAe;AAAA,EAChC;AAAA,EAEQ,aAAa,OAAqB;AACxC,QAAI,MAAM,gBAAgB,QAAS;AAEnC,UAAM,YAAY,KAAK,UAAU,QAAQ;AACzC,UAAM,CAAC,OAAO,eAAe,IAAI,KAAK,aAAa,KAAK;AAExD,QAAI,aAAa,UAAU,KAAK,EAAE;AAClC,WAAO,YAAY;AACjB,UAAI,WAAW,CAAC,EAAE,QAAQ,YAAY;AACpC,mBAAW,CAAC,EAAE,SAAS,eAAe;AAAA,MACxC,OAAO;AACL,mBAAW,CAAC,EAAE,SAAS,KAAK;AAAA,MAC9B;AAEA,mBAAa,UAAU,KAAK,EAAE;AAAA,IAChC;AAAA,EACF;AACF;AAEA,IAAM,cAAc,IAAI,sBAAsB;AAEvC,SAAS,iBACd,UACA,UAAuB;AAAA,EACrB,YAAY;AACd,GACA;AACA,QAAM,KAAK,MAAM;AAEjB,EAAAA,iBAAgB,MAAM;AACpB,gBAAY,gBAAgB,IAAI,UAAU,OAAO;AAEjD,WAAO,MAAM;AACX,kBAAY,mBAAmB,EAAE;AAAA,IACnC;AAAA,EACF,GAAG,CAAC,UAAU,IAAI,OAAO,CAAC;AAC5B;;;AC7FA,SAAS,eAAAC,oBAAmB;AAC5B,SAAS,mBAAmB;AAErB,SAAS,kBAAkB,YAAyB;AACzD,QAAM,WAAW,YAAY;AAE7B,SAAOA;AAAA,IACL,CAAC,UAA2D;AAC1D,YAAM,eAAe;AACrB,YAAM,OAAO,MAAM,cAAc,aAAa,MAAM;AACpD,UAAI,MAAM;AACR,YAAI,YAAY;AACd,qBAAW;AAAA,QACb;AAEA,YAAI,SAAS,OAAO,SAAS,UAAU;AACrC,mBAAS,MAAM,cAAc,aAAa,MAAM,KAAK,EAAE;AAAA,QACzD;AAAA,MACF;AAAA,IACF;AAAA,IACA,CAAC,YAAY,QAAQ;AAAA,EACvB;AACF;;;ACtBA,SAAS,mBAAmB;AAErB,SAAS,aACd,QACA,OACwB;AACxB,QAAM,EAAE,SAAS,IAAI,YAAY;AAEjC,QAAM,eAAe,SAAS,QAAQ,IAAI,OAAO,MAAM,GAAG,EAAE;AAC5D,MAAI,iBAAiB,UAAU;AAC7B,WAAO,CAAC;AAAA,EACV;AAEA,SAAO,aACJ,MAAM,GAAG,EACT,OAAO,CAAC,UAAU,UAAU,EAAE,EAC9B,MAAM,KAAK;AAChB;;;ACjBA,SAAS,eAAAC,cAAa,mBAAAC,wBAAuB;AAC7C,SAAS,eAAAC,cAAa,eAAAC,oBAAmB;AAElC,SAAS,mBAAmB,SAAmC;AACpE,QAAM,EAAE,SAAS,IAAID,aAAY;AACjC,QAAM,WAAWC,aAAY;AAE7B,QAAM,aAAaH;AAAA,IACjB,CAAC,UAAkB,MAAM,QAAQ,UAAU,MAAM,GAAG;AAAA,IACpD,CAAC;AAAA,EACH;AAEA,EAAAC,iBAAgB,MAAM;AACpB,UAAM,SAAS,WAAW,QAAQ;AAClC,QAAI,QAAQ,eAAe,WAAW,UAAU;AAC9C,aAAO,SAAS,QAAQ,MAAM;AAAA,IAChC;AAAA,EACF,GAAG,CAAC,QAAQ,aAAa,UAAU,UAAU,UAAU,CAAC;AAExD,SAAO;AAAA,IACL;AAAA,IACA;AAAA,EACF;AACF;;;ACvBA,SAAS,eAAAG,cAAa,mBAAAC,kBAAiB,YAAAC,iBAAgB;AAEhD,SAAS,YAAY;AAC1B,QAAM,CAAC,OAAO,QAAQ,IAAIA,UAAS,SAAS,KAAK,WAAW;AAC5D,QAAM,CAAC,QAAQ,SAAS,IAAIA,UAAS,SAAS,gBAAgB,YAAY;AAE1E,QAAM,YAAYF,aAAY,MAAM;AAClC,aAAS,SAAS,KAAK,WAAW;AAClC,cAAU,SAAS,gBAAgB,YAAY;AAAA,EACjD,GAAG,CAAC,CAAC;AAEL,EAAAC,iBAAgB,MAAM;AACpB,WAAO,iBAAiB,UAAU,WAAW,EAAE,SAAS,KAAK,CAAC;AAE9D,WAAO,MAAM;AACX,aAAO,oBAAoB,UAAU,SAAS;AAAA,IAChD;AAAA,EACF,GAAG,CAAC,SAAS,CAAC;AAEd,SAAO,EAAE,OAAc,OAAe;AACxC;;;ACpBA,SAAS,gBAAgB;AACzB,SAAS,eAAAE,cAAa,YAAAC,iBAAgB;AAI/B,SAAS,YACd,cACA;AACA,QAAM,EAAE,UAAU,OAAO,IAAI,SAAS;AAEtC,QAAM,CAAC,OAAO,QAAQ,IAAIC,UAAS,SAAS,mBAAmB,EAAE,KAAK;AACtE,QAAM,CAAC,QAAQ,SAAS,IAAIA,UAAS,SAAS,mBAAmB,EAAE,MAAM;AAEzE,QAAM,iBAAiBC,aAAY,MAAM;AACvC,UAAM,iBAAiB,SAAS,mBAAmB,gBAAgB,MAAM;AACzE,aAAS,eAAe,KAAK;AAC7B,cAAU,eAAe,MAAM;AAAA,EACjC,GAAG,CAAC,QAAQ,cAAc,QAAQ,CAAC;AACnC,oBAAkB,cAAc;AAEhC,SAAO,EAAE,OAAc,OAAe;AACxC;","names":["useLayoutEffect","useCallback","useLayoutEffect","useLayoutEffect","useCallback","useLayoutEffect","useLayoutEffect","useCallback","useCallback","useLayoutEffect","useLocation","useNavigate","useCallback","useLayoutEffect","useState","useCallback","useState","useState","useCallback"]}
|
package/dist/routing.d.mts
CHANGED
|
@@ -56,22 +56,15 @@ interface PipelineProps {
|
|
|
56
56
|
*/
|
|
57
57
|
debugName: string;
|
|
58
58
|
/**
|
|
59
|
-
* This is
|
|
59
|
+
* This is the only feature where weaver will use lenis to directly manipulate scrolling behaviour.
|
|
60
60
|
*
|
|
61
|
-
*
|
|
62
|
-
*/
|
|
63
|
-
parentPath: string;
|
|
64
|
-
/**
|
|
65
|
-
* By default, this value is `true`
|
|
66
|
-
*
|
|
67
|
-
* When navigating off of a previous `Pipeline`. It will stop lenis as a clean up.
|
|
61
|
+
* By default, this value is `true` when a lenis instance is provided.
|
|
68
62
|
*
|
|
69
|
-
*
|
|
63
|
+
* `Pipeline` will stop and start lenis automatically when this variable is `true`.
|
|
70
64
|
*
|
|
71
|
-
*
|
|
72
|
-
* you don't have to clean up yourself.
|
|
65
|
+
* Disable this feature to gains complete control over lenis when mounting/unmounting to handle however you want.
|
|
73
66
|
*/
|
|
74
|
-
|
|
67
|
+
lenisUsage?: boolean;
|
|
75
68
|
}
|
|
76
69
|
/**
|
|
77
70
|
* A core part of an in-house tool called `weaver`.
|
package/dist/routing.d.ts
CHANGED
|
@@ -56,22 +56,15 @@ interface PipelineProps {
|
|
|
56
56
|
*/
|
|
57
57
|
debugName: string;
|
|
58
58
|
/**
|
|
59
|
-
* This is
|
|
59
|
+
* This is the only feature where weaver will use lenis to directly manipulate scrolling behaviour.
|
|
60
60
|
*
|
|
61
|
-
*
|
|
62
|
-
*/
|
|
63
|
-
parentPath: string;
|
|
64
|
-
/**
|
|
65
|
-
* By default, this value is `true`
|
|
66
|
-
*
|
|
67
|
-
* When navigating off of a previous `Pipeline`. It will stop lenis as a clean up.
|
|
61
|
+
* By default, this value is `true` when a lenis instance is provided.
|
|
68
62
|
*
|
|
69
|
-
*
|
|
63
|
+
* `Pipeline` will stop and start lenis automatically when this variable is `true`.
|
|
70
64
|
*
|
|
71
|
-
*
|
|
72
|
-
* you don't have to clean up yourself.
|
|
65
|
+
* Disable this feature to gains complete control over lenis when mounting/unmounting to handle however you want.
|
|
73
66
|
*/
|
|
74
|
-
|
|
67
|
+
lenisUsage?: boolean;
|
|
75
68
|
}
|
|
76
69
|
/**
|
|
77
70
|
* A core part of an in-house tool called `weaver`.
|
package/dist/routing.js
CHANGED
|
@@ -169,7 +169,14 @@ var weaverSetup = new WeaverSetup();
|
|
|
169
169
|
// src/routing/Pipeline.tsx
|
|
170
170
|
function Pipeline(props) {
|
|
171
171
|
const { children, ...restOfProps } = props;
|
|
172
|
-
|
|
172
|
+
const parentPath = (0, import_react5.useMemo)(
|
|
173
|
+
() => getParentRoute(window.location.pathname),
|
|
174
|
+
[]
|
|
175
|
+
);
|
|
176
|
+
(0, import_react5.useLayoutEffect)(() => {
|
|
177
|
+
console.log(parentPath);
|
|
178
|
+
}, [parentPath]);
|
|
179
|
+
return /* @__PURE__ */ import_react5.default.createElement(import_react5.default.Fragment, null, /* @__PURE__ */ import_react5.default.createElement(RouteHandler, { ...restOfProps, parentPath }), children);
|
|
173
180
|
}
|
|
174
181
|
function RouteHandler(props) {
|
|
175
182
|
const navigating = useWeaverContext((state) => state.navigating);
|
|
@@ -188,8 +195,8 @@ function RouteHandler(props) {
|
|
|
188
195
|
return;
|
|
189
196
|
}
|
|
190
197
|
if (!navigating && (!pageRendered || activeParent !== props.parentPath)) {
|
|
191
|
-
if (props.
|
|
192
|
-
weaverSetup._lenisInstance
|
|
198
|
+
if (props.lenisUsage === void 0 || props.lenisUsage) {
|
|
199
|
+
weaverSetup._lenisInstance?.start();
|
|
193
200
|
}
|
|
194
201
|
setPageRendered(true);
|
|
195
202
|
setActiveParent(props.parentPath);
|
|
@@ -200,7 +207,7 @@ function RouteHandler(props) {
|
|
|
200
207
|
setActivePipeline,
|
|
201
208
|
navigating,
|
|
202
209
|
pageRendered,
|
|
203
|
-
props.
|
|
210
|
+
props.lenisUsage,
|
|
204
211
|
props.contentReady,
|
|
205
212
|
props.debugName,
|
|
206
213
|
props.parentPath,
|
|
@@ -210,8 +217,13 @@ function RouteHandler(props) {
|
|
|
210
217
|
]);
|
|
211
218
|
useLayoutEffectOnce(() => {
|
|
212
219
|
return () => {
|
|
213
|
-
|
|
214
|
-
|
|
220
|
+
if (props.lenisUsage === void 0 || props.lenisUsage) {
|
|
221
|
+
weaverSetup._lenisInstance?.stop();
|
|
222
|
+
weaverSetup._lenisInstance?.scrollTo(0, {
|
|
223
|
+
immediate: true,
|
|
224
|
+
force: true
|
|
225
|
+
});
|
|
226
|
+
}
|
|
215
227
|
console.log(`[${props.debugName}] Renderer status: Unmounted`);
|
|
216
228
|
};
|
|
217
229
|
});
|
package/dist/routing.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/routing/index.ts","../src/routing/context.ts","../src/routing/DelayedOutlet.tsx","../src/hooks/routeNormalizer.ts","../src/utils/getParentRoute.ts","../src/routing/Pipeline.tsx","../src/hooks/effectOnce.ts","../src/setup.ts"],"sourcesContent":["import { useWeaverContext, WeaverContextGetter } from './context';\nimport DelayedOutlet from './DelayedOutlet';\nimport Pipeline from './Pipeline';\n\n/// A read-only state for reacting with changes reflected by weaver.\nexport const useWeaverState = (givenState: keyof WeaverContextGetter) => {\n const state = useWeaverContext((state) => state[givenState]);\n return state;\n};\n\nexport { DelayedOutlet, Pipeline };\n","import { create } from 'zustand/react';\n\nexport interface WeaverContextGetter {\n /**\n * Current active parent, **AFTER** Pipeline has finished rendering, so the `activeParent`\n * will be delayed. Example: \"/\", \"/works\",...\n */\n activeParent: string;\n\n /**\n * Current active Pipeline. Example: \"/\", \"/works\",...\n *\n * This is **not based on URL**, it's based on which `Pipeline` has access to the the site.\n */\n activePipeline: string;\n\n /**\n * `DelayedOutlet` special variable, indicating if the route is current transitioning to a new route or not.\n */\n navigating: boolean;\n\n /**\n * When the page is rendered, it will turns this to true,\n * any parent page navigation will causes this to goes false, set to false in `DelayedOulet`.\n *\n * It's set to `false` right after `navigating` is set to `true`. `true` statement will be handled by `Pipeline`.\n */\n pageRendered: boolean;\n}\n\ninterface WeaverContextSetter {\n setActiveParent: (activeParent: string) => void;\n setActivePipeline: (activePipeline: string) => void;\n setNavigating: (navigating: boolean) => void;\n setPageRendered: (pageRendered: boolean) => void;\n}\n\nexport const useWeaverContext = create<\n WeaverContextSetter & WeaverContextGetter\n>()((set) => ({\n activeParent: '',\n setActiveParent: (activeParent) => set({ activeParent }),\n\n activePipeline: '',\n setActivePipeline: (activePipeline) => set({ activePipeline }),\n\n navigating: true,\n setNavigating: (navigating) => set({ navigating }),\n\n pageRendered: false,\n setPageRendered: (pageRendered) => set({ pageRendered }),\n}));\n","import { type ReactNode, useLayoutEffect, useRef, useState } from 'react';\nimport { useOutlet } from 'react-router';\nimport { useRouteNormalizer } from '../hooks/routeNormalizer';\nimport { getParentRoute } from '../utils/getParentRoute';\nimport { useWeaverContext } from './context';\n\n/**\n * A core part of an in-house tool called `weaver`.\n *\n * Delaying the routing process from `react-router`, handles gracefully between `Pipeline`s\n * while allowing any loading fallback component to listen and react with event changes.\n */\nexport default function DelayedOutlet(props: { delay: number }) {\n // Middleware to detect and replace invalid url.\n useRouteNormalizer({ autoReplace: true });\n\n const activePipeline = useWeaverContext((state) => state.activePipeline);\n const setNavigating = useWeaverContext((state) => state.setNavigating);\n const setPageRendered = useWeaverContext((state) => state.setPageRendered);\n\n const renderPageTask = useRef(setTimeout(() => {}));\n const routerOutlet = useOutlet();\n\n const [renderer, setRenderer] = useState<ReactNode>(null);\n\n // Handle and update new parent page.\n useLayoutEffect(() => {\n /**\n * `pageRendered` should be outside of `renderPageTask`,\n * we alrady have `Pipeline` to correct errors.\n */\n if ('scrollRestoration' in history) {\n history.scrollRestoration = 'manual';\n }\n\n if (getParentRoute(window.location.pathname) === activePipeline) {\n // Avoid while changing page, cancelling before new page pushed in\n // cause `activePipeline` to not change, making `navigating` softlock.\n setNavigating(false);\n return;\n }\n\n setNavigating(true);\n setPageRendered(false);\n\n clearTimeout(renderPageTask.current);\n renderPageTask.current = setTimeout(() => {\n setRenderer(routerOutlet!);\n setNavigating(false);\n }, props.delay);\n\n return () => {\n /**\n * Clear invalid task that were scheduled last effect.\n */\n clearInterval(renderPageTask.current);\n };\n }, [\n activePipeline,\n props.delay,\n routerOutlet,\n setNavigating,\n setPageRendered,\n ]);\n\n return renderer;\n}\n","import { useCallback, useLayoutEffect } from 'react';\nimport { useLocation, useNavigate } from 'react-router';\n\nexport function useRouteNormalizer(options: { autoReplace: boolean }) {\n const { pathname } = useLocation();\n const navigate = useNavigate();\n\n const normalizer = useCallback(\n (input: string) => input.replace(/\\/+\\//g, () => '/'),\n []\n );\n\n useLayoutEffect(() => {\n const result = normalizer(pathname);\n if (options.autoReplace && result !== pathname) {\n window.location.replace(result);\n }\n }, [options.autoReplace, pathname, navigate, normalizer]);\n\n return {\n pathname,\n normalizer,\n };\n}\n","export function getParentRoute(pathname: string) {\n let slashes = 0;\n let sliceAt = 0;\n for (sliceAt; sliceAt < pathname.length; sliceAt++) {\n if (pathname[sliceAt] == '/') {\n slashes++;\n }\n if (slashes === 2) {\n break;\n }\n }\n\n return pathname.slice(0, sliceAt);\n}\n","import React, { useLayoutEffect, type ReactNode } from 'react';\nimport { useLayoutEffectOnce } from '../hooks/effectOnce';\nimport { weaverSetup } from '../setup';\nimport { useWeaverContext } from './context';\n\ninterface PipelineProps {\n children?: ReactNode;\n\n /**\n * A state switch to notifies `Pipeline` that the content and elements of the page is ready to be displayed.\n *\n * Usually, you will need to preload some other external sources, or initialize 3D scene, this state\n * make sure that the loading fallback doesn't mess up and show initializing stuff.\n *\n * Using `BakeScene`, you can ensure that the scene is loaded via its callback, you can then pass the state value that\n * `BakeScene` changes to this variable to hide all the lags behind loading screen.\n */\n contentReady?: boolean;\n\n /**\n * Title for the page.\n */\n title: string;\n\n /**\n * By default, `Pipeline` will log the current phase to console.\n */\n debugName: string;\n\n /**\n * This is crucial for different `Pipeline`s to differentiate each other and avoiding conflict.\n *\n * Example for parent path: `/`, `/about`, `/projects`,...\n */\n parentPath: string;\n\n /**\n * By default, this value is `true`\n *\n * When navigating off of a previous `Pipeline`. It will stop lenis as a clean up.\n *\n * So when a new `Pipeline` takes in, it will enable lenis immediately when `contentReady` is switched to `true`.\n *\n * Set to `false` to gain manual control over when lenis will start. This does not affect to stop mechanism,\n * you don't have to clean up yourself.\n */\n autoStartLenis?: boolean;\n}\n\n/**\n * A core part of an in-house tool called `weaver`.\n *\n * `Pipeline`: Notifies & reflect changes to/from `LoadingFallback`\n * and `DelayedOutlet` about its page loading status.\n *\n * All parent routes must have `Pipeline` in order to work and sync with `DelayedOutlet`.\n */\nexport default function Pipeline(props: PipelineProps) {\n const { children, ...restOfProps } = props;\n return (\n <>\n <RouteHandler {...restOfProps} />\n {children}\n </>\n );\n}\n\nfunction RouteHandler(props: Omit<PipelineProps, 'children'>) {\n const navigating = useWeaverContext((state) => state.navigating);\n const pageRendered = useWeaverContext((state) => state.pageRendered);\n const activeParent = useWeaverContext((state) => state.activeParent);\n\n const setActivePipeline = useWeaverContext(\n (state) => state.setActivePipeline\n );\n const setPageRendered = useWeaverContext((state) => state.setPageRendered);\n const setActiveParent = useWeaverContext((state) => state.setActiveParent);\n\n useLayoutEffect(() => {\n document.title = props.title;\n setActivePipeline(props.parentPath);\n\n if (props.contentReady !== undefined && !props.contentReady) {\n console.log(`[${props.debugName}] Renderer status: Loading scene`);\n return;\n }\n\n if (!navigating && (!pageRendered || activeParent !== props.parentPath)) {\n if (props.autoStartLenis === undefined || props.autoStartLenis) {\n weaverSetup._lenisInstance!.start();\n }\n\n setPageRendered(true);\n setActiveParent(props.parentPath);\n\n console.log(`[${props.debugName}] Renderer status: Mounted`);\n }\n }, [\n activeParent,\n setActivePipeline,\n navigating,\n pageRendered,\n props.autoStartLenis,\n props.contentReady,\n props.debugName,\n props.parentPath,\n props.title,\n setActiveParent,\n setPageRendered,\n ]);\n\n useLayoutEffectOnce(() => {\n return () => {\n /**\n * When unmounted, stop lenis to pass control to another Pipline instance.\n *\n * The unmount process only happens when the `<LoadingFallback />` kicks in,\n * so any visual glitches can happen in here, we can now set the scroll position to 0.\n */\n weaverSetup._lenisInstance!.stop();\n weaverSetup._lenisInstance!.scrollTo(0, { immediate: true, force: true });\n\n console.log(`[${props.debugName}] Renderer status: Unmounted`);\n };\n });\n\n return null;\n}\n","import { useEffect, useLayoutEffect } from 'react';\n\nexport function useEffectOnce(callback: React.EffectCallback) {\n // eslint-disable-next-line react-hooks/exhaustive-deps\n useEffect(callback, []);\n}\n\nexport function useLayoutEffectOnce(callback: React.EffectCallback) {\n // eslint-disable-next-line react-hooks/exhaustive-deps\n useLayoutEffect(callback, []);\n}\n","import Lenis from 'lenis';\nimport { ReactNode } from 'react';\n\nexport type BasicTunnelIn = ({ children }: { children: ReactNode }) => null;\n\nclass WeaverSetup {\n /**\n * This variable is handled internally by weaver. **Do not use**.\n */\n get _lenisInstance(): Lenis | undefined {\n return (globalThis as any).__weaverLenis;\n }\n set _lenisInstance(val: Lenis | undefined) {\n (globalThis as any).__weaverLenis = val;\n }\n\n /**\n * This variable is handled internally by weaver. **Do not use**.\n */\n get _Default3DTunnelIn(): BasicTunnelIn | undefined {\n return (globalThis as any).__weaver3DTunnel;\n }\n set _Default3DTunnelIn(val: BasicTunnelIn | undefined) {\n (globalThis as any).__weaver3DTunnel = val;\n }\n\n setLenisInstance(instance: Lenis) {\n this._lenisInstance = instance;\n }\n set3DTunnel(tunnelIn: BasicTunnelIn) {\n this._Default3DTunnelIn = tunnelIn;\n }\n}\n\nexport const weaverSetup = new WeaverSetup();\n"],"mappings":"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","names":["import_react","import_react_router","import_react","import_react","import_react","React","state"]}
|
|
1
|
+
{"version":3,"sources":["../src/routing/index.ts","../src/routing/context.ts","../src/routing/DelayedOutlet.tsx","../src/hooks/routeNormalizer.ts","../src/utils/getParentRoute.ts","../src/routing/Pipeline.tsx","../src/hooks/effectOnce.ts","../src/setup.ts"],"sourcesContent":["import { useWeaverContext, WeaverContextGetter } from './context';\nimport DelayedOutlet from './DelayedOutlet';\nimport Pipeline from './Pipeline';\n\n/// A read-only state for reacting with changes reflected by weaver.\nexport const useWeaverState = (givenState: keyof WeaverContextGetter) => {\n const state = useWeaverContext((state) => state[givenState]);\n return state;\n};\n\nexport { DelayedOutlet, Pipeline };\n","import { create } from 'zustand/react';\n\nexport interface WeaverContextGetter {\n /**\n * Current active parent, **AFTER** Pipeline has finished rendering, so the `activeParent`\n * will be delayed. Example: \"/\", \"/works\",...\n */\n activeParent: string;\n\n /**\n * Current active Pipeline. Example: \"/\", \"/works\",...\n *\n * This is **not based on URL**, it's based on which `Pipeline` has access to the the site.\n */\n activePipeline: string;\n\n /**\n * `DelayedOutlet` special variable, indicating if the route is current transitioning to a new route or not.\n */\n navigating: boolean;\n\n /**\n * When the page is rendered, it will turns this to true,\n * any parent page navigation will causes this to goes false, set to false in `DelayedOulet`.\n *\n * It's set to `false` right after `navigating` is set to `true`. `true` statement will be handled by `Pipeline`.\n */\n pageRendered: boolean;\n}\n\ninterface WeaverContextSetter {\n setActiveParent: (activeParent: string) => void;\n setActivePipeline: (activePipeline: string) => void;\n setNavigating: (navigating: boolean) => void;\n setPageRendered: (pageRendered: boolean) => void;\n}\n\nexport const useWeaverContext = create<\n WeaverContextSetter & WeaverContextGetter\n>()((set) => ({\n activeParent: '',\n setActiveParent: (activeParent) => set({ activeParent }),\n\n activePipeline: '',\n setActivePipeline: (activePipeline) => set({ activePipeline }),\n\n navigating: true,\n setNavigating: (navigating) => set({ navigating }),\n\n pageRendered: false,\n setPageRendered: (pageRendered) => set({ pageRendered }),\n}));\n","import { type ReactNode, useLayoutEffect, useRef, useState } from 'react';\nimport { useOutlet } from 'react-router';\nimport { useRouteNormalizer } from '../hooks/routeNormalizer';\nimport { getParentRoute } from '../utils/getParentRoute';\nimport { useWeaverContext } from './context';\n\n/**\n * A core part of an in-house tool called `weaver`.\n *\n * Delaying the routing process from `react-router`, handles gracefully between `Pipeline`s\n * while allowing any loading fallback component to listen and react with event changes.\n */\nexport default function DelayedOutlet(props: { delay: number }) {\n // Middleware to detect and replace invalid url.\n useRouteNormalizer({ autoReplace: true });\n\n const activePipeline = useWeaverContext((state) => state.activePipeline);\n const setNavigating = useWeaverContext((state) => state.setNavigating);\n const setPageRendered = useWeaverContext((state) => state.setPageRendered);\n\n const renderPageTask = useRef(setTimeout(() => {}));\n const routerOutlet = useOutlet();\n\n const [renderer, setRenderer] = useState<ReactNode>(null);\n\n // Handle and update new parent page.\n useLayoutEffect(() => {\n /**\n * `pageRendered` should be outside of `renderPageTask`,\n * we alrady have `Pipeline` to correct errors.\n */\n if ('scrollRestoration' in history) {\n history.scrollRestoration = 'manual';\n }\n\n if (getParentRoute(window.location.pathname) === activePipeline) {\n // Avoid while changing page, cancelling before new page pushed in\n // cause `activePipeline` to not change, making `navigating` softlock.\n setNavigating(false);\n return;\n }\n\n setNavigating(true);\n setPageRendered(false);\n\n clearTimeout(renderPageTask.current);\n renderPageTask.current = setTimeout(() => {\n setRenderer(routerOutlet!);\n setNavigating(false);\n }, props.delay);\n\n return () => {\n /**\n * Clear invalid task that were scheduled last effect.\n */\n clearInterval(renderPageTask.current);\n };\n }, [\n activePipeline,\n props.delay,\n routerOutlet,\n setNavigating,\n setPageRendered,\n ]);\n\n return renderer;\n}\n","import { useCallback, useLayoutEffect } from 'react';\nimport { useLocation, useNavigate } from 'react-router';\n\nexport function useRouteNormalizer(options: { autoReplace: boolean }) {\n const { pathname } = useLocation();\n const navigate = useNavigate();\n\n const normalizer = useCallback(\n (input: string) => input.replace(/\\/+\\//g, () => '/'),\n []\n );\n\n useLayoutEffect(() => {\n const result = normalizer(pathname);\n if (options.autoReplace && result !== pathname) {\n window.location.replace(result);\n }\n }, [options.autoReplace, pathname, navigate, normalizer]);\n\n return {\n pathname,\n normalizer,\n };\n}\n","export function getParentRoute(pathname: string) {\n let slashes = 0;\n let sliceAt = 0;\n for (sliceAt; sliceAt < pathname.length; sliceAt++) {\n if (pathname[sliceAt] == '/') {\n slashes++;\n }\n if (slashes === 2) {\n break;\n }\n }\n\n return pathname.slice(0, sliceAt);\n}\n","import React, { useLayoutEffect, useMemo, type ReactNode } from 'react';\nimport { useLayoutEffectOnce } from '../hooks/effectOnce';\nimport { weaverSetup } from '../setup';\nimport { getParentRoute } from '../utils/getParentRoute';\nimport { useWeaverContext } from './context';\n\ninterface PipelineProps {\n children?: ReactNode;\n\n /**\n * A state switch to notifies `Pipeline` that the content and elements of the page is ready to be displayed.\n *\n * Usually, you will need to preload some other external sources, or initialize 3D scene, this state\n * make sure that the loading fallback doesn't mess up and show initializing stuff.\n *\n * Using `BakeScene`, you can ensure that the scene is loaded via its callback, you can then pass the state value that\n * `BakeScene` changes to this variable to hide all the lags behind loading screen.\n */\n contentReady?: boolean;\n\n /**\n * Title for the page.\n */\n title: string;\n\n /**\n * By default, `Pipeline` will log the current phase to console.\n */\n debugName: string;\n\n /**\n * This is the only feature where weaver will use lenis to directly manipulate scrolling behaviour.\n *\n * By default, this value is `true` when a lenis instance is provided.\n *\n * `Pipeline` will stop and start lenis automatically when this variable is `true`.\n *\n * Disable this feature to gains complete control over lenis when mounting/unmounting to handle however you want.\n */\n lenisUsage?: boolean;\n}\n\n/**\n * A core part of an in-house tool called `weaver`.\n *\n * `Pipeline`: Notifies & reflect changes to/from `LoadingFallback`\n * and `DelayedOutlet` about its page loading status.\n *\n * All parent routes must have `Pipeline` in order to work and sync with `DelayedOutlet`.\n */\nexport default function Pipeline(props: PipelineProps) {\n const { children, ...restOfProps } = props;\n const parentPath = useMemo(\n () => getParentRoute(window.location.pathname),\n []\n );\n\n useLayoutEffect(() => {\n console.log(parentPath);\n }, [parentPath]);\n\n return (\n <>\n <RouteHandler {...restOfProps} parentPath={parentPath} />\n {children}\n </>\n );\n}\n\nfunction RouteHandler(\n props: Omit<PipelineProps, 'children'> & { parentPath: string }\n) {\n const navigating = useWeaverContext((state) => state.navigating);\n const pageRendered = useWeaverContext((state) => state.pageRendered);\n const activeParent = useWeaverContext((state) => state.activeParent);\n\n const setActivePipeline = useWeaverContext(\n (state) => state.setActivePipeline\n );\n const setPageRendered = useWeaverContext((state) => state.setPageRendered);\n const setActiveParent = useWeaverContext((state) => state.setActiveParent);\n\n useLayoutEffect(() => {\n document.title = props.title;\n setActivePipeline(props.parentPath);\n\n if (props.contentReady !== undefined && !props.contentReady) {\n console.log(`[${props.debugName}] Renderer status: Loading scene`);\n return;\n }\n\n if (!navigating && (!pageRendered || activeParent !== props.parentPath)) {\n if (props.lenisUsage === undefined || props.lenisUsage) {\n weaverSetup._lenisInstance?.start();\n }\n\n setPageRendered(true);\n setActiveParent(props.parentPath);\n\n console.log(`[${props.debugName}] Renderer status: Mounted`);\n }\n }, [\n activeParent,\n setActivePipeline,\n navigating,\n pageRendered,\n props.lenisUsage,\n props.contentReady,\n props.debugName,\n props.parentPath,\n props.title,\n setActiveParent,\n setPageRendered,\n ]);\n\n useLayoutEffectOnce(() => {\n return () => {\n /**\n * When unmounted, stop lenis to pass control to another Pipline instance.\n *\n * The unmount process only happens when the `<LoadingFallback />` kicks in,\n * so any visual glitches can happen in here, we can now set the scroll position to 0.\n */\n if (props.lenisUsage === undefined || props.lenisUsage) {\n weaverSetup._lenisInstance?.stop();\n weaverSetup._lenisInstance?.scrollTo(0, {\n immediate: true,\n force: true,\n });\n }\n\n console.log(`[${props.debugName}] Renderer status: Unmounted`);\n };\n });\n\n return null;\n}\n","import { useEffect, useLayoutEffect } from 'react';\n\nexport function useEffectOnce(callback: React.EffectCallback) {\n // eslint-disable-next-line react-hooks/exhaustive-deps\n useEffect(callback, []);\n}\n\nexport function useLayoutEffectOnce(callback: React.EffectCallback) {\n // eslint-disable-next-line react-hooks/exhaustive-deps\n useLayoutEffect(callback, []);\n}\n","import Lenis from 'lenis';\nimport { ReactNode } from 'react';\n\nexport type BasicTunnelIn = ({ children }: { children: ReactNode }) => null;\n\nclass WeaverSetup {\n /**\n * This variable is handled internally by weaver. **Do not use**.\n */\n get _lenisInstance(): Lenis | undefined {\n return (globalThis as any).__weaverLenis;\n }\n set _lenisInstance(val: Lenis | undefined) {\n (globalThis as any).__weaverLenis = val;\n }\n\n /**\n * This variable is handled internally by weaver. **Do not use**.\n */\n get _Default3DTunnelIn(): BasicTunnelIn | undefined {\n return (globalThis as any).__weaver3DTunnel;\n }\n set _Default3DTunnelIn(val: BasicTunnelIn | undefined) {\n (globalThis as any).__weaver3DTunnel = val;\n }\n\n setLenisInstance(instance: Lenis) {\n this._lenisInstance = instance;\n }\n set3DTunnel(tunnelIn: BasicTunnelIn) {\n this._Default3DTunnelIn = tunnelIn;\n }\n}\n\nexport const weaverSetup = new WeaverSetup();\n"],"mappings":"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","names":["import_react","import_react_router","import_react","import_react","import_react","React","state"]}
|
package/dist/routing.mjs
CHANGED
|
@@ -91,7 +91,7 @@ function DelayedOutlet(props) {
|
|
|
91
91
|
}
|
|
92
92
|
|
|
93
93
|
// src/routing/Pipeline.tsx
|
|
94
|
-
import React, { useLayoutEffect as useLayoutEffect4 } from "react";
|
|
94
|
+
import React, { useLayoutEffect as useLayoutEffect4, useMemo } from "react";
|
|
95
95
|
|
|
96
96
|
// src/hooks/effectOnce.ts
|
|
97
97
|
import { useEffect, useLayoutEffect as useLayoutEffect3 } from "react";
|
|
@@ -131,7 +131,14 @@ var weaverSetup = new WeaverSetup();
|
|
|
131
131
|
// src/routing/Pipeline.tsx
|
|
132
132
|
function Pipeline(props) {
|
|
133
133
|
const { children, ...restOfProps } = props;
|
|
134
|
-
|
|
134
|
+
const parentPath = useMemo(
|
|
135
|
+
() => getParentRoute(window.location.pathname),
|
|
136
|
+
[]
|
|
137
|
+
);
|
|
138
|
+
useLayoutEffect4(() => {
|
|
139
|
+
console.log(parentPath);
|
|
140
|
+
}, [parentPath]);
|
|
141
|
+
return /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement(RouteHandler, { ...restOfProps, parentPath }), children);
|
|
135
142
|
}
|
|
136
143
|
function RouteHandler(props) {
|
|
137
144
|
const navigating = useWeaverContext((state) => state.navigating);
|
|
@@ -150,8 +157,8 @@ function RouteHandler(props) {
|
|
|
150
157
|
return;
|
|
151
158
|
}
|
|
152
159
|
if (!navigating && (!pageRendered || activeParent !== props.parentPath)) {
|
|
153
|
-
if (props.
|
|
154
|
-
weaverSetup._lenisInstance
|
|
160
|
+
if (props.lenisUsage === void 0 || props.lenisUsage) {
|
|
161
|
+
weaverSetup._lenisInstance?.start();
|
|
155
162
|
}
|
|
156
163
|
setPageRendered(true);
|
|
157
164
|
setActiveParent(props.parentPath);
|
|
@@ -162,7 +169,7 @@ function RouteHandler(props) {
|
|
|
162
169
|
setActivePipeline,
|
|
163
170
|
navigating,
|
|
164
171
|
pageRendered,
|
|
165
|
-
props.
|
|
172
|
+
props.lenisUsage,
|
|
166
173
|
props.contentReady,
|
|
167
174
|
props.debugName,
|
|
168
175
|
props.parentPath,
|
|
@@ -172,8 +179,13 @@ function RouteHandler(props) {
|
|
|
172
179
|
]);
|
|
173
180
|
useLayoutEffectOnce(() => {
|
|
174
181
|
return () => {
|
|
175
|
-
|
|
176
|
-
|
|
182
|
+
if (props.lenisUsage === void 0 || props.lenisUsage) {
|
|
183
|
+
weaverSetup._lenisInstance?.stop();
|
|
184
|
+
weaverSetup._lenisInstance?.scrollTo(0, {
|
|
185
|
+
immediate: true,
|
|
186
|
+
force: true
|
|
187
|
+
});
|
|
188
|
+
}
|
|
177
189
|
console.log(`[${props.debugName}] Renderer status: Unmounted`);
|
|
178
190
|
};
|
|
179
191
|
});
|
package/dist/routing.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/routing/context.ts","../src/routing/DelayedOutlet.tsx","../src/hooks/routeNormalizer.ts","../src/utils/getParentRoute.ts","../src/routing/Pipeline.tsx","../src/hooks/effectOnce.ts","../src/setup.ts","../src/routing/index.ts"],"sourcesContent":["import { create } from 'zustand/react';\n\nexport interface WeaverContextGetter {\n /**\n * Current active parent, **AFTER** Pipeline has finished rendering, so the `activeParent`\n * will be delayed. Example: \"/\", \"/works\",...\n */\n activeParent: string;\n\n /**\n * Current active Pipeline. Example: \"/\", \"/works\",...\n *\n * This is **not based on URL**, it's based on which `Pipeline` has access to the the site.\n */\n activePipeline: string;\n\n /**\n * `DelayedOutlet` special variable, indicating if the route is current transitioning to a new route or not.\n */\n navigating: boolean;\n\n /**\n * When the page is rendered, it will turns this to true,\n * any parent page navigation will causes this to goes false, set to false in `DelayedOulet`.\n *\n * It's set to `false` right after `navigating` is set to `true`. `true` statement will be handled by `Pipeline`.\n */\n pageRendered: boolean;\n}\n\ninterface WeaverContextSetter {\n setActiveParent: (activeParent: string) => void;\n setActivePipeline: (activePipeline: string) => void;\n setNavigating: (navigating: boolean) => void;\n setPageRendered: (pageRendered: boolean) => void;\n}\n\nexport const useWeaverContext = create<\n WeaverContextSetter & WeaverContextGetter\n>()((set) => ({\n activeParent: '',\n setActiveParent: (activeParent) => set({ activeParent }),\n\n activePipeline: '',\n setActivePipeline: (activePipeline) => set({ activePipeline }),\n\n navigating: true,\n setNavigating: (navigating) => set({ navigating }),\n\n pageRendered: false,\n setPageRendered: (pageRendered) => set({ pageRendered }),\n}));\n","import { type ReactNode, useLayoutEffect, useRef, useState } from 'react';\nimport { useOutlet } from 'react-router';\nimport { useRouteNormalizer } from '../hooks/routeNormalizer';\nimport { getParentRoute } from '../utils/getParentRoute';\nimport { useWeaverContext } from './context';\n\n/**\n * A core part of an in-house tool called `weaver`.\n *\n * Delaying the routing process from `react-router`, handles gracefully between `Pipeline`s\n * while allowing any loading fallback component to listen and react with event changes.\n */\nexport default function DelayedOutlet(props: { delay: number }) {\n // Middleware to detect and replace invalid url.\n useRouteNormalizer({ autoReplace: true });\n\n const activePipeline = useWeaverContext((state) => state.activePipeline);\n const setNavigating = useWeaverContext((state) => state.setNavigating);\n const setPageRendered = useWeaverContext((state) => state.setPageRendered);\n\n const renderPageTask = useRef(setTimeout(() => {}));\n const routerOutlet = useOutlet();\n\n const [renderer, setRenderer] = useState<ReactNode>(null);\n\n // Handle and update new parent page.\n useLayoutEffect(() => {\n /**\n * `pageRendered` should be outside of `renderPageTask`,\n * we alrady have `Pipeline` to correct errors.\n */\n if ('scrollRestoration' in history) {\n history.scrollRestoration = 'manual';\n }\n\n if (getParentRoute(window.location.pathname) === activePipeline) {\n // Avoid while changing page, cancelling before new page pushed in\n // cause `activePipeline` to not change, making `navigating` softlock.\n setNavigating(false);\n return;\n }\n\n setNavigating(true);\n setPageRendered(false);\n\n clearTimeout(renderPageTask.current);\n renderPageTask.current = setTimeout(() => {\n setRenderer(routerOutlet!);\n setNavigating(false);\n }, props.delay);\n\n return () => {\n /**\n * Clear invalid task that were scheduled last effect.\n */\n clearInterval(renderPageTask.current);\n };\n }, [\n activePipeline,\n props.delay,\n routerOutlet,\n setNavigating,\n setPageRendered,\n ]);\n\n return renderer;\n}\n","import { useCallback, useLayoutEffect } from 'react';\nimport { useLocation, useNavigate } from 'react-router';\n\nexport function useRouteNormalizer(options: { autoReplace: boolean }) {\n const { pathname } = useLocation();\n const navigate = useNavigate();\n\n const normalizer = useCallback(\n (input: string) => input.replace(/\\/+\\//g, () => '/'),\n []\n );\n\n useLayoutEffect(() => {\n const result = normalizer(pathname);\n if (options.autoReplace && result !== pathname) {\n window.location.replace(result);\n }\n }, [options.autoReplace, pathname, navigate, normalizer]);\n\n return {\n pathname,\n normalizer,\n };\n}\n","export function getParentRoute(pathname: string) {\n let slashes = 0;\n let sliceAt = 0;\n for (sliceAt; sliceAt < pathname.length; sliceAt++) {\n if (pathname[sliceAt] == '/') {\n slashes++;\n }\n if (slashes === 2) {\n break;\n }\n }\n\n return pathname.slice(0, sliceAt);\n}\n","import React, { useLayoutEffect, type ReactNode } from 'react';\nimport { useLayoutEffectOnce } from '../hooks/effectOnce';\nimport { weaverSetup } from '../setup';\nimport { useWeaverContext } from './context';\n\ninterface PipelineProps {\n children?: ReactNode;\n\n /**\n * A state switch to notifies `Pipeline` that the content and elements of the page is ready to be displayed.\n *\n * Usually, you will need to preload some other external sources, or initialize 3D scene, this state\n * make sure that the loading fallback doesn't mess up and show initializing stuff.\n *\n * Using `BakeScene`, you can ensure that the scene is loaded via its callback, you can then pass the state value that\n * `BakeScene` changes to this variable to hide all the lags behind loading screen.\n */\n contentReady?: boolean;\n\n /**\n * Title for the page.\n */\n title: string;\n\n /**\n * By default, `Pipeline` will log the current phase to console.\n */\n debugName: string;\n\n /**\n * This is crucial for different `Pipeline`s to differentiate each other and avoiding conflict.\n *\n * Example for parent path: `/`, `/about`, `/projects`,...\n */\n parentPath: string;\n\n /**\n * By default, this value is `true`\n *\n * When navigating off of a previous `Pipeline`. It will stop lenis as a clean up.\n *\n * So when a new `Pipeline` takes in, it will enable lenis immediately when `contentReady` is switched to `true`.\n *\n * Set to `false` to gain manual control over when lenis will start. This does not affect to stop mechanism,\n * you don't have to clean up yourself.\n */\n autoStartLenis?: boolean;\n}\n\n/**\n * A core part of an in-house tool called `weaver`.\n *\n * `Pipeline`: Notifies & reflect changes to/from `LoadingFallback`\n * and `DelayedOutlet` about its page loading status.\n *\n * All parent routes must have `Pipeline` in order to work and sync with `DelayedOutlet`.\n */\nexport default function Pipeline(props: PipelineProps) {\n const { children, ...restOfProps } = props;\n return (\n <>\n <RouteHandler {...restOfProps} />\n {children}\n </>\n );\n}\n\nfunction RouteHandler(props: Omit<PipelineProps, 'children'>) {\n const navigating = useWeaverContext((state) => state.navigating);\n const pageRendered = useWeaverContext((state) => state.pageRendered);\n const activeParent = useWeaverContext((state) => state.activeParent);\n\n const setActivePipeline = useWeaverContext(\n (state) => state.setActivePipeline\n );\n const setPageRendered = useWeaverContext((state) => state.setPageRendered);\n const setActiveParent = useWeaverContext((state) => state.setActiveParent);\n\n useLayoutEffect(() => {\n document.title = props.title;\n setActivePipeline(props.parentPath);\n\n if (props.contentReady !== undefined && !props.contentReady) {\n console.log(`[${props.debugName}] Renderer status: Loading scene`);\n return;\n }\n\n if (!navigating && (!pageRendered || activeParent !== props.parentPath)) {\n if (props.autoStartLenis === undefined || props.autoStartLenis) {\n weaverSetup._lenisInstance!.start();\n }\n\n setPageRendered(true);\n setActiveParent(props.parentPath);\n\n console.log(`[${props.debugName}] Renderer status: Mounted`);\n }\n }, [\n activeParent,\n setActivePipeline,\n navigating,\n pageRendered,\n props.autoStartLenis,\n props.contentReady,\n props.debugName,\n props.parentPath,\n props.title,\n setActiveParent,\n setPageRendered,\n ]);\n\n useLayoutEffectOnce(() => {\n return () => {\n /**\n * When unmounted, stop lenis to pass control to another Pipline instance.\n *\n * The unmount process only happens when the `<LoadingFallback />` kicks in,\n * so any visual glitches can happen in here, we can now set the scroll position to 0.\n */\n weaverSetup._lenisInstance!.stop();\n weaverSetup._lenisInstance!.scrollTo(0, { immediate: true, force: true });\n\n console.log(`[${props.debugName}] Renderer status: Unmounted`);\n };\n });\n\n return null;\n}\n","import { useEffect, useLayoutEffect } from 'react';\n\nexport function useEffectOnce(callback: React.EffectCallback) {\n // eslint-disable-next-line react-hooks/exhaustive-deps\n useEffect(callback, []);\n}\n\nexport function useLayoutEffectOnce(callback: React.EffectCallback) {\n // eslint-disable-next-line react-hooks/exhaustive-deps\n useLayoutEffect(callback, []);\n}\n","import Lenis from 'lenis';\nimport { ReactNode } from 'react';\n\nexport type BasicTunnelIn = ({ children }: { children: ReactNode }) => null;\n\nclass WeaverSetup {\n /**\n * This variable is handled internally by weaver. **Do not use**.\n */\n get _lenisInstance(): Lenis | undefined {\n return (globalThis as any).__weaverLenis;\n }\n set _lenisInstance(val: Lenis | undefined) {\n (globalThis as any).__weaverLenis = val;\n }\n\n /**\n * This variable is handled internally by weaver. **Do not use**.\n */\n get _Default3DTunnelIn(): BasicTunnelIn | undefined {\n return (globalThis as any).__weaver3DTunnel;\n }\n set _Default3DTunnelIn(val: BasicTunnelIn | undefined) {\n (globalThis as any).__weaver3DTunnel = val;\n }\n\n setLenisInstance(instance: Lenis) {\n this._lenisInstance = instance;\n }\n set3DTunnel(tunnelIn: BasicTunnelIn) {\n this._Default3DTunnelIn = tunnelIn;\n }\n}\n\nexport const weaverSetup = new WeaverSetup();\n","import { useWeaverContext, WeaverContextGetter } from './context';\nimport DelayedOutlet from './DelayedOutlet';\nimport Pipeline from './Pipeline';\n\n/// A read-only state for reacting with changes reflected by weaver.\nexport const useWeaverState = (givenState: keyof WeaverContextGetter) => {\n const state = useWeaverContext((state) => state[givenState]);\n return state;\n};\n\nexport { DelayedOutlet, Pipeline };\n"],"mappings":"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","names":["useLayoutEffect","useLayoutEffect","useLayoutEffect","useLayoutEffect","useLayoutEffect","useLayoutEffect","state"]}
|
|
1
|
+
{"version":3,"sources":["../src/routing/context.ts","../src/routing/DelayedOutlet.tsx","../src/hooks/routeNormalizer.ts","../src/utils/getParentRoute.ts","../src/routing/Pipeline.tsx","../src/hooks/effectOnce.ts","../src/setup.ts","../src/routing/index.ts"],"sourcesContent":["import { create } from 'zustand/react';\n\nexport interface WeaverContextGetter {\n /**\n * Current active parent, **AFTER** Pipeline has finished rendering, so the `activeParent`\n * will be delayed. Example: \"/\", \"/works\",...\n */\n activeParent: string;\n\n /**\n * Current active Pipeline. Example: \"/\", \"/works\",...\n *\n * This is **not based on URL**, it's based on which `Pipeline` has access to the the site.\n */\n activePipeline: string;\n\n /**\n * `DelayedOutlet` special variable, indicating if the route is current transitioning to a new route or not.\n */\n navigating: boolean;\n\n /**\n * When the page is rendered, it will turns this to true,\n * any parent page navigation will causes this to goes false, set to false in `DelayedOulet`.\n *\n * It's set to `false` right after `navigating` is set to `true`. `true` statement will be handled by `Pipeline`.\n */\n pageRendered: boolean;\n}\n\ninterface WeaverContextSetter {\n setActiveParent: (activeParent: string) => void;\n setActivePipeline: (activePipeline: string) => void;\n setNavigating: (navigating: boolean) => void;\n setPageRendered: (pageRendered: boolean) => void;\n}\n\nexport const useWeaverContext = create<\n WeaverContextSetter & WeaverContextGetter\n>()((set) => ({\n activeParent: '',\n setActiveParent: (activeParent) => set({ activeParent }),\n\n activePipeline: '',\n setActivePipeline: (activePipeline) => set({ activePipeline }),\n\n navigating: true,\n setNavigating: (navigating) => set({ navigating }),\n\n pageRendered: false,\n setPageRendered: (pageRendered) => set({ pageRendered }),\n}));\n","import { type ReactNode, useLayoutEffect, useRef, useState } from 'react';\nimport { useOutlet } from 'react-router';\nimport { useRouteNormalizer } from '../hooks/routeNormalizer';\nimport { getParentRoute } from '../utils/getParentRoute';\nimport { useWeaverContext } from './context';\n\n/**\n * A core part of an in-house tool called `weaver`.\n *\n * Delaying the routing process from `react-router`, handles gracefully between `Pipeline`s\n * while allowing any loading fallback component to listen and react with event changes.\n */\nexport default function DelayedOutlet(props: { delay: number }) {\n // Middleware to detect and replace invalid url.\n useRouteNormalizer({ autoReplace: true });\n\n const activePipeline = useWeaverContext((state) => state.activePipeline);\n const setNavigating = useWeaverContext((state) => state.setNavigating);\n const setPageRendered = useWeaverContext((state) => state.setPageRendered);\n\n const renderPageTask = useRef(setTimeout(() => {}));\n const routerOutlet = useOutlet();\n\n const [renderer, setRenderer] = useState<ReactNode>(null);\n\n // Handle and update new parent page.\n useLayoutEffect(() => {\n /**\n * `pageRendered` should be outside of `renderPageTask`,\n * we alrady have `Pipeline` to correct errors.\n */\n if ('scrollRestoration' in history) {\n history.scrollRestoration = 'manual';\n }\n\n if (getParentRoute(window.location.pathname) === activePipeline) {\n // Avoid while changing page, cancelling before new page pushed in\n // cause `activePipeline` to not change, making `navigating` softlock.\n setNavigating(false);\n return;\n }\n\n setNavigating(true);\n setPageRendered(false);\n\n clearTimeout(renderPageTask.current);\n renderPageTask.current = setTimeout(() => {\n setRenderer(routerOutlet!);\n setNavigating(false);\n }, props.delay);\n\n return () => {\n /**\n * Clear invalid task that were scheduled last effect.\n */\n clearInterval(renderPageTask.current);\n };\n }, [\n activePipeline,\n props.delay,\n routerOutlet,\n setNavigating,\n setPageRendered,\n ]);\n\n return renderer;\n}\n","import { useCallback, useLayoutEffect } from 'react';\nimport { useLocation, useNavigate } from 'react-router';\n\nexport function useRouteNormalizer(options: { autoReplace: boolean }) {\n const { pathname } = useLocation();\n const navigate = useNavigate();\n\n const normalizer = useCallback(\n (input: string) => input.replace(/\\/+\\//g, () => '/'),\n []\n );\n\n useLayoutEffect(() => {\n const result = normalizer(pathname);\n if (options.autoReplace && result !== pathname) {\n window.location.replace(result);\n }\n }, [options.autoReplace, pathname, navigate, normalizer]);\n\n return {\n pathname,\n normalizer,\n };\n}\n","export function getParentRoute(pathname: string) {\n let slashes = 0;\n let sliceAt = 0;\n for (sliceAt; sliceAt < pathname.length; sliceAt++) {\n if (pathname[sliceAt] == '/') {\n slashes++;\n }\n if (slashes === 2) {\n break;\n }\n }\n\n return pathname.slice(0, sliceAt);\n}\n","import React, { useLayoutEffect, useMemo, type ReactNode } from 'react';\nimport { useLayoutEffectOnce } from '../hooks/effectOnce';\nimport { weaverSetup } from '../setup';\nimport { getParentRoute } from '../utils/getParentRoute';\nimport { useWeaverContext } from './context';\n\ninterface PipelineProps {\n children?: ReactNode;\n\n /**\n * A state switch to notifies `Pipeline` that the content and elements of the page is ready to be displayed.\n *\n * Usually, you will need to preload some other external sources, or initialize 3D scene, this state\n * make sure that the loading fallback doesn't mess up and show initializing stuff.\n *\n * Using `BakeScene`, you can ensure that the scene is loaded via its callback, you can then pass the state value that\n * `BakeScene` changes to this variable to hide all the lags behind loading screen.\n */\n contentReady?: boolean;\n\n /**\n * Title for the page.\n */\n title: string;\n\n /**\n * By default, `Pipeline` will log the current phase to console.\n */\n debugName: string;\n\n /**\n * This is the only feature where weaver will use lenis to directly manipulate scrolling behaviour.\n *\n * By default, this value is `true` when a lenis instance is provided.\n *\n * `Pipeline` will stop and start lenis automatically when this variable is `true`.\n *\n * Disable this feature to gains complete control over lenis when mounting/unmounting to handle however you want.\n */\n lenisUsage?: boolean;\n}\n\n/**\n * A core part of an in-house tool called `weaver`.\n *\n * `Pipeline`: Notifies & reflect changes to/from `LoadingFallback`\n * and `DelayedOutlet` about its page loading status.\n *\n * All parent routes must have `Pipeline` in order to work and sync with `DelayedOutlet`.\n */\nexport default function Pipeline(props: PipelineProps) {\n const { children, ...restOfProps } = props;\n const parentPath = useMemo(\n () => getParentRoute(window.location.pathname),\n []\n );\n\n useLayoutEffect(() => {\n console.log(parentPath);\n }, [parentPath]);\n\n return (\n <>\n <RouteHandler {...restOfProps} parentPath={parentPath} />\n {children}\n </>\n );\n}\n\nfunction RouteHandler(\n props: Omit<PipelineProps, 'children'> & { parentPath: string }\n) {\n const navigating = useWeaverContext((state) => state.navigating);\n const pageRendered = useWeaverContext((state) => state.pageRendered);\n const activeParent = useWeaverContext((state) => state.activeParent);\n\n const setActivePipeline = useWeaverContext(\n (state) => state.setActivePipeline\n );\n const setPageRendered = useWeaverContext((state) => state.setPageRendered);\n const setActiveParent = useWeaverContext((state) => state.setActiveParent);\n\n useLayoutEffect(() => {\n document.title = props.title;\n setActivePipeline(props.parentPath);\n\n if (props.contentReady !== undefined && !props.contentReady) {\n console.log(`[${props.debugName}] Renderer status: Loading scene`);\n return;\n }\n\n if (!navigating && (!pageRendered || activeParent !== props.parentPath)) {\n if (props.lenisUsage === undefined || props.lenisUsage) {\n weaverSetup._lenisInstance?.start();\n }\n\n setPageRendered(true);\n setActiveParent(props.parentPath);\n\n console.log(`[${props.debugName}] Renderer status: Mounted`);\n }\n }, [\n activeParent,\n setActivePipeline,\n navigating,\n pageRendered,\n props.lenisUsage,\n props.contentReady,\n props.debugName,\n props.parentPath,\n props.title,\n setActiveParent,\n setPageRendered,\n ]);\n\n useLayoutEffectOnce(() => {\n return () => {\n /**\n * When unmounted, stop lenis to pass control to another Pipline instance.\n *\n * The unmount process only happens when the `<LoadingFallback />` kicks in,\n * so any visual glitches can happen in here, we can now set the scroll position to 0.\n */\n if (props.lenisUsage === undefined || props.lenisUsage) {\n weaverSetup._lenisInstance?.stop();\n weaverSetup._lenisInstance?.scrollTo(0, {\n immediate: true,\n force: true,\n });\n }\n\n console.log(`[${props.debugName}] Renderer status: Unmounted`);\n };\n });\n\n return null;\n}\n","import { useEffect, useLayoutEffect } from 'react';\n\nexport function useEffectOnce(callback: React.EffectCallback) {\n // eslint-disable-next-line react-hooks/exhaustive-deps\n useEffect(callback, []);\n}\n\nexport function useLayoutEffectOnce(callback: React.EffectCallback) {\n // eslint-disable-next-line react-hooks/exhaustive-deps\n useLayoutEffect(callback, []);\n}\n","import Lenis from 'lenis';\nimport { ReactNode } from 'react';\n\nexport type BasicTunnelIn = ({ children }: { children: ReactNode }) => null;\n\nclass WeaverSetup {\n /**\n * This variable is handled internally by weaver. **Do not use**.\n */\n get _lenisInstance(): Lenis | undefined {\n return (globalThis as any).__weaverLenis;\n }\n set _lenisInstance(val: Lenis | undefined) {\n (globalThis as any).__weaverLenis = val;\n }\n\n /**\n * This variable is handled internally by weaver. **Do not use**.\n */\n get _Default3DTunnelIn(): BasicTunnelIn | undefined {\n return (globalThis as any).__weaver3DTunnel;\n }\n set _Default3DTunnelIn(val: BasicTunnelIn | undefined) {\n (globalThis as any).__weaver3DTunnel = val;\n }\n\n setLenisInstance(instance: Lenis) {\n this._lenisInstance = instance;\n }\n set3DTunnel(tunnelIn: BasicTunnelIn) {\n this._Default3DTunnelIn = tunnelIn;\n }\n}\n\nexport const weaverSetup = new WeaverSetup();\n","import { useWeaverContext, WeaverContextGetter } from './context';\nimport DelayedOutlet from './DelayedOutlet';\nimport Pipeline from './Pipeline';\n\n/// A read-only state for reacting with changes reflected by weaver.\nexport const useWeaverState = (givenState: keyof WeaverContextGetter) => {\n const state = useWeaverContext((state) => state[givenState]);\n return state;\n};\n\nexport { DelayedOutlet, Pipeline };\n"],"mappings":"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","names":["useLayoutEffect","useLayoutEffect","useLayoutEffect","useLayoutEffect","useLayoutEffect","useLayoutEffect","state"]}
|
package/package.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"author": "neveranyart",
|
|
3
3
|
"license": "GPL-3.0-or-later",
|
|
4
4
|
"name": "@neveranyart/weaver",
|
|
5
|
-
"version": "1.0.
|
|
5
|
+
"version": "1.0.9",
|
|
6
6
|
"description": "An in-house package by neverany for making interactive React CSR.",
|
|
7
7
|
"packageManager": "yarn@4.10.3",
|
|
8
8
|
"publishConfig": {
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
},
|
|
11
11
|
"scripts": {
|
|
12
12
|
"build": "tsup",
|
|
13
|
-
"
|
|
13
|
+
"prepublishOnly": "tsup"
|
|
14
14
|
},
|
|
15
15
|
"tsup": {
|
|
16
16
|
"entry": {
|