@neveranyart/weaver 1.0.5 → 1.0.6
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/dist/hooks.js +34 -9
- package/dist/hooks.js.map +1 -1
- package/dist/hooks.mjs +34 -9
- package/dist/hooks.mjs.map +1 -1
- package/dist/index-BF71fQbH.d.mts +21 -0
- package/dist/index-BF71fQbH.d.ts +21 -0
- package/dist/index.d.mts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +13 -6
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +13 -6
- package/dist/index.mjs.map +1 -1
- package/dist/routing.js +20 -4
- package/dist/routing.js.map +1 -1
- package/dist/routing.mjs +20 -4
- package/dist/routing.mjs.map +1 -1
- package/dist/scene.d.mts +1 -1
- package/dist/scene.d.ts +1 -1
- package/dist/scene.js +37 -13
- package/dist/scene.js.map +1 -1
- package/dist/scene.mjs +37 -13
- package/dist/scene.mjs.map +1 -1
- package/package.json +3 -2
- package/dist/index-BRbPCByN.d.mts +0 -12
- package/dist/index-BRbPCByN.d.ts +0 -12
package/dist/routing.mjs
CHANGED
|
@@ -100,7 +100,23 @@ function useLayoutEffectOnce(callback) {
|
|
|
100
100
|
}
|
|
101
101
|
|
|
102
102
|
// src/setup.ts
|
|
103
|
-
var
|
|
103
|
+
var WeaverSetup = class {
|
|
104
|
+
/**
|
|
105
|
+
* This variable is handled internally by weaver. **Do not use**.
|
|
106
|
+
*/
|
|
107
|
+
_lenisInstance = void 0;
|
|
108
|
+
/**
|
|
109
|
+
* This variable is handled internally by weaver. **Do not use**.
|
|
110
|
+
*/
|
|
111
|
+
_Default3DTunnelIn = void 0;
|
|
112
|
+
setLenisInstance(instance) {
|
|
113
|
+
this._lenisInstance = instance;
|
|
114
|
+
}
|
|
115
|
+
set3DTunnel(tunnelIn) {
|
|
116
|
+
this._Default3DTunnelIn = tunnelIn;
|
|
117
|
+
}
|
|
118
|
+
};
|
|
119
|
+
var weaverSetup = new WeaverSetup();
|
|
104
120
|
|
|
105
121
|
// src/routing/Pipeline.tsx
|
|
106
122
|
function Pipeline(props) {
|
|
@@ -125,7 +141,7 @@ function RouteHandler(props) {
|
|
|
125
141
|
}
|
|
126
142
|
if (!navigating && (!pageRendered || activeParent !== props.parentPath)) {
|
|
127
143
|
if (props.autoStartLenis === void 0 || props.autoStartLenis) {
|
|
128
|
-
|
|
144
|
+
weaverSetup._lenisInstance.start();
|
|
129
145
|
}
|
|
130
146
|
setPageRendered(true);
|
|
131
147
|
setActiveParent(props.parentPath);
|
|
@@ -146,8 +162,8 @@ function RouteHandler(props) {
|
|
|
146
162
|
]);
|
|
147
163
|
useLayoutEffectOnce(() => {
|
|
148
164
|
return () => {
|
|
149
|
-
|
|
150
|
-
|
|
165
|
+
weaverSetup._lenisInstance.stop();
|
|
166
|
+
weaverSetup._lenisInstance.scrollTo(0, { immediate: true, force: true });
|
|
151
167
|
console.log(`[${props.debugName}] Renderer status: Unmounted`);
|
|
152
168
|
};
|
|
153
169
|
});
|
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 { lenisInstance } 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 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 lenisInstance!.stop();\n 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 let lenisInstance: Lenis | undefined = undefined;\n\nexport type BasicTunnelIn = ({ children }: { children: ReactNode }) => null;\nexport let Default3DTunnelIn: BasicTunnelIn | undefined = undefined;\n\nexport const weaverSetup = {\n setLenisInstance(instance: Lenis) {\n lenisInstance = instance;\n },\n set3DTunnel(tunnelIn: BasicTunnelIn) {\n Default3DTunnelIn = tunnelIn;\n },\n};\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, 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 _lenisInstance: Lenis | undefined = undefined;\n /**\n * This variable is handled internally by weaver. **Do not use**.\n */\n _Default3DTunnelIn: BasicTunnelIn | undefined = undefined;\n\n setLenisInstance(instance: Lenis) {\n this._lenisInstance = instance;\n }\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/dist/scene.d.mts
CHANGED
package/dist/scene.d.ts
CHANGED
package/dist/scene.js
CHANGED
|
@@ -40,14 +40,29 @@ var import_fiber = require("@react-three/fiber");
|
|
|
40
40
|
var import_react = __toESM(require("react"));
|
|
41
41
|
|
|
42
42
|
// src/setup.ts
|
|
43
|
-
var
|
|
44
|
-
|
|
43
|
+
var WeaverSetup = class {
|
|
44
|
+
/**
|
|
45
|
+
* This variable is handled internally by weaver. **Do not use**.
|
|
46
|
+
*/
|
|
47
|
+
_lenisInstance = void 0;
|
|
48
|
+
/**
|
|
49
|
+
* This variable is handled internally by weaver. **Do not use**.
|
|
50
|
+
*/
|
|
51
|
+
_Default3DTunnelIn = void 0;
|
|
52
|
+
setLenisInstance(instance) {
|
|
53
|
+
this._lenisInstance = instance;
|
|
54
|
+
}
|
|
55
|
+
set3DTunnel(tunnelIn) {
|
|
56
|
+
this._Default3DTunnelIn = tunnelIn;
|
|
57
|
+
}
|
|
58
|
+
};
|
|
59
|
+
var weaverSetup = new WeaverSetup();
|
|
45
60
|
|
|
46
61
|
// src/scene/BakeScene.tsx
|
|
47
62
|
function BakeScene(props) {
|
|
48
63
|
const unique = (0, import_react.useId)();
|
|
49
64
|
const pipeObjects = (0, import_react.useId)();
|
|
50
|
-
const TunnelIn = props.tunnelIn ??
|
|
65
|
+
const TunnelIn = props.tunnelIn ?? weaverSetup._Default3DTunnelIn;
|
|
51
66
|
if (!TunnelIn) {
|
|
52
67
|
throw Error(
|
|
53
68
|
"Failed to find a tunnel to use. Consider setting a default tunnel."
|
|
@@ -133,11 +148,17 @@ var scrollCallbackReason = {
|
|
|
133
148
|
};
|
|
134
149
|
function useLenisCallback(callback, options) {
|
|
135
150
|
const callbackWrapScroll = (0, import_react4.useCallback)(
|
|
136
|
-
() => callback(
|
|
151
|
+
() => callback(
|
|
152
|
+
weaverSetup._lenisInstance.actualScroll,
|
|
153
|
+
scrollCallbackReason.Scroll
|
|
154
|
+
),
|
|
137
155
|
[callback]
|
|
138
156
|
);
|
|
139
157
|
const callbackWrapResize = (0, import_react4.useCallback)(
|
|
140
|
-
() => callback(
|
|
158
|
+
() => callback(
|
|
159
|
+
weaverSetup._lenisInstance.actualScroll,
|
|
160
|
+
scrollCallbackReason.Resize
|
|
161
|
+
),
|
|
141
162
|
[callback]
|
|
142
163
|
);
|
|
143
164
|
const intersectOn = (0, import_react4.useMemo)(
|
|
@@ -153,10 +174,10 @@ function useLenisCallback(callback, options) {
|
|
|
153
174
|
events: {
|
|
154
175
|
onIntersect(entry) {
|
|
155
176
|
if (entry.isIntersecting) {
|
|
156
|
-
|
|
177
|
+
weaverSetup._lenisInstance.on("scroll", callbackWrapScroll);
|
|
157
178
|
window.addEventListener("resize", callbackWrapResize);
|
|
158
179
|
} else {
|
|
159
|
-
|
|
180
|
+
weaverSetup._lenisInstance.off("scroll", callbackWrapScroll);
|
|
160
181
|
window.removeEventListener("resize", callbackWrapResize);
|
|
161
182
|
}
|
|
162
183
|
}
|
|
@@ -165,14 +186,17 @@ function useLenisCallback(callback, options) {
|
|
|
165
186
|
});
|
|
166
187
|
(0, import_react4.useLayoutEffect)(() => {
|
|
167
188
|
if (!intersectOn) {
|
|
168
|
-
|
|
189
|
+
weaverSetup._lenisInstance.on("scroll", callbackWrapScroll);
|
|
169
190
|
window.addEventListener("resize", callbackWrapResize);
|
|
170
191
|
}
|
|
171
192
|
if (initialCall) {
|
|
172
|
-
callback(
|
|
193
|
+
callback(
|
|
194
|
+
weaverSetup._lenisInstance.actualScroll,
|
|
195
|
+
scrollCallbackReason.Initialize
|
|
196
|
+
);
|
|
173
197
|
}
|
|
174
198
|
return () => {
|
|
175
|
-
|
|
199
|
+
weaverSetup._lenisInstance.off("scroll", callbackWrapScroll);
|
|
176
200
|
window.removeEventListener("resize", callbackWrapResize);
|
|
177
201
|
};
|
|
178
202
|
}, [
|
|
@@ -187,7 +211,7 @@ function useLenisCallback(callback, options) {
|
|
|
187
211
|
// src/scene/SceneSync.tsx
|
|
188
212
|
function SceneSync(props) {
|
|
189
213
|
const unique = (0, import_react6.useId)();
|
|
190
|
-
const TunnelIn = props.tunnelIn ??
|
|
214
|
+
const TunnelIn = props.tunnelIn ?? weaverSetup._Default3DTunnelIn;
|
|
191
215
|
if (!TunnelIn) {
|
|
192
216
|
throw Error(
|
|
193
217
|
"Failed to find a tunnel to use. Consider setting a default tunnel."
|
|
@@ -221,11 +245,11 @@ function SyncInternal(props) {
|
|
|
221
245
|
const screenW = document.body.clientWidth;
|
|
222
246
|
const vpWidthRatio = vp.width / screenW;
|
|
223
247
|
const vpHeightRatio = vp.height / screenH;
|
|
224
|
-
const scrollOffset =
|
|
248
|
+
const scrollOffset = weaverSetup._lenisInstance.actualScroll / screenH * vp.height;
|
|
225
249
|
const w = domRect.width * vpWidthRatio;
|
|
226
250
|
const h = domRect.height * vpHeightRatio;
|
|
227
251
|
const x = domRect.x * vpWidthRatio + w * 0.5 - vp.width * 0.5;
|
|
228
|
-
const y = vp.height * 0.5 - (domRect.y +
|
|
252
|
+
const y = vp.height * 0.5 - (domRect.y + weaverSetup._lenisInstance.actualScroll) * vpHeightRatio - h * 0.5 + scrollOffset;
|
|
229
253
|
if (onLayoutUpdate) {
|
|
230
254
|
onLayoutUpdate(domRect, { w, h }, { x, y });
|
|
231
255
|
}
|
package/dist/scene.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/scene/index.ts","../src/scene/BakeScene.tsx","../src/setup.ts","../src/scene/SceneSync.tsx","../src/hooks/effectOnce.ts","../src/hooks/lenisCallback.ts","../src/hooks/orbit.ts"],"sourcesContent":["import BakeScene from './BakeScene';\nimport SceneSync from './SceneSync';\n\nexport { BakeScene, SceneSync };\n","import { useFrame } from '@react-three/fiber';\nimport React, {\n type Dispatch,\n Fragment,\n type ReactNode,\n type SetStateAction,\n useId,\n useRef,\n} from 'react';\nimport { BasicTunnelIn, Default3DTunnelIn } from '../setup';\n\n/**\n * A core part of an in-house tool called `weaver`.\n *\n * `BakeScene`: This component will notifiy when the global 3D scene is ready.\n *\n * It works by tune in the `useFrame` from `@react-three/fiber`. When the scene is loaded, `useFreame` will fire\n * with ease, the component takes advantage of that, and because `useLoader` is unreliable.\n *\n * This component also accepts 3D elements `children` to be rendered directly to the canvas with some camera options.\n * But you don't have to put every 3D components inside the baker, for example, `SceneSync`s in the page are also\n * being watched by this component.\n *\n * The route renderer **CAN'T** detect if the page has 3D elements or not, so if a page uses any sort of 3D rendering,\n * this component **MUST** be a children iniside `Pipeline` (`index.tsx`), then pass the state value that bake changes\n * to `Pipeline`'s `contentReady` in order for the `BakeScene` to work behind loading fallback screen.\n */\nexport default function BakeScene(props: {\n children?: ReactNode;\n sceneReady: boolean;\n tunnelIn?: BasicTunnelIn;\n loadTaskDelay?: number;\n setSceneReady: Dispatch<SetStateAction<boolean>>;\n onReady?: () => void;\n}) {\n const unique = useId();\n const pipeObjects = useId();\n\n const TunnelIn = props.tunnelIn ?? Default3DTunnelIn;\n\n if (!TunnelIn) {\n throw Error(\n 'Failed to find a tunnel to use. Consider setting a default tunnel.'\n );\n }\n\n return (\n <TunnelIn>\n <Fragment key={pipeObjects}>{props.children}</Fragment>\n <NotificationHandler\n key={unique}\n callback={props.onReady}\n sceneReady={props.sceneReady}\n setSceneReady={props.setSceneReady}\n />\n </TunnelIn>\n );\n}\n\nfunction NotificationHandler(props: {\n callback?: (isSceneReady: boolean) => void;\n sceneReady: boolean;\n setSceneReady: (value: boolean) => void;\n}) {\n /**\n * `useFrame` is expensive for something that only triggers once, so yea,\n * we'll remove the notification as soon as the job is done.\n */\n return !props.sceneReady && <RenderNotification {...props} />;\n}\n\nfunction RenderNotification(props: {\n callback?: (isSceneReady: boolean) => void;\n sceneReady: boolean;\n loadTaskDelay?: number;\n setSceneReady: (value: boolean) => void;\n}) {\n const scheduledForCallback = useRef(false);\n\n useFrame(() => {\n if (!props.sceneReady && !scheduledForCallback.current) {\n scheduledForCallback.current = true;\n setTimeout(() => {\n if (props.callback) {\n props.callback(true);\n }\n props.setSceneReady(true);\n }, props.loadTaskDelay ?? 50);\n }\n });\n\n return null;\n}\n","import Lenis from 'lenis';\nimport { ReactNode } from 'react';\n\nexport let lenisInstance: Lenis | undefined = undefined;\n\nexport type BasicTunnelIn = ({ children }: { children: ReactNode }) => null;\nexport let Default3DTunnelIn: BasicTunnelIn | undefined = undefined;\n\nexport const weaverSetup = {\n setLenisInstance(instance: Lenis) {\n lenisInstance = instance;\n },\n set3DTunnel(tunnelIn: BasicTunnelIn) {\n Default3DTunnelIn = tunnelIn;\n },\n};\n","import { Hud } from '@react-three/drei';\nimport { useThree, type Viewport } from '@react-three/fiber';\nimport { cancelFrame, frame } from 'motion/react';\nimport React, {\n type ReactNode,\n type RefObject,\n useCallback,\n useId,\n useLayoutEffect,\n useRef,\n useState,\n} from 'react';\nimport { Group } from 'three';\nimport { useLayoutEffectOnce } from '../hooks/effectOnce';\nimport { useLenisCallback } from '../hooks/lenisCallback';\nimport { useOrbit } from '../hooks/orbit';\nimport { BasicTunnelIn, Default3DTunnelIn, lenisInstance } from '../setup';\n\nexport type Basic3DTransforms = {\n scale: {\n set: (x: number, y: number, z: number) => void;\n };\n position: {\n x: number;\n y: number;\n };\n};\n\ninterface SyncProps {\n /**\n * HTML element ref that `<SceneSync />` will use to sync with the scene.\n *\n * ```tsx\n * <div ref={container} />\n * <SceneSync attach={container}>\n * <group />\n * </SceneSync>\n * ```\n */\n attach: RefObject<HTMLElement | null>;\n\n /**\n * This variable allows fine-grain control over your scene when passed to `<SceneSync />`.\n *\n * `<SceneSync />` will use its own ref and group when creating your scene to control its scale and position.\n * Setting this variable will disable the internal ref, and you can decide on which object gets controlled.\n *\n * This variable is needed for `hud` if you wanted to add a custom camera.\n *\n * For listening to change details, use `onLayoutChange` instead.\n */\n control?: RefObject<Basic3DTransforms | null>;\n\n /**\n * When this variable is set, `<SceneSync />` will send updates when the scene update its positions.\n *\n * The function return the calculated DOM rect, with dimension and position in 3D measurements.\n */\n onLayoutUpdate?: (\n rect: DOMRect,\n dimension: { w: number; h: number },\n position: { x: number; y: number }\n ) => void;\n\n /**\n * Use `Hud` for this scene or not.\n *\n * This is useful when you want to apply custom camera for this scene, or renders multiple scenes on each other.\n *\n * NOTE: When setting a custom camera, the `control` variable must also be set and mount to your scene, not related to the camera\n * to avoid unwanted behavior.\n *\n * `<SceneSync />` groups children passed to it by default, so the camera is also in the group, when syncer updates the group,\n * the camera is also change, ruining the effect.\n */\n hud?: boolean;\n\n /**\n * Control the scene's scaling when positioning.\n */\n scaleFactor?: number;\n\n /**\n * `<SceneSync />` avoid stretching the object by default by using the smallest dimension of the DOM element.\n *\n * This variable will tell `<SceneSync />` to stretch it anyways.\n */\n stretch?: boolean;\n\n /**\n * Disable automatic scaling on the object.\n *\n * This variable will also disable any scaling settings like `stretch` and `scaleFactor`.\n */\n disableScaling?: boolean;\n\n /**\n * `<SceneSync />` will depend on this variable to adjust how it should update.\n *\n * There are 3 modes: `relaxed`, `balanced` and `aggressive`.\n *\n * For each mode, there will be some very distinct trade-offs\n *\n * - `relaxed`: Uses IntersectionObserver paired with a scroll hook, together with ResizeObserver.\n * - (+): Minimal update calls, best performance.\n * - (-): The scene get desynced the moment DOM element moves without changing its sizes.\n * When the scene bleeds out of the DOM element too much, if IntersectionObserver reported that the DOM element\n * is out of view, the scene that did not fully moved out of view will stay there, as scroll hook will be disabled.\n * - `balanced`: Uses IntersectionObserver paired with frame-based update, together with ResizeObserver.\n * - (+): Just enough update calls to allow the DOM element to move freely while maintain aceptable performance.\n * - (-): It will update on every frame when the object gets into view as reported by IntersectionObserver. And the same\n * problem with `relaxed` mode when the scene bleeds out too much.\n * - `aggressive`: Frame-based update only. This mode is like how `<View />` from `@react-three/drei` kepts track of DOM elements.\n * - (+): Designed for precise element <-> scene updates. Can't be desynced, if desynced, that's a bug.\n * - (-): This is frame-based. It will fire updates as long as the scene is still mounted. Too many scenes with this\n * mode enabled is not a good idea. Acceptable amount would be 3 scenes with this mode.\n *\n * Best of both worlds is `balanced` mode, for simpler scenes that doesn't change its position, `relaxed` should be used.\n */\n trackingMode: 'relaxed' | 'balanced' | 'aggressive';\n\n /**\n * Set a custom tunnel for `<SceneSync />` send the components to for this scene only.\n *\n * Which is useful for example, put the objects inside a container in the scene.\n *\n * To set a default tunnel, pass it to `setDefaulTunnel` before use.\n */\n tunnelIn?: BasicTunnelIn;\n\n children: ReactNode;\n}\n\ninterface HudProps extends SyncProps {\n hud: true;\n /**\n * Set the `renderPriority` to render things for `Hud`.\n *\n * This variable is ignored when `hud` is not `true`.\n */\n hudRenderPriority: number;\n}\n\ninterface NormalProps extends SyncProps {\n hud?: false;\n}\n\n/**\n * A core part of an in-house tool called `weaver`.\n *\n * A component to allow three objects to track and sync with DOM element.\n *\n * The component uses `<Hud />` under the \"hud\", so if you want to use more than one `<SceneSync />`,\n * you must set `renderPriority`. If not, the component will render the last scene pushed through React.\n */\nexport default function SceneSync(props: NormalProps | HudProps) {\n const unique = useId();\n\n const TunnelIn = props.tunnelIn ?? Default3DTunnelIn;\n\n if (!TunnelIn) {\n throw Error(\n 'Failed to find a tunnel to use. Consider setting a default tunnel.'\n );\n }\n\n if (props.hud) {\n return (\n <TunnelIn>\n <Hud key={unique} renderPriority={props.hudRenderPriority}>\n <SyncInternal {...props} />\n </Hud>\n </TunnelIn>\n );\n }\n\n return (\n <TunnelIn>\n <SyncInternal key={unique} {...props} />\n </TunnelIn>\n );\n}\n\nfunction SyncInternal(props: SyncProps) {\n const { viewport, camera } = useThree();\n\n const defaultControl = useRef<Group>(null);\n const {\n attach,\n control,\n scaleFactor,\n stretch,\n disableScaling,\n onLayoutUpdate,\n } = props;\n\n const properties: RefObject<{\n viewport?: Omit<Viewport, 'dpr' | 'initialDpr'>;\n }> = useRef({\n viewport: undefined,\n });\n\n const updatePosition = useCallback(() => {\n const activeControl = control ?? defaultControl;\n\n const vp = properties.current.viewport;\n if (!vp) return;\n\n const domRect = attach.current!.getBoundingClientRect();\n const screenH = document.documentElement.clientHeight;\n const screenW = document.body.clientWidth;\n\n const vpWidthRatio = vp.width / screenW;\n const vpHeightRatio = vp.height / screenH;\n\n const scrollOffset = (lenisInstance!.actualScroll / screenH) * vp.height;\n\n const w = domRect.width * vpWidthRatio;\n const h = domRect.height * vpHeightRatio;\n\n const x = domRect.x * vpWidthRatio + w * 0.5 - vp.width * 0.5;\n const y =\n vp.height * 0.5 -\n (domRect.y + lenisInstance!.actualScroll) * vpHeightRatio -\n h * 0.5 +\n scrollOffset;\n\n if (onLayoutUpdate) {\n onLayoutUpdate(domRect, { w, h }, { x, y });\n }\n\n const unwrapedScaleFactor = scaleFactor ?? 1;\n\n if (!disableScaling) {\n if (!stretch) {\n const minScale = Math.min(w, h) * unwrapedScaleFactor;\n activeControl.current!.scale.set(minScale, minScale, minScale);\n } else {\n activeControl.current!.scale.set(\n w * unwrapedScaleFactor,\n h * unwrapedScaleFactor,\n Math.min(w, h) * unwrapedScaleFactor\n );\n }\n }\n\n // eslint-disable-next-line react-hooks/immutability\n activeControl.current!.position.x = x;\n activeControl.current!.position.y = y;\n }, [attach, onLayoutUpdate, control, scaleFactor, disableScaling, stretch]);\n\n /**\n * Update position when `camera` changes.\n */\n useLayoutEffect(() => {\n properties.current.viewport = viewport.getCurrentViewport(camera);\n updatePosition();\n }, [camera, updatePosition, viewport]);\n\n const graceUpdate = useCallback(() => {\n try {\n updatePosition();\n } catch {\n /* empty */\n }\n }, [updatePosition]);\n\n const mode = {\n relaxed: (\n <RelaxedUpdate attach={props.attach} updatePosition={graceUpdate} />\n ),\n balanced: (\n <BalancedUpdate attach={props.attach} updatePosition={graceUpdate} />\n ),\n aggressive: <AggressiveUpdate updatePosition={graceUpdate} />,\n };\n\n if (props.control) {\n return (\n <>\n {props.children}\n {mode[props.trackingMode]}\n </>\n );\n }\n\n return (\n <group ref={defaultControl}>\n {props.children}\n {mode[props.trackingMode]}\n </group>\n );\n}\n\nfunction RelaxedUpdate(props: {\n attach: RefObject<HTMLElement | null>;\n updatePosition: () => void;\n}) {\n const { updatePosition } = props;\n\n /**\n * Scroll hook to update object correctly to the current HTML scroll position.\n */\n useLenisCallback(updatePosition, {\n initialCall: true,\n intersectOn: props.attach,\n });\n\n /**\n * Allows the element to resize too.\n */\n useOrbit({\n target: props.attach,\n events: {\n onIntersect: updatePosition,\n onResize: updatePosition,\n },\n });\n\n useLayoutEffectOnce(updatePosition);\n return null;\n}\n\nfunction BalancedUpdate(props: {\n attach: RefObject<HTMLElement | null>;\n updatePosition: () => void;\n}) {\n const { updatePosition } = props;\n\n const [shouldUpdate, setShouldUpdate] = useState(false);\n\n useOrbit({\n target: props.attach,\n events: {\n onIntersect(entry) {\n setShouldUpdate(entry.isIntersecting);\n },\n onResize: updatePosition,\n },\n rootMargin: '50% 0px 50% 0px',\n });\n\n useLayoutEffect(() => {\n if (shouldUpdate) {\n frame.read(updatePosition, true);\n } else {\n cancelFrame(updatePosition);\n }\n\n return () => {\n cancelFrame(updatePosition);\n };\n }, [updatePosition, shouldUpdate]);\n\n useLayoutEffectOnce(updatePosition);\n return null;\n}\n\nfunction AggressiveUpdate(props: { updatePosition: () => void }) {\n const { updatePosition } = props;\n\n useLayoutEffect(() => {\n frame.read(updatePosition, true);\n\n return () => {\n cancelFrame(updatePosition);\n };\n }, [updatePosition]);\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 { type RefObject, useCallback, useLayoutEffect, useMemo } from 'react';\nimport { lenisInstance } 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 () => callback(lenisInstance!.actualScroll, scrollCallbackReason.Scroll),\n [callback]\n );\n const callbackWrapResize = useCallback(\n () => callback(lenisInstance!.actualScroll, scrollCallbackReason.Resize),\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 lenisInstance!.on('scroll', callbackWrapScroll);\n window.addEventListener('resize', callbackWrapResize);\n } else {\n 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 lenisInstance!.on('scroll', callbackWrapScroll);\n window.addEventListener('resize', callbackWrapResize);\n }\n\n if (initialCall) {\n callback(lenisInstance!.actualScroll, scrollCallbackReason.Initialize);\n }\n\n return () => {\n 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 { 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"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACAA,mBAAyB;AACzB,mBAOO;;;ACLA,IAAI,gBAAmC;AAGvC,IAAI,oBAA+C;;;ADqB3C,SAAR,UAA2B,OAO/B;AACD,QAAM,aAAS,oBAAM;AACrB,QAAM,kBAAc,oBAAM;AAE1B,QAAM,WAAW,MAAM,YAAY;AAEnC,MAAI,CAAC,UAAU;AACb,UAAM;AAAA,MACJ;AAAA,IACF;AAAA,EACF;AAEA,SACE,6BAAAA,QAAA,cAAC,gBACC,6BAAAA,QAAA,cAAC,yBAAS,KAAK,eAAc,MAAM,QAAS,GAC5C,6BAAAA,QAAA;AAAA,IAAC;AAAA;AAAA,MACC,KAAK;AAAA,MACL,UAAU,MAAM;AAAA,MAChB,YAAY,MAAM;AAAA,MAClB,eAAe,MAAM;AAAA;AAAA,EACvB,CACF;AAEJ;AAEA,SAAS,oBAAoB,OAI1B;AAKD,SAAO,CAAC,MAAM,cAAc,6BAAAA,QAAA,cAAC,sBAAoB,GAAG,OAAO;AAC7D;AAEA,SAAS,mBAAmB,OAKzB;AACD,QAAM,2BAAuB,qBAAO,KAAK;AAEzC,6BAAS,MAAM;AACb,QAAI,CAAC,MAAM,cAAc,CAAC,qBAAqB,SAAS;AACtD,2BAAqB,UAAU;AAC/B,iBAAW,MAAM;AACf,YAAI,MAAM,UAAU;AAClB,gBAAM,SAAS,IAAI;AAAA,QACrB;AACA,cAAM,cAAc,IAAI;AAAA,MAC1B,GAAG,MAAM,iBAAiB,EAAE;AAAA,IAC9B;AAAA,EACF,CAAC;AAED,SAAO;AACT;;;AE5FA,kBAAoB;AACpB,IAAAC,gBAAwC;AACxC,IAAAC,gBAAmC;AACnC,IAAAA,gBAQO;;;ACXP,IAAAC,gBAA2C;AAOpC,SAAS,oBAAoB,UAAgC;AAElE,qCAAgB,UAAU,CAAC,CAAC;AAC9B;;;ACVA,IAAAC,gBAAsE;;;ACAtE,IAAAC,gBAAgD;AAQzC,SAAS,SAAS,SAOtB;AACD,QAAM,EAAE,UAAU,YAAY,IAAI,QAAQ;AAC1C,QAAM,EAAE,aAAa,kBAAkB,IAAI;AAE3C,qCAAgB,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;;;AD3BO,IAAM,uBAAuB;AAAA,EAClC,QAAQ;AAAA,EACR,QAAQ;AAAA,EACR,YAAY;AACd;AAMO,SAAS,iBAAiB,UAAoB,SAAuB;AAC1E,QAAM,yBAAqB;AAAA,IACzB,MAAM,SAAS,cAAe,cAAc,qBAAqB,MAAM;AAAA,IACvE,CAAC,QAAQ;AAAA,EACX;AACA,QAAM,yBAAqB;AAAA,IACzB,MAAM,SAAS,cAAe,cAAc,qBAAqB,MAAM;AAAA,IACvE,CAAC,QAAQ;AAAA,EACX;AAEA,QAAM,kBAAc;AAAA,IAClB,MAAM,SAAS;AAAA,IACf,CAAC,SAAS,WAAW;AAAA,EACvB;AACA,QAAM,kBAAc;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,wBAAe,GAAG,UAAU,kBAAkB;AAC9C,iBAAO,iBAAiB,UAAU,kBAAkB;AAAA,QACtD,OAAO;AACL,wBAAe,IAAI,UAAU,kBAAkB;AAC/C,iBAAO,oBAAoB,UAAU,kBAAkB;AAAA,QACzD;AAAA,MACF;AAAA,IACF;AAAA,IACA,YAAY;AAAA,EACd,CAAC;AAED,qCAAgB,MAAM;AACpB,QAAI,CAAC,aAAa;AAChB,oBAAe,GAAG,UAAU,kBAAkB;AAC9C,aAAO,iBAAiB,UAAU,kBAAkB;AAAA,IACtD;AAEA,QAAI,aAAa;AACf,eAAS,cAAe,cAAc,qBAAqB,UAAU;AAAA,IACvE;AAEA,WAAO,MAAM;AACX,oBAAe,IAAI,UAAU,kBAAkB;AAC/C,aAAO,oBAAoB,UAAU,kBAAkB;AAAA,IACzD;AAAA,EACF,GAAG;AAAA,IACD;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF,CAAC;AACH;;;AF0Ee,SAAR,UAA2B,OAA+B;AAC/D,QAAM,aAAS,qBAAM;AAErB,QAAM,WAAW,MAAM,YAAY;AAEnC,MAAI,CAAC,UAAU;AACb,UAAM;AAAA,MACJ;AAAA,IACF;AAAA,EACF;AAEA,MAAI,MAAM,KAAK;AACb,WACE,8BAAAC,QAAA,cAAC,gBACC,8BAAAA,QAAA,cAAC,mBAAI,KAAK,QAAQ,gBAAgB,MAAM,qBACtC,8BAAAA,QAAA,cAAC,gBAAc,GAAG,OAAO,CAC3B,CACF;AAAA,EAEJ;AAEA,SACE,8BAAAA,QAAA,cAAC,gBACC,8BAAAA,QAAA,cAAC,gBAAa,KAAK,QAAS,GAAG,OAAO,CACxC;AAEJ;AAEA,SAAS,aAAa,OAAkB;AACtC,QAAM,EAAE,UAAU,OAAO,QAAI,wBAAS;AAEtC,QAAM,qBAAiB,sBAAc,IAAI;AACzC,QAAM;AAAA,IACJ;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF,IAAI;AAEJ,QAAM,iBAED,sBAAO;AAAA,IACV,UAAU;AAAA,EACZ,CAAC;AAED,QAAM,qBAAiB,2BAAY,MAAM;AACvC,UAAM,gBAAgB,WAAW;AAEjC,UAAM,KAAK,WAAW,QAAQ;AAC9B,QAAI,CAAC,GAAI;AAET,UAAM,UAAU,OAAO,QAAS,sBAAsB;AACtD,UAAM,UAAU,SAAS,gBAAgB;AACzC,UAAM,UAAU,SAAS,KAAK;AAE9B,UAAM,eAAe,GAAG,QAAQ;AAChC,UAAM,gBAAgB,GAAG,SAAS;AAElC,UAAM,eAAgB,cAAe,eAAe,UAAW,GAAG;AAElE,UAAM,IAAI,QAAQ,QAAQ;AAC1B,UAAM,IAAI,QAAQ,SAAS;AAE3B,UAAM,IAAI,QAAQ,IAAI,eAAe,IAAI,MAAM,GAAG,QAAQ;AAC1D,UAAM,IACJ,GAAG,SAAS,OACX,QAAQ,IAAI,cAAe,gBAAgB,gBAC5C,IAAI,MACJ;AAEF,QAAI,gBAAgB;AAClB,qBAAe,SAAS,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,CAAC;AAAA,IAC5C;AAEA,UAAM,sBAAsB,eAAe;AAE3C,QAAI,CAAC,gBAAgB;AACnB,UAAI,CAAC,SAAS;AACZ,cAAM,WAAW,KAAK,IAAI,GAAG,CAAC,IAAI;AAClC,sBAAc,QAAS,MAAM,IAAI,UAAU,UAAU,QAAQ;AAAA,MAC/D,OAAO;AACL,sBAAc,QAAS,MAAM;AAAA,UAC3B,IAAI;AAAA,UACJ,IAAI;AAAA,UACJ,KAAK,IAAI,GAAG,CAAC,IAAI;AAAA,QACnB;AAAA,MACF;AAAA,IACF;AAGA,kBAAc,QAAS,SAAS,IAAI;AACpC,kBAAc,QAAS,SAAS,IAAI;AAAA,EACtC,GAAG,CAAC,QAAQ,gBAAgB,SAAS,aAAa,gBAAgB,OAAO,CAAC;AAK1E,qCAAgB,MAAM;AACpB,eAAW,QAAQ,WAAW,SAAS,mBAAmB,MAAM;AAChE,mBAAe;AAAA,EACjB,GAAG,CAAC,QAAQ,gBAAgB,QAAQ,CAAC;AAErC,QAAM,kBAAc,2BAAY,MAAM;AACpC,QAAI;AACF,qBAAe;AAAA,IACjB,QAAQ;AAAA,IAER;AAAA,EACF,GAAG,CAAC,cAAc,CAAC;AAEnB,QAAM,OAAO;AAAA,IACX,SACE,8BAAAA,QAAA,cAAC,iBAAc,QAAQ,MAAM,QAAQ,gBAAgB,aAAa;AAAA,IAEpE,UACE,8BAAAA,QAAA,cAAC,kBAAe,QAAQ,MAAM,QAAQ,gBAAgB,aAAa;AAAA,IAErE,YAAY,8BAAAA,QAAA,cAAC,oBAAiB,gBAAgB,aAAa;AAAA,EAC7D;AAEA,MAAI,MAAM,SAAS;AACjB,WACE,8BAAAA,QAAA,4BAAAA,QAAA,gBACG,MAAM,UACN,KAAK,MAAM,YAAY,CAC1B;AAAA,EAEJ;AAEA,SACE,8BAAAA,QAAA,cAAC,WAAM,KAAK,kBACT,MAAM,UACN,KAAK,MAAM,YAAY,CAC1B;AAEJ;AAEA,SAAS,cAAc,OAGpB;AACD,QAAM,EAAE,eAAe,IAAI;AAK3B,mBAAiB,gBAAgB;AAAA,IAC/B,aAAa;AAAA,IACb,aAAa,MAAM;AAAA,EACrB,CAAC;AAKD,WAAS;AAAA,IACP,QAAQ,MAAM;AAAA,IACd,QAAQ;AAAA,MACN,aAAa;AAAA,MACb,UAAU;AAAA,IACZ;AAAA,EACF,CAAC;AAED,sBAAoB,cAAc;AAClC,SAAO;AACT;AAEA,SAAS,eAAe,OAGrB;AACD,QAAM,EAAE,eAAe,IAAI;AAE3B,QAAM,CAAC,cAAc,eAAe,QAAI,wBAAS,KAAK;AAEtD,WAAS;AAAA,IACP,QAAQ,MAAM;AAAA,IACd,QAAQ;AAAA,MACN,YAAY,OAAO;AACjB,wBAAgB,MAAM,cAAc;AAAA,MACtC;AAAA,MACA,UAAU;AAAA,IACZ;AAAA,IACA,YAAY;AAAA,EACd,CAAC;AAED,qCAAgB,MAAM;AACpB,QAAI,cAAc;AAChB,0BAAM,KAAK,gBAAgB,IAAI;AAAA,IACjC,OAAO;AACL,qCAAY,cAAc;AAAA,IAC5B;AAEA,WAAO,MAAM;AACX,qCAAY,cAAc;AAAA,IAC5B;AAAA,EACF,GAAG,CAAC,gBAAgB,YAAY,CAAC;AAEjC,sBAAoB,cAAc;AAClC,SAAO;AACT;AAEA,SAAS,iBAAiB,OAAuC;AAC/D,QAAM,EAAE,eAAe,IAAI;AAE3B,qCAAgB,MAAM;AACpB,wBAAM,KAAK,gBAAgB,IAAI;AAE/B,WAAO,MAAM;AACX,qCAAY,cAAc;AAAA,IAC5B;AAAA,EACF,GAAG,CAAC,cAAc,CAAC;AAEnB,SAAO;AACT;","names":["React","import_fiber","import_react","import_react","import_react","import_react","React"]}
|
|
1
|
+
{"version":3,"sources":["../src/scene/index.ts","../src/scene/BakeScene.tsx","../src/setup.ts","../src/scene/SceneSync.tsx","../src/hooks/effectOnce.ts","../src/hooks/lenisCallback.ts","../src/hooks/orbit.ts"],"sourcesContent":["import BakeScene from './BakeScene';\nimport SceneSync from './SceneSync';\n\nexport { BakeScene, SceneSync };\n","import { useFrame } from '@react-three/fiber';\nimport React, {\n type Dispatch,\n Fragment,\n type ReactNode,\n type SetStateAction,\n useId,\n useRef,\n} from 'react';\nimport { BasicTunnelIn, weaverSetup } from '../setup';\n\n/**\n * A core part of an in-house tool called `weaver`.\n *\n * `BakeScene`: This component will notifiy when the global 3D scene is ready.\n *\n * It works by tune in the `useFrame` from `@react-three/fiber`. When the scene is loaded, `useFreame` will fire\n * with ease, the component takes advantage of that, and because `useLoader` is unreliable.\n *\n * This component also accepts 3D elements `children` to be rendered directly to the canvas with some camera options.\n * But you don't have to put every 3D components inside the baker, for example, `SceneSync`s in the page are also\n * being watched by this component.\n *\n * The route renderer **CAN'T** detect if the page has 3D elements or not, so if a page uses any sort of 3D rendering,\n * this component **MUST** be a children iniside `Pipeline` (`index.tsx`), then pass the state value that bake changes\n * to `Pipeline`'s `contentReady` in order for the `BakeScene` to work behind loading fallback screen.\n */\nexport default function BakeScene(props: {\n children?: ReactNode;\n sceneReady: boolean;\n tunnelIn?: BasicTunnelIn;\n loadTaskDelay?: number;\n setSceneReady: Dispatch<SetStateAction<boolean>>;\n onReady?: () => void;\n}) {\n const unique = useId();\n const pipeObjects = useId();\n\n const TunnelIn = props.tunnelIn ?? weaverSetup._Default3DTunnelIn;\n\n if (!TunnelIn) {\n throw Error(\n 'Failed to find a tunnel to use. Consider setting a default tunnel.'\n );\n }\n\n return (\n <TunnelIn>\n <Fragment key={pipeObjects}>{props.children}</Fragment>\n <NotificationHandler\n key={unique}\n callback={props.onReady}\n sceneReady={props.sceneReady}\n setSceneReady={props.setSceneReady}\n />\n </TunnelIn>\n );\n}\n\nfunction NotificationHandler(props: {\n callback?: (isSceneReady: boolean) => void;\n sceneReady: boolean;\n setSceneReady: (value: boolean) => void;\n}) {\n /**\n * `useFrame` is expensive for something that only triggers once, so yea,\n * we'll remove the notification as soon as the job is done.\n */\n return !props.sceneReady && <RenderNotification {...props} />;\n}\n\nfunction RenderNotification(props: {\n callback?: (isSceneReady: boolean) => void;\n sceneReady: boolean;\n loadTaskDelay?: number;\n setSceneReady: (value: boolean) => void;\n}) {\n const scheduledForCallback = useRef(false);\n\n useFrame(() => {\n if (!props.sceneReady && !scheduledForCallback.current) {\n scheduledForCallback.current = true;\n setTimeout(() => {\n if (props.callback) {\n props.callback(true);\n }\n props.setSceneReady(true);\n }, props.loadTaskDelay ?? 50);\n }\n });\n\n return null;\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 _lenisInstance: Lenis | undefined = undefined;\n /**\n * This variable is handled internally by weaver. **Do not use**.\n */\n _Default3DTunnelIn: BasicTunnelIn | undefined = undefined;\n\n setLenisInstance(instance: Lenis) {\n this._lenisInstance = instance;\n }\n\n set3DTunnel(tunnelIn: BasicTunnelIn) {\n this._Default3DTunnelIn = tunnelIn;\n }\n}\n\nexport const weaverSetup = new WeaverSetup();\n","import { Hud } from '@react-three/drei';\nimport { useThree, type Viewport } from '@react-three/fiber';\nimport { cancelFrame, frame } from 'motion/react';\nimport React, {\n type ReactNode,\n type RefObject,\n useCallback,\n useId,\n useLayoutEffect,\n useRef,\n useState,\n} from 'react';\nimport { Group } from 'three';\nimport { useLayoutEffectOnce } from '../hooks/effectOnce';\nimport { useLenisCallback } from '../hooks/lenisCallback';\nimport { useOrbit } from '../hooks/orbit';\nimport { BasicTunnelIn, weaverSetup } from '../setup';\n\nexport type Basic3DTransforms = {\n scale: {\n set: (x: number, y: number, z: number) => void;\n };\n position: {\n x: number;\n y: number;\n };\n};\n\ninterface SyncProps {\n /**\n * HTML element ref that `<SceneSync />` will use to sync with the scene.\n *\n * ```tsx\n * <div ref={container} />\n * <SceneSync attach={container}>\n * <group />\n * </SceneSync>\n * ```\n */\n attach: RefObject<HTMLElement | null>;\n\n /**\n * This variable allows fine-grain control over your scene when passed to `<SceneSync />`.\n *\n * `<SceneSync />` will use its own ref and group when creating your scene to control its scale and position.\n * Setting this variable will disable the internal ref, and you can decide on which object gets controlled.\n *\n * This variable is needed for `hud` if you wanted to add a custom camera.\n *\n * For listening to change details, use `onLayoutChange` instead.\n */\n control?: RefObject<Basic3DTransforms | null>;\n\n /**\n * When this variable is set, `<SceneSync />` will send updates when the scene update its positions.\n *\n * The function return the calculated DOM rect, with dimension and position in 3D measurements.\n */\n onLayoutUpdate?: (\n rect: DOMRect,\n dimension: { w: number; h: number },\n position: { x: number; y: number }\n ) => void;\n\n /**\n * Use `Hud` for this scene or not.\n *\n * This is useful when you want to apply custom camera for this scene, or renders multiple scenes on each other.\n *\n * NOTE: When setting a custom camera, the `control` variable must also be set and mount to your scene, not related to the camera\n * to avoid unwanted behavior.\n *\n * `<SceneSync />` groups children passed to it by default, so the camera is also in the group, when syncer updates the group,\n * the camera is also change, ruining the effect.\n */\n hud?: boolean;\n\n /**\n * Control the scene's scaling when positioning.\n */\n scaleFactor?: number;\n\n /**\n * `<SceneSync />` avoid stretching the object by default by using the smallest dimension of the DOM element.\n *\n * This variable will tell `<SceneSync />` to stretch it anyways.\n */\n stretch?: boolean;\n\n /**\n * Disable automatic scaling on the object.\n *\n * This variable will also disable any scaling settings like `stretch` and `scaleFactor`.\n */\n disableScaling?: boolean;\n\n /**\n * `<SceneSync />` will depend on this variable to adjust how it should update.\n *\n * There are 3 modes: `relaxed`, `balanced` and `aggressive`.\n *\n * For each mode, there will be some very distinct trade-offs\n *\n * - `relaxed`: Uses IntersectionObserver paired with a scroll hook, together with ResizeObserver.\n * - (+): Minimal update calls, best performance.\n * - (-): The scene get desynced the moment DOM element moves without changing its sizes.\n * When the scene bleeds out of the DOM element too much, if IntersectionObserver reported that the DOM element\n * is out of view, the scene that did not fully moved out of view will stay there, as scroll hook will be disabled.\n * - `balanced`: Uses IntersectionObserver paired with frame-based update, together with ResizeObserver.\n * - (+): Just enough update calls to allow the DOM element to move freely while maintain aceptable performance.\n * - (-): It will update on every frame when the object gets into view as reported by IntersectionObserver. And the same\n * problem with `relaxed` mode when the scene bleeds out too much.\n * - `aggressive`: Frame-based update only. This mode is like how `<View />` from `@react-three/drei` kepts track of DOM elements.\n * - (+): Designed for precise element <-> scene updates. Can't be desynced, if desynced, that's a bug.\n * - (-): This is frame-based. It will fire updates as long as the scene is still mounted. Too many scenes with this\n * mode enabled is not a good idea. Acceptable amount would be 3 scenes with this mode.\n *\n * Best of both worlds is `balanced` mode, for simpler scenes that doesn't change its position, `relaxed` should be used.\n */\n trackingMode: 'relaxed' | 'balanced' | 'aggressive';\n\n /**\n * Set a custom tunnel for `<SceneSync />` send the components to for this scene only.\n *\n * Which is useful for example, put the objects inside a container in the scene.\n *\n * To set a default tunnel, pass it to `setDefaulTunnel` before use.\n */\n tunnelIn?: BasicTunnelIn;\n\n children: ReactNode;\n}\n\ninterface HudProps extends SyncProps {\n hud: true;\n /**\n * Set the `renderPriority` to render things for `Hud`.\n *\n * This variable is ignored when `hud` is not `true`.\n */\n hudRenderPriority: number;\n}\n\ninterface NormalProps extends SyncProps {\n hud?: false;\n}\n\n/**\n * A core part of an in-house tool called `weaver`.\n *\n * A component to allow three objects to track and sync with DOM element.\n *\n * The component uses `<Hud />` under the \"hud\", so if you want to use more than one `<SceneSync />`,\n * you must set `renderPriority`. If not, the component will render the last scene pushed through React.\n */\nexport default function SceneSync(props: NormalProps | HudProps) {\n const unique = useId();\n\n const TunnelIn = props.tunnelIn ?? weaverSetup._Default3DTunnelIn;\n\n if (!TunnelIn) {\n throw Error(\n 'Failed to find a tunnel to use. Consider setting a default tunnel.'\n );\n }\n\n if (props.hud) {\n return (\n <TunnelIn>\n <Hud key={unique} renderPriority={props.hudRenderPriority}>\n <SyncInternal {...props} />\n </Hud>\n </TunnelIn>\n );\n }\n\n return (\n <TunnelIn>\n <SyncInternal key={unique} {...props} />\n </TunnelIn>\n );\n}\n\nfunction SyncInternal(props: SyncProps) {\n const { viewport, camera } = useThree();\n\n const defaultControl = useRef<Group>(null);\n const {\n attach,\n control,\n scaleFactor,\n stretch,\n disableScaling,\n onLayoutUpdate,\n } = props;\n\n const properties: RefObject<{\n viewport?: Omit<Viewport, 'dpr' | 'initialDpr'>;\n }> = useRef({\n viewport: undefined,\n });\n\n const updatePosition = useCallback(() => {\n const activeControl = control ?? defaultControl;\n\n const vp = properties.current.viewport;\n if (!vp) return;\n\n const domRect = attach.current!.getBoundingClientRect();\n const screenH = document.documentElement.clientHeight;\n const screenW = document.body.clientWidth;\n\n const vpWidthRatio = vp.width / screenW;\n const vpHeightRatio = vp.height / screenH;\n\n const scrollOffset = (weaverSetup._lenisInstance!.actualScroll / screenH) * vp.height;\n\n const w = domRect.width * vpWidthRatio;\n const h = domRect.height * vpHeightRatio;\n\n const x = domRect.x * vpWidthRatio + w * 0.5 - vp.width * 0.5;\n const y =\n vp.height * 0.5 -\n (domRect.y + weaverSetup._lenisInstance!.actualScroll) * vpHeightRatio -\n h * 0.5 +\n scrollOffset;\n\n if (onLayoutUpdate) {\n onLayoutUpdate(domRect, { w, h }, { x, y });\n }\n\n const unwrapedScaleFactor = scaleFactor ?? 1;\n\n if (!disableScaling) {\n if (!stretch) {\n const minScale = Math.min(w, h) * unwrapedScaleFactor;\n activeControl.current!.scale.set(minScale, minScale, minScale);\n } else {\n activeControl.current!.scale.set(\n w * unwrapedScaleFactor,\n h * unwrapedScaleFactor,\n Math.min(w, h) * unwrapedScaleFactor\n );\n }\n }\n\n // eslint-disable-next-line react-hooks/immutability\n activeControl.current!.position.x = x;\n activeControl.current!.position.y = y;\n }, [attach, onLayoutUpdate, control, scaleFactor, disableScaling, stretch]);\n\n /**\n * Update position when `camera` changes.\n */\n useLayoutEffect(() => {\n properties.current.viewport = viewport.getCurrentViewport(camera);\n updatePosition();\n }, [camera, updatePosition, viewport]);\n\n const graceUpdate = useCallback(() => {\n try {\n updatePosition();\n } catch {\n /* empty */\n }\n }, [updatePosition]);\n\n const mode = {\n relaxed: (\n <RelaxedUpdate attach={props.attach} updatePosition={graceUpdate} />\n ),\n balanced: (\n <BalancedUpdate attach={props.attach} updatePosition={graceUpdate} />\n ),\n aggressive: <AggressiveUpdate updatePosition={graceUpdate} />,\n };\n\n if (props.control) {\n return (\n <>\n {props.children}\n {mode[props.trackingMode]}\n </>\n );\n }\n\n return (\n <group ref={defaultControl}>\n {props.children}\n {mode[props.trackingMode]}\n </group>\n );\n}\n\nfunction RelaxedUpdate(props: {\n attach: RefObject<HTMLElement | null>;\n updatePosition: () => void;\n}) {\n const { updatePosition } = props;\n\n /**\n * Scroll hook to update object correctly to the current HTML scroll position.\n */\n useLenisCallback(updatePosition, {\n initialCall: true,\n intersectOn: props.attach,\n });\n\n /**\n * Allows the element to resize too.\n */\n useOrbit({\n target: props.attach,\n events: {\n onIntersect: updatePosition,\n onResize: updatePosition,\n },\n });\n\n useLayoutEffectOnce(updatePosition);\n return null;\n}\n\nfunction BalancedUpdate(props: {\n attach: RefObject<HTMLElement | null>;\n updatePosition: () => void;\n}) {\n const { updatePosition } = props;\n\n const [shouldUpdate, setShouldUpdate] = useState(false);\n\n useOrbit({\n target: props.attach,\n events: {\n onIntersect(entry) {\n setShouldUpdate(entry.isIntersecting);\n },\n onResize: updatePosition,\n },\n rootMargin: '50% 0px 50% 0px',\n });\n\n useLayoutEffect(() => {\n if (shouldUpdate) {\n frame.read(updatePosition, true);\n } else {\n cancelFrame(updatePosition);\n }\n\n return () => {\n cancelFrame(updatePosition);\n };\n }, [updatePosition, shouldUpdate]);\n\n useLayoutEffectOnce(updatePosition);\n return null;\n}\n\nfunction AggressiveUpdate(props: { updatePosition: () => void }) {\n const { updatePosition } = props;\n\n useLayoutEffect(() => {\n frame.read(updatePosition, true);\n\n return () => {\n cancelFrame(updatePosition);\n };\n }, [updatePosition]);\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 { 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 { 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"],"mappings":"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","names":["React","import_fiber","import_react","import_react","import_react","import_react","React"]}
|
package/dist/scene.mjs
CHANGED
|
@@ -7,14 +7,29 @@ import React, {
|
|
|
7
7
|
} from "react";
|
|
8
8
|
|
|
9
9
|
// src/setup.ts
|
|
10
|
-
var
|
|
11
|
-
|
|
10
|
+
var WeaverSetup = class {
|
|
11
|
+
/**
|
|
12
|
+
* This variable is handled internally by weaver. **Do not use**.
|
|
13
|
+
*/
|
|
14
|
+
_lenisInstance = void 0;
|
|
15
|
+
/**
|
|
16
|
+
* This variable is handled internally by weaver. **Do not use**.
|
|
17
|
+
*/
|
|
18
|
+
_Default3DTunnelIn = void 0;
|
|
19
|
+
setLenisInstance(instance) {
|
|
20
|
+
this._lenisInstance = instance;
|
|
21
|
+
}
|
|
22
|
+
set3DTunnel(tunnelIn) {
|
|
23
|
+
this._Default3DTunnelIn = tunnelIn;
|
|
24
|
+
}
|
|
25
|
+
};
|
|
26
|
+
var weaverSetup = new WeaverSetup();
|
|
12
27
|
|
|
13
28
|
// src/scene/BakeScene.tsx
|
|
14
29
|
function BakeScene(props) {
|
|
15
30
|
const unique = useId();
|
|
16
31
|
const pipeObjects = useId();
|
|
17
|
-
const TunnelIn = props.tunnelIn ??
|
|
32
|
+
const TunnelIn = props.tunnelIn ?? weaverSetup._Default3DTunnelIn;
|
|
18
33
|
if (!TunnelIn) {
|
|
19
34
|
throw Error(
|
|
20
35
|
"Failed to find a tunnel to use. Consider setting a default tunnel."
|
|
@@ -106,11 +121,17 @@ var scrollCallbackReason = {
|
|
|
106
121
|
};
|
|
107
122
|
function useLenisCallback(callback, options) {
|
|
108
123
|
const callbackWrapScroll = useCallback(
|
|
109
|
-
() => callback(
|
|
124
|
+
() => callback(
|
|
125
|
+
weaverSetup._lenisInstance.actualScroll,
|
|
126
|
+
scrollCallbackReason.Scroll
|
|
127
|
+
),
|
|
110
128
|
[callback]
|
|
111
129
|
);
|
|
112
130
|
const callbackWrapResize = useCallback(
|
|
113
|
-
() => callback(
|
|
131
|
+
() => callback(
|
|
132
|
+
weaverSetup._lenisInstance.actualScroll,
|
|
133
|
+
scrollCallbackReason.Resize
|
|
134
|
+
),
|
|
114
135
|
[callback]
|
|
115
136
|
);
|
|
116
137
|
const intersectOn = useMemo(
|
|
@@ -126,10 +147,10 @@ function useLenisCallback(callback, options) {
|
|
|
126
147
|
events: {
|
|
127
148
|
onIntersect(entry) {
|
|
128
149
|
if (entry.isIntersecting) {
|
|
129
|
-
|
|
150
|
+
weaverSetup._lenisInstance.on("scroll", callbackWrapScroll);
|
|
130
151
|
window.addEventListener("resize", callbackWrapResize);
|
|
131
152
|
} else {
|
|
132
|
-
|
|
153
|
+
weaverSetup._lenisInstance.off("scroll", callbackWrapScroll);
|
|
133
154
|
window.removeEventListener("resize", callbackWrapResize);
|
|
134
155
|
}
|
|
135
156
|
}
|
|
@@ -138,14 +159,17 @@ function useLenisCallback(callback, options) {
|
|
|
138
159
|
});
|
|
139
160
|
useLayoutEffect3(() => {
|
|
140
161
|
if (!intersectOn) {
|
|
141
|
-
|
|
162
|
+
weaverSetup._lenisInstance.on("scroll", callbackWrapScroll);
|
|
142
163
|
window.addEventListener("resize", callbackWrapResize);
|
|
143
164
|
}
|
|
144
165
|
if (initialCall) {
|
|
145
|
-
callback(
|
|
166
|
+
callback(
|
|
167
|
+
weaverSetup._lenisInstance.actualScroll,
|
|
168
|
+
scrollCallbackReason.Initialize
|
|
169
|
+
);
|
|
146
170
|
}
|
|
147
171
|
return () => {
|
|
148
|
-
|
|
172
|
+
weaverSetup._lenisInstance.off("scroll", callbackWrapScroll);
|
|
149
173
|
window.removeEventListener("resize", callbackWrapResize);
|
|
150
174
|
};
|
|
151
175
|
}, [
|
|
@@ -160,7 +184,7 @@ function useLenisCallback(callback, options) {
|
|
|
160
184
|
// src/scene/SceneSync.tsx
|
|
161
185
|
function SceneSync(props) {
|
|
162
186
|
const unique = useId2();
|
|
163
|
-
const TunnelIn = props.tunnelIn ??
|
|
187
|
+
const TunnelIn = props.tunnelIn ?? weaverSetup._Default3DTunnelIn;
|
|
164
188
|
if (!TunnelIn) {
|
|
165
189
|
throw Error(
|
|
166
190
|
"Failed to find a tunnel to use. Consider setting a default tunnel."
|
|
@@ -194,11 +218,11 @@ function SyncInternal(props) {
|
|
|
194
218
|
const screenW = document.body.clientWidth;
|
|
195
219
|
const vpWidthRatio = vp.width / screenW;
|
|
196
220
|
const vpHeightRatio = vp.height / screenH;
|
|
197
|
-
const scrollOffset =
|
|
221
|
+
const scrollOffset = weaverSetup._lenisInstance.actualScroll / screenH * vp.height;
|
|
198
222
|
const w = domRect.width * vpWidthRatio;
|
|
199
223
|
const h = domRect.height * vpHeightRatio;
|
|
200
224
|
const x = domRect.x * vpWidthRatio + w * 0.5 - vp.width * 0.5;
|
|
201
|
-
const y = vp.height * 0.5 - (domRect.y +
|
|
225
|
+
const y = vp.height * 0.5 - (domRect.y + weaverSetup._lenisInstance.actualScroll) * vpHeightRatio - h * 0.5 + scrollOffset;
|
|
202
226
|
if (onLayoutUpdate) {
|
|
203
227
|
onLayoutUpdate(domRect, { w, h }, { x, y });
|
|
204
228
|
}
|
package/dist/scene.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/scene/BakeScene.tsx","../src/setup.ts","../src/scene/SceneSync.tsx","../src/hooks/effectOnce.ts","../src/hooks/lenisCallback.ts","../src/hooks/orbit.ts"],"sourcesContent":["import { useFrame } from '@react-three/fiber';\nimport React, {\n type Dispatch,\n Fragment,\n type ReactNode,\n type SetStateAction,\n useId,\n useRef,\n} from 'react';\nimport { BasicTunnelIn, Default3DTunnelIn } from '../setup';\n\n/**\n * A core part of an in-house tool called `weaver`.\n *\n * `BakeScene`: This component will notifiy when the global 3D scene is ready.\n *\n * It works by tune in the `useFrame` from `@react-three/fiber`. When the scene is loaded, `useFreame` will fire\n * with ease, the component takes advantage of that, and because `useLoader` is unreliable.\n *\n * This component also accepts 3D elements `children` to be rendered directly to the canvas with some camera options.\n * But you don't have to put every 3D components inside the baker, for example, `SceneSync`s in the page are also\n * being watched by this component.\n *\n * The route renderer **CAN'T** detect if the page has 3D elements or not, so if a page uses any sort of 3D rendering,\n * this component **MUST** be a children iniside `Pipeline` (`index.tsx`), then pass the state value that bake changes\n * to `Pipeline`'s `contentReady` in order for the `BakeScene` to work behind loading fallback screen.\n */\nexport default function BakeScene(props: {\n children?: ReactNode;\n sceneReady: boolean;\n tunnelIn?: BasicTunnelIn;\n loadTaskDelay?: number;\n setSceneReady: Dispatch<SetStateAction<boolean>>;\n onReady?: () => void;\n}) {\n const unique = useId();\n const pipeObjects = useId();\n\n const TunnelIn = props.tunnelIn ?? Default3DTunnelIn;\n\n if (!TunnelIn) {\n throw Error(\n 'Failed to find a tunnel to use. Consider setting a default tunnel.'\n );\n }\n\n return (\n <TunnelIn>\n <Fragment key={pipeObjects}>{props.children}</Fragment>\n <NotificationHandler\n key={unique}\n callback={props.onReady}\n sceneReady={props.sceneReady}\n setSceneReady={props.setSceneReady}\n />\n </TunnelIn>\n );\n}\n\nfunction NotificationHandler(props: {\n callback?: (isSceneReady: boolean) => void;\n sceneReady: boolean;\n setSceneReady: (value: boolean) => void;\n}) {\n /**\n * `useFrame` is expensive for something that only triggers once, so yea,\n * we'll remove the notification as soon as the job is done.\n */\n return !props.sceneReady && <RenderNotification {...props} />;\n}\n\nfunction RenderNotification(props: {\n callback?: (isSceneReady: boolean) => void;\n sceneReady: boolean;\n loadTaskDelay?: number;\n setSceneReady: (value: boolean) => void;\n}) {\n const scheduledForCallback = useRef(false);\n\n useFrame(() => {\n if (!props.sceneReady && !scheduledForCallback.current) {\n scheduledForCallback.current = true;\n setTimeout(() => {\n if (props.callback) {\n props.callback(true);\n }\n props.setSceneReady(true);\n }, props.loadTaskDelay ?? 50);\n }\n });\n\n return null;\n}\n","import Lenis from 'lenis';\nimport { ReactNode } from 'react';\n\nexport let lenisInstance: Lenis | undefined = undefined;\n\nexport type BasicTunnelIn = ({ children }: { children: ReactNode }) => null;\nexport let Default3DTunnelIn: BasicTunnelIn | undefined = undefined;\n\nexport const weaverSetup = {\n setLenisInstance(instance: Lenis) {\n lenisInstance = instance;\n },\n set3DTunnel(tunnelIn: BasicTunnelIn) {\n Default3DTunnelIn = tunnelIn;\n },\n};\n","import { Hud } from '@react-three/drei';\nimport { useThree, type Viewport } from '@react-three/fiber';\nimport { cancelFrame, frame } from 'motion/react';\nimport React, {\n type ReactNode,\n type RefObject,\n useCallback,\n useId,\n useLayoutEffect,\n useRef,\n useState,\n} from 'react';\nimport { Group } from 'three';\nimport { useLayoutEffectOnce } from '../hooks/effectOnce';\nimport { useLenisCallback } from '../hooks/lenisCallback';\nimport { useOrbit } from '../hooks/orbit';\nimport { BasicTunnelIn, Default3DTunnelIn, lenisInstance } from '../setup';\n\nexport type Basic3DTransforms = {\n scale: {\n set: (x: number, y: number, z: number) => void;\n };\n position: {\n x: number;\n y: number;\n };\n};\n\ninterface SyncProps {\n /**\n * HTML element ref that `<SceneSync />` will use to sync with the scene.\n *\n * ```tsx\n * <div ref={container} />\n * <SceneSync attach={container}>\n * <group />\n * </SceneSync>\n * ```\n */\n attach: RefObject<HTMLElement | null>;\n\n /**\n * This variable allows fine-grain control over your scene when passed to `<SceneSync />`.\n *\n * `<SceneSync />` will use its own ref and group when creating your scene to control its scale and position.\n * Setting this variable will disable the internal ref, and you can decide on which object gets controlled.\n *\n * This variable is needed for `hud` if you wanted to add a custom camera.\n *\n * For listening to change details, use `onLayoutChange` instead.\n */\n control?: RefObject<Basic3DTransforms | null>;\n\n /**\n * When this variable is set, `<SceneSync />` will send updates when the scene update its positions.\n *\n * The function return the calculated DOM rect, with dimension and position in 3D measurements.\n */\n onLayoutUpdate?: (\n rect: DOMRect,\n dimension: { w: number; h: number },\n position: { x: number; y: number }\n ) => void;\n\n /**\n * Use `Hud` for this scene or not.\n *\n * This is useful when you want to apply custom camera for this scene, or renders multiple scenes on each other.\n *\n * NOTE: When setting a custom camera, the `control` variable must also be set and mount to your scene, not related to the camera\n * to avoid unwanted behavior.\n *\n * `<SceneSync />` groups children passed to it by default, so the camera is also in the group, when syncer updates the group,\n * the camera is also change, ruining the effect.\n */\n hud?: boolean;\n\n /**\n * Control the scene's scaling when positioning.\n */\n scaleFactor?: number;\n\n /**\n * `<SceneSync />` avoid stretching the object by default by using the smallest dimension of the DOM element.\n *\n * This variable will tell `<SceneSync />` to stretch it anyways.\n */\n stretch?: boolean;\n\n /**\n * Disable automatic scaling on the object.\n *\n * This variable will also disable any scaling settings like `stretch` and `scaleFactor`.\n */\n disableScaling?: boolean;\n\n /**\n * `<SceneSync />` will depend on this variable to adjust how it should update.\n *\n * There are 3 modes: `relaxed`, `balanced` and `aggressive`.\n *\n * For each mode, there will be some very distinct trade-offs\n *\n * - `relaxed`: Uses IntersectionObserver paired with a scroll hook, together with ResizeObserver.\n * - (+): Minimal update calls, best performance.\n * - (-): The scene get desynced the moment DOM element moves without changing its sizes.\n * When the scene bleeds out of the DOM element too much, if IntersectionObserver reported that the DOM element\n * is out of view, the scene that did not fully moved out of view will stay there, as scroll hook will be disabled.\n * - `balanced`: Uses IntersectionObserver paired with frame-based update, together with ResizeObserver.\n * - (+): Just enough update calls to allow the DOM element to move freely while maintain aceptable performance.\n * - (-): It will update on every frame when the object gets into view as reported by IntersectionObserver. And the same\n * problem with `relaxed` mode when the scene bleeds out too much.\n * - `aggressive`: Frame-based update only. This mode is like how `<View />` from `@react-three/drei` kepts track of DOM elements.\n * - (+): Designed for precise element <-> scene updates. Can't be desynced, if desynced, that's a bug.\n * - (-): This is frame-based. It will fire updates as long as the scene is still mounted. Too many scenes with this\n * mode enabled is not a good idea. Acceptable amount would be 3 scenes with this mode.\n *\n * Best of both worlds is `balanced` mode, for simpler scenes that doesn't change its position, `relaxed` should be used.\n */\n trackingMode: 'relaxed' | 'balanced' | 'aggressive';\n\n /**\n * Set a custom tunnel for `<SceneSync />` send the components to for this scene only.\n *\n * Which is useful for example, put the objects inside a container in the scene.\n *\n * To set a default tunnel, pass it to `setDefaulTunnel` before use.\n */\n tunnelIn?: BasicTunnelIn;\n\n children: ReactNode;\n}\n\ninterface HudProps extends SyncProps {\n hud: true;\n /**\n * Set the `renderPriority` to render things for `Hud`.\n *\n * This variable is ignored when `hud` is not `true`.\n */\n hudRenderPriority: number;\n}\n\ninterface NormalProps extends SyncProps {\n hud?: false;\n}\n\n/**\n * A core part of an in-house tool called `weaver`.\n *\n * A component to allow three objects to track and sync with DOM element.\n *\n * The component uses `<Hud />` under the \"hud\", so if you want to use more than one `<SceneSync />`,\n * you must set `renderPriority`. If not, the component will render the last scene pushed through React.\n */\nexport default function SceneSync(props: NormalProps | HudProps) {\n const unique = useId();\n\n const TunnelIn = props.tunnelIn ?? Default3DTunnelIn;\n\n if (!TunnelIn) {\n throw Error(\n 'Failed to find a tunnel to use. Consider setting a default tunnel.'\n );\n }\n\n if (props.hud) {\n return (\n <TunnelIn>\n <Hud key={unique} renderPriority={props.hudRenderPriority}>\n <SyncInternal {...props} />\n </Hud>\n </TunnelIn>\n );\n }\n\n return (\n <TunnelIn>\n <SyncInternal key={unique} {...props} />\n </TunnelIn>\n );\n}\n\nfunction SyncInternal(props: SyncProps) {\n const { viewport, camera } = useThree();\n\n const defaultControl = useRef<Group>(null);\n const {\n attach,\n control,\n scaleFactor,\n stretch,\n disableScaling,\n onLayoutUpdate,\n } = props;\n\n const properties: RefObject<{\n viewport?: Omit<Viewport, 'dpr' | 'initialDpr'>;\n }> = useRef({\n viewport: undefined,\n });\n\n const updatePosition = useCallback(() => {\n const activeControl = control ?? defaultControl;\n\n const vp = properties.current.viewport;\n if (!vp) return;\n\n const domRect = attach.current!.getBoundingClientRect();\n const screenH = document.documentElement.clientHeight;\n const screenW = document.body.clientWidth;\n\n const vpWidthRatio = vp.width / screenW;\n const vpHeightRatio = vp.height / screenH;\n\n const scrollOffset = (lenisInstance!.actualScroll / screenH) * vp.height;\n\n const w = domRect.width * vpWidthRatio;\n const h = domRect.height * vpHeightRatio;\n\n const x = domRect.x * vpWidthRatio + w * 0.5 - vp.width * 0.5;\n const y =\n vp.height * 0.5 -\n (domRect.y + lenisInstance!.actualScroll) * vpHeightRatio -\n h * 0.5 +\n scrollOffset;\n\n if (onLayoutUpdate) {\n onLayoutUpdate(domRect, { w, h }, { x, y });\n }\n\n const unwrapedScaleFactor = scaleFactor ?? 1;\n\n if (!disableScaling) {\n if (!stretch) {\n const minScale = Math.min(w, h) * unwrapedScaleFactor;\n activeControl.current!.scale.set(minScale, minScale, minScale);\n } else {\n activeControl.current!.scale.set(\n w * unwrapedScaleFactor,\n h * unwrapedScaleFactor,\n Math.min(w, h) * unwrapedScaleFactor\n );\n }\n }\n\n // eslint-disable-next-line react-hooks/immutability\n activeControl.current!.position.x = x;\n activeControl.current!.position.y = y;\n }, [attach, onLayoutUpdate, control, scaleFactor, disableScaling, stretch]);\n\n /**\n * Update position when `camera` changes.\n */\n useLayoutEffect(() => {\n properties.current.viewport = viewport.getCurrentViewport(camera);\n updatePosition();\n }, [camera, updatePosition, viewport]);\n\n const graceUpdate = useCallback(() => {\n try {\n updatePosition();\n } catch {\n /* empty */\n }\n }, [updatePosition]);\n\n const mode = {\n relaxed: (\n <RelaxedUpdate attach={props.attach} updatePosition={graceUpdate} />\n ),\n balanced: (\n <BalancedUpdate attach={props.attach} updatePosition={graceUpdate} />\n ),\n aggressive: <AggressiveUpdate updatePosition={graceUpdate} />,\n };\n\n if (props.control) {\n return (\n <>\n {props.children}\n {mode[props.trackingMode]}\n </>\n );\n }\n\n return (\n <group ref={defaultControl}>\n {props.children}\n {mode[props.trackingMode]}\n </group>\n );\n}\n\nfunction RelaxedUpdate(props: {\n attach: RefObject<HTMLElement | null>;\n updatePosition: () => void;\n}) {\n const { updatePosition } = props;\n\n /**\n * Scroll hook to update object correctly to the current HTML scroll position.\n */\n useLenisCallback(updatePosition, {\n initialCall: true,\n intersectOn: props.attach,\n });\n\n /**\n * Allows the element to resize too.\n */\n useOrbit({\n target: props.attach,\n events: {\n onIntersect: updatePosition,\n onResize: updatePosition,\n },\n });\n\n useLayoutEffectOnce(updatePosition);\n return null;\n}\n\nfunction BalancedUpdate(props: {\n attach: RefObject<HTMLElement | null>;\n updatePosition: () => void;\n}) {\n const { updatePosition } = props;\n\n const [shouldUpdate, setShouldUpdate] = useState(false);\n\n useOrbit({\n target: props.attach,\n events: {\n onIntersect(entry) {\n setShouldUpdate(entry.isIntersecting);\n },\n onResize: updatePosition,\n },\n rootMargin: '50% 0px 50% 0px',\n });\n\n useLayoutEffect(() => {\n if (shouldUpdate) {\n frame.read(updatePosition, true);\n } else {\n cancelFrame(updatePosition);\n }\n\n return () => {\n cancelFrame(updatePosition);\n };\n }, [updatePosition, shouldUpdate]);\n\n useLayoutEffectOnce(updatePosition);\n return null;\n}\n\nfunction AggressiveUpdate(props: { updatePosition: () => void }) {\n const { updatePosition } = props;\n\n useLayoutEffect(() => {\n frame.read(updatePosition, true);\n\n return () => {\n cancelFrame(updatePosition);\n };\n }, [updatePosition]);\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 { type RefObject, useCallback, useLayoutEffect, useMemo } from 'react';\nimport { lenisInstance } 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 () => callback(lenisInstance!.actualScroll, scrollCallbackReason.Scroll),\n [callback]\n );\n const callbackWrapResize = useCallback(\n () => callback(lenisInstance!.actualScroll, scrollCallbackReason.Resize),\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 lenisInstance!.on('scroll', callbackWrapScroll);\n window.addEventListener('resize', callbackWrapResize);\n } else {\n 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 lenisInstance!.on('scroll', callbackWrapScroll);\n window.addEventListener('resize', callbackWrapResize);\n }\n\n if (initialCall) {\n callback(lenisInstance!.actualScroll, scrollCallbackReason.Initialize);\n }\n\n return () => {\n 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 { 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"],"mappings":"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","names":["React","useCallback","useId","useLayoutEffect","useRef","useLayoutEffect","useLayoutEffect","useLayoutEffect","useId","React","useRef","useCallback","useLayoutEffect"]}
|
|
1
|
+
{"version":3,"sources":["../src/scene/BakeScene.tsx","../src/setup.ts","../src/scene/SceneSync.tsx","../src/hooks/effectOnce.ts","../src/hooks/lenisCallback.ts","../src/hooks/orbit.ts"],"sourcesContent":["import { useFrame } from '@react-three/fiber';\nimport React, {\n type Dispatch,\n Fragment,\n type ReactNode,\n type SetStateAction,\n useId,\n useRef,\n} from 'react';\nimport { BasicTunnelIn, weaverSetup } from '../setup';\n\n/**\n * A core part of an in-house tool called `weaver`.\n *\n * `BakeScene`: This component will notifiy when the global 3D scene is ready.\n *\n * It works by tune in the `useFrame` from `@react-three/fiber`. When the scene is loaded, `useFreame` will fire\n * with ease, the component takes advantage of that, and because `useLoader` is unreliable.\n *\n * This component also accepts 3D elements `children` to be rendered directly to the canvas with some camera options.\n * But you don't have to put every 3D components inside the baker, for example, `SceneSync`s in the page are also\n * being watched by this component.\n *\n * The route renderer **CAN'T** detect if the page has 3D elements or not, so if a page uses any sort of 3D rendering,\n * this component **MUST** be a children iniside `Pipeline` (`index.tsx`), then pass the state value that bake changes\n * to `Pipeline`'s `contentReady` in order for the `BakeScene` to work behind loading fallback screen.\n */\nexport default function BakeScene(props: {\n children?: ReactNode;\n sceneReady: boolean;\n tunnelIn?: BasicTunnelIn;\n loadTaskDelay?: number;\n setSceneReady: Dispatch<SetStateAction<boolean>>;\n onReady?: () => void;\n}) {\n const unique = useId();\n const pipeObjects = useId();\n\n const TunnelIn = props.tunnelIn ?? weaverSetup._Default3DTunnelIn;\n\n if (!TunnelIn) {\n throw Error(\n 'Failed to find a tunnel to use. Consider setting a default tunnel.'\n );\n }\n\n return (\n <TunnelIn>\n <Fragment key={pipeObjects}>{props.children}</Fragment>\n <NotificationHandler\n key={unique}\n callback={props.onReady}\n sceneReady={props.sceneReady}\n setSceneReady={props.setSceneReady}\n />\n </TunnelIn>\n );\n}\n\nfunction NotificationHandler(props: {\n callback?: (isSceneReady: boolean) => void;\n sceneReady: boolean;\n setSceneReady: (value: boolean) => void;\n}) {\n /**\n * `useFrame` is expensive for something that only triggers once, so yea,\n * we'll remove the notification as soon as the job is done.\n */\n return !props.sceneReady && <RenderNotification {...props} />;\n}\n\nfunction RenderNotification(props: {\n callback?: (isSceneReady: boolean) => void;\n sceneReady: boolean;\n loadTaskDelay?: number;\n setSceneReady: (value: boolean) => void;\n}) {\n const scheduledForCallback = useRef(false);\n\n useFrame(() => {\n if (!props.sceneReady && !scheduledForCallback.current) {\n scheduledForCallback.current = true;\n setTimeout(() => {\n if (props.callback) {\n props.callback(true);\n }\n props.setSceneReady(true);\n }, props.loadTaskDelay ?? 50);\n }\n });\n\n return null;\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 _lenisInstance: Lenis | undefined = undefined;\n /**\n * This variable is handled internally by weaver. **Do not use**.\n */\n _Default3DTunnelIn: BasicTunnelIn | undefined = undefined;\n\n setLenisInstance(instance: Lenis) {\n this._lenisInstance = instance;\n }\n\n set3DTunnel(tunnelIn: BasicTunnelIn) {\n this._Default3DTunnelIn = tunnelIn;\n }\n}\n\nexport const weaverSetup = new WeaverSetup();\n","import { Hud } from '@react-three/drei';\nimport { useThree, type Viewport } from '@react-three/fiber';\nimport { cancelFrame, frame } from 'motion/react';\nimport React, {\n type ReactNode,\n type RefObject,\n useCallback,\n useId,\n useLayoutEffect,\n useRef,\n useState,\n} from 'react';\nimport { Group } from 'three';\nimport { useLayoutEffectOnce } from '../hooks/effectOnce';\nimport { useLenisCallback } from '../hooks/lenisCallback';\nimport { useOrbit } from '../hooks/orbit';\nimport { BasicTunnelIn, weaverSetup } from '../setup';\n\nexport type Basic3DTransforms = {\n scale: {\n set: (x: number, y: number, z: number) => void;\n };\n position: {\n x: number;\n y: number;\n };\n};\n\ninterface SyncProps {\n /**\n * HTML element ref that `<SceneSync />` will use to sync with the scene.\n *\n * ```tsx\n * <div ref={container} />\n * <SceneSync attach={container}>\n * <group />\n * </SceneSync>\n * ```\n */\n attach: RefObject<HTMLElement | null>;\n\n /**\n * This variable allows fine-grain control over your scene when passed to `<SceneSync />`.\n *\n * `<SceneSync />` will use its own ref and group when creating your scene to control its scale and position.\n * Setting this variable will disable the internal ref, and you can decide on which object gets controlled.\n *\n * This variable is needed for `hud` if you wanted to add a custom camera.\n *\n * For listening to change details, use `onLayoutChange` instead.\n */\n control?: RefObject<Basic3DTransforms | null>;\n\n /**\n * When this variable is set, `<SceneSync />` will send updates when the scene update its positions.\n *\n * The function return the calculated DOM rect, with dimension and position in 3D measurements.\n */\n onLayoutUpdate?: (\n rect: DOMRect,\n dimension: { w: number; h: number },\n position: { x: number; y: number }\n ) => void;\n\n /**\n * Use `Hud` for this scene or not.\n *\n * This is useful when you want to apply custom camera for this scene, or renders multiple scenes on each other.\n *\n * NOTE: When setting a custom camera, the `control` variable must also be set and mount to your scene, not related to the camera\n * to avoid unwanted behavior.\n *\n * `<SceneSync />` groups children passed to it by default, so the camera is also in the group, when syncer updates the group,\n * the camera is also change, ruining the effect.\n */\n hud?: boolean;\n\n /**\n * Control the scene's scaling when positioning.\n */\n scaleFactor?: number;\n\n /**\n * `<SceneSync />` avoid stretching the object by default by using the smallest dimension of the DOM element.\n *\n * This variable will tell `<SceneSync />` to stretch it anyways.\n */\n stretch?: boolean;\n\n /**\n * Disable automatic scaling on the object.\n *\n * This variable will also disable any scaling settings like `stretch` and `scaleFactor`.\n */\n disableScaling?: boolean;\n\n /**\n * `<SceneSync />` will depend on this variable to adjust how it should update.\n *\n * There are 3 modes: `relaxed`, `balanced` and `aggressive`.\n *\n * For each mode, there will be some very distinct trade-offs\n *\n * - `relaxed`: Uses IntersectionObserver paired with a scroll hook, together with ResizeObserver.\n * - (+): Minimal update calls, best performance.\n * - (-): The scene get desynced the moment DOM element moves without changing its sizes.\n * When the scene bleeds out of the DOM element too much, if IntersectionObserver reported that the DOM element\n * is out of view, the scene that did not fully moved out of view will stay there, as scroll hook will be disabled.\n * - `balanced`: Uses IntersectionObserver paired with frame-based update, together with ResizeObserver.\n * - (+): Just enough update calls to allow the DOM element to move freely while maintain aceptable performance.\n * - (-): It will update on every frame when the object gets into view as reported by IntersectionObserver. And the same\n * problem with `relaxed` mode when the scene bleeds out too much.\n * - `aggressive`: Frame-based update only. This mode is like how `<View />` from `@react-three/drei` kepts track of DOM elements.\n * - (+): Designed for precise element <-> scene updates. Can't be desynced, if desynced, that's a bug.\n * - (-): This is frame-based. It will fire updates as long as the scene is still mounted. Too many scenes with this\n * mode enabled is not a good idea. Acceptable amount would be 3 scenes with this mode.\n *\n * Best of both worlds is `balanced` mode, for simpler scenes that doesn't change its position, `relaxed` should be used.\n */\n trackingMode: 'relaxed' | 'balanced' | 'aggressive';\n\n /**\n * Set a custom tunnel for `<SceneSync />` send the components to for this scene only.\n *\n * Which is useful for example, put the objects inside a container in the scene.\n *\n * To set a default tunnel, pass it to `setDefaulTunnel` before use.\n */\n tunnelIn?: BasicTunnelIn;\n\n children: ReactNode;\n}\n\ninterface HudProps extends SyncProps {\n hud: true;\n /**\n * Set the `renderPriority` to render things for `Hud`.\n *\n * This variable is ignored when `hud` is not `true`.\n */\n hudRenderPriority: number;\n}\n\ninterface NormalProps extends SyncProps {\n hud?: false;\n}\n\n/**\n * A core part of an in-house tool called `weaver`.\n *\n * A component to allow three objects to track and sync with DOM element.\n *\n * The component uses `<Hud />` under the \"hud\", so if you want to use more than one `<SceneSync />`,\n * you must set `renderPriority`. If not, the component will render the last scene pushed through React.\n */\nexport default function SceneSync(props: NormalProps | HudProps) {\n const unique = useId();\n\n const TunnelIn = props.tunnelIn ?? weaverSetup._Default3DTunnelIn;\n\n if (!TunnelIn) {\n throw Error(\n 'Failed to find a tunnel to use. Consider setting a default tunnel.'\n );\n }\n\n if (props.hud) {\n return (\n <TunnelIn>\n <Hud key={unique} renderPriority={props.hudRenderPriority}>\n <SyncInternal {...props} />\n </Hud>\n </TunnelIn>\n );\n }\n\n return (\n <TunnelIn>\n <SyncInternal key={unique} {...props} />\n </TunnelIn>\n );\n}\n\nfunction SyncInternal(props: SyncProps) {\n const { viewport, camera } = useThree();\n\n const defaultControl = useRef<Group>(null);\n const {\n attach,\n control,\n scaleFactor,\n stretch,\n disableScaling,\n onLayoutUpdate,\n } = props;\n\n const properties: RefObject<{\n viewport?: Omit<Viewport, 'dpr' | 'initialDpr'>;\n }> = useRef({\n viewport: undefined,\n });\n\n const updatePosition = useCallback(() => {\n const activeControl = control ?? defaultControl;\n\n const vp = properties.current.viewport;\n if (!vp) return;\n\n const domRect = attach.current!.getBoundingClientRect();\n const screenH = document.documentElement.clientHeight;\n const screenW = document.body.clientWidth;\n\n const vpWidthRatio = vp.width / screenW;\n const vpHeightRatio = vp.height / screenH;\n\n const scrollOffset = (weaverSetup._lenisInstance!.actualScroll / screenH) * vp.height;\n\n const w = domRect.width * vpWidthRatio;\n const h = domRect.height * vpHeightRatio;\n\n const x = domRect.x * vpWidthRatio + w * 0.5 - vp.width * 0.5;\n const y =\n vp.height * 0.5 -\n (domRect.y + weaverSetup._lenisInstance!.actualScroll) * vpHeightRatio -\n h * 0.5 +\n scrollOffset;\n\n if (onLayoutUpdate) {\n onLayoutUpdate(domRect, { w, h }, { x, y });\n }\n\n const unwrapedScaleFactor = scaleFactor ?? 1;\n\n if (!disableScaling) {\n if (!stretch) {\n const minScale = Math.min(w, h) * unwrapedScaleFactor;\n activeControl.current!.scale.set(minScale, minScale, minScale);\n } else {\n activeControl.current!.scale.set(\n w * unwrapedScaleFactor,\n h * unwrapedScaleFactor,\n Math.min(w, h) * unwrapedScaleFactor\n );\n }\n }\n\n // eslint-disable-next-line react-hooks/immutability\n activeControl.current!.position.x = x;\n activeControl.current!.position.y = y;\n }, [attach, onLayoutUpdate, control, scaleFactor, disableScaling, stretch]);\n\n /**\n * Update position when `camera` changes.\n */\n useLayoutEffect(() => {\n properties.current.viewport = viewport.getCurrentViewport(camera);\n updatePosition();\n }, [camera, updatePosition, viewport]);\n\n const graceUpdate = useCallback(() => {\n try {\n updatePosition();\n } catch {\n /* empty */\n }\n }, [updatePosition]);\n\n const mode = {\n relaxed: (\n <RelaxedUpdate attach={props.attach} updatePosition={graceUpdate} />\n ),\n balanced: (\n <BalancedUpdate attach={props.attach} updatePosition={graceUpdate} />\n ),\n aggressive: <AggressiveUpdate updatePosition={graceUpdate} />,\n };\n\n if (props.control) {\n return (\n <>\n {props.children}\n {mode[props.trackingMode]}\n </>\n );\n }\n\n return (\n <group ref={defaultControl}>\n {props.children}\n {mode[props.trackingMode]}\n </group>\n );\n}\n\nfunction RelaxedUpdate(props: {\n attach: RefObject<HTMLElement | null>;\n updatePosition: () => void;\n}) {\n const { updatePosition } = props;\n\n /**\n * Scroll hook to update object correctly to the current HTML scroll position.\n */\n useLenisCallback(updatePosition, {\n initialCall: true,\n intersectOn: props.attach,\n });\n\n /**\n * Allows the element to resize too.\n */\n useOrbit({\n target: props.attach,\n events: {\n onIntersect: updatePosition,\n onResize: updatePosition,\n },\n });\n\n useLayoutEffectOnce(updatePosition);\n return null;\n}\n\nfunction BalancedUpdate(props: {\n attach: RefObject<HTMLElement | null>;\n updatePosition: () => void;\n}) {\n const { updatePosition } = props;\n\n const [shouldUpdate, setShouldUpdate] = useState(false);\n\n useOrbit({\n target: props.attach,\n events: {\n onIntersect(entry) {\n setShouldUpdate(entry.isIntersecting);\n },\n onResize: updatePosition,\n },\n rootMargin: '50% 0px 50% 0px',\n });\n\n useLayoutEffect(() => {\n if (shouldUpdate) {\n frame.read(updatePosition, true);\n } else {\n cancelFrame(updatePosition);\n }\n\n return () => {\n cancelFrame(updatePosition);\n };\n }, [updatePosition, shouldUpdate]);\n\n useLayoutEffectOnce(updatePosition);\n return null;\n}\n\nfunction AggressiveUpdate(props: { updatePosition: () => void }) {\n const { updatePosition } = props;\n\n useLayoutEffect(() => {\n frame.read(updatePosition, true);\n\n return () => {\n cancelFrame(updatePosition);\n };\n }, [updatePosition]);\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 { 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 { 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"],"mappings":"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","names":["React","useCallback","useId","useLayoutEffect","useRef","useLayoutEffect","useLayoutEffect","useLayoutEffect","useId","React","useRef","useCallback","useLayoutEffect"]}
|
package/package.json
CHANGED
|
@@ -2,14 +2,15 @@
|
|
|
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.6",
|
|
6
6
|
"description": "An in-house package by neverany for making interactive React CSR.",
|
|
7
7
|
"packageManager": "yarn@4.10.3",
|
|
8
8
|
"publishConfig": {
|
|
9
9
|
"access": "public"
|
|
10
10
|
},
|
|
11
11
|
"scripts": {
|
|
12
|
-
"build": "tsup"
|
|
12
|
+
"build": "tsup",
|
|
13
|
+
"publish": "tsup && npm publish"
|
|
13
14
|
},
|
|
14
15
|
"tsup": {
|
|
15
16
|
"entry": {
|