722 lines
23 KiB
TypeScript
722 lines
23 KiB
TypeScript
import { DeesInputBase } from '../dees-input-base/dees-input-base.js';
|
|
import {
|
|
customElement,
|
|
type TemplateResult,
|
|
property,
|
|
html,
|
|
cssManager,
|
|
css,
|
|
state,
|
|
} from '@design.estate/dees-element';
|
|
import { themeDefaultStyles } from '../../00theme.js';
|
|
import { DeesModal } from '../../dees-modal/dees-modal.js';
|
|
import '../../dees-icon/dees-icon.js';
|
|
import '../../dees-label/dees-label.js';
|
|
import '../../00group-workspace/dees-workspace-monaco/dees-workspace-monaco.js';
|
|
import { DeesWorkspaceMonaco } from '../../00group-workspace/dees-workspace-monaco/dees-workspace-monaco.js';
|
|
|
|
declare global {
|
|
interface HTMLElementTagNameMap {
|
|
'dees-input-code': DeesInputCode;
|
|
}
|
|
}
|
|
|
|
// Common programming languages for the language selector
|
|
const LANGUAGES = [
|
|
{ key: 'typescript', label: 'TypeScript' },
|
|
{ key: 'javascript', label: 'JavaScript' },
|
|
{ key: 'json', label: 'JSON' },
|
|
{ key: 'html', label: 'HTML' },
|
|
{ key: 'css', label: 'CSS' },
|
|
{ key: 'scss', label: 'SCSS' },
|
|
{ key: 'markdown', label: 'Markdown' },
|
|
{ key: 'yaml', label: 'YAML' },
|
|
{ key: 'xml', label: 'XML' },
|
|
{ key: 'sql', label: 'SQL' },
|
|
{ key: 'python', label: 'Python' },
|
|
{ key: 'java', label: 'Java' },
|
|
{ key: 'csharp', label: 'C#' },
|
|
{ key: 'cpp', label: 'C++' },
|
|
{ key: 'go', label: 'Go' },
|
|
{ key: 'rust', label: 'Rust' },
|
|
{ key: 'shell', label: 'Shell' },
|
|
{ key: 'plaintext', label: 'Plain Text' },
|
|
];
|
|
|
|
@customElement('dees-input-code')
|
|
export class DeesInputCode extends DeesInputBase<string> {
|
|
public static demo = () => html`
|
|
<dees-input-code
|
|
label="TypeScript Code"
|
|
key="code"
|
|
language="typescript"
|
|
height="300px"
|
|
.value=${'const greeting: string = "Hello World";\nconsole.log(greeting);'}
|
|
></dees-input-code>
|
|
`;
|
|
public static demoGroup = 'Input';
|
|
|
|
// INSTANCE
|
|
@property({ type: String })
|
|
accessor value: string = '';
|
|
|
|
@property({ type: String })
|
|
accessor language: string = 'typescript';
|
|
|
|
@property({ type: String })
|
|
accessor height: string = '200px';
|
|
|
|
@property({ type: String })
|
|
accessor wordWrap: 'on' | 'off' = 'off';
|
|
|
|
@property({ type: Boolean })
|
|
accessor showLineNumbers: boolean = true;
|
|
|
|
@state()
|
|
accessor isLanguageDropdownOpen: boolean = false;
|
|
|
|
@state()
|
|
accessor copySuccess: boolean = false;
|
|
|
|
private editorElement: DeesWorkspaceMonaco | null = null;
|
|
|
|
public static styles = [
|
|
themeDefaultStyles,
|
|
...DeesInputBase.baseStyles,
|
|
cssManager.defaultStyles,
|
|
css`
|
|
* {
|
|
box-sizing: border-box;
|
|
}
|
|
|
|
:host {
|
|
display: block;
|
|
}
|
|
|
|
.code-container {
|
|
border: 1px solid ${cssManager.bdTheme('hsl(0 0% 89.8%)', 'hsl(0 0% 14.9%)')};
|
|
border-radius: 6px;
|
|
overflow: hidden;
|
|
background: ${cssManager.bdTheme('hsl(0 0% 100%)', 'hsl(0 0% 9%)')};
|
|
}
|
|
|
|
.toolbar {
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: space-between;
|
|
padding: 8px 12px;
|
|
background: ${cssManager.bdTheme('hsl(0 0% 97%)', 'hsl(0 0% 7%)')};
|
|
border-bottom: 1px solid ${cssManager.bdTheme('hsl(0 0% 89.8%)', 'hsl(0 0% 14.9%)')};
|
|
gap: 8px;
|
|
}
|
|
|
|
.toolbar-left {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 8px;
|
|
}
|
|
|
|
.toolbar-right {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 4px;
|
|
}
|
|
|
|
.language-selector {
|
|
position: relative;
|
|
}
|
|
|
|
.language-button {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 6px;
|
|
padding: 4px 10px;
|
|
font-size: 12px;
|
|
font-weight: 500;
|
|
background: ${cssManager.bdTheme('hsl(0 0% 100%)', 'hsl(0 0% 12%)')};
|
|
border: 1px solid ${cssManager.bdTheme('hsl(0 0% 89.8%)', 'hsl(0 0% 20%)')};
|
|
border-radius: 4px;
|
|
cursor: pointer;
|
|
color: ${cssManager.bdTheme('hsl(0 0% 20%)', 'hsl(0 0% 90%)')};
|
|
transition: all 0.15s ease;
|
|
}
|
|
|
|
.language-button:hover {
|
|
background: ${cssManager.bdTheme('hsl(0 0% 95%)', 'hsl(0 0% 15%)')};
|
|
}
|
|
|
|
.language-dropdown {
|
|
position: absolute;
|
|
top: 100%;
|
|
left: 0;
|
|
margin-top: 4px;
|
|
background: ${cssManager.bdTheme('hsl(0 0% 100%)', 'hsl(0 0% 9%)')};
|
|
border: 1px solid ${cssManager.bdTheme('hsl(0 0% 89.8%)', 'hsl(0 0% 20%)')};
|
|
border-radius: 6px;
|
|
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
|
|
z-index: 100;
|
|
max-height: 250px;
|
|
overflow-y: auto;
|
|
min-width: 140px;
|
|
}
|
|
|
|
.language-option {
|
|
padding: 8px 12px;
|
|
font-size: 12px;
|
|
cursor: pointer;
|
|
color: ${cssManager.bdTheme('hsl(0 0% 20%)', 'hsl(0 0% 90%)')};
|
|
transition: background 0.15s ease;
|
|
}
|
|
|
|
.language-option:hover {
|
|
background: ${cssManager.bdTheme('hsl(0 0% 95%)', 'hsl(0 0% 15%)')};
|
|
}
|
|
|
|
.language-option.selected {
|
|
background: ${cssManager.bdTheme('hsl(0 0% 90%)', 'hsl(0 0% 20%)')};
|
|
}
|
|
|
|
.toolbar-button {
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
width: 32px;
|
|
height: 32px;
|
|
background: transparent;
|
|
border: none;
|
|
border-radius: 4px;
|
|
cursor: pointer;
|
|
color: ${cssManager.bdTheme('hsl(0 0% 45%)', 'hsl(0 0% 60%)')};
|
|
transition: all 0.15s ease;
|
|
}
|
|
|
|
.toolbar-button:hover {
|
|
background: ${cssManager.bdTheme('hsl(0 0% 90%)', 'hsl(0 0% 15%)')};
|
|
color: ${cssManager.bdTheme('hsl(0 0% 20%)', 'hsl(0 0% 90%)')};
|
|
}
|
|
|
|
.toolbar-button.active {
|
|
background: ${cssManager.bdTheme('hsl(0 0% 85%)', 'hsl(0 0% 20%)')};
|
|
color: ${cssManager.bdTheme('hsl(0 0% 20%)', 'hsl(0 0% 90%)')};
|
|
}
|
|
|
|
.toolbar-button.success {
|
|
color: hsl(142.1 76.2% 36.3%);
|
|
}
|
|
|
|
.editor-wrapper {
|
|
position: relative;
|
|
}
|
|
|
|
dees-workspace-monaco {
|
|
display: block;
|
|
}
|
|
|
|
.toolbar-divider {
|
|
width: 1px;
|
|
height: 20px;
|
|
background: ${cssManager.bdTheme('hsl(0 0% 85%)', 'hsl(0 0% 20%)')};
|
|
margin: 0 4px;
|
|
}
|
|
|
|
:host([disabled]) .code-container {
|
|
opacity: 0.5;
|
|
pointer-events: none;
|
|
}
|
|
`,
|
|
];
|
|
|
|
public render(): TemplateResult {
|
|
const currentLanguage = LANGUAGES.find(l => l.key === this.language) || LANGUAGES[0];
|
|
|
|
return html`
|
|
<style>
|
|
.editor-wrapper {
|
|
height: ${this.height};
|
|
}
|
|
</style>
|
|
<div class="input-wrapper">
|
|
<dees-label .label=${this.label} .description=${this.description} .required=${this.required}></dees-label>
|
|
<div class="code-container">
|
|
<div class="toolbar">
|
|
<div class="toolbar-left">
|
|
<div class="language-selector">
|
|
<button
|
|
class="language-button"
|
|
@click=${this.toggleLanguageDropdown}
|
|
@blur=${this.handleLanguageBlur}
|
|
>
|
|
${currentLanguage.label}
|
|
<dees-icon .icon=${'lucide:ChevronDown'} iconSize="14"></dees-icon>
|
|
</button>
|
|
${this.isLanguageDropdownOpen ? html`
|
|
<div class="language-dropdown">
|
|
${LANGUAGES.map(lang => html`
|
|
<div
|
|
class="language-option ${lang.key === this.language ? 'selected' : ''}"
|
|
@mousedown=${(e: Event) => this.selectLanguage(e, lang.key)}
|
|
>
|
|
${lang.label}
|
|
</div>
|
|
`)}
|
|
</div>
|
|
` : ''}
|
|
</div>
|
|
</div>
|
|
<div class="toolbar-right">
|
|
<button
|
|
class="toolbar-button ${this.wordWrap === 'on' ? 'active' : ''}"
|
|
title="Word Wrap"
|
|
@click=${this.toggleWordWrap}
|
|
>
|
|
<dees-icon .icon=${'lucide:WrapText'} iconSize="16"></dees-icon>
|
|
</button>
|
|
<button
|
|
class="toolbar-button ${this.showLineNumbers ? 'active' : ''}"
|
|
title="Line Numbers"
|
|
@click=${this.toggleLineNumbers}
|
|
>
|
|
<dees-icon .icon=${'lucide:Hash'} iconSize="16"></dees-icon>
|
|
</button>
|
|
<div class="toolbar-divider"></div>
|
|
<button
|
|
class="toolbar-button ${this.copySuccess ? 'success' : ''}"
|
|
title="Copy Code"
|
|
@click=${this.copyCode}
|
|
>
|
|
<dees-icon .icon=${this.copySuccess ? 'lucide:Check' : 'lucide:Copy'} iconSize="16"></dees-icon>
|
|
</button>
|
|
<button
|
|
class="toolbar-button"
|
|
title="Expand"
|
|
@click=${this.openFullscreen}
|
|
>
|
|
<dees-icon .icon=${'lucide:Maximize2'} iconSize="16"></dees-icon>
|
|
</button>
|
|
</div>
|
|
</div>
|
|
<div class="editor-wrapper">
|
|
<dees-workspace-monaco
|
|
.content=${this.value}
|
|
.language=${this.language}
|
|
.wordWrap=${this.wordWrap}
|
|
@content-change=${this.handleContentChange}
|
|
></dees-workspace-monaco>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
`;
|
|
}
|
|
|
|
async firstUpdated() {
|
|
this.editorElement = this.shadowRoot?.querySelector('dees-workspace-monaco') as DeesWorkspaceMonaco;
|
|
if (this.editorElement) {
|
|
// Subscribe to content changes from the editor
|
|
this.editorElement.contentSubject.subscribe((newContent: string) => {
|
|
if (this.value !== newContent) {
|
|
this.value = newContent;
|
|
this.changeSubject.next(this as any);
|
|
}
|
|
});
|
|
}
|
|
}
|
|
|
|
private toggleLanguageDropdown() {
|
|
this.isLanguageDropdownOpen = !this.isLanguageDropdownOpen;
|
|
}
|
|
|
|
private handleLanguageBlur() {
|
|
// Small delay to allow click events on dropdown items
|
|
setTimeout(() => {
|
|
this.isLanguageDropdownOpen = false;
|
|
}, 150);
|
|
}
|
|
|
|
private async selectLanguage(e: Event, languageKey: string) {
|
|
e.preventDefault();
|
|
this.language = languageKey;
|
|
this.isLanguageDropdownOpen = false;
|
|
|
|
// Update the editor language
|
|
if (this.editorElement) {
|
|
this.editorElement.language = languageKey;
|
|
const editor = await this.editorElement.editorDeferred.promise;
|
|
const model = editor.getModel();
|
|
if (model) {
|
|
(window as any).monaco.editor.setModelLanguage(model, languageKey);
|
|
}
|
|
}
|
|
}
|
|
|
|
private toggleWordWrap() {
|
|
this.wordWrap = this.wordWrap === 'on' ? 'off' : 'on';
|
|
this.updateEditorOption('wordWrap', this.wordWrap);
|
|
}
|
|
|
|
private toggleLineNumbers() {
|
|
this.showLineNumbers = !this.showLineNumbers;
|
|
this.updateEditorOption('lineNumbers', this.showLineNumbers ? 'on' : 'off');
|
|
}
|
|
|
|
private async updateEditorOption(option: string, value: any) {
|
|
if (this.editorElement) {
|
|
const editor = await this.editorElement.editorDeferred.promise;
|
|
editor.updateOptions({ [option]: value });
|
|
}
|
|
}
|
|
|
|
private async copyCode() {
|
|
try {
|
|
await navigator.clipboard.writeText(this.value);
|
|
this.copySuccess = true;
|
|
setTimeout(() => {
|
|
this.copySuccess = false;
|
|
}, 2000);
|
|
} catch (err) {
|
|
console.error('Failed to copy code:', err);
|
|
}
|
|
}
|
|
|
|
private handleContentChange(e: CustomEvent) {
|
|
const newContent = e.detail;
|
|
if (this.value !== newContent) {
|
|
this.value = newContent;
|
|
this.changeSubject.next(this as any);
|
|
}
|
|
}
|
|
|
|
public async openFullscreen() {
|
|
const currentValue = this.value;
|
|
let modalEditorElement: DeesWorkspaceMonaco | null = null;
|
|
|
|
// Modal-specific state
|
|
let modalLanguage = this.language;
|
|
let modalWordWrap = this.wordWrap;
|
|
let modalShowLineNumbers = this.showLineNumbers;
|
|
let modalLanguageDropdownOpen = false;
|
|
let modalCopySuccess = false;
|
|
|
|
// Helper to get current language label
|
|
const getLanguageLabel = () => {
|
|
const lang = LANGUAGES.find(l => l.key === modalLanguage);
|
|
return lang ? lang.label : 'TypeScript';
|
|
};
|
|
|
|
// Helper to update toolbar UI
|
|
const updateToolbarUI = (modal: DeesModal) => {
|
|
const toolbar = modal.shadowRoot?.querySelector('.modal-toolbar');
|
|
if (!toolbar) return;
|
|
|
|
// Update language button text
|
|
const langBtn = toolbar.querySelector('.language-button span');
|
|
if (langBtn) langBtn.textContent = getLanguageLabel();
|
|
|
|
// Update word wrap button
|
|
const wrapBtn = toolbar.querySelector('.wrap-btn') as HTMLElement;
|
|
if (wrapBtn) {
|
|
wrapBtn.classList.toggle('active', modalWordWrap === 'on');
|
|
}
|
|
|
|
// Update line numbers button
|
|
const linesBtn = toolbar.querySelector('.lines-btn') as HTMLElement;
|
|
if (linesBtn) {
|
|
linesBtn.classList.toggle('active', modalShowLineNumbers);
|
|
}
|
|
|
|
// Update copy button
|
|
const copyBtn = toolbar.querySelector('.copy-btn') as HTMLElement;
|
|
const copyIcon = copyBtn?.querySelector('dees-icon') as any;
|
|
if (copyBtn && copyIcon) {
|
|
copyBtn.classList.toggle('success', modalCopySuccess);
|
|
copyIcon.icon = modalCopySuccess ? 'lucide:Check' : 'lucide:Copy';
|
|
}
|
|
|
|
// Update dropdown visibility
|
|
const dropdown = toolbar.querySelector('.language-dropdown') as HTMLElement;
|
|
if (dropdown) {
|
|
dropdown.style.display = modalLanguageDropdownOpen ? 'block' : 'none';
|
|
}
|
|
};
|
|
|
|
const modal = await DeesModal.createAndShow({
|
|
heading: this.label || 'Code Editor',
|
|
width: 'fullscreen',
|
|
contentPadding: 0,
|
|
content: html`
|
|
<style>
|
|
.modal-toolbar {
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: space-between;
|
|
padding: 8px 12px;
|
|
background: ${cssManager.bdTheme('hsl(0 0% 97%)', 'hsl(0 0% 7%)')};
|
|
border-bottom: 1px solid ${cssManager.bdTheme('hsl(0 0% 89.8%)', 'hsl(0 0% 14.9%)')};
|
|
gap: 8px;
|
|
}
|
|
.modal-toolbar .toolbar-left {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 8px;
|
|
}
|
|
.modal-toolbar .toolbar-right {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 4px;
|
|
}
|
|
.modal-toolbar .language-selector {
|
|
position: relative;
|
|
}
|
|
.modal-toolbar .language-button {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 6px;
|
|
padding: 4px 10px;
|
|
font-size: 12px;
|
|
font-weight: 500;
|
|
background: ${cssManager.bdTheme('hsl(0 0% 100%)', 'hsl(0 0% 12%)')};
|
|
border: 1px solid ${cssManager.bdTheme('hsl(0 0% 89.8%)', 'hsl(0 0% 20%)')};
|
|
border-radius: 4px;
|
|
cursor: pointer;
|
|
color: ${cssManager.bdTheme('hsl(0 0% 20%)', 'hsl(0 0% 90%)')};
|
|
transition: all 0.15s ease;
|
|
}
|
|
.modal-toolbar .language-button:hover {
|
|
background: ${cssManager.bdTheme('hsl(0 0% 95%)', 'hsl(0 0% 15%)')};
|
|
}
|
|
.modal-toolbar .language-dropdown {
|
|
position: absolute;
|
|
top: 100%;
|
|
left: 0;
|
|
margin-top: 4px;
|
|
background: ${cssManager.bdTheme('hsl(0 0% 100%)', 'hsl(0 0% 9%)')};
|
|
border: 1px solid ${cssManager.bdTheme('hsl(0 0% 89.8%)', 'hsl(0 0% 20%)')};
|
|
border-radius: 6px;
|
|
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
|
|
z-index: 100;
|
|
max-height: 250px;
|
|
overflow-y: auto;
|
|
min-width: 140px;
|
|
display: none;
|
|
}
|
|
.modal-toolbar .language-option {
|
|
padding: 8px 12px;
|
|
font-size: 12px;
|
|
cursor: pointer;
|
|
color: ${cssManager.bdTheme('hsl(0 0% 20%)', 'hsl(0 0% 90%)')};
|
|
transition: background 0.15s ease;
|
|
}
|
|
.modal-toolbar .language-option:hover {
|
|
background: ${cssManager.bdTheme('hsl(0 0% 95%)', 'hsl(0 0% 15%)')};
|
|
}
|
|
.modal-toolbar .language-option.selected {
|
|
background: ${cssManager.bdTheme('hsl(0 0% 90%)', 'hsl(0 0% 20%)')};
|
|
}
|
|
.modal-toolbar .toolbar-button {
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
width: 32px;
|
|
height: 32px;
|
|
background: transparent;
|
|
border: none;
|
|
border-radius: 4px;
|
|
cursor: pointer;
|
|
color: ${cssManager.bdTheme('hsl(0 0% 45%)', 'hsl(0 0% 60%)')};
|
|
transition: all 0.15s ease;
|
|
}
|
|
.modal-toolbar .toolbar-button:hover {
|
|
background: ${cssManager.bdTheme('hsl(0 0% 90%)', 'hsl(0 0% 15%)')};
|
|
color: ${cssManager.bdTheme('hsl(0 0% 20%)', 'hsl(0 0% 90%)')};
|
|
}
|
|
.modal-toolbar .toolbar-button.active {
|
|
background: ${cssManager.bdTheme('hsl(0 0% 85%)', 'hsl(0 0% 20%)')};
|
|
color: ${cssManager.bdTheme('hsl(0 0% 20%)', 'hsl(0 0% 90%)')};
|
|
}
|
|
.modal-toolbar .toolbar-button.success {
|
|
color: hsl(142.1 76.2% 36.3%);
|
|
}
|
|
.modal-toolbar .toolbar-divider {
|
|
width: 1px;
|
|
height: 20px;
|
|
background: ${cssManager.bdTheme('hsl(0 0% 85%)', 'hsl(0 0% 20%)')};
|
|
margin: 0 4px;
|
|
}
|
|
.modal-editor-wrapper {
|
|
position: relative;
|
|
height: calc(100vh - 175px);
|
|
width: 100%;
|
|
}
|
|
</style>
|
|
<div class="modal-toolbar">
|
|
<div class="toolbar-left">
|
|
<div class="language-selector">
|
|
<button class="language-button">
|
|
<span>${getLanguageLabel()}</span>
|
|
<dees-icon .icon=${'lucide:ChevronDown'} iconSize="14"></dees-icon>
|
|
</button>
|
|
<div class="language-dropdown">
|
|
${LANGUAGES.map(lang => html`
|
|
<div
|
|
class="language-option ${lang.key === modalLanguage ? 'selected' : ''}"
|
|
data-lang="${lang.key}"
|
|
>
|
|
${lang.label}
|
|
</div>
|
|
`)}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="toolbar-right">
|
|
<button class="toolbar-button wrap-btn ${modalWordWrap === 'on' ? 'active' : ''}" title="Word Wrap">
|
|
<dees-icon .icon=${'lucide:WrapText'} iconSize="16"></dees-icon>
|
|
</button>
|
|
<button class="toolbar-button lines-btn ${modalShowLineNumbers ? 'active' : ''}" title="Line Numbers">
|
|
<dees-icon .icon=${'lucide:Hash'} iconSize="16"></dees-icon>
|
|
</button>
|
|
<div class="toolbar-divider"></div>
|
|
<button class="toolbar-button copy-btn" title="Copy Code">
|
|
<dees-icon .icon=${'lucide:Copy'} iconSize="16"></dees-icon>
|
|
</button>
|
|
</div>
|
|
</div>
|
|
<div class="modal-editor-wrapper">
|
|
<dees-workspace-monaco
|
|
.content=${currentValue}
|
|
.language=${modalLanguage}
|
|
.wordWrap=${modalWordWrap}
|
|
></dees-workspace-monaco>
|
|
</div>
|
|
`,
|
|
menuOptions: [
|
|
{
|
|
name: 'Cancel',
|
|
action: async (modalRef) => {
|
|
await modalRef.destroy();
|
|
},
|
|
},
|
|
{
|
|
name: 'Save & Close',
|
|
action: async (modalRef) => {
|
|
// Get the editor content from the modal
|
|
modalEditorElement = modalRef.shadowRoot?.querySelector('dees-workspace-monaco') as DeesWorkspaceMonaco;
|
|
if (modalEditorElement) {
|
|
const editor = await modalEditorElement.editorDeferred.promise;
|
|
const newValue = editor.getValue();
|
|
this.setValue(newValue);
|
|
}
|
|
await modalRef.destroy();
|
|
},
|
|
},
|
|
],
|
|
});
|
|
|
|
// Wait for modal to render
|
|
await new Promise(resolve => setTimeout(resolve, 100));
|
|
modalEditorElement = modal.shadowRoot?.querySelector('dees-workspace-monaco') as DeesWorkspaceMonaco;
|
|
|
|
// Wire up toolbar event handlers
|
|
const toolbar = modal.shadowRoot?.querySelector('.modal-toolbar');
|
|
if (toolbar) {
|
|
// Language button click
|
|
const langBtn = toolbar.querySelector('.language-button');
|
|
langBtn?.addEventListener('click', () => {
|
|
modalLanguageDropdownOpen = !modalLanguageDropdownOpen;
|
|
updateToolbarUI(modal);
|
|
});
|
|
|
|
// Language option clicks
|
|
const langOptions = toolbar.querySelectorAll('.language-option');
|
|
langOptions.forEach((option) => {
|
|
option.addEventListener('click', async () => {
|
|
const newLang = (option as HTMLElement).dataset.lang;
|
|
if (newLang && modalEditorElement) {
|
|
modalLanguage = newLang;
|
|
modalLanguageDropdownOpen = false;
|
|
|
|
// Update editor language
|
|
const editor = await modalEditorElement.editorDeferred.promise;
|
|
const model = editor.getModel();
|
|
if (model) {
|
|
(window as any).monaco.editor.setModelLanguage(model, newLang);
|
|
}
|
|
|
|
// Update selected state
|
|
langOptions.forEach(opt => opt.classList.remove('selected'));
|
|
option.classList.add('selected');
|
|
|
|
updateToolbarUI(modal);
|
|
}
|
|
});
|
|
});
|
|
|
|
// Word wrap button
|
|
const wrapBtn = toolbar.querySelector('.wrap-btn');
|
|
wrapBtn?.addEventListener('click', async () => {
|
|
modalWordWrap = modalWordWrap === 'on' ? 'off' : 'on';
|
|
if (modalEditorElement) {
|
|
const editor = await modalEditorElement.editorDeferred.promise;
|
|
editor.updateOptions({ wordWrap: modalWordWrap });
|
|
}
|
|
updateToolbarUI(modal);
|
|
});
|
|
|
|
// Line numbers button
|
|
const linesBtn = toolbar.querySelector('.lines-btn');
|
|
linesBtn?.addEventListener('click', async () => {
|
|
modalShowLineNumbers = !modalShowLineNumbers;
|
|
if (modalEditorElement) {
|
|
const editor = await modalEditorElement.editorDeferred.promise;
|
|
editor.updateOptions({ lineNumbers: modalShowLineNumbers ? 'on' : 'off' });
|
|
}
|
|
updateToolbarUI(modal);
|
|
});
|
|
|
|
// Copy button
|
|
const copyBtn = toolbar.querySelector('.copy-btn');
|
|
copyBtn?.addEventListener('click', async () => {
|
|
if (modalEditorElement) {
|
|
const editor = await modalEditorElement.editorDeferred.promise;
|
|
const content = editor.getValue();
|
|
try {
|
|
await navigator.clipboard.writeText(content);
|
|
modalCopySuccess = true;
|
|
updateToolbarUI(modal);
|
|
setTimeout(() => {
|
|
modalCopySuccess = false;
|
|
updateToolbarUI(modal);
|
|
}, 2000);
|
|
} catch (err) {
|
|
console.error('Failed to copy code:', err);
|
|
}
|
|
}
|
|
});
|
|
|
|
// Close dropdown when clicking outside
|
|
document.addEventListener('click', (e) => {
|
|
if (modalLanguageDropdownOpen && !langBtn?.contains(e.target as Node)) {
|
|
modalLanguageDropdownOpen = false;
|
|
updateToolbarUI(modal);
|
|
}
|
|
}, { once: true });
|
|
}
|
|
}
|
|
|
|
public getValue(): string {
|
|
return this.value;
|
|
}
|
|
|
|
public setValue(value: string): void {
|
|
this.value = value;
|
|
if (this.editorElement) {
|
|
this.editorElement.content = value;
|
|
// Also update the Monaco editor directly if it's already loaded
|
|
this.editorElement.editorDeferred.promise.then(editor => {
|
|
if (editor.getValue() !== value) {
|
|
editor.setValue(value);
|
|
}
|
|
});
|
|
}
|
|
this.changeSubject.next(this as any);
|
|
}
|
|
}
|