@sofereditor/collab 0.2.0 → 0.3.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.
- package/dist/index.cjs +8 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +10 -1
- package/dist/index.d.ts +10 -1
- package/dist/index.js +7 -1
- package/dist/index.js.map +1 -1
- package/package.json +8 -8
package/dist/index.cjs
CHANGED
|
@@ -23,6 +23,7 @@ __export(index_exports, {
|
|
|
23
23
|
bindCollab: () => bindCollab,
|
|
24
24
|
getPeers: () => getPeers,
|
|
25
25
|
observePeers: () => observePeers,
|
|
26
|
+
setLocalCursor: () => setLocalCursor,
|
|
26
27
|
useCollab: () => useCollab
|
|
27
28
|
});
|
|
28
29
|
module.exports = __toCommonJS(index_exports);
|
|
@@ -70,9 +71,11 @@ function getPeers(awareness) {
|
|
|
70
71
|
const peers = [];
|
|
71
72
|
awareness.getStates().forEach((state, clientId) => {
|
|
72
73
|
if (clientId === awareness.clientID) return;
|
|
74
|
+
const s = state;
|
|
73
75
|
peers.push({
|
|
74
76
|
clientId,
|
|
75
|
-
user:
|
|
77
|
+
user: s.user,
|
|
78
|
+
cursor: s.cursor ?? void 0
|
|
76
79
|
});
|
|
77
80
|
});
|
|
78
81
|
return peers;
|
|
@@ -83,6 +86,9 @@ function observePeers(awareness, callback) {
|
|
|
83
86
|
emit();
|
|
84
87
|
return () => awareness.off("change", emit);
|
|
85
88
|
}
|
|
89
|
+
function setLocalCursor(awareness, cursor) {
|
|
90
|
+
awareness.setLocalStateField("cursor", cursor);
|
|
91
|
+
}
|
|
86
92
|
|
|
87
93
|
// src/useCollab.ts
|
|
88
94
|
var import_react = require("react");
|
|
@@ -119,6 +125,7 @@ function useCollab(options) {
|
|
|
119
125
|
bindCollab,
|
|
120
126
|
getPeers,
|
|
121
127
|
observePeers,
|
|
128
|
+
setLocalCursor,
|
|
122
129
|
useCollab
|
|
123
130
|
});
|
|
124
131
|
//# sourceMappingURL=index.cjs.map
|
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/binding.ts","../src/awareness.ts","../src/useCollab.ts"],"sourcesContent":["export {\n bindCollab,\n type BindCollabOptions,\n type CollabBinding,\n type CollabUser,\n type ConnectionStatus,\n} from \"./binding\";\n\nexport {
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/binding.ts","../src/awareness.ts","../src/useCollab.ts"],"sourcesContent":["export {\n bindCollab,\n type BindCollabOptions,\n type CollabBinding,\n type CollabUser,\n type ConnectionStatus,\n} from \"./binding\";\n\nexport {\n getPeers,\n observePeers,\n setLocalCursor,\n type PeerState,\n} from \"./awareness\";\n\nexport {\n useCollab,\n type UseCollabOptions,\n type UseCollabResult,\n} from \"./useCollab\";\n","import type * as Y from \"yjs\";\nimport { HocuspocusProvider } from \"@hocuspocus/provider\";\nimport type { Awareness } from \"y-protocols/awareness\";\n\nexport type ConnectionStatus = \"connecting\" | \"connected\" | \"disconnected\";\n\nexport interface CollabUser {\n name: string;\n color: string;\n}\n\nexport interface BindCollabOptions {\n ydoc: Y.Doc;\n url: string;\n name: string;\n token?: string;\n user?: CollabUser;\n onStatus?: (status: ConnectionStatus) => void;\n onSynced?: (synced: boolean) => void;\n}\n\nexport interface CollabBinding {\n readonly provider: HocuspocusProvider;\n readonly awareness: Awareness;\n setUser(user: CollabUser | null): void;\n destroy(): void;\n}\n\nexport function bindCollab(opts: BindCollabOptions): CollabBinding {\n const provider = new HocuspocusProvider({\n url: opts.url,\n name: opts.name,\n document: opts.ydoc,\n token: opts.token,\n onStatus: opts.onStatus\n ? ({ status }) => opts.onStatus!(status as ConnectionStatus)\n : undefined,\n onSynced: opts.onSynced\n ? ({ state }) => opts.onSynced!(state)\n : undefined,\n });\n\n if (opts.user) {\n provider.awareness?.setLocalStateField(\"user\", opts.user);\n }\n\n let destroyed = false;\n\n return {\n provider,\n get awareness() {\n const a = provider.awareness;\n if (!a) {\n throw new Error(\n \"[@sofereditor/collab] Awareness not yet available (provider not connected).\",\n );\n }\n return a;\n },\n setUser(user) {\n if (destroyed) return;\n provider.awareness?.setLocalStateField(\"user\", user);\n },\n destroy() {\n if (destroyed) return;\n destroyed = true;\n provider.destroy();\n },\n };\n}\n","import type { Awareness } from \"y-protocols/awareness\";\nimport type { EncodedCursor } from \"@sofereditor/core\";\nimport type { CollabUser } from \"./binding\";\n\nexport interface PeerState {\n clientId: number;\n user?: CollabUser;\n /** Cursor/seleção remota codificada (Y.RelativePosition + blockId). */\n cursor?: EncodedCursor;\n}\n\nexport function getPeers(awareness: Awareness): PeerState[] {\n const peers: PeerState[] = [];\n awareness.getStates().forEach((state, clientId) => {\n if (clientId === awareness.clientID) return;\n const s = state as { user?: CollabUser; cursor?: EncodedCursor };\n peers.push({\n clientId,\n user: s.user,\n cursor: s.cursor ?? undefined,\n });\n });\n return peers;\n}\n\nexport function observePeers(\n awareness: Awareness,\n callback: (peers: PeerState[]) => void,\n): () => void {\n const emit = () => callback(getPeers(awareness));\n awareness.on(\"change\", emit);\n emit();\n return () => awareness.off(\"change\", emit);\n}\n\n/**\n * Publica (ou limpa, com null) o cursor/seleção local no awareness. O editor\n * chama isto a cada mudança de seleção (com throttle). Os peers leem via\n * `getPeers`/`observePeers`.\n */\nexport function setLocalCursor(\n awareness: Awareness,\n cursor: EncodedCursor | null,\n): void {\n awareness.setLocalStateField(\"cursor\", cursor);\n}\n","import { useEffect, useRef, useState } from \"react\";\nimport type * as Y from \"yjs\";\nimport {\n bindCollab,\n type BindCollabOptions,\n type CollabBinding,\n type ConnectionStatus,\n} from \"./binding\";\n\nexport interface UseCollabOptions extends Omit<BindCollabOptions, \"ydoc\"> {\n ydoc: Y.Doc;\n}\n\nexport interface UseCollabResult {\n status: ConnectionStatus;\n synced: boolean;\n binding: CollabBinding | null;\n}\n\nexport function useCollab(options: UseCollabOptions): UseCollabResult {\n const { ydoc, url, name, token, user } = options;\n const [status, setStatus] = useState<ConnectionStatus>(\"connecting\");\n const [synced, setSynced] = useState(false);\n const bindingRef = useRef<CollabBinding | null>(null);\n\n useEffect(() => {\n const binding = bindCollab({\n ydoc,\n url,\n name,\n token,\n user,\n onStatus: (s) => setStatus(s),\n onSynced: (s) => setSynced(s),\n });\n bindingRef.current = binding;\n return () => {\n binding.destroy();\n bindingRef.current = null;\n setStatus(\"disconnected\");\n setSynced(false);\n };\n // Re-bind when document identity or connection params change. `user` is\n // updated via setUser below so changes don't tear down the socket.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [ydoc, url, name, token]);\n\n useEffect(() => {\n bindingRef.current?.setUser(user ?? null);\n }, [user?.name, user?.color]);\n\n return { status, synced, binding: bindingRef.current };\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACCA,sBAAmC;AA2B5B,SAAS,WAAW,MAAwC;AACjE,QAAM,WAAW,IAAI,mCAAmB;AAAA,IACtC,KAAK,KAAK;AAAA,IACV,MAAM,KAAK;AAAA,IACX,UAAU,KAAK;AAAA,IACf,OAAO,KAAK;AAAA,IACZ,UAAU,KAAK,WACX,CAAC,EAAE,OAAO,MAAM,KAAK,SAAU,MAA0B,IACzD;AAAA,IACJ,UAAU,KAAK,WACX,CAAC,EAAE,MAAM,MAAM,KAAK,SAAU,KAAK,IACnC;AAAA,EACN,CAAC;AAED,MAAI,KAAK,MAAM;AACb,aAAS,WAAW,mBAAmB,QAAQ,KAAK,IAAI;AAAA,EAC1D;AAEA,MAAI,YAAY;AAEhB,SAAO;AAAA,IACL;AAAA,IACA,IAAI,YAAY;AACd,YAAM,IAAI,SAAS;AACnB,UAAI,CAAC,GAAG;AACN,cAAM,IAAI;AAAA,UACR;AAAA,QACF;AAAA,MACF;AACA,aAAO;AAAA,IACT;AAAA,IACA,QAAQ,MAAM;AACZ,UAAI,UAAW;AACf,eAAS,WAAW,mBAAmB,QAAQ,IAAI;AAAA,IACrD;AAAA,IACA,UAAU;AACR,UAAI,UAAW;AACf,kBAAY;AACZ,eAAS,QAAQ;AAAA,IACnB;AAAA,EACF;AACF;;;AC1DO,SAAS,SAAS,WAAmC;AAC1D,QAAM,QAAqB,CAAC;AAC5B,YAAU,UAAU,EAAE,QAAQ,CAAC,OAAO,aAAa;AACjD,QAAI,aAAa,UAAU,SAAU;AACrC,UAAM,IAAI;AACV,UAAM,KAAK;AAAA,MACT;AAAA,MACA,MAAM,EAAE;AAAA,MACR,QAAQ,EAAE,UAAU;AAAA,IACtB,CAAC;AAAA,EACH,CAAC;AACD,SAAO;AACT;AAEO,SAAS,aACd,WACA,UACY;AACZ,QAAM,OAAO,MAAM,SAAS,SAAS,SAAS,CAAC;AAC/C,YAAU,GAAG,UAAU,IAAI;AAC3B,OAAK;AACL,SAAO,MAAM,UAAU,IAAI,UAAU,IAAI;AAC3C;AAOO,SAAS,eACd,WACA,QACM;AACN,YAAU,mBAAmB,UAAU,MAAM;AAC/C;;;AC7CA,mBAA4C;AAmBrC,SAAS,UAAU,SAA4C;AACpE,QAAM,EAAE,MAAM,KAAK,MAAM,OAAO,KAAK,IAAI;AACzC,QAAM,CAAC,QAAQ,SAAS,QAAI,uBAA2B,YAAY;AACnE,QAAM,CAAC,QAAQ,SAAS,QAAI,uBAAS,KAAK;AAC1C,QAAM,iBAAa,qBAA6B,IAAI;AAEpD,8BAAU,MAAM;AACd,UAAM,UAAU,WAAW;AAAA,MACzB;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA,UAAU,CAAC,MAAM,UAAU,CAAC;AAAA,MAC5B,UAAU,CAAC,MAAM,UAAU,CAAC;AAAA,IAC9B,CAAC;AACD,eAAW,UAAU;AACrB,WAAO,MAAM;AACX,cAAQ,QAAQ;AAChB,iBAAW,UAAU;AACrB,gBAAU,cAAc;AACxB,gBAAU,KAAK;AAAA,IACjB;AAAA,EAIF,GAAG,CAAC,MAAM,KAAK,MAAM,KAAK,CAAC;AAE3B,8BAAU,MAAM;AACd,eAAW,SAAS,QAAQ,QAAQ,IAAI;AAAA,EAC1C,GAAG,CAAC,MAAM,MAAM,MAAM,KAAK,CAAC;AAE5B,SAAO,EAAE,QAAQ,QAAQ,SAAS,WAAW,QAAQ;AACvD;","names":[]}
|
package/dist/index.d.cts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import * as Y from 'yjs';
|
|
2
2
|
import { HocuspocusProvider } from '@hocuspocus/provider';
|
|
3
3
|
import { Awareness } from 'y-protocols/awareness';
|
|
4
|
+
import { EncodedCursor } from '@sofereditor/core';
|
|
4
5
|
|
|
5
6
|
type ConnectionStatus = "connecting" | "connected" | "disconnected";
|
|
6
7
|
interface CollabUser {
|
|
@@ -27,9 +28,17 @@ declare function bindCollab(opts: BindCollabOptions): CollabBinding;
|
|
|
27
28
|
interface PeerState {
|
|
28
29
|
clientId: number;
|
|
29
30
|
user?: CollabUser;
|
|
31
|
+
/** Cursor/seleção remota codificada (Y.RelativePosition + blockId). */
|
|
32
|
+
cursor?: EncodedCursor;
|
|
30
33
|
}
|
|
31
34
|
declare function getPeers(awareness: Awareness): PeerState[];
|
|
32
35
|
declare function observePeers(awareness: Awareness, callback: (peers: PeerState[]) => void): () => void;
|
|
36
|
+
/**
|
|
37
|
+
* Publica (ou limpa, com null) o cursor/seleção local no awareness. O editor
|
|
38
|
+
* chama isto a cada mudança de seleção (com throttle). Os peers leem via
|
|
39
|
+
* `getPeers`/`observePeers`.
|
|
40
|
+
*/
|
|
41
|
+
declare function setLocalCursor(awareness: Awareness, cursor: EncodedCursor | null): void;
|
|
33
42
|
|
|
34
43
|
interface UseCollabOptions extends Omit<BindCollabOptions, "ydoc"> {
|
|
35
44
|
ydoc: Y.Doc;
|
|
@@ -41,4 +50,4 @@ interface UseCollabResult {
|
|
|
41
50
|
}
|
|
42
51
|
declare function useCollab(options: UseCollabOptions): UseCollabResult;
|
|
43
52
|
|
|
44
|
-
export { type BindCollabOptions, type CollabBinding, type CollabUser, type ConnectionStatus, type PeerState, type UseCollabOptions, type UseCollabResult, bindCollab, getPeers, observePeers, useCollab };
|
|
53
|
+
export { type BindCollabOptions, type CollabBinding, type CollabUser, type ConnectionStatus, type PeerState, type UseCollabOptions, type UseCollabResult, bindCollab, getPeers, observePeers, setLocalCursor, useCollab };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import * as Y from 'yjs';
|
|
2
2
|
import { HocuspocusProvider } from '@hocuspocus/provider';
|
|
3
3
|
import { Awareness } from 'y-protocols/awareness';
|
|
4
|
+
import { EncodedCursor } from '@sofereditor/core';
|
|
4
5
|
|
|
5
6
|
type ConnectionStatus = "connecting" | "connected" | "disconnected";
|
|
6
7
|
interface CollabUser {
|
|
@@ -27,9 +28,17 @@ declare function bindCollab(opts: BindCollabOptions): CollabBinding;
|
|
|
27
28
|
interface PeerState {
|
|
28
29
|
clientId: number;
|
|
29
30
|
user?: CollabUser;
|
|
31
|
+
/** Cursor/seleção remota codificada (Y.RelativePosition + blockId). */
|
|
32
|
+
cursor?: EncodedCursor;
|
|
30
33
|
}
|
|
31
34
|
declare function getPeers(awareness: Awareness): PeerState[];
|
|
32
35
|
declare function observePeers(awareness: Awareness, callback: (peers: PeerState[]) => void): () => void;
|
|
36
|
+
/**
|
|
37
|
+
* Publica (ou limpa, com null) o cursor/seleção local no awareness. O editor
|
|
38
|
+
* chama isto a cada mudança de seleção (com throttle). Os peers leem via
|
|
39
|
+
* `getPeers`/`observePeers`.
|
|
40
|
+
*/
|
|
41
|
+
declare function setLocalCursor(awareness: Awareness, cursor: EncodedCursor | null): void;
|
|
33
42
|
|
|
34
43
|
interface UseCollabOptions extends Omit<BindCollabOptions, "ydoc"> {
|
|
35
44
|
ydoc: Y.Doc;
|
|
@@ -41,4 +50,4 @@ interface UseCollabResult {
|
|
|
41
50
|
}
|
|
42
51
|
declare function useCollab(options: UseCollabOptions): UseCollabResult;
|
|
43
52
|
|
|
44
|
-
export { type BindCollabOptions, type CollabBinding, type CollabUser, type ConnectionStatus, type PeerState, type UseCollabOptions, type UseCollabResult, bindCollab, getPeers, observePeers, useCollab };
|
|
53
|
+
export { type BindCollabOptions, type CollabBinding, type CollabUser, type ConnectionStatus, type PeerState, type UseCollabOptions, type UseCollabResult, bindCollab, getPeers, observePeers, setLocalCursor, useCollab };
|
package/dist/index.js
CHANGED
|
@@ -41,9 +41,11 @@ function getPeers(awareness) {
|
|
|
41
41
|
const peers = [];
|
|
42
42
|
awareness.getStates().forEach((state, clientId) => {
|
|
43
43
|
if (clientId === awareness.clientID) return;
|
|
44
|
+
const s = state;
|
|
44
45
|
peers.push({
|
|
45
46
|
clientId,
|
|
46
|
-
user:
|
|
47
|
+
user: s.user,
|
|
48
|
+
cursor: s.cursor ?? void 0
|
|
47
49
|
});
|
|
48
50
|
});
|
|
49
51
|
return peers;
|
|
@@ -54,6 +56,9 @@ function observePeers(awareness, callback) {
|
|
|
54
56
|
emit();
|
|
55
57
|
return () => awareness.off("change", emit);
|
|
56
58
|
}
|
|
59
|
+
function setLocalCursor(awareness, cursor) {
|
|
60
|
+
awareness.setLocalStateField("cursor", cursor);
|
|
61
|
+
}
|
|
57
62
|
|
|
58
63
|
// src/useCollab.ts
|
|
59
64
|
import { useEffect, useRef, useState } from "react";
|
|
@@ -89,6 +94,7 @@ export {
|
|
|
89
94
|
bindCollab,
|
|
90
95
|
getPeers,
|
|
91
96
|
observePeers,
|
|
97
|
+
setLocalCursor,
|
|
92
98
|
useCollab
|
|
93
99
|
};
|
|
94
100
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/binding.ts","../src/awareness.ts","../src/useCollab.ts"],"sourcesContent":["import type * as Y from \"yjs\";\nimport { HocuspocusProvider } from \"@hocuspocus/provider\";\nimport type { Awareness } from \"y-protocols/awareness\";\n\nexport type ConnectionStatus = \"connecting\" | \"connected\" | \"disconnected\";\n\nexport interface CollabUser {\n name: string;\n color: string;\n}\n\nexport interface BindCollabOptions {\n ydoc: Y.Doc;\n url: string;\n name: string;\n token?: string;\n user?: CollabUser;\n onStatus?: (status: ConnectionStatus) => void;\n onSynced?: (synced: boolean) => void;\n}\n\nexport interface CollabBinding {\n readonly provider: HocuspocusProvider;\n readonly awareness: Awareness;\n setUser(user: CollabUser | null): void;\n destroy(): void;\n}\n\nexport function bindCollab(opts: BindCollabOptions): CollabBinding {\n const provider = new HocuspocusProvider({\n url: opts.url,\n name: opts.name,\n document: opts.ydoc,\n token: opts.token,\n onStatus: opts.onStatus\n ? ({ status }) => opts.onStatus!(status as ConnectionStatus)\n : undefined,\n onSynced: opts.onSynced\n ? ({ state }) => opts.onSynced!(state)\n : undefined,\n });\n\n if (opts.user) {\n provider.awareness?.setLocalStateField(\"user\", opts.user);\n }\n\n let destroyed = false;\n\n return {\n provider,\n get awareness() {\n const a = provider.awareness;\n if (!a) {\n throw new Error(\n \"[@sofereditor/collab] Awareness not yet available (provider not connected).\",\n );\n }\n return a;\n },\n setUser(user) {\n if (destroyed) return;\n provider.awareness?.setLocalStateField(\"user\", user);\n },\n destroy() {\n if (destroyed) return;\n destroyed = true;\n provider.destroy();\n },\n };\n}\n","import type { Awareness } from \"y-protocols/awareness\";\nimport type { CollabUser } from \"./binding\";\n\nexport interface PeerState {\n clientId: number;\n user?: CollabUser;\n}\n\nexport function getPeers(awareness: Awareness): PeerState[] {\n const peers: PeerState[] = [];\n awareness.getStates().forEach((state, clientId) => {\n if (clientId === awareness.clientID) return;\n peers.push({\n clientId,\n user:
|
|
1
|
+
{"version":3,"sources":["../src/binding.ts","../src/awareness.ts","../src/useCollab.ts"],"sourcesContent":["import type * as Y from \"yjs\";\nimport { HocuspocusProvider } from \"@hocuspocus/provider\";\nimport type { Awareness } from \"y-protocols/awareness\";\n\nexport type ConnectionStatus = \"connecting\" | \"connected\" | \"disconnected\";\n\nexport interface CollabUser {\n name: string;\n color: string;\n}\n\nexport interface BindCollabOptions {\n ydoc: Y.Doc;\n url: string;\n name: string;\n token?: string;\n user?: CollabUser;\n onStatus?: (status: ConnectionStatus) => void;\n onSynced?: (synced: boolean) => void;\n}\n\nexport interface CollabBinding {\n readonly provider: HocuspocusProvider;\n readonly awareness: Awareness;\n setUser(user: CollabUser | null): void;\n destroy(): void;\n}\n\nexport function bindCollab(opts: BindCollabOptions): CollabBinding {\n const provider = new HocuspocusProvider({\n url: opts.url,\n name: opts.name,\n document: opts.ydoc,\n token: opts.token,\n onStatus: opts.onStatus\n ? ({ status }) => opts.onStatus!(status as ConnectionStatus)\n : undefined,\n onSynced: opts.onSynced\n ? ({ state }) => opts.onSynced!(state)\n : undefined,\n });\n\n if (opts.user) {\n provider.awareness?.setLocalStateField(\"user\", opts.user);\n }\n\n let destroyed = false;\n\n return {\n provider,\n get awareness() {\n const a = provider.awareness;\n if (!a) {\n throw new Error(\n \"[@sofereditor/collab] Awareness not yet available (provider not connected).\",\n );\n }\n return a;\n },\n setUser(user) {\n if (destroyed) return;\n provider.awareness?.setLocalStateField(\"user\", user);\n },\n destroy() {\n if (destroyed) return;\n destroyed = true;\n provider.destroy();\n },\n };\n}\n","import type { Awareness } from \"y-protocols/awareness\";\nimport type { EncodedCursor } from \"@sofereditor/core\";\nimport type { CollabUser } from \"./binding\";\n\nexport interface PeerState {\n clientId: number;\n user?: CollabUser;\n /** Cursor/seleção remota codificada (Y.RelativePosition + blockId). */\n cursor?: EncodedCursor;\n}\n\nexport function getPeers(awareness: Awareness): PeerState[] {\n const peers: PeerState[] = [];\n awareness.getStates().forEach((state, clientId) => {\n if (clientId === awareness.clientID) return;\n const s = state as { user?: CollabUser; cursor?: EncodedCursor };\n peers.push({\n clientId,\n user: s.user,\n cursor: s.cursor ?? undefined,\n });\n });\n return peers;\n}\n\nexport function observePeers(\n awareness: Awareness,\n callback: (peers: PeerState[]) => void,\n): () => void {\n const emit = () => callback(getPeers(awareness));\n awareness.on(\"change\", emit);\n emit();\n return () => awareness.off(\"change\", emit);\n}\n\n/**\n * Publica (ou limpa, com null) o cursor/seleção local no awareness. O editor\n * chama isto a cada mudança de seleção (com throttle). Os peers leem via\n * `getPeers`/`observePeers`.\n */\nexport function setLocalCursor(\n awareness: Awareness,\n cursor: EncodedCursor | null,\n): void {\n awareness.setLocalStateField(\"cursor\", cursor);\n}\n","import { useEffect, useRef, useState } from \"react\";\nimport type * as Y from \"yjs\";\nimport {\n bindCollab,\n type BindCollabOptions,\n type CollabBinding,\n type ConnectionStatus,\n} from \"./binding\";\n\nexport interface UseCollabOptions extends Omit<BindCollabOptions, \"ydoc\"> {\n ydoc: Y.Doc;\n}\n\nexport interface UseCollabResult {\n status: ConnectionStatus;\n synced: boolean;\n binding: CollabBinding | null;\n}\n\nexport function useCollab(options: UseCollabOptions): UseCollabResult {\n const { ydoc, url, name, token, user } = options;\n const [status, setStatus] = useState<ConnectionStatus>(\"connecting\");\n const [synced, setSynced] = useState(false);\n const bindingRef = useRef<CollabBinding | null>(null);\n\n useEffect(() => {\n const binding = bindCollab({\n ydoc,\n url,\n name,\n token,\n user,\n onStatus: (s) => setStatus(s),\n onSynced: (s) => setSynced(s),\n });\n bindingRef.current = binding;\n return () => {\n binding.destroy();\n bindingRef.current = null;\n setStatus(\"disconnected\");\n setSynced(false);\n };\n // Re-bind when document identity or connection params change. `user` is\n // updated via setUser below so changes don't tear down the socket.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [ydoc, url, name, token]);\n\n useEffect(() => {\n bindingRef.current?.setUser(user ?? null);\n }, [user?.name, user?.color]);\n\n return { status, synced, binding: bindingRef.current };\n}\n"],"mappings":";AACA,SAAS,0BAA0B;AA2B5B,SAAS,WAAW,MAAwC;AACjE,QAAM,WAAW,IAAI,mBAAmB;AAAA,IACtC,KAAK,KAAK;AAAA,IACV,MAAM,KAAK;AAAA,IACX,UAAU,KAAK;AAAA,IACf,OAAO,KAAK;AAAA,IACZ,UAAU,KAAK,WACX,CAAC,EAAE,OAAO,MAAM,KAAK,SAAU,MAA0B,IACzD;AAAA,IACJ,UAAU,KAAK,WACX,CAAC,EAAE,MAAM,MAAM,KAAK,SAAU,KAAK,IACnC;AAAA,EACN,CAAC;AAED,MAAI,KAAK,MAAM;AACb,aAAS,WAAW,mBAAmB,QAAQ,KAAK,IAAI;AAAA,EAC1D;AAEA,MAAI,YAAY;AAEhB,SAAO;AAAA,IACL;AAAA,IACA,IAAI,YAAY;AACd,YAAM,IAAI,SAAS;AACnB,UAAI,CAAC,GAAG;AACN,cAAM,IAAI;AAAA,UACR;AAAA,QACF;AAAA,MACF;AACA,aAAO;AAAA,IACT;AAAA,IACA,QAAQ,MAAM;AACZ,UAAI,UAAW;AACf,eAAS,WAAW,mBAAmB,QAAQ,IAAI;AAAA,IACrD;AAAA,IACA,UAAU;AACR,UAAI,UAAW;AACf,kBAAY;AACZ,eAAS,QAAQ;AAAA,IACnB;AAAA,EACF;AACF;;;AC1DO,SAAS,SAAS,WAAmC;AAC1D,QAAM,QAAqB,CAAC;AAC5B,YAAU,UAAU,EAAE,QAAQ,CAAC,OAAO,aAAa;AACjD,QAAI,aAAa,UAAU,SAAU;AACrC,UAAM,IAAI;AACV,UAAM,KAAK;AAAA,MACT;AAAA,MACA,MAAM,EAAE;AAAA,MACR,QAAQ,EAAE,UAAU;AAAA,IACtB,CAAC;AAAA,EACH,CAAC;AACD,SAAO;AACT;AAEO,SAAS,aACd,WACA,UACY;AACZ,QAAM,OAAO,MAAM,SAAS,SAAS,SAAS,CAAC;AAC/C,YAAU,GAAG,UAAU,IAAI;AAC3B,OAAK;AACL,SAAO,MAAM,UAAU,IAAI,UAAU,IAAI;AAC3C;AAOO,SAAS,eACd,WACA,QACM;AACN,YAAU,mBAAmB,UAAU,MAAM;AAC/C;;;AC7CA,SAAS,WAAW,QAAQ,gBAAgB;AAmBrC,SAAS,UAAU,SAA4C;AACpE,QAAM,EAAE,MAAM,KAAK,MAAM,OAAO,KAAK,IAAI;AACzC,QAAM,CAAC,QAAQ,SAAS,IAAI,SAA2B,YAAY;AACnE,QAAM,CAAC,QAAQ,SAAS,IAAI,SAAS,KAAK;AAC1C,QAAM,aAAa,OAA6B,IAAI;AAEpD,YAAU,MAAM;AACd,UAAM,UAAU,WAAW;AAAA,MACzB;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA,UAAU,CAAC,MAAM,UAAU,CAAC;AAAA,MAC5B,UAAU,CAAC,MAAM,UAAU,CAAC;AAAA,IAC9B,CAAC;AACD,eAAW,UAAU;AACrB,WAAO,MAAM;AACX,cAAQ,QAAQ;AAChB,iBAAW,UAAU;AACrB,gBAAU,cAAc;AACxB,gBAAU,KAAK;AAAA,IACjB;AAAA,EAIF,GAAG,CAAC,MAAM,KAAK,MAAM,KAAK,CAAC;AAE3B,YAAU,MAAM;AACd,eAAW,SAAS,QAAQ,QAAQ,IAAI;AAAA,EAC1C,GAAG,CAAC,MAAM,MAAM,MAAM,KAAK,CAAC;AAE5B,SAAO,EAAE,QAAQ,QAAQ,SAAS,WAAW,QAAQ;AACvD;","names":[]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sofereditor/collab",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.1",
|
|
4
4
|
"description": "@sofereditor/collab — Hocuspocus binding for real-time collaboration with the Sofer editor. Bidirectional Y.Doc sync + awareness.",
|
|
5
5
|
"license": "AGPL-3.0-or-later",
|
|
6
6
|
"author": "Rafael Marreca",
|
|
@@ -22,14 +22,14 @@
|
|
|
22
22
|
"sofer"
|
|
23
23
|
],
|
|
24
24
|
"type": "module",
|
|
25
|
-
"main": "./
|
|
26
|
-
"module": "./
|
|
27
|
-
"types": "./
|
|
25
|
+
"main": "./dist/index.cjs",
|
|
26
|
+
"module": "./dist/index.js",
|
|
27
|
+
"types": "./dist/index.d.ts",
|
|
28
28
|
"exports": {
|
|
29
29
|
".": {
|
|
30
|
-
"types": "./
|
|
31
|
-
"import": "./
|
|
32
|
-
"require": "./
|
|
30
|
+
"types": "./dist/index.d.ts",
|
|
31
|
+
"import": "./dist/index.js",
|
|
32
|
+
"require": "./dist/index.cjs"
|
|
33
33
|
}
|
|
34
34
|
},
|
|
35
35
|
"publishConfig": {
|
|
@@ -62,7 +62,7 @@
|
|
|
62
62
|
}
|
|
63
63
|
},
|
|
64
64
|
"dependencies": {
|
|
65
|
-
"@sofereditor/core": "^0.
|
|
65
|
+
"@sofereditor/core": "^0.3.1",
|
|
66
66
|
"@hocuspocus/provider": "^3.4.4",
|
|
67
67
|
"y-protocols": "^1.0.6",
|
|
68
68
|
"yjs": "^13.6.20"
|