@netless/fastboard-core 0.2.4 → 0.2.7
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-ERMK3Q77.mjs → chunk-T7K6EOIP.mjs} +60 -23
- package/dist/chunk-T7K6EOIP.mjs.map +1 -0
- package/dist/index.js +57 -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 +57 -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 +26 -15
- package/src/helpers/utils.ts +4 -0
- package/src/helpers/value.ts +13 -3
- package/src/impl/app.ts +23 -3
- package/src/minimal.ts +31 -5
- package/dist/chunk-ERMK3Q77.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,36 @@ 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
|
-
HTML5Codebase: "https://flat-storage-cn-hz.whiteboard.agora.io/GeoGebra/HTML5/5.0/web3d"
|
|
66
|
+
var DefaultApps = {
|
|
67
|
+
Monaco: {
|
|
68
|
+
src: "https://cdn.jsdelivr.net/npm/@netless/app-monaco@0.1.12/dist/main.iife.js"
|
|
69
|
+
},
|
|
70
|
+
Countdown: {
|
|
71
|
+
src: "https://cdn.jsdelivr.net/npm/@netless/app-countdown@0.0.2/dist/main.iife.js"
|
|
72
|
+
},
|
|
73
|
+
GeoGebra: {
|
|
74
|
+
src: "https://cdn.jsdelivr.net/npm/@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
|
+
}
|
|
77
78
|
}
|
|
78
|
-
}
|
|
79
|
+
};
|
|
80
|
+
function registerApps(config) {
|
|
81
|
+
for (const kind in config) {
|
|
82
|
+
if (Object.prototype.hasOwnProperty.call(config, kind)) {
|
|
83
|
+
const options = config[kind];
|
|
84
|
+
import_window_manager.WindowManager.register(__spreadValues({ kind }, options));
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
}
|
|
79
88
|
|
|
80
89
|
// src/helpers/utils.ts
|
|
81
90
|
var import_window_manager2 = require("@netless/window-manager");
|
|
82
91
|
function noop() {
|
|
83
92
|
}
|
|
93
|
+
function safe_not_equal(a, b) {
|
|
94
|
+
return a != a ? b == b : a !== b || a && typeof a === "object" || typeof a === "function";
|
|
95
|
+
}
|
|
84
96
|
function getImageSize(url, fallback) {
|
|
85
97
|
return new Promise((resolve) => {
|
|
86
98
|
const img = new Image();
|
|
@@ -163,7 +175,9 @@ var FastboardEmitter = class {
|
|
|
163
175
|
function createValue(value, effect, setValue = noop) {
|
|
164
176
|
const emitter = new FastboardEmitter();
|
|
165
177
|
function set(newValue) {
|
|
166
|
-
|
|
178
|
+
if (safe_not_equal(value, newValue)) {
|
|
179
|
+
emitter.dispatch(value = newValue);
|
|
180
|
+
}
|
|
167
181
|
}
|
|
168
182
|
const dispose = effect(set) || noop;
|
|
169
183
|
function subscribe(callback) {
|
|
@@ -175,7 +189,15 @@ function createValue(value, effect, setValue = noop) {
|
|
|
175
189
|
emitter.addListener(callback);
|
|
176
190
|
return () => emitter.removeListener(callback);
|
|
177
191
|
}
|
|
178
|
-
return {
|
|
192
|
+
return {
|
|
193
|
+
get value() {
|
|
194
|
+
return value;
|
|
195
|
+
},
|
|
196
|
+
subscribe,
|
|
197
|
+
reaction,
|
|
198
|
+
setValue,
|
|
199
|
+
dispose
|
|
200
|
+
};
|
|
179
201
|
}
|
|
180
202
|
|
|
181
203
|
// src/impl/app.ts
|
|
@@ -233,6 +255,14 @@ var FastboardApp = class extends FastboardAppBase {
|
|
|
233
255
|
this.memberState = this.createValue(this.room.state.memberState, (set) => this._addRoomListener("onRoomStateChanged", ({ memberState: m }) => m && set(m)));
|
|
234
256
|
this.sceneIndex = this.createValue(this.manager.mainViewSceneIndex, (set) => this._addManagerListener("mainViewSceneIndexChange", set), this.manager.setMainViewSceneIndex.bind(this.manager));
|
|
235
257
|
this.sceneLength = this.createValue(this.manager.mainViewScenesLength, (set) => this._addManagerListener("mainViewScenesLengthChange", set));
|
|
258
|
+
this._appsStatus = {};
|
|
259
|
+
this.appsStatus = this.createValue({}, (set) => this._addManagerListener("loadApp", ({ kind, status, reason }) => {
|
|
260
|
+
this._appsStatus[kind] = {
|
|
261
|
+
status: status === "start" ? "loading" : status === "failed" ? "failed" : "idle",
|
|
262
|
+
reason
|
|
263
|
+
};
|
|
264
|
+
set(this._appsStatus);
|
|
265
|
+
}));
|
|
236
266
|
}
|
|
237
267
|
bindContainer(container) {
|
|
238
268
|
this._assertNotDestroyed();
|
|
@@ -260,7 +290,7 @@ var FastboardApp = class extends FastboardAppBase {
|
|
|
260
290
|
}
|
|
261
291
|
cleanCurrentScene() {
|
|
262
292
|
this._assertNotDestroyed();
|
|
263
|
-
this.manager.
|
|
293
|
+
this.manager.cleanCurrentScene();
|
|
264
294
|
}
|
|
265
295
|
setAppliance(appliance, shape) {
|
|
266
296
|
this._assertNotDestroyed();
|
|
@@ -319,7 +349,6 @@ var FastboardApp = class extends FastboardAppBase {
|
|
|
319
349
|
this._assertNotDestroyed();
|
|
320
350
|
switch (fileType) {
|
|
321
351
|
case "pdf":
|
|
322
|
-
case "ppt":
|
|
323
352
|
return this.manager.addApp({
|
|
324
353
|
kind: "DocsViewer",
|
|
325
354
|
options: { scenePath, title, scenes }
|
|
@@ -456,8 +485,10 @@ async function createFastboard(_a) {
|
|
|
456
485
|
sdkConfig,
|
|
457
486
|
joinRoom: _c
|
|
458
487
|
} = _b, _d = _c, { callbacks } = _d, joinRoomParams = __objRest(_d, ["callbacks"]), {
|
|
459
|
-
managerConfig
|
|
488
|
+
managerConfig,
|
|
489
|
+
appsConfig = DefaultApps
|
|
460
490
|
} = _b;
|
|
491
|
+
registerApps(appsConfig);
|
|
461
492
|
const sdk = new import_white_web_sdk.WhiteWebSdk(__spreadProps(__spreadValues({}, sdkConfig), {
|
|
462
493
|
useMobXState: true
|
|
463
494
|
}));
|
|
@@ -486,6 +517,10 @@ async function createFastboard(_a) {
|
|
|
486
517
|
}, managerConfig), {
|
|
487
518
|
room
|
|
488
519
|
}));
|
|
520
|
+
manager.mainView.setCameraBound({
|
|
521
|
+
minContentMode: (0, import_white_web_sdk.contentModeScale)(0.3),
|
|
522
|
+
maxContentMode: (0, import_white_web_sdk.contentModeScale)(3)
|
|
523
|
+
});
|
|
489
524
|
return new FastboardApp(sdk, room, manager, hotKeys);
|
|
490
525
|
}
|
|
491
526
|
async function replayFastboard(_a) {
|
|
@@ -493,8 +528,10 @@ async function replayFastboard(_a) {
|
|
|
493
528
|
sdkConfig,
|
|
494
529
|
replayRoom: _c
|
|
495
530
|
} = _b, _d = _c, { callbacks } = _d, replayRoomParams = __objRest(_d, ["callbacks"]), {
|
|
496
|
-
managerConfig
|
|
531
|
+
managerConfig,
|
|
532
|
+
appsConfig = DefaultApps
|
|
497
533
|
} = _b;
|
|
534
|
+
registerApps(appsConfig);
|
|
498
535
|
const sdk = new import_white_web_sdk.WhiteWebSdk(__spreadProps(__spreadValues({}, sdkConfig), {
|
|
499
536
|
useMobXState: true
|
|
500
537
|
}));
|
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 { 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 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.mainView.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 {\n FastboardApp,\n AppsStatus,\n InsertDocsDynamic,\n InsertDocsParams,\n InsertDocsStatic,\n} from \"./impl/app\";\n\nexport type { AppsConfig };\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 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 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://cdn.jsdelivr.net/npm/@netless/app-monaco@0.1.12/dist/main.iife.js\",\n },\n Countdown: {\n src: \"https://cdn.jsdelivr.net/npm/@netless/app-countdown@0.0.2/dist/main.iife.js\",\n },\n GeoGebra: {\n src: \"https://cdn.jsdelivr.net/npm/@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};\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-T7K6EOIP.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.7",
|
|
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.7",
|
|
21
|
+
"tsup": "^5.11.13",
|
|
22
|
+
"white-web-sdk": "^2.16.10"
|
|
28
23
|
},
|
|
29
24
|
"scripts": {
|
|
30
25
|
"build": "tsup",
|
|
@@ -1,19 +1,30 @@
|
|
|
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
|
-
kind: "GeoGebra",
|
|
15
|
-
src: "https://cdn.jsdelivr.net/npm/@netless/app-geogebra@latest/dist/main.iife.js",
|
|
16
|
-
appOptions: {
|
|
17
|
-
HTML5Codebase: "https://flat-storage-cn-hz.whiteboard.agora.io/GeoGebra/HTML5/5.0/web3d",
|
|
8
|
+
export const DefaultApps: AppsConfig = {
|
|
9
|
+
Monaco: {
|
|
10
|
+
src: "https://cdn.jsdelivr.net/npm/@netless/app-monaco@0.1.12/dist/main.iife.js",
|
|
11
|
+
},
|
|
12
|
+
Countdown: {
|
|
13
|
+
src: "https://cdn.jsdelivr.net/npm/@netless/app-countdown@0.0.2/dist/main.iife.js",
|
|
18
14
|
},
|
|
19
|
-
|
|
15
|
+
GeoGebra: {
|
|
16
|
+
src: "https://cdn.jsdelivr.net/npm/@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
|
+
},
|
|
20
|
+
},
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
export function registerApps(config: AppsConfig) {
|
|
24
|
+
for (const kind in config) {
|
|
25
|
+
if (Object.prototype.hasOwnProperty.call(config, kind)) {
|
|
26
|
+
const options = config[kind];
|
|
27
|
+
WindowManager.register({ kind, ...options });
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
}
|
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
|
*/
|
|
@@ -217,7 +238,7 @@ export class FastboardApp extends FastboardAppBase {
|
|
|
217
238
|
*/
|
|
218
239
|
cleanCurrentScene() {
|
|
219
240
|
this._assertNotDestroyed();
|
|
220
|
-
this.manager.
|
|
241
|
+
this.manager.cleanCurrentScene();
|
|
221
242
|
}
|
|
222
243
|
|
|
223
244
|
/**
|
|
@@ -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
|
@@ -10,24 +10,36 @@ import type {
|
|
|
10
10
|
} from "white-web-sdk";
|
|
11
11
|
import type { MountParams } from "@netless/window-manager";
|
|
12
12
|
|
|
13
|
-
import { DefaultHotKeys, WhiteWebSdk } from "white-web-sdk";
|
|
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 {
|
|
26
|
+
FastboardApp,
|
|
27
|
+
AppsStatus,
|
|
28
|
+
InsertDocsDynamic,
|
|
29
|
+
InsertDocsParams,
|
|
30
|
+
InsertDocsStatic,
|
|
31
|
+
} from "./impl/app";
|
|
32
|
+
|
|
33
|
+
export type { AppsConfig };
|
|
34
|
+
export { DefaultApps, registerApps };
|
|
24
35
|
|
|
25
36
|
export interface FastboardOptions {
|
|
26
|
-
sdkConfig: Omit<WhiteWebSdkConfiguration, "useMobXState"
|
|
37
|
+
sdkConfig: Omit<WhiteWebSdkConfiguration, "useMobXState"> & { region: string };
|
|
27
38
|
joinRoom: Omit<JoinRoomParams, "useMultiViews" | "disableNewPencil" | "disableMagixEventDispatchLimit"> & {
|
|
28
39
|
callbacks?: Partial<RoomCallbacks>;
|
|
29
40
|
};
|
|
30
41
|
managerConfig?: Omit<MountParams, "room">;
|
|
42
|
+
appsConfig?: AppsConfig;
|
|
31
43
|
}
|
|
32
44
|
|
|
33
45
|
/**
|
|
@@ -36,6 +48,7 @@ export interface FastboardOptions {
|
|
|
36
48
|
* let app = await createFastboard({
|
|
37
49
|
* sdkConfig: {
|
|
38
50
|
* appIdentifier: import.meta.env.VITE_APPID,
|
|
51
|
+
* region: "ch-hz",
|
|
39
52
|
* },
|
|
40
53
|
* joinRoom: {
|
|
41
54
|
* uid: unique_id,
|
|
@@ -48,7 +61,10 @@ export async function createFastboard({
|
|
|
48
61
|
sdkConfig,
|
|
49
62
|
joinRoom: { callbacks, ...joinRoomParams },
|
|
50
63
|
managerConfig,
|
|
64
|
+
appsConfig = DefaultApps,
|
|
51
65
|
}: FastboardOptions) {
|
|
66
|
+
registerApps(appsConfig);
|
|
67
|
+
|
|
52
68
|
const sdk = new WhiteWebSdk({
|
|
53
69
|
...sdkConfig,
|
|
54
70
|
useMobXState: true,
|
|
@@ -86,15 +102,21 @@ export async function createFastboard({
|
|
|
86
102
|
room,
|
|
87
103
|
});
|
|
88
104
|
|
|
105
|
+
manager.mainView.setCameraBound({
|
|
106
|
+
minContentMode: contentModeScale(0.3),
|
|
107
|
+
maxContentMode: contentModeScale(3),
|
|
108
|
+
});
|
|
109
|
+
|
|
89
110
|
return new FastboardApp(sdk, room, manager, hotKeys);
|
|
90
111
|
}
|
|
91
112
|
|
|
92
113
|
export interface FastboardReplayOptions {
|
|
93
|
-
sdkConfig: Omit<WhiteWebSdkConfiguration, "useMobXState"
|
|
114
|
+
sdkConfig: Omit<WhiteWebSdkConfiguration, "useMobXState"> & { region: string };
|
|
94
115
|
replayRoom: Omit<ReplayRoomParams, "useMultiViews"> & {
|
|
95
116
|
callbacks?: Partial<PlayerCallbacks>;
|
|
96
117
|
};
|
|
97
118
|
managerConfig?: Omit<MountParams, "room">;
|
|
119
|
+
appsConfig?: AppsConfig;
|
|
98
120
|
}
|
|
99
121
|
|
|
100
122
|
/**
|
|
@@ -103,6 +125,7 @@ export interface FastboardReplayOptions {
|
|
|
103
125
|
* let app = await replayFastboard({
|
|
104
126
|
* sdkConfig: {
|
|
105
127
|
* appIdentifier: import.meta.env.VITE_APPID,
|
|
128
|
+
* region: "ch-hz",
|
|
106
129
|
* },
|
|
107
130
|
* replayRoom: {
|
|
108
131
|
* uid: unique_id,
|
|
@@ -115,7 +138,10 @@ export async function replayFastboard({
|
|
|
115
138
|
sdkConfig,
|
|
116
139
|
replayRoom: { callbacks, ...replayRoomParams },
|
|
117
140
|
managerConfig,
|
|
141
|
+
appsConfig = DefaultApps,
|
|
118
142
|
}: FastboardReplayOptions) {
|
|
143
|
+
registerApps(appsConfig);
|
|
144
|
+
|
|
119
145
|
const sdk = new WhiteWebSdk({
|
|
120
146
|
...sdkConfig,
|
|
121
147
|
useMobXState: true,
|