@sciflow/editor-start 0.0.3 → 0.1.0

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.
@@ -0,0 +1,95 @@
1
+ /**
2
+ * @module read-only
3
+ *
4
+ * A generic, toggleable read-only `Feature`: vetoes every doc-changing
5
+ * transaction while leaving selection/scroll transactions free to pass (so
6
+ * browsing — clicking around, selecting text to read it — still works),
7
+ * disables the DOM's own `contenteditable`/caret/IME behavior, and marks the
8
+ * editable surface with a styling hook so consumers can render a muted look.
9
+ *
10
+ * # Mechanism
11
+ *
12
+ * - `filterTransaction: (tr, state) => !tr.docChanged || isExternalSyncTransaction(tr) || key.getState(state) !== true`
13
+ * — `EditorState.applyTransaction` checks this BEFORE running any plugin's
14
+ * `state.apply`, so a vetoed transaction never reaches the doc, the
15
+ * undo-history plugin, or anything else — the state comes back byte-for-
16
+ * byte unchanged (`newState === oldState`). Selection-only and meta-only
17
+ * transactions (`tr.docChanged === false` — e.g. a click, or another
18
+ * feature's own `dispatchMeta` update) are explicitly let through, and so
19
+ * is `Editor`'s own external-doc reconciliation transaction (see the
20
+ * "Programmatic doc replacement" section below) — only an actual user/
21
+ * command edit is vetoed.
22
+ * - `props.editable: (state) => key.getState(state) !== true` — the DOM-level
23
+ * backstop: disables `contenteditable`, so the browser's own caret/IME
24
+ * never engages in the first place. `filterTransaction` alone would still
25
+ * technically block an edit, but a live caret sitting in "dead" text reads
26
+ * as broken, not read-only.
27
+ * - `props.attributes: (state) => (key.getState(state) ? { 'data-readonly': 'true' } : {})`
28
+ * — the styling hook. No baked-in colors here (only a `data-readonly`
29
+ * attribute) — style the muted look with your own token-based CSS, e.g.
30
+ * `.sf-editable-surface .ProseMirror[data-readonly] { opacity: var(--sf-opacity-muted); }`.
31
+ *
32
+ * # Programmatic doc replacement still works while read-only
33
+ *
34
+ * "Read-only" means "the user cannot edit this document" — not "this
35
+ * document can never change from any source." A host that reassigns
36
+ * `editor.doc` (e.g. a revision viewer paging through history) drives
37
+ * `Editor.updateFromSync()`, which reconciles the mounted view via its own
38
+ * transaction (`Editor`'s internal `syncViewWithState()`), tagged with
39
+ * `EXTERNAL_SYNC_TRANSACTION_META`. `filterTransaction` lets THAT transaction
40
+ * through even while read-only, so the view keeps rendering every
41
+ * subsequent doc the host assigns; only a transaction WITHOUT that meta
42
+ * (a real edit) is vetoed. See `@sciflow/editor-core`'s
43
+ * `EXTERNAL_SYNC_TRANSACTION_META`/`isExternalSyncTransaction` doc for the
44
+ * full contract — any custom read-only-style `filterTransaction` should
45
+ * follow the same check, or it will "freeze" the editor's own
46
+ * `updateFromSync()` calls after the first doc assignment, not just block
47
+ * user typing.
48
+ *
49
+ * # Toggling without re-initializing the editor
50
+ *
51
+ * The read-only flag lives in PLUGIN STATE (keyed, like `range-decorations.ts`,
52
+ * so it survives every transaction via a plain `state.apply`), not a value
53
+ * captured once at feature-construction time — `filterTransaction`/`editable`/
54
+ * `attributes` all read the CURRENT state on every check. This means the
55
+ * flag genuinely toggles live, no `configureFeatures()`/re-mount needed:
56
+ *
57
+ * ```typescript
58
+ * import { createReadOnlyFeature } from '@sciflow/editor-start/bundle';
59
+ *
60
+ * const { feature, key } = createReadOnlyFeature('my-read-only');
61
+ * await editor.configureFeatures([...otherFeatures, feature]);
62
+ *
63
+ * editor.plugins.dispatchMeta(key, true); // now read-only
64
+ * editor.plugins.dispatchMeta(key, false); // editable again, same editor instance
65
+ * ```
66
+ *
67
+ * # A caveat worth stating plainly, not silently
68
+ *
69
+ * `filterTransaction` guarantees the DOC never actually changes for a
70
+ * vetoed transaction, but a host's own `dispatchTransaction` handler that
71
+ * inspects the REJECTED transaction object directly (rather than comparing
72
+ * before/after state) can still be misled: `tr.docChanged` reflects what the
73
+ * transaction WOULD have done, not whether it was applied. A consumer
74
+ * wiring up its own change-tracking on a read-only editor should compare
75
+ * `newState !== oldState` (or `newState.doc.eq(oldState.doc)`) rather than
76
+ * trusting `tr.docChanged` alone. `@sciflow/editor-core`'s own
77
+ * `handleTransaction` does inspect `tr.docChanged` directly — this is a
78
+ * known, narrow gap for the (unusual) case of listening to `editor-change`
79
+ * on a read-only instance, not something this feature can close from a
80
+ * plugin alone. Not a concern for the ordinary "browse a read-view editor,
81
+ * nobody listens to its `editor-change`" case.
82
+ */
83
+ import { PluginKey } from 'prosemirror-state';
84
+ import { type Feature } from '@sciflow/editor-core';
85
+ /**
86
+ * Build a fresh, independently-keyed read-only `Feature`. `initialReadOnly`
87
+ * sets the STARTING value (default `false` — editable, matching an ordinary
88
+ * editor's least-surprising default); flip it live afterward via
89
+ * `editor.plugins.dispatchMeta(key, true | false)`.
90
+ */
91
+ export declare function createReadOnlyFeature(name: string, initialReadOnly?: boolean): {
92
+ feature: Feature;
93
+ key: PluginKey<boolean>;
94
+ };
95
+ //# sourceMappingURL=read-only.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"read-only.d.ts","sourceRoot":"","sources":["../../src/lib/read-only.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiFG;AAEH,OAAO,EAAU,SAAS,EAAE,MAAM,mBAAmB,CAAC;AACtD,OAAO,EAA6B,KAAK,OAAO,EAAE,MAAM,sBAAsB,CAAC;AAE/E;;;;;GAKG;AACH,wBAAgB,qBAAqB,CACnC,IAAI,EAAE,MAAM,EACZ,eAAe,UAAQ,GACtB;IAAE,OAAO,EAAE,OAAO,CAAC;IAAC,GAAG,EAAE,SAAS,CAAC,OAAO,CAAC,CAAA;CAAE,CAiC/C"}
@@ -0,0 +1,123 @@
1
+ /**
2
+ * @module read-only
3
+ *
4
+ * A generic, toggleable read-only `Feature`: vetoes every doc-changing
5
+ * transaction while leaving selection/scroll transactions free to pass (so
6
+ * browsing — clicking around, selecting text to read it — still works),
7
+ * disables the DOM's own `contenteditable`/caret/IME behavior, and marks the
8
+ * editable surface with a styling hook so consumers can render a muted look.
9
+ *
10
+ * # Mechanism
11
+ *
12
+ * - `filterTransaction: (tr, state) => !tr.docChanged || isExternalSyncTransaction(tr) || key.getState(state) !== true`
13
+ * — `EditorState.applyTransaction` checks this BEFORE running any plugin's
14
+ * `state.apply`, so a vetoed transaction never reaches the doc, the
15
+ * undo-history plugin, or anything else — the state comes back byte-for-
16
+ * byte unchanged (`newState === oldState`). Selection-only and meta-only
17
+ * transactions (`tr.docChanged === false` — e.g. a click, or another
18
+ * feature's own `dispatchMeta` update) are explicitly let through, and so
19
+ * is `Editor`'s own external-doc reconciliation transaction (see the
20
+ * "Programmatic doc replacement" section below) — only an actual user/
21
+ * command edit is vetoed.
22
+ * - `props.editable: (state) => key.getState(state) !== true` — the DOM-level
23
+ * backstop: disables `contenteditable`, so the browser's own caret/IME
24
+ * never engages in the first place. `filterTransaction` alone would still
25
+ * technically block an edit, but a live caret sitting in "dead" text reads
26
+ * as broken, not read-only.
27
+ * - `props.attributes: (state) => (key.getState(state) ? { 'data-readonly': 'true' } : {})`
28
+ * — the styling hook. No baked-in colors here (only a `data-readonly`
29
+ * attribute) — style the muted look with your own token-based CSS, e.g.
30
+ * `.sf-editable-surface .ProseMirror[data-readonly] { opacity: var(--sf-opacity-muted); }`.
31
+ *
32
+ * # Programmatic doc replacement still works while read-only
33
+ *
34
+ * "Read-only" means "the user cannot edit this document" — not "this
35
+ * document can never change from any source." A host that reassigns
36
+ * `editor.doc` (e.g. a revision viewer paging through history) drives
37
+ * `Editor.updateFromSync()`, which reconciles the mounted view via its own
38
+ * transaction (`Editor`'s internal `syncViewWithState()`), tagged with
39
+ * `EXTERNAL_SYNC_TRANSACTION_META`. `filterTransaction` lets THAT transaction
40
+ * through even while read-only, so the view keeps rendering every
41
+ * subsequent doc the host assigns; only a transaction WITHOUT that meta
42
+ * (a real edit) is vetoed. See `@sciflow/editor-core`'s
43
+ * `EXTERNAL_SYNC_TRANSACTION_META`/`isExternalSyncTransaction` doc for the
44
+ * full contract — any custom read-only-style `filterTransaction` should
45
+ * follow the same check, or it will "freeze" the editor's own
46
+ * `updateFromSync()` calls after the first doc assignment, not just block
47
+ * user typing.
48
+ *
49
+ * # Toggling without re-initializing the editor
50
+ *
51
+ * The read-only flag lives in PLUGIN STATE (keyed, like `range-decorations.ts`,
52
+ * so it survives every transaction via a plain `state.apply`), not a value
53
+ * captured once at feature-construction time — `filterTransaction`/`editable`/
54
+ * `attributes` all read the CURRENT state on every check. This means the
55
+ * flag genuinely toggles live, no `configureFeatures()`/re-mount needed:
56
+ *
57
+ * ```typescript
58
+ * import { createReadOnlyFeature } from '@sciflow/editor-start/bundle';
59
+ *
60
+ * const { feature, key } = createReadOnlyFeature('my-read-only');
61
+ * await editor.configureFeatures([...otherFeatures, feature]);
62
+ *
63
+ * editor.plugins.dispatchMeta(key, true); // now read-only
64
+ * editor.plugins.dispatchMeta(key, false); // editable again, same editor instance
65
+ * ```
66
+ *
67
+ * # A caveat worth stating plainly, not silently
68
+ *
69
+ * `filterTransaction` guarantees the DOC never actually changes for a
70
+ * vetoed transaction, but a host's own `dispatchTransaction` handler that
71
+ * inspects the REJECTED transaction object directly (rather than comparing
72
+ * before/after state) can still be misled: `tr.docChanged` reflects what the
73
+ * transaction WOULD have done, not whether it was applied. A consumer
74
+ * wiring up its own change-tracking on a read-only editor should compare
75
+ * `newState !== oldState` (or `newState.doc.eq(oldState.doc)`) rather than
76
+ * trusting `tr.docChanged` alone. `@sciflow/editor-core`'s own
77
+ * `handleTransaction` does inspect `tr.docChanged` directly — this is a
78
+ * known, narrow gap for the (unusual) case of listening to `editor-change`
79
+ * on a read-only instance, not something this feature can close from a
80
+ * plugin alone. Not a concern for the ordinary "browse a read-view editor,
81
+ * nobody listens to its `editor-change`" case.
82
+ */
83
+ import { Plugin, PluginKey } from 'prosemirror-state';
84
+ import { isExternalSyncTransaction } from '@sciflow/editor-core';
85
+ /**
86
+ * Build a fresh, independently-keyed read-only `Feature`. `initialReadOnly`
87
+ * sets the STARTING value (default `false` — editable, matching an ordinary
88
+ * editor's least-surprising default); flip it live afterward via
89
+ * `editor.plugins.dispatchMeta(key, true | false)`.
90
+ */
91
+ export function createReadOnlyFeature(name, initialReadOnly = false) {
92
+ const key = new PluginKey(name);
93
+ const plugin = new Plugin({
94
+ key,
95
+ state: {
96
+ init: () => initialReadOnly,
97
+ apply(tr, readOnly) {
98
+ const meta = tr.getMeta(key);
99
+ return typeof meta === 'boolean' ? meta : readOnly;
100
+ },
101
+ },
102
+ filterTransaction(tr, state) {
103
+ if (!tr.docChanged)
104
+ return true;
105
+ // The editor's OWN external-doc reconciliation (Editor.updateFromSync /
106
+ // .applyOps, via syncViewWithState) — not a user edit. Letting it
107
+ // through is what makes `editor.doc = nextSnapshot` keep rendering on a
108
+ // read-only instance after the first assignment; see the module doc.
109
+ if (isExternalSyncTransaction(tr))
110
+ return true;
111
+ return key.getState(state) !== true;
112
+ },
113
+ props: {
114
+ editable: (state) => key.getState(state) !== true,
115
+ attributes: (state) => (key.getState(state) ? { 'data-readonly': 'true' } : {}),
116
+ },
117
+ });
118
+ const feature = {
119
+ name,
120
+ addPlugins: () => [plugin],
121
+ };
122
+ return { feature, key };
123
+ }
@@ -0,0 +1,217 @@
1
+ /**
2
+ * @module external-widget-simulator
3
+ * @internal
4
+ *
5
+ * INTERNAL TESTING UTILITY — NOT STABLE PUBLIC API.
6
+ * This module is exported from the `@sciflow/editor-start` package solely to
7
+ * enable automated tests and the interactive demo page to verify light-DOM
8
+ * reachability. Its API may change without a semver notice. Do not depend on
9
+ * it in production code.
10
+ *
11
+ * A vanilla-JS simulator that models the three key behaviours of browser
12
+ * proofreading and AI writing extensions (e.g. Grammarly, the LanguageTool
13
+ * browser add-on, DeepL Write, etc.) when they interact with a page's
14
+ * editable surface.
15
+ *
16
+ * Design constraints
17
+ * ------------------
18
+ * - Zero runtime dependencies — only public web APIs.
19
+ * - Never traverses into any ShadowRoot. Extensions operate exclusively on
20
+ * the flat document tree; they have no access to shadow-DOM internals.
21
+ * - Suitable for both automated tests (jsdom / vitest) and manual in-browser
22
+ * testing via the demo page.
23
+ *
24
+ * The three capabilities modelled
25
+ * --------------------------------
26
+ * 1. `discover(root?)` — walks the light DOM for editable targets exactly as a
27
+ * real extension would: `querySelectorAll` on [contenteditable], textarea,
28
+ * and text inputs, then filters to nodes whose root is the document (i.e.
29
+ * not behind a shadow boundary).
30
+ *
31
+ * 2. `markRange(target, from, to, options?)` — draws underline-style overlay
32
+ * markers over a character range inside a text node the way widgets render
33
+ * grammar/spell highlights. Uses Range + getClientRects() and places
34
+ * absolutely-positioned <span> elements in an overlay layer that is a
35
+ * sibling of the editable (never inside it).
36
+ *
37
+ * 3. DOM mutation operations that mimic extensions touching the editable
38
+ * directly, bypassing the editor's own transaction mechanism:
39
+ * - `injectMarker(target, from, to)` — wraps a text sub-range in a
40
+ * `<span data-extn-marker="1">` (how widgets tag matches for hover
41
+ * interactions without accepting/rejecting them yet).
42
+ * - `applyCorrection(target, from, to, replacement)` — replaces a text
43
+ * sub-range via raw Range manipulation (the "accept suggestion" action).
44
+ *
45
+ * Threat/usage model
46
+ * ------------------
47
+ * A ProseMirror contenteditable mounted inside a shadow root is INVISIBLE to
48
+ * extensions because they do not call `shadowRoot.querySelector`. This
49
+ * simulator encodes that exact distinction: `discover()` returns only light-DOM
50
+ * editables whose `getRootNode() === document`. The fact that a slotted
51
+ * element satisfies this condition while a shadow-buried element does not is
52
+ * the core regression guard for the light-DOM spike (Option B).
53
+ *
54
+ * jsdom limitation
55
+ * ----------------
56
+ * `getClientRects()` is not implemented in jsdom and always returns an empty
57
+ * DOMRectList. `markRange()` therefore cannot be meaningfully tested in the
58
+ * standard vitest suite — it is exercised through the manual demo page instead.
59
+ * `discover()`, `injectMarker()`, and `applyCorrection()` are all jsdom-safe
60
+ * and form the automated test surface.
61
+ */
62
+ /** An editable element found by the simulator's discovery walk. */
63
+ export interface EditableTarget {
64
+ /** The discovered element. */
65
+ element: HTMLElement;
66
+ /**
67
+ * The root node of the element. For a light-DOM element this will be the
68
+ * `Document`; for a shadow-buried element it would be a `ShadowRoot`.
69
+ * The simulator's `discover()` only returns elements where this is
70
+ * `document` — this field is exposed so tests can assert it explicitly.
71
+ */
72
+ rootNode: Node;
73
+ /** True when the element is inside the light DOM (`rootNode === document`). */
74
+ isLightDom: boolean;
75
+ }
76
+ /** Options for the `markRange` overlay operation. */
77
+ export interface MarkRangeOptions {
78
+ /** CSS color for the underline. Defaults to `'#ef4444'` (red). */
79
+ color?: string;
80
+ /**
81
+ * How many pixels below the text baseline the underline is offset.
82
+ * Defaults to `2`.
83
+ */
84
+ offsetY?: number;
85
+ /** CSS z-index for the overlay layer. Defaults to `'9999'`. */
86
+ zIndex?: string;
87
+ }
88
+ /** A marker handle returned by `injectMarker`, used for cleanup. */
89
+ export interface InjectedMarker {
90
+ /** The `<span data-extn-marker="1">` wrapper element. */
91
+ span: HTMLSpanElement;
92
+ /** Removes the injected span and restores the original text layout. */
93
+ remove(): void;
94
+ }
95
+ /** Result of `applyCorrection`. */
96
+ export interface CorrectionResult {
97
+ /** The text that was replaced. */
98
+ replaced: string;
99
+ /** The replacement text that was inserted. */
100
+ inserted: string;
101
+ }
102
+ /**
103
+ * Walk the light DOM for editable targets, exactly as browser extensions do.
104
+ *
105
+ * Extensions use `document.querySelectorAll` (or equivalent TreeWalker
106
+ * traversals) to find `[contenteditable]`, `textarea`, and `input[type=text]`.
107
+ * Critically, they do NOT call `shadowRoot.querySelectorAll` or otherwise
108
+ * traverse into shadow trees — they only see what is in the flat document tree.
109
+ *
110
+ * This function replicates that: it queries from `root` (defaulting to
111
+ * `document`) and then filters the results to those whose `getRootNode()` is
112
+ * the passed `root`. An editable that lives inside a shadow root will NOT
113
+ * satisfy this condition and will NOT be returned.
114
+ *
115
+ * @param root The root to query from. Defaults to `document`.
116
+ * @returns An array of `EditableTarget` objects for each discovered field.
117
+ *
118
+ * @example
119
+ * // Asserts the editor's contenteditable is reachable from the document root:
120
+ * const targets = discover(document);
121
+ * const ce = targets.find(t => t.element.hasAttribute('contenteditable'));
122
+ * assert(ce?.isLightDom === true);
123
+ * assert(ce?.rootNode === document);
124
+ */
125
+ export declare function discover(root?: Document | Element): EditableTarget[];
126
+ /**
127
+ * Position overlay underline markers over a character range inside `target`.
128
+ *
129
+ * Mimics how extensions draw underlines: they create a DOM Range, call
130
+ * `getClientRects()` to obtain the line boxes, and then absolutely-position
131
+ * overlay `<span>` elements in a sibling container at those coordinates.
132
+ * Critically, the overlay is NOT inserted inside the contenteditable — it is
133
+ * a sibling to avoid invalidating the editable's DOM tree from the extension's
134
+ * perspective.
135
+ *
136
+ * NOTE: `getClientRects()` always returns an empty list in jsdom. This
137
+ * function is a no-op in that environment and is intended for manual
138
+ * in-browser verification via the demo page. The automated test suite
139
+ * tests `discover`, `injectMarker`, and `applyCorrection` instead.
140
+ *
141
+ * @param target The editable element to overlay.
142
+ * @param from Character offset (from the start of `target.textContent`) of
143
+ * the range start.
144
+ * @param to Character offset of the range end.
145
+ * @param options Visual options.
146
+ * @returns The overlay container element, or `null` when `getClientRects`
147
+ * returned nothing (jsdom / hidden element).
148
+ */
149
+ export declare function markRange(target: HTMLElement, from: number, to: number, options?: MarkRangeOptions): HTMLElement | null;
150
+ /**
151
+ * Wrap a character sub-range of `target` in a `<span data-extn-marker="1">`.
152
+ *
153
+ * This is what extensions do to tag a match for subsequent accept/reject
154
+ * interactions — they insert a wrapper span *inside* the contenteditable via
155
+ * raw DOM Range manipulation without going through the editor's transaction
156
+ * system.
157
+ *
158
+ * From ProseMirror's perspective this is a foreign DOM mutation. ProseMirror's
159
+ * DOMObserver will observe the mutation and attempt to reconcile its internal
160
+ * model. The mutation-tolerance tests in the spec verify that this does not
161
+ * corrupt the document or cause PM to throw.
162
+ *
163
+ * @param target The contenteditable element to mutate.
164
+ * @param from Character offset of the range start (within `target.textContent`).
165
+ * @param to Character offset of the range end.
166
+ * @returns An `InjectedMarker` handle with a `remove()` method for cleanup.
167
+ * Returns `null` when the range cannot be resolved.
168
+ */
169
+ export declare function injectMarker(target: HTMLElement, from: number, to: number): InjectedMarker | null;
170
+ /**
171
+ * Replace a character sub-range of `target` with `replacement` via raw DOM.
172
+ *
173
+ * This is the "accept suggestion" operation: the extension overwrites a word
174
+ * by creating a Range, deleting its contents, and inserting a new text node.
175
+ * It does NOT fire a ProseMirror transaction.
176
+ *
177
+ * The test that calls this should follow up with a normal PM transaction (e.g.
178
+ * `view.dispatch(view.state.tr.insertText(...))`) to verify that ProseMirror
179
+ * reconciles the foreign mutation cleanly and does not produce corrupted or
180
+ * duplicated content.
181
+ *
182
+ * @param target The contenteditable element.
183
+ * @param from Character offset of the range to replace.
184
+ * @param to Character offset of the range end.
185
+ * @param replacement The text to insert in place of the matched range.
186
+ * @returns A `CorrectionResult` describing what was swapped, or
187
+ * `null` when the range cannot be resolved.
188
+ */
189
+ export declare function applyCorrection(target: HTMLElement, from: number, to: number, replacement: string): CorrectionResult | null;
190
+ /** A character-offset range within an element's flat `textContent`. */
191
+ export interface TextRange {
192
+ from: number;
193
+ to: number;
194
+ }
195
+ /**
196
+ * Find all occurrences of `searchString` within `target.textContent` and
197
+ * return their character-offset ranges.
198
+ *
199
+ * This is the bridge between "a word I want to underline" and the `{from, to}`
200
+ * pair that `markRange`, `injectMarker`, and `applyCorrection` consume.
201
+ * Extensions compute positions exactly this way: read the full `textContent`
202
+ * of the editable as one flat string, locate every match, then use those
203
+ * offsets to build DOM Ranges.
204
+ *
205
+ * @param target The element whose `textContent` is searched.
206
+ * @param searchString The literal string to find (case-sensitive).
207
+ * @returns Array of `{from, to}` ranges, one per occurrence,
208
+ * in document order. Empty array when there are no matches.
209
+ *
210
+ * @example
211
+ * const hits = findTextOccurrences(editable, 'SciFlow');
212
+ * for (const { from, to } of hits) {
213
+ * markRange(editable, from, to, { color: '#f97316' });
214
+ * }
215
+ */
216
+ export declare function findTextOccurrences(target: HTMLElement, searchString: string): TextRange[];
217
+ //# sourceMappingURL=external-widget-simulator.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"external-widget-simulator.d.ts","sourceRoot":"","sources":["../../src/testing/external-widget-simulator.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4DG;AAMH,mEAAmE;AACnE,MAAM,WAAW,cAAc;IAC7B,8BAA8B;IAC9B,OAAO,EAAE,WAAW,CAAC;IACrB;;;;;OAKG;IACH,QAAQ,EAAE,IAAI,CAAC;IACf,+EAA+E;IAC/E,UAAU,EAAE,OAAO,CAAC;CACrB;AAED,qDAAqD;AACrD,MAAM,WAAW,gBAAgB;IAC/B,mEAAmE;IACnE,KAAK,CAAC,EAAE,MAAM,CAAC;IACf;;;OAGG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,gEAAgE;IAChE,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,oEAAoE;AACpE,MAAM,WAAW,cAAc;IAC7B,yDAAyD;IACzD,IAAI,EAAE,eAAe,CAAC;IACtB,uEAAuE;IACvE,MAAM,IAAI,IAAI,CAAC;CAChB;AAED,mCAAmC;AACnC,MAAM,WAAW,gBAAgB;IAC/B,kCAAkC;IAClC,QAAQ,EAAE,MAAM,CAAC;IACjB,8CAA8C;IAC9C,QAAQ,EAAE,MAAM,CAAC;CAClB;AAMD;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,wBAAgB,QAAQ,CAAC,IAAI,GAAE,QAAQ,GAAG,OAAkB,GAAG,cAAc,EAAE,CAwC9E;AAMD;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,wBAAgB,SAAS,CACvB,MAAM,EAAE,WAAW,EACnB,IAAI,EAAE,MAAM,EACZ,EAAE,EAAE,MAAM,EACV,OAAO,GAAE,gBAAqB,GAC7B,WAAW,GAAG,IAAI,CA8CpB;AAMD;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,YAAY,CAC1B,MAAM,EAAE,WAAW,EACnB,IAAI,EAAE,MAAM,EACZ,EAAE,EAAE,MAAM,GACT,cAAc,GAAG,IAAI,CA0BvB;AAMD;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,eAAe,CAC7B,MAAM,EAAE,WAAW,EACnB,IAAI,EAAE,MAAM,EACZ,EAAE,EAAE,MAAM,EACV,WAAW,EAAE,MAAM,GAClB,gBAAgB,GAAG,IAAI,CASzB;AAMD,uEAAuE;AACvE,MAAM,WAAW,SAAS;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,EAAE,EAAE,MAAM,CAAC;CACZ;AAED;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAgB,mBAAmB,CACjC,MAAM,EAAE,WAAW,EACnB,YAAY,EAAE,MAAM,GACnB,SAAS,EAAE,CAYb"}