@netless/app-slide 0.0.29 → 0.0.34

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.
@@ -0,0 +1,20 @@
1
+ import type { SlideController } from "../SlideController";
2
+ declare class Logger {
3
+ enable: boolean;
4
+ apps: Record<string, {
5
+ context?: any;
6
+ controller?: SlideController;
7
+ }>;
8
+ level: "debug" | "verbose";
9
+ constructor(enable: boolean);
10
+ log(...args: Parameters<Console["log"]>): void;
11
+ verbose(...args: Parameters<Console["log"]>): void;
12
+ dispose(appId: string): void;
13
+ _onMessage: (ev: MessageEvent<{
14
+ slide: boolean | "__instance";
15
+ }>) => void;
16
+ }
17
+ export declare const logger: Logger;
18
+ export declare const log: (...args: Parameters<Console["log"]>) => void;
19
+ export declare const verbose: (...args: Parameters<Console["log"]>) => void;
20
+ export {};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@netless/app-slide",
3
- "version": "0.0.29",
3
+ "version": "0.0.34",
4
4
  "main": "dist/main.cjs.js",
5
5
  "module": "dist/main.es.js",
6
6
  "types": "dist/index.d.ts",
@@ -11,9 +11,9 @@
11
11
  ],
12
12
  "devDependencies": {
13
13
  "@netless/app-shared": "^0.1.1",
14
- "@netless/slide": "^0.1.34",
15
- "@types/color-string": "^1.5.0",
16
- "color-string": "^1.7.1",
14
+ "@netless/slide": "^0.1.37",
15
+ "@types/color-string": "^1.5.2",
16
+ "color-string": "^1.8.2",
17
17
  "side-effect-manager": "^0.1.5",
18
18
  "vanilla-lazyload": "^17.5.0"
19
19
  },
@@ -4,7 +4,6 @@ import { arrowRightSVG } from "./icons/arrow-right";
4
4
  import { playSVG } from "./icons/play";
5
5
  import { pauseSVG } from "./icons/pause";
6
6
 
7
- import type { ReadonlyTeleBox } from "@netless/window-manager";
8
7
  import type { ILazyLoadInstance } from "vanilla-lazyload";
9
8
  import LazyLoad from "vanilla-lazyload";
10
9
  import { SideEffectManager } from "side-effect-manager";
@@ -18,15 +17,13 @@ export interface DocsViewerPage {
18
17
 
19
18
  export interface DocsViewerConfig {
20
19
  readonly: boolean;
21
- box: ReadonlyTeleBox;
22
20
  onNewPageIndex: (index: number) => void;
23
21
  onPlay?: () => void;
24
22
  }
25
23
 
26
24
  export class DocsViewer {
27
- public constructor({ readonly, box, onNewPageIndex, onPlay }: DocsViewerConfig) {
25
+ public constructor({ readonly, onNewPageIndex, onPlay }: DocsViewerConfig) {
28
26
  this.readonly = readonly;
29
- this.box = box;
30
27
  this.onNewPageIndex = onNewPageIndex;
31
28
  this.onPlay = onPlay;
32
29
 
@@ -34,7 +31,6 @@ export class DocsViewer {
34
31
  }
35
32
 
36
33
  protected readonly: boolean;
37
- protected box: ReadonlyTeleBox;
38
34
  protected onNewPageIndex: (index: number) => void;
39
35
  protected onPlay?: () => void;
40
36
 
@@ -62,11 +58,6 @@ export class DocsViewer {
62
58
 
63
59
  public pageIndex = 0;
64
60
 
65
- public mount(): void {
66
- this.box.mountContent(this.$content);
67
- this.box.mountFooter(this.$footer);
68
- }
69
-
70
61
  public unmount(): void {
71
62
  this.$content.remove();
72
63
  this.$footer.remove();
@@ -17,6 +17,7 @@ import { SideEffectManager } from "side-effect-manager";
17
17
  import { Slide, SLIDE_EVENTS } from "@netless/slide";
18
18
  import { clamp, deepClone, isObj } from "../utils/helpers";
19
19
  import { cachedGetBgColor } from "../utils/bgcolor";
20
+ import { logger, log, verbose } from "../utils/logger";
20
21
  export { syncSceneWithSlide, createDocsViewerPages } from "./helpers";
21
22
 
22
23
  export const DefaultUrl = "https://convertcdn.netless.link/dynamicConvert";
@@ -39,7 +40,6 @@ export interface SlideControllerOptions {
39
40
  export class SlideController {
40
41
  public readonly context: SlideControllerOptions["context"];
41
42
  public readonly slide: Slide;
42
- public readonly debug: boolean;
43
43
 
44
44
  private readonly channel: string;
45
45
  private readonly room?: Room;
@@ -69,7 +69,6 @@ export class SlideController {
69
69
  this.channel = `channel-${context.appId}`;
70
70
  this.room = context.getRoom();
71
71
  this.player = this.room ? undefined : (context.getDisplayer() as Player);
72
- this.debug = import.meta.env.DEV || !!context.getAppOptions()?.debug;
73
72
  this.slide = this.createSlide(anchor);
74
73
  // the adder does not need to sync state
75
74
  this.syncStateOnceFlag = !this.context.isAddApp;
@@ -104,16 +103,12 @@ export class SlideController {
104
103
  slide.setResource(taskId, url || DefaultUrl);
105
104
  if (state) {
106
105
  // if we already have state, try restore from it
107
- if (this.debug) {
108
- console.log("[Slide] init with state", deepClone(state));
109
- }
106
+ log("[Slide] init with state", deepClone(state));
110
107
  this.syncStateOnceFlag = false;
111
108
  slide.setSlideState(deepClone(state));
112
109
  } else if (context.isAddApp) {
113
110
  // otherwise, maybe this slide is just added, let the adder kick start first render
114
- if (this.debug) {
115
- console.log("[Slide] init by renderSlide", 1);
116
- }
111
+ log("[Slide] init by renderSlide", 1);
117
112
  slide.renderSlide(1);
118
113
  }
119
114
  // there's still some risk that the adder is left and no first render
@@ -175,9 +170,7 @@ export class SlideController {
175
170
  type: SLIDE_EVENTS.syncDispatch,
176
171
  payload: event,
177
172
  };
178
- if (this.debug) {
179
- console.log("[Slide] dispatch", event);
180
- }
173
+ log("[Slide] dispatch", event);
181
174
  this.room.dispatchMagixEvent(this.channel, payload);
182
175
  }
183
176
  };
@@ -187,9 +180,7 @@ export class SlideController {
187
180
  const { type, payload } = ev.payload as MagixPayload;
188
181
  if (type === SLIDE_EVENTS.syncDispatch) {
189
182
  this.syncStateOnce();
190
- if (this.debug) {
191
- console.log("[Slide] receive", payload);
192
- }
183
+ log("[Slide] receive", payload);
193
184
  // only emit the event if the slide state is sync-ed
194
185
  if (!this.syncStateOnceFlag) {
195
186
  this.slide.emit(SLIDE_EVENTS.syncReceive, payload);
@@ -203,9 +194,7 @@ export class SlideController {
203
194
  if (this.syncStateOnceFlag) {
204
195
  const { state } = { ...EmptyAttributes, ...this.context.getAttributes() };
205
196
  if (state) {
206
- if (this.debug) {
207
- console.log("[Slide] sync with state (once)", deepClone(state));
208
- }
197
+ log("[Slide] sync with state (once)", deepClone(state));
209
198
  this.slide.setSlideState(deepClone(state));
210
199
  this.syncStateOnceFlag = false;
211
200
  }
@@ -214,20 +203,18 @@ export class SlideController {
214
203
 
215
204
  private onStateChange = (state: SlideState) => {
216
205
  if (this.context.getIsWritable()) {
217
- if (import.meta.env.DEV) {
218
- console.log("[Slide] state change", JSON.stringify(state, null, 2));
219
- }
206
+ verbose("[Slide] state change", JSON.stringify(state, null, 2));
220
207
  this.context.updateAttributes(["state"], state);
221
208
  }
222
209
  };
223
210
 
224
211
  private onSeeked = () => {
225
212
  // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
226
- const state = this.context.getAttributes()!.state
213
+ const state = this.context.getAttributes()!.state;
227
214
  if (state) {
228
215
  this.slide.setSlideState(deepClone(state));
229
216
  }
230
- }
217
+ };
231
218
 
232
219
  private pollCount = 0;
233
220
  private pollReadyState = () => {
@@ -242,9 +229,7 @@ export class SlideController {
242
229
  setTimeout(this.pollReadyState, 500);
243
230
  } else {
244
231
  this.pollCount = 0;
245
- if (this.debug) {
246
- console.log("[Slide] renderSlide (retry after timeout)", 1);
247
- }
232
+ log("[Slide] renderSlide (retry after timeout)", 1);
248
233
  this.slide.renderSlide(1);
249
234
  }
250
235
  };
@@ -268,7 +253,7 @@ export class SlideController {
268
253
  interactive: true,
269
254
  mode: "interactive",
270
255
  resize: true,
271
- controller: this.debug,
256
+ controller: logger.enable,
272
257
  renderOptions: {
273
258
  minFPS: 25,
274
259
  maxFPS: 30,
@@ -279,7 +264,7 @@ export class SlideController {
279
264
  },
280
265
  timestamp: this.timestamp,
281
266
  });
282
- if (this.debug) {
267
+ if (import.meta.env.DEV) {
283
268
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
284
269
  (window as any).slide = slide;
285
270
  }
@@ -291,9 +276,7 @@ export class SlideController {
291
276
  public destroy() {
292
277
  this.sideEffect.flushAll();
293
278
  if (!this.destroyed) {
294
- if (this.debug) {
295
- console.log("[Slide] destroy slide (once)");
296
- }
279
+ log("[Slide] destroy slide (once)");
297
280
  this.slide.destroy();
298
281
  this.destroyed = true;
299
282
  }
@@ -331,9 +314,7 @@ export class SlideController {
331
314
 
332
315
  public freeze = () => {
333
316
  if (this.ready) {
334
- if (this.debug) {
335
- console.log("[Slide] freeze", this.context.appId);
336
- }
317
+ log("[Slide] freeze", this.context.appId);
337
318
  if (this.freezePromise) {
338
319
  this._toFreeze = 1;
339
320
  } else if (!this.isFrozen) {
@@ -347,9 +328,7 @@ export class SlideController {
347
328
 
348
329
  public unfreeze = async () => {
349
330
  if (this.ready) {
350
- if (this.debug) {
351
- console.log("[Slide] unfreeze", this.context.appId);
352
- }
331
+ log("[Slide] unfreeze", this.context.appId);
353
332
  if (this.freezePromise) {
354
333
  this._toFreeze = -1;
355
334
  } else if (this.isFrozen) {
@@ -5,7 +5,7 @@ import { SideEffectManager } from "side-effect-manager";
5
5
  import { createDocsViewerPages } from "../SlideController";
6
6
  import { DocsViewer } from "../DocsViewer";
7
7
 
8
- export const ClickThroughAppliances = new Set(["clicker", "selector"]);
8
+ export const ClickThroughAppliances = new Set(["clicker"]);
9
9
 
10
10
  export type MountSlideOptions = Omit<SlideControllerOptions, "context" | "onPageChanged"> & {
11
11
  onReady: () => void;
@@ -35,7 +35,6 @@ export class SlideDocsViewer {
35
35
  this.mountWhiteboard = mountWhiteboard;
36
36
 
37
37
  this.viewer = new DocsViewer({
38
- box,
39
38
  readonly: box.readonly,
40
39
  onNewPageIndex: this.onNewPageIndex,
41
40
  onPlay: this.onPlay,
@@ -98,7 +97,8 @@ export class SlideDocsViewer {
98
97
  }
99
98
 
100
99
  public mount() {
101
- this.viewer.mount();
100
+ this.box.mountContent(this.viewer.$content);
101
+ this.box.mountFooter(this.viewer.$footer);
102
102
 
103
103
  this.slideController = this.mountSlideController({
104
104
  anchor: this.$slide,
@@ -0,0 +1,184 @@
1
+ import { Slide, SLIDE_EVENTS } from "@netless/slide";
2
+ import { DocsViewer } from "../DocsViewer";
3
+ import { createDocsViewerPages, DefaultUrl } from "../SlideController";
4
+ import { cachedGetBgColor } from "../utils/bgcolor";
5
+ import { clamp } from "../utils/helpers";
6
+ import { log } from "../utils/logger";
7
+ import style from "../style.scss?inline";
8
+
9
+ export interface PreviewParams {
10
+ container: HTMLElement;
11
+ taskId: string;
12
+ url?: string;
13
+ debug?: boolean;
14
+ }
15
+
16
+ export default function previewSlide({
17
+ container,
18
+ taskId,
19
+ url = DefaultUrl,
20
+ debug = import.meta.env.DEV,
21
+ }: PreviewParams) {
22
+ if (!taskId) {
23
+ throw new Error("[Slide] taskId is required");
24
+ }
25
+
26
+ container.style.cssText += `display:flex;flex-direction:column`;
27
+ const previewer = new SlidePreviewer({ target: container });
28
+ previewer.debug = !!debug;
29
+
30
+ previewer.mount(taskId, url);
31
+
32
+ return previewer;
33
+ }
34
+
35
+ if (import.meta.env.DEV) {
36
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
37
+ (window as any).previewSlide = previewSlide;
38
+ }
39
+
40
+ export class SlidePreviewer {
41
+ public readonly viewer: DocsViewer;
42
+ public readonly bgColor: string;
43
+ public readonly target: HTMLElement;
44
+ public slide: Slide | null = null;
45
+ public debug = import.meta.env.DEV;
46
+
47
+ public $slide!: HTMLDivElement;
48
+ public ready = false;
49
+ private resolveReady!: () => void;
50
+ public readonly readyPromise = new Promise<void>(resolve => {
51
+ this.resolveReady = () => {
52
+ this.ready = true;
53
+ resolve();
54
+ };
55
+ });
56
+
57
+ public constructor(config: { target: HTMLElement }) {
58
+ this.target = config.target;
59
+ this.bgColor = cachedGetBgColor(this.target);
60
+ this.viewer = new DocsViewer({
61
+ readonly: false,
62
+ onNewPageIndex: this.onNewPageIndex,
63
+ onPlay: this.onPlay,
64
+ });
65
+ this.render();
66
+ }
67
+
68
+ public render() {
69
+ this.viewer.$content.appendChild(this.renderSlideContainer());
70
+ }
71
+
72
+ public mount(taskId: string, url: string) {
73
+ this.target.appendChild(this.renderStyle());
74
+ this.target.appendChild(this.viewer.$content);
75
+ this.target.appendChild(this.viewer.$footer);
76
+
77
+ this.slide = new Slide({
78
+ anchor: this.$slide,
79
+ interactive: false,
80
+ mode: "local",
81
+ resize: true,
82
+ controller: this.debug,
83
+ renderOptions: {
84
+ minFPS: 25,
85
+ maxFPS: 30,
86
+ autoFPS: true,
87
+ autoResolution: true,
88
+ transactionBgColor: this.bgColor,
89
+ },
90
+ });
91
+
92
+ this.registerEventListeners();
93
+
94
+ this.slide.setResource(taskId, url);
95
+ this.slide.renderSlide(1);
96
+ }
97
+
98
+ protected renderStyle(): HTMLElement {
99
+ const element = document.createElement("style");
100
+ element.appendChild(document.createTextNode(style));
101
+ return element;
102
+ }
103
+
104
+ protected registerEventListeners() {
105
+ if (!this.slide) return;
106
+ const { slide } = this;
107
+
108
+ slide.on(SLIDE_EVENTS.slideChange, this.onPageChanged);
109
+ slide.on(SLIDE_EVENTS.renderStart, this.onTransitionStart);
110
+ slide.on(SLIDE_EVENTS.renderEnd, this.onTransitionEnd);
111
+ slide.on(SLIDE_EVENTS.mainSeqStepStart, this.onTransitionStart);
112
+ slide.on(SLIDE_EVENTS.mainSeqStepEnd, this.onTransitionEnd);
113
+ slide.on(SLIDE_EVENTS.renderError, this.onError);
114
+ slide.on(SLIDE_EVENTS.renderEnd, this.resolveReady);
115
+
116
+ this.readyPromise.then(this.refreshPages);
117
+ }
118
+
119
+ protected onPageChanged = (page: number) => {
120
+ this.viewer.setPageIndex(page - 1);
121
+ };
122
+
123
+ protected onTransitionStart = () => {
124
+ this.viewer.setPlaying();
125
+ };
126
+
127
+ protected onTransitionEnd = () => {
128
+ this.viewer.setPaused();
129
+ };
130
+
131
+ protected onError = ({ error }: { error: Error }) => {
132
+ this.viewer.setPaused();
133
+ console.warn("[Slide] render error", error);
134
+ };
135
+
136
+ private destroyed = false;
137
+ public destroy() {
138
+ if (this.slide && !this.destroyed) {
139
+ log("[Slide] destroy slide (once)");
140
+ this.slide.destroy();
141
+ this.destroyed = true;
142
+ }
143
+ this.viewer.destroy();
144
+ }
145
+
146
+ protected refreshPages = () => {
147
+ if (this.slide) {
148
+ this.viewer.pages = createDocsViewerPages(this.slide);
149
+ this.viewer.setPageIndex(this.getPageIndex(this.slide.slideCount));
150
+ }
151
+ };
152
+
153
+ protected getPageIndex(page: number) {
154
+ return (page > 0 ? page : 1) - 1;
155
+ }
156
+
157
+ protected renderSlideContainer(): HTMLDivElement {
158
+ if (!this.$slide) {
159
+ const $slide = document.createElement("div");
160
+ $slide.className = this.wrapClassName("slide");
161
+ $slide.dataset.appKind = "Slide";
162
+ this.$slide = $slide;
163
+ }
164
+ return this.$slide;
165
+ }
166
+
167
+ protected onPlay = () => {
168
+ if (this.slide) {
169
+ this.slide.nextStep();
170
+ }
171
+ };
172
+
173
+ protected onNewPageIndex = (index: number) => {
174
+ if (this.slide && this.slide.slideCount > 0) {
175
+ this.slide.renderSlide(clamp(index + 1, 1, this.slide.slideCount));
176
+ }
177
+ };
178
+
179
+ protected wrapClassName(className: string) {
180
+ return `${this.namespace}-${className}`;
181
+ }
182
+
183
+ protected namespace = "netless-app-slide";
184
+ }
package/src/index.ts CHANGED
@@ -14,8 +14,12 @@ import {
14
14
  } from "./SlideController";
15
15
  import { SlideDocsViewer } from "./SlideDocsViewer";
16
16
  import { apps, FreezerLength, addHooks } from "./utils/freezer";
17
+ import { log, logger } from "./utils/logger";
17
18
  import styles from "./style.scss?inline";
18
19
 
20
+ export type { PreviewParams } from "./SlidePreviewer";
21
+ export { SlidePreviewer, default as previewSlide } from "./SlidePreviewer";
22
+
19
23
  export type { Attributes, AddHooks, FreezableSlide };
20
24
 
21
25
  export { DefaultUrl, apps, FreezerLength, addHooks };
@@ -48,11 +52,13 @@ const SlideApp: NetlessApp<Attributes> = {
48
52
 
49
53
  const onPageChanged = (page: number) => {
50
54
  const room = context.getRoom();
51
- if (docsViewer && docsViewer.slideController && room && context.getIsWritable()) {
52
- syncSceneWithSlide(room, context, docsViewer.slideController.slide, baseScenePath);
53
- if (context.getAppOptions()?.debug || import.meta.env.DEV) {
54
- console.log("[Slide] page to", page);
55
+ if (docsViewer && docsViewer.slideController) {
56
+ let synced = false;
57
+ if (room && context.getIsWritable()) {
58
+ syncSceneWithSlide(room, context, docsViewer.slideController.slide, baseScenePath);
59
+ synced = true;
55
60
  }
61
+ log("[Slide] page to", page, synced);
56
62
  docsViewer.viewer.setPageIndex(page - 1);
57
63
  }
58
64
  };
@@ -64,6 +70,7 @@ const SlideApp: NetlessApp<Attributes> = {
64
70
  onPageChanged,
65
71
  });
66
72
  apps.set(context.appId, slideController);
73
+ (logger.apps[context.appId] ||= {}).controller = slideController;
67
74
  if (import.meta.env.DEV) {
68
75
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
69
76
  (window as any).slideController = slideController;
@@ -86,6 +93,14 @@ const SlideApp: NetlessApp<Attributes> = {
86
93
 
87
94
  const room = context.getRoom();
88
95
  const sideEffect = new SideEffectManager();
96
+
97
+ sideEffect.add(() => {
98
+ (logger.apps[context.appId] ||= {}).context = context;
99
+ logger.enable = context.getAppOptions()?.debug || import.meta.env.DEV;
100
+ logger.level = import.meta.env.DEV ? "verbose" : "debug";
101
+ return () => logger.dispose(context.appId);
102
+ });
103
+
89
104
  if (room) {
90
105
  docsViewer.toggleClickThrough(room.state.memberState.currentApplianceName);
91
106
  sideEffect.add(() => {
@@ -100,7 +115,7 @@ const SlideApp: NetlessApp<Attributes> = {
100
115
  }
101
116
 
102
117
  context.emitter.on("destroy", () => {
103
- console.log("[Slide]: destroy");
118
+ log("[Slide]: destroy");
104
119
  apps.delete(context.appId);
105
120
  sideEffect.flushAll();
106
121
  if (docsViewer) {
@@ -1,4 +1,5 @@
1
1
  import ColorString from "color-string";
2
+ import { log } from "./logger";
2
3
 
3
4
  export function guessBgColor(el: HTMLElement): string {
4
5
  try {
@@ -38,9 +39,7 @@ let cachedBgColor = "";
38
39
  export function cachedGetBgColor(el: HTMLElement): string {
39
40
  if (!cachedBgColor) {
40
41
  cachedBgColor = toHex(guessBgColor(el));
41
- if (import.meta.env.DEV) {
42
- console.log("[Slide] guess bg color", cachedBgColor);
43
- }
42
+ log("[Slide] guess bg color", cachedBgColor);
44
43
  }
45
44
  return cachedBgColor;
46
45
  }
@@ -1,4 +1,5 @@
1
1
  import type { RegisterParams } from "@netless/window-manager";
2
+ import { log } from "./logger";
2
3
 
3
4
  export interface FreezableSlide {
4
5
  freeze: () => void;
@@ -11,24 +12,18 @@ export const apps = {
11
12
  map: new Map<string, FreezableSlide>(),
12
13
  queue: [] as string[],
13
14
  validateQueue() {
14
- if (import.meta.env.DEV) {
15
- console.log("[Slide] freezer: validate", this.queue);
16
- }
15
+ log("[Slide] freezer: validate", this.queue);
17
16
  while (this.queue.length > FreezerLength) {
18
17
  const appId = this.queue.pop() as string;
19
18
  const slide = this.map.get(appId);
20
19
  if (slide) {
21
- if (import.meta.env.DEV) {
22
- console.log("[Slide] freezer: validate-freeze", appId, this.queue);
23
- }
20
+ log("[Slide] freezer: validate-freeze", appId, this.queue);
24
21
  slide.freeze();
25
22
  }
26
23
  }
27
24
  },
28
25
  set(appId: string, slide: FreezableSlide) {
29
- if (import.meta.env.DEV) {
30
- console.log("[Slide] freezer: add", appId, this.queue);
31
- }
26
+ log("[Slide] freezer: add", appId, this.queue);
32
27
  this.map.set(appId, slide);
33
28
  if (!this.queue.includes(appId)) {
34
29
  this.queue.unshift(appId);
@@ -36,9 +31,7 @@ export const apps = {
36
31
  this.validateQueue();
37
32
  },
38
33
  delete(appId: string) {
39
- if (import.meta.env.DEV) {
40
- console.log("[Slide] freezer: delete", appId, this.queue);
41
- }
34
+ log("[Slide] freezer: delete", appId, this.queue);
42
35
  this.map.delete(appId);
43
36
  this.queue = this.queue.filter(id => id !== appId);
44
37
  },
@@ -50,9 +43,7 @@ export const apps = {
50
43
  }
51
44
  this.queue.unshift(appId);
52
45
  this.validateQueue();
53
- if (import.meta.env.DEV) {
54
- console.log("[Slide] freezer: focus", appId, this.queue);
55
- }
46
+ log("[Slide] freezer: focus", appId, this.queue);
56
47
  if (slide) {
57
48
  slide.unfreeze();
58
49
  }
@@ -0,0 +1,39 @@
1
+ import type { SlideController } from "../SlideController";
2
+ import { isObj } from "./helpers";
3
+
4
+ class Logger {
5
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
6
+ public apps: Record<string, { context?: any; controller?: SlideController }> = {};
7
+ public level: "debug" | "verbose" = import.meta.env.DEV ? "verbose" : "debug";
8
+ constructor(public enable: boolean) {
9
+ window.addEventListener("message", this._onMessage);
10
+ }
11
+ log(...args: Parameters<Console["log"]>) {
12
+ if (this.enable) {
13
+ console.log(...args);
14
+ }
15
+ }
16
+ verbose(...args: Parameters<Console["log"]>) {
17
+ if (this.enable && this.level === "verbose") {
18
+ console.log(...args);
19
+ }
20
+ }
21
+ dispose(appId: string) {
22
+ this.enable = false;
23
+ delete this.apps[appId];
24
+ window.removeEventListener("message", this._onMessage);
25
+ }
26
+ _onMessage = (ev: MessageEvent<{ slide: boolean | "__instance" }>) => {
27
+ if (isObj(ev.data)) {
28
+ if (typeof ev.data.slide === "boolean") {
29
+ this.enable = ev.data.slide;
30
+ } else if (ev.data.slide === "__instance") {
31
+ console.log(this);
32
+ }
33
+ }
34
+ };
35
+ }
36
+
37
+ export const logger = new Logger(import.meta.env.DEV);
38
+ export const log = logger.log.bind(logger);
39
+ export const verbose = logger.verbose.bind(logger);