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

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 (74) hide show
  1. package/.idea/inspectionProfiles/Project_Default.xml +7 -0
  2. package/.idea/modules.xml +8 -0
  3. package/.idea/vcs.xml +6 -0
  4. package/.idea/window-manager.iml +12 -0
  5. package/.vscode/settings.json +1 -0
  6. package/CHANGELOG.md +43 -2
  7. package/README.md +3 -0
  8. package/dist/App/MagixEvent/index.d.ts +29 -0
  9. package/dist/App/Storage/index.d.ts +19 -6
  10. package/dist/App/Storage/typings.d.ts +1 -0
  11. package/dist/AppContext.d.ts +39 -17
  12. package/dist/AppListener.d.ts +2 -0
  13. package/dist/AppManager.d.ts +22 -8
  14. package/dist/AppProxy.d.ts +5 -5
  15. package/dist/AttributesDelegate.d.ts +2 -2
  16. package/dist/BoxManager.d.ts +6 -4
  17. package/dist/BuiltinApps.d.ts +0 -1
  18. package/dist/Cursor/Cursor.d.ts +10 -12
  19. package/dist/Cursor/index.d.ts +6 -16
  20. package/dist/Helper.d.ts +1 -0
  21. package/dist/Register/index.d.ts +5 -0
  22. package/dist/Register/storage.d.ts +5 -1
  23. package/dist/Utils/AppCreateQueue.d.ts +11 -0
  24. package/dist/Utils/Common.d.ts +4 -1
  25. package/dist/Utils/RoomHacker.d.ts +3 -3
  26. package/dist/View/MainView.d.ts +4 -3
  27. package/dist/constants.d.ts +5 -2
  28. package/dist/index.d.ts +32 -6
  29. package/dist/index.es.js +41 -1
  30. package/dist/index.es.js.map +1 -1
  31. package/dist/index.umd.js +41 -1
  32. package/dist/index.umd.js.map +1 -1
  33. package/dist/style.css +1 -1
  34. package/dist/typings.d.ts +2 -2
  35. package/docs/advanced.md +53 -0
  36. package/docs/api.md +79 -6
  37. package/docs/concept.md +9 -0
  38. package/docs/replay.md +40 -0
  39. package/package.json +8 -9
  40. package/src/App/MagixEvent/index.ts +68 -0
  41. package/src/App/Storage/index.ts +89 -43
  42. package/src/App/Storage/typings.ts +4 -2
  43. package/src/AppContext.ts +61 -24
  44. package/src/AppListener.ts +27 -8
  45. package/src/AppManager.ts +231 -70
  46. package/src/AppProxy.ts +40 -29
  47. package/src/AttributesDelegate.ts +2 -2
  48. package/src/BoxManager.ts +33 -19
  49. package/src/BuiltinApps.ts +0 -1
  50. package/src/ContainerResizeObserver.ts +3 -3
  51. package/src/Cursor/Cursor.svelte +25 -21
  52. package/src/Cursor/Cursor.ts +25 -38
  53. package/src/Cursor/icons.ts +2 -0
  54. package/src/Cursor/index.ts +45 -139
  55. package/src/Helper.ts +12 -1
  56. package/src/Register/index.ts +32 -17
  57. package/src/Register/loader.ts +28 -13
  58. package/src/Register/storage.ts +6 -1
  59. package/src/Utils/AppCreateQueue.ts +54 -0
  60. package/src/Utils/Common.ts +35 -2
  61. package/src/Utils/RoomHacker.ts +33 -18
  62. package/src/View/MainView.ts +19 -12
  63. package/src/View/ViewManager.ts +1 -2
  64. package/src/constants.ts +6 -2
  65. package/src/image/laser-pointer-cursor.svg +17 -0
  66. package/src/index.ts +150 -33
  67. package/src/shim.d.ts +2 -1
  68. package/src/style.css +6 -1
  69. package/src/typings.ts +2 -2
  70. package/vite.config.js +7 -4
  71. package/dist/Base/Context.d.ts +0 -12
  72. package/dist/Base/index.d.ts +0 -7
  73. package/src/Base/Context.ts +0 -45
  74. package/src/Base/index.ts +0 -10
package/dist/style.css CHANGED
@@ -1 +1 @@
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}
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 .1s;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-laserPointer-image{margin-left:-22px;margin-top:3px}.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;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{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;touch-action:manipulation}.telebox-title-area{overflow:hidden;position:relative;height:100%;flex:1;display:flex;align-items:center}.telebox-title{overflow:hidden;margin: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-drag-area{position:absolute;top:0;left:0;right:0;bottom:0;margin:auto;z-index:10}.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 .telebox-drag-area{height:100%;min-width:16px;position:static;margin:0;flex-grow:1;flex-shrink:0}.telebox-max-titlebar-maximized{display:flex}.telebox-titles{height:100%;margin:0;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{height:100%;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;user-select:none}.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
  /**
@@ -0,0 +1,53 @@
1
+ ## 进阶使用
2
+
3
+ - 目录
4
+ - [撤销重做](#redo-undo)
5
+ - [清屏](#clean-current-scene)
6
+
7
+
8
+ <h3 id="redo-undo">撤销重做</h3>
9
+
10
+ > 以下事件和属性都会根据 `focus` 的窗口来进行自动切换应用对象
11
+
12
+ #### 获取可以撤销/重做的步数
13
+
14
+ ```ts
15
+ manager.canUndoSteps
16
+ manager.canRedoSteps
17
+ ```
18
+
19
+ #### 监听可以撤销/重做的步数的变化
20
+
21
+ `canRedoStepsChange` 和 `canUndoStepsChange` 会在切换窗口时重新触发
22
+
23
+ ```ts
24
+ manager.emitter.on("canUndoStepsChange", (steps: number) => {
25
+ // 可以撤销的步数更新
26
+ })
27
+ manager.emitter.on("canRedoStepsChange", (steps: number) => {
28
+ // 可以重做的步数更新
29
+ })
30
+ ```
31
+
32
+ #### 撤销/重做
33
+
34
+ ```ts
35
+ manager.undo() //撤销
36
+ manager.redo() // 重做
37
+ ```
38
+
39
+ <br>
40
+
41
+ <h3 id="clean-current-scene">清屏</h3>
42
+
43
+ 因为在多窗口模式下有多个白板, 如果想要清除当前 `focus` 的白板只需要调用
44
+
45
+ ```ts
46
+ manager.cleanCurrentScene()
47
+ ```
48
+
49
+ 只想清理主白板的笔迹则需要
50
+
51
+ ```ts
52
+ manager.mainView.cleanCurrentScene()
53
+ ```
package/docs/api.md CHANGED
@@ -9,9 +9,16 @@
9
9
  - [实例方法](#instance-methods)
10
10
  - [`addApp`](#addApp)
11
11
  - [`closeApp`](#closeApp)
12
+ - [`setMainViewSceneIndex`](#setMainViewSceneIndex)
13
+ - [`setBoxState`](#setBoxState)
14
+ - [`cleanCurrentScene`](#cleanCurrentScene)
15
+ - [`redo`](#redo)
16
+ - [`undo`](#undo)
12
17
  - [实例属性](#prototypes)
13
18
  - [事件回调](#events)
14
19
 
20
+ <br>
21
+
15
22
  <h2 id="static-methods">静态方法</h2>
16
23
 
17
24
  <h3 id="mount">WindowManager.mount</h3>
@@ -42,6 +49,7 @@ const manager = await WindowManager.mount(
42
49
  | prefersColorScheme | [optional] string | light | auto, light, dark |
43
50
  | debug | [optional] boolean | false | 打印日志信息
44
51
 
52
+
45
53
  <h3 id="register">WindowManager.register</h3>
46
54
 
47
55
  > 注册 `APP` 到 `WindowManager`
@@ -81,6 +89,8 @@ WindowManager.setContainer(document.getElementById("container"));
81
89
  WindowManager.setCollectorContainer(document.getElementById("collector-container"));
82
90
  ```
83
91
 
92
+ <br>
93
+
84
94
  <h2 id="instance-methods">实例方法</h2>
85
95
 
86
96
  <h3 id="addApp">addApp</h3>
@@ -105,15 +115,63 @@ const appId = await manager.addApp({
105
115
  manager.closeApp(appId)
106
116
  ```
107
117
 
118
+ <h3 id="setMainViewSceneIndex">setMainViewSceneIndex</h3>
119
+
120
+ > 设置主白板的 `SceneIndex`
121
+
122
+ ```ts
123
+ manager.setMainViewSceneIndex(1)
124
+ ```
125
+
126
+ <h3 id="setBoxState">setBoxState</h3>
127
+
128
+ > 设置当前的 `boxState`
129
+
130
+ ```ts
131
+ manager.setBoxState("normal") // boxState: normal | maximized | minimized
132
+ ```
133
+
134
+ <h3 id="cleanCurrentScene">cleanCurrentScene</h3>
135
+
136
+ > 清除当前 focus 的 view 的笔迹
137
+
138
+ ```ts
139
+ manager.cleanCurrentScene()
140
+ ```
141
+
142
+ <h3 id="redo">redo</h3>
143
+
144
+ > 在当前 focus 的 view 上重做上一步操作
145
+
146
+ ```ts
147
+ manager.redo()
148
+ ```
149
+
150
+ <h3 id="undo">undo</h3>
151
+
152
+ > 在当前 focus 的 view 上撤消上一步操作
153
+
154
+ ```ts
155
+ manager.undo()
156
+ ```
157
+
158
+ <br>
159
+
108
160
  <h2 id="prototypes">实例属性</h2>
109
161
 
110
- | name | type | default | desc |
111
- | ------------------ | ------- | ------- | ------ |
112
- | mainView | View | | 主白板 |
113
- | boxState | string | | 当前窗口状态 |
114
- | darkMode | boolean | | 黑夜模式 |
115
- | prefersColorScheme | string | | 颜色主题 |
162
+ | name | type | default | desc |
163
+ | ------------------ | ------- | ------- | ----------------- |
164
+ | mainView | View | | 主白板 |
165
+ | mainViewSceneIndex | number | | 当前主白板的 SceneIndex |
166
+ | mainViewScenesLength | number | | mainView 的 scenes 长度 |
167
+ | boxState | string | | 当前窗口状态 |
168
+ | darkMode | boolean | | 黑夜模式 |
169
+ | prefersColorScheme | string | | 颜色主题 |
170
+ | focused | string | | focus 的 app |
171
+ | canRedoSteps | number | | 当前 focus 的 view 可以重做的步数 |
172
+ | canRedoSteps | number | | 当前 focus 的 view 可以撤销的步数 |
116
173
 
174
+ <br>
117
175
 
118
176
  <h2 id="events">事件回调</h2>
119
177
 
@@ -124,7 +182,22 @@ manager.callbacks.on(events, listener)
124
182
  | name | type | default | desc |
125
183
  | ------------------------ | -------------- | ------- | -------------------------- |
126
184
  | mainViewModeChange | ViewVisionMode | | |
185
+ | mainViewSceneIndexChange | index: number | | |
127
186
  | boxStateChange | string | | normal,minimized,maximized |
128
187
  | darkModeChange | boolean | | |
129
188
  | prefersColorSchemeChange | string | | auto,light,dark |
130
189
  | cameraStateChange | CameraState | | |
190
+ | focusedChange | string, undefined | | 当前 focus 的 appId,主白板时为 undefined |
191
+ | mainViewScenesLengthChange | number | | mainView scenes 添加或删除时触发 |
192
+ | canRedoStepsChange | number | | 当前 focus 的 view 可重做步数改变 |
193
+ | canUndoStepsChange | number | | 当前 focus 的 view 可撤销步数改变 |
194
+ | loadApp | LoadAppEvent | | 加载远程APP 事件 |
195
+
196
+
197
+ ```ts
198
+ type LoadAppEvent = {
199
+ kind: string;
200
+ status: "start" | "success" | "failed";
201
+ reason?: string;
202
+ }
203
+ ```
@@ -0,0 +1,9 @@
1
+ # 概念
2
+
3
+ ## 同步区域
4
+
5
+ 在不同分辨率的设备上,想要看到相同的区域和窗口,我们就需要在所有设备保持一个相同的比例。
6
+
7
+ 所以 `WindowManager` 有一个 `containerSizeRatio` 的选项来配置白板的宽高比,默认为 `9 / 16`
8
+
9
+ 如果外层给到 `WindowManager` 宽高并不是完美适配这个宽高比的话, `WindowManger` 会自动在内部算出一个适配这个比例的最大宽高,然后填充上去,这时在内部就会有一些区域不能操作
package/docs/replay.md ADDED
@@ -0,0 +1,40 @@
1
+ ## 回放
2
+
3
+ > 注意: 多窗口的回放只支持从创建房间开始就是多窗口的房间
4
+
5
+ > 如果是一开始作为单窗口模式使用,又转变成多窗口模式使用, 则会造成回放渲染空白
6
+
7
+ <br>
8
+
9
+
10
+ ```typescript
11
+ import { WhiteWebSdk } from "white-web-sdk";
12
+ import { WindowManager, BuiltinApps } from "@netless/window-manager";
13
+ import "@netless/window-manager/dist/style.css";
14
+
15
+ const sdk = new WhiteWebSdk({
16
+ appIdentifier: "appIdentifier",
17
+ useMobXState: true // 请确保打开这个选项
18
+ });
19
+
20
+ let manager: WindowManager;
21
+
22
+ sdk.replayRoom({
23
+ uuid: "room uuid",
24
+ roomToken: "room token",
25
+ invisiblePlugins: [WindowManager],
26
+ useMultiViews: true, // 多窗口必须用开启 useMultiViews
27
+ }).then(player => {
28
+ player.callbacks.on("onPhaseChanged", async (phase) => {
29
+ if (phase === PlayerPhase.Playing) {
30
+ if (manager) return;
31
+ manager = await WindowManager.mount({
32
+ room: player,
33
+ container: document.getElementById("container")
34
+ });
35
+ }
36
+ })
37
+ });
38
+
39
+ player.play(); // WindowManager 只有在播放之后才能挂载
40
+ ```
package/package.json CHANGED
@@ -1,10 +1,11 @@
1
1
  {
2
2
  "name": "@netless/window-manager",
3
- "version": "0.4.0-canary.9",
3
+ "version": "0.4.2",
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",
@@ -17,22 +18,21 @@
17
18
  "author": "",
18
19
  "license": "ISC",
19
20
  "peerDependencies": {
20
- "video.js": ">=7",
21
- "white-web-sdk": "^2.13.16"
21
+ "white-web-sdk": "^2.16.0"
22
22
  },
23
23
  "dependencies": {
24
24
  "@juggle/resize-observer": "^3.3.1",
25
- "@netless/app-docs-viewer": "0.2.0",
26
- "@netless/app-media-player": "0.1.0-beta.5",
27
- "@netless/telebox-insider": "0.2.18",
28
25
  "emittery": "^0.9.2",
29
26
  "lodash": "^4.17.21",
30
27
  "p-retry": "^4.6.1",
31
28
  "side-effect-manager": "^0.1.5",
32
29
  "uuid": "^7.0.3",
33
- "video.js": ">=7"
30
+ "video.js": ">=7",
31
+ "@netless/telebox-insider": "0.2.22"
34
32
  },
35
33
  "devDependencies": {
34
+ "@netless/app-docs-viewer": "^0.2.6",
35
+ "@netless/app-media-player": "0.1.0-beta.5",
36
36
  "@rollup/plugin-commonjs": "^20.0.0",
37
37
  "@rollup/plugin-node-resolve": "^13.0.4",
38
38
  "@rollup/plugin-url": "^6.1.0",
@@ -55,8 +55,7 @@
55
55
  "rollup-plugin-styles": "^3.14.1",
56
56
  "svelte": "^3.42.4",
57
57
  "typescript": "^4.3.5",
58
- "video.js": "^7.14.3",
59
58
  "vite": "^2.5.3",
60
- "white-web-sdk": "^2.16.0"
59
+ "white-web-sdk": "2.16.3"
61
60
  }
62
61
  }
@@ -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;
@@ -1,20 +1,20 @@
1
1
  import type { AkkoObjectUpdatedProperty } from "white-web-sdk";
2
- import { get, has, isObject } from "lodash";
2
+ import { get, has, mapValues, isObject, size, noop } from "lodash";
3
3
  import { SideEffectManager } from "side-effect-manager";
4
4
  import type { AppContext } from "../../AppContext";
5
5
  import { safeListenPropsUpdated } from "../../Utils/Reactive";
6
6
  import { isRef, makeRef, plainObjectKeys } from "./utils";
7
- import type { Diff, MaybeRefValue, RefValue, StorageStateChangedEvent } from "./typings";
7
+ import type { Diff, MaybeRefValue, RefValue, StorageStateChangedEvent, StorageStateChangedListener, StorageStateChangedListenerDisposer } from "./typings";
8
8
  import { StorageEvent } from "./StorageEvent";
9
9
 
10
10
  export * from './typings';
11
11
 
12
- const STORAGE_NS = "_WM-STORAGE_";
12
+ export const STORAGE_NS = "_WM-STORAGE_";
13
13
 
14
- export class Storage<TState = any> implements Storage<TState> {
15
- readonly id: string;
14
+ export class Storage<TState extends Record<string, any> = any> implements Storage<TState> {
15
+ readonly id: string | null;
16
16
 
17
- private readonly _context: AppContext<{ [STORAGE_NS]: TState }>;
17
+ private readonly _context: AppContext;
18
18
  private readonly _sideEffect = new SideEffectManager();
19
19
  private _state: TState;
20
20
  private _destroyed = false;
@@ -26,54 +26,52 @@ export class Storage<TState = any> implements Storage<TState> {
26
26
  */
27
27
  private _lastValue = new Map<string | number | symbol, TState[Extract<keyof TState, string>]>();
28
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
-
29
+ constructor(context: AppContext, id?: string, defaultState?: TState) {
34
30
  if (defaultState && !isObject(defaultState)) {
35
31
  throw new Error(`Default state for Storage ${id} is not an object.`);
36
32
  }
37
33
 
38
34
  this._context = context;
39
- this.id = id;
35
+ this.id = id || null;
40
36
 
41
- const attrs = context.getAttributes();
42
37
  this._state = {} as TState;
43
- const rawState = get<TState>(attrs, [STORAGE_NS, id], this._state);
38
+ const rawState = this._getRawState(this._state);
44
39
 
45
- if (this._context.getIsWritable()) {
46
- if (!isObject(rawState) || rawState === this._state) {
47
- if (!attrs[STORAGE_NS]) {
40
+ if (this.id !== null && this._context.getIsWritable()) {
41
+ if (rawState === this._state || !isObject(rawState)) {
42
+ if (!get(this._context.getAttributes(), [STORAGE_NS])) {
48
43
  this._context.updateAttributes([STORAGE_NS], {});
49
44
  }
50
45
  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
- });
46
+ }
47
+ if (defaultState) {
48
+ this.setState(defaultState);
71
49
  }
72
50
  }
73
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
+
74
72
  this._sideEffect.addDisposer(
75
73
  safeListenPropsUpdated(
76
- () => get(context.getAttributes(), [STORAGE_NS, this.id]),
74
+ () => this.id === null ? context.getAttributes() : get(context.getAttributes(), [STORAGE_NS, this.id]),
77
75
  this._updateProperties.bind(this),
78
76
  this.destroy.bind(this)
79
77
  )
@@ -88,6 +86,11 @@ export class Storage<TState = any> implements Storage<TState> {
88
86
  }
89
87
 
90
88
  readonly onStateChanged = new StorageEvent<StorageStateChangedEvent<TState>>();
89
+
90
+ addStateChangedListener(handler: StorageStateChangedListener<TState>): StorageStateChangedListenerDisposer {
91
+ this.onStateChanged.addListener(handler);
92
+ return () => this.onStateChanged.removeListener(handler);
93
+ }
91
94
 
92
95
  ensureState(state: Partial<TState>): void {
93
96
  return this.setState(
@@ -122,7 +125,7 @@ export class Storage<TState = any> implements Storage<TState> {
122
125
  if (value === void 0) {
123
126
  this._lastValue.set(key, this._state[key]);
124
127
  delete this._state[key];
125
- this._context.updateAttributes([STORAGE_NS, this.id, key], value);
128
+ this._setRawState(key, value);
126
129
  } else {
127
130
  this._lastValue.set(key, this._state[key]);
128
131
  this._state[key] = value as TState[Extract<keyof TState, string>];
@@ -137,13 +140,20 @@ export class Storage<TState = any> implements Storage<TState> {
137
140
  payload = refValue;
138
141
  }
139
142
 
140
- this._context.updateAttributes([STORAGE_NS, this.id, key], payload);
143
+ this._setRawState(key, payload)
141
144
  }
142
145
  });
143
146
  }
144
147
  }
145
148
 
146
- emptyStore(): void {
149
+ /**
150
+ * Empty storage data.
151
+ */
152
+ emptyStorage(): void {
153
+ if (size(this._state) <= 0) {
154
+ return;
155
+ }
156
+
147
157
  if (this._destroyed) {
148
158
  console.error(new Error(`Cannot empty destroyed Storage "${this.id}".`));
149
159
  return;
@@ -154,10 +164,17 @@ export class Storage<TState = any> implements Storage<TState> {
154
164
  return;
155
165
  }
156
166
 
157
- this._context.updateAttributes([STORAGE_NS, this.id], {});
167
+ this.setState(mapValues(this._state, noop as () => undefined));
158
168
  }
159
169
 
160
- deleteStore(): void {
170
+ /**
171
+ * Delete storage index with all of its data and destroy the Storage instance.
172
+ */
173
+ deleteStorage(): void {
174
+ if (this.id === null) {
175
+ throw new Error(`Cannot delete main Storage`);
176
+ }
177
+
161
178
  if (!this._context.getIsWritable()) {
162
179
  console.error(new Error(`Cannot delete Storage "${this.id}" without writable access.`));
163
180
  return;
@@ -172,11 +189,35 @@ export class Storage<TState = any> implements Storage<TState> {
172
189
  return this._destroyed;
173
190
  }
174
191
 
192
+ /**
193
+ * Destroy the Storage instance. The data will be kept.
194
+ */
175
195
  destroy() {
176
196
  this._destroyed = true;
177
197
  this._sideEffect.flushAll();
178
198
  }
179
199
 
200
+ private _getRawState(): TState | undefined
201
+ private _getRawState(defaultValue: TState): TState
202
+ private _getRawState(defaultValue?: TState): TState | undefined {
203
+ if (this.id === null) {
204
+ return this._context.getAttributes() ?? defaultValue;
205
+ } else {
206
+ return get(this._context.getAttributes(), [STORAGE_NS, this.id], defaultValue);
207
+ }
208
+ }
209
+
210
+ private _setRawState(key: string, value: any): void {
211
+ if (this.id === null) {
212
+ if (key === STORAGE_NS) {
213
+ throw new Error(`Cannot set attribute internal filed "${STORAGE_NS}"`)
214
+ }
215
+ return this._context.updateAttributes([key], value);
216
+ } else {
217
+ return this._context.updateAttributes([STORAGE_NS, this.id, key], value);
218
+ }
219
+ }
220
+
180
221
  private _updateProperties(actions: ReadonlyArray<AkkoObjectUpdatedProperty<TState, string>>): void {
181
222
  if (this._destroyed) {
182
223
  console.error(new Error(`Cannot call _updateProperties on destroyed Storage "${this.id}".`));
@@ -190,6 +231,11 @@ export class Storage<TState = any> implements Storage<TState> {
190
231
  try {
191
232
  const action = actions[i]
192
233
  const key = action.key as Extract<keyof TState, string>;
234
+
235
+ if (this.id === null && key === STORAGE_NS) {
236
+ continue
237
+ }
238
+
193
239
  const value = isObject(action.value) ? JSON.parse(JSON.stringify(action.value)) : action.value;
194
240
  let oldValue: TState[Extract<keyof TState, string>] | undefined;
195
241
  if (this._lastValue.has(key)) {
@@ -16,6 +16,8 @@ export type StorageOnSetStatePayload<TState = unknown> = {
16
16
  [K in keyof TState]?: MaybeRefValue<TState[K]>;
17
17
  };
18
18
 
19
- export type StorageStateChangedEvent<TState = any> = Diff<TState>
19
+ export type StorageStateChangedEvent<TState = any> = Diff<TState>;
20
20
 
21
- export type StorageStateChangedListener<TState = any> = StorageEventListener<StorageStateChangedEvent<TState>>
21
+ export type StorageStateChangedListener<TState = any> = StorageEventListener<StorageStateChangedEvent<TState>>;
22
+
23
+ export type StorageStateChangedListenerDisposer = () => void;