@moloodev/editor-sdk 0.9.1 → 0.10.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/package.json +4 -4
- package/src/index.ts +5 -0
- package/src/message-samples.ts +2 -0
- package/src/protocol-entry.ts +2 -0
- package/src/protocol.ts +6 -0
- package/src/view/hooks.ts +6 -0
- package/src/view/port-binding.ts +3 -0
- package/src/view.ts +23 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@moloodev/editor-sdk",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.10.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"exports": {
|
|
6
6
|
".": "./src/view.ts",
|
|
@@ -29,8 +29,8 @@
|
|
|
29
29
|
"y-protocols": "^1.0.7",
|
|
30
30
|
"yjs": "^13.6.32",
|
|
31
31
|
"zod": "^4.5.4",
|
|
32
|
-
"@moloodev/platform": "0.
|
|
33
|
-
"@moloodev/ui": "0.
|
|
32
|
+
"@moloodev/platform": "0.10.0",
|
|
33
|
+
"@moloodev/ui": "0.10.0"
|
|
34
34
|
},
|
|
35
35
|
"peerDependencies": {
|
|
36
36
|
"react": "^19.0.0",
|
|
@@ -48,7 +48,7 @@
|
|
|
48
48
|
"react-dom": "^19.2.8",
|
|
49
49
|
"tsx": "^4.23.13",
|
|
50
50
|
"typescript": "^7.0.2",
|
|
51
|
-
"@moloodev/typescript-config": "0.
|
|
51
|
+
"@moloodev/typescript-config": "0.10.0"
|
|
52
52
|
},
|
|
53
53
|
"publishConfig": {
|
|
54
54
|
"access": "public"
|
package/src/index.ts
CHANGED
|
@@ -207,7 +207,12 @@ export type EditorResponse<Type extends EditorRequestType = EditorRequestType> =
|
|
|
207
207
|
| EditorSuccess<Type>
|
|
208
208
|
| EditorFailure;
|
|
209
209
|
|
|
210
|
+
export type EditorSettingValue = boolean | number | string;
|
|
211
|
+
export type EditorSettingsValues = Record<string, EditorSettingValue>;
|
|
212
|
+
|
|
210
213
|
export type EditorEvent =
|
|
214
|
+
| { v: 1; type: "settings.snapshot"; body: { values: EditorSettingsValues } }
|
|
215
|
+
| { v: 1; type: "settings.changed"; body: { values: EditorSettingsValues } }
|
|
211
216
|
| { v: 1; type: "file.import"; body: { name: string; data: string } }
|
|
212
217
|
| { v: 1; type: "session"; body: EditorSession }
|
|
213
218
|
| { v: 1; type: "access"; body: EditorAccess }
|
package/src/message-samples.ts
CHANGED
|
@@ -313,6 +313,8 @@ export const session = {
|
|
|
313
313
|
} satisfies EditorSession;
|
|
314
314
|
|
|
315
315
|
export const events = {
|
|
316
|
+
"settings.snapshot": { v: 1, type: "settings.snapshot", body: { values: { "notes.indent": 2 } } },
|
|
317
|
+
"settings.changed": { v: 1, type: "settings.changed", body: { values: { "notes.indent": 4 } } },
|
|
316
318
|
"file.import": { v: 1, type: "file.import", body: { name: "notes.md", data: "" } },
|
|
317
319
|
session: {
|
|
318
320
|
v: 1,
|
package/src/protocol-entry.ts
CHANGED
package/src/protocol.ts
CHANGED
|
@@ -125,6 +125,10 @@ const themeSchema = z.strictObject({
|
|
|
125
125
|
theme: z.enum(["dark", "light"]),
|
|
126
126
|
});
|
|
127
127
|
|
|
128
|
+
const settingsSchema = z.strictObject({
|
|
129
|
+
values: z.record(z.string(), z.union([z.boolean(), z.number(), z.string()])),
|
|
130
|
+
});
|
|
131
|
+
|
|
128
132
|
const commandIdSchema = z.string().min(1);
|
|
129
133
|
|
|
130
134
|
const commandInvokeBodySchema = z.strictObject({
|
|
@@ -319,6 +323,8 @@ const handshakeReplySchema = z.discriminatedUnion("ok", [
|
|
|
319
323
|
export type HandshakeReply = z.infer<typeof handshakeReplySchema>;
|
|
320
324
|
|
|
321
325
|
export const editorEventSchema = z.discriminatedUnion("type", [
|
|
326
|
+
z.strictObject({ v: z.literal(1), type: z.literal("settings.snapshot"), body: settingsSchema }),
|
|
327
|
+
z.strictObject({ v: z.literal(1), type: z.literal("settings.changed"), body: settingsSchema }),
|
|
322
328
|
z.strictObject({
|
|
323
329
|
v: z.literal(1),
|
|
324
330
|
type: z.literal("file.import"),
|
package/src/view/hooks.ts
CHANGED
|
@@ -9,6 +9,7 @@ import type {
|
|
|
9
9
|
EditorRevision,
|
|
10
10
|
EditorSession,
|
|
11
11
|
EditorSessionAsset,
|
|
12
|
+
EditorSettingValue,
|
|
12
13
|
} from "../index";
|
|
13
14
|
|
|
14
15
|
export type { EditorAsset, EditorSessionAsset, EditorLayoutValues } from "../index";
|
|
@@ -30,6 +31,7 @@ export type EditorOpenBrowserArgs = {
|
|
|
30
31
|
};
|
|
31
32
|
|
|
32
33
|
export type EditorViewBinding = {
|
|
34
|
+
useEditorSetting(key: string): EditorSettingValue | undefined;
|
|
33
35
|
useTheme(): { theme: "dark" | "light" };
|
|
34
36
|
useKind(type: string): { id: string; label: string; color: string; icon: string };
|
|
35
37
|
useKinds(): { id: string; label: string; color: string; icon: string }[];
|
|
@@ -136,6 +138,10 @@ export function useTheme() {
|
|
|
136
138
|
return useBinding("useTheme").useTheme();
|
|
137
139
|
}
|
|
138
140
|
|
|
141
|
+
export function useEditorSetting(key: string): EditorSettingValue | undefined {
|
|
142
|
+
return useBinding("useEditorSetting").useEditorSetting(key);
|
|
143
|
+
}
|
|
144
|
+
|
|
139
145
|
export function useKind(type: string) {
|
|
140
146
|
return useBinding("useKind").useKind(type);
|
|
141
147
|
}
|
package/src/view/port-binding.ts
CHANGED
|
@@ -57,6 +57,9 @@ function createPortBinding(view: EditorView, acceptedTypes: readonly string[]):
|
|
|
57
57
|
}
|
|
58
58
|
|
|
59
59
|
return {
|
|
60
|
+
useEditorSetting(key) {
|
|
61
|
+
return useSyncExternalStore(view.onSettingsChange, () => view.getSetting(key), () => view.getSetting(key));
|
|
62
|
+
},
|
|
60
63
|
useTheme() {
|
|
61
64
|
const theme = useSnapshot().theme ?? "dark";
|
|
62
65
|
return useMemo(() => ({ theme }), [theme]);
|
package/src/view.ts
CHANGED
|
@@ -25,10 +25,14 @@ import type {
|
|
|
25
25
|
EditorRequestType,
|
|
26
26
|
EditorResponse,
|
|
27
27
|
EditorSession,
|
|
28
|
+
EditorSettingValue,
|
|
29
|
+
EditorSettingsValues,
|
|
28
30
|
} from "./index";
|
|
29
31
|
import { EDITOR_IMPORT_BYTES_MAX, parseEditorId, type ChromeManifest } from "./protocol";
|
|
30
32
|
import { editorPort } from "./view/port";
|
|
31
33
|
|
|
34
|
+
export type { EditorSettingValue, EditorSettingsValues } from "./index";
|
|
35
|
+
|
|
32
36
|
export type EditorViewSnapshot = {
|
|
33
37
|
session: EditorSession | null;
|
|
34
38
|
access: EditorAccess | null;
|
|
@@ -59,6 +63,8 @@ export type EditorView = {
|
|
|
59
63
|
subscribe(listener: () => void): () => void;
|
|
60
64
|
onImportFile(listener: (file: File) => void): () => void;
|
|
61
65
|
onCommand(listener: (commandId: string) => void): () => void;
|
|
66
|
+
getSetting(key: string): EditorSettingValue | undefined;
|
|
67
|
+
onSettingsChange(listener: (values: Readonly<EditorSettingsValues>) => void): () => void;
|
|
62
68
|
sendCommandState(state: CommandStateBody): boolean;
|
|
63
69
|
sendShortcut(body: ShortcutBody): boolean;
|
|
64
70
|
close(): void;
|
|
@@ -124,6 +130,8 @@ export function connectEditorView(deps: EditorViewDeps): EditorView {
|
|
|
124
130
|
const importFileListeners = new Set<(file: File) => void>();
|
|
125
131
|
const pendingImportFiles: File[] = [];
|
|
126
132
|
const commandListeners = new Set<(commandId: string) => void>();
|
|
133
|
+
let settings: Readonly<EditorSettingsValues> = {};
|
|
134
|
+
const settingsListeners = new Set<(values: Readonly<EditorSettingsValues>) => void>();
|
|
127
135
|
let submitted: SubmittedChrome | null = null;
|
|
128
136
|
let stopped = false;
|
|
129
137
|
let channel: EditorChannel | undefined;
|
|
@@ -158,6 +166,12 @@ export function connectEditorView(deps: EditorViewDeps): EditorView {
|
|
|
158
166
|
function onEvent(event: EditorEvent) {
|
|
159
167
|
if (stopped) return;
|
|
160
168
|
switch (event.type) {
|
|
169
|
+
case "settings.snapshot":
|
|
170
|
+
case "settings.changed": {
|
|
171
|
+
settings = Object.freeze(event.body.values);
|
|
172
|
+
for (const listener of [...settingsListeners]) listener(settings);
|
|
173
|
+
return;
|
|
174
|
+
}
|
|
161
175
|
case "file.import": {
|
|
162
176
|
const bytes = fromBase64(event.body.data);
|
|
163
177
|
if (bytes.byteLength > EDITOR_IMPORT_BYTES_MAX) return;
|
|
@@ -281,6 +295,14 @@ export function connectEditorView(deps: EditorViewDeps): EditorView {
|
|
|
281
295
|
commandListeners.delete(listener);
|
|
282
296
|
};
|
|
283
297
|
},
|
|
298
|
+
getSetting(key) {
|
|
299
|
+
return Object.hasOwn(settings, key) ? settings[key] : undefined;
|
|
300
|
+
},
|
|
301
|
+
onSettingsChange(listener) {
|
|
302
|
+
if (stopped) return () => {};
|
|
303
|
+
settingsListeners.add(listener);
|
|
304
|
+
return () => { settingsListeners.delete(listener); };
|
|
305
|
+
},
|
|
284
306
|
sendCommandState(state) {
|
|
285
307
|
if (!submitted?.commandIds.has(state.id)) return false;
|
|
286
308
|
return channel?.emit({ v: 1, type: "command.state", body: state }) ?? false;
|
|
@@ -300,6 +322,7 @@ export function connectEditorView(deps: EditorViewDeps): EditorView {
|
|
|
300
322
|
doc.off("update", onDocUpdate);
|
|
301
323
|
listeners.clear();
|
|
302
324
|
commandListeners.clear();
|
|
325
|
+
settingsListeners.clear();
|
|
303
326
|
importFileListeners.clear();
|
|
304
327
|
pendingImportFiles.length = 0;
|
|
305
328
|
channel?.close();
|