composite-monaco-diff 1.0.2

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.
Files changed (49) hide show
  1. package/LICENSE +338 -0
  2. package/dist/cjs/CenterAndHeightResizer.cjs +325 -0
  3. package/dist/cjs/CenterResizer.cjs +195 -0
  4. package/dist/cjs/Module.cjs +12 -0
  5. package/dist/cjs/MonacoDiffManager.cjs +306 -0
  6. package/dist/cjs/composite-monaco-diff.cjs +123 -0
  7. package/dist/cjs/manager/index.cjs +177 -0
  8. package/dist/cjs/react.cjs +64 -0
  9. package/dist/cjs/trimLeft.cjs +28 -0
  10. package/dist/cjs/urlchange/ChildSection.cjs +174 -0
  11. package/dist/cjs/urlchange/index.cjs +229 -0
  12. package/dist/cjs/urlchange/toolsURLSearchParams.cjs +111 -0
  13. package/dist/cjs/urlchange/urlchange.cjs +197 -0
  14. package/dist/cjs/web-component/from-js/index.cjs +160 -0
  15. package/dist/cjs/web-component/from-scripts/index.cjs +114 -0
  16. package/dist/esm/CenterAndHeightResizer.js +325 -0
  17. package/dist/esm/CenterResizer.js +195 -0
  18. package/dist/esm/Module.js +12 -0
  19. package/dist/esm/MonacoDiffManager.js +306 -0
  20. package/dist/esm/composite-monaco-diff.js +123 -0
  21. package/dist/esm/manager/index.js +177 -0
  22. package/dist/esm/react.js +64 -0
  23. package/dist/esm/trimLeft.js +28 -0
  24. package/dist/esm/urlchange/ChildSection.js +174 -0
  25. package/dist/esm/urlchange/index.js +229 -0
  26. package/dist/esm/urlchange/toolsURLSearchParams.js +111 -0
  27. package/dist/esm/urlchange/urlchange.js +197 -0
  28. package/dist/esm/web-component/from-js/index.js +160 -0
  29. package/dist/esm/web-component/from-scripts/index.js +114 -0
  30. package/dist/types/CenterAndHeightResizer.d.ts +27 -0
  31. package/dist/types/CenterResizer.d.ts +16 -0
  32. package/dist/types/Module.d.ts +11 -0
  33. package/dist/types/MonacoDiffManager.d.ts +62 -0
  34. package/dist/types/composite-monaco-diff.d.ts +48 -0
  35. package/dist/types/manager/index.d.ts +1 -0
  36. package/dist/types/react.d.ts +19 -0
  37. package/dist/types/trimLeft.d.ts +1 -0
  38. package/dist/types/urlchange/ChildSection.d.ts +41 -0
  39. package/dist/types/urlchange/index.d.ts +1 -0
  40. package/dist/types/urlchange/toolsURLSearchParams.d.ts +40 -0
  41. package/dist/types/urlchange/urlchange.d.ts +107 -0
  42. package/dist/types/web-component/from-js/index.d.ts +1 -0
  43. package/dist/types/web-component/from-scripts/index.d.ts +1 -0
  44. package/package.json +44 -0
  45. package/web-component/Module.js +413 -0
  46. package/web-component/MonacoDiffManager.js +306 -0
  47. package/web-component/composite-monaco-diff.js +123 -0
  48. package/web-component/react.js +64 -0
  49. package/web-component/trimLeft.js +28 -0
@@ -0,0 +1,41 @@
1
+ export declare const radioOptions: readonly ["radio1", "radio2", "radio3"];
2
+ export type RadioOptionType = (typeof radioOptions)[number];
3
+ export declare const defaultRadioOption: RadioOptionType;
4
+ export declare const selectOptions: readonly ["item1", "item2", "item3", "item4"];
5
+ export type SingleOptionType = (typeof selectOptions)[number];
6
+ export type MultiSelectOptionsArray = SingleOptionType[];
7
+ /**
8
+ * ChildSection encapsulates all aspects of DOM manipulation for a single
9
+ * index/instance of the test components, keeping DOM queries and mutations
10
+ * isolated from the URL-handling business logic.
11
+ */
12
+ export declare class ChildSection {
13
+ readonly index: number;
14
+ readonly root: HTMLElement;
15
+ private readonly textInput;
16
+ private readonly multiSelect;
17
+ private readonly checkboxA;
18
+ private readonly checkboxB;
19
+ private readonly dumpPre;
20
+ private readonly radioInputs;
21
+ constructor(container: HTMLElement, index: number);
22
+ getText(): string;
23
+ setText(value: string): void;
24
+ getRadio(): RadioOptionType;
25
+ setRadio(value: RadioOptionType): void;
26
+ getMultiSelect(): MultiSelectOptionsArray;
27
+ setMultiSelect(values: MultiSelectOptionsArray): void;
28
+ getCheckboxA(): boolean;
29
+ setCheckboxA(value: boolean): void;
30
+ getCheckboxB(): boolean;
31
+ setCheckboxB(value: boolean): void;
32
+ setDump(data: any): void;
33
+ onText(callback: (index: number, value: string) => void): void;
34
+ onRadio(callback: (index: number, value: RadioOptionType) => void): void;
35
+ onMultiSelect(callback: (index: number, values: MultiSelectOptionsArray) => void): void;
36
+ onCheckboxA(callback: (index: number, value: boolean) => void): void;
37
+ onCheckboxB(callback: (index: number, value: boolean) => void): void;
38
+ onDelete(callback: (index: number) => void): void;
39
+ onReconfigure(callback: (index: number) => void): void;
40
+ destroy(): void;
41
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,40 @@
1
+ /**
2
+ * Merges multiple URLSearchParams instances. The first parameter acts as the base.
3
+ * Subsequent parameters overwrite existing keys. If a string array is provided,
4
+ * it acts as an allowlist, meaning only those keys will be merged from subsequent instances.
5
+ * The final result is sorted alphabetically.
6
+ */
7
+ export declare function mergeURLSearchParams(...args: (URLSearchParams | string[])[]): URLSearchParams;
8
+ /**
9
+ * Creates a deep, distinct copy of a URLSearchParams instance, preserving its data
10
+ * but decoupling its object reference so mutations don't affect the original.
11
+ */
12
+ export declare function cloneSearchParams(params: URLSearchParams): URLSearchParams;
13
+ /**
14
+ * Returns a new URLSearchParams instance with all keys sorted alphabetically.
15
+ * Useful for ensuring consistent parameter ordering before serialization.
16
+ */
17
+ export declare function normalizeSearchParams(params: URLSearchParams): URLSearchParams;
18
+ /**
19
+ * Compares two URLSearchParams instances for equality by normalizing and sorting them.
20
+ * Returns true if they contain the exact same keys and values regardless of original order.
21
+ */
22
+ export declare function compareNormalizedSearchParams(a: URLSearchParams, b: URLSearchParams): boolean;
23
+ /**
24
+ * Returns a new URLSearchParams instance sorted primarily by keys,
25
+ * and secondarily by values if the keys are identical.
26
+ */
27
+ export declare function sortSearchParamsByKeyThenValue(params: URLSearchParams): URLSearchParams;
28
+ /**
29
+ * Merges consecutive source URLSearchParams into a base URLSearchParams, but strictly
30
+ * limits updates and deletions to a specific list of governed keys.
31
+ * Sources are applied in sequence. For each key in governedKeys and each source:
32
+ * - If the key is present in the source, it overwrites the value in result.
33
+ * - If the key is absent from the source, it is deleted from the result.
34
+ */
35
+ export declare function syncURLSearchParams(base: URLSearchParams, governedKeys: string[] | Set<string>, ...sources: URLSearchParams[]): URLSearchParams;
36
+ /**
37
+ * Updates a URL string with new search parameters, preserving origin, pathname, and hash.
38
+ * Handles both absolute and relative locations.
39
+ */
40
+ export declare function buildUrlWithSearchParams(location: string, nextParams: URLSearchParams | string): string;
@@ -0,0 +1,107 @@
1
+ import { compareNormalizedSearchParams, mergeURLSearchParams } from "./toolsURLSearchParams.js";
2
+ /**
3
+ * Definition for a single URL parameter.
4
+ * Used to specify the default value, the query string key, and functions to encode/decode the value.
5
+ */
6
+ export type ParamDef<T> = {
7
+ /** The default value used when the parameter is not present in the URL. */
8
+ default: T;
9
+ /** The actual query parameter key in the URL (e.g. "t" for text). */
10
+ getParam: string;
11
+ /** Function to serialize the value of type T to a string for the URL. */
12
+ encode: (value: T) => string;
13
+ /** Function to parse the parameter string from the URL back to type T. */
14
+ decode: (value: string) => T;
15
+ };
16
+ type ParamValues<C> = C;
17
+ /**
18
+ * Param value types inferred from a config object's `default` fields.
19
+ * Extracts the types of default values to create a strongly-typed parameter object.
20
+ */
21
+ export type InferParamsFromConfig<T extends Record<string, {
22
+ default: unknown;
23
+ }>> = {
24
+ [K in keyof T]: T[K]["default"];
25
+ };
26
+ /**
27
+ * Options for tracking the URL.
28
+ */
29
+ export type TrackUrlOptions<Ctx = unknown> = {
30
+ /** Optional function to customize or namespace the URL key depending on a context/index. */
31
+ keyFn?: (key: string, ctx?: Ctx) => string;
32
+ /** Optional context value (like an index or ID) passed to keyFn. */
33
+ ctx?: Ctx;
34
+ /** When false, use history.pushState instead of replaceState. Default: true */
35
+ replace?: boolean;
36
+ /** When false, skip the initial onChange call. Default: true */
37
+ fireOnMount?: boolean;
38
+ };
39
+ /**
40
+ * Handle returned by `trackUrl` for managing URL parameters of a component instance.
41
+ */
42
+ export type TrackUrlHandle<C extends Record<string, unknown>> = {
43
+ /** Update a single parameter value. */
44
+ setParam: <K extends keyof C>(key: K, value: C[K]) => void;
45
+ /** Update multiple parameter values at once. */
46
+ setParams: (updates: Partial<ParamValues<C>>) => void;
47
+ /** Get the current decoded parameter values. */
48
+ getParams: () => ParamValues<C>;
49
+ /** Get the current updated URLSearchParams representing only governed keys. */
50
+ getUpdatedURLSearchParams: () => URLSearchParams;
51
+ /** Re-read the URL and invoke onChange (same as the initial mount sync). */
52
+ refresh: () => void;
53
+ /** Unsubscribe from URL changes. */
54
+ disconnect: () => void;
55
+ /** List of query parameter keys governed by this instance. */
56
+ governedKeys: string[];
57
+ };
58
+ /** Callback type for URL changes. */
59
+ type UrlChangeListener = () => void;
60
+ /**
61
+ * Internal factory that creates trackers for a specific configuration of URL parameters.
62
+ * Encapsulates the logic of reading, writing, and separating parameter sets.
63
+ */
64
+ declare function createURLParamTracker<C extends Record<string, unknown>, Ctx = unknown>(config: {
65
+ [K in keyof C]: ParamDef<C[K]>;
66
+ }, keyFn?: (key: string, ctx?: Ctx) => string): {
67
+ separateIndexedSearchParams: (search: string | URLSearchParams, ctx?: Ctx) => URLSearchParams;
68
+ trackUrl: (onChange: (params: ParamValues<C>, updatedURLSearchParams: URLSearchParams, governedKeys: string[]) => void, options?: TrackUrlOptions<Ctx>) => TrackUrlHandle<C>;
69
+ readState: (search: string | URLSearchParams, ctx?: Ctx) => {
70
+ params: ParamValues<C>;
71
+ updatedURLSearchParams: URLSearchParams;
72
+ };
73
+ };
74
+ /**
75
+ * Vanilla counterpart to React `modURLSearchParams`. Define params once, then call
76
+ * `trackUrl(onChange)` or use the standalone `trackUrl(config, onChange)` helper.
77
+ */
78
+ export default function modURLSearchParams<C extends Record<string, unknown>, Ctx = unknown>(config: {
79
+ [K in keyof C]: ParamDef<C[K]>;
80
+ }, keyFn?: (key: string, ctx?: Ctx) => string): {
81
+ separateIndexedSearchParams: (search: string | URLSearchParams, ctx?: Ctx | undefined) => URLSearchParams;
82
+ trackUrl: (onChange: (params: C, updatedURLSearchParams: URLSearchParams, governedKeys: string[]) => void, options?: TrackUrlOptions<Ctx> | undefined) => TrackUrlHandle<C>;
83
+ readState: (search: string | URLSearchParams, ctx?: Ctx | undefined) => {
84
+ params: C;
85
+ updatedURLSearchParams: URLSearchParams;
86
+ };
87
+ };
88
+ /**
89
+ * Subscribe to URL changes for a fixed param schema. The callback runs only when
90
+ * tracked keys (per config) change — other query/hash navigation is ignored.
91
+ *
92
+ * @example
93
+ * const { setParam, setParams } = trackUrl(
94
+ * {
95
+ * emptyList: { default: false, getParam: "emp", encode: (v) => (v ? "1" : "0"), decode: (v) => v === "1" },
96
+ * },
97
+ * (params, updatedURLSearchParams) => { ... },
98
+ * );
99
+ */
100
+ export declare function trackUrl<C extends Record<string, unknown>, Ctx = unknown>(config: {
101
+ [K in keyof C]: ParamDef<C[K]>;
102
+ }, onChange: (params: ParamValues<C>, updatedURLSearchParams: URLSearchParams, governedKeys: string[]) => void, options?: TrackUrlOptions<Ctx> & {
103
+ keyFn?: (key: string, ctx?: Ctx) => string;
104
+ }): TrackUrlHandle<C>;
105
+ /** Subscribe to query-string updates (history push/replace/popstate). */
106
+ export declare function onUrlChange(listener: UrlChangeListener): () => void;
107
+ export { mergeURLSearchParams, createURLParamTracker, compareNormalizedSearchParams };
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1 @@
1
+ export {};
package/package.json ADDED
@@ -0,0 +1,44 @@
1
+ {
2
+ "name": "composite-monaco-diff",
3
+ "version": "1.0.2",
4
+ "type": "module",
5
+ "description": "Web component wrapper on top of monaco editor",
6
+ "scripts": {
7
+ "start": "node --env-file=.env server.ts",
8
+ "dev": "node --env-file=.env server.ts",
9
+ "monaco": "node --experimental-strip-types scripts/sync-monaco-version.ts",
10
+ "monaco:skip": "node --experimental-strip-types scripts/sync-monaco-version.ts --skip"
11
+ },
12
+ "keywords": [
13
+ "monaco",
14
+ "web-component",
15
+ "monaco-editor"
16
+ ],
17
+ "author": "Szymon Dzialowski",
18
+ "license": "GPL-2.0-only",
19
+ "repository": {
20
+ "type": "git",
21
+ "url": "git+https://github.com/stopsopa/monaco-editor-webcomponent.git"
22
+ },
23
+ "bugs": {
24
+ "url": "https://github.com/stopsopa/monaco-editor-webcomponent/issues"
25
+ },
26
+ "main": "./dist/esm/Module.js",
27
+ "types": "./dist/types/Module.d.ts",
28
+ "module": "./dist/esm/Module.js",
29
+ "exports": {
30
+ ".": {
31
+ "types": "./dist/types/Module.d.ts",
32
+ "import": "./dist/esm/Module.js",
33
+ "require": "./dist/cjs/Module.cjs"
34
+ },
35
+ "./package.json": "./package.json",
36
+ "./web-component/*": "./web-component/*",
37
+ "./*": {
38
+ "types": "./dist/types/*.d.ts",
39
+ "import": "./dist/esm/*.js",
40
+ "require": "./dist/cjs/*.js",
41
+ "default": "./*"
42
+ }
43
+ }
44
+ }
@@ -0,0 +1,413 @@
1
+ // web-component/trimLeft.js
2
+ function trimLeft(str, offset = 0) {
3
+ let o = typeof offset === "number" ? offset : parseInt(offset, 10);
4
+ if (isNaN(o)) {
5
+ throw new Error(`offset must be a number, ${offset}`);
6
+ }
7
+ if (o < 0) {
8
+ throw new Error(`offset must be a non-negative number, ${offset}`);
9
+ }
10
+ const lines = str.split("\n");
11
+ let diff = Infinity;
12
+ lines.forEach((line) => {
13
+ if (!/^\s*$/.test(line)) {
14
+ const lengthBefore = line.length;
15
+ const lengthAfter = line.replace(/^\s+/, "").length;
16
+ const indentation = lengthBefore - lengthAfter;
17
+ if (indentation < diff) {
18
+ diff = indentation;
19
+ }
20
+ }
21
+ });
22
+ let result = lines.map((line) => line.substring(diff));
23
+ if (o > 0) {
24
+ const spaces = " ".repeat(o);
25
+ result = result.map((line) => `${spaces}${line}`);
26
+ }
27
+ return result.join("\n");
28
+ }
29
+
30
+ // web-component/MonacoDiffManager.js
31
+ var MONACO_GENERATED = {
32
+ "version": "0.55.1",
33
+ "vs": [
34
+ "https://cdn.jsdelivr.net/npm/monaco-editor@0.55.1/min/vs",
35
+ "https://unpkg.com/monaco-editor@0.55.1/min/vs",
36
+ "/monaco/vs"
37
+ ]
38
+ };
39
+ var cachedMonaco = null;
40
+ var cachedVsBase = null;
41
+ var loadingPromise = null;
42
+ var MONACO_VS_STYLESHEET = /\/vs\/(base|editor|platform)/;
43
+ var MONACO_SHADOW_STYLES_ATTR = "data-monaco-shadow-styles";
44
+ function loadStylesheetLink(link) {
45
+ if (link.sheet) {
46
+ return Promise.resolve();
47
+ }
48
+ return new Promise((resolve, reject) => {
49
+ link.addEventListener("load", () => resolve(), { once: true });
50
+ link.addEventListener("error", () => reject(new Error(`Failed to load Monaco stylesheet: ${link.href}`)), {
51
+ once: true
52
+ });
53
+ });
54
+ }
55
+ async function ensureMonacoStylesInShadowRoot(container) {
56
+ const root = container.getRootNode();
57
+ if (!(root instanceof ShadowRoot)) {
58
+ return;
59
+ }
60
+ if (root.querySelector(`[${MONACO_SHADOW_STYLES_ATTR}]`)) {
61
+ return;
62
+ }
63
+ const documentLinks = Array.from(document.querySelectorAll("link[rel='stylesheet']")).filter((link) => {
64
+ const href = link.getAttribute("href") ?? "";
65
+ return MONACO_VS_STYLESHEET.test(href);
66
+ });
67
+ const loads = [];
68
+ for (const documentLink of documentLinks) {
69
+ const clone = documentLink.cloneNode(true);
70
+ clone.setAttribute(MONACO_SHADOW_STYLES_ATTR, "");
71
+ loads.push(loadStylesheetLink(clone));
72
+ root.insertBefore(clone, root.firstChild);
73
+ }
74
+ if (documentLinks.length === 0 && cachedVsBase) {
75
+ const link = document.createElement("link");
76
+ link.rel = "stylesheet";
77
+ link.href = `${cachedVsBase}/editor/editor.main.css`;
78
+ link.setAttribute(MONACO_SHADOW_STYLES_ATTR, "");
79
+ loads.push(loadStylesheetLink(link));
80
+ root.insertBefore(link, root.firstChild);
81
+ }
82
+ await Promise.all(loads);
83
+ }
84
+ function loadMonaco(vsBase) {
85
+ return new Promise((resolve, reject) => {
86
+ const win = window;
87
+ const finish = () => {
88
+ win.require?.config({ paths: { vs: vsBase } });
89
+ win.require?.(["vs/editor/editor.main"], () => {
90
+ if (win.monaco) {
91
+ resolve(win.monaco);
92
+ } else {
93
+ reject(new Error(`Monaco did not initialize from ${vsBase}`));
94
+ }
95
+ }, (err) => {
96
+ reject(err instanceof Error ? err : new Error(String(err)));
97
+ });
98
+ };
99
+ if (win.monaco) {
100
+ resolve(win.monaco);
101
+ return;
102
+ }
103
+ if (win.require) {
104
+ finish();
105
+ return;
106
+ }
107
+ const script = document.createElement("script");
108
+ script.src = `${vsBase}/loader.js`;
109
+ script.async = true;
110
+ script.onload = () => finish();
111
+ script.onerror = () => reject(new Error(`Failed to load Monaco loader from ${vsBase}`));
112
+ document.head.appendChild(script);
113
+ });
114
+ }
115
+ function hydrateCache(generated = MONACO_GENERATED) {
116
+ if (cachedMonaco) {
117
+ return Promise.resolve(cachedMonaco);
118
+ }
119
+ if (loadingPromise) {
120
+ return loadingPromise;
121
+ }
122
+ loadingPromise = (async () => {
123
+ const errors = [];
124
+ for (const vsBase of generated.vs) {
125
+ try {
126
+ cachedMonaco = await loadMonaco(vsBase);
127
+ cachedVsBase = vsBase;
128
+ return cachedMonaco;
129
+ } catch (err) {
130
+ errors.push(err instanceof Error ? err : new Error(String(err)));
131
+ }
132
+ }
133
+ loadingPromise = null;
134
+ throw new AggregateError(errors, `Failed to load monaco-editor@${generated.version} from all sources`);
135
+ })();
136
+ return loadingPromise;
137
+ }
138
+ var SCRIPT_TYPE_ORIGINAL = "text/original";
139
+ var SCRIPT_TYPE_MODIFIED = "text/modified";
140
+ function readDeclarativeDiffScripts(host) {
141
+ const scripts = Array.from(host.querySelectorAll(":scope > script"));
142
+ if (scripts.length === 0) {
143
+ return null;
144
+ }
145
+ if (scripts.length < 2) {
146
+ throw new Error(`<composite-monaco-diff>: expected exactly at leasttwo <script> elements (type="${SCRIPT_TYPE_ORIGINAL}" and type="${SCRIPT_TYPE_MODIFIED}"), found ${scripts.length}`);
147
+ }
148
+ let originalScript;
149
+ let modifiedScript;
150
+ for (const script of scripts) {
151
+ const type = script.getAttribute("type");
152
+ if (type === SCRIPT_TYPE_ORIGINAL) {
153
+ if (originalScript) {
154
+ throw new Error(`<composite-monaco-diff>: duplicate <script type="${SCRIPT_TYPE_ORIGINAL}">`);
155
+ }
156
+ originalScript = script;
157
+ } else if (type === SCRIPT_TYPE_MODIFIED) {
158
+ if (modifiedScript) {
159
+ throw new Error(`<composite-monaco-diff>: duplicate <script type="${SCRIPT_TYPE_MODIFIED}">`);
160
+ }
161
+ modifiedScript = script;
162
+ } else {
163
+ throw new Error(`<composite-monaco-diff>: <script> must have type="${SCRIPT_TYPE_ORIGINAL}" or type="${SCRIPT_TYPE_MODIFIED}"`);
164
+ }
165
+ }
166
+ if (!originalScript || !modifiedScript) {
167
+ const missing = !originalScript ? SCRIPT_TYPE_ORIGINAL : SCRIPT_TYPE_MODIFIED;
168
+ throw new Error(`<composite-monaco-diff>: missing <script type="${missing}">`);
169
+ }
170
+ let original = originalScript.textContent ?? "";
171
+ let modified = modifiedScript.textContent ?? "";
172
+ const originalLanguage = originalScript.getAttribute("lang") ?? void 0;
173
+ const modifiedLanguage = modifiedScript.getAttribute("lang") ?? void 0;
174
+ let originalOffset = parseInt(originalScript.getAttribute("data-offset"), 10) ?? 0;
175
+ let modifiedOffset = parseInt(modifiedScript.getAttribute("data-offset"), 10) ?? 0;
176
+ if (!(originalOffset > 0)) {
177
+ throw new Error(`<composite-monaco-diff><script type='text/original'>: data-offset must be a positive integer >${originalOffset}<`);
178
+ }
179
+ if (!(modifiedOffset > 0)) {
180
+ throw new Error(`<composite-monaco-diff><script type='text/modified'>: data-offset must be a positive integer >${modifiedOffset}<`);
181
+ }
182
+ original = trimLeft(original, originalOffset);
183
+ modified = trimLeft(modified, modifiedOffset);
184
+ originalScript.remove();
185
+ modifiedScript.remove();
186
+ return { original, modified, originalLanguage, modifiedLanguage };
187
+ }
188
+ var DEFAULT_LANGUAGE = "javascript";
189
+ function resolveDiffContent(options) {
190
+ let original = options.original ?? "";
191
+ let modified = options.modified ?? "";
192
+ let originalLanguage = options.originalLanguage;
193
+ let modifiedLanguage = options.modifiedLanguage;
194
+ if (options.host) {
195
+ const declarative = readDeclarativeDiffScripts(options.host);
196
+ if (declarative) {
197
+ original = declarative.original;
198
+ modified = declarative.modified;
199
+ originalLanguage = originalLanguage ?? declarative.originalLanguage;
200
+ modifiedLanguage = modifiedLanguage ?? declarative.modifiedLanguage;
201
+ }
202
+ }
203
+ const sharedLanguage = options.language;
204
+ return {
205
+ original,
206
+ modified,
207
+ originalLanguage: originalLanguage ?? sharedLanguage ?? DEFAULT_LANGUAGE,
208
+ modifiedLanguage: modifiedLanguage ?? sharedLanguage ?? DEFAULT_LANGUAGE
209
+ };
210
+ }
211
+ var MonacoDiffManager = class {
212
+ _readyPromise;
213
+ _editor = null;
214
+ _resizeObserver = null;
215
+ _layoutRaf = null;
216
+ _container;
217
+ /**
218
+ * Mounts a side-by-side diff editor into the given element: loads Monaco, applies styles,
219
+ * fills in original/modified text, and starts watching size changes.
220
+ */
221
+ constructor(container, options) {
222
+ this._container = container;
223
+ container.style.height = "100%";
224
+ container.style.width = "100%";
225
+ const { original, modified, originalLanguage, modifiedLanguage } = resolveDiffContent(options);
226
+ this._readyPromise = (async () => {
227
+ const monaco = await hydrateCache(MONACO_GENERATED);
228
+ await ensureMonacoStylesInShadowRoot(container);
229
+ this._editor = monaco.editor.createDiffEditor(container, {
230
+ automaticLayout: false,
231
+ scrollbar: {
232
+ vertical: "auto"
233
+ },
234
+ scrollBeyondLastLine: false,
235
+ ...options.editorOptions
236
+ });
237
+ this._editor.setModel({
238
+ original: monaco.editor.createModel(original, originalLanguage),
239
+ modified: monaco.editor.createModel(modified, modifiedLanguage)
240
+ });
241
+ this._scheduleLayout();
242
+ this._resizeObserver = new ResizeObserver(() => this._scheduleLayout());
243
+ this._resizeObserver.observe(container);
244
+ })();
245
+ }
246
+ /** Promise that resolves when the editor has finished loading and is safe to use. */
247
+ whenReady() {
248
+ return this._readyPromise;
249
+ }
250
+ /** Returns the underlying Monaco diff editor instance (or null if not ready yet). */
251
+ getEditor() {
252
+ return this._editor;
253
+ }
254
+ /** Returns the global Monaco API instance (or null if not loaded yet). */
255
+ getMonaco() {
256
+ return cachedMonaco;
257
+ }
258
+ /** Tears down the editor, frees memory, and stops listening for resize events. */
259
+ destroy() {
260
+ this._resizeObserver?.disconnect();
261
+ this._resizeObserver = null;
262
+ if (this._layoutRaf !== null) {
263
+ cancelAnimationFrame(this._layoutRaf);
264
+ this._layoutRaf = null;
265
+ }
266
+ const model = this._editor?.getModel();
267
+ this._editor?.dispose();
268
+ this._editor = null;
269
+ model?.original.dispose();
270
+ model?.modified.dispose();
271
+ }
272
+ /** Updates the language for both sides of the diff editor. Falls back to the default language when undefined. */
273
+ setLanguage(language) {
274
+ const model = this._editor?.getModel();
275
+ if (!model)
276
+ return;
277
+ const lang = language ?? DEFAULT_LANGUAGE;
278
+ cachedMonaco?.editor.setModelLanguage(model.original, lang);
279
+ cachedMonaco?.editor.setModelLanguage(model.modified, lang);
280
+ }
281
+ /** Resizes the editor to match its container on the next animation frame (avoids jank). */
282
+ _scheduleLayout() {
283
+ if (this._layoutRaf !== null)
284
+ return;
285
+ this._layoutRaf = requestAnimationFrame(() => {
286
+ this._layoutRaf = null;
287
+ if (!this._editor)
288
+ return;
289
+ const { width, height } = this._container.getBoundingClientRect();
290
+ if (width === 0 || height === 0) {
291
+ return;
292
+ }
293
+ this._editor.layout({ width, height });
294
+ });
295
+ }
296
+ };
297
+
298
+ // web-component/composite-monaco-diff.js
299
+ var tagName = "composite-monaco-diff";
300
+ var MONACO_THEMES = ["vs", "vs-dark", "hc-black", "hc-light"];
301
+ function isMonacoTheme(value) {
302
+ return MONACO_THEMES.includes(value);
303
+ }
304
+ function parseThemeAttribute(value) {
305
+ if (value && isMonacoTheme(value)) {
306
+ return value;
307
+ }
308
+ return void 0;
309
+ }
310
+ var MonacoDiffElement = class extends HTMLElement {
311
+ static tagName = tagName;
312
+ static get observedAttributes() {
313
+ return ["theme", "language"];
314
+ }
315
+ _container;
316
+ _manager = null;
317
+ constructor() {
318
+ super();
319
+ this.attachShadow({ mode: "open" });
320
+ this.shadowRoot.innerHTML = `
321
+ <style>
322
+ :host {
323
+ display: block;
324
+ width: 100%;
325
+ height: 100%;
326
+ min-height: 200px;
327
+ }
328
+ .container {
329
+ width: 100%;
330
+ height: 100%;
331
+ }
332
+ </style>
333
+ <div class="container"></div>
334
+ `;
335
+ this._container = this.shadowRoot.querySelector(".container");
336
+ }
337
+ connectedCallback() {
338
+ if (this._manager) {
339
+ return;
340
+ }
341
+ const theme = parseThemeAttribute(this.getAttribute("theme"));
342
+ const language = this.getAttribute("language") ?? void 0;
343
+ this._manager = new MonacoDiffManager(this._container, {
344
+ host: this,
345
+ language,
346
+ editorOptions: {
347
+ theme
348
+ }
349
+ });
350
+ }
351
+ attributeChangedCallback(name, _oldValue, newValue) {
352
+ if (name === "theme") {
353
+ void this._applyTheme(parseThemeAttribute(newValue));
354
+ } else if (name === "language") {
355
+ void this._applyLanguage(newValue ?? void 0);
356
+ }
357
+ }
358
+ disconnectedCallback() {
359
+ this._manager?.destroy();
360
+ this._manager = null;
361
+ }
362
+ /** Promise that resolves when the editor has finished loading and is safe to use. */
363
+ whenReady() {
364
+ if (!this._manager) {
365
+ throw new Error("<composite-monaco-diff>: not connected");
366
+ }
367
+ return this._manager.whenReady();
368
+ }
369
+ getManager() {
370
+ if (!this._manager) {
371
+ throw new Error("<composite-monaco-diff>: not connected");
372
+ }
373
+ return this._manager;
374
+ }
375
+ async _applyTheme(theme) {
376
+ if (!this._manager) {
377
+ return;
378
+ }
379
+ await this.whenReady();
380
+ const monaco = await hydrateCache();
381
+ monaco.editor.setTheme(theme ?? "vs");
382
+ }
383
+ async _applyLanguage(language) {
384
+ if (!this._manager) {
385
+ return;
386
+ }
387
+ await this.whenReady();
388
+ this._manager.setLanguage(language);
389
+ }
390
+ };
391
+ customElements.define(tagName, MonacoDiffElement);
392
+
393
+ // web-component/Module.ts
394
+ /** @es.ts
395
+ {
396
+ mode: "bundle",
397
+ extension: ".js",
398
+ options: {
399
+ }
400
+ }
401
+ @es.ts */// export * from "./react.js"
402
+ export {
403
+ MONACO_GENERATED,
404
+ MONACO_THEMES,
405
+ MonacoDiffElement,
406
+ MonacoDiffManager,
407
+ SCRIPT_TYPE_MODIFIED,
408
+ SCRIPT_TYPE_ORIGINAL,
409
+ hydrateCache,
410
+ isMonacoTheme,
411
+ readDeclarativeDiffScripts,
412
+ tagName
413
+ };