@mpxjs/webpack-plugin 2.9.67 → 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.
Files changed (48) hide show
  1. package/lib/index.js +13 -8
  2. package/lib/platform/template/wx/component-config/canvas.js +8 -0
  3. package/lib/platform/template/wx/component-config/unsupported.js +1 -1
  4. package/lib/react/processStyles.js +14 -4
  5. package/lib/resolver/AddModePlugin.js +8 -8
  6. package/lib/runtime/components/react/context.ts +2 -0
  7. package/lib/runtime/components/react/dist/context.js +1 -0
  8. package/lib/runtime/components/react/dist/getInnerListeners.js +3 -12
  9. package/lib/runtime/components/react/dist/mpx-button.jsx +43 -8
  10. package/lib/runtime/components/react/dist/mpx-canvas/Bus.js +60 -0
  11. package/lib/runtime/components/react/dist/mpx-canvas/CanvasGradient.js +15 -0
  12. package/lib/runtime/components/react/dist/mpx-canvas/CanvasRenderingContext2D.js +84 -0
  13. package/lib/runtime/components/react/dist/mpx-canvas/Image.js +87 -0
  14. package/lib/runtime/components/react/dist/mpx-canvas/ImageData.js +15 -0
  15. package/lib/runtime/components/react/dist/mpx-canvas/constructorsRegistry.js +28 -0
  16. package/lib/runtime/components/react/dist/mpx-canvas/html.js +343 -0
  17. package/lib/runtime/components/react/dist/mpx-canvas/index.jsx +214 -0
  18. package/lib/runtime/components/react/dist/mpx-canvas/utils.jsx +89 -0
  19. package/lib/runtime/components/react/dist/mpx-picker-view-column.jsx +143 -84
  20. package/lib/runtime/components/react/dist/mpx-picker-view.jsx +69 -113
  21. package/lib/runtime/components/react/dist/mpx-view.jsx +45 -26
  22. package/lib/runtime/components/react/dist/mpx-web-view.jsx +19 -5
  23. package/lib/runtime/components/react/dist/pickerFaces.js +75 -0
  24. package/lib/runtime/components/react/dist/pickerOverlay.jsx +21 -0
  25. package/lib/runtime/components/react/dist/utils.jsx +54 -3
  26. package/lib/runtime/components/react/getInnerListeners.ts +3 -17
  27. package/lib/runtime/components/react/mpx-button.tsx +41 -8
  28. package/lib/runtime/components/react/mpx-canvas/Bus.ts +70 -0
  29. package/lib/runtime/components/react/mpx-canvas/CanvasGradient.ts +18 -0
  30. package/lib/runtime/components/react/mpx-canvas/CanvasRenderingContext2D.ts +87 -0
  31. package/lib/runtime/components/react/mpx-canvas/Image.ts +102 -0
  32. package/lib/runtime/components/react/mpx-canvas/ImageData.ts +23 -0
  33. package/lib/runtime/components/react/mpx-canvas/constructorsRegistry.ts +38 -0
  34. package/lib/runtime/components/react/mpx-canvas/html.ts +343 -0
  35. package/lib/runtime/components/react/mpx-canvas/index.tsx +302 -0
  36. package/lib/runtime/components/react/mpx-canvas/utils.tsx +150 -0
  37. package/lib/runtime/components/react/mpx-picker-view-column.tsx +232 -103
  38. package/lib/runtime/components/react/mpx-picker-view.tsx +126 -122
  39. package/lib/runtime/components/react/mpx-view.tsx +57 -27
  40. package/lib/runtime/components/react/mpx-web-view.tsx +22 -5
  41. package/lib/runtime/components/react/pickerFaces.ts +104 -0
  42. package/lib/runtime/components/react/pickerOverlay.tsx +32 -0
  43. package/lib/runtime/components/react/types/common.ts +2 -0
  44. package/lib/runtime/components/react/types/global.d.ts +2 -0
  45. package/lib/runtime/components/react/utils.tsx +78 -7
  46. package/lib/template-compiler/compiler.js +3 -2
  47. package/lib/template-compiler/gen-node-react.js +2 -2
  48. package/package.json +5 -4
@@ -1,15 +1,19 @@
1
- import { forwardRef, useEffect, useRef } from 'react';
1
+ import { forwardRef, useEffect, useRef, useContext, useMemo } from 'react';
2
2
  import { noop, warn } from '@mpxjs/utils';
3
3
  import { Portal } from '@ant-design/react-native';
4
4
  import { getCustomEvent } from './getInnerListeners';
5
5
  import { promisify, redirectTo, navigateTo, navigateBack, reLaunch, switchTab } from '@mpxjs/api-proxy';
6
6
  import { WebView } from 'react-native-webview';
7
7
  import useNodesRef from './useNodesRef';
8
+ import { getCurrentPage } from './utils';
9
+ import { RouteContext } from './context';
8
10
  const _WebView = forwardRef((props, ref) => {
9
11
  const { src = '', bindmessage = noop, bindload = noop, binderror = noop } = props;
10
12
  if (props.style) {
11
13
  warn('The web-view component does not support the style prop.');
12
14
  }
15
+ const pageId = useContext(RouteContext);
16
+ const currentPage = useMemo(() => getCurrentPage(pageId), [pageId]);
13
17
  const defaultWebViewStyle = {
14
18
  position: 'absolute',
15
19
  left: 0,
@@ -21,16 +25,21 @@ const _WebView = forwardRef((props, ref) => {
21
25
  useNodesRef(props, ref, webViewRef, {
22
26
  defaultStyle: defaultWebViewStyle
23
27
  });
24
- const _messageList = [];
28
+ const _messageList = useRef([]);
25
29
  const handleUnload = () => {
26
30
  // 这里是 WebView 销毁前执行的逻辑
27
31
  bindmessage(getCustomEvent('messsage', {}, {
28
32
  detail: {
29
- data: _messageList
33
+ data: _messageList.current
30
34
  },
31
35
  layoutRef: webViewRef
32
36
  }));
33
37
  };
38
+ useEffect(() => {
39
+ if (currentPage) {
40
+ currentPage.__webViewUrl = src;
41
+ }
42
+ }, [src, currentPage]);
34
43
  useEffect(() => {
35
44
  // 组件卸载时执行
36
45
  return () => {
@@ -57,6 +66,11 @@ const _WebView = forwardRef((props, ref) => {
57
66
  };
58
67
  binderror(result);
59
68
  };
69
+ const _changeUrl = function (navState) {
70
+ if (currentPage) {
71
+ currentPage.__webViewUrl = navState.url;
72
+ }
73
+ };
60
74
  const _message = function (res) {
61
75
  let data = {};
62
76
  let asyncCallback;
@@ -73,7 +87,7 @@ const _WebView = forwardRef((props, ref) => {
73
87
  const postData = data.payload || {};
74
88
  switch (data.type) {
75
89
  case 'postMessage':
76
- _messageList.push(postData.data);
90
+ _messageList.current.push(postData.data);
77
91
  asyncCallback = Promise.resolve({
78
92
  errMsg: 'invokeWebappApi:ok'
79
93
  });
@@ -106,7 +120,7 @@ const _WebView = forwardRef((props, ref) => {
106
120
  });
107
121
  };
108
122
  return (<Portal>
109
- <WebView style={defaultWebViewStyle} source={{ uri: src }} ref={webViewRef} onLoad={_load} onError={_error} onMessage={_message} javaScriptEnabled={true}></WebView>
123
+ <WebView style={defaultWebViewStyle} source={{ uri: src }} ref={webViewRef} onLoad={_load} onError={_error} onMessage={_message} onNavigationStateChange={_changeUrl} javaScriptEnabled={true}></WebView>
110
124
  </Portal>);
111
125
  });
112
126
  _WebView.displayName = 'MpxWebview';
@@ -0,0 +1,75 @@
1
+ /**
2
+ * Borrowed from open-source code: https://github.com/quidone/react-native-wheel-picker
3
+ * Special thanks to the authors for their contribution to the open-source community.
4
+ */
5
+ export const degToRad = (deg) => (Math.PI * deg) / 180;
6
+ // Calculates the height of the element after rotating it relative to the user's screen.
7
+ const calcHeight = (degree, itemHeight) => itemHeight * Math.cos(degToRad(degree));
8
+ export const calcPickerHeight = (faces, itemHeight) => {
9
+ if (faces.length === 7) {
10
+ return itemHeight * 5;
11
+ }
12
+ return faces.reduce((r, v) => r + calcHeight(Math.abs(v.deg), itemHeight), 0);
13
+ };
14
+ export const createFaces = (itemHeight, visibleCount) => {
15
+ // e.g [30, 60, 90]
16
+ const getDegreesRelativeCenter = () => {
17
+ const maxStep = Math.trunc((visibleCount + 2) / 2); // + 2 because there are 2 more faces at 90 degrees
18
+ const stepDegree = 90 / maxStep;
19
+ const result = [];
20
+ for (let i = 1; i <= maxStep; i++) {
21
+ result.push(i * stepDegree);
22
+ }
23
+ return result;
24
+ };
25
+ const getScreenHeightsAndOffsets = (degrees) => {
26
+ const screenHeights = degrees.map((deg) => calcHeight(deg, itemHeight));
27
+ const freeSpaces = screenHeights.map((screenHeight) => itemHeight - screenHeight);
28
+ const offsets = freeSpaces.map((freeSpace, index) => {
29
+ let offset = freeSpace / 2;
30
+ for (let i = 0; i < index; i++) {
31
+ offset += freeSpaces[i];
32
+ }
33
+ return offset;
34
+ });
35
+ return [screenHeights, offsets];
36
+ };
37
+ const getOpacity = (index) => {
38
+ const map = {
39
+ 0: 0,
40
+ 1: 0.2,
41
+ 2: 0.35,
42
+ 3: 0.45,
43
+ 4: 0.5
44
+ };
45
+ return map[index] ?? Math.min(1, map[4] + index * 0.5);
46
+ };
47
+ const degrees = getDegreesRelativeCenter();
48
+ const [screenHeight, offsets] = getScreenHeightsAndOffsets(degrees);
49
+ return [
50
+ // top items
51
+ ...degrees
52
+ .map((degree, index) => {
53
+ return {
54
+ index: -1 * (index + 1),
55
+ deg: degree,
56
+ opacity: getOpacity(degrees.length - 1 - index),
57
+ offsetY: -1 * offsets[index],
58
+ screenHeight: screenHeight[index]
59
+ };
60
+ })
61
+ .reverse(),
62
+ // center item
63
+ { index: 0, deg: 0, opacity: 1, offsetY: 0, screenHeight: itemHeight },
64
+ // bottom items
65
+ ...degrees.map((degree, index) => {
66
+ return {
67
+ index: index + 1,
68
+ deg: -1 * degree,
69
+ opacity: getOpacity(degrees.length - 1 - index),
70
+ offsetY: offsets[index],
71
+ screenHeight: screenHeight[index]
72
+ };
73
+ })
74
+ ];
75
+ };
@@ -0,0 +1,21 @@
1
+ import React from 'react';
2
+ import { StyleSheet, View } from 'react-native';
3
+ const Overlay = ({ itemHeight, overlayItemStyle, overlayContainerStyle }) => {
4
+ return (<View style={[styles.overlayContainer, overlayContainerStyle]} pointerEvents={'none'}>
5
+ <View style={[styles.selection, { height: itemHeight }, overlayItemStyle]}/>
6
+ </View>);
7
+ };
8
+ const styles = StyleSheet.create({
9
+ overlayContainer: {
10
+ ...StyleSheet.absoluteFillObject,
11
+ justifyContent: 'center',
12
+ alignItems: 'center'
13
+ },
14
+ selection: {
15
+ borderTopWidth: 1,
16
+ borderBottomWidth: 1,
17
+ borderColor: 'rgba(0, 0, 0, 0.05)',
18
+ alignSelf: 'stretch'
19
+ }
20
+ });
21
+ export default React.memo(Overlay);
@@ -1,8 +1,10 @@
1
- import { useEffect, useRef, isValidElement, useContext, useState, Children, cloneElement } from 'react';
2
- import { isObject, hasOwn, diffAndCloneA, error, warn, getFocusedNavigation } from '@mpxjs/utils';
1
+ import { useEffect, useCallback, useMemo, useRef, isValidElement, useContext, useState, Children, cloneElement } from 'react';
2
+ import { Image } from 'react-native';
3
+ import { isObject, isFunction, hasOwn, diffAndCloneA, error, warn, getFocusedNavigation } from '@mpxjs/utils';
3
4
  import { VarContext } from './context';
4
5
  import { ExpressionParser, parseFunc, ReplaceSource } from './parser';
5
6
  import { initialWindowMetrics } from 'react-native-safe-area-context';
7
+ import FastImage from '@d11/react-native-fast-image';
6
8
  export const TEXT_STYLE_REGEX = /color|font.*|text.*|letterSpacing|lineHeight|includeFontPadding|writingDirection/;
7
9
  export const PERCENT_REGEX = /^\s*-?\d+(\.\d+)?%\s*$/;
8
10
  export const URL_REGEX = /^\s*url\(["']?(.*?)["']?\)\s*$/;
@@ -69,7 +71,7 @@ export const parseInlineStyle = (inlineStyle = '') => {
69
71
  if (rest.length || !v || !k)
70
72
  return styleObj;
71
73
  const key = k.trim().replace(/-./g, c => c.substring(1).toUpperCase());
72
- return Object.assign(styleObj, { [key]: v.trim() });
74
+ return Object.assign(styleObj, { [key]: global.__formatValue(v.trim()) });
73
75
  }, {});
74
76
  };
75
77
  export const parseUrl = (cssUrl = '') => {
@@ -444,6 +446,34 @@ export function wrapChildren(props = {}, { hasVarDec, varContext, textStyle, tex
444
446
  }
445
447
  return children;
446
448
  }
449
+ export const debounce = (func, delay) => {
450
+ let timer;
451
+ const wrapper = (...args) => {
452
+ clearTimeout(timer);
453
+ timer = setTimeout(() => {
454
+ func(...args);
455
+ }, delay);
456
+ };
457
+ wrapper.clear = () => {
458
+ clearTimeout(timer);
459
+ };
460
+ return wrapper;
461
+ };
462
+ export const useDebounceCallback = (func, delay) => {
463
+ const debounced = useMemo(() => debounce(func, delay), [func]);
464
+ return debounced;
465
+ };
466
+ export const useStableCallback = (callback) => {
467
+ const ref = useRef(callback);
468
+ ref.current = callback;
469
+ return useCallback((...args) => ref.current?.(...args), []);
470
+ };
471
+ export const usePrevious = (value) => {
472
+ const ref = useRef(undefined);
473
+ const prev = ref.current;
474
+ ref.current = value;
475
+ return prev;
476
+ };
447
477
  export function flatGesture(gestures = []) {
448
478
  return (gestures && gestures.flatMap((gesture) => {
449
479
  if (gesture && gesture.nodeRefs) {
@@ -453,3 +483,24 @@ export function flatGesture(gestures = []) {
453
483
  return gesture?.current ? [gesture] : [];
454
484
  })) || [];
455
485
  }
486
+ export function extendObject(...args) {
487
+ return Object.assign({}, ...args);
488
+ }
489
+ export function getCurrentPage(pageId) {
490
+ if (!global.getCurrentPages)
491
+ return;
492
+ const pages = global.getCurrentPages();
493
+ return pages.find((page) => isFunction(page.getPageId) && page.getPageId() === pageId);
494
+ }
495
+ export function renderImage(imageProps, enableFastImage = false) {
496
+ const Component = enableFastImage ? FastImage : Image;
497
+ return <Component {...imageProps}/>;
498
+ }
499
+ export function pickStyle(styleObj = {}, pickedKeys, callback) {
500
+ return pickedKeys.reduce((acc, key) => {
501
+ if (key in styleObj) {
502
+ acc[key] = callback ? callback(key, styleObj[key]) : styleObj[key];
503
+ }
504
+ return acc;
505
+ }, {});
506
+ }
@@ -1,5 +1,5 @@
1
1
  import { useRef } from 'react'
2
- import { NativeSyntheticEvent } from 'react-native'
2
+ import { collectDataset } from '@mpxjs/utils'
3
3
  import { omit } from './utils'
4
4
  import eventConfigMap from './event.config'
5
5
  import {
@@ -9,7 +9,6 @@ import {
9
9
  UseInnerPropsConfig,
10
10
  InnerRef,
11
11
  SetTimeoutReturnType,
12
- DataSetType,
13
12
  LayoutRef,
14
13
  NativeTouchEvent
15
14
  } from './types/getInnerListeners'
@@ -37,7 +36,7 @@ const getTouchEvent = (
37
36
  currentTarget: {
38
37
  ...(event.currentTarget || {}),
39
38
  id: id || '',
40
- dataset: getDataSet(props),
39
+ dataset: collectDataset(props),
41
40
  offsetLeft: layoutRef?.current?.offsetLeft || 0,
42
41
  offsetTop: layoutRef?.current?.offsetTop || 0
43
42
  },
@@ -69,19 +68,6 @@ const getTouchEvent = (
69
68
  }
70
69
  }
71
70
 
72
- export const getDataSet = (props: Record<string, any>) => {
73
- const result: DataSetType = {}
74
-
75
- for (const key in props) {
76
- if (key.indexOf('data-') === 0) {
77
- const newKey = key.substr(5)
78
- result[newKey] = props[key]
79
- }
80
- }
81
-
82
- return result
83
- }
84
-
85
71
  export const getCustomEvent = (
86
72
  type = '',
87
73
  oe: any = {},
@@ -95,7 +81,7 @@ export const getCustomEvent = (
95
81
  target: {
96
82
  ...(oe.target || {}),
97
83
  id: props.id || '',
98
- dataset: getDataSet(props),
84
+ dataset: collectDataset(props),
99
85
  offsetLeft: layoutRef?.current?.offsetLeft || 0,
100
86
  offsetTop: layoutRef?.current?.offsetTop || 0
101
87
  },
@@ -45,10 +45,10 @@ import {
45
45
  NativeSyntheticEvent
46
46
  } from 'react-native'
47
47
  import { warn } from '@mpxjs/utils'
48
- import { splitProps, splitStyle, useLayout, useTransformStyle, wrapChildren } from './utils'
48
+ import { getCurrentPage, splitProps, splitStyle, useLayout, useTransformStyle, wrapChildren } from './utils'
49
49
  import useInnerProps, { getCustomEvent } from './getInnerListeners'
50
50
  import useNodesRef, { HandlerRef } from './useNodesRef'
51
- import { FormContext } from './context'
51
+ import { RouteContext, FormContext } from './context'
52
52
 
53
53
  export type Type = 'default' | 'primary' | 'warn'
54
54
 
@@ -128,7 +128,8 @@ const styles = StyleSheet.create({
128
128
  }
129
129
  })
130
130
 
131
- const getOpenTypeEvent = (openType: OpenType) => {
131
+ const getOpenTypeEvent = (openType?: OpenType) => {
132
+ if (!openType) return
132
133
  if (!global.__mpx?.config?.rnConfig) {
133
134
  warn('Environment not supported')
134
135
  return
@@ -148,6 +149,12 @@ const getOpenTypeEvent = (openType: OpenType) => {
148
149
  return event
149
150
  }
150
151
 
152
+ const timer = (data: any, time = 3000) => new Promise((resolve) => {
153
+ setTimeout(() => {
154
+ resolve(data)
155
+ }, time)
156
+ })
157
+
151
158
  const Loading = ({ alone = false }: { alone: boolean }): JSX.Element => {
152
159
  const image = useRef(new Animated.Value(0)).current
153
160
 
@@ -211,6 +218,8 @@ const Button = forwardRef<HandlerRef<View, ButtonProps>, ButtonProps>((buttonPro
211
218
  bindtouchend
212
219
  } = props
213
220
 
221
+ const pageId = useContext(RouteContext)
222
+
214
223
  const formContext = useContext(FormContext)
215
224
 
216
225
  let submitFn: () => void | undefined
@@ -310,17 +319,41 @@ const Button = forwardRef<HandlerRef<View, ButtonProps>, ButtonProps>((buttonPro
310
319
  }
311
320
 
312
321
  const handleOpenTypeEvent = (evt: NativeSyntheticEvent<TouchEvent>) => {
313
- if (!openType) return
314
322
  const handleEvent = getOpenTypeEvent(openType)
323
+ if (!handleEvent) return
315
324
 
316
325
  if (openType === 'share') {
317
- handleEvent && handleEvent({
326
+ const currentPage = getCurrentPage(pageId)
327
+ const event = {
318
328
  from: 'button',
319
- target: getCustomEvent('tap', evt, { layoutRef }, props).target
320
- })
329
+ target: getCustomEvent('tap', evt, { layoutRef }, props).target,
330
+ webViewUrl: currentPage?.__webViewUrl
331
+ }
332
+ if (currentPage) {
333
+ const defaultMessage = {
334
+ title: global.__mpx.config.rnConfig.projectName || 'AwesomeProject',
335
+ path: currentPage.route || ''
336
+ }
337
+ if (currentPage.onShareAppMessage) {
338
+ const { promise, ...message } = currentPage.onShareAppMessage(event) || {}
339
+ if (promise) {
340
+ Promise.race([Promise.resolve(promise), timer(message)])
341
+ .then((msg) => {
342
+ handleEvent(Object.assign({}, defaultMessage, msg))
343
+ })
344
+ } else {
345
+ handleEvent(Object.assign({}, defaultMessage, message))
346
+ }
347
+ } else {
348
+ handleEvent(defaultMessage)
349
+ }
350
+ } else {
351
+ warn('Current page not found')
352
+ // Todo handleEvent(event)
353
+ }
321
354
  }
322
355
 
323
- if (openType === 'getUserInfo' && handleEvent && bindgetuserinfo) {
356
+ if (openType === 'getUserInfo' && bindgetuserinfo) {
324
357
  Promise.resolve(handleEvent)
325
358
  .then((userInfo) => {
326
359
  if (typeof userInfo === 'object') {
@@ -0,0 +1,70 @@
1
+ import { warn } from '@mpxjs/utils'
2
+ interface Message {
3
+ id?: string
4
+ type: string
5
+ payload?: any
6
+ }
7
+ export default class Bus {
8
+ _paused: Boolean = false;
9
+ _messageListeners: { [key: string]: (message: Message) => void } = {}
10
+ _queue: Message[] = []
11
+ _send: (message: Message | Message[]) => void
12
+ _timeoutId: NodeJS.Timeout | null = null
13
+ constructor (send: (message: Message | Message[]) => void) {
14
+ this._send = send
15
+ }
16
+
17
+ post (message: Message): Promise<any> {
18
+ return new Promise((resolve) => {
19
+ if (message.type !== 'set' && message.id) {
20
+ this._messageListeners[message.id] = resolve
21
+ }
22
+
23
+ if (!this._paused) {
24
+ this._queue.push(message)
25
+ this.startBatching()
26
+ } else {
27
+ this._queue.push(message)
28
+ }
29
+ })
30
+ }
31
+
32
+ handle (message: Message): void {
33
+ if (!message.id) return
34
+ const handler = this._messageListeners[message.id]
35
+ delete this._messageListeners[message.id]
36
+
37
+ if (handler) {
38
+ handler(message)
39
+ } else {
40
+ warn(`Received unexpected message: ${message}`)
41
+ }
42
+ }
43
+
44
+ pause (): void {
45
+ this._paused = true
46
+ }
47
+
48
+ resume (): void {
49
+ this._paused = false
50
+ this._send(this._queue)
51
+ this._queue = []
52
+ }
53
+
54
+ startBatching (): void {
55
+ if (this._timeoutId) return
56
+
57
+ this._timeoutId = setTimeout(() => {
58
+ this._send(this._queue)
59
+ this._queue = []
60
+ this._timeoutId = null
61
+ }, 16)
62
+ }
63
+
64
+ clearBatchingTimeout (): void {
65
+ if (this._timeoutId) {
66
+ clearTimeout(this._timeoutId)
67
+ this._timeoutId = null
68
+ }
69
+ }
70
+ }
@@ -0,0 +1,18 @@
1
+ import { WebviewMessage, CanvasInstance, registerWebviewMethods } from './utils'
2
+
3
+ const METHODS = ['addColorStop']
4
+ export default class CanvasGradient {
5
+ private canvas: CanvasInstance;
6
+ [key: string]: any;
7
+ constructor (canvas: CanvasInstance, noOnConstruction = false) {
8
+ this.canvas = canvas
9
+ registerWebviewMethods(this, METHODS)
10
+ if (this.onConstruction && !noOnConstruction) {
11
+ this.onConstruction()
12
+ }
13
+ }
14
+
15
+ postMessage (message: WebviewMessage) {
16
+ return this.canvas.postMessage(message)
17
+ }
18
+ }
@@ -0,0 +1,87 @@
1
+ import { CanvasInstance, WebviewMessage, registerWebviewProperties, registerWebviewMethods, registerWebviewTarget } from './utils'
2
+
3
+ const PROPERTIES = {
4
+ direction: 'inherit',
5
+ fillStyle: '#000',
6
+ filter: 'none',
7
+ font: '10px sans-serif',
8
+ fontKerning: 'auto',
9
+ fontStretch: 'auto',
10
+ fontVariantCaps: 'normal',
11
+ globalAlpha: 1.0,
12
+ globalCompositeOperation: 'source-over',
13
+ imageSmoothingEnabled: 'true',
14
+ imageSmoothingQuality: 'low',
15
+ letterSpacing: '0px',
16
+ lineCap: 'butt',
17
+ lineDashOffset: 0.0,
18
+ lineJoin: 'miter',
19
+ lineWidth: 1.0,
20
+ miterLimit: 10.0,
21
+ shadowBlur: 0,
22
+ shadowColor: 'rgba(0,0,0,0)',
23
+ shadowOffsetX: 0,
24
+ shadowOffsetY: 0,
25
+ strokeStyle: '#000',
26
+ textAlign: 'start',
27
+ textBaseline: 'alphabetic',
28
+ textRendering: 'auto',
29
+ wordSpacing: '0px'
30
+ }
31
+
32
+ const METHODS = [
33
+ 'arc',
34
+ 'arcTo',
35
+ 'beginPath',
36
+ 'bezierCurveTo',
37
+ 'clearRect',
38
+ 'clip',
39
+ 'closePath',
40
+ 'createConicGradient',
41
+ 'createImageData',
42
+ 'createLinearGradient',
43
+ 'createPattern',
44
+ 'createRadialGradient',
45
+ 'drawFocusIfNeeded',
46
+ 'drawImage',
47
+ 'ellipse',
48
+ 'fill',
49
+ 'fillRect',
50
+ 'fillText',
51
+ 'getImageData',
52
+ 'getLineDash',
53
+ 'getTransform',
54
+ 'lineTo',
55
+ 'measureText',
56
+ 'moveTo',
57
+ 'putImageData',
58
+ 'quadraticCurveTo',
59
+ 'rect',
60
+ 'reset',
61
+ 'resetTransform',
62
+ 'restore',
63
+ 'rotate',
64
+ 'roundRect',
65
+ 'save',
66
+ 'scale',
67
+ 'setLineDash',
68
+ 'setTransform',
69
+ 'stroke',
70
+ 'strokeRect',
71
+ 'strokeText',
72
+ 'transform',
73
+ 'translate'
74
+ ]
75
+ export default class CanvasRenderingContext2D {
76
+ canvas: CanvasInstance
77
+ constructor (canvas: CanvasInstance) {
78
+ this.canvas = canvas
79
+ registerWebviewTarget(this, 'context2D')
80
+ registerWebviewProperties(this, PROPERTIES)
81
+ registerWebviewMethods(this, METHODS)
82
+ }
83
+
84
+ postMessage (message: WebviewMessage) {
85
+ return this.canvas.postMessage(message)
86
+ }
87
+ }
@@ -0,0 +1,102 @@
1
+ import { WebviewMessage, WEBVIEW_TARGET, registerWebviewProperties, CanvasInstance } from './utils'
2
+
3
+ const PROPERTIES = {
4
+ crossOrigin: undefined,
5
+ height: undefined,
6
+ src: undefined,
7
+ width: undefined
8
+ }
9
+
10
+ export class Image {
11
+ [WEBVIEW_TARGET]: string;
12
+ canvas: any;
13
+ width: number;
14
+ height: number;
15
+ private _loadListener: any;
16
+ private _errorListener: any;
17
+ private _onload: ((...args: any[]) => void);
18
+ private _onerror: ((...args: any[]) => void);
19
+ [key: string]: any;
20
+
21
+ constructor (canvas: CanvasInstance, width?: number, height?: number, noOnConstruction = false) {
22
+ this.canvas = canvas
23
+ registerWebviewProperties(this, PROPERTIES)
24
+
25
+ if (width) {
26
+ this.width = width
27
+ }
28
+ if (height) {
29
+ this.height = height
30
+ }
31
+
32
+ if (this.onConstruction && !noOnConstruction) {
33
+ this.onConstruction()
34
+ this.postMessage({
35
+ type: 'listen',
36
+ payload: {
37
+ types: ['error', 'load'],
38
+ target: this[WEBVIEW_TARGET]
39
+ }
40
+ })
41
+ }
42
+ }
43
+
44
+ postMessage (message: WebviewMessage) {
45
+ return this.canvas.postMessage(message)
46
+ }
47
+
48
+ addEventListener (type: 'load' | 'error', callbackFn: Function) {
49
+ return this.canvas.addMessageListener((message: WebviewMessage) => {
50
+ const target = message?.payload?.target as { [key: string]: any } || {}
51
+ if (
52
+ message &&
53
+ message.type === 'event' &&
54
+ target[WEBVIEW_TARGET] === this[WEBVIEW_TARGET] &&
55
+ message.payload.type === type
56
+ ) {
57
+ for (const key in target) {
58
+ const value = target[key]
59
+ if (key in this && this[key] !== value) {
60
+ this[key] = value
61
+ }
62
+ }
63
+ callbackFn({
64
+ ...message.payload,
65
+ target: this
66
+ })
67
+ }
68
+ })
69
+ }
70
+
71
+ set onload (callback: ((...args: any[]) => void)) {
72
+ this._onload = callback
73
+ if (this._loadListener) {
74
+ this.canvas.removeMessageListener(this._loadListener)
75
+ }
76
+ if (callback) {
77
+ this._loadListener = this.addEventListener('load', callback)
78
+ }
79
+ }
80
+
81
+ get onload (): ((...args: any[]) => void) {
82
+ return this._onload
83
+ }
84
+
85
+ set onerror (callback: ((...args: any[]) => void)) {
86
+ this._onerror = callback
87
+ if (this._errorListener) {
88
+ this.canvas.removeMessageListener(this._errorListener)
89
+ }
90
+ if (callback) {
91
+ this._errorListener = this.addEventListener('error', callback)
92
+ }
93
+ }
94
+
95
+ get onerror () : ((...args: any[]) => void) {
96
+ return this._onerror
97
+ }
98
+ }
99
+
100
+ export function createImage (canvas: CanvasInstance, width?: number, height?: number) {
101
+ return new Image(canvas, width, height)
102
+ }