Skip to content

Commit

Permalink
Merge branch 'main' into skip-comment-nodes
Browse files Browse the repository at this point in the history
  • Loading branch information
JoviDeCroock authored Dec 29, 2023
2 parents 0f12d8d + da9d488 commit b1c6ce5
Show file tree
Hide file tree
Showing 18 changed files with 606 additions and 93 deletions.
1 change: 1 addition & 0 deletions .github/workflows/saucelabs.yml
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
name: Saucelabs

on:
workflow_dispatch:
push:
branches:
- main
Expand Down
1 change: 1 addition & 0 deletions compat/src/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ declare namespace React {
export import RefObject = preact.RefObject;
export import Component = preact.Component;
export import FunctionComponent = preact.FunctionComponent;
export import ComponentType = preact.ComponentType;
export import FC = preact.FunctionComponent;
export import createContext = preact.createContext;
export import createRef = preact.createRef;
Expand Down
7 changes: 5 additions & 2 deletions compat/src/suspense.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { Component, createElement, options, Fragment } from 'preact';
import { MODE_HYDRATE } from 'preact/src/constants';
import { MODE_HYDRATE } from '../../src/constants';
import { assign } from './util';

const oldCatchError = options._catchError;
Expand Down Expand Up @@ -167,7 +167,10 @@ Suspense.prototype._childDidSuspend = function (promise, suspendingVNode) {
* to remain on screen and hydrate it when the suspense actually gets resolved.
* While in non-hydration cases the usual fallback -> component flow would occour.
*/
if (!c._pendingSuspensionCount++ && !(suspendingVNode._flags & MODE_HYDRATE)) {
if (
!c._pendingSuspensionCount++ &&
!(suspendingVNode._flags & MODE_HYDRATE)
) {
c.setState({ _suspended: (c._detachOnNextRender = c._vnode._children[0]) });
}
promise.then(onResolved, onResolved);
Expand Down
8 changes: 7 additions & 1 deletion compat/test/browser/render.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -263,7 +263,13 @@ describe('compat render', () => {
/>,
scratch
);
expect(sortAttributes(scratch.innerHTML)).to.equal(

let html = sortAttributes(scratch.innerHTML);
if (/Trident/.test(navigator.userAgent)) {
html = html.toLowerCase();
}

expect(html).to.equal(
'<link as="image" href="preact.jpg" imagesrcset="preact_400px.jpg 400w" rel="preload">'
);
});
Expand Down
2 changes: 1 addition & 1 deletion devtools/src/devtools.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { options, Fragment, Component } from 'preact';

export function initDevTools() {
if (typeof window != 'undefined' && window.__PREACT_DEVTOOLS__) {
window.__PREACT_DEVTOOLS__.attachPreact('10.18.2', options, {
window.__PREACT_DEVTOOLS__.attachPreact('10.19.3', options, {
Fragment,
Component
});
Expand Down
79 changes: 59 additions & 20 deletions hooks/src/index.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { options } from 'preact';
import { options as _options } from 'preact';

/** @type {number} */
let currentIndex;
Expand All @@ -17,6 +17,9 @@ let afterPaintEffects = [];

let EMPTY = [];

// Cast to use internal Options type
const options = /** @type {import('./internal').Options} */ (_options);

let oldBeforeDiff = options._diff;
let oldBeforeRender = options._render;
let oldAfterDiff = options.diffed;
Expand All @@ -26,11 +29,13 @@ let oldBeforeUnmount = options.unmount;
const RAF_TIMEOUT = 100;
let prevRaf;

/** @type {(vnode: import('./internal').VNode) => void} */
options._diff = vnode => {
currentComponent = null;
if (oldBeforeDiff) oldBeforeDiff(vnode);
};

/** @type {(vnode: import('./internal').VNode) => void} */
options._render = vnode => {
if (oldBeforeRender) oldBeforeRender(vnode);

Expand Down Expand Up @@ -59,6 +64,7 @@ options._render = vnode => {
previousComponent = currentComponent;
};

/** @type {(vnode: import('./internal').VNode) => void} */
options.diffed = vnode => {
if (oldAfterDiff) oldAfterDiff(vnode);

Expand All @@ -79,6 +85,8 @@ options.diffed = vnode => {
previousComponent = currentComponent = null;
};

// TODO: Improve typing of commitQueue parameter
/** @type {(vnode: import('./internal').VNode, commitQueue: any) => void} */
options._commit = (vnode, commitQueue) => {
commitQueue.some(component => {
try {
Expand All @@ -98,6 +106,7 @@ options._commit = (vnode, commitQueue) => {
if (oldCommit) oldCommit(vnode, commitQueue);
};

/** @type {(vnode: import('./internal').VNode) => void} */
options.unmount = vnode => {
if (oldBeforeUnmount) oldBeforeUnmount(vnode);

Expand Down Expand Up @@ -143,22 +152,27 @@ function getHookState(index, type) {
if (index >= hooks._list.length) {
hooks._list.push({ _pendingValue: EMPTY });
}

return hooks._list[index];
}

/**
* @param {import('./index').StateUpdater<any>} [initialState]
* @template {unknown} S
* @param {import('./index').StateUpdater<S>} [initialState]
* @returns {[S, (state: S) => void]}
*/
export function useState(initialState) {
currentHook = 1;
return useReducer(invokeOrReturn, initialState);
}

/**
* @param {import('./index').Reducer<any, any>} reducer
* @param {import('./index').StateUpdater<any>} initialState
* @template {unknown} S
* @template {unknown} A
* @param {import('./index').Reducer<S, A>} reducer
* @param {import('./index').StateUpdater<S>} initialState
* @param {(initialState: any) => void} [init]
* @returns {[ any, (state: any) => void ]}
* @returns {[ S, (state: S) => void ]}
*/
export function useReducer(reducer, initialState, init) {
/** @type {import('./internal').ReducerHookState} */
Expand Down Expand Up @@ -218,9 +232,11 @@ export function useReducer(reducer, initialState, init) {
function updateHookState(p, s, c) {
if (!hookState._component.__hooks) return true;

const stateHooks = hookState._component.__hooks._list.filter(
x => x._component
);
/** @type {(x: import('./internal').HookState) => x is import('./internal').ReducerHookState} */
const isStateHook = x => !!x._component;
const stateHooks =
hookState._component.__hooks._list.filter(isStateHook);

const allHooksEmpty = stateHooks.every(x => !x._nextValue);
// When we have no updated hooks in the component we invoke the previous SCU or
// traverse the VDOM tree further.
Expand Down Expand Up @@ -257,7 +273,8 @@ export function useReducer(reducer, initialState, init) {

/**
* @param {import('./internal').Effect} callback
* @param {any[]} args
* @param {unknown[]} args
* @returns {void}
*/
export function useEffect(callback, args) {
/** @type {import('./internal').EffectHookState} */
Expand All @@ -272,7 +289,8 @@ export function useEffect(callback, args) {

/**
* @param {import('./internal').Effect} callback
* @param {any[]} args
* @param {unknown[]} args
* @returns {void}
*/
export function useLayoutEffect(callback, args) {
/** @type {import('./internal').EffectHookState} */
Expand All @@ -285,6 +303,7 @@ export function useLayoutEffect(callback, args) {
}
}

/** @type {(initialValue: unknown) => unknown} */
export function useRef(initialValue) {
currentHook = 5;
return useMemo(() => ({ current: initialValue }), []);
Expand All @@ -293,7 +312,8 @@ export function useRef(initialValue) {
/**
* @param {object} ref
* @param {() => object} createHandle
* @param {any[]} args
* @param {unknown[]} args
* @returns {void}
*/
export function useImperativeHandle(ref, createHandle, args) {
currentHook = 6;
Expand All @@ -312,11 +332,13 @@ export function useImperativeHandle(ref, createHandle, args) {
}

/**
* @param {() => any} factory
* @param {any[]} args
* @template {unknown} T
* @param {() => T} factory
* @param {unknown[]} args
* @returns {T}
*/
export function useMemo(factory, args) {
/** @type {import('./internal').MemoHookState} */
/** @type {import('./internal').MemoHookState<T>} */
const state = getHookState(currentIndex++, 7);
if (argsChanged(state._args, args)) {
state._pendingValue = factory();
Expand All @@ -330,7 +352,8 @@ export function useMemo(factory, args) {

/**
* @param {() => void} callback
* @param {any[]} args
* @param {unknown[]} args
* @returns {() => void}
*/
export function useCallback(callback, args) {
currentHook = 8;
Expand Down Expand Up @@ -366,12 +389,15 @@ export function useContext(context) {
*/
export function useDebugValue(value, formatter) {
if (options.useDebugValue) {
options.useDebugValue(formatter ? formatter(value) : value);
options.useDebugValue(
formatter ? formatter(value) : /** @type {any}*/ (value)
);
}
}

/**
* @param {(error: any, errorInfo: import('preact').ErrorInfo) => void} cb
* @param {(error: unknown, errorInfo: import('preact').ErrorInfo) => void} cb
* @returns {[unknown, () => void]}
*/
export function useErrorBoundary(cb) {
/** @type {import('./internal').ErrorBoundaryHookState} */
Expand All @@ -392,7 +418,9 @@ export function useErrorBoundary(cb) {
];
}

/** @type {() => string} */
export function useId() {
/** @type {import('./internal').IdHookState} */
const state = getHookState(currentIndex++, 11);
if (!state._value) {
// Grab either the root node or the nearest async boundary node.
Expand All @@ -408,6 +436,7 @@ export function useId() {

return state._value;
}

/**
* After paint effects consumer.
*/
Expand Down Expand Up @@ -458,6 +487,7 @@ function afterNextFrame(callback) {
/**
* Schedule afterPaintEffects flush after the browser paints
* @param {number} newQueueLength
* @returns {void}
*/
function afterPaint(newQueueLength) {
if (newQueueLength === 1 || prevRaf !== options.requestAnimationFrame) {
Expand All @@ -467,7 +497,8 @@ function afterPaint(newQueueLength) {
}

/**
* @param {import('./internal').EffectHookState} hook
* @param {import('./internal').HookState} hook
* @returns {void}
*/
function invokeCleanup(hook) {
// A hook cleanup can introduce a call to render which creates a new root, this will call options.vnode
Expand All @@ -485,6 +516,7 @@ function invokeCleanup(hook) {
/**
* Invoke a Hook's effect
* @param {import('./internal').EffectHookState} hook
* @returns {void}
*/
function invokeEffect(hook) {
// A hook call can introduce a call to render which creates a new root, this will call options.vnode
Expand All @@ -495,8 +527,9 @@ function invokeEffect(hook) {
}

/**
* @param {any[]} oldArgs
* @param {any[]} newArgs
* @param {unknown[]} oldArgs
* @param {unknown[]} newArgs
* @returns {boolean}
*/
function argsChanged(oldArgs, newArgs) {
return (
Expand All @@ -506,6 +539,12 @@ function argsChanged(oldArgs, newArgs) {
);
}

/**
* @template Arg
* @param {Arg} arg
* @param {(arg: Arg) => any} f
* @returns {any}
*/
function invokeOrReturn(arg, f) {
return typeof f == 'function' ? f(arg) : f;
}
Loading

0 comments on commit b1c6ce5

Please sign in to comment.