download
raw
8.18 kB
import * as React from 'react'
import type ReactReconciler from 'react-reconciler'
/**
* An SSR-friendly useLayoutEffect.
*
* React currently throws a warning when using useLayoutEffect on the server.
* To get around it, we can conditionally useEffect on the server (no-op) and
* useLayoutEffect elsewhere.
*
* @see https://github.com/facebook/react/issues/14927
*/
const useIsomorphicLayoutEffect =
typeof window !== 'undefined' && (window.document?.createElement || window.navigator?.product === 'ReactNative')
? React.useLayoutEffect
: React.useEffect
/**
* Represents a react-internal Fiber node.
*/
export type Fiber<T = any> = Omit<ReactReconciler.Fiber, 'stateNode'> & { stateNode: T }
/**
* Represents a {@link Fiber} node selector for traversal.
*/
export type FiberSelector<T = any> = (
/** The current {@link Fiber} node. */
node: Fiber<T | null>,
) => boolean | void
/**
* Traverses up or down a {@link Fiber}, return `true` to stop and select a node.
*/
export function traverseFiber<T = any>(
/** Input {@link Fiber} to traverse. */
fiber: Fiber | undefined,
/** Whether to ascend and walk up the tree. Will walk down if `false`. */
ascending: boolean,
/** A {@link Fiber} node selector, returns the first match when `true` is passed. */
selector: FiberSelector<T>,
): Fiber<T> | undefined {
if (!fiber) return
if (selector(fiber) === true) return fiber
let child = ascending ? fiber.return : fiber.child
while (child) {
const match = traverseFiber(child, ascending, selector)
if (match) return match
child = ascending ? null : child.sibling
}
}
// In development, React will warn about using contexts between renderers.
// Hide the warning because its-fine fixes this issue
// https://github.com/facebook/react/pull/12779
function wrapContext<T>(context: React.Context<T>): React.Context<T> {
try {
return Object.defineProperties(context, {
_currentRenderer: {
get() {
return null
},
set() {},
},
_currentRenderer2: {
get() {
return null
},
set() {},
},
})
} catch (_) {
return context
}
}
const error = console.error
console.error = function () {
const message = [...arguments].join('')
if (message?.startsWith('Warning:') && message.includes('useContext')) {
console.error = error
return
}
return error.apply(this, arguments as any)
}
const FiberContext = wrapContext(React.createContext<Fiber>(null!))
/**
* A react-internal {@link Fiber} provider. This component binds React children to the React Fiber tree. Call its-fine hooks within this.
*/
export class FiberProvider extends React.Component<{ children?: React.ReactNode }> {
private _reactInternals!: Fiber
render() {
return <FiberContext.Provider value={this._reactInternals}>{this.props.children}</FiberContext.Provider>
}
}
/**
* Returns the current react-internal {@link Fiber}. This is an implementation detail of [react-reconciler](https://github.com/facebook/react/tree/main/packages/react-reconciler).
*/
export function useFiber(): Fiber<null> | undefined {
const root = React.useContext(FiberContext)
if (root === null) throw new Error('its-fine: useFiber must be called within a <FiberProvider />!')
const id = React.useId()
const fiber = React.useMemo(() => {
for (const maybeFiber of [root, root?.alternate]) {
if (!maybeFiber) continue
const fiber = traverseFiber<null>(maybeFiber, false, (node) => {
let state = node.memoizedState
while (state) {
if (state.memoizedState === id) return true
state = state.next
}
})
if (fiber) return fiber
}
}, [root, id])
return fiber
}
/**
* Represents a react-reconciler container instance.
*/
export interface ContainerInstance<T = any> {
containerInfo: T
}
/**
* Returns the current react-reconciler container info passed to {@link ReactReconciler.Reconciler.createContainer}.
*
* In react-dom, a container will point to the root DOM element; in react-three-fiber, it will point to the root Zustand store.
*/
export function useContainer<T = any>(): T | undefined {
const fiber = useFiber()
const root = React.useMemo(
() => traverseFiber<ContainerInstance<T>>(fiber, true, (node) => node.stateNode?.containerInfo != null),
[fiber],
)
return root?.stateNode.containerInfo
}
/**
* Returns the nearest react-reconciler child instance or the node created from {@link ReactReconciler.HostConfig.createInstance}.
*
* In react-dom, this would be a DOM element; in react-three-fiber this would be an instance descriptor.
*/
export function useNearestChild<T = any>(
/** An optional element type to filter to. */
type?: keyof JSX.IntrinsicElements,
): React.MutableRefObject<T | undefined> {
const fiber = useFiber()
const childRef = React.useRef<T>()
useIsomorphicLayoutEffect(() => {
childRef.current = traverseFiber<T>(
fiber,
false,
(node) => typeof node.type === 'string' && (type === undefined || node.type === type),
)?.stateNode
}, [fiber])
return childRef
}
/**
* Returns the nearest react-reconciler parent instance or the node created from {@link ReactReconciler.HostConfig.createInstance}.
*
* In react-dom, this would be a DOM element; in react-three-fiber this would be an instance descriptor.
*/
export function useNearestParent<T = any>(
/** An optional element type to filter to. */
type?: keyof JSX.IntrinsicElements,
): React.MutableRefObject<T | undefined> {
const fiber = useFiber()
const parentRef = React.useRef<T>()
useIsomorphicLayoutEffect(() => {
parentRef.current = traverseFiber<T>(
fiber,
true,
(node) => typeof node.type === 'string' && (type === undefined || node.type === type),
)?.stateNode
}, [fiber])
return parentRef
}
export type ContextMap = Map<React.Context<any>, any> & {
get<T>(context: React.Context<T>): T | undefined
}
/**
* Returns a map of all contexts and their values.
*/
export function useContextMap(): ContextMap {
const fiber = useFiber()
const [contextMap] = React.useState(() => new Map<React.Context<any>, any>())
// Collect live context
contextMap.clear()
let node = fiber
while (node) {
if (node.type && typeof node.type === 'object') {
// https://github.com/facebook/react/pull/28226
const enableRenderableContext = node.type._context === undefined && node.type.Provider === node.type
const context = enableRenderableContext ? node.type : node.type._context
if (context && context !== FiberContext && !contextMap.has(context)) {
contextMap.set(context, React.useContext(wrapContext(context)))
}
}
node = node.return!
}
return contextMap
}
/**
* Represents a react-context bridge provider component.
*/
export type ContextBridge = React.FC<React.PropsWithChildren<{}>>
/**
* React Context currently cannot be shared across [React renderers](https://reactjs.org/docs/codebase-overview.html#renderers) but explicitly forwarded between providers (see [react#17275](https://github.com/facebook/react/issues/17275)). This hook returns a {@link ContextBridge} of live context providers to pierce Context across renderers.
*
* Pass {@link ContextBridge} as a component to a secondary renderer to enable context-sharing within its children.
*/
export function useContextBridge(): ContextBridge {
const contextMap = useContextMap()
// Flatten context and their memoized values into a `ContextBridge` provider
return React.useMemo(
() =>
Array.from(contextMap.keys()).reduce(
(Prev, context) => (props) =>
(
<Prev>
<context.Provider {...props} value={contextMap.get(context)} />
</Prev>
),
(props) => <FiberProvider {...props} />,
),
[contextMap],
)
}

Xet Storage Details

Size:
8.18 kB
·
Xet hash:
fd9a336d126e00eb386a321efde598a9023280dc5bed83a517b8a95331e11016

Xet efficiently stores files, intelligently splitting them into unique chunks and accelerating uploads and downloads. More info.