171171 < div class ="sep "> </ div >
172172 < h1 > Playground</ h1 >
173173 < div class ="spacer "> </ div >
174+ < label for ="sample-select " style ="font-size:.8rem;color:var(--muted) "> Sample:</ label >
175+ < select id ="sample-select ">
176+ < option value ="default " selected > Default</ option >
177+ < option value ="webComponent "> Web Component</ option >
178+ </ select >
179+ < div class ="sep "> </ div >
174180 < label for ="lang-select " style ="font-size:.8rem;color:var(--muted) "> Language:</ label >
175181 < select id ="lang-select ">
176182 < option value ="javascript " selected > JavaScript</ option >
@@ -263,7 +269,9 @@ <h1>Playground</h1>
263269self . MonacoEnvironment = { getWorker : ( _id , label ) => makeWorker ( label ) } ;
264270
265271// ─── Default setup code ──────────────────────────────────────────────────────
266- const DEFAULT_CODE = `\
272+ // ─── Samples ─────────────────────────────────────────────────────────────────
273+ const SAMPLES = {
274+ default : `\
267275// This code runs every time you click ▶ Run.
268276// The variable \`monaco\` is already available.
269277// Use \`container\` to target the preview pane's host element.
@@ -283,7 +291,61 @@ <h1>Playground</h1>
283291 automaticLayout: true,
284292 minimap: { enabled: false },
285293});
286- ` ;
294+ ` ,
295+ webComponent : `\
296+ // Monaco Editor inside a Web Component (Shadow DOM)
297+ // This demonstrates that @node-projects/monaco-editor-esm supports Shadow DOM.
298+
299+ const MONACO_CSS = 'https://cdn.jsdelivr.net/npm/@node-projects/monaco-editor-esm@latest/min/vs/editor/editor.main.css';
300+
301+ class MonacoEditorElement extends HTMLElement {
302+ constructor() {
303+ super();
304+ const shadow = this.attachShadow({ mode: 'open' });
305+
306+ // Add Monaco CSS inside the shadow root
307+ const link = document.createElement('link');
308+ link.rel = 'stylesheet';
309+ link.href = MONACO_CSS;
310+ shadow.appendChild(link);
311+
312+ // Editor host div
313+ const div = document.createElement('div');
314+ div.style.cssText = 'position:absolute;inset:0';
315+ shadow.appendChild(div);
316+ this.style.cssText = 'display:block;position:absolute;inset:0';
317+
318+ link.onload = () => {
319+ monaco.editor.create(div, {
320+ value: [
321+ '// Monaco Editor inside a Web Component!',
322+ '',
323+ 'class Greeter {',
324+ ' greet(name) { return \`Hello, \${name}!\`; }',
325+ '}',
326+ '',
327+ 'new Greeter().greet("Shadow DOM");',
328+ ].join('\\n'),
329+ language: 'javascript',
330+ theme: 'vs-dark',
331+ automaticLayout: true,
332+ minimap: { enabled: false },
333+ });
334+ };
335+ }
336+ }
337+
338+ if (!customElements.get('monaco-editor-wc')) {
339+ customElements.define('monaco-editor-wc', MonacoEditorElement);
340+ }
341+
342+ container.style.cssText = 'position:relative';
343+ const el = document.createElement('monaco-editor-wc');
344+ container.appendChild(el);
345+ ` ,
346+ } ;
347+
348+ const DEFAULT_CODE = SAMPLES . default ;
287349
288350// ─── Load Monaco once ────────────────────────────────────────────────────────
289351let monaco ;
@@ -309,7 +371,91 @@ <h1>Playground</h1>
309371 }
310372) ;
311373
374+ // ─── Code completion for monaco / container ───────────────────────────────
375+ monaco . languages . typescript . javascriptDefaults . addExtraLib ( `
376+ declare const container: HTMLElement;
377+ declare namespace monaco {
378+ namespace editor {
379+ function create(container: HTMLElement, options?: IStandaloneEditorConstructionOptions): IStandaloneCodeEditor;
380+ function setTheme(theme: string): void;
381+ function setModelLanguage(model: ITextModel, languageId: string): void;
382+ function getEditors(): ICodeEditor[];
383+ interface IStandaloneEditorConstructionOptions {
384+ value?: string;
385+ language?: string;
386+ theme?: string;
387+ automaticLayout?: boolean;
388+ minimap?: { enabled?: boolean; size?: 'proportional' | 'fill' | 'actual' };
389+ fontSize?: number;
390+ readOnly?: boolean;
391+ wordWrap?: 'off' | 'on' | 'wordWrapColumn' | 'bounded';
392+ lineNumbers?: 'on' | 'off' | 'relative' | 'interval';
393+ scrollBeyondLastLine?: boolean;
394+ folding?: boolean;
395+ glyphMargin?: boolean;
396+ tabSize?: number;
397+ insertSpaces?: boolean;
398+ renderWhitespace?: 'none' | 'boundary' | 'selection' | 'trailing' | 'all';
399+ renderLineHighlight?: 'none' | 'gutter' | 'line' | 'all';
400+ cursorStyle?: 'line' | 'block' | 'underline' | 'line-thin' | 'block-outline' | 'underline-thin';
401+ cursorBlinking?: 'blink' | 'smooth' | 'phase' | 'expand' | 'solid';
402+ scrollbar?: { vertical?: 'auto' | 'visible' | 'hidden'; horizontal?: 'auto' | 'visible' | 'hidden'; verticalScrollbarSize?: number; horizontalScrollbarSize?: number };
403+ suggest?: { showKeywords?: boolean; showSnippets?: boolean };
404+ quickSuggestions?: boolean | { other?: boolean; comments?: boolean; strings?: boolean };
405+ acceptSuggestionOnEnter?: 'on' | 'smart' | 'off';
406+ bracketPairColorization?: { enabled?: boolean };
407+ guides?: { bracketPairs?: boolean | 'active'; indentation?: boolean };
408+ padding?: { top?: number; bottom?: number };
409+ stickyScroll?: { enabled?: boolean };
410+ contextmenu?: boolean;
411+ smoothScrolling?: boolean;
412+ fontFamily?: string;
413+ fontLigatures?: boolean | string;
414+ fontWeight?: string;
415+ letterSpacing?: number;
416+ lineHeight?: number;
417+ }
418+ interface IStandaloneCodeEditor {
419+ getValue(): string;
420+ setValue(value: string): void;
421+ getModel(): ITextModel | null;
422+ dispose(): void;
423+ focus(): void;
424+ layout(dimension?: { width: number; height: number }): void;
425+ onDidChangeModelContent(listener: (e: any) => void): { dispose(): void };
426+ }
427+ interface ITextModel {
428+ getValue(): string;
429+ setValue(value: string): void;
430+ getLanguageId(): string;
431+ dispose(): void;
432+ }
433+ interface ICodeEditor extends IStandaloneCodeEditor {}
434+ }
435+ namespace languages {
436+ namespace typescript {
437+ const javascriptDefaults: { addExtraLib(content: string, filePath?: string): { dispose(): void }; setCompilerOptions(options: any): void };
438+ const typescriptDefaults: { addExtraLib(content: string, filePath?: string): { dispose(): void }; setCompilerOptions(options: any): void };
439+ }
440+ function register(language: { id: string }): void;
441+ function registerCompletionItemProvider(languageId: string, provider: any): { dispose(): void };
442+ function setMonarchTokensProvider(languageId: string, languageDef: any): { dispose(): void };
443+ }
444+ const KeyMod: { CtrlCmd: number; Shift: number; Alt: number; WinCtrl: number };
445+ const KeyCode: { [key: string]: number };
446+ }
447+ ` , 'ts:monaco-playground.d.ts' ) ;
448+
312449// ─── Language / Theme selectors ───────────────────────────────────────────
450+ // ─── Sample selector ──────────────────────────────────────────────────────
451+ document . getElementById ( 'sample-select' ) . addEventListener ( 'change' , ( e ) => {
452+ const sample = SAMPLES [ e . target . value ] ;
453+ if ( sample ) {
454+ setupEditor . setValue ( sample ) ;
455+ runSetupCode ( ) ;
456+ }
457+ } ) ;
458+
313459document . getElementById ( 'lang-select' ) . addEventListener ( 'change' , ( e ) => {
314460 monaco . editor . setModelLanguage ( setupEditor . getModel ( ) , e . target . value ) ;
315461} ) ;
0 commit comments