@ray-js/robot-map 0.0.2 → 0.0.5-beta.10

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.
@@ -5,17 +5,19 @@ import "core-js/modules/esnext.iterator.map.js";
5
5
  import "core-js/modules/web.dom-collections.iterator.js";
6
6
  /* eslint-disable func-names */
7
7
  import Render from './index.rjs';
8
- import { MAP_API_METHODS, MAP_CALLBACK_METHODS } from '@ray-js/robot-map-sdk';
8
+ import { MAP_CALLBACK_METHODS } from '@ray-js/robot-map-sdk';
9
9
  import { isEqual } from 'lodash-es';
10
10
  const componentOptions = {
11
11
  options: {
12
12
  pureDataPattern: /^init$/
13
13
  },
14
14
  data: {
15
- initialized: false,
16
- mapApi: null
15
+ initialized: false
17
16
  },
18
17
  properties: {
18
+ containerId: {
19
+ type: String
20
+ },
19
21
  path: {
20
22
  type: String,
21
23
  observer: function (newValue, oldValue) {
@@ -126,11 +128,13 @@ const componentOptions = {
126
128
  lifetimes: {
127
129
  created() {
128
130
  this.render = new Render(this);
129
- this.mapApi = null;
130
131
  },
131
132
  async ready() {
132
- const config = this.properties.config || {};
133
- await this.render.initialize(config);
133
+ const {
134
+ config: configProp = {},
135
+ containerId
136
+ } = this.properties;
137
+ await this.render.initialize(configProp || {}, containerId);
134
138
  this.setData({
135
139
  initialized: true
136
140
  });
@@ -183,56 +187,26 @@ const componentOptions = {
183
187
  },
184
188
  pageLifetimes: {},
185
189
  methods: {
186
- // render 对象动态添加 API 代理方法
187
- setupApiProxyMethods() {
188
- const {
189
- render
190
- } = this;
191
- if (!render) {
192
- return;
190
+ // 调用 RJS 层的 mapInstance 方法(异步,通过回调返回结果)
191
+ invokeMapApi(requestId, methodName, args) {
192
+ if (this.render) {
193
+ this.render.callMapInstanceMethodAsync(requestId, methodName, ...args);
193
194
  }
194
-
195
- // 如果已经设置过,不重复设置(使用标记避免重复执行)
196
- if (render.__apiProxyMethodsSetup) {
197
- return;
198
- }
199
- MAP_API_METHODS.forEach(methodName => {
200
- // 为 this.render 添加代理方法,通过 callMapInstanceMethod 来间接调用
201
- // 因为 render.mapInstance 在外部无法访问(封装的私有属性)
202
- render[methodName] = function () {
203
- for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
204
- args[_key] = arguments[_key];
205
- }
206
- return render.callMapInstanceMethod(methodName, ...args);
207
- };
208
- });
209
-
210
- // 标记已设置,避免重复执行
211
- render.__apiProxyMethodsSetup = true;
212
- },
213
- // 创建MapApi对象,将rjs方法映射为API
214
- createMapApi() {
215
- if (!this.render) {
216
- return null;
217
- }
218
- const mapApi = {};
219
- MAP_API_METHODS.forEach(methodName => {
220
- // 将方法绑定到 this.render,这样调用时会通过 render 代理到 mapInstance
221
- if (typeof this.render[methodName] === 'function') {
222
- mapApi[methodName] = this.render[methodName].bind(this.render);
223
- }
195
+ },
196
+ // 接收 RJS 层的 API 调用结果回调
197
+ onApiResponse(requestId, result, error) {
198
+ this.triggerEvent('onApiResponse', {
199
+ requestId,
200
+ result,
201
+ error
224
202
  });
225
- return mapApi;
226
203
  },
227
204
  // 处理rjs回调事件
228
205
  onInitialized() {
229
- // 确保代理方法已设置(防止时序问题)
230
- this.setupApiProxyMethods();
231
- this.mapApi = this.createMapApi();
232
- this.setData({
233
- mapApi: this.mapApi
206
+ // 传递组件实例,让 TS 层可以通过 instance.invokeMapApi() 调用方法
207
+ this.triggerEvent('onInitialized', {
208
+ instance: this
234
209
  });
235
- this.triggerEvent('onInitialized', this.mapApi);
236
210
  }
237
211
  }
238
212
  };
@@ -240,8 +214,8 @@ const componentOptions = {
240
214
  // 动态添加所有 MAP_CALLBACK_METHODS 中定义的回调方法
241
215
  MAP_CALLBACK_METHODS.forEach(methodName => {
242
216
  componentOptions.methods[methodName] = function () {
243
- for (var _len2 = arguments.length, args = new Array(_len2), _key2 = 0; _key2 < _len2; _key2++) {
244
- args[_key2] = arguments[_key2];
217
+ for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
218
+ args[_key] = arguments[_key];
245
219
  }
246
220
  this.triggerEvent(methodName, ...args);
247
221
  };
@@ -1,20 +1,20 @@
1
- import { MapApplication, MAP_API_METHODS, MAP_CALLBACK_METHODS } from "@ray-js/robot-map-sdk/rjs";
1
+ import { MapApplication, MAP_CALLBACK_METHODS } from "@ray-js/robot-map-sdk/rjs";
2
2
  import { decodeMap, decodeMapStructured, decodePath } from '@ray-js/robot-protocol'
3
3
 
4
4
  export default Render({
5
5
  mapInstance: null,
6
6
  initialized: false,
7
7
 
8
- async initialize(config = {}) {
8
+ async initialize(config = {}, containerId = 'container') {
9
9
  const { mapInstance } = this;
10
-
10
+
11
11
  if (mapInstance) {
12
12
  console.warn('Map instance already initialized')
13
13
  return
14
14
  }
15
15
 
16
16
  this.mapInstance = new MapApplication()
17
- const containerElement = document.getElementById('container')
17
+ const containerElement = document.getElementById(containerId)
18
18
 
19
19
  // 定义事件处理器
20
20
  const events = {}
@@ -140,11 +140,22 @@ export default Render({
140
140
 
141
141
  // 通用的 API 调用方法,用于代理所有 mapInstance 上的方法
142
142
  // 因为外部无法直接访问 this.mapInstance,所以提供这个方法来间接调用
143
- callMapInstanceMethod(methodName, ...args) {
143
+ // 注意:RJS 层无法直接 return 值给 JS 层,需要通过 callMethod 回调
144
+ callMapInstanceMethodAsync(requestId, methodName, ...args) {
145
+ let result = null
146
+ let error = null
147
+
144
148
  if (this.mapInstance && typeof this.mapInstance[methodName] === 'function') {
145
- return this.mapInstance[methodName](...args)
149
+ try {
150
+ result = this.mapInstance[methodName](...args)
151
+ } catch (e) {
152
+ error = e?.message || String(e)
153
+ }
154
+ } else {
155
+ error = `Method ${methodName} not available on mapInstance`
146
156
  }
147
- console.warn(`Method ${methodName} not available on mapInstance`)
148
- return null
157
+
158
+ // 通过 callMethod 将结果回调给 JS 层
159
+ this.callMethod('onApiResponse', requestId, result, error)
149
160
  }
150
161
  })
@@ -1 +1 @@
1
- <view id="container" />
1
+ <view id="{{containerId}}" class="container" />
@@ -1,4 +1,4 @@
1
- #container {
1
+ .container {
2
2
  position: absolute;
3
3
  width: 100%;
4
4
  height: 100%;
@@ -1,6 +1,5 @@
1
1
  import _extends from "@babel/runtime/helpers/esm/extends";
2
2
  import _objectWithoutProperties from "@babel/runtime/helpers/esm/objectWithoutProperties";
3
- import _objectSpread from "@babel/runtime/helpers/esm/objectSpread2";
4
3
  const _excluded = ["map", "path", "roomProperties", "forbiddenSweepZones", "forbiddenMopZones", "cleanZones", "virtualWalls", "spots", "wayPoints", "detectedObjects", "customElements", "config", "runtime", "onMapReady"];
5
4
  import "core-js/modules/esnext.iterator.constructor.js";
6
5
  import "core-js/modules/esnext.iterator.for-each.js";
@@ -8,17 +7,13 @@ import "core-js/modules/esnext.iterator.map.js";
8
7
  import "core-js/modules/esnext.iterator.reduce.js";
9
8
  import "core-js/modules/web.dom-collections.iterator.js";
10
9
  import React, { useCallback, useEffect, useRef, useMemo } from 'react';
11
- import { MAP_CALLBACK_METHODS } from '@ray-js/robot-map-sdk';
10
+ import { MAP_CALLBACK_METHODS, MAP_API_METHODS } from '@ray-js/robot-map-sdk';
11
+ import { nanoid } from 'nanoid/non-secure';
12
12
  import RjsComponent from './RjsComponent';
13
13
  import { robotMapDefaultProps } from './props';
14
14
 
15
- // 回调名到事件名的映射
16
- const CALLBACK_TO_EVENT_MAP = _objectSpread({
17
- onInitialized: 'onInitialized'
18
- }, MAP_CALLBACK_METHODS.reduce((acc, methodName) => {
19
- acc[methodName] = methodName;
20
- return acc;
21
- }, {}));
15
+ // 存储待处理的请求:requestId -> { resolve, reject }
16
+
22
17
  const RjsRobotMap = _ref => {
23
18
  let {
24
19
  map,
@@ -39,35 +34,98 @@ const RjsRobotMap = _ref => {
39
34
  callbacks = _objectWithoutProperties(_ref, _excluded);
40
35
  const componentRef = useRef(null);
41
36
  const callbacksRef = useRef(callbacks);
37
+ // 存储小程序组件实例的引用
38
+ const instanceRef = useRef(null);
39
+ // 存储待处理的 API 请求
40
+ const pendingRequestsRef = useRef(new Map());
41
+ // 为每个组件实例生成唯一的 containerId
42
+ const containerId = useRef("robot-map-container-".concat(nanoid())).current;
42
43
 
43
44
  // 更新回调引用
44
45
  useEffect(() => {
45
46
  callbacksRef.current = callbacks;
46
47
  });
47
48
 
48
- // 事件分发函数 - 这个函数是稳定的,不会随渲染变化
49
+ // 事件分发函数
49
50
  const eventDispatcher = useCallback(function (eventName) {
50
- const propName = CALLBACK_TO_EVENT_MAP[eventName];
51
- if (propName && callbacksRef.current[propName]) {
52
- for (var _len = arguments.length, args = new Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {
53
- args[_key - 1] = arguments[_key];
51
+ var _callbacksRef$current, _callbacksRef$current2;
52
+ for (var _len = arguments.length, args = new Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {
53
+ args[_key - 1] = arguments[_key];
54
+ }
55
+ (_callbacksRef$current = (_callbacksRef$current2 = callbacksRef.current)[eventName]) === null || _callbacksRef$current === void 0 || _callbacksRef$current.call(_callbacksRef$current2, ...args);
56
+ }, []);
57
+
58
+ // 在 TS 层创建 mapApi,每个方法返回 Promise
59
+ const createMapApi = useCallback(() => {
60
+ const mapApi = MAP_API_METHODS.reduce((acc, methodName) => {
61
+ acc[methodName] = function () {
62
+ for (var _len2 = arguments.length, args = new Array(_len2), _key2 = 0; _key2 < _len2; _key2++) {
63
+ args[_key2] = arguments[_key2];
64
+ }
65
+ return new Promise((resolve, reject) => {
66
+ const instance = instanceRef.current;
67
+ if (!instance) {
68
+ reject(new Error('Map instance not available'));
69
+ return;
70
+ }
71
+
72
+ // 生成唯一的请求 ID
73
+ const requestId = nanoid();
74
+
75
+ // 存储 resolve/reject,等待回调
76
+ pendingRequestsRef.current.set(requestId, {
77
+ resolve,
78
+ reject
79
+ });
80
+
81
+ // 调用组件实例的方法,通知 RJS 层执行
82
+ instance.invokeMapApi(requestId, methodName, args);
83
+ });
84
+ };
85
+ return acc;
86
+ }, {});
87
+ return mapApi;
88
+ }, []);
89
+
90
+ // 处理 API 响应事件
91
+ const handleApiResponse = useCallback(event => {
92
+ const {
93
+ requestId,
94
+ result,
95
+ error
96
+ } = event.detail || {};
97
+ const pending = pendingRequestsRef.current.get(requestId);
98
+ if (pending) {
99
+ pendingRequestsRef.current.delete(requestId);
100
+ if (error) {
101
+ pending.reject(new Error(error));
102
+ } else {
103
+ pending.resolve(result);
54
104
  }
55
- // 调用最新的prop回调
56
- callbacksRef.current[propName](...args);
57
105
  }
58
106
  }, []);
59
107
 
60
108
  // 处理初始化完成事件
61
109
  const handleInitialized = useCallback(event => {
62
- const api = event.detail;
63
- onMapReady === null || onMapReady === void 0 || onMapReady(api);
64
- eventDispatcher('onInitialized', api);
65
- }, [onMapReady, eventDispatcher]);
110
+ const {
111
+ instance
112
+ } = event.detail || {};
113
+ if (instance) {
114
+ // 保存组件实例引用
115
+ instanceRef.current = instance;
116
+
117
+ // 创建 mapApi
118
+ const mapApi = createMapApi();
119
+ onMapReady === null || onMapReady === void 0 || onMapReady(mapApi);
120
+ eventDispatcher('onInitialized', mapApi);
121
+ }
122
+ }, [onMapReady, eventDispatcher, createMapApi]);
66
123
 
67
124
  // 动态生成所有回调处理函数的绑定属性
68
125
  const eventBindings = useMemo(() => {
69
126
  const bindings = {
70
- bindonInitialized: handleInitialized
127
+ bindonInitialized: handleInitialized,
128
+ bindonApiResponse: handleApiResponse
71
129
  };
72
130
 
73
131
  // 为 MAP_CALLBACK_METHODS 中的每个方法创建绑定
@@ -77,7 +135,7 @@ const RjsRobotMap = _ref => {
77
135
  };
78
136
  });
79
137
  return bindings;
80
- }, [handleInitialized, eventDispatcher]);
138
+ }, [handleInitialized, handleApiResponse, eventDispatcher]);
81
139
  return /*#__PURE__*/React.createElement(RjsComponent, _extends({
82
140
  ref: componentRef,
83
141
  map: map,
@@ -92,7 +150,8 @@ const RjsRobotMap = _ref => {
92
150
  detectedObjects: detectedObjects,
93
151
  customElements: customElements,
94
152
  config: config,
95
- runtime: runtime
153
+ runtime: runtime,
154
+ containerId: containerId
96
155
  }, eventBindings));
97
156
  };
98
157
  RjsRobotMap.defaultProps = robotMapDefaultProps;
package/lib/RobotMap.d.ts CHANGED
@@ -2,7 +2,7 @@ import React from 'react';
2
2
  import { AppOptions } from '@ray-js/robot-map-sdk';
3
3
  import { RobotMapProps } from './props';
4
4
  declare const RobotMap: {
5
- ({ map, path, roomProperties, forbiddenSweepZones, forbiddenMopZones, cleanZones, virtualWalls, spots, wayPoints, detectedObjects, customElements, onMapReady, config, runtime, ...callbacks }: RobotMapProps & AppOptions['events']): React.JSX.Element;
5
+ ({ map, path, roomProperties, forbiddenSweepZones, forbiddenMopZones, cleanZones, virtualWalls, spots, wayPoints, detectedObjects, customElements, customCarpets, onMapReady, config, runtime, ...callbacks }: RobotMapProps & AppOptions['events']): React.JSX.Element;
6
6
  defaultProps: RobotMapProps;
7
7
  displayName: string;
8
8
  };
package/lib/RobotMap.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import _objectWithoutProperties from "@babel/runtime/helpers/esm/objectWithoutProperties";
2
2
  import _objectSpread from "@babel/runtime/helpers/esm/objectSpread2";
3
- const _excluded = ["map", "path", "roomProperties", "forbiddenSweepZones", "forbiddenMopZones", "cleanZones", "virtualWalls", "spots", "wayPoints", "detectedObjects", "customElements", "onMapReady", "config", "runtime"];
3
+ const _excluded = ["map", "path", "roomProperties", "forbiddenSweepZones", "forbiddenMopZones", "cleanZones", "virtualWalls", "spots", "wayPoints", "detectedObjects", "customElements", "customCarpets", "onMapReady", "config", "runtime"];
4
4
  import "core-js/modules/esnext.iterator.constructor.js";
5
5
  import "core-js/modules/esnext.iterator.for-each.js";
6
6
  import "core-js/modules/esnext.iterator.map.js";
@@ -13,7 +13,6 @@ import { createWebviewContext, WebView } from '@ray-js/ray';
13
13
  import { MAP_API_METHODS, MAP_CALLBACK_METHODS } from '@ray-js/robot-map-sdk';
14
14
  import { nanoid } from 'nanoid/non-secure';
15
15
  import { robotMapDefaultProps } from './props';
16
-
17
16
  // 回调名到事件名的映射
18
17
  const CALLBACK_TO_EVENT_MAP = _objectSpread({
19
18
  onInitialized: 'onInitialized'
@@ -34,6 +33,7 @@ const RobotMap = _ref => {
34
33
  wayPoints,
35
34
  detectedObjects,
36
35
  customElements,
36
+ customCarpets,
37
37
  onMapReady,
38
38
  config = {},
39
39
  runtime = {}
@@ -56,7 +56,8 @@ const RobotMap = _ref => {
56
56
  onReceiveWayPoints: () => {},
57
57
  onReceiveDetectedObjects: () => {},
58
58
  onReceiveCustomElements: () => {},
59
- onUpdateRuntime: () => {}
59
+ onUpdateRuntime: () => {},
60
+ onReceiveCustomCarpets: () => {}
60
61
  });
61
62
  const handleMessage = useCallback(event => {
62
63
  if (invoke.current) {
@@ -104,6 +105,7 @@ const RobotMap = _ref => {
104
105
  triggersRef.current.onReceiveDetectedObjects = invoke.current.bind('onReceiveDetectedObjects');
105
106
  triggersRef.current.onReceiveCustomElements = invoke.current.bind('onReceiveCustomElements');
106
107
  triggersRef.current.onUpdateRuntime = invoke.current.bind('onUpdateRuntime');
108
+ triggersRef.current.onReceiveCustomCarpets = invoke.current.bind('onReceiveCustomCarpets');
107
109
 
108
110
  // 为每个需要的事件定义分发函数
109
111
  Object.keys(CALLBACK_TO_EVENT_MAP).forEach(eventName => {
@@ -178,6 +180,11 @@ const RobotMap = _ref => {
178
180
  triggersRef.current.onReceiveCustomElements(customElements);
179
181
  }
180
182
  }, [customElements, mapApi]);
183
+ useEffect(() => {
184
+ if (mapApi && customCarpets) {
185
+ triggersRef.current.onReceiveCustomCarpets(customCarpets);
186
+ }
187
+ }, [customCarpets, mapApi]);
181
188
  useEffect(() => {
182
189
  if (mapApi && runtime) {
183
190
  var _runtime$dividingRoom;
package/lib/index.d.ts CHANGED
@@ -1,3 +1,4 @@
1
1
  export { RobotMap } from './RobotMap';
2
2
  export { RjsRobotMap } from './RjsRobotMap';
3
+ export type { MapApi } from './types';
3
4
  export * from '@ray-js/robot-map-sdk';
package/lib/index.js CHANGED
@@ -1,3 +1,7 @@
1
1
  export { RobotMap } from './RobotMap';
2
2
  export { RjsRobotMap } from './RjsRobotMap';
3
+
4
+ // 先导出我们的类型定义(覆盖 MapApi 为 Promise 版本)
5
+
6
+ // 然后导出 SDK 的其他内容(MapApi 会被我们的定义覆盖)
3
7
  export * from '@ray-js/robot-map-sdk';
package/lib/props.d.ts CHANGED
@@ -1,4 +1,5 @@
1
- import { DeepPartialAppConfig, DeepPartialRuntimeConfig, MapApi, RoomProperty, ZoneParam, VirtualWallParam, DetectedObjectParam, CustomElementParam, MapState, PathState, Point, RoomData, SpotParam, WayPointParam } from '@ray-js/robot-map-sdk';
1
+ import { DeepPartialAppConfig, DeepPartialRuntimeConfig, RoomProperty, ZoneParam, VirtualWallParam, DetectedObjectParam, CustomElementParam, MapState, PathState, Point, RoomData, SpotParam, WayPointParam, CustomCarpetParam } from '@ray-js/robot-map-sdk';
2
+ import { MapApi } from './types';
2
3
  /**
3
4
  * 机器人地图组件属性接口
4
5
  *
@@ -83,6 +84,13 @@ export interface RobotMapProps {
83
84
  * @description.en User-defined map elements, which can be images, GIFs, and HTML.
84
85
  */
85
86
  customElements?: CustomElementParam[];
87
+ /**
88
+ * @description.zh 自定义地毯
89
+ * @description.en Custom carpets
90
+ * @description.zh 用户自定义的地毯信息,支持图片、GIF和HTML三种格式。
91
+ * @description.en User-defined carpet information, which can be images, GIFs, and HTML.
92
+ */
93
+ customCarpets?: CustomCarpetParam[];
86
94
  /**
87
95
  * @description.zh 配置项
88
96
  * @description.en Configuration options
@@ -102,7 +110,7 @@ export interface RobotMapProps {
102
110
  * @description.en Callback when the map is initialized and the API is ready
103
111
  * @description.zh 当地图组件初始化完成并且所有API功能可用时触发的回调函数。
104
112
  * @description.en Callback function triggered when the map component is initialized and all API functions are available.
105
- * @param mapApi - 可供使用的地图 API 函数对象 / Available map API functions object
113
+ * @param mapApi - 可供使用的地图 API 函数对象,所有方法返回 Promise / Available map API functions object, all methods return Promise
106
114
  */
107
115
  onMapReady?: (mapApi: MapApi) => void;
108
116
  /**
@@ -114,6 +122,7 @@ export interface RobotMapProps {
114
122
  * @param.en mapState - Map state information including map ID, origin, dimensions, etc.
115
123
  */
116
124
  onMapFirstDrawed?: (mapState: MapState) => void;
125
+ onCarpetsUpdated?: (carpets: CustomCarpetParam[]) => void;
117
126
  /**
118
127
  * @description.zh 地图绘制完成回调
119
128
  * @description.en Callback when the map is drawn
package/lib/types.d.ts ADDED
@@ -0,0 +1,8 @@
1
+ import { MapApi as OriginalMapApi } from '@ray-js/robot-map-sdk';
2
+ /**
3
+ * MapApi 类型定义(所有方法返回 Promise)
4
+ * MapApi type definition (all methods return Promise)
5
+ */
6
+ export type MapApi = {
7
+ [K in keyof OriginalMapApi]: OriginalMapApi[K] extends (...args: infer Args) => infer Return ? (...args: Args) => Promise<Return> : OriginalMapApi[K];
8
+ };
package/lib/types.js ADDED
@@ -0,0 +1 @@
1
+ export {};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ray-js/robot-map",
3
- "version": "0.0.2",
3
+ "version": "0.0.5-beta.10",
4
4
  "description": "机器人地图组件",
5
5
  "main": "lib/index",
6
6
  "files": [
@@ -33,7 +33,7 @@
33
33
  "@ray-js/ray": "^1.7.39"
34
34
  },
35
35
  "dependencies": {
36
- "@ray-js/robot-map-sdk": "^0.0.4-beta.1",
36
+ "@ray-js/robot-map-sdk": "^0.0.5-beta.1",
37
37
  "clsx": "^1.2.1",
38
38
  "nanoid": "^5.1.6"
39
39
  },