@netless/fastboard 0.0.11 → 0.2.1

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 (113) 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 +24 -85
  7. package/src/index.ts +2 -49
  8. package/README.md +0 -136
  9. package/dist/index.cjs.js +0 -14
  10. package/dist/index.cjs.js.map +0 -1
  11. package/dist/index.es.js +0 -2804
  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 -32
  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 -43
  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/PageControl.scss +0 -80
  25. package/src/components/PageControl/PageControl.tsx +0 -110
  26. package/src/components/PageControl/hooks.ts +0 -70
  27. package/src/components/PageControl/index.ts +0 -2
  28. package/src/components/PlayerControl/PlayerControl.scss +0 -145
  29. package/src/components/PlayerControl/PlayerControl.tsx +0 -157
  30. package/src/components/PlayerControl/components/Button.tsx +0 -55
  31. package/src/components/PlayerControl/hooks.ts +0 -88
  32. package/src/components/PlayerControl/icons/Loading.tsx +0 -13
  33. package/src/components/PlayerControl/icons/Pause.tsx +0 -13
  34. package/src/components/PlayerControl/icons/Play.tsx +0 -13
  35. package/src/components/PlayerControl/icons/index.ts +0 -10
  36. package/src/components/PlayerControl/index.ts +0 -2
  37. package/src/components/RedoUndo/RedoUndo.scss +0 -56
  38. package/src/components/RedoUndo/RedoUndo.tsx +0 -79
  39. package/src/components/RedoUndo/hooks.ts +0 -50
  40. package/src/components/RedoUndo/index.ts +0 -2
  41. package/src/components/Root.scss +0 -55
  42. package/src/components/Root.tsx +0 -65
  43. package/src/components/Toolbar/Content.tsx +0 -94
  44. package/src/components/Toolbar/Toolbar.scss +0 -281
  45. package/src/components/Toolbar/Toolbar.tsx +0 -132
  46. package/src/components/Toolbar/components/ApplianceButtons.tsx +0 -132
  47. package/src/components/Toolbar/components/AppsButton.tsx +0 -106
  48. package/src/components/Toolbar/components/Button.tsx +0 -54
  49. package/src/components/Toolbar/components/ColorBox.tsx +0 -56
  50. package/src/components/Toolbar/components/CutLine.tsx +0 -8
  51. package/src/components/Toolbar/components/Mask.tsx +0 -44
  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/collapsed.png +0 -0
  59. package/src/components/Toolbar/components/assets/countdown.png +0 -0
  60. package/src/components/Toolbar/components/assets/expanded.png +0 -0
  61. package/src/components/Toolbar/components/assets/geogebra.png +0 -0
  62. package/src/components/Toolbar/components/assets/vscode.png +0 -0
  63. package/src/components/Toolbar/const.ts +0 -32
  64. package/src/components/Toolbar/hooks.ts +0 -112
  65. package/src/components/Toolbar/icons/Apps.tsx +0 -16
  66. package/src/components/Toolbar/icons/Arrow.tsx +0 -16
  67. package/src/components/Toolbar/icons/Circle.tsx +0 -21
  68. package/src/components/Toolbar/icons/Clean.tsx +0 -16
  69. package/src/components/Toolbar/icons/Clicker.tsx +0 -19
  70. package/src/components/Toolbar/icons/Collapse.tsx +0 -17
  71. package/src/components/Toolbar/icons/Diamond.tsx +0 -17
  72. package/src/components/Toolbar/icons/Down.tsx +0 -17
  73. package/src/components/Toolbar/icons/Eraser.tsx +0 -16
  74. package/src/components/Toolbar/icons/Expand.tsx +0 -17
  75. package/src/components/Toolbar/icons/Line.tsx +0 -13
  76. package/src/components/Toolbar/icons/Pencil.tsx +0 -16
  77. package/src/components/Toolbar/icons/Rectangle.tsx +0 -13
  78. package/src/components/Toolbar/icons/Selector.tsx +0 -16
  79. package/src/components/Toolbar/icons/SpeechBalloon.tsx +0 -17
  80. package/src/components/Toolbar/icons/Star.tsx +0 -17
  81. package/src/components/Toolbar/icons/Text.tsx +0 -16
  82. package/src/components/Toolbar/icons/Triangle.tsx +0 -17
  83. package/src/components/Toolbar/icons/Up.tsx +0 -17
  84. package/src/components/Toolbar/icons/index.ts +0 -42
  85. package/src/components/Toolbar/index.ts +0 -2
  86. package/src/components/ZoomControl/ZoomControl.scss +0 -80
  87. package/src/components/ZoomControl/ZoomControl.tsx +0 -109
  88. package/src/components/ZoomControl/hooks.ts +0 -111
  89. package/src/components/ZoomControl/index.ts +0 -2
  90. package/src/components/hooks.ts +0 -80
  91. package/src/i18n/en.json +0 -31
  92. package/src/i18n/index.ts +0 -22
  93. package/src/i18n/zh-CN.json +0 -32
  94. package/src/icons/ChevronLeft.tsx +0 -21
  95. package/src/icons/ChevronRight.tsx +0 -21
  96. package/src/icons/FilePlus.tsx +0 -18
  97. package/src/icons/Minus.tsx +0 -21
  98. package/src/icons/Plus.tsx +0 -21
  99. package/src/icons/Redo.tsx +0 -24
  100. package/src/icons/Reset.tsx +0 -23
  101. package/src/icons/Undo.tsx +0 -24
  102. package/src/icons/index.tsx +0 -11
  103. package/src/internal/Instance.tsx +0 -275
  104. package/src/internal/helpers.ts +0 -86
  105. package/src/internal/hooks.ts +0 -9
  106. package/src/internal/index.ts +0 -3
  107. package/src/internal/mount-whiteboard.ts +0 -90
  108. package/src/react.tsx +0 -52
  109. package/src/style.scss +0 -35
  110. package/src/svelte.ts +0 -45
  111. package/src/theme/index.ts +0 -36
  112. package/src/types/index.ts +0 -22
  113. package/src/vue.ts +0 -74
@@ -1,94 +0,0 @@
1
- import React, { useCallback, useEffect, useRef, useState } from "react";
2
-
3
- import { useInstance, clamp } from "../../internal";
4
- import { name } from "./Toolbar";
5
- import { ItemHeight, ItemsCount, MaxHeight, MinHeight } from "./const";
6
- import { DownButton, UpButton } from "./components/UpDownButtons";
7
- import {
8
- CleanButton,
9
- ClickerButton,
10
- EraserButton,
11
- SelectorButton,
12
- } from "./components/ApplianceButtons";
13
- import { AppsButton } from "./components/AppsButton";
14
- import { PencilButton } from "./components/PencilButton";
15
- import { TextButton } from "./components/TextButton";
16
- import { ShapesButton } from "./components/ShapesButton";
17
- import clsx from "clsx";
18
-
19
- export const Content = React.memo(() => {
20
- const app = useInstance();
21
- const ref = useRef<HTMLDivElement>(null);
22
- const [scrollTop, setScrollTop] = useState(0);
23
- const [parentHeight, setParentHeight] = useState(0);
24
-
25
- const hasAppButton = app?.config.toolbar?.apps?.enable ?? true;
26
- const needScroll = parentHeight < ItemHeight * ItemsCount + 48;
27
- const sectionHeight = clamp(
28
- parentHeight - 48 * (needScroll ? 3 : 1),
29
- MinHeight,
30
- MaxHeight
31
- );
32
- const scrollBuffer = Math.max(parentHeight - sectionHeight - 1, 0);
33
- const disableScrollUp = scrollTop === 0;
34
- const disableScrollDown = scrollTop === scrollBuffer;
35
-
36
- const scrollTo = useCallback(
37
- (height: number) => {
38
- setScrollTop(clamp(scrollTop + height, 0, scrollBuffer));
39
- },
40
- [scrollBuffer, scrollTop]
41
- );
42
-
43
- useEffect(() => {
44
- if (ref.current) {
45
- ref.current.scrollTop = scrollTop;
46
- }
47
- }, [scrollTop]);
48
-
49
- useEffect(() => {
50
- const container = ref.current?.parentElement?.parentElement;
51
- if (container) {
52
- const { paddingTop, paddingBottom } = getComputedStyle(container);
53
- const padding = parseInt(paddingTop) + parseInt(paddingBottom) || 0;
54
- const resizeObserver = new ResizeObserver(() => {
55
- setParentHeight(container.getBoundingClientRect().height - padding);
56
- });
57
- resizeObserver.observe(container);
58
- return () => resizeObserver.disconnect();
59
- }
60
- }, []);
61
-
62
- return (
63
- <>
64
- {needScroll && (
65
- <UpButton scrollTo={scrollTo} disabled={disableScrollUp} />
66
- )}
67
- <div
68
- ref={ref}
69
- className={clsx(`${name}-section`)}
70
- style={{
71
- height: `${sectionHeight}px`,
72
- overflow: needScroll ? "hidden" : "visible",
73
- }}
74
- >
75
- <ClickerButton />
76
- <SelectorButton />
77
- <PencilButton />
78
- <TextButton />
79
- <ShapesButton />
80
- <EraserButton />
81
- <CleanButton />
82
- {hasAppButton && (
83
- <AppsButton
84
- content={app?.config.toolbar?.apps?.content}
85
- onClick={app?.config.toolbar?.apps?.onClick}
86
- />
87
- )}
88
- </div>
89
- {needScroll && (
90
- <DownButton scrollTo={scrollTo} disabled={disableScrollDown} />
91
- )}
92
- </>
93
- );
94
- });
@@ -1,281 +0,0 @@
1
- $name: "fastboard-toolbar";
2
-
3
- .#{$name} {
4
- display: flex;
5
- align-items: center;
6
- padding: 4px;
7
- border-radius: 4px;
8
- flex-direction: column;
9
- gap: 4px;
10
- position: absolute;
11
- z-index: 100;
12
- backdrop-filter: blur(2px);
13
- -webkit-backdrop-filter: blur(2px);
14
-
15
- .rc-slider {
16
- padding: 6px 0;
17
- }
18
- .rc-slider-rail,
19
- .rc-slider-track {
20
- height: 2px;
21
- }
22
-
23
- .tippy-content {
24
- padding: 8px;
25
- }
26
- .tippy-box {
27
- border: 1px solid rgba(0, 0, 0, 0.15);
28
- background-color: rgba($color: #333, $alpha: 0.95);
29
- backdrop-filter: blur(2px);
30
- -webkit-backdrop-filter: blur(2px);
31
- }
32
- .tippy-box[data-theme~="light"] {
33
- background-color: rgba($color: #fff, $alpha: 0.95);
34
- box-shadow: 0px 5px 10px 0px rgba(0, 0, 0, 0.25);
35
- }
36
-
37
- &.light {
38
- color: #333;
39
- background-color: rgba($color: #fff, $alpha: 0.85);
40
- border: 1px solid rgba(0, 0, 0, 0.15);
41
- }
42
-
43
- &.expanded {
44
- border: 1px solid rgba(0, 0, 0, 0.15);
45
- }
46
-
47
- &.dark {
48
- color: #ddd;
49
- background-color: rgba($color: #333, $alpha: 0.85);
50
- }
51
-
52
- &.expanded:hover {
53
- box-shadow: 0px 0px 5px 0px rgba(0, 0, 0, 0.25);
54
- transform: translate3d(0, 0, 0);
55
- }
56
-
57
- &.collapsed {
58
- padding: 0;
59
- background-color: transparent;
60
- }
61
-
62
- &-tooltip {
63
- display: inline-flex;
64
- align-items: center;
65
- gap: 4px;
66
- }
67
-
68
- &-hotkey {
69
- margin-right: -4px;
70
- width: 24px;
71
- height: 24px;
72
- border-radius: 4px;
73
- background-color: rgba($color: #fff, $alpha: 0.1);
74
- display: inline-flex;
75
- align-items: center;
76
- justify-content: center;
77
- }
78
-
79
- &-btn {
80
- appearance: none;
81
- cursor: pointer;
82
- margin: 0;
83
- border: 0;
84
- padding: 4px;
85
- width: 32px;
86
- height: 32px;
87
- background-color: transparent;
88
- border-radius: 4px;
89
- font-size: 24px;
90
- line-height: 1;
91
- position: relative;
92
-
93
- &-interactive {
94
- display: inline-block;
95
- width: 32px;
96
- height: 32px;
97
- }
98
-
99
- svg,
100
- img {
101
- width: 1em;
102
- height: 1em;
103
- }
104
-
105
- &:disabled {
106
- opacity: 0.5;
107
- cursor: not-allowed;
108
- }
109
-
110
- &.light:not(:disabled):hover {
111
- background-color: rgba(51, 129, 255, 0.1);
112
- }
113
-
114
- &.dark:not(:disabled):hover {
115
- background-color: rgba(51, 129, 255, 0.25);
116
- }
117
- }
118
-
119
- &-triangle {
120
- width: 0px;
121
- height: 0px;
122
- border-bottom: 4px solid;
123
- border-left: 4px solid transparent;
124
- position: absolute;
125
- bottom: 0;
126
- right: 0;
127
- }
128
-
129
- &-cut-line {
130
- display: inline-block;
131
- height: 0.5px;
132
- width: 100%;
133
-
134
- &.light {
135
- background-color: #e7e7e7;
136
- }
137
-
138
- &.dark {
139
- background-color: rgba(255, 255, 255, 0.15);
140
- }
141
- }
142
-
143
- &-section {
144
- display: inline-flex;
145
- flex-flow: column nowrap;
146
- gap: 4px;
147
- scroll-behavior: smooth;
148
-
149
- &.collapsed {
150
- transform: translateX(-100%);
151
- transition: 1s transform;
152
- }
153
- }
154
-
155
- &-panel {
156
- width: 136px - 8px * 2;
157
- padding: 0;
158
- display: flex;
159
- flex-flow: column nowrap;
160
- align-items: center;
161
- gap: 8px;
162
-
163
- &.apps {
164
- width: 240px - 8px * 2;
165
- }
166
- }
167
-
168
- &-color-box,
169
- &-shapes {
170
- display: grid;
171
- grid-template-columns: repeat(4, 1fr);
172
- gap: 8px;
173
- align-items: center;
174
- justify-items: center;
175
-
176
- .#{$name}-btn {
177
- padding: 0;
178
- width: 24px;
179
- height: 24px;
180
- }
181
- }
182
-
183
- &-apps {
184
- width: 100%;
185
- display: grid;
186
- grid-template-columns: repeat(3, 1fr);
187
- gap: 8px;
188
- align-items: center;
189
- justify-items: center;
190
-
191
- .#{$name}-btn {
192
- width: 40px;
193
- height: 40px;
194
- font-size: 40px;
195
- }
196
- }
197
-
198
- &-app-icon {
199
- padding-top: 4px;
200
- display: inline-flex;
201
- flex-flow: column nowrap;
202
- align-items: center;
203
- gap: 4px;
204
-
205
- .fastboard-toolbar-btn {
206
- padding: 0;
207
- }
208
-
209
- &-text {
210
- font-size: 12px;
211
- color: #5d5d5d;
212
- overflow: hidden;
213
- white-space: nowrap;
214
- text-overflow: ellipsis;
215
- }
216
- }
217
-
218
- &-color-item {
219
- width: 24px;
220
- height: 24px;
221
- border-radius: 4px;
222
- cursor: pointer;
223
-
224
- *.light:hover {
225
- background-color: #f5f5f5;
226
- }
227
-
228
- *.dark:hover {
229
- background-color: #333;
230
- }
231
- }
232
-
233
- &-color-border {
234
- width: 24px;
235
- height: 24px;
236
- border: 1px solid transparent;
237
- border-radius: 4px;
238
- display: inline-flex;
239
- align-items: center;
240
- justify-content: center;
241
-
242
- &.active.light {
243
- border: 1px solid rgba(51, 129, 255, 0.8);
244
- }
245
-
246
- &.active.dark {
247
- border: 1px solid rgba(51, 129, 255, 0.8);
248
- }
249
- }
250
-
251
- &-color-btn {
252
- margin: 0;
253
- border: 1px solid rgba(0, 0, 0, 0.24);
254
- padding: 0;
255
- appearance: none;
256
- width: 16px;
257
- height: 16px;
258
- border-radius: 4px;
259
- cursor: pointer;
260
-
261
- &:focus-visible {
262
- outline-offset: 2px;
263
- }
264
- }
265
-
266
- &-mask-btn {
267
- width: 17px;
268
- height: 62px;
269
- cursor: pointer;
270
- &.dark {
271
- filter: invert(0.8);
272
- }
273
- }
274
-
275
- &-expand-btn {
276
- display: flex;
277
- align-items: center;
278
- position: absolute;
279
- left: 0;
280
- }
281
- }
@@ -1,132 +0,0 @@
1
- import type { i18n } from "i18next";
2
- import type { CommonProps, GenericIcon, Theme } from "../../types";
3
- import { AnimatePresence, motion } from "framer-motion";
4
-
5
- import React, { createContext, useCallback, useState } from "react";
6
-
7
- import { Icon } from "../../icons";
8
- import { EmptyToolbarHook, useToolbar, type ToolbarHook } from "./hooks";
9
- import { Content } from "./Content";
10
-
11
- import collapsePNG from "./components/assets/collapsed.png";
12
- import expandPNG from "./components/assets/expanded.png";
13
-
14
- import clsx from "clsx";
15
- import { Mask } from "./components/Mask";
16
-
17
- export type ToolbarProps = CommonProps & {
18
- icons?: GenericIcon<
19
- | "clicker"
20
- | "selector"
21
- | "pencil"
22
- | "eraser"
23
- | "clean"
24
- | "expand"
25
- | "collapse"
26
- | "up"
27
- | "down"
28
- | "text"
29
- | "apps"
30
- >;
31
- };
32
-
33
- type ToolbarContextType = ToolbarHook & {
34
- theme: Theme;
35
- icons?: ToolbarProps["icons"];
36
- i18n?: i18n | null;
37
- };
38
-
39
- export const ToolbarContext = createContext<ToolbarContextType>({
40
- theme: "light",
41
- ...EmptyToolbarHook,
42
- });
43
-
44
- export const name = "fastboard-toolbar";
45
-
46
- export const Toolbar = ({
47
- theme = "light",
48
- icons,
49
- room,
50
- manager,
51
- i18n,
52
- }: ToolbarProps) => {
53
- const [expanded, setExpanded] = useState(true);
54
- const hook = useToolbar(room, manager);
55
- const [toolbar, toolbarRef] = useState<HTMLDivElement | null>(null);
56
- const [onHover, setOnHover] = useState<boolean>(false);
57
- const [pointEvents, setPointEvents] = useState(true);
58
- const disabled = !hook.writable;
59
-
60
- const toggle = useCallback(() => {
61
- setExpanded(e => !e);
62
- }, []);
63
-
64
- return (
65
- <ToolbarContext.Provider value={{ theme, icons, ...hook, i18n }}>
66
- <AnimatePresence>
67
- {expanded ? (
68
- <motion.div
69
- initial={{ x: -100 }}
70
- animate={{
71
- x: 0,
72
- transition: { duration: 0.5 },
73
- }}
74
- key="toolbar"
75
- ref={toolbarRef}
76
- className={clsx(name, theme)}
77
- onPointerEnter={() => {
78
- if (expanded) {
79
- setOnHover(true);
80
- }
81
- }}
82
- onMouseLeave={() => setOnHover(false)}
83
- exit={{
84
- x: -100,
85
- transition: { duration: 0.5 },
86
- }}
87
- onAnimationStart={() => setPointEvents(false)}
88
- onAnimationComplete={() => setPointEvents(true)}
89
- style={{ pointerEvents: pointEvents ? "auto" : "none" }}
90
- >
91
- <Content />
92
- {expanded && onHover && (
93
- <Mask toolbar={toolbar}>
94
- <div onClick={toggle}>
95
- <img
96
- draggable={false}
97
- className={clsx(`${name}-mask-btn`, theme)}
98
- src={collapsePNG}
99
- />
100
- </div>
101
- </Mask>
102
- )}
103
- </motion.div>
104
- ) : (
105
- <motion.div
106
- className={clsx(`${name}-expand-btn`, theme)}
107
- key="expand"
108
- onClick={toggle}
109
- initial={{ x: -100 }}
110
- animate={{
111
- x: 0,
112
- transition: { duration: 0.5 },
113
- }}
114
- >
115
- {!expanded && (
116
- <Icon
117
- fallback={
118
- <img
119
- draggable={false}
120
- src={expandPNG}
121
- className={clsx(`${name}-mask-btn`, theme)}
122
- />
123
- }
124
- src={disabled ? icons?.expandIconDisable : icons?.expandIcon}
125
- />
126
- )}
127
- </motion.div>
128
- )}
129
- </AnimatePresence>
130
- </ToolbarContext.Provider>
131
- );
132
- };
@@ -1,132 +0,0 @@
1
- import type { HotKey } from "white-web-sdk";
2
-
3
- import React, { useCallback, useContext } from "react";
4
- import { ApplianceNames } from "white-web-sdk";
5
-
6
- import { defaultHotKeys, useInstance } from "../../../internal";
7
- import { Icon } from "../../../icons";
8
- import { Icons } from "../icons";
9
- import { ToolbarContext } from "../Toolbar";
10
- import { Button } from "./Button";
11
-
12
- export function renderToolTip(text: string | undefined, hotkey?: HotKey) {
13
- if (!(typeof hotkey === "string")) return text;
14
- return (
15
- <span className="fastboard-toolbar-tooltip">
16
- <span>{text}</span>
17
- <span className="fastboard-toolbar-hotkey">{hotkey.toUpperCase()}</span>
18
- </span>
19
- );
20
- }
21
-
22
- export function ClickerButton() {
23
- const app = useInstance();
24
-
25
- const { theme, icons, writable, setAppliance, memberState, i18n } =
26
- useContext(ToolbarContext);
27
-
28
- const changeAppliance = useCallback(
29
- () => setAppliance(ApplianceNames.clicker),
30
- [setAppliance]
31
- );
32
-
33
- const shortcut = app?.config.joinRoom.hotKeys?.changeToClick;
34
- const appliance = memberState?.currentApplianceName;
35
- const active = appliance === ApplianceNames.clicker;
36
- const disabled = !writable;
37
-
38
- return (
39
- <Button
40
- content={renderToolTip(i18n?.t("clicker"), shortcut)}
41
- onClick={changeAppliance}
42
- active={active}
43
- >
44
- <Icon
45
- fallback={<Icons.Clicker theme={theme} active={active} />}
46
- src={disabled ? icons?.clickerIconDisable : icons?.clickerIcon}
47
- alt="[clicker]"
48
- />
49
- </Button>
50
- );
51
- }
52
-
53
- export function SelectorButton() {
54
- const app = useInstance();
55
-
56
- const { theme, icons, writable, setAppliance, memberState, i18n } =
57
- useContext(ToolbarContext);
58
-
59
- const changeAppliance = useCallback(
60
- () => setAppliance(ApplianceNames.selector),
61
- [setAppliance]
62
- );
63
-
64
- const appliance = memberState?.currentApplianceName;
65
- const active = appliance === ApplianceNames.selector;
66
- const disabled = !writable;
67
- const shortcut = (app?.config.joinRoom.hotKeys || defaultHotKeys)
68
- .changeToSelector;
69
-
70
- return (
71
- <Button
72
- content={renderToolTip(i18n?.t("selector"), shortcut)}
73
- onClick={changeAppliance}
74
- active={active}
75
- >
76
- <Icon
77
- fallback={<Icons.Selector theme={theme} active={active} />}
78
- src={disabled ? icons?.selectorIconDisable : icons?.selectorIcon}
79
- alt="[selector]"
80
- />
81
- </Button>
82
- );
83
- }
84
-
85
- export function EraserButton() {
86
- const app = useInstance();
87
-
88
- const { theme, icons, writable, setAppliance, memberState, i18n } =
89
- useContext(ToolbarContext);
90
-
91
- const changeAppliance = useCallback(
92
- () => setAppliance(ApplianceNames.eraser),
93
- [setAppliance]
94
- );
95
-
96
- const appliance = memberState?.currentApplianceName;
97
- const active = appliance === ApplianceNames.eraser;
98
- const disabled = !writable;
99
- const shortcut = (app?.config.joinRoom.hotKeys || defaultHotKeys)
100
- .changeToEraser;
101
-
102
- return (
103
- <Button
104
- content={renderToolTip(i18n?.t("eraser"), shortcut)}
105
- onClick={changeAppliance}
106
- active={active}
107
- >
108
- <Icon
109
- fallback={<Icons.Eraser theme={theme} active={active} />}
110
- src={disabled ? icons?.eraserIconDisable : icons?.eraserIcon}
111
- alt="[eraser]"
112
- />
113
- </Button>
114
- );
115
- }
116
-
117
- export function CleanButton() {
118
- const { theme, icons, writable, cleanCurrentScene, i18n } =
119
- useContext(ToolbarContext);
120
-
121
- const disabled = !writable;
122
-
123
- return (
124
- <Button content={i18n?.t("clean")} onClick={cleanCurrentScene}>
125
- <Icon
126
- fallback={<Icons.Clean theme={theme} />}
127
- src={disabled ? icons?.cleanIconDisable : icons?.cleanIcon}
128
- alt="[clean]"
129
- />
130
- </Button>
131
- );
132
- }