@netless/fastboard 0.0.8 → 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 (107) hide show
  1. package/LICENSE.txt +1 -1
  2. package/dist/index.js +426 -0
  3. package/dist/index.js.map +1 -0
  4. package/dist/index.mjs +393 -0
  5. package/dist/index.mjs.map +1 -0
  6. package/package.json +16 -71
  7. package/src/base.ts +55 -0
  8. package/src/core.ts +307 -0
  9. package/src/emitter.ts +21 -0
  10. package/src/index.ts +70 -24
  11. package/src/{behaviors/register-apps.ts → register-apps.ts} +6 -14
  12. package/src/utils.ts +74 -0
  13. package/src/value.ts +74 -0
  14. package/README.md +0 -134
  15. package/dist/index.cjs.js +0 -14
  16. package/dist/index.cjs.js.map +0 -1
  17. package/dist/index.es.js +0 -2538
  18. package/dist/index.es.js.map +0 -1
  19. package/dist/svelte.cjs.js +0 -2
  20. package/dist/svelte.cjs.js.map +0 -1
  21. package/dist/svelte.es.js +0 -31
  22. package/dist/svelte.es.js.map +0 -1
  23. package/dist/vue.cjs.js +0 -2
  24. package/dist/vue.cjs.js.map +0 -1
  25. package/dist/vue.es.js +0 -42
  26. package/dist/vue.es.js.map +0 -1
  27. package/src/WhiteboardApp.ts +0 -80
  28. package/src/behaviors/style.ts +0 -17
  29. package/src/components/PageControl.scss +0 -80
  30. package/src/components/PageControl.tsx +0 -181
  31. package/src/components/PlayerControl/PlayerControl.scss +0 -145
  32. package/src/components/PlayerControl/PlayerControl.tsx +0 -158
  33. package/src/components/PlayerControl/components/Button.tsx +0 -55
  34. package/src/components/PlayerControl/hooks.ts +0 -95
  35. package/src/components/PlayerControl/icons/Loading.tsx +0 -13
  36. package/src/components/PlayerControl/icons/Pause.tsx +0 -13
  37. package/src/components/PlayerControl/icons/Play.tsx +0 -13
  38. package/src/components/PlayerControl/icons/index.ts +0 -10
  39. package/src/components/PlayerControl/index.ts +0 -1
  40. package/src/components/RedoUndo.scss +0 -56
  41. package/src/components/RedoUndo.tsx +0 -95
  42. package/src/components/Root.scss +0 -55
  43. package/src/components/Root.tsx +0 -61
  44. package/src/components/Toolbar/Content.tsx +0 -93
  45. package/src/components/Toolbar/Toolbar.scss +0 -247
  46. package/src/components/Toolbar/Toolbar.tsx +0 -82
  47. package/src/components/Toolbar/components/ApplianceButtons.tsx +0 -132
  48. package/src/components/Toolbar/components/AppsButton.tsx +0 -106
  49. package/src/components/Toolbar/components/Button.tsx +0 -54
  50. package/src/components/Toolbar/components/ColorBox.tsx +0 -56
  51. package/src/components/Toolbar/components/CutLine.tsx +0 -8
  52. package/src/components/Toolbar/components/PencilButton.tsx +0 -70
  53. package/src/components/Toolbar/components/ShapesButton.tsx +0 -143
  54. package/src/components/Toolbar/components/Slider.tsx +0 -27
  55. package/src/components/Toolbar/components/TextButton.tsx +0 -66
  56. package/src/components/Toolbar/components/UpDownButtons.tsx +0 -49
  57. package/src/components/Toolbar/components/assets/cocos.png +0 -0
  58. package/src/components/Toolbar/components/assets/countdown.png +0 -0
  59. package/src/components/Toolbar/components/assets/geogebra.png +0 -0
  60. package/src/components/Toolbar/components/assets/vscode.png +0 -0
  61. package/src/components/Toolbar/const.ts +0 -32
  62. package/src/components/Toolbar/hooks.ts +0 -113
  63. package/src/components/Toolbar/icons/Apps.tsx +0 -16
  64. package/src/components/Toolbar/icons/Arrow.tsx +0 -16
  65. package/src/components/Toolbar/icons/Circle.tsx +0 -21
  66. package/src/components/Toolbar/icons/Clean.tsx +0 -16
  67. package/src/components/Toolbar/icons/Clicker.tsx +0 -19
  68. package/src/components/Toolbar/icons/Collapse.tsx +0 -17
  69. package/src/components/Toolbar/icons/Diamond.tsx +0 -17
  70. package/src/components/Toolbar/icons/Down.tsx +0 -17
  71. package/src/components/Toolbar/icons/Eraser.tsx +0 -16
  72. package/src/components/Toolbar/icons/Expand.tsx +0 -17
  73. package/src/components/Toolbar/icons/Line.tsx +0 -13
  74. package/src/components/Toolbar/icons/Pencil.tsx +0 -16
  75. package/src/components/Toolbar/icons/Rectangle.tsx +0 -13
  76. package/src/components/Toolbar/icons/Selector.tsx +0 -16
  77. package/src/components/Toolbar/icons/SpeechBalloon.tsx +0 -17
  78. package/src/components/Toolbar/icons/Star.tsx +0 -17
  79. package/src/components/Toolbar/icons/Text.tsx +0 -16
  80. package/src/components/Toolbar/icons/Triangle.tsx +0 -17
  81. package/src/components/Toolbar/icons/Up.tsx +0 -17
  82. package/src/components/Toolbar/icons/index.ts +0 -42
  83. package/src/components/Toolbar/index.ts +0 -1
  84. package/src/components/ZoomControl.scss +0 -80
  85. package/src/components/ZoomControl.tsx +0 -221
  86. package/src/hooks.ts +0 -53
  87. package/src/i18n/en.json +0 -31
  88. package/src/i18n/index.ts +0 -22
  89. package/src/i18n/zh-CN.json +0 -32
  90. package/src/icons/ChevronLeft.tsx +0 -21
  91. package/src/icons/ChevronRight.tsx +0 -21
  92. package/src/icons/FilePlus.tsx +0 -18
  93. package/src/icons/Minus.tsx +0 -21
  94. package/src/icons/Plus.tsx +0 -21
  95. package/src/icons/Redo.tsx +0 -24
  96. package/src/icons/Reset.tsx +0 -23
  97. package/src/icons/Undo.tsx +0 -24
  98. package/src/icons/index.tsx +0 -11
  99. package/src/internal/Instance.tsx +0 -251
  100. package/src/internal/helpers.ts +0 -42
  101. package/src/internal/index.ts +0 -3
  102. package/src/internal/mount-whiteboard.ts +0 -90
  103. package/src/style.scss +0 -29
  104. package/src/svelte.ts +0 -45
  105. package/src/theme/index.ts +0 -36
  106. package/src/types/index.ts +0 -22
  107. package/src/vue.ts +0 -74
@@ -1,80 +0,0 @@
1
- $name: "fastboard-page-control";
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
- }
57
-
58
- .#{$name}-cut-line {
59
- height: 24px;
60
- width: 0.5px;
61
-
62
- &.light {
63
- background-color: #e7e7e7;
64
- }
65
-
66
- &.dark {
67
- background-color: rgba(255, 255, 255, 0.15);
68
- }
69
- }
70
-
71
- .#{$name}-slash {
72
- opacity: 0.6;
73
- }
74
-
75
- .#{$name}-page,
76
- .#{$name}-slash,
77
- .#{$name}-page-count {
78
- font-size: 12px;
79
- font-variant-numeric: tabular-nums;
80
- }
@@ -1,181 +0,0 @@
1
- import type { RoomState, ViewVisionMode } from "white-web-sdk";
2
- import type { CommonProps, GenericIcon } from "../types";
3
-
4
- import clsx from "clsx";
5
- import React, { useCallback, useEffect, useState } from "react";
6
- import Tippy from "@tippyjs/react";
7
-
8
- import { TopOffset } from "../theme";
9
- import { Icon } from "../icons";
10
- import { FilePlus } from "../icons/FilePlus";
11
- import { ChevronLeft } from "../icons/ChevronLeft";
12
- import { ChevronRight } from "../icons/ChevronRight";
13
-
14
- export const name = "fastboard-page-control";
15
-
16
- export type PageControlProps = CommonProps &
17
- GenericIcon<"add" | "prev" | "next">;
18
-
19
- export function PageControl({
20
- room,
21
- manager,
22
- theme = "light",
23
- addIcon,
24
- addIconDisable,
25
- prevIcon,
26
- prevIconDisable,
27
- nextIcon,
28
- nextIconDisable,
29
- i18n,
30
- }: PageControlProps) {
31
- const [writable, setWritable] = useState(false);
32
- const [pageIndex, setPageIndex] = useState(0);
33
- const [pageCount, setPageCount] = useState(0);
34
-
35
- const addPage = useCallback(async () => {
36
- if (manager && room) {
37
- await manager.switchMainViewToWriter();
38
- const path = room.state.sceneState.contextPath;
39
- room.putScenes(path, [{}], pageIndex + 1);
40
- await manager.setMainViewSceneIndex(pageIndex + 1);
41
- } else if (!manager && room) {
42
- const path = room.state.sceneState.contextPath;
43
- room.putScenes(path, [{}], pageIndex + 1);
44
- room.setSceneIndex(pageIndex + 1);
45
- }
46
- }, [room, manager, pageIndex]);
47
-
48
- const prevPage = useCallback(() => {
49
- if (room?.isWritable) {
50
- if (manager) {
51
- manager.setMainViewSceneIndex(pageIndex - 1);
52
- } else {
53
- room.pptPreviousStep();
54
- }
55
- }
56
- }, [room, manager, pageIndex]);
57
-
58
- const nextPage = useCallback(() => {
59
- if (room?.isWritable) {
60
- if (manager) {
61
- manager.setMainViewSceneIndex(pageIndex + 1);
62
- } else {
63
- room.pptNextStep();
64
- }
65
- }
66
- }, [room, manager, pageIndex]);
67
-
68
- useEffect(() => {
69
- if (room) {
70
- setWritable(room.isWritable);
71
- setPageIndex(room.state.sceneState.index);
72
- setPageCount(room.state.sceneState.scenes.length);
73
- }
74
-
75
- const onRoomStateChanged = (modifyState: Partial<RoomState>) => {
76
- if (modifyState.sceneState) {
77
- setPageIndex(modifyState.sceneState.index);
78
- setPageCount(modifyState.sceneState.scenes.length);
79
- }
80
- };
81
-
82
- const onMainViewModeChanged = (mode: number) => {
83
- if (room && mode === (0 as ViewVisionMode.Writable)) {
84
- setPageIndex(room.state.sceneState.index);
85
- setPageCount(room.state.sceneState.scenes.length);
86
- }
87
- };
88
-
89
- const updateWritable = () => setWritable(room?.isWritable || false);
90
-
91
- if (room) {
92
- room.callbacks.on("onEnableWriteNowChanged", updateWritable);
93
- room.callbacks.on("onRoomStateChanged", onRoomStateChanged);
94
- manager?.callbacks.on("mainViewModeChange", onMainViewModeChanged);
95
- }
96
-
97
- return () => {
98
- if (room) {
99
- room.callbacks.off("onEnableWriteNowChanged", updateWritable);
100
- room.callbacks.off("onRoomStateChanged", onRoomStateChanged);
101
- manager?.callbacks.off("mainViewModeChange", onMainViewModeChanged);
102
- }
103
- };
104
- }, [room, manager]);
105
-
106
- const disabled = !writable;
107
-
108
- return (
109
- <div className={clsx(name, theme)}>
110
- {/* <span className={clsx(`${name}-cut-line`, theme)} />{" "} */}
111
- <Tippy
112
- className="fastboard-tip"
113
- content={i18n?.t("prevPage")}
114
- theme={theme}
115
- disabled={disabled}
116
- placement="top"
117
- duration={300}
118
- offset={TopOffset}
119
- >
120
- <button
121
- className={clsx(`${name}-btn`, "prev", theme)}
122
- disabled={disabled || pageIndex === 0}
123
- onClick={prevPage}
124
- >
125
- <Icon
126
- fallback={<ChevronLeft theme={theme} />}
127
- src={disabled ? prevIconDisable : prevIcon}
128
- alt="[prev]"
129
- />
130
- </button>
131
- </Tippy>
132
- <span className={clsx(`${name}-page`, theme)}>
133
- {pageCount === 0 ? "\u2026" : pageIndex + 1}
134
- </span>
135
- <span className={clsx(`${name}-slash`, theme)}>/</span>
136
- <span className={clsx(`${name}-page-count`, theme)}>{pageCount}</span>
137
- <Tippy
138
- className="fastboard-tip"
139
- content={i18n?.t("nextPage")}
140
- theme={theme}
141
- disabled={disabled}
142
- placement="top"
143
- duration={300}
144
- offset={TopOffset}
145
- >
146
- <button
147
- className={clsx(`${name}-btn`, "next", theme)}
148
- disabled={disabled || pageIndex === pageCount - 1}
149
- onClick={nextPage}
150
- >
151
- <Icon
152
- fallback={<ChevronRight theme={theme} />}
153
- src={disabled ? nextIconDisable : nextIcon}
154
- alt="[next]"
155
- />
156
- </button>
157
- </Tippy>
158
- <Tippy
159
- className="fastboard-tip"
160
- content={i18n?.t("addPage")}
161
- theme={theme}
162
- disabled={disabled}
163
- placement="top"
164
- duration={300}
165
- offset={TopOffset}
166
- >
167
- <button
168
- className={clsx(`${name}-btn`, "add", theme)}
169
- disabled={disabled}
170
- onClick={addPage}
171
- >
172
- <Icon
173
- fallback={<FilePlus theme={theme} />}
174
- src={disabled ? addIconDisable : addIcon}
175
- alt="[add]"
176
- />
177
- </button>
178
- </Tippy>
179
- </div>
180
- );
181
- }
@@ -1,145 +0,0 @@
1
- $name: "fastboard-player-control";
2
-
3
- .#{$name} {
4
- width: 100%;
5
- display: inline-flex;
6
- align-items: center;
7
- gap: 4px;
8
- padding: 4px;
9
- border-radius: 4px;
10
- backdrop-filter: blur(2px);
11
- -webkit-backdrop-filter: blur(2px);
12
-
13
- &.auto-hide {
14
- opacity: 0;
15
- transition: opacity 0.2s;
16
-
17
- &:hover {
18
- opacity: 1;
19
- }
20
- }
21
-
22
- .rc-slider-disabled {
23
- background: transparent;
24
- opacity: 0.5;
25
- }
26
-
27
- .rc-slider-rail,
28
- .rc-slider-track {
29
- height: 2px;
30
- }
31
-
32
- .tippy-content {
33
- padding: 8px;
34
- }
35
- .tippy-box {
36
- border: 1px solid rgba(0, 0, 0, 0.15);
37
- background-color: rgba($color: #333, $alpha: 0.95);
38
- backdrop-filter: blur(2px);
39
- -webkit-backdrop-filter: blur(2px);
40
- }
41
- .tippy-box[data-theme~="light"] {
42
- background-color: rgba($color: #fff, $alpha: 0.95);
43
- box-shadow: 0px 5px 10px 0px rgba(0, 0, 0, 0.25);
44
- }
45
-
46
- &.light {
47
- color: #333;
48
- background-color: rgba($color: #fff, $alpha: 0.85);
49
- border: 1px solid rgba(0, 0, 0, 0.15);
50
- }
51
-
52
- &.dark {
53
- color: #ddd;
54
- background-color: rgba($color: #333, $alpha: 0.85);
55
- border: 1px solid rgba(0, 0, 0, 0.45);
56
- }
57
- }
58
-
59
- .#{$name}-btn {
60
- appearance: none;
61
- cursor: pointer;
62
- margin: 0;
63
- border: 0;
64
- padding: 0;
65
- min-width: 24px;
66
- height: 24px;
67
- background-color: transparent;
68
- border-radius: 4px;
69
- font-size: 24px;
70
- line-height: 1;
71
- display: inline-flex;
72
- align-items: center;
73
- justify-content: center;
74
-
75
- svg,
76
- img {
77
- width: 1em;
78
- height: 1em;
79
- }
80
-
81
- &:disabled {
82
- opacity: 0.5;
83
- cursor: not-allowed;
84
- }
85
-
86
- &.light:not(:disabled):hover {
87
- background-color: rgba(51, 129, 255, 0.1);
88
- }
89
-
90
- &.dark:not(:disabled):hover {
91
- background-color: rgba(51, 129, 255, 0.25);
92
- }
93
-
94
- &.loading {
95
- animation: fastboard-player-control-rotate 0.5s linear infinite;
96
- }
97
-
98
- @keyframes fastboard-player-control-rotate {
99
- 100% {
100
- transform: rotate(360deg);
101
- }
102
- }
103
- }
104
-
105
- .#{$name}-panel {
106
- padding: 0;
107
- display: flex;
108
- flex-flow: column nowrap;
109
- align-items: stretch;
110
- gap: 4px;
111
-
112
- .#{$name}-btn {
113
- width: initial;
114
- height: initial;
115
- user-select: none;
116
- font-size: 12px;
117
- padding: 4px;
118
- justify-content: flex-end;
119
-
120
- &.active {
121
- color: #3381ff;
122
- }
123
- }
124
- }
125
-
126
- .#{$name}-slider {
127
- width: 100%;
128
- padding: 0 7px;
129
-
130
- &.loading {
131
- cursor: not-allowed;
132
- }
133
- }
134
-
135
- .#{$name}-slash {
136
- opacity: 0.6;
137
- }
138
-
139
- .#{$name}-current,
140
- .#{$name}-slash,
141
- .#{$name}-total,
142
- .#{$name}-speed-text {
143
- font-size: 12px;
144
- font-variant-numeric: tabular-nums;
145
- }
@@ -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,95 +0,0 @@
1
- import type { DependencyList } from "react";
2
- import type { Player } from "white-web-sdk";
3
-
4
- import { useCallback, useEffect, useRef, useState } from "react";
5
- import { PlayerPhase } from "white-web-sdk";
6
-
7
- const EMPTY_ARRAY: DependencyList = [];
8
-
9
- function useForceUpdate() {
10
- const [, forceUpdate_] = useState({});
11
- // eslint-disable-next-line react-hooks/exhaustive-deps
12
- return useCallback(() => forceUpdate_({}), EMPTY_ARRAY);
13
- }
14
-
15
- function useLastValue<T>(value: T) {
16
- const ref = useRef<T>(value);
17
- useEffect(() => {
18
- ref.current = value;
19
- }, [value]);
20
- return ref.current;
21
- }
22
-
23
- export function usePlayer(player?: Player | null) {
24
- const togglePlay = useCallback(() => {
25
- if (player) {
26
- switch (player.phase) {
27
- case PlayerPhase.WaitingFirstFrame:
28
- case PlayerPhase.Pause:
29
- case PlayerPhase.Ended: {
30
- player.play();
31
- break;
32
- }
33
- case PlayerPhase.Playing: {
34
- player.pause();
35
- break;
36
- }
37
- }
38
- }
39
- }, [player]);
40
-
41
- const seekToProgressTime = useCallback(
42
- (time: number) => {
43
- if (player) {
44
- player.seekToProgressTime(time);
45
- }
46
- },
47
- [player]
48
- );
49
-
50
- const lastPlayer = useLastValue(player);
51
-
52
- const forceUpdate = useForceUpdate();
53
-
54
- const setSpeed = useCallback(
55
- (speed: number) => {
56
- if (player) {
57
- player.playbackSpeed = speed;
58
- forceUpdate();
59
- }
60
- },
61
- [forceUpdate, player]
62
- );
63
-
64
- useEffect(() => {
65
- if (!lastPlayer && player) {
66
- forceUpdate();
67
- }
68
- }, [forceUpdate, lastPlayer, player]);
69
-
70
- useEffect(() => {
71
- if (player) {
72
- player.callbacks.on("onPhaseChanged", forceUpdate);
73
- player.callbacks.on("onProgressTimeChanged", forceUpdate);
74
- return () => {
75
- player.callbacks.off("onPhaseChanged", forceUpdate);
76
- player.callbacks.off("onProgressTimeChanged", forceUpdate);
77
- };
78
- }
79
- }, [forceUpdate, player]);
80
-
81
- const phase = player ? player.phase : PlayerPhase.WaitingFirstFrame;
82
- const currentTime = player ? player.progressTime : 0;
83
- const totalTime = player ? player.timeDuration : 0;
84
- const speed = player ? player.playbackSpeed : 1;
85
-
86
- return {
87
- phase,
88
- currentTime,
89
- totalTime,
90
- speed,
91
- setSpeed,
92
- togglePlay,
93
- seekToProgressTime,
94
- };
95
- }