@netless/window-manager 1.0.0-canary.7 → 1.0.0-canary.71
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/README.md +30 -6
- package/dist/index.js +13625 -0
- package/dist/index.mjs +13622 -0
- package/dist/index.umd.js +13620 -46
- package/dist/{App → src/App}/AppContext.d.ts +16 -14
- package/dist/{App → src/App}/AppPageStateImpl.d.ts +0 -0
- package/dist/{App → src/App}/AppProxy.d.ts +30 -11
- package/dist/{App → src/App}/MagixEvent/index.d.ts +0 -0
- package/dist/src/App/WhiteboardView.d.ts +27 -0
- package/dist/{App → src/App}/index.d.ts +1 -0
- package/dist/src/App/type.d.ts +21 -0
- package/dist/{AppListener.d.ts → src/AppListener.d.ts} +2 -2
- package/dist/{AppManager.d.ts → src/AppManager.d.ts} +12 -7
- package/dist/{AttributesDelegate.d.ts → src/AttributesDelegate.d.ts} +5 -2
- package/dist/{BoxEmitter.d.ts → src/BoxEmitter.d.ts} +0 -0
- package/dist/{BoxManager.d.ts → src/BoxManager.d.ts} +12 -6
- package/dist/{BuiltinApps.d.ts → src/BuiltinApps.d.ts} +3 -0
- package/dist/{Cursor → src/Cursor}/Cursor.d.ts +0 -0
- package/dist/{Cursor → src/Cursor}/icons.d.ts +0 -0
- package/dist/{Cursor → src/Cursor}/index.d.ts +4 -3
- package/dist/{Helper.d.ts → src/Helper.d.ts} +4 -8
- package/dist/{InternalEmitter.d.ts → src/InternalEmitter.d.ts} +1 -4
- package/dist/{Page → src/Page}/PageController.d.ts +3 -1
- package/dist/{Page → src/Page}/index.d.ts +0 -0
- package/dist/{PageState.d.ts → src/PageState.d.ts} +1 -0
- package/dist/{ReconnectRefresher.d.ts → src/ReconnectRefresher.d.ts} +0 -0
- package/dist/{RedoUndo.d.ts → src/RedoUndo.d.ts} +0 -0
- package/dist/{Register → src/Register}/index.d.ts +4 -2
- package/dist/{Register → src/Register}/loader.d.ts +1 -1
- package/dist/src/Register/storage.d.ts +11 -0
- package/dist/{Utils → src/Utils}/AppCreateQueue.d.ts +0 -0
- package/dist/{Utils → src/Utils}/Common.d.ts +0 -0
- package/dist/{Utils → src/Utils}/Reactive.d.ts +1 -1
- package/dist/{Utils → src/Utils}/RoomHacker.d.ts +0 -0
- package/dist/{Utils → src/Utils}/error.d.ts +4 -1
- package/dist/{Utils → src/Utils}/log.d.ts +0 -0
- package/dist/src/View/CameraSynchronizer.d.ts +21 -0
- package/dist/{View → src/View}/MainView.d.ts +25 -7
- package/dist/src/View/ScrollMode.d.ts +32 -0
- package/dist/{View → src/View}/ViewManager.d.ts +0 -0
- package/dist/src/View/ViewSync.d.ts +32 -0
- package/dist/{callback.d.ts → src/callback.d.ts} +12 -1
- package/dist/{constants.d.ts → src/constants.d.ts} +12 -5
- package/dist/src/image.d.ts +19 -0
- package/dist/{index.d.ts → src/index.d.ts} +63 -17
- package/dist/src/shim.d.ts +11 -0
- package/dist/src/storage.d.ts +7 -0
- package/dist/{typings.d.ts → src/typings.d.ts} +21 -8
- package/dist/style.css +810 -1
- package/docs/api.md +10 -0
- package/docs/app-context.md +155 -27
- package/docs/mirgrate-to-1.0.md +68 -0
- package/package.json +27 -22
- package/playwright.config.ts +29 -0
- package/src/App/AppContext.ts +81 -46
- package/src/App/AppPageStateImpl.ts +3 -0
- package/src/App/AppProxy.ts +249 -141
- package/src/App/WhiteboardView.ts +37 -14
- package/src/App/index.ts +1 -0
- package/src/App/type.ts +22 -0
- package/src/AppListener.ts +27 -21
- package/src/AppManager.ts +96 -50
- package/src/AttributesDelegate.ts +6 -3
- package/src/BoxManager.ts +76 -38
- package/src/BuiltinApps.ts +9 -8
- package/src/Cursor/Cursor.svelte +6 -2
- package/src/Cursor/Cursor.ts +15 -4
- package/src/Cursor/icons.ts +6 -0
- package/src/Cursor/index.ts +16 -11
- package/src/Helper.ts +25 -7
- package/src/InternalEmitter.ts +1 -4
- package/src/Page/PageController.ts +3 -1
- package/src/PageState.ts +8 -1
- package/src/ReconnectRefresher.ts +7 -3
- package/src/Register/index.ts +36 -14
- package/src/Register/loader.ts +20 -9
- package/src/Register/storage.ts +26 -5
- package/src/Utils/Common.ts +3 -0
- package/src/Utils/Reactive.ts +29 -27
- package/src/Utils/RoomHacker.ts +3 -0
- package/src/Utils/error.ts +6 -2
- package/src/View/CameraSynchronizer.ts +55 -36
- package/src/View/MainView.ts +163 -77
- package/src/View/ScrollMode.ts +240 -0
- package/src/View/ViewSync.ts +138 -6
- package/src/callback.ts +8 -1
- package/src/constants.ts +11 -3
- package/src/image/pencil-eraser-1.svg +3 -0
- package/src/image/pencil-eraser-2.svg +3 -0
- package/src/image/pencil-eraser-3.svg +3 -0
- package/src/index.ts +197 -60
- package/src/storage.ts +15 -0
- package/src/style.css +18 -47
- package/src/typings.ts +24 -7
- package/vite.config.js +12 -7
- package/dist/App/AppViewSync.d.ts +0 -11
- package/dist/App/Storage/StorageEvent.d.ts +0 -8
- package/dist/App/Storage/index.d.ts +0 -39
- package/dist/App/Storage/typings.d.ts +0 -22
- package/dist/App/Storage/utils.d.ts +0 -5
- package/dist/App/WhiteboardView.d.ts +0 -21
- package/dist/Register/storage.d.ts +0 -8
- package/dist/View/CameraSynchronizer.d.ts +0 -17
- package/dist/View/ViewSync.d.ts +0 -7
- package/dist/index.cjs.js +0 -46
- package/dist/index.es.js +0 -16161
- package/pnpm-lock.yaml +0 -6302
- package/src/App/AppViewSync.ts +0 -68
- package/src/App/Storage/StorageEvent.ts +0 -21
- package/src/App/Storage/index.ts +0 -295
- package/src/App/Storage/typings.ts +0 -23
- package/src/App/Storage/utils.ts +0 -17
package/docs/api.md
CHANGED
@@ -283,6 +283,8 @@ manager.callbacks.on(events, listener)
|
|
283
283
|
| ready | undefined | | 当所有 APP 创建完毕时触发 |
|
284
284
|
| sceneStateChange | SceneState | | 当 sceneState 修改时触发 |
|
285
285
|
| pageStateChange | PageState | | |
|
286
|
+
| scrollStateChange | ScrollState | | 当在 `ScrollState` 变化时触发 |
|
287
|
+
| userScroll | void | | 当用户主动滚动时触发 |
|
286
288
|
|
287
289
|
```ts
|
288
290
|
type LoadAppEvent = {
|
@@ -297,4 +299,12 @@ type PageState = {
|
|
297
299
|
index: number;
|
298
300
|
length: number;
|
299
301
|
}
|
302
|
+
```
|
303
|
+
|
304
|
+
```ts
|
305
|
+
type ScrollState = {
|
306
|
+
scrollTop: number;
|
307
|
+
page: number;
|
308
|
+
maxScrollPage: number;
|
309
|
+
};
|
300
310
|
```
|
package/docs/app-context.md
CHANGED
@@ -4,8 +4,9 @@
|
|
4
4
|
- [view](#view)
|
5
5
|
- [page](#page)
|
6
6
|
- [storage](#storage)
|
7
|
-
- [
|
7
|
+
- [实例属性](#attributes)
|
8
8
|
- [box](#box)
|
9
|
+
- [events](#events)
|
9
10
|
- [Advanced](#Advanced)
|
10
11
|
|
11
12
|
<h2 id="api">API</h2>
|
@@ -75,7 +76,7 @@
|
|
75
76
|
```
|
76
77
|
|
77
78
|
```ts
|
78
|
-
const view = context.createWhiteBoardView(10); // 生成带有 10 页的白板
|
79
|
+
const view = context.createWhiteBoardView({ size: 10 }); // 生成带有 10 页的白板
|
79
80
|
```
|
80
81
|
|
81
82
|
- **WhiteBoardView**
|
@@ -148,6 +149,18 @@
|
|
148
149
|
console.log("pageStateChange", pageState)
|
149
150
|
})
|
150
151
|
```
|
152
|
+
- **setRect**
|
153
|
+
|
154
|
+
设置白板的显示的宽高\
|
155
|
+
在不同分辨率下会保证所有打开的窗口都能完整显示这个区域
|
156
|
+
|
157
|
+
```ts
|
158
|
+
const view = context.createWhiteBoardView();
|
159
|
+
// 此方法建议只在插入时设置一次
|
160
|
+
if (context.isAddApp) {
|
161
|
+
view.setRect({ width: 500, height: 500 })
|
162
|
+
}
|
163
|
+
```
|
151
164
|
|
152
165
|
<h3 id="storage">storage</h3>
|
153
166
|
|
@@ -253,53 +266,88 @@
|
|
253
266
|
context.dispatchMagixEvent("click", { data: "data" });
|
254
267
|
```
|
255
268
|
|
256
|
-
<h2 id="
|
269
|
+
<h2 id="attributes">属性</h2>
|
257
270
|
|
258
|
-
- **
|
271
|
+
- **destroyed**
|
259
272
|
|
260
|
-
|
273
|
+
当前应用是否已经被销毁
|
274
|
+
|
275
|
+
类型: `boolean`
|
261
276
|
|
262
277
|
```ts
|
263
|
-
|
264
|
-
// release your listeners
|
265
|
-
});
|
278
|
+
contest.destroyed
|
266
279
|
```
|
267
280
|
|
268
|
-
- **
|
281
|
+
- **members**
|
282
|
+
|
283
|
+
当前房间的所有用户
|
269
284
|
|
270
|
-
|
285
|
+
类型: `Member[]`
|
271
286
|
|
272
287
|
```ts
|
273
|
-
|
274
|
-
|
275
|
-
|
288
|
+
type Member = {
|
289
|
+
uid: string;
|
290
|
+
memberId: number;
|
291
|
+
memberState: MemberState;
|
292
|
+
session: string;
|
293
|
+
payload?: UserPayload;
|
294
|
+
}
|
276
295
|
```
|
277
296
|
|
278
|
-
- **
|
297
|
+
- **currentMember**
|
279
298
|
|
280
|
-
|
299
|
+
当前用户
|
300
|
+
|
301
|
+
类型: `Member`
|
281
302
|
|
282
303
|
```ts
|
283
|
-
context.
|
284
|
-
//
|
285
|
-
});
|
304
|
+
context.currentMember
|
286
305
|
```
|
287
306
|
|
288
|
-
<h2 id="Advanced">Advanced</h2>
|
289
307
|
|
290
|
-
|
308
|
+
<h2 id="box">box</h2>
|
291
309
|
|
292
|
-
|
310
|
+
`box` 为应用窗口本身
|
311
|
+
|
312
|
+
类型: `ReadonlyTeleBox`
|
313
|
+
|
314
|
+
- **mountStyles()**
|
315
|
+
|
316
|
+
挂载样式到 `box` 上
|
317
|
+
|
318
|
+
参数: `string | HTMLStyleElement`
|
293
319
|
|
294
320
|
```ts
|
295
|
-
|
321
|
+
box.mountStyles(`
|
322
|
+
.hello-world-app span {
|
323
|
+
color: red;
|
324
|
+
}
|
325
|
+
`);
|
296
326
|
```
|
297
327
|
|
298
|
-
|
328
|
+
- **mountContent()**
|
299
329
|
|
300
|
-
`box`
|
330
|
+
挂载元素到 `box` 中\
|
331
|
+
推荐使用 `mountStage` 方法挂载元素到 `stage` 中
|
301
332
|
|
302
|
-
|
333
|
+
参数: `HTMLElement`
|
334
|
+
|
335
|
+
```ts
|
336
|
+
const app = document.createElement("div");
|
337
|
+
box.mountContent(app);
|
338
|
+
```
|
339
|
+
|
340
|
+
- **mountStage()**
|
341
|
+
|
342
|
+
挂载元素到 `box` 的 `contentStage` 中\
|
343
|
+
如无特殊情况, 推荐把所有内容挂载到 `stage` 中
|
344
|
+
|
345
|
+
参数: `HTMLElement`
|
346
|
+
|
347
|
+
```ts
|
348
|
+
const app = document.createElement("div");
|
349
|
+
box.mountStage(app);
|
350
|
+
```
|
303
351
|
|
304
352
|
- **contentStageRect**
|
305
353
|
|
@@ -324,7 +372,87 @@
|
|
324
372
|
订阅 `contextStateRect` 的变化
|
325
373
|
|
326
374
|
```ts
|
327
|
-
box.
|
375
|
+
box.onValChanged("contentStageRect", rect => {
|
328
376
|
console.log("contentStageRect changed", rect);
|
329
377
|
});
|
330
|
-
```
|
378
|
+
```
|
379
|
+
|
380
|
+
- **highlightStage**
|
381
|
+
|
382
|
+
是否高亮 `stage` 区域\
|
383
|
+
默认为 `true`
|
384
|
+
|
385
|
+
类型: `boolean`
|
386
|
+
|
387
|
+
- **setHighlightStage()**
|
388
|
+
|
389
|
+
参数: `boolean`
|
390
|
+
|
391
|
+
|
392
|
+
- **$content**
|
393
|
+
|
394
|
+
应用窗口的内容区域
|
395
|
+
|
396
|
+
类型: `HTMLElement`
|
397
|
+
|
398
|
+
- **$footer**
|
399
|
+
|
400
|
+
应用窗口的底部区域
|
401
|
+
|
402
|
+
类型: `HTMLElement`
|
403
|
+
|
404
|
+
- **resizable**
|
405
|
+
|
406
|
+
是否可以改变窗口大小
|
407
|
+
|
408
|
+
类型: `boolean`
|
409
|
+
|
410
|
+
- **draggable**
|
411
|
+
|
412
|
+
窗口是否可以拖动
|
413
|
+
|
414
|
+
类型: `boolean`
|
415
|
+
|
416
|
+
|
417
|
+
<h2 id="events">events</h2>
|
418
|
+
|
419
|
+
- **destroy**
|
420
|
+
|
421
|
+
app 被关闭时发送
|
422
|
+
|
423
|
+
```ts
|
424
|
+
context.emitter.on("destroy", () => {
|
425
|
+
// release your listeners
|
426
|
+
});
|
427
|
+
```
|
428
|
+
|
429
|
+
- **writableChange**
|
430
|
+
|
431
|
+
白板可写状态切换时触发
|
432
|
+
|
433
|
+
```ts
|
434
|
+
context.emitter.on("writableChange", isWritable => {
|
435
|
+
//
|
436
|
+
});
|
437
|
+
```
|
438
|
+
|
439
|
+
- **focus**
|
440
|
+
|
441
|
+
当前 app 获得焦点或者失去焦点时触发
|
442
|
+
|
443
|
+
```ts
|
444
|
+
context.emitter.on("focus", focus => {
|
445
|
+
//
|
446
|
+
});
|
447
|
+
```
|
448
|
+
|
449
|
+
|
450
|
+
<h2 id="Advanced">Advanced</h2>
|
451
|
+
|
452
|
+
- **context.getView()**
|
453
|
+
|
454
|
+
获取 `view` 实例
|
455
|
+
|
456
|
+
```ts
|
457
|
+
const view = context.view;
|
458
|
+
```
|
@@ -0,0 +1,68 @@
|
|
1
|
+
## 迁移至 `@netless/window-manager@1.0`
|
2
|
+
|
3
|
+
### 样式
|
4
|
+
|
5
|
+
1.0 之前
|
6
|
+
|
7
|
+
```html
|
8
|
+
<div class="netless-window-manager-playground">
|
9
|
+
<div class="netless-window-manager-sizer">
|
10
|
+
<div class="netless-window-manager-wrapper">
|
11
|
+
<div class="netless-window-manager-main-view"></div>
|
12
|
+
</div>
|
13
|
+
</div>
|
14
|
+
</div>
|
15
|
+
```
|
16
|
+
|
17
|
+
1.0 之后
|
18
|
+
|
19
|
+
```html
|
20
|
+
<div class="netless-window-manager-playground">
|
21
|
+
<div class="telebox-manager-container">
|
22
|
+
<div class="telebox-manager-stage">
|
23
|
+
<div class="netless-window-manager-main-view"></div>
|
24
|
+
</div>
|
25
|
+
</div>
|
26
|
+
</div>
|
27
|
+
```
|
28
|
+
|
29
|
+
|
30
|
+
### `WindowManager.mount()` 迁移
|
31
|
+
|
32
|
+
废弃: `chessboard` 属性
|
33
|
+
|
34
|
+
- 添加: `containerStyle` 配置
|
35
|
+
- 配置 `telebox-manager-container` 的样式
|
36
|
+
- 添加: `stageStyle` 配置**
|
37
|
+
- 配置 `telebox-manager-stage` 的样式
|
38
|
+
- 添加: `defaultBoxBodyStyle` 配置
|
39
|
+
- 配置应用窗口默认 `body` 的样式
|
40
|
+
- 添加: `defaultBoxStageStyle` 配置
|
41
|
+
- 配置应用窗口默认 `stage` 也就是内容区域的样式
|
42
|
+
- 添加: `fullscreen` 配置
|
43
|
+
- 控制应用是否以全屏模式进入
|
44
|
+
- 添加: `theme` 配置
|
45
|
+
- 配置默认的颜色变量
|
46
|
+
|
47
|
+
### `manager.setContainerSizeRatio()` 行为修改
|
48
|
+
|
49
|
+
1.0 之前反复修改 `containerSizeRatio` 会导致内容一直变小
|
50
|
+
|
51
|
+
1.0 之后重复修改 `containerSizeRatio` 不会导致内容一致缩小
|
52
|
+
|
53
|
+
### baseSize
|
54
|
+
|
55
|
+
`baseSize` 主白板会去匹配内容到此大小
|
56
|
+
|
57
|
+
添加: `manager.baseSize` 属性\
|
58
|
+
添加: `manager.setBaseSize()` 方法\
|
59
|
+
添加: `baseSizeChange` 回调
|
60
|
+
|
61
|
+
### baseCamera
|
62
|
+
|
63
|
+
主白板的 `camera` 会根据 `baseSize` 的值和 `baseCamera` 的值计算一个最终值
|
64
|
+
|
65
|
+
添加: `manager.baseSize` 属性\
|
66
|
+
添加: `baseCamera` 回调
|
67
|
+
|
68
|
+
修改 `baseCamera` 依旧通过 `manager.moveCamera` 来实现
|
package/package.json
CHANGED
@@ -1,19 +1,21 @@
|
|
1
1
|
{
|
2
2
|
"name": "@netless/window-manager",
|
3
|
-
"version": "1.0.0-canary.
|
3
|
+
"version": "1.0.0-canary.71",
|
4
4
|
"description": "",
|
5
|
-
"main": "dist/index.
|
6
|
-
"module": "dist/index.
|
7
|
-
"types": "dist/index.d.ts",
|
5
|
+
"main": "dist/index.js",
|
6
|
+
"module": "dist/index.mjs",
|
7
|
+
"types": "dist/src/index.d.ts",
|
8
8
|
"repository": "netless-io/window-manager",
|
9
9
|
"scripts": {
|
10
10
|
"prettier": "prettier --write .",
|
11
|
-
"
|
11
|
+
"dev": "vite build --watch",
|
12
|
+
"build": "vite build",
|
12
13
|
"type-gen": "tsc --emitDeclarationOnly",
|
13
14
|
"predev": "yarn type-gen",
|
14
15
|
"build:lib:types": "tsc --emitDeclarationOnly",
|
15
16
|
"lint": "eslint --ext .ts,.tsx,.svelte . && prettier --check .",
|
16
|
-
"test": "vitest"
|
17
|
+
"test": "vitest",
|
18
|
+
"e2e": "playwright test"
|
17
19
|
},
|
18
20
|
"keywords": [],
|
19
21
|
"author": "",
|
@@ -23,45 +25,48 @@
|
|
23
25
|
},
|
24
26
|
"dependencies": {
|
25
27
|
"@juggle/resize-observer": "^3.3.1",
|
26
|
-
"@netless/
|
27
|
-
"
|
28
|
+
"@netless/synced-store": "^2.0.7",
|
29
|
+
"@netless/telebox-insider": "1.0.0-alpha.37",
|
30
|
+
"emittery": "^0.11.0",
|
28
31
|
"lodash": "^4.17.21",
|
29
|
-
"p-retry": "^4.6.
|
30
|
-
"side-effect-manager": "^1.1
|
32
|
+
"p-retry": "^4.6.2",
|
33
|
+
"side-effect-manager": "^1.2.1",
|
31
34
|
"uuid": "^7.0.3",
|
32
|
-
"value-enhancer": "^1.2
|
33
|
-
"video.js": ">=7"
|
35
|
+
"value-enhancer": "^1.3.2"
|
34
36
|
},
|
35
37
|
"devDependencies": {
|
36
|
-
"@netless/app-docs-viewer": "^0.
|
37
|
-
"@netless/app-
|
38
|
+
"@netless/app-docs-viewer": "^1.0.0-canary.3",
|
39
|
+
"@netless/app-plyr": "^0.2.4",
|
40
|
+
"@playwright/test": "^1.23.2",
|
38
41
|
"@rollup/plugin-commonjs": "^20.0.0",
|
39
42
|
"@rollup/plugin-node-resolve": "^13.0.4",
|
40
43
|
"@rollup/plugin-url": "^6.1.0",
|
41
|
-
"@sveltejs/vite-plugin-svelte": "^1.0.0-next.
|
44
|
+
"@sveltejs/vite-plugin-svelte": "^1.0.0-next.49",
|
42
45
|
"@tsconfig/svelte": "^2.0.1",
|
43
46
|
"@types/debug": "^4.1.7",
|
44
47
|
"@types/lodash": "^4.14.182",
|
45
|
-
"@types/lodash-es": "^4.17.
|
46
|
-
"@types/
|
48
|
+
"@types/lodash-es": "^4.17.6",
|
49
|
+
"@types/node": "^18.0.3",
|
50
|
+
"@types/uuid": "^8.3.4",
|
47
51
|
"@typescript-eslint/eslint-plugin": "^4.30.0",
|
48
52
|
"@typescript-eslint/parser": "^4.30.0",
|
49
|
-
"@vitest/ui": "^0.14.
|
53
|
+
"@vitest/ui": "^0.14.2",
|
50
54
|
"cypress": "^8.7.0",
|
51
55
|
"dotenv": "^10.0.0",
|
52
56
|
"eslint": "^7.32.0",
|
53
57
|
"eslint-config-prettier": "^8.3.0",
|
54
58
|
"eslint-plugin-svelte3": "^3.2.0",
|
55
59
|
"jsdom": "^19.0.0",
|
56
|
-
"less": "^4.1.
|
60
|
+
"less": "^4.1.3",
|
57
61
|
"prettier": "^2.3.2",
|
58
62
|
"prettier-plugin-svelte": "^2.4.0",
|
59
63
|
"rollup-plugin-analyzer": "^4.0.0",
|
60
64
|
"rollup-plugin-styles": "^3.14.1",
|
61
65
|
"svelte": "^3.42.4",
|
62
66
|
"typescript": "^4.5.5",
|
63
|
-
"vite": "^
|
64
|
-
"
|
65
|
-
"
|
67
|
+
"vite": "^3.1.3",
|
68
|
+
"vite-plugin-dts": "^1.5.0",
|
69
|
+
"vitest": "^0.23.4",
|
70
|
+
"white-web-sdk": "^2.16.35"
|
66
71
|
}
|
67
72
|
}
|
@@ -0,0 +1,29 @@
|
|
1
|
+
import type { PlaywrightTestConfig} from '@playwright/test';
|
2
|
+
import dotenv from "dotenv";
|
3
|
+
import path from "path";
|
4
|
+
|
5
|
+
dotenv.config({ path: path.resolve(__dirname, "example", ".env") });
|
6
|
+
|
7
|
+
const config: PlaywrightTestConfig = {
|
8
|
+
forbidOnly: !!process.env.CI,
|
9
|
+
retries: process.env.CI ? 2 : 0,
|
10
|
+
use: {
|
11
|
+
trace: 'on-first-retry',
|
12
|
+
baseURL: "http://localhost:4000",
|
13
|
+
headless: true,
|
14
|
+
},
|
15
|
+
timeout: 5 * 60 * 1000,
|
16
|
+
workers: 4,
|
17
|
+
projects: [
|
18
|
+
{
|
19
|
+
name: 'chrome',
|
20
|
+
use: {
|
21
|
+
launchOptions: {
|
22
|
+
executablePath: "/Applications/Google Chrome.app/Contents/MacOS/Google Chrome"
|
23
|
+
}
|
24
|
+
},
|
25
|
+
},
|
26
|
+
],
|
27
|
+
testDir: "./e2e",
|
28
|
+
};
|
29
|
+
export default config;
|
package/src/App/AppContext.ts
CHANGED
@@ -1,5 +1,4 @@
|
|
1
1
|
import { BoxNotCreatedError } from "../Utils/error";
|
2
|
-
import { Storage } from "./Storage";
|
3
2
|
import {
|
4
3
|
autorun,
|
5
4
|
listenDisposed,
|
@@ -7,17 +6,18 @@ import {
|
|
7
6
|
reaction,
|
8
7
|
unlistenDisposed,
|
9
8
|
unlistenUpdated,
|
10
|
-
toJS
|
9
|
+
toJS
|
11
10
|
} from "white-web-sdk";
|
11
|
+
import { Storage } from "@netless/synced-store";
|
12
12
|
import type {
|
13
13
|
Room,
|
14
14
|
SceneDefinition,
|
15
15
|
View,
|
16
|
-
EventListener as WhiteEventListener
|
16
|
+
EventListener as WhiteEventListener,
|
17
|
+
Player
|
17
18
|
} from "white-web-sdk";
|
18
19
|
import type { ReadonlyTeleBox } from "@netless/telebox-insider";
|
19
20
|
import type Emittery from "emittery";
|
20
|
-
import type { BoxManager } from "../BoxManager";
|
21
21
|
import type { AppEmitterEvent, Member } from "../index";
|
22
22
|
import type { AppManager } from "../AppManager";
|
23
23
|
import type { AppProxy } from "./AppProxy";
|
@@ -29,10 +29,15 @@ import type {
|
|
29
29
|
import { WhiteBoardView } from "./WhiteboardView";
|
30
30
|
import { findMemberByUid } from "../Helper";
|
31
31
|
import { MAX_PAGE_SIZE } from "../constants";
|
32
|
-
import {
|
33
|
-
import {
|
32
|
+
import { isBoolean, isNumber } from "lodash";
|
33
|
+
import { Val } from "value-enhancer";
|
34
34
|
|
35
|
-
export
|
35
|
+
export type CreateWhiteBoardViewParams = {
|
36
|
+
size?: number;
|
37
|
+
syncCamera?: boolean;
|
38
|
+
}
|
39
|
+
|
40
|
+
export class AppContext<TAttributes extends Record<string, any> = any, TMagixEventPayloads = any, TAppOptions = any> {
|
36
41
|
public readonly emitter: Emittery<AppEmitterEvent<TAttributes>>;
|
37
42
|
public readonly mobxUtils = {
|
38
43
|
autorun,
|
@@ -49,12 +54,11 @@ export class AppContext<TAttributes = any, TMagixEventPayloads = any, TAppOption
|
|
49
54
|
private store = this.manager.store;
|
50
55
|
public readonly isAddApp: boolean;
|
51
56
|
public readonly isReplay = this.manager.isReplay;
|
52
|
-
|
57
|
+
public whiteBoardView?: WhiteBoardView;
|
53
58
|
public _viewWrapper?: HTMLElement;
|
54
59
|
|
55
60
|
constructor(
|
56
61
|
private manager: AppManager,
|
57
|
-
private boxManager: BoxManager,
|
58
62
|
public appId: string,
|
59
63
|
private appProxy: AppProxy,
|
60
64
|
private appOptions?: TAppOptions | (() => TAppOptions)
|
@@ -63,9 +67,17 @@ export class AppContext<TAttributes = any, TMagixEventPayloads = any, TAppOption
|
|
63
67
|
this.isAddApp = appProxy.isAddApp;
|
64
68
|
}
|
65
69
|
|
66
|
-
public get displayer(){
|
70
|
+
public get displayer() {
|
67
71
|
return this.manager.displayer;
|
68
|
-
}
|
72
|
+
}
|
73
|
+
|
74
|
+
public get destroyed() {
|
75
|
+
return this.appProxy.status === "destroyed";
|
76
|
+
}
|
77
|
+
|
78
|
+
public get attributes(): TAttributes {
|
79
|
+
return this.appProxy.attributes;
|
80
|
+
}
|
69
81
|
|
70
82
|
/** @deprecated Use context.storage.state instead. */
|
71
83
|
public getAttributes = (): TAttributes | undefined => {
|
@@ -85,7 +97,16 @@ export class AppContext<TAttributes = any, TMagixEventPayloads = any, TAppOption
|
|
85
97
|
return this.appProxy.view;
|
86
98
|
};
|
87
99
|
|
88
|
-
public
|
100
|
+
public get now(): number {
|
101
|
+
if (this.isReplay) {
|
102
|
+
const player = this.displayer as Player;
|
103
|
+
return player.beginTimestamp + player.progressTime;
|
104
|
+
} else {
|
105
|
+
return (this.displayer as Room).calibrationTimestamp;
|
106
|
+
}
|
107
|
+
}
|
108
|
+
|
109
|
+
public createWhiteBoardView = (params?: CreateWhiteBoardViewParams): WhiteBoardView => {
|
89
110
|
if (this.whiteBoardView) {
|
90
111
|
return this.whiteBoardView;
|
91
112
|
}
|
@@ -93,23 +114,39 @@ export class AppContext<TAttributes = any, TMagixEventPayloads = any, TAppOption
|
|
93
114
|
if (!view) {
|
94
115
|
view = this.appProxy.createAppDir();
|
95
116
|
}
|
117
|
+
if (params) {
|
118
|
+
if (isBoolean(params.syncCamera)) {
|
119
|
+
this.appProxy.syncCamera$.setValue(params.syncCamera);
|
120
|
+
}
|
121
|
+
}
|
96
122
|
const viewWrapper = document.createElement("div");
|
97
123
|
this._viewWrapper = viewWrapper;
|
98
124
|
viewWrapper.className = "window-manager-view-wrapper";
|
99
|
-
this.box.$
|
100
|
-
const removeViewWrapper = () => {
|
101
|
-
this.box.$content.parentElement?.removeChild(viewWrapper);
|
102
|
-
this._viewWrapper = undefined;
|
103
|
-
}
|
125
|
+
this.box.$main.appendChild(viewWrapper);
|
104
126
|
view.divElement = viewWrapper;
|
127
|
+
this.appProxy.fireMemberStateChange();
|
105
128
|
if (this.isAddApp) {
|
106
|
-
this.
|
129
|
+
this.ensurePageSize(params?.size);
|
107
130
|
}
|
108
|
-
this.whiteBoardView = new WhiteBoardView(this, this.appProxy,
|
131
|
+
this.whiteBoardView = new WhiteBoardView(view, this, this.appProxy, this.ensurePageSize);
|
132
|
+
this.appProxy.sideEffectManager.add(() => [
|
133
|
+
this.box._stageRect$.subscribe(rect => {
|
134
|
+
viewWrapper.style.left = `${rect.x}px`;
|
135
|
+
viewWrapper.style.top = `${rect.y}px`;
|
136
|
+
viewWrapper.style.width = `${rect.width}px`;
|
137
|
+
viewWrapper.style.height = `${rect.height}px`;
|
138
|
+
}),
|
139
|
+
() => {
|
140
|
+
return () => {
|
141
|
+
this.whiteBoardView = undefined;
|
142
|
+
}
|
143
|
+
}
|
144
|
+
]);
|
145
|
+
this.appProxy.whiteBoardViewCreated$.setValue(true);
|
109
146
|
return this.whiteBoardView;
|
110
147
|
}
|
111
148
|
|
112
|
-
private
|
149
|
+
private ensurePageSize = (size?: number) => {
|
113
150
|
if (!isNumber(size)) return;
|
114
151
|
if (!this.appProxy.scenePath) return;
|
115
152
|
if (this.appProxy.pageState.length >= size) return;
|
@@ -117,25 +154,22 @@ export class AppContext<TAttributes = any, TMagixEventPayloads = any, TAppOption
|
|
117
154
|
throw Error(`[WindowManager]: size ${size} muse be in range [1, ${MAX_PAGE_SIZE}]`);
|
118
155
|
}
|
119
156
|
const needInsert = size - this.appProxy.pageState.length;
|
120
|
-
const
|
121
|
-
|
122
|
-
return { name: `${startPageNumber + index + 1}` };
|
123
|
-
});
|
124
|
-
putScenes(this.room, this.appProxy.scenePath, scenes);
|
157
|
+
const scenes = new Array(needInsert).fill({});
|
158
|
+
this.room?.putScenes(this.appProxy.scenePath, scenes);
|
125
159
|
}
|
126
160
|
|
127
161
|
public getInitScenePath = () => {
|
128
|
-
return this.
|
162
|
+
return this.appProxy.scenePath;
|
129
163
|
};
|
130
164
|
|
131
165
|
/** Get App writable status. */
|
132
166
|
public get isWritable(): boolean {
|
133
|
-
return this.manager.canOperate;
|
167
|
+
return this.manager.canOperate && !this.destroyed;
|
134
168
|
};
|
135
169
|
|
136
170
|
/** Get the App Window UI box. */
|
137
171
|
public get box(): ReadonlyTeleBox {
|
138
|
-
const box = this.
|
172
|
+
const box = this.appProxy.box$.value;
|
139
173
|
if (box) {
|
140
174
|
return box;
|
141
175
|
} else {
|
@@ -147,14 +181,15 @@ export class AppContext<TAttributes = any, TMagixEventPayloads = any, TAppOption
|
|
147
181
|
return this.manager.room;
|
148
182
|
};
|
149
183
|
|
150
|
-
public get members() {
|
151
|
-
return this.manager.members;
|
184
|
+
public get members(): Member[] {
|
185
|
+
return this.manager.members$.value;
|
152
186
|
}
|
153
187
|
|
154
|
-
|
188
|
+
//** currentMember is undefined in read-only and replay mode. */
|
189
|
+
public get currentMember(): Member | undefined {
|
155
190
|
const self = findMemberByUid(this.room, this.manager.uid);
|
156
191
|
if (!self) {
|
157
|
-
|
192
|
+
return undefined;
|
158
193
|
}
|
159
194
|
return {
|
160
195
|
uid: this.manager.uid,
|
@@ -189,26 +224,26 @@ export class AppContext<TAttributes = any, TMagixEventPayloads = any, TAppOption
|
|
189
224
|
: this.appOptions;
|
190
225
|
};
|
191
226
|
|
192
|
-
private _storage?: Storage<TAttributes>;
|
193
|
-
|
194
|
-
/** Main Storage for attributes. */
|
195
|
-
public get storage(): Storage<TAttributes> {
|
196
|
-
if (!this._storage) {
|
197
|
-
this._storage = new Storage(this);
|
198
|
-
}
|
199
|
-
return this._storage;
|
200
|
-
}
|
201
|
-
|
202
227
|
/**
|
203
228
|
* Create separated storages for flexible state management.
|
204
|
-
* @param
|
229
|
+
* @param namespace Namespace for the storage. Storages of the same namespace share the same data.
|
205
230
|
* @param defaultState Default state for initial storage creation.
|
206
231
|
* @returns
|
207
232
|
*/
|
208
|
-
public createStorage = <TState
|
209
|
-
const
|
233
|
+
public createStorage = <TState extends Record<string, any>>(namespace: string, defaultState?: TState): Storage<TState> => {
|
234
|
+
const isWritable$ = new Val(this.isWritable);
|
235
|
+
const plugin$ = new Val(this.manager.windowManger);
|
236
|
+
const storage = new Storage({
|
237
|
+
plugin$,
|
238
|
+
isWritable$,
|
239
|
+
namespace: `${this.appId}:${namespace}`,
|
240
|
+
defaultState: defaultState
|
241
|
+
});
|
242
|
+
this.emitter.on("writableChange", writable => {
|
243
|
+
isWritable$.setValue(writable);
|
244
|
+
})
|
210
245
|
this.emitter.on("destroy", () => {
|
211
|
-
storage.
|
246
|
+
storage.disconnect();
|
212
247
|
});
|
213
248
|
return storage;
|
214
249
|
};
|