@netless/app-slide 0.2.39 → 0.2.40

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/src/index.ts CHANGED
@@ -1,283 +1,283 @@
1
- import type { NetlessApp } from "@netless/window-manager";
2
- import type { RoomState } from "white-web-sdk";
3
- import type { ISlideConfig } from "@netless/slide";
4
- import type { MountSlideOptions } from "./SlideDocsViewer";
5
- import type { Attributes, MagixEvents } from "./typings";
6
- import type { AddHooks, FreezableSlide } from "./utils/freezer";
7
-
8
- import { Slide } from "@netless/slide";
9
- import { SideEffectManager } from "side-effect-manager";
10
- import {
11
- DefaultUrl,
12
- EmptyAttributes,
13
- syncSceneWithSlide,
14
- SlideController,
15
- } from "./SlideController";
16
- import { SlideDocsViewer } from "./SlideDocsViewer";
17
- import { apps, FreezerLength, addHooks, useFreezer } from "./utils/freezer";
18
- import { log, logger } from "./utils/logger";
19
- import styles from "./style.scss?inline";
20
-
21
- export type { PreviewParams } from "./SlidePreviewer";
22
- export { SlidePreviewer, default as previewSlide } from "./SlidePreviewer";
23
-
24
- export type { Attributes, AddHooks, FreezableSlide };
25
- export { Slide };
26
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
27
- export const usePlugin: (plugin: any) => any = /* @__PURE__ */ Slide.usePlugin.bind(Slide);
28
-
29
- export const version = __APP_VERSION__;
30
-
31
- export { DefaultUrl, apps, FreezerLength, addHooks };
32
-
33
- export { setFreezerLength, getFreezerLength, onCreated, onDestroyed } from "./utils/freezer";
34
-
35
- export interface AppOptions
36
- extends Pick<
37
- ISlideConfig,
38
- | "rtcAudio"
39
- | "useLocalCache"
40
- | "resourceTimeout"
41
- | "loaderDelegate"
42
- | "urlInterrupter"
43
- | "navigatorDelegate"
44
- | "fixedFrameSize"
45
- | "logger"
46
- > {
47
- /** show debug controller */
48
- debug?: boolean;
49
- /** scale */
50
- resolution?: number;
51
- /** background color for slide animations */
52
- bgColor?: string;
53
- /** minimal fps @default 25 */
54
- minFPS?: number;
55
- /** maximal fps @default 30 */
56
- maxFPS?: number;
57
- /** automatically decrease fps @default true */
58
- autoFPS?: boolean;
59
- /** whether to re-scale automatically @default true */
60
- autoResolution?: boolean;
61
- /** 1~4, default: 3 */
62
- maxResolutionLevel?: number;
63
- /** use canvas2d mode, downside: some 3d effects are lost */
64
- forceCanvas?: boolean;
65
- /** fix windows 11 nvidia rendering bug, downside: render next page slows down */
66
- enableNvidiaDetect?: boolean;
67
- /** custom error handler */
68
- onRenderError?: (error: Error, pageIndex: number) => void;
69
- /** whether to show an overlay of error message @default: true */
70
- showRenderError?: boolean;
71
- }
72
-
73
- export interface ILogger {
74
- info?(msg: string): void;
75
- error?(msg: string): void;
76
- warn?(msg: string): void;
77
- }
78
-
79
- export interface AppResult {
80
- viewer: () => SlideDocsViewer | null;
81
- controller: () => SlideController | null | undefined;
82
- slide: () => Slide | undefined;
83
- position: () => [page: number, pageCount: number] | undefined;
84
- nextStep: () => boolean;
85
- prevStep: () => boolean;
86
- nextPage: () => boolean;
87
- prevPage: () => boolean;
88
- jumpToPage: (page: number) => boolean;
89
- }
90
-
91
- const SlideApp: NetlessApp<Attributes, MagixEvents, AppOptions, AppResult> = {
92
- kind: "Slide",
93
- setup(context) {
94
- console.log("[Slide] setup @ " + version);
95
-
96
- if (context.getIsWritable()) {
97
- context.storage.ensureState(EmptyAttributes);
98
- }
99
-
100
- if (!context.storage.state.taskId) {
101
- throw new Error("[Slide] no taskId");
102
- }
103
-
104
- const view = context.getView();
105
- if (!view) {
106
- throw new Error("[Slide] no view, please set scenePath on addApp()");
107
- }
108
- view.disableCameraTransform = true;
109
-
110
- const box = context.getBox();
111
- box.mountStyles(styles);
112
- try {
113
- box.$content.dataset.appSlideVersion = version;
114
- } catch {
115
- // ignore
116
- }
117
-
118
- // must exist because of view
119
- const baseScenePath = context.getInitScenePath() as string;
120
-
121
- let docsViewer: SlideDocsViewer | null = null;
122
-
123
- const onPageChanged = (page: number) => {
124
- const room = context.getRoom();
125
- if (docsViewer && docsViewer.slideController) {
126
- let synced = false;
127
- if (room && context.getIsWritable()) {
128
- syncSceneWithSlide(room, context, docsViewer.slideController.slide, baseScenePath);
129
- synced = true;
130
- }
131
- log("[Slide] page to", page, synced ? "(synced)" : "");
132
- docsViewer.viewer.setPageIndex(page - 1);
133
- }
134
- };
135
-
136
- const mountSlideController = (options: MountSlideOptions): SlideController => {
137
- const appOptions = context.getAppOptions() || {};
138
-
139
- const slideController = new SlideController({
140
- context,
141
- ...options,
142
- onPageChanged,
143
- onRenderError: appOptions.onRenderError,
144
- showRenderError: appOptions.showRenderError,
145
- });
146
- if (useFreezer) apps.set(context.appId, slideController, box);
147
- logger.setAppController(context.appId, slideController);
148
- if (import.meta.env.DEV) {
149
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
150
- (window as any).slideController = slideController;
151
- }
152
- slideController.readyPromise.then(options.onReady).then(() => {
153
- const room = context.getRoom();
154
- let synced = false;
155
- if (room && context.getIsWritable()) {
156
- syncSceneWithSlide(room, context, slideController.slide, baseScenePath);
157
- synced = true;
158
- }
159
- const page = slideController.slide.slideState.currentSlideIndex;
160
- log("[Slide] page to", page, synced ? "(synced)" : "", "(on ready)");
161
- slideController.slide.on("renderEnd", options.onRenderEnd);
162
- });
163
- return slideController;
164
- };
165
-
166
- docsViewer = new SlideDocsViewer({
167
- box,
168
- view,
169
- mountSlideController,
170
- mountWhiteboard: context.mountView.bind(context),
171
- baseScenePath,
172
- appId: context.appId,
173
- urlInterrupter: context.getAppOptions()?.urlInterrupter,
174
- });
175
-
176
- if (import.meta.env.DEV) {
177
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
178
- (window as any).slideDoc = docsViewer;
179
- }
180
-
181
- const room = context.getRoom();
182
- const sideEffect = new SideEffectManager();
183
-
184
- sideEffect.add(() => {
185
- logger.setAppContext(context.appId, context);
186
- logger.enable = context.getAppOptions()?.debug || import.meta.env.DEV;
187
- logger.level = import.meta.env.DEV ? "verbose" : "debug";
188
- return () => logger.deleteApp(context.appId);
189
- });
190
-
191
- if (room) {
192
- docsViewer.toggleClickThrough(room.state.memberState.currentApplianceName);
193
- sideEffect.add(() => {
194
- const onRoomStateChanged = (e: Partial<RoomState>) => {
195
- if (e.memberState && docsViewer) {
196
- docsViewer.toggleClickThrough(e.memberState.currentApplianceName);
197
- }
198
- };
199
- room.callbacks.on("onRoomStateChanged", onRoomStateChanged);
200
- return () => room.callbacks.off("onRoomStateChanged", onRoomStateChanged);
201
- });
202
- }
203
-
204
- context.emitter.on("destroy", () => {
205
- log("[Slide] destroy", context.appId);
206
- if (useFreezer) apps.delete(context.appId);
207
- sideEffect.flushAll();
208
- if (docsViewer) {
209
- docsViewer.destroy();
210
- docsViewer = null;
211
- }
212
- });
213
-
214
- docsViewer.mount();
215
-
216
- return {
217
- viewer: () => {
218
- return docsViewer;
219
- },
220
- controller: () => {
221
- return docsViewer?.slideController;
222
- },
223
- slide: () => {
224
- return docsViewer?.slideController?.slide;
225
- },
226
- nextStep: () => {
227
- if (docsViewer && docsViewer.slideController) {
228
- docsViewer?.slideController?.slide.nextStep();
229
- return true;
230
- }
231
- return false;
232
- },
233
- prevStep: () => {
234
- if (docsViewer && docsViewer.slideController) {
235
- docsViewer?.slideController?.slide.prevStep();
236
- return true;
237
- }
238
- return false;
239
- },
240
- position: () => {
241
- const controller = docsViewer?.slideController;
242
- if (controller) {
243
- return [controller.page, controller.pageCount] as [page: number, pageCount: number];
244
- }
245
- },
246
- nextPage: () => {
247
- const controller = docsViewer?.slideController;
248
- if (controller) {
249
- const { page, pageCount } = controller;
250
- if (pageCount > 0 && page < pageCount) {
251
- controller.jumpToPage(page + 1);
252
- return true;
253
- }
254
- }
255
- return false;
256
- },
257
- prevPage: () => {
258
- const controller = docsViewer?.slideController;
259
- if (controller) {
260
- const { page, pageCount } = controller;
261
- if (pageCount > 0 && page > 1) {
262
- controller.jumpToPage(page - 1);
263
- return true;
264
- }
265
- }
266
- return false;
267
- },
268
- jumpToPage: (newPage: number) => {
269
- const controller = docsViewer?.slideController;
270
- if (controller) {
271
- const { page, pageCount } = controller;
272
- if (pageCount > 0 && page > 0 && page <= pageCount) {
273
- controller.jumpToPage(newPage);
274
- return true;
275
- }
276
- }
277
- return false;
278
- },
279
- };
280
- },
281
- };
282
-
283
- export default SlideApp;
1
+ import type { NetlessApp } from "@netless/window-manager";
2
+ import type { RoomState } from "white-web-sdk";
3
+ import type { ISlideConfig } from "@netless/slide";
4
+ import type { MountSlideOptions } from "./SlideDocsViewer";
5
+ import type { Attributes, MagixEvents } from "./typings";
6
+ import type { AddHooks, FreezableSlide } from "./utils/freezer";
7
+
8
+ import { Slide } from "@netless/slide";
9
+ import { SideEffectManager } from "side-effect-manager";
10
+ import {
11
+ DefaultUrl,
12
+ EmptyAttributes,
13
+ syncSceneWithSlide,
14
+ SlideController,
15
+ } from "./SlideController";
16
+ import { SlideDocsViewer } from "./SlideDocsViewer";
17
+ import { apps, FreezerLength, addHooks, useFreezer } from "./utils/freezer";
18
+ import { log, logger } from "./utils/logger";
19
+ import styles from "./style.scss?inline";
20
+
21
+ export type { PreviewParams } from "./SlidePreviewer";
22
+ export { SlidePreviewer, default as previewSlide } from "./SlidePreviewer";
23
+
24
+ export type { Attributes, AddHooks, FreezableSlide };
25
+ export { Slide };
26
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
27
+ export const usePlugin: (plugin: any) => any = /* @__PURE__ */ Slide.usePlugin.bind(Slide);
28
+
29
+ export const version = __APP_VERSION__;
30
+
31
+ export { DefaultUrl, apps, FreezerLength, addHooks };
32
+
33
+ export { setFreezerLength, getFreezerLength, onCreated, onDestroyed } from "./utils/freezer";
34
+
35
+ export interface AppOptions
36
+ extends Pick<
37
+ ISlideConfig,
38
+ | "rtcAudio"
39
+ | "useLocalCache"
40
+ | "resourceTimeout"
41
+ | "loaderDelegate"
42
+ | "urlInterrupter"
43
+ | "navigatorDelegate"
44
+ | "fixedFrameSize"
45
+ | "logger"
46
+ > {
47
+ /** show debug controller */
48
+ debug?: boolean;
49
+ /** scale */
50
+ resolution?: number;
51
+ /** background color for slide animations */
52
+ bgColor?: string;
53
+ /** minimal fps @default 25 */
54
+ minFPS?: number;
55
+ /** maximal fps @default 30 */
56
+ maxFPS?: number;
57
+ /** automatically decrease fps @default true */
58
+ autoFPS?: boolean;
59
+ /** whether to re-scale automatically @default true */
60
+ autoResolution?: boolean;
61
+ /** 1~4, default: 3 */
62
+ maxResolutionLevel?: number;
63
+ /** use canvas2d mode, downside: some 3d effects are lost */
64
+ forceCanvas?: boolean;
65
+ /** fix windows 11 nvidia rendering bug, downside: render next page slows down */
66
+ enableNvidiaDetect?: boolean;
67
+ /** custom error handler */
68
+ onRenderError?: (error: Error, pageIndex: number) => void;
69
+ /** whether to show an overlay of error message @default: true */
70
+ showRenderError?: boolean;
71
+ }
72
+
73
+ export interface ILogger {
74
+ info?(msg: string): void;
75
+ error?(msg: string): void;
76
+ warn?(msg: string): void;
77
+ }
78
+
79
+ export interface AppResult {
80
+ viewer: () => SlideDocsViewer | null;
81
+ controller: () => SlideController | null | undefined;
82
+ slide: () => Slide | undefined;
83
+ position: () => [page: number, pageCount: number] | undefined;
84
+ nextStep: () => boolean;
85
+ prevStep: () => boolean;
86
+ nextPage: () => boolean;
87
+ prevPage: () => boolean;
88
+ jumpToPage: (page: number) => boolean;
89
+ }
90
+
91
+ const SlideApp: NetlessApp<Attributes, MagixEvents, AppOptions, AppResult> = {
92
+ kind: "Slide",
93
+ setup(context) {
94
+ console.log("[Slide] setup @ " + version);
95
+
96
+ if (context.getIsWritable()) {
97
+ context.storage.ensureState(EmptyAttributes);
98
+ }
99
+
100
+ if (!context.storage.state.taskId) {
101
+ throw new Error("[Slide] no taskId");
102
+ }
103
+
104
+ const view = context.getView();
105
+ if (!view) {
106
+ throw new Error("[Slide] no view, please set scenePath on addApp()");
107
+ }
108
+ view.disableCameraTransform = true;
109
+
110
+ const box = context.getBox();
111
+ box.mountStyles(styles);
112
+ try {
113
+ box.$content.dataset.appSlideVersion = version;
114
+ } catch {
115
+ // ignore
116
+ }
117
+
118
+ // must exist because of view
119
+ const baseScenePath = context.getInitScenePath() as string;
120
+
121
+ let docsViewer: SlideDocsViewer | null = null;
122
+
123
+ const onPageChanged = (page: number) => {
124
+ const room = context.getRoom();
125
+ if (docsViewer && docsViewer.slideController) {
126
+ let synced = false;
127
+ if (room && context.getIsWritable()) {
128
+ syncSceneWithSlide(room, context, docsViewer.slideController.slide, baseScenePath);
129
+ synced = true;
130
+ }
131
+ log("[Slide] page to", page, synced ? "(synced)" : "");
132
+ docsViewer.viewer.setPageIndex(page - 1);
133
+ }
134
+ };
135
+
136
+ const mountSlideController = (options: MountSlideOptions): SlideController => {
137
+ const appOptions = context.getAppOptions() || {};
138
+
139
+ const slideController = new SlideController({
140
+ context,
141
+ ...options,
142
+ onPageChanged,
143
+ onRenderError: appOptions.onRenderError,
144
+ showRenderError: appOptions.showRenderError,
145
+ });
146
+ if (useFreezer) apps.set(context.appId, slideController, box);
147
+ logger.setAppController(context.appId, slideController);
148
+ if (import.meta.env.DEV) {
149
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
150
+ (window as any).slideController = slideController;
151
+ }
152
+ slideController.readyPromise.then(options.onReady).then(() => {
153
+ const room = context.getRoom();
154
+ let synced = false;
155
+ if (room && context.getIsWritable()) {
156
+ syncSceneWithSlide(room, context, slideController.slide, baseScenePath);
157
+ synced = true;
158
+ }
159
+ const page = slideController.slide.slideState.currentSlideIndex;
160
+ log("[Slide] page to", page, synced ? "(synced)" : "", "(on ready)");
161
+ slideController.slide.on("renderEnd", options.onRenderEnd);
162
+ });
163
+ return slideController;
164
+ };
165
+
166
+ docsViewer = new SlideDocsViewer({
167
+ box,
168
+ view,
169
+ mountSlideController,
170
+ mountWhiteboard: context.mountView.bind(context),
171
+ baseScenePath,
172
+ appId: context.appId,
173
+ urlInterrupter: context.getAppOptions()?.urlInterrupter,
174
+ });
175
+
176
+ if (import.meta.env.DEV) {
177
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
178
+ (window as any).slideDoc = docsViewer;
179
+ }
180
+
181
+ const room = context.getRoom();
182
+ const sideEffect = new SideEffectManager();
183
+
184
+ sideEffect.add(() => {
185
+ logger.setAppContext(context.appId, context);
186
+ logger.enable = context.getAppOptions()?.debug || import.meta.env.DEV;
187
+ logger.level = import.meta.env.DEV ? "verbose" : "debug";
188
+ return () => logger.deleteApp(context.appId);
189
+ });
190
+
191
+ if (room) {
192
+ docsViewer.toggleClickThrough(room.state.memberState.currentApplianceName);
193
+ sideEffect.add(() => {
194
+ const onRoomStateChanged = (e: Partial<RoomState>) => {
195
+ if (e.memberState && docsViewer) {
196
+ docsViewer.toggleClickThrough(e.memberState.currentApplianceName);
197
+ }
198
+ };
199
+ room.callbacks.on("onRoomStateChanged", onRoomStateChanged);
200
+ return () => room.callbacks.off("onRoomStateChanged", onRoomStateChanged);
201
+ });
202
+ }
203
+
204
+ context.emitter.on("destroy", () => {
205
+ log("[Slide] destroy", context.appId);
206
+ if (useFreezer) apps.delete(context.appId);
207
+ sideEffect.flushAll();
208
+ if (docsViewer) {
209
+ docsViewer.destroy();
210
+ docsViewer = null;
211
+ }
212
+ });
213
+
214
+ docsViewer.mount();
215
+
216
+ return {
217
+ viewer: () => {
218
+ return docsViewer;
219
+ },
220
+ controller: () => {
221
+ return docsViewer?.slideController;
222
+ },
223
+ slide: () => {
224
+ return docsViewer?.slideController?.slide;
225
+ },
226
+ nextStep: () => {
227
+ if (docsViewer && docsViewer.slideController) {
228
+ docsViewer?.slideController?.slide.nextStep();
229
+ return true;
230
+ }
231
+ return false;
232
+ },
233
+ prevStep: () => {
234
+ if (docsViewer && docsViewer.slideController) {
235
+ docsViewer?.slideController?.slide.prevStep();
236
+ return true;
237
+ }
238
+ return false;
239
+ },
240
+ position: () => {
241
+ const controller = docsViewer?.slideController;
242
+ if (controller) {
243
+ return [controller.page, controller.pageCount] as [page: number, pageCount: number];
244
+ }
245
+ },
246
+ nextPage: () => {
247
+ const controller = docsViewer?.slideController;
248
+ if (controller) {
249
+ const { page, pageCount } = controller;
250
+ if (pageCount > 0 && page < pageCount) {
251
+ controller.jumpToPage(page + 1);
252
+ return true;
253
+ }
254
+ }
255
+ return false;
256
+ },
257
+ prevPage: () => {
258
+ const controller = docsViewer?.slideController;
259
+ if (controller) {
260
+ const { page, pageCount } = controller;
261
+ if (pageCount > 0 && page > 1) {
262
+ controller.jumpToPage(page - 1);
263
+ return true;
264
+ }
265
+ }
266
+ return false;
267
+ },
268
+ jumpToPage: (newPage: number) => {
269
+ const controller = docsViewer?.slideController;
270
+ if (controller) {
271
+ const { page, pageCount } = controller;
272
+ if (pageCount > 0 && page > 0 && page <= pageCount) {
273
+ controller.jumpToPage(newPage);
274
+ return true;
275
+ }
276
+ }
277
+ return false;
278
+ },
279
+ };
280
+ },
281
+ };
282
+
283
+ export default SlideApp;
package/src/style.scss CHANGED
@@ -1,14 +1,14 @@
1
- @import "./DocsViewer/style.scss";
2
- @import "./SlideDocsViewer/style.scss";
3
-
4
- .netless-app-slide-slide {
5
- width: 100%;
6
- height: 100%;
7
- display: flex;
8
- align-items: center;
9
- justify-content: center;
10
-
11
- canvas {
12
- transform: scale(var(--netless-app-slide-scale, 1));
13
- }
14
- }
1
+ @import "./DocsViewer/style.scss";
2
+ @import "./SlideDocsViewer/style.scss";
3
+
4
+ .netless-app-slide-slide {
5
+ width: 100%;
6
+ height: 100%;
7
+ display: flex;
8
+ align-items: center;
9
+ justify-content: center;
10
+
11
+ canvas {
12
+ transform: scale(var(--netless-app-slide-scale, 1));
13
+ }
14
+ }
package/src/typings.ts CHANGED
@@ -1,21 +1,21 @@
1
- import type { Slide, SLIDE_EVENTS, SyncEvent } from "@netless/slide";
2
-
3
- export type SlideState = Slide["slideState"];
4
-
5
- export interface Attributes {
6
- /** convert task id */
7
- taskId: string;
8
- /** base url of converted resources */
9
- url: string;
10
- /** internal state of slide, do not change */
11
- state: SlideState | null;
12
- }
13
-
14
- export type MagixPayload = {
15
- type: typeof SLIDE_EVENTS.syncDispatch;
16
- payload: SyncEvent;
17
- };
18
-
19
- export type MagixEvents = {
20
- [SLIDE_EVENTS.syncDispatch]: MagixPayload;
21
- };
1
+ import type { Slide, SLIDE_EVENTS, SyncEvent } from "@netless/slide";
2
+
3
+ export type SlideState = Slide["slideState"];
4
+
5
+ export interface Attributes {
6
+ /** convert task id */
7
+ taskId: string;
8
+ /** base url of converted resources */
9
+ url: string;
10
+ /** internal state of slide, do not change */
11
+ state: SlideState | null;
12
+ }
13
+
14
+ export type MagixPayload = {
15
+ type: typeof SLIDE_EVENTS.syncDispatch;
16
+ payload: SyncEvent;
17
+ };
18
+
19
+ export type MagixEvents = {
20
+ [SLIDE_EVENTS.syncDispatch]: MagixPayload;
21
+ };