@workbench-kit/monaco 0.0.2-prototype.0.2.10

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 ADDED
@@ -0,0 +1,40 @@
1
+ {
2
+ "name": "@workbench-kit/monaco",
3
+ "version": "0.0.2-prototype.0.2.10",
4
+ "private": false,
5
+ "type": "module",
6
+ "exports": {
7
+ ".": "./src/index.ts",
8
+ "./environment": "./src/installMonacoEnvironment.ts"
9
+ },
10
+ "files": [
11
+ "src",
12
+ "!src/**/*.test.ts",
13
+ "!src/**/*.test.tsx",
14
+ "!src/**/*.stories.ts",
15
+ "!src/**/*.stories.tsx"
16
+ ],
17
+ "dependencies": {
18
+ "@monaco-editor/react": "^4.7.0",
19
+ "monaco-editor": "^0.56.0"
20
+ },
21
+ "peerDependencies": {
22
+ "react": "^19.0.0",
23
+ "react-dom": "^19.0.0"
24
+ },
25
+ "description": "Monaco editor integration for Workbench Kit hosts and UI packages.",
26
+ "publishConfig": {
27
+ "access": "public",
28
+ "tag": "prototype",
29
+ "provenance": true
30
+ },
31
+ "repository": {
32
+ "type": "git",
33
+ "url": "git+https://github.com/NewChoBo/workbench-kit.git",
34
+ "directory": "packages/monaco"
35
+ },
36
+ "scripts": {
37
+ "test": "pnpm exec vitest run --config ../../vitest.config.ts src",
38
+ "typecheck": "tsc -p tsconfig.json --noEmit"
39
+ }
40
+ }
@@ -0,0 +1,108 @@
1
+ import { useCallback, type ReactNode } from 'react';
2
+ import type { OnMount } from '@monaco-editor/react';
3
+ import type * as Monaco from 'monaco-editor';
4
+
5
+ import { Editor } from './monaco-loader.js';
6
+ import type { WorkbenchMonaco } from './monaco-loader.js';
7
+ import {
8
+ defineMonacoWorkbenchTheme,
9
+ monacoThemeForWorkspaceTheme,
10
+ type MonacoWorkbenchResolvedTheme,
11
+ } from './monacoWorkbenchTheme.js';
12
+ import { configureWorkspaceEditorTypeScriptDiagnostics } from './workspaceTypeScriptDiagnostics.js';
13
+
14
+ export type WorkbenchMonacoEditorTheme = MonacoWorkbenchResolvedTheme;
15
+
16
+ export function prepareMonacoWorkbenchEditor(
17
+ monacoInstance: WorkbenchMonaco,
18
+ resolvedTheme: WorkbenchMonacoEditorTheme = 'dark',
19
+ ) {
20
+ defineMonacoWorkbenchTheme(monacoInstance, resolvedTheme);
21
+ configureWorkspaceEditorTypeScriptDiagnostics(monacoInstance);
22
+ }
23
+
24
+ export interface WorkbenchMonacoEditorProps {
25
+ beforeMount?: ((monacoInstance: WorkbenchMonaco) => void) | undefined;
26
+ className?: string | undefined;
27
+ height?: number | string | undefined;
28
+ language: string;
29
+ loading?: ReactNode | undefined;
30
+ onChange?: ((value: string) => void) | undefined;
31
+ onMount?: OnMount | undefined;
32
+ options?: Monaco.editor.IStandaloneEditorConstructionOptions | undefined;
33
+ path?: string | undefined;
34
+ readOnly?: boolean | undefined;
35
+ theme?: WorkbenchMonacoEditorTheme | undefined;
36
+ value?: string | undefined;
37
+ }
38
+
39
+ const defaultEditorOptions: Monaco.editor.IStandaloneEditorConstructionOptions = {
40
+ automaticLayout: true,
41
+ contextmenu: true,
42
+ fixedOverflowWidgets: true,
43
+ fontFamily: 'ui-monospace, SFMono-Regular, Consolas, monospace',
44
+ fontSize: 13,
45
+ lineHeight: 20,
46
+ glyphMargin: false,
47
+ minimap: { enabled: false },
48
+ overviewRulerBorder: false,
49
+ overviewRulerLanes: 0,
50
+ padding: { bottom: 12, top: 12 },
51
+ renderLineHighlight: 'line',
52
+ scrollBeyondLastLine: false,
53
+ scrollbar: {
54
+ alwaysConsumeMouseWheel: false,
55
+ horizontalScrollbarSize: 10,
56
+ verticalScrollbarSize: 10,
57
+ },
58
+ tabSize: 2,
59
+ wordWrap: 'on',
60
+ };
61
+
62
+ export function WorkbenchMonacoEditor({
63
+ beforeMount,
64
+ className,
65
+ height = '100%',
66
+ language,
67
+ loading = (
68
+ <div className="ui-panel-loading ui-panel-centered-state" role="status" aria-live="polite">
69
+ <i aria-hidden className="codicon codicon-loading codicon-modifier-spin" />
70
+ <span>Loading editor...</span>
71
+ </div>
72
+ ),
73
+ onChange,
74
+ onMount,
75
+ options,
76
+ path,
77
+ readOnly = false,
78
+ theme = 'dark',
79
+ value = '',
80
+ }: WorkbenchMonacoEditorProps) {
81
+ const handleBeforeMount = useCallback(
82
+ (monacoInstance: WorkbenchMonaco) => {
83
+ prepareMonacoWorkbenchEditor(monacoInstance, theme);
84
+ beforeMount?.(monacoInstance);
85
+ },
86
+ [beforeMount, theme],
87
+ );
88
+
89
+ return (
90
+ <Editor
91
+ className={className}
92
+ beforeMount={handleBeforeMount}
93
+ height={height}
94
+ language={language}
95
+ loading={loading}
96
+ options={{
97
+ ...defaultEditorOptions,
98
+ ...options,
99
+ readOnly,
100
+ }}
101
+ path={path}
102
+ theme={monacoThemeForWorkspaceTheme(theme)}
103
+ value={value}
104
+ onChange={(nextValue) => onChange?.(nextValue ?? '')}
105
+ onMount={onMount}
106
+ />
107
+ );
108
+ }
package/src/index.ts ADDED
@@ -0,0 +1,34 @@
1
+ export type { OnMount } from '@monaco-editor/react';
2
+ export type { IDisposable, editor } from 'monaco-editor';
3
+ export type { WorkbenchMonaco } from './monaco-loader.js';
4
+
5
+ export { Editor, loader, monaco } from './monaco-loader.js';
6
+ export {
7
+ createMonacoWorker,
8
+ installMonacoEnvironment,
9
+ resolveMonacoWorkerSource,
10
+ type InstallMonacoEnvironmentOptions,
11
+ type MonacoEnvironmentWorkers,
12
+ type MonacoWorkerSource,
13
+ } from './installMonacoEnvironment.js';
14
+ export {
15
+ MONACO_DARK_THEME_ID,
16
+ MONACO_LIGHT_THEME_ID,
17
+ buildMonacoThemeColors,
18
+ defineMonacoWorkbenchTheme,
19
+ getWorkbenchThemeAppearanceSignature,
20
+ monacoThemeForWorkspaceTheme,
21
+ readWorkbenchThemeColors,
22
+ resolveMonacoThemeRoot,
23
+ withAlpha,
24
+ type MonacoWorkbenchResolvedTheme,
25
+ type WorkbenchThemeCssColors,
26
+ } from './monacoWorkbenchTheme.js';
27
+ export { useMonacoWorkbenchThemeSync } from './useMonacoWorkbenchThemeSync.js';
28
+ export { configureWorkspaceEditorTypeScriptDiagnostics } from './workspaceTypeScriptDiagnostics.js';
29
+ export {
30
+ WorkbenchMonacoEditor,
31
+ prepareMonacoWorkbenchEditor,
32
+ type WorkbenchMonacoEditorProps,
33
+ type WorkbenchMonacoEditorTheme,
34
+ } from './WorkbenchMonacoEditor.js';
@@ -0,0 +1,76 @@
1
+ /**
2
+ * Bundler-agnostic `MonacoEnvironment.getWorker` bootstrap.
3
+ *
4
+ * Pass worker **URL strings** (Vite `?worker&url`) or **factories** that return
5
+ * a `Worker` (Vite/Storybook `?worker` constructors wrapped as `() => new Ctor()`).
6
+ */
7
+
8
+ export type MonacoWorkerSource = string | (() => Worker);
9
+
10
+ export interface MonacoEnvironmentWorkers {
11
+ readonly editor: MonacoWorkerSource;
12
+ readonly json?: MonacoWorkerSource | undefined;
13
+ readonly css?: MonacoWorkerSource | undefined;
14
+ readonly html?: MonacoWorkerSource | undefined;
15
+ readonly typescript?: MonacoWorkerSource | undefined;
16
+ }
17
+
18
+ export interface InstallMonacoEnvironmentOptions {
19
+ /** Worker `type` when the source is a URL string. Defaults to `module`. */
20
+ readonly workerType?: WorkerType | undefined;
21
+ }
22
+
23
+ type MonacoEnvironmentGlobal = typeof globalThis & {
24
+ MonacoEnvironment?: {
25
+ getWorker?: (moduleId: string, label: string) => Worker;
26
+ };
27
+ };
28
+
29
+ /** Resolve the worker source for a Monaco language label (unknown → editor). */
30
+ export function resolveMonacoWorkerSource(
31
+ label: string,
32
+ workers: MonacoEnvironmentWorkers,
33
+ ): MonacoWorkerSource {
34
+ if (label === 'json') {
35
+ return workers.json ?? workers.editor;
36
+ }
37
+ if (label === 'css' || label === 'scss' || label === 'less') {
38
+ return workers.css ?? workers.editor;
39
+ }
40
+ if (label === 'html' || label === 'handlebars' || label === 'razor') {
41
+ return workers.html ?? workers.editor;
42
+ }
43
+ if (label === 'typescript' || label === 'javascript') {
44
+ return workers.typescript ?? workers.editor;
45
+ }
46
+ return workers.editor;
47
+ }
48
+
49
+ export function createMonacoWorker(
50
+ source: MonacoWorkerSource,
51
+ label: string,
52
+ workerType: WorkerType = 'module',
53
+ ): Worker {
54
+ if (typeof source === 'string') {
55
+ return new Worker(source, { name: `monaco-${label}-worker`, type: workerType });
56
+ }
57
+ return source();
58
+ }
59
+
60
+ /**
61
+ * Installs `globalThis.MonacoEnvironment.getWorker` from a label→source map.
62
+ * Safe to call more than once (replaces `getWorker`).
63
+ */
64
+ export function installMonacoEnvironment(
65
+ workers: MonacoEnvironmentWorkers,
66
+ options: InstallMonacoEnvironmentOptions = {},
67
+ ): void {
68
+ const workerType = options.workerType ?? 'module';
69
+ const monacoGlobal = globalThis as MonacoEnvironmentGlobal;
70
+
71
+ monacoGlobal.MonacoEnvironment = {
72
+ ...monacoGlobal.MonacoEnvironment,
73
+ getWorker: (_moduleId: string, label: string) =>
74
+ createMonacoWorker(resolveMonacoWorkerSource(label, workers), label, workerType),
75
+ };
76
+ }
@@ -0,0 +1,8 @@
1
+ import Editor, { loader } from '@monaco-editor/react';
2
+ import * as monaco from 'monaco-editor';
3
+
4
+ loader.config({ monaco });
5
+
6
+ export type WorkbenchMonaco = typeof monaco;
7
+
8
+ export { Editor, loader, monaco };
@@ -0,0 +1,178 @@
1
+ import type * as monaco from 'monaco-editor';
2
+
3
+ export const MONACO_DARK_THEME_ID = 'workbench-kit-dark';
4
+ export const MONACO_LIGHT_THEME_ID = 'workbench-kit-light';
5
+
6
+ export type MonacoWorkbenchResolvedTheme = 'dark' | 'light';
7
+
8
+ export interface WorkbenchThemeCssColors {
9
+ accent: string;
10
+ bg: string;
11
+ border: string;
12
+ danger: string;
13
+ focusBorder: string;
14
+ scrollbarThumb: string;
15
+ scrollbarThumbActive: string;
16
+ scrollbarThumbHover: string;
17
+ surface: string;
18
+ surfaceElevated: string;
19
+ surfaceHover: string;
20
+ text: string;
21
+ textMuted: string;
22
+ textSubtle: string;
23
+ }
24
+
25
+ function readCssVariable(root: HTMLElement, variableName: string): string {
26
+ return getComputedStyle(root).getPropertyValue(variableName).trim();
27
+ }
28
+
29
+ export function readWorkbenchThemeColors(root: HTMLElement): WorkbenchThemeCssColors {
30
+ return {
31
+ accent: readCssVariable(root, '--color-accent'),
32
+ bg: readCssVariable(root, '--color-bg'),
33
+ border: readCssVariable(root, '--color-border'),
34
+ danger: readCssVariable(root, '--color-danger'),
35
+ focusBorder: readCssVariable(root, '--color-focus-border'),
36
+ scrollbarThumb: readCssVariable(root, '--scrollbar-thumb'),
37
+ scrollbarThumbActive: readCssVariable(root, '--scrollbar-thumb-active'),
38
+ scrollbarThumbHover: readCssVariable(root, '--scrollbar-thumb-hover'),
39
+ surface: readCssVariable(root, '--color-surface'),
40
+ surfaceElevated: readCssVariable(root, '--color-surface-elevated'),
41
+ surfaceHover: readCssVariable(root, '--color-surface-hover'),
42
+ text: readCssVariable(root, '--color-text'),
43
+ textMuted: readCssVariable(root, '--color-text-muted'),
44
+ textSubtle: readCssVariable(root, '--color-text-subtle'),
45
+ };
46
+ }
47
+
48
+ function parseRgbChannels(color: string): [number, number, number] | null {
49
+ const normalized = color.trim();
50
+
51
+ const hexMatch = normalized.match(/^#([0-9a-f]{3,8})$/i);
52
+ if (hexMatch) {
53
+ const hex = hexMatch[1];
54
+ if (hex.length === 3) {
55
+ return [
56
+ Number.parseInt(hex[0] + hex[0], 16),
57
+ Number.parseInt(hex[1] + hex[1], 16),
58
+ Number.parseInt(hex[2] + hex[2], 16),
59
+ ];
60
+ }
61
+ if (hex.length === 6 || hex.length === 8) {
62
+ return [
63
+ Number.parseInt(hex.slice(0, 2), 16),
64
+ Number.parseInt(hex.slice(2, 4), 16),
65
+ Number.parseInt(hex.slice(4, 6), 16),
66
+ ];
67
+ }
68
+ }
69
+
70
+ const rgbMatch = normalized.match(
71
+ /^rgba?\(\s*([\d.]+)\s*,\s*([\d.]+)\s*,\s*([\d.]+)(?:\s*,\s*[\d.]+\s*)?\)$/i,
72
+ );
73
+ if (rgbMatch) {
74
+ return [
75
+ Math.round(Number(rgbMatch[1])),
76
+ Math.round(Number(rgbMatch[2])),
77
+ Math.round(Number(rgbMatch[3])),
78
+ ];
79
+ }
80
+
81
+ return null;
82
+ }
83
+
84
+ export function withAlpha(color: string, alpha: number): string {
85
+ const channels = parseRgbChannels(color);
86
+ if (!channels) {
87
+ return color;
88
+ }
89
+
90
+ const clampedAlpha = Math.min(1, Math.max(0, alpha));
91
+ const alphaHex = Math.round(clampedAlpha * 255)
92
+ .toString(16)
93
+ .padStart(2, '0');
94
+ const [red, green, blue] = channels;
95
+ return `#${red.toString(16).padStart(2, '0')}${green.toString(16).padStart(2, '0')}${blue.toString(16).padStart(2, '0')}${alphaHex}`;
96
+ }
97
+
98
+ export function buildMonacoThemeColors(colors: WorkbenchThemeCssColors): monaco.editor.IColors {
99
+ return {
100
+ 'editor.background': colors.bg,
101
+ 'editor.foreground': colors.text,
102
+ 'editorGutter.background': colors.bg,
103
+ 'editorLineNumber.foreground': colors.textSubtle,
104
+ 'editorLineNumber.activeForeground': colors.textMuted,
105
+ 'editorCursor.foreground': colors.text,
106
+ 'editor.lineHighlightBackground': colors.surface,
107
+ 'editor.selectionBackground': withAlpha(colors.accent, 0.35),
108
+ 'editor.inactiveSelectionBackground': withAlpha(colors.accent, 0.22),
109
+ 'editorWidget.background': colors.surfaceElevated,
110
+ 'editorWidget.border': colors.border,
111
+ 'editorHoverWidget.background': colors.surfaceElevated,
112
+ 'editorHoverWidget.border': colors.border,
113
+ 'editorSuggestWidget.background': colors.surfaceElevated,
114
+ 'editorSuggestWidget.border': colors.border,
115
+ focusBorder: colors.focusBorder,
116
+ 'input.background': colors.surfaceElevated,
117
+ 'input.border': colors.border,
118
+ 'minimap.background': colors.bg,
119
+ 'scrollbarSlider.background': colors.scrollbarThumb,
120
+ 'scrollbarSlider.hoverBackground': colors.scrollbarThumbHover,
121
+ 'scrollbarSlider.activeBackground': colors.scrollbarThumbActive,
122
+ 'editorIndentGuide.background1': colors.border,
123
+ 'editorIndentGuide.activeBackground1': colors.textMuted,
124
+ 'editorWhitespace.foreground': colors.border,
125
+ 'editorBracketMatch.background': colors.surfaceHover,
126
+ 'editorBracketMatch.border': colors.textMuted,
127
+ 'editorError.foreground': withAlpha(colors.danger, 0.7),
128
+ 'editorWarning.foreground': withAlpha(colors.textMuted, 0.7),
129
+ 'editorOverviewRuler.border': colors.bg,
130
+ 'editorOverviewRuler.errorForeground': withAlpha(colors.danger, 0.35),
131
+ 'editorOverviewRuler.warningForeground': withAlpha(colors.textMuted, 0.35),
132
+ };
133
+ }
134
+
135
+ export function resolveMonacoThemeRoot(root?: HTMLElement): HTMLElement | null {
136
+ if (root) {
137
+ return root;
138
+ }
139
+
140
+ if (typeof document === 'undefined') {
141
+ return null;
142
+ }
143
+
144
+ return document.documentElement;
145
+ }
146
+
147
+ export function defineMonacoWorkbenchTheme(
148
+ monacoInstance: typeof monaco,
149
+ resolvedTheme: MonacoWorkbenchResolvedTheme,
150
+ root?: HTMLElement,
151
+ ) {
152
+ const themeRoot = resolveMonacoThemeRoot(root);
153
+ if (!themeRoot) {
154
+ return;
155
+ }
156
+
157
+ const themeId = resolvedTheme === 'light' ? MONACO_LIGHT_THEME_ID : MONACO_DARK_THEME_ID;
158
+
159
+ monacoInstance.editor.defineTheme(themeId, {
160
+ base: resolvedTheme === 'light' ? 'vs' : 'vs-dark',
161
+ inherit: true,
162
+ rules: [],
163
+ colors: buildMonacoThemeColors(readWorkbenchThemeColors(themeRoot)),
164
+ });
165
+ }
166
+
167
+ export function monacoThemeForWorkspaceTheme(theme: MonacoWorkbenchResolvedTheme) {
168
+ return theme === 'light' ? MONACO_LIGHT_THEME_ID : MONACO_DARK_THEME_ID;
169
+ }
170
+
171
+ export function getWorkbenchThemeAppearanceSignature(root?: HTMLElement): string {
172
+ const themeRoot = resolveMonacoThemeRoot(root);
173
+ if (!themeRoot) {
174
+ return '';
175
+ }
176
+
177
+ return `${themeRoot.dataset.theme ?? ''}:${themeRoot.dataset.themePreset ?? ''}`;
178
+ }
@@ -0,0 +1,71 @@
1
+ import { createElement, type ChangeEvent } from 'react';
2
+
3
+ export interface MockWorkbenchMonacoEditorProps {
4
+ language?: string;
5
+ onChange?: (value?: string) => void;
6
+ path?: string;
7
+ theme?: string;
8
+ value?: string;
9
+ }
10
+
11
+ export function WorkbenchMonacoEditor({
12
+ language,
13
+ onChange,
14
+ path,
15
+ theme = 'dark',
16
+ value,
17
+ }: MockWorkbenchMonacoEditorProps) {
18
+ return createElement('textarea', {
19
+ 'data-language': language,
20
+ 'data-path': path,
21
+ 'data-theme': monacoThemeForWorkspaceTheme(theme),
22
+ 'data-testid': 'monaco-editor',
23
+ value: value ?? '',
24
+ onChange: (event: ChangeEvent<HTMLTextAreaElement>) => onChange?.(event.currentTarget.value),
25
+ });
26
+ }
27
+
28
+ export const useMonacoWorkbenchThemeSync = () => undefined;
29
+ export const prepareMonacoWorkbenchEditor = () => undefined;
30
+ export const defineMonacoWorkbenchTheme = () => undefined;
31
+ export const configureWorkspaceEditorTypeScriptDiagnostics = () => undefined;
32
+ export const monacoThemeForWorkspaceTheme = (theme: string) =>
33
+ theme === 'light' ? MONACO_LIGHT_THEME_ID : MONACO_DARK_THEME_ID;
34
+ export const MONACO_DARK_THEME_ID = 'workbench-kit-dark';
35
+ export const MONACO_LIGHT_THEME_ID = 'workbench-kit-light';
36
+ export const buildMonacoThemeColors = () => ({});
37
+ export const getWorkbenchThemeAppearanceSignature = () => '';
38
+ export const readWorkbenchThemeColors = () => ({});
39
+ export const resolveMonacoThemeRoot = () => null;
40
+ export const withAlpha = (color: string, _alpha?: number) => color;
41
+
42
+ export const monaco = {
43
+ KeyMod: { CtrlCmd: 1 },
44
+ KeyCode: { KeyS: 1 },
45
+ editor: {
46
+ defineTheme: () => undefined,
47
+ setTheme: () => undefined,
48
+ onDidChangeMarkers: () => ({ dispose: () => undefined }),
49
+ getModelMarkers: () => [],
50
+ },
51
+ };
52
+
53
+ export const Editor = WorkbenchMonacoEditor;
54
+ export const loader = { config: () => undefined };
55
+
56
+ export function createWorkbenchMonacoMockModule(
57
+ renderEditor?: (props: MockWorkbenchMonacoEditorProps) => ReturnType<typeof createElement>,
58
+ ) {
59
+ const defaultRender = ({ value }: MockWorkbenchMonacoEditorProps) =>
60
+ createElement('div', { 'data-testid': 'monaco-editor' }, value ?? 'Mocked Monaco Editor');
61
+
62
+ return {
63
+ WorkbenchMonacoEditor: renderEditor ?? defaultRender,
64
+ useMonacoWorkbenchThemeSync: () => undefined,
65
+ prepareMonacoWorkbenchEditor: () => undefined,
66
+ monacoThemeForWorkspaceTheme: (theme: string) => theme,
67
+ MONACO_DARK_THEME_ID: 'workbench-kit-dark',
68
+ MONACO_LIGHT_THEME_ID: 'workbench-kit-light',
69
+ monaco,
70
+ };
71
+ }
@@ -0,0 +1,47 @@
1
+ import { useEffect, useState } from 'react';
2
+
3
+ import { monaco } from './monaco-loader.js';
4
+ import {
5
+ defineMonacoWorkbenchTheme,
6
+ getWorkbenchThemeAppearanceSignature,
7
+ monacoThemeForWorkspaceTheme,
8
+ type MonacoWorkbenchResolvedTheme,
9
+ } from './monacoWorkbenchTheme.js';
10
+
11
+ function useWorkbenchThemeAppearanceSignature(): string {
12
+ const [signature, setSignature] = useState(() => getWorkbenchThemeAppearanceSignature());
13
+
14
+ useEffect(() => {
15
+ if (typeof document === 'undefined') {
16
+ return undefined;
17
+ }
18
+
19
+ const root = document.documentElement;
20
+ const updateSignature = () => {
21
+ setSignature(getWorkbenchThemeAppearanceSignature(root));
22
+ };
23
+
24
+ updateSignature();
25
+
26
+ const observer = new MutationObserver(updateSignature);
27
+ observer.observe(root, {
28
+ attributes: true,
29
+ attributeFilter: ['data-theme', 'data-theme-preset'],
30
+ });
31
+
32
+ return () => {
33
+ observer.disconnect();
34
+ };
35
+ }, []);
36
+
37
+ return signature;
38
+ }
39
+
40
+ export function useMonacoWorkbenchThemeSync(resolvedTheme: MonacoWorkbenchResolvedTheme) {
41
+ const appearanceSignature = useWorkbenchThemeAppearanceSignature();
42
+
43
+ useEffect(() => {
44
+ defineMonacoWorkbenchTheme(monaco, resolvedTheme);
45
+ monaco.editor.setTheme(monacoThemeForWorkspaceTheme(resolvedTheme));
46
+ }, [appearanceSignature, resolvedTheme]);
47
+ }
@@ -0,0 +1,59 @@
1
+ import type * as Monaco from 'monaco-editor';
2
+
3
+ let workspaceTypeScriptDiagnosticsConfigured = false;
4
+
5
+ interface MonacoTypeScriptLanguageService {
6
+ JsxEmit: { React: number };
7
+ ModuleKind: { ESNext: number };
8
+ ModuleResolutionKind: { NodeJs: number };
9
+ ScriptTarget: { ESNext: number };
10
+ javascriptDefaults: {
11
+ setCompilerOptions: (options: Record<string, unknown>) => void;
12
+ setDiagnosticsOptions: (options: Record<string, unknown>) => void;
13
+ setEagerModelSync: (value: boolean) => void;
14
+ };
15
+ typescriptDefaults: {
16
+ setCompilerOptions: (options: Record<string, unknown>) => void;
17
+ setDiagnosticsOptions: (options: Record<string, unknown>) => void;
18
+ setEagerModelSync: (value: boolean) => void;
19
+ };
20
+ }
21
+
22
+ const workspaceTypeScriptDiagnosticsOptions = {
23
+ noSemanticValidation: true,
24
+ noSuggestionDiagnostics: true,
25
+ };
26
+
27
+ function getMonacoTypeScriptLanguageService(
28
+ monacoInstance: typeof Monaco,
29
+ ): MonacoTypeScriptLanguageService | undefined {
30
+ return monacoInstance.languages.typescript as unknown as MonacoTypeScriptLanguageService;
31
+ }
32
+
33
+ export function configureWorkspaceEditorTypeScriptDiagnostics(monacoInstance: typeof Monaco): void {
34
+ if (workspaceTypeScriptDiagnosticsConfigured) return;
35
+
36
+ const typescript = getMonacoTypeScriptLanguageService(monacoInstance);
37
+ if (!typescript) return;
38
+
39
+ const compilerOptions = {
40
+ allowJs: true,
41
+ allowNonTsExtensions: true,
42
+ esModuleInterop: true,
43
+ jsx: typescript.JsxEmit.React,
44
+ module: typescript.ModuleKind.ESNext,
45
+ moduleResolution: typescript.ModuleResolutionKind.NodeJs,
46
+ noEmit: true,
47
+ reactNamespace: 'React',
48
+ target: typescript.ScriptTarget.ESNext,
49
+ };
50
+
51
+ typescript.typescriptDefaults.setCompilerOptions(compilerOptions);
52
+ typescript.javascriptDefaults.setCompilerOptions(compilerOptions);
53
+ typescript.typescriptDefaults.setDiagnosticsOptions(workspaceTypeScriptDiagnosticsOptions);
54
+ typescript.javascriptDefaults.setDiagnosticsOptions(workspaceTypeScriptDiagnosticsOptions);
55
+ typescript.typescriptDefaults.setEagerModelSync(true);
56
+ typescript.javascriptDefaults.setEagerModelSync(true);
57
+
58
+ workspaceTypeScriptDiagnosticsConfigured = true;
59
+ }