@korajs/react 1.0.0-beta.12 → 1.0.0-beta.13
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/README.md +48 -40
- package/dist/index.cjs +165 -62
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +150 -5
- package/dist/index.d.ts +150 -5
- package/dist/index.js +163 -62
- package/dist/index.js.map +1 -1
- package/package.json +4 -4
package/README.md
CHANGED
|
@@ -1,70 +1,78 @@
|
|
|
1
1
|
# @korajs/react
|
|
2
2
|
|
|
3
|
-
React
|
|
3
|
+
React bindings for Kora.js: a provider, reactive queries, mutations, sync status, rich text and
|
|
4
|
+
presence. Hooks use `useSyncExternalStore`, so they are safe in concurrent rendering, StrictMode and
|
|
5
|
+
server rendering.
|
|
4
6
|
|
|
5
7
|
## Install
|
|
6
8
|
|
|
7
9
|
```bash
|
|
8
|
-
pnpm add korajs @korajs/react
|
|
10
|
+
pnpm add korajs@beta @korajs/react@beta
|
|
9
11
|
```
|
|
10
12
|
|
|
11
13
|
## Usage
|
|
12
14
|
|
|
13
|
-
|
|
15
|
+
<!-- docs-check-prelude
|
|
16
|
+
import { createApp, defineSchema, t } from 'korajs'
|
|
17
|
+
const schema = defineSchema({
|
|
18
|
+
version: 1,
|
|
19
|
+
collections: { todos: { fields: { title: t.string(), completed: t.boolean().default(false), createdAt: t.timestamp().auto() } } },
|
|
20
|
+
})
|
|
21
|
+
const app = createApp({ schema })
|
|
22
|
+
-->
|
|
14
23
|
|
|
15
24
|
```tsx
|
|
16
|
-
import { KoraProvider } from '@korajs/react'
|
|
25
|
+
import { createKoraHooks, KoraProvider } from '@korajs/react'
|
|
17
26
|
|
|
18
|
-
|
|
27
|
+
// Hooks typed by your schema
|
|
28
|
+
const { useCollection, useMutation, useQuery, useSyncStatus } = createKoraHooks<typeof app>()
|
|
29
|
+
|
|
30
|
+
export function Root() {
|
|
19
31
|
return (
|
|
20
|
-
<KoraProvider app={app}>
|
|
32
|
+
<KoraProvider app={app} fallback={<p>Loading...</p>}>
|
|
21
33
|
<TodoList />
|
|
22
34
|
</KoraProvider>
|
|
23
35
|
)
|
|
24
36
|
}
|
|
25
|
-
```
|
|
26
|
-
|
|
27
|
-
### Reactive Queries
|
|
28
|
-
|
|
29
|
-
```tsx
|
|
30
|
-
import { useQuery } from '@korajs/react'
|
|
31
37
|
|
|
32
38
|
function TodoList() {
|
|
33
|
-
const todos =
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
}
|
|
38
|
-
```
|
|
39
|
-
|
|
40
|
-
### Mutations
|
|
41
|
-
|
|
42
|
-
```tsx
|
|
43
|
-
import { useMutation } from '@korajs/react'
|
|
44
|
-
|
|
45
|
-
function AddTodo() {
|
|
46
|
-
const addTodo = useMutation(app.todos.insert)
|
|
39
|
+
const todos = useCollection('todos')
|
|
40
|
+
const open = useQuery(todos.where({ completed: false }).orderBy('createdAt'))
|
|
41
|
+
const addTodo = useMutation(todos.insert)
|
|
42
|
+
const status = useSyncStatus()
|
|
47
43
|
|
|
48
|
-
return
|
|
44
|
+
return (
|
|
45
|
+
<>
|
|
46
|
+
<button onClick={() => addTodo.mutate({ title: 'New todo' })}>Add</button>
|
|
47
|
+
{addTodo.error && <p role="alert">{addTodo.error.message}</p>}
|
|
48
|
+
<ul>
|
|
49
|
+
{open.map((todo) => (
|
|
50
|
+
<li key={todo.id}>{todo.title}</li>
|
|
51
|
+
))}
|
|
52
|
+
</ul>
|
|
53
|
+
<small>
|
|
54
|
+
{status.status}, {status.pendingOperations} pending
|
|
55
|
+
</small>
|
|
56
|
+
</>
|
|
57
|
+
)
|
|
49
58
|
}
|
|
50
59
|
```
|
|
51
60
|
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
61
|
+
- `KoraProvider` renders `fallback` until the local database is open.
|
|
62
|
+
- `useQuery` renders `[]` first and the rows right after mount, then re-renders only when the
|
|
63
|
+
result changes. `useQueryState` returns `{ data, error, ready }`.
|
|
64
|
+
- `useMutation` returns `{ mutate, mutateAsync, isLoading, error, reset }`; writes land locally at
|
|
65
|
+
once and upload in the background.
|
|
66
|
+
- `useSyncStatus()` returns the full status (`status`, `pendingOperations`, `lastSyncedAt`, ...)
|
|
67
|
+
and re-renders only when it changes.
|
|
68
|
+
- `useRichText`, `usePresence`, `useCollaborators` and `AuthBoundKoraProvider` cover collaborative
|
|
69
|
+
editing and per-user databases.
|
|
56
70
|
|
|
57
|
-
|
|
58
|
-
const status = useSyncStatus()
|
|
59
|
-
// 'connected' | 'syncing' | 'synced' | 'offline' | 'error'
|
|
60
|
-
return <span>{status}</span>
|
|
61
|
-
}
|
|
62
|
-
```
|
|
71
|
+
## Documentation
|
|
63
72
|
|
|
64
|
-
|
|
73
|
+
[React Hooks guide](https://korajs.dev/guide/react-hooks) and the
|
|
74
|
+
[React API reference](https://korajs.dev/api/react).
|
|
65
75
|
|
|
66
76
|
## License
|
|
67
77
|
|
|
68
78
|
MIT
|
|
69
|
-
|
|
70
|
-
See the [full documentation](https://github.com/ehoneahobed/kora) for guides, API reference, and examples.
|
package/dist/index.cjs
CHANGED
|
@@ -23,12 +23,14 @@ __export(index_exports, {
|
|
|
23
23
|
AuthBoundKoraProvider: () => AuthBoundKoraProvider,
|
|
24
24
|
KoraProvider: () => KoraProvider,
|
|
25
25
|
classifyKoraInitializationError: () => classifyKoraInitializationError,
|
|
26
|
+
createKoraHooks: () => createKoraHooks,
|
|
26
27
|
useApp: () => useApp,
|
|
27
28
|
useCollaborators: () => useCollaborators,
|
|
28
29
|
useCollection: () => useCollection,
|
|
29
30
|
useMutation: () => useMutation,
|
|
30
31
|
usePresence: () => usePresence,
|
|
31
32
|
useQuery: () => useQuery,
|
|
33
|
+
useQueryState: () => useQueryState,
|
|
32
34
|
useRichText: () => useRichText,
|
|
33
35
|
useSyncStatus: () => useSyncStatus
|
|
34
36
|
});
|
|
@@ -151,6 +153,7 @@ function AuthBoundKoraProvider({
|
|
|
151
153
|
authClient,
|
|
152
154
|
createApp,
|
|
153
155
|
signedOut = null,
|
|
156
|
+
locked,
|
|
154
157
|
fallback = null,
|
|
155
158
|
error: renderError,
|
|
156
159
|
children
|
|
@@ -244,6 +247,7 @@ function AuthBoundKoraProvider({
|
|
|
244
247
|
);
|
|
245
248
|
}
|
|
246
249
|
if (state.state === "signed-out" || state.state === "anonymous") return signedOut;
|
|
250
|
+
if (state.state === "authenticated" && state.locked) return locked ?? signedOut;
|
|
247
251
|
if (!app) return fallback;
|
|
248
252
|
return (0, import_react2.createElement)(KoraProvider, { app, fallback }, children);
|
|
249
253
|
}
|
|
@@ -267,10 +271,17 @@ var noopSubscribe = (_onStoreChange) => {
|
|
|
267
271
|
return () => {
|
|
268
272
|
};
|
|
269
273
|
};
|
|
270
|
-
|
|
274
|
+
var getServerSnapshot = () => EMPTY_ARRAY;
|
|
275
|
+
var getNoError = () => null;
|
|
276
|
+
function readQueryError(queryStore) {
|
|
277
|
+
if (!queryStore) return null;
|
|
278
|
+
const channel = queryStore;
|
|
279
|
+
return typeof channel.getError === "function" ? channel.getError() : null;
|
|
280
|
+
}
|
|
281
|
+
function useQuerySubscription(query, options) {
|
|
271
282
|
const { queryStoreCache } = useKoraContext();
|
|
272
283
|
const enabled = options?.enabled !== false;
|
|
273
|
-
const descriptorKey =
|
|
284
|
+
const descriptorKey = (0, import_store2.queryKey)(query.getDescriptor());
|
|
274
285
|
const queryRef = (0, import_react3.useRef)(query);
|
|
275
286
|
queryRef.current = query;
|
|
276
287
|
const lastSnapshotRef = (0, import_react3.useRef)(EMPTY_ARRAY);
|
|
@@ -288,23 +299,42 @@ function useQuery(query, options) {
|
|
|
288
299
|
queryStoreCache.release(currentQuery);
|
|
289
300
|
};
|
|
290
301
|
}, [descriptorKey, enabled, queryStoreCache]);
|
|
302
|
+
const subscribe = enabled && queryStore ? queryStore.subscribe : noopSubscribe;
|
|
291
303
|
const getSnapshot = (0, import_react3.useCallback)(() => {
|
|
292
304
|
if (!enabled) {
|
|
293
305
|
lastSnapshotRef.current = EMPTY_ARRAY;
|
|
294
306
|
return lastSnapshotRef.current;
|
|
295
307
|
}
|
|
296
|
-
if (!queryStore) {
|
|
297
|
-
return lastSnapshotRef.current;
|
|
298
|
-
}
|
|
299
|
-
if (!queryStore.hasSnapshot()) {
|
|
308
|
+
if (!queryStore || !queryStore.hasSnapshot()) {
|
|
300
309
|
return lastSnapshotRef.current;
|
|
301
310
|
}
|
|
302
311
|
const snapshot = queryStore.getSnapshot();
|
|
303
312
|
lastSnapshotRef.current = snapshot;
|
|
304
313
|
return snapshot;
|
|
305
314
|
}, [enabled, queryStore]);
|
|
306
|
-
|
|
315
|
+
const getError = (0, import_react3.useCallback)(
|
|
316
|
+
() => enabled ? readQueryError(queryStore) : null,
|
|
317
|
+
[enabled, queryStore]
|
|
318
|
+
);
|
|
319
|
+
const data = (0, import_react3.useSyncExternalStore)(subscribe, getSnapshot, getServerSnapshot);
|
|
320
|
+
const error = (0, import_react3.useSyncExternalStore)(subscribe, getError, getNoError);
|
|
321
|
+
const ready = enabled && queryStore !== null && queryStore.hasSnapshot();
|
|
322
|
+
return { data, error, ready };
|
|
307
323
|
}
|
|
324
|
+
function useQuery(query, options) {
|
|
325
|
+
const { data, error } = useQuerySubscription(query, options);
|
|
326
|
+
if (error && options?.throwOnError !== false) {
|
|
327
|
+
throw error;
|
|
328
|
+
}
|
|
329
|
+
return data;
|
|
330
|
+
}
|
|
331
|
+
function useQueryState(query, options) {
|
|
332
|
+
const { data, error, ready } = useQuerySubscription(query, options);
|
|
333
|
+
return (0, import_react3.useMemo)(() => ({ data, error, ready }), [data, error, ready]);
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
// src/hooks/create-kora-hooks.ts
|
|
337
|
+
var import_react7 = require("react");
|
|
308
338
|
|
|
309
339
|
// src/hooks/use-mutation.ts
|
|
310
340
|
var import_bindings = require("@korajs/core/bindings");
|
|
@@ -312,98 +342,161 @@ var import_react5 = require("react");
|
|
|
312
342
|
|
|
313
343
|
// src/hooks/use-controller.ts
|
|
314
344
|
var import_react4 = require("react");
|
|
345
|
+
var ORPHAN_REAP_MS = 1e3;
|
|
315
346
|
function useController(create, destroy, deps) {
|
|
316
|
-
const
|
|
347
|
+
const entryRef = (0, import_react4.useRef)(null);
|
|
317
348
|
const createRef = (0, import_react4.useRef)(create);
|
|
318
349
|
createRef.current = create;
|
|
319
|
-
const
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
350
|
+
const destroyRef = (0, import_react4.useRef)(destroy);
|
|
351
|
+
destroyRef.current = destroy;
|
|
352
|
+
const [version, bumpVersion] = (0, import_react4.useReducer)((count) => count + 1, 0);
|
|
353
|
+
const handle = (0, import_react4.useRef)({
|
|
354
|
+
get: () => {
|
|
355
|
+
const current = entryRef.current;
|
|
356
|
+
if (current !== null && !current.reaped) {
|
|
357
|
+
return current.controller;
|
|
358
|
+
}
|
|
359
|
+
const entry = {
|
|
360
|
+
controller: createRef.current(),
|
|
361
|
+
claimed: false,
|
|
362
|
+
reaped: false
|
|
363
|
+
};
|
|
364
|
+
entryRef.current = entry;
|
|
365
|
+
setTimeout(() => {
|
|
366
|
+
if (!entry.claimed && !entry.reaped) {
|
|
367
|
+
entry.reaped = true;
|
|
368
|
+
destroyRef.current(entry.controller);
|
|
369
|
+
}
|
|
370
|
+
}, ORPHAN_REAP_MS);
|
|
371
|
+
return entry.controller;
|
|
372
|
+
},
|
|
373
|
+
peek: () => {
|
|
374
|
+
const current = entryRef.current;
|
|
375
|
+
return current?.claimed && !current.reaped ? current.controller : null;
|
|
323
376
|
}
|
|
324
|
-
return controllerRef.current;
|
|
325
377
|
}).current;
|
|
326
378
|
(0, import_react4.useEffect)(() => {
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
379
|
+
const current = entryRef.current;
|
|
380
|
+
if (current !== null && !current.reaped && !current.claimed) {
|
|
381
|
+
current.claimed = true;
|
|
382
|
+
} else if (current === null || current.reaped) {
|
|
383
|
+
entryRef.current = { controller: createRef.current(), claimed: true, reaped: false };
|
|
384
|
+
bumpVersion();
|
|
330
385
|
}
|
|
331
386
|
return () => {
|
|
332
|
-
const
|
|
333
|
-
|
|
334
|
-
if (
|
|
335
|
-
|
|
387
|
+
const entry = entryRef.current;
|
|
388
|
+
entryRef.current = null;
|
|
389
|
+
if (entry !== null && !entry.reaped) {
|
|
390
|
+
entry.reaped = true;
|
|
391
|
+
destroyRef.current(entry.controller);
|
|
336
392
|
}
|
|
337
393
|
};
|
|
338
394
|
}, deps);
|
|
339
|
-
return
|
|
395
|
+
return { get: handle.get, peek: handle.peek, version };
|
|
340
396
|
}
|
|
341
397
|
|
|
342
398
|
// src/hooks/use-mutation.ts
|
|
399
|
+
var IDLE = Object.freeze({ isLoading: false, error: null });
|
|
400
|
+
var getServerSnapshot2 = () => IDLE;
|
|
343
401
|
function useMutation(mutationFn, options) {
|
|
344
402
|
const fnRef = (0, import_react5.useRef)(mutationFn);
|
|
345
403
|
fnRef.current = mutationFn;
|
|
346
404
|
const optionsRef = (0, import_react5.useRef)(options);
|
|
347
405
|
optionsRef.current = options;
|
|
348
|
-
const
|
|
406
|
+
const controller = useController(
|
|
349
407
|
() => (0, import_bindings.createMutationController)({
|
|
350
408
|
mutationFn: (...args) => fnRef.current(...args),
|
|
351
409
|
resolveOptions: () => optionsRef.current
|
|
352
410
|
}),
|
|
353
|
-
(
|
|
411
|
+
(instance) => instance.destroy(),
|
|
354
412
|
[]
|
|
355
413
|
);
|
|
356
|
-
const
|
|
414
|
+
const getController = controller.get;
|
|
415
|
+
const subscribe = (0, import_react5.useCallback)(
|
|
357
416
|
(onStoreChange) => getController().subscribe(onStoreChange),
|
|
358
|
-
|
|
359
|
-
|
|
417
|
+
[getController, controller.version]
|
|
418
|
+
);
|
|
419
|
+
const getSnapshot = (0, import_react5.useCallback)(() => getController().getSnapshot(), [getController]);
|
|
420
|
+
const state = (0, import_react5.useSyncExternalStore)(subscribe, getSnapshot, getServerSnapshot2);
|
|
421
|
+
const mutate = (0, import_react5.useCallback)((...args) => getController().mutate(...args), [getController]);
|
|
422
|
+
const mutateAsync = (0, import_react5.useCallback)(
|
|
423
|
+
(...args) => getController().mutateAsync(...args),
|
|
424
|
+
[getController]
|
|
425
|
+
);
|
|
426
|
+
const reset = (0, import_react5.useCallback)(() => getController().reset(), [getController]);
|
|
427
|
+
return (0, import_react5.useMemo)(
|
|
428
|
+
() => ({ mutate, mutateAsync, isLoading: state.isLoading, error: state.error, reset }),
|
|
429
|
+
[mutate, mutateAsync, reset, state.isLoading, state.error]
|
|
360
430
|
);
|
|
361
|
-
return {
|
|
362
|
-
mutate: (...args) => getController().mutate(...args),
|
|
363
|
-
mutateAsync: (...args) => getController().mutateAsync(...args),
|
|
364
|
-
isLoading: state.isLoading,
|
|
365
|
-
error: state.error,
|
|
366
|
-
reset: () => getController().reset()
|
|
367
|
-
};
|
|
368
431
|
}
|
|
369
432
|
|
|
370
433
|
// src/hooks/use-sync-status.ts
|
|
371
434
|
var import_sync = require("@korajs/sync");
|
|
372
435
|
var import_react6 = require("react");
|
|
436
|
+
var getServerSnapshot3 = () => import_sync.OFFLINE_SYNC_STATUS;
|
|
373
437
|
function useSyncStatus() {
|
|
374
438
|
const { syncEngine, subscribeSyncStatus, events } = useKoraContext();
|
|
375
|
-
const
|
|
439
|
+
const controller = useController(
|
|
376
440
|
() => (0, import_sync.createSyncStatusController)({
|
|
377
441
|
syncEngine,
|
|
378
442
|
subscribeSyncStatus,
|
|
379
443
|
events: subscribeSyncStatus ? null : events
|
|
380
444
|
}),
|
|
381
|
-
(
|
|
445
|
+
(instance) => instance.destroy(),
|
|
382
446
|
[syncEngine, subscribeSyncStatus, events]
|
|
383
447
|
);
|
|
384
|
-
|
|
448
|
+
const getController = controller.get;
|
|
449
|
+
const subscribe = (0, import_react6.useCallback)(
|
|
385
450
|
(onStoreChange) => getController().subscribe(onStoreChange),
|
|
386
|
-
|
|
387
|
-
|
|
451
|
+
[getController, controller.version]
|
|
452
|
+
);
|
|
453
|
+
const peek = controller.peek;
|
|
454
|
+
const getSnapshot = (0, import_react6.useCallback)(
|
|
455
|
+
() => peek()?.getSnapshot() ?? import_sync.OFFLINE_SYNC_STATUS,
|
|
456
|
+
[peek]
|
|
388
457
|
);
|
|
458
|
+
return (0, import_react6.useSyncExternalStore)(subscribe, getSnapshot, getServerSnapshot3);
|
|
459
|
+
}
|
|
460
|
+
|
|
461
|
+
// src/hooks/create-kora-hooks.ts
|
|
462
|
+
function createKoraHooks() {
|
|
463
|
+
function useTypedApp() {
|
|
464
|
+
return useApp();
|
|
465
|
+
}
|
|
466
|
+
function useTypedCollection(name) {
|
|
467
|
+
const { app, store } = useKoraContext();
|
|
468
|
+
return (0, import_react7.useMemo)(() => {
|
|
469
|
+
const collections = app?.collections;
|
|
470
|
+
const accessor = collections && name in collections ? collections[name] : store.collection(name);
|
|
471
|
+
return accessor;
|
|
472
|
+
}, [app, store, name]);
|
|
473
|
+
}
|
|
474
|
+
return {
|
|
475
|
+
useApp: useTypedApp,
|
|
476
|
+
useCollection: useTypedCollection,
|
|
477
|
+
useQuery,
|
|
478
|
+
useQueryState,
|
|
479
|
+
useMutation,
|
|
480
|
+
useSyncStatus
|
|
481
|
+
};
|
|
389
482
|
}
|
|
390
483
|
|
|
391
484
|
// src/hooks/use-collection.ts
|
|
392
|
-
var
|
|
485
|
+
var import_react8 = require("react");
|
|
393
486
|
function useCollection(name) {
|
|
394
487
|
const { store } = useKoraContext();
|
|
395
|
-
return (0,
|
|
488
|
+
return (0, import_react8.useMemo)(() => {
|
|
396
489
|
return store.collection(name);
|
|
397
490
|
}, [store, name]);
|
|
398
491
|
}
|
|
399
492
|
|
|
400
493
|
// src/hooks/use-rich-text.ts
|
|
401
494
|
var import_store3 = require("@korajs/store");
|
|
402
|
-
var
|
|
495
|
+
var import_react9 = require("react");
|
|
403
496
|
function useRichText(collectionName, recordId, fieldName, options) {
|
|
404
497
|
const { store, syncEngine } = useKoraContext();
|
|
405
|
-
const collection = (0,
|
|
406
|
-
const
|
|
498
|
+
const collection = (0, import_react9.useMemo)(() => store.collection(collectionName), [store, collectionName]);
|
|
499
|
+
const controller = useController(
|
|
407
500
|
() => (0, import_store3.createRichTextController)({
|
|
408
501
|
collection,
|
|
409
502
|
collectionName,
|
|
@@ -414,29 +507,35 @@ function useRichText(collectionName, recordId, fieldName, options) {
|
|
|
414
507
|
useDocChannel: options?.useDocChannel,
|
|
415
508
|
user: options?.user
|
|
416
509
|
}),
|
|
417
|
-
(
|
|
510
|
+
(instance) => instance.destroy(),
|
|
418
511
|
[collection, collectionName, fieldName, options?.useDocChannel, recordId, store, syncEngine]
|
|
419
512
|
);
|
|
420
|
-
|
|
513
|
+
const getController = controller.get;
|
|
514
|
+
(0, import_react9.useEffect)(() => {
|
|
421
515
|
getController().setUser(options?.user);
|
|
422
|
-
}, [getController, options?.user]);
|
|
423
|
-
const
|
|
516
|
+
}, [getController, options?.user, controller.version]);
|
|
517
|
+
const subscribe = (0, import_react9.useCallback)(
|
|
424
518
|
(onStoreChange) => getController().subscribe(onStoreChange),
|
|
425
|
-
|
|
426
|
-
() => getController().getSnapshot()
|
|
519
|
+
[getController, controller.version]
|
|
427
520
|
);
|
|
428
|
-
const
|
|
521
|
+
const getSnapshot = (0, import_react9.useCallback)(() => getController().getSnapshot(), [getController]);
|
|
522
|
+
const snapshot = (0, import_react9.useSyncExternalStore)(subscribe, getSnapshot, getSnapshot);
|
|
523
|
+
const undo = (0, import_react9.useCallback)(() => {
|
|
429
524
|
getController().undo();
|
|
430
525
|
}, [getController]);
|
|
431
|
-
const redo = (0,
|
|
526
|
+
const redo = (0, import_react9.useCallback)(() => {
|
|
432
527
|
getController().redo();
|
|
433
528
|
}, [getController]);
|
|
434
|
-
const setCursor = (0,
|
|
529
|
+
const setCursor = (0, import_react9.useCallback)(
|
|
435
530
|
(anchor, head) => getController().setCursor(anchor, head),
|
|
436
531
|
[getController]
|
|
437
532
|
);
|
|
438
|
-
const clearCursor = (0,
|
|
439
|
-
|
|
533
|
+
const clearCursor = (0, import_react9.useCallback)(() => getController().clearCursor(), [getController]);
|
|
534
|
+
const live = getController();
|
|
535
|
+
return (0, import_react9.useMemo)(
|
|
536
|
+
() => buildResult(live, snapshot, undo, redo, setCursor, clearCursor),
|
|
537
|
+
[live, snapshot, undo, redo, setCursor, clearCursor, controller.version]
|
|
538
|
+
);
|
|
440
539
|
}
|
|
441
540
|
function buildResult(controller, snapshot, undo, redo, setCursor, clearCursor) {
|
|
442
541
|
return {
|
|
@@ -455,13 +554,13 @@ function buildResult(controller, snapshot, undo, redo, setCursor, clearCursor) {
|
|
|
455
554
|
}
|
|
456
555
|
|
|
457
556
|
// src/hooks/use-presence.ts
|
|
458
|
-
var
|
|
557
|
+
var import_react10 = require("react");
|
|
459
558
|
function usePresence(user) {
|
|
460
559
|
const { syncEngine } = useKoraContext();
|
|
461
560
|
const name = user?.name ?? null;
|
|
462
561
|
const color = user?.color ?? null;
|
|
463
562
|
const avatar = user?.avatar ?? null;
|
|
464
|
-
(0,
|
|
563
|
+
(0, import_react10.useEffect)(() => {
|
|
465
564
|
if (!syncEngine || !name || !color) return;
|
|
466
565
|
const awareness = syncEngine.getAwarenessManager();
|
|
467
566
|
awareness.setLocalState({
|
|
@@ -475,12 +574,13 @@ function usePresence(user) {
|
|
|
475
574
|
|
|
476
575
|
// src/hooks/use-collaborators.ts
|
|
477
576
|
var import_sync2 = require("@korajs/sync");
|
|
478
|
-
var
|
|
577
|
+
var import_react11 = require("react");
|
|
479
578
|
var EMPTY_ARRAY2 = [];
|
|
579
|
+
var getServerSnapshot4 = () => EMPTY_ARRAY2;
|
|
480
580
|
function useCollaborators() {
|
|
481
581
|
const { syncEngine } = useKoraContext();
|
|
482
|
-
const snapshotRef = (0,
|
|
483
|
-
const subscribe = (0,
|
|
582
|
+
const snapshotRef = (0, import_react11.useRef)(EMPTY_ARRAY2);
|
|
583
|
+
const subscribe = (0, import_react11.useCallback)(
|
|
484
584
|
(onStoreChange) => {
|
|
485
585
|
if (!syncEngine) {
|
|
486
586
|
snapshotRef.current = EMPTY_ARRAY2;
|
|
@@ -488,6 +588,7 @@ function useCollaborators() {
|
|
|
488
588
|
};
|
|
489
589
|
}
|
|
490
590
|
const awareness = syncEngine.getAwarenessManager();
|
|
591
|
+
snapshotRef.current = EMPTY_ARRAY2;
|
|
491
592
|
return (0, import_sync2.subscribeRemoteAwarenessStates)(awareness, (states) => {
|
|
492
593
|
snapshotRef.current = states;
|
|
493
594
|
onStoreChange();
|
|
@@ -495,25 +596,27 @@ function useCollaborators() {
|
|
|
495
596
|
},
|
|
496
597
|
[syncEngine]
|
|
497
598
|
);
|
|
498
|
-
const getSnapshot = (0,
|
|
499
|
-
(0,
|
|
599
|
+
const getSnapshot = (0, import_react11.useCallback)(() => snapshotRef.current, []);
|
|
600
|
+
(0, import_react11.useEffect)(() => {
|
|
500
601
|
if (!syncEngine) {
|
|
501
602
|
snapshotRef.current = EMPTY_ARRAY2;
|
|
502
603
|
}
|
|
503
604
|
}, [syncEngine]);
|
|
504
|
-
return (0,
|
|
605
|
+
return (0, import_react11.useSyncExternalStore)(subscribe, getSnapshot, getServerSnapshot4);
|
|
505
606
|
}
|
|
506
607
|
// Annotate the CommonJS export names for ESM import in node:
|
|
507
608
|
0 && (module.exports = {
|
|
508
609
|
AuthBoundKoraProvider,
|
|
509
610
|
KoraProvider,
|
|
510
611
|
classifyKoraInitializationError,
|
|
612
|
+
createKoraHooks,
|
|
511
613
|
useApp,
|
|
512
614
|
useCollaborators,
|
|
513
615
|
useCollection,
|
|
514
616
|
useMutation,
|
|
515
617
|
usePresence,
|
|
516
618
|
useQuery,
|
|
619
|
+
useQueryState,
|
|
517
620
|
useRichText,
|
|
518
621
|
useSyncStatus
|
|
519
622
|
});
|