@reckona/mreact-compat 0.0.174 → 0.0.176
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/dist/element.d.ts +1 -0
- package/dist/element.d.ts.map +1 -1
- package/dist/element.js +35 -1
- package/dist/element.js.map +1 -1
- package/dist/host-reconciler.d.ts.map +1 -1
- package/dist/host-reconciler.js +187 -23
- package/dist/host-reconciler.js.map +1 -1
- package/dist/reactive-prop-cell.d.ts +8 -0
- package/dist/reactive-prop-cell.d.ts.map +1 -1
- package/dist/reactive-prop-cell.js +108 -4
- package/dist/reactive-prop-cell.js.map +1 -1
- package/package.json +3 -3
- package/src/element.ts +49 -1
- package/src/host-reconciler.ts +272 -34
- package/src/reactive-prop-cell.ts +154 -4
|
@@ -3,11 +3,19 @@ import type { ReactiveDomBlockResult } from "./element.js";
|
|
|
3
3
|
export interface ReactivePropCell {
|
|
4
4
|
value: Record<string, unknown>;
|
|
5
5
|
source: Source;
|
|
6
|
+
propertySources?: Map<PropertyKey, Source> | undefined;
|
|
7
|
+
propertySnapshots?: Map<PropertyKey, ShallowObjectSnapshot> | undefined;
|
|
6
8
|
}
|
|
7
9
|
export interface ReactiveDomBlockState extends ReactiveDomBlockResult {
|
|
8
10
|
propCell?: ReactivePropCell | undefined;
|
|
9
11
|
}
|
|
10
12
|
export declare function createReactivePropCell(props: Record<string, unknown>): ReactivePropCell;
|
|
13
|
+
export declare function batchReactivePropCellUpdates<T>(run: () => T): T;
|
|
11
14
|
export declare function createReactivePropProxy<P extends object>(cell: ReactivePropCell): P;
|
|
15
|
+
interface ShallowObjectSnapshot {
|
|
16
|
+
value: object;
|
|
17
|
+
entries: Map<PropertyKey, unknown>;
|
|
18
|
+
}
|
|
12
19
|
export declare function setReactivePropCell(cell: ReactivePropCell, next: Record<string, unknown>): void;
|
|
20
|
+
export {};
|
|
13
21
|
//# sourceMappingURL=reactive-prop-cell.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"reactive-prop-cell.d.ts","sourceRoot":"","sources":["../src/reactive-prop-cell.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"reactive-prop-cell.d.ts","sourceRoot":"","sources":["../src/reactive-prop-cell.ts"],"names":[],"mappings":"AACA,OAAO,EAIL,KAAK,MAAM,EACZ,MAAM,wCAAwC,CAAC;AAChD,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,cAAc,CAAC;AAQ3D,MAAM,WAAW,gBAAgB;IAC/B,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC/B,MAAM,EAAE,MAAM,CAAC;IACf,eAAe,CAAC,EAAE,GAAG,CAAC,WAAW,EAAE,MAAM,CAAC,GAAG,SAAS,CAAC;IACvD,iBAAiB,CAAC,EAAE,GAAG,CAAC,WAAW,EAAE,qBAAqB,CAAC,GAAG,SAAS,CAAC;CACzE;AAID,MAAM,WAAW,qBAAsB,SAAQ,sBAAsB;IACnE,QAAQ,CAAC,EAAE,gBAAgB,GAAG,SAAS,CAAC;CACzC;AAKD,wBAAgB,sBAAsB,CAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,gBAAgB,CAEvF;AAED,wBAAgB,4BAA4B,CAAC,CAAC,EAAE,GAAG,EAAE,MAAM,CAAC,GAAG,CAAC,CAW/D;AAuBD,wBAAgB,uBAAuB,CAAC,CAAC,SAAS,MAAM,EAAE,IAAI,EAAE,gBAAgB,GAAG,CAAC,CAEnF;AAoBD,UAAU,qBAAqB;IAC7B,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,GAAG,CAAC,WAAW,EAAE,OAAO,CAAC,CAAC;CACpC;AAgFD,wBAAgB,mBAAmB,CACjC,IAAI,EAAE,gBAAgB,EACtB,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAC5B,IAAI,CAuCN"}
|
|
@@ -1,14 +1,32 @@
|
|
|
1
|
+
import { batch } from "@reckona/mreact-reactive-core";
|
|
1
2
|
import { flushQueuedComputations, notifySubscribers, trackSource, } from "@reckona/mreact-reactive-core/internal";
|
|
3
|
+
let propCellBatchDepth = 0;
|
|
4
|
+
let propCellBatchNeedsFlush = false;
|
|
2
5
|
export function createReactivePropCell(props) {
|
|
3
6
|
return { value: props, source: { subscribers: null } };
|
|
4
7
|
}
|
|
8
|
+
export function batchReactivePropCellUpdates(run) {
|
|
9
|
+
propCellBatchDepth += 1;
|
|
10
|
+
try {
|
|
11
|
+
return batch(run);
|
|
12
|
+
}
|
|
13
|
+
finally {
|
|
14
|
+
propCellBatchDepth -= 1;
|
|
15
|
+
if (propCellBatchDepth === 0 && propCellBatchNeedsFlush) {
|
|
16
|
+
propCellBatchNeedsFlush = false;
|
|
17
|
+
flushQueuedComputations();
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
}
|
|
5
21
|
const PROP_PROXY_HANDLER = {
|
|
6
22
|
get(cell, property) {
|
|
7
|
-
trackSource(cell
|
|
8
|
-
|
|
23
|
+
trackSource(getReactivePropPropertySource(cell, property));
|
|
24
|
+
const value = Reflect.get(cell.value, property);
|
|
25
|
+
rememberReactivePropObjectSnapshot(cell, property, value);
|
|
26
|
+
return value;
|
|
9
27
|
},
|
|
10
28
|
has(cell, property) {
|
|
11
|
-
trackSource(cell
|
|
29
|
+
trackSource(getReactivePropPropertySource(cell, property));
|
|
12
30
|
return property in cell.value;
|
|
13
31
|
},
|
|
14
32
|
ownKeys(cell) {
|
|
@@ -23,14 +41,100 @@ const PROP_PROXY_HANDLER = {
|
|
|
23
41
|
export function createReactivePropProxy(cell) {
|
|
24
42
|
return new Proxy(cell, PROP_PROXY_HANDLER);
|
|
25
43
|
}
|
|
44
|
+
function getReactivePropPropertySource(cell, property) {
|
|
45
|
+
let propertySources = cell.propertySources;
|
|
46
|
+
if (propertySources === undefined) {
|
|
47
|
+
propertySources = new Map();
|
|
48
|
+
cell.propertySources = propertySources;
|
|
49
|
+
}
|
|
50
|
+
let source = propertySources.get(property);
|
|
51
|
+
if (source === undefined) {
|
|
52
|
+
source = { subscribers: null };
|
|
53
|
+
propertySources.set(property, source);
|
|
54
|
+
}
|
|
55
|
+
return source;
|
|
56
|
+
}
|
|
57
|
+
function rememberReactivePropObjectSnapshot(cell, property, value) {
|
|
58
|
+
if (!isObjectLike(value)) {
|
|
59
|
+
cell.propertySnapshots?.delete(property);
|
|
60
|
+
return;
|
|
61
|
+
}
|
|
62
|
+
let snapshots = cell.propertySnapshots;
|
|
63
|
+
if (snapshots === undefined) {
|
|
64
|
+
snapshots = new Map();
|
|
65
|
+
cell.propertySnapshots = snapshots;
|
|
66
|
+
}
|
|
67
|
+
snapshots.set(property, createShallowObjectSnapshot(value));
|
|
68
|
+
}
|
|
69
|
+
function createShallowObjectSnapshot(value) {
|
|
70
|
+
const entries = new Map();
|
|
71
|
+
for (const key of Reflect.ownKeys(value)) {
|
|
72
|
+
const descriptor = Reflect.getOwnPropertyDescriptor(value, key);
|
|
73
|
+
if (descriptor !== undefined && "value" in descriptor) {
|
|
74
|
+
entries.set(key, descriptor.value);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
return { value, entries };
|
|
78
|
+
}
|
|
79
|
+
function isObjectLike(value) {
|
|
80
|
+
return (typeof value === "object" && value !== null) || typeof value === "function";
|
|
81
|
+
}
|
|
82
|
+
function hasShallowObjectSnapshotChanged(snapshot, nextValue) {
|
|
83
|
+
if (snapshot === undefined || snapshot.value !== nextValue || !isObjectLike(nextValue)) {
|
|
84
|
+
return false;
|
|
85
|
+
}
|
|
86
|
+
for (const key of Reflect.ownKeys(nextValue)) {
|
|
87
|
+
const descriptor = Reflect.getOwnPropertyDescriptor(nextValue, key);
|
|
88
|
+
if (descriptor !== undefined && "value" in descriptor) {
|
|
89
|
+
if (!snapshot.entries.has(key) || !Object.is(snapshot.entries.get(key), descriptor.value)) {
|
|
90
|
+
return true;
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
for (const key of snapshot.entries.keys()) {
|
|
95
|
+
const descriptor = Reflect.getOwnPropertyDescriptor(nextValue, key);
|
|
96
|
+
if (descriptor === undefined || !("value" in descriptor)) {
|
|
97
|
+
return true;
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
return false;
|
|
101
|
+
}
|
|
102
|
+
function shouldNotifyReactivePropProperty(previous, next, property, snapshot) {
|
|
103
|
+
if ((property in previous) !== (property in next)) {
|
|
104
|
+
return true;
|
|
105
|
+
}
|
|
106
|
+
const previousValue = Reflect.get(previous, property);
|
|
107
|
+
const nextValue = Reflect.get(next, property);
|
|
108
|
+
return !Object.is(previousValue, nextValue) ||
|
|
109
|
+
hasShallowObjectSnapshotChanged(snapshot, nextValue);
|
|
110
|
+
}
|
|
26
111
|
export function setReactivePropCell(cell, next) {
|
|
27
112
|
if (Object.is(cell.value, next)) {
|
|
28
113
|
return;
|
|
29
114
|
}
|
|
115
|
+
const previous = cell.value;
|
|
116
|
+
const propertySources = cell.propertySources;
|
|
117
|
+
let notified = false;
|
|
30
118
|
cell.value = next;
|
|
119
|
+
if (propertySources !== undefined) {
|
|
120
|
+
for (const [property, source] of propertySources) {
|
|
121
|
+
if (shouldNotifyReactivePropProperty(previous, next, property, cell.propertySnapshots?.get(property))) {
|
|
122
|
+
notifySubscribers(source);
|
|
123
|
+
notified = true;
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
}
|
|
31
127
|
if (cell.source.subscribers !== null) {
|
|
32
128
|
notifySubscribers(cell.source);
|
|
33
|
-
|
|
129
|
+
notified = true;
|
|
130
|
+
}
|
|
131
|
+
if (notified) {
|
|
132
|
+
if (propCellBatchDepth === 0) {
|
|
133
|
+
flushQueuedComputations();
|
|
134
|
+
}
|
|
135
|
+
else {
|
|
136
|
+
propCellBatchNeedsFlush = true;
|
|
137
|
+
}
|
|
34
138
|
}
|
|
35
139
|
}
|
|
36
140
|
//# sourceMappingURL=reactive-prop-cell.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"reactive-prop-cell.js","sourceRoot":"","sources":["../src/reactive-prop-cell.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,uBAAuB,EACvB,iBAAiB,EACjB,WAAW,GAEZ,MAAM,wCAAwC,CAAC;AAoBhD,MAAM,UAAU,sBAAsB,CAAC,KAA8B;IACnE,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,EAAE,WAAW,EAAE,IAAI,EAAE,EAAE,CAAC;AACzD,CAAC;AAED,MAAM,kBAAkB,GAAmC;IACzD,GAAG,CAAC,IAAI,EAAE,QAAQ;QAChB,WAAW,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QACzB,OAAO,IAAI,CAAC,KAAK,CAAC,QAAkB,CAAC,CAAC;IACxC,CAAC;IACD,GAAG,CAAC,IAAI,EAAE,QAAQ;QAChB,WAAW,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QACzB,OAAO,QAAQ,IAAI,IAAI,CAAC,KAAK,CAAC;IAChC,CAAC;IACD,OAAO,CAAC,IAAI;QACV,WAAW,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QACzB,OAAO,OAAO,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IACrC,CAAC;IACD,wBAAwB,CAAC,IAAI,EAAE,QAAQ;QACrC,WAAW,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QACzB,OAAO,OAAO,CAAC,wBAAwB,CAAC,IAAI,CAAC,KAAK,EAAE,QAAQ,CAAC,CAAC;IAChE,CAAC;CACF,CAAC;AAEF,MAAM,UAAU,uBAAuB,CAAmB,IAAsB;IAC9E,OAAO,IAAI,KAAK,CAAC,IAAI,EAAE,kBAAkB,CAAiB,CAAC;AAC7D,CAAC;AAED,MAAM,UAAU,mBAAmB,CACjC,IAAsB,EACtB,IAA6B;IAE7B,IAAI,MAAM,CAAC,EAAE,CAAC,IAAI,CAAC,KAAK,EAAE,IAAI,CAAC,EAAE,CAAC;QAChC,OAAO;IACT,CAAC;IAED,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC;IAElB,IAAI,IAAI,CAAC,MAAM,CAAC,WAAW,KAAK,IAAI,EAAE,CAAC;QACrC,iBAAiB,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QAC/B,uBAAuB,EAAE,CAAC;IAC5B,CAAC;AACH,CAAC","sourcesContent":["import {\n flushQueuedComputations,\n notifySubscribers,\n trackSource,\n type Source,\n} from \"@reckona/mreact-reactive-core/internal\";\nimport type { ReactiveDomBlockResult } from \"./element.js\";\n\n// A stable reactive box over a component's incoming props, analogous to the\n// native keyed list's KeyedItemCell (packages/reactive-dom/src/bind-list.ts).\n// A reactive-dom-block reads its props through a proxy backed by this cell;\n// when the component re-renders with new props the reconciler swaps the cell's\n// value and notifies, so bound text/attributes update without re-running the\n// block's render closure or reconciling its subtree.\nexport interface ReactivePropCell {\n value: Record<string, unknown>;\n source: Source;\n}\n\n// What a reactive-dom-block fiber stores in stateNode: the committed node and\n// its dispose, plus the prop cell when the block bridges component props.\nexport interface ReactiveDomBlockState extends ReactiveDomBlockResult {\n propCell?: ReactivePropCell | undefined;\n}\n\nexport function createReactivePropCell(props: Record<string, unknown>): ReactivePropCell {\n return { value: props, source: { subscribers: null } };\n}\n\nconst PROP_PROXY_HANDLER: ProxyHandler<ReactivePropCell> = {\n get(cell, property) {\n trackSource(cell.source);\n return cell.value[property as string];\n },\n has(cell, property) {\n trackSource(cell.source);\n return property in cell.value;\n },\n ownKeys(cell) {\n trackSource(cell.source);\n return Reflect.ownKeys(cell.value);\n },\n getOwnPropertyDescriptor(cell, property) {\n trackSource(cell.source);\n return Reflect.getOwnPropertyDescriptor(cell.value, property);\n },\n};\n\nexport function createReactivePropProxy<P extends object>(cell: ReactivePropCell): P {\n return new Proxy(cell, PROP_PROXY_HANDLER) as unknown as P;\n}\n\nexport function setReactivePropCell(\n cell: ReactivePropCell,\n next: Record<string, unknown>,\n): void {\n if (Object.is(cell.value, next)) {\n return;\n }\n\n cell.value = next;\n\n if (cell.source.subscribers !== null) {\n notifySubscribers(cell.source);\n flushQueuedComputations();\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"reactive-prop-cell.js","sourceRoot":"","sources":["../src/reactive-prop-cell.ts"],"names":[],"mappings":"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","sourcesContent":["import { batch } from \"@reckona/mreact-reactive-core\";\nimport {\n flushQueuedComputations,\n notifySubscribers,\n trackSource,\n type Source,\n} from \"@reckona/mreact-reactive-core/internal\";\nimport type { ReactiveDomBlockResult } from \"./element.js\";\n\n// A stable reactive box over a component's incoming props, analogous to the\n// native keyed list's KeyedItemCell (packages/reactive-dom/src/bind-list.ts).\n// A reactive-dom-block reads its props through a proxy backed by this cell;\n// when the component re-renders with new props the reconciler swaps the cell's\n// value and notifies, so bound text/attributes update without re-running the\n// block's render closure or reconciling its subtree.\nexport interface ReactivePropCell {\n value: Record<string, unknown>;\n source: Source;\n propertySources?: Map<PropertyKey, Source> | undefined;\n propertySnapshots?: Map<PropertyKey, ShallowObjectSnapshot> | undefined;\n}\n\n// What a reactive-dom-block fiber stores in stateNode: the committed node and\n// its dispose, plus the prop cell when the block bridges component props.\nexport interface ReactiveDomBlockState extends ReactiveDomBlockResult {\n propCell?: ReactivePropCell | undefined;\n}\n\nlet propCellBatchDepth = 0;\nlet propCellBatchNeedsFlush = false;\n\nexport function createReactivePropCell(props: Record<string, unknown>): ReactivePropCell {\n return { value: props, source: { subscribers: null } };\n}\n\nexport function batchReactivePropCellUpdates<T>(run: () => T): T {\n propCellBatchDepth += 1;\n try {\n return batch(run);\n } finally {\n propCellBatchDepth -= 1;\n if (propCellBatchDepth === 0 && propCellBatchNeedsFlush) {\n propCellBatchNeedsFlush = false;\n flushQueuedComputations();\n }\n }\n}\n\nconst PROP_PROXY_HANDLER: ProxyHandler<ReactivePropCell> = {\n get(cell, property) {\n trackSource(getReactivePropPropertySource(cell, property));\n const value = Reflect.get(cell.value, property);\n rememberReactivePropObjectSnapshot(cell, property, value);\n return value;\n },\n has(cell, property) {\n trackSource(getReactivePropPropertySource(cell, property));\n return property in cell.value;\n },\n ownKeys(cell) {\n trackSource(cell.source);\n return Reflect.ownKeys(cell.value);\n },\n getOwnPropertyDescriptor(cell, property) {\n trackSource(cell.source);\n return Reflect.getOwnPropertyDescriptor(cell.value, property);\n },\n};\n\nexport function createReactivePropProxy<P extends object>(cell: ReactivePropCell): P {\n return new Proxy(cell, PROP_PROXY_HANDLER) as unknown as P;\n}\n\nfunction getReactivePropPropertySource(cell: ReactivePropCell, property: PropertyKey): Source {\n let propertySources = cell.propertySources;\n\n if (propertySources === undefined) {\n propertySources = new Map();\n cell.propertySources = propertySources;\n }\n\n let source = propertySources.get(property);\n\n if (source === undefined) {\n source = { subscribers: null };\n propertySources.set(property, source);\n }\n\n return source;\n}\n\ninterface ShallowObjectSnapshot {\n value: object;\n entries: Map<PropertyKey, unknown>;\n}\n\nfunction rememberReactivePropObjectSnapshot(\n cell: ReactivePropCell,\n property: PropertyKey,\n value: unknown,\n): void {\n if (!isObjectLike(value)) {\n cell.propertySnapshots?.delete(property);\n return;\n }\n\n let snapshots = cell.propertySnapshots;\n if (snapshots === undefined) {\n snapshots = new Map();\n cell.propertySnapshots = snapshots;\n }\n\n snapshots.set(property, createShallowObjectSnapshot(value));\n}\n\nfunction createShallowObjectSnapshot(value: object): ShallowObjectSnapshot {\n const entries = new Map<PropertyKey, unknown>();\n for (const key of Reflect.ownKeys(value)) {\n const descriptor = Reflect.getOwnPropertyDescriptor(value, key);\n if (descriptor !== undefined && \"value\" in descriptor) {\n entries.set(key, descriptor.value);\n }\n }\n\n return { value, entries };\n}\n\nfunction isObjectLike(value: unknown): value is object {\n return (typeof value === \"object\" && value !== null) || typeof value === \"function\";\n}\n\nfunction hasShallowObjectSnapshotChanged(\n snapshot: ShallowObjectSnapshot | undefined,\n nextValue: unknown,\n): boolean {\n if (snapshot === undefined || snapshot.value !== nextValue || !isObjectLike(nextValue)) {\n return false;\n }\n\n for (const key of Reflect.ownKeys(nextValue)) {\n const descriptor = Reflect.getOwnPropertyDescriptor(nextValue, key);\n if (descriptor !== undefined && \"value\" in descriptor) {\n if (!snapshot.entries.has(key) || !Object.is(snapshot.entries.get(key), descriptor.value)) {\n return true;\n }\n }\n }\n\n for (const key of snapshot.entries.keys()) {\n const descriptor = Reflect.getOwnPropertyDescriptor(nextValue, key);\n if (descriptor === undefined || !(\"value\" in descriptor)) {\n return true;\n }\n }\n\n return false;\n}\n\nfunction shouldNotifyReactivePropProperty(\n previous: Record<string, unknown>,\n next: Record<string, unknown>,\n property: PropertyKey,\n snapshot: ShallowObjectSnapshot | undefined,\n): boolean {\n if ((property in previous) !== (property in next)) {\n return true;\n }\n\n const previousValue = Reflect.get(previous, property);\n const nextValue = Reflect.get(next, property);\n return !Object.is(previousValue, nextValue) ||\n hasShallowObjectSnapshotChanged(snapshot, nextValue);\n}\n\nexport function setReactivePropCell(\n cell: ReactivePropCell,\n next: Record<string, unknown>,\n): void {\n if (Object.is(cell.value, next)) {\n return;\n }\n\n const previous = cell.value;\n const propertySources = cell.propertySources;\n let notified = false;\n\n cell.value = next;\n\n if (propertySources !== undefined) {\n for (const [property, source] of propertySources) {\n if (\n shouldNotifyReactivePropProperty(\n previous,\n next,\n property,\n cell.propertySnapshots?.get(property),\n )\n ) {\n notifySubscribers(source);\n notified = true;\n }\n }\n }\n\n if (cell.source.subscribers !== null) {\n notifySubscribers(cell.source);\n notified = true;\n }\n\n if (notified) {\n if (propCellBatchDepth === 0) {\n flushQueuedComputations();\n } else {\n propCellBatchNeedsFlush = true;\n }\n }\n}\n"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@reckona/mreact-compat",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.176",
|
|
4
4
|
"description": "React-compatible runtime implementation for mreact.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"compatibility",
|
|
@@ -69,7 +69,7 @@
|
|
|
69
69
|
"access": "public"
|
|
70
70
|
},
|
|
71
71
|
"dependencies": {
|
|
72
|
-
"@reckona/mreact-
|
|
73
|
-
"@reckona/mreact-
|
|
72
|
+
"@reckona/mreact-shared": "0.0.176",
|
|
73
|
+
"@reckona/mreact-reactive-core": "0.0.176"
|
|
74
74
|
}
|
|
75
75
|
}
|
package/src/element.ts
CHANGED
|
@@ -211,6 +211,16 @@ export function createElementFromJsxConfig<P extends object>(
|
|
|
211
211
|
? String(keyArgument)
|
|
212
212
|
: config?.key === undefined ? null : String(config.key);
|
|
213
213
|
const ref = config?.ref ?? null;
|
|
214
|
+
if (canReuseJsxConfigAsComponentProps(normalizedType, config)) {
|
|
215
|
+
return {
|
|
216
|
+
$$typeof: REACT_COMPAT_ELEMENT_TYPE,
|
|
217
|
+
type: normalizedType as ElementType<P>,
|
|
218
|
+
key,
|
|
219
|
+
ref,
|
|
220
|
+
props: config as P & { children?: ReactCompatNode },
|
|
221
|
+
};
|
|
222
|
+
}
|
|
223
|
+
|
|
214
224
|
const hasChildren = config !== null && config !== undefined && hasOwnProperty.call(config, "children");
|
|
215
225
|
const children = config?.children;
|
|
216
226
|
const copiedProps = copyElementProps(config, undefined, true);
|
|
@@ -237,6 +247,34 @@ export function createElementFromJsxConfig<P extends object>(
|
|
|
237
247
|
};
|
|
238
248
|
}
|
|
239
249
|
|
|
250
|
+
function canReuseJsxConfigAsComponentProps(
|
|
251
|
+
type: unknown,
|
|
252
|
+
config: object | null | undefined,
|
|
253
|
+
): boolean {
|
|
254
|
+
if (
|
|
255
|
+
config === null ||
|
|
256
|
+
config === undefined ||
|
|
257
|
+
typeof type === "string" ||
|
|
258
|
+
hasDefaultProps(type)
|
|
259
|
+
) {
|
|
260
|
+
return false;
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
for (const name in config) {
|
|
264
|
+
if (
|
|
265
|
+
hasOwnProperty.call(config, name) &&
|
|
266
|
+
(name === "key" ||
|
|
267
|
+
name === "ref" ||
|
|
268
|
+
name === "__self" ||
|
|
269
|
+
name === "__source")
|
|
270
|
+
) {
|
|
271
|
+
return false;
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
return true;
|
|
276
|
+
}
|
|
277
|
+
|
|
240
278
|
/** Returns true when a value is a React-compatible element record. */
|
|
241
279
|
export function isReactCompatElement(
|
|
242
280
|
value: unknown,
|
|
@@ -287,6 +325,7 @@ export interface MemoType<P = Record<string, unknown>> {
|
|
|
287
325
|
$$typeof: typeof MEMO_TYPE;
|
|
288
326
|
type: ElementType<P>;
|
|
289
327
|
compare?: (previous: P, next: P) => boolean;
|
|
328
|
+
__mreactMemoCompareProps?: readonly string[];
|
|
290
329
|
}
|
|
291
330
|
|
|
292
331
|
/** Element type record produced by lazy. */
|
|
@@ -497,7 +536,7 @@ function applyDefaultProps(
|
|
|
497
536
|
type: unknown,
|
|
498
537
|
props: Record<string, unknown>,
|
|
499
538
|
): Record<string, unknown> {
|
|
500
|
-
if (
|
|
539
|
+
if (!canHaveDefaultProps(type)) {
|
|
501
540
|
return props;
|
|
502
541
|
}
|
|
503
542
|
|
|
@@ -517,6 +556,15 @@ function applyDefaultProps(
|
|
|
517
556
|
return props;
|
|
518
557
|
}
|
|
519
558
|
|
|
559
|
+
function hasDefaultProps(type: unknown): boolean {
|
|
560
|
+
return canHaveDefaultProps(type) &&
|
|
561
|
+
(type as { defaultProps?: Record<string, unknown> }).defaultProps !== undefined;
|
|
562
|
+
}
|
|
563
|
+
|
|
564
|
+
function canHaveDefaultProps(type: unknown): boolean {
|
|
565
|
+
return typeof type === "function" || (typeof type === "object" && type !== null);
|
|
566
|
+
}
|
|
567
|
+
|
|
520
568
|
interface ReactReservedProps {
|
|
521
569
|
key?: unknown;
|
|
522
570
|
ref?: unknown;
|