@korajs/svelte 0.5.0 → 0.6.0
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 +97 -9
- package/dist/components/KoraProvider.js +105 -0
- package/dist/components/KoraQuery.js +59 -0
- package/dist/components/KoraRichText.js +76 -0
- package/dist/components/KoraStoreProvider.js +39 -0
- package/dist/index.cjs +304 -7
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +106 -15
- package/dist/index.d.ts +106 -15
- package/dist/index.js +283 -7
- package/dist/index.js.map +1 -1
- package/package.json +46 -16
- package/src/components/KoraProvider.svelte +54 -0
- package/src/components/KoraQuery.svelte +44 -0
- package/src/components/KoraRichText.svelte +63 -0
- package/src/components/KoraStoreProvider.svelte +18 -0
package/dist/index.js
CHANGED
|
@@ -1,7 +1,23 @@
|
|
|
1
|
-
// src/
|
|
1
|
+
// src/context.ts
|
|
2
2
|
import { KoraError } from "@korajs/core";
|
|
3
|
+
import { QueryStoreCache } from "@korajs/store";
|
|
3
4
|
import { getContext, setContext } from "svelte";
|
|
5
|
+
var koraContextKey = /* @__PURE__ */ Symbol("korajs-context");
|
|
4
6
|
var koraAppContextKey = /* @__PURE__ */ Symbol("korajs-app");
|
|
7
|
+
function setKoraContext(value) {
|
|
8
|
+
setContext(koraContextKey, value);
|
|
9
|
+
}
|
|
10
|
+
function getKoraContext() {
|
|
11
|
+
const context = getContext(koraContextKey);
|
|
12
|
+
if (!context) {
|
|
13
|
+
throw new KoraError(
|
|
14
|
+
"Kora context missing. Wrap your app with <KoraProvider app={kora}> or <KoraStoreProvider store={store}>.",
|
|
15
|
+
"KORA_NOT_PROVIDED",
|
|
16
|
+
{ fix: "Wrap your app with <KoraProvider app={kora}> or <KoraStoreProvider store={store}>." }
|
|
17
|
+
);
|
|
18
|
+
}
|
|
19
|
+
return context;
|
|
20
|
+
}
|
|
5
21
|
function setKoraAppContext(koraApp) {
|
|
6
22
|
setContext(koraAppContextKey, koraApp);
|
|
7
23
|
}
|
|
@@ -9,17 +25,277 @@ function getKoraApp() {
|
|
|
9
25
|
const app = getContext(koraAppContextKey);
|
|
10
26
|
if (!app) {
|
|
11
27
|
throw new KoraError(
|
|
12
|
-
"getKoraApp() requires setKoraAppContext(koraApp) on an ancestor
|
|
13
|
-
"KORA_NOT_PROVIDED"
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
28
|
+
"getKoraApp() requires setKoraAppContext(koraApp) on an ancestor.",
|
|
29
|
+
"KORA_NOT_PROVIDED"
|
|
30
|
+
);
|
|
31
|
+
}
|
|
32
|
+
return app;
|
|
33
|
+
}
|
|
34
|
+
async function initKoraProvider(app) {
|
|
35
|
+
await app.ready;
|
|
36
|
+
const queryStoreCache = typeof app.getQueryStoreCache === "function" ? app.getQueryStoreCache() : new QueryStoreCache();
|
|
37
|
+
const value = {
|
|
38
|
+
store: app.getStore(),
|
|
39
|
+
syncEngine: app.getSyncEngine(),
|
|
40
|
+
app,
|
|
41
|
+
events: app.events ?? null,
|
|
42
|
+
subscribeSyncStatus: app.sync?.subscribeStatus ?? null,
|
|
43
|
+
queryStoreCache
|
|
44
|
+
};
|
|
45
|
+
setKoraContext(value);
|
|
46
|
+
setKoraAppContext(app);
|
|
47
|
+
return value;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
// src/stores/query-store.ts
|
|
51
|
+
import { assertQueryReady } from "@korajs/store";
|
|
52
|
+
import { readable } from "svelte/store";
|
|
53
|
+
var EMPTY_ARRAY = Object.freeze([]);
|
|
54
|
+
function createQueryStore(query, options) {
|
|
55
|
+
const { queryStoreCache } = getKoraContext();
|
|
56
|
+
const enabled = options?.enabled !== false;
|
|
57
|
+
return readable(EMPTY_ARRAY, (set) => {
|
|
58
|
+
if (!enabled) {
|
|
59
|
+
set(EMPTY_ARRAY);
|
|
60
|
+
return () => {
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
assertQueryReady(query);
|
|
64
|
+
const queryStore = queryStoreCache.getOrCreate(query);
|
|
65
|
+
const unsubscribe = queryStore.subscribe(() => {
|
|
66
|
+
set(queryStore.getSnapshot());
|
|
67
|
+
});
|
|
68
|
+
set(queryStore.getSnapshot());
|
|
69
|
+
return () => {
|
|
70
|
+
unsubscribe();
|
|
71
|
+
queryStoreCache.release(query);
|
|
72
|
+
};
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
var useQuery = createQueryStore;
|
|
76
|
+
|
|
77
|
+
// src/composables/use-mutation.ts
|
|
78
|
+
import { createMutationController } from "@korajs/core/bindings";
|
|
79
|
+
function createMutation(mutationFn, options) {
|
|
80
|
+
const optionsRef = { current: options };
|
|
81
|
+
optionsRef.current = options;
|
|
82
|
+
const fnRef = { current: mutationFn };
|
|
83
|
+
fnRef.current = mutationFn;
|
|
84
|
+
const controller = createMutationController({
|
|
85
|
+
mutationFn: (...args) => fnRef.current(...args),
|
|
86
|
+
resolveOptions: () => optionsRef.current
|
|
87
|
+
});
|
|
88
|
+
const loadingListeners = /* @__PURE__ */ new Set();
|
|
89
|
+
const errorListeners = /* @__PURE__ */ new Set();
|
|
90
|
+
controller.subscribe(() => {
|
|
91
|
+
const snapshot = controller.getSnapshot();
|
|
92
|
+
for (const listener of loadingListeners) {
|
|
93
|
+
listener(snapshot.isLoading);
|
|
94
|
+
}
|
|
95
|
+
for (const listener of errorListeners) {
|
|
96
|
+
listener(snapshot.error);
|
|
97
|
+
}
|
|
98
|
+
});
|
|
99
|
+
return {
|
|
100
|
+
mutate: (...args) => controller.mutate(...args),
|
|
101
|
+
mutateAsync: (...args) => controller.mutateAsync(...args),
|
|
102
|
+
subscribeLoading: (fn) => {
|
|
103
|
+
loadingListeners.add(fn);
|
|
104
|
+
fn(controller.getSnapshot().isLoading);
|
|
105
|
+
return () => loadingListeners.delete(fn);
|
|
106
|
+
},
|
|
107
|
+
subscribeError: (fn) => {
|
|
108
|
+
errorListeners.add(fn);
|
|
109
|
+
fn(controller.getSnapshot().error);
|
|
110
|
+
return () => errorListeners.delete(fn);
|
|
111
|
+
},
|
|
112
|
+
get loading() {
|
|
113
|
+
return controller.getSnapshot().isLoading;
|
|
114
|
+
},
|
|
115
|
+
get isLoading() {
|
|
116
|
+
return controller.getSnapshot().isLoading;
|
|
117
|
+
},
|
|
118
|
+
get error() {
|
|
119
|
+
return controller.getSnapshot().error;
|
|
120
|
+
},
|
|
121
|
+
reset: () => controller.reset()
|
|
122
|
+
};
|
|
123
|
+
}
|
|
124
|
+
var useMutation = createMutation;
|
|
125
|
+
|
|
126
|
+
// src/composables/use-sync-status.ts
|
|
127
|
+
import { OFFLINE_SYNC_STATUS, createSyncStatusController } from "@korajs/sync";
|
|
128
|
+
import { readable as readable2 } from "svelte/store";
|
|
129
|
+
function createSyncStatusStore() {
|
|
130
|
+
const { syncEngine, subscribeSyncStatus, events } = getKoraContext();
|
|
131
|
+
return readable2(OFFLINE_SYNC_STATUS, (set) => {
|
|
132
|
+
const controller = createSyncStatusController({
|
|
133
|
+
syncEngine,
|
|
134
|
+
subscribeSyncStatus,
|
|
135
|
+
events: subscribeSyncStatus ? null : events
|
|
136
|
+
});
|
|
137
|
+
set(controller.getSnapshot());
|
|
138
|
+
const unsubscribe = controller.subscribe(() => {
|
|
139
|
+
set(controller.getSnapshot());
|
|
140
|
+
});
|
|
141
|
+
return () => {
|
|
142
|
+
unsubscribe();
|
|
143
|
+
controller.destroy();
|
|
144
|
+
};
|
|
145
|
+
});
|
|
146
|
+
}
|
|
147
|
+
var useSyncStatus = createSyncStatusStore;
|
|
148
|
+
|
|
149
|
+
// src/composables/use-app.ts
|
|
150
|
+
function getApp() {
|
|
151
|
+
const { app } = getKoraContext();
|
|
152
|
+
if (!app) {
|
|
153
|
+
throw new Error(
|
|
154
|
+
"getApp() requires <KoraProvider app={kora}> or <KoraStoreProvider store={store}> with a createApp() instance."
|
|
17
155
|
);
|
|
18
156
|
}
|
|
19
157
|
return app;
|
|
20
158
|
}
|
|
159
|
+
var useApp = getApp;
|
|
160
|
+
|
|
161
|
+
// src/composables/use-collection.ts
|
|
162
|
+
function getCollection(name) {
|
|
163
|
+
const { store } = getKoraContext();
|
|
164
|
+
return store.collection(name);
|
|
165
|
+
}
|
|
166
|
+
var useCollection = getCollection;
|
|
167
|
+
|
|
168
|
+
// src/composables/use-rich-text.ts
|
|
169
|
+
import { asRichTextSyncEngine, createRichTextController } from "@korajs/store";
|
|
170
|
+
import { onDestroy } from "svelte";
|
|
171
|
+
import { get, readable as readable3 } from "svelte/store";
|
|
172
|
+
function createRichTextBinding(collectionName, recordId, fieldName, options) {
|
|
173
|
+
const { store, syncEngine } = getKoraContext();
|
|
174
|
+
const controller = createRichTextController({
|
|
175
|
+
collection: store.collection(collectionName),
|
|
176
|
+
collectionName,
|
|
177
|
+
recordId,
|
|
178
|
+
fieldName,
|
|
179
|
+
store,
|
|
180
|
+
syncEngine: asRichTextSyncEngine(syncEngine),
|
|
181
|
+
useDocChannel: options?.useDocChannel,
|
|
182
|
+
user: options?.user
|
|
183
|
+
});
|
|
184
|
+
onDestroy(() => {
|
|
185
|
+
controller.destroy();
|
|
186
|
+
});
|
|
187
|
+
const resultStore = readable3(buildResult(controller), (set) => {
|
|
188
|
+
const sync = () => {
|
|
189
|
+
set(buildResult(controller));
|
|
190
|
+
};
|
|
191
|
+
sync();
|
|
192
|
+
return controller.subscribe(sync);
|
|
193
|
+
});
|
|
194
|
+
return {
|
|
195
|
+
get doc() {
|
|
196
|
+
return controller.doc;
|
|
197
|
+
},
|
|
198
|
+
get text() {
|
|
199
|
+
return controller.text;
|
|
200
|
+
},
|
|
201
|
+
undo: () => controller.undo(),
|
|
202
|
+
redo: () => controller.redo(),
|
|
203
|
+
get ready() {
|
|
204
|
+
return get(resultStore).ready;
|
|
205
|
+
},
|
|
206
|
+
get error() {
|
|
207
|
+
return get(resultStore).error;
|
|
208
|
+
},
|
|
209
|
+
get canUndo() {
|
|
210
|
+
return get(resultStore).canUndo;
|
|
211
|
+
},
|
|
212
|
+
get canRedo() {
|
|
213
|
+
return get(resultStore).canRedo;
|
|
214
|
+
},
|
|
215
|
+
get cursors() {
|
|
216
|
+
return get(resultStore).cursors;
|
|
217
|
+
},
|
|
218
|
+
setCursor: (anchor, head) => controller.setCursor(anchor, head),
|
|
219
|
+
clearCursor: () => controller.clearCursor(),
|
|
220
|
+
subscribe: resultStore.subscribe
|
|
221
|
+
};
|
|
222
|
+
}
|
|
223
|
+
var useRichText = createRichTextBinding;
|
|
224
|
+
function buildResult(controller) {
|
|
225
|
+
const snapshot = controller.getSnapshot();
|
|
226
|
+
return {
|
|
227
|
+
doc: controller.doc,
|
|
228
|
+
text: controller.text,
|
|
229
|
+
undo: () => controller.undo(),
|
|
230
|
+
redo: () => controller.redo(),
|
|
231
|
+
ready: snapshot.ready,
|
|
232
|
+
error: snapshot.error,
|
|
233
|
+
canUndo: snapshot.canUndo,
|
|
234
|
+
canRedo: snapshot.canRedo,
|
|
235
|
+
cursors: [...snapshot.cursors],
|
|
236
|
+
setCursor: (anchor, head) => controller.setCursor(anchor, head),
|
|
237
|
+
clearCursor: () => controller.clearCursor()
|
|
238
|
+
};
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
// src/composables/use-presence.ts
|
|
242
|
+
function applyPresence(user) {
|
|
243
|
+
const { syncEngine } = getKoraContext();
|
|
244
|
+
if (!syncEngine || !user?.name || !user?.color) {
|
|
245
|
+
return () => {
|
|
246
|
+
};
|
|
247
|
+
}
|
|
248
|
+
const awareness = syncEngine.getAwarenessManager();
|
|
249
|
+
awareness.setLocalState({
|
|
250
|
+
user: {
|
|
251
|
+
name: user.name,
|
|
252
|
+
color: user.color,
|
|
253
|
+
avatar: user.avatar
|
|
254
|
+
}
|
|
255
|
+
});
|
|
256
|
+
return () => {
|
|
257
|
+
awareness.setLocalState(null);
|
|
258
|
+
};
|
|
259
|
+
}
|
|
260
|
+
var usePresence = applyPresence;
|
|
261
|
+
|
|
262
|
+
// src/composables/use-collaborators.ts
|
|
263
|
+
import { subscribeRemoteAwarenessStates } from "@korajs/sync";
|
|
264
|
+
import { readable as readable4 } from "svelte/store";
|
|
265
|
+
function createCollaboratorsStore() {
|
|
266
|
+
const { syncEngine } = getKoraContext();
|
|
267
|
+
return readable4([], (set) => {
|
|
268
|
+
if (!syncEngine) {
|
|
269
|
+
set([]);
|
|
270
|
+
return () => {
|
|
271
|
+
};
|
|
272
|
+
}
|
|
273
|
+
const awareness = syncEngine.getAwarenessManager();
|
|
274
|
+
return subscribeRemoteAwarenessStates(awareness, set);
|
|
275
|
+
});
|
|
276
|
+
}
|
|
277
|
+
var useCollaborators = createCollaboratorsStore;
|
|
21
278
|
export {
|
|
279
|
+
applyPresence,
|
|
280
|
+
createCollaboratorsStore,
|
|
281
|
+
createMutation,
|
|
282
|
+
createQueryStore,
|
|
283
|
+
createRichTextBinding,
|
|
284
|
+
createSyncStatusStore,
|
|
285
|
+
getApp,
|
|
286
|
+
getCollection,
|
|
22
287
|
getKoraApp,
|
|
23
|
-
|
|
288
|
+
getKoraContext,
|
|
289
|
+
initKoraProvider,
|
|
290
|
+
setKoraAppContext,
|
|
291
|
+
setKoraContext,
|
|
292
|
+
useApp,
|
|
293
|
+
useCollaborators,
|
|
294
|
+
useCollection,
|
|
295
|
+
useMutation,
|
|
296
|
+
usePresence,
|
|
297
|
+
useQuery,
|
|
298
|
+
useRichText,
|
|
299
|
+
useSyncStatus
|
|
24
300
|
};
|
|
25
301
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts"],"sourcesContent":["import { KoraError } from '@korajs/core'\nimport { getContext, setContext } from 'svelte'\nimport type { KoraAppHandle } from './types'\n\nexport type { KoraAppHandle } from './types'\n\nconst koraAppContextKey = Symbol('korajs-app')\n\n/**\n * Set the Kora app in Svelte context (call from a root layout or `+layout.svelte`).\n */\nexport function setKoraAppContext(koraApp: KoraAppHandle): void {\n\tsetContext(koraAppContextKey, koraApp)\n}\n\n/**\n * Read the Kora app from Svelte context in child components.\n */\nexport function getKoraApp(): KoraAppHandle {\n\tconst app = getContext<KoraAppHandle | undefined>(koraAppContextKey)\n\tif (!app) {\n\t\tthrow new KoraError(\n\t\t\t'getKoraApp() requires setKoraAppContext(koraApp) on an ancestor component.',\n\t\t\t'KORA_NOT_PROVIDED',\n\t\t\t{\n\t\t\t\tfix: 'In +layout.svelte: setKoraAppContext(kora); await kora.ready before queries.',\n\t\t\t},\n\t\t)\n\t}\n\treturn app\n}\n"],"mappings":";AAAA,SAAS,iBAAiB;AAC1B,SAAS,YAAY,kBAAkB;AAKvC,IAAM,oBAAoB,uBAAO,YAAY;AAKtC,SAAS,kBAAkB,SAA8B;AAC/D,aAAW,mBAAmB,OAAO;AACtC;AAKO,SAAS,aAA4B;AAC3C,QAAM,MAAM,WAAsC,iBAAiB;AACnE,MAAI,CAAC,KAAK;AACT,UAAM,IAAI;AAAA,MACT;AAAA,MACA;AAAA,MACA;AAAA,QACC,KAAK;AAAA,MACN;AAAA,IACD;AAAA,EACD;AACA,SAAO;AACR;","names":[]}
|
|
1
|
+
{"version":3,"sources":["../src/context.ts","../src/stores/query-store.ts","../src/composables/use-mutation.ts","../src/composables/use-sync-status.ts","../src/composables/use-app.ts","../src/composables/use-collection.ts","../src/composables/use-rich-text.ts","../src/composables/use-presence.ts","../src/composables/use-collaborators.ts"],"sourcesContent":["import { KoraError } from '@korajs/core'\nimport { QueryStoreCache } from '@korajs/store'\nimport { getContext, setContext } from 'svelte'\nimport type { KoraAppLike, KoraContextValue } from './types'\n\nconst koraContextKey = Symbol('korajs-context')\nconst koraAppContextKey = Symbol('korajs-app')\n\nexport function setKoraContext(value: KoraContextValue): void {\n\tsetContext(koraContextKey, value)\n}\n\nexport function getKoraContext(): KoraContextValue {\n\tconst context = getContext<KoraContextValue | undefined>(koraContextKey)\n\tif (!context) {\n\t\tthrow new KoraError(\n\t\t\t'Kora context missing. Wrap your app with <KoraProvider app={kora}> or <KoraStoreProvider store={store}>.',\n\t\t\t'KORA_NOT_PROVIDED',\n\t\t\t{ fix: 'Wrap your app with <KoraProvider app={kora}> or <KoraStoreProvider store={store}>.' },\n\t\t)\n\t}\n\treturn context\n}\n\n/** @deprecated Use {@link setKoraContext} via {@link KoraProvider} or {@link KoraStoreProvider}. */\nexport function setKoraAppContext(koraApp: KoraAppLike): void {\n\tsetContext(koraAppContextKey, koraApp)\n}\n\n/** @deprecated Use {@link getKoraContext} and {@link getApp}. */\nexport function getKoraApp(): KoraAppLike {\n\tconst app = getContext<KoraAppLike | undefined>(koraAppContextKey)\n\tif (!app) {\n\t\tthrow new KoraError(\n\t\t\t'getKoraApp() requires setKoraAppContext(koraApp) on an ancestor.',\n\t\t\t'KORA_NOT_PROVIDED',\n\t\t)\n\t}\n\treturn app\n}\n\n/**\n * Initialize Kora provider context after `app.ready`.\n *\n * @deprecated Prefer {@link KoraProvider} or {@link KoraStoreProvider} in root layout.\n */\nexport async function initKoraProvider(app: KoraAppLike): Promise<KoraContextValue> {\n\tawait app.ready\n\tconst queryStoreCache =\n\t\ttypeof app.getQueryStoreCache === 'function'\n\t\t\t? app.getQueryStoreCache()\n\t\t\t: new QueryStoreCache()\n\tconst value: KoraContextValue = {\n\t\tstore: app.getStore(),\n\t\tsyncEngine: app.getSyncEngine(),\n\t\tapp,\n\t\tevents: app.events ?? null,\n\t\tsubscribeSyncStatus: app.sync?.subscribeStatus ?? null,\n\t\tqueryStoreCache,\n\t}\n\tsetKoraContext(value)\n\tsetKoraAppContext(app)\n\treturn value\n}\n","import type { CollectionRecord, QueryBuilder } from '@korajs/store'\nimport { assertQueryReady } from '@korajs/store'\nimport { readable, type Readable } from 'svelte/store'\nimport { getKoraContext } from '../context'\nimport type { UseQueryOptions } from '../types'\n\nconst EMPTY_ARRAY: readonly unknown[] = Object.freeze([])\n\n/**\n * Create a Svelte readable store for a static Kora query.\n *\n * For reactive filter changes, use {@link KoraQuery} which re-subscribes when the\n * query descriptor changes.\n */\nexport function createQueryStore<T = CollectionRecord>(\n\tquery: QueryBuilder<T>,\n\toptions?: UseQueryOptions,\n): Readable<readonly T[]> {\n\tconst { queryStoreCache } = getKoraContext()\n\tconst enabled = options?.enabled !== false\n\n\treturn readable<readonly T[]>(EMPTY_ARRAY as readonly T[], (set) => {\n\t\tif (!enabled) {\n\t\t\tset(EMPTY_ARRAY as readonly T[])\n\t\t\treturn () => {}\n\t\t}\n\n\t\tassertQueryReady(query as QueryBuilder<unknown>)\n\t\tconst queryStore = queryStoreCache.getOrCreate(query)\n\t\tconst unsubscribe = queryStore.subscribe(() => {\n\t\t\tset(queryStore.getSnapshot())\n\t\t})\n\t\tset(queryStore.getSnapshot())\n\n\t\treturn () => {\n\t\t\tunsubscribe()\n\t\t\tqueryStoreCache.release(query as QueryBuilder<unknown>)\n\t\t}\n\t})\n}\n\n/** Alias for {@link createQueryStore}. */\nexport const useQuery = createQueryStore\n","import { createMutationController } from '@korajs/core/bindings'\nimport type { UseMutationOptions, UseMutationResult } from '../types'\n\n/**\n * Create a mutation controller with optimistic update hooks.\n */\nexport function createMutation<TData, TArgs extends unknown[], TContext = void>(\n\tmutationFn: (...args: TArgs) => Promise<TData>,\n\toptions?: UseMutationOptions<TData, TArgs, TContext>,\n): UseMutationResult<TData, TArgs> {\n\tconst optionsRef = { current: options }\n\toptionsRef.current = options\n\n\tconst fnRef = { current: mutationFn }\n\tfnRef.current = mutationFn\n\n\tconst controller = createMutationController<TData, TArgs, TContext>({\n\t\tmutationFn: (...args) => fnRef.current(...args),\n\t\tresolveOptions: () => optionsRef.current,\n\t})\n\n\tconst loadingListeners = new Set<(value: boolean) => void>()\n\tconst errorListeners = new Set<(value: Error | null) => void>()\n\n\tcontroller.subscribe(() => {\n\t\tconst snapshot = controller.getSnapshot()\n\t\tfor (const listener of loadingListeners) {\n\t\t\tlistener(snapshot.isLoading)\n\t\t}\n\t\tfor (const listener of errorListeners) {\n\t\t\tlistener(snapshot.error)\n\t\t}\n\t})\n\n\treturn {\n\t\tmutate: (...args: TArgs) => controller.mutate(...args),\n\t\tmutateAsync: (...args: TArgs) => controller.mutateAsync(...args),\n\t\tsubscribeLoading: (fn) => {\n\t\t\tloadingListeners.add(fn)\n\t\t\tfn(controller.getSnapshot().isLoading)\n\t\t\treturn () => loadingListeners.delete(fn)\n\t\t},\n\t\tsubscribeError: (fn) => {\n\t\t\terrorListeners.add(fn)\n\t\t\tfn(controller.getSnapshot().error)\n\t\t\treturn () => errorListeners.delete(fn)\n\t\t},\n\t\tget loading() {\n\t\t\treturn controller.getSnapshot().isLoading\n\t\t},\n\t\tget isLoading() {\n\t\t\treturn controller.getSnapshot().isLoading\n\t\t},\n\t\tget error() {\n\t\t\treturn controller.getSnapshot().error\n\t\t},\n\t\treset: () => controller.reset(),\n\t}\n}\n\n/** Alias for {@link createMutation}. */\nexport const useMutation = createMutation\n","import { OFFLINE_SYNC_STATUS, createSyncStatusController } from '@korajs/sync'\nimport type { SyncStatusInfo } from '@korajs/sync'\nimport { readable, type Readable } from 'svelte/store'\nimport { getKoraContext } from '../context'\n\n/**\n * Readable store of sync engine status.\n */\nexport function createSyncStatusStore(): Readable<SyncStatusInfo> {\n\tconst { syncEngine, subscribeSyncStatus, events } = getKoraContext()\n\n\treturn readable<SyncStatusInfo>(OFFLINE_SYNC_STATUS, (set) => {\n\t\tconst controller = createSyncStatusController({\n\t\t\tsyncEngine,\n\t\t\tsubscribeSyncStatus,\n\t\t\tevents: subscribeSyncStatus ? null : events,\n\t\t})\n\t\tset(controller.getSnapshot())\n\t\tconst unsubscribe = controller.subscribe(() => {\n\t\t\tset(controller.getSnapshot())\n\t\t})\n\t\treturn () => {\n\t\t\tunsubscribe()\n\t\t\tcontroller.destroy()\n\t\t}\n\t})\n}\n\n/** Alias for {@link createSyncStatusStore}. */\nexport const useSyncStatus = createSyncStatusStore\n","import { getKoraContext } from '../context'\nimport type { KoraAppLike } from '../types'\n\nexport function getApp<T extends KoraAppLike = KoraAppLike>(): T {\n\tconst { app } = getKoraContext()\n\tif (!app) {\n\t\tthrow new Error(\n\t\t\t'getApp() requires <KoraProvider app={kora}> or <KoraStoreProvider store={store}> with a createApp() instance.',\n\t\t)\n\t}\n\treturn app as T\n}\n\n/** Alias for {@link getApp}. */\nexport const useApp = getApp\n","import type { CollectionAccessor } from '@korajs/store'\nimport { getKoraContext } from '../context'\n\nexport function getCollection(name: string): CollectionAccessor {\n\tconst { store } = getKoraContext()\n\treturn store.collection(name)\n}\n\n/** Alias for {@link getCollection}. */\nexport const useCollection = getCollection\n","import { asRichTextSyncEngine, createRichTextController } from '@korajs/store'\nimport type { AwarenessUser } from '@korajs/sync'\nimport { onDestroy } from 'svelte'\nimport { get, readable, type Readable } from 'svelte/store'\nimport { getKoraContext } from '../context'\nimport type { UseRichTextResult } from '../types'\n\nexport interface UseRichTextOptions {\n\tuser?: AwarenessUser\n\tuseDocChannel?: boolean\n}\n\n/**\n * Binds a richtext field to a shared Yjs document for editor integration.\n *\n * Must be called during component initialization. For reactive target changes,\n * use {@link KoraRichText} instead.\n */\nexport function createRichTextBinding(\n\tcollectionName: string,\n\trecordId: string,\n\tfieldName: string,\n\toptions?: UseRichTextOptions,\n): UseRichTextResult & { subscribe: Readable<UseRichTextResult>['subscribe'] } {\n\tconst { store, syncEngine } = getKoraContext()\n\n\tconst controller = createRichTextController({\n\t\tcollection: store.collection(collectionName),\n\t\tcollectionName,\n\t\trecordId,\n\t\tfieldName,\n\t\tstore,\n\t\tsyncEngine: asRichTextSyncEngine(syncEngine),\n\t\tuseDocChannel: options?.useDocChannel,\n\t\tuser: options?.user,\n\t})\n\n\tonDestroy(() => {\n\t\tcontroller.destroy()\n\t})\n\n\tconst resultStore = readable<UseRichTextResult>(buildResult(controller), (set) => {\n\t\tconst sync = (): void => {\n\t\t\tset(buildResult(controller))\n\t\t}\n\t\tsync()\n\t\treturn controller.subscribe(sync)\n\t})\n\n\treturn {\n\t\tget doc() {\n\t\t\treturn controller.doc\n\t\t},\n\t\tget text() {\n\t\t\treturn controller.text\n\t\t},\n\t\tundo: () => controller.undo(),\n\t\tredo: () => controller.redo(),\n\t\tget ready() {\n\t\t\treturn get(resultStore).ready\n\t\t},\n\t\tget error() {\n\t\t\treturn get(resultStore).error\n\t\t},\n\t\tget canUndo() {\n\t\t\treturn get(resultStore).canUndo\n\t\t},\n\t\tget canRedo() {\n\t\t\treturn get(resultStore).canRedo\n\t\t},\n\t\tget cursors() {\n\t\t\treturn get(resultStore).cursors\n\t\t},\n\t\tsetCursor: (anchor: number, head: number) => controller.setCursor(anchor, head),\n\t\tclearCursor: () => controller.clearCursor(),\n\t\tsubscribe: resultStore.subscribe,\n\t}\n}\n\n/** @alias createRichTextBinding */\nexport const useRichText = createRichTextBinding\n\nfunction buildResult(\n\tcontroller: ReturnType<typeof createRichTextController>,\n): UseRichTextResult {\n\tconst snapshot = controller.getSnapshot()\n\treturn {\n\t\tdoc: controller.doc,\n\t\ttext: controller.text,\n\t\tundo: () => controller.undo(),\n\t\tredo: () => controller.redo(),\n\t\tready: snapshot.ready,\n\t\terror: snapshot.error,\n\t\tcanUndo: snapshot.canUndo,\n\t\tcanRedo: snapshot.canRedo,\n\t\tcursors: [...snapshot.cursors],\n\t\tsetCursor: (anchor, head) => controller.setCursor(anchor, head),\n\t\tclearCursor: () => controller.clearCursor(),\n\t}\n}\n","import { getKoraContext } from '../context'\n\n/**\n * Applies local collaborative presence. Returns a cleanup function.\n *\n * In Svelte components, call from an effect:\n * `$effect(() => applyPresence(user))`\n */\nexport function applyPresence(\n\tuser: { name: string; color: string; avatar?: string } | null,\n): () => void {\n\tconst { syncEngine } = getKoraContext()\n\tif (!syncEngine || !user?.name || !user?.color) {\n\t\treturn () => {}\n\t}\n\n\tconst awareness = syncEngine.getAwarenessManager()\n\tawareness.setLocalState({\n\t\tuser: {\n\t\t\tname: user.name,\n\t\t\tcolor: user.color,\n\t\t\tavatar: user.avatar,\n\t\t},\n\t})\n\n\treturn () => {\n\t\tawareness.setLocalState(null)\n\t}\n}\n\n/** Alias for {@link applyPresence} — use inside `$effect()` in `.svelte` files. */\nexport const usePresence = applyPresence\n","import type { AwarenessState } from '@korajs/sync'\nimport { subscribeRemoteAwarenessStates } from '@korajs/sync'\nimport { readable, type Readable } from 'svelte/store'\nimport { getKoraContext } from '../context'\n\n/**\n * Readable store of remote collaborators' awareness states.\n */\nexport function createCollaboratorsStore(): Readable<AwarenessState[]> {\n\tconst { syncEngine } = getKoraContext()\n\n\treturn readable<AwarenessState[]>([], (set) => {\n\t\tif (!syncEngine) {\n\t\t\tset([])\n\t\t\treturn () => {}\n\t\t}\n\n\t\tconst awareness = syncEngine.getAwarenessManager()\n\t\treturn subscribeRemoteAwarenessStates(awareness, set)\n\t})\n}\n\n/** Alias for {@link createCollaboratorsStore}. */\nexport const useCollaborators = createCollaboratorsStore\n"],"mappings":"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","names":["readable","readable","readable","readable","readable","readable"]}
|
package/package.json
CHANGED
|
@@ -1,44 +1,74 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@korajs/svelte",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "
|
|
3
|
+
"version": "0.6.0",
|
|
4
|
+
"description": "Kora.js Svelte bindings for offline-first applications",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.cjs",
|
|
7
7
|
"module": "./dist/index.js",
|
|
8
8
|
"types": "./dist/index.d.ts",
|
|
9
|
+
"svelte": "./dist/index.js",
|
|
9
10
|
"exports": {
|
|
10
11
|
".": {
|
|
11
|
-
"
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
12
|
+
"types": "./dist/index.d.ts",
|
|
13
|
+
"svelte": "./dist/index.js",
|
|
14
|
+
"import": "./dist/index.js",
|
|
15
|
+
"require": "./dist/index.cjs"
|
|
16
|
+
},
|
|
17
|
+
"./KoraQuery.svelte": {
|
|
18
|
+
"svelte": "./src/components/KoraQuery.svelte",
|
|
19
|
+
"import": "./dist/components/KoraQuery.js",
|
|
20
|
+
"default": "./dist/components/KoraQuery.js"
|
|
21
|
+
},
|
|
22
|
+
"./KoraRichText.svelte": {
|
|
23
|
+
"svelte": "./src/components/KoraRichText.svelte",
|
|
24
|
+
"import": "./dist/components/KoraRichText.js",
|
|
25
|
+
"default": "./dist/components/KoraRichText.js"
|
|
26
|
+
},
|
|
27
|
+
"./KoraProvider.svelte": {
|
|
28
|
+
"svelte": "./src/components/KoraProvider.svelte",
|
|
29
|
+
"import": "./dist/components/KoraProvider.js",
|
|
30
|
+
"default": "./dist/components/KoraProvider.js"
|
|
31
|
+
},
|
|
32
|
+
"./KoraStoreProvider.svelte": {
|
|
33
|
+
"svelte": "./src/components/KoraStoreProvider.svelte",
|
|
34
|
+
"import": "./dist/components/KoraStoreProvider.js",
|
|
35
|
+
"default": "./dist/components/KoraStoreProvider.js"
|
|
19
36
|
}
|
|
20
37
|
},
|
|
21
38
|
"files": [
|
|
22
|
-
"dist"
|
|
39
|
+
"dist",
|
|
40
|
+
"src/components/KoraQuery.svelte",
|
|
41
|
+
"src/components/KoraRichText.svelte",
|
|
42
|
+
"src/components/KoraProvider.svelte",
|
|
43
|
+
"src/components/KoraStoreProvider.svelte"
|
|
23
44
|
],
|
|
24
45
|
"peerDependencies": {
|
|
25
46
|
"svelte": "^4.0.0 || ^5.0.0"
|
|
26
47
|
},
|
|
27
48
|
"dependencies": {
|
|
28
|
-
"
|
|
29
|
-
"@korajs/core": "0.
|
|
49
|
+
"yjs": "^13.6.30",
|
|
50
|
+
"@korajs/core": "0.6.0",
|
|
51
|
+
"@korajs/store": "0.6.0",
|
|
52
|
+
"@korajs/sync": "0.6.0"
|
|
30
53
|
},
|
|
31
54
|
"devDependencies": {
|
|
55
|
+
"@sveltejs/vite-plugin-svelte": "^5.0.3",
|
|
56
|
+
"@testing-library/svelte": "^5.2.6",
|
|
57
|
+
"@testing-library/user-event": "^14.6.1",
|
|
58
|
+
"happy-dom": "^17.4.4",
|
|
59
|
+
"svelte": "^5.0.0",
|
|
32
60
|
"tsup": "^8.3.6",
|
|
33
61
|
"typescript": "^5.7.3",
|
|
34
|
-
"
|
|
62
|
+
"vitest": "^3.0.4"
|
|
35
63
|
},
|
|
36
64
|
"license": "MIT",
|
|
37
65
|
"scripts": {
|
|
38
|
-
"build": "tsup",
|
|
66
|
+
"build": "tsup && node scripts/build-components.mjs",
|
|
39
67
|
"dev": "tsup --watch",
|
|
68
|
+
"test": "vitest run",
|
|
69
|
+
"test:watch": "vitest",
|
|
40
70
|
"typecheck": "tsc --noEmit",
|
|
41
71
|
"lint": "biome check src/",
|
|
42
|
-
"clean": "rm -rf dist .turbo"
|
|
72
|
+
"clean": "rm -rf dist .turbo coverage"
|
|
43
73
|
}
|
|
44
74
|
}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import type { KoraAppLike } from '../types'
|
|
3
|
+
import KoraContextBridge from './KoraContextBridge.svelte'
|
|
4
|
+
import KoraStoreBridge from './KoraStoreBridge.svelte'
|
|
5
|
+
|
|
6
|
+
interface Props {
|
|
7
|
+
app: KoraAppLike
|
|
8
|
+
fallback?: import('svelte').Snippet
|
|
9
|
+
children?: import('svelte').Snippet
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
let { app, fallback, children }: Props = $props()
|
|
13
|
+
|
|
14
|
+
let ready = $state(false)
|
|
15
|
+
let initError = $state<Error | null>(null)
|
|
16
|
+
|
|
17
|
+
$effect(() => {
|
|
18
|
+
let cancelled = false
|
|
19
|
+
ready = false
|
|
20
|
+
initError = null
|
|
21
|
+
|
|
22
|
+
void (async () => {
|
|
23
|
+
try {
|
|
24
|
+
await app.ready
|
|
25
|
+
if (cancelled) return
|
|
26
|
+
ready = true
|
|
27
|
+
} catch (error: unknown) {
|
|
28
|
+
if (cancelled) return
|
|
29
|
+
initError = error instanceof Error ? error : new Error(String(error))
|
|
30
|
+
console.error('[Kora] Initialization failed:', initError)
|
|
31
|
+
}
|
|
32
|
+
})()
|
|
33
|
+
|
|
34
|
+
return () => {
|
|
35
|
+
cancelled = true
|
|
36
|
+
}
|
|
37
|
+
})
|
|
38
|
+
</script>
|
|
39
|
+
|
|
40
|
+
{#if initError}
|
|
41
|
+
<div role="alert" style="color: red; padding: 1rem; font-family: monospace;">
|
|
42
|
+
<strong>Kora initialization error: </strong>{initError.message}
|
|
43
|
+
</div>
|
|
44
|
+
{:else if !ready}
|
|
45
|
+
{#if fallback}
|
|
46
|
+
{@render fallback()}
|
|
47
|
+
{:else}
|
|
48
|
+
<div>Loading...</div>
|
|
49
|
+
{/if}
|
|
50
|
+
{:else if children}
|
|
51
|
+
<KoraContextBridge {app}>
|
|
52
|
+
{@render children()}
|
|
53
|
+
</KoraContextBridge>
|
|
54
|
+
{/if}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
<script lang="ts" module>
|
|
2
|
+
import type { CollectionRecord, QueryBuilder } from '@korajs/store'
|
|
3
|
+
</script>
|
|
4
|
+
|
|
5
|
+
<script lang="ts" generics="T extends CollectionRecord = CollectionRecord">
|
|
6
|
+
import { assertQueryReady } from '@korajs/store'
|
|
7
|
+
import { getKoraContext } from '../context'
|
|
8
|
+
|
|
9
|
+
interface Props {
|
|
10
|
+
query: QueryBuilder<T>
|
|
11
|
+
enabled?: boolean
|
|
12
|
+
children?: import('svelte').Snippet<[readonly T[]]>
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
let { query, enabled = true, children }: Props = $props()
|
|
16
|
+
|
|
17
|
+
getKoraContext()
|
|
18
|
+
|
|
19
|
+
let data = $state<readonly T[]>([])
|
|
20
|
+
|
|
21
|
+
$effect(() => {
|
|
22
|
+
if (!enabled) {
|
|
23
|
+
data = []
|
|
24
|
+
return
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
const { queryStoreCache } = getKoraContext()
|
|
28
|
+
assertQueryReady(query as QueryBuilder<unknown>)
|
|
29
|
+
const queryStore = queryStoreCache.getOrCreate(query)
|
|
30
|
+
const unsubscribe = queryStore.subscribe(() => {
|
|
31
|
+
data = queryStore.getSnapshot()
|
|
32
|
+
})
|
|
33
|
+
data = queryStore.getSnapshot()
|
|
34
|
+
|
|
35
|
+
return () => {
|
|
36
|
+
unsubscribe()
|
|
37
|
+
queryStoreCache.release(query as QueryBuilder<unknown>)
|
|
38
|
+
}
|
|
39
|
+
})
|
|
40
|
+
</script>
|
|
41
|
+
|
|
42
|
+
{#if children}
|
|
43
|
+
{@render children(data)}
|
|
44
|
+
{/if}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import { asRichTextSyncEngine, createRichTextController } from '@korajs/store'
|
|
3
|
+
import type { AwarenessUser } from '@korajs/sync'
|
|
4
|
+
import { getKoraContext } from '../context'
|
|
5
|
+
import type { UseRichTextResult } from '../types'
|
|
6
|
+
|
|
7
|
+
interface Props {
|
|
8
|
+
collectionName: string
|
|
9
|
+
recordId: string
|
|
10
|
+
fieldName: string
|
|
11
|
+
user?: AwarenessUser
|
|
12
|
+
useDocChannel?: boolean
|
|
13
|
+
children?: import('svelte').Snippet<[UseRichTextResult]>
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
let { collectionName, recordId, fieldName, user, useDocChannel, children }: Props = $props()
|
|
17
|
+
|
|
18
|
+
const { store, syncEngine } = getKoraContext()
|
|
19
|
+
let result = $state<UseRichTextResult | null>(null)
|
|
20
|
+
|
|
21
|
+
$effect(() => {
|
|
22
|
+
const controller = createRichTextController({
|
|
23
|
+
collection: store.collection(collectionName),
|
|
24
|
+
collectionName,
|
|
25
|
+
recordId,
|
|
26
|
+
fieldName,
|
|
27
|
+
store,
|
|
28
|
+
syncEngine: asRichTextSyncEngine(syncEngine),
|
|
29
|
+
useDocChannel,
|
|
30
|
+
user,
|
|
31
|
+
})
|
|
32
|
+
|
|
33
|
+
const sync = (): void => {
|
|
34
|
+
const snapshot = controller.getSnapshot()
|
|
35
|
+
result = {
|
|
36
|
+
doc: controller.doc,
|
|
37
|
+
text: controller.text,
|
|
38
|
+
undo: () => controller.undo(),
|
|
39
|
+
redo: () => controller.redo(),
|
|
40
|
+
ready: snapshot.ready,
|
|
41
|
+
error: snapshot.error,
|
|
42
|
+
canUndo: snapshot.canUndo,
|
|
43
|
+
canRedo: snapshot.canRedo,
|
|
44
|
+
cursors: [...snapshot.cursors],
|
|
45
|
+
setCursor: (anchor, head) => controller.setCursor(anchor, head),
|
|
46
|
+
clearCursor: () => controller.clearCursor(),
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
sync()
|
|
51
|
+
const unsubscribe = controller.subscribe(sync)
|
|
52
|
+
|
|
53
|
+
return () => {
|
|
54
|
+
unsubscribe()
|
|
55
|
+
controller.destroy()
|
|
56
|
+
result = null
|
|
57
|
+
}
|
|
58
|
+
})
|
|
59
|
+
</script>
|
|
60
|
+
|
|
61
|
+
{#if result && children}
|
|
62
|
+
{@render children(result)}
|
|
63
|
+
{/if}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import type { KoraContextValue } from '../types'
|
|
3
|
+
import KoraStoreBridge from './KoraStoreBridge.svelte'
|
|
4
|
+
|
|
5
|
+
interface Props {
|
|
6
|
+
store: KoraContextValue['store']
|
|
7
|
+
syncEngine?: KoraContextValue['syncEngine']
|
|
8
|
+
children?: import('svelte').Snippet
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
let { store, syncEngine = null, children }: Props = $props()
|
|
12
|
+
</script>
|
|
13
|
+
|
|
14
|
+
<KoraStoreBridge {store} {syncEngine}>
|
|
15
|
+
{#if children}
|
|
16
|
+
{@render children()}
|
|
17
|
+
{/if}
|
|
18
|
+
</KoraStoreBridge>
|