@netless/fastboard-core 0.2.6 → 0.2.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{chunk-CS5DXHML.mjs → chunk-Z66W5SHZ.mjs} +65 -22
- package/dist/chunk-Z66W5SHZ.mjs.map +1 -0
- package/dist/index.js +63 -20
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +5 -1
- package/dist/index.mjs.map +1 -1
- package/dist/minimal.js +63 -20
- package/dist/minimal.js.map +1 -1
- package/dist/minimal.mjs +5 -1
- package/package.json +4 -9
- package/src/behaviors/register-apps.ts +33 -15
- package/src/helpers/utils.ts +4 -0
- package/src/helpers/value.ts +13 -3
- package/src/impl/app.ts +22 -2
- package/src/minimal.ts +24 -5
- package/dist/chunk-CS5DXHML.mjs.map +0 -1
package/dist/minimal.js
CHANGED
|
@@ -53,7 +53,9 @@ var __toCommonJS = /* @__PURE__ */ ((cache) => {
|
|
|
53
53
|
// src/minimal.ts
|
|
54
54
|
var minimal_exports = {};
|
|
55
55
|
__export(minimal_exports, {
|
|
56
|
+
DefaultApps: () => DefaultApps,
|
|
56
57
|
createFastboard: () => createFastboard,
|
|
58
|
+
registerApps: () => registerApps,
|
|
57
59
|
replayFastboard: () => replayFastboard
|
|
58
60
|
});
|
|
59
61
|
var import_white_web_sdk = require("white-web-sdk");
|
|
@@ -61,26 +63,43 @@ var import_window_manager4 = require("@netless/window-manager");
|
|
|
61
63
|
|
|
62
64
|
// src/behaviors/register-apps.ts
|
|
63
65
|
var import_window_manager = require("@netless/window-manager");
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
66
|
+
var DefaultApps = {
|
|
67
|
+
Monaco: {
|
|
68
|
+
src: "https://netless-app.oss-cn-hangzhou.aliyuncs.com/@netless/app-monaco/0.1.12/dist/main.iife.js"
|
|
69
|
+
},
|
|
70
|
+
Countdown: {
|
|
71
|
+
src: "https://netless-app.oss-cn-hangzhou.aliyuncs.com/@netless/app-countdown/0.0.2/dist/main.iife.js"
|
|
72
|
+
},
|
|
73
|
+
GeoGebra: {
|
|
74
|
+
src: "https://netless-app.oss-cn-hangzhou.aliyuncs.com/@netless/app-geogebra/0.0.4/dist/main.iife.js",
|
|
75
|
+
appOptions: {
|
|
76
|
+
HTML5Codebase: "https://flat-storage-cn-hz.whiteboard.agora.io/GeoGebra/HTML5/5.0/web3d"
|
|
77
|
+
}
|
|
78
|
+
},
|
|
79
|
+
EmbeddedPage: {
|
|
80
|
+
src: "https://netless-app.oss-cn-hangzhou.aliyuncs.com/@netless/app-embedded-page/0.1.1/dist/main.iife.js"
|
|
81
|
+
},
|
|
82
|
+
Player: {
|
|
83
|
+
name: "NetlessAppMediaPlayer",
|
|
84
|
+
src: "https://netless-app.oss-cn-hangzhou.aliyuncs.com/@netless/app-media-player/0.1.1/dist/main.iife.js"
|
|
77
85
|
}
|
|
78
|
-
}
|
|
86
|
+
};
|
|
87
|
+
function registerApps(config) {
|
|
88
|
+
for (const kind in config) {
|
|
89
|
+
if (Object.prototype.hasOwnProperty.call(config, kind)) {
|
|
90
|
+
const options = config[kind];
|
|
91
|
+
import_window_manager.WindowManager.register(__spreadValues({ kind }, options));
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
}
|
|
79
95
|
|
|
80
96
|
// src/helpers/utils.ts
|
|
81
97
|
var import_window_manager2 = require("@netless/window-manager");
|
|
82
98
|
function noop() {
|
|
83
99
|
}
|
|
100
|
+
function safe_not_equal(a, b) {
|
|
101
|
+
return a != a ? b == b : a !== b || a && typeof a === "object" || typeof a === "function";
|
|
102
|
+
}
|
|
84
103
|
function getImageSize(url, fallback) {
|
|
85
104
|
return new Promise((resolve) => {
|
|
86
105
|
const img = new Image();
|
|
@@ -163,7 +182,9 @@ var FastboardEmitter = class {
|
|
|
163
182
|
function createValue(value, effect, setValue = noop) {
|
|
164
183
|
const emitter = new FastboardEmitter();
|
|
165
184
|
function set(newValue) {
|
|
166
|
-
|
|
185
|
+
if (safe_not_equal(value, newValue)) {
|
|
186
|
+
emitter.dispatch(value = newValue);
|
|
187
|
+
}
|
|
167
188
|
}
|
|
168
189
|
const dispose = effect(set) || noop;
|
|
169
190
|
function subscribe(callback) {
|
|
@@ -175,7 +196,15 @@ function createValue(value, effect, setValue = noop) {
|
|
|
175
196
|
emitter.addListener(callback);
|
|
176
197
|
return () => emitter.removeListener(callback);
|
|
177
198
|
}
|
|
178
|
-
return {
|
|
199
|
+
return {
|
|
200
|
+
get value() {
|
|
201
|
+
return value;
|
|
202
|
+
},
|
|
203
|
+
subscribe,
|
|
204
|
+
reaction,
|
|
205
|
+
setValue,
|
|
206
|
+
dispose
|
|
207
|
+
};
|
|
179
208
|
}
|
|
180
209
|
|
|
181
210
|
// src/impl/app.ts
|
|
@@ -233,6 +262,14 @@ var FastboardApp = class extends FastboardAppBase {
|
|
|
233
262
|
this.memberState = this.createValue(this.room.state.memberState, (set) => this._addRoomListener("onRoomStateChanged", ({ memberState: m }) => m && set(m)));
|
|
234
263
|
this.sceneIndex = this.createValue(this.manager.mainViewSceneIndex, (set) => this._addManagerListener("mainViewSceneIndexChange", set), this.manager.setMainViewSceneIndex.bind(this.manager));
|
|
235
264
|
this.sceneLength = this.createValue(this.manager.mainViewScenesLength, (set) => this._addManagerListener("mainViewScenesLengthChange", set));
|
|
265
|
+
this._appsStatus = {};
|
|
266
|
+
this.appsStatus = this.createValue({}, (set) => this._addManagerListener("loadApp", ({ kind, status, reason }) => {
|
|
267
|
+
this._appsStatus[kind] = {
|
|
268
|
+
status: status === "start" ? "loading" : status === "failed" ? "failed" : "idle",
|
|
269
|
+
reason
|
|
270
|
+
};
|
|
271
|
+
set(this._appsStatus);
|
|
272
|
+
}));
|
|
236
273
|
}
|
|
237
274
|
bindContainer(container) {
|
|
238
275
|
this._assertNotDestroyed();
|
|
@@ -319,7 +356,6 @@ var FastboardApp = class extends FastboardAppBase {
|
|
|
319
356
|
this._assertNotDestroyed();
|
|
320
357
|
switch (fileType) {
|
|
321
358
|
case "pdf":
|
|
322
|
-
case "ppt":
|
|
323
359
|
return this.manager.addApp({
|
|
324
360
|
kind: "DocsViewer",
|
|
325
361
|
options: { scenePath, title, scenes }
|
|
@@ -456,8 +492,10 @@ async function createFastboard(_a) {
|
|
|
456
492
|
sdkConfig,
|
|
457
493
|
joinRoom: _c
|
|
458
494
|
} = _b, _d = _c, { callbacks } = _d, joinRoomParams = __objRest(_d, ["callbacks"]), {
|
|
459
|
-
managerConfig
|
|
495
|
+
managerConfig,
|
|
496
|
+
appsConfig = DefaultApps
|
|
460
497
|
} = _b;
|
|
498
|
+
registerApps(appsConfig);
|
|
461
499
|
const sdk = new import_white_web_sdk.WhiteWebSdk(__spreadProps(__spreadValues({}, sdkConfig), {
|
|
462
500
|
useMobXState: true
|
|
463
501
|
}));
|
|
@@ -497,19 +535,24 @@ async function replayFastboard(_a) {
|
|
|
497
535
|
sdkConfig,
|
|
498
536
|
replayRoom: _c
|
|
499
537
|
} = _b, _d = _c, { callbacks } = _d, replayRoomParams = __objRest(_d, ["callbacks"]), {
|
|
500
|
-
managerConfig
|
|
538
|
+
managerConfig,
|
|
539
|
+
appsConfig = DefaultApps
|
|
501
540
|
} = _b;
|
|
541
|
+
registerApps(appsConfig);
|
|
502
542
|
const sdk = new import_white_web_sdk.WhiteWebSdk(__spreadProps(__spreadValues({}, sdkConfig), {
|
|
503
543
|
useMobXState: true
|
|
504
544
|
}));
|
|
505
545
|
const player = await sdk.replayRoom(__spreadProps(__spreadValues({}, ensureWindowManager(replayRoomParams)), {
|
|
506
546
|
useMultiViews: true
|
|
507
547
|
}), callbacks);
|
|
508
|
-
const
|
|
548
|
+
const managerPromise = import_window_manager4.WindowManager.mount(__spreadProps(__spreadValues({
|
|
509
549
|
cursor: true
|
|
510
550
|
}, managerConfig), {
|
|
511
551
|
room: player
|
|
512
552
|
}));
|
|
553
|
+
player.play();
|
|
554
|
+
const manager = await managerPromise;
|
|
555
|
+
player.pause();
|
|
513
556
|
return new FastboardPlayer(sdk, player, manager);
|
|
514
557
|
}
|
|
515
558
|
module.exports = __toCommonJS(minimal_exports);
|
package/dist/minimal.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/minimal.ts","../src/behaviors/register-apps.ts","../src/helpers/utils.ts","../src/impl/app.ts","../src/helpers/emitter.ts","../src/helpers/value.ts","../src/impl/player.ts"],"sourcesContent":["import type {\n Displayer,\n HotKeys,\n JoinRoomParams,\n PlayerCallbacks,\n ReplayRoomParams,\n Room,\n RoomCallbacks,\n WhiteWebSdkConfiguration,\n} from \"white-web-sdk\";\nimport type { MountParams } from \"@netless/window-manager\";\n\nimport { contentModeScale, DefaultHotKeys, WhiteWebSdk } from \"white-web-sdk\";\nimport { WindowManager } from \"@netless/window-manager\";\n\nimport \"./behaviors/register-apps\";\nimport { ensureWindowManager } from \"./helpers/utils\";\nimport { FastboardApp } from \"./impl/app\";\nimport { FastboardPlayer } from \"./impl/player\";\n\nexport type { FastboardReadable, FastboardWritable } from \"./helpers/value\";\n\nexport type { FastboardApp };\n\nexport interface FastboardOptions {\n sdkConfig: Omit<WhiteWebSdkConfiguration, \"useMobXState\">;\n joinRoom: Omit<JoinRoomParams, \"useMultiViews\" | \"disableNewPencil\" | \"disableMagixEventDispatchLimit\"> & {\n callbacks?: Partial<RoomCallbacks>;\n };\n managerConfig?: Omit<MountParams, \"room\">;\n}\n\n/**\n * Create a FastboardApp instance.\n * @example\n * let app = await createFastboard({\n * sdkConfig: {\n * appIdentifier: import.meta.env.VITE_APPID,\n * },\n * joinRoom: {\n * uid: unique_id,\n * uuid: import.meta.env.VITE_ROOM_UUID,\n * roomToken: import.meta.env.VITE_ROOM_TOKEN,\n * },\n * })\n */\nexport async function createFastboard({\n sdkConfig,\n joinRoom: { callbacks, ...joinRoomParams },\n managerConfig,\n}: FastboardOptions) {\n const sdk = new WhiteWebSdk({\n ...sdkConfig,\n useMobXState: true,\n });\n\n const hotKeys: Partial<HotKeys> = {\n ...DefaultHotKeys,\n changeToSelector: \"s\",\n changeToLaserPointer: \"z\",\n changeToPencil: \"p\",\n changeToRectangle: \"r\",\n changeToEllipse: \"c\",\n changeToEraser: \"e\",\n changeToText: \"t\",\n changeToStraight: \"l\",\n changeToArrow: \"a\",\n changeToHand: \"h\",\n };\n\n const room = await sdk.joinRoom(\n {\n floatBar: true,\n hotKeys,\n ...ensureWindowManager(joinRoomParams),\n useMultiViews: true,\n disableNewPencil: false,\n disableMagixEventDispatchLimit: true,\n },\n callbacks\n );\n\n const manager = await WindowManager.mount({\n cursor: true,\n ...managerConfig,\n room,\n });\n\n manager.mainView.setCameraBound({\n minContentMode: contentModeScale(0.3),\n maxContentMode: contentModeScale(3),\n });\n\n return new FastboardApp(sdk, room, manager, hotKeys);\n}\n\nexport interface FastboardReplayOptions {\n sdkConfig: Omit<WhiteWebSdkConfiguration, \"useMobXState\">;\n replayRoom: Omit<ReplayRoomParams, \"useMultiViews\"> & {\n callbacks?: Partial<PlayerCallbacks>;\n };\n managerConfig?: Omit<MountParams, \"room\">;\n}\n\n/**\n * Create a FastboardPlayer instance.\n * @example\n * let app = await replayFastboard({\n * sdkConfig: {\n * appIdentifier: import.meta.env.VITE_APPID,\n * },\n * replayRoom: {\n * uid: unique_id,\n * uuid: import.meta.env.VITE_ROOM_UUID,\n * roomToken: import.meta.env.VITE_ROOM_TOKEN,\n * },\n * })\n */\nexport async function replayFastboard({\n sdkConfig,\n replayRoom: { callbacks, ...replayRoomParams },\n managerConfig,\n}: FastboardReplayOptions) {\n const sdk = new WhiteWebSdk({\n ...sdkConfig,\n useMobXState: true,\n });\n\n const player = await sdk.replayRoom(\n {\n ...ensureWindowManager(replayRoomParams),\n useMultiViews: true,\n },\n callbacks\n );\n\n const manager = await WindowManager.mount({\n cursor: true,\n ...managerConfig,\n room: player as Displayer as Room,\n });\n\n return new FastboardPlayer(sdk, player, manager);\n}\n","import { WindowManager } from \"@netless/window-manager\";\n\nWindowManager.register({\n kind: \"Monaco\",\n src: \"https://cdn.jsdelivr.net/npm/@netless/app-monaco@latest/dist/main.iife.js\",\n});\n\nWindowManager.register({\n kind: \"Countdown\",\n src: \"https://cdn.jsdelivr.net/npm/@netless/app-countdown@latest/dist/main.iife.js\",\n});\n\nWindowManager.register({\n kind: \"GeoGebra\",\n src: \"https://cdn.jsdelivr.net/npm/@netless/app-geogebra@latest/dist/main.iife.js\",\n appOptions: {\n HTML5Codebase: \"https://flat-storage-cn-hz.whiteboard.agora.io/GeoGebra/HTML5/5.0/web3d\",\n },\n});\n","import type { ConvertedFile, JoinRoomParams, ReplayRoomParams, SceneDefinition, Size } from \"white-web-sdk\";\nimport { WindowManager } from \"@netless/window-manager\";\n\nexport function noop() {\n /* noop */\n}\n\nexport function getImageSize(url: string, fallback: Size) {\n return new Promise<Size>(resolve => {\n const img = new Image();\n img.onload = () => resolve(img);\n img.onerror = () => resolve(fallback);\n img.src = url;\n });\n}\n\nexport function makeSlideParams(scenes: SceneDefinition[]) {\n const emptyScenes: SceneDefinition[] = [];\n let taskId = \"\";\n let url = \"\";\n\n // e.g. \"ppt(x)://cdn/prefix/dynamicConvert/{taskId}/1.slide\"\n const pptSrcRE = /^pptx?(?<prefix>:\\/\\/\\S+?dynamicConvert)\\/(?<taskId>\\w+)\\//;\n\n for (const { name, ppt } of scenes) {\n // make sure scenesWithoutPPT.length === scenes.length\n emptyScenes.push({ name });\n\n if (!ppt || !ppt.src.startsWith(\"ppt\")) {\n continue;\n }\n const match = pptSrcRE.exec(ppt.src);\n if (!match || !match.groups) {\n continue;\n }\n taskId = match.groups.taskId;\n url = \"https\" + match.groups.prefix;\n break;\n }\n\n return { emptyScenes, taskId, url };\n}\n\nexport function convertedFileToScene(f: ConvertedFile, i: number) {\n return {\n name: String(i + 1),\n ppt: {\n src: f.conversionFileUrl,\n width: f.width,\n height: f.height,\n previewURL: f.preview,\n },\n };\n}\n\nexport function ensureWindowManager<T extends JoinRoomParams | ReplayRoomParams>(joinRoom: T): T {\n if (!joinRoom.invisiblePlugins || !joinRoom.invisiblePlugins.includes(WindowManager)) {\n joinRoom.invisiblePlugins = [...(joinRoom.invisiblePlugins || []), WindowManager];\n }\n return joinRoom;\n}\n\n// Copy from https://github.com/crimx/side-effect-manager/blob/main/src/gen-uid.ts\nconst SOUP = \"!#%()*+,-./:;=?@[]^_`{|}~\" + \"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789\";\nconst SOUP_LEN = SOUP.length;\nconst ID_LEN = 20;\nconst reusedIdCarrier = /* @__PURE__ */ Array(ID_LEN);\n\nexport function genUID() {\n for (let i = 0; i < ID_LEN; i++) {\n reusedIdCarrier[i] = SOUP.charAt(Math.random() * SOUP_LEN);\n }\n return reusedIdCarrier.join(\"\");\n}\n","import type { PublicEvent, WindowManager } from \"@netless/window-manager\";\nimport type {\n AnimationMode,\n ApplianceNames,\n Camera,\n Color,\n ConversionResponse,\n HotKeys,\n MemberState,\n Rectangle,\n Room,\n RoomCallbacks,\n RoomState,\n SceneDefinition,\n ShapeType,\n ViewCallbacks,\n WhiteWebSdk,\n} from \"white-web-sdk\";\nimport type { FastboardDisposer, FastboardInternalValue } from \"../helpers/value\";\n\nimport { BuiltinApps } from \"@netless/window-manager\";\nimport { convertedFileToScene, genUID, getImageSize, makeSlideParams } from \"../helpers/utils\";\nimport { createValue } from \"../helpers/value\";\n\nclass FastboardAppBase {\n public constructor(\n readonly sdk: WhiteWebSdk,\n readonly room: Room,\n readonly manager: WindowManager,\n readonly hotKeys: Partial<HotKeys>\n ) {}\n\n protected readonly _disposers: FastboardDisposer[] = [];\n protected _destroyed = false;\n protected _assertNotDestroyed() {\n if (this._destroyed) {\n throw new Error(\"[FastboardApp] Can not call any method on destroyed FastboardApp.\");\n }\n }\n\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n protected createValue: typeof createValue = (...args: [any, any]): any => {\n const value = createValue(...args);\n this._disposers.push((value as FastboardInternalValue<unknown>).dispose);\n return value;\n };\n\n protected _addRoomListener<K extends keyof RoomCallbacks, T = RoomCallbacks[K]>(name: K, listener: T) {\n this._assertNotDestroyed();\n this.room.callbacks.on(name, listener);\n return () => this.room.callbacks.off(name, listener);\n }\n\n protected _addManagerListener<K extends keyof PublicEvent>(name: K, set: (value: PublicEvent[K]) => void) {\n this._assertNotDestroyed();\n this.manager.emitter.on(name, set);\n return () => this.manager.emitter.off(name, set);\n }\n\n protected _addMainViewListener<K extends keyof ViewCallbacks, T = ViewCallbacks[K]>(name: K, listener: T) {\n this._assertNotDestroyed();\n this.manager.mainView.callbacks.on(name, listener);\n return () => this.manager.mainView.callbacks.off(name, listener);\n }\n\n public destroy() {\n this._disposers.forEach(dispose => dispose());\n this._disposers.length = 0;\n this._destroyed = true;\n this.manager.destroy();\n return this.room.disconnect();\n }\n}\n\nexport interface InsertDocsStatic {\n readonly fileType: \"pdf\" | \"ppt\";\n readonly scenePath: string;\n readonly scenes: SceneDefinition[];\n readonly title?: string;\n}\n\nexport interface InsertDocsDynamic {\n readonly fileType: \"pptx\";\n readonly scenePath: string;\n readonly taskId: string;\n readonly title?: string;\n readonly url?: string;\n /** @example [{ name: '1' }, { name: '2' }, { name: '3' }] */\n readonly scenes?: SceneDefinition[];\n}\n\nexport type InsertDocsParams = InsertDocsStatic | InsertDocsDynamic;\n\nexport type SetMemberStateFn = (partialMemberState: Partial<MemberState>) => void;\n\nexport type RoomStateChanged = (diff: Partial<RoomState>) => void;\n\nexport class FastboardApp extends FastboardAppBase {\n /**\n * Render this app to some DOM.\n */\n bindContainer(container: HTMLElement) {\n this._assertNotDestroyed();\n this.manager.bindContainer(container);\n }\n\n /**\n * Move window-manager's collector to some place.\n */\n bindCollector(container: HTMLElement) {\n this._assertNotDestroyed();\n this.manager.bindCollectorContainer(container);\n }\n\n /**\n * Is current room writable?\n */\n readonly writable = this.createValue(\n this.room.isWritable,\n set => this._addRoomListener(\"onEnableWriteNowChanged\", () => set(this.room.isWritable)),\n this.room.setWritable.bind(this.room)\n );\n\n /**\n * Current window-manager's windows' state (is it maximized?).\n */\n readonly boxState = this.createValue(this.manager.boxState, set =>\n this._addManagerListener(\"boxStateChange\", set)\n );\n\n /**\n * Current window-manager's focused app's id.\n * @example \"HelloWorld-1A2b3C4d\"\n */\n readonly focusedApp = this.createValue(this.manager.focused, set =>\n this._addManagerListener(\"focusedChange\", set)\n );\n\n /**\n * How many times can I call `app.redo()`?\n */\n readonly canRedoSteps = this.createValue(this.manager.canRedoSteps, set =>\n this._addManagerListener(\"canRedoStepsChange\", set)\n );\n\n /**\n * How many times can I call `app.undo()`?\n */\n readonly canUndoSteps = this.createValue(this.manager.canUndoSteps, set =>\n this._addManagerListener(\"canUndoStepsChange\", set)\n );\n\n /**\n * Current camera information of main view.\n */\n readonly camera = this.createValue(this.manager.mainView.camera, set =>\n this._addMainViewListener(\"onCameraUpdated\", set)\n );\n\n /**\n * Current tool's info, like \"is using pencil?\", \"what color?\".\n */\n readonly memberState = this.createValue(this.room.state.memberState, set =>\n this._addRoomListener(\"onRoomStateChanged\", ({ memberState: m }) => m && set(m))\n );\n\n /**\n * 0..n-1, current index of main view scenes.\n */\n readonly sceneIndex = this.createValue(\n this.manager.mainViewSceneIndex,\n set => this._addManagerListener(\"mainViewSceneIndexChange\", set),\n this.manager.setMainViewSceneIndex.bind(this.manager)\n );\n\n /**\n * How many pages are in the main view?\n */\n readonly sceneLength = this.createValue(this.manager.mainViewScenesLength, set =>\n this._addManagerListener(\"mainViewScenesLengthChange\", set)\n );\n\n /**\n * Undo a step on main view.\n */\n undo() {\n this._assertNotDestroyed();\n this.manager.mainView.undo();\n }\n\n /**\n * Redo a step on main view.\n */\n redo() {\n this._assertNotDestroyed();\n this.manager.mainView.redo();\n }\n\n /**\n * Move current main view's camera position.\n */\n moveCamera(camera: Partial<Camera> & { animationMode?: AnimationMode | undefined }) {\n this._assertNotDestroyed();\n this.manager.moveCamera(camera);\n }\n\n /**\n * Move current main view's camera to include a rectangle.\n */\n moveCameraToContain(rectangle: Rectangle & { animationMode?: AnimationMode }) {\n this._assertNotDestroyed();\n this.manager.moveCameraToContain(rectangle);\n }\n\n /**\n * Delete all things on the main view.\n */\n cleanCurrentScene() {\n this._assertNotDestroyed();\n this.manager.cleanCurrentScene();\n }\n\n /**\n * Set current tool, like \"pencil\".\n */\n setAppliance(appliance: ApplianceNames, shape?: ShapeType) {\n this._assertNotDestroyed();\n this.manager.mainView.setMemberState({ currentApplianceName: appliance, shapeType: shape });\n }\n\n setStrokeWidth(strokeWidth: number) {\n this._assertNotDestroyed();\n this.manager.mainView.setMemberState({ strokeWidth });\n }\n\n setStrokeColor(strokeColor: Color) {\n this._assertNotDestroyed();\n this.manager.mainView.setMemberState({ strokeColor });\n }\n\n /**\n * Insert an image to the main view.\n */\n async insertImage(url: string) {\n this._assertNotDestroyed();\n await this.manager.switchMainViewToWriter();\n\n const { divElement } = this.manager.mainView;\n const containerSize = {\n width: divElement?.scrollWidth || window.innerWidth,\n height: divElement?.scrollHeight || window.innerHeight,\n };\n\n // 1. shrink the image a little to fit container **width**\n const maxWidth = containerSize.width * 0.8;\n let { width, height } = await getImageSize(url, containerSize);\n const scale = Math.min(maxWidth / width, 1);\n const uuid = genUID();\n const { centerX, centerY } = this.manager.camera;\n width *= scale;\n height *= scale;\n this.manager.mainView.insertImage({ uuid, centerX, centerY, width, height, locked: false });\n this.manager.mainView.completeImageUpload(uuid, url);\n\n // 2. move camera to fit image **height**\n width /= 0.8;\n height /= 0.8;\n const originX = centerX - width / 2;\n const originY = centerY - height / 2;\n this.manager.moveCameraToContain({ originX, originY, width, height });\n }\n\n /**\n * Insert PDF/PPTX from conversion result.\n * @param status https://developer.netless.link/server-en/home/server-conversion#get-query-task-conversion-progress\n */\n insertDocs(filename: string, status: ConversionResponse): Promise<string | undefined>;\n\n /**\n * Manual way.\n * @example\n * app.insertDocs({\n * fileType: 'pptx',\n * scenePath: `/pptx/${conversion.taskId}`,\n * taskId: conversion.taskId,\n * title: 'Title',\n * })\n */\n insertDocs(params: InsertDocsParams): Promise<string | undefined>;\n\n insertDocs(arg1: string | InsertDocsParams, arg2?: ConversionResponse) {\n if (typeof arg1 === \"object\" && \"fileType\" in arg1) {\n return this._insertDocsImpl(arg1);\n } else if (arg2 && arg2.status !== \"Finished\") {\n throw new Error(\"[FastboardApp] Can not insert a converting doc.\");\n } else if (arg2 && arg2.progress) {\n const scenes: SceneDefinition[] = arg2.progress.convertedFileList.map(convertedFileToScene);\n const scenePath = `/${arg2.uuid}/${genUID()}`;\n const { emptyScenes, taskId, url } = makeSlideParams(scenes);\n if (taskId && url) {\n const title = arg1;\n return this._insertDocsImpl({ fileType: \"pptx\", scenePath, taskId, title, url, scenes: emptyScenes });\n } else {\n return this._insertDocsImpl({ fileType: \"pdf\", scenePath, scenes, title: arg1 });\n }\n }\n }\n\n private _insertDocsImpl({ fileType, scenePath, title, scenes, ...attributes }: InsertDocsParams) {\n this._assertNotDestroyed();\n switch (fileType) {\n case \"pdf\":\n case \"ppt\":\n return this.manager.addApp({\n kind: \"DocsViewer\",\n options: { scenePath, title, scenes },\n });\n case \"pptx\":\n return this.manager.addApp({\n kind: \"Slide\",\n options: { scenePath, title, scenes },\n attributes,\n });\n }\n }\n\n /**\n * Insert the Monaco Code Editor app.\n */\n insertCodeEditor() {\n this._assertNotDestroyed();\n return this.manager.addApp({\n kind: \"Monaco\",\n options: { title: \"Code Editor\" },\n });\n }\n\n /**\n * Insert the Countdown app.\n */\n insertCountdown() {\n this._assertNotDestroyed();\n return this.manager.addApp({\n kind: \"Countdown\",\n options: { title: \"Countdown\" },\n });\n }\n\n /**\n * Insert the Media Player app.\n */\n insertMedia(title: string, src: string) {\n this._assertNotDestroyed();\n return this.manager.addApp({\n kind: BuiltinApps.MediaPlayer,\n options: { title },\n attributes: { src },\n });\n }\n\n /**\n * Insert the GeoGebra app.\n */\n insertGeoGebra() {\n this._assertNotDestroyed();\n return this.manager.addApp({\n kind: \"GeoGebra\",\n options: { title: \"GeoGebra\" },\n });\n }\n}\n","export type FastboardListener<T> = (event: T) => void;\n\nexport class FastboardEmitter<T> {\n listeners = new Set<FastboardListener<T>>();\n\n get length(): number {\n return this.listeners.size;\n }\n\n dispatch(message: T) {\n this.listeners.forEach(callback => callback(message));\n }\n\n addListener(listener: FastboardListener<T>) {\n this.listeners.add(listener);\n }\n\n removeListener(listener: FastboardListener<T>) {\n this.listeners.delete(listener);\n }\n}\n","import { FastboardEmitter } from \"./emitter\";\nimport { noop } from \"./utils\";\n\nexport type FastboardDisposer = () => void;\n\nexport interface FastboardReadable<T> {\n readonly value: T;\n subscribe(callback: (value: T) => void): FastboardDisposer;\n reaction(callback: (value: T) => void): FastboardDisposer;\n}\n\nexport interface FastboardWritable<T, SetFn = (value: T) => void> extends FastboardReadable<T> {\n setValue: SetFn;\n}\n\nexport interface FastboardInternalValue<T> extends FastboardWritable<T> {\n dispose: FastboardDisposer;\n}\n\n/**\n * Create a readonly, reactive value.\n * @example\n * createValue(manager.getMainViewSceneIndex(), (set) => {\n * manager.emitter.on(\"mainViewSceneIndexChanged\", set)\n * return () => manager.emitter.off(\"mainViewSceneIndexChanged\", set)\n * })\n */\nexport function createValue<T>(\n value: T,\n effect: (set: (value: T) => void) => FastboardDisposer | void\n): FastboardReadable<T>;\n\n/**\n * Create a writable, reactive value.\n * @example\n * createValue(manager.getMainViewSceneIndex(), (set) => {\n * manager.emitter.on(\"mainViewSceneIndexChanged\", set)\n * return () => manager.emitter.off(\"mainViewSceneIndexChanged\", set)\n * }, (newValue) => {\n * manager.setMainViewSceneIndex(newValue)\n * })\n */\nexport function createValue<T, SetFn = (value: T) => void>(\n value: T,\n effect: (set: (value: T) => void) => FastboardDisposer | void,\n set: (value: T) => void\n): FastboardWritable<T, SetFn>;\n\nexport function createValue<T>(\n value: T,\n effect: (set: (value: T) => void) => FastboardDisposer | void,\n setValue: (value: T) => void = noop\n): FastboardInternalValue<T> {\n const emitter = new FastboardEmitter<T>();\n\n function set(newValue: T) {\n emitter.dispatch((value = newValue));\n }\n\n const dispose = effect(set) || noop;\n\n function subscribe(callback: (value: T) => void) {\n emitter.addListener(callback);\n callback(value);\n return () => emitter.removeListener(callback);\n }\n\n function reaction(callback: (value: T) => void) {\n emitter.addListener(callback);\n return () => emitter.removeListener(callback);\n }\n\n return { value, subscribe, reaction, setValue, dispose };\n}\n","import type { Player, PlayerCallbacks, PlayerState, ViewCallbacks, WhiteWebSdk } from \"white-web-sdk\";\nimport type { PublicEvent, WindowManager } from \"@netless/window-manager\";\nimport type { FastboardDisposer, FastboardInternalValue } from \"../helpers/value\";\n\nimport { createValue } from \"../helpers/value\";\n\nclass FastboardPlayerBase {\n public constructor(readonly sdk: WhiteWebSdk, readonly player: Player, readonly manager: WindowManager) {}\n\n protected readonly _disposers: FastboardDisposer[] = [];\n protected _destroyed = false;\n protected _assertNotDestroyed() {\n if (this._destroyed) {\n throw new Error(\"[FastboardPlayer] Can not call any method on destroyed FastboardPlayer.\");\n }\n }\n\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n protected createValue: typeof createValue = (...args: [any, any]): any => {\n const value = createValue(...args);\n this._disposers.push((value as FastboardInternalValue<unknown>).dispose);\n return value;\n };\n\n protected _addPlayerListener<K extends keyof PlayerCallbacks, T = PlayerCallbacks[K]>(\n name: K,\n listener: T\n ) {\n this._assertNotDestroyed();\n this.player.callbacks.on(name, listener);\n return () => this.player.callbacks.off(name, listener);\n }\n\n protected _addManagerListener<K extends keyof PublicEvent>(name: K, set: (value: PublicEvent[K]) => void) {\n this._assertNotDestroyed();\n this.manager.emitter.on(name, set);\n return () => this.manager.emitter.off(name, set);\n }\n\n protected _addMainViewListener<K extends keyof ViewCallbacks, T = ViewCallbacks[K]>(name: K, listener: T) {\n this._assertNotDestroyed();\n this.manager.mainView.callbacks.on(name, listener);\n return () => this.manager.mainView.callbacks.off(name, listener);\n }\n\n public destroy() {\n this._disposers.forEach(dispose => dispose());\n this._disposers.length = 0;\n this._destroyed = true;\n this.manager.destroy();\n this.player.callbacks.off();\n }\n}\n\nexport class FastboardPlayer extends FastboardPlayerBase {\n /**\n * Render this player to some DOM.\n */\n bindContainer(container: HTMLElement) {\n this._assertNotDestroyed();\n this.manager.bindContainer(container);\n }\n\n /**\n * Move window-manager's collector to some place.\n */\n bindCollector(container: HTMLElement) {\n this._assertNotDestroyed();\n this.manager.bindCollectorContainer(container);\n }\n\n readonly currentTime = this.createValue(\n this.player.progressTime,\n set => this._addPlayerListener(\"onProgressTimeChanged\", set),\n this.player.seekToProgressTime.bind(this.player)\n );\n\n readonly phase = this.createValue(this.player.phase, set => this._addPlayerListener(\"onPhaseChanged\", set));\n\n readonly canplay = this.createValue(this.player.isPlayable, set =>\n this._addPlayerListener(\"onIsPlayableChanged\", set)\n );\n\n private _setSpeed!: (value: number) => void;\n readonly speed = this.createValue(\n this.player.playbackSpeed,\n set => {\n this._setSpeed = set;\n },\n value => {\n this.player.playbackSpeed = value;\n this._setSpeed(value);\n }\n );\n\n readonly state = this.createValue<PlayerState | null>(null, set => {\n const update = () => set(this.player.state);\n const dispose1 = this._addPlayerListener(\"onLoadFirstFrame\", update);\n const dispose2 = this._addPlayerListener(\"onPlayerStateChanged\", update);\n return () => (dispose1(), dispose2());\n });\n\n seek(timestamp: number) {\n this._assertNotDestroyed();\n return this.player.seekToProgressTime(timestamp);\n }\n\n play() {\n this._assertNotDestroyed();\n this.player.play();\n }\n\n pause() {\n this._assertNotDestroyed();\n this.player.pause();\n }\n\n stop() {\n this._assertNotDestroyed();\n this.player.stop();\n }\n}\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../src/minimal.ts","../src/behaviors/register-apps.ts","../src/helpers/utils.ts","../src/impl/app.ts","../src/helpers/emitter.ts","../src/helpers/value.ts","../src/impl/player.ts"],"sourcesContent":["import type {\n Displayer,\n HotKeys,\n JoinRoomParams,\n PlayerCallbacks,\n ReplayRoomParams,\n Room,\n RoomCallbacks,\n WhiteWebSdkConfiguration,\n} from \"white-web-sdk\";\nimport type { MountParams } from \"@netless/window-manager\";\n\nimport { contentModeScale, DefaultHotKeys, WhiteWebSdk } from \"white-web-sdk\";\nimport { WindowManager } from \"@netless/window-manager\";\n\nimport type { AppsConfig } from \"./behaviors/register-apps\";\n\nimport { DefaultApps, registerApps } from \"./behaviors/register-apps\";\nimport { ensureWindowManager } from \"./helpers/utils\";\nimport { FastboardApp } from \"./impl/app\";\nimport { FastboardPlayer } from \"./impl/player\";\n\nexport type { FastboardReadable, FastboardWritable } from \"./helpers/value\";\n\nexport type { AppsStatus, InsertDocsDynamic, InsertDocsParams, InsertDocsStatic } from \"./impl/app\";\n\nexport type { AppsConfig, FastboardApp, FastboardPlayer };\nexport { DefaultApps, registerApps };\n\nexport interface FastboardOptions {\n sdkConfig: Omit<WhiteWebSdkConfiguration, \"useMobXState\"> & { region: string };\n joinRoom: Omit<JoinRoomParams, \"useMultiViews\" | \"disableNewPencil\" | \"disableMagixEventDispatchLimit\"> & {\n callbacks?: Partial<RoomCallbacks>;\n };\n managerConfig?: Omit<MountParams, \"room\">;\n appsConfig?: AppsConfig;\n}\n\n/**\n * Create a FastboardApp instance.\n * @example\n * let app = await createFastboard({\n * sdkConfig: {\n * appIdentifier: import.meta.env.VITE_APPID,\n * region: \"ch-hz\",\n * },\n * joinRoom: {\n * uid: unique_id,\n * uuid: import.meta.env.VITE_ROOM_UUID,\n * roomToken: import.meta.env.VITE_ROOM_TOKEN,\n * },\n * })\n */\nexport async function createFastboard({\n sdkConfig,\n joinRoom: { callbacks, ...joinRoomParams },\n managerConfig,\n appsConfig = DefaultApps,\n}: FastboardOptions) {\n registerApps(appsConfig);\n\n const sdk = new WhiteWebSdk({\n ...sdkConfig,\n useMobXState: true,\n });\n\n const hotKeys: Partial<HotKeys> = {\n ...DefaultHotKeys,\n changeToSelector: \"s\",\n changeToLaserPointer: \"z\",\n changeToPencil: \"p\",\n changeToRectangle: \"r\",\n changeToEllipse: \"c\",\n changeToEraser: \"e\",\n changeToText: \"t\",\n changeToStraight: \"l\",\n changeToArrow: \"a\",\n changeToHand: \"h\",\n };\n\n const room = await sdk.joinRoom(\n {\n floatBar: true,\n hotKeys,\n ...ensureWindowManager(joinRoomParams),\n useMultiViews: true,\n disableNewPencil: false,\n disableMagixEventDispatchLimit: true,\n },\n callbacks\n );\n\n const manager = await WindowManager.mount({\n cursor: true,\n ...managerConfig,\n room,\n });\n\n manager.mainView.setCameraBound({\n minContentMode: contentModeScale(0.3),\n maxContentMode: contentModeScale(3),\n });\n\n return new FastboardApp(sdk, room, manager, hotKeys);\n}\n\nexport interface FastboardReplayOptions {\n sdkConfig: Omit<WhiteWebSdkConfiguration, \"useMobXState\"> & { region: string };\n replayRoom: Omit<ReplayRoomParams, \"useMultiViews\"> & {\n callbacks?: Partial<PlayerCallbacks>;\n };\n managerConfig?: Omit<MountParams, \"room\">;\n appsConfig?: AppsConfig;\n}\n\n/**\n * Create a FastboardPlayer instance.\n * @example\n * let app = await replayFastboard({\n * sdkConfig: {\n * appIdentifier: import.meta.env.VITE_APPID,\n * region: \"ch-hz\",\n * },\n * replayRoom: {\n * uid: unique_id,\n * uuid: import.meta.env.VITE_ROOM_UUID,\n * roomToken: import.meta.env.VITE_ROOM_TOKEN,\n * },\n * })\n */\nexport async function replayFastboard({\n sdkConfig,\n replayRoom: { callbacks, ...replayRoomParams },\n managerConfig,\n appsConfig = DefaultApps,\n}: FastboardReplayOptions) {\n registerApps(appsConfig);\n\n const sdk = new WhiteWebSdk({\n ...sdkConfig,\n useMobXState: true,\n });\n\n const player = await sdk.replayRoom(\n {\n ...ensureWindowManager(replayRoomParams),\n useMultiViews: true,\n },\n callbacks\n );\n\n const managerPromise = WindowManager.mount({\n cursor: true,\n ...managerConfig,\n room: player as Displayer as Room,\n });\n\n player.play();\n const manager = await managerPromise;\n player.pause();\n\n return new FastboardPlayer(sdk, player, manager);\n}\n","import type { RegisterParams } from \"@netless/window-manager\";\nimport { WindowManager } from \"@netless/window-manager\";\n\nexport interface AppsConfig {\n [kind: string]: Omit<RegisterParams, \"kind\">;\n}\n\nexport const DefaultApps: AppsConfig = {\n Monaco: {\n src: \"https://netless-app.oss-cn-hangzhou.aliyuncs.com/@netless/app-monaco/0.1.12/dist/main.iife.js\",\n },\n Countdown: {\n src: \"https://netless-app.oss-cn-hangzhou.aliyuncs.com/@netless/app-countdown/0.0.2/dist/main.iife.js\",\n },\n GeoGebra: {\n src: \"https://netless-app.oss-cn-hangzhou.aliyuncs.com/@netless/app-geogebra/0.0.4/dist/main.iife.js\",\n appOptions: {\n HTML5Codebase: \"https://flat-storage-cn-hz.whiteboard.agora.io/GeoGebra/HTML5/5.0/web3d\",\n },\n },\n EmbeddedPage: {\n src: \"https://netless-app.oss-cn-hangzhou.aliyuncs.com/@netless/app-embedded-page/0.1.1/dist/main.iife.js\",\n },\n Player: {\n name: \"NetlessAppMediaPlayer\",\n src: \"https://netless-app.oss-cn-hangzhou.aliyuncs.com/@netless/app-media-player/0.1.1/dist/main.iife.js\",\n },\n};\n\nexport function registerApps(config: AppsConfig) {\n for (const kind in config) {\n if (Object.prototype.hasOwnProperty.call(config, kind)) {\n const options = config[kind];\n WindowManager.register({ kind, ...options });\n }\n }\n}\n","import type { ConvertedFile, JoinRoomParams, ReplayRoomParams, SceneDefinition, Size } from \"white-web-sdk\";\nimport { WindowManager } from \"@netless/window-manager\";\n\nexport function noop() {\n /* noop */\n}\n\nexport function safe_not_equal(a: unknown, b: unknown) {\n return a != a ? b == b : a !== b || (a && typeof a === \"object\") || typeof a === \"function\";\n}\n\nexport function getImageSize(url: string, fallback: Size) {\n return new Promise<Size>(resolve => {\n const img = new Image();\n img.onload = () => resolve(img);\n img.onerror = () => resolve(fallback);\n img.src = url;\n });\n}\n\nexport function makeSlideParams(scenes: SceneDefinition[]) {\n const emptyScenes: SceneDefinition[] = [];\n let taskId = \"\";\n let url = \"\";\n\n // e.g. \"ppt(x)://cdn/prefix/dynamicConvert/{taskId}/1.slide\"\n const pptSrcRE = /^pptx?(?<prefix>:\\/\\/\\S+?dynamicConvert)\\/(?<taskId>\\w+)\\//;\n\n for (const { name, ppt } of scenes) {\n // make sure scenesWithoutPPT.length === scenes.length\n emptyScenes.push({ name });\n\n if (!ppt || !ppt.src.startsWith(\"ppt\")) {\n continue;\n }\n const match = pptSrcRE.exec(ppt.src);\n if (!match || !match.groups) {\n continue;\n }\n taskId = match.groups.taskId;\n url = \"https\" + match.groups.prefix;\n break;\n }\n\n return { emptyScenes, taskId, url };\n}\n\nexport function convertedFileToScene(f: ConvertedFile, i: number) {\n return {\n name: String(i + 1),\n ppt: {\n src: f.conversionFileUrl,\n width: f.width,\n height: f.height,\n previewURL: f.preview,\n },\n };\n}\n\nexport function ensureWindowManager<T extends JoinRoomParams | ReplayRoomParams>(joinRoom: T): T {\n if (!joinRoom.invisiblePlugins || !joinRoom.invisiblePlugins.includes(WindowManager)) {\n joinRoom.invisiblePlugins = [...(joinRoom.invisiblePlugins || []), WindowManager];\n }\n return joinRoom;\n}\n\n// Copy from https://github.com/crimx/side-effect-manager/blob/main/src/gen-uid.ts\nconst SOUP = \"!#%()*+,-./:;=?@[]^_`{|}~\" + \"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789\";\nconst SOUP_LEN = SOUP.length;\nconst ID_LEN = 20;\nconst reusedIdCarrier = /* @__PURE__ */ Array(ID_LEN);\n\nexport function genUID() {\n for (let i = 0; i < ID_LEN; i++) {\n reusedIdCarrier[i] = SOUP.charAt(Math.random() * SOUP_LEN);\n }\n return reusedIdCarrier.join(\"\");\n}\n","import type { PublicEvent, WindowManager } from \"@netless/window-manager\";\nimport type {\n AnimationMode,\n ApplianceNames,\n Camera,\n Color,\n ConversionResponse,\n HotKeys,\n MemberState,\n Rectangle,\n Room,\n RoomCallbacks,\n RoomState,\n SceneDefinition,\n ShapeType,\n ViewCallbacks,\n WhiteWebSdk,\n} from \"white-web-sdk\";\nimport type { FastboardDisposer, FastboardInternalValue } from \"../helpers/value\";\n\nimport { BuiltinApps } from \"@netless/window-manager\";\nimport { convertedFileToScene, genUID, getImageSize, makeSlideParams } from \"../helpers/utils\";\nimport { createValue } from \"../helpers/value\";\n\nclass FastboardAppBase {\n public constructor(\n readonly sdk: WhiteWebSdk,\n readonly room: Room,\n readonly manager: WindowManager,\n readonly hotKeys: Partial<HotKeys>\n ) {}\n\n protected readonly _disposers: FastboardDisposer[] = [];\n protected _destroyed = false;\n protected _assertNotDestroyed() {\n if (this._destroyed) {\n throw new Error(\"[FastboardApp] Can not call any method on destroyed FastboardApp.\");\n }\n }\n\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n protected createValue: typeof createValue = (...args: [any, any]): any => {\n const value = createValue(...args);\n this._disposers.push((value as FastboardInternalValue<unknown>).dispose);\n return value;\n };\n\n protected _addRoomListener<K extends keyof RoomCallbacks, T = RoomCallbacks[K]>(name: K, listener: T) {\n this._assertNotDestroyed();\n this.room.callbacks.on(name, listener);\n return () => this.room.callbacks.off(name, listener);\n }\n\n protected _addManagerListener<K extends keyof PublicEvent>(name: K, set: (value: PublicEvent[K]) => void) {\n this._assertNotDestroyed();\n this.manager.emitter.on(name, set);\n return () => this.manager.emitter.off(name, set);\n }\n\n protected _addMainViewListener<K extends keyof ViewCallbacks, T = ViewCallbacks[K]>(name: K, listener: T) {\n this._assertNotDestroyed();\n this.manager.mainView.callbacks.on(name, listener);\n return () => this.manager.mainView.callbacks.off(name, listener);\n }\n\n public destroy() {\n this._disposers.forEach(dispose => dispose());\n this._disposers.length = 0;\n this._destroyed = true;\n this.manager.destroy();\n return this.room.disconnect();\n }\n}\n\nexport interface InsertDocsStatic {\n readonly fileType: \"pdf\";\n readonly scenePath: string;\n readonly scenes: SceneDefinition[];\n readonly title?: string;\n}\n\nexport interface InsertDocsDynamic {\n readonly fileType: \"pptx\";\n readonly scenePath: string;\n readonly taskId: string;\n readonly title?: string;\n readonly url?: string;\n /** @example [{ name: '1' }, { name: '2' }, { name: '3' }] */\n readonly scenes?: SceneDefinition[];\n}\n\nexport type InsertDocsParams = InsertDocsStatic | InsertDocsDynamic;\n\nexport type SetMemberStateFn = (partialMemberState: Partial<MemberState>) => void;\n\nexport type RoomStateChanged = (diff: Partial<RoomState>) => void;\n\nexport interface AppsStatus {\n [kind: string]: {\n status: \"idle\" | \"loading\" | \"failed\";\n reason?: string;\n };\n}\n\nexport class FastboardApp extends FastboardAppBase {\n /**\n * Render this app to some DOM.\n */\n bindContainer(container: HTMLElement) {\n this._assertNotDestroyed();\n this.manager.bindContainer(container);\n }\n\n /**\n * Move window-manager's collector to some place.\n */\n bindCollector(container: HTMLElement) {\n this._assertNotDestroyed();\n this.manager.bindCollectorContainer(container);\n }\n\n /**\n * Is current room writable?\n */\n readonly writable = this.createValue(\n this.room.isWritable,\n set => this._addRoomListener(\"onEnableWriteNowChanged\", () => set(this.room.isWritable)),\n this.room.setWritable.bind(this.room)\n );\n\n /**\n * Current window-manager's windows' state (is it maximized?).\n */\n readonly boxState = this.createValue(this.manager.boxState, set =>\n this._addManagerListener(\"boxStateChange\", set)\n );\n\n /**\n * Current window-manager's focused app's id.\n * @example \"HelloWorld-1A2b3C4d\"\n */\n readonly focusedApp = this.createValue(this.manager.focused, set =>\n this._addManagerListener(\"focusedChange\", set)\n );\n\n /**\n * How many times can I call `app.redo()`?\n */\n readonly canRedoSteps = this.createValue(this.manager.canRedoSteps, set =>\n this._addManagerListener(\"canRedoStepsChange\", set)\n );\n\n /**\n * How many times can I call `app.undo()`?\n */\n readonly canUndoSteps = this.createValue(this.manager.canUndoSteps, set =>\n this._addManagerListener(\"canUndoStepsChange\", set)\n );\n\n /**\n * Current camera information of main view.\n */\n readonly camera = this.createValue(this.manager.mainView.camera, set =>\n this._addMainViewListener(\"onCameraUpdated\", set)\n );\n\n /**\n * Current tool's info, like \"is using pencil?\", \"what color?\".\n */\n readonly memberState = this.createValue(this.room.state.memberState, set =>\n this._addRoomListener(\"onRoomStateChanged\", ({ memberState: m }) => m && set(m))\n );\n\n /**\n * 0..n-1, current index of main view scenes.\n */\n readonly sceneIndex = this.createValue(\n this.manager.mainViewSceneIndex,\n set => this._addManagerListener(\"mainViewSceneIndexChange\", set),\n this.manager.setMainViewSceneIndex.bind(this.manager)\n );\n\n /**\n * How many pages are in the main view?\n */\n readonly sceneLength = this.createValue(this.manager.mainViewScenesLength, set =>\n this._addManagerListener(\"mainViewScenesLengthChange\", set)\n );\n\n private _appsStatus: AppsStatus = {};\n /**\n * Apps status.\n */\n readonly appsStatus = this.createValue<AppsStatus>({}, set =>\n this._addManagerListener(\"loadApp\", ({ kind, status, reason }) => {\n this._appsStatus[kind] = {\n status: status === \"start\" ? \"loading\" : status === \"failed\" ? \"failed\" : \"idle\",\n reason,\n };\n set(this._appsStatus);\n })\n );\n\n /**\n * Undo a step on main view.\n */\n undo() {\n this._assertNotDestroyed();\n this.manager.mainView.undo();\n }\n\n /**\n * Redo a step on main view.\n */\n redo() {\n this._assertNotDestroyed();\n this.manager.mainView.redo();\n }\n\n /**\n * Move current main view's camera position.\n */\n moveCamera(camera: Partial<Camera> & { animationMode?: AnimationMode | undefined }) {\n this._assertNotDestroyed();\n this.manager.moveCamera(camera);\n }\n\n /**\n * Move current main view's camera to include a rectangle.\n */\n moveCameraToContain(rectangle: Rectangle & { animationMode?: AnimationMode }) {\n this._assertNotDestroyed();\n this.manager.moveCameraToContain(rectangle);\n }\n\n /**\n * Delete all things on the main view.\n */\n cleanCurrentScene() {\n this._assertNotDestroyed();\n this.manager.cleanCurrentScene();\n }\n\n /**\n * Set current tool, like \"pencil\".\n */\n setAppliance(appliance: ApplianceNames, shape?: ShapeType) {\n this._assertNotDestroyed();\n this.manager.mainView.setMemberState({ currentApplianceName: appliance, shapeType: shape });\n }\n\n setStrokeWidth(strokeWidth: number) {\n this._assertNotDestroyed();\n this.manager.mainView.setMemberState({ strokeWidth });\n }\n\n setStrokeColor(strokeColor: Color) {\n this._assertNotDestroyed();\n this.manager.mainView.setMemberState({ strokeColor });\n }\n\n /**\n * Insert an image to the main view.\n */\n async insertImage(url: string) {\n this._assertNotDestroyed();\n await this.manager.switchMainViewToWriter();\n\n const { divElement } = this.manager.mainView;\n const containerSize = {\n width: divElement?.scrollWidth || window.innerWidth,\n height: divElement?.scrollHeight || window.innerHeight,\n };\n\n // 1. shrink the image a little to fit container **width**\n const maxWidth = containerSize.width * 0.8;\n let { width, height } = await getImageSize(url, containerSize);\n const scale = Math.min(maxWidth / width, 1);\n const uuid = genUID();\n const { centerX, centerY } = this.manager.camera;\n width *= scale;\n height *= scale;\n this.manager.mainView.insertImage({ uuid, centerX, centerY, width, height, locked: false });\n this.manager.mainView.completeImageUpload(uuid, url);\n\n // 2. move camera to fit image **height**\n width /= 0.8;\n height /= 0.8;\n const originX = centerX - width / 2;\n const originY = centerY - height / 2;\n this.manager.moveCameraToContain({ originX, originY, width, height });\n }\n\n /**\n * Insert PDF/PPTX from conversion result.\n * @param status https://developer.netless.link/server-en/home/server-conversion#get-query-task-conversion-progress\n */\n insertDocs(filename: string, status: ConversionResponse): Promise<string | undefined>;\n\n /**\n * Manual way.\n * @example\n * app.insertDocs({\n * fileType: 'pptx',\n * scenePath: `/pptx/${conversion.taskId}`,\n * taskId: conversion.taskId,\n * title: 'Title',\n * })\n */\n insertDocs(params: InsertDocsParams): Promise<string | undefined>;\n\n insertDocs(arg1: string | InsertDocsParams, arg2?: ConversionResponse) {\n if (typeof arg1 === \"object\" && \"fileType\" in arg1) {\n return this._insertDocsImpl(arg1);\n } else if (arg2 && arg2.status !== \"Finished\") {\n throw new Error(\"[FastboardApp] Can not insert a converting doc.\");\n } else if (arg2 && arg2.progress) {\n const scenes: SceneDefinition[] = arg2.progress.convertedFileList.map(convertedFileToScene);\n const scenePath = `/${arg2.uuid}/${genUID()}`;\n const { emptyScenes, taskId, url } = makeSlideParams(scenes);\n if (taskId && url) {\n const title = arg1;\n return this._insertDocsImpl({ fileType: \"pptx\", scenePath, taskId, title, url, scenes: emptyScenes });\n } else {\n return this._insertDocsImpl({ fileType: \"pdf\", scenePath, scenes, title: arg1 });\n }\n }\n }\n\n private _insertDocsImpl({ fileType, scenePath, title, scenes, ...attributes }: InsertDocsParams) {\n this._assertNotDestroyed();\n switch (fileType) {\n case \"pdf\":\n return this.manager.addApp({\n kind: \"DocsViewer\",\n options: { scenePath, title, scenes },\n });\n case \"pptx\":\n return this.manager.addApp({\n kind: \"Slide\",\n options: { scenePath, title, scenes },\n attributes,\n });\n }\n }\n\n /**\n * Insert the Monaco Code Editor app.\n */\n insertCodeEditor() {\n this._assertNotDestroyed();\n return this.manager.addApp({\n kind: \"Monaco\",\n options: { title: \"Code Editor\" },\n });\n }\n\n /**\n * Insert the Countdown app.\n */\n insertCountdown() {\n this._assertNotDestroyed();\n return this.manager.addApp({\n kind: \"Countdown\",\n options: { title: \"Countdown\" },\n });\n }\n\n /**\n * Insert the Media Player app.\n */\n insertMedia(title: string, src: string) {\n this._assertNotDestroyed();\n return this.manager.addApp({\n kind: BuiltinApps.MediaPlayer,\n options: { title },\n attributes: { src },\n });\n }\n\n /**\n * Insert the GeoGebra app.\n */\n insertGeoGebra() {\n this._assertNotDestroyed();\n return this.manager.addApp({\n kind: \"GeoGebra\",\n options: { title: \"GeoGebra\" },\n });\n }\n}\n","export type FastboardListener<T> = (event: T) => void;\n\nexport class FastboardEmitter<T> {\n listeners = new Set<FastboardListener<T>>();\n\n get length(): number {\n return this.listeners.size;\n }\n\n dispatch(message: T) {\n this.listeners.forEach(callback => callback(message));\n }\n\n addListener(listener: FastboardListener<T>) {\n this.listeners.add(listener);\n }\n\n removeListener(listener: FastboardListener<T>) {\n this.listeners.delete(listener);\n }\n}\n","import { FastboardEmitter } from \"./emitter\";\nimport { noop, safe_not_equal } from \"./utils\";\n\nexport type FastboardDisposer = () => void;\n\nexport interface FastboardReadable<T> {\n readonly value: T;\n subscribe(callback: (value: T) => void): FastboardDisposer;\n reaction(callback: (value: T) => void): FastboardDisposer;\n}\n\nexport interface FastboardWritable<T, SetFn = (value: T) => void> extends FastboardReadable<T> {\n setValue: SetFn;\n}\n\nexport interface FastboardInternalValue<T> extends FastboardWritable<T> {\n dispose: FastboardDisposer;\n}\n\n/**\n * Create a readonly, reactive value.\n * @example\n * createValue(manager.getMainViewSceneIndex(), (set) => {\n * manager.emitter.on(\"mainViewSceneIndexChanged\", set)\n * return () => manager.emitter.off(\"mainViewSceneIndexChanged\", set)\n * })\n */\nexport function createValue<T>(\n value: T,\n effect: (set: (value: T) => void) => FastboardDisposer | void\n): FastboardReadable<T>;\n\n/**\n * Create a writable, reactive value.\n * @example\n * createValue(manager.getMainViewSceneIndex(), (set) => {\n * manager.emitter.on(\"mainViewSceneIndexChanged\", set)\n * return () => manager.emitter.off(\"mainViewSceneIndexChanged\", set)\n * }, (newValue) => {\n * manager.setMainViewSceneIndex(newValue)\n * })\n */\nexport function createValue<T, SetFn = (value: T) => void>(\n value: T,\n effect: (set: (value: T) => void) => FastboardDisposer | void,\n set: (value: T) => void\n): FastboardWritable<T, SetFn>;\n\nexport function createValue<T>(\n value: T,\n effect: (set: (value: T) => void) => FastboardDisposer | void,\n setValue: (value: T) => void = noop\n): FastboardInternalValue<T> {\n const emitter = new FastboardEmitter<T>();\n\n function set(newValue: T) {\n if (safe_not_equal(value, newValue)) {\n emitter.dispatch((value = newValue));\n }\n }\n\n const dispose = effect(set) || noop;\n\n function subscribe(callback: (value: T) => void) {\n emitter.addListener(callback);\n callback(value);\n return () => emitter.removeListener(callback);\n }\n\n function reaction(callback: (value: T) => void) {\n emitter.addListener(callback);\n return () => emitter.removeListener(callback);\n }\n\n return {\n get value() {\n return value;\n },\n subscribe,\n reaction,\n setValue,\n dispose,\n };\n}\n","import type { Player, PlayerCallbacks, PlayerState, ViewCallbacks, WhiteWebSdk } from \"white-web-sdk\";\nimport type { PublicEvent, WindowManager } from \"@netless/window-manager\";\nimport type { FastboardDisposer, FastboardInternalValue } from \"../helpers/value\";\n\nimport { createValue } from \"../helpers/value\";\n\nclass FastboardPlayerBase {\n public constructor(readonly sdk: WhiteWebSdk, readonly player: Player, readonly manager: WindowManager) {}\n\n protected readonly _disposers: FastboardDisposer[] = [];\n protected _destroyed = false;\n protected _assertNotDestroyed() {\n if (this._destroyed) {\n throw new Error(\"[FastboardPlayer] Can not call any method on destroyed FastboardPlayer.\");\n }\n }\n\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n protected createValue: typeof createValue = (...args: [any, any]): any => {\n const value = createValue(...args);\n this._disposers.push((value as FastboardInternalValue<unknown>).dispose);\n return value;\n };\n\n protected _addPlayerListener<K extends keyof PlayerCallbacks, T = PlayerCallbacks[K]>(\n name: K,\n listener: T\n ) {\n this._assertNotDestroyed();\n this.player.callbacks.on(name, listener);\n return () => this.player.callbacks.off(name, listener);\n }\n\n protected _addManagerListener<K extends keyof PublicEvent>(name: K, set: (value: PublicEvent[K]) => void) {\n this._assertNotDestroyed();\n this.manager.emitter.on(name, set);\n return () => this.manager.emitter.off(name, set);\n }\n\n protected _addMainViewListener<K extends keyof ViewCallbacks, T = ViewCallbacks[K]>(name: K, listener: T) {\n this._assertNotDestroyed();\n this.manager.mainView.callbacks.on(name, listener);\n return () => this.manager.mainView.callbacks.off(name, listener);\n }\n\n public destroy() {\n this._disposers.forEach(dispose => dispose());\n this._disposers.length = 0;\n this._destroyed = true;\n this.manager.destroy();\n this.player.callbacks.off();\n }\n}\n\nexport class FastboardPlayer extends FastboardPlayerBase {\n /**\n * Render this player to some DOM.\n */\n bindContainer(container: HTMLElement) {\n this._assertNotDestroyed();\n this.manager.bindContainer(container);\n }\n\n /**\n * Move window-manager's collector to some place.\n */\n bindCollector(container: HTMLElement) {\n this._assertNotDestroyed();\n this.manager.bindCollectorContainer(container);\n }\n\n readonly currentTime = this.createValue(\n this.player.progressTime,\n set => this._addPlayerListener(\"onProgressTimeChanged\", set),\n this.player.seekToProgressTime.bind(this.player)\n );\n\n readonly phase = this.createValue(this.player.phase, set => this._addPlayerListener(\"onPhaseChanged\", set));\n\n readonly canplay = this.createValue(this.player.isPlayable, set =>\n this._addPlayerListener(\"onIsPlayableChanged\", set)\n );\n\n private _setSpeed!: (value: number) => void;\n readonly speed = this.createValue(\n this.player.playbackSpeed,\n set => {\n this._setSpeed = set;\n },\n value => {\n this.player.playbackSpeed = value;\n this._setSpeed(value);\n }\n );\n\n readonly state = this.createValue<PlayerState | null>(null, set => {\n const update = () => set(this.player.state);\n const dispose1 = this._addPlayerListener(\"onLoadFirstFrame\", update);\n const dispose2 = this._addPlayerListener(\"onPlayerStateChanged\", update);\n return () => (dispose1(), dispose2());\n });\n\n seek(timestamp: number) {\n this._assertNotDestroyed();\n return this.player.seekToProgressTime(timestamp);\n }\n\n play() {\n this._assertNotDestroyed();\n this.player.play();\n }\n\n pause() {\n this._assertNotDestroyed();\n this.player.pause();\n }\n\n stop() {\n this._assertNotDestroyed();\n this.player.stop();\n }\n}\n"],"mappings":"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","names":[]}
|
package/dist/minimal.mjs
CHANGED
|
@@ -1,9 +1,13 @@
|
|
|
1
1
|
import {
|
|
2
|
+
DefaultApps,
|
|
2
3
|
createFastboard,
|
|
4
|
+
registerApps,
|
|
3
5
|
replayFastboard
|
|
4
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-Z66W5SHZ.mjs";
|
|
5
7
|
export {
|
|
8
|
+
DefaultApps,
|
|
6
9
|
createFastboard,
|
|
10
|
+
registerApps,
|
|
7
11
|
replayFastboard
|
|
8
12
|
};
|
|
9
13
|
//# sourceMappingURL=minimal.mjs.map
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@netless/fastboard-core",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.9",
|
|
4
4
|
"description": "A tiny wrapper of white-web-sdk and @netless/window-manager.",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"files": [
|
|
@@ -17,14 +17,9 @@
|
|
|
17
17
|
"white-web-sdk": ">=2.16.0"
|
|
18
18
|
},
|
|
19
19
|
"devDependencies": {
|
|
20
|
-
"@netless/window-manager": "^0.4.
|
|
21
|
-
"tsup": "^5.11.
|
|
22
|
-
"white-web-sdk": "^2.16.
|
|
23
|
-
},
|
|
24
|
-
"publishConfig": {
|
|
25
|
-
"main": "dist/index.js",
|
|
26
|
-
"module": "dist/index.mjs",
|
|
27
|
-
"types": "src/index.ts"
|
|
20
|
+
"@netless/window-manager": "^0.4.10",
|
|
21
|
+
"tsup": "^5.11.13",
|
|
22
|
+
"white-web-sdk": "^2.16.10"
|
|
28
23
|
},
|
|
29
24
|
"scripts": {
|
|
30
25
|
"build": "tsup",
|
|
@@ -1,19 +1,37 @@
|
|
|
1
|
+
import type { RegisterParams } from "@netless/window-manager";
|
|
1
2
|
import { WindowManager } from "@netless/window-manager";
|
|
2
3
|
|
|
3
|
-
|
|
4
|
-
kind: "
|
|
5
|
-
|
|
6
|
-
});
|
|
4
|
+
export interface AppsConfig {
|
|
5
|
+
[kind: string]: Omit<RegisterParams, "kind">;
|
|
6
|
+
}
|
|
7
7
|
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
8
|
+
export const DefaultApps: AppsConfig = {
|
|
9
|
+
Monaco: {
|
|
10
|
+
src: "https://netless-app.oss-cn-hangzhou.aliyuncs.com/@netless/app-monaco/0.1.12/dist/main.iife.js",
|
|
11
|
+
},
|
|
12
|
+
Countdown: {
|
|
13
|
+
src: "https://netless-app.oss-cn-hangzhou.aliyuncs.com/@netless/app-countdown/0.0.2/dist/main.iife.js",
|
|
14
|
+
},
|
|
15
|
+
GeoGebra: {
|
|
16
|
+
src: "https://netless-app.oss-cn-hangzhou.aliyuncs.com/@netless/app-geogebra/0.0.4/dist/main.iife.js",
|
|
17
|
+
appOptions: {
|
|
18
|
+
HTML5Codebase: "https://flat-storage-cn-hz.whiteboard.agora.io/GeoGebra/HTML5/5.0/web3d",
|
|
19
|
+
},
|
|
18
20
|
},
|
|
19
|
-
|
|
21
|
+
EmbeddedPage: {
|
|
22
|
+
src: "https://netless-app.oss-cn-hangzhou.aliyuncs.com/@netless/app-embedded-page/0.1.1/dist/main.iife.js",
|
|
23
|
+
},
|
|
24
|
+
Player: {
|
|
25
|
+
name: "NetlessAppMediaPlayer",
|
|
26
|
+
src: "https://netless-app.oss-cn-hangzhou.aliyuncs.com/@netless/app-media-player/0.1.1/dist/main.iife.js",
|
|
27
|
+
},
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
export function registerApps(config: AppsConfig) {
|
|
31
|
+
for (const kind in config) {
|
|
32
|
+
if (Object.prototype.hasOwnProperty.call(config, kind)) {
|
|
33
|
+
const options = config[kind];
|
|
34
|
+
WindowManager.register({ kind, ...options });
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
}
|
package/src/helpers/utils.ts
CHANGED
|
@@ -5,6 +5,10 @@ export function noop() {
|
|
|
5
5
|
/* noop */
|
|
6
6
|
}
|
|
7
7
|
|
|
8
|
+
export function safe_not_equal(a: unknown, b: unknown) {
|
|
9
|
+
return a != a ? b == b : a !== b || (a && typeof a === "object") || typeof a === "function";
|
|
10
|
+
}
|
|
11
|
+
|
|
8
12
|
export function getImageSize(url: string, fallback: Size) {
|
|
9
13
|
return new Promise<Size>(resolve => {
|
|
10
14
|
const img = new Image();
|
package/src/helpers/value.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { FastboardEmitter } from "./emitter";
|
|
2
|
-
import { noop } from "./utils";
|
|
2
|
+
import { noop, safe_not_equal } from "./utils";
|
|
3
3
|
|
|
4
4
|
export type FastboardDisposer = () => void;
|
|
5
5
|
|
|
@@ -54,7 +54,9 @@ export function createValue<T>(
|
|
|
54
54
|
const emitter = new FastboardEmitter<T>();
|
|
55
55
|
|
|
56
56
|
function set(newValue: T) {
|
|
57
|
-
|
|
57
|
+
if (safe_not_equal(value, newValue)) {
|
|
58
|
+
emitter.dispatch((value = newValue));
|
|
59
|
+
}
|
|
58
60
|
}
|
|
59
61
|
|
|
60
62
|
const dispose = effect(set) || noop;
|
|
@@ -70,5 +72,13 @@ export function createValue<T>(
|
|
|
70
72
|
return () => emitter.removeListener(callback);
|
|
71
73
|
}
|
|
72
74
|
|
|
73
|
-
return {
|
|
75
|
+
return {
|
|
76
|
+
get value() {
|
|
77
|
+
return value;
|
|
78
|
+
},
|
|
79
|
+
subscribe,
|
|
80
|
+
reaction,
|
|
81
|
+
setValue,
|
|
82
|
+
dispose,
|
|
83
|
+
};
|
|
74
84
|
}
|
package/src/impl/app.ts
CHANGED
|
@@ -73,7 +73,7 @@ class FastboardAppBase {
|
|
|
73
73
|
}
|
|
74
74
|
|
|
75
75
|
export interface InsertDocsStatic {
|
|
76
|
-
readonly fileType: "pdf"
|
|
76
|
+
readonly fileType: "pdf";
|
|
77
77
|
readonly scenePath: string;
|
|
78
78
|
readonly scenes: SceneDefinition[];
|
|
79
79
|
readonly title?: string;
|
|
@@ -95,6 +95,13 @@ export type SetMemberStateFn = (partialMemberState: Partial<MemberState>) => voi
|
|
|
95
95
|
|
|
96
96
|
export type RoomStateChanged = (diff: Partial<RoomState>) => void;
|
|
97
97
|
|
|
98
|
+
export interface AppsStatus {
|
|
99
|
+
[kind: string]: {
|
|
100
|
+
status: "idle" | "loading" | "failed";
|
|
101
|
+
reason?: string;
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
|
|
98
105
|
export class FastboardApp extends FastboardAppBase {
|
|
99
106
|
/**
|
|
100
107
|
* Render this app to some DOM.
|
|
@@ -180,6 +187,20 @@ export class FastboardApp extends FastboardAppBase {
|
|
|
180
187
|
this._addManagerListener("mainViewScenesLengthChange", set)
|
|
181
188
|
);
|
|
182
189
|
|
|
190
|
+
private _appsStatus: AppsStatus = {};
|
|
191
|
+
/**
|
|
192
|
+
* Apps status.
|
|
193
|
+
*/
|
|
194
|
+
readonly appsStatus = this.createValue<AppsStatus>({}, set =>
|
|
195
|
+
this._addManagerListener("loadApp", ({ kind, status, reason }) => {
|
|
196
|
+
this._appsStatus[kind] = {
|
|
197
|
+
status: status === "start" ? "loading" : status === "failed" ? "failed" : "idle",
|
|
198
|
+
reason,
|
|
199
|
+
};
|
|
200
|
+
set(this._appsStatus);
|
|
201
|
+
})
|
|
202
|
+
);
|
|
203
|
+
|
|
183
204
|
/**
|
|
184
205
|
* Undo a step on main view.
|
|
185
206
|
*/
|
|
@@ -310,7 +331,6 @@ export class FastboardApp extends FastboardAppBase {
|
|
|
310
331
|
this._assertNotDestroyed();
|
|
311
332
|
switch (fileType) {
|
|
312
333
|
case "pdf":
|
|
313
|
-
case "ppt":
|
|
314
334
|
return this.manager.addApp({
|
|
315
335
|
kind: "DocsViewer",
|
|
316
336
|
options: { scenePath, title, scenes },
|
package/src/minimal.ts
CHANGED
|
@@ -13,21 +13,27 @@ import type { MountParams } from "@netless/window-manager";
|
|
|
13
13
|
import { contentModeScale, DefaultHotKeys, WhiteWebSdk } from "white-web-sdk";
|
|
14
14
|
import { WindowManager } from "@netless/window-manager";
|
|
15
15
|
|
|
16
|
-
import "./behaviors/register-apps";
|
|
16
|
+
import type { AppsConfig } from "./behaviors/register-apps";
|
|
17
|
+
|
|
18
|
+
import { DefaultApps, registerApps } from "./behaviors/register-apps";
|
|
17
19
|
import { ensureWindowManager } from "./helpers/utils";
|
|
18
20
|
import { FastboardApp } from "./impl/app";
|
|
19
21
|
import { FastboardPlayer } from "./impl/player";
|
|
20
22
|
|
|
21
23
|
export type { FastboardReadable, FastboardWritable } from "./helpers/value";
|
|
22
24
|
|
|
23
|
-
export type {
|
|
25
|
+
export type { AppsStatus, InsertDocsDynamic, InsertDocsParams, InsertDocsStatic } from "./impl/app";
|
|
26
|
+
|
|
27
|
+
export type { AppsConfig, FastboardApp, FastboardPlayer };
|
|
28
|
+
export { DefaultApps, registerApps };
|
|
24
29
|
|
|
25
30
|
export interface FastboardOptions {
|
|
26
|
-
sdkConfig: Omit<WhiteWebSdkConfiguration, "useMobXState"
|
|
31
|
+
sdkConfig: Omit<WhiteWebSdkConfiguration, "useMobXState"> & { region: string };
|
|
27
32
|
joinRoom: Omit<JoinRoomParams, "useMultiViews" | "disableNewPencil" | "disableMagixEventDispatchLimit"> & {
|
|
28
33
|
callbacks?: Partial<RoomCallbacks>;
|
|
29
34
|
};
|
|
30
35
|
managerConfig?: Omit<MountParams, "room">;
|
|
36
|
+
appsConfig?: AppsConfig;
|
|
31
37
|
}
|
|
32
38
|
|
|
33
39
|
/**
|
|
@@ -36,6 +42,7 @@ export interface FastboardOptions {
|
|
|
36
42
|
* let app = await createFastboard({
|
|
37
43
|
* sdkConfig: {
|
|
38
44
|
* appIdentifier: import.meta.env.VITE_APPID,
|
|
45
|
+
* region: "ch-hz",
|
|
39
46
|
* },
|
|
40
47
|
* joinRoom: {
|
|
41
48
|
* uid: unique_id,
|
|
@@ -48,7 +55,10 @@ export async function createFastboard({
|
|
|
48
55
|
sdkConfig,
|
|
49
56
|
joinRoom: { callbacks, ...joinRoomParams },
|
|
50
57
|
managerConfig,
|
|
58
|
+
appsConfig = DefaultApps,
|
|
51
59
|
}: FastboardOptions) {
|
|
60
|
+
registerApps(appsConfig);
|
|
61
|
+
|
|
52
62
|
const sdk = new WhiteWebSdk({
|
|
53
63
|
...sdkConfig,
|
|
54
64
|
useMobXState: true,
|
|
@@ -95,11 +105,12 @@ export async function createFastboard({
|
|
|
95
105
|
}
|
|
96
106
|
|
|
97
107
|
export interface FastboardReplayOptions {
|
|
98
|
-
sdkConfig: Omit<WhiteWebSdkConfiguration, "useMobXState"
|
|
108
|
+
sdkConfig: Omit<WhiteWebSdkConfiguration, "useMobXState"> & { region: string };
|
|
99
109
|
replayRoom: Omit<ReplayRoomParams, "useMultiViews"> & {
|
|
100
110
|
callbacks?: Partial<PlayerCallbacks>;
|
|
101
111
|
};
|
|
102
112
|
managerConfig?: Omit<MountParams, "room">;
|
|
113
|
+
appsConfig?: AppsConfig;
|
|
103
114
|
}
|
|
104
115
|
|
|
105
116
|
/**
|
|
@@ -108,6 +119,7 @@ export interface FastboardReplayOptions {
|
|
|
108
119
|
* let app = await replayFastboard({
|
|
109
120
|
* sdkConfig: {
|
|
110
121
|
* appIdentifier: import.meta.env.VITE_APPID,
|
|
122
|
+
* region: "ch-hz",
|
|
111
123
|
* },
|
|
112
124
|
* replayRoom: {
|
|
113
125
|
* uid: unique_id,
|
|
@@ -120,7 +132,10 @@ export async function replayFastboard({
|
|
|
120
132
|
sdkConfig,
|
|
121
133
|
replayRoom: { callbacks, ...replayRoomParams },
|
|
122
134
|
managerConfig,
|
|
135
|
+
appsConfig = DefaultApps,
|
|
123
136
|
}: FastboardReplayOptions) {
|
|
137
|
+
registerApps(appsConfig);
|
|
138
|
+
|
|
124
139
|
const sdk = new WhiteWebSdk({
|
|
125
140
|
...sdkConfig,
|
|
126
141
|
useMobXState: true,
|
|
@@ -134,11 +149,15 @@ export async function replayFastboard({
|
|
|
134
149
|
callbacks
|
|
135
150
|
);
|
|
136
151
|
|
|
137
|
-
const
|
|
152
|
+
const managerPromise = WindowManager.mount({
|
|
138
153
|
cursor: true,
|
|
139
154
|
...managerConfig,
|
|
140
155
|
room: player as Displayer as Room,
|
|
141
156
|
});
|
|
142
157
|
|
|
158
|
+
player.play();
|
|
159
|
+
const manager = await managerPromise;
|
|
160
|
+
player.pause();
|
|
161
|
+
|
|
143
162
|
return new FastboardPlayer(sdk, player, manager);
|
|
144
163
|
}
|