@netless/window-manager 0.4.0-canary.5 → 0.4.0-canary.9

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 (57) hide show
  1. package/dist/App/Storage/StorageEvent.d.ts +8 -0
  2. package/dist/App/Storage/index.d.ts +26 -0
  3. package/dist/App/Storage/typings.d.ts +21 -0
  4. package/dist/App/Storage/utils.d.ts +5 -0
  5. package/dist/AppContext.d.ts +3 -1
  6. package/dist/AppListener.d.ts +0 -1
  7. package/dist/AppManager.d.ts +5 -5
  8. package/dist/AppProxy.d.ts +2 -3
  9. package/dist/Base/Context.d.ts +0 -1
  10. package/dist/BoxManager.d.ts +2 -1
  11. package/dist/BuiltinApps.d.ts +6 -0
  12. package/dist/ContainerResizeObserver.d.ts +10 -0
  13. package/dist/Helper.d.ts +6 -0
  14. package/dist/Utils/Common.d.ts +3 -1
  15. package/dist/Utils/Reactive.d.ts +1 -1
  16. package/dist/{MainView.d.ts → View/MainView.d.ts} +2 -4
  17. package/dist/View/ViewManager.d.ts +13 -0
  18. package/dist/constants.d.ts +1 -6
  19. package/dist/index.d.ts +5 -10
  20. package/dist/index.es.js +1 -1
  21. package/dist/index.es.js.map +1 -1
  22. package/dist/index.umd.js +1 -1
  23. package/dist/index.umd.js.map +1 -1
  24. package/dist/style.css +1 -1
  25. package/dist/typings.d.ts +1 -0
  26. package/package.json +3 -3
  27. package/src/App/Storage/StorageEvent.ts +21 -0
  28. package/src/App/Storage/index.ts +243 -0
  29. package/src/App/Storage/typings.ts +21 -0
  30. package/src/App/Storage/utils.ts +17 -0
  31. package/src/AppContext.ts +10 -2
  32. package/src/AppListener.ts +1 -8
  33. package/src/AppManager.ts +45 -27
  34. package/src/AppProxy.ts +14 -36
  35. package/src/Base/Context.ts +0 -4
  36. package/src/BoxManager.ts +9 -7
  37. package/src/BuiltinApps.ts +24 -0
  38. package/src/ContainerResizeObserver.ts +62 -0
  39. package/src/Helper.ts +30 -0
  40. package/src/ReconnectRefresher.ts +0 -1
  41. package/src/Utils/Common.ts +35 -13
  42. package/src/Utils/Reactive.ts +9 -3
  43. package/src/Utils/RoomHacker.ts +15 -0
  44. package/src/{MainView.ts → View/MainView.ts} +7 -25
  45. package/src/View/ViewManager.ts +53 -0
  46. package/src/constants.ts +1 -3
  47. package/src/index.ts +19 -71
  48. package/src/shim.d.ts +4 -0
  49. package/src/style.css +6 -0
  50. package/src/typings.ts +1 -0
  51. package/vite.config.js +4 -1
  52. package/dist/Utils/CameraStore.d.ts +0 -15
  53. package/dist/ViewManager.d.ts +0 -29
  54. package/dist/sdk.d.ts +0 -14
  55. package/src/Utils/CameraStore.ts +0 -72
  56. package/src/sdk.ts +0 -39
  57. package/src/viewManager.ts +0 -177
package/dist/style.css CHANGED
@@ -1 +1 @@
1
- .netless-window-manager-playground{width:100%;height:100%;position:relative;z-index:1;overflow:hidden;user-select:none}.netless-window-manager-sizer{position:absolute;top:0;left:0;width:100%;height:100%;z-index:1;overflow:hidden;display:flex}.netless-window-manager-sizer-horizontal{flex-direction:column}.netless-window-manager-sizer:before,.netless-window-manager-sizer:after{flex:1;content:"";display:block}.netless-window-manager-chess-sizer:before,.netless-window-manager-chess-sizer:after{background-image:linear-gradient(45deg,#b0b0b0 25%,transparent 25%),linear-gradient(-45deg,#b0b0b0 25%,transparent 25%),linear-gradient(45deg,transparent 75%,#b0b0b0 75%),linear-gradient(-45deg,transparent 75%,#b0b0b0 75%);background-color:#fff;background-size:20px 20px;background-position:0 0,0 10px,10px -10px,-10px 0px}.netless-window-manager-wrapper{position:relative;z-index:1;width:100%;height:100%;overflow:hidden}.netless-window-manager-main-view{width:100%;height:100%}.netless-window-manager-cursor-pencil-image{width:26px;height:26px}.netless-window-manager-cursor-eraser-image{width:26px;height:26px}.netless-window-manager-cursor-selector-image{width:24px;height:24px}.netless-window-manager-cursor-selector-avatar{border-radius:50%;border-style:solid;border-width:2px;border-color:#fff;margin-bottom:2px}.netless-window-manager-cursor-selector-avatar img{width:12px}.netless-window-manager-cursor-inner{border-radius:4px;display:flex;align-items:center;justify-content:center;flex-direction:row;padding-left:4px;padding-right:4px;font-size:12px}.netless-window-manager-cursor-inner-mellow{height:32px;border-radius:16px;display:flex;align-items:center;justify-content:center;flex-direction:row;padding-left:16px;padding-right:16px}.netless-window-manager-cursor-tag-name{font-size:12px;margin-left:4px;padding:2px 8px;border-radius:4px}.netless-window-manager-cursor-mid{display:flex;flex-direction:column;align-items:center;justify-content:center;position:absolute;width:26px;height:26px;z-index:2147483647;left:0;top:0;will-change:transform;transition:transform .05s;transform-origin:0 0;user-select:none}.netless-window-manager-cursor-pencil-offset{margin-left:-20px}.netless-window-manager-cursor-selector-offset{margin-left:-22px;margin-top:56px}.netless-window-manager-cursor-text-offset{margin-left:-30px;margin-top:18px}.netless-window-manager-cursor-shape-offset{display:flex;flex-direction:column;align-items:center;justify-content:center;position:absolute;width:180px;height:64px;margin-left:-30px;margin-top:12px}.netless-window-manager-cursor-name{width:100%;height:48px;display:flex;align-items:center;justify-content:center;position:absolute;top:-40px}.cursor-image-wrapper{display:flex;justify-content:center}.tele-fancy-scrollbar{overscroll-behavior:contain;overflow:auto;overflow-y:scroll;overflow-y:overlay;-webkit-overflow-scrolling:touch;-ms-overflow-style:-ms-autohiding-scrollbar;scrollbar-width:auto}.tele-fancy-scrollbar::-webkit-scrollbar{height:8px;width:8px}.tele-fancy-scrollbar::-webkit-scrollbar-track{background-color:transparent}.tele-fancy-scrollbar::-webkit-scrollbar-thumb{background-color:#444e601a;background-color:transparent;border-radius:4px;transition:background-color .4s}.tele-fancy-scrollbar:hover::-webkit-scrollbar-thumb{background-color:#444e601a}.tele-fancy-scrollbar::-webkit-scrollbar-thumb:hover{background-color:#444e6033}.tele-fancy-scrollbar::-webkit-scrollbar-thumb:active{background-color:#444e6033}.tele-fancy-scrollbar::-webkit-scrollbar-thumb:vertical{min-height:50px}.tele-fancy-scrollbar::-webkit-scrollbar-thumb:horizontal{min-width:50px}.telebox-box{position:absolute;top:0;left:0;z-index:100;will-change:transform;transition:width .4s cubic-bezier(.4,.9,.71,1.02),height .4s cubic-bezier(.55,.82,.63,.95),opacity .6s cubic-bezier(.7,0,.84,0),transform .4s ease}.telebox-box-main{position:relative;width:100%;height:100%;display:flex;flex-direction:column;overflow:hidden;background:#f9f9fc;box-shadow:0 4px 10px #2f419226;border-radius:6px;border:1px solid #e3e3ec}.telebox-titlebar-wrap{flex-shrink:0;position:relative;z-index:1}.telebox-content-wrap{flex:1;width:100%;overflow:hidden;display:flex;justify-content:center;align-items:center}.telebox-content{width:100%;height:100%;position:relative}.telebox-footer-wrap{flex-shrink:0;display:flex;flex-direction:column}.telebox-footer-wrap:before{content:"";display:block;flex:1}.telebox-resize-handle{position:absolute;z-index:2147483647}.telebox-n{width:100%;height:5px;left:0;top:-5px;cursor:n-resize}.telebox-s{width:100%;height:5px;left:0;bottom:-5px;cursor:s-resize}.telebox-w{width:5px;height:100%;left:-5px;top:0;cursor:w-resize}.telebox-e{width:5px;height:100%;right:-5px;top:0;cursor:e-resize}.telebox-nw{width:15px;height:15px;top:-5px;left:-5px;cursor:nw-resize}.telebox-ne{width:15px;height:15px;top:-5px;right:-5px;cursor:ne-resize}.telebox-se{width:15px;height:15px;bottom:-5px;right:-5px;cursor:se-resize}.telebox-sw{width:15px;height:15px;bottom:-5px;left:-5px;cursor:sw-resize}.telebox-track-mask{position:fixed;top:0;left:0;z-index:2147483647;width:100%;height:100%;background:rgba(0,0,0,.0001);cursor:move}.telebox-cursor-n{cursor:n-resize}.telebox-cursor-s{cursor:s-resize}.telebox-cursor-w{cursor:w-resize}.telebox-cursor-e{cursor:e-resize}.telebox-cursor-nw{cursor:nw-resize}.telebox-cursor-ne{cursor:ne-resize}.telebox-cursor-se{cursor:se-resize}.telebox-cursor-sw{cursor:sw-resize}.telebox-maximized .telebox-resize-handles,.telebox-no-resize .telebox-resize-handles{display:none}.telebox-maximized{box-shadow:none;transition:none}.telebox-minimized{will-change:transform;transition:width 50ms cubic-bezier(.4,.9,.71,1.02),height 50ms cubic-bezier(.55,.82,.63,.95),opacity .6s cubic-bezier(.7,0,.84,0),transform .6s ease;opacity:0;pointer-events:none;user-select:none}.telebox-transforming{will-change:transform;transition:opacity .6s cubic-bezier(.7,0,.84,0)}.telebox-readonly .telebox-resize-handle{cursor:initial!important;pointer-events:none!important}.telebox-color-scheme-dark .telebox-box-main{color:#e9e9e9;background:#212126;border-color:#43434d}.telebox-titlebar{box-sizing:border-box;height:26px;display:flex;align-items:center;padding:0 16px;background:#fff;user-select:none;border-bottom:1px solid #eeeef7}.telebox-title{overflow:hidden;margin:0 24px 0 0;padding:0;font-size:14px;font-weight:400;font-family:PingFangSC-Regular,PingFang SC;white-space:nowrap;word-break:keep-all;text-overflow:ellipsis;color:#191919}.telebox-titlebar-btns{white-space:nowrap;word-break:keep-all;margin-left:auto;font-size:0}.telebox-titlebar-btn{width:22px;height:22px;padding:0;outline:0;border:none;background:0 0;cursor:pointer}.telebox-titlebar-btn~.telebox-titlebar-btn{margin-left:10px}.telebox-titlebar-btn-icon{width:22px;height:22px}.telebox-readonly .telebox-titlebar-btn{cursor:not-allowed}.telebox-titlebar-icon-minimize{background:center/cover no-repeat url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIiB2aWV3Qm94PSIwIDAgMjggMjgiPgogICAgPGRlZnM+CiAgICAgICAgPHBhdGggaWQ9ImEiIGQ9Ik0wIDBoMjh2MjhIMHoiIC8+CiAgICA8L2RlZnM+CiAgICA8ZyBmaWxsPSJub25lIiBmaWxsLXJ1bGU9ImV2ZW5vZGQiPgogICAgICAgIDxtYXNrIGlkPSJiIiBmaWxsPSIjZmZmIj4KICAgICAgICAgICAgPHVzZSB4bGluazpocmVmPSIjYSIgLz4KICAgICAgICA8L21hc2s+CiAgICAgICAgPHBhdGggZmlsbD0iI0E3QTdDQSIgZmlsbC1ydWxlPSJub256ZXJvIiBkPSJNOSAxM2gxMHYxLjZIOXoiIG1hc2s9InVybCgjYikiIC8+CiAgICA8L2c+Cjwvc3ZnPgo=)}.telebox-titlebar-icon-maximize{background:center/cover no-repeat url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIiB2aWV3Qm94PSIwIDAgMjggMjgiPgogICAgPGRlZnM+CiAgICAgICAgPHBhdGggaWQ9ImEiIGQ9Ik0wIDBoMjh2MjhIMHoiIC8+CiAgICA8L2RlZnM+CiAgICA8ZyBmaWxsPSJub25lIiBmaWxsLXJ1bGU9ImV2ZW5vZGQiPgogICAgICAgIDxtYXNrIGlkPSJiIiBmaWxsPSIjZmZmIj4KICAgICAgICAgICAgPHVzZSB4bGluazpocmVmPSIjYSIgLz4KICAgICAgICA8L21hc2s+CiAgICAgICAgPGcgZmlsbD0iI0E3QTdDQSIgZmlsbC1ydWxlPSJub256ZXJvIiBtYXNrPSJ1cmwoI2IpIj4KICAgICAgICAgICAgPHBhdGgKICAgICAgICAgICAgICAgIGQ9Ik0yMC40ODEgMTcuMWgxLjJ2NC41ODFIMTcuMXYtMS4yaDMuMzgxVjE3LjF6bS0xNC4xOTA1LS4wMDloMS4ydjMuMzgxaDMuMzgwOXYxLjJoLTQuNTgxdi00LjU4MXpNMTcuMSA2LjE5MDVoNC41ODF2NC41ODA5aC0xLjJ2LTMuMzgxSDE3LjF2LTEuMnptLTEwLjcwMDguMTA4N2g0Ljc5ODV2MS4ySDcuNTk5MnYzLjU5ODVoLTEuMlY2LjI5OTJ6IiAvPgogICAgICAgIDwvZz4KICAgIDwvZz4KPC9zdmc+Cg==)}.telebox-titlebar-icon-maximize.is-active{background-image:url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIiB2aWV3Qm94PSIwIDAgMjggMjgiPgogICAgPGRlZnM+CiAgICAgICAgPHBhdGggaWQ9ImEiIGQ9Ik0wIDBoMjZ2MjZIMHoiIC8+CiAgICAgICAgPHBhdGggaWQ9ImMiIGQ9Ik0yNi44NjkgMEwyOCAxLjEzMVYyNi44N0wyNi44NjkgMjhIMS4xM0wwIDI2Ljg3VjEuMTMxTDEuMTMgMHoiIC8+CiAgICA8L2RlZnM+CiAgICA8ZyBmaWxsPSJub25lIiBmaWxsLXJ1bGU9ImV2ZW5vZGQiPgogICAgICAgIDxnIHRyYW5zZm9ybT0idHJhbnNsYXRlKDEgMSkiPgogICAgICAgICAgICA8bWFzayBpZD0iYiIgZmlsbD0iI2ZmZiI+CiAgICAgICAgICAgICAgICA8dXNlIHhsaW5rOmhyZWY9IiNhIiAvPgogICAgICAgICAgICA8L21hc2s+CiAgICAgICAgICAgIDxwYXRoIGZpbGw9Im5vbmUiIGQ9Ik0tNC42NDI5LTQuNjQyOWgzNS4yODU4djM1LjI4NThILTQuNjQyOXoiIG1hc2s9InVybCgjYikiIC8+CiAgICAgICAgPC9nPgogICAgICAgIDxnPgogICAgICAgICAgICA8bWFzayBpZD0iZCIgZmlsbD0iI2ZmZiI+CiAgICAgICAgICAgICAgICA8dXNlIHhsaW5rOmhyZWY9IiNjIiAvPgogICAgICAgICAgICA8L21hc2s+CiAgICAgICAgICAgIDxwYXRoIGZpbGw9Im5vbmUiIGQ9Ik0tMTcuNTE2OCAxNEwxNC0xNy41MTY4IDQ1LjUxNjggMTQgMTQgNDUuNTE2OHoiIG1hc2s9InVybCgjZCkiIC8+CiAgICAgICAgPC9nPgogICAgICAgIDxwYXRoIHN0cm9rZT0iI0E3QTdDQSIgc3Ryb2tlLXdpZHRoPSIxLjIiCiAgICAgICAgICAgIGQ9Ik0xMC4wODg2IDIxLjQ4NjV2LTMuNjk2Nkg2LjM5Mk0yMS4zODU1IDEwLjE4OTVoLTMuNjk2NlY2LjQ5M00yMS40MDIgMTcuNzk4M2gtMy42OTY2djMuNjk2Nk0xMC4yNTAzIDYuMTQ5OHYzLjg5ODVINi4zNTE3IiAvPgogICAgPC9nPgo8L3N2Zz4K)}.telebox-titlebar-icon-close{background:center/cover no-repeat url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAyOCAyOCI+CiAgICA8ZyBmaWxsPSJub25lIiBmaWxsLXJ1bGU9ImV2ZW5vZGQiIHN0cm9rZT0iI0E3QTdDQSIgc3Ryb2tlLXdpZHRoPSIxLjQiPgogICAgICAgIDxwYXRoIGQ9Ik04LjM1MyAyMC4zMzIxTDIwLjMzMiA4LjM1M00yMC4zMzIyIDIwLjMzMjFMOC4zNTMgOC4zNTMiIC8+CiAgICA8L2c+Cjwvc3ZnPgo=)}.telebox-color-scheme-dark .telebox-titlebar{color:#e9e9e9;background:#43434d;border-bottom:none}.telebox-collector{visibility:hidden;display:block;position:absolute;z-index:200;width:40px;height:40px;margin:0;padding:0;border:none;outline:0;font-size:0;border-radius:50%;background:#fff;box-shadow:0 2px 6px #2f419226;cursor:pointer;user-select:none;pointer-events:none;background-repeat:no-repeat;background-size:18px 16px;background-position:center}.telebox-collector-visible{visibility:visible;pointer-events:initial}.telebox-collector-readonly{cursor:not-allowed}.telebox-color-scheme-dark.telebox-collector{background-color:#43434d}.telebox-max-titlebar{display:none;position:absolute;top:0;left:0;z-index:50000;user-select:none}.telebox-max-titlebar-maximized{display:flex}.telebox-titles{flex:1;height:100%;margin:0 16px 0 -16px;overflow-y:hidden;overflow-x:scroll;overflow-x:overlay;-webkit-overflow-scrolling:touch;-ms-overflow-style:-ms-autohiding-scrollbar;scrollbar-width:auto}.telebox-titles::-webkit-scrollbar{height:8px;width:8px}.telebox-titles::-webkit-scrollbar-track{background-color:transparent}.telebox-titles::-webkit-scrollbar-thumb{background-color:#eeeef7cc;background-color:transparent;border-radius:4px;transition:background-color .4s}.telebox-titles:hover::-webkit-scrollbar-thumb{background-color:#eeeef7cc}.telebox-titles::-webkit-scrollbar-thumb:hover{background-color:#eeeef7}.telebox-titles::-webkit-scrollbar-thumb:active{background-color:#eeeef7}.telebox-titles::-webkit-scrollbar-thumb:vertical{min-height:50px}.telebox-titles::-webkit-scrollbar-thumb:horizontal{min-width:50px}.telebox-titles-content{height:100%;display:flex;flex-wrap:nowrap;align-items:center;padding:0}.telebox-titles-tab{overflow:hidden;max-width:182px;min-width:50px;padding:0 26px 0 16px;outline:0;font-size:13px;font-family:PingFangSC-Regular,PingFang SC;font-weight:400;text-overflow:ellipsis;white-space:nowrap;word-break:keep-all;border:none;border-right:1px solid #e5e5f0;color:#7b88a0;background:0 0;cursor:pointer}.telebox-titles-tab~.telebox-titles-tab{margin-left:2px}.telebox-titles-tab-focus{color:#357bf6}.telebox-readonly .telebox-titles-tab{cursor:not-allowed}.telebox-color-scheme-dark{color-scheme:dark}.telebox-color-scheme-dark.telebox-titlebar{color:#e9e9e9;background:#43434d;border-bottom:none}.telebox-color-scheme-dark .telebox-titles-tab{border-right-color:#7b88a0}.telebox-color-scheme-dark .telebox-title{color:#e9e9e9}.page-renderer-pages-container{position:relative;overflow:hidden}.page-renderer-page{position:absolute;top:0;left:0;will-change:transform;background-position:center;background-size:cover;background-repeat:no-repeat}.page-renderer-page-img{display:block;width:100%;height:auto;user-select:none}.netless-app-docs-viewer-static-scrollbar{position:absolute;top:0;right:0;z-index:2147483647;width:8px;min-height:30px;margin:0;padding:0;border:none;outline:none;border-radius:4px;background:rgba(68,78,96,.4);box-shadow:1px 1px 8px #ffffffb3;opacity:0;transition:background .4s,opacity .4s 3s,transform .2s;will-change:transform,height;user-select:none}.netless-app-docs-viewer-static-scrollbar.netless-app-docs-viewer-static-scrollbar-dragging{background:rgba(68,78,96,.6);opacity:1;transition:background .4s,opacity .4s 3s!important}.netless-app-docs-viewer-static-scrollbar:hover,.netless-app-docs-viewer-static-scrollbar:focus{background:rgba(68,78,96,.5)}.netless-app-docs-viewer-static-scrollbar:active{background:rgba(68,78,96,.6)}.netless-app-docs-viewer-content:hover .netless-app-docs-viewer-static-scrollbar{opacity:1;transition:background .4s,opacity .4s,transform .2s}.netless-app-docs-viewer-readonly .netless-app-docs-viewer-static-scrollbar{display:none}.netless-app-docs-viewer-static-pages:hover .netless-app-docs-viewer-static-scrollbar{opacity:1;transition:background .4s,opacity .4s,transform .2s}
1
+ .page-renderer-pages-container{position:relative;overflow:hidden}.page-renderer-page{position:absolute;top:0;left:0;will-change:transform;background-position:center;background-size:cover;background-repeat:no-repeat}.page-renderer-page-img{display:block;width:100%;height:auto;user-select:none}.netless-app-docs-viewer-static-scrollbar{position:absolute;top:0;right:0;z-index:2147483647;width:8px;min-height:30px;margin:0;padding:0;border:none;outline:none;border-radius:4px;background:rgba(68,78,96,.4);box-shadow:1px 1px 8px #ffffffb3;opacity:0;transition:background .4s,opacity .4s 3s,transform .2s;will-change:transform,height;user-select:none}.netless-app-docs-viewer-static-scrollbar.netless-app-docs-viewer-static-scrollbar-dragging{background:rgba(68,78,96,.6);opacity:1;transition:background .4s,opacity .4s 3s!important}.netless-app-docs-viewer-static-scrollbar:hover,.netless-app-docs-viewer-static-scrollbar:focus{background:rgba(68,78,96,.5)}.netless-app-docs-viewer-static-scrollbar:active{background:rgba(68,78,96,.6)}.netless-app-docs-viewer-content:hover .netless-app-docs-viewer-static-scrollbar{opacity:1;transition:background .4s,opacity .4s,transform .2s}.netless-app-docs-viewer-readonly .netless-app-docs-viewer-static-scrollbar{display:none}.netless-app-docs-viewer-static-pages:hover .netless-app-docs-viewer-static-scrollbar{opacity:1;transition:background .4s,opacity .4s,transform .2s}.netless-window-manager-playground{width:100%;height:100%;position:relative;z-index:1;overflow:hidden;user-select:none}.netless-window-manager-sizer{position:absolute;top:0;left:0;width:100%;height:100%;z-index:1;overflow:hidden;display:flex}.netless-window-manager-sizer-horizontal{flex-direction:column}.netless-window-manager-sizer:before,.netless-window-manager-sizer:after{flex:1;content:"";display:block}.netless-window-manager-chess-sizer:before,.netless-window-manager-chess-sizer:after{background-image:linear-gradient(45deg,#b0b0b0 25%,transparent 25%),linear-gradient(-45deg,#b0b0b0 25%,transparent 25%),linear-gradient(45deg,transparent 75%,#b0b0b0 75%),linear-gradient(-45deg,transparent 75%,#b0b0b0 75%);background-color:#fff;background-size:20px 20px;background-position:0 0,0 10px,10px -10px,-10px 0px}.netless-window-manager-wrapper{position:relative;z-index:1;width:100%;height:100%;overflow:hidden}.netless-window-manager-main-view{width:100%;height:100%}.netless-window-manager-cursor-pencil-image{width:26px;height:26px}.netless-window-manager-cursor-eraser-image{width:26px;height:26px}.netless-window-manager-cursor-selector-image{width:24px;height:24px}.netless-window-manager-cursor-selector-avatar{border-radius:50%;border-style:solid;border-width:2px;border-color:#fff;margin-bottom:2px}.netless-window-manager-cursor-selector-avatar img{width:12px}.netless-window-manager-cursor-inner{border-radius:4px;display:flex;align-items:center;justify-content:center;flex-direction:row;padding-left:4px;padding-right:4px;font-size:12px}.netless-window-manager-cursor-inner-mellow{height:32px;border-radius:16px;display:flex;align-items:center;justify-content:center;flex-direction:row;padding-left:16px;padding-right:16px}.netless-window-manager-cursor-tag-name{font-size:12px;margin-left:4px;padding:2px 8px;border-radius:4px}.netless-window-manager-cursor-mid{display:flex;flex-direction:column;align-items:center;justify-content:center;position:absolute;width:26px;height:26px;z-index:2147483647;left:0;top:0;will-change:transform;transition:transform .05s;transform-origin:0 0;user-select:none}.netless-window-manager-cursor-pencil-offset{margin-left:-20px}.netless-window-manager-cursor-selector-offset{margin-left:-22px;margin-top:56px}.netless-window-manager-cursor-text-offset{margin-left:-30px;margin-top:18px}.netless-window-manager-cursor-shape-offset{display:flex;flex-direction:column;align-items:center;justify-content:center;position:absolute;width:180px;height:64px;margin-left:-30px;margin-top:12px}.netless-window-manager-cursor-name{width:100%;height:48px;display:flex;align-items:center;justify-content:center;position:absolute;top:-40px}.cursor-image-wrapper{display:flex;justify-content:center}.telebox-collector{position:absolute;right:10px;bottom:15px}.tele-fancy-scrollbar{overscroll-behavior:contain;overflow:auto;overflow-y:scroll;overflow-y:overlay;-webkit-overflow-scrolling:touch;-ms-overflow-style:-ms-autohiding-scrollbar;scrollbar-width:auto}.tele-fancy-scrollbar::-webkit-scrollbar{height:8px;width:8px}.tele-fancy-scrollbar::-webkit-scrollbar-track{background-color:transparent}.tele-fancy-scrollbar::-webkit-scrollbar-thumb{background-color:#444e601a;background-color:transparent;border-radius:4px;transition:background-color .4s}.tele-fancy-scrollbar:hover::-webkit-scrollbar-thumb{background-color:#444e601a}.tele-fancy-scrollbar::-webkit-scrollbar-thumb:hover{background-color:#444e6033}.tele-fancy-scrollbar::-webkit-scrollbar-thumb:active{background-color:#444e6033}.tele-fancy-scrollbar::-webkit-scrollbar-thumb:vertical{min-height:50px}.tele-fancy-scrollbar::-webkit-scrollbar-thumb:horizontal{min-width:50px}.telebox-box{position:absolute;top:0;left:0;z-index:100;will-change:transform;transition:width .4s cubic-bezier(.4,.9,.71,1.02),height .4s cubic-bezier(.55,.82,.63,.95),opacity .6s cubic-bezier(.7,0,.84,0),transform .4s ease}.telebox-box-main{position:relative;width:100%;height:100%;display:flex;flex-direction:column;overflow:hidden;background:#f9f9fc;box-shadow:0 4px 10px #2f419226;border-radius:6px;border:1px solid #e3e3ec}.telebox-titlebar-wrap{flex-shrink:0;position:relative;z-index:1}.telebox-content-wrap{flex:1;width:100%;overflow:hidden;display:flex;justify-content:center;align-items:center}.telebox-content{width:100%;height:100%;position:relative}.telebox-footer-wrap{flex-shrink:0;display:flex;flex-direction:column}.telebox-footer-wrap:before{content:"";display:block;flex:1}.telebox-resize-handle{position:absolute;z-index:2147483647}.telebox-n{width:100%;height:5px;left:0;top:-5px;cursor:n-resize}.telebox-s{width:100%;height:5px;left:0;bottom:-5px;cursor:s-resize}.telebox-w{width:5px;height:100%;left:-5px;top:0;cursor:w-resize}.telebox-e{width:5px;height:100%;right:-5px;top:0;cursor:e-resize}.telebox-nw{width:15px;height:15px;top:-5px;left:-5px;cursor:nw-resize}.telebox-ne{width:15px;height:15px;top:-5px;right:-5px;cursor:ne-resize}.telebox-se{width:15px;height:15px;bottom:-5px;right:-5px;cursor:se-resize}.telebox-sw{width:15px;height:15px;bottom:-5px;left:-5px;cursor:sw-resize}.telebox-track-mask{position:fixed;top:0;left:0;z-index:2147483647;width:100%;height:100%;background:rgba(0,0,0,.0001);cursor:move}.telebox-cursor-n{cursor:n-resize}.telebox-cursor-s{cursor:s-resize}.telebox-cursor-w{cursor:w-resize}.telebox-cursor-e{cursor:e-resize}.telebox-cursor-nw{cursor:nw-resize}.telebox-cursor-ne{cursor:ne-resize}.telebox-cursor-se{cursor:se-resize}.telebox-cursor-sw{cursor:sw-resize}.telebox-maximized .telebox-resize-handles,.telebox-no-resize .telebox-resize-handles{display:none}.telebox-maximized{box-shadow:none;transition:none}.telebox-minimized{will-change:transform;transition:width 50ms cubic-bezier(.4,.9,.71,1.02),height 50ms cubic-bezier(.55,.82,.63,.95),opacity .6s cubic-bezier(.7,0,.84,0),transform .6s ease;opacity:0;pointer-events:none;user-select:none}.telebox-transforming{will-change:transform;transition:opacity .6s cubic-bezier(.7,0,.84,0)}.telebox-readonly .telebox-resize-handle{cursor:initial!important;pointer-events:none!important}.telebox-color-scheme-dark .telebox-box-main{color:#e9e9e9;background:#212126;border-color:#43434d}.telebox-titlebar{box-sizing:border-box;height:26px;display:flex;align-items:center;padding:0 16px;background:#fff;user-select:none;border-bottom:1px solid #eeeef7}.telebox-title{overflow:hidden;margin:0 24px 0 0;padding:0;font-size:14px;font-weight:400;font-family:PingFangSC-Regular,PingFang SC;white-space:nowrap;word-break:keep-all;text-overflow:ellipsis;color:#191919}.telebox-titlebar-btns{white-space:nowrap;word-break:keep-all;margin-left:auto;font-size:0}.telebox-titlebar-btn{width:22px;height:22px;padding:0;outline:0;border:none;background:0 0;cursor:pointer}.telebox-titlebar-btn~.telebox-titlebar-btn{margin-left:10px}.telebox-titlebar-btn-icon{width:22px;height:22px}.telebox-readonly .telebox-titlebar-btn{cursor:not-allowed}.telebox-titlebar-icon-minimize{background:center/cover no-repeat url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIiB2aWV3Qm94PSIwIDAgMjggMjgiPgogICAgPGRlZnM+CiAgICAgICAgPHBhdGggaWQ9ImEiIGQ9Ik0wIDBoMjh2MjhIMHoiIC8+CiAgICA8L2RlZnM+CiAgICA8ZyBmaWxsPSJub25lIiBmaWxsLXJ1bGU9ImV2ZW5vZGQiPgogICAgICAgIDxtYXNrIGlkPSJiIiBmaWxsPSIjZmZmIj4KICAgICAgICAgICAgPHVzZSB4bGluazpocmVmPSIjYSIgLz4KICAgICAgICA8L21hc2s+CiAgICAgICAgPHBhdGggZmlsbD0iI0E3QTdDQSIgZmlsbC1ydWxlPSJub256ZXJvIiBkPSJNOSAxM2gxMHYxLjZIOXoiIG1hc2s9InVybCgjYikiIC8+CiAgICA8L2c+Cjwvc3ZnPgo=)}.telebox-titlebar-icon-maximize{background:center/cover no-repeat url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIiB2aWV3Qm94PSIwIDAgMjggMjgiPgogICAgPGRlZnM+CiAgICAgICAgPHBhdGggaWQ9ImEiIGQ9Ik0wIDBoMjh2MjhIMHoiIC8+CiAgICA8L2RlZnM+CiAgICA8ZyBmaWxsPSJub25lIiBmaWxsLXJ1bGU9ImV2ZW5vZGQiPgogICAgICAgIDxtYXNrIGlkPSJiIiBmaWxsPSIjZmZmIj4KICAgICAgICAgICAgPHVzZSB4bGluazpocmVmPSIjYSIgLz4KICAgICAgICA8L21hc2s+CiAgICAgICAgPGcgZmlsbD0iI0E3QTdDQSIgZmlsbC1ydWxlPSJub256ZXJvIiBtYXNrPSJ1cmwoI2IpIj4KICAgICAgICAgICAgPHBhdGgKICAgICAgICAgICAgICAgIGQ9Ik0yMC40ODEgMTcuMWgxLjJ2NC41ODFIMTcuMXYtMS4yaDMuMzgxVjE3LjF6bS0xNC4xOTA1LS4wMDloMS4ydjMuMzgxaDMuMzgwOXYxLjJoLTQuNTgxdi00LjU4MXpNMTcuMSA2LjE5MDVoNC41ODF2NC41ODA5aC0xLjJ2LTMuMzgxSDE3LjF2LTEuMnptLTEwLjcwMDguMTA4N2g0Ljc5ODV2MS4ySDcuNTk5MnYzLjU5ODVoLTEuMlY2LjI5OTJ6IiAvPgogICAgICAgIDwvZz4KICAgIDwvZz4KPC9zdmc+Cg==)}.telebox-titlebar-icon-maximize.is-active{background-image:url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIiB2aWV3Qm94PSIwIDAgMjggMjgiPgogICAgPGRlZnM+CiAgICAgICAgPHBhdGggaWQ9ImEiIGQ9Ik0wIDBoMjZ2MjZIMHoiIC8+CiAgICAgICAgPHBhdGggaWQ9ImMiIGQ9Ik0yNi44NjkgMEwyOCAxLjEzMVYyNi44N0wyNi44NjkgMjhIMS4xM0wwIDI2Ljg3VjEuMTMxTDEuMTMgMHoiIC8+CiAgICA8L2RlZnM+CiAgICA8ZyBmaWxsPSJub25lIiBmaWxsLXJ1bGU9ImV2ZW5vZGQiPgogICAgICAgIDxnIHRyYW5zZm9ybT0idHJhbnNsYXRlKDEgMSkiPgogICAgICAgICAgICA8bWFzayBpZD0iYiIgZmlsbD0iI2ZmZiI+CiAgICAgICAgICAgICAgICA8dXNlIHhsaW5rOmhyZWY9IiNhIiAvPgogICAgICAgICAgICA8L21hc2s+CiAgICAgICAgICAgIDxwYXRoIGZpbGw9Im5vbmUiIGQ9Ik0tNC42NDI5LTQuNjQyOWgzNS4yODU4djM1LjI4NThILTQuNjQyOXoiIG1hc2s9InVybCgjYikiIC8+CiAgICAgICAgPC9nPgogICAgICAgIDxnPgogICAgICAgICAgICA8bWFzayBpZD0iZCIgZmlsbD0iI2ZmZiI+CiAgICAgICAgICAgICAgICA8dXNlIHhsaW5rOmhyZWY9IiNjIiAvPgogICAgICAgICAgICA8L21hc2s+CiAgICAgICAgICAgIDxwYXRoIGZpbGw9Im5vbmUiIGQ9Ik0tMTcuNTE2OCAxNEwxNC0xNy41MTY4IDQ1LjUxNjggMTQgMTQgNDUuNTE2OHoiIG1hc2s9InVybCgjZCkiIC8+CiAgICAgICAgPC9nPgogICAgICAgIDxwYXRoIHN0cm9rZT0iI0E3QTdDQSIgc3Ryb2tlLXdpZHRoPSIxLjIiCiAgICAgICAgICAgIGQ9Ik0xMC4wODg2IDIxLjQ4NjV2LTMuNjk2Nkg2LjM5Mk0yMS4zODU1IDEwLjE4OTVoLTMuNjk2NlY2LjQ5M00yMS40MDIgMTcuNzk4M2gtMy42OTY2djMuNjk2Nk0xMC4yNTAzIDYuMTQ5OHYzLjg5ODVINi4zNTE3IiAvPgogICAgPC9nPgo8L3N2Zz4K)}.telebox-titlebar-icon-close{background:center/cover no-repeat url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAyOCAyOCI+CiAgICA8ZyBmaWxsPSJub25lIiBmaWxsLXJ1bGU9ImV2ZW5vZGQiIHN0cm9rZT0iI0E3QTdDQSIgc3Ryb2tlLXdpZHRoPSIxLjQiPgogICAgICAgIDxwYXRoIGQ9Ik04LjM1MyAyMC4zMzIxTDIwLjMzMiA4LjM1M00yMC4zMzIyIDIwLjMzMjFMOC4zNTMgOC4zNTMiIC8+CiAgICA8L2c+Cjwvc3ZnPgo=)}.telebox-color-scheme-dark .telebox-titlebar{color:#e9e9e9;background:#43434d;border-bottom:none}.telebox-collector{visibility:hidden;display:block;position:absolute;z-index:200;width:40px;height:40px;margin:0;padding:0;border:none;outline:0;font-size:0;border-radius:50%;background:#fff;box-shadow:0 2px 6px #2f419226;cursor:pointer;user-select:none;pointer-events:none;background-repeat:no-repeat;background-size:18px 16px;background-position:center}.telebox-collector-visible{visibility:visible;pointer-events:initial}.telebox-collector-readonly{cursor:not-allowed}.telebox-color-scheme-dark.telebox-collector{background-color:#43434d}.telebox-max-titlebar{display:none;position:absolute;top:0;left:0;z-index:50000;user-select:none}.telebox-max-titlebar-maximized{display:flex}.telebox-titles{flex:1;height:100%;margin:0 16px 0 -16px;overflow-y:hidden;overflow-x:scroll;overflow-x:overlay;-webkit-overflow-scrolling:touch;-ms-overflow-style:-ms-autohiding-scrollbar;scrollbar-width:auto}.telebox-titles::-webkit-scrollbar{height:8px;width:8px}.telebox-titles::-webkit-scrollbar-track{background-color:transparent}.telebox-titles::-webkit-scrollbar-thumb{background-color:#eeeef7cc;background-color:transparent;border-radius:4px;transition:background-color .4s}.telebox-titles:hover::-webkit-scrollbar-thumb{background-color:#eeeef7cc}.telebox-titles::-webkit-scrollbar-thumb:hover{background-color:#eeeef7}.telebox-titles::-webkit-scrollbar-thumb:active{background-color:#eeeef7}.telebox-titles::-webkit-scrollbar-thumb:vertical{min-height:50px}.telebox-titles::-webkit-scrollbar-thumb:horizontal{min-width:50px}.telebox-titles-content{height:100%;display:flex;flex-wrap:nowrap;align-items:center;padding:0}.telebox-titles-tab{overflow:hidden;max-width:182px;min-width:50px;padding:0 26px 0 16px;outline:0;font-size:13px;font-family:PingFangSC-Regular,PingFang SC;font-weight:400;text-overflow:ellipsis;white-space:nowrap;word-break:keep-all;border:none;border-right:1px solid #e5e5f0;color:#7b88a0;background:0 0;cursor:pointer}.telebox-titles-tab~.telebox-titles-tab{margin-left:2px}.telebox-titles-tab-focus{color:#357bf6}.telebox-readonly .telebox-titles-tab{cursor:not-allowed}.telebox-color-scheme-dark{color-scheme:dark}.telebox-color-scheme-dark.telebox-titlebar{color:#e9e9e9;background:#43434d;border-bottom:none}.telebox-color-scheme-dark .telebox-titles-tab{border-right-color:#7b88a0}.telebox-color-scheme-dark .telebox-title{color:#e9e9e9}
package/dist/typings.d.ts CHANGED
@@ -70,3 +70,4 @@ export declare type AppListenerKeys = keyof AppEmitterEvent;
70
70
  export type { AppContext } from "./AppContext";
71
71
  export type { ReadonlyTeleBox, TeleBoxRect };
72
72
  export type { SceneState, SceneDefinition, View, AnimationMode, Displayer, Room, Player };
73
+ export type { Storage, StorageStateChangedEvent, StorageStateChangedListener } from "./App/Storage";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@netless/window-manager",
3
- "version": "0.4.0-canary.5",
3
+ "version": "0.4.0-canary.9",
4
4
  "description": "",
5
5
  "main": "dist/index.es.js",
6
6
  "module": "dist/index.es.js",
@@ -24,7 +24,7 @@
24
24
  "@juggle/resize-observer": "^3.3.1",
25
25
  "@netless/app-docs-viewer": "0.2.0",
26
26
  "@netless/app-media-player": "0.1.0-beta.5",
27
- "@netless/telebox-insider": "0.2.17",
27
+ "@netless/telebox-insider": "0.2.18",
28
28
  "emittery": "^0.9.2",
29
29
  "lodash": "^4.17.21",
30
30
  "p-retry": "^4.6.1",
@@ -57,6 +57,6 @@
57
57
  "typescript": "^4.3.5",
58
58
  "video.js": "^7.14.3",
59
59
  "vite": "^2.5.3",
60
- "white-web-sdk": "^2.15.12"
60
+ "white-web-sdk": "^2.16.0"
61
61
  }
62
62
  }
@@ -0,0 +1,21 @@
1
+ export type StorageEventListener<T> = (event: T) => void;
2
+
3
+ export class StorageEvent<TMessage> {
4
+ listeners = new Set<StorageEventListener<TMessage>>();
5
+
6
+ get length(): number {
7
+ return this.listeners.size;
8
+ }
9
+
10
+ dispatch(message: TMessage): void {
11
+ this.listeners.forEach(callback => callback(message));
12
+ }
13
+
14
+ addListener(listener: StorageEventListener<TMessage>): void {
15
+ this.listeners.add(listener);
16
+ }
17
+
18
+ removeListener(listener: StorageEventListener<TMessage>): void {
19
+ this.listeners.delete(listener);
20
+ }
21
+ }
@@ -0,0 +1,243 @@
1
+ import type { AkkoObjectUpdatedProperty } from "white-web-sdk";
2
+ import { get, has, isObject } from "lodash";
3
+ import { SideEffectManager } from "side-effect-manager";
4
+ import type { AppContext } from "../../AppContext";
5
+ import { safeListenPropsUpdated } from "../../Utils/Reactive";
6
+ import { isRef, makeRef, plainObjectKeys } from "./utils";
7
+ import type { Diff, MaybeRefValue, RefValue, StorageStateChangedEvent } from "./typings";
8
+ import { StorageEvent } from "./StorageEvent";
9
+
10
+ export * from './typings';
11
+
12
+ const STORAGE_NS = "_WM-STORAGE_";
13
+
14
+ export class Storage<TState = any> implements Storage<TState> {
15
+ readonly id: string;
16
+
17
+ private readonly _context: AppContext<{ [STORAGE_NS]: TState }>;
18
+ private readonly _sideEffect = new SideEffectManager();
19
+ private _state: TState;
20
+ private _destroyed = false;
21
+
22
+ private _refMap = new WeakMap<any, RefValue>();
23
+
24
+ /**
25
+ * `setState` alters local state immediately before sending to server. This will cache the old value for onStateChanged diffing.
26
+ */
27
+ private _lastValue = new Map<string | number | symbol, TState[Extract<keyof TState, string>]>();
28
+
29
+ constructor(context: AppContext<any>, id: string, defaultState?: TState) {
30
+ if (id == null) {
31
+ throw new Error("Cannot create Storage with empty id.");
32
+ }
33
+
34
+ if (defaultState && !isObject(defaultState)) {
35
+ throw new Error(`Default state for Storage ${id} is not an object.`);
36
+ }
37
+
38
+ this._context = context;
39
+ this.id = id;
40
+
41
+ const attrs = context.getAttributes();
42
+ this._state = {} as TState;
43
+ const rawState = get<TState>(attrs, [STORAGE_NS, id], this._state);
44
+
45
+ if (this._context.getIsWritable()) {
46
+ if (!isObject(rawState) || rawState === this._state) {
47
+ if (!attrs[STORAGE_NS]) {
48
+ this._context.updateAttributes([STORAGE_NS], {});
49
+ }
50
+ this._context.updateAttributes([STORAGE_NS, this.id], this._state);
51
+ if (defaultState) {
52
+ this.setState(defaultState);
53
+ }
54
+ } else {
55
+ // strip mobx
56
+ plainObjectKeys(rawState).forEach(key => {
57
+ try {
58
+ const rawValue = isObject(rawState[key]) ? JSON.parse(JSON.stringify(rawState[key])) : rawState[key];
59
+ if (isRef<TState[Extract<keyof TState, string>]>(rawValue)) {
60
+ this._state[key] = rawValue.v;
61
+ if (isObject(rawValue.v)) {
62
+ this._refMap.set(rawValue.v, rawValue);
63
+ }
64
+ } else {
65
+ this._state[key] = rawValue;
66
+ }
67
+ } catch (e) {
68
+ console.error(e);
69
+ }
70
+ });
71
+ }
72
+ }
73
+
74
+ this._sideEffect.addDisposer(
75
+ safeListenPropsUpdated(
76
+ () => get(context.getAttributes(), [STORAGE_NS, this.id]),
77
+ this._updateProperties.bind(this),
78
+ this.destroy.bind(this)
79
+ )
80
+ );
81
+ }
82
+
83
+ get state(): Readonly<TState> {
84
+ if (this._destroyed) {
85
+ console.warn(`Accessing state on destroyed Storage "${this.id}"`)
86
+ }
87
+ return this._state;
88
+ }
89
+
90
+ readonly onStateChanged = new StorageEvent<StorageStateChangedEvent<TState>>();
91
+
92
+ ensureState(state: Partial<TState>): void {
93
+ return this.setState(
94
+ plainObjectKeys(state).reduce((payload, key) => {
95
+ if (!has(this._state, key)) {
96
+ payload[key] = state[key];
97
+ }
98
+ return payload;
99
+ }, {} as Partial<TState>)
100
+ );
101
+ }
102
+
103
+ setState(state: Partial<TState>): void {
104
+ if (this._destroyed) {
105
+ console.error(new Error(`Cannot call setState on destroyed Storage "${this.id}".`));
106
+ return;
107
+ }
108
+
109
+ if (!this._context.getIsWritable()) {
110
+ console.error(new Error(`Cannot setState on Storage "${this.id}" without writable access`), state);
111
+ return;
112
+ }
113
+
114
+ const keys = plainObjectKeys(state);
115
+ if (keys.length > 0) {
116
+ keys.forEach(key => {
117
+ const value = state[key];
118
+ if (value === this._state[key]) {
119
+ return;
120
+ }
121
+
122
+ if (value === void 0) {
123
+ this._lastValue.set(key, this._state[key]);
124
+ delete this._state[key];
125
+ this._context.updateAttributes([STORAGE_NS, this.id, key], value);
126
+ } else {
127
+ this._lastValue.set(key, this._state[key]);
128
+ this._state[key] = value as TState[Extract<keyof TState, string>];
129
+
130
+ let payload: MaybeRefValue<typeof value> = value;
131
+ if (isObject(value)) {
132
+ let refValue = this._refMap.get(value);
133
+ if (!refValue) {
134
+ refValue = makeRef(value);
135
+ this._refMap.set(value, refValue);
136
+ }
137
+ payload = refValue;
138
+ }
139
+
140
+ this._context.updateAttributes([STORAGE_NS, this.id, key], payload);
141
+ }
142
+ });
143
+ }
144
+ }
145
+
146
+ emptyStore(): void {
147
+ if (this._destroyed) {
148
+ console.error(new Error(`Cannot empty destroyed Storage "${this.id}".`));
149
+ return;
150
+ }
151
+
152
+ if (!this._context.getIsWritable()) {
153
+ console.error(new Error(`Cannot empty Storage "${this.id}" without writable access.`));
154
+ return;
155
+ }
156
+
157
+ this._context.updateAttributes([STORAGE_NS, this.id], {});
158
+ }
159
+
160
+ deleteStore(): void {
161
+ if (!this._context.getIsWritable()) {
162
+ console.error(new Error(`Cannot delete Storage "${this.id}" without writable access.`));
163
+ return;
164
+ }
165
+
166
+ this.destroy();
167
+
168
+ this._context.updateAttributes([STORAGE_NS, this.id], void 0);
169
+ }
170
+
171
+ get destroyed(): boolean {
172
+ return this._destroyed;
173
+ }
174
+
175
+ destroy() {
176
+ this._destroyed = true;
177
+ this._sideEffect.flushAll();
178
+ }
179
+
180
+ private _updateProperties(actions: ReadonlyArray<AkkoObjectUpdatedProperty<TState, string>>): void {
181
+ if (this._destroyed) {
182
+ console.error(new Error(`Cannot call _updateProperties on destroyed Storage "${this.id}".`));
183
+ return;
184
+ }
185
+
186
+ if (actions.length > 0) {
187
+ const diffs: Diff<TState> = {};
188
+
189
+ for (let i = 0; i < actions.length; i++) {
190
+ try {
191
+ const action = actions[i]
192
+ const key = action.key as Extract<keyof TState, string>;
193
+ const value = isObject(action.value) ? JSON.parse(JSON.stringify(action.value)) : action.value;
194
+ let oldValue: TState[Extract<keyof TState, string>] | undefined;
195
+ if (this._lastValue.has(key)) {
196
+ oldValue = this._lastValue.get(key);
197
+ this._lastValue.delete(key);
198
+ }
199
+
200
+ switch (action.kind) {
201
+ case 2: {
202
+ // Removed
203
+ if (has(this._state, key)) {
204
+ oldValue = this._state[key];
205
+ delete this._state[key];
206
+ }
207
+ diffs[key] = { oldValue };
208
+ break;
209
+ }
210
+ default: {
211
+ let newValue = value;
212
+
213
+ if (isRef<TState[Extract<keyof TState, string>]>(value)) {
214
+ const { k, v } = value;
215
+ const curValue = this._state[key];
216
+ if (isObject(curValue) && this._refMap.get(curValue)?.k === k) {
217
+ newValue = curValue;
218
+ } else {
219
+ newValue = v;
220
+ if (isObject(v)) {
221
+ this._refMap.set(v, value);
222
+ }
223
+ }
224
+ }
225
+
226
+ if (newValue !== this._state[key]) {
227
+ oldValue = this._state[key];
228
+ this._state[key] = newValue;
229
+ }
230
+
231
+ diffs[key] = { newValue, oldValue };
232
+ break;
233
+ }
234
+ }
235
+ } catch (e) {
236
+ console.error(e)
237
+ }
238
+ }
239
+
240
+ this.onStateChanged.dispatch(diffs);
241
+ }
242
+ }
243
+ }
@@ -0,0 +1,21 @@
1
+ import type { StorageEventListener } from "./StorageEvent";
2
+
3
+ export type RefValue<TValue = any> = { k: string; v: TValue; __isRef: true };
4
+
5
+ export type ExtractRawValue<TValue> = TValue extends RefValue<infer TRefValue> ? TRefValue : TValue;
6
+
7
+ export type AutoRefValue<TValue> = RefValue<ExtractRawValue<TValue>>;
8
+
9
+ export type MaybeRefValue<TValue> = TValue | AutoRefValue<TValue>;
10
+
11
+ export type DiffOne<T> = { oldValue?: T; newValue?: T };
12
+
13
+ export type Diff<T> = { [K in keyof T]?: DiffOne<T[K]> };
14
+
15
+ export type StorageOnSetStatePayload<TState = unknown> = {
16
+ [K in keyof TState]?: MaybeRefValue<TState[K]>;
17
+ };
18
+
19
+ export type StorageStateChangedEvent<TState = any> = Diff<TState>
20
+
21
+ export type StorageStateChangedListener<TState = any> = StorageEventListener<StorageStateChangedEvent<TState>>
@@ -0,0 +1,17 @@
1
+ import { has } from "lodash";
2
+ import { genUID } from "side-effect-manager";
3
+ import type { AutoRefValue, ExtractRawValue, RefValue } from "./typings";
4
+
5
+ export const plainObjectKeys = Object.keys as <T>(o: T) => Array<Extract<keyof T, string>>;
6
+
7
+ export function isRef<TValue = unknown>(e: unknown): e is RefValue<TValue> {
8
+ return Boolean(has(e, '__isRef'));
9
+ }
10
+
11
+ export function makeRef<TValue>(v: TValue): RefValue<TValue> {
12
+ return { k: genUID(), v, __isRef: true };
13
+ }
14
+
15
+ export function makeAutoRef<TValue>(v: TValue): AutoRefValue<TValue> {
16
+ return isRef<ExtractRawValue<TValue>>(v) ? v : makeRef(v as ExtractRawValue<TValue>);
17
+ }
package/src/AppContext.ts CHANGED
@@ -15,8 +15,9 @@ import type { BoxManager } from "./BoxManager";
15
15
  import type { AppEmitterEvent } from "./index";
16
16
  import type { AppManager } from "./AppManager";
17
17
  import type { AppProxy } from "./AppProxy";
18
+ import { Storage } from './App/Storage';
18
19
 
19
- export class AppContext<TAttrs extends Record<string, any>, AppOptions = any> {
20
+ export class AppContext<TAttrs extends Record<string, any> = any, AppOptions = any> {
20
21
  public readonly emitter: Emittery<AppEmitterEvent<TAttrs>>;
21
22
  public readonly mobxUtils = {
22
23
  autorun,
@@ -103,7 +104,6 @@ export class AppContext<TAttrs extends Record<string, any>, AppOptions = any> {
103
104
  public async setScenePath(scenePath: string): Promise<void> {
104
105
  if (!this.appProxy.box) return;
105
106
  this.appProxy.setFullPath(scenePath);
106
- this.appProxy.context.switchAppToWriter(this.appId);
107
107
  }
108
108
 
109
109
  public mountView(dom: HTMLDivElement): void {
@@ -120,4 +120,12 @@ export class AppContext<TAttrs extends Record<string, any>, AppOptions = any> {
120
120
  public getAppOptions(): AppOptions | undefined {
121
121
  return typeof this.appOptions === 'function' ? (this.appOptions as () => AppOptions)() : this.appOptions
122
122
  }
123
+
124
+ public createStorage<TState>(storeId: string, defaultState?: TState): Storage<TState> {
125
+ const storage = new Storage(this, storeId, defaultState);
126
+ this.emitter.on("destroy", () => {
127
+ storage.destroy();
128
+ });
129
+ return storage;
130
+ }
123
131
  }
@@ -34,10 +34,6 @@ export class AppListeners {
34
34
  this.appResizeHandler(data.payload);
35
35
  break;
36
36
  }
37
- case Events.SwitchViewsToFreedom: {
38
- this.switchViewsToFreedomHandler();
39
- break;
40
- }
41
37
  case Events.AppBoxStateChange: {
42
38
  this.boxStateChangeHandler(data.payload);
43
39
  break;
@@ -65,16 +61,13 @@ export class AppListeners {
65
61
  this.manager.room?.refreshViewSize();
66
62
  };
67
63
 
68
- private switchViewsToFreedomHandler = () => {
69
- this.manager.viewManager.freedomAllViews();
70
- };
71
-
72
64
  private boxStateChangeHandler = (state: TeleBoxState) => {
73
65
  callbacks.emit("boxStateChange", state);
74
66
  }
75
67
 
76
68
  private setMainViewScenePathHandler = ({ nextScenePath }: { nextScenePath: string }) => {
77
69
  setViewFocusScenePath(this.manager.mainView, nextScenePath);
70
+ callbacks.emit("mainViewScenePathChange", nextScenePath);
78
71
  }
79
72
 
80
73
  private moveCameraToContainHandler = (payload: any) => {
package/src/AppManager.ts CHANGED
@@ -2,16 +2,15 @@ import pRetry from "p-retry";
2
2
  import { AppAttributes, AppStatus, Events, MagixEventName } from "./constants";
3
3
  import { AppListeners } from "./AppListener";
4
4
  import { AppProxy } from "./AppProxy";
5
- import { autorun, isPlayer, isRoom, ScenePathType, ViewVisionMode } from "white-web-sdk";
5
+ import { autorun, isPlayer, isRoom, ScenePathType } from "white-web-sdk";
6
6
  import { callbacks, emitter, WindowManager, reconnectRefresher } from "./index";
7
- import { CameraStore } from "./Utils/CameraStore";
8
- import { genAppId, makeValidScenePath, setScenePath } from "./Utils/Common";
7
+ import { genAppId, makeValidScenePath, setScenePath, setViewFocusScenePath } from "./Utils/Common";
9
8
  import { log } from "./Utils/log";
10
- import { MainViewProxy } from "./MainView";
9
+ import { MainViewProxy } from "./View/MainView";
11
10
  import { onObjectRemoved, safeListenPropsUpdated } from "./Utils/Reactive";
12
- import { sortBy } from "lodash";
11
+ import { get, sortBy } from "lodash";
13
12
  import { store } from "./AttributesDelegate";
14
- import { ViewManager } from "./ViewManager";
13
+ import { ViewManager } from "./View/ViewManager";
15
14
  import type { ReconnectRefresher } from "./ReconnectRefresher";
16
15
  import type { BoxManager } from "./BoxManager";
17
16
  import type { Displayer, DisplayerState, Room } from "white-web-sdk";
@@ -19,7 +18,6 @@ import type { AddAppParams, BaseInsertParams, TeleBoxRect, EmitterEvent } from "
19
18
 
20
19
  export class AppManager {
21
20
  public displayer: Displayer;
22
- public cameraStore: CameraStore;
23
21
  public viewManager: ViewManager;
24
22
  public appProxies: Map<string, AppProxy> = new Map();
25
23
  public appStatus: Map<string, AppStatus> = new Map();
@@ -31,6 +29,8 @@ export class AppManager {
31
29
  private appListeners: AppListeners;
32
30
  public boxManager?: BoxManager;
33
31
 
32
+ private _prevSceneIndex: number | undefined;
33
+
34
34
  constructor(public windowManger: WindowManager) {
35
35
  this.displayer = windowManger.displayer;
36
36
  this.store.setContext({
@@ -38,9 +38,8 @@ export class AppManager {
38
38
  safeSetAttributes: attributes => this.safeSetAttributes(attributes),
39
39
  safeUpdateAttributes: (keys, val) => this.safeUpdateAttributes(keys, val),
40
40
  });
41
- this.cameraStore = new CameraStore();
42
41
  this.mainViewProxy = new MainViewProxy(this);
43
- this.viewManager = new ViewManager(this);
42
+ this.viewManager = new ViewManager(this.displayer);
44
43
  this.appListeners = new AppListeners(this);
45
44
  this.displayer.callbacks.on(this.eventName, this.displayerStateListener);
46
45
  this.appListeners.addListeners();
@@ -98,6 +97,15 @@ export class AppManager {
98
97
  }
99
98
  });
100
99
  });
100
+ this.refresher?.add("mainViewIndex", () => {
101
+ return autorun(() => {
102
+ const mainSceneIndex = get(this.attributes, "_mainSceneIndex");
103
+ if (mainSceneIndex !== undefined && this._prevSceneIndex !== mainSceneIndex) {
104
+ callbacks.emit("mainViewSceneIndexChange", mainSceneIndex);
105
+ this._prevSceneIndex = mainSceneIndex;
106
+ }
107
+ });
108
+ });
101
109
  if (!this.attributes.apps || Object.keys(this.attributes.apps).length === 0) {
102
110
  const mainScenePath = this.store.getMainViewScenePath();
103
111
  if (!mainScenePath) return;
@@ -188,15 +196,18 @@ export class AppManager {
188
196
  mainView.disableCameraTransform = disableCameraTransform;
189
197
  mainView.divElement = divElement;
190
198
  if (!mainView.focusScenePath) {
191
- this.store.setMainViewFocusPath(mainView);
192
- }
193
- if (this.store.focus === undefined && mainView.mode !== ViewVisionMode.Writable) {
194
- this.viewManager.switchMainViewToWriter();
199
+ this.setMainViewFocusPath();
195
200
  }
196
- this.mainViewProxy.addMainViewListener();
197
201
  emitter.emit("mainViewMounted");
198
202
  }
199
203
 
204
+ public setMainViewFocusPath() {
205
+ const scenePath = this.store.getMainViewScenePath();
206
+ if (scenePath) {
207
+ setViewFocusScenePath(this.mainView, scenePath);
208
+ }
209
+ }
210
+
200
211
  public async addApp(params: AddAppParams, isDynamicPPT: boolean): Promise<string | undefined> {
201
212
  log("addApp", params);
202
213
  const { appId, needFocus } = await this.beforeAddApp(params, isDynamicPPT);
@@ -282,7 +293,7 @@ export class AppManager {
282
293
  emitter.emit("observerIdChange", this.displayer.observerId);
283
294
  };
284
295
 
285
- private displayerWritableListener = (isReadonly: boolean) => {
296
+ public displayerWritableListener = (isReadonly: boolean) => {
286
297
  const isWritable = !isReadonly;
287
298
  const isManualWritable =
288
299
  this.windowManger.readonly === undefined || this.windowManger.readonly === false;
@@ -295,9 +306,6 @@ export class AppManager {
295
306
  appProxy.emitAppIsWritableChange();
296
307
  });
297
308
  if (isWritable === true) {
298
- if (!this.store.focus) {
299
- this.mainViewProxy.switchViewModeToWriter();
300
- }
301
309
  this.mainView.disableCameraTransform = false;
302
310
  } else {
303
311
  this.mainView.disableCameraTransform = true;
@@ -347,15 +355,16 @@ export class AppManager {
347
355
  await this._setMainViewScenePath(scenePath);
348
356
  } else if (scenePathType === ScenePathType.Dir) {
349
357
  const validScenePath = makeValidScenePath(this.displayer, scenePath);
350
- await this._setMainViewScenePath(validScenePath);
358
+ if (validScenePath) {
359
+ await this._setMainViewScenePath(validScenePath);
360
+ }
351
361
  }
352
362
  }
353
363
  }
354
364
 
355
365
  private async _setMainViewScenePath(scenePath: string) {
356
366
  this.safeSetAttributes({ _mainScenePath: scenePath });
357
- await this.viewManager.switchMainViewToWriter();
358
- setScenePath(this.room, scenePath);
367
+ this.setMainViewFocusPath();
359
368
  this.store.setMainViewFocusPath(this.mainView);
360
369
  this.dispatchInternalEvent(Events.SetMainViewScenePath, { nextScenePath: scenePath });
361
370
  }
@@ -363,12 +372,20 @@ export class AppManager {
363
372
  public async setMainViewSceneIndex(index: number) {
364
373
  if (this.room) {
365
374
  this.safeSetAttributes({ _mainSceneIndex: index });
366
- await this.viewManager.switchMainViewToWriter();
367
- this.room.setSceneIndex(index);
368
- const nextScenePath = this.room.state.sceneState.scenePath;
369
- this.store.setMainViewScenePath(nextScenePath);
370
- this.store.setMainViewFocusPath(this.mainView);
371
- this.dispatchInternalEvent(Events.SetMainViewScenePath, { nextScenePath });
375
+ const mainViewScenePath = this.store.getMainViewScenePath() as string;
376
+ if (mainViewScenePath) {
377
+ const sceneList = mainViewScenePath.split("/");
378
+ sceneList.pop();
379
+ let sceneDir = sceneList.join("/");
380
+ if (sceneDir === "") {
381
+ sceneDir = "/";
382
+ }
383
+ const scenePath = makeValidScenePath(this.displayer, sceneDir, index);
384
+ if (scenePath) {
385
+ this.store.setMainViewScenePath(scenePath);
386
+ this.setMainViewFocusPath();
387
+ }
388
+ }
372
389
  }
373
390
  }
374
391
 
@@ -471,5 +488,6 @@ export class AppManager {
471
488
  this.refresher?.destroy();
472
489
  this.mainViewProxy.destroy();
473
490
  callbacks.clearListeners();
491
+ this._prevSceneIndex = undefined;
474
492
  }
475
493
  }