@netless/fastboard-core 0.3.8 → 0.3.10

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/index.mjs CHANGED
@@ -104,20 +104,43 @@ function writable(value, start = noop, set) {
104
104
  reaction: internal.reaction,
105
105
  set,
106
106
  update(fn) {
107
- set(fn(value));
107
+ set(fn(internal.value));
108
108
  }
109
109
  };
110
110
  }
111
111
 
112
112
  // src/utils/misc.ts
113
- function getImageSize(url, fallback) {
113
+ function getImageSize(url, fallback, crossOrigin) {
114
114
  return new Promise((resolve) => {
115
115
  const img = new Image();
116
+ applyCrossOrigin(img, url, crossOrigin);
116
117
  img.onload = () => resolve(img);
117
118
  img.onerror = () => resolve(fallback);
118
119
  img.src = url;
119
120
  });
120
121
  }
122
+ function applyCrossOrigin(image, src, crossOrigin) {
123
+ if (crossOrigin === void 0 && !src.startsWith("data:")) {
124
+ image.crossOrigin = determineCrossOrigin(src);
125
+ } else if (crossOrigin !== false) {
126
+ image.crossOrigin = typeof crossOrigin === "string" ? crossOrigin : "anonymous";
127
+ }
128
+ }
129
+ function determineCrossOrigin(src) {
130
+ if (src.startsWith("data:") || typeof window === "undefined" || !window.location) {
131
+ return "";
132
+ }
133
+ const loc = window.location;
134
+ try {
135
+ const parsedUrl = new URL(src, document.baseURI);
136
+ if (parsedUrl.hostname !== loc.hostname || parsedUrl.port !== loc.port || parsedUrl.protocol !== loc.protocol) {
137
+ return "anonymous";
138
+ }
139
+ return "";
140
+ } catch (e) {
141
+ return "";
142
+ }
143
+ }
121
144
  function makeSlideParams(scenes) {
122
145
  const emptyScenes = [];
123
146
  let taskId = "";
@@ -214,7 +237,7 @@ for (const kind in DefaultApps) {
214
237
  }
215
238
  }
216
239
  var register = WindowManager.register.bind(WindowManager);
217
- var version = "0.3.8";
240
+ var version = "0.3.10";
218
241
  if (typeof window !== "undefined") {
219
242
  let str = window.__netlessUA || "";
220
243
  str += ` ${"@netless/fastboard"}@${version} `;
@@ -231,26 +254,33 @@ var FastboardAppBase = class {
231
254
  this.syncedStore = syncedStore;
232
255
  __publicField(this, "_destroyed", false);
233
256
  }
257
+ /** @internal */
234
258
  _assertNotDestroyed() {
235
259
  if (this._destroyed) {
236
260
  throw new Error("FastboardApp has been destroyed");
237
261
  }
238
262
  }
263
+ /** @internal */
239
264
  _addRoomListener(name, listener) {
240
265
  this._assertNotDestroyed();
241
266
  this.room.callbacks.on(name, listener);
242
267
  return () => this.room.callbacks.off(name, listener);
243
268
  }
269
+ /** @internal */
244
270
  _addManagerListener(name, listener) {
245
271
  this._assertNotDestroyed();
246
272
  this.manager.emitter.on(name, listener);
247
273
  return () => this.manager.emitter.off(name, listener);
248
274
  }
275
+ /** @internal */
249
276
  _addMainViewListener(name, listener) {
250
277
  this._assertNotDestroyed();
251
278
  this.manager.mainView.callbacks.on(name, listener);
252
279
  return () => this.manager.mainView.callbacks.off(name, listener);
253
280
  }
281
+ /**
282
+ * Destroy fastboard (disconnect from the whiteboard room).
283
+ */
254
284
  destroy() {
255
285
  this._destroyed = true;
256
286
  this.manager.destroy();
@@ -260,6 +290,9 @@ var FastboardAppBase = class {
260
290
  var FastboardApp = class extends FastboardAppBase {
261
291
  constructor() {
262
292
  super(...arguments);
293
+ /**
294
+ * Is current room writable?
295
+ */
263
296
  __publicField(this, "writable", writable(
264
297
  this.room.isWritable,
265
298
  (set) => {
@@ -268,34 +301,63 @@ var FastboardApp = class extends FastboardAppBase {
268
301
  },
269
302
  this.room.setWritable.bind(this.room)
270
303
  ));
304
+ /**
305
+ * Is current room online?
306
+ */
271
307
  __publicField(this, "phase", readable(this.room.phase, (set) => {
272
308
  set(this.room.phase);
273
309
  return this._addRoomListener("onPhaseChanged", set);
274
310
  }));
311
+ /**
312
+ * Current window-manager's windows' state (is it maximized?).
313
+ */
275
314
  __publicField(this, "boxState", readable(this.manager.boxState, (set) => {
276
315
  set(this.manager.boxState);
277
316
  return this._addManagerListener("boxStateChange", set);
278
317
  }));
318
+ /**
319
+ * Current window-manager's focused app's id.
320
+ * @example "HelloWorld-1A2b3C4d"
321
+ */
279
322
  __publicField(this, "focusedApp", readable(this.manager.focused, (set) => {
280
323
  set(this.manager.focused);
281
324
  return this._addManagerListener("focusedChange", set);
282
325
  }));
326
+ /**
327
+ * How many times can I call `app.redo()`?
328
+ */
283
329
  __publicField(this, "canRedoSteps", readable(this.manager.canRedoSteps, (set) => {
284
330
  set(this.manager.canRedoSteps);
285
331
  return this._addManagerListener("canRedoStepsChange", set);
286
332
  }));
333
+ /**
334
+ * How many times can I call `app.undo()`?
335
+ */
287
336
  __publicField(this, "canUndoSteps", readable(this.manager.canUndoSteps, (set) => {
288
337
  set(this.manager.canUndoSteps);
289
338
  return this._addManagerListener("canUndoStepsChange", set);
290
339
  }));
291
- __publicField(this, "camera", readable(this.manager.camera, (set) => {
292
- set(this.manager.camera);
293
- return this._addMainViewListener("onCameraUpdated", set);
340
+ /**
341
+ * Current camera information of main view.
342
+ *
343
+ * Change the camera position by `app.moveCamera()`.
344
+ */
345
+ __publicField(this, "camera", readable(this.manager.cameraState, (set) => {
346
+ set(this.manager.cameraState);
347
+ return this._addManagerListener("cameraStateChange", set);
294
348
  }));
349
+ /**
350
+ * Current tool's info, like "is using pencil?", "what color?".
351
+ *
352
+ * Change the tool by `app.setAppliance()`.
353
+ */
295
354
  __publicField(this, "memberState", readable(this.room.state.memberState, (set) => {
296
355
  set(this.room.state.memberState);
297
356
  return this._addRoomListener("onRoomStateChanged", ({ memberState: m }) => m && set(m));
298
357
  }));
358
+ /**
359
+ * 0..n-1, current index of main view scenes.
360
+ */
299
361
  __publicField(this, "sceneIndex", writable(
300
362
  this.manager.mainViewSceneIndex,
301
363
  (set) => {
@@ -304,11 +366,18 @@ var FastboardApp = class extends FastboardAppBase {
304
366
  },
305
367
  this.manager.setMainViewSceneIndex.bind(this.manager)
306
368
  ));
369
+ /**
370
+ * How many pages are in the main view?
371
+ */
307
372
  __publicField(this, "sceneLength", readable(this.manager.mainViewScenesLength, (set) => {
308
373
  set(this.manager.mainViewScenesLength);
309
374
  return this._addManagerListener("mainViewScenesLengthChange", set);
310
375
  }));
376
+ /** @internal */
311
377
  __publicField(this, "_appsStatus", {});
378
+ /**
379
+ * Apps status.
380
+ */
312
381
  __publicField(this, "appsStatus", readable(
313
382
  {},
314
383
  (set) => this._addManagerListener("loadApp", ({ kind, status, reason }) => {
@@ -317,34 +386,58 @@ var FastboardApp = class extends FastboardAppBase {
317
386
  })
318
387
  ));
319
388
  }
389
+ /**
390
+ * Render this app to some DOM.
391
+ */
320
392
  bindContainer(container) {
321
393
  this._assertNotDestroyed();
322
394
  this.manager.bindContainer(container);
323
395
  }
396
+ /**
397
+ * Move window-manager's collector to some place.
398
+ */
324
399
  bindCollector(container) {
325
400
  this._assertNotDestroyed();
326
401
  this.manager.bindCollectorContainer(container);
327
402
  }
403
+ /**
404
+ * Undo a step on main view.
405
+ */
328
406
  undo() {
329
407
  this._assertNotDestroyed();
330
408
  this.manager.undo();
331
409
  }
410
+ /**
411
+ * Redo a step on main view.
412
+ */
332
413
  redo() {
333
414
  this._assertNotDestroyed();
334
415
  this.manager.redo();
335
416
  }
417
+ /**
418
+ * Move current main view's camera position.
419
+ */
336
420
  moveCamera(camera) {
337
421
  this._assertNotDestroyed();
338
422
  this.manager.moveCamera(camera);
339
423
  }
424
+ /**
425
+ * Move current main view's camera to include a rectangle.
426
+ */
340
427
  moveCameraToContain(rectangle) {
341
428
  this._assertNotDestroyed();
342
429
  this.manager.moveCameraToContain(rectangle);
343
430
  }
431
+ /**
432
+ * Delete all things on the main view.
433
+ */
344
434
  cleanCurrentScene() {
345
435
  this._assertNotDestroyed();
346
436
  this.manager.cleanCurrentScene();
347
437
  }
438
+ /**
439
+ * Set current tool, like "pencil".
440
+ */
348
441
  setAppliance(appliance, shape) {
349
442
  this._assertNotDestroyed();
350
443
  this.manager.mainView.setMemberState({
@@ -352,39 +445,104 @@ var FastboardApp = class extends FastboardAppBase {
352
445
  shapeType: shape
353
446
  });
354
447
  }
448
+ /**
449
+ * Set pencil and shape's thickness.
450
+ */
355
451
  setStrokeWidth(strokeWidth) {
356
452
  this._assertNotDestroyed();
357
453
  this.manager.mainView.setMemberState({ strokeWidth });
358
454
  }
455
+ /**
456
+ * Set pencil and shape's color.
457
+ */
359
458
  setStrokeColor(strokeColor) {
360
459
  this._assertNotDestroyed();
361
460
  this.manager.mainView.setMemberState({ strokeColor });
362
461
  }
462
+ /**
463
+ * Set text size. Default is 16.
464
+ */
363
465
  setTextSize(textSize) {
364
466
  this._assertNotDestroyed();
365
467
  this.manager.mainView.setMemberState({ textSize });
366
468
  }
469
+ /**
470
+ * Set text color.
471
+ *
472
+ * @example
473
+ * setTextColor([0x66, 0xcc, 0xff])
474
+ */
367
475
  setTextColor(textColor) {
368
476
  this._assertNotDestroyed();
369
477
  this.manager.mainView.setMemberState({ textColor });
370
478
  }
479
+ /**
480
+ * Toggle dotted line effect on pencil.
481
+ */
482
+ toggleDottedLine(force) {
483
+ this._assertNotDestroyed();
484
+ this.manager.mainView.setMemberState({ dottedLine: force != null ? force : !this.memberState.value.dottedLine });
485
+ }
486
+ /**
487
+ * Set pencil eraser size.
488
+ */
489
+ setPencilEraserSize(size) {
490
+ this._assertNotDestroyed();
491
+ this.manager.mainView.setMemberState({ pencilEraserSize: size });
492
+ }
493
+ /**
494
+ * Goto previous page (the main whiteboard view).
495
+ */
371
496
  prevPage() {
372
497
  this._assertNotDestroyed();
373
498
  return this.manager.prevPage();
374
499
  }
500
+ /**
501
+ * Goto next page (the main whiteboard view).
502
+ */
375
503
  nextPage() {
376
504
  this._assertNotDestroyed();
377
505
  return this.manager.nextPage();
378
506
  }
507
+ /**
508
+ * Goto any page (index range: 0..n-1)
509
+ */
510
+ jumpPage(index) {
511
+ this._assertNotDestroyed();
512
+ return this.manager.jumpPage(index);
513
+ }
514
+ /**
515
+ * Add one page to the main whiteboard view.
516
+ *
517
+ * @example
518
+ * addPage({ after: true }) // add one page right after current one.
519
+ * nextPage() // then, goto that page.
520
+ */
379
521
  addPage(params) {
380
522
  this._assertNotDestroyed();
381
523
  return this.manager.addPage(params);
382
524
  }
525
+ /**
526
+ * Remove one page at given index or current page (by default).
527
+ *
528
+ * Requires `@netless/window-manager` >= 0.4.30.
529
+ *
530
+ * @example
531
+ * removePage() // remove current page
532
+ */
383
533
  removePage(index) {
384
534
  this._assertNotDestroyed();
385
535
  return this.manager.removePage(index);
386
536
  }
387
- async insertImage(url) {
537
+ /**
538
+ * Insert an image to the main view.
539
+ *
540
+ * @param crossOrigin Whether to load the image with CORS enabled, default is `true`.
541
+ *
542
+ * @example
543
+ * insertImage("https://i.imgur.com/CzXTtJV.jpg")
544
+ */
545
+ async insertImage(url, crossOrigin) {
388
546
  this._assertNotDestroyed();
389
547
  await this.manager.switchMainViewToWriter();
390
548
  const { divElement } = this.manager.mainView;
@@ -393,13 +551,21 @@ var FastboardApp = class extends FastboardAppBase {
393
551
  height: (divElement == null ? void 0 : divElement.scrollHeight) || window.innerHeight
394
552
  };
395
553
  const maxWidth = containerSize.width * 0.8;
396
- let { width, height } = await getImageSize(url, containerSize);
554
+ let { width, height } = await getImageSize(url, containerSize, crossOrigin);
397
555
  const scale = Math.min(maxWidth / width, 1);
398
556
  const uuid = genUID();
399
557
  const { centerX, centerY } = this.manager.camera;
400
558
  width *= scale;
401
559
  height *= scale;
402
- this.manager.mainView.insertImage({ uuid, centerX, centerY, width, height, locked: false });
560
+ this.manager.mainView.insertImage({
561
+ uuid,
562
+ centerX,
563
+ centerY,
564
+ width,
565
+ height,
566
+ locked: false,
567
+ crossOrigin
568
+ });
403
569
  this.manager.mainView.completeImageUpload(uuid, url);
404
570
  width /= 0.8;
405
571
  height /= 0.8;
@@ -442,6 +608,7 @@ var FastboardApp = class extends FastboardAppBase {
442
608
  throw new Error("Invalid input: not found 'progress', 'prefix' nor 'images'");
443
609
  }
444
610
  }
611
+ /** @internal */
445
612
  _insertDocsImpl(_a) {
446
613
  var _b = _a, { fileType, scenePath, title, scenes } = _b, attributes = __objRest(_b, ["fileType", "scenePath", "title", "scenes"]);
447
614
  this._assertNotDestroyed();
@@ -462,6 +629,9 @@ var FastboardApp = class extends FastboardAppBase {
462
629
  });
463
630
  }
464
631
  }
632
+ /**
633
+ * Insert the Media Player app.
634
+ */
465
635
  insertMedia(title, src) {
466
636
  this._assertNotDestroyed();
467
637
  return this.manager.addApp({
@@ -470,6 +640,10 @@ var FastboardApp = class extends FastboardAppBase {
470
640
  attributes: { src }
471
641
  });
472
642
  }
643
+ /**
644
+ * Insert the Monaco Code Editor app.
645
+ * @deprecated Use `app.manager.addApp({ kind: 'Monaco' })` instead.
646
+ */
473
647
  insertCodeEditor() {
474
648
  this._assertNotDestroyed();
475
649
  return this.manager.addApp({
@@ -477,6 +651,10 @@ var FastboardApp = class extends FastboardAppBase {
477
651
  options: { title: "Code Editor" }
478
652
  });
479
653
  }
654
+ /**
655
+ * Insert the Countdown app.
656
+ * @deprecated Use `app.manager.addApp({ kind: 'Countdown' })` instead.
657
+ */
480
658
  insertCountdown() {
481
659
  this._assertNotDestroyed();
482
660
  return this.manager.addApp({
@@ -484,6 +662,10 @@ var FastboardApp = class extends FastboardAppBase {
484
662
  options: { title: "Countdown" }
485
663
  });
486
664
  }
665
+ /**
666
+ * Insert the GeoGebra app.
667
+ * @deprecated Use `app.manager.addApp({ kind: 'GeoGebra' })` instead.
668
+ */
487
669
  insertGeoGebra() {
488
670
  this._assertNotDestroyed();
489
671
  return this.manager.addApp({
@@ -551,21 +733,25 @@ var FastboardPlayerBase = class {
551
733
  this.syncedStore = syncedStore;
552
734
  __publicField(this, "_destroyed", false);
553
735
  }
736
+ /** @internal */
554
737
  _assertNotDestroyed() {
555
738
  if (this._destroyed) {
556
739
  throw new Error("FastboardApp has been destroyed");
557
740
  }
558
741
  }
742
+ /** @internal */
559
743
  _addPlayerListener(name, listener) {
560
744
  this._assertNotDestroyed();
561
745
  this.player.callbacks.on(name, listener);
562
746
  return () => this.player.callbacks.off(name, listener);
563
747
  }
748
+ /** @internal */
564
749
  _addManagerListener(name, listener) {
565
750
  this._assertNotDestroyed();
566
751
  this.manager.emitter.on(name, listener);
567
752
  return () => this.manager.emitter.off(name, listener);
568
753
  }
754
+ /** @internal */
569
755
  _addMainViewListener(name, listener) {
570
756
  this._assertNotDestroyed();
571
757
  this.manager.mainView.callbacks.on(name, listener);
@@ -580,6 +766,9 @@ var FastboardPlayerBase = class {
580
766
  var FastboardPlayer = class extends FastboardPlayerBase {
581
767
  constructor() {
582
768
  super(...arguments);
769
+ /**
770
+ * Player current time in milliseconds.
771
+ */
583
772
  __publicField(this, "currentTime", writable(
584
773
  this.player.progressTime,
585
774
  (set) => {
@@ -588,15 +777,25 @@ var FastboardPlayer = class extends FastboardPlayerBase {
588
777
  },
589
778
  this.player.seekToProgressTime.bind(this.player)
590
779
  ));
780
+ /**
781
+ * Player state, like "is it playing?".
782
+ */
591
783
  __publicField(this, "phase", readable(this.player.phase, (set) => {
592
784
  set(this.player.phase);
593
785
  return this._addPlayerListener("onPhaseChanged", set);
594
786
  }));
787
+ /**
788
+ * Will become true after buffering.
789
+ */
595
790
  __publicField(this, "canplay", readable(this.player.isPlayable, (set) => {
596
791
  set(this.player.isPlayable);
597
792
  return this._addPlayerListener("onIsPlayableChanged", set);
598
793
  }));
794
+ /** @internal */
599
795
  __publicField(this, "_setPlaybackRate");
796
+ /**
797
+ * Playback speed, default `1`.
798
+ */
600
799
  __publicField(this, "playbackRate", writable(
601
800
  this.player.playbackSpeed,
602
801
  (set) => {
@@ -608,38 +807,65 @@ var FastboardPlayer = class extends FastboardPlayerBase {
608
807
  this._setPlaybackRate(value);
609
808
  }
610
809
  ));
810
+ /**
811
+ * Playback duration in milliseconds.
812
+ */
611
813
  __publicField(this, "duration", readable(this.player.timeDuration, (set) => {
612
814
  set(this.player.timeDuration);
613
815
  }));
816
+ /**
817
+ * Get state of room at that time, like "who was in the room?".
818
+ */
614
819
  __publicField(this, "state", readable(this.player.state, (set) => {
615
820
  set(this.player.state);
616
821
  return this._addPlayerListener("onPlayerStateChanged", () => set(this.player.state));
617
822
  }));
618
823
  }
824
+ /**
825
+ * Render this player to some DOM.
826
+ */
619
827
  bindContainer(container) {
620
828
  this._assertNotDestroyed();
621
829
  this.manager.bindContainer(container);
622
830
  }
831
+ /**
832
+ * Move window-manager's collector to some place.
833
+ */
623
834
  bindCollector(container) {
624
835
  this._assertNotDestroyed();
625
836
  this.manager.bindCollectorContainer(container);
626
837
  }
838
+ /**
839
+ * Seek to some time in milliseconds.
840
+ */
627
841
  seek(timestamp) {
628
842
  this._assertNotDestroyed();
629
843
  return this.player.seekToProgressTime(timestamp);
630
844
  }
845
+ /**
846
+ * Change player state to playing.
847
+ */
631
848
  play() {
632
849
  this._assertNotDestroyed();
633
850
  this.player.play();
634
851
  }
852
+ /**
853
+ * Change player state to paused.
854
+ */
635
855
  pause() {
636
856
  this._assertNotDestroyed();
637
857
  this.player.pause();
638
858
  }
859
+ /**
860
+ * Change player state to stopped.
861
+ */
639
862
  stop() {
640
863
  this._assertNotDestroyed();
641
864
  this.player.stop();
642
865
  }
866
+ /**
867
+ * Set playback speed, a shortcut for `speed.set(x)`.
868
+ */
643
869
  setPlaybackRate(value) {
644
870
  this._assertNotDestroyed();
645
871
  this.playbackRate.set(value);
@@ -773,5 +999,4 @@ function dispatchDocsEvent(fastboard, event, options = {}) {
773
999
  }
774
1000
 
775
1001
  export { FastboardApp, FastboardPlayer, addManagerListener, addPlayerListener, addRoomListener, addViewListener, convertedFileToScene, createFastboard, dispatchDocsEvent, genUID, getImageSize, makeSlideParams, readable, register, replayFastboard, version, warn, writable };
776
- //# sourceMappingURL=out.js.map
777
- //# sourceMappingURL=index.mjs.map
1002
+ //# sourceMappingURL=index.mjs.map