@dataloop-ai/components 0.20.186 → 0.20.187-code.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 +3 -1
- package/src/components/compound/DlMonacoEditor/DlMonacoEditor.vue +424 -0
- package/src/components/compound/DlMonacoEditor/index.ts +4 -0
- package/src/components/compound/DlMonacoEditor/types.ts +116 -0
- package/src/components/compound/index.ts +1 -0
- package/src/demos/DlMonacoEditorDemo.vue +238 -0
- package/src/demos/index.ts +3 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dataloop-ai/components",
|
|
3
|
-
"version": "0.20.
|
|
3
|
+
"version": "0.20.187-code.0",
|
|
4
4
|
"exports": {
|
|
5
5
|
".": "./index.ts",
|
|
6
6
|
"./models": "./models.ts",
|
|
@@ -24,6 +24,8 @@
|
|
|
24
24
|
},
|
|
25
25
|
"dependencies": {
|
|
26
26
|
"@dataloop-ai/icons": "^3.1.37",
|
|
27
|
+
"@monaco-editor/loader": "^1.4.0",
|
|
28
|
+
"monaco-editor": "^0.45.0",
|
|
27
29
|
"@types/flat": "^5.0.2",
|
|
28
30
|
"@types/lodash": "^4.14.184",
|
|
29
31
|
"@types/sortablejs": "^1.15.7",
|
|
@@ -0,0 +1,424 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div
|
|
3
|
+
class="dl-monaco-editor-wrapper"
|
|
4
|
+
:class="{
|
|
5
|
+
'dl-monaco-editor-wrapper--bordered': bordered,
|
|
6
|
+
'dl-monaco-editor-wrapper--dark': isDarkTheme
|
|
7
|
+
}"
|
|
8
|
+
:style="cssVars"
|
|
9
|
+
>
|
|
10
|
+
<!-- Header -->
|
|
11
|
+
<div v-if="!options.hideHeader" class="dl-monaco-editor__header">
|
|
12
|
+
<div class="dl-monaco-editor__header-left">
|
|
13
|
+
<span
|
|
14
|
+
v-if="!options.hideLanguage"
|
|
15
|
+
class="dl-monaco-editor__language"
|
|
16
|
+
>
|
|
17
|
+
{{ displayLanguage }}
|
|
18
|
+
</span>
|
|
19
|
+
<span v-if="title" class="dl-monaco-editor__title">
|
|
20
|
+
{{ title }}
|
|
21
|
+
</span>
|
|
22
|
+
</div>
|
|
23
|
+
<div class="dl-monaco-editor__header-right">
|
|
24
|
+
<dl-button
|
|
25
|
+
v-if="!options.hideCopyButton"
|
|
26
|
+
icon="icon-dl-copy"
|
|
27
|
+
icon-color="dl-color-medium"
|
|
28
|
+
size="14px"
|
|
29
|
+
flat
|
|
30
|
+
round
|
|
31
|
+
tooltip="Copy to clipboard"
|
|
32
|
+
@click="copyToClipboard"
|
|
33
|
+
/>
|
|
34
|
+
</div>
|
|
35
|
+
</div>
|
|
36
|
+
|
|
37
|
+
<!-- Monaco Editor Container -->
|
|
38
|
+
<div ref="editorContainer" class="dl-monaco-editor__container" />
|
|
39
|
+
</div>
|
|
40
|
+
</template>
|
|
41
|
+
|
|
42
|
+
<script lang="ts">
|
|
43
|
+
import {
|
|
44
|
+
defineComponent,
|
|
45
|
+
ref,
|
|
46
|
+
computed,
|
|
47
|
+
watch,
|
|
48
|
+
onMounted,
|
|
49
|
+
onBeforeUnmount,
|
|
50
|
+
PropType,
|
|
51
|
+
toRefs
|
|
52
|
+
} from 'vue-demi'
|
|
53
|
+
import loader from '@monaco-editor/loader'
|
|
54
|
+
import type * as Monaco from 'monaco-editor'
|
|
55
|
+
import {
|
|
56
|
+
DlMonacoEditorTheme,
|
|
57
|
+
DlMonacoEditorOptions,
|
|
58
|
+
getMonacoTheme,
|
|
59
|
+
getLanguageTitle,
|
|
60
|
+
normalizeLanguage
|
|
61
|
+
} from './types'
|
|
62
|
+
import { DlButton } from '../../basic'
|
|
63
|
+
|
|
64
|
+
export default defineComponent({
|
|
65
|
+
name: 'DlMonacoEditor',
|
|
66
|
+
components: {
|
|
67
|
+
DlButton
|
|
68
|
+
},
|
|
69
|
+
model: {
|
|
70
|
+
prop: 'modelValue',
|
|
71
|
+
event: 'update:model-value'
|
|
72
|
+
},
|
|
73
|
+
props: {
|
|
74
|
+
/**
|
|
75
|
+
* The code content (v-model)
|
|
76
|
+
*/
|
|
77
|
+
modelValue: {
|
|
78
|
+
type: String as PropType<string>,
|
|
79
|
+
default: ''
|
|
80
|
+
},
|
|
81
|
+
/**
|
|
82
|
+
* Width of the editor
|
|
83
|
+
*/
|
|
84
|
+
width: {
|
|
85
|
+
type: [String, Number] as PropType<string | number>,
|
|
86
|
+
default: '100%'
|
|
87
|
+
},
|
|
88
|
+
/**
|
|
89
|
+
* Height of the editor
|
|
90
|
+
*/
|
|
91
|
+
height: {
|
|
92
|
+
type: [String, Number] as PropType<string | number>,
|
|
93
|
+
default: '100%'
|
|
94
|
+
},
|
|
95
|
+
/**
|
|
96
|
+
* Programming language for syntax highlighting
|
|
97
|
+
*/
|
|
98
|
+
language: {
|
|
99
|
+
type: String as PropType<string>,
|
|
100
|
+
default: 'javascript'
|
|
101
|
+
},
|
|
102
|
+
/**
|
|
103
|
+
* Color theme
|
|
104
|
+
*/
|
|
105
|
+
theme: {
|
|
106
|
+
type: String as PropType<DlMonacoEditorTheme | string>,
|
|
107
|
+
default: DlMonacoEditorTheme.Light
|
|
108
|
+
},
|
|
109
|
+
/**
|
|
110
|
+
* Read-only mode
|
|
111
|
+
*/
|
|
112
|
+
readonly: {
|
|
113
|
+
type: Boolean as PropType<boolean>,
|
|
114
|
+
default: false
|
|
115
|
+
},
|
|
116
|
+
/**
|
|
117
|
+
* Show border around editor
|
|
118
|
+
*/
|
|
119
|
+
bordered: {
|
|
120
|
+
type: Boolean as PropType<boolean>,
|
|
121
|
+
default: true
|
|
122
|
+
},
|
|
123
|
+
/**
|
|
124
|
+
* Title to display in header
|
|
125
|
+
*/
|
|
126
|
+
title: {
|
|
127
|
+
type: String as PropType<string>,
|
|
128
|
+
default: null
|
|
129
|
+
},
|
|
130
|
+
/**
|
|
131
|
+
* Editor options
|
|
132
|
+
*/
|
|
133
|
+
options: {
|
|
134
|
+
type: Object as PropType<DlMonacoEditorOptions>,
|
|
135
|
+
default: () => ({} as DlMonacoEditorOptions)
|
|
136
|
+
}
|
|
137
|
+
},
|
|
138
|
+
emits: ['update:model-value', 'change', 'save', 'ready'],
|
|
139
|
+
setup(props, { emit }) {
|
|
140
|
+
const {
|
|
141
|
+
modelValue,
|
|
142
|
+
language,
|
|
143
|
+
theme,
|
|
144
|
+
readonly,
|
|
145
|
+
options,
|
|
146
|
+
width,
|
|
147
|
+
height
|
|
148
|
+
} = toRefs(props)
|
|
149
|
+
|
|
150
|
+
const editorContainer = ref<HTMLElement | null>(null)
|
|
151
|
+
let editor: Monaco.editor.IStandaloneCodeEditor | null = null
|
|
152
|
+
let monaco: typeof Monaco | null = null
|
|
153
|
+
|
|
154
|
+
// Computed styles
|
|
155
|
+
const styleWidth = computed(() => {
|
|
156
|
+
if (typeof width.value === 'number') {
|
|
157
|
+
return `${width.value}px`
|
|
158
|
+
}
|
|
159
|
+
return width.value
|
|
160
|
+
})
|
|
161
|
+
|
|
162
|
+
const styleHeight = computed(() => {
|
|
163
|
+
if (typeof height.value === 'number') {
|
|
164
|
+
return `${height.value}px`
|
|
165
|
+
}
|
|
166
|
+
return height.value
|
|
167
|
+
})
|
|
168
|
+
|
|
169
|
+
const cssVars = computed(() => ({
|
|
170
|
+
'--dl-monaco-editor-width': styleWidth.value,
|
|
171
|
+
'--dl-monaco-editor-height': styleHeight.value
|
|
172
|
+
}))
|
|
173
|
+
|
|
174
|
+
const monacoTheme = computed(() => getMonacoTheme(theme.value))
|
|
175
|
+
|
|
176
|
+
const isDarkTheme = computed(() => monacoTheme.value === 'vs-dark')
|
|
177
|
+
|
|
178
|
+
const displayLanguage = computed(() => getLanguageTitle(language.value))
|
|
179
|
+
|
|
180
|
+
const normalizedLanguage = computed(() =>
|
|
181
|
+
normalizeLanguage(language.value)
|
|
182
|
+
)
|
|
183
|
+
|
|
184
|
+
const fontSize = computed(() => {
|
|
185
|
+
if (options.value.fontSize) {
|
|
186
|
+
return options.value.fontSize
|
|
187
|
+
}
|
|
188
|
+
return 14
|
|
189
|
+
})
|
|
190
|
+
|
|
191
|
+
// Initialize Monaco Editor
|
|
192
|
+
const initEditor = async () => {
|
|
193
|
+
if (!editorContainer.value) return
|
|
194
|
+
|
|
195
|
+
try {
|
|
196
|
+
monaco = await loader.init()
|
|
197
|
+
|
|
198
|
+
editor = monaco.editor.create(editorContainer.value, {
|
|
199
|
+
value: modelValue.value,
|
|
200
|
+
language: normalizedLanguage.value,
|
|
201
|
+
theme: monacoTheme.value,
|
|
202
|
+
readOnly: readonly.value,
|
|
203
|
+
fontSize: fontSize.value,
|
|
204
|
+
tabSize: options.value.tabSpaces || 4,
|
|
205
|
+
wordWrap: options.value.textWrapping ? 'on' : 'off',
|
|
206
|
+
lineNumbers:
|
|
207
|
+
options.value.lineNumbers !== false ? 'on' : 'off',
|
|
208
|
+
minimap: {
|
|
209
|
+
enabled: options.value.minimap !== false
|
|
210
|
+
},
|
|
211
|
+
automaticLayout: true,
|
|
212
|
+
scrollBeyondLastLine: false,
|
|
213
|
+
scrollBeyondLastColumn: 0,
|
|
214
|
+
renderWhitespace: 'selection',
|
|
215
|
+
folding: true,
|
|
216
|
+
foldingStrategy: 'indentation',
|
|
217
|
+
suggestOnTriggerCharacters:
|
|
218
|
+
options.value.autoComplete !== false,
|
|
219
|
+
quickSuggestions: options.value.autoComplete !== false,
|
|
220
|
+
scrollbar: {
|
|
221
|
+
vertical: 'auto',
|
|
222
|
+
horizontal: 'auto',
|
|
223
|
+
verticalScrollbarSize: 10,
|
|
224
|
+
horizontalScrollbarSize: 10,
|
|
225
|
+
alwaysConsumeMouseWheel: false
|
|
226
|
+
},
|
|
227
|
+
padding: { top: 10, bottom: 10 },
|
|
228
|
+
fixedOverflowWidgets: true
|
|
229
|
+
})
|
|
230
|
+
|
|
231
|
+
// Listen to content changes
|
|
232
|
+
editor.onDidChangeModelContent(() => {
|
|
233
|
+
const value = editor?.getValue() || ''
|
|
234
|
+
emit('update:model-value', value)
|
|
235
|
+
emit('change', value)
|
|
236
|
+
})
|
|
237
|
+
|
|
238
|
+
// Add save command (Ctrl/Cmd + S)
|
|
239
|
+
editor.addCommand(
|
|
240
|
+
monaco.KeyMod.CtrlCmd | monaco.KeyCode.KeyS,
|
|
241
|
+
() => {
|
|
242
|
+
emit('save', editor?.getValue() || '')
|
|
243
|
+
}
|
|
244
|
+
)
|
|
245
|
+
|
|
246
|
+
emit('ready', editor)
|
|
247
|
+
} catch (error) {
|
|
248
|
+
console.error('Failed to initialize Monaco Editor:', error)
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
// Watch for external value changes
|
|
253
|
+
watch(modelValue, (newValue) => {
|
|
254
|
+
if (editor && newValue !== editor.getValue()) {
|
|
255
|
+
editor.setValue(newValue)
|
|
256
|
+
}
|
|
257
|
+
})
|
|
258
|
+
|
|
259
|
+
// Watch for language changes
|
|
260
|
+
watch(normalizedLanguage, (newLanguage) => {
|
|
261
|
+
if (editor && monaco) {
|
|
262
|
+
const model = editor.getModel()
|
|
263
|
+
if (model) {
|
|
264
|
+
monaco.editor.setModelLanguage(model, newLanguage)
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
})
|
|
268
|
+
|
|
269
|
+
// Watch for theme changes
|
|
270
|
+
watch(monacoTheme, (newTheme) => {
|
|
271
|
+
if (monaco) {
|
|
272
|
+
monaco.editor.setTheme(newTheme)
|
|
273
|
+
}
|
|
274
|
+
})
|
|
275
|
+
|
|
276
|
+
// Watch for readonly changes
|
|
277
|
+
watch(readonly, (newReadonly) => {
|
|
278
|
+
if (editor) {
|
|
279
|
+
editor.updateOptions({ readOnly: newReadonly })
|
|
280
|
+
}
|
|
281
|
+
})
|
|
282
|
+
|
|
283
|
+
// Watch for option changes
|
|
284
|
+
watch(
|
|
285
|
+
options,
|
|
286
|
+
(newOptions) => {
|
|
287
|
+
if (editor) {
|
|
288
|
+
editor.updateOptions({
|
|
289
|
+
fontSize: newOptions.fontSize || 14,
|
|
290
|
+
tabSize: newOptions.tabSpaces || 4,
|
|
291
|
+
wordWrap: newOptions.textWrapping ? 'on' : 'off',
|
|
292
|
+
lineNumbers:
|
|
293
|
+
newOptions.lineNumbers !== false ? 'on' : 'off',
|
|
294
|
+
minimap: { enabled: newOptions.minimap !== false }
|
|
295
|
+
})
|
|
296
|
+
}
|
|
297
|
+
},
|
|
298
|
+
{ deep: true }
|
|
299
|
+
)
|
|
300
|
+
|
|
301
|
+
onMounted(() => {
|
|
302
|
+
initEditor()
|
|
303
|
+
})
|
|
304
|
+
|
|
305
|
+
onBeforeUnmount(() => {
|
|
306
|
+
if (editor) {
|
|
307
|
+
editor.dispose()
|
|
308
|
+
editor = null
|
|
309
|
+
}
|
|
310
|
+
})
|
|
311
|
+
|
|
312
|
+
// Copy to clipboard
|
|
313
|
+
const copyToClipboard = async () => {
|
|
314
|
+
try {
|
|
315
|
+
const content = editor?.getValue() || modelValue.value
|
|
316
|
+
await navigator.clipboard.writeText(content)
|
|
317
|
+
// Could emit a success event or show a toast
|
|
318
|
+
} catch (error) {
|
|
319
|
+
console.error('Failed to copy to clipboard:', error)
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
// Public methods
|
|
324
|
+
const focus = () => editor?.focus()
|
|
325
|
+
const getEditor = () => editor
|
|
326
|
+
const setValue = (value: string) => editor?.setValue(value)
|
|
327
|
+
const getValue = () => editor?.getValue() || ''
|
|
328
|
+
const formatDocument = () => {
|
|
329
|
+
editor?.getAction('editor.action.formatDocument')?.run()
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
return {
|
|
333
|
+
editorContainer,
|
|
334
|
+
cssVars,
|
|
335
|
+
isDarkTheme,
|
|
336
|
+
displayLanguage,
|
|
337
|
+
copyToClipboard,
|
|
338
|
+
focus,
|
|
339
|
+
getEditor,
|
|
340
|
+
setValue,
|
|
341
|
+
getValue,
|
|
342
|
+
formatDocument
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
})
|
|
346
|
+
</script>
|
|
347
|
+
|
|
348
|
+
<style scoped lang="scss">
|
|
349
|
+
.dl-monaco-editor-wrapper {
|
|
350
|
+
width: var(--dl-monaco-editor-width, 100%);
|
|
351
|
+
min-width: 200px;
|
|
352
|
+
height: var(--dl-monaco-editor-height, 100%);
|
|
353
|
+
display: flex;
|
|
354
|
+
flex-direction: column;
|
|
355
|
+
background: var(--dl-color-bg);
|
|
356
|
+
overflow: hidden;
|
|
357
|
+
box-sizing: border-box;
|
|
358
|
+
|
|
359
|
+
&--bordered {
|
|
360
|
+
border: 1px solid var(--dl-color-separator);
|
|
361
|
+
border-radius: 2px;
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
&--dark {
|
|
365
|
+
background: #1e1e1e;
|
|
366
|
+
|
|
367
|
+
.dl-monaco-editor__header {
|
|
368
|
+
background: #252526;
|
|
369
|
+
border-bottom-color: #3c3c3c;
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
.dl-monaco-editor__language,
|
|
373
|
+
.dl-monaco-editor__title {
|
|
374
|
+
color: #cccccc;
|
|
375
|
+
}
|
|
376
|
+
}
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
.dl-monaco-editor {
|
|
380
|
+
&__header {
|
|
381
|
+
display: flex;
|
|
382
|
+
align-items: center;
|
|
383
|
+
justify-content: space-between;
|
|
384
|
+
padding: 6px 12px;
|
|
385
|
+
background: var(--dl-color-panel-background);
|
|
386
|
+
border-bottom: 1px solid var(--dl-color-separator);
|
|
387
|
+
min-height: 34px;
|
|
388
|
+
box-sizing: border-box;
|
|
389
|
+
flex-shrink: 0;
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
&__header-left {
|
|
393
|
+
display: flex;
|
|
394
|
+
align-items: center;
|
|
395
|
+
gap: 12px;
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
&__header-right {
|
|
399
|
+
display: flex;
|
|
400
|
+
align-items: center;
|
|
401
|
+
gap: 4px;
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
&__language {
|
|
405
|
+
font-size: 12px;
|
|
406
|
+
font-weight: 500;
|
|
407
|
+
color: var(--dl-color-darker);
|
|
408
|
+
text-transform: uppercase;
|
|
409
|
+
letter-spacing: 0.5px;
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
&__title {
|
|
413
|
+
font-size: 12px;
|
|
414
|
+
color: var(--dl-color-medium);
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
&__container {
|
|
418
|
+
flex: 1 1 auto;
|
|
419
|
+
min-height: 100px;
|
|
420
|
+
min-width: 0;
|
|
421
|
+
overflow: hidden;
|
|
422
|
+
}
|
|
423
|
+
}
|
|
424
|
+
</style>
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Theme options for DlMonacoEditor
|
|
3
|
+
* Maps the existing DlCodeEditorTheme values to Monaco themes
|
|
4
|
+
*/
|
|
5
|
+
export enum DlMonacoEditorTheme {
|
|
6
|
+
// Same as DlCodeEditorTheme for compatibility
|
|
7
|
+
Dark = 'atom-one-dark',
|
|
8
|
+
Light = 'atom-one-light',
|
|
9
|
+
ATOM_ONE_DARK = 'atom-one-dark',
|
|
10
|
+
ATOM_ONE_LIGHT = 'atom-one-light',
|
|
11
|
+
DRACULA = 'dracula',
|
|
12
|
+
GITHUB = 'github',
|
|
13
|
+
GITHUB_DARK = 'github-dark',
|
|
14
|
+
VS = 'vs',
|
|
15
|
+
VS_DARK = 'vs2015'
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Options for DlMonacoEditor
|
|
20
|
+
* Same interface as DlCodeEditorOptions for compatibility
|
|
21
|
+
*/
|
|
22
|
+
export interface DlMonacoEditorOptions {
|
|
23
|
+
/** Font size in pixels */
|
|
24
|
+
fontSize?: number
|
|
25
|
+
/** Tab size in spaces */
|
|
26
|
+
tabSpaces?: number
|
|
27
|
+
/** Enable text wrapping */
|
|
28
|
+
textWrapping?: boolean
|
|
29
|
+
/** Hide the header bar */
|
|
30
|
+
hideHeader?: boolean
|
|
31
|
+
/** Hide the copy button */
|
|
32
|
+
hideCopyButton?: boolean
|
|
33
|
+
/** Show line numbers */
|
|
34
|
+
lineNumbers?: boolean
|
|
35
|
+
/** Hide language display */
|
|
36
|
+
hideLanguage?: boolean
|
|
37
|
+
/** Enable minimap (Monaco specific) */
|
|
38
|
+
minimap?: boolean
|
|
39
|
+
/** Enable autocomplete (Monaco specific) */
|
|
40
|
+
autoComplete?: boolean
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Map theme names to Monaco editor themes
|
|
45
|
+
*/
|
|
46
|
+
export function getMonacoTheme(theme: string): 'vs' | 'vs-dark' | 'hc-black' {
|
|
47
|
+
switch (theme) {
|
|
48
|
+
case 'atom-one-dark':
|
|
49
|
+
case 'dracula':
|
|
50
|
+
case 'github-dark':
|
|
51
|
+
case 'vs2015':
|
|
52
|
+
return 'vs-dark'
|
|
53
|
+
case 'atom-one-light':
|
|
54
|
+
case 'github':
|
|
55
|
+
case 'vs':
|
|
56
|
+
default:
|
|
57
|
+
return 'vs'
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Get display title for language
|
|
63
|
+
*/
|
|
64
|
+
export function getLanguageTitle(language: string): string {
|
|
65
|
+
const titles: Record<string, string> = {
|
|
66
|
+
javascript: 'JavaScript',
|
|
67
|
+
typescript: 'TypeScript',
|
|
68
|
+
python: 'Python',
|
|
69
|
+
py: 'Python',
|
|
70
|
+
js: 'JavaScript',
|
|
71
|
+
ts: 'TypeScript',
|
|
72
|
+
html: 'HTML',
|
|
73
|
+
css: 'CSS',
|
|
74
|
+
scss: 'SCSS',
|
|
75
|
+
json: 'JSON',
|
|
76
|
+
yaml: 'YAML',
|
|
77
|
+
markdown: 'Markdown',
|
|
78
|
+
md: 'Markdown',
|
|
79
|
+
sql: 'SQL',
|
|
80
|
+
shell: 'Shell',
|
|
81
|
+
bash: 'Bash',
|
|
82
|
+
java: 'Java',
|
|
83
|
+
csharp: 'C#',
|
|
84
|
+
cpp: 'C++',
|
|
85
|
+
c: 'C',
|
|
86
|
+
go: 'Go',
|
|
87
|
+
rust: 'Rust',
|
|
88
|
+
php: 'PHP',
|
|
89
|
+
ruby: 'Ruby',
|
|
90
|
+
swift: 'Swift',
|
|
91
|
+
kotlin: 'Kotlin',
|
|
92
|
+
xml: 'XML',
|
|
93
|
+
vue: 'Vue'
|
|
94
|
+
}
|
|
95
|
+
return (
|
|
96
|
+
titles[language.toLowerCase()] ||
|
|
97
|
+
language.charAt(0).toUpperCase() + language.slice(1)
|
|
98
|
+
)
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
/**
|
|
102
|
+
* Normalize language name to Monaco language ID
|
|
103
|
+
*/
|
|
104
|
+
export function normalizeLanguage(language: string): string {
|
|
105
|
+
const languageMap: Record<string, string> = {
|
|
106
|
+
js: 'javascript',
|
|
107
|
+
ts: 'typescript',
|
|
108
|
+
py: 'python',
|
|
109
|
+
md: 'markdown',
|
|
110
|
+
yml: 'yaml',
|
|
111
|
+
sh: 'shell',
|
|
112
|
+
bash: 'shell',
|
|
113
|
+
zsh: 'shell'
|
|
114
|
+
}
|
|
115
|
+
return languageMap[language.toLowerCase()] || language.toLowerCase()
|
|
116
|
+
}
|
|
@@ -0,0 +1,238 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div class="monaco-editor-demo">
|
|
3
|
+
<h2>DlMonacoEditor Demo</h2>
|
|
4
|
+
<p class="demo-description">
|
|
5
|
+
Drop-in replacement for DlCodeEditor with Monaco Editor (VS Code's
|
|
6
|
+
editor)
|
|
7
|
+
</p>
|
|
8
|
+
|
|
9
|
+
<!-- Controls -->
|
|
10
|
+
<div class="controls">
|
|
11
|
+
<dl-select
|
|
12
|
+
v-model="selectedLanguage"
|
|
13
|
+
:options="languageOptions"
|
|
14
|
+
label="Language"
|
|
15
|
+
width="150px"
|
|
16
|
+
/>
|
|
17
|
+
<dl-select
|
|
18
|
+
v-model="selectedTheme"
|
|
19
|
+
:options="themeOptions"
|
|
20
|
+
label="Theme"
|
|
21
|
+
width="150px"
|
|
22
|
+
/>
|
|
23
|
+
<dl-checkbox v-model="showLineNumbers" label="Line Numbers" />
|
|
24
|
+
<dl-checkbox v-model="showMinimap" label="Minimap" />
|
|
25
|
+
<dl-checkbox v-model="readonly" label="Readonly" />
|
|
26
|
+
<dl-checkbox v-model="bordered" label="Bordered" />
|
|
27
|
+
</div>
|
|
28
|
+
|
|
29
|
+
<!-- Monaco Editor -->
|
|
30
|
+
<div class="editor-container">
|
|
31
|
+
<dl-monaco-editor
|
|
32
|
+
v-model="code"
|
|
33
|
+
:language="selectedLanguage.value"
|
|
34
|
+
:theme="selectedTheme.value"
|
|
35
|
+
:readonly="readonly"
|
|
36
|
+
:bordered="bordered"
|
|
37
|
+
:options="editorOptions"
|
|
38
|
+
width="100%"
|
|
39
|
+
height="400px"
|
|
40
|
+
@change="onCodeChange"
|
|
41
|
+
@save="onSave"
|
|
42
|
+
/>
|
|
43
|
+
</div>
|
|
44
|
+
|
|
45
|
+
<!-- Comparison with DlCodeEditor -->
|
|
46
|
+
<div class="comparison">
|
|
47
|
+
<h3>Same API as DlCodeEditor</h3>
|
|
48
|
+
<p>
|
|
49
|
+
Just replace <code>dl-code-editor</code> with
|
|
50
|
+
<code>dl-monaco-editor</code>:
|
|
51
|
+
</p>
|
|
52
|
+
<pre class="code-example">{{ usageExample }}</pre>
|
|
53
|
+
</div>
|
|
54
|
+
</div>
|
|
55
|
+
</template>
|
|
56
|
+
|
|
57
|
+
<script lang="ts">
|
|
58
|
+
import { defineComponent, ref, computed } from 'vue-demi'
|
|
59
|
+
import {
|
|
60
|
+
DlMonacoEditor,
|
|
61
|
+
DlMonacoEditorTheme
|
|
62
|
+
} from '../components/compound/DlMonacoEditor'
|
|
63
|
+
import { DlSelect } from '../components/compound/DlSelect'
|
|
64
|
+
import { DlCheckbox } from '../components/essential'
|
|
65
|
+
|
|
66
|
+
export default defineComponent({
|
|
67
|
+
name: 'DlMonacoEditorDemo',
|
|
68
|
+
components: {
|
|
69
|
+
DlMonacoEditor,
|
|
70
|
+
DlSelect,
|
|
71
|
+
DlCheckbox
|
|
72
|
+
},
|
|
73
|
+
setup() {
|
|
74
|
+
const code = ref(`// Welcome to DlMonacoEditor!
|
|
75
|
+
// A drop-in replacement for DlCodeEditor with Monaco (VS Code's editor)
|
|
76
|
+
|
|
77
|
+
function greet(name: string): string {
|
|
78
|
+
return \`Hello, \${name}!\`;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
const result = greet('World');
|
|
82
|
+
console.log(result);
|
|
83
|
+
|
|
84
|
+
// Features:
|
|
85
|
+
// - Full IntelliSense
|
|
86
|
+
// - Syntax highlighting for 50+ languages
|
|
87
|
+
// - Code folding
|
|
88
|
+
// - Find and replace
|
|
89
|
+
// - Minimap
|
|
90
|
+
// - And much more!
|
|
91
|
+
`)
|
|
92
|
+
|
|
93
|
+
const languageOptions = [
|
|
94
|
+
{ label: 'JavaScript', value: 'javascript' },
|
|
95
|
+
{ label: 'TypeScript', value: 'typescript' },
|
|
96
|
+
{ label: 'Python', value: 'python' },
|
|
97
|
+
{ label: 'HTML', value: 'html' },
|
|
98
|
+
{ label: 'CSS', value: 'css' },
|
|
99
|
+
{ label: 'JSON', value: 'json' },
|
|
100
|
+
{ label: 'Markdown', value: 'markdown' },
|
|
101
|
+
{ label: 'SQL', value: 'sql' },
|
|
102
|
+
{ label: 'YAML', value: 'yaml' },
|
|
103
|
+
{ label: 'Shell', value: 'shell' }
|
|
104
|
+
]
|
|
105
|
+
const selectedLanguage = ref(languageOptions[1])
|
|
106
|
+
|
|
107
|
+
const themeOptions = [
|
|
108
|
+
{ label: 'Light', value: DlMonacoEditorTheme.Light },
|
|
109
|
+
{ label: 'Dark', value: DlMonacoEditorTheme.Dark },
|
|
110
|
+
{ label: 'VS', value: DlMonacoEditorTheme.VS },
|
|
111
|
+
{ label: 'VS Dark', value: DlMonacoEditorTheme.VS_DARK },
|
|
112
|
+
{ label: 'GitHub', value: DlMonacoEditorTheme.GITHUB },
|
|
113
|
+
{ label: 'GitHub Dark', value: DlMonacoEditorTheme.GITHUB_DARK },
|
|
114
|
+
{ label: 'Dracula', value: DlMonacoEditorTheme.DRACULA }
|
|
115
|
+
]
|
|
116
|
+
const selectedTheme = ref(themeOptions[1])
|
|
117
|
+
|
|
118
|
+
const showLineNumbers = ref(true)
|
|
119
|
+
const showMinimap = ref(true)
|
|
120
|
+
const readonly = ref(false)
|
|
121
|
+
const bordered = ref(true)
|
|
122
|
+
|
|
123
|
+
const editorOptions = computed(() => ({
|
|
124
|
+
lineNumbers: showLineNumbers.value,
|
|
125
|
+
minimap: showMinimap.value,
|
|
126
|
+
fontSize: 14,
|
|
127
|
+
tabSpaces: 4
|
|
128
|
+
}))
|
|
129
|
+
|
|
130
|
+
const onCodeChange = (newCode: string) => {
|
|
131
|
+
console.log('Code changed, length:', newCode.length)
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
const onSave = (content: string) => {
|
|
135
|
+
console.log('Save triggered (Ctrl+S)')
|
|
136
|
+
alert('Save triggered! Check console for content.')
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
const usageExample = `<!-- Before (DlCodeEditor) -->
|
|
140
|
+
<dl-code-editor
|
|
141
|
+
v-model="code"
|
|
142
|
+
language="typescript"
|
|
143
|
+
theme="atom-one-dark"
|
|
144
|
+
:options="{ lineNumbers: true }"
|
|
145
|
+
/>
|
|
146
|
+
|
|
147
|
+
<!-- After (DlMonacoEditor) - Same API! -->
|
|
148
|
+
<dl-monaco-editor
|
|
149
|
+
v-model="code"
|
|
150
|
+
language="typescript"
|
|
151
|
+
theme="atom-one-dark"
|
|
152
|
+
:options="{ lineNumbers: true }"
|
|
153
|
+
/>`
|
|
154
|
+
|
|
155
|
+
return {
|
|
156
|
+
code,
|
|
157
|
+
languageOptions,
|
|
158
|
+
selectedLanguage,
|
|
159
|
+
themeOptions,
|
|
160
|
+
selectedTheme,
|
|
161
|
+
showLineNumbers,
|
|
162
|
+
showMinimap,
|
|
163
|
+
readonly,
|
|
164
|
+
bordered,
|
|
165
|
+
editorOptions,
|
|
166
|
+
onCodeChange,
|
|
167
|
+
onSave,
|
|
168
|
+
usageExample
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
})
|
|
172
|
+
</script>
|
|
173
|
+
|
|
174
|
+
<style scoped lang="scss">
|
|
175
|
+
.monaco-editor-demo {
|
|
176
|
+
padding: 20px;
|
|
177
|
+
max-width: 1200px;
|
|
178
|
+
margin: 0 auto;
|
|
179
|
+
|
|
180
|
+
h2 {
|
|
181
|
+
margin-bottom: 8px;
|
|
182
|
+
color: var(--dl-color-darker);
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
.demo-description {
|
|
186
|
+
color: var(--dl-color-medium);
|
|
187
|
+
margin-bottom: 20px;
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
.controls {
|
|
191
|
+
display: flex;
|
|
192
|
+
gap: 20px;
|
|
193
|
+
margin-bottom: 20px;
|
|
194
|
+
align-items: center;
|
|
195
|
+
flex-wrap: wrap;
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
.editor-container {
|
|
199
|
+
margin-bottom: 30px;
|
|
200
|
+
width: 100%;
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
.comparison {
|
|
204
|
+
background: var(--dl-color-bg);
|
|
205
|
+
padding: 20px;
|
|
206
|
+
border-radius: 4px;
|
|
207
|
+
border: 1px solid var(--dl-color-separator);
|
|
208
|
+
|
|
209
|
+
h3 {
|
|
210
|
+
margin: 0 0 12px 0;
|
|
211
|
+
color: var(--dl-color-darker);
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
p {
|
|
215
|
+
margin: 0 0 12px 0;
|
|
216
|
+
color: var(--dl-color-medium);
|
|
217
|
+
|
|
218
|
+
code {
|
|
219
|
+
background: var(--dl-color-panel-background);
|
|
220
|
+
padding: 2px 6px;
|
|
221
|
+
border-radius: 3px;
|
|
222
|
+
font-family: monospace;
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
.code-example {
|
|
227
|
+
background: #1e1e1e;
|
|
228
|
+
color: #d4d4d4;
|
|
229
|
+
padding: 16px;
|
|
230
|
+
border-radius: 4px;
|
|
231
|
+
overflow-x: auto;
|
|
232
|
+
font-size: 13px;
|
|
233
|
+
line-height: 1.5;
|
|
234
|
+
margin: 0;
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
</style>
|
package/src/demos/index.ts
CHANGED
|
@@ -71,6 +71,7 @@ import DlLabelPickerDemo from './DlLabelPickerDemo.vue'
|
|
|
71
71
|
import DlInfiniteScrollDemo from './DlInfiniteScrollDemo.vue'
|
|
72
72
|
import DlMarkdownDemo from './DlMarkdownDemo.vue'
|
|
73
73
|
import DlTextInputDemo from './DlTextInputDemo.vue'
|
|
74
|
+
import DlMonacoEditorDemo from './DlMonacoEditorDemo.vue'
|
|
74
75
|
|
|
75
76
|
export default {
|
|
76
77
|
AvatarDemo,
|
|
@@ -142,5 +143,6 @@ export default {
|
|
|
142
143
|
DlLabelPickerDemo,
|
|
143
144
|
DlInfiniteScrollDemo,
|
|
144
145
|
DlMarkdownDemo,
|
|
145
|
-
DlTextInputDemo
|
|
146
|
+
DlTextInputDemo,
|
|
147
|
+
DlMonacoEditorDemo
|
|
146
148
|
}
|