feat(editor): add code input component and editor-bare, replace dees-editor usage, and add modal contentPadding
This commit is contained in:
10
changelog.md
10
changelog.md
@@ -1,5 +1,15 @@
|
|||||||
# Changelog
|
# Changelog
|
||||||
|
|
||||||
|
## 2025-12-30 - 3.12.0 - feat(editor)
|
||||||
|
add code input component and editor-bare, replace dees-editor usage, and add modal contentPadding
|
||||||
|
|
||||||
|
- Add new dees-input-code component (full-featured code editor input with modal, toolbar, language selector, copy and wrap toggles).
|
||||||
|
- Introduce dees-editor-bare component and remove the legacy dees-editor implementation; update editor markdown component to use dees-editor-bare.
|
||||||
|
- Export and include DeesInputCode in input index and include it in the unified form input types and dees-form usage.
|
||||||
|
- Add contentPadding property to DeesModal and apply it to the modal content area (configurable modal inner padding).
|
||||||
|
- Update element exports to point to dees-editor-bare and adjust related imports/usages.
|
||||||
|
- Bump devDependency @design.estate/dees-wcctools from ^3.3.0 to ^3.4.0 in package.json
|
||||||
|
|
||||||
## 2025-12-30 - 3.11.2 - fix(tests)
|
## 2025-12-30 - 3.11.2 - fix(tests)
|
||||||
make WYSIWYG tests more robust and deterministic by initializing and attaching elements consistently, awaiting customElements/firstUpdated, adjusting selectors and assertions, and cleaning up DOM after tests
|
make WYSIWYG tests more robust and deterministic by initializing and attaching elements consistently, awaiting customElements/firstUpdated, adjusting selectors and assertions, and cleaning up DOM after tests
|
||||||
|
|
||||||
|
|||||||
@@ -44,7 +44,7 @@
|
|||||||
"xterm-addon-fit": "^0.8.0"
|
"xterm-addon-fit": "^0.8.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@design.estate/dees-wcctools": "^3.3.0",
|
"@design.estate/dees-wcctools": "^3.4.0",
|
||||||
"@git.zone/tsbuild": "^4.0.2",
|
"@git.zone/tsbuild": "^4.0.2",
|
||||||
"@git.zone/tsbundle": "^2.6.3",
|
"@git.zone/tsbundle": "^2.6.3",
|
||||||
"@git.zone/tstest": "^3.1.4",
|
"@git.zone/tstest": "^3.1.4",
|
||||||
|
|||||||
10
pnpm-lock.yaml
generated
10
pnpm-lock.yaml
generated
@@ -88,8 +88,8 @@ importers:
|
|||||||
version: 0.8.0(xterm@5.3.0)
|
version: 0.8.0(xterm@5.3.0)
|
||||||
devDependencies:
|
devDependencies:
|
||||||
'@design.estate/dees-wcctools':
|
'@design.estate/dees-wcctools':
|
||||||
specifier: ^3.3.0
|
specifier: ^3.4.0
|
||||||
version: 3.3.0
|
version: 3.4.0
|
||||||
'@git.zone/tsbuild':
|
'@git.zone/tsbuild':
|
||||||
specifier: ^4.0.2
|
specifier: ^4.0.2
|
||||||
version: 4.0.2
|
version: 4.0.2
|
||||||
@@ -337,8 +337,8 @@ packages:
|
|||||||
'@design.estate/dees-wcctools@1.3.0':
|
'@design.estate/dees-wcctools@1.3.0':
|
||||||
resolution: {integrity: sha512-+yd8c1gTIKNRQYCvG0xu6Am8dHsRm7ymluX2gnoBQN4aFOpZgIBi/v9CvGyPhTD1p/VRouIBz1wsUCejnwrFCA==}
|
resolution: {integrity: sha512-+yd8c1gTIKNRQYCvG0xu6Am8dHsRm7ymluX2gnoBQN4aFOpZgIBi/v9CvGyPhTD1p/VRouIBz1wsUCejnwrFCA==}
|
||||||
|
|
||||||
'@design.estate/dees-wcctools@3.3.0':
|
'@design.estate/dees-wcctools@3.4.0':
|
||||||
resolution: {integrity: sha512-ZOxG5LkbLLsqDQWO+JCOjFkL77l9FuLDa7LBuZRkTSX0jRoYG6ICI1UoI9i6twxm4JKSzQ4iHjL/F5mHbQiKTg==}
|
resolution: {integrity: sha512-B263qJxK1Ob5ZmC+qj/utiuKZvdewIO6WwTfrTKF3X0Y24pcxoJVwJsDDcJID4kRd44EcNU9CP0FfWD2uYX9GQ==}
|
||||||
|
|
||||||
'@emnapi/core@1.7.1':
|
'@emnapi/core@1.7.1':
|
||||||
resolution: {integrity: sha512-o1uhUASyo921r2XtHYOHy7gdkGLge8ghBEQHMWmyJFoXlpU58kIrhhN3w26lpQb6dspetweapMn2CSNwQ8I4wg==}
|
resolution: {integrity: sha512-o1uhUASyo921r2XtHYOHy7gdkGLge8ghBEQHMWmyJFoXlpU58kIrhhN3w26lpQb6dspetweapMn2CSNwQ8I4wg==}
|
||||||
@@ -4605,7 +4605,7 @@ snapshots:
|
|||||||
- supports-color
|
- supports-color
|
||||||
- vue
|
- vue
|
||||||
|
|
||||||
'@design.estate/dees-wcctools@3.3.0':
|
'@design.estate/dees-wcctools@3.4.0':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@design.estate/dees-domtools': 2.3.6
|
'@design.estate/dees-domtools': 2.3.6
|
||||||
'@design.estate/dees-element': 2.1.3
|
'@design.estate/dees-element': 2.1.3
|
||||||
|
|||||||
@@ -3,6 +3,6 @@
|
|||||||
*/
|
*/
|
||||||
export const commitinfo = {
|
export const commitinfo = {
|
||||||
name: '@design.estate/dees-catalog',
|
name: '@design.estate/dees-catalog',
|
||||||
version: '3.11.2',
|
version: '3.12.0',
|
||||||
description: 'A comprehensive library that provides dynamic web components for building sophisticated and modern web applications using JavaScript and TypeScript.'
|
description: 'A comprehensive library that provides dynamic web components for building sophisticated and modern web applications using JavaScript and TypeScript.'
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,14 +15,14 @@ import type * as monaco from 'monaco-editor';
|
|||||||
|
|
||||||
declare global {
|
declare global {
|
||||||
interface HTMLElementTagNameMap {
|
interface HTMLElementTagNameMap {
|
||||||
'dees-editor': DeesEditor;
|
'dees-editor-bare': DeesEditorBare;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@customElement('dees-editor')
|
@customElement('dees-editor-bare')
|
||||||
export class DeesEditor extends DeesElement {
|
export class DeesEditorBare extends DeesElement {
|
||||||
// DEMO
|
// DEMO
|
||||||
public static demo = () => html` <dees-editor></dees-editor> `;
|
public static demo = () => html` <dees-editor-bare></dees-editor-bare> `;
|
||||||
|
|
||||||
// STATIC
|
// STATIC
|
||||||
public static monacoDeferred: ReturnType<typeof domtools.plugins.smartpromise.defer>;
|
public static monacoDeferred: ReturnType<typeof domtools.plugins.smartpromise.defer>;
|
||||||
@@ -86,17 +86,17 @@ export class DeesEditor extends DeesElement {
|
|||||||
const container = this.shadowRoot.getElementById('container');
|
const container = this.shadowRoot.getElementById('container');
|
||||||
const monacoCdnBase = `https://cdn.jsdelivr.net/npm/monaco-editor@${MONACO_VERSION}`;
|
const monacoCdnBase = `https://cdn.jsdelivr.net/npm/monaco-editor@${MONACO_VERSION}`;
|
||||||
|
|
||||||
if (!DeesEditor.monacoDeferred) {
|
if (!DeesEditorBare.monacoDeferred) {
|
||||||
DeesEditor.monacoDeferred = domtools.plugins.smartpromise.defer();
|
DeesEditorBare.monacoDeferred = domtools.plugins.smartpromise.defer();
|
||||||
const scriptUrl = `${monacoCdnBase}/min/vs/loader.js`;
|
const scriptUrl = `${monacoCdnBase}/min/vs/loader.js`;
|
||||||
const script = document.createElement('script');
|
const script = document.createElement('script');
|
||||||
script.src = scriptUrl;
|
script.src = scriptUrl;
|
||||||
script.onload = () => {
|
script.onload = () => {
|
||||||
DeesEditor.monacoDeferred.resolve();
|
DeesEditorBare.monacoDeferred.resolve();
|
||||||
};
|
};
|
||||||
document.head.appendChild(script);
|
document.head.appendChild(script);
|
||||||
}
|
}
|
||||||
await DeesEditor.monacoDeferred.promise;
|
await DeesEditorBare.monacoDeferred.promise;
|
||||||
|
|
||||||
(window as any).require.config({
|
(window as any).require.config({
|
||||||
paths: { vs: `${monacoCdnBase}/min/vs` },
|
paths: { vs: `${monacoCdnBase}/min/vs` },
|
||||||
1
ts_web/elements/00group-editor/dees-editor-bare/index.ts
Normal file
1
ts_web/elements/00group-editor/dees-editor-bare/index.ts
Normal file
@@ -0,0 +1 @@
|
|||||||
|
export * from './dees-editor-bare.js';
|
||||||
@@ -9,6 +9,7 @@ import {
|
|||||||
domtools
|
domtools
|
||||||
} from '@design.estate/dees-element';
|
} from '@design.estate/dees-element';
|
||||||
import { themeDefaultStyles } from '../../00theme.js';
|
import { themeDefaultStyles } from '../../00theme.js';
|
||||||
|
import { DeesEditorBare } from '../dees-editor-bare/dees-editor-bare.js';
|
||||||
|
|
||||||
const deferred = domtools.plugins.smartpromise.defer();
|
const deferred = domtools.plugins.smartpromise.defer();
|
||||||
|
|
||||||
@@ -51,7 +52,7 @@ export class DeesEditorMarkdown extends DeesElement {
|
|||||||
return html`
|
return html`
|
||||||
<div class="gridcontainer">
|
<div class="gridcontainer">
|
||||||
<div class="editorContainer">
|
<div class="editorContainer">
|
||||||
<dees-editor
|
<dees-editor-bare
|
||||||
.language=${'markdown'}
|
.language=${'markdown'}
|
||||||
.content=${`# a test content
|
.content=${`# a test content
|
||||||
|
|
||||||
@@ -75,7 +76,7 @@ const hello = 'yes'
|
|||||||
\`\`\`
|
\`\`\`
|
||||||
`}
|
`}
|
||||||
wordWrap="bounded"
|
wordWrap="bounded"
|
||||||
></dees-editor>
|
></dees-editor-bare>
|
||||||
</div>
|
</div>
|
||||||
<div class="outletContainer">
|
<div class="outletContainer">
|
||||||
<dees-editormarkdownoutlet></dees-editormarkdownoutlet>
|
<dees-editormarkdownoutlet></dees-editormarkdownoutlet>
|
||||||
@@ -86,8 +87,8 @@ const hello = 'yes'
|
|||||||
|
|
||||||
public async firstUpdated(_changedPropertiesArg) {
|
public async firstUpdated(_changedPropertiesArg) {
|
||||||
await super.firstUpdated(_changedPropertiesArg);
|
await super.firstUpdated(_changedPropertiesArg);
|
||||||
const editor = this.shadowRoot.querySelector('dees-editor');
|
const editor = this.shadowRoot.querySelector('dees-editor-bare') as DeesEditorBare;
|
||||||
|
|
||||||
// lets care about wiring the markdown stuff.
|
// lets care about wiring the markdown stuff.
|
||||||
const markdownOutlet = this.shadowRoot.querySelector('dees-editormarkdownoutlet');
|
const markdownOutlet = this.shadowRoot.querySelector('dees-editormarkdownoutlet');
|
||||||
const smartmarkdownInstance = new domtools.plugins.smartmarkdown.SmartMarkdown();
|
const smartmarkdownInstance = new domtools.plugins.smartmarkdown.SmartMarkdown();
|
||||||
|
|||||||
@@ -1 +0,0 @@
|
|||||||
export * from './dees-editor.js';
|
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
// Editor Components
|
// Editor Components
|
||||||
export * from './dees-editor/index.js';
|
export * from './dees-editor-bare/index.js';
|
||||||
export * from './dees-editor-markdown/index.js';
|
export * from './dees-editor-markdown/index.js';
|
||||||
export * from './dees-editor-markdownoutlet/index.js';
|
export * from './dees-editor-markdownoutlet/index.js';
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ import {
|
|||||||
import * as domtools from '@design.estate/dees-domtools';
|
import * as domtools from '@design.estate/dees-domtools';
|
||||||
|
|
||||||
import { DeesInputCheckbox } from '../../00group-input/dees-input-checkbox/dees-input-checkbox.js';
|
import { DeesInputCheckbox } from '../../00group-input/dees-input-checkbox/dees-input-checkbox.js';
|
||||||
|
import { DeesInputCode } from '../../00group-input/dees-input-code/dees-input-code.js';
|
||||||
import { DeesInputDatepicker } from '../../00group-input/dees-input-datepicker/index.js';
|
import { DeesInputDatepicker } from '../../00group-input/dees-input-datepicker/index.js';
|
||||||
import { DeesInputText } from '../../00group-input/dees-input-text/dees-input-text.js';
|
import { DeesInputText } from '../../00group-input/dees-input-text/dees-input-text.js';
|
||||||
import { DeesInputQuantitySelector } from '../../00group-input/dees-input-quantityselector/dees-input-quantityselector.js';
|
import { DeesInputQuantitySelector } from '../../00group-input/dees-input-quantityselector/dees-input-quantityselector.js';
|
||||||
@@ -26,6 +27,7 @@ import { demoFunc } from './dees-form.demo.js';
|
|||||||
// Unified set for form input types
|
// Unified set for form input types
|
||||||
const FORM_INPUT_TYPES = [
|
const FORM_INPUT_TYPES = [
|
||||||
DeesInputCheckbox,
|
DeesInputCheckbox,
|
||||||
|
DeesInputCode,
|
||||||
DeesInputDatepicker,
|
DeesInputDatepicker,
|
||||||
DeesInputDropdown,
|
DeesInputDropdown,
|
||||||
DeesInputFileupload,
|
DeesInputFileupload,
|
||||||
@@ -41,6 +43,7 @@ const FORM_INPUT_TYPES = [
|
|||||||
|
|
||||||
export type TFormInputElement =
|
export type TFormInputElement =
|
||||||
| DeesInputCheckbox
|
| DeesInputCheckbox
|
||||||
|
| DeesInputCode
|
||||||
| DeesInputDatepicker
|
| DeesInputDatepicker
|
||||||
| DeesInputDropdown
|
| DeesInputDropdown
|
||||||
| DeesInputFileupload
|
| DeesInputFileupload
|
||||||
|
|||||||
719
ts_web/elements/00group-input/dees-input-code/dees-input-code.ts
Normal file
719
ts_web/elements/00group-input/dees-input-code/dees-input-code.ts
Normal file
@@ -0,0 +1,719 @@
|
|||||||
|
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-editor/dees-editor-bare/dees-editor-bare.js';
|
||||||
|
import { DeesEditorBare } from '../../00group-editor/dees-editor-bare/dees-editor-bare.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>
|
||||||
|
`;
|
||||||
|
|
||||||
|
// 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: DeesEditorBare | 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-editor-bare {
|
||||||
|
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-editor-bare
|
||||||
|
.content=${this.value}
|
||||||
|
.language=${this.language}
|
||||||
|
.wordWrap=${this.wordWrap}
|
||||||
|
@content-change=${this.handleContentChange}
|
||||||
|
></dees-editor-bare>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
|
||||||
|
async firstUpdated() {
|
||||||
|
this.editorElement = this.shadowRoot?.querySelector('dees-editor-bare') as DeesEditorBare;
|
||||||
|
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: DeesEditorBare | 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 {
|
||||||
|
height: calc(100vh - 160px);
|
||||||
|
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-editor-bare
|
||||||
|
.content=${currentValue}
|
||||||
|
.language=${modalLanguage}
|
||||||
|
.wordWrap=${modalWordWrap}
|
||||||
|
></dees-editor-bare>
|
||||||
|
</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-editor-bare') as DeesEditorBare;
|
||||||
|
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-editor-bare') as DeesEditorBare;
|
||||||
|
|
||||||
|
// 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
1
ts_web/elements/00group-input/dees-input-code/index.ts
Normal file
1
ts_web/elements/00group-input/dees-input-code/index.ts
Normal file
@@ -0,0 +1 @@
|
|||||||
|
export * from './dees-input-code.js';
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
// Input Components
|
// Input Components
|
||||||
export * from './dees-input-base/index.js';
|
export * from './dees-input-base/index.js';
|
||||||
export * from './dees-input-checkbox/index.js';
|
export * from './dees-input-checkbox/index.js';
|
||||||
|
export * from './dees-input-code/index.js';
|
||||||
export * from './dees-input-datepicker/index.js';
|
export * from './dees-input-datepicker/index.js';
|
||||||
export * from './dees-input-dropdown/index.js';
|
export * from './dees-input-dropdown/index.js';
|
||||||
export * from './dees-input-fileupload/index.js';
|
export * from './dees-input-fileupload/index.js';
|
||||||
|
|||||||
@@ -45,6 +45,7 @@ export class DeesModal extends DeesElement {
|
|||||||
showHelpButton?: boolean;
|
showHelpButton?: boolean;
|
||||||
onHelp?: () => void | Promise<void>;
|
onHelp?: () => void | Promise<void>;
|
||||||
mobileFullscreen?: boolean;
|
mobileFullscreen?: boolean;
|
||||||
|
contentPadding?: number;
|
||||||
}) {
|
}) {
|
||||||
const body = document.body;
|
const body = document.body;
|
||||||
const modal = new DeesModal();
|
const modal = new DeesModal();
|
||||||
@@ -58,6 +59,7 @@ export class DeesModal extends DeesElement {
|
|||||||
if (optionsArg.showHelpButton !== undefined) modal.showHelpButton = optionsArg.showHelpButton;
|
if (optionsArg.showHelpButton !== undefined) modal.showHelpButton = optionsArg.showHelpButton;
|
||||||
if (optionsArg.onHelp) modal.onHelp = optionsArg.onHelp;
|
if (optionsArg.onHelp) modal.onHelp = optionsArg.onHelp;
|
||||||
if (optionsArg.mobileFullscreen !== undefined) modal.mobileFullscreen = optionsArg.mobileFullscreen;
|
if (optionsArg.mobileFullscreen !== undefined) modal.mobileFullscreen = optionsArg.mobileFullscreen;
|
||||||
|
if (optionsArg.contentPadding !== undefined) modal.contentPadding = optionsArg.contentPadding;
|
||||||
modal.windowLayer = await DeesWindowLayer.createAndShow({
|
modal.windowLayer = await DeesWindowLayer.createAndShow({
|
||||||
blur: true,
|
blur: true,
|
||||||
});
|
});
|
||||||
@@ -108,6 +110,9 @@ export class DeesModal extends DeesElement {
|
|||||||
@property({ type: Boolean })
|
@property({ type: Boolean })
|
||||||
accessor mobileFullscreen: boolean = false;
|
accessor mobileFullscreen: boolean = false;
|
||||||
|
|
||||||
|
@property({ type: Number })
|
||||||
|
accessor contentPadding: number = 16;
|
||||||
|
|
||||||
@state()
|
@state()
|
||||||
accessor modalZIndex: number = 1000;
|
accessor modalZIndex: number = 1000;
|
||||||
|
|
||||||
@@ -272,7 +277,6 @@ export class DeesModal extends DeesElement {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.modal .content {
|
.modal .content {
|
||||||
padding: 16px;
|
|
||||||
flex: 1;
|
flex: 1;
|
||||||
overflow-y: auto;
|
overflow-y: auto;
|
||||||
overflow-x: hidden;
|
overflow-x: hidden;
|
||||||
@@ -361,7 +365,7 @@ export class DeesModal extends DeesElement {
|
|||||||
` : ''}
|
` : ''}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="content">${this.content}</div>
|
<div class="content" style="padding: ${this.contentPadding}px;">${this.content}</div>
|
||||||
${this.menuOptions.length > 0 ? html`
|
${this.menuOptions.length > 0 ? html`
|
||||||
<div class="bottomButtons">
|
<div class="bottomButtons">
|
||||||
${this.menuOptions.map(
|
${this.menuOptions.map(
|
||||||
|
|||||||
Reference in New Issue
Block a user