@dotdirfm/ui 0.1.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.
Files changed (95) hide show
  1. package/dist/dotdir.css +2 -0
  2. package/dist/dotdir.js +130 -0
  3. package/dist/dotdir.mjs +9538 -0
  4. package/dist/lib/DotDir.d.ts +8 -0
  5. package/dist/lib/actionQueue.d.ts +7 -0
  6. package/dist/lib/app.d.ts +3 -0
  7. package/dist/lib/atoms.d.ts +84 -0
  8. package/dist/lib/components/ActionBar.d.ts +1 -0
  9. package/dist/lib/components/CommandLine.d.ts +1 -0
  10. package/dist/lib/components/CommandPalette.d.ts +10 -0
  11. package/dist/lib/components/ErrorBoundary.d.ts +18 -0
  12. package/dist/lib/components/ExtensionContainer.d.ts +48 -0
  13. package/dist/lib/components/ExtensionsPanel.d.ts +1 -0
  14. package/dist/lib/components/FileList/Breadcrumbs.d.ts +6 -0
  15. package/dist/lib/components/FileList/ColumnsScroller.d.ts +16 -0
  16. package/dist/lib/components/FileList/FileList.d.ts +15 -0
  17. package/dist/lib/components/FileList/PanelTabs.d.ts +24 -0
  18. package/dist/lib/components/FileList/ScrollableContainer.d.ts +13 -0
  19. package/dist/lib/components/FileList/index.d.ts +1 -0
  20. package/dist/lib/components/FileList/useElementSize.d.ts +7 -0
  21. package/dist/lib/components/PanelGroup.d.ts +23 -0
  22. package/dist/lib/components/Terminal.d.ts +2 -0
  23. package/dist/lib/dialogs/ConflictDialog.d.ts +11 -0
  24. package/dist/lib/dialogs/CopyConfigDialog.d.ts +8 -0
  25. package/dist/lib/dialogs/CopyProgressDialog.d.ts +9 -0
  26. package/dist/lib/dialogs/DeleteProgressDialog.d.ts +6 -0
  27. package/dist/lib/dialogs/HelpDialog.d.ts +6 -0
  28. package/dist/lib/dialogs/MakeFolderDialog.d.ts +13 -0
  29. package/dist/lib/dialogs/ModalDialog.d.ts +14 -0
  30. package/dist/lib/dialogs/MoveConfigDialog.d.ts +8 -0
  31. package/dist/lib/dialogs/OpenCreateFileDialog.d.ts +11 -0
  32. package/dist/lib/dialogs/RenameDialog.d.ts +6 -0
  33. package/dist/lib/dialogs/dialogContext.d.ts +115 -0
  34. package/dist/lib/dialogs/dialogHotkeys.d.ts +18 -0
  35. package/dist/lib/entities/panel/model/panelSide.d.ts +9 -0
  36. package/dist/lib/entities/panel/model/types.d.ts +1 -0
  37. package/dist/lib/entities/tab/model/tabsAtoms.d.ts +25 -0
  38. package/dist/lib/features/bridge/index.d.ts +209 -0
  39. package/dist/lib/features/bridge/useBridge.d.ts +9 -0
  40. package/dist/lib/features/commands/builtInCommandContributions.d.ts +2 -0
  41. package/dist/lib/features/commands/commands.d.ts +90 -0
  42. package/dist/lib/features/extensions/browserExtensionHost.d.ts +36 -0
  43. package/dist/lib/features/extensions/browserFsProvider.d.ts +5 -0
  44. package/dist/lib/features/extensions/extensionApi.d.ts +196 -0
  45. package/dist/lib/features/extensions/extensionHost.worker.d.ts +174 -0
  46. package/dist/lib/features/extensions/extensionHostClient.d.ts +29 -0
  47. package/dist/lib/features/extensions/extensionLoader.d.ts +8 -0
  48. package/dist/lib/features/extensions/extensions.d.ts +251 -0
  49. package/dist/lib/features/extensions/useExtensionHost.d.ts +6 -0
  50. package/dist/lib/features/file-icons/iconCache.d.ts +3 -0
  51. package/dist/lib/features/file-icons/iconResolver.d.ts +34 -0
  52. package/dist/lib/features/file-icons/vscodeIconTheme.d.ts +62 -0
  53. package/dist/lib/features/file-ops/model/fileOperationHandlers.d.ts +10 -0
  54. package/dist/lib/features/file-ops/model/useFileOperations.d.ts +15 -0
  55. package/dist/lib/features/marketplace/vscodeMarketplace.d.ts +33 -0
  56. package/dist/lib/features/navigation/lib/commandLineCd.d.ts +20 -0
  57. package/dist/lib/features/settings/types.d.ts +12 -0
  58. package/dist/lib/features/settings/useUserSettings.d.ts +6 -0
  59. package/dist/lib/features/settings/userSettings.d.ts +8 -0
  60. package/dist/lib/features/ui-state/types.d.ts +22 -0
  61. package/dist/lib/features/ui-state/uiState.d.ts +5 -0
  62. package/dist/lib/fileListHandlers.d.ts +31 -0
  63. package/dist/lib/focusContext.d.ts +21 -0
  64. package/dist/lib/fs.d.ts +36 -0
  65. package/dist/lib/fss.d.ts +9 -0
  66. package/dist/lib/hooks/useBuiltInCommands.d.ts +24 -0
  67. package/dist/lib/hooks/useDialogButtonNav.d.ts +10 -0
  68. package/dist/lib/hooks/useMediaQuery.d.ts +1 -0
  69. package/dist/lib/hooks/usePanel.d.ts +23 -0
  70. package/dist/lib/hooks/useTerminal.d.ts +12 -0
  71. package/dist/lib/jsoncFileWatcher.d.ts +15 -0
  72. package/dist/lib/languageRegistry.d.ts +43 -0
  73. package/dist/lib/panelGroupHandlers.d.ts +6 -0
  74. package/dist/lib/processes/workspace-session/model/useWorkspaceSessionProcess.d.ts +59 -0
  75. package/dist/lib/registerKeybindings.d.ts +11 -0
  76. package/dist/lib/styleHost.d.ts +2 -0
  77. package/dist/lib/terminal/TerminalSession.d.ts +59 -0
  78. package/dist/lib/terminal/TerminalView.d.ts +8 -0
  79. package/dist/lib/terminal/path.d.ts +7 -0
  80. package/dist/lib/terminal/shellProfiles.d.ts +15 -0
  81. package/dist/lib/terminal/terminalAtoms.d.ts +7 -0
  82. package/dist/lib/terminal/types.d.ts +53 -0
  83. package/dist/lib/terminal/useTerminalState.d.ts +20 -0
  84. package/dist/lib/types.d.ts +12 -0
  85. package/dist/lib/userKeybindings.d.ts +3 -0
  86. package/dist/lib/utils/containerPath.d.ts +45 -0
  87. package/dist/lib/utils/cssModules.d.ts +1 -0
  88. package/dist/lib/utils/inputNoAssist.d.ts +9 -0
  89. package/dist/lib/utils/langDetect.d.ts +1 -0
  90. package/dist/lib/utils/mediaFiles.d.ts +7 -0
  91. package/dist/lib/utils/path.d.ts +26 -0
  92. package/dist/lib/utils/vfs.d.ts +2 -0
  93. package/dist/lib/viewerEditorRegistry.d.ts +53 -0
  94. package/dist/lib/vscodeColorTheme.d.ts +27 -0
  95. package/package.json +66 -0
@@ -0,0 +1,209 @@
1
+ export type EntryKind = "file" | "directory" | "symlink" | "block_device" | "char_device" | "named_pipe" | "socket" | "whiteout" | "door" | "event_port" | "unknown";
2
+ export interface FsRawEntry {
3
+ name: string;
4
+ kind: EntryKind;
5
+ size: number;
6
+ mtimeMs: number;
7
+ mode: number;
8
+ nlink: number;
9
+ hidden: boolean;
10
+ /** Populated only when kind === 'symlink'. Omitted when not a symlink. */
11
+ linkTarget?: string;
12
+ }
13
+ export type FsChangeType = "appeared" | "disappeared" | "modified" | "errored" | "unknown";
14
+ export interface FsChangeEvent {
15
+ watchId: string;
16
+ type: FsChangeType;
17
+ name: string | null;
18
+ }
19
+ export type ConflictPolicy = "ask" | "overwrite" | "skip" | "rename" | "append" | "onlyNewer";
20
+ export type SymlinkMode = "smart" | "alwaysLink" | "alwaysTarget";
21
+ export interface CopyOptions {
22
+ conflictPolicy: ConflictPolicy;
23
+ copyPermissions: boolean;
24
+ copyXattrs: boolean;
25
+ sparseFiles: boolean;
26
+ useCow: boolean;
27
+ symlinkMode: SymlinkMode;
28
+ disableWriteCache: boolean;
29
+ }
30
+ export type ConflictResolution = {
31
+ type: "overwrite";
32
+ } | {
33
+ type: "skip";
34
+ } | {
35
+ type: "rename";
36
+ newName: string;
37
+ } | {
38
+ type: "overwriteAll";
39
+ } | {
40
+ type: "skipAll";
41
+ } | {
42
+ type: "cancel";
43
+ };
44
+ export interface CopyProgress {
45
+ bytesCopied: number;
46
+ bytesTotal: number;
47
+ filesDone: number;
48
+ filesTotal: number;
49
+ currentFile: string;
50
+ }
51
+ export type CopyProgressEvent = {
52
+ copyId: number;
53
+ event: {
54
+ kind: "progress";
55
+ bytesCopied: number;
56
+ bytesTotal: number;
57
+ filesDone: number;
58
+ filesTotal: number;
59
+ currentFile: string;
60
+ } | {
61
+ kind: "conflict";
62
+ src: string;
63
+ dest: string;
64
+ srcSize: number;
65
+ srcMtimeMs: number;
66
+ destSize: number;
67
+ destMtimeMs: number;
68
+ } | {
69
+ kind: "done";
70
+ filesDone: number;
71
+ bytesCopied: number;
72
+ } | {
73
+ kind: "error";
74
+ message: string;
75
+ };
76
+ };
77
+ export interface MoveOptions {
78
+ conflictPolicy: ConflictPolicy;
79
+ }
80
+ export type MoveProgressEvent = {
81
+ moveId: number;
82
+ event: {
83
+ kind: "progress";
84
+ bytesCopied: number;
85
+ bytesTotal: number;
86
+ filesDone: number;
87
+ filesTotal: number;
88
+ currentFile: string;
89
+ } | {
90
+ kind: "conflict";
91
+ src: string;
92
+ dest: string;
93
+ srcSize: number;
94
+ srcMtimeMs: number;
95
+ destSize: number;
96
+ destMtimeMs: number;
97
+ } | {
98
+ kind: "done";
99
+ filesDone: number;
100
+ bytesCopied: number;
101
+ } | {
102
+ kind: "error";
103
+ message: string;
104
+ };
105
+ };
106
+ export type DeleteProgressEvent = {
107
+ deleteId: number;
108
+ event: {
109
+ kind: "progress";
110
+ filesDone: number;
111
+ currentFile: string;
112
+ } | {
113
+ kind: "done";
114
+ filesDone: number;
115
+ } | {
116
+ kind: "error";
117
+ message: string;
118
+ };
119
+ };
120
+ export interface PtyLaunchInfo {
121
+ ptyId: number;
122
+ cwd: string;
123
+ shell: string;
124
+ }
125
+ export type CwdEscapeMode = "posix" | "powershell" | "cmd";
126
+ export interface TerminalProfile {
127
+ id: string;
128
+ label: string;
129
+ shell: string;
130
+ hiddenCdTemplate: string;
131
+ cwdEscape: CwdEscapeMode;
132
+ lineEnding: "\n" | "\r\n";
133
+ spawnArgs: string[];
134
+ }
135
+ export interface FspEntry {
136
+ name: string;
137
+ kind: "file" | "directory";
138
+ size?: number;
139
+ mtimeMs?: number;
140
+ }
141
+ export interface Bridge {
142
+ fs: {
143
+ entries(dirPath: string): Promise<FsRawEntry[]>;
144
+ stat(filePath: string): Promise<{
145
+ size: number;
146
+ mtimeMs: number;
147
+ }>;
148
+ exists(filePath: string): Promise<boolean>;
149
+ readFile(filePath: string): Promise<ArrayBuffer>;
150
+ open(filePath: string): Promise<number>;
151
+ read(fd: number, offset: number, length: number): Promise<ArrayBuffer>;
152
+ close(fd: number): Promise<void>;
153
+ watch(watchId: string, dirPath: string): Promise<boolean>;
154
+ unwatch(watchId: string): Promise<void>;
155
+ onFsChange(callback: (event: FsChangeEvent) => void): () => void;
156
+ writeFile(filePath: string, data: string): Promise<void>;
157
+ writeBinaryFile(filePath: string, data: Uint8Array): Promise<void>;
158
+ createDir?(dirPath: string): Promise<void>;
159
+ moveToTrash(paths: string[]): Promise<void>;
160
+ copy: {
161
+ start(sources: string[], destDir: string, options: CopyOptions): Promise<number>;
162
+ cancel(copyId: number): Promise<void>;
163
+ resolveConflict(copyId: number, resolution: ConflictResolution): Promise<void>;
164
+ onProgress(callback: (event: CopyProgressEvent) => void): () => void;
165
+ };
166
+ move: {
167
+ start(sources: string[], destDir: string, options: MoveOptions): Promise<number>;
168
+ cancel(moveId: number): Promise<void>;
169
+ resolveConflict(moveId: number, resolution: ConflictResolution): Promise<void>;
170
+ onProgress(callback: (event: MoveProgressEvent) => void): () => void;
171
+ };
172
+ delete: {
173
+ start(paths: string[]): Promise<number>;
174
+ cancel(deleteId: number): Promise<void>;
175
+ onProgress(callback: (event: DeleteProgressEvent) => void): () => void;
176
+ };
177
+ rename: {
178
+ rename(source: string, newName: string): Promise<void>;
179
+ };
180
+ };
181
+ pty: {
182
+ spawn(cwd: string, shellPath: string, options?: {
183
+ spawnArgs?: string[];
184
+ }): Promise<PtyLaunchInfo>;
185
+ write(ptyId: number, data: string): Promise<void>;
186
+ resize(ptyId: number, cols: number, rows: number): Promise<void>;
187
+ close(ptyId: number): Promise<void>;
188
+ onData(callback: (ptyId: number, data: string | Uint8Array) => void): () => void;
189
+ onExit(callback: (ptyId: number) => void): () => void;
190
+ setShellIntegrations?(integrations: Record<string, {
191
+ script: string;
192
+ scriptArg: boolean;
193
+ }>): Promise<void>;
194
+ };
195
+ utils: {
196
+ getHomePath(): Promise<string>;
197
+ getEnv(): Promise<Record<string, string>>;
198
+ };
199
+ theme: {
200
+ get(): Promise<string>;
201
+ onChange(callback: (theme: string) => void): () => void;
202
+ };
203
+ onReconnect?(callback: () => void): () => void;
204
+ fsProvider?: {
205
+ load(wasmPath: string): Promise<void>;
206
+ listEntries(wasmPath: string, containerPath: string, innerPath: string): Promise<FspEntry[]>;
207
+ readFileRange(wasmPath: string, containerPath: string, innerPath: string, offset: number, length: number): Promise<ArrayBuffer>;
208
+ };
209
+ }
@@ -0,0 +1,9 @@
1
+ import { Bridge } from '.';
2
+ export declare const bridgeAtom: import('jotai').PrimitiveAtom<Bridge | null> & {
3
+ init: Bridge | null;
4
+ };
5
+ export declare function useBridge(): Bridge;
6
+ export declare function BridgeProvider({ bridge, children }: {
7
+ bridge: Bridge;
8
+ children: React.ReactNode;
9
+ }): import("react/jsx-runtime").JSX.Element | null;
@@ -0,0 +1,2 @@
1
+ import { CommandContribution } from './commands';
2
+ export declare const builtInCommandContributions: CommandContribution[];
@@ -0,0 +1,90 @@
1
+ /**
2
+ * Command System
3
+ *
4
+ * VS Code compatible command registry with support for:
5
+ * - Command registration and execution
6
+ * - Keyboard shortcuts (keybindings) with layered override system
7
+ * - Extension-contributed commands
8
+ * - Command palette integration
9
+ *
10
+ * Keybinding layers (later layers override earlier ones):
11
+ * 1. Default (.dir built-in)
12
+ * 2. Extensions
13
+ * 3. User (from ~/.dotdir/keybindings.json)
14
+ */
15
+ export interface Command {
16
+ id: string;
17
+ title: string;
18
+ shortTitle?: string;
19
+ category?: string;
20
+ icon?: string;
21
+ }
22
+ export interface Keybinding {
23
+ command: string;
24
+ key: string;
25
+ mac?: string;
26
+ when?: string;
27
+ }
28
+ export interface CommandContribution {
29
+ command: string;
30
+ title: string;
31
+ shortTitle?: string;
32
+ category?: string;
33
+ icon?: string;
34
+ }
35
+ export interface KeybindingContribution {
36
+ command: string;
37
+ key: string;
38
+ mac?: string;
39
+ when?: string;
40
+ }
41
+ export type KeybindingLayer = "default" | "extension" | "user";
42
+ type CommandHandler = (...args: unknown[]) => void | Promise<void>;
43
+ type ContextGetter = () => Record<string, unknown>;
44
+ declare class CommandRegistry {
45
+ private contributions;
46
+ private handlers;
47
+ private keybindingLayers;
48
+ private contextGetter;
49
+ private contextValues;
50
+ private listeners;
51
+ private batchDepth;
52
+ private batchDirty;
53
+ beginBatch(): void;
54
+ endBatch(): void;
55
+ setContext(key: string, value: unknown): void;
56
+ getContext(key: string): unknown;
57
+ registerContributions(contributions: CommandContribution[]): () => void;
58
+ registerCommand(id: string, handler: CommandHandler): () => void;
59
+ registerKeybinding(binding: Keybinding, layer?: KeybindingLayer): () => void;
60
+ setLayerKeybindings(layer: KeybindingLayer, bindings: Keybinding[]): void;
61
+ clearLayerKeybindings(layer: KeybindingLayer): void;
62
+ setContextGetter(getter: ContextGetter): void;
63
+ executeCommand(id: string, ...args: unknown[]): Promise<void>;
64
+ getCommand(id: string): Command | undefined;
65
+ getAllCommands(): Command[];
66
+ getKeybindings(): Keybinding[];
67
+ getKeybindingsForLayer(layer: KeybindingLayer): Keybinding[];
68
+ getKeybindingForCommand(commandId: string): Keybinding | undefined;
69
+ evaluateWhen(when: string | undefined): boolean;
70
+ /** Evaluate a `when` expression. Supports `&&` and `||`, and `!` negation. */
71
+ private static evalWhen;
72
+ handleKeyboardEvent(e: KeyboardEvent): boolean;
73
+ private isMac;
74
+ /**
75
+ * Map physical key position (`KeyboardEvent.code`) to our normalized key id.
76
+ * Layout-independent so shortcuts work with non-Latin / non-QWERTY layouts.
77
+ */
78
+ private physicalCodeToKeyPart;
79
+ /**
80
+ * Fallback when `code` is missing (e.g. synthetic events) or unmapped: use `key` (layout-dependent).
81
+ */
82
+ private keyStringToKeyPart;
83
+ private eventToKeyCombo;
84
+ private normalizeKey;
85
+ onChange(callback: () => void): () => void;
86
+ private notifyListeners;
87
+ }
88
+ export declare const commandRegistry: CommandRegistry;
89
+ export declare function formatKeybinding(binding: Keybinding): string;
90
+ export {};
@@ -0,0 +1,36 @@
1
+ import { LoadedExtension } from '../../../features/extensions/extensions';
2
+ export type BrowserDisposable = {
3
+ dispose: () => void;
4
+ };
5
+ export interface BrowserExtensionKeybinding {
6
+ command: string;
7
+ key: string;
8
+ mac?: string;
9
+ when?: string;
10
+ }
11
+ export interface BrowserExtensionContributions {
12
+ keybindings?: BrowserExtensionKeybinding[];
13
+ }
14
+ export interface BrowserExtensionContext {
15
+ subscriptions: BrowserDisposable[];
16
+ dotdir: {
17
+ commands: {
18
+ registerCommand: (commandId: string, handler: (...args: unknown[]) => void | Promise<void>, options?: {
19
+ title?: string;
20
+ category?: string;
21
+ icon?: string;
22
+ when?: string;
23
+ }) => BrowserDisposable;
24
+ registerKeybinding: (binding: BrowserExtensionKeybinding) => BrowserDisposable;
25
+ };
26
+ };
27
+ }
28
+ export declare class BrowserExtensionHost {
29
+ private active;
30
+ private queue;
31
+ private dotdir;
32
+ reconcile(extensions: LoadedExtension[]): Promise<void>;
33
+ private activateOne;
34
+ private deactivateOne;
35
+ dispose(): Promise<void>;
36
+ }
@@ -0,0 +1,5 @@
1
+ import { Bridge } from '../../../features/bridge';
2
+ import { FsProviderExtensionApi } from '../../../features/extensions/extensionApi';
3
+ export declare function loadFsProvider(bridge: Bridge, extensionDirPath: string, entry: string): Promise<FsProviderExtensionApi>;
4
+ /** Evict all cached providers (e.g. when extensions reload). */
5
+ export declare function clearFsProviderCache(): void;
@@ -0,0 +1,196 @@
1
+ /**
2
+ * Shared types for the host ↔ extension iframe communication (postMessage RPC).
3
+ *
4
+ * Host exposes HostApi to the iframe.
5
+ * Viewer extensions expose ViewerExtensionApi; editor extensions expose EditorExtensionApi.
6
+ */
7
+ export interface ViewerProps {
8
+ filePath: string;
9
+ fileName: string;
10
+ fileSize: number;
11
+ inline?: boolean;
12
+ /** When set (e.g. Web VFS), extension can load scripts/workers from this base URL. */
13
+ extensionScriptBaseUrl?: string;
14
+ }
15
+ /** Grammar contribution + loaded content (from host, for custom syntax highlighting). */
16
+ export interface EditorGrammarPayload {
17
+ contribution: {
18
+ language: string;
19
+ scopeName: string;
20
+ path: string;
21
+ embeddedLanguages?: Record<string, string>;
22
+ };
23
+ /** Absolute path to grammar JSON file (used for lazy loading). */
24
+ path?: string;
25
+ /** Parsed TextMate grammar JSON (optional; host may lazy-load and fill it). */
26
+ content?: object;
27
+ }
28
+ export interface EditorLanguagePayload {
29
+ id: string;
30
+ aliases?: string[];
31
+ extensions?: string[];
32
+ filenames?: string[];
33
+ }
34
+ export interface EditorProps {
35
+ filePath: string;
36
+ fileName: string;
37
+ langId: string;
38
+ /** Extension root path (for reading package.json / grammars). */
39
+ extensionDirPath?: string;
40
+ /** All languages from loaded extensions (for Monaco registration). */
41
+ languages?: EditorLanguagePayload[];
42
+ /** All grammars with content from loaded extensions (for TextMate tokenization). */
43
+ grammars?: EditorGrammarPayload[];
44
+ /** True when shown inline (e.g. preview tab). Extensions should not steal focus when inline. */
45
+ inline?: boolean;
46
+ /** When set (e.g. Web VFS), extension can load scripts/workers from this base URL for lazy loading. */
47
+ extensionScriptBaseUrl?: string;
48
+ }
49
+ export interface ColorThemeData {
50
+ /** Theme kind: 'dark' or 'light'. */
51
+ kind: "dark" | "light";
52
+ /** VS Code color theme colors (e.g. 'editor.background' → '#1e1e2e'). Undefined when no VS Code theme active. */
53
+ colors?: Record<string, string>;
54
+ /** VS Code tokenColors for syntax highlighting. Undefined when no VS Code theme active. */
55
+ tokenColors?: unknown[];
56
+ }
57
+ export interface HostApi {
58
+ readFile(path: string): Promise<ArrayBuffer>;
59
+ readFileText(path: string): Promise<string>;
60
+ /** Read a byte range (for chunked viewing). */
61
+ readFileRange?(path: string, offset: number, length: number): Promise<ArrayBuffer>;
62
+ /** Lightweight stat for the currently viewed file. */
63
+ statFile?(path: string): Promise<{
64
+ size: number;
65
+ mtimeMs: number;
66
+ }>;
67
+ /** Subscribe to external changes of the currently viewed file. */
68
+ onFileChange?(callback: () => void): () => void;
69
+ writeFile(path: string, content: string): Promise<void>;
70
+ getTheme(): Promise<string>;
71
+ /** Get the active color theme data (colors + tokenColors). Returns null if no VS Code theme is active. */
72
+ getColorTheme?(): ColorThemeData | null;
73
+ /** Subscribe to theme changes. Callback fires when the color theme changes. Returns unsubscribe function. */
74
+ onThemeChange?(callback: (theme: ColorThemeData) => void): () => void;
75
+ onClose(): void;
76
+ /** Execute a host command (e.g. navigatePrev, navigateNext, getFileIndex). */
77
+ executeCommand?<T = unknown>(command: string, args?: unknown): Promise<T>;
78
+ /**
79
+ * Commands API exposed to extensions running inside the iframe.
80
+ * Implemented to mimic VS Code: `registerCommand(id, callback) -> Disposable`.
81
+ */
82
+ registerCommand?(commandId: string, handler: (...args: unknown[]) => void | Promise<void>): () => void;
83
+ /** Contribute a keybinding (extension layer). */
84
+ registerKeybinding?(binding: {
85
+ command: string;
86
+ key: string;
87
+ mac?: string;
88
+ when?: string;
89
+ }): () => void;
90
+ /** Oniguruma WASM binary for TextMate grammars (optional). */
91
+ getOnigurumaWasm?(): Promise<ArrayBuffer>;
92
+ /** URL to a file inside the extension dir (for lazy-loading workers). Returns blob URL. */
93
+ getExtensionResourceUrl?(relativePath: string): Promise<string>;
94
+ }
95
+ export interface ViewerExtensionApi {
96
+ /** Render viewer UI into the provided root. */
97
+ mount(root: HTMLElement, props: ViewerProps): Promise<void>;
98
+ unmount(): Promise<void>;
99
+ }
100
+ export interface EditorExtensionApi {
101
+ /** Render editor UI into the provided root. */
102
+ mount(root: HTMLElement, props: EditorProps): Promise<void>;
103
+ unmount(): Promise<void>;
104
+ setDirty?(dirty: boolean): void;
105
+ /** Change the editor language (e.g. for syntax highlighting). */
106
+ setLanguage?(langId: string): void | Promise<void>;
107
+ }
108
+ /** A single entry returned by an fsProvider. */
109
+ export interface FsProviderEntry {
110
+ name: string;
111
+ type: "file" | "directory";
112
+ size?: number;
113
+ mtimeMs?: number;
114
+ }
115
+ /**
116
+ * Host API available to fsProvider extensions (injected as `window.__dotdirProviderHostApi`
117
+ * before the provider bundle is evaluated).
118
+ */
119
+ export interface FsProviderHostApi {
120
+ /** Read the entire container file from the real filesystem. */
121
+ readFile(realPath: string): Promise<ArrayBuffer>;
122
+ /** Read a byte range from the real filesystem. */
123
+ readFileRange(realPath: string, offset: number, length: number): Promise<ArrayBuffer>;
124
+ }
125
+ /**
126
+ * API that an fsProvider extension bundle must expose.
127
+ *
128
+ * Protocol: the bundle assigns a factory to `window.__dotdirProviderReady`.
129
+ * The host evaluates the bundle, then calls `window.__dotdirProviderReady(hostApi)`
130
+ * and stores the returned object.
131
+ *
132
+ * Example bundle (CommonJS):
133
+ * ```js
134
+ * window.__dotdirProviderReady = function(hostApi) {
135
+ * return {
136
+ * async listEntries(containerPath, innerPath) {
137
+ * const bytes = await hostApi.readFile(containerPath);
138
+ * // ... parse format, return entries
139
+ * return [{ name: 'README.md', type: 'file', size: 1234 }];
140
+ * }
141
+ * };
142
+ * };
143
+ * ```
144
+ */
145
+ export interface FsProviderExtensionApi {
146
+ /**
147
+ * List the entries at `innerPath` inside the container at `containerPath`.
148
+ * `containerPath` is always a real filesystem path.
149
+ * `innerPath` is always absolute, e.g. '/' for the root.
150
+ */
151
+ listEntries(containerPath: string, innerPath: string): Promise<FsProviderEntry[]>;
152
+ /**
153
+ * Read a byte range of a file inside the container.
154
+ * Optional — only needed if the host should be able to open files inside containers.
155
+ */
156
+ readFileRange?(containerPath: string, innerPath: string, offset: number, length: number): Promise<ArrayBuffer>;
157
+ }
158
+ /** Extension calls this when loaded; host sets it before injecting the script. */
159
+ export type DotDirHostReadyCallback = (api: ViewerExtensionApi | EditorExtensionApi) => void;
160
+ /** Factory signature for fsProvider bundles. */
161
+ export type FsProviderFactory = (hostApi: FsProviderHostApi) => FsProviderExtensionApi;
162
+ declare global {
163
+ interface Window {
164
+ __dotdirHostReady?: DotDirHostReadyCallback;
165
+ /**
166
+ * Set by the fsProvider bundle. The host calls it after the bundle loads,
167
+ * passing the HostApi, and stores the returned FsProviderExtensionApi.
168
+ */
169
+ __dotdirProviderReady?: FsProviderFactory;
170
+ /**
171
+ * Host API exposed to isolated extensions (iframe) as a global.
172
+ * Extensions can call `window.dotdir.readFile(...)`, etc.
173
+ *
174
+ * We'll later publish these typings via an npm package (`dotdir`).
175
+ */
176
+ dotdir?: HostApi & {
177
+ commands?: {
178
+ registerCommand: (commandId: string, handler: (...args: unknown[]) => void | Promise<void>, options?: {
179
+ title?: string;
180
+ category?: string;
181
+ icon?: string;
182
+ }) => {
183
+ dispose: () => void;
184
+ };
185
+ registerKeybinding: (binding: {
186
+ command: string;
187
+ key: string;
188
+ mac?: string;
189
+ when?: string;
190
+ }) => {
191
+ dispose: () => void;
192
+ };
193
+ };
194
+ };
195
+ }
196
+ }