@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.
- package/LICENSE +21 -0
- package/README.md +50 -29
- package/dist/bundle/sciflow-editor.css +1 -1
- package/dist/bundle/sciflow-editor.js +4446 -3980
- package/dist/index.d.ts +4 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -1
- package/dist/lib/default-features.d.ts +21 -0
- package/dist/lib/default-features.d.ts.map +1 -0
- package/dist/lib/default-features.js +34 -0
- package/dist/lib/editor-element.d.ts +97 -1
- package/dist/lib/editor-element.d.ts.map +1 -1
- package/dist/lib/editor-element.js +435 -25
- package/dist/lib/format-bar.d.ts +22 -0
- package/dist/lib/format-bar.d.ts.map +1 -1
- package/dist/lib/format-bar.js +37 -1
- package/dist/lib/outline.d.ts +44 -0
- package/dist/lib/outline.d.ts.map +1 -1
- package/dist/lib/outline.js +120 -6
- package/dist/lib/range-decorations.d.ts +120 -0
- package/dist/lib/range-decorations.d.ts.map +1 -0
- package/dist/lib/range-decorations.js +131 -0
- package/dist/lib/read-only.d.ts +95 -0
- package/dist/lib/read-only.d.ts.map +1 -0
- package/dist/lib/read-only.js +123 -0
- package/dist/testing/external-widget-simulator.d.ts +217 -0
- package/dist/testing/external-widget-simulator.d.ts.map +1 -0
- package/dist/testing/external-widget-simulator.js +350 -0
- package/package.json +25 -13
- package/dist/tsconfig.lib.tsbuildinfo +0 -1
|
@@ -22,6 +22,27 @@
|
|
|
22
22
|
*
|
|
23
23
|
* The rest of this file is heavily documented to map those steps to concrete
|
|
24
24
|
* code. Treat it as a cookbook for your own integration.
|
|
25
|
+
*
|
|
26
|
+
* Light-DOM editable surface
|
|
27
|
+
* --------------------------
|
|
28
|
+
* The ProseMirror `contenteditable` (`view.dom`) is mounted on a **light-DOM
|
|
29
|
+
* child** of the host element (class `sf-editable-surface`), projected
|
|
30
|
+
* visually into the shadow root via a `<slot>`. All chrome (formatbar,
|
|
31
|
+
* selection editor, node-view popovers) continues to live in the shadow root
|
|
32
|
+
* and is fully encapsulated.
|
|
33
|
+
*
|
|
34
|
+
* Why: external proofreading / AI writing extensions (Grammarly, LanguageTool
|
|
35
|
+
* browser add-on) walk the page's flat document tree for `[contenteditable]`
|
|
36
|
+
* and never enter shadow roots. Mounting the editable in the light DOM makes
|
|
37
|
+
* it discoverable by those tools without sacrificing shadow encapsulation for
|
|
38
|
+
* the surrounding chrome.
|
|
39
|
+
*
|
|
40
|
+
* Consequence for theming: `.ProseMirror` content styles and inline node-view
|
|
41
|
+
* styles (figures, citations, footnotes, marks) are injected into a `<style>`
|
|
42
|
+
* element appended to `document.head` (scoped to `.sf-editable-surface`) so
|
|
43
|
+
* they reach PM's nested DOM. Shadow-scoped `::part` / `:host` rules that
|
|
44
|
+
* applied to the editable content must be migrated to the
|
|
45
|
+
* `.sf-editable-surface .ProseMirror { … }` selector instead.
|
|
25
46
|
*/
|
|
26
47
|
import { __decorate } from "tslib";
|
|
27
48
|
import { css, html, unsafeCSS, LitElement } from 'lit';
|
|
@@ -31,6 +52,200 @@ import { manuscript as manuscriptSchema } from '@sciflow/schema-prosemirror';
|
|
|
31
52
|
import editorStyles from './editor-element.css?inline';
|
|
32
53
|
import { ghostCursorFeature } from './ghost-cursor.js';
|
|
33
54
|
import { applyThemeStylesToRoot, subscribeToSciFlowTheme } from './theme.js';
|
|
55
|
+
// ---------------------------------------------------------------------------
|
|
56
|
+
// Light-DOM content styles
|
|
57
|
+
//
|
|
58
|
+
// ProseMirror's `.contenteditable` (view.dom) is mounted on `.sf-editable-surface`,
|
|
59
|
+
// a light-DOM child of the host element. Because `::slotted()` cannot reach
|
|
60
|
+
// PM's nested content, content styles are injected into `document.head` under
|
|
61
|
+
// a data attribute guard.
|
|
62
|
+
//
|
|
63
|
+
// Ref-counting: the shared `<style>` is injected when the first instance
|
|
64
|
+
// connects and removed when the last instance disconnects. A per-element
|
|
65
|
+
// width `<style>` is also managed in `document.head`, keyed by a unique id
|
|
66
|
+
// written as a `data-sf-width-<id>` attribute so it can be replaced or removed
|
|
67
|
+
// without touching the shared content styles.
|
|
68
|
+
//
|
|
69
|
+
// These styles are scoped to `.sf-editable-surface` so they don't leak into
|
|
70
|
+
// unrelated page content. Chrome styles (:host, .editor border, theme vars)
|
|
71
|
+
// remain shadow-scoped in `editor-element.css`.
|
|
72
|
+
// ---------------------------------------------------------------------------
|
|
73
|
+
const LIGHT_DOM_CONTENT_STYLES_ATTR = 'data-sf-content-styles';
|
|
74
|
+
/** Module-level ref-count: number of currently connected `<sciflow-editor>` instances. */
|
|
75
|
+
let _contentStylesRefCount = 0;
|
|
76
|
+
const LIGHT_DOM_CONTENT_STYLES = `
|
|
77
|
+
/* === SciFlow editor content styles (light-DOM surface) === */
|
|
78
|
+
/* Scoped to .sf-editable-surface to avoid leaking into the host page. */
|
|
79
|
+
.sf-editable-surface .ProseMirror {
|
|
80
|
+
position: relative;
|
|
81
|
+
word-wrap: break-word;
|
|
82
|
+
white-space: pre-wrap;
|
|
83
|
+
white-space: break-spaces;
|
|
84
|
+
-webkit-font-variant-ligatures: none;
|
|
85
|
+
font-variant-ligatures: none;
|
|
86
|
+
font-feature-settings: "liga" 0;
|
|
87
|
+
font-weight: lighter;
|
|
88
|
+
outline: none;
|
|
89
|
+
min-height: inherit;
|
|
90
|
+
padding: calc(0.75rem + 1.5em) 4rem 0.5rem calc(2.5rem + 1rem);
|
|
91
|
+
color: inherit;
|
|
92
|
+
font-size: 1rem;
|
|
93
|
+
counter-reset: sciflow-footnote;
|
|
94
|
+
line-height: 1.6;
|
|
95
|
+
}
|
|
96
|
+
.sf-editable-surface .ProseMirror p { margin: 0 0 0.75rem; }
|
|
97
|
+
.sf-editable-surface .ProseMirror p:only-child:last-child,
|
|
98
|
+
.sf-editable-surface .ProseMirror table p { margin: 0; }
|
|
99
|
+
.sf-editable-surface .ProseMirror h1,
|
|
100
|
+
.sf-editable-surface .ProseMirror h2,
|
|
101
|
+
.sf-editable-surface .ProseMirror h3,
|
|
102
|
+
.sf-editable-surface .ProseMirror h4,
|
|
103
|
+
.sf-editable-surface .ProseMirror h5,
|
|
104
|
+
.sf-editable-surface .ProseMirror h6 {
|
|
105
|
+
margin: 1.25rem 0 0.5rem; line-height: 1.2; position: relative;
|
|
106
|
+
}
|
|
107
|
+
.sf-editable-surface .ProseMirror > h1:first-child,
|
|
108
|
+
.sf-editable-surface .ProseMirror > h2:first-child,
|
|
109
|
+
.sf-editable-surface .ProseMirror > h3:first-child,
|
|
110
|
+
.sf-editable-surface .ProseMirror > h4:first-child,
|
|
111
|
+
.sf-editable-surface .ProseMirror > h5:first-child,
|
|
112
|
+
.sf-editable-surface .ProseMirror > h6:first-child { margin-top: 0; }
|
|
113
|
+
.sf-editable-surface .ProseMirror h1 { font-size: 1.33em; padding-top: 0.35em; font-weight: normal; }
|
|
114
|
+
.sf-editable-surface .ProseMirror h2 { font-size: 1.22em; font-weight: normal; }
|
|
115
|
+
.sf-editable-surface .ProseMirror h3 { font-size: 1.17em; font-weight: normal; }
|
|
116
|
+
.sf-editable-surface .ProseMirror h4 { font-size: 1.11em; font-weight: normal; }
|
|
117
|
+
.sf-editable-surface .ProseMirror h5 { font-size: 1.06em; font-weight: normal; }
|
|
118
|
+
.sf-editable-surface .ProseMirror h6 { font-size: 1em; font-weight: bold; }
|
|
119
|
+
.sf-editable-surface .ProseMirror h1::before {
|
|
120
|
+
content: "#"; opacity: 0.5; font-size: 0.8rem; position: absolute;
|
|
121
|
+
left: -2.5rem; top: 60%; transform: translateY(-50%); padding-right: .5rem;
|
|
122
|
+
}
|
|
123
|
+
.sf-editable-surface .ProseMirror h2::before {
|
|
124
|
+
content: "##"; opacity: 0.5; font-size: 0.8rem; padding-right: .5rem;
|
|
125
|
+
position: absolute; left: -2.5rem; top: 50%; transform: translateY(-50%);
|
|
126
|
+
}
|
|
127
|
+
.sf-editable-surface .ProseMirror h3::before {
|
|
128
|
+
content: "###"; opacity: 0.5; font-size: 0.8rem; padding-right: .5rem;
|
|
129
|
+
position: absolute; left: -2.5rem; top: 50%; transform: translateY(-50%);
|
|
130
|
+
}
|
|
131
|
+
.sf-editable-surface .ProseMirror li { position: relative; }
|
|
132
|
+
.sf-editable-surface .ProseMirror img { max-width: 40vw; height: auto; }
|
|
133
|
+
.sf-editable-surface .ProseMirror pre { white-space: pre-wrap; }
|
|
134
|
+
.sf-editable-surface .ProseMirror cite {
|
|
135
|
+
background: var(--sciflow-editor-citation-bg, rgba(15,23,42,0.05));
|
|
136
|
+
color: var(--sciflow-editor-citation-color, inherit);
|
|
137
|
+
padding: 0.1rem 0.35rem; border-radius: 4px;
|
|
138
|
+
}
|
|
139
|
+
.sf-editable-surface .ProseMirror a[data-type='xref'] {
|
|
140
|
+
background: var(--sciflow-editor-citation-bg, rgba(15,23,42,0.05));
|
|
141
|
+
color: var(--sciflow-editor-citation-color, inherit);
|
|
142
|
+
padding: 0.1rem 0.35rem; border-radius: 4px; text-decoration: none;
|
|
143
|
+
}
|
|
144
|
+
.sf-editable-surface .ProseMirror a[data-type='xref']:hover { text-decoration: underline; }
|
|
145
|
+
.sf-editable-surface .ProseMirror table {
|
|
146
|
+
width: 100%; border-collapse: collapse; border-spacing: 0; margin: 1rem 0;
|
|
147
|
+
}
|
|
148
|
+
.sf-editable-surface .ProseMirror th,
|
|
149
|
+
.sf-editable-surface .ProseMirror td {
|
|
150
|
+
padding: 0.5rem 0.75rem;
|
|
151
|
+
border: 1px solid color-mix(in srgb, currentColor 18%, transparent);
|
|
152
|
+
vertical-align: top; box-sizing: border-box; position: relative;
|
|
153
|
+
}
|
|
154
|
+
.sf-editable-surface .ProseMirror td:not([data-colwidth]):not(.column-resize-dragging),
|
|
155
|
+
.sf-editable-surface .ProseMirror th:not([data-colwidth]):not(.column-resize-dragging) {
|
|
156
|
+
min-width: var(--default-cell-min-width, 80px);
|
|
157
|
+
}
|
|
158
|
+
.sf-editable-surface .ProseMirror .tableWrapper { overflow-x: auto; }
|
|
159
|
+
.sf-editable-surface .ProseMirror .column-resize-handle {
|
|
160
|
+
position: absolute; right: -2px; top: 0; bottom: 0; width: 4px;
|
|
161
|
+
z-index: 20; background-color: #adf; pointer-events: none;
|
|
162
|
+
}
|
|
163
|
+
.sf-editable-surface .ProseMirror.resize-cursor { cursor: ew-resize; cursor: col-resize; }
|
|
164
|
+
.sf-editable-surface .ProseMirror .selectedCell::after {
|
|
165
|
+
z-index: 2; position: absolute; content: '';
|
|
166
|
+
left: 0; right: 0; top: 0; bottom: 0;
|
|
167
|
+
background: rgba(200,200,255,0.4); pointer-events: none;
|
|
168
|
+
}
|
|
169
|
+
.sf-editable-surface .ProseMirror section { margin-top: 2.5rem; }
|
|
170
|
+
.sf-editable-surface .ProseMirror section:first-child { margin-top: 0.5rem; }
|
|
171
|
+
.sf-editable-surface .ProseMirror-hideselection *::selection { background: transparent; }
|
|
172
|
+
.sf-editable-surface .ProseMirror-hideselection *::-moz-selection { background: transparent; }
|
|
173
|
+
.sf-editable-surface .ProseMirror-hideselection { caret-color: transparent; }
|
|
174
|
+
.sf-editable-surface .ProseMirror [draggable][contenteditable='false'] { user-select: text; }
|
|
175
|
+
.sf-editable-surface .ProseMirror-selectednode {
|
|
176
|
+
outline: 2px solid var(--sciflow-editor-selectednode, var(--sciflow-editor-border-active, #2563eb));
|
|
177
|
+
outline-offset: 1px;
|
|
178
|
+
}
|
|
179
|
+
.sf-editable-surface .ProseMirror cite.ProseMirror-selectednode {
|
|
180
|
+
outline: none;
|
|
181
|
+
box-shadow: 0 0 0 2px var(--sciflow-editor-border-active, #2563eb);
|
|
182
|
+
}
|
|
183
|
+
.sf-editable-surface .ProseMirror span[data-type='footnote'].ProseMirror-selectednode {
|
|
184
|
+
outline: none; box-shadow: none;
|
|
185
|
+
}
|
|
186
|
+
.sf-editable-surface .ProseMirror span[data-type='footnote'].ProseMirror-selectednode .sciflow-footnote-body {
|
|
187
|
+
border-color: var(--sciflow-editor-border-active, #2563eb);
|
|
188
|
+
}
|
|
189
|
+
.sf-editable-surface .ProseMirror a[data-type='xref'].ProseMirror-selectednode {
|
|
190
|
+
outline: none;
|
|
191
|
+
box-shadow: 0 0 0 2px var(--sciflow-editor-selectednode, var(--sciflow-editor-border-active, #2563eb));
|
|
192
|
+
}
|
|
193
|
+
.sf-editable-surface .ProseMirror li.ProseMirror-selectednode { outline: none; }
|
|
194
|
+
.sf-editable-surface .ProseMirror li.ProseMirror-selectednode:after {
|
|
195
|
+
content: ''; position: absolute; left: -32px; right: -2px; top: -2px; bottom: -2px;
|
|
196
|
+
border: 2px solid var(--sciflow-editor-selectednode, var(--sciflow-editor-border-active, #2563eb));
|
|
197
|
+
pointer-events: none;
|
|
198
|
+
}
|
|
199
|
+
.sf-editable-surface .ProseMirror img.ProseMirror-separator {
|
|
200
|
+
display: inline !important; border: none !important; margin: 0 !important;
|
|
201
|
+
}
|
|
202
|
+
.sf-editable-surface .prosemirror-ghost-cursor {
|
|
203
|
+
display: inline-block; width: 3px; height: 1.25em;
|
|
204
|
+
background: #2563eb; border-radius: 2px; vertical-align: text-bottom;
|
|
205
|
+
margin: 0 -1px; pointer-events: none;
|
|
206
|
+
box-shadow: 0 0 0 1.5px color-mix(in srgb, #2563eb 30%, transparent);
|
|
207
|
+
animation: sf-ghost-cursor-pulse 1.8s ease-in-out infinite;
|
|
208
|
+
}
|
|
209
|
+
@keyframes sf-ghost-cursor-pulse { 0%, 100% { opacity: 1; } 50% { opacity: 0.4; } }
|
|
210
|
+
.sf-editable-surface .prosemirror-ghost-selection {
|
|
211
|
+
background: color-mix(in srgb, #2563eb 25%, transparent);
|
|
212
|
+
border-radius: 2px;
|
|
213
|
+
outline: 1px solid color-mix(in srgb, #2563eb 40%, transparent);
|
|
214
|
+
}
|
|
215
|
+
@media (prefers-color-scheme: dark) {
|
|
216
|
+
.sf-editable-surface .ProseMirror-selectednode { outline-color: var(--sciflow-editor-selectednode, rgba(148,163,184,0.6)); }
|
|
217
|
+
.sf-editable-surface .ProseMirror cite.ProseMirror-selectednode { box-shadow: 0 0 0 2px var(--sciflow-editor-border-active, #3b82f6); }
|
|
218
|
+
.sf-editable-surface .ProseMirror a[data-type='xref'].ProseMirror-selectednode { box-shadow: 0 0 0 2px var(--sciflow-editor-selectednode, rgba(148,163,184,0.6)); }
|
|
219
|
+
.sf-editable-surface .ProseMirror li.ProseMirror-selectednode:after { border-color: var(--sciflow-editor-selectednode, rgba(148,163,184,0.6)); }
|
|
220
|
+
}
|
|
221
|
+
`;
|
|
222
|
+
/**
|
|
223
|
+
* Increment the ref-count and inject the light-DOM content styles into
|
|
224
|
+
* document.head if this is the first active instance. SSR-safe.
|
|
225
|
+
*/
|
|
226
|
+
function acquireLightDomContentStyles() {
|
|
227
|
+
if (typeof document === 'undefined')
|
|
228
|
+
return;
|
|
229
|
+
_contentStylesRefCount++;
|
|
230
|
+
if (_contentStylesRefCount === 1) {
|
|
231
|
+
const style = document.createElement('style');
|
|
232
|
+
style.setAttribute(LIGHT_DOM_CONTENT_STYLES_ATTR, '');
|
|
233
|
+
style.textContent = LIGHT_DOM_CONTENT_STYLES;
|
|
234
|
+
document.head.appendChild(style);
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
/**
|
|
238
|
+
* Decrement the ref-count and remove the shared content styles from
|
|
239
|
+
* document.head once the last active instance disconnects. SSR-safe.
|
|
240
|
+
*/
|
|
241
|
+
function releaseLightDomContentStyles() {
|
|
242
|
+
if (typeof document === 'undefined')
|
|
243
|
+
return;
|
|
244
|
+
_contentStylesRefCount = Math.max(0, _contentStylesRefCount - 1);
|
|
245
|
+
if (_contentStylesRefCount === 0) {
|
|
246
|
+
document.querySelector(`[${LIGHT_DOM_CONTENT_STYLES_ATTR}]`)?.remove();
|
|
247
|
+
}
|
|
248
|
+
}
|
|
34
249
|
/**
|
|
35
250
|
* Custom element that owns a SciFlow editor instance.
|
|
36
251
|
*
|
|
@@ -93,6 +308,72 @@ let SciFlowEditorElement = class SciFlowEditorElement extends LitElement {
|
|
|
93
308
|
* ```
|
|
94
309
|
*/
|
|
95
310
|
this.locale = null;
|
|
311
|
+
// -------------------------------------------------------------------------
|
|
312
|
+
// Binding: which document, which part, which client, through which strategy.
|
|
313
|
+
//
|
|
314
|
+
// All four are mount-time identity. A running editor is bound to exactly one
|
|
315
|
+
// of each, and none can be swapped underneath it, so changing any of them
|
|
316
|
+
// after the editor is up tears the editor down and re-creates it against the
|
|
317
|
+
// new binding — the same path a replaced `features` list takes.
|
|
318
|
+
//
|
|
319
|
+
// The element opens no connections of its own: it only forwards what the
|
|
320
|
+
// host gives it to `Editor.create()`.
|
|
321
|
+
// -------------------------------------------------------------------------
|
|
322
|
+
/**
|
|
323
|
+
* Sync strategy that owns loading and persisting this document.
|
|
324
|
+
*
|
|
325
|
+
* Unset (the default) means the element uses a built-in in-memory strategy:
|
|
326
|
+
* the document stays in the page and nothing is persisted. Set it to hand
|
|
327
|
+
* loading, persistence and — with `clientID` — collaborative concurrency to
|
|
328
|
+
* your own implementation.
|
|
329
|
+
*
|
|
330
|
+
* When a strategy is supplied and neither `doc` nor `initialContent` is set,
|
|
331
|
+
* the editor starts from the strategy's `load(docId)`.
|
|
332
|
+
*
|
|
333
|
+
* Note that tearing the editor down (element disconnect, or a change to any
|
|
334
|
+
* binding property) disposes the strategy via its `dispose()`. Supply a
|
|
335
|
+
* fresh strategy whenever you change the binding.
|
|
336
|
+
*
|
|
337
|
+
* @example
|
|
338
|
+
* ```js
|
|
339
|
+
* editor.docId = 'doc-123';
|
|
340
|
+
* editor.partId = 'chapter-2';
|
|
341
|
+
* editor.clientID = 'tab-7';
|
|
342
|
+
* editor.sync = myStrategy;
|
|
343
|
+
* ```
|
|
344
|
+
*/
|
|
345
|
+
this.sync = null;
|
|
346
|
+
/**
|
|
347
|
+
* Stable identifier of the document this editor is bound to. Handed to the
|
|
348
|
+
* sync strategy's `load()` and `bind()`.
|
|
349
|
+
*
|
|
350
|
+
* Defaults to a fresh random id per mount, which is only meaningful for the
|
|
351
|
+
* built-in in-memory strategy — set it whenever you supply your own `sync`.
|
|
352
|
+
*/
|
|
353
|
+
this.docId = null;
|
|
354
|
+
/**
|
|
355
|
+
* Stable client identifier for collaborative editing. Setting it activates
|
|
356
|
+
* step-based concurrency (`prosemirror-collab`) in the editor runtime, so
|
|
357
|
+
* remote changes rebase local edits instead of replacing the document.
|
|
358
|
+
*
|
|
359
|
+
* Should stay stable across reloads of the same client (for example one id
|
|
360
|
+
* per browser tab) so the server and other clients can recognize this
|
|
361
|
+
* client's own confirmed changes. Only useful together with a `sync`
|
|
362
|
+
* strategy that speaks a step protocol.
|
|
363
|
+
*
|
|
364
|
+
* Set as an attribute (`client-id`) the value is always a string; set as a
|
|
365
|
+
* property it may also be a number.
|
|
366
|
+
*/
|
|
367
|
+
this.clientID = null;
|
|
368
|
+
/**
|
|
369
|
+
* Part of the document this editor is bound to, for backends whose
|
|
370
|
+
* concurrency unit is narrower than a document — one document holding
|
|
371
|
+
* several parts, each with its own version counter and change log.
|
|
372
|
+
*
|
|
373
|
+
* The editor never interprets it; it is forwarded to the sync strategy's
|
|
374
|
+
* `bind()` so the strategy can address the right part.
|
|
375
|
+
*/
|
|
376
|
+
this.partId = null;
|
|
96
377
|
this.view = null;
|
|
97
378
|
this.pendingOps = [];
|
|
98
379
|
this.pendingOpsFromTransform = false;
|
|
@@ -101,6 +382,20 @@ let SciFlowEditorElement = class SciFlowEditorElement extends LitElement {
|
|
|
101
382
|
this.shadowStyleElements = [];
|
|
102
383
|
this.themeStyleElements = [];
|
|
103
384
|
this._hostDragoverBound = null;
|
|
385
|
+
/**
|
|
386
|
+
* The light-DOM container that ProseMirror mounts into.
|
|
387
|
+
* A direct child of the host element (not the shadow root), projected
|
|
388
|
+
* visually via the shadow root's `<slot>`.
|
|
389
|
+
*/
|
|
390
|
+
this.lightDomMount = null;
|
|
391
|
+
/**
|
|
392
|
+
* Unique identifier for this element instance. Used to key the per-element
|
|
393
|
+
* width `<style>` in `document.head` so that each instance can update or
|
|
394
|
+
* remove its own rule without affecting other instances.
|
|
395
|
+
*/
|
|
396
|
+
this._instanceId = `sf-${Math.random().toString(36).slice(2)}`;
|
|
397
|
+
/** The `<style>` element in `document.head` that holds this instance's width rules. */
|
|
398
|
+
this._widthStyleEl = null;
|
|
104
399
|
}
|
|
105
400
|
get shadowStyles() {
|
|
106
401
|
return this._shadowStyles;
|
|
@@ -152,9 +447,14 @@ let SciFlowEditorElement = class SciFlowEditorElement extends LitElement {
|
|
|
152
447
|
dispatchEvent: (event) => this.editor?.dispatchEvent(event) ?? false,
|
|
153
448
|
};
|
|
154
449
|
}
|
|
450
|
+
// Shadow root retains chrome styles. The `.editor` wrapper provides the
|
|
451
|
+
// border/focus-ring and projects the light-DOM editable via `<slot>`.
|
|
155
452
|
static { this.styles = css `${unsafeCSS(editorStyles)}`; }
|
|
156
453
|
render() {
|
|
157
|
-
|
|
454
|
+
// The <slot> projects the light-DOM .sf-editable-surface child visually
|
|
455
|
+
// into the shadow layout. All other chrome (formatbar slot, popovers)
|
|
456
|
+
// remains shadow-scoped via the editor-element.css `.editor` rules.
|
|
457
|
+
return html `<div class="editor" part="editor"><slot></slot></div>`;
|
|
158
458
|
}
|
|
159
459
|
/** Lit lifecycle hook: start the editor once the DOM container exists. */
|
|
160
460
|
async firstUpdated() {
|
|
@@ -170,6 +470,29 @@ let SciFlowEditorElement = class SciFlowEditorElement extends LitElement {
|
|
|
170
470
|
if (this.locale) {
|
|
171
471
|
setLocale(this.locale);
|
|
172
472
|
}
|
|
473
|
+
// Inject light-DOM content styles (ref-counted; injected on first connect,
|
|
474
|
+
// removed on last disconnect).
|
|
475
|
+
acquireLightDomContentStyles();
|
|
476
|
+
// Create the light-DOM mount point as a direct child of the host.
|
|
477
|
+
// ProseMirror will mount its editable (view.dom) inside this div.
|
|
478
|
+
// Because it is a child of the host element — not the shadow root — its
|
|
479
|
+
// getRootNode() === document, making it discoverable by external tools.
|
|
480
|
+
if (!this.lightDomMount) {
|
|
481
|
+
const div = document.createElement('div');
|
|
482
|
+
div.className = 'sf-editable-surface';
|
|
483
|
+
div.setAttribute('data-sf-lightdom-mount', '');
|
|
484
|
+
this.appendChild(div);
|
|
485
|
+
this.lightDomMount = div;
|
|
486
|
+
}
|
|
487
|
+
// Re-apply the per-element width style whenever the element (re-)connects.
|
|
488
|
+
// disconnectedCallback removes _widthStyleEl from document.head; without
|
|
489
|
+
// this call the width constraint is silently lost after a DOM re-parent.
|
|
490
|
+
// Guard with hasUpdated so we don't race with firstUpdated on the initial
|
|
491
|
+
// render cycle (firstUpdated → applyShadowStyles → applyWidthStyles already
|
|
492
|
+
// covers that path).
|
|
493
|
+
if (this.hasUpdated) {
|
|
494
|
+
this.applyWidthStyles();
|
|
495
|
+
}
|
|
173
496
|
this._hostDragoverBound = (e) => {
|
|
174
497
|
if (!e.dataTransfer?.types || !this.contains(e.target))
|
|
175
498
|
return;
|
|
@@ -193,11 +516,22 @@ let SciFlowEditorElement = class SciFlowEditorElement extends LitElement {
|
|
|
193
516
|
*/
|
|
194
517
|
updated(changedProperties) {
|
|
195
518
|
super.updated(changedProperties);
|
|
196
|
-
if (this.deferInitializationForDoc && this.
|
|
519
|
+
if (this.deferInitializationForDoc && !this.shouldDeferInitialization()) {
|
|
197
520
|
this.deferInitializationForDoc = false;
|
|
198
521
|
void this.initializeView();
|
|
199
522
|
}
|
|
200
|
-
|
|
523
|
+
// A running editor cannot be re-bound in place: its document identity, its
|
|
524
|
+
// part, its client identity and its strategy are all fixed at creation.
|
|
525
|
+
// Re-create it instead, discarding the previous binding's content — the
|
|
526
|
+
// new instance sources its document the same way a fresh mount does.
|
|
527
|
+
const bindingChanged = changedProperties.has('sync') ||
|
|
528
|
+
changedProperties.has('docId') ||
|
|
529
|
+
changedProperties.has('clientID') ||
|
|
530
|
+
changedProperties.has('partId');
|
|
531
|
+
if (bindingChanged && this.editor) {
|
|
532
|
+
void this.reinitializeEditor({ preserveContent: false });
|
|
533
|
+
}
|
|
534
|
+
else if (!this.suppressFeatureUpdate && changedProperties.has('features') && this.editor) {
|
|
201
535
|
void this.reinitializeEditor();
|
|
202
536
|
}
|
|
203
537
|
// Only apply shadowStyles if changed via property (not via setShadowStyles method)
|
|
@@ -232,6 +566,18 @@ let SciFlowEditorElement = class SciFlowEditorElement extends LitElement {
|
|
|
232
566
|
this.themeUnsub = undefined;
|
|
233
567
|
this.destroyEditor();
|
|
234
568
|
this.view = null;
|
|
569
|
+
// Remove the light-DOM mount point.
|
|
570
|
+
if (this.lightDomMount && this.lightDomMount.parentNode === this) {
|
|
571
|
+
this.removeChild(this.lightDomMount);
|
|
572
|
+
this.lightDomMount = null;
|
|
573
|
+
}
|
|
574
|
+
// Remove the per-element width style from document.head.
|
|
575
|
+
if (this._widthStyleEl) {
|
|
576
|
+
this._widthStyleEl.remove();
|
|
577
|
+
this._widthStyleEl = null;
|
|
578
|
+
}
|
|
579
|
+
// Release the shared content styles (removes from head when last instance disconnects).
|
|
580
|
+
releaseLightDomContentStyles();
|
|
235
581
|
}
|
|
236
582
|
/**
|
|
237
583
|
* Public helper to update the feature list and reconfigure the editor.
|
|
@@ -274,17 +620,20 @@ let SciFlowEditorElement = class SciFlowEditorElement extends LitElement {
|
|
|
274
620
|
return this.features ?? this.getDefaultFeatures();
|
|
275
621
|
}
|
|
276
622
|
shouldDeferInitialization() {
|
|
277
|
-
|
|
623
|
+
// A host-supplied strategy is itself a source for the document (its
|
|
624
|
+
// `load()`), so there is nothing left to wait for.
|
|
625
|
+
return this.doc === null && this.initialContent === null && this.sync === null;
|
|
278
626
|
}
|
|
279
627
|
async initializeView() {
|
|
280
628
|
if (this.view) {
|
|
281
629
|
return;
|
|
282
630
|
}
|
|
283
|
-
|
|
631
|
+
// Mount ProseMirror on the light-DOM child — the visual slot wrapper
|
|
632
|
+
// (.editor) is in the shadow root and projects this via <slot>.
|
|
633
|
+
const mountPoint = this.lightDomMount;
|
|
284
634
|
if (!mountPoint) {
|
|
285
635
|
return;
|
|
286
636
|
}
|
|
287
|
-
const initialDoc = this.resolveInitialDoc();
|
|
288
637
|
const docInput = this.doc;
|
|
289
638
|
const initialFiles = this.isExternalDocUpdate(docInput) && Array.isArray(docInput.files) ? docInput.files : [];
|
|
290
639
|
const initialReferences = this.isExternalDocUpdate(docInput) && Array.isArray(docInput.references) ? docInput.references : [];
|
|
@@ -292,11 +641,28 @@ let SciFlowEditorElement = class SciFlowEditorElement extends LitElement {
|
|
|
292
641
|
const externalSelection = this.isExternalDocUpdate(docInput) ? docInput.selection : undefined;
|
|
293
642
|
const initialVersion = this.isExternalDocUpdate(docInput) && typeof docInput.version === 'number' ? docInput.version : undefined;
|
|
294
643
|
const initialSelection = this.initialSelection ?? externalSelection;
|
|
644
|
+
// Who supplies the starting document: the host, or the strategy? A
|
|
645
|
+
// host-supplied strategy with no host-supplied content owns the load, and
|
|
646
|
+
// `Editor.create()` only calls `sync.load(docId)` when it receives no
|
|
647
|
+
// `initialDoc` — so that option has to be left out entirely, not passed
|
|
648
|
+
// as a placeholder.
|
|
649
|
+
const hostSync = this.sync;
|
|
650
|
+
let syncStrategy;
|
|
651
|
+
let initialDoc = null;
|
|
652
|
+
if (hostSync && docInput === null && this.initialContent === null) {
|
|
653
|
+
syncStrategy = hostSync;
|
|
654
|
+
}
|
|
655
|
+
else {
|
|
656
|
+
initialDoc = this.resolveInitialDoc();
|
|
657
|
+
syncStrategy = hostSync ?? this.createLocalSync(initialDoc);
|
|
658
|
+
}
|
|
295
659
|
try {
|
|
296
660
|
const editor = await Editor.create({
|
|
297
|
-
docId: `lit-${Math.random().toString(36).slice(2)}`,
|
|
298
|
-
sync:
|
|
299
|
-
|
|
661
|
+
docId: this.docId ?? `lit-${Math.random().toString(36).slice(2)}`,
|
|
662
|
+
sync: syncStrategy,
|
|
663
|
+
clientID: this.clientID ?? undefined,
|
|
664
|
+
partId: this.partId ?? undefined,
|
|
665
|
+
...(initialDoc ? { initialDoc: initialDoc.toJSON() } : {}),
|
|
300
666
|
initialFiles,
|
|
301
667
|
initialReferences,
|
|
302
668
|
features: activeFeatures,
|
|
@@ -324,7 +690,7 @@ let SciFlowEditorElement = class SciFlowEditorElement extends LitElement {
|
|
|
324
690
|
this.dispatchSelectionChange(selection);
|
|
325
691
|
});
|
|
326
692
|
this.validationUnsub = editor.onValidation(() => undefined);
|
|
327
|
-
this.dispatchEditorChange(initialDoc.toJSON(), [], editor.getFiles());
|
|
693
|
+
this.dispatchEditorChange(initialDoc ? initialDoc.toJSON() : editor.getDoc(), [], editor.getFiles());
|
|
328
694
|
this.dispatchEditorReady();
|
|
329
695
|
this.initialSelection = undefined;
|
|
330
696
|
}
|
|
@@ -360,7 +726,7 @@ let SciFlowEditorElement = class SciFlowEditorElement extends LitElement {
|
|
|
360
726
|
return {
|
|
361
727
|
doc: docJSON,
|
|
362
728
|
version: 0,
|
|
363
|
-
selection: { anchor:
|
|
729
|
+
selection: { anchor: 1, head: 1 },
|
|
364
730
|
files: [],
|
|
365
731
|
references: [],
|
|
366
732
|
};
|
|
@@ -601,16 +967,27 @@ let SciFlowEditorElement = class SciFlowEditorElement extends LitElement {
|
|
|
601
967
|
* Tear down subscriptions and dispose the editor instance.
|
|
602
968
|
* Called automatically when the element disconnects.
|
|
603
969
|
*/
|
|
604
|
-
async reinitializeEditor() {
|
|
970
|
+
async reinitializeEditor(options = {}) {
|
|
605
971
|
if (!this.isConnected) {
|
|
606
972
|
return;
|
|
607
973
|
}
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
974
|
+
// Reconfiguring the editor (a new feature list) keeps the live document:
|
|
975
|
+
// it is the same document, edited by the same client, through the same
|
|
976
|
+
// strategy. Re-binding it (a new document, part, client or strategy) does
|
|
977
|
+
// not — that content belongs to the previous binding, and the new one
|
|
978
|
+
// sources its own from `doc`/`initialContent`/`sync.load()`.
|
|
979
|
+
const preserveContent = options.preserveContent ?? true;
|
|
980
|
+
const currentDoc = preserveContent ? this.editor?.getDoc() ?? null : null;
|
|
981
|
+
const currentSelection = preserveContent ? this.editor?.getSelection() ?? null : null;
|
|
982
|
+
const currentFiles = preserveContent ? this.editor?.getFiles() ?? [] : [];
|
|
983
|
+
const currentVersion = preserveContent ? this.editor?.getVersion() : undefined;
|
|
612
984
|
this.destroyEditor();
|
|
613
985
|
this.view = null;
|
|
986
|
+
// Clear the light-DOM mount so ProseMirror gets a fresh container on
|
|
987
|
+
// re-init (avoids stale node-view DOM from the previous instance).
|
|
988
|
+
if (this.lightDomMount) {
|
|
989
|
+
this.lightDomMount.innerHTML = '';
|
|
990
|
+
}
|
|
614
991
|
if (currentDoc) {
|
|
615
992
|
const nextDoc = {
|
|
616
993
|
doc: currentDoc,
|
|
@@ -624,7 +1001,9 @@ let SciFlowEditorElement = class SciFlowEditorElement extends LitElement {
|
|
|
624
1001
|
}
|
|
625
1002
|
this.doc = nextDoc;
|
|
626
1003
|
}
|
|
627
|
-
this.initialSelection =
|
|
1004
|
+
this.initialSelection = preserveContent
|
|
1005
|
+
? currentSelection ?? this.initialSelection
|
|
1006
|
+
: undefined;
|
|
628
1007
|
await this.initializeView();
|
|
629
1008
|
}
|
|
630
1009
|
/**
|
|
@@ -684,30 +1063,49 @@ let SciFlowEditorElement = class SciFlowEditorElement extends LitElement {
|
|
|
684
1063
|
if (!root || typeof root.appendChild !== 'function') {
|
|
685
1064
|
return;
|
|
686
1065
|
}
|
|
1066
|
+
// Remove previously injected consumer shadow styles.
|
|
687
1067
|
for (const styleEl of this.shadowStyleElements) {
|
|
688
1068
|
if (styleEl.parentNode === root) {
|
|
689
1069
|
root.removeChild(styleEl);
|
|
690
1070
|
}
|
|
691
1071
|
}
|
|
692
1072
|
this.shadowStyleElements = [];
|
|
1073
|
+
// Consumer-supplied shadow styles go into the shadow root (unchanged API).
|
|
693
1074
|
const cssTexts = this.normalizeShadowStyles(this.shadowStyles);
|
|
694
|
-
const widthCss = this.getEditorWidthStyles();
|
|
695
|
-
if (widthCss) {
|
|
696
|
-
cssTexts.push(widthCss);
|
|
697
|
-
}
|
|
698
|
-
if (cssTexts.length === 0) {
|
|
699
|
-
return;
|
|
700
|
-
}
|
|
701
1075
|
for (const cssText of cssTexts) {
|
|
702
1076
|
const styleEl = document.createElement('style');
|
|
703
1077
|
styleEl.textContent = cssText;
|
|
704
1078
|
root.appendChild(styleEl);
|
|
705
1079
|
this.shadowStyleElements.push(styleEl);
|
|
706
1080
|
}
|
|
1081
|
+
// Width styles target the light-DOM editable (.sf-editable-surface .ProseMirror).
|
|
1082
|
+
// Shadow CSS cannot pierce into slotted descendants, so these must live in
|
|
1083
|
+
// document.head where they reach the light-DOM tree directly.
|
|
1084
|
+
this.applyWidthStyles();
|
|
1085
|
+
}
|
|
1086
|
+
/**
|
|
1087
|
+
* Inject (or replace) the per-element width style in `document.head`.
|
|
1088
|
+
* Keyed by `data-sf-width-<instanceId>` so each instance manages its own rule.
|
|
1089
|
+
* SSR-safe.
|
|
1090
|
+
*/
|
|
1091
|
+
applyWidthStyles() {
|
|
1092
|
+
if (typeof document === 'undefined')
|
|
1093
|
+
return;
|
|
1094
|
+
const css = this.getEditorWidthStyles();
|
|
1095
|
+
if (!this._widthStyleEl) {
|
|
1096
|
+
const el = document.createElement('style');
|
|
1097
|
+
el.setAttribute(`data-sf-width-${this._instanceId}`, '');
|
|
1098
|
+
document.head.appendChild(el);
|
|
1099
|
+
this._widthStyleEl = el;
|
|
1100
|
+
}
|
|
1101
|
+
this._widthStyleEl.textContent = css;
|
|
707
1102
|
}
|
|
708
1103
|
getEditorWidthStyles() {
|
|
709
1104
|
const isNarrow = this.editorWidth === 'narrow';
|
|
710
|
-
|
|
1105
|
+
// Scoped to .sf-editable-surface so the rule reaches the light-DOM editable.
|
|
1106
|
+
// Injected into document.head (not the shadow root) so shadow-CSS slot
|
|
1107
|
+
// restrictions do not apply.
|
|
1108
|
+
return `.sf-editable-surface[data-sf-lightdom-mount] .ProseMirror {
|
|
711
1109
|
font-size: 11pt;
|
|
712
1110
|
max-width: ${isNarrow ? '52ch' : '82ch'};
|
|
713
1111
|
margin-left: auto;
|
|
@@ -776,6 +1174,18 @@ __decorate([
|
|
|
776
1174
|
__decorate([
|
|
777
1175
|
property({ type: String, reflect: true })
|
|
778
1176
|
], SciFlowEditorElement.prototype, "locale", void 0);
|
|
1177
|
+
__decorate([
|
|
1178
|
+
property({ attribute: false })
|
|
1179
|
+
], SciFlowEditorElement.prototype, "sync", void 0);
|
|
1180
|
+
__decorate([
|
|
1181
|
+
property({ type: String, attribute: 'doc-id' })
|
|
1182
|
+
], SciFlowEditorElement.prototype, "docId", void 0);
|
|
1183
|
+
__decorate([
|
|
1184
|
+
property({ attribute: 'client-id' })
|
|
1185
|
+
], SciFlowEditorElement.prototype, "clientID", void 0);
|
|
1186
|
+
__decorate([
|
|
1187
|
+
property({ type: String, attribute: 'part-id' })
|
|
1188
|
+
], SciFlowEditorElement.prototype, "partId", void 0);
|
|
779
1189
|
SciFlowEditorElement = __decorate([
|
|
780
1190
|
customElement('sciflow-editor')
|
|
781
1191
|
], SciFlowEditorElement);
|
package/dist/lib/format-bar.d.ts
CHANGED
|
@@ -35,6 +35,16 @@ export declare class SciFlowFormatBarElement extends LitElement {
|
|
|
35
35
|
editor: SciFlowEditorElement | null;
|
|
36
36
|
/** ID reference to resolve an editor instance declaratively. */
|
|
37
37
|
for?: string;
|
|
38
|
+
/**
|
|
39
|
+
* Space- or comma-separated list of command-metadata `group` names to omit
|
|
40
|
+
* from rendering (e.g. `"align"`). Suppresses the toolbar buttons for that
|
|
41
|
+
* group without touching command registration — the commands stay
|
|
42
|
+
* schema-legal and remain reachable via `editor.commands`/`runner.available()`.
|
|
43
|
+
* Use this for structured-manuscript contexts (e.g. a JATS-based export)
|
|
44
|
+
* where a UI-exposed capability isn't representable in the export content
|
|
45
|
+
* model. See docs/pages/user-guide/web-component-api.md.
|
|
46
|
+
*/
|
|
47
|
+
hiddenGroups: string;
|
|
38
48
|
private selectionVersion;
|
|
39
49
|
private styleMenuOpen;
|
|
40
50
|
private insertMenuOpen;
|
|
@@ -109,6 +119,18 @@ export declare class SciFlowFormatBarElement extends LitElement {
|
|
|
109
119
|
* Render a single command button, wiring up availability checks and active state handling.
|
|
110
120
|
*/
|
|
111
121
|
private renderCommandButton;
|
|
122
|
+
/**
|
|
123
|
+
* Parse the `hidden-groups` attribute into a set of group names to suppress.
|
|
124
|
+
* Accepts whitespace- and/or comma-separated values (e.g. `"align table"`, `"align,table"`).
|
|
125
|
+
*/
|
|
126
|
+
private get hiddenGroupSet();
|
|
127
|
+
/**
|
|
128
|
+
* Drop metadata entries whose `group` is listed in `hidden-groups` before any
|
|
129
|
+
* rendering derivation runs. This is a rendering-only filter: it does not touch
|
|
130
|
+
* command registration, so hidden commands stay schema-legal and remain reachable
|
|
131
|
+
* via `editor.commands`/`runner.available()` — only the toolbar buttons disappear.
|
|
132
|
+
*/
|
|
133
|
+
private filterHiddenGroups;
|
|
112
134
|
/**
|
|
113
135
|
* Determine which groups should be displayed and in which order based on command metadata.
|
|
114
136
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"format-bar.d.ts","sourceRoot":"","sources":["../../src/lib/format-bar.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AACH,OAAO,EAAa,UAAU,EAAsB,MAAM,KAAK,CAAC;AAOhE,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,qBAAqB,CAAC;AAoChE;;;;;;;;;;;GAWG;AACH,qBACa,uBAAwB,SAAQ,UAAU;IACrD,oFAAoF;IAEpF,MAAM,EAAE,oBAAoB,GAAG,IAAI,CAAQ;IAE3C,gEAAgE;IAEhE,GAAG,CAAC,EAAE,MAAM,CAAC;
|
|
1
|
+
{"version":3,"file":"format-bar.d.ts","sourceRoot":"","sources":["../../src/lib/format-bar.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AACH,OAAO,EAAa,UAAU,EAAsB,MAAM,KAAK,CAAC;AAOhE,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,qBAAqB,CAAC;AAoChE;;;;;;;;;;;GAWG;AACH,qBACa,uBAAwB,SAAQ,UAAU;IACrD,oFAAoF;IAEpF,MAAM,EAAE,oBAAoB,GAAG,IAAI,CAAQ;IAE3C,gEAAgE;IAEhE,GAAG,CAAC,EAAE,MAAM,CAAC;IAEb;;;;;;;;OAQG;IAEH,YAAY,SAAM;IAGlB,OAAO,CAAC,gBAAgB,CAAK;IAG7B,OAAO,CAAC,aAAa,CAAS;IAG9B,OAAO,CAAC,cAAc,CAAS;IAE/B,OAAO,CAAC,cAAc,CAAqC;IAC3D,OAAO,CAAC,iBAAiB,CAAC,CAAgB;IAC1C,OAAO,CAAC,aAAa,CAAC,CAAgB;IACtC,OAAO,CAAC,cAAc,CAAC,CAAgB;IACvC,OAAO,CAAC,UAAU,CAAC,CAAa;IAChC,OAAO,CAAC,kBAAkB,CAA0B;IACpD,OAAO,CAAC,mBAAmB,CAAC,CAA0B;IAEtD,OAAgB,MAAM,0BAAmC;IAEzD,uEAAuE;IAC9D,iBAAiB,IAAI,IAAI;IAoBlC,qDAAqD;IAC5C,oBAAoB,IAAI,IAAI;IAYrC;;;OAGG;cACgB,OAAO,CAAC,OAAO,EAAE,GAAG,CAAC,MAAM,GAAG,MAAM,GAAG,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI;IAMjF;;;OAGG;cACgB,MAAM;IAwCzB,OAAO,CAAC,mBAAmB;IAyD3B,OAAO,CAAC,eAAe;IAWvB,OAAO,CAAC,WAAW;IAoBnB,OAAO,CAAC,kBAAkB;IAc1B,OAAO,CAAC,aAAa;IAUrB,OAAO,CAAC,oBAAoB;IAuD5B,OAAO,CAAC,gBAAgB;IAWxB,OAAO,CAAC,oBAAoB;IAmB5B,OAAO,CAAC,0BAA0B;IAkBlC,OAAO,CAAC,yBAAyB;IAWjC;;OAEG;IACH,OAAO,CAAC,wBAAwB;IA2ChC;;;OAGG;IACH,OAAO,CAAC,sBAAsB;IA+B9B,OAAO,CAAC,aAAa;IAkBrB,+DAA+D;IAC/D,OAAO,CAAC,qBAAqB;IAc7B,2DAA2D;IAC3D,OAAO,CAAC,gBAAgB;IAQxB,8EAA8E;IAC9E,OAAO,CAAC,gBAAgB;IA6BxB,mDAAmD;IACnD,OAAO,CAAC,kBAAkB;IA6B1B,yEAAyE;IACzE,OAAO,CAAC,mBAAmB;IA6C3B,gFAAgF;IAChF,OAAO,CAAC,iBAAiB;IAmBzB,wEAAwE;IACxE,OAAO,CAAC,kBAAkB;IAmB1B;;;OAGG;IACH,OAAO,CAAC,oBAAoB;IAkB5B;;;;OAIG;IACH,OAAO,CAAC,kBAAkB;IAoB1B;;OAEG;IACH,OAAO,CAAC,mBAAmB;IAuC3B;;;OAGG;IACH,OAAO,KAAK,cAAc,GAOzB;IAED;;;;;OAKG;IACH,OAAO,CAAC,kBAAkB;IAY1B;;OAEG;IACH,OAAO,CAAC,gBAAgB;CA2BzB;AAED,OAAO,CAAC,MAAM,CAAC;IACb,UAAU,qBAAqB;QAC7B,mBAAmB,EAAE,uBAAuB,CAAC;KAC9C;CACF"}
|