@netless/window-manager 1.0.0-canary.52 → 1.0.0-canary.54

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.
Files changed (44) hide show
  1. package/dist/index.cjs.js +389 -445
  2. package/dist/index.es.js +434 -490
  3. package/dist/index.umd.js +389 -446
  4. package/dist/src/App/AppContext.d.ts +8 -8
  5. package/dist/src/AppManager.d.ts +5 -1
  6. package/dist/src/Cursor/index.d.ts +1 -0
  7. package/dist/src/Utils/Reactive.d.ts +1 -1
  8. package/dist/src/View/CameraSynchronizer.d.ts +4 -3
  9. package/dist/src/View/ScrollMode.d.ts +32 -0
  10. package/dist/src/View/ViewSync.d.ts +4 -2
  11. package/dist/src/callback.d.ts +3 -0
  12. package/dist/src/constants.d.ts +2 -0
  13. package/dist/src/index.d.ts +21 -11
  14. package/dist/src/storage.d.ts +7 -0
  15. package/dist/src/typings.d.ts +5 -4
  16. package/dist/style.css +2 -1
  17. package/docs/api.md +10 -0
  18. package/package.json +4 -3
  19. package/pnpm-lock.yaml +28 -73
  20. package/src/App/AppContext.ts +19 -8
  21. package/src/App/WhiteboardView.ts +4 -2
  22. package/src/AppListener.ts +1 -10
  23. package/src/AppManager.ts +19 -1
  24. package/src/Cursor/index.ts +6 -2
  25. package/src/Utils/Reactive.ts +2 -1
  26. package/src/View/CameraSynchronizer.ts +35 -23
  27. package/src/View/MainView.ts +1 -0
  28. package/src/View/ScrollMode.ts +229 -0
  29. package/src/View/ViewSync.ts +31 -18
  30. package/src/callback.ts +3 -0
  31. package/src/constants.ts +3 -0
  32. package/src/index.ts +56 -63
  33. package/src/storage.ts +15 -0
  34. package/src/style.css +1 -1
  35. package/src/typings.ts +6 -3
  36. package/vite.config.js +1 -1
  37. package/dist/src/App/Storage/StorageEvent.d.ts +0 -8
  38. package/dist/src/App/Storage/index.d.ts +0 -39
  39. package/dist/src/App/Storage/typings.d.ts +0 -22
  40. package/dist/src/App/Storage/utils.d.ts +0 -5
  41. package/src/App/Storage/StorageEvent.ts +0 -21
  42. package/src/App/Storage/index.ts +0 -295
  43. package/src/App/Storage/typings.ts +0 -23
  44. package/src/App/Storage/utils.ts +0 -17
package/dist/index.es.js CHANGED
@@ -31,11 +31,12 @@ var __objRest = (source, exclude) => {
31
31
  };
32
32
  import pRetry from "p-retry";
33
33
  import Emittery from "emittery";
34
- import { debounce, throttle, isEqual, pick, isObject, has, get, size, mapValues, noop as noop$1, isBoolean, isNumber, omitBy, isUndefined, isInteger, orderBy, isEmpty, omit, isFunction, isNull } from "lodash";
35
- import { ScenePathType, AnimationMode, UpdateEventKind, listenUpdated, unlistenUpdated, reaction, toJS, WhiteVersion, autorun, listenDisposed, unlistenDisposed, ViewMode, isPlayer, isRoom, ApplianceNames, RoomPhase, InvisiblePlugin } from "white-web-sdk";
34
+ import { debounce, pick, isBoolean, isNumber, throttle, isEqual, isEmpty, get, omitBy, isUndefined, isObject, isInteger, orderBy, omit, isFunction, isNull } from "lodash";
35
+ import { ScenePathType, toJS, WhiteVersion, autorun, reaction, listenUpdated, unlistenUpdated, listenDisposed, unlistenDisposed, AnimationMode, ViewMode, UpdateEventKind, isPlayer, isRoom, ApplianceNames, RoomPhase, InvisiblePlugin } from "white-web-sdk";
36
36
  import { v4 } from "uuid";
37
- import { genUID, SideEffectManager } from "side-effect-manager";
38
- import { Val, combine, ValManager, withReadonlyValueEnhancer, withValueEnhancer, derive } from "value-enhancer";
37
+ import { Storage } from "@netless/synced-store";
38
+ import { Val, derive, combine, ValManager, withReadonlyValueEnhancer, withValueEnhancer } from "value-enhancer";
39
+ import { SideEffectManager, genUID } from "side-effect-manager";
39
40
  import { ResizeObserver as ResizeObserver$2 } from "@juggle/resize-observer";
40
41
  var Events = /* @__PURE__ */ ((Events2) => {
41
42
  Events2["AppMove"] = "AppMove";
@@ -95,6 +96,8 @@ const ROOT_DIR = "/";
95
96
  const INIT_DIR = "/init";
96
97
  const SETUP_APP_DELAY = 50;
97
98
  const MAX_PAGE_SIZE = 500;
99
+ const SCROLL_MODE_BASE_WIDTH = 1600;
100
+ const SCROLL_MODE_BASE_HEIGHT = SCROLL_MODE_BASE_WIDTH * 3;
98
101
  const callbacks = new Emittery();
99
102
  class AppCreateQueue {
100
103
  constructor() {
@@ -515,66 +518,6 @@ const isRootDirPage = (scenePath) => {
515
518
  }, 0);
516
519
  return delimiterCount === 1;
517
520
  };
518
- class CameraSynchronizer {
519
- constructor(saveCamera) {
520
- this.saveCamera = saveCamera;
521
- this.setRect = (rect) => {
522
- this.rect = rect;
523
- if (this.remoteCamera && this.remoteSize) {
524
- this.onRemoteUpdate(this.remoteCamera, this.remoteSize);
525
- }
526
- };
527
- this.onRemoteUpdate = throttle((camera, size2) => {
528
- this.remoteCamera = camera;
529
- this.remoteSize = size2;
530
- if (this.remoteSize && this.rect) {
531
- const nextScale = camera.scale * computedMinScale(size2, this.rect);
532
- const config = {
533
- scale: nextScale
534
- };
535
- if (camera.centerX !== null) {
536
- config.centerX = camera.centerX;
537
- }
538
- if (camera.centerY !== null) {
539
- config.centerY = camera.centerY;
540
- }
541
- this.moveCamera(config);
542
- }
543
- }, 10);
544
- }
545
- setView(view) {
546
- this.view = view;
547
- }
548
- onRemoteSizeUpdate(size2) {
549
- var _a;
550
- this.remoteSize = size2;
551
- const needMoveCamera = !isEqual(pick(this.rect, ["width", "height"]), pick(size2, ["width", "height"]));
552
- if (this.rect && this.remoteCamera && needMoveCamera) {
553
- if (!this.view)
554
- return;
555
- const currentCamera = this.view.camera;
556
- (_a = this.view) == null ? void 0 : _a.moveCameraToContain({
557
- width: size2.width,
558
- height: size2.height,
559
- originX: currentCamera.centerX - size2.width / 2,
560
- originY: currentCamera.centerY - size2.height / 2
561
- });
562
- }
563
- }
564
- onLocalCameraUpdate(camera) {
565
- this.saveCamera(camera);
566
- this.remoteCamera = camera;
567
- }
568
- moveCamera(camera) {
569
- var _a;
570
- (_a = this.view) == null ? void 0 : _a.moveCamera(__spreadProps(__spreadValues({}, camera), { animationMode: AnimationMode.Immediately }));
571
- }
572
- }
573
- const computedMinScale = (remoteSize, currentSize) => {
574
- const wScale = currentSize.width / remoteSize.width;
575
- const hScale = currentSize.height / remoteSize.height;
576
- return Math.min(wScale, hScale);
577
- };
578
521
  class AppListeners {
579
522
  constructor(manager) {
580
523
  this.manager = manager;
@@ -675,16 +618,7 @@ class AppListeners {
675
618
  }
676
619
  };
677
620
  this.moveCameraHandler = (payload) => {
678
- var _a;
679
- const cameraPayload = payload;
680
- if (payload.scale) {
681
- const remoteSize = this.manager.mainViewProxy.size$.value;
682
- const currentSize = (_a = this.manager.boxManager) == null ? void 0 : _a.stageRect;
683
- if (remoteSize && currentSize) {
684
- cameraPayload.scale = payload.scale * computedMinScale(remoteSize, currentSize);
685
- }
686
- }
687
- this.manager.mainView.moveCamera(cameraPayload);
621
+ this.manager.mainView.moveCamera(payload);
688
622
  };
689
623
  this.moveCameraToContainHandler = (payload) => {
690
624
  this.manager.mainView.moveCameraToContain(payload);
@@ -752,292 +686,6 @@ class BindContainerRoomPhaseInvalidError extends Error {
752
686
  this.message = "[WindowManager]: room phase only Connected can be bindContainer";
753
687
  }
754
688
  }
755
- const onObjectByEvent = (event) => {
756
- return (object, func) => {
757
- if (object === void 0)
758
- return;
759
- if (listenUpdated) {
760
- const listener = (events) => {
761
- const kinds = events.map((e) => e.kind);
762
- if (kinds.includes(event)) {
763
- func();
764
- }
765
- };
766
- listenUpdated(object, listener);
767
- func();
768
- return () => unlistenUpdated(object, listener);
769
- } else {
770
- return reaction(() => object, () => {
771
- func();
772
- }, {
773
- fireImmediately: true
774
- });
775
- }
776
- };
777
- };
778
- const safeListenPropsUpdated = (getProps, callback, onDestroyed) => {
779
- let disposeListenUpdated = null;
780
- const disposeReaction = reaction(getProps, () => {
781
- if (disposeListenUpdated) {
782
- disposeListenUpdated();
783
- disposeListenUpdated = null;
784
- }
785
- const props = getProps();
786
- if (isObject(props)) {
787
- disposeListenUpdated = () => unlistenUpdated(props, callback);
788
- listenUpdated(props, callback);
789
- } else {
790
- onDestroyed == null ? void 0 : onDestroyed(props);
791
- }
792
- }, { fireImmediately: true });
793
- return () => {
794
- disposeListenUpdated == null ? void 0 : disposeListenUpdated();
795
- disposeReaction();
796
- };
797
- };
798
- const onObjectRemoved = onObjectByEvent(UpdateEventKind.Removed);
799
- onObjectByEvent(UpdateEventKind.Inserted);
800
- const plainObjectKeys = Object.keys;
801
- function isRef(e) {
802
- return Boolean(has(e, "__isRef"));
803
- }
804
- function makeRef(v) {
805
- return { k: genUID(), v, __isRef: true };
806
- }
807
- class StorageEvent {
808
- constructor() {
809
- this.listeners = /* @__PURE__ */ new Set();
810
- }
811
- get length() {
812
- return this.listeners.size;
813
- }
814
- dispatch(message) {
815
- this.listeners.forEach((callback) => callback(message));
816
- }
817
- addListener(listener) {
818
- this.listeners.add(listener);
819
- }
820
- removeListener(listener) {
821
- this.listeners.delete(listener);
822
- }
823
- }
824
- const STORAGE_NS = "_WM-STORAGE_";
825
- class Storage {
826
- constructor(context, id, defaultState) {
827
- this._sideEffect = new SideEffectManager();
828
- this._destroyed = false;
829
- this._refMap = /* @__PURE__ */ new WeakMap();
830
- this._lastValue = /* @__PURE__ */ new Map();
831
- this.onStateChanged = new StorageEvent();
832
- if (defaultState && !isObject(defaultState)) {
833
- throw new Error(`Default state for Storage ${id} is not an object.`);
834
- }
835
- this._context = context;
836
- this.id = id || null;
837
- this._state = {};
838
- const rawState = this._getRawState(this._state);
839
- if (this._context.isWritable) {
840
- if (this.id === null) {
841
- if (context.isAddApp && defaultState) {
842
- this.setState(defaultState);
843
- }
844
- } else {
845
- if (rawState === this._state || !isObject(rawState)) {
846
- if (!get(this._context.getAttributes(), [STORAGE_NS])) {
847
- this._context.updateAttributes([STORAGE_NS], {});
848
- }
849
- this._context.updateAttributes([STORAGE_NS, this.id], this._state);
850
- if (defaultState) {
851
- this.setState(defaultState);
852
- }
853
- }
854
- }
855
- }
856
- plainObjectKeys(rawState).forEach((key) => {
857
- if (this.id === null && key === STORAGE_NS) {
858
- return;
859
- }
860
- try {
861
- const rawValue = isObject(rawState[key]) ? JSON.parse(JSON.stringify(rawState[key])) : rawState[key];
862
- if (isRef(rawValue)) {
863
- this._state[key] = rawValue.v;
864
- if (isObject(rawValue.v)) {
865
- this._refMap.set(rawValue.v, rawValue);
866
- }
867
- } else {
868
- this._state[key] = rawValue;
869
- }
870
- } catch (e) {
871
- console.error(e);
872
- }
873
- });
874
- this._sideEffect.addDisposer(safeListenPropsUpdated(() => this.id === null ? context.getAttributes() : get(context.getAttributes(), [STORAGE_NS, this.id]), this._updateProperties.bind(this), this.destroy.bind(this)));
875
- }
876
- get state() {
877
- if (this._destroyed) {
878
- console.warn(`Accessing state on destroyed Storage "${this.id}"`);
879
- }
880
- return this._state;
881
- }
882
- addStateChangedListener(handler) {
883
- this.onStateChanged.addListener(handler);
884
- return () => this.onStateChanged.removeListener(handler);
885
- }
886
- ensureState(state) {
887
- return this.setState(plainObjectKeys(state).reduce((payload, key) => {
888
- if (!has(this._state, key)) {
889
- payload[key] = state[key];
890
- }
891
- return payload;
892
- }, {}));
893
- }
894
- setState(state) {
895
- if (this._destroyed) {
896
- console.error(new Error(`Cannot call setState on destroyed Storage "${this.id}".`));
897
- return;
898
- }
899
- if (!this._context.isWritable) {
900
- console.error(new Error(`Cannot setState on Storage "${this.id}" without writable access`), state);
901
- return;
902
- }
903
- const keys = plainObjectKeys(state);
904
- if (keys.length > 0) {
905
- keys.forEach((key) => {
906
- const value = state[key];
907
- if (value === this._state[key]) {
908
- return;
909
- }
910
- if (value === void 0) {
911
- this._lastValue.set(key, this._state[key]);
912
- delete this._state[key];
913
- this._setRawState(key, value);
914
- } else {
915
- this._lastValue.set(key, this._state[key]);
916
- this._state[key] = value;
917
- let payload = value;
918
- if (isObject(value)) {
919
- let refValue = this._refMap.get(value);
920
- if (!refValue) {
921
- refValue = makeRef(value);
922
- this._refMap.set(value, refValue);
923
- }
924
- payload = refValue;
925
- }
926
- this._setRawState(key, payload);
927
- }
928
- });
929
- }
930
- }
931
- emptyStorage() {
932
- if (size(this._state) <= 0) {
933
- return;
934
- }
935
- if (this._destroyed) {
936
- console.error(new Error(`Cannot empty destroyed Storage "${this.id}".`));
937
- return;
938
- }
939
- if (!this._context.isWritable) {
940
- console.error(new Error(`Cannot empty Storage "${this.id}" without writable access.`));
941
- return;
942
- }
943
- this.setState(mapValues(this._state, noop$1));
944
- }
945
- deleteStorage() {
946
- if (this.id === null) {
947
- throw new Error(`Cannot delete main Storage`);
948
- }
949
- if (!this._context.isWritable) {
950
- console.error(new Error(`Cannot delete Storage "${this.id}" without writable access.`));
951
- return;
952
- }
953
- this.destroy();
954
- this._context.updateAttributes([STORAGE_NS, this.id], void 0);
955
- }
956
- get destroyed() {
957
- return this._destroyed;
958
- }
959
- destroy() {
960
- this._destroyed = true;
961
- this._sideEffect.flushAll();
962
- }
963
- _getRawState(defaultValue) {
964
- var _a;
965
- if (this.id === null) {
966
- return (_a = this._context.getAttributes()) != null ? _a : defaultValue;
967
- } else {
968
- return get(this._context.getAttributes(), [STORAGE_NS, this.id], defaultValue);
969
- }
970
- }
971
- _setRawState(key, value) {
972
- if (this.id === null) {
973
- if (key === STORAGE_NS) {
974
- throw new Error(`Cannot set attribute internal filed "${STORAGE_NS}"`);
975
- }
976
- return this._context.updateAttributes([key], value);
977
- } else {
978
- return this._context.updateAttributes([STORAGE_NS, this.id, key], value);
979
- }
980
- }
981
- _updateProperties(actions) {
982
- var _a;
983
- if (this._destroyed) {
984
- console.error(new Error(`Cannot call _updateProperties on destroyed Storage "${this.id}".`));
985
- return;
986
- }
987
- if (actions.length > 0) {
988
- const diffs = {};
989
- for (let i = 0; i < actions.length; i++) {
990
- try {
991
- const action = actions[i];
992
- const key = action.key;
993
- if (this.id === null && key === STORAGE_NS) {
994
- continue;
995
- }
996
- const value = isObject(action.value) ? JSON.parse(JSON.stringify(action.value)) : action.value;
997
- let oldValue;
998
- if (this._lastValue.has(key)) {
999
- oldValue = this._lastValue.get(key);
1000
- this._lastValue.delete(key);
1001
- }
1002
- switch (action.kind) {
1003
- case 2: {
1004
- if (has(this._state, key)) {
1005
- oldValue = this._state[key];
1006
- delete this._state[key];
1007
- }
1008
- diffs[key] = { oldValue };
1009
- break;
1010
- }
1011
- default: {
1012
- let newValue = value;
1013
- if (isRef(value)) {
1014
- const { k: k2, v } = value;
1015
- const curValue = this._state[key];
1016
- if (isObject(curValue) && ((_a = this._refMap.get(curValue)) == null ? void 0 : _a.k) === k2) {
1017
- newValue = curValue;
1018
- } else {
1019
- newValue = v;
1020
- if (isObject(v)) {
1021
- this._refMap.set(v, value);
1022
- }
1023
- }
1024
- }
1025
- if (newValue !== this._state[key]) {
1026
- oldValue = this._state[key];
1027
- this._state[key] = newValue;
1028
- }
1029
- diffs[key] = { newValue, oldValue };
1030
- break;
1031
- }
1032
- }
1033
- } catch (e) {
1034
- console.error(e);
1035
- }
1036
- }
1037
- this.onStateChanged.dispatch(diffs);
1038
- }
1039
- }
1040
- }
1041
689
  class WhiteBoardView {
1042
690
  constructor(view, appContext, appProxy, ensureSize) {
1043
691
  this.view = view;
@@ -1066,11 +714,12 @@ class WhiteBoardView {
1066
714
  const scenePath = this.appProxy.scenePath;
1067
715
  if (!scenePath)
1068
716
  return;
717
+ const scenes = Array.isArray(scene) ? scene : [scene || {}];
1069
718
  if (after) {
1070
719
  const nextIndex = this.pageState.index + 1;
1071
- putScenes(this.appContext.room, scenePath, [scene || {}], nextIndex);
720
+ putScenes(this.appContext.room, scenePath, scenes, nextIndex);
1072
721
  } else {
1073
- putScenes(this.appContext.room, scenePath, [scene || {}]);
722
+ putScenes(this.appContext.room, scenePath, scenes);
1074
723
  }
1075
724
  };
1076
725
  this.removePage = async (index2) => {
@@ -1099,9 +748,9 @@ class WhiteBoardView {
1099
748
  camera$.setValue(pickCamera(camera));
1100
749
  }
1101
750
  }),
1102
- appProxy.size$.subscribe((size2) => {
1103
- if (size2) {
1104
- baseRect$.setValue(pick(size2, ["width", "height"]));
751
+ appProxy.size$.subscribe((size) => {
752
+ if (size) {
753
+ baseRect$.setValue(pick(size, ["width", "height"]));
1105
754
  }
1106
755
  })
1107
756
  ]);
@@ -1234,18 +883,18 @@ class AppContext {
1234
883
  this.appProxy.whiteBoardViewCreated$.setValue(true);
1235
884
  return this.whiteBoardView;
1236
885
  };
1237
- this.ensurePageSize = (size2) => {
886
+ this.ensurePageSize = (size) => {
1238
887
  var _a;
1239
- if (!isNumber(size2))
888
+ if (!isNumber(size))
1240
889
  return;
1241
890
  if (!this.appProxy.scenePath)
1242
891
  return;
1243
- if (this.appProxy.pageState.length >= size2)
892
+ if (this.appProxy.pageState.length >= size)
1244
893
  return;
1245
- if (size2 <= 0 || size2 >= MAX_PAGE_SIZE) {
1246
- throw Error(`[WindowManager]: size ${size2} muse be in range [1, ${MAX_PAGE_SIZE}]`);
894
+ if (size <= 0 || size >= MAX_PAGE_SIZE) {
895
+ throw Error(`[WindowManager]: size ${size} muse be in range [1, ${MAX_PAGE_SIZE}]`);
1247
896
  }
1248
- const needInsert = size2 - this.appProxy.pageState.length;
897
+ const needInsert = size - this.appProxy.pageState.length;
1249
898
  const scenes = new Array(needInsert).fill({});
1250
899
  (_a = this.room) == null ? void 0 : _a.putScenes(this.appProxy.scenePath, scenes);
1251
900
  };
@@ -1270,10 +919,20 @@ class AppContext {
1270
919
  this.getAppOptions = () => {
1271
920
  return typeof this.appOptions === "function" ? this.appOptions() : this.appOptions;
1272
921
  };
1273
- this.createStorage = (storeId, defaultState) => {
1274
- const storage = new Storage(this, storeId, defaultState);
922
+ this.createStorage = (namespace, defaultState) => {
923
+ const isWritable$ = new Val(this.isWritable);
924
+ const plugin$ = new Val(this.manager.windowManger);
925
+ const storage = new Storage({
926
+ plugin$,
927
+ isWritable$,
928
+ namespace,
929
+ defaultState
930
+ });
931
+ this.emitter.on("writableChange", (writable) => {
932
+ isWritable$.setValue(writable);
933
+ });
1275
934
  this.emitter.on("destroy", () => {
1276
- storage.destroy();
935
+ storage.disconnect();
1277
936
  });
1278
937
  return storage;
1279
938
  };
@@ -1336,7 +995,7 @@ class AppContext {
1336
995
  }
1337
996
  get storage() {
1338
997
  if (!this._storage) {
1339
- this._storage = new Storage(this);
998
+ this._storage = this.createStorage(this.appId, this.getAttributes());
1340
999
  }
1341
1000
  return this._storage;
1342
1001
  }
@@ -1394,6 +1053,77 @@ class AppPageStateImpl {
1394
1053
  (_a = this.sceneNode) == null ? void 0 : _a.dispose();
1395
1054
  }
1396
1055
  }
1056
+ class CameraSynchronizer {
1057
+ constructor(saveCamera) {
1058
+ this.saveCamera = saveCamera;
1059
+ this.scale = 1;
1060
+ this.setRect = (rect, updateCamera = true) => {
1061
+ this.rect = rect;
1062
+ if (this.remoteCamera && this.remoteSize && updateCamera) {
1063
+ this.onRemoteUpdate(this.remoteCamera, this.remoteSize);
1064
+ }
1065
+ };
1066
+ this.onRemoteUpdate = throttle((camera, size) => {
1067
+ this.remoteCamera = camera;
1068
+ this.remoteSize = size;
1069
+ if (this.remoteSize && this.rect) {
1070
+ requestAnimationFrame(() => {
1071
+ this.moveCameraToContian(size);
1072
+ this.moveCamera(camera);
1073
+ });
1074
+ }
1075
+ }, 32);
1076
+ }
1077
+ setView(view) {
1078
+ this.view = view;
1079
+ }
1080
+ onRemoteSizeUpdate(size) {
1081
+ var _a;
1082
+ this.remoteSize = size;
1083
+ const needMoveCamera = !isEqual(pick(this.rect, ["width", "height"]), pick(size, ["width", "height"]));
1084
+ if (this.rect && this.remoteCamera && needMoveCamera) {
1085
+ if (!this.view)
1086
+ return;
1087
+ const currentCamera = this.view.camera;
1088
+ (_a = this.view) == null ? void 0 : _a.moveCameraToContain({
1089
+ width: size.width,
1090
+ height: size.height,
1091
+ originX: currentCamera.centerX - size.width / 2,
1092
+ originY: currentCamera.centerY - size.height / 2
1093
+ });
1094
+ }
1095
+ }
1096
+ onLocalCameraUpdate(camera) {
1097
+ this.saveCamera(camera);
1098
+ this.remoteCamera = camera;
1099
+ }
1100
+ moveCameraToContian(size) {
1101
+ if (!isEmpty(size) && this.view) {
1102
+ this.view.moveCameraToContain({
1103
+ width: size.width,
1104
+ height: size.height,
1105
+ originX: -size.width / 2,
1106
+ originY: -size.height / 2,
1107
+ animationMode: AnimationMode.Immediately
1108
+ });
1109
+ this.scale = this.view.camera.scale;
1110
+ }
1111
+ }
1112
+ moveCamera(camera) {
1113
+ if (!isEmpty(camera) && this.view && camera.centerX && camera.centerY) {
1114
+ if (isEqual(camera, this.view.camera))
1115
+ return;
1116
+ const { centerX, centerY, scale: scale2 } = camera;
1117
+ const needScale = scale2 * (this.scale || 1);
1118
+ this.view.moveCamera({
1119
+ centerX,
1120
+ centerY,
1121
+ scale: needScale,
1122
+ animationMode: AnimationMode.Immediately
1123
+ });
1124
+ }
1125
+ }
1126
+ }
1397
1127
  class ViewSync {
1398
1128
  constructor(context) {
1399
1129
  this.context = context;
@@ -1411,8 +1141,9 @@ class ViewSync {
1411
1141
  };
1412
1142
  this.subscribeView = () => {
1413
1143
  return this.context.view$.subscribe((view) => {
1144
+ var _a;
1414
1145
  const currentCamera = this.context.camera$.value;
1415
- if (currentCamera && this.context.size$.value) {
1146
+ if (currentCamera && this.context.size$.value && ((_a = this.needRecoverCamera$) == null ? void 0 : _a.value)) {
1416
1147
  view == null ? void 0 : view.moveCamera({
1417
1148
  scale: 1,
1418
1149
  animationMode: AnimationMode.Immediately
@@ -1426,23 +1157,23 @@ class ViewSync {
1426
1157
  return this.context.camera$.subscribe((camera, skipUpdate) => {
1427
1158
  if (skipUpdate)
1428
1159
  return;
1429
- const size2 = this.context.size$.value;
1430
- if (camera && size2) {
1431
- this.synchronizer.onRemoteUpdate(camera, size2);
1160
+ const size = this.context.size$.value;
1161
+ if (camera && size) {
1162
+ this.synchronizer.onRemoteUpdate(camera, size);
1432
1163
  }
1433
1164
  });
1434
1165
  };
1435
1166
  this.subscribeSize = () => {
1436
- return this.context.size$.subscribe((size2) => {
1437
- if (size2) {
1438
- this.synchronizer.onRemoteSizeUpdate(size2);
1167
+ return this.context.size$.subscribe((size) => {
1168
+ if (size && this.isBroadcastMode) {
1169
+ this.synchronizer.onRemoteSizeUpdate(size);
1439
1170
  }
1440
1171
  });
1441
1172
  };
1442
1173
  this.subscribeStageRect = () => {
1443
1174
  return this.context.stageRect$.subscribe((rect) => {
1444
1175
  if (rect) {
1445
- this.synchronizer.setRect(rect);
1176
+ this.synchronizer.setRect(rect, this.isBroadcastMode);
1446
1177
  }
1447
1178
  });
1448
1179
  };
@@ -1459,10 +1190,15 @@ class ViewSync {
1459
1190
  this.onCameraUpdatedByDevice = (camera) => {
1460
1191
  if (!camera)
1461
1192
  return;
1462
- if (this.context.size$.value && this.context.stageRect$.value) {
1463
- const diffScale = computedMinScale(this.context.size$.value, this.context.stageRect$.value);
1464
- const remoteScale = camera.scale / diffScale;
1465
- this.synchronizer.onLocalCameraUpdate(__spreadProps(__spreadValues({}, camera), { scale: remoteScale, id: this.context.uid }));
1193
+ if (!this.isBroadcastMode)
1194
+ return;
1195
+ const { size$, stageRect$, view$ } = this.context;
1196
+ if (size$.value && stageRect$.value && view$.value) {
1197
+ this.synchronizer.onLocalCameraUpdate(__spreadProps(__spreadValues({}, camera), { id: this.context.uid }));
1198
+ const newSize = __spreadProps(__spreadValues({}, view$.value.size), { id: this.context.uid });
1199
+ if (!isEqual(size$.value, newSize)) {
1200
+ this.context.storeSize(newSize);
1201
+ }
1466
1202
  }
1467
1203
  };
1468
1204
  this.synchronizer = this.createSynchronizer();
@@ -1473,14 +1209,22 @@ class ViewSync {
1473
1209
  this.subscribeSize(),
1474
1210
  this.subscribeStageRect()
1475
1211
  ]);
1212
+ if (context.viewMode$) {
1213
+ this.needRecoverCamera$ = derive(context.viewMode$, (mode) => mode !== "scroll");
1214
+ }
1476
1215
  const camera$size$ = combine([this.context.camera$, this.context.size$]);
1477
- camera$size$.reaction(([camera, size2]) => {
1478
- if (camera && size2) {
1479
- this.synchronizer.onRemoteUpdate(camera, size2);
1216
+ camera$size$.reaction(([camera, size]) => {
1217
+ var _a;
1218
+ if (camera && size && ((_a = this.needRecoverCamera$) == null ? void 0 : _a.value)) {
1219
+ this.synchronizer.onRemoteUpdate(camera, size);
1480
1220
  camera$size$.destroy();
1481
1221
  }
1482
1222
  });
1483
1223
  }
1224
+ get isBroadcastMode() {
1225
+ var _a;
1226
+ return ((_a = this.context.viewMode$) == null ? void 0 : _a.value) === ViewMode.Broadcaster;
1227
+ }
1484
1228
  destroy() {
1485
1229
  this.sem.flushAll();
1486
1230
  }
@@ -1625,13 +1369,13 @@ class AttributesDelegate {
1625
1369
  setMainViewCamera(camera) {
1626
1370
  this.context.safeSetAttributes({ ["mainViewCamera"]: __spreadValues({}, camera) });
1627
1371
  }
1628
- setMainViewSize(size2) {
1629
- this.context.safeSetAttributes({ ["mainViewSize"]: __spreadValues({}, size2) });
1372
+ setMainViewSize(size) {
1373
+ this.context.safeSetAttributes({ ["mainViewSize"]: __spreadValues({}, size) });
1630
1374
  }
1631
- setMainViewCameraAndSize(camera, size2) {
1375
+ setMainViewCameraAndSize(camera, size) {
1632
1376
  this.context.safeSetAttributes({
1633
1377
  ["mainViewCamera"]: __spreadValues({}, camera),
1634
- ["mainViewSize"]: __spreadValues({}, size2)
1378
+ ["mainViewSize"]: __spreadValues({}, size)
1635
1379
  });
1636
1380
  }
1637
1381
  updateCursor(uid, position) {
@@ -1791,8 +1535,8 @@ class AppProxy {
1791
1535
  this.storeCamera = (camera) => {
1792
1536
  this.store.updateAppAttributes(this.id, Fields.Camera, camera);
1793
1537
  };
1794
- this.storeSize = (size2) => {
1795
- this.store.updateAppAttributes(this.id, Fields.Size, size2);
1538
+ this.storeSize = (size) => {
1539
+ this.store.updateAppAttributes(this.id, Fields.Size, size);
1796
1540
  };
1797
1541
  this.updateSize = (width, height) => {
1798
1542
  const iSize = {
@@ -1828,9 +1572,9 @@ class AppProxy {
1828
1572
  this.sideEffectManager.add(() => this.manager.refresher.add(`${this.id}-size`, () => reaction(() => {
1829
1573
  var _a2;
1830
1574
  return (_a2 = this.appAttributes) == null ? void 0 : _a2.size;
1831
- }, (size2) => {
1832
- if (size2) {
1833
- const rawSize = toJS(size2);
1575
+ }, (size) => {
1576
+ if (size) {
1577
+ const rawSize = toJS(size);
1834
1578
  if (!isEqual(rawSize, this.size$.value)) {
1835
1579
  this.size$.setValue(rawSize);
1836
1580
  }
@@ -2367,8 +2111,8 @@ class MainViewProxy {
2367
2111
  this.storeCamera = (camera) => {
2368
2112
  this.store.setMainViewCamera(camera);
2369
2113
  };
2370
- this.storeSize = (size2) => {
2371
- this.store.setMainViewSize(size2);
2114
+ this.storeSize = (size) => {
2115
+ this.store.setMainViewSize(size);
2372
2116
  };
2373
2117
  this.cameraReaction = () => {
2374
2118
  return reaction(() => this.mainViewCamera, (camera) => {
@@ -2381,9 +2125,9 @@ class MainViewProxy {
2381
2125
  }, { fireImmediately: true });
2382
2126
  };
2383
2127
  this.sizeReaction = () => {
2384
- return reaction(() => this.mainViewSize, (size2) => {
2385
- if (size2) {
2386
- const rawSize = toJS(size2);
2128
+ return reaction(() => this.mainViewSize, (size) => {
2129
+ if (size) {
2130
+ const rawSize = toJS(size);
2387
2131
  if (!isEqual(rawSize, this.size$.value)) {
2388
2132
  this.size$.setValue(rawSize);
2389
2133
  }
@@ -2393,8 +2137,8 @@ class MainViewProxy {
2393
2137
  this.mainViewClickListener = () => {
2394
2138
  this.mainViewClickHandler();
2395
2139
  };
2396
- this.setMainViewSize = debounce((size2) => {
2397
- this.store.setMainViewSize(__spreadProps(__spreadValues({}, size2), { id: this.manager.uid }));
2140
+ this.setMainViewSize = debounce((size) => {
2141
+ this.store.setMainViewSize(__spreadProps(__spreadValues({}, size), { id: this.manager.uid }));
2398
2142
  }, 50);
2399
2143
  this.onCameraOrSizeUpdated = () => {
2400
2144
  callbacks.emit("cameraStateChange", this.cameraState);
@@ -2425,9 +2169,9 @@ class MainViewProxy {
2425
2169
  callbacks.emit("baseCameraChange", camera);
2426
2170
  }
2427
2171
  });
2428
- this.size$.reaction((size2) => {
2429
- if (size2) {
2430
- callbacks.emit("baseSizeChange", size2);
2172
+ this.size$.reaction((size) => {
2173
+ if (size) {
2174
+ callbacks.emit("baseSizeChange", size);
2431
2175
  }
2432
2176
  });
2433
2177
  }
@@ -2552,6 +2296,51 @@ class MainViewProxy {
2552
2296
  this.sideEffectManager.flushAll();
2553
2297
  }
2554
2298
  }
2299
+ const onObjectByEvent = (event) => {
2300
+ return (object, func) => {
2301
+ if (object === void 0)
2302
+ return;
2303
+ if (listenUpdated) {
2304
+ const listener = (events) => {
2305
+ const kinds = events.map((e) => e.kind);
2306
+ if (kinds.includes(event)) {
2307
+ func();
2308
+ }
2309
+ };
2310
+ listenUpdated(object, listener);
2311
+ func();
2312
+ return () => unlistenUpdated(object, listener);
2313
+ } else {
2314
+ return reaction(() => object, () => {
2315
+ func();
2316
+ }, {
2317
+ fireImmediately: true
2318
+ });
2319
+ }
2320
+ };
2321
+ };
2322
+ const safeListenPropsUpdated = (getProps, callback, onDestroyed) => {
2323
+ let disposeListenUpdated = null;
2324
+ const disposeReaction = reaction(getProps, () => {
2325
+ if (disposeListenUpdated) {
2326
+ disposeListenUpdated();
2327
+ disposeListenUpdated = null;
2328
+ }
2329
+ const props = getProps();
2330
+ if (isObject(props)) {
2331
+ disposeListenUpdated = () => unlistenUpdated(props, callback);
2332
+ listenUpdated(props, callback);
2333
+ } else {
2334
+ onDestroyed == null ? void 0 : onDestroyed(props);
2335
+ }
2336
+ }, { fireImmediately: true });
2337
+ return () => {
2338
+ disposeListenUpdated == null ? void 0 : disposeListenUpdated();
2339
+ disposeReaction();
2340
+ };
2341
+ };
2342
+ const onObjectRemoved = onObjectByEvent(UpdateEventKind.Removed);
2343
+ onObjectByEvent(UpdateEventKind.Inserted);
2555
2344
  class RedoUndo {
2556
2345
  constructor(context) {
2557
2346
  this.context = context;
@@ -2611,24 +2400,181 @@ class RedoUndo {
2611
2400
  this.disposePrevFocusViewRedoUndoListeners(this.context.focus());
2612
2401
  }
2613
2402
  }
2403
+ const createScrollStorage = (manager) => {
2404
+ return new Storage({
2405
+ plugin$: new Val(manager.windowManger),
2406
+ isWritable$: manager.isWritable$,
2407
+ namespace: "scrollStorage",
2408
+ defaultState: { scrollTop: 0 }
2409
+ });
2410
+ };
2411
+ function clamp$2(x2, min, max) {
2412
+ return x2 < min ? min : x2 > max ? max : x2;
2413
+ }
2414
+ class ScrollMode {
2415
+ constructor(manager) {
2416
+ var _a;
2417
+ this.manager = manager;
2418
+ this.sideEffect = new SideEffectManager();
2419
+ this.baseWidth = SCROLL_MODE_BASE_WIDTH;
2420
+ this.baseHeight = SCROLL_MODE_BASE_HEIGHT;
2421
+ this.initScroll = () => {
2422
+ const halfWbHeight = this._size$.value.height / 2 / this._scale$.value;
2423
+ const scrollTop = this._scrollTop$.value;
2424
+ this._scrollTop$.setValue(clamp$2(scrollTop, halfWbHeight, this.baseHeight - halfWbHeight) - 0.01);
2425
+ };
2426
+ this.getWhiteboardElement = (root) => {
2427
+ const className = ".netless-window-manager-main-view";
2428
+ return root && root.querySelector(className);
2429
+ };
2430
+ this.onWheel = (ev) => {
2431
+ var _a2;
2432
+ const target = ev.target;
2433
+ if (this.manager.canOperate && ((_a2 = this._whiteboard$.value) == null ? void 0 : _a2.contains(target))) {
2434
+ ev.preventDefault();
2435
+ ev.stopPropagation();
2436
+ const dy = ev.deltaY || 0;
2437
+ const { width } = this._size$.value;
2438
+ if (dy && width > 0) {
2439
+ const halfWbHeight = this._size$.value.height / 2 / this._scale$.value;
2440
+ const scrollTop = this._scrollTop$.value + dy / this._scale$.value;
2441
+ this.scrollStorage.setState({
2442
+ scrollTop: clamp$2(scrollTop, halfWbHeight, this.baseHeight - halfWbHeight)
2443
+ });
2444
+ callbacks.emit("userScroll");
2445
+ }
2446
+ }
2447
+ };
2448
+ this._root$ = new Val(null);
2449
+ this._mainView$ = new Val(this.manager.mainView);
2450
+ this._mainView$.value.disableCameraTransform = true;
2451
+ if ((_a = manager.scrollBaseSize$) == null ? void 0 : _a.value) {
2452
+ this.baseWidth = manager.scrollBaseSize$.value.width;
2453
+ this.baseHeight = manager.scrollBaseSize$.value.height;
2454
+ }
2455
+ this.scrollStorage = createScrollStorage(manager);
2456
+ const scrollTop$ = new Val(this.scrollStorage.state.scrollTop);
2457
+ this._scrollTop$ = scrollTop$;
2458
+ this.sideEffect.push(this.scrollStorage.on("stateChanged", () => {
2459
+ this._scrollTop$.setValue(this.scrollStorage.state.scrollTop);
2460
+ }));
2461
+ const size$ = new Val({ width: 0, height: 0 }, { compare: (a, b2) => a.width === b2.width && a.height === b2.height });
2462
+ this._size$ = size$;
2463
+ this.sideEffect.add(() => {
2464
+ const onSizeUpdated = size$.setValue.bind(size$);
2465
+ onSizeUpdated(this._mainView$.value.size);
2466
+ this._mainView$.value.callbacks.on("onSizeUpdated", onSizeUpdated);
2467
+ return () => this._mainView$.value.callbacks.off("onSizeUpdated", onSizeUpdated);
2468
+ });
2469
+ this.sideEffect.add(() => {
2470
+ const onCameraUpdated = (camera) => {
2471
+ const halfWbHeight = size$.value.height / 2 / scale$.value;
2472
+ const scrollTop = camera.centerY;
2473
+ this.scrollStorage.setState({
2474
+ scrollTop: clamp$2(scrollTop, halfWbHeight, this.baseHeight - halfWbHeight)
2475
+ });
2476
+ callbacks.emit("userScroll");
2477
+ };
2478
+ this._mainView$.value.callbacks.on("onCameraUpdatedByDevice", onCameraUpdated);
2479
+ return () => this._mainView$.value.callbacks.off("onCameraUpdatedByDevice", onCameraUpdated);
2480
+ });
2481
+ const scale$ = derive(size$, (size) => size.width / this.baseWidth);
2482
+ this._scale$ = scale$;
2483
+ const page$ = new Val(0);
2484
+ this.sideEffect.push(combine([scrollTop$, size$, scale$]).subscribe(([scrollTop, size, scale2]) => {
2485
+ if (scale2 > 0) {
2486
+ const wbHeight = size.height / scale2;
2487
+ page$.setValue(Math.max(scrollTop / wbHeight - 0.5, 0));
2488
+ }
2489
+ }));
2490
+ this._page$ = page$;
2491
+ this.sideEffect.push(combine([scrollTop$, scale$]).subscribe(([scrollTop, scale2]) => {
2492
+ this.updateBound(scrollTop, size$.value, scale2);
2493
+ }));
2494
+ this.sideEffect.push(size$.reaction(() => {
2495
+ this.updateScroll(scrollTop$.value);
2496
+ }));
2497
+ const whiteboard$ = derive(this._root$, this.getWhiteboardElement);
2498
+ this._whiteboard$ = whiteboard$;
2499
+ this.sideEffect.push(whiteboard$.reaction((el) => {
2500
+ if (el == null ? void 0 : el.parentElement) {
2501
+ this.sideEffect.addEventListener(el.parentElement, "wheel", this.onWheel, { capture: true, passive: false }, "wheel");
2502
+ }
2503
+ }));
2504
+ this.sideEffect.push(scale$.reaction((scale2) => {
2505
+ if (scale2 > 0) {
2506
+ this.sideEffect.flush("initScroll");
2507
+ this.sideEffect.setTimeout(this.initScroll, 0);
2508
+ }
2509
+ }), "initScroll");
2510
+ const maxScrollPage$ = combine([this._size$, this._scale$], ([size, scale2]) => {
2511
+ const halfWbHeight = size.height / 2 / scale2;
2512
+ return (this.baseHeight - halfWbHeight) / halfWbHeight / 2 - 0.51;
2513
+ });
2514
+ this.scrollState$ = combine([this._scrollTop$, this._page$, maxScrollPage$], ([scrollTop, page, maxScrollPage]) => {
2515
+ return {
2516
+ scrollTop,
2517
+ page,
2518
+ maxScrollPage
2519
+ };
2520
+ });
2521
+ this.updateScroll(scrollTop$.value);
2522
+ this.sideEffect.push(this.scrollState$.subscribe((state) => callbacks.emit("scrollStateChange", state)));
2523
+ }
2524
+ setRoot(root) {
2525
+ this._root$.setValue(root);
2526
+ }
2527
+ updateScroll(scrollTop) {
2528
+ this._mainView$.value.moveCamera({
2529
+ centerY: scrollTop,
2530
+ animationMode: AnimationMode.Immediately
2531
+ });
2532
+ }
2533
+ updateBound(scrollTop, { height }, scale2) {
2534
+ if (scale2 > 0) {
2535
+ this._mainView$.value.moveCameraToContain({
2536
+ originX: 0,
2537
+ originY: scrollTop - height / scale2 / 2,
2538
+ width: this.baseWidth,
2539
+ height: height / scale2,
2540
+ animationMode: AnimationMode.Immediately
2541
+ });
2542
+ this._mainView$.value.setCameraBound({
2543
+ damping: 1,
2544
+ maxContentMode: () => scale2,
2545
+ minContentMode: () => scale2,
2546
+ centerX: this.baseWidth / 2,
2547
+ centerY: this.baseHeight / 2,
2548
+ width: this.baseWidth,
2549
+ height: this.baseHeight
2550
+ });
2551
+ }
2552
+ }
2553
+ dispose() {
2554
+ this.sideEffect.flushAll();
2555
+ }
2556
+ }
2614
2557
  class AppManager {
2615
2558
  constructor(windowManger) {
2559
+ var _a;
2616
2560
  this.windowManger = windowManger;
2617
2561
  this.appProxies = /* @__PURE__ */ new Map();
2618
2562
  this.appStatus = /* @__PURE__ */ new Map();
2619
2563
  this.store = store;
2620
2564
  this.isReplay = this.windowManger.isReplay;
2621
2565
  this.mainViewScenesLength = 0;
2566
+ this.scrollBaseSize$ = new Val(null);
2622
2567
  this.callbacksNode = null;
2623
2568
  this.appCreateQueue = new AppCreateQueue();
2624
2569
  this.sceneIndex$ = new Val(void 0);
2625
2570
  this.focused$ = new Val(void 0);
2626
2571
  this.members$ = new Val([]);
2572
+ this.isWritable$ = new Val(Boolean((_a = this.room) == null ? void 0 : _a.isWritable));
2627
2573
  this.sideEffectManager = new SideEffectManager();
2628
2574
  this.sceneState = null;
2629
2575
  this.rootDirRemoving = false;
2630
2576
  this.onRemoveScenes = async (params) => {
2631
- var _a, _b;
2577
+ var _a2, _b;
2632
2578
  const { scenePath } = params;
2633
2579
  if (scenePath === ROOT_DIR) {
2634
2580
  await this.onRootDirRemoved();
@@ -2637,7 +2583,7 @@ class AppManager {
2637
2583
  }
2638
2584
  if (isRootDirPage(scenePath)) {
2639
2585
  let nextIndex = this.mainView.focusSceneIndex || 0;
2640
- let sceneName = (_a = this.callbacksNode) == null ? void 0 : _a.scenes[nextIndex];
2586
+ let sceneName = (_a2 = this.callbacksNode) == null ? void 0 : _a2.scenes[nextIndex];
2641
2587
  if (!sceneName) {
2642
2588
  nextIndex = 0;
2643
2589
  sceneName = (_b = this.callbacksNode) == null ? void 0 : _b.scenes[nextIndex];
@@ -2688,11 +2634,11 @@ class AppManager {
2688
2634
  }
2689
2635
  };
2690
2636
  this.removeSceneByIndex = async (index2) => {
2691
- var _a;
2637
+ var _a2;
2692
2638
  const nextIndex = calculateNextIndex(index2, this.windowManger.pageState);
2693
2639
  this.setSceneIndexWithoutSync(nextIndex);
2694
2640
  this.dispatchInternalEvent(Events.SetAppFocusIndex, { type: "main", index: nextIndex });
2695
- const scene = (_a = this.callbacksNode) == null ? void 0 : _a.scenes[index2];
2641
+ const scene = (_a2 = this.callbacksNode) == null ? void 0 : _a2.scenes[index2];
2696
2642
  setTimeout(() => {
2697
2643
  if (scene) {
2698
2644
  removeScenes(this.room, `${ROOT_DIR}${scene}`, index2);
@@ -2710,8 +2656,8 @@ class AppManager {
2710
2656
  });
2711
2657
  };
2712
2658
  this.setSceneIndexWithoutSync = (index2) => {
2713
- var _a;
2714
- const sceneName = (_a = this.callbacksNode) == null ? void 0 : _a.scenes[index2];
2659
+ var _a2;
2660
+ const sceneName = (_a2 = this.callbacksNode) == null ? void 0 : _a2.scenes[index2];
2715
2661
  if (sceneName) {
2716
2662
  this.mainViewProxy.setFocusScenePath(`${ROOT_DIR}${sceneName}`);
2717
2663
  }
@@ -2782,8 +2728,8 @@ class AppManager {
2782
2728
  });
2783
2729
  };
2784
2730
  this.addAppCloseListener = () => {
2785
- var _a;
2786
- (_a = this.refresher) == null ? void 0 : _a.add("appsClose", () => {
2731
+ var _a2;
2732
+ (_a2 = this.refresher) == null ? void 0 : _a2.add("appsClose", () => {
2787
2733
  return onObjectRemoved(this.attributes.apps, () => {
2788
2734
  this.onAppDelete(this.attributes.apps);
2789
2735
  });
@@ -2800,13 +2746,13 @@ class AppManager {
2800
2746
  }
2801
2747
  };
2802
2748
  this.onFocusChange = (focused) => {
2803
- var _a;
2749
+ var _a2;
2804
2750
  if (this.focused$.value !== focused) {
2805
2751
  callbacks.emit("focusedChange", focused);
2806
2752
  emitter.emit("focusedChange", { focused, prev: this.focused$.value });
2807
2753
  this.focused$.setValue(focused);
2808
2754
  if (focused !== void 0) {
2809
- (_a = this.boxManager) == null ? void 0 : _a.focusBox({ appId: focused });
2755
+ (_a2 = this.boxManager) == null ? void 0 : _a2.focusBox({ appId: focused });
2810
2756
  setTimeout(() => {
2811
2757
  const appProxy = this.appProxies.get(focused);
2812
2758
  if (appProxy) {
@@ -2832,14 +2778,14 @@ class AppManager {
2832
2778
  });
2833
2779
  };
2834
2780
  this.onMinimized = (minimized) => {
2835
- var _a, _b;
2836
- if (((_a = this.boxManager) == null ? void 0 : _a.minimized) !== minimized) {
2781
+ var _a2, _b;
2782
+ if (((_a2 = this.boxManager) == null ? void 0 : _a2.minimized) !== minimized) {
2837
2783
  if (minimized === true) {
2838
2784
  (_b = this.boxManager) == null ? void 0 : _b.blurAllBox();
2839
2785
  }
2840
2786
  setTimeout(() => {
2841
- var _a2;
2842
- (_a2 = this.boxManager) == null ? void 0 : _a2.setMinimized(Boolean(minimized));
2787
+ var _a3;
2788
+ (_a3 = this.boxManager) == null ? void 0 : _a3.setMinimized(Boolean(minimized));
2843
2789
  }, 0);
2844
2790
  }
2845
2791
  };
@@ -2879,11 +2825,11 @@ class AppManager {
2879
2825
  }
2880
2826
  };
2881
2827
  this.displayerWritableListener = (isReadonly) => {
2882
- var _a, _b;
2828
+ var _a2, _b;
2883
2829
  const isWritable = !isReadonly;
2884
2830
  const isManualWritable = this.windowManger.readonly === void 0 || !this.windowManger.readonly;
2885
2831
  if (this.windowManger.readonly === void 0) {
2886
- (_a = this.boxManager) == null ? void 0 : _a.setReadonly(isReadonly);
2832
+ (_a2 = this.boxManager) == null ? void 0 : _a2.setReadonly(isReadonly);
2887
2833
  } else {
2888
2834
  (_b = this.boxManager) == null ? void 0 : _b.setReadonly(!(isWritable && isManualWritable));
2889
2835
  }
@@ -2896,6 +2842,7 @@ class AppManager {
2896
2842
  }
2897
2843
  }
2898
2844
  emitter.emit("writableChange", isWritable);
2845
+ this.isWritable$.setValue(isWritable);
2899
2846
  };
2900
2847
  this.updateSceneIndex = () => {
2901
2848
  const scenePath = this.store.getMainViewScenePath();
@@ -2928,10 +2875,10 @@ class AppManager {
2928
2875
  this.refresher.setContext({ emitter });
2929
2876
  this.sideEffectManager.add(() => {
2930
2877
  return () => {
2931
- var _a, _b, _c;
2878
+ var _a2, _b, _c;
2932
2879
  this.appCreateQueue.destroy();
2933
2880
  this.mainViewProxy.destroy();
2934
- (_a = this.refresher) == null ? void 0 : _a.destroy();
2881
+ (_a2 = this.refresher) == null ? void 0 : _a2.destroy();
2935
2882
  this.viewManager.destroy();
2936
2883
  (_b = this.boxManager) == null ? void 0 : _b.destroy();
2937
2884
  (_c = this.callbacksNode) == null ? void 0 : _c.dispose();
@@ -2950,6 +2897,16 @@ class AppManager {
2950
2897
  this.safeUpdateAttributes([Fields.Registered, payload.kind], payload);
2951
2898
  });
2952
2899
  this.members$.setValue(serializeRoomMembers(this.displayer.state.roomMembers));
2900
+ emitter.on("mainViewMounted", () => {
2901
+ this.windowManger.viewMode$.subscribe((viewMode) => {
2902
+ const playground = this.windowManger.playground$.value;
2903
+ if (viewMode === "scroll" && playground) {
2904
+ const scrollMode = new ScrollMode(this);
2905
+ this.scrollMode = scrollMode;
2906
+ scrollMode.setRoot(playground);
2907
+ }
2908
+ });
2909
+ });
2953
2910
  }
2954
2911
  async onRootDirRemoved(needClose = true) {
2955
2912
  await this.setMainViewScenePath(INIT_DIR);
@@ -3121,6 +3078,7 @@ class AppManager {
3121
3078
  bindMainView(divElement, disableCameraTransform) {
3122
3079
  const mainView = this.mainViewProxy.view;
3123
3080
  mainView.disableCameraTransform = disableCameraTransform;
3081
+ console.log("bindMainView", mainView.disableCameraTransform);
3124
3082
  wait(30).then(() => {
3125
3083
  mainView.divElement = divElement;
3126
3084
  emitter.emit("mainViewMounted");
@@ -3990,8 +3948,8 @@ var progressToPixels = function(progress, length) {
3990
3948
  return px.transform(progress * length);
3991
3949
  };
3992
3950
  var unmeasured = { x: 0, y: 0, width: 0, height: 0 };
3993
- function calcOrigin(origin, offset, size2) {
3994
- return typeof origin === "string" ? origin : px.transform(offset + size2 * origin);
3951
+ function calcOrigin(origin, offset, size) {
3952
+ return typeof origin === "string" ? origin : px.transform(offset + size * origin);
3995
3953
  }
3996
3954
  function calculateSVGTransformOrigin(dimensions, originX, originY) {
3997
3955
  return calcOrigin(originX, dimensions.x, dimensions.width) + " " + calcOrigin(originY, dimensions.y, dimensions.height);
@@ -4468,9 +4426,9 @@ class TeleBox {
4468
4426
  }, skipUpdate);
4469
4427
  }));
4470
4428
  const intrinsicCoord$ = new Val({ x: x2, y: y2 }, { compare: shallowequal });
4471
- const pxIntrinsicSize$ = combine([intrinsicSize$, managerStageRect$], ([size2, managerStageRect]) => ({
4472
- width: managerStageRect.width * size2.width,
4473
- height: managerStageRect.height * size2.height
4429
+ const pxIntrinsicSize$ = combine([intrinsicSize$, managerStageRect$], ([size, managerStageRect]) => ({
4430
+ width: managerStageRect.width * size.width,
4431
+ height: managerStageRect.height * size.height
4474
4432
  }), { compare: shallowequal });
4475
4433
  const pxIntrinsicCoord$ = combine([intrinsicCoord$, managerStageRect$], ([intrinsicCoord, managerStageRect]) => ({
4476
4434
  x: intrinsicCoord.x * managerStageRect.width,
@@ -6887,7 +6845,7 @@ class CursorManager {
6887
6845
  this.initCursorInstance = (uid) => {
6888
6846
  let cursorInstance = this.cursorInstances.get(uid);
6889
6847
  if (!cursorInstance) {
6890
- cursorInstance = new Cursor(this.manager, uid, this, WindowManager.playground);
6848
+ cursorInstance = new Cursor(this.manager, uid, this, this.playground$.value);
6891
6849
  this.cursorInstances.set(uid, cursorInstance);
6892
6850
  }
6893
6851
  return cursorInstance;
@@ -6930,7 +6888,7 @@ class CursorManager {
6930
6888
  this.hideCursor(this.manager.uid);
6931
6889
  };
6932
6890
  this.roomMembers = (_a = this.manager.room) == null ? void 0 : _a.state.roomMembers;
6933
- const playground = WindowManager.playground;
6891
+ const playground = this.playground$.value;
6934
6892
  if (playground) {
6935
6893
  this.setupWrapper(playground);
6936
6894
  }
@@ -6944,6 +6902,9 @@ class CursorManager {
6944
6902
  this.applianceIcons = __spreadValues(__spreadValues({}, ApplianceMap), applianceIcons);
6945
6903
  }
6946
6904
  }
6905
+ get playground$() {
6906
+ return this.manager.windowManger.playground$;
6907
+ }
6947
6908
  canMoveCursor(member) {
6948
6909
  const isLaserPointer = (member == null ? void 0 : member.memberState.currentApplianceName) === ApplianceNames.laserPointer;
6949
6910
  return this.enableCursor || isLaserPointer;
@@ -11681,70 +11642,35 @@ const reconnectRefresher = new ReconnectRefresher({ emitter });
11681
11642
  const _WindowManager = class extends InvisiblePlugin {
11682
11643
  constructor(context) {
11683
11644
  super(context);
11684
- this.version = "1.0.0-canary.52";
11685
- this.dependencies = { "dependencies": { "@juggle/resize-observer": "^3.3.1", "@netless/telebox-insider": "1.0.0-alpha.37", "emittery": "^0.11.0", "lodash": "^4.17.21", "p-retry": "^4.6.2", "side-effect-manager": "^1.1.1", "uuid": "^7.0.3", "value-enhancer": "^1.3.2" }, "peerDependencies": { "white-web-sdk": "^2.16.0" }, "devDependencies": { "@netless/app-docs-viewer": "^0.3.3", "@netless/app-plyr": "0.2.2", "@playwright/test": "^1.23.2", "@rollup/plugin-commonjs": "^20.0.0", "@rollup/plugin-node-resolve": "^13.0.4", "@rollup/plugin-url": "^6.1.0", "@sveltejs/vite-plugin-svelte": "^1.0.0-next.49", "@tsconfig/svelte": "^2.0.1", "@types/debug": "^4.1.7", "@types/lodash": "^4.14.182", "@types/lodash-es": "^4.17.6", "@types/node": "^18.0.3", "@types/uuid": "^8.3.4", "@typescript-eslint/eslint-plugin": "^4.30.0", "@typescript-eslint/parser": "^4.30.0", "@vitest/ui": "^0.14.2", "cypress": "^8.7.0", "dotenv": "^10.0.0", "eslint": "^7.32.0", "eslint-config-prettier": "^8.3.0", "eslint-plugin-svelte3": "^3.2.0", "jsdom": "^19.0.0", "less": "^4.1.3", "prettier": "^2.3.2", "prettier-plugin-svelte": "^2.4.0", "rollup-plugin-analyzer": "^4.0.0", "rollup-plugin-styles": "^3.14.1", "svelte": "^3.42.4", "typescript": "^4.5.5", "vite": "^2.5.3", "vite-plugin-dts": "^1.2.1", "vitest": "^0.18.0", "white-web-sdk": "2.16.26" } };
11645
+ this.version = "1.0.0-canary.54";
11646
+ this.dependencies = { "dependencies": { "@juggle/resize-observer": "^3.3.1", "@netless/synced-store": "^2.0.7", "@netless/telebox-insider": "1.0.0-alpha.37", "emittery": "^0.11.0", "lodash": "^4.17.21", "p-retry": "^4.6.2", "side-effect-manager": "^1.2.1", "uuid": "^7.0.3", "value-enhancer": "^1.3.2" }, "peerDependencies": { "white-web-sdk": "^2.16.0" }, "devDependencies": { "@netless/app-docs-viewer": "^0.3.3", "@netless/app-plyr": "0.2.2", "@playwright/test": "^1.23.2", "@rollup/plugin-commonjs": "^20.0.0", "@rollup/plugin-node-resolve": "^13.0.4", "@rollup/plugin-url": "^6.1.0", "@sveltejs/vite-plugin-svelte": "^1.0.0-next.49", "@tsconfig/svelte": "^2.0.1", "@types/debug": "^4.1.7", "@types/lodash": "^4.14.182", "@types/lodash-es": "^4.17.6", "@types/node": "^18.0.3", "@types/uuid": "^8.3.4", "@typescript-eslint/eslint-plugin": "^4.30.0", "@typescript-eslint/parser": "^4.30.0", "@vitest/ui": "^0.14.2", "cypress": "^8.7.0", "dotenv": "^10.0.0", "eslint": "^7.32.0", "eslint-config-prettier": "^8.3.0", "eslint-plugin-svelte3": "^3.2.0", "jsdom": "^19.0.0", "less": "^4.1.3", "prettier": "^2.3.2", "prettier-plugin-svelte": "^2.4.0", "rollup-plugin-analyzer": "^4.0.0", "rollup-plugin-styles": "^3.14.1", "svelte": "^3.42.4", "typescript": "^4.5.5", "vite": "^2.5.3", "vite-plugin-dts": "^1.2.1", "vitest": "^0.18.0", "white-web-sdk": "^2.16.35" } };
11686
11647
  this.emitter = callbacks;
11687
11648
  this.viewMode = ViewMode.Broadcaster;
11688
11649
  this.viewMode$ = new Val(ViewMode.Broadcaster);
11650
+ this.playground$ = new Val(void 0);
11689
11651
  this.isReplay = isPlayer(this.displayer);
11690
- this.cameraUpdating = 0;
11691
- this.nextCamera = null;
11692
11652
  this.containerSizeRatio = _WindowManager.containerSizeRatio;
11693
11653
  this.moveCamera = (camera) => {
11694
11654
  var _a;
11655
+ const pureCamera = omit(camera, ["animationMode"]);
11695
11656
  const mainViewCamera = __spreadValues({}, this.mainView.camera);
11696
- const nextCamera = __spreadValues(__spreadValues({}, mainViewCamera), camera);
11697
- if (isEqual(nextCamera, mainViewCamera))
11698
- return;
11699
- if (!this.appManager)
11657
+ if (isEqual(__spreadValues(__spreadValues({}, mainViewCamera), pureCamera), mainViewCamera))
11700
11658
  return;
11701
- if (camera.animationMode === AnimationMode.Immediately) {
11702
- this.appManager.mainViewProxy.storeCamera(__spreadValues({
11703
- id: this.appManager.uid
11704
- }, nextCamera));
11705
- } else {
11706
- const remoteCamera = this.appManager.mainViewProxy.size$.value;
11707
- const currentSize = (_a = this.boxManager) == null ? void 0 : _a.stageRect;
11708
- let nextScale;
11709
- if (camera.scale && remoteCamera && currentSize) {
11710
- nextScale = camera.scale * computedMinScale(remoteCamera, currentSize);
11711
- }
11712
- if (nextScale) {
11713
- this.mainView.moveCamera(__spreadProps(__spreadValues({}, camera), {
11714
- scale: nextScale
11715
- }));
11716
- } else {
11717
- this.mainView.moveCamera(camera);
11718
- }
11719
- this.appManager.dispatchInternalEvent(Events.MoveCamera, camera);
11720
- this.mainView.callbacks.off("onCameraUpdated", this.onCameraUpdated);
11721
- clearTimeout(this.cameraUpdating);
11722
- this.cameraUpdating = 0;
11723
- this.mainView.callbacks.on("onCameraUpdated", this.onCameraUpdated);
11724
- if (nextScale) {
11725
- this.nextCamera = nextCamera;
11726
- }
11727
- }
11728
- };
11729
- this.onCameraUpdated = () => {
11730
- if (this.cameraUpdating) {
11731
- clearTimeout(this.cameraUpdating);
11732
- this.cameraUpdating = 0;
11733
- }
11734
- this.cameraUpdating = setTimeout(() => {
11735
- this.mainView.callbacks.off("onCameraUpdated", this.onCameraUpdated);
11736
- clearTimeout(this.cameraUpdating);
11737
- this.cameraUpdating = 0;
11738
- if (!this.appManager || !this.nextCamera)
11739
- return;
11740
- this.appManager.mainViewProxy.storeCamera(__spreadValues({
11741
- id: this.appManager.uid
11742
- }, this.nextCamera));
11743
- this.nextCamera = null;
11744
- }, 50);
11659
+ this.debouncedStoreCamera();
11660
+ this.mainView.moveCamera(camera);
11661
+ (_a = this.appManager) == null ? void 0 : _a.dispatchInternalEvent(Events.MoveCamera, camera);
11662
+ };
11663
+ this.debouncedStoreCamera = () => {
11664
+ const storeCamera = debounce(() => {
11665
+ var _a, _b;
11666
+ (_a = this.appManager) == null ? void 0 : _a.mainViewProxy.storeCurrentCamera();
11667
+ (_b = this.appManager) == null ? void 0 : _b.mainViewProxy.storeCurrentSize();
11668
+ this.mainView.callbacks.off("onCameraUpdated", storeCamera);
11669
+ }, 200);
11670
+ this.mainView.callbacks.on("onCameraUpdated", storeCamera);
11745
11671
  };
11746
11672
  _WindowManager.displayer = context.displayer;
11747
- window.NETLESS_DEPS = { "dependencies": { "@juggle/resize-observer": "^3.3.1", "@netless/telebox-insider": "1.0.0-alpha.37", "emittery": "^0.11.0", "lodash": "^4.17.21", "p-retry": "^4.6.2", "side-effect-manager": "^1.1.1", "uuid": "^7.0.3", "value-enhancer": "^1.3.2" }, "peerDependencies": { "white-web-sdk": "^2.16.0" }, "devDependencies": { "@netless/app-docs-viewer": "^0.3.3", "@netless/app-plyr": "0.2.2", "@playwright/test": "^1.23.2", "@rollup/plugin-commonjs": "^20.0.0", "@rollup/plugin-node-resolve": "^13.0.4", "@rollup/plugin-url": "^6.1.0", "@sveltejs/vite-plugin-svelte": "^1.0.0-next.49", "@tsconfig/svelte": "^2.0.1", "@types/debug": "^4.1.7", "@types/lodash": "^4.14.182", "@types/lodash-es": "^4.17.6", "@types/node": "^18.0.3", "@types/uuid": "^8.3.4", "@typescript-eslint/eslint-plugin": "^4.30.0", "@typescript-eslint/parser": "^4.30.0", "@vitest/ui": "^0.14.2", "cypress": "^8.7.0", "dotenv": "^10.0.0", "eslint": "^7.32.0", "eslint-config-prettier": "^8.3.0", "eslint-plugin-svelte3": "^3.2.0", "jsdom": "^19.0.0", "less": "^4.1.3", "prettier": "^2.3.2", "prettier-plugin-svelte": "^2.4.0", "rollup-plugin-analyzer": "^4.0.0", "rollup-plugin-styles": "^3.14.1", "svelte": "^3.42.4", "typescript": "^4.5.5", "vite": "^2.5.3", "vite-plugin-dts": "^1.2.1", "vitest": "^0.18.0", "white-web-sdk": "2.16.26" } };
11673
+ window.NETLESS_DEPS = { "dependencies": { "@juggle/resize-observer": "^3.3.1", "@netless/synced-store": "^2.0.7", "@netless/telebox-insider": "1.0.0-alpha.37", "emittery": "^0.11.0", "lodash": "^4.17.21", "p-retry": "^4.6.2", "side-effect-manager": "^1.2.1", "uuid": "^7.0.3", "value-enhancer": "^1.3.2" }, "peerDependencies": { "white-web-sdk": "^2.16.0" }, "devDependencies": { "@netless/app-docs-viewer": "^0.3.3", "@netless/app-plyr": "0.2.2", "@playwright/test": "^1.23.2", "@rollup/plugin-commonjs": "^20.0.0", "@rollup/plugin-node-resolve": "^13.0.4", "@rollup/plugin-url": "^6.1.0", "@sveltejs/vite-plugin-svelte": "^1.0.0-next.49", "@tsconfig/svelte": "^2.0.1", "@types/debug": "^4.1.7", "@types/lodash": "^4.14.182", "@types/lodash-es": "^4.17.6", "@types/node": "^18.0.3", "@types/uuid": "^8.3.4", "@typescript-eslint/eslint-plugin": "^4.30.0", "@typescript-eslint/parser": "^4.30.0", "@vitest/ui": "^0.14.2", "cypress": "^8.7.0", "dotenv": "^10.0.0", "eslint": "^7.32.0", "eslint-config-prettier": "^8.3.0", "eslint-plugin-svelte3": "^3.2.0", "jsdom": "^19.0.0", "less": "^4.1.3", "prettier": "^2.3.2", "prettier-plugin-svelte": "^2.4.0", "rollup-plugin-analyzer": "^4.0.0", "rollup-plugin-styles": "^3.14.1", "svelte": "^3.42.4", "typescript": "^4.5.5", "vite": "^2.5.3", "vite-plugin-dts": "^1.2.1", "vitest": "^0.18.0", "white-web-sdk": "^2.16.35" } };
11748
11674
  }
11749
11675
  static async mount(params) {
11750
11676
  var _a;
@@ -11791,6 +11717,9 @@ const _WindowManager = class extends InvisiblePlugin {
11791
11717
  }
11792
11718
  manager.containerSizeRatio = _WindowManager.containerSizeRatio;
11793
11719
  await manager.ensureAttributes();
11720
+ if (params.viewMode) {
11721
+ manager.viewMode$.setValue(params.viewMode);
11722
+ }
11794
11723
  manager.appManager = new AppManager(manager);
11795
11724
  manager._pageState = new PageStateImpl(manager.appManager);
11796
11725
  manager.cursorManager = new CursorManager(manager.appManager, Boolean(cursor), params.applianceIcons);
@@ -11808,6 +11737,9 @@ const _WindowManager = class extends InvisiblePlugin {
11808
11737
  if (params.container) {
11809
11738
  manager.bindContainer(params.container);
11810
11739
  }
11740
+ if (params.scrollModeWidth && params.scrollModeHeight) {
11741
+ manager.appManager.scrollBaseSize$.setValue({ width: params.scrollModeWidth, height: params.scrollModeHeight });
11742
+ }
11811
11743
  replaceRoomFunction(room, manager);
11812
11744
  emitter.emit("onCreated");
11813
11745
  _WindowManager.isCreated = true;
@@ -11876,6 +11808,7 @@ const _WindowManager = class extends InvisiblePlugin {
11876
11808
  this.bindMainView(mainViewElement, params.disableCameraTransform);
11877
11809
  if (_WindowManager.playground) {
11878
11810
  (_b = this.cursorManager) == null ? void 0 : _b.setupWrapper(_WindowManager.playground);
11811
+ this.playground$.setValue(_WindowManager.playground);
11879
11812
  }
11880
11813
  }
11881
11814
  }
@@ -12091,10 +12024,11 @@ const _WindowManager = class extends InvisiblePlugin {
12091
12024
  if (mode === ViewMode.Broadcaster) {
12092
12025
  if (this.canOperate) {
12093
12026
  mainViewProxy == null ? void 0 : mainViewProxy.storeCurrentCamera();
12027
+ mainViewProxy == null ? void 0 : mainViewProxy.storeCurrentSize();
12094
12028
  }
12095
12029
  mainViewProxy == null ? void 0 : mainViewProxy.start();
12096
12030
  }
12097
- if (mode === ViewMode.Freedom) {
12031
+ if (mode === ViewMode.Freedom || mode === "scroll") {
12098
12032
  mainViewProxy == null ? void 0 : mainViewProxy.stop();
12099
12033
  }
12100
12034
  this.viewMode = mode;
@@ -12245,6 +12179,10 @@ const _WindowManager = class extends InvisiblePlugin {
12245
12179
  throw new AppManagerNotInitError();
12246
12180
  }
12247
12181
  }
12182
+ get scrollState() {
12183
+ var _a, _b;
12184
+ return (_b = (_a = this.appManager) == null ? void 0 : _a.scrollMode) == null ? void 0 : _b.scrollState$.value;
12185
+ }
12248
12186
  get teleboxManager() {
12249
12187
  if (!this.boxManager) {
12250
12188
  throw new BoxManagerNotInitializeError();
@@ -12263,6 +12201,12 @@ const _WindowManager = class extends InvisiblePlugin {
12263
12201
  var _a;
12264
12202
  return (_a = this.appManager) == null ? void 0 : _a.closeApp(appId);
12265
12203
  }
12204
+ moveCameraToContain(rectangle) {
12205
+ var _a;
12206
+ this.debouncedStoreCamera();
12207
+ this.mainView.moveCameraToContain(rectangle);
12208
+ (_a = this.appManager) == null ? void 0 : _a.dispatchInternalEvent(Events.MoveCameraToContain, rectangle);
12209
+ }
12266
12210
  convertToPointInWorld(point) {
12267
12211
  return this.mainView.convertToPointInWorld(point);
12268
12212
  }
@@ -12399,9 +12343,9 @@ const _WindowManager = class extends InvisiblePlugin {
12399
12343
  var _a;
12400
12344
  (_a = this.boxManager) == null ? void 0 : _a.teleBoxManager.setStageStyle(style2);
12401
12345
  }
12402
- setBaseSize(size2) {
12346
+ setBaseSize(size) {
12403
12347
  var _a;
12404
- (_a = this.appManager) == null ? void 0 : _a.mainViewProxy.setMainViewSize(size2);
12348
+ (_a = this.appManager) == null ? void 0 : _a.mainViewProxy.setMainViewSize(size);
12405
12349
  setTimeout(() => {
12406
12350
  if (!this.appManager || !this.appManager.mainViewProxy.camera$.value)
12407
12351
  return;