@djangocfg/ui-tools 2.1.239 → 2.1.240
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 +49 -3
- package/dist/index.cjs +731 -0
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +233 -1
- package/dist/index.d.ts +233 -1
- package/dist/index.mjs +726 -2
- package/dist/index.mjs.map +1 -1
- package/package.json +15 -7
- package/src/tools/CodeEditor/CodeEditor.story.tsx +202 -0
- package/src/tools/CodeEditor/README.md +189 -0
- package/src/tools/CodeEditor/components/DiffEditor.tsx +123 -0
- package/src/tools/CodeEditor/components/Editor.tsx +222 -0
- package/src/tools/CodeEditor/components/index.ts +2 -0
- package/src/tools/CodeEditor/context/EditorProvider.tsx +194 -0
- package/src/tools/CodeEditor/context/index.ts +1 -0
- package/src/tools/CodeEditor/hooks/index.ts +4 -0
- package/src/tools/CodeEditor/hooks/useEditor.ts +36 -0
- package/src/tools/CodeEditor/hooks/useEditorTheme.ts +158 -0
- package/src/tools/CodeEditor/hooks/useLanguage.ts +29 -0
- package/src/tools/CodeEditor/hooks/useMonaco.ts +64 -0
- package/src/tools/CodeEditor/index.ts +16 -0
- package/src/tools/CodeEditor/lib/index.ts +2 -0
- package/src/tools/CodeEditor/lib/languages.ts +227 -0
- package/src/tools/CodeEditor/lib/themes.ts +78 -0
- package/src/tools/CodeEditor/types/index.ts +130 -0
- package/src/tools/CodeEditor/workers/index.ts +1 -0
- package/src/tools/CodeEditor/workers/setup.ts +58 -0
- package/src/tools/index.ts +25 -0
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import { useState, useEffect } from 'react';
|
|
4
|
+
import type * as MonacoEditor from 'monaco-editor';
|
|
5
|
+
|
|
6
|
+
import { setupMonacoWorkers } from '../workers/setup';
|
|
7
|
+
import type { UseMonacoReturn } from '../types';
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Hook to load and access Monaco Editor instance
|
|
11
|
+
*
|
|
12
|
+
* Handles:
|
|
13
|
+
* - Dynamic import of Monaco (client-side only)
|
|
14
|
+
* - Web worker configuration
|
|
15
|
+
* - Loading state management
|
|
16
|
+
*
|
|
17
|
+
* @example
|
|
18
|
+
* ```tsx
|
|
19
|
+
* const { monaco, isLoading, error } = useMonaco();
|
|
20
|
+
*
|
|
21
|
+
* if (isLoading) return <Spinner />;
|
|
22
|
+
* if (error) return <Error message={error.message} />;
|
|
23
|
+
*
|
|
24
|
+
* // Use monaco API
|
|
25
|
+
* monaco.editor.create(...)
|
|
26
|
+
* ```
|
|
27
|
+
*/
|
|
28
|
+
export function useMonaco(): UseMonacoReturn {
|
|
29
|
+
const [monaco, setMonaco] = useState<typeof MonacoEditor | null>(null);
|
|
30
|
+
const [isLoading, setIsLoading] = useState(true);
|
|
31
|
+
const [error, setError] = useState<Error | null>(null);
|
|
32
|
+
|
|
33
|
+
useEffect(() => {
|
|
34
|
+
let mounted = true;
|
|
35
|
+
|
|
36
|
+
async function loadMonaco() {
|
|
37
|
+
try {
|
|
38
|
+
// Setup workers first
|
|
39
|
+
setupMonacoWorkers();
|
|
40
|
+
|
|
41
|
+
// Dynamic import Monaco
|
|
42
|
+
const monacoModule = await import('monaco-editor');
|
|
43
|
+
|
|
44
|
+
if (mounted) {
|
|
45
|
+
setMonaco(monacoModule);
|
|
46
|
+
setIsLoading(false);
|
|
47
|
+
}
|
|
48
|
+
} catch (err) {
|
|
49
|
+
if (mounted) {
|
|
50
|
+
setError(err instanceof Error ? err : new Error('Failed to load Monaco Editor'));
|
|
51
|
+
setIsLoading(false);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
loadMonaco();
|
|
57
|
+
|
|
58
|
+
return () => {
|
|
59
|
+
mounted = false;
|
|
60
|
+
};
|
|
61
|
+
}, []);
|
|
62
|
+
|
|
63
|
+
return { monaco, isLoading, error };
|
|
64
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
// ============================================================================
|
|
2
|
+
// CodeEditor - Monaco Editor Integration (~550KB)
|
|
3
|
+
// Code editor components with Next.js support
|
|
4
|
+
// ============================================================================
|
|
5
|
+
|
|
6
|
+
// Components
|
|
7
|
+
export * from './components';
|
|
8
|
+
|
|
9
|
+
// Hooks
|
|
10
|
+
export * from './hooks';
|
|
11
|
+
|
|
12
|
+
// Context
|
|
13
|
+
export * from './context';
|
|
14
|
+
|
|
15
|
+
// Types
|
|
16
|
+
export * from './types';
|
|
@@ -0,0 +1,227 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Language Detection & Mapping
|
|
3
|
+
*
|
|
4
|
+
* Maps file extensions to Monaco Editor language IDs.
|
|
5
|
+
* Monaco supports 80+ languages out of the box.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* File extension to Monaco language ID mapping
|
|
10
|
+
*/
|
|
11
|
+
export const LANGUAGE_MAP: Record<string, string> = {
|
|
12
|
+
// Web
|
|
13
|
+
'.html': 'html',
|
|
14
|
+
'.htm': 'html',
|
|
15
|
+
'.xhtml': 'html',
|
|
16
|
+
'.vue': 'html',
|
|
17
|
+
'.svelte': 'html',
|
|
18
|
+
|
|
19
|
+
// CSS
|
|
20
|
+
'.css': 'css',
|
|
21
|
+
'.scss': 'scss',
|
|
22
|
+
'.sass': 'scss',
|
|
23
|
+
'.less': 'less',
|
|
24
|
+
|
|
25
|
+
// JavaScript/TypeScript
|
|
26
|
+
'.js': 'javascript',
|
|
27
|
+
'.mjs': 'javascript',
|
|
28
|
+
'.cjs': 'javascript',
|
|
29
|
+
'.jsx': 'javascript',
|
|
30
|
+
'.ts': 'typescript',
|
|
31
|
+
'.tsx': 'typescript',
|
|
32
|
+
'.mts': 'typescript',
|
|
33
|
+
'.cts': 'typescript',
|
|
34
|
+
|
|
35
|
+
// Data formats
|
|
36
|
+
'.json': 'json',
|
|
37
|
+
'.jsonc': 'json',
|
|
38
|
+
'.json5': 'json',
|
|
39
|
+
'.yaml': 'yaml',
|
|
40
|
+
'.yml': 'yaml',
|
|
41
|
+
'.toml': 'ini',
|
|
42
|
+
'.xml': 'xml',
|
|
43
|
+
'.svg': 'xml',
|
|
44
|
+
'.xsl': 'xml',
|
|
45
|
+
'.xsd': 'xml',
|
|
46
|
+
|
|
47
|
+
// Markdown & Documentation
|
|
48
|
+
'.md': 'markdown',
|
|
49
|
+
'.mdx': 'markdown',
|
|
50
|
+
'.markdown': 'markdown',
|
|
51
|
+
'.rst': 'restructuredtext',
|
|
52
|
+
'.txt': 'plaintext',
|
|
53
|
+
'.text': 'plaintext',
|
|
54
|
+
|
|
55
|
+
// Programming languages
|
|
56
|
+
'.py': 'python',
|
|
57
|
+
'.pyw': 'python',
|
|
58
|
+
'.pyi': 'python',
|
|
59
|
+
'.rb': 'ruby',
|
|
60
|
+
'.rake': 'ruby',
|
|
61
|
+
'.gemspec': 'ruby',
|
|
62
|
+
'.php': 'php',
|
|
63
|
+
'.phtml': 'php',
|
|
64
|
+
'.java': 'java',
|
|
65
|
+
'.kt': 'kotlin',
|
|
66
|
+
'.kts': 'kotlin',
|
|
67
|
+
'.scala': 'scala',
|
|
68
|
+
'.go': 'go',
|
|
69
|
+
'.rs': 'rust',
|
|
70
|
+
'.swift': 'swift',
|
|
71
|
+
'.c': 'c',
|
|
72
|
+
'.h': 'c',
|
|
73
|
+
'.cpp': 'cpp',
|
|
74
|
+
'.cc': 'cpp',
|
|
75
|
+
'.cxx': 'cpp',
|
|
76
|
+
'.hpp': 'cpp',
|
|
77
|
+
'.hxx': 'cpp',
|
|
78
|
+
'.cs': 'csharp',
|
|
79
|
+
'.fs': 'fsharp',
|
|
80
|
+
'.fsx': 'fsharp',
|
|
81
|
+
'.vb': 'vb',
|
|
82
|
+
'.lua': 'lua',
|
|
83
|
+
'.r': 'r',
|
|
84
|
+
'.R': 'r',
|
|
85
|
+
'.m': 'objective-c',
|
|
86
|
+
'.mm': 'objective-c',
|
|
87
|
+
'.pl': 'perl',
|
|
88
|
+
'.pm': 'perl',
|
|
89
|
+
'.ex': 'elixir',
|
|
90
|
+
'.exs': 'elixir',
|
|
91
|
+
'.erl': 'erlang',
|
|
92
|
+
'.hrl': 'erlang',
|
|
93
|
+
'.clj': 'clojure',
|
|
94
|
+
'.cljs': 'clojure',
|
|
95
|
+
'.cljc': 'clojure',
|
|
96
|
+
'.hs': 'haskell',
|
|
97
|
+
'.lhs': 'haskell',
|
|
98
|
+
'.ml': 'fsharp',
|
|
99
|
+
'.mli': 'fsharp',
|
|
100
|
+
'.dart': 'dart',
|
|
101
|
+
'.groovy': 'groovy',
|
|
102
|
+
'.gradle': 'groovy',
|
|
103
|
+
'.jl': 'julia',
|
|
104
|
+
|
|
105
|
+
// Shell & Scripts
|
|
106
|
+
'.sh': 'shell',
|
|
107
|
+
'.bash': 'shell',
|
|
108
|
+
'.zsh': 'shell',
|
|
109
|
+
'.fish': 'shell',
|
|
110
|
+
'.ps1': 'powershell',
|
|
111
|
+
'.psm1': 'powershell',
|
|
112
|
+
'.psd1': 'powershell',
|
|
113
|
+
'.bat': 'bat',
|
|
114
|
+
'.cmd': 'bat',
|
|
115
|
+
|
|
116
|
+
// Config files
|
|
117
|
+
'.ini': 'ini',
|
|
118
|
+
'.cfg': 'ini',
|
|
119
|
+
'.conf': 'ini',
|
|
120
|
+
'.properties': 'ini',
|
|
121
|
+
'.env': 'ini',
|
|
122
|
+
'.gitignore': 'ini',
|
|
123
|
+
'.gitattributes': 'ini',
|
|
124
|
+
'.editorconfig': 'ini',
|
|
125
|
+
'.npmrc': 'ini',
|
|
126
|
+
|
|
127
|
+
// Database
|
|
128
|
+
'.sql': 'sql',
|
|
129
|
+
'.mysql': 'mysql',
|
|
130
|
+
'.pgsql': 'pgsql',
|
|
131
|
+
'.plsql': 'plsql',
|
|
132
|
+
'.redis': 'redis',
|
|
133
|
+
|
|
134
|
+
// Templates
|
|
135
|
+
'.hbs': 'handlebars',
|
|
136
|
+
'.handlebars': 'handlebars',
|
|
137
|
+
'.mustache': 'handlebars',
|
|
138
|
+
'.ejs': 'html',
|
|
139
|
+
'.pug': 'pug',
|
|
140
|
+
'.jade': 'pug',
|
|
141
|
+
'.twig': 'twig',
|
|
142
|
+
'.liquid': 'liquid',
|
|
143
|
+
|
|
144
|
+
// GraphQL
|
|
145
|
+
'.graphql': 'graphql',
|
|
146
|
+
'.gql': 'graphql',
|
|
147
|
+
|
|
148
|
+
// Docker
|
|
149
|
+
'.dockerfile': 'dockerfile',
|
|
150
|
+
|
|
151
|
+
// Other
|
|
152
|
+
'.diff': 'diff',
|
|
153
|
+
'.patch': 'diff',
|
|
154
|
+
'.log': 'log',
|
|
155
|
+
'.tex': 'latex',
|
|
156
|
+
'.cls': 'latex',
|
|
157
|
+
'.sty': 'latex',
|
|
158
|
+
'.proto': 'protobuf',
|
|
159
|
+
'.sol': 'sol',
|
|
160
|
+
'.asm': 'mips',
|
|
161
|
+
'.s': 'mips',
|
|
162
|
+
'.wasm': 'wasm',
|
|
163
|
+
};
|
|
164
|
+
|
|
165
|
+
/**
|
|
166
|
+
* Special filename mappings (without extension)
|
|
167
|
+
*/
|
|
168
|
+
const FILENAME_MAP: Record<string, string> = {
|
|
169
|
+
Dockerfile: 'dockerfile',
|
|
170
|
+
'docker-compose.yml': 'yaml',
|
|
171
|
+
'docker-compose.yaml': 'yaml',
|
|
172
|
+
Makefile: 'makefile',
|
|
173
|
+
makefile: 'makefile',
|
|
174
|
+
Gemfile: 'ruby',
|
|
175
|
+
Rakefile: 'ruby',
|
|
176
|
+
Jenkinsfile: 'groovy',
|
|
177
|
+
Vagrantfile: 'ruby',
|
|
178
|
+
'.bashrc': 'shell',
|
|
179
|
+
'.bash_profile': 'shell',
|
|
180
|
+
'.zshrc': 'shell',
|
|
181
|
+
'.profile': 'shell',
|
|
182
|
+
'.vimrc': 'plaintext',
|
|
183
|
+
'.gitconfig': 'ini',
|
|
184
|
+
'.htaccess': 'ini',
|
|
185
|
+
'nginx.conf': 'ini',
|
|
186
|
+
'package.json': 'json',
|
|
187
|
+
'tsconfig.json': 'json',
|
|
188
|
+
'jsconfig.json': 'json',
|
|
189
|
+
'.prettierrc': 'json',
|
|
190
|
+
'.eslintrc': 'json',
|
|
191
|
+
'composer.json': 'json',
|
|
192
|
+
'Cargo.toml': 'ini',
|
|
193
|
+
'go.mod': 'go',
|
|
194
|
+
'go.sum': 'plaintext',
|
|
195
|
+
'requirements.txt': 'plaintext',
|
|
196
|
+
'pyproject.toml': 'ini',
|
|
197
|
+
'setup.py': 'python',
|
|
198
|
+
'setup.cfg': 'ini',
|
|
199
|
+
};
|
|
200
|
+
|
|
201
|
+
/**
|
|
202
|
+
* Get Monaco language ID from file extension
|
|
203
|
+
*/
|
|
204
|
+
export function getLanguageByExtension(extension: string): string {
|
|
205
|
+
const ext = extension.startsWith('.') ? extension.toLowerCase() : `.${extension.toLowerCase()}`;
|
|
206
|
+
return LANGUAGE_MAP[ext] || 'plaintext';
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
/**
|
|
210
|
+
* Get Monaco language ID from filename
|
|
211
|
+
* Checks special filenames first, then falls back to extension
|
|
212
|
+
*/
|
|
213
|
+
export function getLanguageByFilename(filename: string): string {
|
|
214
|
+
// Check special filenames first
|
|
215
|
+
if (FILENAME_MAP[filename]) {
|
|
216
|
+
return FILENAME_MAP[filename];
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
// Extract extension
|
|
220
|
+
const lastDot = filename.lastIndexOf('.');
|
|
221
|
+
if (lastDot === -1) {
|
|
222
|
+
return 'plaintext';
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
const extension = filename.slice(lastDot).toLowerCase();
|
|
226
|
+
return LANGUAGE_MAP[extension] || 'plaintext';
|
|
227
|
+
}
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Editor Themes
|
|
3
|
+
*
|
|
4
|
+
* Built-in Monaco themes and custom CMDOP themes
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
export type EditorTheme = 'vs' | 'vs-dark' | 'hc-black' | 'hc-light' | 'cmdop-dark' | 'cmdop-light';
|
|
8
|
+
|
|
9
|
+
export const EDITOR_THEMES = {
|
|
10
|
+
// Built-in themes
|
|
11
|
+
'vs': 'Light (VS Code)',
|
|
12
|
+
'vs-dark': 'Dark (VS Code)',
|
|
13
|
+
'hc-black': 'High Contrast Dark',
|
|
14
|
+
'hc-light': 'High Contrast Light',
|
|
15
|
+
// Custom themes (to be defined)
|
|
16
|
+
'cmdop-dark': 'CMDOP Dark',
|
|
17
|
+
'cmdop-light': 'CMDOP Light',
|
|
18
|
+
} as const;
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Get default theme based on system preference
|
|
22
|
+
*/
|
|
23
|
+
export function getDefaultTheme(): EditorTheme {
|
|
24
|
+
if (typeof window === 'undefined') return 'vs-dark';
|
|
25
|
+
|
|
26
|
+
const prefersDark = window.matchMedia('(prefers-color-scheme: dark)').matches;
|
|
27
|
+
return prefersDark ? 'vs-dark' : 'vs';
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* CMDOP Dark Theme Definition
|
|
32
|
+
* Can be registered with monaco.editor.defineTheme()
|
|
33
|
+
*/
|
|
34
|
+
export const cmdopDarkTheme = {
|
|
35
|
+
base: 'vs-dark' as const,
|
|
36
|
+
inherit: true,
|
|
37
|
+
rules: [
|
|
38
|
+
{ token: 'comment', foreground: '6A9955', fontStyle: 'italic' },
|
|
39
|
+
{ token: 'keyword', foreground: 'C586C0' },
|
|
40
|
+
{ token: 'string', foreground: 'CE9178' },
|
|
41
|
+
{ token: 'number', foreground: 'B5CEA8' },
|
|
42
|
+
{ token: 'type', foreground: '4EC9B0' },
|
|
43
|
+
{ token: 'function', foreground: 'DCDCAA' },
|
|
44
|
+
{ token: 'variable', foreground: '9CDCFE' },
|
|
45
|
+
],
|
|
46
|
+
colors: {
|
|
47
|
+
'editor.background': '#1a1a1a',
|
|
48
|
+
'editor.foreground': '#D4D4D4',
|
|
49
|
+
'editor.lineHighlightBackground': '#2d2d2d',
|
|
50
|
+
'editor.selectionBackground': '#264F78',
|
|
51
|
+
'editorCursor.foreground': '#AEAFAD',
|
|
52
|
+
'editorLineNumber.foreground': '#858585',
|
|
53
|
+
'editorLineNumber.activeForeground': '#C6C6C6',
|
|
54
|
+
},
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* CMDOP Light Theme Definition
|
|
59
|
+
*/
|
|
60
|
+
export const cmdopLightTheme = {
|
|
61
|
+
base: 'vs' as const,
|
|
62
|
+
inherit: true,
|
|
63
|
+
rules: [
|
|
64
|
+
{ token: 'comment', foreground: '008000', fontStyle: 'italic' },
|
|
65
|
+
{ token: 'keyword', foreground: 'AF00DB' },
|
|
66
|
+
{ token: 'string', foreground: 'A31515' },
|
|
67
|
+
{ token: 'number', foreground: '098658' },
|
|
68
|
+
{ token: 'type', foreground: '267F99' },
|
|
69
|
+
{ token: 'function', foreground: '795E26' },
|
|
70
|
+
{ token: 'variable', foreground: '001080' },
|
|
71
|
+
],
|
|
72
|
+
colors: {
|
|
73
|
+
'editor.background': '#FFFFFF',
|
|
74
|
+
'editor.foreground': '#000000',
|
|
75
|
+
'editor.lineHighlightBackground': '#F5F5F5',
|
|
76
|
+
'editor.selectionBackground': '#ADD6FF',
|
|
77
|
+
},
|
|
78
|
+
};
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
import type * as monaco from 'monaco-editor';
|
|
2
|
+
|
|
3
|
+
// ============================================================================
|
|
4
|
+
// Editor Types
|
|
5
|
+
// ============================================================================
|
|
6
|
+
|
|
7
|
+
export interface EditorFile {
|
|
8
|
+
/** Unique file path */
|
|
9
|
+
path: string;
|
|
10
|
+
/** File content */
|
|
11
|
+
content: string;
|
|
12
|
+
/** Detected or specified language */
|
|
13
|
+
language: string;
|
|
14
|
+
/** Whether file has unsaved changes */
|
|
15
|
+
isDirty: boolean;
|
|
16
|
+
/** Monaco model reference */
|
|
17
|
+
model?: monaco.editor.ITextModel;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export interface EditorOptions {
|
|
21
|
+
/** Editor theme: 'vs' | 'vs-dark' | 'hc-black' | custom */
|
|
22
|
+
theme?: string;
|
|
23
|
+
/** Font size in pixels */
|
|
24
|
+
fontSize?: number;
|
|
25
|
+
/** Font family */
|
|
26
|
+
fontFamily?: string;
|
|
27
|
+
/** Tab size */
|
|
28
|
+
tabSize?: number;
|
|
29
|
+
/** Insert spaces instead of tabs */
|
|
30
|
+
insertSpaces?: boolean;
|
|
31
|
+
/** Word wrap mode */
|
|
32
|
+
wordWrap?: 'off' | 'on' | 'wordWrapColumn' | 'bounded';
|
|
33
|
+
/** Show minimap */
|
|
34
|
+
minimap?: boolean;
|
|
35
|
+
/** Show line numbers */
|
|
36
|
+
lineNumbers?: 'on' | 'off' | 'relative' | 'interval';
|
|
37
|
+
/** Read-only mode */
|
|
38
|
+
readOnly?: boolean;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export interface EditorProps {
|
|
42
|
+
/** File content */
|
|
43
|
+
value?: string;
|
|
44
|
+
/** Programming language for syntax highlighting */
|
|
45
|
+
language?: string;
|
|
46
|
+
/** Called when content changes */
|
|
47
|
+
onChange?: (value: string) => void;
|
|
48
|
+
/** Called when editor is mounted */
|
|
49
|
+
onMount?: (editor: monaco.editor.IStandaloneCodeEditor) => void;
|
|
50
|
+
/** Editor options */
|
|
51
|
+
options?: EditorOptions;
|
|
52
|
+
/** CSS class name */
|
|
53
|
+
className?: string;
|
|
54
|
+
/** Height — fixed px, CSS string, or '100%' (default: '100%'). Ignored when autoHeight=true */
|
|
55
|
+
height?: string | number;
|
|
56
|
+
/** Width (default: '100%') */
|
|
57
|
+
width?: string | number;
|
|
58
|
+
/** Auto-resize height to fit content. Editor grows/shrinks with content lines */
|
|
59
|
+
autoHeight?: boolean;
|
|
60
|
+
/** Min height in px when autoHeight is enabled (default: 100) */
|
|
61
|
+
minHeight?: number;
|
|
62
|
+
/** Max height in px when autoHeight is enabled (default: 600) */
|
|
63
|
+
maxHeight?: number;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
export interface DiffEditorProps {
|
|
67
|
+
/** Original content (left side) */
|
|
68
|
+
original: string;
|
|
69
|
+
/** Modified content (right side) */
|
|
70
|
+
modified: string;
|
|
71
|
+
/** Programming language */
|
|
72
|
+
language?: string;
|
|
73
|
+
/** Editor options */
|
|
74
|
+
options?: EditorOptions;
|
|
75
|
+
/** CSS class name */
|
|
76
|
+
className?: string;
|
|
77
|
+
/** Height (default: '100%') */
|
|
78
|
+
height?: string | number;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
// ============================================================================
|
|
82
|
+
// Context Types
|
|
83
|
+
// ============================================================================
|
|
84
|
+
|
|
85
|
+
export interface EditorContextValue {
|
|
86
|
+
/** Currently open files */
|
|
87
|
+
openFiles: EditorFile[];
|
|
88
|
+
/** Currently active file */
|
|
89
|
+
activeFile: EditorFile | null;
|
|
90
|
+
/** Monaco instance (null during SSR) */
|
|
91
|
+
monaco: typeof monaco | null;
|
|
92
|
+
/** Editor instance */
|
|
93
|
+
editor: monaco.editor.IStandaloneCodeEditor | null;
|
|
94
|
+
/** Whether editor is ready */
|
|
95
|
+
isReady: boolean;
|
|
96
|
+
|
|
97
|
+
// File operations
|
|
98
|
+
openFile: (path: string, content: string, language?: string) => void;
|
|
99
|
+
closeFile: (path: string) => void;
|
|
100
|
+
setActiveFile: (path: string) => void;
|
|
101
|
+
updateContent: (path: string, content: string) => void;
|
|
102
|
+
saveFile: (path: string) => Promise<void>;
|
|
103
|
+
|
|
104
|
+
// State queries
|
|
105
|
+
isDirty: (path: string) => boolean;
|
|
106
|
+
getContent: (path: string) => string | null;
|
|
107
|
+
getFile: (path: string) => EditorFile | null;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
// ============================================================================
|
|
111
|
+
// Hook Return Types
|
|
112
|
+
// ============================================================================
|
|
113
|
+
|
|
114
|
+
export interface UseEditorReturn {
|
|
115
|
+
/** Editor instance */
|
|
116
|
+
editor: monaco.editor.IStandaloneCodeEditor | null;
|
|
117
|
+
/** Whether editor is mounted and ready */
|
|
118
|
+
isReady: boolean;
|
|
119
|
+
/** Set editor reference */
|
|
120
|
+
setEditor: (editor: monaco.editor.IStandaloneCodeEditor | null) => void;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
export interface UseMonacoReturn {
|
|
124
|
+
/** Monaco namespace */
|
|
125
|
+
monaco: typeof monaco | null;
|
|
126
|
+
/** Whether Monaco is loaded */
|
|
127
|
+
isLoading: boolean;
|
|
128
|
+
/** Loading error if any */
|
|
129
|
+
error: Error | null;
|
|
130
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { setupMonacoWorkers } from './setup';
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Monaco Editor Web Worker Setup
|
|
5
|
+
*
|
|
6
|
+
* Workers improve performance for language services (TypeScript type-checking,
|
|
7
|
+
* JSON validation, etc.) but require bundler-specific configuration:
|
|
8
|
+
*
|
|
9
|
+
* **Vite**: Use `?worker` imports (see example below)
|
|
10
|
+
* **Next.js/Webpack**: Use `monaco-editor-webpack-plugin`
|
|
11
|
+
* **No config**: Monaco falls back to main-thread execution (fully functional)
|
|
12
|
+
*
|
|
13
|
+
* @example Vite setup (call once in app entry):
|
|
14
|
+
* ```ts
|
|
15
|
+
* import editorWorker from 'monaco-editor/esm/vs/editor/editor.worker?worker'
|
|
16
|
+
* import tsWorker from 'monaco-editor/esm/vs/language/typescript/ts.worker?worker'
|
|
17
|
+
* import jsonWorker from 'monaco-editor/esm/vs/language/json/json.worker?worker'
|
|
18
|
+
* import cssWorker from 'monaco-editor/esm/vs/language/css/css.worker?worker'
|
|
19
|
+
* import htmlWorker from 'monaco-editor/esm/vs/language/html/html.worker?worker'
|
|
20
|
+
*
|
|
21
|
+
* setupMonacoWorkers((label) => {
|
|
22
|
+
* switch (label) {
|
|
23
|
+
* case 'typescript': case 'javascript': return new tsWorker()
|
|
24
|
+
* case 'json': return new jsonWorker()
|
|
25
|
+
* case 'css': case 'scss': case 'less': return new cssWorker()
|
|
26
|
+
* case 'html': case 'handlebars': case 'razor': return new htmlWorker()
|
|
27
|
+
* default: return new editorWorker()
|
|
28
|
+
* }
|
|
29
|
+
* })
|
|
30
|
+
* ```
|
|
31
|
+
*
|
|
32
|
+
* @example Next.js setup:
|
|
33
|
+
* ```ts
|
|
34
|
+
* // next.config.js — add monaco-editor-webpack-plugin
|
|
35
|
+
* // Then just call setupMonacoWorkers() without arguments
|
|
36
|
+
* setupMonacoWorkers()
|
|
37
|
+
* ```
|
|
38
|
+
*/
|
|
39
|
+
|
|
40
|
+
type GetWorkerFn = (label: string) => Worker;
|
|
41
|
+
|
|
42
|
+
let isSetup = false;
|
|
43
|
+
|
|
44
|
+
export function setupMonacoWorkers(getWorker?: GetWorkerFn): void {
|
|
45
|
+
if (isSetup || typeof window === 'undefined') return;
|
|
46
|
+
|
|
47
|
+
if (getWorker) {
|
|
48
|
+
// App provides bundler-specific worker factory
|
|
49
|
+
(self as unknown as { MonacoEnvironment: object }).MonacoEnvironment = {
|
|
50
|
+
getWorker: (_workerId: string, label: string) => getWorker(label),
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
// else: don't set MonacoEnvironment at all.
|
|
54
|
+
// - If webpack plugin is installed, it sets MonacoEnvironment automatically.
|
|
55
|
+
// - If nothing sets it, Monaco falls back to main-thread execution.
|
|
56
|
+
|
|
57
|
+
isSetup = true;
|
|
58
|
+
}
|
package/src/tools/index.ts
CHANGED
|
@@ -197,6 +197,31 @@ export type {
|
|
|
197
197
|
CronSchedulerContextValue,
|
|
198
198
|
} from './CronScheduler';
|
|
199
199
|
|
|
200
|
+
// Export CodeEditor (Monaco ~550KB)
|
|
201
|
+
export {
|
|
202
|
+
Editor,
|
|
203
|
+
DiffEditor,
|
|
204
|
+
} from './CodeEditor/components';
|
|
205
|
+
export type { EditorRef } from './CodeEditor/components/Editor';
|
|
206
|
+
export {
|
|
207
|
+
EditorProvider,
|
|
208
|
+
useEditorContext,
|
|
209
|
+
} from './CodeEditor/context';
|
|
210
|
+
export {
|
|
211
|
+
useMonaco,
|
|
212
|
+
useEditor,
|
|
213
|
+
useLanguage,
|
|
214
|
+
} from './CodeEditor/hooks';
|
|
215
|
+
export type {
|
|
216
|
+
EditorFile,
|
|
217
|
+
EditorOptions,
|
|
218
|
+
EditorProps,
|
|
219
|
+
DiffEditorProps,
|
|
220
|
+
EditorContextValue,
|
|
221
|
+
UseEditorReturn,
|
|
222
|
+
UseMonacoReturn,
|
|
223
|
+
} from './CodeEditor/types';
|
|
224
|
+
|
|
200
225
|
// Export Media Cache Store
|
|
201
226
|
export {
|
|
202
227
|
useMediaCacheStore,
|