@react-pixi-fiber/react-17 0.0.0-stage → 1.0.0-beta.0

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/src/index.ts ADDED
@@ -0,0 +1,174 @@
1
+ import React from "react";
2
+ import Reconciler from "react-reconciler";
3
+ import type { HostOps, ReactAdapter, Renderer } from "react-pixi-fiber";
4
+
5
+ // https://github.com/facebook/react/blob/v17.0.2/packages/react-reconciler/src/ReactTypeOfMode.js: StrictMode
6
+ export const strictModeBit = 1;
7
+ // https://github.com/facebook/react/blob/v17.0.2/packages/react-reconciler/src/ReactRootTags.js
8
+ const LegacyRoot = 0;
9
+ const ConcurrentRoot = 2;
10
+ const emptyObject = Object.freeze({});
11
+
12
+ export interface React17Options {
13
+ /**
14
+ * The kind of root Stage and `render` create: `"legacy"` (the default) commits every update synchronously, as 2.x
15
+ * did; `"concurrent"` is the experimental concurrent mode of React 17.
16
+ */
17
+ root?: "concurrent" | "legacy";
18
+ }
19
+
20
+ function invariant(condition: unknown, message: string): asserts condition {
21
+ if (!condition) throw new Error(message);
22
+ }
23
+
24
+ // The mutation host config of react-reconciler 0.26.2. The hydration, persistence and test selector keys are left
25
+ // out: the reconciler reads them only behind supportsHydration, supportsPersistence and supportsTestSelectors.
26
+ // Typed loosely on purpose: it goes straight into Reconciler, and the declaration stays free of inferred core types.
27
+ export function createHostConfig(hostOps: HostOps): Record<string, unknown> {
28
+ return {
29
+ supportsMutation: true,
30
+ supportsPersistence: false,
31
+ supportsHydration: false,
32
+ supportsTestSelectors: false,
33
+ noTimeout: -1,
34
+ scheduleTimeout: setTimeout,
35
+ cancelTimeout: clearTimeout,
36
+ now: () =>
37
+ typeof performance === "object" && typeof performance.now === "function" ? performance.now() : Date.now(),
38
+ getRootHostContext: () => emptyObject,
39
+ getChildHostContext: (parentHostContext: unknown) => parentHostContext,
40
+ getPublicInstance: (instance: unknown) => instance,
41
+ prepareForCommit: () => null,
42
+ resetAfterCommit() {},
43
+ preparePortalMount() {},
44
+ shouldSetTextContent: () => false,
45
+ createInstance: (type: string, props: Record<string, unknown>, rootContainer: unknown) =>
46
+ hostOps.createInstance(type, props, rootContainer),
47
+ createTextInstance() {
48
+ invariant(false, "ReactPixiFiber does not support text instances. Use `Text` component instead.");
49
+ },
50
+ appendInitialChild: hostOps.appendChild,
51
+ appendChild: hostOps.appendChild,
52
+ appendChildToContainer: hostOps.appendChild,
53
+ insertBefore: hostOps.insertBefore,
54
+ insertInContainerBefore: hostOps.insertBefore,
55
+ removeChild: hostOps.removeChild,
56
+ removeChildFromContainer: hostOps.removeChild,
57
+ clearContainer: hostOps.clearContainer,
58
+ hideInstance: hostOps.hideInstance,
59
+ unhideInstance: hostOps.unhideInstance,
60
+ hideTextInstance() {},
61
+ unhideTextInstance() {},
62
+ finalizeInitialChildren(instance: unknown, type: string, props: Record<string, unknown>) {
63
+ hostOps.setInitialProperties(type, instance, props);
64
+ return true;
65
+ },
66
+ commitMount(instance: unknown, type: string, props: Record<string, unknown>, internalHandle: unknown) {
67
+ if (__DEV__) hostOps.validateProperties(type, props, internalHandle);
68
+ },
69
+ prepareUpdate(
70
+ instance: unknown,
71
+ type: string,
72
+ oldProps: Record<string, unknown>,
73
+ newProps: Record<string, unknown>
74
+ ) {
75
+ return hostOps.diffProperties(type, instance, oldProps, newProps);
76
+ },
77
+ commitUpdate(
78
+ instance: unknown,
79
+ payload: unknown[],
80
+ type: string,
81
+ prevProps: Record<string, unknown>,
82
+ nextProps: Record<string, unknown>,
83
+ internalHandle: unknown
84
+ ) {
85
+ hostOps.updateProperties(type, instance, payload, prevProps, nextProps, internalHandle);
86
+ if (__DEV__) hostOps.validateProperties(type, nextProps, internalHandle);
87
+ },
88
+ commitTextUpdate() {},
89
+ resetTextContent() {},
90
+ getInstanceFromNode() {
91
+ invariant(false, "Not yet implemented.");
92
+ },
93
+ getInstanceFromScope() {
94
+ invariant(false, "Not yet implemented.");
95
+ },
96
+ beforeActiveInstanceBlur() {},
97
+ afterActiveInstanceBlur() {},
98
+ };
99
+ }
100
+
101
+ function getStackAddendum(): string {
102
+ if (!__DEV__) return "";
103
+ const internals = (React as any).__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED;
104
+ const frame = internals && internals.ReactDebugCurrentFrame;
105
+ if (frame == null) return "";
106
+ const stack = frame.getStackAddendum();
107
+ return stack != null ? stack : "";
108
+ }
109
+
110
+ function createRenderer(hostOps: HostOps, isPrimaryRenderer: boolean, rootTag: number): Renderer {
111
+ const reconciler = Reconciler({ ...createHostConfig(hostOps), isPrimaryRenderer } as any);
112
+ reconciler.injectIntoDevTools({
113
+ findFiberByHostInstance: () => null,
114
+ bundleType: __DEV__ ? 1 : 0,
115
+ version: React.version,
116
+ rendererPackageName: "react-pixi-fiber",
117
+ });
118
+ const roots = new WeakMap<object, unknown>();
119
+ // A concurrent root commits the first render and the unmount before they return, as a legacy root does, so Stage
120
+ // reads its tree in the same effect on both.
121
+ const commit =
122
+ rootTag === ConcurrentRoot
123
+ ? (update: () => void) => reconciler.flushSync(update, undefined)
124
+ : (update: () => void) => update();
125
+ return {
126
+ render(element, container, callback, parentComponent) {
127
+ let root = roots.get(container);
128
+ if (!root) {
129
+ // @types/react-reconciler 0.26 declares the createContainer signature of a later reconciler.
130
+ root = (
131
+ reconciler as unknown as {
132
+ createContainer(container: unknown, tag: number, hydrate: boolean, hydrationCallbacks: null): unknown;
133
+ }
134
+ ).createContainer(container, rootTag, false, null);
135
+ roots.set(container, root);
136
+ }
137
+ commit(() => {
138
+ reconciler.updateContainer(element, root as any, parentComponent as any, callback as any);
139
+ });
140
+ return reconciler.getPublicRootInstance(root as any);
141
+ },
142
+ unmount(container) {
143
+ const root = roots.get(container);
144
+ if (!root) return false;
145
+ commit(() => {
146
+ reconciler.updateContainer(null, root as any, null, null);
147
+ });
148
+ return true;
149
+ },
150
+ getStackAddendum,
151
+ };
152
+ }
153
+
154
+ // One renderer per core, kind and root for the lifetime of the page: React DevTools keeps every renderer injected into
155
+ // it, and `configure` may be called more than once.
156
+ const renderers = new WeakMap<HostOps, Record<string, Renderer>>();
157
+
158
+ export default function react17({ root = "legacy" }: React17Options = {}): ReactAdapter {
159
+ if (root !== "concurrent" && root !== "legacy") {
160
+ throw new Error(
161
+ `\`react17({ root })\` got ${JSON.stringify(root)}. Pass "concurrent" or "legacy", or leave \`root\` out.`
162
+ );
163
+ }
164
+ const rootTag = root === "concurrent" ? ConcurrentRoot : LegacyRoot;
165
+ return {
166
+ strictModeBit,
167
+ createRenderer(hostOps, { isPrimaryRenderer }): Renderer {
168
+ let cached = renderers.get(hostOps);
169
+ if (!cached) renderers.set(hostOps, (cached = {}));
170
+ const key = `${isPrimaryRenderer ? "primary" : "secondary"} ${root}`;
171
+ return cached[key] || (cached[key] = createRenderer(hostOps, isPrimaryRenderer, rootTag));
172
+ },
173
+ };
174
+ }