@netless/fastboard-react 0.1.0

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 (163) hide show
  1. package/LICENSE.txt +21 -0
  2. package/dist/behaviors/style.d.ts +1 -0
  3. package/dist/components/Fastboard.d.ts +15 -0
  4. package/dist/components/PageControl/PageControl.d.ts +5 -0
  5. package/dist/components/PageControl/hooks.d.ts +9 -0
  6. package/dist/components/PageControl/index.d.ts +2 -0
  7. package/dist/components/PlayerControl/PlayerControl.d.ts +9 -0
  8. package/dist/components/PlayerControl/hooks.d.ts +11 -0
  9. package/dist/components/PlayerControl/icons/Loading.d.ts +3 -0
  10. package/dist/components/PlayerControl/icons/Pause.d.ts +3 -0
  11. package/dist/components/PlayerControl/icons/Play.d.ts +3 -0
  12. package/dist/components/PlayerControl/icons/index.d.ts +6 -0
  13. package/dist/components/PlayerControl/index.d.ts +2 -0
  14. package/dist/components/RedoUndo/RedoUndo.d.ts +5 -0
  15. package/dist/components/RedoUndo/hooks.d.ts +6 -0
  16. package/dist/components/RedoUndo/index.d.ts +2 -0
  17. package/dist/components/Toolbar/Content.d.ts +2 -0
  18. package/dist/components/Toolbar/Toolbar.d.ts +14 -0
  19. package/dist/components/Toolbar/components/ApplianceButtons.d.ts +7 -0
  20. package/dist/components/Toolbar/components/AppsButton.d.ts +6 -0
  21. package/dist/components/Toolbar/components/ColorBox.d.ts +2 -0
  22. package/dist/components/Toolbar/components/CutLine.d.ts +2 -0
  23. package/dist/components/Toolbar/components/Mask.d.ts +7 -0
  24. package/dist/components/Toolbar/components/PencilButton.d.ts +2 -0
  25. package/dist/components/Toolbar/components/ShapesButton.d.ts +3 -0
  26. package/dist/components/Toolbar/components/Slider.d.ts +2 -0
  27. package/dist/components/Toolbar/components/TextButton.d.ts +2 -0
  28. package/dist/components/Toolbar/components/UpDownButtons.d.ts +7 -0
  29. package/dist/components/Toolbar/const.d.ts +18 -0
  30. package/dist/components/Toolbar/hooks.d.ts +12 -0
  31. package/dist/components/Toolbar/icons/Apps.d.ts +3 -0
  32. package/dist/components/Toolbar/icons/Arrow.d.ts +3 -0
  33. package/dist/components/Toolbar/icons/Circle.d.ts +3 -0
  34. package/dist/components/Toolbar/icons/Clean.d.ts +3 -0
  35. package/dist/components/Toolbar/icons/Clicker.d.ts +3 -0
  36. package/dist/components/Toolbar/icons/Collapse.d.ts +3 -0
  37. package/dist/components/Toolbar/icons/Diamond.d.ts +3 -0
  38. package/dist/components/Toolbar/icons/Down.d.ts +3 -0
  39. package/dist/components/Toolbar/icons/Eraser.d.ts +3 -0
  40. package/dist/components/Toolbar/icons/Expand.d.ts +3 -0
  41. package/dist/components/Toolbar/icons/Line.d.ts +3 -0
  42. package/dist/components/Toolbar/icons/Pencil.d.ts +3 -0
  43. package/dist/components/Toolbar/icons/Rectangle.d.ts +3 -0
  44. package/dist/components/Toolbar/icons/Selector.d.ts +3 -0
  45. package/dist/components/Toolbar/icons/SpeechBalloon.d.ts +3 -0
  46. package/dist/components/Toolbar/icons/Star.d.ts +3 -0
  47. package/dist/components/Toolbar/icons/Text.d.ts +3 -0
  48. package/dist/components/Toolbar/icons/Triangle.d.ts +3 -0
  49. package/dist/components/Toolbar/icons/Up.d.ts +3 -0
  50. package/dist/components/Toolbar/icons/index.d.ts +22 -0
  51. package/dist/components/Toolbar/index.d.ts +2 -0
  52. package/dist/components/ZoomControl/ZoomControl.d.ts +5 -0
  53. package/dist/components/ZoomControl/hooks.d.ts +7 -0
  54. package/dist/components/ZoomControl/index.d.ts +2 -0
  55. package/dist/components/hooks.d.ts +13 -0
  56. package/dist/i18n/index.d.ts +12 -0
  57. package/dist/icons/ChevronLeft.d.ts +3 -0
  58. package/dist/icons/ChevronRight.d.ts +3 -0
  59. package/dist/icons/FilePlus.d.ts +3 -0
  60. package/dist/icons/Minus.d.ts +3 -0
  61. package/dist/icons/Plus.d.ts +3 -0
  62. package/dist/icons/Redo.d.ts +3 -0
  63. package/dist/icons/Reset.d.ts +3 -0
  64. package/dist/icons/Undo.d.ts +3 -0
  65. package/dist/icons/index.d.ts +7 -0
  66. package/dist/index.d.ts +9 -0
  67. package/dist/index.js +2116 -0
  68. package/dist/index.js.map +1 -0
  69. package/dist/index.mjs +2083 -0
  70. package/dist/index.mjs.map +1 -0
  71. package/dist/internal/helpers.d.ts +16 -0
  72. package/dist/internal/hooks.d.ts +3 -0
  73. package/dist/internal/index.d.ts +2 -0
  74. package/dist/theme.d.ts +16 -0
  75. package/dist/typings.d.ts +10 -0
  76. package/package.json +41 -0
  77. package/src/behaviors/style.ts +4 -0
  78. package/src/components/Fastboard.scss +41 -0
  79. package/src/components/Fastboard.tsx +97 -0
  80. package/src/components/PageControl/PageControl.scss +80 -0
  81. package/src/components/PageControl/PageControl.tsx +105 -0
  82. package/src/components/PageControl/hooks.ts +67 -0
  83. package/src/components/PageControl/index.ts +2 -0
  84. package/src/components/PlayerControl/PlayerControl.scss +145 -0
  85. package/src/components/PlayerControl/PlayerControl.tsx +131 -0
  86. package/src/components/PlayerControl/components/Button.tsx +45 -0
  87. package/src/components/PlayerControl/hooks.ts +88 -0
  88. package/src/components/PlayerControl/icons/Loading.tsx +13 -0
  89. package/src/components/PlayerControl/icons/Pause.tsx +13 -0
  90. package/src/components/PlayerControl/icons/Play.tsx +13 -0
  91. package/src/components/PlayerControl/icons/index.ts +10 -0
  92. package/src/components/PlayerControl/index.ts +2 -0
  93. package/src/components/RedoUndo/RedoUndo.scss +56 -0
  94. package/src/components/RedoUndo/RedoUndo.tsx +76 -0
  95. package/src/components/RedoUndo/hooks.ts +18 -0
  96. package/src/components/RedoUndo/index.ts +2 -0
  97. package/src/components/Toolbar/Content.tsx +74 -0
  98. package/src/components/Toolbar/Toolbar.scss +281 -0
  99. package/src/components/Toolbar/Toolbar.tsx +116 -0
  100. package/src/components/Toolbar/components/ApplianceButtons.tsx +108 -0
  101. package/src/components/Toolbar/components/AppsButton.tsx +101 -0
  102. package/src/components/Toolbar/components/Button.tsx +46 -0
  103. package/src/components/Toolbar/components/ColorBox.tsx +55 -0
  104. package/src/components/Toolbar/components/CutLine.tsx +8 -0
  105. package/src/components/Toolbar/components/Mask.tsx +44 -0
  106. package/src/components/Toolbar/components/PencilButton.tsx +66 -0
  107. package/src/components/Toolbar/components/ShapesButton.tsx +128 -0
  108. package/src/components/Toolbar/components/Slider.tsx +26 -0
  109. package/src/components/Toolbar/components/TextButton.tsx +62 -0
  110. package/src/components/Toolbar/components/UpDownButtons.tsx +49 -0
  111. package/src/components/Toolbar/components/assets/cocos.png +0 -0
  112. package/src/components/Toolbar/components/assets/collapsed.png +0 -0
  113. package/src/components/Toolbar/components/assets/countdown.png +0 -0
  114. package/src/components/Toolbar/components/assets/expanded.png +0 -0
  115. package/src/components/Toolbar/components/assets/geogebra.png +0 -0
  116. package/src/components/Toolbar/components/assets/vscode.png +0 -0
  117. package/src/components/Toolbar/const.ts +32 -0
  118. package/src/components/Toolbar/hooks.ts +68 -0
  119. package/src/components/Toolbar/icons/Apps.tsx +16 -0
  120. package/src/components/Toolbar/icons/Arrow.tsx +13 -0
  121. package/src/components/Toolbar/icons/Circle.tsx +13 -0
  122. package/src/components/Toolbar/icons/Clean.tsx +16 -0
  123. package/src/components/Toolbar/icons/Clicker.tsx +19 -0
  124. package/src/components/Toolbar/icons/Collapse.tsx +13 -0
  125. package/src/components/Toolbar/icons/Diamond.tsx +13 -0
  126. package/src/components/Toolbar/icons/Down.tsx +13 -0
  127. package/src/components/Toolbar/icons/Eraser.tsx +16 -0
  128. package/src/components/Toolbar/icons/Expand.tsx +13 -0
  129. package/src/components/Toolbar/icons/Line.tsx +13 -0
  130. package/src/components/Toolbar/icons/Pencil.tsx +16 -0
  131. package/src/components/Toolbar/icons/Rectangle.tsx +13 -0
  132. package/src/components/Toolbar/icons/Selector.tsx +13 -0
  133. package/src/components/Toolbar/icons/SpeechBalloon.tsx +17 -0
  134. package/src/components/Toolbar/icons/Star.tsx +17 -0
  135. package/src/components/Toolbar/icons/Text.tsx +13 -0
  136. package/src/components/Toolbar/icons/Triangle.tsx +13 -0
  137. package/src/components/Toolbar/icons/Up.tsx +13 -0
  138. package/src/components/Toolbar/icons/index.ts +42 -0
  139. package/src/components/Toolbar/index.ts +2 -0
  140. package/src/components/ZoomControl/ZoomControl.scss +80 -0
  141. package/src/components/ZoomControl/ZoomControl.tsx +94 -0
  142. package/src/components/ZoomControl/hooks.ts +52 -0
  143. package/src/components/ZoomControl/index.ts +2 -0
  144. package/src/components/hooks.ts +59 -0
  145. package/src/i18n/en.json +31 -0
  146. package/src/i18n/index.ts +29 -0
  147. package/src/i18n/zh-CN.json +32 -0
  148. package/src/icons/ChevronLeft.tsx +21 -0
  149. package/src/icons/ChevronRight.tsx +21 -0
  150. package/src/icons/FilePlus.tsx +18 -0
  151. package/src/icons/Minus.tsx +15 -0
  152. package/src/icons/Plus.tsx +15 -0
  153. package/src/icons/Redo.tsx +18 -0
  154. package/src/icons/Reset.tsx +19 -0
  155. package/src/icons/Undo.tsx +18 -0
  156. package/src/icons/index.tsx +11 -0
  157. package/src/index.ts +10 -0
  158. package/src/internal/helpers.ts +31 -0
  159. package/src/internal/hooks.ts +23 -0
  160. package/src/internal/index.ts +2 -0
  161. package/src/style.scss +29 -0
  162. package/src/theme.ts +36 -0
  163. package/src/typings.ts +15 -0
package/dist/index.mjs ADDED
@@ -0,0 +1,2083 @@
1
+ var __defProp = Object.defineProperty;
2
+ var __defProps = Object.defineProperties;
3
+ var __getOwnPropDescs = Object.getOwnPropertyDescriptors;
4
+ var __getOwnPropSymbols = Object.getOwnPropertySymbols;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __propIsEnum = Object.prototype.propertyIsEnumerable;
7
+ var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
8
+ var __spreadValues = (a, b) => {
9
+ for (var prop in b || (b = {}))
10
+ if (__hasOwnProp.call(b, prop))
11
+ __defNormalProp(a, prop, b[prop]);
12
+ if (__getOwnPropSymbols)
13
+ for (var prop of __getOwnPropSymbols(b)) {
14
+ if (__propIsEnum.call(b, prop))
15
+ __defNormalProp(a, prop, b[prop]);
16
+ }
17
+ return a;
18
+ };
19
+ var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b));
20
+ var __objRest = (source, exclude) => {
21
+ var target = {};
22
+ for (var prop in source)
23
+ if (__hasOwnProp.call(source, prop) && exclude.indexOf(prop) < 0)
24
+ target[prop] = source[prop];
25
+ if (source != null && __getOwnPropSymbols)
26
+ for (var prop of __getOwnPropSymbols(source)) {
27
+ if (exclude.indexOf(prop) < 0 && __propIsEnum.call(source, prop))
28
+ target[prop] = source[prop];
29
+ }
30
+ return target;
31
+ };
32
+
33
+ // src/internal/helpers.ts
34
+ function noop() {
35
+ return;
36
+ }
37
+ function applyStyles(css) {
38
+ const el = document.createElement("style");
39
+ el.appendChild(document.createTextNode(css));
40
+ document.head.appendChild(el);
41
+ return el;
42
+ }
43
+ function clamp(value, min, max) {
44
+ return value < min ? min : value > max ? max : value;
45
+ }
46
+ function isEqualArray(a, b) {
47
+ return a.length === b.length && a.every((e, i) => e === b[i]);
48
+ }
49
+ var defaultHotKeys = {
50
+ changeToSelector: "s",
51
+ changeToLaserPointer: "z",
52
+ changeToPencil: "p",
53
+ changeToRectangle: "r",
54
+ changeToEllipse: "c",
55
+ changeToEraser: "e",
56
+ changeToText: "t",
57
+ changeToStraight: "l",
58
+ changeToArrow: "a",
59
+ changeToHand: "h"
60
+ };
61
+
62
+ // src/internal/hooks.ts
63
+ import { useCallback, useEffect, useRef, useState } from "react";
64
+ function useLastValue(value) {
65
+ const ref = useRef(value);
66
+ useEffect(() => {
67
+ ref.current = value;
68
+ }, [value]);
69
+ return ref.current;
70
+ }
71
+ function useAsyncValue(fn) {
72
+ const [value, setValue] = useState(null);
73
+ useEffect(() => {
74
+ fn().then(setValue);
75
+ }, []);
76
+ return value;
77
+ }
78
+ function useForceUpdate() {
79
+ const [, forceUpdate] = useState({});
80
+ return useCallback(() => forceUpdate({}), []);
81
+ }
82
+
83
+ // src/style.scss?inline
84
+ var style_default = '.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,.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;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;inset: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}.tippy-box[data-animation=fade][data-state=hidden]{opacity:0}[data-tippy-root]{max-width:calc(100vw - 10px)}.tippy-box{position:relative;background-color:#333;color:#fff;border-radius:4px;font-size:14px;line-height:1.4;white-space:normal;outline:0;transition-property:transform,visibility,opacity}.tippy-box[data-placement^=top]>.tippy-arrow{bottom:0}.tippy-box[data-placement^=top]>.tippy-arrow:before{bottom:-7px;left:0;border-width:8px 8px 0;border-top-color:initial;transform-origin:center top}.tippy-box[data-placement^=bottom]>.tippy-arrow{top:0}.tippy-box[data-placement^=bottom]>.tippy-arrow:before{top:-7px;left:0;border-width:0 8px 8px;border-bottom-color:initial;transform-origin:center bottom}.tippy-box[data-placement^=left]>.tippy-arrow{right:0}.tippy-box[data-placement^=left]>.tippy-arrow:before{border-width:8px 0 8px 8px;border-left-color:initial;right:-7px;transform-origin:center left}.tippy-box[data-placement^=right]>.tippy-arrow{left:0}.tippy-box[data-placement^=right]>.tippy-arrow:before{left:-7px;border-width:8px 8px 8px 0;border-right-color:initial;transform-origin:center right}.tippy-box[data-inertia][data-state=visible]{transition-timing-function:cubic-bezier(.54,1.5,.38,1.11)}.tippy-arrow{width:16px;height:16px;color:#333}.tippy-arrow:before{content:"";position:absolute;border-color:transparent;border-style:solid}.tippy-content{position:relative;padding:5px 9px;z-index:1}.tippy-box[data-theme~=light]{color:#26323d;box-shadow:0 0 20px 4px #9aa1b126,0 4px 80px -8px #24282f40,0 4px 4px -2px #5b5e6926;background-color:#fff}.tippy-box[data-theme~=light][data-placement^=top]>.tippy-arrow:before{border-top-color:#fff}.tippy-box[data-theme~=light][data-placement^=bottom]>.tippy-arrow:before{border-bottom-color:#fff}.tippy-box[data-theme~=light][data-placement^=left]>.tippy-arrow:before{border-left-color:#fff}.tippy-box[data-theme~=light][data-placement^=right]>.tippy-arrow:before{border-right-color:#fff}.tippy-box[data-theme~=light]>.tippy-backdrop{background-color:#fff}.tippy-box[data-theme~=light]>.tippy-svg-arrow{fill:#fff}.rc-slider{position:relative;height:14px;padding:5px 0;width:100%;border-radius:6px;touch-action:none;box-sizing:border-box;-webkit-tap-highlight-color:rgba(0,0,0,0)}.rc-slider *{box-sizing:border-box;-webkit-tap-highlight-color:rgba(0,0,0,0)}.rc-slider-rail{position:absolute;width:100%;background-color:#e9e9e9;height:4px;border-radius:6px}.rc-slider-track{position:absolute;left:0;height:4px;border-radius:6px;background-color:#abe2fb}.rc-slider-handle{position:absolute;width:14px;height:14px;cursor:pointer;cursor:-webkit-grab;margin-top:-5px;cursor:grab;border-radius:50%;border:solid 2px #96dbfa;background-color:#fff;touch-action:pan-x}.rc-slider-handle-dragging.rc-slider-handle-dragging.rc-slider-handle-dragging{border-color:#57c5f7;box-shadow:0 0 0 5px #96dbfa}.rc-slider-handle:focus{outline:none}.rc-slider-handle-click-focused:focus{border-color:#96dbfa;box-shadow:unset}.rc-slider-handle:hover{border-color:#57c5f7}.rc-slider-handle:active{border-color:#57c5f7;box-shadow:0 0 5px #57c5f7;cursor:-webkit-grabbing;cursor:grabbing}.rc-slider-mark{position:absolute;top:18px;left:0;width:100%;font-size:12px}.rc-slider-mark-text{position:absolute;display:inline-block;vertical-align:middle;text-align:center;cursor:pointer;color:#999}.rc-slider-mark-text-active{color:#666}.rc-slider-step{position:absolute;width:100%;height:4px;background:transparent}.rc-slider-dot{position:absolute;bottom:-2px;margin-left:-4px;width:8px;height:8px;border:2px solid #e9e9e9;background-color:#fff;cursor:pointer;border-radius:50%;vertical-align:middle}.rc-slider-dot-active{border-color:#96dbfa}.rc-slider-dot-reverse{margin-right:-4px}.rc-slider-disabled{background-color:#e9e9e9}.rc-slider-disabled .rc-slider-track{background-color:#ccc}.rc-slider-disabled .rc-slider-handle,.rc-slider-disabled .rc-slider-dot{border-color:#ccc;box-shadow:none;background-color:#fff;cursor:not-allowed}.rc-slider-disabled .rc-slider-mark-text,.rc-slider-disabled .rc-slider-dot{cursor:not-allowed!important}.rc-slider-vertical{width:14px;height:100%;padding:0 5px}.rc-slider-vertical .rc-slider-rail{height:100%;width:4px}.rc-slider-vertical .rc-slider-track{left:5px;bottom:0;width:4px}.rc-slider-vertical .rc-slider-handle{margin-left:-5px;touch-action:pan-y}.rc-slider-vertical .rc-slider-mark{top:0;left:18px;height:100%}.rc-slider-vertical .rc-slider-step{height:100%;width:4px}.rc-slider-vertical .rc-slider-dot{left:2px;margin-bottom:-4px}.rc-slider-vertical .rc-slider-dot:first-child{margin-bottom:-4px}.rc-slider-vertical .rc-slider-dot:last-child{margin-bottom:-4px}.rc-slider-tooltip-zoom-down-enter,.rc-slider-tooltip-zoom-down-appear,.rc-slider-tooltip-zoom-down-leave{animation-duration:.3s;animation-fill-mode:both;display:block!important;animation-play-state:paused}.rc-slider-tooltip-zoom-down-enter.rc-slider-tooltip-zoom-down-enter-active,.rc-slider-tooltip-zoom-down-appear.rc-slider-tooltip-zoom-down-appear-active{animation-name:rcSliderTooltipZoomDownIn;animation-play-state:running}.rc-slider-tooltip-zoom-down-leave.rc-slider-tooltip-zoom-down-leave-active{animation-name:rcSliderTooltipZoomDownOut;animation-play-state:running}.rc-slider-tooltip-zoom-down-enter,.rc-slider-tooltip-zoom-down-appear{transform:scale(0);animation-timing-function:cubic-bezier(.23,1,.32,1)}.rc-slider-tooltip-zoom-down-leave{animation-timing-function:cubic-bezier(.755,.05,.855,.06)}@keyframes rcSliderTooltipZoomDownIn{0%{opacity:0;transform-origin:50% 100%;transform:scale(0)}to{transform-origin:50% 100%;transform:scale(1)}}@keyframes rcSliderTooltipZoomDownOut{0%{transform-origin:50% 100%;transform:scale(1)}to{opacity:0;transform-origin:50% 100%;transform:scale(0)}}.rc-slider-tooltip{position:absolute;left:-9999px;top:-9999px;visibility:visible;box-sizing:border-box;-webkit-tap-highlight-color:rgba(0,0,0,0)}.rc-slider-tooltip *{box-sizing:border-box;-webkit-tap-highlight-color:rgba(0,0,0,0)}.rc-slider-tooltip-hidden{display:none}.rc-slider-tooltip-placement-top{padding:4px 0 8px}.rc-slider-tooltip-inner{padding:6px 2px;min-width:24px;height:24px;font-size:12px;line-height:1;color:#fff;text-align:center;text-decoration:none;background-color:#6c6c6c;border-radius:6px;box-shadow:0 0 4px #d9d9d9}.rc-slider-tooltip-arrow{position:absolute;width:0;height:0;border-color:transparent;border-style:solid}.rc-slider-tooltip-placement-top .rc-slider-tooltip-arrow{bottom:4px;left:50%;margin-left:-4px;border-width:4px 4px 0;border-top-color:#6c6c6c}.fastboard-root{position:relative;width:100%;height:100%;overflow:hidden}.fastboard-view{position:absolute;top:0;left:0;width:100%;height:100%}.fastboard-left{position:absolute;top:0;left:0;height:calc(100% - 48px);padding:16px;z-index:201;display:flex;align-items:center}.fastboard-bottom-left,.fastboard-bottom-right{display:flex;gap:10px;position:absolute;bottom:8px;left:8px;padding:8px;z-index:200}.fastboard-bottom-right{left:initial;right:8px}.fastboard-redo-undo{display:inline-flex;align-items:center;gap:4px;padding:4px;border-radius:4px;backdrop-filter:blur(2px);-webkit-backdrop-filter:blur(2px)}.fastboard-redo-undo.light{color:#333;background-color:#ffffffd9;border:1px solid rgba(0,0,0,.15)}.fastboard-redo-undo.dark{color:#ddd;background-color:#333333d9;border:1px solid rgba(0,0,0,.45)}.fastboard-redo-undo-btn{appearance:none;cursor:pointer;margin:0;border:0;padding:0;width:24px;height:24px;background-color:transparent;border-radius:4px;font-size:24px;line-height:1}.fastboard-redo-undo-btn svg,.fastboard-redo-undo-btn img{width:1em;height:1em}.fastboard-redo-undo-btn:disabled{opacity:.5;cursor:not-allowed}.fastboard-redo-undo-btn.light:not(:disabled):hover{background-color:#3381ff1a}.fastboard-redo-undo-btn.dark:not(:disabled):hover{background-color:#3381ff40}.fastboard-page-control{display:inline-flex;align-items:center;gap:4px;padding:4px;border-radius:4px;backdrop-filter:blur(2px);-webkit-backdrop-filter:blur(2px)}.fastboard-page-control.light{color:#333;background-color:#ffffffd9;border:1px solid rgba(0,0,0,.15)}.fastboard-page-control.dark{color:#ddd;background-color:#333333d9;border:1px solid rgba(0,0,0,.45)}.fastboard-page-control-btn{appearance:none;cursor:pointer;margin:0;border:0;padding:0;width:24px;height:24px;background-color:transparent;border-radius:4px;font-size:24px;line-height:1}.fastboard-page-control-btn svg,.fastboard-page-control-btn img{width:1em;height:1em}.fastboard-page-control-btn:disabled{opacity:.5;cursor:not-allowed}.fastboard-page-control-btn.light:not(:disabled):hover{background-color:#3381ff1a}.fastboard-page-control-btn.dark:not(:disabled):hover{background-color:#3381ff40}.fastboard-page-control-cut-line{height:24px;width:.5px}.fastboard-page-control-cut-line.light{background-color:#e7e7e7}.fastboard-page-control-cut-line.dark{background-color:#ffffff26}.fastboard-page-control-slash{opacity:.6}.fastboard-page-control-page,.fastboard-page-control-slash,.fastboard-page-control-page-count{font-size:12px;font-variant-numeric:tabular-nums}.fastboard-zoom-control{position:relative;display:inline-flex;align-items:center;gap:4px;padding:4px;border-radius:4px;backdrop-filter:blur(2px);-webkit-backdrop-filter:blur(2px)}.fastboard-zoom-control.light{color:#333;background-color:#ffffffd9;border:1px solid rgba(0,0,0,.15)}.fastboard-zoom-control.dark{color:#ddd;background-color:#333333d9;border:1px solid rgba(0,0,0,.45)}.fastboard-zoom-control-btn{appearance:none;cursor:pointer;margin:0;border:0;padding:0;width:24px;height:24px;background-color:transparent;border-radius:4px;font-size:24px;line-height:1}.fastboard-zoom-control-btn svg,.fastboard-zoom-control-btn img{width:1em;height:1em}.fastboard-zoom-control-btn:disabled{opacity:.5;cursor:not-allowed}.fastboard-zoom-control-btn.light:not(:disabled):hover{background-color:#3381ff1a}.fastboard-zoom-control-btn.dark:not(:disabled):hover{background-color:#3381ff40}.fastboard-zoom-control-cut-line{height:24px;width:.5px}.fastboard-zoom-control-cut-line.light{background-color:#e7e7e7}.fastboard-zoom-control-cut-line.dark{background-color:#ffffff26}.fastboard-zoom-control-percent{opacity:.6}.fastboard-zoom-control-scale,.fastboard-zoom-control-percent{font-size:12px;font-variant-numeric:tabular-nums}.fastboard-toolbar{display:flex;align-items:center;padding:4px;border-radius:4px;flex-direction:column;gap:4px;position:absolute;z-index:100;backdrop-filter:blur(2px);-webkit-backdrop-filter:blur(2px)}.fastboard-toolbar .rc-slider{padding:6px 0}.fastboard-toolbar .rc-slider-rail,.fastboard-toolbar .rc-slider-track{height:2px}.fastboard-toolbar .tippy-content{padding:8px}.fastboard-toolbar .tippy-box{border:1px solid rgba(0,0,0,.15);background-color:#333333f2;backdrop-filter:blur(2px);-webkit-backdrop-filter:blur(2px)}.fastboard-toolbar .tippy-box[data-theme~=light]{background-color:#fffffff2;box-shadow:0 5px 10px #00000040}.fastboard-toolbar.light{color:#333;background-color:#ffffffd9;border:1px solid rgba(0,0,0,.15)}.fastboard-toolbar.expanded{border:1px solid rgba(0,0,0,.15)}.fastboard-toolbar.dark{color:#ddd;background-color:#333333d9}.fastboard-toolbar.expanded:hover{box-shadow:0 0 5px #00000040;transform:translate(0)}.fastboard-toolbar.collapsed{padding:0;background-color:transparent}.fastboard-toolbar-tooltip{display:inline-flex;align-items:center;gap:4px}.fastboard-toolbar-hotkey{margin-right:-4px;width:24px;height:24px;border-radius:4px;background-color:#ffffff1a;display:inline-flex;align-items:center;justify-content:center}.fastboard-toolbar-btn{appearance:none;cursor:pointer;margin:0;border:0;padding:4px;width:32px;height:32px;background-color:transparent;border-radius:4px;font-size:24px;line-height:1;position:relative}.fastboard-toolbar-btn-interactive{display:inline-block;width:32px;height:32px}.fastboard-toolbar-btn svg,.fastboard-toolbar-btn img{width:1em;height:1em}.fastboard-toolbar-btn:disabled{opacity:.5;cursor:not-allowed}.fastboard-toolbar-btn.light:not(:disabled):hover{background-color:#3381ff1a}.fastboard-toolbar-btn.dark:not(:disabled):hover{background-color:#3381ff40}.fastboard-toolbar-triangle{width:0px;height:0px;border-bottom:4px solid;border-left:4px solid transparent;position:absolute;bottom:0;right:0}.fastboard-toolbar-cut-line{display:inline-block;height:.5px;width:100%}.fastboard-toolbar-cut-line.light{background-color:#e7e7e7}.fastboard-toolbar-cut-line.dark{background-color:#ffffff26}.fastboard-toolbar-section{display:inline-flex;flex-flow:column nowrap;gap:4px;scroll-behavior:smooth}.fastboard-toolbar-section.collapsed{transform:translate(-100%);transition:1s transform}.fastboard-toolbar-panel{width:120px;padding:0;display:flex;flex-flow:column nowrap;align-items:center;gap:8px}.fastboard-toolbar-panel.apps{width:224px}.fastboard-toolbar-color-box,.fastboard-toolbar-shapes{display:grid;grid-template-columns:repeat(4,1fr);gap:8px;align-items:center;justify-items:center}.fastboard-toolbar-color-box .fastboard-toolbar-btn,.fastboard-toolbar-shapes .fastboard-toolbar-btn{padding:0;width:24px;height:24px}.fastboard-toolbar-apps{width:100%;display:grid;grid-template-columns:repeat(3,1fr);gap:8px;align-items:center;justify-items:center}.fastboard-toolbar-apps .fastboard-toolbar-btn{width:40px;height:40px;font-size:40px}.fastboard-toolbar-app-icon{padding-top:4px;display:inline-flex;flex-flow:column nowrap;align-items:center;gap:4px}.fastboard-toolbar-app-icon .fastboard-toolbar-btn{padding:0}.fastboard-toolbar-app-icon-text{font-size:12px;color:#5d5d5d;overflow:hidden;white-space:nowrap;text-overflow:ellipsis}.fastboard-toolbar-color-item{width:24px;height:24px;border-radius:4px;cursor:pointer}.fastboard-toolbar-color-item *.light:hover{background-color:#f5f5f5}.fastboard-toolbar-color-item *.dark:hover{background-color:#333}.fastboard-toolbar-color-border{width:24px;height:24px;border:1px solid transparent;border-radius:4px;display:inline-flex;align-items:center;justify-content:center}.fastboard-toolbar-color-border.active.light,.fastboard-toolbar-color-border.active.dark{border:1px solid rgba(51,129,255,.8)}.fastboard-toolbar-color-btn{margin:0;border:1px solid rgba(0,0,0,.24);padding:0;appearance:none;width:16px;height:16px;border-radius:4px;cursor:pointer}.fastboard-toolbar-color-btn:focus-visible{outline-offset:2px}.fastboard-toolbar-mask-btn{width:17px;height:62px;cursor:pointer}.fastboard-toolbar-mask-btn.dark{filter:invert(.8)}.fastboard-toolbar-expand-btn{display:flex;align-items:center;position:absolute;left:0}.fastboard-player-control{width:100%;display:inline-flex;align-items:center;gap:4px;padding:4px;border-radius:4px;backdrop-filter:blur(2px);-webkit-backdrop-filter:blur(2px)}.fastboard-player-control.auto-hide{opacity:0;transition:opacity .2s}.fastboard-player-control.auto-hide:hover{opacity:1}.fastboard-player-control .rc-slider-disabled{background:transparent;opacity:.5}.fastboard-player-control .rc-slider-rail,.fastboard-player-control .rc-slider-track{height:2px}.fastboard-player-control .tippy-content{padding:8px}.fastboard-player-control .tippy-box{border:1px solid rgba(0,0,0,.15);background-color:#333333f2;backdrop-filter:blur(2px);-webkit-backdrop-filter:blur(2px)}.fastboard-player-control .tippy-box[data-theme~=light]{background-color:#fffffff2;box-shadow:0 5px 10px #00000040}.fastboard-player-control.light{color:#333;background-color:#ffffffd9;border:1px solid rgba(0,0,0,.15)}.fastboard-player-control.dark{color:#ddd;background-color:#333333d9;border:1px solid rgba(0,0,0,.45)}.fastboard-player-control-btn{appearance:none;cursor:pointer;margin:0;border:0;padding:0;min-width:24px;height:24px;background-color:transparent;border-radius:4px;font-size:24px;line-height:1;display:inline-flex;align-items:center;justify-content:center}.fastboard-player-control-btn svg,.fastboard-player-control-btn img{width:1em;height:1em}.fastboard-player-control-btn:disabled{opacity:.5;cursor:not-allowed}.fastboard-player-control-btn.light:not(:disabled):hover{background-color:#3381ff1a}.fastboard-player-control-btn.dark:not(:disabled):hover{background-color:#3381ff40}.fastboard-player-control-btn.loading{animation:fastboard-player-control-rotate .5s linear infinite}@keyframes fastboard-player-control-rotate{to{transform:rotate(360deg)}}.fastboard-player-control-panel{padding:0;display:flex;flex-flow:column nowrap;align-items:stretch;gap:4px}.fastboard-player-control-panel .fastboard-player-control-btn{width:initial;height:initial;user-select:none;font-size:12px;padding:4px;justify-content:flex-end}.fastboard-player-control-panel .fastboard-player-control-btn.active{color:#3381ff}.fastboard-player-control-slider{width:100%;padding:0 7px}.fastboard-player-control-slider.loading{cursor:not-allowed}.fastboard-player-control-slash{opacity:.6}.fastboard-player-control-current,.fastboard-player-control-slash,.fastboard-player-control-total,.fastboard-player-control-speed-text{font-size:12px;font-variant-numeric:tabular-nums}.tippy-box.fastboard-tip{color:#eee;background-color:#000000f2;backdrop-filter:blur(2px);-webkit-backdrop-filter:blur(2px)}.tippy-box.fastboard-tip[data-placement^=right]>.tippy-arrow:before{top:4px;border-width:4px;border-right-color:#000}.tippy-box.fastboard-tip[data-placement^=top]>.tippy-arrow:before{left:4px;border-width:4px;border-top-color:#000}\n';
85
+
86
+ // src/behaviors/style.ts
87
+ applyStyles(style_default);
88
+
89
+ // src/components/hooks.ts
90
+ import { BuiltinApps } from "@netless/window-manager";
91
+ import { createContext, useContext, useEffect as useEffect2, useState as useState2 } from "react";
92
+ var FastboardAppContext = createContext(null);
93
+ var ThemeContext = createContext("light");
94
+ function useTheme(userTheme) {
95
+ const themeFromContext = useContext(ThemeContext);
96
+ return userTheme || themeFromContext;
97
+ }
98
+ function useFastboardApp() {
99
+ const app = useContext(FastboardAppContext);
100
+ if (!app) {
101
+ throw new Error("useFastboardApp() can only be called inside of <Fastboard>");
102
+ }
103
+ return app;
104
+ }
105
+ function useFastboardValue(val) {
106
+ const [value, setValue] = useState2(val.value);
107
+ useEffect2(() => val.subscribe(setValue), [val]);
108
+ return value;
109
+ }
110
+ function useWritable() {
111
+ return useFastboardValue(useFastboardApp().writable);
112
+ }
113
+ function useBoxState() {
114
+ return useFastboardValue(useFastboardApp().boxState);
115
+ }
116
+ function useFocusedApp() {
117
+ return useFastboardValue(useFastboardApp().focusedApp);
118
+ }
119
+ function useMaximized() {
120
+ return useBoxState() === "maximized";
121
+ }
122
+ function useHideControls() {
123
+ const maximized = useMaximized();
124
+ const focusedApp = useFocusedApp();
125
+ if (maximized) {
126
+ if (Object.values(BuiltinApps).some((kind) => focusedApp == null ? void 0 : focusedApp.includes(kind))) {
127
+ return "toolbar-only";
128
+ } else {
129
+ return true;
130
+ }
131
+ }
132
+ return false;
133
+ }
134
+
135
+ // src/components/RedoUndo/hooks.ts
136
+ import { useCallback as useCallback2 } from "react";
137
+ function useRedoUndo() {
138
+ const app = useFastboardApp();
139
+ const undoSteps = useFastboardValue(app.canUndoSteps);
140
+ const redoSteps = useFastboardValue(app.canRedoSteps);
141
+ const undo = useCallback2(() => {
142
+ app.undo();
143
+ }, [app]);
144
+ const redo = useCallback2(() => {
145
+ app.redo();
146
+ }, [app]);
147
+ return { redoSteps, undoSteps, redo, undo };
148
+ }
149
+
150
+ // src/components/RedoUndo/RedoUndo.tsx
151
+ import Tippy from "@tippyjs/react";
152
+ import clsx from "clsx";
153
+ import React4 from "react";
154
+
155
+ // src/i18n/index.ts
156
+ import { createContext as createContext2, useContext as useContext2, useMemo } from "react";
157
+ import i18next from "i18next";
158
+
159
+ // src/i18n/en.json
160
+ var translation = {
161
+ clicker: "clicker",
162
+ selector: "selector",
163
+ text: "text",
164
+ pencil: "pencil",
165
+ arrow: "arrow",
166
+ hand: "hand",
167
+ eraser: "eraser",
168
+ laser: "laser",
169
+ collapse: "Collapse",
170
+ expand: "Expand",
171
+ zoomIn: "Zoom In",
172
+ zoomOut: "Zoom Out",
173
+ reset: "Reset",
174
+ prevPage: "Prev Page",
175
+ nextPage: "Next Page",
176
+ addPage: "Add Page",
177
+ redo: "Redo",
178
+ undo: "Undo",
179
+ shape: "Shape",
180
+ triangle: "Triangle",
181
+ rhombus: "Rhombus",
182
+ pentagram: "Pentagram",
183
+ speechBalloon: "Speech Balloon",
184
+ rectangle: "Rectangle",
185
+ ellipse: "Ellipse",
186
+ straight: "Straight",
187
+ speed: "Speed"
188
+ };
189
+ var en_default = {
190
+ translation
191
+ };
192
+
193
+ // src/i18n/zh-CN.json
194
+ var translation2 = {
195
+ clicker: "\u70B9\u51FB",
196
+ selector: "\u9009\u62E9",
197
+ text: "\u6587\u5B57",
198
+ pencil: "\u94C5\u7B14",
199
+ arrow: "\u7BAD\u5934",
200
+ hand: "\u6293\u624B",
201
+ eraser: "\u6A61\u76AE",
202
+ laser: "\u6FC0\u5149\u7B14",
203
+ zoomIn: "\u653E\u5927",
204
+ zoomOut: "\u7F29\u5C0F",
205
+ reset: "\u91CD\u7F6E",
206
+ prevPage: "\u4E0A\u4E00\u9875",
207
+ nextPage: "\u4E0B\u4E00\u9875",
208
+ addPage: "\u6DFB\u52A0\u9875\u9762",
209
+ redo: "\u91CD\u505A",
210
+ undo: "\u64A4\u9500",
211
+ collapse: "\u6536\u8D77",
212
+ expand: "\u5C55\u5F00",
213
+ clean: "\u6E05\u5C4F",
214
+ shape: "\u5F62\u72B6",
215
+ triangle: "\u4E09\u89D2\u5F62",
216
+ rhombus: "\u83F1\u5F62",
217
+ pentagram: "\u4E94\u89D2\u661F",
218
+ speechBalloon: "\u6C14\u7403",
219
+ rectangle: "\u77E9\u5F62",
220
+ ellipse: "\u692D\u5706",
221
+ straight: "\u76F4\u7EBF",
222
+ speed: "\u901F\u5EA6"
223
+ };
224
+ var zh_CN_default = {
225
+ translation: translation2
226
+ };
227
+
228
+ // src/i18n/index.ts
229
+ var createI18n = async ({
230
+ language = navigator.language || "zh-CN"
231
+ } = {}) => {
232
+ await i18next.init({
233
+ lng: language,
234
+ resources: { en: en_default, "zh-CN": zh_CN_default }
235
+ });
236
+ return i18next;
237
+ };
238
+ var I18nContext = createContext2(null);
239
+ function useTranslation() {
240
+ const i18n = useContext2(I18nContext);
241
+ const t = useMemo(() => i18n ? i18n.getFixedT(null, ["translation"]) : (id) => id, [i18n]);
242
+ return { t, i18n };
243
+ }
244
+
245
+ // src/icons/index.tsx
246
+ import React from "react";
247
+ function Icon({ fallback, src, alt = "[icon]" }) {
248
+ return src ? React.createElement("img", {
249
+ src,
250
+ alt,
251
+ title: alt
252
+ }) : fallback;
253
+ }
254
+
255
+ // src/icons/Redo.tsx
256
+ import React2 from "react";
257
+
258
+ // src/theme.ts
259
+ var light = {
260
+ color: "#5D5D5D",
261
+ activeColor: "#3381FF",
262
+ backgroundColor: "#fff",
263
+ hoverBackgroundColor: "rgba(51, 129, 255, 0.1)"
264
+ };
265
+ var dark = __spreadProps(__spreadValues({}, light), {
266
+ color: "#eee",
267
+ backgroundColor: "#111"
268
+ });
269
+ var themes = { light, dark };
270
+ var getStroke = (props) => {
271
+ let config;
272
+ if (props.theme) {
273
+ config = themes[props.theme];
274
+ } else {
275
+ config = themes.light;
276
+ }
277
+ return props.active ? config.activeColor : config.color;
278
+ };
279
+ var TopOffset = [0, 11];
280
+ var RightOffset = [0, 11];
281
+
282
+ // src/icons/Redo.tsx
283
+ function Redo({ theme = "light", active }) {
284
+ const config = themes[theme];
285
+ const stroke = active ? config.activeColor : config.color;
286
+ return React2.createElement("svg", {
287
+ viewBox: "0 0 24 24"
288
+ }, React2.createElement("g", {
289
+ fill: "none",
290
+ fillRule: "evenodd",
291
+ stroke,
292
+ strokeLinecap: "round",
293
+ strokeLinejoin: "round"
294
+ }, React2.createElement("path", {
295
+ d: "M14 14h4v-4"
296
+ }), React2.createElement("path", {
297
+ d: "m18 14-.788-.9A7.005 7.005 0 0 0 6 14h0"
298
+ })));
299
+ }
300
+
301
+ // src/icons/Undo.tsx
302
+ import React3 from "react";
303
+ function Undo({ theme = "light", active }) {
304
+ const config = themes[theme];
305
+ const stroke = active ? config.activeColor : config.color;
306
+ return React3.createElement("svg", {
307
+ viewBox: "0 0 24 24"
308
+ }, React3.createElement("g", {
309
+ fill: "none",
310
+ fillRule: "evenodd",
311
+ stroke,
312
+ strokeLinecap: "round",
313
+ strokeLinejoin: "round"
314
+ }, React3.createElement("path", {
315
+ d: "M10 14H6v-4"
316
+ }), React3.createElement("path", {
317
+ d: "m6 14 .788-.9A7.005 7.005 0 0 1 18 14h0"
318
+ })));
319
+ }
320
+
321
+ // src/components/RedoUndo/RedoUndo.tsx
322
+ var name = "fastboard-redo-undo";
323
+ function RedoUndo({ theme, undoIcon, undoIconDisable, redoIcon, redoIconDisable }) {
324
+ theme = useTheme(theme);
325
+ const { t } = useTranslation();
326
+ const writable = useWritable();
327
+ const { redoSteps, undoSteps, redo, undo } = useRedoUndo();
328
+ const disabled = !writable;
329
+ return React4.createElement("div", {
330
+ className: clsx(name, theme)
331
+ }, React4.createElement(Tippy, {
332
+ className: "fastboard-tip",
333
+ content: t("undo"),
334
+ theme,
335
+ disabled,
336
+ placement: "top",
337
+ delay: [1e3, 400],
338
+ duration: 300,
339
+ offset: TopOffset
340
+ }, React4.createElement("button", {
341
+ className: clsx(`${name}-btn`, "undo", theme),
342
+ disabled: disabled || undoSteps === 0,
343
+ onClick: undo
344
+ }, React4.createElement(Icon, {
345
+ fallback: React4.createElement(Undo, {
346
+ theme
347
+ }),
348
+ src: undoSteps === 0 ? undoIconDisable : undoIcon,
349
+ alt: "[undo]"
350
+ }))), React4.createElement(Tippy, {
351
+ className: "fastboard-tip",
352
+ content: t("redo"),
353
+ theme,
354
+ disabled,
355
+ placement: "top",
356
+ delay: [1e3, 400],
357
+ duration: 300,
358
+ offset: TopOffset
359
+ }, React4.createElement("button", {
360
+ className: clsx(`${name}-btn`, "redo", theme),
361
+ disabled: disabled || redoSteps === 0,
362
+ onClick: redo
363
+ }, React4.createElement(Icon, {
364
+ fallback: React4.createElement(Redo, {
365
+ theme
366
+ }),
367
+ src: redoSteps === 0 ? redoIconDisable : redoIcon,
368
+ alt: "[redo]"
369
+ }))));
370
+ }
371
+
372
+ // src/components/ZoomControl/hooks.ts
373
+ import { useCallback as useCallback3 } from "react";
374
+ var ScalePoints = [
375
+ 0.10737418240000011,
376
+ 0.13421772800000012,
377
+ 0.16777216000000014,
378
+ 0.20971520000000016,
379
+ 0.26214400000000015,
380
+ 0.3276800000000002,
381
+ 0.4096000000000002,
382
+ 0.5120000000000001,
383
+ 0.6400000000000001,
384
+ 0.8,
385
+ 1,
386
+ 1.26,
387
+ 1.5876000000000001,
388
+ 2.000376,
389
+ 2.5204737600000002,
390
+ 3.1757969376000004,
391
+ 4.001504141376,
392
+ 5.041895218133761,
393
+ 6.352787974848539,
394
+ 8.00451284830916,
395
+ 10
396
+ ];
397
+ function nextScale(scale, delta) {
398
+ const { length } = ScalePoints;
399
+ const last = length - 1;
400
+ if (scale < ScalePoints[0])
401
+ return ScalePoints[0];
402
+ if (scale > ScalePoints[last])
403
+ return ScalePoints[last];
404
+ for (let i = 0; i < length; ++i) {
405
+ const curr = ScalePoints[i];
406
+ const prev = i === 0 ? -Infinity : (ScalePoints[i - 1] + curr) / 2;
407
+ const next = i === last ? Infinity : (ScalePoints[i + 1] + curr) / 2;
408
+ if (prev <= scale && scale <= next)
409
+ return ScalePoints[clamp(i + delta, 0, last)];
410
+ }
411
+ return 1;
412
+ }
413
+ function useZoomControl() {
414
+ const app = useFastboardApp();
415
+ const scale = useFastboardValue(app.camera).scale || 1;
416
+ const resetCamera = useCallback3(() => {
417
+ app.moveCamera({ scale: 1, centerX: 0, centerY: 0 });
418
+ }, [app]);
419
+ const zoomIn = useCallback3(() => {
420
+ app.moveCamera({
421
+ scale: nextScale(scale, 1),
422
+ centerX: 0,
423
+ centerY: 0
424
+ });
425
+ }, [app, scale]);
426
+ const zoomOut = useCallback3(() => {
427
+ app.moveCamera({
428
+ scale: nextScale(scale, -1),
429
+ centerX: 0,
430
+ centerY: 0
431
+ });
432
+ }, [app, scale]);
433
+ return { scale, resetCamera, zoomIn, zoomOut };
434
+ }
435
+
436
+ // src/components/ZoomControl/ZoomControl.tsx
437
+ import Tippy2 from "@tippyjs/react";
438
+ import clsx2 from "clsx";
439
+ import React8 from "react";
440
+
441
+ // src/icons/Minus.tsx
442
+ import React5 from "react";
443
+ function Minus({ theme = "light", active }) {
444
+ const config = themes[theme];
445
+ const stroke = active ? config.activeColor : config.color;
446
+ return React5.createElement("svg", {
447
+ viewBox: "0 0 24 24"
448
+ }, React5.createElement("path", {
449
+ fill: "none",
450
+ stroke,
451
+ strokeLinecap: "round",
452
+ strokeLinejoin: "round",
453
+ d: "M7 12h10"
454
+ }));
455
+ }
456
+
457
+ // src/icons/Plus.tsx
458
+ import React6 from "react";
459
+ function Plus({ theme = "light", active }) {
460
+ const config = themes[theme];
461
+ const stroke = active ? config.activeColor : config.color;
462
+ return React6.createElement("svg", {
463
+ viewBox: "0 0 24 24"
464
+ }, React6.createElement("path", {
465
+ fill: "none",
466
+ stroke,
467
+ strokeLinecap: "round",
468
+ strokeLinejoin: "round",
469
+ d: "M12 7v10m-5-5h10"
470
+ }));
471
+ }
472
+
473
+ // src/icons/Reset.tsx
474
+ import React7 from "react";
475
+ function Reset({ theme = "light", active }) {
476
+ const config = themes[theme];
477
+ const stroke = active ? config.activeColor : config.color;
478
+ return React7.createElement("svg", {
479
+ viewBox: "0 0 24 24"
480
+ }, React7.createElement("g", {
481
+ fill: "none",
482
+ fillRule: "evenodd",
483
+ transform: "translate(-176 -684)"
484
+ }, React7.createElement("path", {
485
+ stroke,
486
+ strokeLinejoin: "round",
487
+ d: "M188 688v4m0 8v4m8-8h-4m-8 0h-4"
488
+ }), React7.createElement("circle", {
489
+ cx: "188",
490
+ cy: "696",
491
+ r: "6",
492
+ stroke
493
+ }), React7.createElement("circle", {
494
+ cx: "188",
495
+ cy: "696",
496
+ r: "1",
497
+ fill: stroke
498
+ })));
499
+ }
500
+
501
+ // src/components/ZoomControl/ZoomControl.tsx
502
+ var name2 = "fastboard-zoom-control";
503
+ function ZoomControl({
504
+ theme,
505
+ resetIcon,
506
+ resetIconDisable,
507
+ minusIcon,
508
+ minusIconDisable,
509
+ plusIcon,
510
+ plusIconDisable
511
+ }) {
512
+ theme = useTheme(theme);
513
+ const { t } = useTranslation();
514
+ const writable = useWritable();
515
+ const { scale, resetCamera, zoomIn, zoomOut } = useZoomControl();
516
+ const disabled = !writable;
517
+ return React8.createElement("div", {
518
+ className: clsx2(name2, theme)
519
+ }, React8.createElement(Tippy2, {
520
+ className: "fastboard-tip",
521
+ content: t("zoomOut"),
522
+ theme,
523
+ disabled,
524
+ placement: "top",
525
+ delay: [1e3, 400],
526
+ duration: 300,
527
+ offset: TopOffset
528
+ }, React8.createElement("button", {
529
+ className: clsx2(`${name2}-btn`, "minus", theme),
530
+ disabled,
531
+ onClick: zoomOut
532
+ }, React8.createElement(Icon, {
533
+ fallback: React8.createElement(Minus, {
534
+ theme
535
+ }),
536
+ src: disabled ? minusIconDisable : minusIcon,
537
+ alt: "[minus]"
538
+ }))), React8.createElement("span", {
539
+ className: clsx2(`${name2}-scale`, theme)
540
+ }, Math.ceil(scale * 100)), React8.createElement("span", {
541
+ className: clsx2(`${name2}-percent`, theme)
542
+ }, "%"), React8.createElement(Tippy2, {
543
+ className: "fastboard-tip",
544
+ content: t("zoomIn"),
545
+ theme,
546
+ disabled,
547
+ placement: "top",
548
+ delay: [1e3, 400],
549
+ duration: 300,
550
+ offset: TopOffset
551
+ }, React8.createElement("button", {
552
+ className: clsx2(`${name2}-btn`, "plus", theme),
553
+ disabled,
554
+ onClick: zoomIn
555
+ }, React8.createElement(Icon, {
556
+ fallback: React8.createElement(Plus, {
557
+ theme
558
+ }),
559
+ src: disabled ? plusIconDisable : plusIcon,
560
+ alt: "[plus]"
561
+ }))), React8.createElement(Tippy2, {
562
+ className: "fastboard-tip",
563
+ content: t("reset"),
564
+ theme,
565
+ disabled,
566
+ placement: "top",
567
+ delay: [1e3, 400],
568
+ duration: 300,
569
+ offset: TopOffset
570
+ }, React8.createElement("button", {
571
+ className: clsx2(`${name2}-btn`, "reset", theme),
572
+ disabled,
573
+ onClick: resetCamera
574
+ }, React8.createElement(Icon, {
575
+ fallback: React8.createElement(Reset, {
576
+ theme
577
+ }),
578
+ src: disabled ? resetIconDisable : resetIcon,
579
+ alt: "[reset]"
580
+ }))));
581
+ }
582
+
583
+ // src/components/PageControl/hooks.ts
584
+ import { useCallback as useCallback4, useEffect as useEffect3, useState as useState3 } from "react";
585
+ function usePageControl(room, manager) {
586
+ const [pageIndex, setPageIndex] = useState3(0);
587
+ const [pageCount, setPageCount] = useState3(0);
588
+ const addPage = useCallback4(async () => {
589
+ if (manager && room) {
590
+ await manager.switchMainViewToWriter();
591
+ const path = room.state.sceneState.contextPath;
592
+ room.putScenes(path, [{}], pageIndex + 1);
593
+ await manager.setMainViewSceneIndex(pageIndex + 1);
594
+ } else if (!manager && room) {
595
+ const path = room.state.sceneState.contextPath;
596
+ room.putScenes(path, [{}], pageIndex + 1);
597
+ room.setSceneIndex(pageIndex + 1);
598
+ }
599
+ }, [room, manager, pageIndex]);
600
+ const prevPage = useCallback4(() => {
601
+ if (manager) {
602
+ manager.setMainViewSceneIndex(pageIndex - 1);
603
+ } else if (room) {
604
+ room.pptPreviousStep();
605
+ }
606
+ }, [room, manager, pageIndex]);
607
+ const nextPage = useCallback4(() => {
608
+ if (manager) {
609
+ manager.setMainViewSceneIndex(pageIndex + 1);
610
+ } else if (room) {
611
+ room.pptNextStep();
612
+ }
613
+ }, [room, manager, pageIndex]);
614
+ useEffect3(() => {
615
+ if (room) {
616
+ setPageIndex(room.state.sceneState.index);
617
+ setPageCount(room.state.sceneState.scenes.length);
618
+ if (manager) {
619
+ manager.emitter.on("mainViewSceneIndexChange", setPageIndex);
620
+ return () => {
621
+ manager.emitter.off("mainViewSceneIndexChange", setPageIndex);
622
+ };
623
+ } else {
624
+ const onRoomStateChanged = (modifyState) => {
625
+ if (modifyState.sceneState) {
626
+ setPageIndex(modifyState.sceneState.index);
627
+ setPageCount(modifyState.sceneState.scenes.length);
628
+ }
629
+ };
630
+ room.callbacks.on("onRoomStateChanged", onRoomStateChanged);
631
+ return () => {
632
+ room.callbacks.off("onRoomStateChanged", onRoomStateChanged);
633
+ };
634
+ }
635
+ }
636
+ }, [room, manager]);
637
+ return { pageIndex, pageCount, prevPage, nextPage, addPage };
638
+ }
639
+
640
+ // src/components/PageControl/PageControl.tsx
641
+ import Tippy3 from "@tippyjs/react";
642
+ import clsx3 from "clsx";
643
+ import React12 from "react";
644
+
645
+ // src/icons/ChevronLeft.tsx
646
+ import React9 from "react";
647
+ function ChevronLeft({ theme = "light", active }) {
648
+ const config = themes[theme];
649
+ const stroke = active ? config.activeColor : config.color;
650
+ return React9.createElement("svg", {
651
+ viewBox: "0 0 24 24"
652
+ }, React9.createElement("path", {
653
+ fill: "none",
654
+ stroke,
655
+ strokeLinecap: "round",
656
+ strokeLinejoin: "round",
657
+ d: "m14 16-2-2-2-2 2-2 2-2"
658
+ }));
659
+ }
660
+
661
+ // src/icons/ChevronRight.tsx
662
+ import React10 from "react";
663
+ function ChevronRight({ theme = "light", active }) {
664
+ const config = themes[theme];
665
+ const stroke = active ? config.activeColor : config.color;
666
+ return React10.createElement("svg", {
667
+ viewBox: "0 0 24 24"
668
+ }, React10.createElement("path", {
669
+ fill: "none",
670
+ stroke,
671
+ strokeLinecap: "round",
672
+ strokeLinejoin: "round",
673
+ d: "m10 16 2-2 2-2-2-2-2-2"
674
+ }));
675
+ }
676
+
677
+ // src/icons/FilePlus.tsx
678
+ import React11 from "react";
679
+ function FilePlus({ theme = "light", active }) {
680
+ const config = themes[theme];
681
+ const stroke = active ? config.activeColor : config.color;
682
+ return React11.createElement("svg", {
683
+ viewBox: "0 0 24 24"
684
+ }, React11.createElement("path", {
685
+ fill: stroke,
686
+ d: "M12 7.5a.5.5 0 0 1 .09.992L12 8.5H8a1.5 1.5 0 0 0-1.493 1.356L6.5 10v6a1.5 1.5 0 0 0 1.356 1.493L8 17.5h6a1.5 1.5 0 0 0 1.493-1.356L15.5 16v-4a.5.5 0 0 1 .992-.09l.008.09v4a2.5 2.5 0 0 1-2.336 2.495L14 18.5H8a2.5 2.5 0 0 1-2.495-2.336L5.5 16v-6a2.5 2.5 0 0 1 2.336-2.495L8 7.5h4Zm4-2a.5.5 0 0 1 .492.41L16.5 6v1.5H18a.5.5 0 0 1 .09.992L18 8.5h-1.5V10a.5.5 0 0 1-.992.09L15.5 10V8.5H14a.5.5 0 0 1-.09-.992L14 7.5h1.5V6a.5.5 0 0 1 .5-.5Z"
687
+ }));
688
+ }
689
+
690
+ // src/components/PageControl/PageControl.tsx
691
+ var name3 = "fastboard-page-control";
692
+ function PageControl({
693
+ theme,
694
+ addIcon,
695
+ addIconDisable,
696
+ prevIcon,
697
+ prevIconDisable,
698
+ nextIcon,
699
+ nextIconDisable
700
+ }) {
701
+ const app = useFastboardApp();
702
+ theme = useTheme(theme);
703
+ const { t } = useTranslation();
704
+ const writable = useWritable();
705
+ const _a = usePageControl(app.room, app.manager), { pageIndex, pageCount } = _a, actions = __objRest(_a, ["pageIndex", "pageCount"]);
706
+ const disabled = !writable;
707
+ return React12.createElement("div", {
708
+ className: clsx3(name3, theme)
709
+ }, React12.createElement(Tippy3, {
710
+ className: "fastboard-tip",
711
+ content: t("prevPage"),
712
+ theme,
713
+ disabled,
714
+ placement: "top",
715
+ delay: [1e3, 400],
716
+ duration: 300,
717
+ offset: TopOffset
718
+ }, React12.createElement("button", {
719
+ className: clsx3(`${name3}-btn`, "prev", theme),
720
+ disabled: disabled || pageIndex === 0,
721
+ onClick: actions.prevPage
722
+ }, React12.createElement(Icon, {
723
+ fallback: React12.createElement(ChevronLeft, {
724
+ theme
725
+ }),
726
+ src: disabled ? prevIconDisable : prevIcon,
727
+ alt: "[prev]"
728
+ }))), React12.createElement("span", {
729
+ className: clsx3(`${name3}-page`, theme)
730
+ }, pageCount === 0 ? "\u2026" : pageIndex + 1), React12.createElement("span", {
731
+ className: clsx3(`${name3}-slash`, theme)
732
+ }, "/"), React12.createElement("span", {
733
+ className: clsx3(`${name3}-page-count`, theme)
734
+ }, pageCount), React12.createElement(Tippy3, {
735
+ className: "fastboard-tip",
736
+ content: t("nextPage"),
737
+ theme,
738
+ disabled,
739
+ placement: "top",
740
+ delay: [1e3, 400],
741
+ duration: 300,
742
+ offset: TopOffset
743
+ }, React12.createElement("button", {
744
+ className: clsx3(`${name3}-btn`, "next", theme),
745
+ disabled: disabled || pageIndex === pageCount - 1,
746
+ onClick: actions.nextPage
747
+ }, React12.createElement(Icon, {
748
+ fallback: React12.createElement(ChevronRight, {
749
+ theme
750
+ }),
751
+ src: disabled ? nextIconDisable : nextIcon,
752
+ alt: "[next]"
753
+ }))), React12.createElement(Tippy3, {
754
+ className: "fastboard-tip",
755
+ content: t("addPage"),
756
+ theme,
757
+ disabled,
758
+ placement: "top",
759
+ delay: [1e3, 400],
760
+ duration: 300,
761
+ offset: TopOffset
762
+ }, React12.createElement("button", {
763
+ className: clsx3(`${name3}-btn`, "add", theme),
764
+ disabled,
765
+ onClick: actions.addPage
766
+ }, React12.createElement(Icon, {
767
+ fallback: React12.createElement(FilePlus, {
768
+ theme
769
+ }),
770
+ src: disabled ? addIconDisable : addIcon,
771
+ alt: "[add]"
772
+ }))));
773
+ }
774
+
775
+ // src/components/Toolbar/hooks.ts
776
+ import { useCallback as useCallback5 } from "react";
777
+ function useRoomState() {
778
+ return useFastboardValue(useFastboardApp().memberState);
779
+ }
780
+ function useToolbar() {
781
+ const app = useFastboardApp();
782
+ const writable = useWritable();
783
+ const memberState = useRoomState();
784
+ const cleanCurrentScene = useCallback5(() => {
785
+ app.cleanCurrentScene();
786
+ }, [app]);
787
+ const setAppliance = useCallback5((appliance, shape) => {
788
+ app.setAppliance(appliance, shape);
789
+ }, [app]);
790
+ const setStrokeWidth = useCallback5((strokeWidth) => {
791
+ app.setStrokeWidth(strokeWidth);
792
+ }, [app]);
793
+ const setStrokeColor = useCallback5((strokeColor) => {
794
+ app.setStrokeColor(strokeColor);
795
+ }, [app]);
796
+ return {
797
+ writable,
798
+ memberState,
799
+ cleanCurrentScene,
800
+ setAppliance,
801
+ setStrokeWidth,
802
+ setStrokeColor
803
+ };
804
+ }
805
+ var EmptyToolbarHook = {
806
+ writable: false,
807
+ memberState: void 0,
808
+ cleanCurrentScene: noop,
809
+ setAppliance: noop,
810
+ setStrokeWidth: noop,
811
+ setStrokeColor: noop
812
+ };
813
+
814
+ // src/components/Toolbar/Toolbar.tsx
815
+ import clsx9 from "clsx";
816
+ import { AnimatePresence, motion } from "framer-motion";
817
+ import React44, { createContext as createContext3, useCallback as useCallback11, useEffect as useEffect6, useState as useState6 } from "react";
818
+
819
+ // src/components/Toolbar/components/assets/collapsed.png
820
+ var collapsed_default = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACIAAAB8CAYAAAAMw2JFAAAAAXNSR0IArs4c6QAAA49JREFUeF7tnLFv00AUh5/TFVYkxIDEnKFjJ/gb2CIqpUPagYXNEV2LRGk7tAiRSA0bWcC0QzowwQKuVDnCLE2KTZCMSNLkHCLalCpBkdFVMTKh8TXO+c4S16XDSb0vv/vyfE3fqwQR+ZIA4AoAdADgJ08mSVXVV9ls9nE+nzcBAAFAnweQ1Gg06gihrmEYubm5OeX4+LgBAD9Yw0iO49S63S7U6/VYq9UyCoXC2tLS0kcAwEA9VkBnIO5m7XYbJwTVanVLluWcruvfAOA7ADhhA/0Fgjfr9/tweHgYs20baZq2sbCw8HaQTqgy/wPivvKTkxN8XFPNZvMdC5lHgmAgx3EAISQhhHqGYWyGKbMviJsOC5kvBOIjcxUAWjRkHgtkSGZb07R1WjKPDeIj82cAaAatzIFBhmU2TTOXTCZfBq3ME4HQlJkKCA2ZqYJMIjN1kKAyhwYyrsyhgpwns6IoyysrK/rgQfrnqc4ExCtzrVb7tbe39yCVSr0GAFyZz2CYguANT09PwbIsaWdn5146nX4zuO+wB8EwnU5HqlQqdiKRuHNwcFDC1Zh5Iu4xWZYVU1V1eXZ29jlOhRvI0dGRVC6XP8zMzNwFgK/cQHq9HpTLZXt6evo2AFS4geDbX6lUisXj8VsA8IkbCHZlf39/Kh6P3xQg7jtHJDL826JIRCRC+gRBOCIcEY6QEhCOkBISdUQ4IhwhJSAcISUk6kjojjxaXbt0Py3jP1DCtes3ruLvVetLnenRYIgnT7OX3Y25gLgQ3gSYg3ghuIEMQ3ABOQ+COcgoCKYgfhD/Jwh+1ZE4GrdKRkJWPxhulTUSBe28ZLglMgzDHcR9N3G/BpDuHH7r4qoY+lUx6PGIoxFHQ3JHOCIcEY6QEhCOkBISdUQ4IhwhJSAcISUk6ohwxM+RyLR/RaYhLjItgpFomoxEG2kkGmvxRBPXVmPPWIypKMpD5s3X3kEh0zSfJZPJF6NmK0JrI3VHpxBCaiaTWc/n877TJtRBPMNkdrFY3Jifn8ed3njUzneYjCqIZ7xue3FxMadpGh6vu9BEEhUQr4yFQmE1yMDhRCDjyEi6JAUGGVdG6iBBZaQK4pVRluVNXdfZjsfRkHGiRGjKGBjEI+P7TCazQaqMpI1I635jtmNVRtJGpPVRg8fbtGW8EAiL6VUiyGA4vUd6TJN+0KTr0u7u7hYLGUmg0fkHBiRSVuu/AWpfZNft9vFDAAAAAElFTkSuQmCC";
821
+
822
+ // src/components/Toolbar/components/assets/expanded.png
823
+ var expanded_default = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACIAAAB8CAYAAAAMw2JFAAAAAXNSR0IArs4c6QAAA5xJREFUeF7tnL9v00AUx5/TlRkJMSAxZ+jYCf4GtopK6dB2qBBsjshaJErboWVJpYaNLGDaIR2YYAFXqlxhlvzAJkhGJGlyDhVNSpWgyOiqBJnQ+urznW2Jy1JVVnKffv3x8yV9LxLE5CEBwFUA6ALAzyiZJFVVX21ubj7N5/MmACAAGEQBJDWbzQZCqGcYRm52dlbpdDpNAPgRNozkOE691+tBo9FItNtto1AorC0tLX0EAAzUDwvoDGS02NHREU4IarXatizLOV3XvwHAdwBweAP9BYIXGwwGcHh4mLBtG2matrGwsPB2mA5Xmf8BGf3lJycn+HRNtFqtd2HIfCEIBnIcBxBCEkKobxjGFk+ZPUFG6YQh86VAPGSuAUCbhcy+QMZktjVNW2cls28QD5k/A0CLtjJTg4zLbJpmLpVKvaStzIFAWMrMBISFzExBgsjMHIRWZm4gfmXmCnKezIqiLK+srOjDG+mfu3ooIG6Z6/X6r/39/Udzc3OvAQBX5jOYUEHwgqenp2BZlrS7u/sgnU6/Ge53wgfBMN1uV6pWq/b09PTdSqVSwtU49ERGp8myrISqqsszMzPPcSqRgRwfH0vlcvnD1NTUIgB8jQyk3+9DuVy2Jycn7wBANTIQvPsrlUqJZDJ5GwA+RQaCXSkWixPJZPKWABldOSKR8XeLIhGRCOkTBOGIcEQ4QkpAOEJKSNQR4YhwhJSAcISUkKgjTBy5fuPmNfxCNetLA/98srp25WFaxv+UpH5QnZpxEPz7/XuLnSAwzEBwFEFgmIIEgWEOQgvDBYQGhhuIXxiuIH5g/g8QP5czt0T8QFB/mHdeZXXXdr8QXEBoIJiD0EIwBQkCwQwksm0A9abD44lUl68A4ZEAkz0rDzDhiDg1JK+EI8IR4QgpAeEIKSFRR4QjwhFSAsIRUkKijsTSkdi0f8WmIS42LYKxaJqMRRtpLBpr8URTpK3GrrEYU1GUx6E3X7sHhUzTfJZKpV5cNFvBrY10NDqFEFKz2ex6Pp/3nDZhDuIaJrMPDg425ufncac3HrXzHCZjCuIar9vJZDI5TdPweN2lJpKYgLhlLBQKqzQDh4FA/MhI2ptQg/iVkTkIrYxMQdwyyrK8pet6uONxLGQMlAhLGalBXDK+z2azG6TKSFqIdNxrzNZXZSQtRDp+0eDxDmsZLwUSxvQqEWQ4nN4n3aZJLxT0uLS3t7cdhowk0Ph8gQGJNKzjvwGKWUjXcvHclAAAAABJRU5ErkJggg==";
824
+
825
+ // src/components/Toolbar/components/Mask.tsx
826
+ import React13, { useState as useState4, useEffect as useEffect4 } from "react";
827
+ import ReactDOM from "react-dom";
828
+ var Mask = React13.memo(({ toolbar, children }) => {
829
+ const [rootElement] = useState4(() => {
830
+ const element = document.createElement("div");
831
+ element.style.position = "absolute";
832
+ return element;
833
+ });
834
+ useEffect4(() => {
835
+ if (toolbar && rootElement) {
836
+ toolbar.appendChild(rootElement);
837
+ }
838
+ }, [rootElement, toolbar]);
839
+ useEffect4(() => {
840
+ if (rootElement && toolbar) {
841
+ toolbar.appendChild(rootElement);
842
+ const toolbarRect = toolbar.getBoundingClientRect();
843
+ const halfHeight = toolbarRect.height / 2 - 31;
844
+ rootElement.style.top = halfHeight + "px";
845
+ rootElement.style.left = "41px";
846
+ rootElement.style.width = "17px";
847
+ rootElement.style.height = "62px";
848
+ return () => {
849
+ toolbar.removeChild(rootElement);
850
+ };
851
+ }
852
+ }, [rootElement, toolbar]);
853
+ if (rootElement) {
854
+ return ReactDOM.createPortal(children, rootElement);
855
+ } else {
856
+ return null;
857
+ }
858
+ });
859
+
860
+ // src/components/Toolbar/Content.tsx
861
+ import clsx8 from "clsx";
862
+ import React43, { useCallback as useCallback10, useEffect as useEffect5, useRef as useRef2, useState as useState5 } from "react";
863
+
864
+ // src/components/Toolbar/components/ApplianceButtons.tsx
865
+ import React34, { useCallback as useCallback6, useContext as useContext4 } from "react";
866
+ import { ApplianceNames } from "white-web-sdk";
867
+
868
+ // src/components/Toolbar/icons/index.ts
869
+ import { memo } from "react";
870
+
871
+ // src/components/Toolbar/icons/Apps.tsx
872
+ import React14 from "react";
873
+ var Apps = (props) => {
874
+ const stroke = getStroke(props);
875
+ return React14.createElement("svg", {
876
+ viewBox: "0 0 24 24"
877
+ }, React14.createElement("g", {
878
+ fill: stroke
879
+ }, React14.createElement("path", {
880
+ d: "M17.667 4.5h-3.334c-1.012 0-1.833.82-1.833 1.833V11.5h5.167c1.012 0 1.833-.82 1.833-1.833V6.333c0-1.012-.82-1.833-1.833-1.833Zm-3.334 1h3.334c.46 0 .833.373.833.833v3.334l-.006.104a.833.833 0 0 1-.827.729H13.5V6.333c0-.46.373-.833.833-.833Z"
881
+ }), React14.createElement("path", {
882
+ d: "M6.333 19.5A1.833 1.833 0 0 1 4.5 17.667v-3.334c0-.525.221-1 .576-1.334a1.822 1.822 0 0 1-.576-1.332V8.333c0-1.012.82-1.833 1.833-1.833H10A1.5 1.5 0 0 1 11.5 8v4.5h4.167c.962 0 1.75.74 1.827 1.683l.006.15v3.334c0 1.012-.82 1.833-1.833 1.833Zm4.167-6H6.333a.833.833 0 0 0-.827.729l-.006.104v3.334c0 .46.373.833.833.833H10.5v-5Zm5.167 0H11.5v5h4.167c.46 0 .833-.373.833-.833v-3.334a.833.833 0 0 0-.833-.833ZM10 7.5H6.333a.833.833 0 0 0-.833.833v3.334c0 .46.373.833.833.833H10.5V8a.5.5 0 0 0-.41-.492L10 7.5Z"
883
+ })));
884
+ };
885
+
886
+ // src/components/Toolbar/icons/Arrow.tsx
887
+ import React15 from "react";
888
+ var Arrow = (props) => {
889
+ const stroke = getStroke(props);
890
+ return React15.createElement("svg", {
891
+ viewBox: "0 0 24 24"
892
+ }, React15.createElement("path", {
893
+ fill: stroke,
894
+ d: "M19 5v6l-2.647-2.646L5.99 18.718l-.708-.708L15.645 7.646 13 5h6Z"
895
+ }));
896
+ };
897
+
898
+ // src/components/Toolbar/icons/Circle.tsx
899
+ import React16 from "react";
900
+ var Circle = (props) => {
901
+ const stroke = getStroke(props);
902
+ return React16.createElement("svg", {
903
+ viewBox: "0 0 24 24"
904
+ }, React16.createElement("rect", {
905
+ width: "15",
906
+ height: "15",
907
+ x: "4.5",
908
+ y: "4.5",
909
+ fill: "none",
910
+ stroke,
911
+ rx: "7.5"
912
+ }));
913
+ };
914
+
915
+ // src/components/Toolbar/icons/Clean.tsx
916
+ import React17 from "react";
917
+ var Clean = (props) => {
918
+ const stroke = getStroke(props);
919
+ return React17.createElement("svg", {
920
+ viewBox: "0 0 24 24"
921
+ }, React17.createElement("path", {
922
+ fill: stroke,
923
+ d: "M9.754 11.99c0 1.856-.711 3.62-1.96 4.951l-.151.155h1.403l.855-.853h.707l.853.853h2.635l.094-.064a6.237 6.237 0 0 0 2.559-4.781l.005-.26h1a7.237 7.237 0 0 1-2.994 5.862l-.229.16-.277.083h-3l-.353-.146-.647-.647-.646.647-.354.146h-3l-.286-.91.214-.148a6.237 6.237 0 0 0 2.567-4.787l.005-.26h1Zm4.772-6.502v2l.35.039a2.98 2.98 0 0 1 2.644 2.78l.006.181h-8a2.98 2.98 0 0 1 2.65-2.961l.35-.039v-2h2Z"
924
+ }));
925
+ };
926
+
927
+ // src/components/Toolbar/icons/Clicker.tsx
928
+ import React18 from "react";
929
+ var Clicker = (props) => {
930
+ const stroke = getStroke(props);
931
+ return React18.createElement("svg", {
932
+ viewBox: "0 0 24 24"
933
+ }, React18.createElement("g", {
934
+ fill: "none"
935
+ }, React18.createElement("path", {
936
+ d: "M0 0h24v24H0z"
937
+ }), React18.createElement("path", {
938
+ fill: stroke,
939
+ d: "m7 5.072 10.33 7.892-4.879.549 3.232 5.598-.866.5-3.233-5.597-2.914 3.95L7 5.072Z"
940
+ })));
941
+ };
942
+
943
+ // src/components/Toolbar/icons/Collapse.tsx
944
+ import React19 from "react";
945
+ var Collapse = (props) => {
946
+ const stroke = getStroke(props);
947
+ return React19.createElement("svg", {
948
+ viewBox: "0 0 24 24"
949
+ }, React19.createElement("path", {
950
+ fill: "none",
951
+ stroke,
952
+ d: "m8 10-2 2 2 2m10-8H6m12 12H6m12-4h-8m8-4h-8"
953
+ }));
954
+ };
955
+
956
+ // src/components/Toolbar/icons/Diamond.tsx
957
+ import React20 from "react";
958
+ var Diamond = (props) => {
959
+ const stroke = getStroke(props);
960
+ return React20.createElement("svg", {
961
+ viewBox: "0 0 24 24"
962
+ }, React20.createElement("path", {
963
+ fill: "none",
964
+ stroke,
965
+ d: "M4.222 12 12 4.222 19.778 12 12 19.778z"
966
+ }));
967
+ };
968
+
969
+ // src/components/Toolbar/icons/Down.tsx
970
+ import React21 from "react";
971
+ var Down = (props) => {
972
+ const stroke = getStroke(props);
973
+ return React21.createElement("svg", {
974
+ viewBox: "0 0 24 24"
975
+ }, React21.createElement("path", {
976
+ fill: "none",
977
+ stroke,
978
+ d: "m16 13-2 2-2 2-2-2-2-2m8-6-2 2-2 2-2-2-2-2"
979
+ }));
980
+ };
981
+
982
+ // src/components/Toolbar/icons/Eraser.tsx
983
+ import React22 from "react";
984
+ var Eraser = (props) => {
985
+ const stroke = getStroke(props);
986
+ return React22.createElement("svg", {
987
+ viewBox: "0 0 24 24"
988
+ }, React22.createElement("path", {
989
+ fill: stroke,
990
+ d: "m14.333 5.183.165.007c.494.037.978.245 1.356.623l2.333 2.333a2.15 2.15 0 0 1 0 3.04l-5.833 5.834a3.8 3.8 0 0 1-5.374 0l-1.167-1.166a2.15 2.15 0 0 1 0-3.04l7-7c.42-.42.97-.63 1.52-.63ZM11.52 8.52l-4.999 5a1.15 1.15 0 0 0 0 1.626l1.167 1.167a2.8 2.8 0 0 0 3.96 0l3.832-3.833-3.96-3.96Z"
991
+ }));
992
+ };
993
+
994
+ // src/components/Toolbar/icons/Expand.tsx
995
+ import React23 from "react";
996
+ var Expand = (props) => {
997
+ const stroke = getStroke(props);
998
+ return React23.createElement("svg", {
999
+ viewBox: "0 0 24 24"
1000
+ }, React23.createElement("path", {
1001
+ fill: "none",
1002
+ stroke,
1003
+ d: "m16 10 2 2-2 2M6 6h12M6 18h12M6 14h8m-8-4h8"
1004
+ }));
1005
+ };
1006
+
1007
+ // src/components/Toolbar/icons/Line.tsx
1008
+ import React24 from "react";
1009
+ var Line = (props) => {
1010
+ const stroke = getStroke(props);
1011
+ return React24.createElement("svg", {
1012
+ viewBox: "0 0 24 24"
1013
+ }, React24.createElement("path", {
1014
+ fill: stroke,
1015
+ d: "m18.01 5.282.708.708L5.99 18.718l-.708-.708z"
1016
+ }));
1017
+ };
1018
+
1019
+ // src/components/Toolbar/icons/Pencil.tsx
1020
+ import React25 from "react";
1021
+ var Pencil = (props) => {
1022
+ const stroke = getStroke(props);
1023
+ return React25.createElement("svg", {
1024
+ viewBox: "0 0 24 24"
1025
+ }, React25.createElement("path", {
1026
+ fill: stroke,
1027
+ d: "m17.497 4.84.116.105 1.442 1.442a1.52 1.52 0 0 1 .104 2.034l-.104.116L8.733 18.858l-4.347.756.756-4.347L15.463 4.945a1.52 1.52 0 0 1 2.034-.104ZM5.967 16.349l-.353 2.037 2.037-.354-1.683-1.683Zm8.407-8.901-7.946 7.946 2.178 2.178 7.946-7.946-2.178-2.178Zm-.728 2.2.708.707-5 5-.708-.708 5-5Zm2.596-4.055-.072.06-1.09 1.088 2.179 2.178 1.089-1.088a.52.52 0 0 0 .105-.584l-.045-.08-.06-.072-1.442-1.442a.52.52 0 0 0-.664-.06Z"
1028
+ }));
1029
+ };
1030
+
1031
+ // src/components/Toolbar/icons/Rectangle.tsx
1032
+ import React26 from "react";
1033
+ var Rectangle = (props) => {
1034
+ const stroke = getStroke(props);
1035
+ return React26.createElement("svg", {
1036
+ viewBox: "0 0 24 24"
1037
+ }, React26.createElement("path", {
1038
+ fill: "none",
1039
+ stroke,
1040
+ d: "M5.5 5.5h13v13h-13z"
1041
+ }));
1042
+ };
1043
+
1044
+ // src/components/Toolbar/icons/Selector.tsx
1045
+ import React27 from "react";
1046
+ var Selector = (props) => {
1047
+ const stroke = getStroke(props);
1048
+ return React27.createElement("svg", {
1049
+ viewBox: "0 0 24 24"
1050
+ }, React27.createElement("path", {
1051
+ fill: stroke,
1052
+ d: "m12 12 8 2.667-3.556 1.777L14.667 20 12 12Zm3-8v7.5h-1V5H5v9h6.5v1H4V4h11Z"
1053
+ }));
1054
+ };
1055
+
1056
+ // src/components/Toolbar/icons/SpeechBalloon.tsx
1057
+ import React28 from "react";
1058
+ var SpeechBalloon = (props) => {
1059
+ const stroke = getStroke(props);
1060
+ return React28.createElement("svg", {
1061
+ viewBox: "0 0 24 24"
1062
+ }, React28.createElement("path", {
1063
+ fill: "none",
1064
+ stroke,
1065
+ d: "M17 4.5c.414 0 .79.168 1.06.44.272.27.44.646.44 1.06v9c0 .414-.168.79-.44 1.06a1.49 1.49 0 0 1-1.06.44h-4.207l-2.715 2.715-1.81-2.715H7a1.49 1.49 0 0 1-1.06-.44A1.495 1.495 0 0 1 5.5 15V6c0-.414.168-.79.44-1.06A1.49 1.49 0 0 1 7 4.5Z"
1066
+ }));
1067
+ };
1068
+
1069
+ // src/components/Toolbar/icons/Star.tsx
1070
+ import React29 from "react";
1071
+ var Star = (props) => {
1072
+ const stroke = getStroke(props);
1073
+ return React29.createElement("svg", {
1074
+ viewBox: "0 0 24 24"
1075
+ }, React29.createElement("path", {
1076
+ fill: "none",
1077
+ stroke,
1078
+ d: "m12 3.523 1.993 5.734 6.07.123-4.838 3.668 1.758 5.81L12 15.391l-4.983 3.467 1.758-5.81L3.938 9.38l6.069-.123L12 3.523Z"
1079
+ }));
1080
+ };
1081
+
1082
+ // src/components/Toolbar/icons/Text.tsx
1083
+ import React30 from "react";
1084
+ var Text = (props) => {
1085
+ const stroke = getStroke(props);
1086
+ return React30.createElement("svg", {
1087
+ viewBox: "0 0 24 24"
1088
+ }, React30.createElement("path", {
1089
+ fill: stroke,
1090
+ d: "M18.5 5.5V8h-1V6.5H13v11h2v1H9v-1h2v-11H6.5V8h-1V5.5h13Z"
1091
+ }));
1092
+ };
1093
+
1094
+ // src/components/Toolbar/icons/Triangle.tsx
1095
+ import React31 from "react";
1096
+ var Triangle = (props) => {
1097
+ const stroke = getStroke(props);
1098
+ return React31.createElement("svg", {
1099
+ viewBox: "0 0 24 24"
1100
+ }, React31.createElement("path", {
1101
+ fill: "none",
1102
+ stroke,
1103
+ d: "M12 6.008 19.138 18.5H4.862L12 6.008Z"
1104
+ }));
1105
+ };
1106
+
1107
+ // src/components/Toolbar/icons/Up.tsx
1108
+ import React32 from "react";
1109
+ var Up = (props) => {
1110
+ const stroke = getStroke(props);
1111
+ return React32.createElement("svg", {
1112
+ viewBox: "0 0 24 24"
1113
+ }, React32.createElement("path", {
1114
+ fill: "none",
1115
+ stroke,
1116
+ d: "m16 11-2-2-2-2-2 2-2 2m8 6-2-2-2-2-2 2-2 2"
1117
+ }));
1118
+ };
1119
+
1120
+ // src/components/Toolbar/icons/index.ts
1121
+ var Icons = {
1122
+ Clicker: memo(Clicker),
1123
+ Collapse: memo(Collapse),
1124
+ Eraser: memo(Eraser),
1125
+ Expand: memo(Expand),
1126
+ Pencil: memo(Pencil),
1127
+ Selector: memo(Selector),
1128
+ Rectangle: memo(Rectangle),
1129
+ Text: memo(Text),
1130
+ Apps: memo(Apps),
1131
+ Clean: memo(Clean),
1132
+ Circle: memo(Circle),
1133
+ Line: memo(Line),
1134
+ Arrow: memo(Arrow),
1135
+ Star: memo(Star),
1136
+ Diamond: memo(Diamond),
1137
+ SpeechBalloon: memo(SpeechBalloon),
1138
+ Triangle: memo(Triangle),
1139
+ Up: memo(Up),
1140
+ Down: memo(Down)
1141
+ };
1142
+
1143
+ // src/components/Toolbar/components/Button.tsx
1144
+ import clsx4 from "clsx";
1145
+ import React33, { forwardRef, useContext as useContext3 } from "react";
1146
+ import Tippy4 from "@tippyjs/react";
1147
+ var Button = forwardRef((props, ref) => {
1148
+ const { content, disabled, active, onClick, interactive, placement = "right", children } = props;
1149
+ const { writable, theme } = useContext3(ToolbarContext);
1150
+ return React33.createElement(Tippy4, {
1151
+ className: "fastboard-tip",
1152
+ content,
1153
+ interactive,
1154
+ theme,
1155
+ disabled: disabled || !writable,
1156
+ placement,
1157
+ offset: placement.includes("right") ? RightOffset : void 0,
1158
+ delay: [1e3, 400],
1159
+ duration: 300
1160
+ }, React33.createElement("button", {
1161
+ ref,
1162
+ className: clsx4("fastboard-toolbar-btn", theme, { active }),
1163
+ onClick,
1164
+ disabled: disabled || !writable
1165
+ }, children));
1166
+ });
1167
+
1168
+ // src/components/Toolbar/components/ApplianceButtons.tsx
1169
+ function renderToolTip(text, hotkey) {
1170
+ if (!(typeof hotkey === "string"))
1171
+ return text;
1172
+ return React34.createElement("span", {
1173
+ className: "fastboard-toolbar-tooltip"
1174
+ }, React34.createElement("span", null, text), React34.createElement("span", {
1175
+ className: "fastboard-toolbar-hotkey"
1176
+ }, hotkey.toUpperCase()));
1177
+ }
1178
+ function ClickerButton() {
1179
+ var _a;
1180
+ const app = useFastboardApp();
1181
+ const { t } = useTranslation();
1182
+ const { theme, icons, writable, setAppliance, memberState } = useContext4(ToolbarContext);
1183
+ const changeAppliance = useCallback6(() => setAppliance(ApplianceNames.clicker), [setAppliance]);
1184
+ const shortcut = (_a = app.hotKeys) == null ? void 0 : _a.changeToClick;
1185
+ const appliance = memberState == null ? void 0 : memberState.currentApplianceName;
1186
+ const active = appliance === ApplianceNames.clicker;
1187
+ const disabled = !writable;
1188
+ return React34.createElement(Button, {
1189
+ content: renderToolTip(t("clicker"), shortcut),
1190
+ onClick: changeAppliance,
1191
+ active
1192
+ }, React34.createElement(Icon, {
1193
+ fallback: React34.createElement(Icons.Clicker, {
1194
+ theme,
1195
+ active
1196
+ }),
1197
+ src: disabled ? icons == null ? void 0 : icons.clickerIconDisable : icons == null ? void 0 : icons.clickerIcon,
1198
+ alt: "[clicker]"
1199
+ }));
1200
+ }
1201
+ function SelectorButton() {
1202
+ const app = useFastboardApp();
1203
+ const { t } = useTranslation();
1204
+ const { theme, icons, writable, setAppliance, memberState } = useContext4(ToolbarContext);
1205
+ const changeAppliance = useCallback6(() => setAppliance(ApplianceNames.selector), [setAppliance]);
1206
+ const appliance = memberState == null ? void 0 : memberState.currentApplianceName;
1207
+ const active = appliance === ApplianceNames.selector;
1208
+ const disabled = !writable;
1209
+ const shortcut = (app.hotKeys || defaultHotKeys).changeToSelector;
1210
+ return React34.createElement(Button, {
1211
+ content: renderToolTip(t("selector"), shortcut),
1212
+ onClick: changeAppliance,
1213
+ active
1214
+ }, React34.createElement(Icon, {
1215
+ fallback: React34.createElement(Icons.Selector, {
1216
+ theme,
1217
+ active
1218
+ }),
1219
+ src: disabled ? icons == null ? void 0 : icons.selectorIconDisable : icons == null ? void 0 : icons.selectorIcon,
1220
+ alt: "[selector]"
1221
+ }));
1222
+ }
1223
+ function EraserButton() {
1224
+ const app = useFastboardApp();
1225
+ const { t } = useTranslation();
1226
+ const { theme, icons, writable, setAppliance, memberState } = useContext4(ToolbarContext);
1227
+ const changeAppliance = useCallback6(() => setAppliance(ApplianceNames.eraser), [setAppliance]);
1228
+ const appliance = memberState == null ? void 0 : memberState.currentApplianceName;
1229
+ const active = appliance === ApplianceNames.eraser;
1230
+ const disabled = !writable;
1231
+ const shortcut = ((app == null ? void 0 : app.hotKeys) || defaultHotKeys).changeToEraser;
1232
+ return React34.createElement(Button, {
1233
+ content: renderToolTip(t("eraser"), shortcut),
1234
+ onClick: changeAppliance,
1235
+ active
1236
+ }, React34.createElement(Icon, {
1237
+ fallback: React34.createElement(Icons.Eraser, {
1238
+ theme,
1239
+ active
1240
+ }),
1241
+ src: disabled ? icons == null ? void 0 : icons.eraserIconDisable : icons == null ? void 0 : icons.eraserIcon,
1242
+ alt: "[eraser]"
1243
+ }));
1244
+ }
1245
+ function CleanButton() {
1246
+ const { t } = useTranslation();
1247
+ const { theme, icons, writable, cleanCurrentScene } = useContext4(ToolbarContext);
1248
+ const disabled = !writable;
1249
+ return React34.createElement(Button, {
1250
+ content: t("clean"),
1251
+ onClick: cleanCurrentScene
1252
+ }, React34.createElement(Icon, {
1253
+ fallback: React34.createElement(Icons.Clean, {
1254
+ theme
1255
+ }),
1256
+ src: disabled ? icons == null ? void 0 : icons.cleanIconDisable : icons == null ? void 0 : icons.cleanIcon,
1257
+ alt: "[clean]"
1258
+ }));
1259
+ }
1260
+
1261
+ // src/components/Toolbar/components/AppsButton.tsx
1262
+ import Tippy5 from "@tippyjs/react";
1263
+ import React35, { useContext as useContext5 } from "react";
1264
+
1265
+ // src/components/Toolbar/components/assets/vscode.png
1266
+ var vscode_default = "data:image/png;base64,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";
1267
+
1268
+ // src/components/Toolbar/components/assets/geogebra.png
1269
+ var geogebra_default = "data:image/png;base64,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";
1270
+
1271
+ // src/components/Toolbar/components/assets/countdown.png
1272
+ var countdown_default = "data:image/png;base64,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";
1273
+
1274
+ // src/components/Toolbar/components/AppsButton.tsx
1275
+ function AppsButton({ content, onClick }) {
1276
+ const { theme, icons, writable } = useContext5(ToolbarContext);
1277
+ const disabled = !writable;
1278
+ const button = React35.createElement(Button, {
1279
+ content: "Apps",
1280
+ onClick
1281
+ }, React35.createElement(Icon, {
1282
+ fallback: React35.createElement(Icons.Apps, {
1283
+ theme
1284
+ }),
1285
+ src: disabled ? icons == null ? void 0 : icons.appsIconDisable : icons == null ? void 0 : icons.appsIcon,
1286
+ alt: "[apps]"
1287
+ }));
1288
+ return content === false ? button : React35.createElement("span", {
1289
+ className: "fastboard-toolbar-btn-interactive"
1290
+ }, React35.createElement(Tippy5, {
1291
+ className: "fastboard-tip",
1292
+ content: renderAppsButtonContent(content),
1293
+ theme,
1294
+ placement: "right-end",
1295
+ trigger: "click",
1296
+ offset: RightOffset,
1297
+ arrow: false,
1298
+ interactive: true
1299
+ }, button));
1300
+ }
1301
+ function renderAppsButtonContent(content) {
1302
+ return React35.createElement("div", {
1303
+ className: "fastboard-toolbar-panel apps"
1304
+ }, React35.createElement("div", {
1305
+ className: "fastboard-toolbar-apps"
1306
+ }, content || React35.createElement(DefaultApps, null)));
1307
+ }
1308
+ function DefaultApps() {
1309
+ const app = useFastboardApp();
1310
+ return React35.createElement(React35.Fragment, null, React35.createElement(AppIcon, {
1311
+ title: "Code Editor",
1312
+ src: vscode_default,
1313
+ alt: "[code editor]",
1314
+ onClick: app == null ? void 0 : app.insertCodeEditor.bind(app)
1315
+ }), React35.createElement(AppIcon, {
1316
+ title: "GeoGebra",
1317
+ src: geogebra_default,
1318
+ alt: "[geogebra]",
1319
+ onClick: app == null ? void 0 : app.insertGeoGebra.bind(app)
1320
+ }), React35.createElement(AppIcon, {
1321
+ title: "Countdown",
1322
+ src: countdown_default,
1323
+ alt: "[countdown]",
1324
+ onClick: app == null ? void 0 : app.insertCountdown.bind(app)
1325
+ }));
1326
+ }
1327
+ function AppIcon({ title, src, alt, onClick }) {
1328
+ return React35.createElement("span", {
1329
+ className: "fastboard-toolbar-app-icon"
1330
+ }, React35.createElement(Button, {
1331
+ placement: "top",
1332
+ content: title,
1333
+ onClick
1334
+ }, React35.createElement("img", {
1335
+ src,
1336
+ alt,
1337
+ title
1338
+ })), React35.createElement("span", {
1339
+ className: "fastboard-toolbar-app-icon-text"
1340
+ }, title));
1341
+ }
1342
+
1343
+ // src/components/Toolbar/components/PencilButton.tsx
1344
+ import Tippy6 from "@tippyjs/react";
1345
+ import React39, { useCallback as useCallback7, useContext as useContext9 } from "react";
1346
+ import { ApplianceNames as ApplianceNames2 } from "white-web-sdk";
1347
+
1348
+ // src/components/Toolbar/components/ColorBox.tsx
1349
+ import clsx5 from "clsx";
1350
+ import React36, { useContext as useContext6 } from "react";
1351
+ var colors = {
1352
+ "#E02020": [224, 32, 32],
1353
+ "#F7B500": [247, 181, 0],
1354
+ "#6DD400": [109, 212, 0],
1355
+ "#32C5FF": [50, 197, 255],
1356
+ "#0091FF": [0, 145, 255],
1357
+ "#6236FF": [98, 54, 255],
1358
+ "#B620E0": [182, 32, 224],
1359
+ "#6D7278": [109, 114, 120]
1360
+ };
1361
+ var colorKeys = Object.keys(colors);
1362
+ function ColorBox() {
1363
+ const { theme, memberState, setStrokeColor, writable } = useContext6(ToolbarContext);
1364
+ const strokeColor = memberState == null ? void 0 : memberState.strokeColor;
1365
+ const disabled = !writable;
1366
+ return React36.createElement("div", {
1367
+ className: clsx5("fastboard-toolbar-color-box", theme)
1368
+ }, colorKeys.map((key) => React36.createElement("div", {
1369
+ key,
1370
+ className: clsx5("fastboard-toolbar-color-item", theme),
1371
+ onClick: () => setStrokeColor(colors[key])
1372
+ }, React36.createElement("div", {
1373
+ className: clsx5("fastboard-toolbar-color-border", theme, {
1374
+ active: strokeColor && isEqualArray(strokeColor, colors[key])
1375
+ })
1376
+ }, React36.createElement("button", {
1377
+ className: clsx5("fastboard-toolbar-color-btn"),
1378
+ style: { background: key },
1379
+ disabled,
1380
+ onClick: (ev) => {
1381
+ ev.stopPropagation();
1382
+ setStrokeColor(colors[key]);
1383
+ }
1384
+ })))));
1385
+ }
1386
+
1387
+ // src/components/Toolbar/components/CutLine.tsx
1388
+ import clsx6 from "clsx";
1389
+ import React37, { useContext as useContext7 } from "react";
1390
+ function CutLine() {
1391
+ const { theme } = useContext7(ToolbarContext);
1392
+ return React37.createElement("span", {
1393
+ className: clsx6(`${name4}-cut-line`, theme)
1394
+ });
1395
+ }
1396
+
1397
+ // src/components/Toolbar/components/Slider.tsx
1398
+ import clsx7 from "clsx";
1399
+ import RcSlider from "rc-slider";
1400
+ import React38, { useContext as useContext8 } from "react";
1401
+ function Slider() {
1402
+ const { theme, writable, memberState, setStrokeWidth } = useContext8(ToolbarContext);
1403
+ const { activeColor } = themes[theme];
1404
+ const strokeWidth = (memberState == null ? void 0 : memberState.strokeWidth) || 0;
1405
+ return React38.createElement(RcSlider, {
1406
+ disabled: !writable,
1407
+ className: clsx7("fastboard-toolbar-slider", theme),
1408
+ trackStyle: { background: activeColor },
1409
+ handleStyle: { border: `1px solid ${activeColor}` },
1410
+ value: strokeWidth,
1411
+ onChange: setStrokeWidth,
1412
+ min: 1,
1413
+ max: 32
1414
+ });
1415
+ }
1416
+
1417
+ // src/components/Toolbar/components/PencilButton.tsx
1418
+ function PencilButton() {
1419
+ const app = useFastboardApp();
1420
+ const { t } = useTranslation();
1421
+ const { theme, icons, writable, setAppliance, memberState } = useContext9(ToolbarContext);
1422
+ const changeAppliance = useCallback7(() => {
1423
+ setAppliance(ApplianceNames2.pencil);
1424
+ }, [setAppliance]);
1425
+ const appliance = memberState == null ? void 0 : memberState.currentApplianceName;
1426
+ const active = appliance === ApplianceNames2.pencil;
1427
+ const disabled = !writable;
1428
+ const shortcut = ((app == null ? void 0 : app.hotKeys) || defaultHotKeys).changeToPencil;
1429
+ return React39.createElement("span", {
1430
+ className: "fastboard-toolbar-btn-interactive"
1431
+ }, React39.createElement(Tippy6, {
1432
+ className: "fastboard-tip",
1433
+ content: renderPencilButtonContent(),
1434
+ theme,
1435
+ placement: "right-start",
1436
+ trigger: "click",
1437
+ offset: RightOffset,
1438
+ arrow: false,
1439
+ interactive: true
1440
+ }, React39.createElement(Button, {
1441
+ content: renderToolTip(t("pencil"), shortcut),
1442
+ active,
1443
+ onClick: changeAppliance
1444
+ }, React39.createElement(Icon, {
1445
+ fallback: React39.createElement(Icons.Pencil, {
1446
+ theme,
1447
+ active
1448
+ }),
1449
+ src: disabled ? icons == null ? void 0 : icons.pencilIconDisable : icons == null ? void 0 : icons.pencilIcon,
1450
+ alt: "[pencil]"
1451
+ }), React39.createElement("span", {
1452
+ className: "fastboard-toolbar-triangle"
1453
+ }))));
1454
+ }
1455
+ function renderPencilButtonContent() {
1456
+ return React39.createElement("div", {
1457
+ className: "fastboard-toolbar-panel pencil"
1458
+ }, React39.createElement(Slider, null), React39.createElement(CutLine, null), React39.createElement(ColorBox, null));
1459
+ }
1460
+
1461
+ // src/components/Toolbar/components/ShapesButton.tsx
1462
+ import Tippy7 from "@tippyjs/react";
1463
+ import React40, { useContext as useContext10 } from "react";
1464
+ import { ApplianceNames as ApplianceNames4 } from "white-web-sdk";
1465
+
1466
+ // src/components/Toolbar/const.ts
1467
+ import { ApplianceNames as ApplianceNames3, ShapeType } from "white-web-sdk";
1468
+ var ShapesMap = {
1469
+ [ApplianceNames3.rectangle]: Icons.Rectangle,
1470
+ [ApplianceNames3.ellipse]: Icons.Circle,
1471
+ [ApplianceNames3.straight]: Icons.Line,
1472
+ [ApplianceNames3.arrow]: Icons.Arrow,
1473
+ [ShapeType.Pentagram]: Icons.Star,
1474
+ [ShapeType.Rhombus]: Icons.Diamond,
1475
+ [ShapeType.Triangle]: Icons.Triangle,
1476
+ [ShapeType.SpeechBalloon]: Icons.SpeechBalloon
1477
+ };
1478
+ var ApplianceShapes = [
1479
+ ApplianceNames3.rectangle,
1480
+ ApplianceNames3.ellipse,
1481
+ ApplianceNames3.straight,
1482
+ ApplianceNames3.arrow
1483
+ ];
1484
+ var Shapes = [
1485
+ ShapeType.Pentagram,
1486
+ ShapeType.Rhombus,
1487
+ ShapeType.Triangle,
1488
+ ShapeType.SpeechBalloon
1489
+ ];
1490
+ var ItemHeight = 32 + 4;
1491
+ var ItemsCount = 8;
1492
+ var MaxHeight = ItemHeight * ItemsCount - 4;
1493
+ var MinHeight = ItemHeight * 2 - 4;
1494
+
1495
+ // src/components/Toolbar/components/ShapesButton.tsx
1496
+ var ShapeTypes = /* @__PURE__ */ new Set([...ApplianceShapes, ...Shapes]);
1497
+ function ShapesButton() {
1498
+ const { t } = useTranslation();
1499
+ const { theme, memberState } = useContext10(ToolbarContext);
1500
+ const appliance = memberState == null ? void 0 : memberState.currentApplianceName;
1501
+ const shape = memberState == null ? void 0 : memberState.shapeType;
1502
+ const key = appliance === ApplianceNames4.shape ? shape : appliance;
1503
+ const active = ShapeTypes.has(key);
1504
+ const CurrentIcon = ShapesMap[key] || Icons.Rectangle;
1505
+ return React40.createElement("span", {
1506
+ className: "fastboard-toolbar-btn-interactive"
1507
+ }, React40.createElement(Tippy7, {
1508
+ className: "fastboard-tip",
1509
+ content: renderShapesButtonContent(),
1510
+ theme,
1511
+ placement: "right-start",
1512
+ trigger: "click",
1513
+ offset: RightOffset,
1514
+ arrow: false,
1515
+ interactive: true
1516
+ }, React40.createElement(Button, {
1517
+ content: t("shape"),
1518
+ active
1519
+ }, React40.createElement(CurrentIcon, {
1520
+ theme,
1521
+ active
1522
+ }), React40.createElement("span", {
1523
+ className: "fastboard-toolbar-triangle"
1524
+ }))));
1525
+ }
1526
+ function renderShapesButtonContent() {
1527
+ return React40.createElement("div", {
1528
+ className: "fastboard-toolbar-panel shapes"
1529
+ }, React40.createElement(ShapesBox, null), React40.createElement(CutLine, null), React40.createElement(Slider, null), React40.createElement(CutLine, null), React40.createElement(ColorBox, null));
1530
+ }
1531
+ function ShapesBox() {
1532
+ const { t } = useTranslation();
1533
+ return React40.createElement("div", {
1534
+ className: "fastboard-toolbar-shapes"
1535
+ }, ApplianceShapes.map((Appliance) => React40.createElement(ApplianceShapeButton, {
1536
+ key: Appliance,
1537
+ content: t(Appliance),
1538
+ Appliance,
1539
+ Icon: ShapesMap[Appliance]
1540
+ })), Shapes.map((shape) => React40.createElement(ShapeShapeButton, {
1541
+ key: shape,
1542
+ content: t(shape),
1543
+ shape,
1544
+ Icon: ShapesMap[shape]
1545
+ })));
1546
+ }
1547
+ function ApplianceShapeButton({ content, Appliance, Icon: Icon2 }) {
1548
+ const { theme, writable, setAppliance, memberState } = useContext10(ToolbarContext);
1549
+ const current = memberState == null ? void 0 : memberState.currentApplianceName;
1550
+ const disabled = !writable;
1551
+ return React40.createElement(Button, {
1552
+ content,
1553
+ disabled,
1554
+ placement: "top",
1555
+ onClick: () => setAppliance(Appliance)
1556
+ }, React40.createElement(Icon2, {
1557
+ theme,
1558
+ active: current === Appliance
1559
+ }));
1560
+ }
1561
+ function ShapeShapeButton({ content, shape, Icon: Icon2 }) {
1562
+ const { theme, writable, setAppliance, memberState } = useContext10(ToolbarContext);
1563
+ const appliance = memberState == null ? void 0 : memberState.currentApplianceName;
1564
+ const current = appliance === ApplianceNames4.shape && (memberState == null ? void 0 : memberState.shapeType);
1565
+ const disabled = !writable;
1566
+ return React40.createElement(Button, {
1567
+ content,
1568
+ disabled,
1569
+ placement: "top",
1570
+ onClick: () => setAppliance(ApplianceNames4.shape, shape)
1571
+ }, React40.createElement(Icon2, {
1572
+ theme,
1573
+ active: current === shape
1574
+ }));
1575
+ }
1576
+
1577
+ // src/components/Toolbar/components/TextButton.tsx
1578
+ import Tippy8 from "@tippyjs/react";
1579
+ import React41, { useCallback as useCallback8, useContext as useContext11 } from "react";
1580
+ import { ApplianceNames as ApplianceNames5 } from "white-web-sdk";
1581
+ function TextButton() {
1582
+ const app = useFastboardApp();
1583
+ const { t } = useTranslation();
1584
+ const { theme, icons, writable, setAppliance, memberState } = useContext11(ToolbarContext);
1585
+ const changeAppliance = useCallback8(() => {
1586
+ setAppliance(ApplianceNames5.text);
1587
+ }, [setAppliance]);
1588
+ const appliance = memberState == null ? void 0 : memberState.currentApplianceName;
1589
+ const active = appliance === ApplianceNames5.text;
1590
+ const disabled = !writable;
1591
+ const shortcut = ((app == null ? void 0 : app.hotKeys) || defaultHotKeys).changeToText;
1592
+ return React41.createElement("span", {
1593
+ className: "fastboard-toolbar-btn-interactive"
1594
+ }, React41.createElement(Tippy8, {
1595
+ className: "fastboard-tip",
1596
+ content: renderTextButtonContent(),
1597
+ theme,
1598
+ placement: "right-start",
1599
+ trigger: "click",
1600
+ offset: RightOffset,
1601
+ arrow: false,
1602
+ interactive: true
1603
+ }, React41.createElement(Button, {
1604
+ content: renderToolTip(t("text"), shortcut),
1605
+ active,
1606
+ onClick: changeAppliance
1607
+ }, React41.createElement(Icon, {
1608
+ fallback: React41.createElement(Icons.Text, {
1609
+ theme,
1610
+ active
1611
+ }),
1612
+ src: disabled ? icons == null ? void 0 : icons.textIconDisable : icons == null ? void 0 : icons.textIcon,
1613
+ alt: "[text]"
1614
+ }), React41.createElement("span", {
1615
+ className: "fastboard-toolbar-triangle"
1616
+ }))));
1617
+ }
1618
+ function renderTextButtonContent() {
1619
+ return React41.createElement("div", {
1620
+ className: "fastboard-toolbar-panel text"
1621
+ }, React41.createElement(ColorBox, null));
1622
+ }
1623
+
1624
+ // src/components/Toolbar/components/UpDownButtons.tsx
1625
+ import React42, { useCallback as useCallback9, useContext as useContext12 } from "react";
1626
+ function UpButton({ disabled, scrollTo }) {
1627
+ const { theme, icons } = useContext12(ToolbarContext);
1628
+ const scrollUp = useCallback9(() => scrollTo(-ItemHeight), [scrollTo]);
1629
+ return React42.createElement(React42.Fragment, null, React42.createElement(Button, {
1630
+ content: "Up",
1631
+ disabled,
1632
+ onClick: scrollUp
1633
+ }, React42.createElement(Icon, {
1634
+ fallback: React42.createElement(Icons.Up, {
1635
+ theme
1636
+ }),
1637
+ src: disabled ? icons == null ? void 0 : icons.upIconDisable : icons == null ? void 0 : icons.upIcon,
1638
+ alt: "[up]"
1639
+ })), React42.createElement(CutLine, null));
1640
+ }
1641
+ function DownButton({ disabled, scrollTo }) {
1642
+ const { theme, icons } = useContext12(ToolbarContext);
1643
+ const scrollDown = useCallback9(() => scrollTo(ItemHeight), [scrollTo]);
1644
+ return React42.createElement(React42.Fragment, null, React42.createElement(CutLine, null), React42.createElement(Button, {
1645
+ content: "Down",
1646
+ disabled,
1647
+ onClick: scrollDown
1648
+ }, React42.createElement(Icon, {
1649
+ fallback: React42.createElement(Icons.Down, {
1650
+ theme
1651
+ }),
1652
+ src: disabled ? icons == null ? void 0 : icons.downIconDisable : icons == null ? void 0 : icons.downIcon,
1653
+ alt: "[down]"
1654
+ })));
1655
+ }
1656
+
1657
+ // src/components/Toolbar/Content.tsx
1658
+ var Content = React43.memo(() => {
1659
+ const ref = useRef2(null);
1660
+ const [scrollTop, setScrollTop] = useState5(0);
1661
+ const [parentHeight, setParentHeight] = useState5(0);
1662
+ const needScroll = parentHeight < ItemHeight * ItemsCount + 48;
1663
+ const sectionHeight = clamp(parentHeight - 48 * (needScroll ? 3 : 1), MinHeight, MaxHeight);
1664
+ const scrollBuffer = Math.max(parentHeight - sectionHeight - 1, 0);
1665
+ const disableScrollUp = scrollTop === 0;
1666
+ const disableScrollDown = scrollTop === scrollBuffer;
1667
+ const scrollTo = useCallback10((height) => {
1668
+ setScrollTop(clamp(scrollTop + height, 0, scrollBuffer));
1669
+ }, [scrollBuffer, scrollTop]);
1670
+ useEffect5(() => {
1671
+ if (ref.current) {
1672
+ ref.current.scrollTop = scrollTop;
1673
+ }
1674
+ }, [scrollTop]);
1675
+ useEffect5(() => {
1676
+ var _a, _b;
1677
+ const container = (_b = (_a = ref.current) == null ? void 0 : _a.parentElement) == null ? void 0 : _b.parentElement;
1678
+ if (container) {
1679
+ const { paddingTop, paddingBottom } = getComputedStyle(container);
1680
+ const padding = parseInt(paddingTop) + parseInt(paddingBottom) || 0;
1681
+ const resizeObserver = new ResizeObserver(() => {
1682
+ setParentHeight(container.getBoundingClientRect().height - padding);
1683
+ });
1684
+ resizeObserver.observe(container);
1685
+ return () => resizeObserver.disconnect();
1686
+ }
1687
+ }, []);
1688
+ return React43.createElement(React43.Fragment, null, needScroll && React43.createElement(UpButton, {
1689
+ scrollTo,
1690
+ disabled: disableScrollUp
1691
+ }), React43.createElement("div", {
1692
+ ref,
1693
+ className: clsx8(`${name4}-section`),
1694
+ style: {
1695
+ height: `${sectionHeight}px`,
1696
+ overflow: needScroll ? "hidden" : "visible"
1697
+ }
1698
+ }, React43.createElement(ClickerButton, null), React43.createElement(SelectorButton, null), React43.createElement(PencilButton, null), React43.createElement(TextButton, null), React43.createElement(ShapesButton, null), React43.createElement(EraserButton, null), React43.createElement(CleanButton, null), React43.createElement(AppsButton, null)), needScroll && React43.createElement(DownButton, {
1699
+ scrollTo,
1700
+ disabled: disableScrollDown
1701
+ }));
1702
+ });
1703
+
1704
+ // src/components/Toolbar/Toolbar.tsx
1705
+ var ToolbarContext = createContext3(__spreadValues({
1706
+ theme: "light"
1707
+ }, EmptyToolbarHook));
1708
+ var name4 = "fastboard-toolbar";
1709
+ var Toolbar = ({ theme, icons }) => {
1710
+ theme = useTheme(theme);
1711
+ const hook = useToolbar();
1712
+ const [expanded, setExpanded] = useState6(true);
1713
+ const [toolbar, toolbarRef] = useState6(null);
1714
+ const [onHover, setOnHover] = useState6(false);
1715
+ const [delayedOnHover, setDelayedOnHover] = useState6(false);
1716
+ const [pointEvents, setPointEvents] = useState6(true);
1717
+ const disabled = !hook.writable;
1718
+ const toggle = useCallback11(() => {
1719
+ setExpanded((e) => !e);
1720
+ }, []);
1721
+ useEffect6(() => {
1722
+ const timer = setTimeout(() => {
1723
+ setDelayedOnHover(onHover);
1724
+ }, 400);
1725
+ return () => clearTimeout(timer);
1726
+ }, [onHover]);
1727
+ return React44.createElement(ToolbarContext.Provider, {
1728
+ value: __spreadValues({ theme, icons }, hook)
1729
+ }, React44.createElement(AnimatePresence, null, expanded ? React44.createElement(motion.div, {
1730
+ initial: { x: -100 },
1731
+ animate: { x: 0, transition: { duration: 0.5 } },
1732
+ key: "toolbar",
1733
+ ref: toolbarRef,
1734
+ className: clsx9(name4, theme),
1735
+ onPointerEnter: () => {
1736
+ expanded && setOnHover(true);
1737
+ },
1738
+ onMouseLeave: () => setOnHover(false),
1739
+ exit: { x: -100, transition: { duration: 0.5 } },
1740
+ onAnimationStart: () => setPointEvents(false),
1741
+ onAnimationComplete: () => setPointEvents(true),
1742
+ style: { pointerEvents: pointEvents ? "auto" : "none" }
1743
+ }, React44.createElement(Content, null), expanded && (onHover || delayedOnHover) && React44.createElement(Mask, {
1744
+ toolbar
1745
+ }, React44.createElement("div", {
1746
+ onClick: toggle
1747
+ }, React44.createElement("img", {
1748
+ draggable: false,
1749
+ className: clsx9(`${name4}-mask-btn`, theme),
1750
+ src: collapsed_default
1751
+ })))) : React44.createElement(motion.div, {
1752
+ className: clsx9(`${name4}-expand-btn`, theme),
1753
+ key: "expand",
1754
+ onClick: toggle,
1755
+ initial: { x: -100 },
1756
+ animate: { x: 0, transition: { duration: 0.5 } }
1757
+ }, !expanded && React44.createElement(Icon, {
1758
+ fallback: React44.createElement("img", {
1759
+ draggable: false,
1760
+ src: expanded_default,
1761
+ className: clsx9(`${name4}-mask-btn`, theme)
1762
+ }),
1763
+ src: disabled ? icons == null ? void 0 : icons.expandIconDisable : icons == null ? void 0 : icons.expandIcon
1764
+ }))));
1765
+ };
1766
+
1767
+ // src/components/PlayerControl/hooks.ts
1768
+ import { useCallback as useCallback12, useEffect as useEffect7, useState as useState7 } from "react";
1769
+ import { PlayerPhase } from "white-web-sdk";
1770
+ var EMPTY_ARRAY = [];
1771
+ function useForceUpdate2() {
1772
+ const [, forceUpdate_] = useState7({});
1773
+ return useCallback12(() => forceUpdate_({}), EMPTY_ARRAY);
1774
+ }
1775
+ function usePlayerControl(player) {
1776
+ const togglePlay = useCallback12(() => {
1777
+ if (player) {
1778
+ switch (player.phase) {
1779
+ case PlayerPhase.WaitingFirstFrame:
1780
+ case PlayerPhase.Pause:
1781
+ case PlayerPhase.Ended: {
1782
+ player.play();
1783
+ break;
1784
+ }
1785
+ case PlayerPhase.Playing: {
1786
+ player.pause();
1787
+ break;
1788
+ }
1789
+ }
1790
+ }
1791
+ }, [player]);
1792
+ const seekToProgressTime = useCallback12((time) => {
1793
+ if (player) {
1794
+ player.seekToProgressTime(time);
1795
+ }
1796
+ }, [player]);
1797
+ const lastPlayer = useLastValue(player);
1798
+ const forceUpdate = useForceUpdate2();
1799
+ const setSpeed = useCallback12((speed2) => {
1800
+ if (player) {
1801
+ player.playbackSpeed = speed2;
1802
+ forceUpdate();
1803
+ }
1804
+ }, [forceUpdate, player]);
1805
+ useEffect7(() => {
1806
+ if (!lastPlayer && player) {
1807
+ forceUpdate();
1808
+ }
1809
+ }, [forceUpdate, lastPlayer, player]);
1810
+ useEffect7(() => {
1811
+ if (player) {
1812
+ player.callbacks.on("onPhaseChanged", forceUpdate);
1813
+ player.callbacks.on("onProgressTimeChanged", forceUpdate);
1814
+ return () => {
1815
+ player.callbacks.off("onPhaseChanged", forceUpdate);
1816
+ player.callbacks.off("onProgressTimeChanged", forceUpdate);
1817
+ };
1818
+ }
1819
+ }, [forceUpdate, player]);
1820
+ const phase = player ? player.phase : PlayerPhase.WaitingFirstFrame;
1821
+ const currentTime = player ? player.progressTime : 0;
1822
+ const totalTime = player ? player.timeDuration : 0;
1823
+ const speed = player ? player.playbackSpeed : 1;
1824
+ return {
1825
+ phase,
1826
+ currentTime,
1827
+ totalTime,
1828
+ speed,
1829
+ setSpeed,
1830
+ togglePlay,
1831
+ seekToProgressTime
1832
+ };
1833
+ }
1834
+
1835
+ // src/components/PlayerControl/PlayerControl.tsx
1836
+ import Tippy10 from "@tippyjs/react";
1837
+ import clsx11 from "clsx";
1838
+ import RcSlider2 from "rc-slider";
1839
+ import React49, { useEffect as useEffect8, useState as useState8 } from "react";
1840
+ import { PlayerPhase as PlayerPhase2 } from "white-web-sdk";
1841
+
1842
+ // src/components/PlayerControl/components/Button.tsx
1843
+ import clsx10 from "clsx";
1844
+ import React45, { forwardRef as forwardRef2 } from "react";
1845
+ import Tippy9 from "@tippyjs/react";
1846
+ var Button2 = forwardRef2((props, ref) => {
1847
+ const { theme, content, disabled, active, onClick, interactive, placement = "top", children } = props;
1848
+ return React45.createElement(Tippy9, {
1849
+ className: "fastboard-tip",
1850
+ content,
1851
+ interactive,
1852
+ theme,
1853
+ disabled,
1854
+ placement,
1855
+ offset: TopOffset,
1856
+ delay: [1e3, 400],
1857
+ duration: 300
1858
+ }, React45.createElement("button", {
1859
+ ref,
1860
+ className: clsx10("fastboard-player-control-btn", theme, { active }),
1861
+ onClick,
1862
+ disabled
1863
+ }, children));
1864
+ });
1865
+
1866
+ // src/components/PlayerControl/icons/index.ts
1867
+ import { memo as memo2 } from "react";
1868
+
1869
+ // src/components/PlayerControl/icons/Loading.tsx
1870
+ import React46 from "react";
1871
+ var Loading = (props) => {
1872
+ const stroke = getStroke(props);
1873
+ return React46.createElement("svg", {
1874
+ viewBox: "0 0 24 24"
1875
+ }, React46.createElement("path", {
1876
+ d: "M12 4V2A10 10 0 0 0 2 12h2a8 8 0 0 1 8-8z",
1877
+ fill: stroke
1878
+ }));
1879
+ };
1880
+
1881
+ // src/components/PlayerControl/icons/Pause.tsx
1882
+ import React47 from "react";
1883
+ var Pause = (props) => {
1884
+ const stroke = getStroke(props);
1885
+ return React47.createElement("svg", {
1886
+ viewBox: "0 0 24 24"
1887
+ }, React47.createElement("path", {
1888
+ d: "M14 19h4V5h-4M6 19h4V5H6v14z",
1889
+ fill: stroke
1890
+ }));
1891
+ };
1892
+
1893
+ // src/components/PlayerControl/icons/Play.tsx
1894
+ import React48 from "react";
1895
+ var Play = (props) => {
1896
+ const stroke = getStroke(props);
1897
+ return React48.createElement("svg", {
1898
+ viewBox: "0 0 24 24"
1899
+ }, React48.createElement("path", {
1900
+ d: "M8 5.14v14l11-7l-11-7z",
1901
+ fill: stroke
1902
+ }));
1903
+ };
1904
+
1905
+ // src/components/PlayerControl/icons/index.ts
1906
+ var Icons2 = {
1907
+ Play: memo2(Play),
1908
+ Pause: memo2(Pause),
1909
+ Loading: memo2(Loading)
1910
+ };
1911
+
1912
+ // src/components/PlayerControl/PlayerControl.tsx
1913
+ var name5 = "fastboard-player-control";
1914
+ function PlayerControl(_a) {
1915
+ var _b = _a, { theme, autoHide = false, player: player_ } = _b, icons = __objRest(_b, ["theme", "autoHide", "player"]);
1916
+ theme = useTheme(theme);
1917
+ const { t } = useTranslation();
1918
+ const [currentTime, setCurrentTime] = useState8(0);
1919
+ const player = usePlayerControl(player_);
1920
+ useEffect8(() => {
1921
+ setCurrentTime(player.currentTime);
1922
+ }, [player.currentTime]);
1923
+ useEffect8(() => {
1924
+ if (player.currentTime !== currentTime) {
1925
+ player.seekToProgressTime(currentTime);
1926
+ }
1927
+ }, [currentTime]);
1928
+ const isLoading = player.phase === PlayerPhase2.WaitingFirstFrame || player.phase === PlayerPhase2.Buffering;
1929
+ const isPlaying = player.phase === PlayerPhase2.Playing;
1930
+ const { activeColor } = themes[theme];
1931
+ return React49.createElement("div", {
1932
+ className: clsx11(name5, theme, { "auto-hide": autoHide })
1933
+ }, React49.createElement("button", {
1934
+ className: clsx11(`${name5}-btn`, isLoading ? "loading" : isPlaying ? "pause" : "play", theme),
1935
+ disabled: isLoading,
1936
+ onClick: player.togglePlay
1937
+ }, React49.createElement(Icon, {
1938
+ fallback: isLoading ? React49.createElement(Icons2.Loading, {
1939
+ theme
1940
+ }) : isPlaying ? React49.createElement(Icons2.Pause, {
1941
+ theme
1942
+ }) : React49.createElement(Icons2.Play, {
1943
+ theme
1944
+ }),
1945
+ src: isLoading ? icons.loadingIcon : isPlaying ? icons.pauseIcon : icons.playIcon,
1946
+ alt: isLoading ? "[loading]" : isPlaying ? "[pause]" : "[play]"
1947
+ })), React49.createElement("span", {
1948
+ className: clsx11(`${name5}-slider`, { loading: isLoading }, theme)
1949
+ }, React49.createElement(RcSlider2, {
1950
+ disabled: isLoading,
1951
+ trackStyle: { background: activeColor },
1952
+ handleStyle: { border: `1px solid ${activeColor}` },
1953
+ value: currentTime,
1954
+ onChange: setCurrentTime,
1955
+ min: 0,
1956
+ max: player.totalTime,
1957
+ step: 100
1958
+ })), React49.createElement("span", {
1959
+ className: clsx11(`${name5}-current`, theme)
1960
+ }, renderTime(player.currentTime)), React49.createElement("span", {
1961
+ className: clsx11(`${name5}-slash`, theme)
1962
+ }, "/"), React49.createElement("span", {
1963
+ className: clsx11(`${name5}-total`, theme)
1964
+ }, renderTime(player.totalTime)), React49.createElement("span", {
1965
+ className: `${name5}-btn-interactive`
1966
+ }, React49.createElement(Tippy10, {
1967
+ className: "fastboard-tip",
1968
+ content: renderSpeeds(player),
1969
+ theme,
1970
+ placement: "top-end",
1971
+ trigger: "click",
1972
+ offset: TopOffset,
1973
+ arrow: false,
1974
+ interactive: true
1975
+ }, React49.createElement(Button2, {
1976
+ content: t("speed"),
1977
+ theme,
1978
+ disabled: isLoading
1979
+ }, React49.createElement("span", {
1980
+ className: clsx11(`${name5}-speed-text`, theme)
1981
+ }, player.speed, "x")))));
1982
+ }
1983
+ function renderTime(ms) {
1984
+ let seconds = ms / 1e3;
1985
+ const minutes = Math.floor(seconds / 60);
1986
+ seconds = Math.floor(seconds) % 60;
1987
+ return `${String(minutes).padStart(2, "0")}:${String(seconds).padStart(2, "0")}`;
1988
+ }
1989
+ var Speeds = [2, 1.5, 1.25, 1, 0.75, 0.5];
1990
+ function renderSpeeds({ speed: current, setSpeed }) {
1991
+ return React49.createElement("div", {
1992
+ className: clsx11(`${name5}-panel`, "speed")
1993
+ }, Speeds.map((speed) => React49.createElement("button", {
1994
+ className: clsx11(`${name5}-btn`, "speed", {
1995
+ active: speed === current
1996
+ }),
1997
+ key: speed,
1998
+ onClick: () => setSpeed(speed)
1999
+ }, speed, "x")));
2000
+ }
2001
+
2002
+ // src/components/Fastboard.tsx
2003
+ import React50, { useCallback as useCallback13, useEffect as useEffect9 } from "react";
2004
+ function Fastboard(_a) {
2005
+ var _b = _a, { app } = _b, restProps = __objRest(_b, ["app"]);
2006
+ if (!app) {
2007
+ return React50.createElement("div", {
2008
+ className: "fastboard-root"
2009
+ });
2010
+ }
2011
+ return React50.createElement(FastboardAppContext.Provider, {
2012
+ value: app
2013
+ }, React50.createElement(FastboardInternal, __spreadValues({}, restProps)));
2014
+ }
2015
+ function FastboardInternal({
2016
+ language,
2017
+ layout = {},
2018
+ theme = "light",
2019
+ children
2020
+ }) {
2021
+ const app = useFastboardApp();
2022
+ const forceUpdate = useForceUpdate();
2023
+ const i18n = useAsyncValue(() => createI18n({ language }));
2024
+ useEffect9(() => {
2025
+ if (i18n)
2026
+ i18n.changeLanguage(language);
2027
+ forceUpdate();
2028
+ }, [forceUpdate, i18n, language]);
2029
+ const useWhiteboard = useCallback13((container) => {
2030
+ container && app && app.manager.bindContainer(container);
2031
+ }, [app]);
2032
+ const hideControls = useHideControls();
2033
+ const showControls = !hideControls;
2034
+ const {
2035
+ Toolbar: toolbar = showControls || hideControls === "toolbar-only",
2036
+ RedoUndo: redo_undo = showControls,
2037
+ ZoomControl: zoom_control = showControls,
2038
+ PageControl: page_control = showControls
2039
+ } = layout;
2040
+ return React50.createElement(ThemeContext.Provider, {
2041
+ value: theme
2042
+ }, React50.createElement(I18nContext.Provider, {
2043
+ value: i18n
2044
+ }, React50.createElement("div", {
2045
+ className: "fastboard-root"
2046
+ }, React50.createElement("div", {
2047
+ className: "fastboard-view",
2048
+ ref: useWhiteboard
2049
+ }), children ? children : React50.createElement(React50.Fragment, null, toolbar && React50.createElement("div", {
2050
+ className: "fastboard-left"
2051
+ }, React50.createElement(Toolbar, null)), (redo_undo || zoom_control) && React50.createElement("div", {
2052
+ className: "fastboard-bottom-left"
2053
+ }, redo_undo && React50.createElement(RedoUndo, null), zoom_control && React50.createElement(ZoomControl, null)), page_control && React50.createElement("div", {
2054
+ className: "fastboard-bottom-right"
2055
+ }, React50.createElement(PageControl, null))))));
2056
+ }
2057
+ export {
2058
+ EmptyToolbarHook,
2059
+ Fastboard,
2060
+ FastboardAppContext,
2061
+ PageControl,
2062
+ PlayerControl,
2063
+ RedoUndo,
2064
+ ScalePoints,
2065
+ ThemeContext,
2066
+ Toolbar,
2067
+ ZoomControl,
2068
+ useBoxState,
2069
+ useFastboardApp,
2070
+ useFastboardValue,
2071
+ useFocusedApp,
2072
+ useHideControls,
2073
+ useMaximized,
2074
+ usePageControl,
2075
+ usePlayerControl,
2076
+ useRedoUndo,
2077
+ useRoomState,
2078
+ useTheme,
2079
+ useToolbar,
2080
+ useWritable,
2081
+ useZoomControl
2082
+ };
2083
+ //# sourceMappingURL=index.mjs.map