@netless/app-slide 0.0.28 → 0.0.33

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.28",
3
+ "version": "0.0.33",
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.33",
15
- "@types/color-string": "^1.5.0",
16
- "color-string": "^1.6.0",
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
@@ -142,6 +137,11 @@ export class SlideController {
142
137
  return disposer;
143
138
  });
144
139
 
140
+ this.sideEffect.add(() => {
141
+ context.emitter.on("seek", this.onSeeked);
142
+ return () => context.emitter.off("seek", this.onSeeked);
143
+ });
144
+
145
145
  this.sideEffect.add(() => {
146
146
  const displayer = context.getDisplayer();
147
147
  displayer.addMagixEventListener(this.channel, this.magixEventListener, {
@@ -170,9 +170,7 @@ export class SlideController {
170
170
  type: SLIDE_EVENTS.syncDispatch,
171
171
  payload: event,
172
172
  };
173
- if (this.debug) {
174
- console.log("[Slide] dispatch", event);
175
- }
173
+ log("[Slide] dispatch", event);
176
174
  this.room.dispatchMagixEvent(this.channel, payload);
177
175
  }
178
176
  };
@@ -182,9 +180,7 @@ export class SlideController {
182
180
  const { type, payload } = ev.payload as MagixPayload;
183
181
  if (type === SLIDE_EVENTS.syncDispatch) {
184
182
  this.syncStateOnce();
185
- if (this.debug) {
186
- console.log("[Slide] receive", payload);
187
- }
183
+ log("[Slide] receive", payload);
188
184
  // only emit the event if the slide state is sync-ed
189
185
  if (!this.syncStateOnceFlag) {
190
186
  this.slide.emit(SLIDE_EVENTS.syncReceive, payload);
@@ -198,9 +194,7 @@ export class SlideController {
198
194
  if (this.syncStateOnceFlag) {
199
195
  const { state } = { ...EmptyAttributes, ...this.context.getAttributes() };
200
196
  if (state) {
201
- if (this.debug) {
202
- console.log("[Slide] sync with state (once)", deepClone(state));
203
- }
197
+ log("[Slide] sync with state (once)", deepClone(state));
204
198
  this.slide.setSlideState(deepClone(state));
205
199
  this.syncStateOnceFlag = false;
206
200
  }
@@ -209,13 +203,19 @@ export class SlideController {
209
203
 
210
204
  private onStateChange = (state: SlideState) => {
211
205
  if (this.context.getIsWritable()) {
212
- if (import.meta.env.DEV) {
213
- console.log("[Slide] state change", JSON.stringify(state, null, 2));
214
- }
206
+ verbose("[Slide] state change", JSON.stringify(state, null, 2));
215
207
  this.context.updateAttributes(["state"], state);
216
208
  }
217
209
  };
218
210
 
211
+ private onSeeked = () => {
212
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
213
+ const state = this.context.getAttributes()!.state;
214
+ if (state) {
215
+ this.slide.setSlideState(deepClone(state));
216
+ }
217
+ };
218
+
219
219
  private pollCount = 0;
220
220
  private pollReadyState = () => {
221
221
  if (this.ready) {
@@ -229,9 +229,7 @@ export class SlideController {
229
229
  setTimeout(this.pollReadyState, 500);
230
230
  } else {
231
231
  this.pollCount = 0;
232
- if (this.debug) {
233
- console.log("[Slide] renderSlide (retry after timeout)", 1);
234
- }
232
+ log("[Slide] renderSlide (retry after timeout)", 1);
235
233
  this.slide.renderSlide(1);
236
234
  }
237
235
  };
@@ -255,7 +253,7 @@ export class SlideController {
255
253
  interactive: true,
256
254
  mode: "interactive",
257
255
  resize: true,
258
- controller: this.debug,
256
+ controller: logger.enable,
259
257
  renderOptions: {
260
258
  minFPS: 25,
261
259
  maxFPS: 30,
@@ -266,7 +264,7 @@ export class SlideController {
266
264
  },
267
265
  timestamp: this.timestamp,
268
266
  });
269
- if (this.debug) {
267
+ if (import.meta.env.DEV) {
270
268
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
271
269
  (window as any).slide = slide;
272
270
  }
@@ -278,9 +276,7 @@ export class SlideController {
278
276
  public destroy() {
279
277
  this.sideEffect.flushAll();
280
278
  if (!this.destroyed) {
281
- if (this.debug) {
282
- console.log("[Slide] destroy slide (once)");
283
- }
279
+ log("[Slide] destroy slide (once)");
284
280
  this.slide.destroy();
285
281
  this.destroyed = true;
286
282
  }
@@ -318,9 +314,7 @@ export class SlideController {
318
314
 
319
315
  public freeze = () => {
320
316
  if (this.ready) {
321
- if (this.debug) {
322
- console.log("[Slide] freeze", this.context.appId);
323
- }
317
+ log("[Slide] freeze", this.context.appId);
324
318
  if (this.freezePromise) {
325
319
  this._toFreeze = 1;
326
320
  } else if (!this.isFrozen) {
@@ -334,9 +328,7 @@ export class SlideController {
334
328
 
335
329
  public unfreeze = async () => {
336
330
  if (this.ready) {
337
- if (this.debug) {
338
- console.log("[Slide] unfreeze", this.context.appId);
339
- }
331
+ log("[Slide] unfreeze", this.context.appId);
340
332
  if (this.freezePromise) {
341
333
  this._toFreeze = -1;
342
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,
@@ -6,6 +6,6 @@ $namespace: "netless-app-slide";
6
6
  left: 0;
7
7
  width: 100%;
8
8
  height: 100%;
9
- z-index: 1001;
9
+ z-index: 100;
10
10
  overflow: hidden;
11
11
  }
@@ -0,0 +1,176 @@
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
+
8
+ export interface PreviewParams {
9
+ container: HTMLElement;
10
+ taskId: string;
11
+ url?: string;
12
+ debug?: boolean;
13
+ }
14
+
15
+ export default function previewSlide({
16
+ container,
17
+ taskId,
18
+ url = DefaultUrl,
19
+ debug = import.meta.env.DEV,
20
+ }: PreviewParams) {
21
+ if (!taskId) {
22
+ throw new Error("[Slide] taskId is required");
23
+ }
24
+
25
+ container.style.cssText += `display:flex;flex-direction:column`;
26
+ const previewer = new SlidePreviewer({ target: container });
27
+ previewer.debug = !!debug;
28
+
29
+ previewer.mount(taskId, url);
30
+
31
+ return previewer;
32
+ }
33
+
34
+ if (import.meta.env.DEV) {
35
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
36
+ (window as any).previewSlide = previewSlide;
37
+ }
38
+
39
+ export class SlidePreviewer {
40
+ public readonly viewer: DocsViewer;
41
+ public readonly bgColor: string;
42
+ public readonly target: HTMLElement;
43
+ public slide: Slide | null = null;
44
+ public debug = import.meta.env.DEV;
45
+
46
+ public $slide!: HTMLDivElement;
47
+ public ready = false;
48
+ private resolveReady!: () => void;
49
+ public readonly readyPromise = new Promise<void>((resolve) => {
50
+ this.resolveReady = () => {
51
+ this.ready = true;
52
+ resolve();
53
+ };
54
+ });
55
+
56
+ public constructor(config: { target: HTMLElement }) {
57
+ this.target = config.target;
58
+ this.bgColor = cachedGetBgColor(this.target);
59
+ this.viewer = new DocsViewer({
60
+ readonly: false,
61
+ onNewPageIndex: this.onNewPageIndex,
62
+ onPlay: this.onPlay,
63
+ });
64
+ this.render();
65
+ }
66
+
67
+ public render() {
68
+ this.viewer.$content.appendChild(this.renderSlideContainer());
69
+ }
70
+
71
+ public mount(taskId: string, url: string) {
72
+ this.target.appendChild(this.viewer.$content);
73
+ this.target.appendChild(this.viewer.$footer);
74
+
75
+ this.slide = new Slide({
76
+ anchor: this.$slide,
77
+ interactive: false,
78
+ mode: "local",
79
+ resize: true,
80
+ controller: this.debug,
81
+ renderOptions: {
82
+ minFPS: 25,
83
+ maxFPS: 30,
84
+ autoFPS: true,
85
+ autoResolution: true,
86
+ transactionBgColor: this.bgColor,
87
+ },
88
+ });
89
+
90
+ this.registerEventListeners();
91
+
92
+ this.slide.setResource(taskId, url);
93
+ this.slide.renderSlide(1);
94
+ }
95
+
96
+ protected registerEventListeners() {
97
+ if (!this.slide) return;
98
+ const { slide } = this;
99
+
100
+ slide.on(SLIDE_EVENTS.slideChange, this.onPageChanged);
101
+ slide.on(SLIDE_EVENTS.renderStart, this.onTransitionStart);
102
+ slide.on(SLIDE_EVENTS.renderEnd, this.onTransitionEnd);
103
+ slide.on(SLIDE_EVENTS.mainSeqStepStart, this.onTransitionStart);
104
+ slide.on(SLIDE_EVENTS.mainSeqStepEnd, this.onTransitionEnd);
105
+ slide.on(SLIDE_EVENTS.renderError, this.onError);
106
+ slide.on(SLIDE_EVENTS.renderEnd, this.resolveReady);
107
+
108
+ this.readyPromise.then(this.refreshPages);
109
+ }
110
+
111
+ protected onPageChanged = (page: number) => {
112
+ this.viewer.setPageIndex(page - 1);
113
+ };
114
+
115
+ protected onTransitionStart = () => {
116
+ this.viewer.setPlaying();
117
+ };
118
+
119
+ protected onTransitionEnd = () => {
120
+ this.viewer.setPaused();
121
+ };
122
+
123
+ protected onError = ({ error }: { error: Error }) => {
124
+ this.viewer.setPaused();
125
+ console.warn("[Slide] render error", error);
126
+ };
127
+
128
+ private destroyed = false;
129
+ public destroy() {
130
+ if (this.slide && !this.destroyed) {
131
+ log("[Slide] destroy slide (once)");
132
+ this.slide.destroy();
133
+ this.destroyed = true;
134
+ }
135
+ this.viewer.destroy();
136
+ }
137
+
138
+ protected refreshPages = () => {
139
+ if (this.slide) {
140
+ this.viewer.pages = createDocsViewerPages(this.slide);
141
+ this.viewer.setPageIndex(this.getPageIndex(this.slide.slideCount));
142
+ }
143
+ };
144
+
145
+ protected getPageIndex(page: number) {
146
+ return (page > 0 ? page : 1) - 1;
147
+ }
148
+
149
+ protected renderSlideContainer(): HTMLDivElement {
150
+ if (!this.$slide) {
151
+ const $slide = document.createElement("div");
152
+ $slide.className = this.wrapClassName("slide");
153
+ $slide.dataset.appKind = "Slide";
154
+ this.$slide = $slide;
155
+ }
156
+ return this.$slide;
157
+ }
158
+
159
+ protected onPlay = () => {
160
+ if (this.slide) {
161
+ this.slide.nextStep();
162
+ }
163
+ };
164
+
165
+ protected onNewPageIndex = (index: number) => {
166
+ if (this.slide && this.slide.slideCount > 0) {
167
+ this.slide.renderSlide(clamp(index + 1, 1, this.slide.slideCount));
168
+ }
169
+ };
170
+
171
+ protected wrapClassName(className: string) {
172
+ return `${this.namespace}-${className}`;
173
+ }
174
+
175
+ protected namespace = "netless-app-slide";
176
+ }
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);