@netless/fastboard 0.0.4 → 0.0.5

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.
@@ -0,0 +1,2 @@
1
+ "use strict";Object.defineProperty(exports,"__esModule",{value:!0});exports[Symbol.toStringTag]="Module";var a=require("svelte/store"),n=require("./index.cjs.js");require("@netless/window-manager");require("white-web-sdk");require("i18next");require("react");require("react-dom");require("clsx");require("@tippyjs/react");require("rc-slider");function o(t,i){return a.readable(null,s=>{let e=null;n.createWhiteboardApp(i).then(r=>{s(e=r)});const u=t.subscribe(r=>{r&&e&&e.bindElement(r)});return()=>{u(),e&&e.dispose()}})}exports.useFastboard=o;
2
+ //# sourceMappingURL=svelte.cjs.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"svelte.cjs.js","sources":["../src/svelte.ts"],"sourcesContent":["import { readable, type Readable } from \"svelte/store\";\nimport { createWhiteboardApp } from \"./index\";\n\nimport type { WhiteboardApp, WhiteboardAppConfig } from \"./WhiteboardApp\";\n\nexport type FastBoardConfig = WhiteboardAppConfig;\n\n/**\n * @example\n * ```svelte\n * <script>\n * let ref = writable(null)\n * let app = useFastboard(ref, { sdkConfig, joinRoom })\n * if (app) {\n * app.insertDocs({...})\n * }\n * </script>\n * <div style=\"width: 100%; height: 100%\" bind:this={$ref} />\n * ```\n */\nexport function useFastboard(\n ref: Readable<HTMLElement | null>,\n config: FastBoardConfig\n): Readable<WhiteboardApp | null> {\n return readable<WhiteboardApp | null>(null, set => {\n let app_: WhiteboardApp | null = null;\n\n createWhiteboardApp(config).then(app => {\n set((app_ = app));\n });\n\n const dispose = ref.subscribe(div => {\n if (div && app_) {\n app_.bindElement(div);\n }\n });\n\n return () => {\n dispose();\n if (app_) {\n app_.dispose();\n }\n };\n });\n}\n"],"names":["readable"],"mappings":"kWAqBE,EACA,EACgC,OACzBA,YAA+B,KAAM,GAAO,IAC7C,GAA6B,2BAEb,GAAQ,KAAK,GAAO,GACjC,EAAO,UAGR,GAAU,EAAI,UAAU,GAAO,CAC/B,GAAO,KACJ,YAAY,WAId,IAAM,KAEP,KACG"}
@@ -0,0 +1,31 @@
1
+ import { readable } from "svelte/store";
2
+ import { createWhiteboardApp } from "./index.es.js";
3
+ import "@netless/window-manager";
4
+ import "white-web-sdk";
5
+ import "i18next";
6
+ import "react";
7
+ import "react-dom";
8
+ import "clsx";
9
+ import "@tippyjs/react";
10
+ import "rc-slider";
11
+ function useFastboard(ref, config) {
12
+ return readable(null, (set) => {
13
+ let app_ = null;
14
+ createWhiteboardApp(config).then((app) => {
15
+ set(app_ = app);
16
+ });
17
+ const dispose = ref.subscribe((div) => {
18
+ if (div && app_) {
19
+ app_.bindElement(div);
20
+ }
21
+ });
22
+ return () => {
23
+ dispose();
24
+ if (app_) {
25
+ app_.dispose();
26
+ }
27
+ };
28
+ });
29
+ }
30
+ export { useFastboard };
31
+ //# sourceMappingURL=svelte.es.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"svelte.es.js","sources":["../src/svelte.ts"],"sourcesContent":["import { readable, type Readable } from \"svelte/store\";\nimport { createWhiteboardApp } from \"./index\";\n\nimport type { WhiteboardApp, WhiteboardAppConfig } from \"./WhiteboardApp\";\n\nexport type FastBoardConfig = WhiteboardAppConfig;\n\n/**\n * @example\n * ```svelte\n * <script>\n * let ref = writable(null)\n * let app = useFastboard(ref, { sdkConfig, joinRoom })\n * if (app) {\n * app.insertDocs({...})\n * }\n * </script>\n * <div style=\"width: 100%; height: 100%\" bind:this={$ref} />\n * ```\n */\nexport function useFastboard(\n ref: Readable<HTMLElement | null>,\n config: FastBoardConfig\n): Readable<WhiteboardApp | null> {\n return readable<WhiteboardApp | null>(null, set => {\n let app_: WhiteboardApp | null = null;\n\n createWhiteboardApp(config).then(app => {\n set((app_ = app));\n });\n\n const dispose = ref.subscribe(div => {\n if (div && app_) {\n app_.bindElement(div);\n }\n });\n\n return () => {\n dispose();\n if (app_) {\n app_.dispose();\n }\n };\n });\n}\n"],"names":[],"mappings":";;;;;;;;;;sBAqBE,KACA,QACgC;SACzB,SAA+B,MAAM,SAAO;QAC7C,OAA6B;wBAEb,QAAQ,KAAK,SAAO;UACjC,OAAO;AAAA;UAGR,UAAU,IAAI,UAAU,SAAO;UAC/B,OAAO,MAAM;aACV,YAAY;AAAA;AAAA;WAId,MAAM;;UAEP,MAAM;aACH;AAAA;AAAA;AAAA;AAAA;;"}
@@ -0,0 +1,2 @@
1
+ "use strict";Object.defineProperty(exports,"__esModule",{value:!0});exports[Symbol.toStringTag]="Module";var t=require("vue-demi"),s=require("./index.cjs.js");require("@netless/window-manager");require("white-web-sdk");require("i18next");require("react");require("react-dom");require("clsx");require("@tippyjs/react");require("rc-slider");function n(u){var e;const r=t.unref(u);return(e=r==null?void 0:r.$el)!=null?e:r}function o(u){return t.getCurrentScope()?(t.onScopeDispose(u),!0):!1}function l(u,r){const e=t.shallowRef(null),i=t.computed(()=>n(u));return s.createWhiteboardApp(r).then(a=>{e.value=a}),t.watchEffect(()=>{i.value&&e.value&&e.value.bindElement(i.value)}),o(()=>{e.value&&e.value.dispose()}),e}exports.unrefElement=n;exports.useFastboard=l;
2
+ //# sourceMappingURL=vue.cjs.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"vue.cjs.js","sources":["../src/vue.ts"],"sourcesContent":["import type { ComponentPublicInstance, Ref } from \"vue-demi\";\nimport {\n computed,\n getCurrentScope,\n onScopeDispose,\n shallowRef,\n unref,\n watchEffect,\n} from \"vue-demi\";\nimport { createWhiteboardApp } from \"./index\";\n\nimport type { WhiteboardApp, WhiteboardAppConfig } from \"./WhiteboardApp\";\n\nexport type FastBoardConfig = WhiteboardAppConfig;\n\nexport type MaybeRef<T> = T | Ref<T>;\nexport type VueInstance = ComponentPublicInstance;\nexport type MaybeElementRef = MaybeRef<\n HTMLElement | SVGElement | VueInstance | undefined | null\n>;\n\n/**\n * Get the dom element of a ref of element or Vue component instance\n */\nexport function unrefElement(elRef: MaybeElementRef) {\n const plain = unref(elRef);\n return (plain as VueInstance)?.$el ?? plain;\n}\n\nfunction tryOnScopeDispose(fn: () => void) {\n if (getCurrentScope()) {\n onScopeDispose(fn);\n return true;\n }\n return false;\n}\n\n/**\n * @example\n * ```vue\n * <script setup>\n * const el = ref(null)\n * const app = useFastboard(el, { sdkConfig, joinRoom })\n * if (app.value) {\n * app.value.insertDocs({...})\n * }\n * </script>\n * <template>\n * <div style=\"width: 100%; height: 100%\" ref=\"el\"></div>\n * </template>\n * ```\n */\nexport function useFastboard(el: MaybeElementRef, config: FastBoardConfig) {\n const app = shallowRef<WhiteboardApp | null>(null);\n const target = computed(() => unrefElement(el));\n\n createWhiteboardApp(config).then(app_ => {\n app.value = app_;\n });\n\n watchEffect(() => {\n if (target.value && app.value) {\n app.value.bindElement(target.value);\n }\n });\n\n tryOnScopeDispose(() => {\n if (app.value) {\n app.value.dispose();\n }\n });\n\n return app;\n}\n"],"names":["unref","getCurrentScope","shallowRef","computed"],"mappings":"8VAwB6B,EAAwB,YAC7C,GAAQA,QAAM,SACZ,oBAAuB,MAAvB,OAA8B,EAGxC,WAA2B,EAAgB,OACrCC,uCACa,GACR,IAEF,cAkBoB,EAAqB,EAAyB,MACnE,GAAMC,aAAiC,MACvC,EAASC,WAAS,IAAM,EAAa,iCAEvB,GAAQ,KAAK,GAAQ,GACnC,MAAQ,kBAGF,IAAM,CACZ,EAAO,OAAS,EAAI,SAClB,MAAM,YAAY,EAAO,WAIf,IAAM,CAClB,EAAI,SACF,MAAM,YAIP"}
package/dist/vue.es.js ADDED
@@ -0,0 +1,42 @@
1
+ import { unref, shallowRef, computed, watchEffect, getCurrentScope, onScopeDispose } from "vue-demi";
2
+ import { createWhiteboardApp } from "./index.es.js";
3
+ import "@netless/window-manager";
4
+ import "white-web-sdk";
5
+ import "i18next";
6
+ import "react";
7
+ import "react-dom";
8
+ import "clsx";
9
+ import "@tippyjs/react";
10
+ import "rc-slider";
11
+ function unrefElement(elRef) {
12
+ var _a;
13
+ const plain = unref(elRef);
14
+ return (_a = plain == null ? void 0 : plain.$el) != null ? _a : plain;
15
+ }
16
+ function tryOnScopeDispose(fn) {
17
+ if (getCurrentScope()) {
18
+ onScopeDispose(fn);
19
+ return true;
20
+ }
21
+ return false;
22
+ }
23
+ function useFastboard(el, config) {
24
+ const app = shallowRef(null);
25
+ const target = computed(() => unrefElement(el));
26
+ createWhiteboardApp(config).then((app_) => {
27
+ app.value = app_;
28
+ });
29
+ watchEffect(() => {
30
+ if (target.value && app.value) {
31
+ app.value.bindElement(target.value);
32
+ }
33
+ });
34
+ tryOnScopeDispose(() => {
35
+ if (app.value) {
36
+ app.value.dispose();
37
+ }
38
+ });
39
+ return app;
40
+ }
41
+ export { unrefElement, useFastboard };
42
+ //# sourceMappingURL=vue.es.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"vue.es.js","sources":["../src/vue.ts"],"sourcesContent":["import type { ComponentPublicInstance, Ref } from \"vue-demi\";\nimport {\n computed,\n getCurrentScope,\n onScopeDispose,\n shallowRef,\n unref,\n watchEffect,\n} from \"vue-demi\";\nimport { createWhiteboardApp } from \"./index\";\n\nimport type { WhiteboardApp, WhiteboardAppConfig } from \"./WhiteboardApp\";\n\nexport type FastBoardConfig = WhiteboardAppConfig;\n\nexport type MaybeRef<T> = T | Ref<T>;\nexport type VueInstance = ComponentPublicInstance;\nexport type MaybeElementRef = MaybeRef<\n HTMLElement | SVGElement | VueInstance | undefined | null\n>;\n\n/**\n * Get the dom element of a ref of element or Vue component instance\n */\nexport function unrefElement(elRef: MaybeElementRef) {\n const plain = unref(elRef);\n return (plain as VueInstance)?.$el ?? plain;\n}\n\nfunction tryOnScopeDispose(fn: () => void) {\n if (getCurrentScope()) {\n onScopeDispose(fn);\n return true;\n }\n return false;\n}\n\n/**\n * @example\n * ```vue\n * <script setup>\n * const el = ref(null)\n * const app = useFastboard(el, { sdkConfig, joinRoom })\n * if (app.value) {\n * app.value.insertDocs({...})\n * }\n * </script>\n * <template>\n * <div style=\"width: 100%; height: 100%\" ref=\"el\"></div>\n * </template>\n * ```\n */\nexport function useFastboard(el: MaybeElementRef, config: FastBoardConfig) {\n const app = shallowRef<WhiteboardApp | null>(null);\n const target = computed(() => unrefElement(el));\n\n createWhiteboardApp(config).then(app_ => {\n app.value = app_;\n });\n\n watchEffect(() => {\n if (target.value && app.value) {\n app.value.bindElement(target.value);\n }\n });\n\n tryOnScopeDispose(() => {\n if (app.value) {\n app.value.dispose();\n }\n });\n\n return app;\n}\n"],"names":[],"mappings":";;;;;;;;;;sBAwB6B,OAAwB;;QAC7C,QAAQ,MAAM;SACZ,qCAAuB,QAAvB,YAA8B;AAAA;AAGxC,2BAA2B,IAAgB;MACrC,mBAAmB;mBACN;WACR;AAAA;SAEF;AAAA;sBAkBoB,IAAqB,QAAyB;QACnE,MAAM,WAAiC;QACvC,SAAS,SAAS,MAAM,aAAa;sBAEvB,QAAQ,KAAK,UAAQ;QACnC,QAAQ;AAAA;cAGF,MAAM;QACZ,OAAO,SAAS,IAAI,OAAO;UACzB,MAAM,YAAY,OAAO;AAAA;AAAA;oBAIf,MAAM;QAClB,IAAI,OAAO;UACT,MAAM;AAAA;AAAA;SAIP;AAAA;;"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@netless/fastboard",
3
- "version": "0.0.4",
3
+ "version": "0.0.5",
4
4
  "description": "An open sourced sdk based on white-web-sdk.",
5
5
  "main": "./dist/index.cjs.js",
6
6
  "module": "./dist/index.es.js",
@@ -14,6 +14,14 @@
14
14
  "default": "./dist/index.es.js",
15
15
  "types": "./src/index.ts"
16
16
  },
17
+ "./vue": {
18
+ "node": {
19
+ "import": "./dist/vue.es.js",
20
+ "require": "./dist/vue.cjs.js"
21
+ },
22
+ "default": "./dist/vue.es.js",
23
+ "types": "./src/vue.ts"
24
+ },
17
25
  "./package.json": "./package.json"
18
26
  },
19
27
  "files": [
@@ -37,8 +45,11 @@
37
45
  "@netless/app-monaco": "*",
38
46
  "@netless/app-slide": "*",
39
47
  "@netless/window-manager": "*",
48
+ "@vue/composition-api": "*",
40
49
  "react": "*",
41
50
  "react-dom": "*",
51
+ "svelte": "*",
52
+ "vue": "*",
42
53
  "white-web-sdk": "*"
43
54
  },
44
55
  "peerDependenciesMeta": {
@@ -53,6 +64,15 @@
53
64
  },
54
65
  "@netless/app-geogebra": {
55
66
  "optional": true
67
+ },
68
+ "@vue/composition-api": {
69
+ "optional": true
70
+ },
71
+ "svelte": {
72
+ "optional": true
73
+ },
74
+ "vue": {
75
+ "optional": true
56
76
  }
57
77
  },
58
78
  "dependencies": {
@@ -60,7 +80,8 @@
60
80
  "clsx": "^1.1.1",
61
81
  "i18next": "^21.6.5",
62
82
  "rc-slider": "^9.7.5",
63
- "tippy.js": "^6.3.7"
83
+ "tippy.js": "^6.3.7",
84
+ "vue-demi": "^0.12.1"
64
85
  },
65
86
  "readme": "# @netless/fastboard\n\nA whiteboard starter, based on [white-web-sdk](https://www.npmjs.com/package/white-web-sdk), [@netless/window-manager](https://www.npmjs.com/package/@netless/window-manager)\nand [netless-app](https://github.com/netless-io/netless-app).\n\n## 目录\n\n- [安装](#install)\n- [使用](#usage)\n- [进阶](./docs/advanced.md)\n- [开发](#开发)\n\n<h2 id=\"install\">安装</h2>\n\n```bash\nnpm add @netless/fastboard @netless/window-manager white-web-sdk react react-dom\n```\n\n<h2 id=\"usage\">使用</h2>\n\n<h3 id=\"mount-whiteboard\">挂载白板</h3>\n\n> 原生 `javascript`\n\n```js\nimport { createWhiteboardApp } from \"@netless/fastboard\";\n\nlet whiteboard = await createWhiteboardApp({\n target: document.getElementById(\"whiteboard\"),\n // [1]\n sdkConfig: {\n appIdentifier: \"whiteboard-appid\",\n },\n // [2]\n joinRoom: {\n uid: \"unique_id_for_each_client\",\n uuid: \"room-uuid\",\n roomToken: \"NETLESSROOM_...\",\n },\n // [3]\n managerConfig: {\n cursor: true,\n },\n});\n```\n\n> 使用 `React`\n\n```typescript\nimport { useFastboard, FastBoardConfig } from \"@netless/fastboard\";\nimport ReactDOM from \"react-dom\";\n\nconst config: FastBoardConfig = {\n sdkConfig: {\n appIdentifier: \"whiteboard-appid\",\n },\n joinRoom: {\n uid: \"unique_id_for_each_client\",\n uuid: \"room-uuid\",\n roomToken: \"NETLESSROOM_...\",\n },\n};\n\nfunction App() {\n const [app, ref] = useFastboard(config);\n return <div ref={ref} />;\n}\nReactDOM.render(<App />, document.getElementById(\"root\"));\n```\n\n[1] 关于 SDK 更多配置请看 [构造 WhiteWebSDK](https://developer.netless.link/javascript-zh/home/construct-white-web-sdk)\n\n[2] 加入房间更多配置请看 [构造 Room 与 Player 对象](https://developer.netless.link/javascript-zh/home/construct-room-and-player)\n\n[3] 配置 `WindowManager` 请看 [WindowManager](https://github.com/netless-io/window-manager#mount)\n\n### 使用 APPS\n\n**注意:** 需要先安装对应的 APP\n\n```bash\nnpm add @netless/app-slide\n```\n\n```typescript\n// 插入动态 PPTX 至白板\nconst appId = await whiteboard.insertDocs({\n fileType: \"pptx\",\n params: {\n scenePath: `/ppt/${uuid}`, // [1]\n title: \"a.pptx\",\n taskId: \"1234567...\", // [2]\n url: \"https://convertcdn.netless.link/dynamicConvert\", // [3]\n },\n});\n\n// 插入 PDF/静态 PPT 至白板\nconst appId = await whiteboard.insertDocs({\n fileType: \"pdf\", // or ppt\n options: {\n scenePath: `/pdf${uuid}`,\n title: \"a.pdf\", // 可选\n scenes: [], // SceneDefinition[] 静态/动态 Scene 数据\n },\n});\n\n// 插入音频/视频至白板\nconst appId = await whiteboard.manager.addApp({\n kind: \"MediaPlayer\",\n options: {\n title: \"test.mp3\", // 可选\n },\n attributes: {\n src: \"xxxx\", // 音视频 url\n },\n});\n```\n\n更多 `app` 请看 [netless-app](#https://github.com/netless-io/netless-app)\n\n## Develop\n\n```bash\npnpm i\n# upgrade dependencies\npnpm up -Li\n# build and see bundle size\npnpm build\nopen node_modules/.visualizer/stats.html\n```\n\n## License\n\nMIT @ [netless](https://github.com/netless-io)\n"
66
87
  }
@@ -10,11 +10,33 @@ export type { WhiteboardAppConfig, InsertDocsParams };
10
10
  export class WhiteboardApp {
11
11
  private readonly _instance: Instance;
12
12
 
13
+ private _target: HTMLElement | null = null;
14
+ public get target(): HTMLElement | null {
15
+ return this._target;
16
+ }
17
+
13
18
  constructor(readonly config: WhiteboardAppConfig) {
14
19
  this._instance = new Instance(config);
15
20
  }
16
21
 
22
+ get room() {
23
+ return this._instance.room;
24
+ }
25
+
26
+ get manager() {
27
+ return this._instance.manager;
28
+ }
29
+
30
+ get sdk() {
31
+ return this._instance.sdk;
32
+ }
33
+
34
+ get i18n() {
35
+ return this._instance.i18n;
36
+ }
37
+
17
38
  public bindElement(target?: HTMLElement | null) {
39
+ this._target = target || null;
18
40
  this._instance.target = target || null;
19
41
  }
20
42
 
@@ -22,6 +44,18 @@ export class WhiteboardApp {
22
44
  return this._instance.insertDocs(params);
23
45
  }
24
46
 
47
+ public insertCodeEditor() {
48
+ return this._instance.insertCodeEditor();
49
+ }
50
+
51
+ public insertGeoGebra() {
52
+ return this._instance.insertGeoGebra();
53
+ }
54
+
55
+ public insertCountdown() {
56
+ return this._instance.insertCountdown();
57
+ }
58
+
25
59
  public changeLanguage(language: Language) {
26
60
  return this._instance.changeLanguage(language);
27
61
  }
package/src/index.ts CHANGED
@@ -10,6 +10,10 @@ export { PageControl, type PageControlProps } from "./components/PageControl";
10
10
  export { RedoUndo, type RedoUndoProps } from "./components/RedoUndo";
11
11
  export { Toolbar, type ToolbarProps } from "./components/Toolbar";
12
12
  export { ZoomControl, type ZoomControlProps } from "./components/ZoomControl";
13
+ export {
14
+ PlayerControl,
15
+ type PlayerControlProps,
16
+ } from "./components/PlayerControl";
13
17
  export * from "./WhiteboardApp";
14
18
  export * from "./hooks";
15
19
 
package/src/svelte.ts ADDED
@@ -0,0 +1,45 @@
1
+ import { readable, type Readable } from "svelte/store";
2
+ import { createWhiteboardApp } from "./index";
3
+
4
+ import type { WhiteboardApp, WhiteboardAppConfig } from "./WhiteboardApp";
5
+
6
+ export type FastBoardConfig = WhiteboardAppConfig;
7
+
8
+ /**
9
+ * @example
10
+ * ```svelte
11
+ * <script>
12
+ * let ref = writable(null)
13
+ * let app = useFastboard(ref, { sdkConfig, joinRoom })
14
+ * if (app) {
15
+ * app.insertDocs({...})
16
+ * }
17
+ * </script>
18
+ * <div style="width: 100%; height: 100%" bind:this={$ref} />
19
+ * ```
20
+ */
21
+ export function useFastboard(
22
+ ref: Readable<HTMLElement | null>,
23
+ config: FastBoardConfig
24
+ ): Readable<WhiteboardApp | null> {
25
+ return readable<WhiteboardApp | null>(null, set => {
26
+ let app_: WhiteboardApp | null = null;
27
+
28
+ createWhiteboardApp(config).then(app => {
29
+ set((app_ = app));
30
+ });
31
+
32
+ const dispose = ref.subscribe(div => {
33
+ if (div && app_) {
34
+ app_.bindElement(div);
35
+ }
36
+ });
37
+
38
+ return () => {
39
+ dispose();
40
+ if (app_) {
41
+ app_.dispose();
42
+ }
43
+ };
44
+ });
45
+ }
package/src/vue.ts ADDED
@@ -0,0 +1,74 @@
1
+ import type { ComponentPublicInstance, Ref } from "vue-demi";
2
+ import {
3
+ computed,
4
+ getCurrentScope,
5
+ onScopeDispose,
6
+ shallowRef,
7
+ unref,
8
+ watchEffect,
9
+ } from "vue-demi";
10
+ import { createWhiteboardApp } from "./index";
11
+
12
+ import type { WhiteboardApp, WhiteboardAppConfig } from "./WhiteboardApp";
13
+
14
+ export type FastBoardConfig = WhiteboardAppConfig;
15
+
16
+ export type MaybeRef<T> = T | Ref<T>;
17
+ export type VueInstance = ComponentPublicInstance;
18
+ export type MaybeElementRef = MaybeRef<
19
+ HTMLElement | SVGElement | VueInstance | undefined | null
20
+ >;
21
+
22
+ /**
23
+ * Get the dom element of a ref of element or Vue component instance
24
+ */
25
+ export function unrefElement(elRef: MaybeElementRef) {
26
+ const plain = unref(elRef);
27
+ return (plain as VueInstance)?.$el ?? plain;
28
+ }
29
+
30
+ function tryOnScopeDispose(fn: () => void) {
31
+ if (getCurrentScope()) {
32
+ onScopeDispose(fn);
33
+ return true;
34
+ }
35
+ return false;
36
+ }
37
+
38
+ /**
39
+ * @example
40
+ * ```vue
41
+ * <script setup>
42
+ * const el = ref(null)
43
+ * const app = useFastboard(el, { sdkConfig, joinRoom })
44
+ * if (app.value) {
45
+ * app.value.insertDocs({...})
46
+ * }
47
+ * </script>
48
+ * <template>
49
+ * <div style="width: 100%; height: 100%" ref="el"></div>
50
+ * </template>
51
+ * ```
52
+ */
53
+ export function useFastboard(el: MaybeElementRef, config: FastBoardConfig) {
54
+ const app = shallowRef<WhiteboardApp | null>(null);
55
+ const target = computed(() => unrefElement(el));
56
+
57
+ createWhiteboardApp(config).then(app_ => {
58
+ app.value = app_;
59
+ });
60
+
61
+ watchEffect(() => {
62
+ if (target.value && app.value) {
63
+ app.value.bindElement(target.value);
64
+ }
65
+ });
66
+
67
+ tryOnScopeDispose(() => {
68
+ if (app.value) {
69
+ app.value.dispose();
70
+ }
71
+ });
72
+
73
+ return app;
74
+ }