CodeMirror 6 editor provider for JupyterLab with comprehensive language support, themes, extensions, and collaborative editing capabilities
—
Pending
Does it follow best practices?
Impact
Pending
No eval scenarios have been run
Pending
The risk profile of this skill
The theme system provides comprehensive styling and theming capabilities with JupyterLab integration, CSS variable-based themes, and custom theme support.
Registry for managing editor themes with support for custom themes and JupyterLab integration.
/**
* CodeMirror 6 theme registry
* Manages themes with JupyterLab integration and CSS variables
*/
class EditorThemeRegistry implements IEditorThemeRegistry {
constructor();
/**
* Get all registered themes
*/
readonly themes: IEditorTheme[];
/**
* Get the default CodeMirror 6 theme for JupyterLab
*/
defaultTheme(): Extension;
/**
* Register a new theme
*/
addTheme(theme: IEditorTheme): void;
/**
* Get a theme by name (falls back to default theme if not found)
*/
getTheme(name: string): Extension;
}
interface IEditorThemeRegistry {
readonly themes: IEditorTheme[];
defaultTheme(): Extension;
addTheme(theme: IEditorTheme): void;
getTheme(name: string): Extension;
}Usage Examples:
import { EditorThemeRegistry } from "@jupyterlab/codemirror";
// Create theme registry
const themes = new EditorThemeRegistry();
// Get default JupyterLab theme
const defaultTheme = themes.defaultTheme();
// Add custom theme
themes.addTheme({
name: 'my-dark-theme',
displayName: 'My Dark Theme',
theme: myDarkThemeExtension
});
// Get theme by name
const darkTheme = themes.getTheme('my-dark-theme');
const fallbackTheme = themes.getTheme('nonexistent'); // Returns default theme
// List all themes
console.log(themes.themes.map(t => t.name));Complete JupyterLab-integrated theme with CSS variables and syntax highlighting.
/**
* Complete JupyterLab CodeMirror 6 theme
* Combines editor theme and syntax highlighting
*/
const jupyterTheme: Extension;
/**
* JupyterLab editor theme definition with CSS variables
*/
const jupyterEditorTheme: EditorView.theme;
/**
* Syntax highlighting style for JupyterLab using CSS variables
*/
const jupyterHighlightStyle: HighlightStyle;Usage Examples:
import {
jupyterTheme,
jupyterEditorTheme,
jupyterHighlightStyle
} from "@jupyterlab/codemirror";
import { EditorView } from "@codemirror/view";
import { syntaxHighlighting } from "@codemirror/language";
// Use complete JupyterLab theme
const editor = new EditorView({
extensions: [
jupyterTheme,
// ... other extensions
],
parent: document.body
});
// Use components separately
const customTheme = [
jupyterEditorTheme,
syntaxHighlighting(jupyterHighlightStyle)
];
// Extend JupyterLab theme
const extendedTheme = [
jupyterTheme,
EditorView.theme({
// Additional custom styles
'.cm-editor': {
fontSize: '16px'
},
'.cm-focused': {
outline: '2px solid var(--jp-brand-color1)'
}
})
];Interface for defining custom themes.
/**
* Editor theme interface
*/
interface IEditorTheme {
/**
* Theme unique identifier
*/
readonly name: string;
/**
* Theme display name (optional)
*/
readonly displayName?: string;
/**
* Editor extension for the theme
*/
readonly theme: Extension;
}Built-in theme collection with JupyterLab integration.
/**
* Get the default editor themes
* Returns array including CodeMirror default theme
*/
static getDefaultThemes(translator?: ITranslator | null): ReadonlyArray<Readonly<IEditorTheme>>;Usage Examples:
import { EditorThemeRegistry } from "@jupyterlab/codemirror";
// Get default themes
const defaultThemes = EditorThemeRegistry.getDefaultThemes();
// Create registry with default themes
const registry = new EditorThemeRegistry();
defaultThemes.forEach(theme => registry.addTheme(theme));
// Get default themes with translation
const translatedThemes = EditorThemeRegistry.getDefaultThemes(translator);Creating custom themes with CSS variables and syntax highlighting.
import { EditorView } from "@codemirror/view";
import { HighlightStyle, syntaxHighlighting } from "@codemirror/language";
import { tags } from "@lezer/highlight";
// Create custom editor theme
const darkEditorTheme = EditorView.theme({
'&': {
color: '#f8f8f2',
backgroundColor: '#272822'
},
'.cm-content': {
padding: '16px',
caretColor: '#f92672'
},
'.cm-focused .cm-cursor': {
borderLeftColor: '#f92672'
},
'.cm-focused .cm-selectionBackground, ::selection': {
backgroundColor: '#49483e'
},
'.cm-panels': {
backgroundColor: '#272822',
color: '#f8f8f2'
},
'.cm-searchMatch': {
backgroundColor: '#49483e',
outline: '1px solid #f92672'
},
'.cm-activeLine': {
backgroundColor: '#49483e22'
},
'.cm-gutters': {
backgroundColor: '#272822',
color: '#75715e',
border: 'none'
},
'.cm-activeLineGutter': {
backgroundColor: '#49483e22'
}
}, { dark: true });
// Create custom syntax highlighting
const darkHighlightStyle = HighlightStyle.define([
{ tag: tags.keyword, color: '#f92672' },
{ tag: tags.string, color: '#e6db74' },
{ tag: tags.comment, color: '#75715e' },
{ tag: tags.number, color: '#ae81ff' },
{ tag: tags.function, color: '#a6e22e' },
{ tag: tags.className, color: '#a6e22e' },
{ tag: tags.operator, color: '#f92672' },
{ tag: tags.variableName, color: '#f8f8f2' },
{ tag: tags.typeName, color: '#66d9ef' },
{ tag: tags.propertyName, color: '#a6e22e' }
]);
// Combine into complete theme
const darkTheme: Extension = [
darkEditorTheme,
syntaxHighlighting(darkHighlightStyle)
];
// Register custom theme
const customTheme: IEditorTheme = {
name: 'monokai-dark',
displayName: 'Monokai Dark',
theme: darkTheme
};
registry.addTheme(customTheme);Using JupyterLab's CSS variables for consistent theming.
// Theme using JupyterLab CSS variables
const jupyterLabIntegratedTheme = EditorView.theme({
'&': {
color: 'var(--jp-content-font-color1)',
backgroundColor: 'var(--jp-layout-color1)'
},
'.cm-content': {
padding: 'var(--jp-code-padding)',
fontFamily: 'var(--jp-code-font-family)',
fontSize: 'var(--jp-code-font-size)',
lineHeight: 'var(--jp-code-line-height)',
caretColor: 'var(--jp-editor-cursor-color)'
},
'.cm-focused .cm-cursor': {
borderLeftColor: 'var(--jp-editor-cursor-color)'
},
'.cm-focused .cm-selectionBackground, ::selection': {
backgroundColor: 'var(--jp-editor-selected-background)'
},
'.cm-gutters': {
backgroundColor: 'var(--jp-layout-color1)',
color: 'var(--jp-ui-font-color2)',
borderRight: '1px solid var(--jp-border-color2)'
},
'.cm-activeLineGutter': {
backgroundColor: 'var(--jp-layout-color2)'
},
'.cm-activeLine': {
backgroundColor: 'rgba(125, 125, 125, 0.1)'
},
'.cm-searchMatch': {
backgroundColor: 'var(--jp-search-selected-match-background-color)',
color: 'var(--jp-search-selected-match-color)'
},
'.cm-searchMatch.cm-searchMatch-selected': {
backgroundColor: 'var(--jp-search-selected-match-background-color)',
color: 'var(--jp-search-selected-match-color)'
}
});
// Syntax highlighting with CSS variables
const jupyterLabHighlightStyle = HighlightStyle.define([
{ tag: tags.keyword, color: 'var(--jp-mirror-editor-keyword-color)' },
{ tag: tags.string, color: 'var(--jp-mirror-editor-string-color)' },
{ tag: tags.comment, color: 'var(--jp-mirror-editor-comment-color)' },
{ tag: tags.number, color: 'var(--jp-mirror-editor-number-color)' },
{ tag: tags.operator, color: 'var(--jp-mirror-editor-operator-color)' },
{ tag: tags.punctuation, color: 'var(--jp-mirror-editor-punctuation-color)' },
{ tag: tags.function, color: 'var(--jp-mirror-editor-def-color)' },
{ tag: tags.className, color: 'var(--jp-mirror-editor-def-color)' },
{ tag: tags.variableName, color: 'var(--jp-mirror-editor-variable-color)' },
{ tag: tags.typeName, color: 'var(--jp-mirror-editor-variable-2-color)' },
{ tag: tags.propertyName, color: 'var(--jp-mirror-editor-property-color)' },
{ tag: tags.attributeName, color: 'var(--jp-mirror-editor-attribute-color)' },
{ tag: tags.tagName, color: 'var(--jp-mirror-editor-tag-color)' }
]);Implementing dynamic theme switching at runtime.
class ThemeManager {
private registry: EditorThemeRegistry;
private currentTheme: string = 'default';
private editors: EditorView[] = [];
constructor(registry: EditorThemeRegistry) {
this.registry = registry;
}
// Register editor for theme updates
registerEditor(editor: EditorView): void {
this.editors.push(editor);
}
// Switch theme for all registered editors
setTheme(themeName: string): void {
const theme = this.registry.getTheme(themeName);
this.currentTheme = themeName;
this.editors.forEach(editor => {
editor.dispatch({
effects: StateEffect.reconfigure.of([
// Reconfigure with new theme
theme,
// ... other extensions
])
});
});
}
// Get current theme name
getCurrentTheme(): string {
return this.currentTheme;
}
// Get available themes
getAvailableThemes(): IEditorTheme[] {
return this.registry.themes;
}
}
// Usage
const themeManager = new ThemeManager(registry);
// Register editors
themeManager.registerEditor(editor1);
themeManager.registerEditor(editor2);
// Switch themes
themeManager.setTheme('monokai-dark');
themeManager.setTheme('jupyter-light');Creating themes that respond to system preferences.
// Responsive theme that adapts to system dark/light mode
const responsiveTheme = EditorView.theme({
'&': {
color: 'var(--jp-content-font-color1)',
backgroundColor: 'var(--jp-layout-color1)'
}
}, {
// Use system preference for dark mode detection
dark: window.matchMedia('(prefers-color-scheme: dark)').matches
});
// Listen for system theme changes
window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', (e) => {
const newTheme = e.matches ? 'dark' : 'light';
themeManager.setTheme(newTheme);
});
// Auto-theme selection based on JupyterLab theme
function getAutoTheme(): string {
const body = document.body;
const isDark = body.classList.contains('jp-theme-dark') ||
body.classList.contains('theme-dark');
return isDark ? 'jupyter-dark' : 'jupyter-light';
}Complex theming with animations, custom properties, and conditional styling.
// Theme with animations and transitions
const animatedTheme = EditorView.theme({
'.cm-cursor': {
transition: 'opacity 0.3s ease-in-out'
},
'.cm-selectionBackground': {
transition: 'background-color 0.2s ease'
},
'.cm-activeLine': {
transition: 'background-color 0.15s ease'
},
'.cm-focused .cm-matchingBracket': {
backgroundColor: 'var(--jp-brand-color0)',
animation: 'bracket-highlight 0.3s ease'
},
'@keyframes bracket-highlight': {
'0%': { backgroundColor: 'transparent' },
'50%': { backgroundColor: 'var(--jp-brand-color0)' },
'100%': { backgroundColor: 'var(--jp-brand-color0)' }
}
});
// Conditional theme based on editor state
const conditionalTheme = EditorView.theme({
'&.cm-editor.cm-readonly': {
backgroundColor: 'var(--jp-layout-color2)',
opacity: 0.8
},
'&.cm-editor.cm-has-errors': {
borderLeft: '3px solid var(--jp-error-color1)'
},
'&.cm-editor.cm-collaborative': {
borderTop: '2px solid var(--jp-brand-color2)'
}
});interface IEditorTheme {
readonly name: string;
readonly displayName?: string;
readonly theme: Extension;
}
interface IEditorThemeRegistry {
readonly themes: IEditorTheme[];
defaultTheme(): Extension;
addTheme(theme: IEditorTheme): void;
getTheme(name: string): Extension;
}