Skip to content

Commit

Permalink
feat: React 19 (#39)
Browse files Browse the repository at this point in the history
  • Loading branch information
CodyJasonBennett authored Feb 18, 2025
1 parent 598b81f commit 9b93a74
Show file tree
Hide file tree
Showing 7 changed files with 857 additions and 558 deletions.
28 changes: 13 additions & 15 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,7 @@
"repository": "https://github.com/pmndrs/its-fine",
"license": "MIT",
"files": [
"dist/*",
"src/*"
"dist/*"
],
"type": "module",
"types": "./dist/index.d.ts",
Expand All @@ -27,23 +26,22 @@
"react-native": "./dist/index.js",
"sideEffects": false,
"devDependencies": {
"@types/node": "^18.7.15",
"@types/react": "^18.0.17",
"@types/react-test-renderer": "^18.0.0",
"react": "^18.2.0",
"react-nil": "^1.2.0",
"react-test-renderer": "^18.2.0",
"rimraf": "^3.0.2",
"suspend-react": "^0.0.8",
"typescript": "^4.7.4",
"vite": "^3.1.0",
"vitest": "^0.23.1"
"@types/node": "^22.13.4",
"@types/react": "^19.0.0",
"@types/react-test-renderer": "^19.0.0",
"react": "^19.0.0",
"react-nil": "^2.0.0",
"react-test-renderer": "^19.0.0",
"rimraf": "^6.0.1",
"typescript": "^5.7.3",
"vite": "^6.1.0",
"vitest": "^3.0.6"
},
"dependencies": {
"@types/react-reconciler": "^0.28.0"
"@types/react-reconciler": "^0.28.9"
},
"peerDependencies": {
"react": ">=18.0"
"react": "^19.0.0"
},
"scripts": {
"build": "rimraf dist && vite build && tsc",
Expand Down
15 changes: 12 additions & 3 deletions tests/index.test.tsx → src/index.test.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import * as React from 'react'
import { describe, expect, it } from 'vitest'
import { type NilNode, type HostContainer, act, render, createPortal } from 'react-nil'
import { type NilNode, type HostContainer, render, createPortal } from 'react-nil'
import { create } from 'react-test-renderer'
import {
type Fiber,
Expand All @@ -11,7 +11,14 @@ import {
useNearestParent,
useContextBridge,
FiberProvider,
} from '../src'
} from './index'

declare global {
var IS_REACT_ACT_ENVIRONMENT: boolean
}

// Let React know that we'll be testing effectful components
global.IS_REACT_ACT_ENVIRONMENT = true

interface ReactProps {
key?: React.Key
Expand All @@ -25,7 +32,7 @@ interface PrimitiveProps {

type Primitive = NilNode<PrimitiveProps>

declare global {
declare module 'react' {
namespace JSX {
interface IntrinsicElements {
primitive: ReactProps & PrimitiveProps
Expand All @@ -41,6 +48,8 @@ class ClassComponent extends React.Component<{ children?: React.ReactNode }> {
}
}

const act = React.act

describe('useFiber', () => {
it('throws when used outside of a FiberProvider', async () => {
let threw = false
Expand Down
48 changes: 19 additions & 29 deletions src/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,10 @@ import type ReactReconciler from 'react-reconciler'
*
* @see https://github.com/facebook/react/issues/14927
*/
const useIsomorphicLayoutEffect =
typeof window !== 'undefined' && (window.document?.createElement || window.navigator?.product === 'ReactNative')
? React.useLayoutEffect
: React.useEffect
const useIsomorphicLayoutEffect = /* @__PURE__ */ (() =>
typeof window !== 'undefined' && (window.document?.createElement || window.navigator?.product === 'ReactNative'))()
? React.useLayoutEffect
: React.useEffect

/**
* Represents a react-internal Fiber node.
Expand Down Expand Up @@ -75,18 +75,7 @@ function wrapContext<T>(context: React.Context<T>): React.Context<T> {
}
}

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!))
const FiberContext = /* @__PURE__ */ wrapContext(/* @__PURE__ */ 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.
Expand Down Expand Up @@ -153,10 +142,10 @@ export function useContainer<T = any>(): T | undefined {
*/
export function useNearestChild<T = any>(
/** An optional element type to filter to. */
type?: keyof JSX.IntrinsicElements,
): React.MutableRefObject<T | undefined> {
type?: keyof React.JSX.IntrinsicElements,
): React.RefObject<T | undefined> {
const fiber = useFiber()
const childRef = React.useRef<T>()
const childRef = React.useRef<T>(undefined)

useIsomorphicLayoutEffect(() => {
childRef.current = traverseFiber<T>(
Expand All @@ -176,10 +165,10 @@ export function useNearestChild<T = any>(
*/
export function useNearestParent<T = any>(
/** An optional element type to filter to. */
type?: keyof JSX.IntrinsicElements,
): React.MutableRefObject<T | undefined> {
type?: keyof React.JSX.IntrinsicElements,
): React.RefObject<T | undefined> {
const fiber = useFiber()
const parentRef = React.useRef<T>()
const parentRef = React.useRef<T>(undefined)

useIsomorphicLayoutEffect(() => {
parentRef.current = traverseFiber<T>(
Expand All @@ -196,6 +185,11 @@ export type ContextMap = Map<React.Context<any>, any> & {
get<T>(context: React.Context<T>): T | undefined
}

const REACT_CONTEXT_TYPE = Symbol.for('react.context')

const isContext = <T,>(type: unknown): type is React.Context<T> =>
type !== null && typeof type === 'object' && '$$typeof' in type && type.$$typeof === REACT_CONTEXT_TYPE

/**
* Returns a map of all contexts and their values.
*/
Expand All @@ -207,13 +201,9 @@ export function useContextMap(): ContextMap {
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)))
}
const context = node.type
if (isContext(context) && context !== FiberContext && !contextMap.has(context)) {
contextMap.set(context, React.use(wrapContext(context)))
}

node = node.return!
Expand Down
11 changes: 0 additions & 11 deletions tests/setupTests.ts

This file was deleted.

5 changes: 3 additions & 2 deletions tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
"target": "es6",
"module": "ESNext",
"lib": ["ESNext", "dom"],
"moduleResolution": "node",
"moduleResolution": "bundler",
"esModuleInterop": true,
"jsx": "react",
"pretty": true,
Expand All @@ -13,5 +13,6 @@
"emitDeclarationOnly": true,
"forceConsistentCasingInFileNames": true
},
"include": ["src/**/*"]
"include": ["src/**/*"],
"exclude": ["src/**/*.test.*"]
}
13 changes: 1 addition & 12 deletions vite.config.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,8 @@
/// <reference types="vitest" />
import * as path from 'path'
import * as path from 'node:path'
import { defineConfig } from 'vite'

export default defineConfig({
test: {
dir: 'tests',
setupFiles: 'tests/setupTests.ts',
},
build: {
minify: false,
sourcemap: true,
target: 'es2018',
lib: {
Expand All @@ -18,11 +12,6 @@ export default defineConfig({
},
rollupOptions: {
external: (id: string) => !id.startsWith('.') && !path.isAbsolute(id),
treeshake: false,
output: {
preserveModules: true,
sourcemapExcludeSources: true,
},
},
},
})
Loading

0 comments on commit 9b93a74

Please sign in to comment.