@singapore-editor/react 0.1.1
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/README.md +34 -0
- package/dist/index.d.ts +93 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +669 -0
- package/dist/index.js.map +1 -0
- package/package.json +53 -0
package/README.md
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
# @singapore-editor/react
|
|
2
|
+
|
|
3
|
+
React bindings for `@singapore-editor/core`.
|
|
4
|
+
|
|
5
|
+
## Install
|
|
6
|
+
|
|
7
|
+
```sh
|
|
8
|
+
npm install @singapore-editor/core @singapore-editor/react react react-dom
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Usage
|
|
12
|
+
|
|
13
|
+
```tsx
|
|
14
|
+
import { EditorHost, useEditor } from '@singapore-editor/react'
|
|
15
|
+
import '@singapore-editor/core/style.css'
|
|
16
|
+
|
|
17
|
+
export function EditorPanel() {
|
|
18
|
+
const controller = useEditor({
|
|
19
|
+
document: {
|
|
20
|
+
documentId: 'example.ts',
|
|
21
|
+
text: 'const value = 1;\n',
|
|
22
|
+
languageId: 'typescript',
|
|
23
|
+
},
|
|
24
|
+
})
|
|
25
|
+
|
|
26
|
+
return <EditorHost controller={controller} />
|
|
27
|
+
}
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
## Exports
|
|
31
|
+
|
|
32
|
+
- `useEditor` creates and synchronizes an editor controller with React state.
|
|
33
|
+
- `EditorHost` mounts the editor into the DOM.
|
|
34
|
+
- `useEditorSelector` subscribes to selected editor store values.
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
import { type EditorControlledSelection } from '@singapore-editor/core';
|
|
2
|
+
import { Editor, type EditorChangeHandler, type EditorCommandContext, type EditorCommandId, type EditorDocumentMode, type EditorDocumentAnalysis, type EditorEditInput, type EditorEditOptions, type EditorOpenDocumentOptions, type EditorOptions, type EditorPreparedDocument, type EditorPreparedTagValue, type EditorScrollPosition, type EditorSetSelectionOptions, type EditorSetTextOptions, type EditorState } from '@singapore-editor/core/editor';
|
|
3
|
+
import { type DocumentSession, type EditorTextBuffer, type EditorViewSession, type TextReadSnapshot, type TextSnapshot } from '@singapore-editor/core/document';
|
|
4
|
+
import type { EditorSyntaxLanguageId } from '@singapore-editor/core/syntax';
|
|
5
|
+
import type { EditorTheme, HiddenCharactersMode } from '@singapore-editor/core/rendering';
|
|
6
|
+
import type { EditorContributionChange, EditorInitialPaintEvent, EditorViewContributionUpdateKind, EditorViewSnapshot } from '@singapore-editor/core/extensions';
|
|
7
|
+
import { type CSSProperties, type ReactElement } from 'react';
|
|
8
|
+
export type ReactEditorDocument = {
|
|
9
|
+
readonly analysis?: EditorDocumentAnalysis | null;
|
|
10
|
+
readonly documentId?: string;
|
|
11
|
+
readonly revision?: string | number;
|
|
12
|
+
readonly buffer?: EditorTextBuffer | null;
|
|
13
|
+
readonly view?: EditorViewSession | null;
|
|
14
|
+
readonly session?: DocumentSession | null;
|
|
15
|
+
readonly text: string;
|
|
16
|
+
readonly documentMode?: EditorDocumentMode;
|
|
17
|
+
readonly documentConfigurationTag?: readonly EditorPreparedTagValue[];
|
|
18
|
+
readonly highlighterConfigurationTag?: readonly EditorPreparedTagValue[];
|
|
19
|
+
readonly languageId?: EditorSyntaxLanguageId | null;
|
|
20
|
+
readonly preparedDocument?: EditorPreparedDocument | null;
|
|
21
|
+
readonly scrollPosition?: EditorScrollPosition;
|
|
22
|
+
readonly textSyncMode?: ReactEditorDocumentTextSyncMode;
|
|
23
|
+
readonly structuralConfigurationTag?: readonly EditorPreparedTagValue[];
|
|
24
|
+
};
|
|
25
|
+
export type ReactEditorDocumentTextSyncMode = 'open' | 'incremental';
|
|
26
|
+
export type ReactEditorSelection = EditorControlledSelection;
|
|
27
|
+
export type ReactEditorOptions = Omit<EditorOptions, 'hiddenCharacters' | 'onChange' | 'onInitialPaint' | 'theme'> & {
|
|
28
|
+
readonly document?: ReactEditorDocument | null | undefined;
|
|
29
|
+
readonly theme?: EditorTheme | null | undefined;
|
|
30
|
+
readonly hiddenCharacters?: HiddenCharactersMode | undefined;
|
|
31
|
+
readonly selection?: ReactEditorSelection | null | undefined;
|
|
32
|
+
readonly scrollPosition?: EditorScrollPosition | null | undefined;
|
|
33
|
+
readonly storeSync?: ReactEditorStoreSyncMode;
|
|
34
|
+
readonly onChange?: EditorChangeHandler;
|
|
35
|
+
readonly onInitialPaint?: (event: EditorInitialPaintEvent) => void;
|
|
36
|
+
};
|
|
37
|
+
export type ReactEditorStoreSyncMode = 'full' | 'none';
|
|
38
|
+
export type ReactEditorCommands = {
|
|
39
|
+
focus(): void;
|
|
40
|
+
openDocument(document: EditorOpenDocumentOptions): void;
|
|
41
|
+
setText(text: string, options?: EditorSetTextOptions): void;
|
|
42
|
+
edit(editOrEdits: EditorEditInput, options?: EditorEditOptions): void;
|
|
43
|
+
setSelection(anchor: number, head?: number, options?: EditorSetSelectionOptions): void;
|
|
44
|
+
setScrollPosition(scrollPosition: EditorScrollPosition): void;
|
|
45
|
+
dispatchCommand(command: EditorCommandId, context?: EditorCommandContext): boolean;
|
|
46
|
+
openFind(): boolean;
|
|
47
|
+
openFindReplace(): boolean;
|
|
48
|
+
closeFind(): boolean;
|
|
49
|
+
findNext(): boolean;
|
|
50
|
+
findPrevious(): boolean;
|
|
51
|
+
replaceOne(): boolean;
|
|
52
|
+
replaceAll(): boolean;
|
|
53
|
+
selectAllMatches(): boolean;
|
|
54
|
+
};
|
|
55
|
+
export type ReactEditorStoreSnapshot = {
|
|
56
|
+
readonly editor: Editor | null;
|
|
57
|
+
readonly state: EditorState | null;
|
|
58
|
+
readonly snapshot: EditorViewSnapshot | null;
|
|
59
|
+
readonly textSnapshot: TextReadSnapshot | null;
|
|
60
|
+
readonly lastChange: EditorContributionChange | null;
|
|
61
|
+
readonly updateKind: EditorViewContributionUpdateKind | null;
|
|
62
|
+
};
|
|
63
|
+
export type ReactEditorSelector<T> = (snapshot: ReactEditorStoreSnapshot) => T;
|
|
64
|
+
export type ReactEditorSelectorEquality<T> = (current: T, next: T) => boolean;
|
|
65
|
+
export type ReactEditorController = {
|
|
66
|
+
mount(element: HTMLElement): void;
|
|
67
|
+
dispose(): void;
|
|
68
|
+
getEditor(): Editor | null;
|
|
69
|
+
getState(): EditorState | null;
|
|
70
|
+
getSnapshot(): EditorViewSnapshot | null;
|
|
71
|
+
getTextSnapshot(): TextSnapshot | null;
|
|
72
|
+
materializeFullText(): string;
|
|
73
|
+
getLastChange(): EditorContributionChange | null;
|
|
74
|
+
getUpdateKind(): EditorViewContributionUpdateKind | null;
|
|
75
|
+
useEditorInstance(): Editor | null;
|
|
76
|
+
useState(): EditorState | null;
|
|
77
|
+
useSnapshot(): EditorViewSnapshot | null;
|
|
78
|
+
useTextSnapshot(): TextReadSnapshot | null;
|
|
79
|
+
/** Re-renders with the whole text on every text revision: O(document length) each time. */
|
|
80
|
+
useFullText(): string;
|
|
81
|
+
useLastChange(): EditorContributionChange | null;
|
|
82
|
+
useUpdateKind(): EditorViewContributionUpdateKind | null;
|
|
83
|
+
readonly commands: ReactEditorCommands;
|
|
84
|
+
};
|
|
85
|
+
export type EditorHostProps = {
|
|
86
|
+
readonly controller: ReactEditorController;
|
|
87
|
+
readonly className?: string;
|
|
88
|
+
readonly style?: CSSProperties;
|
|
89
|
+
};
|
|
90
|
+
export declare function useEditor(options?: ReactEditorOptions): ReactEditorController;
|
|
91
|
+
export declare function EditorHost({ controller, className, style }: EditorHostProps): ReactElement;
|
|
92
|
+
export declare function useEditorSelector<T>(controller: ReactEditorController, selector: ReactEditorSelector<T>, isEqual?: ReactEditorSelectorEquality<T>): T;
|
|
93
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.tsx"],"names":[],"mappings":"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"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,669 @@
|
|
|
1
|
+
import { EDITOR_OPTION_DESCRIPTORS, createEditorOptionSync } from "@singapore-editor/core";
|
|
2
|
+
import { Editor } from "@singapore-editor/core/editor";
|
|
3
|
+
import { createEditorBufferSession } from "@singapore-editor/core/document";
|
|
4
|
+
import { useCallback, useEffect, useLayoutEffect, useRef, useState, useSyncExternalStore } from "react";
|
|
5
|
+
import { jsx } from "react/jsx-runtime";
|
|
6
|
+
//#region src/index.tsx
|
|
7
|
+
var CONTROLLER_PRIVATE = Symbol("controller-private");
|
|
8
|
+
var NO_DOCUMENT = Symbol("no-document");
|
|
9
|
+
var EMPTY_PLUGINS = [];
|
|
10
|
+
var DOCUMENT_OPTION_NAMES = /* @__PURE__ */ new Set([
|
|
11
|
+
"rangeDecorations",
|
|
12
|
+
"selection",
|
|
13
|
+
"scrollPosition"
|
|
14
|
+
]);
|
|
15
|
+
var CONFIGURATION_OPTIONS = EDITOR_OPTION_DESCRIPTORS.filter((descriptor) => !DOCUMENT_OPTION_NAMES.has(descriptor.name));
|
|
16
|
+
var DOCUMENT_OPTIONS = EDITOR_OPTION_DESCRIPTORS.filter((descriptor) => DOCUMENT_OPTION_NAMES.has(descriptor.name));
|
|
17
|
+
var useEditorLayoutEffect = typeof document === "undefined" ? useEffect : useLayoutEffect;
|
|
18
|
+
var selectEditor = (snapshot) => snapshot.editor;
|
|
19
|
+
var selectState = (snapshot) => snapshot.state;
|
|
20
|
+
var selectSnapshot = (snapshot) => snapshot.snapshot;
|
|
21
|
+
var selectTextSnapshot = (snapshot) => snapshot.textSnapshot;
|
|
22
|
+
var selectLastChange = (snapshot) => snapshot.lastChange;
|
|
23
|
+
var selectUpdateKind = (snapshot) => snapshot.updateKind;
|
|
24
|
+
function useEditor(options = {}) {
|
|
25
|
+
const [controller] = useState(() => new ReactEditorControllerImplementation(options));
|
|
26
|
+
controller.setOptions(options);
|
|
27
|
+
useControlledOptionSync(controller, options);
|
|
28
|
+
useEffect(() => {
|
|
29
|
+
controller.retainReactOwner();
|
|
30
|
+
return () => controller.scheduleReactDispose();
|
|
31
|
+
}, [controller]);
|
|
32
|
+
return controller;
|
|
33
|
+
}
|
|
34
|
+
function EditorHost({ controller, className, style }) {
|
|
35
|
+
const hostRef = useRef(null);
|
|
36
|
+
useEditorLayoutEffect(() => {
|
|
37
|
+
const element = hostRef.current;
|
|
38
|
+
if (!element) return;
|
|
39
|
+
controller.mount(element);
|
|
40
|
+
return () => internalController(controller).scheduleReactDispose();
|
|
41
|
+
}, [controller]);
|
|
42
|
+
return /* @__PURE__ */ jsx("div", {
|
|
43
|
+
ref: hostRef,
|
|
44
|
+
className,
|
|
45
|
+
style
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
function useEditorSelector(controller, selector, isEqual = Object.is) {
|
|
49
|
+
const store = internalController(controller).store;
|
|
50
|
+
const [subscription] = useState(() => store.createSubscription(selector, isEqual));
|
|
51
|
+
store.refreshSubscription(subscription, selector, isEqual);
|
|
52
|
+
const subscribe = useCallback((notify) => store.subscribe(subscription, notify), [store, subscription]);
|
|
53
|
+
const getSnapshot = useCallback(() => subscription.value, [subscription]);
|
|
54
|
+
return useSyncExternalStore(subscribe, getSnapshot, getSnapshot);
|
|
55
|
+
}
|
|
56
|
+
var ReactEditorControllerImplementation = class {
|
|
57
|
+
[CONTROLLER_PRIVATE] = this;
|
|
58
|
+
store = new ReactEditorStore();
|
|
59
|
+
commands;
|
|
60
|
+
reactSyncPlugin;
|
|
61
|
+
documentState = createDocumentState();
|
|
62
|
+
optionSync = createEditorOptionSync();
|
|
63
|
+
syncedPlugins = null;
|
|
64
|
+
syncedStoreSyncMode = null;
|
|
65
|
+
syncedSnapshotEligibility = null;
|
|
66
|
+
requestedDocumentGeneration = 0;
|
|
67
|
+
editorIncarnation = 0;
|
|
68
|
+
mountedElement = null;
|
|
69
|
+
scheduledDisposeGeneration = null;
|
|
70
|
+
nextDisposeGeneration = 0;
|
|
71
|
+
suspendedStoreFields = null;
|
|
72
|
+
options;
|
|
73
|
+
constructor(options) {
|
|
74
|
+
this.options = options;
|
|
75
|
+
this.reactSyncPlugin = createReactSyncPlugin(this);
|
|
76
|
+
this.commands = createCommands(() => this.getEditor(), this.documentState);
|
|
77
|
+
}
|
|
78
|
+
mount(element) {
|
|
79
|
+
this.retainReactOwner();
|
|
80
|
+
if (this.mountedElement === element && this.getEditor()) return;
|
|
81
|
+
this.store.batch(() => {
|
|
82
|
+
this.disposeImmediately();
|
|
83
|
+
this.mountedElement = element;
|
|
84
|
+
this.mountEditor(element);
|
|
85
|
+
});
|
|
86
|
+
}
|
|
87
|
+
dispose() {
|
|
88
|
+
this.retainReactOwner();
|
|
89
|
+
this.disposeImmediately();
|
|
90
|
+
}
|
|
91
|
+
retainReactOwner() {
|
|
92
|
+
this.scheduledDisposeGeneration = null;
|
|
93
|
+
this.resumeSuspendedEditor();
|
|
94
|
+
}
|
|
95
|
+
scheduleReactDispose() {
|
|
96
|
+
if (this.scheduledDisposeGeneration !== null) return;
|
|
97
|
+
this.nextDisposeGeneration += 1;
|
|
98
|
+
const generation = this.nextDisposeGeneration;
|
|
99
|
+
this.scheduledDisposeGeneration = generation;
|
|
100
|
+
this.suspendEditor();
|
|
101
|
+
queueMicrotask(() => {
|
|
102
|
+
if (this.scheduledDisposeGeneration !== generation) return;
|
|
103
|
+
this.scheduledDisposeGeneration = null;
|
|
104
|
+
this.disposeImmediately();
|
|
105
|
+
});
|
|
106
|
+
}
|
|
107
|
+
disposeImmediately() {
|
|
108
|
+
this.store.batch(() => {
|
|
109
|
+
this.editorIncarnation += 1;
|
|
110
|
+
this.suspendedStoreFields?.editor?.dispose();
|
|
111
|
+
this.suspendedStoreFields = null;
|
|
112
|
+
disposeEditor(this.store);
|
|
113
|
+
this.mountedElement = null;
|
|
114
|
+
this.documentState.clear();
|
|
115
|
+
this.optionSync.reset();
|
|
116
|
+
this.clearSyncedPlugins();
|
|
117
|
+
this.syncedSnapshotEligibility = null;
|
|
118
|
+
});
|
|
119
|
+
}
|
|
120
|
+
suspendEditor() {
|
|
121
|
+
const snapshot = this.store.read();
|
|
122
|
+
if (!snapshot.editor) return;
|
|
123
|
+
this.suspendedStoreFields = snapshot;
|
|
124
|
+
this.store.update(createEmptyStoreSnapshot());
|
|
125
|
+
}
|
|
126
|
+
resumeSuspendedEditor() {
|
|
127
|
+
const suspended = this.suspendedStoreFields;
|
|
128
|
+
if (!suspended) return;
|
|
129
|
+
this.suspendedStoreFields = null;
|
|
130
|
+
this.store.update(suspended);
|
|
131
|
+
}
|
|
132
|
+
setOptions(options) {
|
|
133
|
+
this.options = options;
|
|
134
|
+
}
|
|
135
|
+
getEditor() {
|
|
136
|
+
return this.store.read().editor;
|
|
137
|
+
}
|
|
138
|
+
getState() {
|
|
139
|
+
return this.getEditor()?.getState() ?? null;
|
|
140
|
+
}
|
|
141
|
+
getSnapshot() {
|
|
142
|
+
return this.store.read().snapshot;
|
|
143
|
+
}
|
|
144
|
+
getTextSnapshot() {
|
|
145
|
+
return this.getEditor()?.getTextSnapshot() ?? null;
|
|
146
|
+
}
|
|
147
|
+
materializeFullText() {
|
|
148
|
+
return this.getEditor()?.materializeFullText() ?? "";
|
|
149
|
+
}
|
|
150
|
+
getLastChange() {
|
|
151
|
+
return this.store.read().lastChange;
|
|
152
|
+
}
|
|
153
|
+
getUpdateKind() {
|
|
154
|
+
return this.store.read().updateKind;
|
|
155
|
+
}
|
|
156
|
+
useEditorInstance = () => useEditorSelector(this, selectEditor);
|
|
157
|
+
useState = () => useEditorSelector(this, selectState);
|
|
158
|
+
useSnapshot = () => useEditorSelector(this, selectSnapshot);
|
|
159
|
+
useTextSnapshot = () => useEditorSelector(this, selectTextSnapshot);
|
|
160
|
+
useFullText = () => {
|
|
161
|
+
const [selectFullText] = useState(createFullTextSelector);
|
|
162
|
+
return useEditorSelector(this, selectFullText);
|
|
163
|
+
};
|
|
164
|
+
useLastChange = () => useEditorSelector(this, selectLastChange);
|
|
165
|
+
useUpdateKind = () => useEditorSelector(this, selectUpdateKind);
|
|
166
|
+
syncDocumentOption() {
|
|
167
|
+
const editor = this.getEditor();
|
|
168
|
+
if (!editor) return;
|
|
169
|
+
this.syncSnapshotEligibility(editor);
|
|
170
|
+
this.syncAuthoritativeDocument(editor);
|
|
171
|
+
}
|
|
172
|
+
syncConfigurationOptions() {
|
|
173
|
+
this.applyControlledOptions(this.getEditor(), CONFIGURATION_OPTIONS);
|
|
174
|
+
}
|
|
175
|
+
syncDocumentControls() {
|
|
176
|
+
this.applyControlledOptions(this.getEditor(), DOCUMENT_OPTIONS);
|
|
177
|
+
}
|
|
178
|
+
syncPluginsOption() {
|
|
179
|
+
const editor = this.getEditor();
|
|
180
|
+
if (!editor) return;
|
|
181
|
+
if (this.pluginsSynced(this.options)) return;
|
|
182
|
+
syncPlugins(editor, this.reactSyncPlugin, this.options);
|
|
183
|
+
this.markPluginsSynced(this.options);
|
|
184
|
+
}
|
|
185
|
+
syncSnapshot(snapshot, kind, change) {
|
|
186
|
+
if (!this.shouldSyncStore()) return;
|
|
187
|
+
if (this.getEditor()?.getPresentationState() === "provisional") return;
|
|
188
|
+
const patch = {
|
|
189
|
+
snapshot,
|
|
190
|
+
textSnapshot: snapshot.textSnapshot,
|
|
191
|
+
lastChange: change,
|
|
192
|
+
updateKind: kind,
|
|
193
|
+
...kind === "selection" ? { state: this.getEditor()?.getState() ?? null } : {}
|
|
194
|
+
};
|
|
195
|
+
this.store.update(patch);
|
|
196
|
+
}
|
|
197
|
+
syncChange(state, change) {
|
|
198
|
+
if (!this.shouldSyncStore()) return;
|
|
199
|
+
this.store.update({
|
|
200
|
+
state,
|
|
201
|
+
textSnapshot: this.getEditor()?.getTextSnapshot() ?? null,
|
|
202
|
+
lastChange: change
|
|
203
|
+
});
|
|
204
|
+
}
|
|
205
|
+
mountEditor(element) {
|
|
206
|
+
this.editorIncarnation += 1;
|
|
207
|
+
const editorIncarnation = this.editorIncarnation;
|
|
208
|
+
const instance = new Editor(element, this.createConstructorOptions(editorIncarnation));
|
|
209
|
+
this.markPluginsSynced(this.options);
|
|
210
|
+
this.syncedSnapshotEligibility = snapshotEligibility(this.options);
|
|
211
|
+
this.store.update({
|
|
212
|
+
editor: instance,
|
|
213
|
+
state: instance.getState(),
|
|
214
|
+
textSnapshot: instance.getTextSnapshot()
|
|
215
|
+
});
|
|
216
|
+
if (instance.getPresentationState() === "provisional") this.clearPresentedSnapshot();
|
|
217
|
+
this.syncMountedOptions(instance);
|
|
218
|
+
}
|
|
219
|
+
createConstructorOptions(editorIncarnation) {
|
|
220
|
+
const { document: _document, hiddenCharacters, onChange: _onChange, onInitialPaint: _onInitialPaint, onPresentationChange: _onPresentationChange, plugins: _plugins, scrollPosition: _scrollPosition, selection: _selection, storeSync: _storeSync, theme, ...constructorOptions } = this.options;
|
|
221
|
+
return {
|
|
222
|
+
...constructorOptions,
|
|
223
|
+
snapshot: snapshotEligibility(this.options).snapshot,
|
|
224
|
+
hiddenCharacters,
|
|
225
|
+
theme: theme ?? void 0,
|
|
226
|
+
plugins: editorPluginsForOptions(this.reactSyncPlugin, this.options),
|
|
227
|
+
onChange: (state, change) => {
|
|
228
|
+
this.syncChange(state, change);
|
|
229
|
+
this.options.onChange?.(state, change);
|
|
230
|
+
},
|
|
231
|
+
onInitialPaint: (event) => this.forwardInitialPaint(event, editorIncarnation),
|
|
232
|
+
onPresentationChange: (state) => this.forwardPresentationChange(state, editorIncarnation)
|
|
233
|
+
};
|
|
234
|
+
}
|
|
235
|
+
forwardInitialPaint(event, editorIncarnation) {
|
|
236
|
+
const documentGeneration = this.documentState.generation();
|
|
237
|
+
const requestedDocumentKey = this.options.documentKey;
|
|
238
|
+
queueMicrotask(() => {
|
|
239
|
+
if (editorIncarnation !== this.editorIncarnation) return;
|
|
240
|
+
if (documentGeneration !== this.documentState.generation()) return;
|
|
241
|
+
if (requestedDocumentKey !== this.options.documentKey) return;
|
|
242
|
+
this.options.onInitialPaint?.(event);
|
|
243
|
+
});
|
|
244
|
+
}
|
|
245
|
+
syncMountedOptions(editor) {
|
|
246
|
+
this.syncAuthoritativeDocument(editor);
|
|
247
|
+
this.applyControlledOptions(editor);
|
|
248
|
+
}
|
|
249
|
+
syncAuthoritativeDocument(editor) {
|
|
250
|
+
syncDocument(editor, this.options.documentKey === null ? null : this.options.document, this.documentState);
|
|
251
|
+
}
|
|
252
|
+
syncSnapshotEligibility(editor) {
|
|
253
|
+
const next = snapshotEligibility(this.options);
|
|
254
|
+
const previous = this.syncedSnapshotEligibility;
|
|
255
|
+
if (previous?.documentKey === next.documentKey && previous.snapshot === next.snapshot) return;
|
|
256
|
+
if (previous && previous.documentKey !== next.documentKey) {
|
|
257
|
+
this.requestedDocumentGeneration += 1;
|
|
258
|
+
editor.clearDocument();
|
|
259
|
+
this.documentState.clear();
|
|
260
|
+
}
|
|
261
|
+
this.syncedSnapshotEligibility = next;
|
|
262
|
+
editor.setSnapshot(next.snapshot, next.documentKey);
|
|
263
|
+
}
|
|
264
|
+
forwardPresentationChange(state, editorIncarnation) {
|
|
265
|
+
if (state === "provisional") this.clearPresentedSnapshot();
|
|
266
|
+
const requestedDocumentKey = this.options.documentKey;
|
|
267
|
+
const requestedDocumentGeneration = this.requestedDocumentGeneration;
|
|
268
|
+
queueMicrotask(() => {
|
|
269
|
+
if (editorIncarnation !== this.editorIncarnation) return;
|
|
270
|
+
if (requestedDocumentKey !== this.options.documentKey) return;
|
|
271
|
+
if (requestedDocumentGeneration !== this.requestedDocumentGeneration) return;
|
|
272
|
+
if (this.getEditor()?.getPresentationState() !== state) return;
|
|
273
|
+
this.options.onPresentationChange?.(state);
|
|
274
|
+
});
|
|
275
|
+
}
|
|
276
|
+
clearPresentedSnapshot() {
|
|
277
|
+
this.store.update({
|
|
278
|
+
snapshot: null,
|
|
279
|
+
updateKind: null
|
|
280
|
+
});
|
|
281
|
+
}
|
|
282
|
+
applyControlledOptions(editor, descriptors = EDITOR_OPTION_DESCRIPTORS) {
|
|
283
|
+
for (const descriptor of descriptors) this.optionSync.apply(editor, descriptor, this.options[descriptor.name]);
|
|
284
|
+
}
|
|
285
|
+
shouldSyncStore() {
|
|
286
|
+
return reactEditorStoreSyncMode(this.options) === "full";
|
|
287
|
+
}
|
|
288
|
+
pluginsSynced(options) {
|
|
289
|
+
if (this.syncedStoreSyncMode !== reactEditorStoreSyncMode(options)) return false;
|
|
290
|
+
return samePlugins(this.syncedPlugins, options.plugins ?? EMPTY_PLUGINS);
|
|
291
|
+
}
|
|
292
|
+
markPluginsSynced(options) {
|
|
293
|
+
this.syncedPlugins = [...options.plugins ?? EMPTY_PLUGINS];
|
|
294
|
+
this.syncedStoreSyncMode = reactEditorStoreSyncMode(options);
|
|
295
|
+
}
|
|
296
|
+
clearSyncedPlugins() {
|
|
297
|
+
this.syncedPlugins = null;
|
|
298
|
+
this.syncedStoreSyncMode = null;
|
|
299
|
+
}
|
|
300
|
+
};
|
|
301
|
+
var ReactEditorStore = class {
|
|
302
|
+
snapshot = createEmptyStoreSnapshot();
|
|
303
|
+
subscriptions = /* @__PURE__ */ new Set();
|
|
304
|
+
version = 0;
|
|
305
|
+
batchDepth = 0;
|
|
306
|
+
notifyAfterBatch = false;
|
|
307
|
+
read() {
|
|
308
|
+
return this.snapshot;
|
|
309
|
+
}
|
|
310
|
+
update(patch) {
|
|
311
|
+
if (!hasStorePatchChange(this.snapshot, patch)) return;
|
|
312
|
+
this.snapshot = mergeStorePatch(this.snapshot, patch);
|
|
313
|
+
this.version += 1;
|
|
314
|
+
this.queueNotify();
|
|
315
|
+
}
|
|
316
|
+
batch(run) {
|
|
317
|
+
this.batchDepth += 1;
|
|
318
|
+
try {
|
|
319
|
+
return run();
|
|
320
|
+
} finally {
|
|
321
|
+
this.batchDepth -= 1;
|
|
322
|
+
this.flushBatchedNotify();
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
createSubscription(selector, isEqual) {
|
|
326
|
+
return {
|
|
327
|
+
selector,
|
|
328
|
+
isEqual,
|
|
329
|
+
value: selector(this.snapshot),
|
|
330
|
+
notify: null
|
|
331
|
+
};
|
|
332
|
+
}
|
|
333
|
+
refreshSubscription(subscription, selector, isEqual) {
|
|
334
|
+
subscription.selector = selector;
|
|
335
|
+
subscription.isEqual = isEqual;
|
|
336
|
+
this.refreshSubscriptionValue(subscription);
|
|
337
|
+
}
|
|
338
|
+
subscribe(subscription, notify) {
|
|
339
|
+
subscription.notify = notify;
|
|
340
|
+
this.refreshSubscriptionValue(subscription);
|
|
341
|
+
this.subscriptions.add(subscription);
|
|
342
|
+
return () => {
|
|
343
|
+
this.subscriptions.delete(subscription);
|
|
344
|
+
subscription.notify = null;
|
|
345
|
+
};
|
|
346
|
+
}
|
|
347
|
+
notify() {
|
|
348
|
+
for (const subscription of this.subscriptions) this.notifySubscription(subscription);
|
|
349
|
+
}
|
|
350
|
+
queueNotify() {
|
|
351
|
+
if (this.batchDepth === 0) {
|
|
352
|
+
this.notify();
|
|
353
|
+
return;
|
|
354
|
+
}
|
|
355
|
+
this.notifyAfterBatch = true;
|
|
356
|
+
}
|
|
357
|
+
flushBatchedNotify() {
|
|
358
|
+
if (this.batchDepth > 0) return;
|
|
359
|
+
if (!this.notifyAfterBatch) return;
|
|
360
|
+
this.notifyAfterBatch = false;
|
|
361
|
+
this.notify();
|
|
362
|
+
}
|
|
363
|
+
notifySubscription(subscription) {
|
|
364
|
+
const nextValue = subscription.selector(this.snapshot);
|
|
365
|
+
if (subscription.isEqual(subscription.value, nextValue)) return;
|
|
366
|
+
subscription.value = nextValue;
|
|
367
|
+
subscription.notify?.();
|
|
368
|
+
}
|
|
369
|
+
refreshSubscriptionValue(subscription) {
|
|
370
|
+
const nextValue = subscription.selector(this.snapshot);
|
|
371
|
+
if (subscription.isEqual(subscription.value, nextValue)) return;
|
|
372
|
+
subscription.value = nextValue;
|
|
373
|
+
}
|
|
374
|
+
};
|
|
375
|
+
function useControlledOptionSync(controller, options) {
|
|
376
|
+
const documentIdentity = documentKey(options.document);
|
|
377
|
+
useEditorLayoutEffect(() => controller.syncPluginsOption(), [
|
|
378
|
+
controller,
|
|
379
|
+
options.plugins,
|
|
380
|
+
options.storeSync
|
|
381
|
+
]);
|
|
382
|
+
useEditorLayoutEffect(() => controller.syncConfigurationOptions());
|
|
383
|
+
useEditorLayoutEffect(() => controller.syncDocumentOption(), [
|
|
384
|
+
controller,
|
|
385
|
+
documentIdentity,
|
|
386
|
+
options.documentKey,
|
|
387
|
+
options.snapshot
|
|
388
|
+
]);
|
|
389
|
+
useEditorLayoutEffect(() => controller.syncDocumentControls());
|
|
390
|
+
}
|
|
391
|
+
function snapshotEligibility(options) {
|
|
392
|
+
return {
|
|
393
|
+
documentKey: options.documentKey ?? null,
|
|
394
|
+
snapshot: options.documentKey === null ? null : options.snapshot ?? null
|
|
395
|
+
};
|
|
396
|
+
}
|
|
397
|
+
function createReactSyncPlugin(controller) {
|
|
398
|
+
return {
|
|
399
|
+
name: "react-editor-sync",
|
|
400
|
+
activate: (context) => context.registerViewContribution({ createContribution: () => ({
|
|
401
|
+
update: (snapshot, kind, change) => controller.syncSnapshot(snapshot, kind, change ?? null),
|
|
402
|
+
dispose: () => void 0
|
|
403
|
+
}) })
|
|
404
|
+
};
|
|
405
|
+
}
|
|
406
|
+
function syncDocument(editor, document, state) {
|
|
407
|
+
if (!editor) return;
|
|
408
|
+
const key = documentKey(document);
|
|
409
|
+
if (key === state.key()) return;
|
|
410
|
+
const identityKey = documentIdentityKey(document);
|
|
411
|
+
const previousIdentityKey = state.identityKey();
|
|
412
|
+
state.setKey(key, identityKey);
|
|
413
|
+
if (!document) {
|
|
414
|
+
editor.clearDocument();
|
|
415
|
+
return;
|
|
416
|
+
}
|
|
417
|
+
const session = reactEditorDocumentSession(document);
|
|
418
|
+
if (session) {
|
|
419
|
+
editor.attachSession(session, {
|
|
420
|
+
analysis: document.analysis,
|
|
421
|
+
documentId: document.documentId,
|
|
422
|
+
documentConfigurationTag: document.documentConfigurationTag,
|
|
423
|
+
highlighterConfigurationTag: document.highlighterConfigurationTag,
|
|
424
|
+
languageId: document.languageId,
|
|
425
|
+
preparedDocument: document.preparedDocument,
|
|
426
|
+
scrollPosition: reactEditorDocumentScrollPosition(document),
|
|
427
|
+
structuralConfigurationTag: document.structuralConfigurationTag
|
|
428
|
+
});
|
|
429
|
+
return;
|
|
430
|
+
}
|
|
431
|
+
if (canSyncDocumentTextIncrementally(document, previousIdentityKey, identityKey)) {
|
|
432
|
+
editor.syncText(document.text, {
|
|
433
|
+
documentMode: document.documentMode,
|
|
434
|
+
languageId: document.languageId,
|
|
435
|
+
scrollPosition: reactEditorDocumentScrollPosition(document)
|
|
436
|
+
});
|
|
437
|
+
return;
|
|
438
|
+
}
|
|
439
|
+
editor.openDocument({
|
|
440
|
+
documentId: document.documentId,
|
|
441
|
+
documentMode: document.documentMode,
|
|
442
|
+
languageId: document.languageId,
|
|
443
|
+
scrollPosition: reactEditorDocumentScrollPosition(document),
|
|
444
|
+
text: document.text
|
|
445
|
+
});
|
|
446
|
+
}
|
|
447
|
+
function canSyncDocumentTextIncrementally(document, previousIdentityKey, identityKey) {
|
|
448
|
+
if (document.textSyncMode !== "incremental") return false;
|
|
449
|
+
if (previousIdentityKey === NO_DOCUMENT) return false;
|
|
450
|
+
return previousIdentityKey === identityKey;
|
|
451
|
+
}
|
|
452
|
+
function syncPlugins(editor, reactSyncPlugin, options) {
|
|
453
|
+
if (!editor) return;
|
|
454
|
+
editor.setPlugins(editorPluginsForOptions(reactSyncPlugin, options));
|
|
455
|
+
}
|
|
456
|
+
function editorPluginsForOptions(reactSyncPlugin, options) {
|
|
457
|
+
if (reactEditorStoreSyncMode(options) === "none") return options.plugins ?? [];
|
|
458
|
+
return [reactSyncPlugin, ...options.plugins ?? []];
|
|
459
|
+
}
|
|
460
|
+
function reactEditorStoreSyncMode(options) {
|
|
461
|
+
return options.storeSync ?? "full";
|
|
462
|
+
}
|
|
463
|
+
function samePlugins(left, right) {
|
|
464
|
+
if (!left) return false;
|
|
465
|
+
if (left.length !== right.length) return false;
|
|
466
|
+
return left.every((plugin, index) => plugin === right[index]);
|
|
467
|
+
}
|
|
468
|
+
function disposeEditor(store) {
|
|
469
|
+
store.read().editor?.dispose();
|
|
470
|
+
store.update(createEmptyStoreSnapshot());
|
|
471
|
+
}
|
|
472
|
+
function createCommands(editor, documentState) {
|
|
473
|
+
return {
|
|
474
|
+
focus: () => editor()?.focus(),
|
|
475
|
+
openDocument: (document) => {
|
|
476
|
+
documentState.setKey(documentKey(document), documentIdentityKey(document));
|
|
477
|
+
editor()?.openDocument(document);
|
|
478
|
+
},
|
|
479
|
+
setText: (text, options) => editor()?.setText(text, options),
|
|
480
|
+
edit: (editOrEdits, options) => editor()?.edit(editOrEdits, options),
|
|
481
|
+
setSelection: (anchor, head, options) => editor()?.setSelection(anchor, head, options),
|
|
482
|
+
setScrollPosition: (scrollPosition) => editor()?.setScrollPosition(scrollPosition),
|
|
483
|
+
dispatchCommand: (command, context) => editor()?.dispatchCommand(command, context) ?? false,
|
|
484
|
+
openFind: () => editor()?.openFind() ?? false,
|
|
485
|
+
openFindReplace: () => editor()?.openFindReplace() ?? false,
|
|
486
|
+
closeFind: () => editor()?.closeFind() ?? false,
|
|
487
|
+
findNext: () => editor()?.findNext() ?? false,
|
|
488
|
+
findPrevious: () => editor()?.findPrevious() ?? false,
|
|
489
|
+
replaceOne: () => editor()?.replaceOne() ?? false,
|
|
490
|
+
replaceAll: () => editor()?.replaceAll() ?? false,
|
|
491
|
+
selectAllMatches: () => editor()?.selectAllMatches() ?? false
|
|
492
|
+
};
|
|
493
|
+
}
|
|
494
|
+
function createDocumentState() {
|
|
495
|
+
let generation = 0;
|
|
496
|
+
let key = NO_DOCUMENT;
|
|
497
|
+
let identityKey = NO_DOCUMENT;
|
|
498
|
+
return {
|
|
499
|
+
generation: () => generation,
|
|
500
|
+
key: () => key,
|
|
501
|
+
identityKey: () => identityKey,
|
|
502
|
+
setKey: (nextKey, nextIdentityKey = nextKey) => {
|
|
503
|
+
generation += 1;
|
|
504
|
+
key = nextKey;
|
|
505
|
+
identityKey = nextIdentityKey;
|
|
506
|
+
},
|
|
507
|
+
clear: () => {
|
|
508
|
+
generation += 1;
|
|
509
|
+
key = NO_DOCUMENT;
|
|
510
|
+
identityKey = NO_DOCUMENT;
|
|
511
|
+
}
|
|
512
|
+
};
|
|
513
|
+
}
|
|
514
|
+
function documentKey(document) {
|
|
515
|
+
if (!document) return NO_DOCUMENT;
|
|
516
|
+
const incremental = document.textSyncMode === "incremental";
|
|
517
|
+
const liveSession = documentHasLiveBuffer(document) || documentHasLiveSession(document);
|
|
518
|
+
const revision = documentRevisionKey(document, incremental);
|
|
519
|
+
const textVersion = incremental && !liveSession ? document.text ?? "" : "";
|
|
520
|
+
const identityKey = documentIdentityKey(document);
|
|
521
|
+
if (identityKey === NO_DOCUMENT) return NO_DOCUMENT;
|
|
522
|
+
return `${identityKey}\u0000${revision}\u0000${textVersion}\u0000${preparedDocumentIdentity(document.preparedDocument)}\u0000${analysisIdentity(document.analysis ?? document.preparedDocument?.analysis)}\u0000${preparedTagsKey(document)}`;
|
|
523
|
+
}
|
|
524
|
+
function documentRevisionKey(document, incremental) {
|
|
525
|
+
if (documentHasLiveBuffer(document)) return "";
|
|
526
|
+
if (incremental) return "";
|
|
527
|
+
if (documentHasLiveSession(document)) return "";
|
|
528
|
+
return document.revision ?? "";
|
|
529
|
+
}
|
|
530
|
+
function documentIdentityKey(document) {
|
|
531
|
+
if (!document) return NO_DOCUMENT;
|
|
532
|
+
const session = "session" in document ? document.session : null;
|
|
533
|
+
const buffer = "buffer" in document ? document.buffer : null;
|
|
534
|
+
const view = "view" in document ? document.view : null;
|
|
535
|
+
return `${document.documentId ?? ""}\u0000${document.documentMode ?? ""}\u0000${document.languageId ?? ""}\u0000${sessionIdentity(session)}\u0000${bufferViewIdentity(buffer, view)}`;
|
|
536
|
+
}
|
|
537
|
+
var sessionKeys = /* @__PURE__ */ new WeakMap();
|
|
538
|
+
var preparedDocumentKeys = /* @__PURE__ */ new WeakMap();
|
|
539
|
+
var analysisKeys = /* @__PURE__ */ new WeakMap();
|
|
540
|
+
var bufferKeys = /* @__PURE__ */ new WeakMap();
|
|
541
|
+
var viewKeys = /* @__PURE__ */ new WeakMap();
|
|
542
|
+
var bufferViewSessions = /* @__PURE__ */ new WeakMap();
|
|
543
|
+
var nextSessionKey = 1;
|
|
544
|
+
var nextPreparedDocumentKey = 1;
|
|
545
|
+
var nextAnalysisKey = 1;
|
|
546
|
+
var nextBufferKey = 1;
|
|
547
|
+
var nextViewKey = 1;
|
|
548
|
+
function sessionIdentity(session) {
|
|
549
|
+
if (!session) return "";
|
|
550
|
+
const existing = sessionKeys.get(session);
|
|
551
|
+
if (existing !== void 0) return `${existing}`;
|
|
552
|
+
const key = nextSessionKey;
|
|
553
|
+
nextSessionKey += 1;
|
|
554
|
+
sessionKeys.set(session, key);
|
|
555
|
+
return `${key}`;
|
|
556
|
+
}
|
|
557
|
+
function preparedDocumentIdentity(preparedDocument) {
|
|
558
|
+
if (!preparedDocument) return "";
|
|
559
|
+
const existing = preparedDocumentKeys.get(preparedDocument);
|
|
560
|
+
if (existing !== void 0) return `${existing}`;
|
|
561
|
+
const key = nextPreparedDocumentKey;
|
|
562
|
+
nextPreparedDocumentKey += 1;
|
|
563
|
+
preparedDocumentKeys.set(preparedDocument, key);
|
|
564
|
+
return `${key}`;
|
|
565
|
+
}
|
|
566
|
+
function analysisIdentity(analysis) {
|
|
567
|
+
if (!analysis) return "";
|
|
568
|
+
const existing = analysisKeys.get(analysis);
|
|
569
|
+
if (existing !== void 0) return `${existing}`;
|
|
570
|
+
const key = nextAnalysisKey++;
|
|
571
|
+
analysisKeys.set(analysis, key);
|
|
572
|
+
return `${key}`;
|
|
573
|
+
}
|
|
574
|
+
function preparedTagsKey(document) {
|
|
575
|
+
return JSON.stringify([document.documentConfigurationTag ?? [], document.structuralConfigurationTag ?? []]);
|
|
576
|
+
}
|
|
577
|
+
function bufferViewIdentity(buffer, view) {
|
|
578
|
+
if (!buffer || !view) return "";
|
|
579
|
+
return `${bufferIdentity(buffer)}:${viewIdentity(view)}`;
|
|
580
|
+
}
|
|
581
|
+
function bufferIdentity(buffer) {
|
|
582
|
+
const existing = bufferKeys.get(buffer);
|
|
583
|
+
if (existing !== void 0) return `${existing}`;
|
|
584
|
+
const key = nextBufferKey;
|
|
585
|
+
nextBufferKey += 1;
|
|
586
|
+
bufferKeys.set(buffer, key);
|
|
587
|
+
return `${key}`;
|
|
588
|
+
}
|
|
589
|
+
function viewIdentity(view) {
|
|
590
|
+
const existing = viewKeys.get(view);
|
|
591
|
+
if (existing !== void 0) return `${existing}`;
|
|
592
|
+
const key = nextViewKey;
|
|
593
|
+
nextViewKey += 1;
|
|
594
|
+
viewKeys.set(view, key);
|
|
595
|
+
return `${key}`;
|
|
596
|
+
}
|
|
597
|
+
function documentHasLiveSession(document) {
|
|
598
|
+
return "session" in document && document.session !== null && document.session !== void 0;
|
|
599
|
+
}
|
|
600
|
+
function documentHasLiveBuffer(document) {
|
|
601
|
+
return "buffer" in document && "view" in document && document.buffer !== null && document.buffer !== void 0 && document.view !== null && document.view !== void 0;
|
|
602
|
+
}
|
|
603
|
+
function reactEditorDocumentSession(document) {
|
|
604
|
+
if (document.buffer && document.view) return bufferViewSession(document.buffer, document.view);
|
|
605
|
+
return document.session ?? null;
|
|
606
|
+
}
|
|
607
|
+
function reactEditorDocumentScrollPosition(document) {
|
|
608
|
+
return document.scrollPosition ?? document.view?.getScrollPosition();
|
|
609
|
+
}
|
|
610
|
+
function bufferViewSession(buffer, view) {
|
|
611
|
+
const existingViews = bufferViewSessions.get(buffer);
|
|
612
|
+
const existing = existingViews?.get(view);
|
|
613
|
+
if (existing) return existing;
|
|
614
|
+
const session = createEditorBufferSession(buffer, view);
|
|
615
|
+
if (existingViews) {
|
|
616
|
+
existingViews.set(view, session);
|
|
617
|
+
return session;
|
|
618
|
+
}
|
|
619
|
+
const views = /* @__PURE__ */ new WeakMap();
|
|
620
|
+
views.set(view, session);
|
|
621
|
+
bufferViewSessions.set(buffer, views);
|
|
622
|
+
return session;
|
|
623
|
+
}
|
|
624
|
+
function createEmptyStoreSnapshot() {
|
|
625
|
+
return {
|
|
626
|
+
editor: null,
|
|
627
|
+
state: null,
|
|
628
|
+
snapshot: null,
|
|
629
|
+
textSnapshot: null,
|
|
630
|
+
lastChange: null,
|
|
631
|
+
updateKind: null
|
|
632
|
+
};
|
|
633
|
+
}
|
|
634
|
+
/** Reads the captured revision whole, once per revision, keeping only the latest pair. */
|
|
635
|
+
function createFullTextSelector() {
|
|
636
|
+
let source = null;
|
|
637
|
+
let text = "";
|
|
638
|
+
return (snapshot) => {
|
|
639
|
+
if (snapshot.textSnapshot === source) return text;
|
|
640
|
+
source = snapshot.textSnapshot;
|
|
641
|
+
text = source ? source.readRange(0, source.length) : "";
|
|
642
|
+
return text;
|
|
643
|
+
};
|
|
644
|
+
}
|
|
645
|
+
function mergeStorePatch(snapshot, patch) {
|
|
646
|
+
return {
|
|
647
|
+
editor: patchValue(snapshot, patch, "editor"),
|
|
648
|
+
state: patchValue(snapshot, patch, "state"),
|
|
649
|
+
snapshot: patchValue(snapshot, patch, "snapshot"),
|
|
650
|
+
textSnapshot: patchValue(snapshot, patch, "textSnapshot"),
|
|
651
|
+
lastChange: patchValue(snapshot, patch, "lastChange"),
|
|
652
|
+
updateKind: patchValue(snapshot, patch, "updateKind")
|
|
653
|
+
};
|
|
654
|
+
}
|
|
655
|
+
function patchValue(snapshot, patch, key) {
|
|
656
|
+
if (Object.prototype.hasOwnProperty.call(patch, key)) return patch[key];
|
|
657
|
+
return snapshot[key];
|
|
658
|
+
}
|
|
659
|
+
function hasStorePatchChange(snapshot, patch) {
|
|
660
|
+
for (const key of Object.keys(patch)) if (!Object.is(snapshot[key], patch[key])) return true;
|
|
661
|
+
return false;
|
|
662
|
+
}
|
|
663
|
+
function internalController(controller) {
|
|
664
|
+
return controller[CONTROLLER_PRIVATE];
|
|
665
|
+
}
|
|
666
|
+
//#endregion
|
|
667
|
+
export { EditorHost, useEditor, useEditorSelector };
|
|
668
|
+
|
|
669
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","names":[],"sources":["../src/index.tsx"],"sourcesContent":["import {\n createEditorOptionSync,\n EDITOR_OPTION_DESCRIPTORS,\n type EditorControlledSelection,\n type EditorOptionDescriptor,\n type EditorOptionSync,\n} from '@singapore-editor/core'\nimport {\n Editor,\n type EditorChangeHandler,\n type EditorCommandContext,\n type EditorCommandId,\n type EditorDocumentMode,\n type EditorDocumentAnalysis,\n type EditorEditInput,\n type EditorEditOptions,\n type EditorOpenDocumentOptions,\n type EditorOptions,\n type EditorPreparedDocument,\n type EditorPreparedTagValue,\n type EditorScrollPosition,\n type EditorSetSelectionOptions,\n type EditorSetTextOptions,\n type EditorState,\n} from '@singapore-editor/core/editor'\nimport {\n createEditorBufferSession,\n type DocumentSession,\n type EditorBufferSession,\n type EditorTextBuffer,\n type EditorViewSession,\n type TextReadSnapshot,\n type TextSnapshot,\n} from '@singapore-editor/core/document'\nimport type { EditorSyntaxLanguageId } from '@singapore-editor/core/syntax'\nimport type { EditorTheme, HiddenCharactersMode } from '@singapore-editor/core/rendering'\nimport type {\n EditorContributionChange,\n EditorInitialPaintEvent,\n EditorPlugin,\n EditorViewContributionUpdateKind,\n EditorViewSnapshot,\n} from '@singapore-editor/core/extensions'\nimport {\n useCallback,\n useEffect,\n useLayoutEffect,\n useRef,\n useState,\n useSyncExternalStore,\n type CSSProperties,\n type ReactElement,\n} from 'react'\n\nexport type ReactEditorDocument = {\n readonly analysis?: EditorDocumentAnalysis | null\n readonly documentId?: string\n readonly revision?: string | number\n readonly buffer?: EditorTextBuffer | null\n readonly view?: EditorViewSession | null\n readonly session?: DocumentSession | null\n readonly text: string\n readonly documentMode?: EditorDocumentMode\n readonly documentConfigurationTag?: readonly EditorPreparedTagValue[]\n readonly highlighterConfigurationTag?: readonly EditorPreparedTagValue[]\n readonly languageId?: EditorSyntaxLanguageId | null\n readonly preparedDocument?: EditorPreparedDocument | null\n readonly scrollPosition?: EditorScrollPosition\n readonly textSyncMode?: ReactEditorDocumentTextSyncMode\n readonly structuralConfigurationTag?: readonly EditorPreparedTagValue[]\n}\n\nexport type ReactEditorDocumentTextSyncMode = 'open' | 'incremental'\n\nexport type ReactEditorSelection = EditorControlledSelection\n\nexport type ReactEditorOptions = Omit<\n EditorOptions,\n 'hiddenCharacters' | 'onChange' | 'onInitialPaint' | 'theme'\n> & {\n readonly document?: ReactEditorDocument | null | undefined\n readonly theme?: EditorTheme | null | undefined\n readonly hiddenCharacters?: HiddenCharactersMode | undefined\n readonly selection?: ReactEditorSelection | null | undefined\n readonly scrollPosition?: EditorScrollPosition | null | undefined\n readonly storeSync?: ReactEditorStoreSyncMode\n readonly onChange?: EditorChangeHandler\n readonly onInitialPaint?: (event: EditorInitialPaintEvent) => void\n}\n\nexport type ReactEditorStoreSyncMode = 'full' | 'none'\n\nexport type ReactEditorCommands = {\n focus(): void\n openDocument(document: EditorOpenDocumentOptions): void\n setText(text: string, options?: EditorSetTextOptions): void\n edit(editOrEdits: EditorEditInput, options?: EditorEditOptions): void\n setSelection(anchor: number, head?: number, options?: EditorSetSelectionOptions): void\n setScrollPosition(scrollPosition: EditorScrollPosition): void\n dispatchCommand(command: EditorCommandId, context?: EditorCommandContext): boolean\n openFind(): boolean\n openFindReplace(): boolean\n closeFind(): boolean\n findNext(): boolean\n findPrevious(): boolean\n replaceOne(): boolean\n replaceAll(): boolean\n selectAllMatches(): boolean\n}\n\nexport type ReactEditorStoreSnapshot = {\n readonly editor: Editor | null\n readonly state: EditorState | null\n readonly snapshot: EditorViewSnapshot | null\n readonly textSnapshot: TextReadSnapshot | null\n readonly lastChange: EditorContributionChange | null\n readonly updateKind: EditorViewContributionUpdateKind | null\n}\n\nexport type ReactEditorSelector<T> = (snapshot: ReactEditorStoreSnapshot) => T\nexport type ReactEditorSelectorEquality<T> = (current: T, next: T) => boolean\n\nexport type ReactEditorController = {\n mount(element: HTMLElement): void\n dispose(): void\n getEditor(): Editor | null\n getState(): EditorState | null\n getSnapshot(): EditorViewSnapshot | null\n getTextSnapshot(): TextSnapshot | null\n materializeFullText(): string\n getLastChange(): EditorContributionChange | null\n getUpdateKind(): EditorViewContributionUpdateKind | null\n useEditorInstance(): Editor | null\n useState(): EditorState | null\n useSnapshot(): EditorViewSnapshot | null\n useTextSnapshot(): TextReadSnapshot | null\n /** Re-renders with the whole text on every text revision: O(document length) each time. */\n useFullText(): string\n useLastChange(): EditorContributionChange | null\n useUpdateKind(): EditorViewContributionUpdateKind | null\n readonly commands: ReactEditorCommands\n}\n\nexport type EditorHostProps = {\n readonly controller: ReactEditorController\n readonly className?: string\n readonly style?: CSSProperties\n}\n\ntype ReactEditorStorePatch = Partial<ReactEditorStoreSnapshot>\n\ntype ReactEditorSelectorSubscription<T> = {\n selector: ReactEditorSelector<T>\n isEqual: ReactEditorSelectorEquality<T>\n value: T\n notify: (() => void) | null\n}\n\ntype ReactEditorDocumentState = {\n generation(): number\n key(): ReactEditorDocumentKey\n identityKey(): ReactEditorDocumentKey\n setKey(key: ReactEditorDocumentKey, identityKey?: ReactEditorDocumentKey): void\n clear(): void\n}\n\ntype ReactEditorDocumentKey = string | typeof NO_DOCUMENT\n\ntype ReactEditorSnapshotEligibility = {\n readonly documentKey: string | null\n readonly snapshot: string | null\n}\n\ntype ReactEditorControllerPrivate = ReactEditorController & {\n readonly [CONTROLLER_PRIVATE]: ReactEditorControllerImplementation\n}\n\nconst CONTROLLER_PRIVATE = Symbol('controller-private')\nconst NO_DOCUMENT = Symbol('no-document')\nconst EMPTY_PLUGINS: readonly EditorPlugin[] = []\nconst DOCUMENT_OPTION_NAMES = new Set(['rangeDecorations', 'selection', 'scrollPosition'])\nconst CONFIGURATION_OPTIONS = EDITOR_OPTION_DESCRIPTORS.filter(\n (descriptor) => !DOCUMENT_OPTION_NAMES.has(descriptor.name),\n)\nconst DOCUMENT_OPTIONS = EDITOR_OPTION_DESCRIPTORS.filter((descriptor) =>\n DOCUMENT_OPTION_NAMES.has(descriptor.name),\n)\nconst useEditorLayoutEffect = typeof document === 'undefined' ? useEffect : useLayoutEffect\n\nconst selectEditor = (snapshot: ReactEditorStoreSnapshot): Editor | null => snapshot.editor\nconst selectState = (snapshot: ReactEditorStoreSnapshot): EditorState | null => snapshot.state\nconst selectSnapshot = (snapshot: ReactEditorStoreSnapshot): EditorViewSnapshot | null =>\n snapshot.snapshot\nconst selectTextSnapshot = (snapshot: ReactEditorStoreSnapshot): TextReadSnapshot | null =>\n snapshot.textSnapshot\nconst selectLastChange = (snapshot: ReactEditorStoreSnapshot): EditorContributionChange | null =>\n snapshot.lastChange\nconst selectUpdateKind = (\n snapshot: ReactEditorStoreSnapshot,\n): EditorViewContributionUpdateKind | null => snapshot.updateKind\n\nexport function useEditor(options: ReactEditorOptions = {}): ReactEditorController {\n // Lazy state, not a lazily filled ref: render reads it, and refs are off-limits in render.\n const [controller] = useState(() => new ReactEditorControllerImplementation(options))\n\n controller.setOptions(options)\n useControlledOptionSync(controller, options)\n useEffect(() => {\n controller.retainReactOwner()\n return () => controller.scheduleReactDispose()\n }, [controller])\n\n return controller\n}\n\nexport function EditorHost({ controller, className, style }: EditorHostProps): ReactElement {\n const hostRef = useRef<HTMLDivElement | null>(null)\n\n useEditorLayoutEffect(() => {\n const element = hostRef.current\n if (!element) return\n\n controller.mount(element)\n return () => internalController(controller).scheduleReactDispose()\n }, [controller])\n\n return <div ref={hostRef} className={className} style={style} />\n}\n\nexport function useEditorSelector<T>(\n controller: ReactEditorController,\n selector: ReactEditorSelector<T>,\n isEqual: ReactEditorSelectorEquality<T> = Object.is,\n): T {\n const store = internalController(controller).store\n // Lazy state, not a lazily filled ref: render reads it, and refs are off-limits in render.\n const [subscription] = useState(() => store.createSubscription(selector, isEqual))\n\n store.refreshSubscription(subscription, selector, isEqual)\n\n const subscribe = useCallback(\n (notify: () => void) => store.subscribe(subscription, notify),\n [store, subscription],\n )\n const getSnapshot = useCallback(() => subscription.value, [subscription])\n\n return useSyncExternalStore(subscribe, getSnapshot, getSnapshot)\n}\n\nclass ReactEditorControllerImplementation implements ReactEditorController {\n public readonly [CONTROLLER_PRIVATE] = this\n public readonly store = new ReactEditorStore()\n public readonly commands: ReactEditorCommands\n private readonly reactSyncPlugin: EditorPlugin\n private readonly documentState = createDocumentState()\n private readonly optionSync: EditorOptionSync = createEditorOptionSync()\n private syncedPlugins: readonly EditorPlugin[] | null = null\n private syncedStoreSyncMode: ReactEditorStoreSyncMode | null = null\n private syncedSnapshotEligibility: ReactEditorSnapshotEligibility | null = null\n private requestedDocumentGeneration = 0\n private editorIncarnation = 0\n private mountedElement: HTMLElement | null = null\n private scheduledDisposeGeneration: number | null = null\n private nextDisposeGeneration = 0\n private suspendedStoreFields: ReactEditorStoreSnapshot | null = null\n private options: ReactEditorOptions\n\n public constructor(options: ReactEditorOptions) {\n this.options = options\n this.reactSyncPlugin = createReactSyncPlugin(this)\n this.commands = createCommands(() => this.getEditor(), this.documentState)\n }\n\n public mount(element: HTMLElement): void {\n this.retainReactOwner()\n if (this.mountedElement === element && this.getEditor()) return\n\n this.store.batch(() => {\n this.disposeImmediately()\n this.mountedElement = element\n this.mountEditor(element)\n })\n }\n\n public dispose(): void {\n this.retainReactOwner()\n this.disposeImmediately()\n }\n\n public retainReactOwner(): void {\n this.scheduledDisposeGeneration = null\n this.resumeSuspendedEditor()\n }\n\n public scheduleReactDispose(): void {\n if (this.scheduledDisposeGeneration !== null) return\n\n this.nextDisposeGeneration += 1\n const generation = this.nextDisposeGeneration\n this.scheduledDisposeGeneration = generation\n this.suspendEditor()\n // @justification Waits out React's synchronous StrictMode unmount and remount; the generation\n // guard drops the disposal when the component came straight back.\n queueMicrotask(() => {\n if (this.scheduledDisposeGeneration !== generation) return\n\n this.scheduledDisposeGeneration = null\n this.disposeImmediately()\n })\n }\n\n private disposeImmediately(): void {\n this.store.batch(() => {\n this.editorIncarnation += 1\n this.suspendedStoreFields?.editor?.dispose()\n this.suspendedStoreFields = null\n disposeEditor(this.store)\n this.mountedElement = null\n this.documentState.clear()\n this.optionSync.reset()\n this.clearSyncedPlugins()\n this.syncedSnapshotEligibility = null\n })\n }\n\n private suspendEditor(): void {\n const snapshot = this.store.read()\n if (!snapshot.editor) return\n\n this.suspendedStoreFields = snapshot\n this.store.update(createEmptyStoreSnapshot())\n }\n\n private resumeSuspendedEditor(): void {\n const suspended = this.suspendedStoreFields\n if (!suspended) return\n\n this.suspendedStoreFields = null\n this.store.update(suspended)\n }\n\n public setOptions(options: ReactEditorOptions): void {\n this.options = options\n }\n\n public getEditor(): Editor | null {\n return this.store.read().editor\n }\n\n public getState(): EditorState | null {\n return this.getEditor()?.getState() ?? null\n }\n\n public getSnapshot(): EditorViewSnapshot | null {\n return this.store.read().snapshot\n }\n\n public getTextSnapshot(): TextSnapshot | null {\n return this.getEditor()?.getTextSnapshot() ?? null\n }\n\n public materializeFullText(): string {\n return this.getEditor()?.materializeFullText() ?? ''\n }\n\n public getLastChange(): EditorContributionChange | null {\n return this.store.read().lastChange\n }\n\n public getUpdateKind(): EditorViewContributionUpdateKind | null {\n return this.store.read().updateKind\n }\n\n public readonly useEditorInstance = (): Editor | null => useEditorSelector(this, selectEditor)\n public readonly useState = (): EditorState | null => useEditorSelector(this, selectState)\n public readonly useSnapshot = (): EditorViewSnapshot | null =>\n useEditorSelector(this, selectSnapshot)\n public readonly useTextSnapshot = (): TextReadSnapshot | null =>\n useEditorSelector(this, selectTextSnapshot)\n public readonly useFullText = (): string => {\n // Per hook, so the string is retained by this subscriber alone and released on unmount.\n const [selectFullText] = useState(createFullTextSelector)\n return useEditorSelector(this, selectFullText)\n }\n public readonly useLastChange = (): EditorContributionChange | null =>\n useEditorSelector(this, selectLastChange)\n public readonly useUpdateKind = (): EditorViewContributionUpdateKind | null =>\n useEditorSelector(this, selectUpdateKind)\n\n public syncDocumentOption(): void {\n const editor = this.getEditor()\n if (!editor) return\n\n this.syncSnapshotEligibility(editor)\n this.syncAuthoritativeDocument(editor)\n }\n\n public syncConfigurationOptions(): void {\n this.applyControlledOptions(this.getEditor(), CONFIGURATION_OPTIONS)\n }\n\n public syncDocumentControls(): void {\n this.applyControlledOptions(this.getEditor(), DOCUMENT_OPTIONS)\n }\n\n public syncPluginsOption(): void {\n const editor = this.getEditor()\n if (!editor) return\n if (this.pluginsSynced(this.options)) return\n\n syncPlugins(editor, this.reactSyncPlugin, this.options)\n this.markPluginsSynced(this.options)\n }\n\n public syncSnapshot(\n snapshot: EditorViewSnapshot,\n kind: EditorViewContributionUpdateKind,\n change: EditorContributionChange | null,\n ): void {\n if (!this.shouldSyncStore()) return\n if (this.getEditor()?.getPresentationState() === 'provisional') return\n\n const patch = {\n snapshot,\n textSnapshot: snapshot.textSnapshot,\n lastChange: change,\n updateKind: kind,\n ...(kind === 'selection' ? { state: this.getEditor()?.getState() ?? null } : {}),\n } satisfies ReactEditorStorePatch\n\n this.store.update(patch)\n }\n\n public syncChange(state: EditorState, change: EditorContributionChange | null): void {\n if (!this.shouldSyncStore()) return\n\n this.store.update({\n state,\n textSnapshot: this.getEditor()?.getTextSnapshot() ?? null,\n lastChange: change,\n })\n }\n\n private mountEditor(element: HTMLElement): void {\n this.editorIncarnation += 1\n const editorIncarnation = this.editorIncarnation\n const instance = new Editor(element, this.createConstructorOptions(editorIncarnation))\n this.markPluginsSynced(this.options)\n this.syncedSnapshotEligibility = snapshotEligibility(this.options)\n\n this.store.update({\n editor: instance,\n state: instance.getState(),\n textSnapshot: instance.getTextSnapshot(),\n })\n if (instance.getPresentationState() === 'provisional') this.clearPresentedSnapshot()\n this.syncMountedOptions(instance)\n }\n\n private createConstructorOptions(editorIncarnation: number): EditorOptions {\n const {\n document: _document,\n hiddenCharacters,\n onChange: _onChange,\n onInitialPaint: _onInitialPaint,\n onPresentationChange: _onPresentationChange,\n plugins: _plugins,\n scrollPosition: _scrollPosition,\n selection: _selection,\n storeSync: _storeSync,\n theme,\n ...constructorOptions\n } = this.options\n\n return {\n ...constructorOptions,\n snapshot: snapshotEligibility(this.options).snapshot,\n hiddenCharacters,\n theme: theme ?? undefined,\n plugins: editorPluginsForOptions(this.reactSyncPlugin, this.options),\n onChange: (state, change) => {\n this.syncChange(state, change)\n this.options.onChange?.(state, change)\n },\n onInitialPaint: (event) => this.forwardInitialPaint(event, editorIncarnation),\n onPresentationChange: (state) => this.forwardPresentationChange(state, editorIncarnation),\n }\n }\n\n private forwardInitialPaint(event: EditorInitialPaintEvent, editorIncarnation: number): void {\n const documentGeneration = this.documentState.generation()\n const requestedDocumentKey = this.options.documentKey\n // @justification Defers delivery until the mount survives React's synchronous StrictMode\n // replay; the incarnation guard cancels disposed mounts, and no editor work is scheduled.\n queueMicrotask(() => {\n if (editorIncarnation !== this.editorIncarnation) return\n if (documentGeneration !== this.documentState.generation()) return\n if (requestedDocumentKey !== this.options.documentKey) return\n\n this.options.onInitialPaint?.(event)\n })\n }\n\n private syncMountedOptions(editor: Editor): void {\n this.syncAuthoritativeDocument(editor)\n this.applyControlledOptions(editor)\n }\n\n private syncAuthoritativeDocument(editor: Editor): void {\n const document = this.options.documentKey === null ? null : this.options.document\n syncDocument(editor, document, this.documentState)\n }\n\n private syncSnapshotEligibility(editor: Editor): void {\n const next = snapshotEligibility(this.options)\n const previous = this.syncedSnapshotEligibility\n if (previous?.documentKey === next.documentKey && previous.snapshot === next.snapshot) return\n\n if (previous && previous.documentKey !== next.documentKey) {\n this.requestedDocumentGeneration += 1\n editor.clearDocument()\n this.documentState.clear()\n }\n\n this.syncedSnapshotEligibility = next\n editor.setSnapshot(next.snapshot, next.documentKey)\n }\n\n private forwardPresentationChange(\n state: ReturnType<Editor['getPresentationState']>,\n editorIncarnation: number,\n ): void {\n if (state === 'provisional') this.clearPresentedSnapshot()\n const requestedDocumentKey = this.options.documentKey\n const requestedDocumentGeneration = this.requestedDocumentGeneration\n // @justification Defers the callback past StrictMode's synchronous replay; the incarnation,\n // document and state guards drop it when the editor moved on, and no editor work is scheduled.\n queueMicrotask(() => {\n if (editorIncarnation !== this.editorIncarnation) return\n if (requestedDocumentKey !== this.options.documentKey) return\n if (requestedDocumentGeneration !== this.requestedDocumentGeneration) return\n if (this.getEditor()?.getPresentationState() !== state) return\n\n this.options.onPresentationChange?.(state)\n })\n }\n\n private clearPresentedSnapshot(): void {\n this.store.update({ snapshot: null, updateKind: null })\n }\n\n private applyControlledOptions(\n editor: Editor | null,\n descriptors: readonly EditorOptionDescriptor[] = EDITOR_OPTION_DESCRIPTORS,\n ): void {\n for (const descriptor of descriptors) {\n this.optionSync.apply(editor, descriptor, this.options[descriptor.name])\n }\n }\n\n private shouldSyncStore(): boolean {\n return reactEditorStoreSyncMode(this.options) === 'full'\n }\n\n private pluginsSynced(options: ReactEditorOptions): boolean {\n if (this.syncedStoreSyncMode !== reactEditorStoreSyncMode(options)) return false\n return samePlugins(this.syncedPlugins, options.plugins ?? EMPTY_PLUGINS)\n }\n\n private markPluginsSynced(options: ReactEditorOptions): void {\n this.syncedPlugins = [...(options.plugins ?? EMPTY_PLUGINS)]\n this.syncedStoreSyncMode = reactEditorStoreSyncMode(options)\n }\n\n private clearSyncedPlugins(): void {\n this.syncedPlugins = null\n this.syncedStoreSyncMode = null\n }\n}\n\nclass ReactEditorStore {\n private snapshot = createEmptyStoreSnapshot()\n private readonly subscriptions = new Set<ReactEditorSelectorSubscription<unknown>>()\n private version = 0\n private batchDepth = 0\n private notifyAfterBatch = false\n\n public read(): ReactEditorStoreSnapshot {\n return this.snapshot\n }\n\n public update(patch: ReactEditorStorePatch): void {\n if (!hasStorePatchChange(this.snapshot, patch)) return\n\n this.snapshot = mergeStorePatch(this.snapshot, patch)\n this.version += 1\n this.queueNotify()\n }\n\n public batch<T>(run: () => T): T {\n this.batchDepth += 1\n try {\n return run()\n } finally {\n this.batchDepth -= 1\n this.flushBatchedNotify()\n }\n }\n\n public createSubscription<T>(\n selector: ReactEditorSelector<T>,\n isEqual: ReactEditorSelectorEquality<T>,\n ): ReactEditorSelectorSubscription<T> {\n return {\n selector,\n isEqual,\n value: selector(this.snapshot),\n notify: null,\n }\n }\n\n public refreshSubscription<T>(\n subscription: ReactEditorSelectorSubscription<T>,\n selector: ReactEditorSelector<T>,\n isEqual: ReactEditorSelectorEquality<T>,\n ): void {\n subscription.selector = selector\n subscription.isEqual = isEqual\n this.refreshSubscriptionValue(subscription)\n }\n\n public subscribe<T>(\n subscription: ReactEditorSelectorSubscription<T>,\n notify: () => void,\n ): () => void {\n subscription.notify = notify\n this.refreshSubscriptionValue(subscription)\n this.subscriptions.add(subscription as ReactEditorSelectorSubscription<unknown>)\n\n return () => {\n this.subscriptions.delete(subscription as ReactEditorSelectorSubscription<unknown>)\n subscription.notify = null\n }\n }\n\n private notify(): void {\n for (const subscription of this.subscriptions) {\n this.notifySubscription(subscription)\n }\n }\n\n private queueNotify(): void {\n if (this.batchDepth === 0) {\n this.notify()\n return\n }\n\n this.notifyAfterBatch = true\n }\n\n private flushBatchedNotify(): void {\n if (this.batchDepth > 0) return\n if (!this.notifyAfterBatch) return\n\n this.notifyAfterBatch = false\n this.notify()\n }\n\n private notifySubscription<T>(subscription: ReactEditorSelectorSubscription<T>): void {\n const nextValue = subscription.selector(this.snapshot)\n if (subscription.isEqual(subscription.value, nextValue)) return\n\n subscription.value = nextValue\n subscription.notify?.()\n }\n\n private refreshSubscriptionValue<T>(subscription: ReactEditorSelectorSubscription<T>): void {\n const nextValue = subscription.selector(this.snapshot)\n if (subscription.isEqual(subscription.value, nextValue)) return\n\n subscription.value = nextValue\n }\n}\n\nfunction useControlledOptionSync(\n controller: ReactEditorControllerImplementation,\n options: ReactEditorOptions,\n): void {\n const documentIdentity = documentKey(options.document)\n\n useEditorLayoutEffect(\n () => controller.syncPluginsOption(),\n [controller, options.plugins, options.storeSync],\n )\n // Admission reads current appearance; document offsets wait until after attachment.\n useEditorLayoutEffect(() => controller.syncConfigurationOptions())\n useEditorLayoutEffect(\n () => controller.syncDocumentOption(),\n [controller, documentIdentity, options.documentKey, options.snapshot],\n )\n // Runs on every render because the descriptors, not a dependency list, decide what moved.\n useEditorLayoutEffect(() => controller.syncDocumentControls())\n}\n\nfunction snapshotEligibility(options: ReactEditorOptions): ReactEditorSnapshotEligibility {\n return {\n documentKey: options.documentKey ?? null,\n snapshot: options.documentKey === null ? null : (options.snapshot ?? null),\n }\n}\n\nfunction createReactSyncPlugin(controller: ReactEditorControllerImplementation): EditorPlugin {\n return {\n name: 'react-editor-sync',\n activate: (context) =>\n context.registerViewContribution({\n createContribution: () => ({\n update: (snapshot, kind, change) =>\n controller.syncSnapshot(snapshot, kind, change ?? null),\n dispose: () => undefined,\n }),\n }),\n }\n}\n\nfunction syncDocument(\n editor: Editor | null,\n document: ReactEditorDocument | null | undefined,\n state: ReactEditorDocumentState,\n): void {\n if (!editor) return\n\n const key = documentKey(document)\n if (key === state.key()) return\n const identityKey = documentIdentityKey(document)\n const previousIdentityKey = state.identityKey()\n\n state.setKey(key, identityKey)\n if (!document) {\n editor.clearDocument()\n return\n }\n\n const session = reactEditorDocumentSession(document)\n if (session) {\n editor.attachSession(session, {\n analysis: document.analysis,\n documentId: document.documentId,\n documentConfigurationTag: document.documentConfigurationTag,\n highlighterConfigurationTag: document.highlighterConfigurationTag,\n languageId: document.languageId,\n preparedDocument: document.preparedDocument,\n scrollPosition: reactEditorDocumentScrollPosition(document),\n structuralConfigurationTag: document.structuralConfigurationTag,\n })\n return\n }\n\n if (canSyncDocumentTextIncrementally(document, previousIdentityKey, identityKey)) {\n editor.syncText(document.text, {\n documentMode: document.documentMode,\n languageId: document.languageId,\n scrollPosition: reactEditorDocumentScrollPosition(document),\n })\n return\n }\n\n editor.openDocument({\n documentId: document.documentId,\n documentMode: document.documentMode,\n languageId: document.languageId,\n scrollPosition: reactEditorDocumentScrollPosition(document),\n text: document.text,\n })\n}\n\nfunction canSyncDocumentTextIncrementally(\n document: ReactEditorDocument,\n previousIdentityKey: ReactEditorDocumentKey,\n identityKey: ReactEditorDocumentKey,\n): boolean {\n if (document.textSyncMode !== 'incremental') return false\n if (previousIdentityKey === NO_DOCUMENT) return false\n\n return previousIdentityKey === identityKey\n}\n\nfunction syncPlugins(\n editor: Editor | null,\n reactSyncPlugin: EditorPlugin,\n options: ReactEditorOptions,\n): void {\n if (!editor) return\n\n editor.setPlugins(editorPluginsForOptions(reactSyncPlugin, options))\n}\n\nfunction editorPluginsForOptions(\n reactSyncPlugin: EditorPlugin,\n options: ReactEditorOptions,\n): readonly EditorPlugin[] {\n if (reactEditorStoreSyncMode(options) === 'none') return options.plugins ?? []\n\n return [reactSyncPlugin, ...(options.plugins ?? [])]\n}\n\nfunction reactEditorStoreSyncMode(options: ReactEditorOptions): ReactEditorStoreSyncMode {\n return options.storeSync ?? 'full'\n}\n\nfunction samePlugins(\n left: readonly EditorPlugin[] | null,\n right: readonly EditorPlugin[],\n): boolean {\n if (!left) return false\n if (left.length !== right.length) return false\n\n return left.every((plugin, index) => plugin === right[index])\n}\n\nfunction disposeEditor(store: ReactEditorStore): void {\n const editor = store.read().editor\n editor?.dispose()\n store.update(createEmptyStoreSnapshot())\n}\n\nfunction createCommands(\n editor: () => Editor | null,\n documentState: ReactEditorDocumentState,\n): ReactEditorCommands {\n return {\n focus: () => editor()?.focus(),\n openDocument: (document) => {\n documentState.setKey(documentKey(document), documentIdentityKey(document))\n editor()?.openDocument(document)\n },\n setText: (text, options) => editor()?.setText(text, options),\n edit: (editOrEdits, options) => editor()?.edit(editOrEdits, options),\n setSelection: (anchor, head, options) => editor()?.setSelection(anchor, head, options),\n setScrollPosition: (scrollPosition) => editor()?.setScrollPosition(scrollPosition),\n dispatchCommand: (command, context) => editor()?.dispatchCommand(command, context) ?? false,\n openFind: () => editor()?.openFind() ?? false,\n openFindReplace: () => editor()?.openFindReplace() ?? false,\n closeFind: () => editor()?.closeFind() ?? false,\n findNext: () => editor()?.findNext() ?? false,\n findPrevious: () => editor()?.findPrevious() ?? false,\n replaceOne: () => editor()?.replaceOne() ?? false,\n replaceAll: () => editor()?.replaceAll() ?? false,\n selectAllMatches: () => editor()?.selectAllMatches() ?? false,\n }\n}\n\nfunction createDocumentState(): ReactEditorDocumentState {\n let generation = 0\n let key: ReactEditorDocumentKey = NO_DOCUMENT\n let identityKey: ReactEditorDocumentKey = NO_DOCUMENT\n\n return {\n generation: () => generation,\n key: () => key,\n identityKey: () => identityKey,\n setKey: (nextKey, nextIdentityKey = nextKey) => {\n generation += 1\n key = nextKey\n identityKey = nextIdentityKey\n },\n clear: () => {\n generation += 1\n key = NO_DOCUMENT\n identityKey = NO_DOCUMENT\n },\n }\n}\n\nfunction documentKey(\n document:\n | (Readonly<{\n readonly analysis?: EditorDocumentAnalysis | null\n readonly buffer?: EditorTextBuffer | null\n readonly documentId?: string\n readonly documentMode?: EditorDocumentMode\n readonly documentConfigurationTag?: readonly EditorPreparedTagValue[]\n readonly highlighterConfigurationTag?: readonly EditorPreparedTagValue[]\n readonly languageId?: EditorSyntaxLanguageId | null\n readonly preparedDocument?: EditorPreparedDocument | null\n readonly revision?: string | number\n readonly session?: DocumentSession | null\n readonly text?: string\n readonly textSyncMode?: ReactEditorDocumentTextSyncMode\n readonly structuralConfigurationTag?: readonly EditorPreparedTagValue[]\n readonly view?: EditorViewSession | null\n }> &\n object)\n | null\n | undefined,\n): ReactEditorDocumentKey {\n if (!document) return NO_DOCUMENT\n\n const incremental = document.textSyncMode === 'incremental'\n const liveSession = documentHasLiveBuffer(document) || documentHasLiveSession(document)\n const revision = documentRevisionKey(document, incremental)\n const textVersion = incremental && !liveSession ? (document.text ?? '') : ''\n const identityKey = documentIdentityKey(document)\n if (identityKey === NO_DOCUMENT) return NO_DOCUMENT\n\n return `${identityKey}\\u0000${revision}\\u0000${textVersion}\\u0000${preparedDocumentIdentity(\n document.preparedDocument,\n )}\\u0000${analysisIdentity(document.analysis ?? document.preparedDocument?.analysis)}\\u0000${preparedTagsKey(document)}`\n}\n\nfunction documentRevisionKey(\n document: Readonly<{\n readonly buffer?: EditorTextBuffer | null\n readonly revision?: string | number\n readonly session?: DocumentSession | null\n readonly view?: EditorViewSession | null\n }> &\n object,\n incremental: boolean,\n) {\n if (documentHasLiveBuffer(document)) return ''\n if (incremental) return ''\n if (documentHasLiveSession(document)) return ''\n\n return document.revision ?? ''\n}\n\nfunction documentIdentityKey(\n document:\n | (Readonly<{\n readonly buffer?: EditorTextBuffer | null\n readonly documentId?: string\n readonly documentMode?: EditorDocumentMode\n readonly languageId?: EditorSyntaxLanguageId | null\n readonly session?: DocumentSession | null\n readonly view?: EditorViewSession | null\n }> &\n object)\n | null\n | undefined,\n): ReactEditorDocumentKey {\n if (!document) return NO_DOCUMENT\n\n const session = 'session' in document ? document.session : null\n const buffer = 'buffer' in document ? document.buffer : null\n const view = 'view' in document ? document.view : null\n return `${document.documentId ?? ''}\\u0000${document.documentMode ?? ''}\\u0000${\n document.languageId ?? ''\n }\\u0000${sessionIdentity(session)}\\u0000${bufferViewIdentity(buffer, view)}`\n}\n\nconst sessionKeys = new WeakMap<DocumentSession, number>()\nconst preparedDocumentKeys = new WeakMap<EditorPreparedDocument, number>()\nconst analysisKeys = new WeakMap<EditorDocumentAnalysis, number>()\nconst bufferKeys = new WeakMap<EditorTextBuffer, number>()\nconst viewKeys = new WeakMap<EditorViewSession, number>()\nconst bufferViewSessions = new WeakMap<\n EditorTextBuffer,\n WeakMap<EditorViewSession, EditorBufferSession>\n>()\nlet nextSessionKey = 1\nlet nextPreparedDocumentKey = 1\nlet nextAnalysisKey = 1\nlet nextBufferKey = 1\nlet nextViewKey = 1\n\nfunction sessionIdentity(session: DocumentSession | null | undefined): string {\n if (!session) return ''\n\n const existing = sessionKeys.get(session)\n if (existing !== undefined) return `${existing}`\n\n const key = nextSessionKey\n nextSessionKey += 1\n sessionKeys.set(session, key)\n return `${key}`\n}\n\nfunction preparedDocumentIdentity(\n preparedDocument: EditorPreparedDocument | null | undefined,\n): string {\n if (!preparedDocument) return ''\n\n const existing = preparedDocumentKeys.get(preparedDocument)\n if (existing !== undefined) return `${existing}`\n\n const key = nextPreparedDocumentKey\n nextPreparedDocumentKey += 1\n preparedDocumentKeys.set(preparedDocument, key)\n return `${key}`\n}\n\nfunction analysisIdentity(analysis: EditorDocumentAnalysis | null | undefined): string {\n if (!analysis) return ''\n const existing = analysisKeys.get(analysis)\n if (existing !== undefined) return `${existing}`\n const key = nextAnalysisKey++\n analysisKeys.set(analysis, key)\n return `${key}`\n}\n\nfunction preparedTagsKey(document: {\n readonly documentConfigurationTag?: readonly EditorPreparedTagValue[]\n readonly structuralConfigurationTag?: readonly EditorPreparedTagValue[]\n}): string {\n // Highlighter tags validate a prepared result at attachment; changing colors is not a new document.\n return JSON.stringify([\n document.documentConfigurationTag ?? [],\n document.structuralConfigurationTag ?? [],\n ])\n}\n\nfunction bufferViewIdentity(\n buffer: EditorTextBuffer | null | undefined,\n view: EditorViewSession | null | undefined,\n): string {\n if (!buffer || !view) return ''\n\n return `${bufferIdentity(buffer)}:${viewIdentity(view)}`\n}\n\nfunction bufferIdentity(buffer: EditorTextBuffer): string {\n const existing = bufferKeys.get(buffer)\n if (existing !== undefined) return `${existing}`\n\n const key = nextBufferKey\n nextBufferKey += 1\n bufferKeys.set(buffer, key)\n return `${key}`\n}\n\nfunction viewIdentity(view: EditorViewSession): string {\n const existing = viewKeys.get(view)\n if (existing !== undefined) return `${existing}`\n\n const key = nextViewKey\n nextViewKey += 1\n viewKeys.set(view, key)\n return `${key}`\n}\n\nfunction documentHasLiveSession(\n document: Readonly<{ readonly session?: DocumentSession | null }> & object,\n): boolean {\n return 'session' in document && document.session !== null && document.session !== undefined\n}\n\nfunction documentHasLiveBuffer(\n document: Readonly<{\n readonly buffer?: EditorTextBuffer | null\n readonly view?: EditorViewSession | null\n }> &\n object,\n): boolean {\n return (\n 'buffer' in document &&\n 'view' in document &&\n document.buffer !== null &&\n document.buffer !== undefined &&\n document.view !== null &&\n document.view !== undefined\n )\n}\n\nfunction reactEditorDocumentSession(\n document: ReactEditorDocument,\n): DocumentSession | EditorBufferSession | null {\n if (document.buffer && document.view) {\n return bufferViewSession(document.buffer, document.view)\n }\n\n return document.session ?? null\n}\n\nfunction reactEditorDocumentScrollPosition(\n document: ReactEditorDocument,\n): EditorScrollPosition | undefined {\n return document.scrollPosition ?? document.view?.getScrollPosition()\n}\n\nfunction bufferViewSession(buffer: EditorTextBuffer, view: EditorViewSession): EditorBufferSession {\n const existingViews = bufferViewSessions.get(buffer)\n const existing = existingViews?.get(view)\n if (existing) return existing\n\n const session = createEditorBufferSession(buffer, view)\n if (existingViews) {\n existingViews.set(view, session)\n return session\n }\n\n const views = new WeakMap<EditorViewSession, EditorBufferSession>()\n views.set(view, session)\n bufferViewSessions.set(buffer, views)\n return session\n}\n\nfunction createEmptyStoreSnapshot(): ReactEditorStoreSnapshot {\n return {\n editor: null,\n state: null,\n snapshot: null,\n textSnapshot: null,\n lastChange: null,\n updateKind: null,\n }\n}\n\n/** Reads the captured revision whole, once per revision, keeping only the latest pair. */\nfunction createFullTextSelector(): ReactEditorSelector<string> {\n let source: TextReadSnapshot | null = null\n let text = ''\n return (snapshot) => {\n if (snapshot.textSnapshot === source) return text\n\n source = snapshot.textSnapshot\n text = source ? source.readRange(0, source.length) : ''\n return text\n }\n}\n\nfunction mergeStorePatch(\n snapshot: ReactEditorStoreSnapshot,\n patch: ReactEditorStorePatch,\n): ReactEditorStoreSnapshot {\n return {\n editor: patchValue(snapshot, patch, 'editor'),\n state: patchValue(snapshot, patch, 'state'),\n snapshot: patchValue(snapshot, patch, 'snapshot'),\n textSnapshot: patchValue(snapshot, patch, 'textSnapshot'),\n lastChange: patchValue(snapshot, patch, 'lastChange'),\n updateKind: patchValue(snapshot, patch, 'updateKind'),\n }\n}\n\nfunction patchValue<K extends keyof ReactEditorStoreSnapshot>(\n snapshot: ReactEditorStoreSnapshot,\n patch: ReactEditorStorePatch,\n key: K,\n): ReactEditorStoreSnapshot[K] {\n if (Object.prototype.hasOwnProperty.call(patch, key)) {\n return patch[key] as ReactEditorStoreSnapshot[K]\n }\n return snapshot[key]\n}\n\nfunction hasStorePatchChange(\n snapshot: ReactEditorStoreSnapshot,\n patch: ReactEditorStorePatch,\n): boolean {\n for (const key of Object.keys(patch) as (keyof ReactEditorStoreSnapshot)[]) {\n if (!Object.is(snapshot[key], patch[key])) return true\n }\n\n return false\n}\n\nfunction internalController(\n controller: ReactEditorController,\n): ReactEditorControllerImplementation {\n return (controller as ReactEditorControllerPrivate)[CONTROLLER_PRIVATE]\n}\n"],"mappings":";;;;;;AAiLA,IAAM,qBAAqB,OAAO,oBAAoB;AACtD,IAAM,cAAc,OAAO,aAAa;AACxC,IAAM,gBAAyC,CAAC;AAChD,IAAM,wCAAwB,IAAI,IAAI;CAAC;CAAoB;CAAa;AAAgB,CAAC;AACzF,IAAM,wBAAwB,0BAA0B,QACrD,eAAe,CAAC,sBAAsB,IAAI,WAAW,IAAI,CAC5D;AACA,IAAM,mBAAmB,0BAA0B,QAAQ,eACzD,sBAAsB,IAAI,WAAW,IAAI,CAC3C;AACA,IAAM,wBAAwB,OAAO,aAAa,cAAc,YAAY;AAE5E,IAAM,gBAAgB,aAAsD,SAAS;AACrF,IAAM,eAAe,aAA2D,SAAS;AACzF,IAAM,kBAAkB,aACtB,SAAS;AACX,IAAM,sBAAsB,aAC1B,SAAS;AACX,IAAM,oBAAoB,aACxB,SAAS;AACX,IAAM,oBACJ,aAC4C,SAAS;AAEvD,SAAgB,UAAU,UAA8B,CAAC,GAA0B;CAEjF,MAAM,CAAC,cAAc,eAAe,IAAI,oCAAoC,OAAO,CAAC;CAEpF,WAAW,WAAW,OAAO;CAC7B,wBAAwB,YAAY,OAAO;CAC3C,gBAAgB;EACd,WAAW,iBAAiB;EAC5B,aAAa,WAAW,qBAAqB;CAC/C,GAAG,CAAC,UAAU,CAAC;CAEf,OAAO;AACT;AAEA,SAAgB,WAAW,EAAE,YAAY,WAAW,SAAwC;CAC1F,MAAM,UAAU,OAA8B,IAAI;CAElD,4BAA4B;EAC1B,MAAM,UAAU,QAAQ;EACxB,IAAI,CAAC,SAAS;EAEd,WAAW,MAAM,OAAO;EACxB,aAAa,mBAAmB,UAAU,CAAC,CAAC,qBAAqB;CACnE,GAAG,CAAC,UAAU,CAAC;CAEf,OAAO,oBAAC,OAAD;EAAK,KAAK;EAAoB;EAAkB;CAAQ,CAAA;AACjE;AAEA,SAAgB,kBACd,YACA,UACA,UAA0C,OAAO,IAC9C;CACH,MAAM,QAAQ,mBAAmB,UAAU,CAAC,CAAC;CAE7C,MAAM,CAAC,gBAAgB,eAAe,MAAM,mBAAmB,UAAU,OAAO,CAAC;CAEjF,MAAM,oBAAoB,cAAc,UAAU,OAAO;CAEzD,MAAM,YAAY,aACf,WAAuB,MAAM,UAAU,cAAc,MAAM,GAC5D,CAAC,OAAO,YAAY,CACtB;CACA,MAAM,cAAc,kBAAkB,aAAa,OAAO,CAAC,YAAY,CAAC;CAExE,OAAO,qBAAqB,WAAW,aAAa,WAAW;AACjE;AAEA,IAAM,sCAAN,MAA2E;CACzE,CAAiB,sBAAsB;CACvC,QAAwB,IAAI,iBAAiB;CAC7C;CACA;CACA,gBAAiC,oBAAoB;CACrD,aAAgD,uBAAuB;CACvE,gBAAwD;CACxD,sBAA+D;CAC/D,4BAA2E;CAC3E,8BAAsC;CACtC,oBAA4B;CAC5B,iBAA6C;CAC7C,6BAAoD;CACpD,wBAAgC;CAChC,uBAAgE;CAChE;CAEA,YAAmB,SAA6B;EAC9C,KAAK,UAAU;EACf,KAAK,kBAAkB,sBAAsB,IAAI;EACjD,KAAK,WAAW,qBAAqB,KAAK,UAAU,GAAG,KAAK,aAAa;CAC3E;CAEA,MAAa,SAA4B;EACvC,KAAK,iBAAiB;EACtB,IAAI,KAAK,mBAAmB,WAAW,KAAK,UAAU,GAAG;EAEzD,KAAK,MAAM,YAAY;GACrB,KAAK,mBAAmB;GACxB,KAAK,iBAAiB;GACtB,KAAK,YAAY,OAAO;EAC1B,CAAC;CACH;CAEA,UAAuB;EACrB,KAAK,iBAAiB;EACtB,KAAK,mBAAmB;CAC1B;CAEA,mBAAgC;EAC9B,KAAK,6BAA6B;EAClC,KAAK,sBAAsB;CAC7B;CAEA,uBAAoC;EAClC,IAAI,KAAK,+BAA+B,MAAM;EAE9C,KAAK,yBAAyB;EAC9B,MAAM,aAAa,KAAK;EACxB,KAAK,6BAA6B;EAClC,KAAK,cAAc;EAGnB,qBAAqB;GACnB,IAAI,KAAK,+BAA+B,YAAY;GAEpD,KAAK,6BAA6B;GAClC,KAAK,mBAAmB;EAC1B,CAAC;CACH;CAEA,qBAAmC;EACjC,KAAK,MAAM,YAAY;GACrB,KAAK,qBAAqB;GAC1B,KAAK,sBAAsB,QAAQ,QAAQ;GAC3C,KAAK,uBAAuB;GAC5B,cAAc,KAAK,KAAK;GACxB,KAAK,iBAAiB;GACtB,KAAK,cAAc,MAAM;GACzB,KAAK,WAAW,MAAM;GACtB,KAAK,mBAAmB;GACxB,KAAK,4BAA4B;EACnC,CAAC;CACH;CAEA,gBAA8B;EAC5B,MAAM,WAAW,KAAK,MAAM,KAAK;EACjC,IAAI,CAAC,SAAS,QAAQ;EAEtB,KAAK,uBAAuB;EAC5B,KAAK,MAAM,OAAO,yBAAyB,CAAC;CAC9C;CAEA,wBAAsC;EACpC,MAAM,YAAY,KAAK;EACvB,IAAI,CAAC,WAAW;EAEhB,KAAK,uBAAuB;EAC5B,KAAK,MAAM,OAAO,SAAS;CAC7B;CAEA,WAAkB,SAAmC;EACnD,KAAK,UAAU;CACjB;CAEA,YAAkC;EAChC,OAAO,KAAK,MAAM,KAAK,CAAC,CAAC;CAC3B;CAEA,WAAsC;EACpC,OAAO,KAAK,UAAU,CAAC,EAAE,SAAS,KAAK;CACzC;CAEA,cAAgD;EAC9C,OAAO,KAAK,MAAM,KAAK,CAAC,CAAC;CAC3B;CAEA,kBAA8C;EAC5C,OAAO,KAAK,UAAU,CAAC,EAAE,gBAAgB,KAAK;CAChD;CAEA,sBAAqC;EACnC,OAAO,KAAK,UAAU,CAAC,EAAE,oBAAoB,KAAK;CACpD;CAEA,gBAAwD;EACtD,OAAO,KAAK,MAAM,KAAK,CAAC,CAAC;CAC3B;CAEA,gBAAgE;EAC9D,OAAO,KAAK,MAAM,KAAK,CAAC,CAAC;CAC3B;CAEA,0BAAyD,kBAAkB,MAAM,YAAY;CAC7F,iBAAqD,kBAAkB,MAAM,WAAW;CACxF,oBACE,kBAAkB,MAAM,cAAc;CACxC,wBACE,kBAAkB,MAAM,kBAAkB;CAC5C,oBAA4C;EAE1C,MAAM,CAAC,kBAAkB,SAAS,sBAAsB;EACxD,OAAO,kBAAkB,MAAM,cAAc;CAC/C;CACA,sBACE,kBAAkB,MAAM,gBAAgB;CAC1C,sBACE,kBAAkB,MAAM,gBAAgB;CAE1C,qBAAkC;EAChC,MAAM,SAAS,KAAK,UAAU;EAC9B,IAAI,CAAC,QAAQ;EAEb,KAAK,wBAAwB,MAAM;EACnC,KAAK,0BAA0B,MAAM;CACvC;CAEA,2BAAwC;EACtC,KAAK,uBAAuB,KAAK,UAAU,GAAG,qBAAqB;CACrE;CAEA,uBAAoC;EAClC,KAAK,uBAAuB,KAAK,UAAU,GAAG,gBAAgB;CAChE;CAEA,oBAAiC;EAC/B,MAAM,SAAS,KAAK,UAAU;EAC9B,IAAI,CAAC,QAAQ;EACb,IAAI,KAAK,cAAc,KAAK,OAAO,GAAG;EAEtC,YAAY,QAAQ,KAAK,iBAAiB,KAAK,OAAO;EACtD,KAAK,kBAAkB,KAAK,OAAO;CACrC;CAEA,aACE,UACA,MACA,QACM;EACN,IAAI,CAAC,KAAK,gBAAgB,GAAG;EAC7B,IAAI,KAAK,UAAU,CAAC,EAAE,qBAAqB,MAAM,eAAe;EAEhE,MAAM,QAAQ;GACZ;GACA,cAAc,SAAS;GACvB,YAAY;GACZ,YAAY;GACZ,GAAI,SAAS,cAAc,EAAE,OAAO,KAAK,UAAU,CAAC,EAAE,SAAS,KAAK,KAAK,IAAI,CAAC;EAChF;EAEA,KAAK,MAAM,OAAO,KAAK;CACzB;CAEA,WAAkB,OAAoB,QAA+C;EACnF,IAAI,CAAC,KAAK,gBAAgB,GAAG;EAE7B,KAAK,MAAM,OAAO;GAChB;GACA,cAAc,KAAK,UAAU,CAAC,EAAE,gBAAgB,KAAK;GACrD,YAAY;EACd,CAAC;CACH;CAEA,YAAoB,SAA4B;EAC9C,KAAK,qBAAqB;EAC1B,MAAM,oBAAoB,KAAK;EAC/B,MAAM,WAAW,IAAI,OAAO,SAAS,KAAK,yBAAyB,iBAAiB,CAAC;EACrF,KAAK,kBAAkB,KAAK,OAAO;EACnC,KAAK,4BAA4B,oBAAoB,KAAK,OAAO;EAEjE,KAAK,MAAM,OAAO;GAChB,QAAQ;GACR,OAAO,SAAS,SAAS;GACzB,cAAc,SAAS,gBAAgB;EACzC,CAAC;EACD,IAAI,SAAS,qBAAqB,MAAM,eAAe,KAAK,uBAAuB;EACnF,KAAK,mBAAmB,QAAQ;CAClC;CAEA,yBAAiC,mBAA0C;EACzE,MAAM,EACJ,UAAU,WACV,kBACA,UAAU,WACV,gBAAgB,iBAChB,sBAAsB,uBACtB,SAAS,UACT,gBAAgB,iBAChB,WAAW,YACX,WAAW,YACX,OACA,GAAG,uBACD,KAAK;EAET,OAAO;GACL,GAAG;GACH,UAAU,oBAAoB,KAAK,OAAO,CAAC,CAAC;GAC5C;GACA,OAAO,SAAS,KAAA;GAChB,SAAS,wBAAwB,KAAK,iBAAiB,KAAK,OAAO;GACnE,WAAW,OAAO,WAAW;IAC3B,KAAK,WAAW,OAAO,MAAM;IAC7B,KAAK,QAAQ,WAAW,OAAO,MAAM;GACvC;GACA,iBAAiB,UAAU,KAAK,oBAAoB,OAAO,iBAAiB;GAC5E,uBAAuB,UAAU,KAAK,0BAA0B,OAAO,iBAAiB;EAC1F;CACF;CAEA,oBAA4B,OAAgC,mBAAiC;EAC3F,MAAM,qBAAqB,KAAK,cAAc,WAAW;EACzD,MAAM,uBAAuB,KAAK,QAAQ;EAG1C,qBAAqB;GACnB,IAAI,sBAAsB,KAAK,mBAAmB;GAClD,IAAI,uBAAuB,KAAK,cAAc,WAAW,GAAG;GAC5D,IAAI,yBAAyB,KAAK,QAAQ,aAAa;GAEvD,KAAK,QAAQ,iBAAiB,KAAK;EACrC,CAAC;CACH;CAEA,mBAA2B,QAAsB;EAC/C,KAAK,0BAA0B,MAAM;EACrC,KAAK,uBAAuB,MAAM;CACpC;CAEA,0BAAkC,QAAsB;EAEtD,aAAa,QADI,KAAK,QAAQ,gBAAgB,OAAO,OAAO,KAAK,QAAQ,UAC1C,KAAK,aAAa;CACnD;CAEA,wBAAgC,QAAsB;EACpD,MAAM,OAAO,oBAAoB,KAAK,OAAO;EAC7C,MAAM,WAAW,KAAK;EACtB,IAAI,UAAU,gBAAgB,KAAK,eAAe,SAAS,aAAa,KAAK,UAAU;EAEvF,IAAI,YAAY,SAAS,gBAAgB,KAAK,aAAa;GACzD,KAAK,+BAA+B;GACpC,OAAO,cAAc;GACrB,KAAK,cAAc,MAAM;EAC3B;EAEA,KAAK,4BAA4B;EACjC,OAAO,YAAY,KAAK,UAAU,KAAK,WAAW;CACpD;CAEA,0BACE,OACA,mBACM;EACN,IAAI,UAAU,eAAe,KAAK,uBAAuB;EACzD,MAAM,uBAAuB,KAAK,QAAQ;EAC1C,MAAM,8BAA8B,KAAK;EAGzC,qBAAqB;GACnB,IAAI,sBAAsB,KAAK,mBAAmB;GAClD,IAAI,yBAAyB,KAAK,QAAQ,aAAa;GACvD,IAAI,gCAAgC,KAAK,6BAA6B;GACtE,IAAI,KAAK,UAAU,CAAC,EAAE,qBAAqB,MAAM,OAAO;GAExD,KAAK,QAAQ,uBAAuB,KAAK;EAC3C,CAAC;CACH;CAEA,yBAAuC;EACrC,KAAK,MAAM,OAAO;GAAE,UAAU;GAAM,YAAY;EAAK,CAAC;CACxD;CAEA,uBACE,QACA,cAAiD,2BAC3C;EACN,KAAK,MAAM,cAAc,aACvB,KAAK,WAAW,MAAM,QAAQ,YAAY,KAAK,QAAQ,WAAW,KAAK;CAE3E;CAEA,kBAAmC;EACjC,OAAO,yBAAyB,KAAK,OAAO,MAAM;CACpD;CAEA,cAAsB,SAAsC;EAC1D,IAAI,KAAK,wBAAwB,yBAAyB,OAAO,GAAG,OAAO;EAC3E,OAAO,YAAY,KAAK,eAAe,QAAQ,WAAW,aAAa;CACzE;CAEA,kBAA0B,SAAmC;EAC3D,KAAK,gBAAgB,CAAC,GAAI,QAAQ,WAAW,aAAc;EAC3D,KAAK,sBAAsB,yBAAyB,OAAO;CAC7D;CAEA,qBAAmC;EACjC,KAAK,gBAAgB;EACrB,KAAK,sBAAsB;CAC7B;AACF;AAEA,IAAM,mBAAN,MAAuB;CACrB,WAAmB,yBAAyB;CAC5C,gCAAiC,IAAI,IAA8C;CACnF,UAAkB;CAClB,aAAqB;CACrB,mBAA2B;CAE3B,OAAwC;EACtC,OAAO,KAAK;CACd;CAEA,OAAc,OAAoC;EAChD,IAAI,CAAC,oBAAoB,KAAK,UAAU,KAAK,GAAG;EAEhD,KAAK,WAAW,gBAAgB,KAAK,UAAU,KAAK;EACpD,KAAK,WAAW;EAChB,KAAK,YAAY;CACnB;CAEA,MAAgB,KAAiB;EAC/B,KAAK,cAAc;EACnB,IAAI;GACF,OAAO,IAAI;EACb,UAAU;GACR,KAAK,cAAc;GACnB,KAAK,mBAAmB;EAC1B;CACF;CAEA,mBACE,UACA,SACoC;EACpC,OAAO;GACL;GACA;GACA,OAAO,SAAS,KAAK,QAAQ;GAC7B,QAAQ;EACV;CACF;CAEA,oBACE,cACA,UACA,SACM;EACN,aAAa,WAAW;EACxB,aAAa,UAAU;EACvB,KAAK,yBAAyB,YAAY;CAC5C;CAEA,UACE,cACA,QACY;EACZ,aAAa,SAAS;EACtB,KAAK,yBAAyB,YAAY;EAC1C,KAAK,cAAc,IAAI,YAAwD;EAE/E,aAAa;GACX,KAAK,cAAc,OAAO,YAAwD;GAClF,aAAa,SAAS;EACxB;CACF;CAEA,SAAuB;EACrB,KAAK,MAAM,gBAAgB,KAAK,eAC9B,KAAK,mBAAmB,YAAY;CAExC;CAEA,cAA4B;EAC1B,IAAI,KAAK,eAAe,GAAG;GACzB,KAAK,OAAO;GACZ;EACF;EAEA,KAAK,mBAAmB;CAC1B;CAEA,qBAAmC;EACjC,IAAI,KAAK,aAAa,GAAG;EACzB,IAAI,CAAC,KAAK,kBAAkB;EAE5B,KAAK,mBAAmB;EACxB,KAAK,OAAO;CACd;CAEA,mBAA8B,cAAwD;EACpF,MAAM,YAAY,aAAa,SAAS,KAAK,QAAQ;EACrD,IAAI,aAAa,QAAQ,aAAa,OAAO,SAAS,GAAG;EAEzD,aAAa,QAAQ;EACrB,aAAa,SAAS;CACxB;CAEA,yBAAoC,cAAwD;EAC1F,MAAM,YAAY,aAAa,SAAS,KAAK,QAAQ;EACrD,IAAI,aAAa,QAAQ,aAAa,OAAO,SAAS,GAAG;EAEzD,aAAa,QAAQ;CACvB;AACF;AAEA,SAAS,wBACP,YACA,SACM;CACN,MAAM,mBAAmB,YAAY,QAAQ,QAAQ;CAErD,4BACQ,WAAW,kBAAkB,GACnC;EAAC;EAAY,QAAQ;EAAS,QAAQ;CAAS,CACjD;CAEA,4BAA4B,WAAW,yBAAyB,CAAC;CACjE,4BACQ,WAAW,mBAAmB,GACpC;EAAC;EAAY;EAAkB,QAAQ;EAAa,QAAQ;CAAQ,CACtE;CAEA,4BAA4B,WAAW,qBAAqB,CAAC;AAC/D;AAEA,SAAS,oBAAoB,SAA6D;CACxF,OAAO;EACL,aAAa,QAAQ,eAAe;EACpC,UAAU,QAAQ,gBAAgB,OAAO,OAAQ,QAAQ,YAAY;CACvE;AACF;AAEA,SAAS,sBAAsB,YAA+D;CAC5F,OAAO;EACL,MAAM;EACN,WAAW,YACT,QAAQ,yBAAyB,EAC/B,2BAA2B;GACzB,SAAS,UAAU,MAAM,WACvB,WAAW,aAAa,UAAU,MAAM,UAAU,IAAI;GACxD,eAAe,KAAA;EACjB,GACF,CAAC;CACL;AACF;AAEA,SAAS,aACP,QACA,UACA,OACM;CACN,IAAI,CAAC,QAAQ;CAEb,MAAM,MAAM,YAAY,QAAQ;CAChC,IAAI,QAAQ,MAAM,IAAI,GAAG;CACzB,MAAM,cAAc,oBAAoB,QAAQ;CAChD,MAAM,sBAAsB,MAAM,YAAY;CAE9C,MAAM,OAAO,KAAK,WAAW;CAC7B,IAAI,CAAC,UAAU;EACb,OAAO,cAAc;EACrB;CACF;CAEA,MAAM,UAAU,2BAA2B,QAAQ;CACnD,IAAI,SAAS;EACX,OAAO,cAAc,SAAS;GAC5B,UAAU,SAAS;GACnB,YAAY,SAAS;GACrB,0BAA0B,SAAS;GACnC,6BAA6B,SAAS;GACtC,YAAY,SAAS;GACrB,kBAAkB,SAAS;GAC3B,gBAAgB,kCAAkC,QAAQ;GAC1D,4BAA4B,SAAS;EACvC,CAAC;EACD;CACF;CAEA,IAAI,iCAAiC,UAAU,qBAAqB,WAAW,GAAG;EAChF,OAAO,SAAS,SAAS,MAAM;GAC7B,cAAc,SAAS;GACvB,YAAY,SAAS;GACrB,gBAAgB,kCAAkC,QAAQ;EAC5D,CAAC;EACD;CACF;CAEA,OAAO,aAAa;EAClB,YAAY,SAAS;EACrB,cAAc,SAAS;EACvB,YAAY,SAAS;EACrB,gBAAgB,kCAAkC,QAAQ;EAC1D,MAAM,SAAS;CACjB,CAAC;AACH;AAEA,SAAS,iCACP,UACA,qBACA,aACS;CACT,IAAI,SAAS,iBAAiB,eAAe,OAAO;CACpD,IAAI,wBAAwB,aAAa,OAAO;CAEhD,OAAO,wBAAwB;AACjC;AAEA,SAAS,YACP,QACA,iBACA,SACM;CACN,IAAI,CAAC,QAAQ;CAEb,OAAO,WAAW,wBAAwB,iBAAiB,OAAO,CAAC;AACrE;AAEA,SAAS,wBACP,iBACA,SACyB;CACzB,IAAI,yBAAyB,OAAO,MAAM,QAAQ,OAAO,QAAQ,WAAW,CAAC;CAE7E,OAAO,CAAC,iBAAiB,GAAI,QAAQ,WAAW,CAAC,CAAE;AACrD;AAEA,SAAS,yBAAyB,SAAuD;CACvF,OAAO,QAAQ,aAAa;AAC9B;AAEA,SAAS,YACP,MACA,OACS;CACT,IAAI,CAAC,MAAM,OAAO;CAClB,IAAI,KAAK,WAAW,MAAM,QAAQ,OAAO;CAEzC,OAAO,KAAK,OAAO,QAAQ,UAAU,WAAW,MAAM,MAAM;AAC9D;AAEA,SAAS,cAAc,OAA+B;CAEpD,MADqB,KAAK,CAAC,CAAC,QACpB,QAAQ;CAChB,MAAM,OAAO,yBAAyB,CAAC;AACzC;AAEA,SAAS,eACP,QACA,eACqB;CACrB,OAAO;EACL,aAAa,OAAO,CAAC,EAAE,MAAM;EAC7B,eAAe,aAAa;GAC1B,cAAc,OAAO,YAAY,QAAQ,GAAG,oBAAoB,QAAQ,CAAC;GACzE,OAAO,CAAC,EAAE,aAAa,QAAQ;EACjC;EACA,UAAU,MAAM,YAAY,OAAO,CAAC,EAAE,QAAQ,MAAM,OAAO;EAC3D,OAAO,aAAa,YAAY,OAAO,CAAC,EAAE,KAAK,aAAa,OAAO;EACnE,eAAe,QAAQ,MAAM,YAAY,OAAO,CAAC,EAAE,aAAa,QAAQ,MAAM,OAAO;EACrF,oBAAoB,mBAAmB,OAAO,CAAC,EAAE,kBAAkB,cAAc;EACjF,kBAAkB,SAAS,YAAY,OAAO,CAAC,EAAE,gBAAgB,SAAS,OAAO,KAAK;EACtF,gBAAgB,OAAO,CAAC,EAAE,SAAS,KAAK;EACxC,uBAAuB,OAAO,CAAC,EAAE,gBAAgB,KAAK;EACtD,iBAAiB,OAAO,CAAC,EAAE,UAAU,KAAK;EAC1C,gBAAgB,OAAO,CAAC,EAAE,SAAS,KAAK;EACxC,oBAAoB,OAAO,CAAC,EAAE,aAAa,KAAK;EAChD,kBAAkB,OAAO,CAAC,EAAE,WAAW,KAAK;EAC5C,kBAAkB,OAAO,CAAC,EAAE,WAAW,KAAK;EAC5C,wBAAwB,OAAO,CAAC,EAAE,iBAAiB,KAAK;CAC1D;AACF;AAEA,SAAS,sBAAgD;CACvD,IAAI,aAAa;CACjB,IAAI,MAA8B;CAClC,IAAI,cAAsC;CAE1C,OAAO;EACL,kBAAkB;EAClB,WAAW;EACX,mBAAmB;EACnB,SAAS,SAAS,kBAAkB,YAAY;GAC9C,cAAc;GACd,MAAM;GACN,cAAc;EAChB;EACA,aAAa;GACX,cAAc;GACd,MAAM;GACN,cAAc;EAChB;CACF;AACF;AAEA,SAAS,YACP,UAoBwB;CACxB,IAAI,CAAC,UAAU,OAAO;CAEtB,MAAM,cAAc,SAAS,iBAAiB;CAC9C,MAAM,cAAc,sBAAsB,QAAQ,KAAK,uBAAuB,QAAQ;CACtF,MAAM,WAAW,oBAAoB,UAAU,WAAW;CAC1D,MAAM,cAAc,eAAe,CAAC,cAAe,SAAS,QAAQ,KAAM;CAC1E,MAAM,cAAc,oBAAoB,QAAQ;CAChD,IAAI,gBAAgB,aAAa,OAAO;CAExC,OAAO,GAAG,YAAY,QAAQ,SAAS,QAAQ,YAAY,QAAQ,yBACjE,SAAS,gBACX,EAAE,QAAQ,iBAAiB,SAAS,YAAY,SAAS,kBAAkB,QAAQ,EAAE,QAAQ,gBAAgB,QAAQ;AACvH;AAEA,SAAS,oBACP,UAOA,aACA;CACA,IAAI,sBAAsB,QAAQ,GAAG,OAAO;CAC5C,IAAI,aAAa,OAAO;CACxB,IAAI,uBAAuB,QAAQ,GAAG,OAAO;CAE7C,OAAO,SAAS,YAAY;AAC9B;AAEA,SAAS,oBACP,UAYwB;CACxB,IAAI,CAAC,UAAU,OAAO;CAEtB,MAAM,UAAU,aAAa,WAAW,SAAS,UAAU;CAC3D,MAAM,SAAS,YAAY,WAAW,SAAS,SAAS;CACxD,MAAM,OAAO,UAAU,WAAW,SAAS,OAAO;CAClD,OAAO,GAAG,SAAS,cAAc,GAAG,QAAQ,SAAS,gBAAgB,GAAG,QACtE,SAAS,cAAc,GACxB,QAAQ,gBAAgB,OAAO,EAAE,QAAQ,mBAAmB,QAAQ,IAAI;AAC3E;AAEA,IAAM,8BAAc,IAAI,QAAiC;AACzD,IAAM,uCAAuB,IAAI,QAAwC;AACzE,IAAM,+BAAe,IAAI,QAAwC;AACjE,IAAM,6BAAa,IAAI,QAAkC;AACzD,IAAM,2BAAW,IAAI,QAAmC;AACxD,IAAM,qCAAqB,IAAI,QAG7B;AACF,IAAI,iBAAiB;AACrB,IAAI,0BAA0B;AAC9B,IAAI,kBAAkB;AACtB,IAAI,gBAAgB;AACpB,IAAI,cAAc;AAElB,SAAS,gBAAgB,SAAqD;CAC5E,IAAI,CAAC,SAAS,OAAO;CAErB,MAAM,WAAW,YAAY,IAAI,OAAO;CACxC,IAAI,aAAa,KAAA,GAAW,OAAO,GAAG;CAEtC,MAAM,MAAM;CACZ,kBAAkB;CAClB,YAAY,IAAI,SAAS,GAAG;CAC5B,OAAO,GAAG;AACZ;AAEA,SAAS,yBACP,kBACQ;CACR,IAAI,CAAC,kBAAkB,OAAO;CAE9B,MAAM,WAAW,qBAAqB,IAAI,gBAAgB;CAC1D,IAAI,aAAa,KAAA,GAAW,OAAO,GAAG;CAEtC,MAAM,MAAM;CACZ,2BAA2B;CAC3B,qBAAqB,IAAI,kBAAkB,GAAG;CAC9C,OAAO,GAAG;AACZ;AAEA,SAAS,iBAAiB,UAA6D;CACrF,IAAI,CAAC,UAAU,OAAO;CACtB,MAAM,WAAW,aAAa,IAAI,QAAQ;CAC1C,IAAI,aAAa,KAAA,GAAW,OAAO,GAAG;CACtC,MAAM,MAAM;CACZ,aAAa,IAAI,UAAU,GAAG;CAC9B,OAAO,GAAG;AACZ;AAEA,SAAS,gBAAgB,UAGd;CAET,OAAO,KAAK,UAAU,CACpB,SAAS,4BAA4B,CAAC,GACtC,SAAS,8BAA8B,CAAC,CAC1C,CAAC;AACH;AAEA,SAAS,mBACP,QACA,MACQ;CACR,IAAI,CAAC,UAAU,CAAC,MAAM,OAAO;CAE7B,OAAO,GAAG,eAAe,MAAM,EAAE,GAAG,aAAa,IAAI;AACvD;AAEA,SAAS,eAAe,QAAkC;CACxD,MAAM,WAAW,WAAW,IAAI,MAAM;CACtC,IAAI,aAAa,KAAA,GAAW,OAAO,GAAG;CAEtC,MAAM,MAAM;CACZ,iBAAiB;CACjB,WAAW,IAAI,QAAQ,GAAG;CAC1B,OAAO,GAAG;AACZ;AAEA,SAAS,aAAa,MAAiC;CACrD,MAAM,WAAW,SAAS,IAAI,IAAI;CAClC,IAAI,aAAa,KAAA,GAAW,OAAO,GAAG;CAEtC,MAAM,MAAM;CACZ,eAAe;CACf,SAAS,IAAI,MAAM,GAAG;CACtB,OAAO,GAAG;AACZ;AAEA,SAAS,uBACP,UACS;CACT,OAAO,aAAa,YAAY,SAAS,YAAY,QAAQ,SAAS,YAAY,KAAA;AACpF;AAEA,SAAS,sBACP,UAKS;CACT,OACE,YAAY,YACZ,UAAU,YACV,SAAS,WAAW,QACpB,SAAS,WAAW,KAAA,KACpB,SAAS,SAAS,QAClB,SAAS,SAAS,KAAA;AAEtB;AAEA,SAAS,2BACP,UAC8C;CAC9C,IAAI,SAAS,UAAU,SAAS,MAC9B,OAAO,kBAAkB,SAAS,QAAQ,SAAS,IAAI;CAGzD,OAAO,SAAS,WAAW;AAC7B;AAEA,SAAS,kCACP,UACkC;CAClC,OAAO,SAAS,kBAAkB,SAAS,MAAM,kBAAkB;AACrE;AAEA,SAAS,kBAAkB,QAA0B,MAA8C;CACjG,MAAM,gBAAgB,mBAAmB,IAAI,MAAM;CACnD,MAAM,WAAW,eAAe,IAAI,IAAI;CACxC,IAAI,UAAU,OAAO;CAErB,MAAM,UAAU,0BAA0B,QAAQ,IAAI;CACtD,IAAI,eAAe;EACjB,cAAc,IAAI,MAAM,OAAO;EAC/B,OAAO;CACT;CAEA,MAAM,wBAAQ,IAAI,QAAgD;CAClE,MAAM,IAAI,MAAM,OAAO;CACvB,mBAAmB,IAAI,QAAQ,KAAK;CACpC,OAAO;AACT;AAEA,SAAS,2BAAqD;CAC5D,OAAO;EACL,QAAQ;EACR,OAAO;EACP,UAAU;EACV,cAAc;EACd,YAAY;EACZ,YAAY;CACd;AACF;;AAGA,SAAS,yBAAsD;CAC7D,IAAI,SAAkC;CACtC,IAAI,OAAO;CACX,QAAQ,aAAa;EACnB,IAAI,SAAS,iBAAiB,QAAQ,OAAO;EAE7C,SAAS,SAAS;EAClB,OAAO,SAAS,OAAO,UAAU,GAAG,OAAO,MAAM,IAAI;EACrD,OAAO;CACT;AACF;AAEA,SAAS,gBACP,UACA,OAC0B;CAC1B,OAAO;EACL,QAAQ,WAAW,UAAU,OAAO,QAAQ;EAC5C,OAAO,WAAW,UAAU,OAAO,OAAO;EAC1C,UAAU,WAAW,UAAU,OAAO,UAAU;EAChD,cAAc,WAAW,UAAU,OAAO,cAAc;EACxD,YAAY,WAAW,UAAU,OAAO,YAAY;EACpD,YAAY,WAAW,UAAU,OAAO,YAAY;CACtD;AACF;AAEA,SAAS,WACP,UACA,OACA,KAC6B;CAC7B,IAAI,OAAO,UAAU,eAAe,KAAK,OAAO,GAAG,GACjD,OAAO,MAAM;CAEf,OAAO,SAAS;AAClB;AAEA,SAAS,oBACP,UACA,OACS;CACT,KAAK,MAAM,OAAO,OAAO,KAAK,KAAK,GACjC,IAAI,CAAC,OAAO,GAAG,SAAS,MAAM,MAAM,IAAI,GAAG,OAAO;CAGpD,OAAO;AACT;AAEA,SAAS,mBACP,YACqC;CACrC,OAAQ,WAA4C;AACtD"}
|
package/package.json
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@singapore-editor/react",
|
|
3
|
+
"version": "0.1.1",
|
|
4
|
+
"files": [
|
|
5
|
+
"README.md",
|
|
6
|
+
"dist"
|
|
7
|
+
],
|
|
8
|
+
"type": "module",
|
|
9
|
+
"exports": {
|
|
10
|
+
".": {
|
|
11
|
+
"types": "./dist/index.d.ts",
|
|
12
|
+
"import": "./dist/index.js",
|
|
13
|
+
"default": "./dist/index.js"
|
|
14
|
+
}
|
|
15
|
+
},
|
|
16
|
+
"publishConfig": {
|
|
17
|
+
"access": "public",
|
|
18
|
+
"registry": "https://registry.npmjs.org/"
|
|
19
|
+
},
|
|
20
|
+
"scripts": {
|
|
21
|
+
"build": "bun ../../scripts/build-package.ts",
|
|
22
|
+
"test": "vitest run",
|
|
23
|
+
"typecheck": "tsgo --noEmit",
|
|
24
|
+
"lint": "oxlint .",
|
|
25
|
+
"format": "oxfmt --write .",
|
|
26
|
+
"format:check": "oxfmt --check ."
|
|
27
|
+
},
|
|
28
|
+
"dependencies": {
|
|
29
|
+
"@singapore-editor/core": "0.1.2"
|
|
30
|
+
},
|
|
31
|
+
"devDependencies": {
|
|
32
|
+
"@playwright/test": "^1.63.0",
|
|
33
|
+
"@shikijs/langs": "4.4.3",
|
|
34
|
+
"@shikijs/themes": "4.4.3",
|
|
35
|
+
"@types/react": "19.3.0",
|
|
36
|
+
"@types/react-dom": "19.3.0",
|
|
37
|
+
"@typescript/native-preview": "7.0.0-dev.20260707.2",
|
|
38
|
+
"@vitest/browser-playwright": "^5.0.2",
|
|
39
|
+
"happy-dom": "^20.14.5",
|
|
40
|
+
"oxfmt": "0.70.0",
|
|
41
|
+
"oxlint": "1.85.0",
|
|
42
|
+
"react": "19.3.0",
|
|
43
|
+
"react-dom": "19.3.0",
|
|
44
|
+
"tree-sitter-typescript": "^0.23.2",
|
|
45
|
+
"typescript": "~6.0.3",
|
|
46
|
+
"vitest": "^5.0.2"
|
|
47
|
+
},
|
|
48
|
+
"peerDependencies": {
|
|
49
|
+
"@singapore-editor/core": "0.1.2",
|
|
50
|
+
"react": ">=18.0.0",
|
|
51
|
+
"react-dom": ">=18.0.0"
|
|
52
|
+
}
|
|
53
|
+
}
|