@netless/fastboard-ui 0.3.6 → 1.0.0-canary.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@netless/fastboard-ui",
3
- "version": "0.3.6",
3
+ "version": "1.0.0-canary.2",
4
4
  "description": "The front-end of @netless/fastboard-core.",
5
5
  "main": "dist/index.js",
6
6
  "svelte": "dist/index.svelte.mjs",
@@ -10,14 +10,14 @@
10
10
  ],
11
11
  "repository": "netless-io/fastboard",
12
12
  "peerDependencies": {
13
- "@netless/fastboard-core": "0.3.6"
13
+ "@netless/fastboard-core": "1.0.0-canary.2"
14
14
  },
15
15
  "dependencies": {
16
16
  "tippy.js": "^6.3.7"
17
17
  },
18
18
  "devDependencies": {
19
19
  "@netless/esbuild-plugin-inline-sass": "0.1.0",
20
- "@netless/fastboard-core": "0.3.6"
20
+ "@netless/fastboard-core": "1.0.0-canary.2"
21
21
  },
22
22
  "scripts": {
23
23
  "cleanup": "rimraf dist",
@@ -19,7 +19,7 @@ if (is_client) {
19
19
  const el = instance.popper.firstElementChild;
20
20
  if (el) {
21
21
  el.classList.add("fastboard-tip");
22
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
22
+
23
23
  const extra = ((instance.props as any).className || "").trim();
24
24
  if (extra) {
25
25
  el.classList.add(extra);
@@ -56,10 +56,14 @@ export const tippy: SvelteAction<Partial<Props & { className: string }>> = funct
56
56
  };
57
57
 
58
58
  export function tippy_hide_all() {
59
- document.querySelectorAll("[data-tippy-root]").forEach(el => {
60
- const instance = (el as unknown as { _tippy: Instance })._tippy;
61
- if (instance) instance.hide();
62
- });
59
+ document.querySelectorAll("[data-tippy-root]").forEach(tippy_hide);
60
+ }
61
+
62
+ export function tippy_hide(el: Element) {
63
+ const instance = (el as unknown as { _tippy: Instance })._tippy;
64
+ if (instance) {
65
+ instance.hide();
66
+ }
63
67
  }
64
68
 
65
69
  export const tippy_menu: Partial<Props> = {
@@ -1,7 +1,7 @@
1
1
  import type { FastboardApp } from "@netless/fastboard-core";
2
- import code_editor_svg from "./icons/visual-studio-code.svg";
3
- import geogebra_svg from "./icons/geogebra.svg";
4
- import countdown_svg from "./icons/countdown.svg";
2
+ // import code_editor_svg from "./icons/visual-studio-code.svg";
3
+ // import geogebra_svg from "./icons/geogebra.svg";
4
+ // import countdown_svg from "./icons/countdown.svg";
5
5
 
6
6
  export interface AppInToolbar {
7
7
  kind: string;
@@ -46,38 +46,4 @@ class AppsInToolbar {
46
46
 
47
47
  export type { AppsInToolbar };
48
48
 
49
- export const apps = new AppsInToolbar([
50
- {
51
- kind: "Monaco",
52
- icon: code_editor_svg,
53
- label: "Code Editor",
54
- onClick(app) {
55
- app.manager.addApp({
56
- kind: "Monaco",
57
- options: { title: "Code Editor" },
58
- });
59
- },
60
- },
61
- {
62
- kind: "GeoGebra",
63
- icon: geogebra_svg,
64
- label: "GeoGebra",
65
- onClick(app) {
66
- app.manager.addApp({
67
- kind: "GeoGebra",
68
- options: { title: "GeoGebra" },
69
- });
70
- },
71
- },
72
- {
73
- kind: "Countdown",
74
- icon: countdown_svg,
75
- label: "Countdown",
76
- onClick(app) {
77
- app.manager.addApp({
78
- kind: "Countdown",
79
- options: { title: "Countdown" },
80
- });
81
- },
82
- },
83
- ]);
49
+ export const apps = new AppsInToolbar([]);
@@ -18,8 +18,7 @@ export declare interface ButtonEvents {
18
18
  }
19
19
 
20
20
  export declare interface ButtonSlots {
21
- // eslint-disable-next-line @typescript-eslint/ban-types
22
- default: {};
21
+ default: any;
23
22
  }
24
23
 
25
24
  declare class Button extends SvelteComponentTyped<ButtonProps, ButtonEvents, ButtonSlots> {}
@@ -79,15 +79,15 @@
79
79
  </div>
80
80
  <div class="{name}-bottom-left" class:hidden={layout !== "visible"}>
81
81
  {#if config.redo_undo?.enable !== false}
82
- <RedoUndo {app} {theme} {language} />
82
+ <RedoUndo {app} {theme} {language} icons={config.redo_undo?.icons} />
83
83
  {/if}
84
84
  {#if config.zoom_control?.enable !== false}
85
- <ZoomControl {app} {theme} {language} />
85
+ <ZoomControl {app} {theme} {language} icons={config.zoom_control?.icons} />
86
86
  {/if}
87
87
  </div>
88
88
  <div class="{name}-bottom-right" class:hidden={layout !== "visible"}>
89
89
  {#if config.page_control?.enable !== false}
90
- <PageControl {app} {theme} {language} />
90
+ <PageControl {app} {theme} {language} icons={config.page_control?.icons} />
91
91
  {/if}
92
92
  </div>
93
93
  </div>
@@ -1,5 +1,5 @@
1
1
  import type { FastboardApp } from "@netless/fastboard-core";
2
- import type { Theme, Language, FastboardUIConfig } from "../../typings";
2
+ import type { FastboardUIConfig, Language, Theme } from "../../typings";
3
3
  import { SvelteComponentTyped } from "svelte";
4
4
 
5
5
  export declare interface FastboardProps {
@@ -2,7 +2,7 @@
2
2
 
3
3
  <script lang="ts">
4
4
  import type { FastboardPlayer } from "@netless/fastboard-core";
5
- import type { Language, Theme } from "../../typings";
5
+ import type { Language, ReplayFastboardUIConfig, Theme } from "../../typings";
6
6
  import { onMount } from "svelte";
7
7
  import { tippy_hide_all } from "../../actions/tippy";
8
8
  import PlayerControl from "../PlayerControl";
@@ -10,6 +10,7 @@
10
10
  export let player: FastboardPlayer | null | undefined = null;
11
11
  export let theme: Theme = "light";
12
12
  export let language: Language = "en";
13
+ export let config: ReplayFastboardUIConfig = {};
13
14
  export let containerRef: ((element: HTMLDivElement | null) => void) | undefined = undefined;
14
15
 
15
16
  const name = "fastboard";
@@ -51,6 +52,8 @@
51
52
  <div class="{name}-root" class:loading={!player}>
52
53
  <div class="{name}-view" bind:this={container} on:touchstart|capture={focus_me} />
53
54
  <div class="{name}-bottom">
54
- <PlayerControl {player} {theme} {language} />
55
+ {#if config.player_control?.enable !== false}
56
+ <PlayerControl {player} {theme} {language} icons={config.player_control?.icons} />
57
+ {/if}
55
58
  </div>
56
59
  </div>
@@ -1,11 +1,12 @@
1
1
  import type { FastboardPlayer } from "@netless/fastboard-core";
2
- import type { Theme, Language } from "../../typings";
2
+ import type { Language, ReplayFastboardUIConfig, Theme } from "../../typings";
3
3
  import { SvelteComponentTyped } from "svelte";
4
4
 
5
5
  export declare interface ReplayFastboardProps {
6
6
  player?: FastboardPlayer | null;
7
7
  theme?: Theme;
8
8
  language?: Language;
9
+ config?: ReplayFastboardUIConfig;
9
10
  containerRef?: (container: HTMLDivElement | null) => void;
10
11
  }
11
12
 
@@ -34,8 +34,8 @@
34
34
  let type: IconType;
35
35
  $: type = disabled ? "disable" : "normal";
36
36
 
37
- $: index = app?.sceneIndex;
38
- $: length = app?.sceneLength;
37
+ $: index = app?.pageIndex;
38
+ $: length = app?.pageLength;
39
39
  $: prev_disabled = disabled || !$index;
40
40
  $: next_disabled = disabled || $length == null || $index === $length - 1;
41
41
 
@@ -52,6 +52,6 @@ The `computed_height` is calculated by:
52
52
 
53
53
  ```js
54
54
  const max_height = button_height * 2 + scrollable_area_full_height;
55
- let full_height = container.height;
55
+ const full_height = container.height;
56
56
  computed_height = full_height < max_height ? full_height : max_height;
57
57
  ```
@@ -25,7 +25,7 @@ $name: "fastboard-toolbar";
25
25
  cursor: pointer;
26
26
  pointer-events: auto;
27
27
 
28
- &:focus-within {
28
+ &:focus-visible {
29
29
  outline: 2px solid -webkit-focus-ring-color;
30
30
  }
31
31
 
@@ -1,6 +1,7 @@
1
1
  <script lang="ts">
2
2
  import type { FastboardApp } from "@netless/fastboard-core";
3
- import type { Language, Theme, ToolbarConfig } from "../../typings";
3
+ import type { Language, Theme } from "../../typings";
4
+ import type { ToolbarConfig } from ".";
4
5
  import { writable as svelte_writable } from "svelte/store";
5
6
  import { height } from "../../actions/height";
6
7
  import { clamp } from "../helpers";
@@ -1,7 +1,13 @@
1
1
  import type { FastboardApp } from "@netless/fastboard-core";
2
- import type { Theme, Language, ToolbarConfig } from "../../typings";
2
+ import type { Theme, Language } from "../../typings";
3
3
  import { SvelteComponentTyped } from "svelte";
4
4
 
5
+ export declare interface ToolbarConfig {
6
+ apps?: {
7
+ enable?: boolean;
8
+ };
9
+ }
10
+
5
11
  export declare interface ToolbarProps {
6
12
  app?: FastboardApp | null;
7
13
  theme?: Theme;
@@ -28,7 +28,6 @@ export type Shape = typeof shapes[number];
28
28
 
29
29
  export const applianceShapes = shapes.slice(0, 4) as Appliance[];
30
30
 
31
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
32
31
  export const shapesIcon: Record<Shape, any> = {
33
32
  rectangle: Icons.Rectangle,
34
33
  ellipse: Icons.Circle,
@@ -40,7 +39,6 @@ export const shapesIcon: Record<Shape, any> = {
40
39
  speechBalloon: Icons.Balloon,
41
40
  };
42
41
 
43
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
44
42
  export const shapesIconActive: Record<Shape, any> = {
45
43
  rectangle: Icons.RectangleBolded,
46
44
  ellipse: Icons.CircleBolded,
@@ -1,5 +1,5 @@
1
1
  import type { HotKey } from "@netless/fastboard-core";
2
- import { element, attr, append } from "svelte/internal";
2
+ import { append, attr, element } from "svelte/internal";
3
3
 
4
4
  /**
5
5
  * ```svelte
@@ -55,10 +55,12 @@
55
55
  let type: IconType;
56
56
  $: type = disabled ? "disable" : "normal";
57
57
 
58
- $: camera = app?.camera;
58
+ $: camera = app?.baseCamera;
59
59
  $: scale = $camera?.scale ?? 1;
60
- $: plus_disabled = disabled || next_scale(scale, 1) === scale;
61
- $: minus_disabled = disabled || next_scale(scale, -1) === scale;
60
+ $: plus_disabled = disabled || next_scale(scale, 1) <= scale;
61
+ $: minus_disabled = disabled || next_scale(scale, -1) >= scale;
62
+
63
+ $: display_scale = clamp(Math.round(scale * 100), 30, 300);
62
64
 
63
65
  function plus() {
64
66
  app?.moveCamera({ scale: next_scale(scale, 1), centerX: 0, centerY: 0 });
@@ -83,7 +85,7 @@
83
85
  {#if $camera == null}
84
86
  &hellip;
85
87
  {:else}
86
- {Math.ceil(scale * 100)}%
88
+ {display_scale}%
87
89
  {/if}
88
90
  </span>
89
91
  <Button class="minus" {name} {theme} disabled={minus_disabled} on:click={minus} content={t.minus}>
@@ -10,6 +10,8 @@ export interface UI {
10
10
  update(props?: FastboardProps): void;
11
11
  /** remove UI */
12
12
  destroy(): void;
13
+ /** div == null ? destroy() : mount() */
14
+ setElement(div: Element | null): void;
13
15
  }
14
16
 
15
17
  /**
@@ -20,29 +22,39 @@ export interface UI {
20
22
  export function createUI(app?: FastboardApp | null, div?: Element): UI {
21
23
  let fastboard: Fastboard | undefined;
22
24
 
23
- const ui: UI = {
24
- mount(div: Element, props?: FastboardProps) {
25
- if (fastboard) {
26
- fastboard.$destroy();
27
- }
28
- fastboard = new Fastboard({ target: div, props: { app, ...props } });
29
- return ui;
30
- },
31
- update(props?: FastboardProps) {
32
- if (fastboard) {
33
- fastboard.$set(props);
34
- }
35
- },
36
- destroy() {
37
- if (fastboard) {
38
- fastboard.$destroy();
39
- }
40
- fastboard = undefined;
41
- },
42
- };
25
+ function mount(div: Element, props?: FastboardProps) {
26
+ if (fastboard) {
27
+ fastboard.$destroy();
28
+ }
29
+ fastboard = new Fastboard({ target: div, props: { app, ...props } });
30
+ return ui;
31
+ }
32
+
33
+ function update(props?: FastboardProps) {
34
+ if (fastboard) {
35
+ fastboard.$set(props);
36
+ }
37
+ }
38
+
39
+ function destroy() {
40
+ if (fastboard) {
41
+ fastboard.$destroy();
42
+ }
43
+ fastboard = undefined;
44
+ }
45
+
46
+ function setElement(div: Element | null) {
47
+ if (div) {
48
+ mount(div);
49
+ } else {
50
+ destroy();
51
+ }
52
+ }
53
+
54
+ const ui: UI = { mount, update, destroy, setElement };
43
55
 
44
56
  if (div) {
45
- ui.mount(div, { app });
57
+ mount(div, { app });
46
58
  }
47
59
 
48
60
  return ui;
@@ -55,6 +67,8 @@ export interface ReplayUI {
55
67
  update(props?: ReplayFastboardProps): void;
56
68
  /** remove UI */
57
69
  destroy(): void;
70
+ /** div == null ? destroy() : mount() */
71
+ setElement(div: Element | null): void;
58
72
  }
59
73
 
60
74
  /**
@@ -65,29 +79,39 @@ export interface ReplayUI {
65
79
  export function createReplayUI(player?: FastboardPlayer | null, div?: Element): ReplayUI {
66
80
  let fastboard: ReplayFastboard | undefined;
67
81
 
68
- const ui: ReplayUI = {
69
- mount(div: Element, props?: ReplayFastboardProps) {
70
- if (fastboard) {
71
- fastboard.$destroy();
72
- }
73
- fastboard = new ReplayFastboard({ target: div, props: { player, ...props } });
74
- return ui;
75
- },
76
- update(props?: ReplayFastboardProps) {
77
- if (fastboard) {
78
- fastboard.$set(props);
79
- }
80
- },
81
- destroy() {
82
- if (fastboard) {
83
- fastboard.$destroy();
84
- }
85
- fastboard = undefined;
86
- },
87
- };
82
+ function mount(div: Element, props?: ReplayFastboardProps) {
83
+ if (fastboard) {
84
+ fastboard.$destroy();
85
+ }
86
+ fastboard = new ReplayFastboard({ target: div, props: { player, ...props } });
87
+ return ui;
88
+ }
89
+
90
+ function update(props?: ReplayFastboardProps) {
91
+ if (fastboard) {
92
+ fastboard.$set(props);
93
+ }
94
+ }
95
+
96
+ function destroy() {
97
+ if (fastboard) {
98
+ fastboard.$destroy();
99
+ }
100
+ fastboard = undefined;
101
+ }
102
+
103
+ function setElement(div: Element | null) {
104
+ if (div) {
105
+ mount(div);
106
+ } else {
107
+ destroy();
108
+ }
109
+ }
110
+
111
+ const ui: ReplayUI = { mount, update, destroy, setElement };
88
112
 
89
113
  if (div) {
90
- ui.mount(div, { player });
114
+ mount(div, { player });
91
115
  }
92
116
 
93
117
  return ui;
package/src/index.ts CHANGED
@@ -1,3 +1,5 @@
1
+ import "./style.scss";
2
+
1
3
  export * from "./typings";
2
4
 
3
5
  export { default as RedoUndo, type RedoUndoProps } from "./components/RedoUndo";
@@ -5,10 +7,12 @@ export { default as PageControl, type PageControlProps } from "./components/Page
5
7
  export { default as ZoomControl, type ZoomControlProps } from "./components/ZoomControl";
6
8
  export { default as Toolbar, type ToolbarProps } from "./components/Toolbar";
7
9
  export { default as PlayerControl, type PlayerControlProps } from "./components/PlayerControl";
8
- export { Fastboard, ReplayFastboard } from "./components/Fastboard";
9
- export type { FastboardProps, ReplayFastboardProps } from "./components/Fastboard";
10
+ export {
11
+ Fastboard,
12
+ ReplayFastboard,
13
+ type FastboardProps,
14
+ type ReplayFastboardProps,
15
+ } from "./components/Fastboard";
10
16
 
11
17
  export * from "./helpers";
12
18
  export * from "./behaviors";
13
-
14
- import "./style.scss";
package/src/style.scss CHANGED
@@ -34,3 +34,7 @@
34
34
  padding: 8px;
35
35
  }
36
36
  }
37
+
38
+ .netless-whiteboard:focus-visible {
39
+ outline: none;
40
+ }
package/src/typings.ts CHANGED
@@ -1,3 +1,9 @@
1
+ import type { PageControlProps } from "./components/PageControl";
2
+ import type { PlayerControlProps } from "./components/PlayerControl";
3
+ import type { RedoUndoProps } from "./components/RedoUndo";
4
+ import type { ToolbarConfig } from "./components/Toolbar";
5
+ import type { ZoomControlProps } from "./components/ZoomControl";
6
+
1
7
  export interface SvelteAction<T = void> {
2
8
  (node: HTMLElement, parameters: T): void | {
3
9
  update?: (parameters: T) => void;
@@ -16,23 +22,27 @@ export type GenericIcon<K extends string, E extends string = IconType> = {
16
22
 
17
23
  export type I18nData<T extends string> = Record<Language, Record<T, string>>;
18
24
 
19
- export interface ToolbarConfig {
20
- apps?: {
21
- enable?: boolean;
22
- };
23
- }
24
-
25
25
  export interface FastboardUIConfig {
26
26
  toolbar?: {
27
27
  enable?: boolean;
28
28
  } & ToolbarConfig;
29
29
  redo_undo?: {
30
30
  enable?: boolean;
31
+ icons?: RedoUndoProps["icons"];
31
32
  };
32
33
  zoom_control?: {
33
34
  enable?: boolean;
35
+ icons?: ZoomControlProps["icons"];
34
36
  };
35
37
  page_control?: {
36
38
  enable?: boolean;
39
+ icons?: PageControlProps["icons"];
40
+ };
41
+ }
42
+
43
+ export interface ReplayFastboardUIConfig {
44
+ player_control?: {
45
+ enable?: boolean;
46
+ icons?: PlayerControlProps["icons"];
37
47
  };
38
48
  }