Skip to content

Commit e471217

Browse files
committed
Move to compat
1 parent 1006fd9 commit e471217

File tree

9 files changed

+73
-84
lines changed

9 files changed

+73
-84
lines changed

compat/src/index.d.ts

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -50,15 +50,21 @@ declare namespace React {
5050
): T;
5151

5252
// Preact Defaults
53-
export import Context = preact.Context;
54-
export import ContextType = preact.ContextType;
53+
export interface Context<T> extends preact.Provider<T> {
54+
Consumer: preact.Consumer<T>;
55+
Provider: preact.Provider<T>;
56+
displayName?: string;
57+
}
58+
export function createContext<T>(defaultValue: T): Context<T>;
59+
export type ContextType<C extends Context<any>> = C extends Context<infer T>
60+
? T
61+
: never;
5562
export import RefObject = preact.RefObject;
5663
export import Component = preact.Component;
5764
export import FunctionComponent = preact.FunctionComponent;
5865
export import ComponentType = preact.ComponentType;
5966
export import ComponentClass = preact.ComponentClass;
6067
export import FC = preact.FunctionComponent;
61-
export import createContext = preact.createContext;
6268
export import Ref = preact.Ref;
6369
export import createRef = preact.createRef;
6470
export import Fragment = preact.Fragment;

compat/src/render.js

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -242,6 +242,16 @@ function handleDomVNode(vnode) {
242242

243243
let oldVNodeHook = options.vnode;
244244
options.vnode = vnode => {
245+
// @ts-expect-error type can't be null, however TS is confused
246+
if (
247+
vnode.type != null &&
248+
typeof vnode.type === 'object' &&
249+
'Provider' in vnode.type
250+
) {
251+
// @ts-expect-error
252+
vnode.type = vnode.type.Provider;
253+
}
254+
245255
// only normalize props on Element nodes
246256
if (typeof vnode.type === 'string') {
247257
handleDomVNode(vnode);

compat/test/browser/render.test.js

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -545,6 +545,40 @@ describe('compat render', () => {
545545
expect(scratch.textContent).to.equal('foo');
546546
});
547547

548+
it('should allow context as a component', () => {
549+
const Context = createContext(null);
550+
const CONTEXT = { a: 'a' };
551+
552+
let receivedContext;
553+
554+
class Inner extends Component {
555+
render(props) {
556+
return <div>{props.a}</div>;
557+
}
558+
}
559+
560+
sinon.spy(Inner.prototype, 'render');
561+
562+
render(
563+
<Context value={CONTEXT}>
564+
<div>
565+
<Context.Consumer>
566+
{data => {
567+
receivedContext = data;
568+
return <Inner {...data} />;
569+
}}
570+
</Context.Consumer>
571+
</div>
572+
</Context>,
573+
scratch
574+
);
575+
576+
// initial render does not invoke anything but render():
577+
expect(Inner.prototype.render).to.have.been.calledWithMatch(CONTEXT);
578+
expect(receivedContext).to.equal(CONTEXT);
579+
expect(scratch.innerHTML).to.equal('<div><div>a</div></div>');
580+
});
581+
548582
it("should support recoils's usage of __SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED", () => {
549583
// Simplified version of: https://github.com/facebookexperimental/Recoil/blob/c1b97f3a0117cad76cbc6ab3cb06d89a9ce717af/packages/recoil/core/Recoil_ReactMode.js#L36-L44
550584
function useStateWrapper(init) {

compat/test/ts/index.tsx

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,3 +15,21 @@ React.unmountComponentAtNode(document.body.shadowRoot!);
1515
React.createPortal(<div />, document.createElement('div'));
1616
React.createPortal(<div />, document.createDocumentFragment());
1717
React.createPortal(<div />, document.body.shadowRoot!);
18+
19+
const Ctx = React.createContext({ contextValue: '' });
20+
class SimpleComponentWithContextAsProvider extends React.Component {
21+
componentProp = 'componentProp';
22+
render() {
23+
// Render inside div to ensure standard JSX elements still work
24+
return (
25+
<Ctx value={{ contextValue: 'value' }}>
26+
<div>
27+
{/* Ensure context still works */}
28+
<Ctx.Consumer>
29+
{({ contextValue }) => contextValue.toLowerCase()}
30+
</Ctx.Consumer>
31+
</div>
32+
</Ctx>
33+
);
34+
}
35+
}

src/create-context.js

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ export let i = 0;
55
export function createContext(defaultValue, contextId) {
66
contextId = '__cC' + i++;
77

8-
/** @type {any} */
98
const context = {
109
_id: contextId,
1110
_defaultValue: defaultValue,

src/create-element.js

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ let vnodeId = 0;
88
* Create an virtual node (used for JSX)
99
* @param {import('./internal').VNode["type"]} type The node name or Component constructor for this
1010
* virtual node
11-
* @param {object | null | undefined | import('.').Context} [props] The properties of the virtual node
11+
* @param {object | null | undefined} [props] The properties of the virtual node
1212
* @param {Array<import('.').ComponentChildren>} [children] The children of the
1313
* virtual node
1414
* @returns {import('./internal').VNode}
@@ -18,13 +18,6 @@ export function createElement(type, props, children) {
1818
key,
1919
ref,
2020
i;
21-
22-
// @ts-expect-error type can't be null, however TS is confused
23-
if (type != null && typeof type === 'object' && 'Provider' in type) {
24-
// @ts-expect-error
25-
type = type.Provider;
26-
}
27-
2821
for (i in props) {
2922
if (i == 'key') key = props[i];
3023
else if (i == 'ref') ref = props[i];

src/index.d.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -388,7 +388,7 @@ export type ContextType<C extends Context<any>> = C extends Context<infer T>
388388
? T
389389
: never;
390390

391-
export interface Context<T> extends Provider<T> {
391+
export interface Context<T> {
392392
Consumer: Consumer<T>;
393393
Provider: Provider<T>;
394394
displayName?: string;

test/browser/createContext.test.js

Lines changed: 0 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -57,40 +57,6 @@ describe('createContext', () => {
5757
expect(scratch.innerHTML).to.equal('<div><div>a</div></div>');
5858
});
5959

60-
it('should allow context as a component', () => {
61-
const Context = createContext(null);
62-
const CONTEXT = { a: 'a' };
63-
64-
let receivedContext;
65-
66-
class Inner extends Component {
67-
render(props) {
68-
return <div>{props.a}</div>;
69-
}
70-
}
71-
72-
sinon.spy(Inner.prototype, 'render');
73-
74-
render(
75-
<Context value={CONTEXT}>
76-
<div>
77-
<Context.Consumer>
78-
{data => {
79-
receivedContext = data;
80-
return <Inner {...data} />;
81-
}}
82-
</Context.Consumer>
83-
</div>
84-
</Context>,
85-
scratch
86-
);
87-
88-
// initial render does not invoke anything but render():
89-
expect(Inner.prototype.render).to.have.been.calledWithMatch(CONTEXT);
90-
expect(receivedContext).to.equal(CONTEXT);
91-
expect(scratch.innerHTML).to.equal('<div><div>a</div></div>');
92-
});
93-
9460
// This optimization helps
9561
// to prevent a Provider from rerendering the children, this means
9662
// we only propagate to children.

test/ts/custom-elements.tsx

Lines changed: 0 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -82,41 +82,4 @@ class SimpleComponent extends Component {
8282
}
8383
}
8484

85-
class SimpleComponentWithContextAsProvider extends Component {
86-
componentProp = 'componentProp';
87-
render() {
88-
// Render inside div to ensure standard JSX elements still work
89-
return (
90-
<Ctx value={{ contextValue: 'value' }}>
91-
<div>
92-
<clickable-ce
93-
onClick={e => {
94-
// `this` should be instance of SimpleComponent since this is an
95-
// arrow function
96-
console.log(this.componentProp);
97-
98-
// Validate `currentTarget` is HTMLElement
99-
console.log('clicked ', e.currentTarget.style.display);
100-
}}
101-
></clickable-ce>
102-
<color-picker space="rgb" dir="rtl"></color-picker>
103-
<custom-whatever
104-
dir="auto" // Inherited prop from HTMLAttributes
105-
someattribute="string"
106-
onsomeevent={function (e) {
107-
// Validate `this` and `e` are the right type
108-
console.log('clicked', this.instanceProp, e.eventProp);
109-
}}
110-
></custom-whatever>
111-
112-
{/* Ensure context still works */}
113-
<Ctx.Consumer>
114-
{({ contextValue }) => contextValue.toLowerCase()}
115-
</Ctx.Consumer>
116-
</div>
117-
</Ctx>
118-
);
119-
}
120-
}
121-
12285
const component = <SimpleComponent />;

0 commit comments

Comments
 (0)