@netless/window-manager 0.4.0-canary.1 → 0.4.0-canary.13

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 (64) hide show
  1. package/dist/App/MagixEvent/index.d.ts +29 -0
  2. package/dist/App/Storage/StorageEvent.d.ts +8 -0
  3. package/dist/App/Storage/index.d.ts +38 -0
  4. package/dist/App/Storage/typings.d.ts +21 -0
  5. package/dist/App/Storage/utils.d.ts +5 -0
  6. package/dist/AppContext.d.ts +40 -16
  7. package/dist/AppListener.d.ts +0 -1
  8. package/dist/AppManager.d.ts +8 -7
  9. package/dist/AppProxy.d.ts +3 -3
  10. package/dist/Base/Context.d.ts +0 -1
  11. package/dist/BoxManager.d.ts +1 -0
  12. package/dist/BuiltinApps.d.ts +6 -0
  13. package/dist/ContainerResizeObserver.d.ts +10 -0
  14. package/dist/Cursor/Cursor.d.ts +2 -3
  15. package/dist/Cursor/index.d.ts +7 -4
  16. package/dist/Helper.d.ts +6 -0
  17. package/dist/ReconnectRefresher.d.ts +5 -2
  18. package/dist/Utils/Common.d.ts +3 -1
  19. package/dist/Utils/Reactive.d.ts +1 -1
  20. package/dist/{MainView.d.ts → View/MainView.d.ts} +2 -4
  21. package/dist/View/ViewManager.d.ts +13 -0
  22. package/dist/constants.d.ts +1 -6
  23. package/dist/index.d.ts +14 -13
  24. package/dist/index.es.js +1 -1
  25. package/dist/index.es.js.map +1 -1
  26. package/dist/index.umd.js +1 -1
  27. package/dist/index.umd.js.map +1 -1
  28. package/dist/style.css +1 -1
  29. package/dist/typings.d.ts +3 -2
  30. package/package.json +6 -5
  31. package/src/App/MagixEvent/index.ts +68 -0
  32. package/src/App/Storage/StorageEvent.ts +21 -0
  33. package/src/App/Storage/index.ts +284 -0
  34. package/src/App/Storage/typings.ts +21 -0
  35. package/src/App/Storage/utils.ts +17 -0
  36. package/src/AppContext.ts +65 -20
  37. package/src/AppListener.ts +1 -8
  38. package/src/AppManager.ts +68 -35
  39. package/src/AppProxy.ts +37 -46
  40. package/src/Base/Context.ts +0 -4
  41. package/src/BoxManager.ts +9 -7
  42. package/src/BuiltinApps.ts +24 -0
  43. package/src/ContainerResizeObserver.ts +62 -0
  44. package/src/Cursor/Cursor.ts +23 -34
  45. package/src/Cursor/index.ts +70 -41
  46. package/src/Helper.ts +30 -0
  47. package/src/ReconnectRefresher.ts +13 -5
  48. package/src/Utils/Common.ts +35 -13
  49. package/src/Utils/Reactive.ts +9 -3
  50. package/src/Utils/RoomHacker.ts +16 -0
  51. package/src/{MainView.ts → View/MainView.ts} +9 -25
  52. package/src/View/ViewManager.ts +53 -0
  53. package/src/constants.ts +1 -3
  54. package/src/index.ts +47 -86
  55. package/src/shim.d.ts +4 -0
  56. package/src/style.css +6 -0
  57. package/src/typings.ts +3 -2
  58. package/vite.config.js +4 -1
  59. package/dist/Utils/CameraStore.d.ts +0 -15
  60. package/dist/ViewManager.d.ts +0 -29
  61. package/dist/sdk.d.ts +0 -14
  62. package/src/Utils/CameraStore.ts +0 -72
  63. package/src/sdk.ts +0 -39
  64. 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}
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
@@ -2,7 +2,7 @@ import type Emittery from "emittery";
2
2
  import type { AnimationMode, Displayer, DisplayerState, Player, Room, SceneDefinition, SceneState, View } from "white-web-sdk";
3
3
  import type { AppContext } from "./AppContext";
4
4
  import type { ReadonlyTeleBox, TeleBoxRect } from "@netless/telebox-insider";
5
- export interface NetlessApp<Attributes = any, SetupResult = any, AppOptions = any> {
5
+ export interface NetlessApp<Attributes = any, MagixEventPayloads = any, AppOptions = any, SetupResult = any> {
6
6
  kind: string;
7
7
  config?: {
8
8
  /** Box width relative to whiteboard. 0~1. Default 0.5. */
@@ -16,7 +16,7 @@ export interface NetlessApp<Attributes = any, SetupResult = any, AppOptions = an
16
16
  /** App only single instance. */
17
17
  singleton?: boolean;
18
18
  };
19
- setup: (context: AppContext<Attributes, AppOptions>) => SetupResult;
19
+ setup: (context: AppContext<Attributes, MagixEventPayloads, AppOptions>) => SetupResult;
20
20
  }
21
21
  export declare type AppEmitterEvent<T = any> = {
22
22
  /**
@@ -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,10 +1,11 @@
1
1
  {
2
2
  "name": "@netless/window-manager",
3
- "version": "0.4.0-canary.1",
3
+ "version": "0.4.0-canary.13",
4
4
  "description": "",
5
5
  "main": "dist/index.es.js",
6
6
  "module": "dist/index.es.js",
7
7
  "types": "dist/index.d.ts",
8
+ "repository": "netless-io/window-manager",
8
9
  "scripts": {
9
10
  "prettier": "prettier --write .",
10
11
  "build": "vite build && yarn type-gen",
@@ -18,13 +19,13 @@
18
19
  "license": "ISC",
19
20
  "peerDependencies": {
20
21
  "video.js": ">=7",
21
- "white-web-sdk": "^2.13.16"
22
+ "white-web-sdk": "^2.16.0"
22
23
  },
23
24
  "dependencies": {
24
25
  "@juggle/resize-observer": "^3.3.1",
25
- "@netless/app-docs-viewer": "0.1.26",
26
+ "@netless/app-docs-viewer": "0.2.0",
26
27
  "@netless/app-media-player": "0.1.0-beta.5",
27
- "@netless/telebox-insider": "0.2.17",
28
+ "@netless/telebox-insider": "0.2.18",
28
29
  "emittery": "^0.9.2",
29
30
  "lodash": "^4.17.21",
30
31
  "p-retry": "^4.6.1",
@@ -57,6 +58,6 @@
57
58
  "typescript": "^4.3.5",
58
59
  "video.js": "^7.14.3",
59
60
  "vite": "^2.5.3",
60
- "white-web-sdk": "^2.15.12"
61
+ "white-web-sdk": "^2.16.0"
61
62
  }
62
63
  }
@@ -0,0 +1,68 @@
1
+ import type {
2
+ MagixEventListenerOptions as WhiteMagixListenerOptions,
3
+ Event as WhiteEvent,
4
+ EventPhase as WhiteEventPhase,
5
+ Scope as WhiteScope,
6
+ } from "white-web-sdk";
7
+
8
+ export interface MagixEventListenerOptions extends WhiteMagixListenerOptions {
9
+ /**
10
+ * Rapid emitted callbacks will be slowed down to this interval (in ms).
11
+ */
12
+ fireInterval?: number;
13
+ /**
14
+ * If `true`, sent events will reach self-listeners after committed to server.
15
+ * Otherwise the events will reach self-listeners immediately.
16
+ */
17
+ fireSelfEventAfterCommit?: boolean;
18
+ }
19
+
20
+ export interface MagixEventMessage<
21
+ TPayloads = any,
22
+ TEvent extends MagixEventTypes<TPayloads> = MagixEventTypes<TPayloads>
23
+ > extends Omit<WhiteEvent, "scope" | "phase"> {
24
+ /** Event name */
25
+ event: TEvent;
26
+ /** Event Payload */
27
+ payload: TPayloads[TEvent];
28
+ /** Whiteboard ID of the client who dispatched the event. It will be AdminObserverId for system events. */
29
+ authorId: number;
30
+ scope: `${WhiteScope}`;
31
+ phase: `${WhiteEventPhase}`;
32
+ }
33
+
34
+ export type MagixEventTypes<TPayloads = any> = Extract<keyof TPayloads, string>;
35
+
36
+ export type MagixEventPayload<
37
+ TPayloads = any,
38
+ TEvent extends MagixEventTypes<TPayloads> = MagixEventTypes<TPayloads>
39
+ > = TPayloads[TEvent];
40
+
41
+ export type MagixEventDispatcher<TPayloads = any> = <
42
+ TEvent extends MagixEventTypes<TPayloads> = MagixEventTypes<TPayloads>
43
+ >(
44
+ event: TEvent,
45
+ payload: TPayloads[TEvent]
46
+ ) => void;
47
+
48
+ export type MagixEventHandler<
49
+ TPayloads = any,
50
+ TEvent extends MagixEventTypes<TPayloads> = MagixEventTypes<TPayloads>
51
+ > = (message: MagixEventMessage<TPayloads, TEvent>) => void;
52
+
53
+ export type MagixEventListenerDisposer = () => void
54
+
55
+ export type MagixEventAddListener<TPayloads = any> = <
56
+ TEvent extends MagixEventTypes<TPayloads> = MagixEventTypes<TPayloads>
57
+ >(
58
+ event: TEvent,
59
+ handler: MagixEventHandler<TPayloads, TEvent>,
60
+ options?: MagixEventListenerOptions | undefined
61
+ ) => MagixEventListenerDisposer;
62
+
63
+ export type MagixEventRemoveListener<TPayloads = any> = <
64
+ TEvent extends MagixEventTypes<TPayloads> = MagixEventTypes<TPayloads>
65
+ >(
66
+ event: TEvent,
67
+ handler?: MagixEventHandler<TPayloads, TEvent>
68
+ ) => void;
@@ -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,284 @@
1
+ import type { AkkoObjectUpdatedProperty } from "white-web-sdk";
2
+ import { get, has, mapValues, isObject, size, noop } 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
+ export const STORAGE_NS = "_WM-STORAGE_";
13
+
14
+ export class Storage<TState extends Record<string, any> = any> implements Storage<TState> {
15
+ readonly id: string | null;
16
+
17
+ private readonly _context: AppContext;
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, id?: string, defaultState?: TState) {
30
+ if (defaultState && !isObject(defaultState)) {
31
+ throw new Error(`Default state for Storage ${id} is not an object.`);
32
+ }
33
+
34
+ this._context = context;
35
+ this.id = id || null;
36
+
37
+ this._state = {} as TState;
38
+ const rawState = this._getRawState(this._state);
39
+
40
+ if (this.id !== null && this._context.getIsWritable()) {
41
+ if (rawState === this._state || !isObject(rawState)) {
42
+ if (!get(this._context.getAttributes(), [STORAGE_NS])) {
43
+ this._context.updateAttributes([STORAGE_NS], {});
44
+ }
45
+ this._context.updateAttributes([STORAGE_NS, this.id], this._state);
46
+ }
47
+ if (defaultState) {
48
+ this.setState(defaultState);
49
+ }
50
+ }
51
+
52
+ // strip mobx
53
+ plainObjectKeys(rawState).forEach(key => {
54
+ if (this.id === null && key === STORAGE_NS) {
55
+ return;
56
+ }
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
+ this._sideEffect.addDisposer(
73
+ safeListenPropsUpdated(
74
+ () => this.id === null ? context.getAttributes() : get(context.getAttributes(), [STORAGE_NS, this.id]),
75
+ this._updateProperties.bind(this),
76
+ this.destroy.bind(this)
77
+ )
78
+ );
79
+ }
80
+
81
+ get state(): Readonly<TState> {
82
+ if (this._destroyed) {
83
+ console.warn(`Accessing state on destroyed Storage "${this.id}"`)
84
+ }
85
+ return this._state;
86
+ }
87
+
88
+ readonly onStateChanged = new StorageEvent<StorageStateChangedEvent<TState>>();
89
+
90
+ ensureState(state: Partial<TState>): void {
91
+ return this.setState(
92
+ plainObjectKeys(state).reduce((payload, key) => {
93
+ if (!has(this._state, key)) {
94
+ payload[key] = state[key];
95
+ }
96
+ return payload;
97
+ }, {} as Partial<TState>)
98
+ );
99
+ }
100
+
101
+ setState(state: Partial<TState>): void {
102
+ if (this._destroyed) {
103
+ console.error(new Error(`Cannot call setState on destroyed Storage "${this.id}".`));
104
+ return;
105
+ }
106
+
107
+ if (!this._context.getIsWritable()) {
108
+ console.error(new Error(`Cannot setState on Storage "${this.id}" without writable access`), state);
109
+ return;
110
+ }
111
+
112
+ const keys = plainObjectKeys(state);
113
+ if (keys.length > 0) {
114
+ keys.forEach(key => {
115
+ const value = state[key];
116
+ if (value === this._state[key]) {
117
+ return;
118
+ }
119
+
120
+ if (value === void 0) {
121
+ this._lastValue.set(key, this._state[key]);
122
+ delete this._state[key];
123
+ this._setRawState(key, value);
124
+ } else {
125
+ this._lastValue.set(key, this._state[key]);
126
+ this._state[key] = value as TState[Extract<keyof TState, string>];
127
+
128
+ let payload: MaybeRefValue<typeof value> = value;
129
+ if (isObject(value)) {
130
+ let refValue = this._refMap.get(value);
131
+ if (!refValue) {
132
+ refValue = makeRef(value);
133
+ this._refMap.set(value, refValue);
134
+ }
135
+ payload = refValue;
136
+ }
137
+
138
+ this._setRawState(key, payload)
139
+ }
140
+ });
141
+ }
142
+ }
143
+
144
+ /**
145
+ * Empty storage data.
146
+ */
147
+ emptyStorage(): void {
148
+ if (size(this._state) <= 0) {
149
+ return;
150
+ }
151
+
152
+ if (this._destroyed) {
153
+ console.error(new Error(`Cannot empty destroyed Storage "${this.id}".`));
154
+ return;
155
+ }
156
+
157
+ if (!this._context.getIsWritable()) {
158
+ console.error(new Error(`Cannot empty Storage "${this.id}" without writable access.`));
159
+ return;
160
+ }
161
+
162
+ this.setState(mapValues(this._state, noop as () => undefined));
163
+ }
164
+
165
+ /**
166
+ * Delete storage index with all of its data and destroy the Storage instance.
167
+ */
168
+ deleteStorage(): void {
169
+ if (this.id === null) {
170
+ throw new Error(`Cannot delete main Storage`);
171
+ }
172
+
173
+ if (!this._context.getIsWritable()) {
174
+ console.error(new Error(`Cannot delete Storage "${this.id}" without writable access.`));
175
+ return;
176
+ }
177
+
178
+ this.destroy();
179
+
180
+ this._context.updateAttributes([STORAGE_NS, this.id], void 0);
181
+ }
182
+
183
+ get destroyed(): boolean {
184
+ return this._destroyed;
185
+ }
186
+
187
+ /**
188
+ * Destroy the Storage instance. The data will be kept.
189
+ */
190
+ destroy() {
191
+ this._destroyed = true;
192
+ this._sideEffect.flushAll();
193
+ }
194
+
195
+ private _getRawState(): TState | undefined
196
+ private _getRawState(defaultValue: TState): TState
197
+ private _getRawState(defaultValue?: TState): TState | undefined {
198
+ if (this.id === null) {
199
+ return get(this._context.getAttributes(), [], defaultValue);
200
+ } else {
201
+ return get(this._context.getAttributes(), [STORAGE_NS, this.id], defaultValue);
202
+ }
203
+ }
204
+
205
+ private _setRawState(key: string, value: any): void {
206
+ if (this.id === null) {
207
+ if (key === STORAGE_NS) {
208
+ throw new Error(`Cannot set attribute internal filed "${STORAGE_NS}"`)
209
+ }
210
+ return this._context.updateAttributes([key], value);
211
+ } else {
212
+ return this._context.updateAttributes([STORAGE_NS, this.id, key], value);
213
+ }
214
+ }
215
+
216
+ private _updateProperties(actions: ReadonlyArray<AkkoObjectUpdatedProperty<TState, string>>): void {
217
+ if (this._destroyed) {
218
+ console.error(new Error(`Cannot call _updateProperties on destroyed Storage "${this.id}".`));
219
+ return;
220
+ }
221
+
222
+ if (actions.length > 0) {
223
+ const diffs: Diff<TState> = {};
224
+
225
+ for (let i = 0; i < actions.length; i++) {
226
+ try {
227
+ const action = actions[i]
228
+ const key = action.key as Extract<keyof TState, string>;
229
+
230
+ if (this.id === null && key === STORAGE_NS) {
231
+ continue
232
+ }
233
+
234
+ const value = isObject(action.value) ? JSON.parse(JSON.stringify(action.value)) : action.value;
235
+ let oldValue: TState[Extract<keyof TState, string>] | undefined;
236
+ if (this._lastValue.has(key)) {
237
+ oldValue = this._lastValue.get(key);
238
+ this._lastValue.delete(key);
239
+ }
240
+
241
+ switch (action.kind) {
242
+ case 2: {
243
+ // Removed
244
+ if (has(this._state, key)) {
245
+ oldValue = this._state[key];
246
+ delete this._state[key];
247
+ }
248
+ diffs[key] = { oldValue };
249
+ break;
250
+ }
251
+ default: {
252
+ let newValue = value;
253
+
254
+ if (isRef<TState[Extract<keyof TState, string>]>(value)) {
255
+ const { k, v } = value;
256
+ const curValue = this._state[key];
257
+ if (isObject(curValue) && this._refMap.get(curValue)?.k === k) {
258
+ newValue = curValue;
259
+ } else {
260
+ newValue = v;
261
+ if (isObject(v)) {
262
+ this._refMap.set(v, value);
263
+ }
264
+ }
265
+ }
266
+
267
+ if (newValue !== this._state[key]) {
268
+ oldValue = this._state[key];
269
+ this._state[key] = newValue;
270
+ }
271
+
272
+ diffs[key] = { newValue, oldValue };
273
+ break;
274
+ }
275
+ }
276
+ } catch (e) {
277
+ console.error(e)
278
+ }
279
+ }
280
+
281
+ this.onStateChanged.dispatch(diffs);
282
+ }
283
+ }
284
+ }
@@ -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
+ }