@netless/fastboard 0.0.10 → 0.2.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 (103) hide show
  1. package/LICENSE.txt +1 -1
  2. package/dist/index.js +32 -0
  3. package/dist/index.js.map +1 -0
  4. package/dist/index.mjs +7 -0
  5. package/dist/index.mjs.map +1 -0
  6. package/package.json +26 -79
  7. package/src/index.ts +2 -34
  8. package/README.md +0 -126
  9. package/dist/index.cjs.js +0 -14
  10. package/dist/index.cjs.js.map +0 -1
  11. package/dist/index.es.js +0 -2642
  12. package/dist/index.es.js.map +0 -1
  13. package/dist/svelte.cjs.js +0 -2
  14. package/dist/svelte.cjs.js.map +0 -1
  15. package/dist/svelte.es.js +0 -31
  16. package/dist/svelte.es.js.map +0 -1
  17. package/dist/vue.cjs.js +0 -2
  18. package/dist/vue.cjs.js.map +0 -1
  19. package/dist/vue.es.js +0 -42
  20. package/dist/vue.es.js.map +0 -1
  21. package/src/WhiteboardApp.ts +0 -146
  22. package/src/behaviors/register-apps.ts +0 -39
  23. package/src/behaviors/style.ts +0 -17
  24. package/src/components/PageControl.scss +0 -80
  25. package/src/components/PageControl.tsx +0 -181
  26. package/src/components/PlayerControl/PlayerControl.scss +0 -145
  27. package/src/components/PlayerControl/PlayerControl.tsx +0 -158
  28. package/src/components/PlayerControl/components/Button.tsx +0 -55
  29. package/src/components/PlayerControl/hooks.ts +0 -88
  30. package/src/components/PlayerControl/icons/Loading.tsx +0 -13
  31. package/src/components/PlayerControl/icons/Pause.tsx +0 -13
  32. package/src/components/PlayerControl/icons/Play.tsx +0 -13
  33. package/src/components/PlayerControl/icons/index.ts +0 -10
  34. package/src/components/PlayerControl/index.ts +0 -1
  35. package/src/components/RedoUndo.scss +0 -56
  36. package/src/components/RedoUndo.tsx +0 -95
  37. package/src/components/Root.scss +0 -55
  38. package/src/components/Root.tsx +0 -61
  39. package/src/components/Toolbar/Content.tsx +0 -93
  40. package/src/components/Toolbar/Toolbar.scss +0 -247
  41. package/src/components/Toolbar/Toolbar.tsx +0 -82
  42. package/src/components/Toolbar/components/ApplianceButtons.tsx +0 -132
  43. package/src/components/Toolbar/components/AppsButton.tsx +0 -106
  44. package/src/components/Toolbar/components/Button.tsx +0 -54
  45. package/src/components/Toolbar/components/ColorBox.tsx +0 -56
  46. package/src/components/Toolbar/components/CutLine.tsx +0 -8
  47. package/src/components/Toolbar/components/PencilButton.tsx +0 -70
  48. package/src/components/Toolbar/components/ShapesButton.tsx +0 -143
  49. package/src/components/Toolbar/components/Slider.tsx +0 -27
  50. package/src/components/Toolbar/components/TextButton.tsx +0 -66
  51. package/src/components/Toolbar/components/UpDownButtons.tsx +0 -49
  52. package/src/components/Toolbar/components/assets/cocos.png +0 -0
  53. package/src/components/Toolbar/components/assets/countdown.png +0 -0
  54. package/src/components/Toolbar/components/assets/geogebra.png +0 -0
  55. package/src/components/Toolbar/components/assets/vscode.png +0 -0
  56. package/src/components/Toolbar/const.ts +0 -32
  57. package/src/components/Toolbar/hooks.ts +0 -113
  58. package/src/components/Toolbar/icons/Apps.tsx +0 -16
  59. package/src/components/Toolbar/icons/Arrow.tsx +0 -16
  60. package/src/components/Toolbar/icons/Circle.tsx +0 -21
  61. package/src/components/Toolbar/icons/Clean.tsx +0 -16
  62. package/src/components/Toolbar/icons/Clicker.tsx +0 -19
  63. package/src/components/Toolbar/icons/Collapse.tsx +0 -17
  64. package/src/components/Toolbar/icons/Diamond.tsx +0 -17
  65. package/src/components/Toolbar/icons/Down.tsx +0 -17
  66. package/src/components/Toolbar/icons/Eraser.tsx +0 -16
  67. package/src/components/Toolbar/icons/Expand.tsx +0 -17
  68. package/src/components/Toolbar/icons/Line.tsx +0 -13
  69. package/src/components/Toolbar/icons/Pencil.tsx +0 -16
  70. package/src/components/Toolbar/icons/Rectangle.tsx +0 -13
  71. package/src/components/Toolbar/icons/Selector.tsx +0 -16
  72. package/src/components/Toolbar/icons/SpeechBalloon.tsx +0 -17
  73. package/src/components/Toolbar/icons/Star.tsx +0 -17
  74. package/src/components/Toolbar/icons/Text.tsx +0 -16
  75. package/src/components/Toolbar/icons/Triangle.tsx +0 -17
  76. package/src/components/Toolbar/icons/Up.tsx +0 -17
  77. package/src/components/Toolbar/icons/index.ts +0 -42
  78. package/src/components/Toolbar/index.ts +0 -1
  79. package/src/components/ZoomControl.scss +0 -80
  80. package/src/components/ZoomControl.tsx +0 -221
  81. package/src/i18n/en.json +0 -31
  82. package/src/i18n/index.ts +0 -22
  83. package/src/i18n/zh-CN.json +0 -32
  84. package/src/icons/ChevronLeft.tsx +0 -21
  85. package/src/icons/ChevronRight.tsx +0 -21
  86. package/src/icons/FilePlus.tsx +0 -18
  87. package/src/icons/Minus.tsx +0 -21
  88. package/src/icons/Plus.tsx +0 -21
  89. package/src/icons/Redo.tsx +0 -24
  90. package/src/icons/Reset.tsx +0 -23
  91. package/src/icons/Undo.tsx +0 -24
  92. package/src/icons/index.tsx +0 -11
  93. package/src/internal/Instance.tsx +0 -275
  94. package/src/internal/helpers.ts +0 -86
  95. package/src/internal/hooks.ts +0 -9
  96. package/src/internal/index.ts +0 -3
  97. package/src/internal/mount-whiteboard.ts +0 -90
  98. package/src/react.tsx +0 -52
  99. package/src/style.scss +0 -35
  100. package/src/svelte.ts +0 -45
  101. package/src/theme/index.ts +0 -36
  102. package/src/types/index.ts +0 -22
  103. package/src/vue.ts +0 -74
@@ -1,158 +0,0 @@
1
- import type { Player } from "white-web-sdk";
2
- import type { CommonProps, GenericIcon } from "../../types";
3
-
4
- import clsx from "clsx";
5
- import React, { useEffect, useState } from "react";
6
- import RcSlider from "rc-slider";
7
- import { PlayerPhase } from "white-web-sdk";
8
- import { usePlayer } from "./hooks";
9
- import { Icon } from "../../icons";
10
- import { themes, TopOffset } from "../../theme";
11
- import { Icons } from "./icons";
12
- import Tippy from "@tippyjs/react";
13
- import { Button } from "./components/Button";
14
-
15
- export type PlayerControlProps = {
16
- autoHide?: boolean;
17
- player?: Player;
18
- } & Omit<CommonProps, "room"> &
19
- GenericIcon<"play" | "pause" | "loading">;
20
-
21
- export const name = "fastboard-player-control";
22
-
23
- export function PlayerControl({
24
- autoHide = false,
25
- player: player_,
26
- theme = "light",
27
- i18n,
28
- ...icons
29
- }: PlayerControlProps) {
30
- const [currentTime, setCurrentTime] = useState(0);
31
- const player = usePlayer(player_);
32
-
33
- useEffect(() => {
34
- setCurrentTime(player.currentTime);
35
- }, [player.currentTime]);
36
-
37
- useEffect(() => {
38
- if (player.currentTime !== currentTime) {
39
- player.seekToProgressTime(currentTime);
40
- }
41
- // eslint-disable-next-line react-hooks/exhaustive-deps
42
- }, [currentTime]);
43
-
44
- const isLoading =
45
- player.phase === PlayerPhase.WaitingFirstFrame ||
46
- player.phase === PlayerPhase.Buffering;
47
- const isPlaying = player.phase === PlayerPhase.Playing;
48
-
49
- const { activeColor } = themes[theme];
50
-
51
- return (
52
- <div className={clsx(name, theme, { "auto-hide": autoHide })}>
53
- <button
54
- className={clsx(
55
- `${name}-btn`,
56
- isLoading ? "loading" : isPlaying ? "pause" : "play",
57
- theme
58
- )}
59
- disabled={isLoading}
60
- onClick={player.togglePlay}
61
- >
62
- <Icon
63
- fallback={
64
- isLoading ? (
65
- <Icons.Loading theme={theme} />
66
- ) : isPlaying ? (
67
- <Icons.Pause theme={theme} />
68
- ) : (
69
- <Icons.Play theme={theme} />
70
- )
71
- }
72
- src={
73
- isLoading
74
- ? icons.loadingIcon
75
- : isPlaying
76
- ? icons.pauseIcon
77
- : icons.playIcon
78
- }
79
- alt={isLoading ? "[loading]" : isPlaying ? "[pause]" : "[play]"}
80
- />
81
- </button>
82
- <span className={clsx(`${name}-slider`, { loading: isLoading }, theme)}>
83
- <RcSlider
84
- disabled={isLoading}
85
- trackStyle={{ background: activeColor }}
86
- handleStyle={{ border: `1px solid ${activeColor}` }}
87
- value={currentTime}
88
- onChange={setCurrentTime}
89
- min={0}
90
- max={player.totalTime}
91
- step={100}
92
- />
93
- </span>
94
- <span className={clsx(`${name}-current`, theme)}>
95
- {renderTime(player.currentTime)}
96
- </span>
97
- <span className={clsx(`${name}-slash`, theme)}>/</span>
98
- <span className={clsx(`${name}-total`, theme)}>
99
- {renderTime(player.totalTime)}
100
- </span>
101
- <span className={`${name}-btn-interactive`}>
102
- <Tippy
103
- className="fastboard-tip"
104
- content={renderSpeeds(player)}
105
- theme={theme}
106
- placement="top-end"
107
- trigger="click"
108
- offset={TopOffset}
109
- arrow={false}
110
- interactive
111
- >
112
- <Button content={i18n?.t("speed")} theme={theme} disabled={isLoading}>
113
- <span className={clsx(`${name}-speed-text`, theme)}>
114
- {player.speed}x
115
- </span>
116
- </Button>
117
- </Tippy>
118
- </span>
119
- </div>
120
- );
121
- }
122
-
123
- function renderTime(ms: number) {
124
- let seconds = ms / 1000;
125
- const minutes = Math.floor(seconds / 60);
126
- seconds = Math.floor(seconds) % 60;
127
-
128
- return (
129
- `${String(minutes).padStart(2, "0")}` +
130
- `:${String(seconds).padStart(2, "0")}`
131
- );
132
- }
133
-
134
- const Speeds = [2.0, 1.5, 1.25, 1.0, 0.75, 0.5];
135
-
136
- function renderSpeeds({
137
- speed: current,
138
- setSpeed,
139
- }: {
140
- speed: number;
141
- setSpeed: (speed: number) => void;
142
- }) {
143
- return (
144
- <div className={clsx(`${name}-panel`, "speed")}>
145
- {Speeds.map(speed => (
146
- <button
147
- className={clsx(`${name}-btn`, "speed", {
148
- active: speed === current,
149
- })}
150
- key={speed}
151
- onClick={() => setSpeed(speed)}
152
- >
153
- {speed}x
154
- </button>
155
- ))}
156
- </div>
157
- );
158
- }
@@ -1,55 +0,0 @@
1
- import type { Placement } from "tippy.js";
2
- import type { Theme } from "../../../types";
3
-
4
- import clsx from "clsx";
5
- import React, { forwardRef, type PropsWithChildren } from "react";
6
- import Tippy from "@tippyjs/react";
7
-
8
- import { TopOffset } from "../../../theme";
9
-
10
- type ButtonProps = PropsWithChildren<{
11
- theme: Theme;
12
- content: React.ReactNode;
13
- disabled?: boolean;
14
- active?: boolean;
15
- onClick?: () => void;
16
- interactive?: boolean;
17
- placement?: Placement;
18
- }>;
19
-
20
- export const Button = forwardRef<HTMLButtonElement, ButtonProps>(
21
- (props, ref) => {
22
- const {
23
- theme,
24
- content,
25
- disabled,
26
- active,
27
- onClick,
28
- interactive,
29
- placement = "top",
30
- children,
31
- } = props;
32
-
33
- return (
34
- <Tippy
35
- className="fastboard-tip"
36
- content={content}
37
- interactive={interactive}
38
- theme={theme}
39
- disabled={disabled}
40
- placement={placement}
41
- offset={TopOffset}
42
- duration={300}
43
- >
44
- <button
45
- ref={ref}
46
- className={clsx("fastboard-player-control-btn", theme, { active })}
47
- onClick={onClick}
48
- disabled={disabled}
49
- >
50
- {children}
51
- </button>
52
- </Tippy>
53
- );
54
- }
55
- );
@@ -1,88 +0,0 @@
1
- import type { DependencyList } from "react";
2
- import type { Player } from "white-web-sdk";
3
-
4
- import { useCallback, useEffect, useState } from "react";
5
- import { PlayerPhase } from "white-web-sdk";
6
- import { useLastValue } from "../../internal/hooks";
7
-
8
- const EMPTY_ARRAY: DependencyList = [];
9
-
10
- function useForceUpdate() {
11
- const [, forceUpdate_] = useState({});
12
- // eslint-disable-next-line react-hooks/exhaustive-deps
13
- return useCallback(() => forceUpdate_({}), EMPTY_ARRAY);
14
- }
15
-
16
- export function usePlayer(player?: Player | null) {
17
- const togglePlay = useCallback(() => {
18
- if (player) {
19
- switch (player.phase) {
20
- case PlayerPhase.WaitingFirstFrame:
21
- case PlayerPhase.Pause:
22
- case PlayerPhase.Ended: {
23
- player.play();
24
- break;
25
- }
26
- case PlayerPhase.Playing: {
27
- player.pause();
28
- break;
29
- }
30
- }
31
- }
32
- }, [player]);
33
-
34
- const seekToProgressTime = useCallback(
35
- (time: number) => {
36
- if (player) {
37
- player.seekToProgressTime(time);
38
- }
39
- },
40
- [player]
41
- );
42
-
43
- const lastPlayer = useLastValue(player);
44
-
45
- const forceUpdate = useForceUpdate();
46
-
47
- const setSpeed = useCallback(
48
- (speed: number) => {
49
- if (player) {
50
- player.playbackSpeed = speed;
51
- forceUpdate();
52
- }
53
- },
54
- [forceUpdate, player]
55
- );
56
-
57
- useEffect(() => {
58
- if (!lastPlayer && player) {
59
- forceUpdate();
60
- }
61
- }, [forceUpdate, lastPlayer, player]);
62
-
63
- useEffect(() => {
64
- if (player) {
65
- player.callbacks.on("onPhaseChanged", forceUpdate);
66
- player.callbacks.on("onProgressTimeChanged", forceUpdate);
67
- return () => {
68
- player.callbacks.off("onPhaseChanged", forceUpdate);
69
- player.callbacks.off("onProgressTimeChanged", forceUpdate);
70
- };
71
- }
72
- }, [forceUpdate, player]);
73
-
74
- const phase = player ? player.phase : PlayerPhase.WaitingFirstFrame;
75
- const currentTime = player ? player.progressTime : 0;
76
- const totalTime = player ? player.timeDuration : 0;
77
- const speed = player ? player.playbackSpeed : 1;
78
-
79
- return {
80
- phase,
81
- currentTime,
82
- totalTime,
83
- speed,
84
- setSpeed,
85
- togglePlay,
86
- seekToProgressTime,
87
- };
88
- }
@@ -1,13 +0,0 @@
1
- import type { IconProps } from "../../../types";
2
-
3
- import React from "react";
4
- import { getStroke } from "../../../theme";
5
-
6
- export const Loading = (props: IconProps) => {
7
- const stroke = getStroke(props);
8
- return (
9
- <svg viewBox="0 0 24 24">
10
- <path d="M12 4V2A10 10 0 0 0 2 12h2a8 8 0 0 1 8-8z" fill={stroke}></path>
11
- </svg>
12
- );
13
- };
@@ -1,13 +0,0 @@
1
- import type { IconProps } from "../../../types";
2
-
3
- import React from "react";
4
- import { getStroke } from "../../../theme";
5
-
6
- export const Pause = (props: IconProps) => {
7
- const stroke = getStroke(props);
8
- return (
9
- <svg viewBox="0 0 24 24">
10
- <path d="M14 19h4V5h-4M6 19h4V5H6v14z" fill={stroke}></path>
11
- </svg>
12
- );
13
- };
@@ -1,13 +0,0 @@
1
- import type { IconProps } from "../../../types";
2
-
3
- import React from "react";
4
- import { getStroke } from "../../../theme";
5
-
6
- export const Play = (props: IconProps) => {
7
- const stroke = getStroke(props);
8
- return (
9
- <svg viewBox="0 0 24 24">
10
- <path d="M8 5.14v14l11-7l-11-7z" fill={stroke}></path>
11
- </svg>
12
- );
13
- };
@@ -1,10 +0,0 @@
1
- import { memo } from "react";
2
- import { Loading } from "./Loading";
3
- import { Pause } from "./Pause";
4
- import { Play } from "./Play";
5
-
6
- export const Icons = {
7
- Play: memo(Play),
8
- Pause: memo(Pause),
9
- Loading: memo(Loading),
10
- };
@@ -1 +0,0 @@
1
- export { PlayerControl, name, type PlayerControlProps } from "./PlayerControl";
@@ -1,56 +0,0 @@
1
- $name: "fastboard-redo-undo";
2
-
3
- .#{$name} {
4
- display: inline-flex;
5
- align-items: center;
6
- gap: 4px;
7
- padding: 4px;
8
- border-radius: 4px;
9
- backdrop-filter: blur(2px);
10
- -webkit-backdrop-filter: blur(2px);
11
-
12
- &.light {
13
- color: #333;
14
- background-color: rgba($color: #fff, $alpha: 0.85);
15
- border: 1px solid rgba(0, 0, 0, 0.15);
16
- }
17
-
18
- &.dark {
19
- color: #ddd;
20
- background-color: rgba($color: #333, $alpha: 0.85);
21
- border: 1px solid rgba(0, 0, 0, 0.45);
22
- }
23
- }
24
-
25
- .#{$name}-btn {
26
- appearance: none;
27
- cursor: pointer;
28
- margin: 0;
29
- border: 0;
30
- padding: 0;
31
- width: 24px;
32
- height: 24px;
33
- background-color: transparent;
34
- border-radius: 4px;
35
- font-size: 24px;
36
- line-height: 1;
37
-
38
- svg,
39
- img {
40
- width: 1em;
41
- height: 1em;
42
- }
43
-
44
- &:disabled {
45
- opacity: 0.5;
46
- cursor: not-allowed;
47
- }
48
-
49
- &.light:not(:disabled):hover {
50
- background-color: rgba(51, 129, 255, 0.1);
51
- }
52
-
53
- &.dark:not(:disabled):hover {
54
- background-color: rgba(51, 129, 255, 0.25);
55
- }
56
- }
@@ -1,95 +0,0 @@
1
- import type { CommonProps, GenericIcon } from "../types";
2
-
3
- import clsx from "clsx";
4
- import React, { useCallback, useEffect, useState } from "react";
5
- import Tippy from "@tippyjs/react";
6
-
7
- import { Icon } from "../icons";
8
- import { Undo } from "../icons/Undo";
9
- import { Redo } from "../icons/Redo";
10
- import { TopOffset } from "../theme";
11
-
12
- export const name = "fastboard-redo-undo";
13
-
14
- export type RedoUndoProps = CommonProps & GenericIcon<"undo" | "redo">;
15
-
16
- export function RedoUndo({
17
- room,
18
- theme = "light",
19
- undoIcon,
20
- undoIconDisable,
21
- redoIcon,
22
- redoIconDisable,
23
- i18n,
24
- }: RedoUndoProps) {
25
- const [writable, setWritable] = useState(false);
26
- const [undoSteps, setUndoSteps] = useState(0);
27
- const [redoSteps, setRedoSteps] = useState(0);
28
-
29
- useEffect(() => {
30
- if (room) {
31
- setWritable(room.isWritable);
32
- room.isWritable && (room.disableSerialization = false);
33
-
34
- const updateWritable = () => setWritable(room?.isWritable || false);
35
-
36
- room.callbacks.on("onEnableWriteNowChanged", updateWritable);
37
- room.callbacks.on("onCanUndoStepsUpdate", setUndoSteps);
38
- room.callbacks.on("onCanRedoStepsUpdate", setRedoSteps);
39
- return () => {
40
- room.callbacks.off("onEnableWriteNowChanged", updateWritable);
41
- room.callbacks.off("onCanUndoStepsUpdate", setUndoSteps);
42
- room.callbacks.off("onCanRedoStepsUpdate", setRedoSteps);
43
- };
44
- }
45
- }, [room]);
46
-
47
- const disabled = !writable;
48
-
49
- return (
50
- <div className={clsx(name, theme)}>
51
- <Tippy
52
- className="fastboard-tip"
53
- content={i18n?.t("undo")}
54
- theme={theme}
55
- disabled={disabled}
56
- placement="top"
57
- duration={300}
58
- offset={TopOffset}
59
- >
60
- <button
61
- className={clsx(`${name}-btn`, "undo", theme)}
62
- disabled={disabled || undoSteps === 0}
63
- onClick={useCallback(() => room && room.undo(), [room])}
64
- >
65
- <Icon
66
- fallback={<Undo theme={theme} />}
67
- src={undoSteps === 0 ? undoIconDisable : undoIcon}
68
- alt="[undo]"
69
- />
70
- </button>
71
- </Tippy>
72
- <Tippy
73
- className="fastboard-tip"
74
- content={i18n?.t("redo")}
75
- theme={theme}
76
- disabled={disabled}
77
- placement="top"
78
- duration={300}
79
- offset={TopOffset}
80
- >
81
- <button
82
- className={clsx(`${name}-btn`, "redo", theme)}
83
- disabled={disabled || redoSteps === 0}
84
- onClick={useCallback(() => room && room.redo(), [room])}
85
- >
86
- <Icon
87
- fallback={<Redo theme={theme} />}
88
- src={redoSteps === 0 ? redoIconDisable : redoIcon}
89
- alt="[redo]"
90
- />
91
- </button>
92
- </Tippy>
93
- </div>
94
- );
95
- }
@@ -1,55 +0,0 @@
1
- .fastboard-root {
2
- position: relative;
3
- width: 100%;
4
- height: 100%;
5
- overflow: hidden;
6
- }
7
-
8
- .fastboard-loading {
9
- position: absolute;
10
- top: 0;
11
- left: 0;
12
- width: 100%;
13
- height: 100%;
14
- display: flex;
15
- align-items: center;
16
- justify-content: center;
17
- opacity: 0.6;
18
- }
19
-
20
- .fastboard-view {
21
- position: absolute;
22
- top: 0;
23
- left: 0;
24
- width: 100%;
25
- height: 100%;
26
- }
27
-
28
- $unit: 8px;
29
-
30
- .fastboard-left {
31
- position: absolute;
32
- top: 0;
33
- left: 0;
34
- height: calc(100% - 48px);
35
- padding: $unit * 2;
36
- z-index: 201;
37
- display: flex;
38
- align-items: center;
39
- }
40
-
41
- .fastboard-bottom-left {
42
- display: flex;
43
- gap: 10px;
44
- position: absolute;
45
- bottom: $unit;
46
- left: $unit;
47
- padding: $unit;
48
- z-index: 200;
49
- }
50
-
51
- .fastboard-bottom-right {
52
- @extend .fastboard-bottom-left;
53
- left: initial;
54
- right: $unit;
55
- }
@@ -1,61 +0,0 @@
1
- import React, { useCallback, useState } from "react";
2
-
3
- import { Lock, Instance } from "../internal";
4
- import { Toolbar } from "./Toolbar";
5
- import { RedoUndo } from "./RedoUndo";
6
- import { ZoomControl } from "./ZoomControl";
7
- import { PageControl } from "./PageControl";
8
-
9
- export interface RootProps {
10
- instance: Instance;
11
- }
12
-
13
- export function Root({ instance: app }: RootProps) {
14
- const [mux] = useState(() => new Lock());
15
-
16
- const useWhiteboard = useCallback(
17
- (container: HTMLDivElement | null) =>
18
- mux.schedule(
19
- container ? () => app.mount(container) : () => app.unmount()
20
- ),
21
- [app, mux]
22
- );
23
-
24
- const {
25
- Toolbar: toolbar = true,
26
- RedoUndo: redo_undo = true,
27
- ZoomControl: zoom_control = true,
28
- PageControl: page_control = true,
29
- } = app.config.layout || {};
30
-
31
- const props = {
32
- room: app.room,
33
- manager: app.manager,
34
- i18n: app.i18n,
35
- };
36
-
37
- return (
38
- <Instance.Context.Provider value={app}>
39
- <div className="fastboard-root">
40
- {!app.room && <div className="fastboard-loading">Loading&hellip;</div>}
41
- <div className="fastboard-view" ref={useWhiteboard} />
42
- {toolbar && (
43
- <div className="fastboard-left">
44
- <Toolbar {...props} />
45
- </div>
46
- )}
47
- {(redo_undo || zoom_control) && (
48
- <div className="fastboard-bottom-left">
49
- {redo_undo && <RedoUndo {...props} />}
50
- {zoom_control && <ZoomControl {...props} />}
51
- </div>
52
- )}
53
- {page_control && (
54
- <div className="fastboard-bottom-right">
55
- <PageControl {...props} />
56
- </div>
57
- )}
58
- </div>
59
- </Instance.Context.Provider>
60
- );
61
- }