@mpxjs/webpack-plugin 2.9.66 → 2.9.69
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/lib/dependencies/RecordGlobalComponentsDependency.js +11 -12
- package/lib/dependencies/RecordRuntimeInfoDependency.js +1 -1
- package/lib/index.js +29 -8
- package/lib/json-compiler/index.js +2 -11
- package/lib/loader.js +24 -45
- package/lib/native-loader.js +49 -64
- package/lib/platform/json/wx/index.js +3 -10
- package/lib/platform/style/wx/index.js +15 -10
- package/lib/platform/template/wx/component-config/canvas.js +8 -0
- package/lib/platform/template/wx/component-config/unsupported.js +1 -1
- package/lib/react/index.js +4 -3
- package/lib/react/processJSON.js +5 -13
- package/lib/react/processMainScript.js +7 -3
- package/lib/react/processScript.js +3 -4
- package/lib/react/processStyles.js +14 -4
- package/lib/react/processTemplate.js +2 -2
- package/lib/resolver/AddModePlugin.js +20 -7
- package/lib/runtime/components/react/context.ts +2 -0
- package/lib/runtime/components/react/dist/context.js +1 -0
- package/lib/runtime/components/react/dist/getInnerListeners.js +3 -12
- package/lib/runtime/components/react/dist/mpx-button.jsx +44 -9
- package/lib/runtime/components/react/dist/mpx-canvas/Bus.js +60 -0
- package/lib/runtime/components/react/dist/mpx-canvas/CanvasGradient.js +15 -0
- package/lib/runtime/components/react/dist/mpx-canvas/CanvasRenderingContext2D.js +84 -0
- package/lib/runtime/components/react/dist/mpx-canvas/Image.js +87 -0
- package/lib/runtime/components/react/dist/mpx-canvas/ImageData.js +15 -0
- package/lib/runtime/components/react/dist/mpx-canvas/constructorsRegistry.js +28 -0
- package/lib/runtime/components/react/dist/mpx-canvas/html.js +343 -0
- package/lib/runtime/components/react/dist/mpx-canvas/index.jsx +214 -0
- package/lib/runtime/components/react/dist/mpx-canvas/utils.jsx +89 -0
- package/lib/runtime/components/react/dist/mpx-checkbox-group.jsx +30 -17
- package/lib/runtime/components/react/dist/mpx-checkbox.jsx +1 -1
- package/lib/runtime/components/react/dist/mpx-form.jsx +33 -24
- package/lib/runtime/components/react/dist/mpx-icon.jsx +1 -1
- package/lib/runtime/components/react/dist/mpx-image/index.jsx +1 -1
- package/lib/runtime/components/react/dist/mpx-input.jsx +44 -38
- package/lib/runtime/components/react/dist/mpx-label.jsx +10 -7
- package/lib/runtime/components/react/dist/mpx-movable-area.jsx +10 -17
- package/lib/runtime/components/react/dist/mpx-movable-view.jsx +378 -294
- package/lib/runtime/components/react/dist/mpx-navigator.jsx +1 -1
- package/lib/runtime/components/react/dist/mpx-picker-view-column.jsx +143 -84
- package/lib/runtime/components/react/dist/mpx-picker-view.jsx +69 -113
- package/lib/runtime/components/react/dist/mpx-radio-group.jsx +30 -17
- package/lib/runtime/components/react/dist/mpx-radio.jsx +1 -1
- package/lib/runtime/components/react/dist/mpx-root-portal.jsx +1 -1
- package/lib/runtime/components/react/dist/mpx-scroll-view.jsx +49 -29
- package/lib/runtime/components/react/dist/mpx-swiper/carouse.jsx +1 -1
- package/lib/runtime/components/react/dist/mpx-swiper/index.jsx +1 -1
- package/lib/runtime/components/react/dist/mpx-swiper-item.jsx +1 -1
- package/lib/runtime/components/react/dist/mpx-switch.jsx +8 -1
- package/lib/runtime/components/react/dist/mpx-text.jsx +1 -1
- package/lib/runtime/components/react/dist/mpx-textarea.jsx +1 -1
- package/lib/runtime/components/react/dist/mpx-view.jsx +46 -27
- package/lib/runtime/components/react/dist/mpx-web-view.jsx +20 -6
- package/lib/runtime/components/react/dist/pickerFaces.js +75 -0
- package/lib/runtime/components/react/dist/pickerOverlay.jsx +21 -0
- package/lib/runtime/components/react/dist/useAnimationHooks.js +96 -8
- package/lib/runtime/components/react/dist/utils.jsx +66 -6
- package/lib/runtime/components/react/getInnerListeners.ts +3 -16
- package/lib/runtime/components/react/mpx-button.tsx +42 -9
- package/lib/runtime/components/react/mpx-canvas/Bus.ts +70 -0
- package/lib/runtime/components/react/mpx-canvas/CanvasGradient.ts +18 -0
- package/lib/runtime/components/react/mpx-canvas/CanvasRenderingContext2D.ts +87 -0
- package/lib/runtime/components/react/mpx-canvas/Image.ts +102 -0
- package/lib/runtime/components/react/mpx-canvas/ImageData.ts +23 -0
- package/lib/runtime/components/react/mpx-canvas/constructorsRegistry.ts +38 -0
- package/lib/runtime/components/react/mpx-canvas/html.ts +343 -0
- package/lib/runtime/components/react/mpx-canvas/index.tsx +302 -0
- package/lib/runtime/components/react/mpx-canvas/utils.tsx +150 -0
- package/lib/runtime/components/react/mpx-checkbox-group.tsx +52 -29
- package/lib/runtime/components/react/mpx-checkbox.tsx +1 -1
- package/lib/runtime/components/react/mpx-form.tsx +42 -34
- package/lib/runtime/components/react/mpx-icon.tsx +1 -1
- package/lib/runtime/components/react/mpx-image/index.tsx +2 -3
- package/lib/runtime/components/react/mpx-input.tsx +68 -66
- package/lib/runtime/components/react/mpx-label.tsx +11 -8
- package/lib/runtime/components/react/mpx-movable-area.tsx +11 -19
- package/lib/runtime/components/react/mpx-movable-view.tsx +456 -334
- package/lib/runtime/components/react/mpx-navigator.tsx +1 -1
- package/lib/runtime/components/react/mpx-picker-view-column.tsx +232 -103
- package/lib/runtime/components/react/mpx-picker-view.tsx +126 -122
- package/lib/runtime/components/react/mpx-radio-group.tsx +55 -29
- package/lib/runtime/components/react/mpx-radio.tsx +1 -1
- package/lib/runtime/components/react/mpx-root-portal.tsx +1 -1
- package/lib/runtime/components/react/mpx-scroll-view.tsx +81 -36
- package/lib/runtime/components/react/mpx-swiper/carouse.tsx +2 -2
- package/lib/runtime/components/react/mpx-swiper/index.tsx +2 -1
- package/lib/runtime/components/react/mpx-swiper-item.tsx +1 -1
- package/lib/runtime/components/react/mpx-switch.tsx +10 -2
- package/lib/runtime/components/react/mpx-text.tsx +1 -1
- package/lib/runtime/components/react/mpx-textarea.tsx +1 -1
- package/lib/runtime/components/react/mpx-view.tsx +58 -28
- package/lib/runtime/components/react/mpx-web-view.tsx +23 -6
- package/lib/runtime/components/react/pickerFaces.ts +104 -0
- package/lib/runtime/components/react/pickerOverlay.tsx +32 -0
- package/lib/runtime/components/react/types/common.ts +2 -0
- package/lib/runtime/components/react/types/global.d.ts +2 -0
- package/lib/runtime/components/react/useAnimationHooks.ts +97 -13
- package/lib/runtime/components/react/useNodesRef.ts +1 -0
- package/lib/runtime/components/react/utils.tsx +94 -8
- package/lib/runtime/optionProcessorReact.js +0 -15
- package/lib/runtime/swanHelper.wxs +1 -1
- package/lib/style-compiler/index.js +1 -1
- package/lib/style-compiler/plugins/scope-id.js +1 -0
- package/lib/template-compiler/compiler.js +47 -16
- package/lib/template-compiler/gen-node-react.js +2 -2
- package/lib/template-compiler/index.js +4 -4
- package/lib/utils/pre-process-json.js +113 -0
- package/lib/web/index.js +5 -4
- package/lib/web/processJSON.js +5 -13
- package/lib/web/processTemplate.js +2 -2
- package/package.json +5 -4
|
@@ -0,0 +1,343 @@
|
|
|
1
|
+
export default `<html><head>
|
|
2
|
+
<meta content="width=device-width, initial-scale=1, maximum-scale=1, user-scaleable=no" name="viewport">
|
|
3
|
+
<style>
|
|
4
|
+
html {
|
|
5
|
+
-ms-content-zooming: none;
|
|
6
|
+
-ms-touch-action: pan-x pan-y;
|
|
7
|
+
}
|
|
8
|
+
body {
|
|
9
|
+
position: fixed;
|
|
10
|
+
top: 0;
|
|
11
|
+
right: 0;
|
|
12
|
+
bottom: 0;
|
|
13
|
+
left: 0;
|
|
14
|
+
margin: 0;
|
|
15
|
+
padding: 0;
|
|
16
|
+
overflow: hidden;
|
|
17
|
+
}
|
|
18
|
+
* {
|
|
19
|
+
user-select: none;
|
|
20
|
+
-ms-user-select: none;
|
|
21
|
+
-moz-user-select: none;
|
|
22
|
+
-webkit-user-select: none;
|
|
23
|
+
}
|
|
24
|
+
</style>
|
|
25
|
+
</head>
|
|
26
|
+
<body>
|
|
27
|
+
<script>
|
|
28
|
+
var scale = function (ratio) {
|
|
29
|
+
return function (item) {
|
|
30
|
+
if (typeof item === "number") {
|
|
31
|
+
return item * ratio;
|
|
32
|
+
}
|
|
33
|
+
return item;
|
|
34
|
+
};
|
|
35
|
+
};
|
|
36
|
+
function autoScaleCanvas(canvas) {
|
|
37
|
+
var ctx = canvas.getContext("2d");
|
|
38
|
+
var ratio = window.devicePixelRatio || 1;
|
|
39
|
+
if (ratio !== 1) {
|
|
40
|
+
canvas.width *= ratio;
|
|
41
|
+
canvas.height *= ratio;
|
|
42
|
+
ctx.scale(ratio, ratio);
|
|
43
|
+
ctx.isPointInPath = function () {
|
|
44
|
+
var args = [];
|
|
45
|
+
for (var _i = 0; _i < arguments.length; _i++) {
|
|
46
|
+
args[_i] = arguments[_i];
|
|
47
|
+
}
|
|
48
|
+
return CanvasRenderingContext2D.prototype.isPointInPath.apply(ctx, args.map(scale(ratio)));
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
return canvas;
|
|
52
|
+
}
|
|
53
|
+
window.autoScaleCanvas = autoScaleCanvas;
|
|
54
|
+
</script>
|
|
55
|
+
<script>
|
|
56
|
+
|
|
57
|
+
var WEBVIEW_TARGET = '@@WEBVIEW_TARGET';
|
|
58
|
+
|
|
59
|
+
var ID = function () {
|
|
60
|
+
return Math.random().toString(32).slice(2);
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
var flattenObjectCopyValue = function (flatObj, srcObj, key) {
|
|
64
|
+
var value = srcObj[key];
|
|
65
|
+
if (typeof value === 'function') {
|
|
66
|
+
return;
|
|
67
|
+
}
|
|
68
|
+
if (typeof value === 'object' && value instanceof Node) {
|
|
69
|
+
return;
|
|
70
|
+
}
|
|
71
|
+
flatObj[key] = flattenObject(value);
|
|
72
|
+
};
|
|
73
|
+
|
|
74
|
+
var flattenObject = function (object) {
|
|
75
|
+
if (typeof object !== 'object' || object === null) {
|
|
76
|
+
return object;
|
|
77
|
+
}
|
|
78
|
+
// Handle TypedArray
|
|
79
|
+
if (object instanceof Uint8ClampedArray) {
|
|
80
|
+
return Array.from(object);
|
|
81
|
+
}
|
|
82
|
+
var flatObject = {};
|
|
83
|
+
for (var key in object) {
|
|
84
|
+
flattenObjectCopyValue(flatObject, object, key);
|
|
85
|
+
}
|
|
86
|
+
for (var key in Object.getOwnPropertyNames(object)) {
|
|
87
|
+
flattenObjectCopyValue(flatObject, object, key);
|
|
88
|
+
}
|
|
89
|
+
return flatObject;
|
|
90
|
+
};
|
|
91
|
+
|
|
92
|
+
var AutoScaledCanvas = function (element) {
|
|
93
|
+
this.element = element;
|
|
94
|
+
};
|
|
95
|
+
|
|
96
|
+
AutoScaledCanvas.prototype.toDataURL = function () {
|
|
97
|
+
return this.element.toDataURL.apply(this.element, arguments);
|
|
98
|
+
};
|
|
99
|
+
|
|
100
|
+
AutoScaledCanvas.prototype.autoScale = function () {
|
|
101
|
+
if (this.savedHeight !== undefined) {
|
|
102
|
+
this.element.height = this.savedHeight;
|
|
103
|
+
}
|
|
104
|
+
if (this.savedWidth !== undefined) {
|
|
105
|
+
this.element.width = this.savedWidth;
|
|
106
|
+
}
|
|
107
|
+
window.autoScaleCanvas(this.element);
|
|
108
|
+
};
|
|
109
|
+
|
|
110
|
+
Object.defineProperty(AutoScaledCanvas.prototype, 'width', {
|
|
111
|
+
get: function () {
|
|
112
|
+
return this.element.width;
|
|
113
|
+
},
|
|
114
|
+
set: function (value) {
|
|
115
|
+
this.savedWidth = value;
|
|
116
|
+
this.autoScale();
|
|
117
|
+
return value;
|
|
118
|
+
},
|
|
119
|
+
});
|
|
120
|
+
|
|
121
|
+
Object.defineProperty(AutoScaledCanvas.prototype, 'height', {
|
|
122
|
+
get: function () {
|
|
123
|
+
return this.element.height;
|
|
124
|
+
},
|
|
125
|
+
set: function (value) {
|
|
126
|
+
this.savedHeight = value;
|
|
127
|
+
this.autoScale();
|
|
128
|
+
return value;
|
|
129
|
+
},
|
|
130
|
+
});
|
|
131
|
+
var toMessage = function (result) {
|
|
132
|
+
if (result instanceof Blob) {
|
|
133
|
+
return {
|
|
134
|
+
type: 'blob',
|
|
135
|
+
payload: btoa(result),
|
|
136
|
+
meta: {},
|
|
137
|
+
};
|
|
138
|
+
}
|
|
139
|
+
if (result instanceof Object) {
|
|
140
|
+
if (!result[WEBVIEW_TARGET]) {
|
|
141
|
+
var id = ID();
|
|
142
|
+
result[WEBVIEW_TARGET] = id;
|
|
143
|
+
targets[id] = result;
|
|
144
|
+
}
|
|
145
|
+
return {
|
|
146
|
+
type: 'json',
|
|
147
|
+
payload: flattenObject(result),
|
|
148
|
+
args: toArgs(flattenObject(result)),
|
|
149
|
+
meta: {
|
|
150
|
+
target: result[WEBVIEW_TARGET],
|
|
151
|
+
constructor: result.__constructorName__ || result.constructor.name,
|
|
152
|
+
},
|
|
153
|
+
};
|
|
154
|
+
}
|
|
155
|
+
return {
|
|
156
|
+
type: 'json',
|
|
157
|
+
payload: typeof result === 'string' ? result : JSON.stringify(result),
|
|
158
|
+
meta: {},
|
|
159
|
+
};
|
|
160
|
+
};
|
|
161
|
+
var toArgs = function (result) {
|
|
162
|
+
var args = [];
|
|
163
|
+
for (var key in result) {
|
|
164
|
+
if (result[key] !== undefined && key !== '@@WEBVIEW_TARGET') {
|
|
165
|
+
args.push(result[key]);
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
return args;
|
|
169
|
+
};
|
|
170
|
+
|
|
171
|
+
var createObjectsFromArgs = function (args) {
|
|
172
|
+
for (var index = 0; index < args.length; index += 1) {
|
|
173
|
+
var currentArg = args[index];
|
|
174
|
+
if (currentArg && currentArg.className !== undefined) {
|
|
175
|
+
var className = currentArg.className, classArgs = currentArg.classArgs;
|
|
176
|
+
// new ImageData,第一个参数需要是 Uint8ClampedArray
|
|
177
|
+
var object = new (Function.prototype.bind.apply(constructors[className], [null].concat(classArgs)))();
|
|
178
|
+
args[index] = object;
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
return args;
|
|
182
|
+
};
|
|
183
|
+
|
|
184
|
+
var canvas = document.createElement('canvas');
|
|
185
|
+
canvas.style.width = '100%';
|
|
186
|
+
canvas.style.height = '100%';
|
|
187
|
+
var autoScaledCanvas = new AutoScaledCanvas(canvas);
|
|
188
|
+
|
|
189
|
+
var targets = {
|
|
190
|
+
canvas: autoScaledCanvas,
|
|
191
|
+
context2D: canvas.getContext('2d'),
|
|
192
|
+
};
|
|
193
|
+
|
|
194
|
+
var constructors = {
|
|
195
|
+
CanvasGradient: CanvasGradient,
|
|
196
|
+
Image: Image,
|
|
197
|
+
ImageData: ImageData,
|
|
198
|
+
Uint8ClampedArray: Uint8ClampedArray,
|
|
199
|
+
};
|
|
200
|
+
|
|
201
|
+
Image.bind =
|
|
202
|
+
Image.bind ||
|
|
203
|
+
function () {
|
|
204
|
+
return Image;
|
|
205
|
+
};
|
|
206
|
+
|
|
207
|
+
ImageData.bind =
|
|
208
|
+
ImageData.bind ||
|
|
209
|
+
function () {
|
|
210
|
+
return ImageData;
|
|
211
|
+
};
|
|
212
|
+
Uint8ClampedArray.bind =
|
|
213
|
+
Uint8ClampedArray.bind ||
|
|
214
|
+
function () {
|
|
215
|
+
return Uint8ClampedArray;
|
|
216
|
+
};
|
|
217
|
+
|
|
218
|
+
var populateRefs = function (arg) {
|
|
219
|
+
if (arg && arg.__ref__) {
|
|
220
|
+
return targets[arg.__ref__];
|
|
221
|
+
}
|
|
222
|
+
return arg;
|
|
223
|
+
};
|
|
224
|
+
document.body.appendChild(canvas);
|
|
225
|
+
|
|
226
|
+
var mergeObjects = function (target, source) {
|
|
227
|
+
for (var key in source) {
|
|
228
|
+
if (source.hasOwnProperty(key)) {
|
|
229
|
+
target[key] = source[key];
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
return target;
|
|
233
|
+
};
|
|
234
|
+
|
|
235
|
+
function handleMessage(message) {
|
|
236
|
+
var id = message.id,
|
|
237
|
+
type = message.type,
|
|
238
|
+
payload = message.payload;
|
|
239
|
+
|
|
240
|
+
switch (type) {
|
|
241
|
+
case 'exec': {
|
|
242
|
+
var target = payload.target,
|
|
243
|
+
method = payload.method,
|
|
244
|
+
args = payload.args;
|
|
245
|
+
var result = targets[target][method].apply(targets[target], args.map(populateRefs));
|
|
246
|
+
var msg = toMessage(result);
|
|
247
|
+
|
|
248
|
+
if (typeof result === 'object' && !msg.meta.constructor) {
|
|
249
|
+
for (var constructorName in constructors) {
|
|
250
|
+
if (result instanceof constructors[constructorName]) {
|
|
251
|
+
msg.meta.constructor = constructorName;
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
window.ReactNativeWebView.postMessage(JSON.stringify(mergeObjects({ id: id }, msg)));
|
|
256
|
+
break;
|
|
257
|
+
}
|
|
258
|
+
case 'set': {
|
|
259
|
+
var target = payload.target,
|
|
260
|
+
key = payload.key,
|
|
261
|
+
value = payload.value;
|
|
262
|
+
targets[target][key] = populateRefs(value);
|
|
263
|
+
break;
|
|
264
|
+
}
|
|
265
|
+
case 'construct': {
|
|
266
|
+
var constructor = payload.constructor,
|
|
267
|
+
target = payload.id,
|
|
268
|
+
args = payload.args || [];
|
|
269
|
+
var newArgs = createObjectsFromArgs(args);
|
|
270
|
+
var object;
|
|
271
|
+
try {
|
|
272
|
+
object = new (Function.prototype.bind.apply(constructors[constructor], [null].concat(newArgs)))();
|
|
273
|
+
}
|
|
274
|
+
catch (error) {
|
|
275
|
+
throw new Error('Error while constructing '.concat(constructor, ' ').concat(error.message));
|
|
276
|
+
}
|
|
277
|
+
object.__constructorName__ = constructor;
|
|
278
|
+
var msg = toMessage({});
|
|
279
|
+
targets[target] = object;
|
|
280
|
+
window.ReactNativeWebView.postMessage(JSON.stringify(mergeObjects({ id: id }, msg)));
|
|
281
|
+
break;
|
|
282
|
+
}
|
|
283
|
+
case 'listen': {
|
|
284
|
+
var types = payload.types,
|
|
285
|
+
target = payload.target;
|
|
286
|
+
for (var i = 0; i < types.length; i++) {
|
|
287
|
+
var eventType = types[i];
|
|
288
|
+
targets[target].addEventListener(eventType, function (e) {
|
|
289
|
+
const message = toMessage({
|
|
290
|
+
type: 'event',
|
|
291
|
+
payload: {
|
|
292
|
+
type: e.type,
|
|
293
|
+
target: mergeObjects(flattenObject(targets[target]), {
|
|
294
|
+
[WEBVIEW_TARGET]: target,
|
|
295
|
+
}),
|
|
296
|
+
},
|
|
297
|
+
});
|
|
298
|
+
window.ReactNativeWebView.postMessage(
|
|
299
|
+
JSON.stringify(mergeObjects({ id: id }, message))
|
|
300
|
+
);
|
|
301
|
+
});
|
|
302
|
+
}
|
|
303
|
+
break;
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
var handleError = function (err, message) {
|
|
308
|
+
window.ReactNativeWebView.postMessage(JSON.stringify({
|
|
309
|
+
id: message.id,
|
|
310
|
+
type: 'error',
|
|
311
|
+
payload: {
|
|
312
|
+
message: err.message,
|
|
313
|
+
stack: err.stack,
|
|
314
|
+
},
|
|
315
|
+
}));
|
|
316
|
+
document.removeEventListener('message', handleIncomingMessage);
|
|
317
|
+
};
|
|
318
|
+
|
|
319
|
+
function handleIncomingMessage(e) {
|
|
320
|
+
var data = JSON.parse(e.data);
|
|
321
|
+
if (Array.isArray(data)) {
|
|
322
|
+
for (var i = 0; i < data.length; i++) {
|
|
323
|
+
try {
|
|
324
|
+
handleMessage(data[i]);
|
|
325
|
+
} catch (err) {
|
|
326
|
+
handleError(err, data[i]);
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
} else {
|
|
330
|
+
try {
|
|
331
|
+
handleMessage(data);
|
|
332
|
+
} catch (err) {
|
|
333
|
+
handleError(err, data);
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
window.addEventListener('message', handleIncomingMessage);
|
|
339
|
+
document.addEventListener('message', handleIncomingMessage);
|
|
340
|
+
</script>
|
|
341
|
+
|
|
342
|
+
|
|
343
|
+
</body></html>`;
|
|
@@ -0,0 +1,214 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ✘ type
|
|
3
|
+
* ✘ canvas-id
|
|
4
|
+
* ✘ disable-scroll
|
|
5
|
+
* ✔ bindtouchstart
|
|
6
|
+
* ✔ bindtouchmove
|
|
7
|
+
* ✔ bindtouchend
|
|
8
|
+
* ✔ bindtouchcancel
|
|
9
|
+
* ✔ bindlongtap
|
|
10
|
+
* ✔ binderror
|
|
11
|
+
*/
|
|
12
|
+
import React, { useRef, useState, useCallback, useEffect, forwardRef } from 'react';
|
|
13
|
+
import { View, Platform, StyleSheet } from 'react-native';
|
|
14
|
+
import { WebView } from 'react-native-webview';
|
|
15
|
+
import useNodesRef from '../useNodesRef';
|
|
16
|
+
import { useLayout, useTransformStyle, extendObject } from '../utils';
|
|
17
|
+
import useInnerProps, { getCustomEvent } from '../getInnerListeners';
|
|
18
|
+
import Bus from './Bus';
|
|
19
|
+
import { useWebviewBinding, constructors, WEBVIEW_TARGET, ID, registerWebviewConstructor } from './utils';
|
|
20
|
+
import CanvasRenderingContext2D from './CanvasRenderingContext2D';
|
|
21
|
+
import html from './html';
|
|
22
|
+
import './CanvasGradient';
|
|
23
|
+
import { createImage as canvasCreateImage } from './Image';
|
|
24
|
+
import { createImageData as canvasCreateImageData } from './ImageData';
|
|
25
|
+
import { useConstructorsRegistry } from './constructorsRegistry';
|
|
26
|
+
const stylesheet = StyleSheet.create({
|
|
27
|
+
container: { overflow: 'hidden', flex: 0 },
|
|
28
|
+
webview: {
|
|
29
|
+
overflow: 'hidden',
|
|
30
|
+
backgroundColor: 'transparent',
|
|
31
|
+
flex: 0
|
|
32
|
+
},
|
|
33
|
+
webviewAndroid9: {
|
|
34
|
+
overflow: 'hidden',
|
|
35
|
+
backgroundColor: 'transparent',
|
|
36
|
+
flex: 0,
|
|
37
|
+
opacity: 0.99
|
|
38
|
+
}
|
|
39
|
+
});
|
|
40
|
+
const _Canvas = forwardRef((props = {}, ref) => {
|
|
41
|
+
const { style = {}, originWhitelist = ['*'], 'enable-var': enableVar, 'external-var-context': externalVarContext, 'parent-font-size': parentFontSize, 'parent-width': parentWidth, 'parent-height': parentHeight } = props;
|
|
42
|
+
const [isLoaded, setIsLoaded] = useState(false);
|
|
43
|
+
const nodeRef = useRef(null);
|
|
44
|
+
const { normalStyle, hasSelfPercent, setWidth, setHeight } = useTransformStyle(extendObject(style, stylesheet.container), {
|
|
45
|
+
enableVar,
|
|
46
|
+
externalVarContext,
|
|
47
|
+
parentFontSize,
|
|
48
|
+
parentWidth,
|
|
49
|
+
parentHeight
|
|
50
|
+
});
|
|
51
|
+
const { width, height } = normalStyle;
|
|
52
|
+
const canvasRef = useWebviewBinding({
|
|
53
|
+
targetName: 'canvas',
|
|
54
|
+
properties: { width, height },
|
|
55
|
+
methods: ['toDataURL']
|
|
56
|
+
});
|
|
57
|
+
const { register } = useConstructorsRegistry();
|
|
58
|
+
const { layoutRef, layoutStyle, layoutProps } = useLayout({ props, hasSelfPercent, setWidth, setHeight, nodeRef });
|
|
59
|
+
const innerProps = useInnerProps(props, {
|
|
60
|
+
ref: nodeRef,
|
|
61
|
+
style: extendObject(normalStyle, layoutStyle, { opacity: isLoaded ? 1 : 0 }),
|
|
62
|
+
...layoutProps
|
|
63
|
+
}, [], {
|
|
64
|
+
layoutRef
|
|
65
|
+
});
|
|
66
|
+
const context2D = new CanvasRenderingContext2D(canvasRef.current);
|
|
67
|
+
register(registerWebviewConstructor);
|
|
68
|
+
// 初始化bus和context2D
|
|
69
|
+
useEffect(() => {
|
|
70
|
+
const webviewPostMessage = (message) => {
|
|
71
|
+
if (canvasRef.current.webview) {
|
|
72
|
+
canvasRef.current.webview.postMessage(JSON.stringify(message));
|
|
73
|
+
}
|
|
74
|
+
};
|
|
75
|
+
// 设置bus
|
|
76
|
+
canvasRef.current.bus = new Bus(webviewPostMessage);
|
|
77
|
+
canvasRef.current.bus.pause();
|
|
78
|
+
// 设置 context 2D
|
|
79
|
+
canvasRef.current.context2D = context2D;
|
|
80
|
+
// 设置 getContext 方法
|
|
81
|
+
canvasRef.current.getContext = getContext;
|
|
82
|
+
// 设置 createImage 方法
|
|
83
|
+
canvasRef.current.createImage = createImage;
|
|
84
|
+
// 设置 postMessage 方法
|
|
85
|
+
canvasRef.current.postMessage = postMessage;
|
|
86
|
+
// 设置 listeners
|
|
87
|
+
canvasRef.current.listeners = [];
|
|
88
|
+
canvasRef.current.addMessageListener = addMessageListener;
|
|
89
|
+
canvasRef.current.removeMessageListener = removeMessageListener;
|
|
90
|
+
canvasRef.current.createImageData = createImageData;
|
|
91
|
+
return () => {
|
|
92
|
+
canvasRef.current.bus?.clearBatchingTimeout();
|
|
93
|
+
};
|
|
94
|
+
}, []);
|
|
95
|
+
const createImageData = (dataArray, width, height) => {
|
|
96
|
+
return canvasCreateImageData(canvasRef.current, dataArray, width, height);
|
|
97
|
+
};
|
|
98
|
+
const createImage = (width, height) => {
|
|
99
|
+
return canvasCreateImage(canvasRef.current, width, height);
|
|
100
|
+
};
|
|
101
|
+
const getContext = useCallback((contextType) => {
|
|
102
|
+
if (contextType === '2d') {
|
|
103
|
+
return context2D;
|
|
104
|
+
}
|
|
105
|
+
return null;
|
|
106
|
+
}, []);
|
|
107
|
+
const postMessage = useCallback(async (message) => {
|
|
108
|
+
if (!canvasRef.current?.bus)
|
|
109
|
+
return;
|
|
110
|
+
const { type, payload } = await canvasRef.current.bus.post({
|
|
111
|
+
id: ID(),
|
|
112
|
+
...message
|
|
113
|
+
});
|
|
114
|
+
switch (type) {
|
|
115
|
+
case 'error': {
|
|
116
|
+
const { binderror } = props;
|
|
117
|
+
binderror &&
|
|
118
|
+
binderror(getCustomEvent('error', {}, {
|
|
119
|
+
detail: {
|
|
120
|
+
errMsg: payload.message
|
|
121
|
+
},
|
|
122
|
+
layoutRef
|
|
123
|
+
}, props));
|
|
124
|
+
break;
|
|
125
|
+
}
|
|
126
|
+
case 'json': {
|
|
127
|
+
return payload;
|
|
128
|
+
}
|
|
129
|
+
case 'blob': {
|
|
130
|
+
return atob(payload);
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
}, []);
|
|
134
|
+
const addMessageListener = (listener) => {
|
|
135
|
+
canvasRef.current.listeners.push(listener);
|
|
136
|
+
return () => canvasRef.current.removeMessageListener(listener);
|
|
137
|
+
};
|
|
138
|
+
const removeMessageListener = (listener) => {
|
|
139
|
+
canvasRef.current.listeners.splice(canvasRef.current.listeners.indexOf(listener), 1);
|
|
140
|
+
};
|
|
141
|
+
const onMessage = useCallback((e) => {
|
|
142
|
+
let data = JSON.parse(e.nativeEvent.data);
|
|
143
|
+
switch (data.type) {
|
|
144
|
+
case 'error': {
|
|
145
|
+
const { binderror } = props;
|
|
146
|
+
binderror &&
|
|
147
|
+
binderror(getCustomEvent('error', e, {
|
|
148
|
+
detail: {
|
|
149
|
+
errMsg: data.payload.message
|
|
150
|
+
},
|
|
151
|
+
layoutRef
|
|
152
|
+
}, props));
|
|
153
|
+
break;
|
|
154
|
+
}
|
|
155
|
+
default: {
|
|
156
|
+
if (data.payload) {
|
|
157
|
+
// createLinearGradient 方法调用需要在 constructors 中需要注册 CanvasGradient
|
|
158
|
+
const constructor = constructors[data.meta.constructor];
|
|
159
|
+
if (constructor) {
|
|
160
|
+
const { args, payload } = data;
|
|
161
|
+
// RN 端同步生成一个 CanvasGradient 的实例
|
|
162
|
+
const object = constructor.constructLocally(canvasRef.current, ...args);
|
|
163
|
+
Object.assign(object, payload, {
|
|
164
|
+
[WEBVIEW_TARGET]: data.meta.target
|
|
165
|
+
});
|
|
166
|
+
data = {
|
|
167
|
+
...data,
|
|
168
|
+
payload: object
|
|
169
|
+
};
|
|
170
|
+
}
|
|
171
|
+
for (const listener of canvasRef.current.listeners) {
|
|
172
|
+
listener(data.payload);
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
if (canvasRef.current.bus) {
|
|
176
|
+
canvasRef.current.bus.handle(data);
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
}, []);
|
|
181
|
+
const onLoad = useCallback(() => {
|
|
182
|
+
setIsLoaded(true);
|
|
183
|
+
if (canvasRef.current?.bus) {
|
|
184
|
+
canvasRef.current.bus.resume();
|
|
185
|
+
}
|
|
186
|
+
}, []);
|
|
187
|
+
useNodesRef(props, ref, nodeRef, {
|
|
188
|
+
style: normalStyle,
|
|
189
|
+
node: canvasRef.current,
|
|
190
|
+
context: context2D
|
|
191
|
+
});
|
|
192
|
+
if (Platform.OS === 'android') {
|
|
193
|
+
const isAndroid9 = Platform.Version >= 28;
|
|
194
|
+
return (<View {...innerProps}>
|
|
195
|
+
<WebView ref={(element) => {
|
|
196
|
+
if (canvasRef.current) {
|
|
197
|
+
canvasRef.current.webview = element;
|
|
198
|
+
}
|
|
199
|
+
}} style={[
|
|
200
|
+
isAndroid9 ? stylesheet.webviewAndroid9 : stylesheet.webview,
|
|
201
|
+
{ height, width }
|
|
202
|
+
]} source={{ html }} originWhitelist={originWhitelist} onMessage={onMessage} onLoad={onLoad} overScrollMode="never" mixedContentMode="always" scalesPageToFit={false} javaScriptEnabled domStorageEnabled thirdPartyCookiesEnabled allowUniversalAccessFromFileURLs/>
|
|
203
|
+
</View>);
|
|
204
|
+
}
|
|
205
|
+
return (<View {...innerProps}>
|
|
206
|
+
<WebView ref={(element) => {
|
|
207
|
+
if (canvasRef.current) {
|
|
208
|
+
canvasRef.current.webview = element;
|
|
209
|
+
}
|
|
210
|
+
}} style={[stylesheet.webview, { height, width }]} source={{ html }} originWhitelist={originWhitelist} onMessage={onMessage} onLoad={onLoad} scrollEnabled={false}/>
|
|
211
|
+
</View>);
|
|
212
|
+
});
|
|
213
|
+
_Canvas.displayName = 'mpxCanvas';
|
|
214
|
+
export default _Canvas;
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import { useEffect, useRef } from 'react';
|
|
2
|
+
export const WEBVIEW_TARGET = '@@WEBVIEW_TARGET';
|
|
3
|
+
export const constructors = {};
|
|
4
|
+
export const ID = () => Math.random().toString(32).slice(2);
|
|
5
|
+
const SPECIAL_CONSTRUCTOR = {
|
|
6
|
+
ImageData: {
|
|
7
|
+
className: 'Uint8ClampedArray',
|
|
8
|
+
paramNum: 0
|
|
9
|
+
}
|
|
10
|
+
};
|
|
11
|
+
export const registerWebviewTarget = (instance, targetName) => {
|
|
12
|
+
instance[WEBVIEW_TARGET] = targetName;
|
|
13
|
+
};
|
|
14
|
+
export const registerWebviewProperties = (instance, properties) => {
|
|
15
|
+
Object.entries(properties).forEach(([key, initialValue]) => {
|
|
16
|
+
const privateKey = `__${key}__`;
|
|
17
|
+
instance[privateKey] = initialValue;
|
|
18
|
+
Object.defineProperty(instance, key, {
|
|
19
|
+
configurable: true,
|
|
20
|
+
enumerable: true,
|
|
21
|
+
get() {
|
|
22
|
+
return instance[privateKey];
|
|
23
|
+
},
|
|
24
|
+
set(value) {
|
|
25
|
+
instance.postMessage({
|
|
26
|
+
type: 'set',
|
|
27
|
+
payload: {
|
|
28
|
+
target: instance[WEBVIEW_TARGET],
|
|
29
|
+
key,
|
|
30
|
+
value
|
|
31
|
+
}
|
|
32
|
+
});
|
|
33
|
+
if (instance.forceUpdate) {
|
|
34
|
+
instance.forceUpdate();
|
|
35
|
+
}
|
|
36
|
+
return (instance[privateKey] = value);
|
|
37
|
+
}
|
|
38
|
+
});
|
|
39
|
+
});
|
|
40
|
+
};
|
|
41
|
+
export const registerWebviewMethods = (instance, methods) => {
|
|
42
|
+
methods.forEach(method => {
|
|
43
|
+
instance[method] = (...args) => {
|
|
44
|
+
return instance.postMessage({
|
|
45
|
+
type: 'exec',
|
|
46
|
+
payload: {
|
|
47
|
+
target: instance[WEBVIEW_TARGET],
|
|
48
|
+
method,
|
|
49
|
+
args
|
|
50
|
+
}
|
|
51
|
+
});
|
|
52
|
+
};
|
|
53
|
+
});
|
|
54
|
+
};
|
|
55
|
+
export const registerWebviewConstructor = (constructor, constructorName) => {
|
|
56
|
+
constructors[constructorName] = constructor;
|
|
57
|
+
constructor.constructLocally = function (...args) {
|
|
58
|
+
return new constructor(...args, true);
|
|
59
|
+
};
|
|
60
|
+
constructor.prototype.onConstruction = function (...args) {
|
|
61
|
+
if (SPECIAL_CONSTRUCTOR[constructorName] !== undefined) {
|
|
62
|
+
const { className, paramNum } = SPECIAL_CONSTRUCTOR[constructorName];
|
|
63
|
+
args[paramNum] = { className, classArgs: [args[paramNum]] };
|
|
64
|
+
}
|
|
65
|
+
this[WEBVIEW_TARGET] = ID();
|
|
66
|
+
this.postMessage({
|
|
67
|
+
type: 'construct',
|
|
68
|
+
payload: {
|
|
69
|
+
constructor: constructorName,
|
|
70
|
+
id: this[WEBVIEW_TARGET],
|
|
71
|
+
args
|
|
72
|
+
}
|
|
73
|
+
});
|
|
74
|
+
};
|
|
75
|
+
constructor.prototype.toJSON = function () {
|
|
76
|
+
return { __ref__: this[WEBVIEW_TARGET] };
|
|
77
|
+
};
|
|
78
|
+
};
|
|
79
|
+
export const useWebviewBinding = ({ targetName, properties = {}, methods = [] }) => {
|
|
80
|
+
const instanceRef = useRef({});
|
|
81
|
+
useEffect(() => {
|
|
82
|
+
if (instanceRef.current) {
|
|
83
|
+
registerWebviewTarget(instanceRef.current, targetName);
|
|
84
|
+
registerWebviewProperties(instanceRef.current, properties);
|
|
85
|
+
registerWebviewMethods(instanceRef.current, methods);
|
|
86
|
+
}
|
|
87
|
+
}, []);
|
|
88
|
+
return instanceRef;
|
|
89
|
+
};
|