@shelamkoff/rector 1.0.3 → 1.0.5
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 +11 -5
- package/dist/core/PopupManager.js +2 -2
- package/dist/core/index.js +38 -24
- package/dist/core/types.d.ts +7 -3
- package/dist/inline-plugins/color/README.md +1 -3
- package/dist/inline-plugins/color/README.ru.md +1 -3
- package/dist/inline-plugins/color.js +3 -2
- package/dist/inline-plugins/mention/README.md +1 -2
- package/dist/inline-plugins/mention/README.ru.md +1 -2
- package/dist/inline-plugins/mention/index.js +5 -10
- package/dist/plugins/attaches/README.md +0 -1
- package/dist/plugins/attaches/README.ru.md +0 -1
- package/dist/plugins/carousel/README.md +0 -1
- package/dist/plugins/carousel/README.ru.md +0 -1
- package/dist/plugins/checklist/README.md +0 -1
- package/dist/plugins/checklist/README.ru.md +0 -1
- package/dist/plugins/code/README.md +0 -1
- package/dist/plugins/code/README.ru.md +0 -1
- package/dist/plugins/columns/README.md +0 -1
- package/dist/plugins/columns/README.ru.md +0 -1
- package/dist/plugins/delimiter/README.md +0 -1
- package/dist/plugins/delimiter/README.ru.md +0 -1
- package/dist/plugins/embed/README.md +0 -1
- package/dist/plugins/embed/README.ru.md +0 -1
- package/dist/plugins/gallery/README.md +0 -1
- package/dist/plugins/gallery/README.ru.md +0 -1
- package/dist/plugins/heading/README.md +0 -1
- package/dist/plugins/heading/README.ru.md +0 -1
- package/dist/plugins/image/README.md +0 -1
- package/dist/plugins/image/README.ru.md +0 -1
- package/dist/plugins/link-preview/README.md +0 -1
- package/dist/plugins/link-preview/README.ru.md +0 -1
- package/dist/plugins/list/README.md +0 -1
- package/dist/plugins/list/README.ru.md +0 -1
- package/dist/plugins/paragraph/README.md +0 -1
- package/dist/plugins/paragraph/README.ru.md +0 -1
- package/dist/plugins/person/README.md +0 -1
- package/dist/plugins/person/README.ru.md +0 -1
- package/dist/plugins/poll/README.md +0 -1
- package/dist/plugins/poll/README.ru.md +0 -1
- package/dist/plugins/quote/README.md +0 -1
- package/dist/plugins/quote/README.ru.md +0 -1
- package/dist/plugins/raw/README.md +0 -1
- package/dist/plugins/raw/README.ru.md +0 -1
- package/dist/plugins/spoiler/README.md +0 -1
- package/dist/plugins/spoiler/README.ru.md +0 -1
- package/dist/plugins/table/README.md +0 -1
- package/dist/plugins/table/README.ru.md +0 -1
- package/dist/plugins/toggle/README.md +0 -1
- package/dist/plugins/toggle/README.ru.md +0 -1
- package/dist/plugins/warning/README.md +0 -1
- package/dist/plugins/warning/README.ru.md +0 -1
- package/dist/renderer/index.js +71 -26
- package/dist/renderer/types.d.ts +4 -2
- package/dist/shared/cloneEditorData.js +14 -7
- package/dist/shared/styleRegistry.js +8 -3
- package/dist/styles/inline-plugins/color.css +1 -0
- package/dist/styles/inline-plugins/mention.css +1 -0
- package/dist/styles/plugins/attaches.css +2 -0
- package/dist/styles/plugins/carousel.css +2 -0
- package/dist/styles/plugins/checklist.css +1 -0
- package/dist/styles/plugins/code.css +1 -0
- package/dist/styles/plugins/columns.css +1 -0
- package/dist/styles/plugins/delimiter.css +1 -0
- package/dist/styles/plugins/embed.css +1 -0
- package/dist/styles/plugins/gallery.css +2 -0
- package/dist/styles/plugins/heading.css +1 -0
- package/dist/styles/plugins/image.css +2 -0
- package/dist/styles/plugins/link-preview.css +1 -0
- package/dist/styles/plugins/list.css +1 -0
- package/dist/styles/plugins/paragraph.css +1 -0
- package/dist/styles/plugins/person.css +2 -0
- package/dist/styles/plugins/poll.css +1 -0
- package/dist/styles/plugins/quote.css +1 -0
- package/dist/styles/plugins/raw.css +1 -0
- package/dist/styles/plugins/spoiler.css +1 -0
- package/dist/styles/plugins/table.css +1 -0
- package/dist/styles/plugins/toggle.css +1 -0
- package/dist/styles/plugins/warning.css +1 -0
- package/dist/styles/renderer.css +1 -0
- package/dist/styles/renderers/attaches.css +1 -0
- package/dist/styles/renderers/carousel.css +2 -0
- package/dist/styles/renderers/checklist.css +1 -0
- package/dist/styles/renderers/code.css +1 -0
- package/dist/styles/renderers/columns.css +1 -0
- package/dist/styles/renderers/delimiter.css +1 -0
- package/dist/styles/renderers/embed.css +1 -0
- package/dist/styles/renderers/gallery.css +2 -0
- package/dist/styles/renderers/heading.css +1 -0
- package/dist/styles/renderers/image.css +1 -0
- package/dist/styles/renderers/link-preview.css +1 -0
- package/dist/styles/renderers/list.css +1 -0
- package/dist/styles/renderers/paragraph.css +1 -0
- package/dist/styles/renderers/person.css +2 -0
- package/dist/styles/renderers/poll.css +1 -0
- package/dist/styles/renderers/quote.css +1 -0
- package/dist/styles/renderers/raw.css +1 -0
- package/dist/styles/renderers/spoiler.css +1 -0
- package/dist/styles/renderers/table.css +1 -0
- package/dist/styles/renderers/toggle.css +1 -0
- package/dist/styles/renderers/warning.css +1 -0
- package/dist/styles.css +46 -0
- package/package.json +15 -11
package/README.md
CHANGED
|
@@ -13,11 +13,17 @@ The complete guides, API reference, extension contracts, plugin catalog, and liv
|
|
|
13
13
|
|
|
14
14
|
## Installation
|
|
15
15
|
|
|
16
|
-
```bash
|
|
17
|
-
npm install @shelamkoff/rector
|
|
18
|
-
```
|
|
19
|
-
|
|
20
|
-
See the [getting started guide](https://shelamkoff.github.io/editor/guide/getting-started) for setup, required styles, plugin registration, document persistence, and lifecycle management.
|
|
16
|
+
```bash
|
|
17
|
+
npm install @shelamkoff/rector
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
See the [getting started guide](https://shelamkoff.github.io/editor/guide/getting-started) for setup, required styles, plugin registration, document persistence, and lifecycle management.
|
|
21
|
+
|
|
22
|
+
## Styles
|
|
23
|
+
|
|
24
|
+
`createEditor()` and `createEditorRenderer()` use `injectStyles: true` by default. They load only the styles declared by the registered extensions and release their reference-counted `<link>` elements on full destruction.
|
|
25
|
+
|
|
26
|
+
Bundler-based applications can instead set `injectStyles: false` and import CSS explicitly. Use `@shelamkoff/rector/styles.css` for every built-in style, or combine `styles/editor.css` / `styles/renderer.css` with selected subpaths such as `plugins/image/styles.css`, `inline-plugins/color/styles.css`, and `renderer/renderers/carousel/styles.css`.
|
|
21
27
|
|
|
22
28
|
## Project
|
|
23
29
|
|
|
@@ -32,7 +32,7 @@ export class PopupManager {
|
|
|
32
32
|
|
|
33
33
|
/** @type {() => boolean} */
|
|
34
34
|
#isReadOnly
|
|
35
|
-
|
|
35
|
+
|
|
36
36
|
/**
|
|
37
37
|
* @param {import('./types').IEventBus} events
|
|
38
38
|
* @param {string} changedEvent
|
|
@@ -51,7 +51,7 @@ export class PopupManager {
|
|
|
51
51
|
get readOnly() {
|
|
52
52
|
return this.#isReadOnly()
|
|
53
53
|
}
|
|
54
|
-
|
|
54
|
+
|
|
55
55
|
/**
|
|
56
56
|
* Set the editor root element (popup inherits CSS variables from it).
|
|
57
57
|
* @param {HTMLElement} rootEl
|
package/dist/core/index.js
CHANGED
|
@@ -182,18 +182,25 @@ function wireInputTracking(rootEl, blocks, events) {
|
|
|
182
182
|
}
|
|
183
183
|
|
|
184
184
|
/**
|
|
185
|
-
* Collect and inject
|
|
185
|
+
* Collect and inject all editor stylesheets via <link> tags (reference-counted).
|
|
186
186
|
*
|
|
187
187
|
* Per-plugin config knobs (passed via plugin constructor):
|
|
188
188
|
* - `injectStyles: false` — skip the default stylesheet for this plugin
|
|
189
189
|
* - `css: '/path/to.css'` — inject an additional stylesheet AFTER the default
|
|
190
190
|
*
|
|
191
|
-
* @param {Map<string, import('./types').BlockPlugin>} plugins
|
|
192
|
-
* @
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
191
|
+
* @param {Map<string, import('./types').BlockPlugin>} plugins
|
|
192
|
+
* @param {import('./InlinePluginRegistry').InlinePluginRegistry} inlinePlugins
|
|
193
|
+
* @param {boolean} enabled
|
|
194
|
+
* @returns {{ destroy(): void } | null}
|
|
195
|
+
*/
|
|
196
|
+
function injectEditorStyles(plugins, inlinePlugins, enabled) {
|
|
197
|
+
if (!enabled) return null
|
|
198
|
+
/** @type {string[]} */
|
|
199
|
+
const styleUrls = [
|
|
200
|
+
new URL('./themes/variables.css', import.meta.url).href,
|
|
201
|
+
new URL('./themes/light.css', import.meta.url).href,
|
|
202
|
+
new URL('./themes/dark.css', import.meta.url).href,
|
|
203
|
+
]
|
|
197
204
|
for (const plugin of plugins.values()) {
|
|
198
205
|
const cfg = typeof plugin.getPluginConfig === 'function'
|
|
199
206
|
? plugin.getPluginConfig()
|
|
@@ -202,11 +209,14 @@ function injectPluginStyles(plugins) {
|
|
|
202
209
|
const constructor = /** @type {import('./types').BlockPluginConstructor} */ (plugin.constructor)
|
|
203
210
|
const urls = constructor.styles
|
|
204
211
|
if (urls) styleUrls.push(...urls)
|
|
205
|
-
}
|
|
206
|
-
if (cfg?.css) styleUrls.push(cfg.css)
|
|
207
|
-
}
|
|
208
|
-
|
|
209
|
-
|
|
212
|
+
}
|
|
213
|
+
if (cfg?.css) styleUrls.push(cfg.css)
|
|
214
|
+
}
|
|
215
|
+
for (const plugin of inlinePlugins.values()) {
|
|
216
|
+
if (plugin.styles) styleUrls.push(...plugin.styles)
|
|
217
|
+
}
|
|
218
|
+
return styleUrls.length > 0 ? injectStyleUrls(styleUrls) : null
|
|
219
|
+
}
|
|
210
220
|
|
|
211
221
|
/**
|
|
212
222
|
* @typedef {Object} EditModeDeps
|
|
@@ -452,9 +462,12 @@ export function createEditor(config) {
|
|
|
452
462
|
if (!Array.isArray(config.plugins)) {
|
|
453
463
|
throw new TypeError('createEditor() requires a plugins array')
|
|
454
464
|
}
|
|
455
|
-
if (config.readOnly !== undefined && typeof config.readOnly !== 'boolean') {
|
|
456
|
-
throw new TypeError('createEditor() readOnly must be a boolean')
|
|
457
|
-
}
|
|
465
|
+
if (config.readOnly !== undefined && typeof config.readOnly !== 'boolean') {
|
|
466
|
+
throw new TypeError('createEditor() readOnly must be a boolean')
|
|
467
|
+
}
|
|
468
|
+
if (config.injectStyles !== undefined && typeof config.injectStyles !== 'boolean') {
|
|
469
|
+
throw new TypeError('createEditor() injectStyles must be a boolean')
|
|
470
|
+
}
|
|
458
471
|
if (config.placeholder !== undefined && typeof config.placeholder !== 'string') {
|
|
459
472
|
throw new TypeError('createEditor() placeholder must be a string')
|
|
460
473
|
}
|
|
@@ -465,7 +478,8 @@ export function createEditor(config) {
|
|
|
465
478
|
throw new RangeError('createEditor() minHeight must be a finite number greater than or equal to 0')
|
|
466
479
|
}
|
|
467
480
|
|
|
468
|
-
let readOnly = config.readOnly ?? false
|
|
481
|
+
let readOnly = config.readOnly ?? false
|
|
482
|
+
const injectStyles = config.injectStyles ?? true
|
|
469
483
|
const defaultBlockType = config.defaultBlock
|
|
470
484
|
|| (config.plugins?.some(plugin => plugin?.type === DEFAULT_BLOCK_TYPE)
|
|
471
485
|
? DEFAULT_BLOCK_TYPE
|
|
@@ -529,13 +543,13 @@ export function createEditor(config) {
|
|
|
529
543
|
|
|
530
544
|
const crossBlockSelection = new CrossBlockSelection()
|
|
531
545
|
|
|
532
|
-
const inlinePluginCtx = new PopupManager(
|
|
533
|
-
events,
|
|
534
|
-
EditorEvent.CHANGED,
|
|
535
|
-
blocks,
|
|
536
|
-
commands,
|
|
537
|
-
() => readOnly,
|
|
538
|
-
)
|
|
546
|
+
const inlinePluginCtx = new PopupManager(
|
|
547
|
+
events,
|
|
548
|
+
EditorEvent.CHANGED,
|
|
549
|
+
blocks,
|
|
550
|
+
commands,
|
|
551
|
+
() => readOnly,
|
|
552
|
+
)
|
|
539
553
|
inlinePluginCtx.setRoot(rootEl)
|
|
540
554
|
inlinePluginRegistry.mount(rootEl, inlinePluginCtx)
|
|
541
555
|
|
|
@@ -657,7 +671,7 @@ export function createEditor(config) {
|
|
|
657
671
|
|
|
658
672
|
if (!readOnly) mountEditMode()
|
|
659
673
|
|
|
660
|
-
const styleCleanup =
|
|
674
|
+
const styleCleanup = injectEditorStyles(plugins, inlinePluginRegistry, injectStyles)
|
|
661
675
|
if (styleCleanup) facade.registerDestroyable(styleCleanup)
|
|
662
676
|
|
|
663
677
|
if (config.autofocus && !readOnly) {
|
package/dist/core/types.d.ts
CHANGED
|
@@ -386,9 +386,11 @@ export interface EditorDiagnostic {
|
|
|
386
386
|
errorName?: string
|
|
387
387
|
}
|
|
388
388
|
|
|
389
|
-
export interface EditorConfig {
|
|
390
|
-
holder: HTMLElement
|
|
391
|
-
plugins: BlockPlugin[]
|
|
389
|
+
export interface EditorConfig {
|
|
390
|
+
holder: HTMLElement
|
|
391
|
+
plugins: BlockPlugin[]
|
|
392
|
+
/** Automatically load registered block and inline-plugin styles through reference-counted link elements. Default: true. */
|
|
393
|
+
injectStyles?: boolean
|
|
392
394
|
/** Custom inline tools. String types filter defaults, objects are used as-is. If omitted, all defaults are used. */
|
|
393
395
|
inlineTools?: Array<string | InlineTool>
|
|
394
396
|
/** Inline plugins (widgets inside text: color swatch, mention, etc.) */
|
|
@@ -686,6 +688,8 @@ export interface IEditor {
|
|
|
686
688
|
// ── Inline Plugins ───────────────────────────────────────────────────────────
|
|
687
689
|
|
|
688
690
|
export interface InlinePlugin extends BasePlugin {
|
|
691
|
+
/** Stylesheets declaratively owned by this plugin. */
|
|
692
|
+
readonly styles?: readonly string[]
|
|
689
693
|
/** Optional activation trigger. Must contain exactly one Unicode code point. */
|
|
690
694
|
readonly trigger?: string
|
|
691
695
|
/** Patterns that auto-convert pasted/typed text into this widget. */
|
|
@@ -12,8 +12,6 @@ npm install @shelamkoff/rector @shelamkoff/color-picker
|
|
|
12
12
|
import { createEditor } from '@shelamkoff/rector'
|
|
13
13
|
import { Paragraph } from '@shelamkoff/rector/plugins/paragraph'
|
|
14
14
|
import { createColorSwatchPlugin } from '@shelamkoff/rector/inline-plugins/color'
|
|
15
|
-
import '@shelamkoff/rector/styles/editor.css'
|
|
16
|
-
import '@shelamkoff/color-picker/styles.css'
|
|
17
15
|
|
|
18
16
|
const editor = createEditor({
|
|
19
17
|
holder: document.querySelector('#editor'),
|
|
@@ -54,7 +52,7 @@ In read-only mode the widget remains visible but does not open the picker. `edit
|
|
|
54
52
|
|
|
55
53
|
## Styles and document output
|
|
56
54
|
|
|
57
|
-
|
|
55
|
+
The plugin declares the color-picker stylesheet to Rector's shared style registry. With the default `injectStyles: true`, no CSS import is needed. In bundler-managed mode, set `injectStyles: false` on `createEditor()` and import `@shelamkoff/rector/inline-plugins/color/styles.css`. The widget root uses `.oe-ip.oe-ip--color`; its dot and label use `.oe-ip__dot` and `.oe-ip__label`. Scope host overrides under the editor or renderer container.
|
|
58
56
|
|
|
59
57
|
For document output, pass `createColorSwatchPlugin()` in `EditorRenderer`'s `inlinePlugins` array. The renderer uses its `createWidget()` and `getData()` subset; the picker is not mounted by the renderer.
|
|
60
58
|
|
|
@@ -12,8 +12,6 @@ npm install @shelamkoff/rector @shelamkoff/color-picker
|
|
|
12
12
|
import { createEditor } from '@shelamkoff/rector'
|
|
13
13
|
import { Paragraph } from '@shelamkoff/rector/plugins/paragraph'
|
|
14
14
|
import { createColorSwatchPlugin } from '@shelamkoff/rector/inline-plugins/color'
|
|
15
|
-
import '@shelamkoff/rector/styles/editor.css'
|
|
16
|
-
import '@shelamkoff/color-picker/styles.css'
|
|
17
15
|
|
|
18
16
|
const editor = createEditor({
|
|
19
17
|
holder: document.querySelector('#editor'),
|
|
@@ -54,7 +52,7 @@ const editor = createEditor({
|
|
|
54
52
|
|
|
55
53
|
## Стили и отображение документа
|
|
56
54
|
|
|
57
|
-
|
|
55
|
+
Плагин объявляет таблицу стилей средства выбора цвета общему реестру Rector. При стандартном `injectStyles: true` импорт CSS не нужен. В режиме сборщика укажите `injectStyles: false` в `createEditor()` и импортируйте `@shelamkoff/rector/inline-plugins/color/styles.css`. Корневой элемент использует `.oe-ip.oe-ip--color`, а точка и подпись — `.oe-ip__dot` и `.oe-ip__label`. Ограничивайте переопределения контейнером редактора или рендерера.
|
|
58
56
|
|
|
59
57
|
Для отображения документа передайте `createColorSwatchPlugin()` в массив `inlinePlugins` конструктора `EditorRenderer`. Рендерер использует только `createWidget()` и `getData()`; окно выбора цвета в нём не подключается.
|
|
60
58
|
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { ColorPicker } from '@shelamkoff/color-picker'
|
|
1
|
+
import { ColorPicker, colorPickerStylesUrl } from '@shelamkoff/color-picker'
|
|
2
2
|
import { generateInlineId } from '../shared/inlineMarshal.js'
|
|
3
3
|
import { normalizeTextValue } from '../shared/textFormat.js'
|
|
4
4
|
|
|
@@ -12,9 +12,9 @@ import { normalizeTextValue } from '../shared/textFormat.js'
|
|
|
12
12
|
export function createColorSwatchPlugin() {
|
|
13
13
|
/** @type {import('../core/types').IScopedI18n | null} */
|
|
14
14
|
let i18n = null
|
|
15
|
-
|
|
16
15
|
return {
|
|
17
16
|
type: 'color',
|
|
17
|
+
styles: [colorPickerStylesUrl],
|
|
18
18
|
get title() { return i18n?.has('title') ? i18n.t('title') : 'Color' },
|
|
19
19
|
icon: '<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M12 21a9 9 0 0 1 0-18c4.97 0 9 3.582 9 8c0 1.06-.474 2.078-1.318 2.828S17.938 15 16.5 15H14a2 2 0 0 0-1 3.75A1.3 1.3 0 0 1 12 21"/><circle cx="7.5" cy="10.5" r=".5" fill="currentColor"/><circle cx="12" cy="7.5" r=".5" fill="currentColor"/><circle cx="16.5" cy="10.5" r=".5" fill="currentColor"/></svg>',
|
|
20
20
|
/** @param {import('../core/types').IScopedI18n} _i18n */
|
|
@@ -72,6 +72,7 @@ export function createColorSwatchPlugin() {
|
|
|
72
72
|
value: element.dataset.value || '#000000',
|
|
73
73
|
}
|
|
74
74
|
},
|
|
75
|
+
|
|
75
76
|
}
|
|
76
77
|
}
|
|
77
78
|
|
|
@@ -8,7 +8,6 @@ Trigger-driven entity search with keyboard navigation, cursor pagination, custom
|
|
|
8
8
|
import { createEditor } from '@shelamkoff/rector'
|
|
9
9
|
import { Paragraph } from '@shelamkoff/rector/plugins/paragraph'
|
|
10
10
|
import { createMentionPlugin } from '@shelamkoff/rector/inline-plugins/mention'
|
|
11
|
-
import '@shelamkoff/rector/styles/editor.css'
|
|
12
11
|
|
|
13
12
|
const mention = createMentionPlugin({
|
|
14
13
|
async searchFunction(query, nextPageUrl, { signal }) {
|
|
@@ -86,7 +85,7 @@ The saved `id` is normalized to a string. `onMentionSelect` receives the source
|
|
|
86
85
|
|
|
87
86
|
A fresh commit or replacement of an existing mention is one undo/redo step. Search text, active-row movement, loading state, and opening or closing the popup are transient UI state and do not create commands.
|
|
88
87
|
|
|
89
|
-
The plugin owns one popup, its document/window listeners, debounce timer, request controller
|
|
88
|
+
The plugin owns one popup, its document/window listeners, debounce timer, and request controller. Its `styles` declaration is owned centrally by the editor, and `editor.destroy()` releases all runtime resources and automatic style references. In bundler-managed mode, import `@shelamkoff/rector/inline-plugins/mention/styles.css` and create the editor with `injectStyles: false`. Register one separately created mention plugin per editor; mounting the same instance twice is rejected.
|
|
90
89
|
|
|
91
90
|
Use `.oe-ip--mention` for saved pills and `.oe-mention-dropdown` plus its child classes for the suggestion UI. `avatar` URLs pass the shared media URL policy, and built-in rows assign names/details through text-safe DOM operations.
|
|
92
91
|
|
|
@@ -8,7 +8,6 @@
|
|
|
8
8
|
import { createEditor } from '@shelamkoff/rector'
|
|
9
9
|
import { Paragraph } from '@shelamkoff/rector/plugins/paragraph'
|
|
10
10
|
import { createMentionPlugin } from '@shelamkoff/rector/inline-plugins/mention'
|
|
11
|
-
import '@shelamkoff/rector/styles/editor.css'
|
|
12
11
|
|
|
13
12
|
const mention = createMentionPlugin({
|
|
14
13
|
async searchFunction(query, nextPageUrl, { signal }) {
|
|
@@ -86,7 +85,7 @@ interface MentionItem {
|
|
|
86
85
|
|
|
87
86
|
Первая вставка или замена существующего упоминания создаёт один шаг отмены и повтора. Текст запроса, перемещение по результатам, состояние загрузки, открытие и закрытие окна являются временным состоянием интерфейса и не создают команд.
|
|
88
87
|
|
|
89
|
-
Плагин владеет одним окном, обработчиками документа и окна браузера, таймером
|
|
88
|
+
Плагин владеет одним окном, обработчиками документа и окна браузера, таймером задержки и контроллером запросов. Его объявление `styles` централизованно принадлежит редактору, а `editor.destroy()` освобождает рабочие ресурсы и ссылки на автоматически загруженные стили. В режиме сборщика импортируйте `@shelamkoff/rector/inline-plugins/mention/styles.css` и создайте редактор с `injectStyles: false`. Для каждого редактора создавайте отдельный экземпляр плагина: повторное подключение одного экземпляра отклоняется.
|
|
90
89
|
|
|
91
90
|
Сохранённая плашка использует `.oe-ip--mention`, а окно подсказок — `.oe-mention-dropdown` и его дочерние классы. Адрес `avatar` проходит общую политику медиафайлов, а стандартные строки записывают имя и пояснение безопасными текстовыми операциями DOM.
|
|
92
91
|
|
|
@@ -17,8 +17,8 @@
|
|
|
17
17
|
* data-value="<entity>" class="oe-ip oe-ip--mention">@Name</span>`.
|
|
18
18
|
* The shared sanitize allowlist preserves this through save / render.
|
|
19
19
|
*
|
|
20
|
-
* Styling lives in `./styles.css` and is
|
|
21
|
-
*
|
|
20
|
+
* Styling lives in `./styles.css` and is declared through the plugin's
|
|
21
|
+
* `styles` property for the editor's shared style registry.
|
|
22
22
|
*/
|
|
23
23
|
|
|
24
24
|
/**
|
|
@@ -33,11 +33,10 @@
|
|
|
33
33
|
* @typedef {import('../../core/types').InlinePluginContext} InlinePluginContext
|
|
34
34
|
*/
|
|
35
35
|
|
|
36
|
-
import { injectStyleUrls } from '../../core/StyleInjector.js'
|
|
37
36
|
import { createMentionWidget } from './widget.js'
|
|
38
37
|
import { setSafeUrlAttribute } from '../../shared/sanitize/sanitizeUrl.js'
|
|
39
38
|
|
|
40
|
-
/** Absolute URL to the plugin's stylesheet.
|
|
39
|
+
/** Absolute URL to the plugin's stylesheet. */
|
|
41
40
|
const STYLES_URL = new URL('./styles.css', import.meta.url).href
|
|
42
41
|
|
|
43
42
|
const DEFAULTS = Object.freeze({
|
|
@@ -348,8 +347,6 @@ export function createMentionPlugin(options = {}) {
|
|
|
348
347
|
|
|
349
348
|
// Editor-scoped resources are acquired later by mount(). Construction is
|
|
350
349
|
// deliberately side-effect free so failed registration cannot leak them.
|
|
351
|
-
/** @type {{ destroy(): void } | null} */
|
|
352
|
-
let styleHandle = null
|
|
353
350
|
/** @type {HTMLElement | null} */
|
|
354
351
|
let rootElement = null
|
|
355
352
|
|
|
@@ -1653,6 +1650,7 @@ export function createMentionPlugin(options = {}) {
|
|
|
1653
1650
|
/** @type {InlinePlugin} */
|
|
1654
1651
|
const plugin = {
|
|
1655
1652
|
type: 'mention',
|
|
1653
|
+
styles: [STYLES_URL],
|
|
1656
1654
|
trigger: opts.trigger,
|
|
1657
1655
|
get title() { return t('title', 'Mention') },
|
|
1658
1656
|
|
|
@@ -1671,7 +1669,6 @@ export function createMentionPlugin(options = {}) {
|
|
|
1671
1669
|
if (rootElement) throw new Error('Mention plugin is already mounted')
|
|
1672
1670
|
rootElement = editorRoot
|
|
1673
1671
|
globalCtx = ctx
|
|
1674
|
-
styleHandle = injectStyleUrls([STYLES_URL])
|
|
1675
1672
|
rootElement.addEventListener('beforeinput', /** @type {EventListener} */ (handleBeforeInput), true)
|
|
1676
1673
|
},
|
|
1677
1674
|
|
|
@@ -1874,15 +1871,13 @@ export function createMentionPlugin(options = {}) {
|
|
|
1874
1871
|
* owning editor and uses it to:
|
|
1875
1872
|
* - close any open session;
|
|
1876
1873
|
* - detach the editor-scoped `beforeinput` listener;
|
|
1877
|
-
* - release
|
|
1874
|
+
* - release editor-scoped listeners and active UI.
|
|
1878
1875
|
*
|
|
1879
1876
|
*/
|
|
1880
1877
|
destroy() {
|
|
1881
1878
|
closeSession()
|
|
1882
1879
|
rootElement?.removeEventListener('beforeinput', /** @type {EventListener} */ (handleBeforeInput), true)
|
|
1883
1880
|
rootElement = null
|
|
1884
|
-
styleHandle?.destroy()
|
|
1885
|
-
styleHandle = null
|
|
1886
1881
|
globalCtx = null
|
|
1887
1882
|
},
|
|
1888
1883
|
}
|
|
@@ -11,7 +11,6 @@ npm install @shelamkoff/rector
|
|
|
11
11
|
```js
|
|
12
12
|
import { createEditor } from '@shelamkoff/rector'
|
|
13
13
|
import { Attaches } from '@shelamkoff/rector/plugins/attaches'
|
|
14
|
-
import '@shelamkoff/rector/styles/editor.css'
|
|
15
14
|
|
|
16
15
|
const editor = createEditor({
|
|
17
16
|
holder: document.querySelector('#editor'),
|
|
@@ -11,7 +11,6 @@ npm install @shelamkoff/rector
|
|
|
11
11
|
```js
|
|
12
12
|
import { createEditor } from '@shelamkoff/rector'
|
|
13
13
|
import { Attaches } from '@shelamkoff/rector/plugins/attaches'
|
|
14
|
-
import '@shelamkoff/rector/styles/editor.css'
|
|
15
14
|
|
|
16
15
|
const editor = createEditor({
|
|
17
16
|
holder: document.querySelector('#editor'),
|
|
@@ -11,7 +11,6 @@ npm install @shelamkoff/rector
|
|
|
11
11
|
```js
|
|
12
12
|
import { createEditor } from '@shelamkoff/rector'
|
|
13
13
|
import { CarouselBlock } from '@shelamkoff/rector/plugins/carousel'
|
|
14
|
-
import '@shelamkoff/rector/styles/editor.css'
|
|
15
14
|
|
|
16
15
|
const editor = createEditor({
|
|
17
16
|
holder: document.querySelector('#editor'),
|
|
@@ -11,7 +11,6 @@ npm install @shelamkoff/rector
|
|
|
11
11
|
```js
|
|
12
12
|
import { createEditor } from '@shelamkoff/rector'
|
|
13
13
|
import { CarouselBlock } from '@shelamkoff/rector/plugins/carousel'
|
|
14
|
-
import '@shelamkoff/rector/styles/editor.css'
|
|
15
14
|
|
|
16
15
|
const editor = createEditor({
|
|
17
16
|
holder: document.querySelector('#editor'),
|
|
@@ -11,7 +11,6 @@ npm install @shelamkoff/rector
|
|
|
11
11
|
```js
|
|
12
12
|
import { createEditor } from '@shelamkoff/rector'
|
|
13
13
|
import { Checklist } from '@shelamkoff/rector/plugins/checklist'
|
|
14
|
-
import '@shelamkoff/rector/styles/editor.css'
|
|
15
14
|
|
|
16
15
|
const editor = createEditor({
|
|
17
16
|
holder: document.querySelector('#editor'),
|
|
@@ -11,7 +11,6 @@ npm install @shelamkoff/rector
|
|
|
11
11
|
```js
|
|
12
12
|
import { createEditor } from '@shelamkoff/rector'
|
|
13
13
|
import { Checklist } from '@shelamkoff/rector/plugins/checklist'
|
|
14
|
-
import '@shelamkoff/rector/styles/editor.css'
|
|
15
14
|
|
|
16
15
|
const editor = createEditor({
|
|
17
16
|
holder: document.querySelector('#editor'),
|
|
@@ -11,7 +11,6 @@ npm install @shelamkoff/rector
|
|
|
11
11
|
```js
|
|
12
12
|
import { createEditor } from '@shelamkoff/rector'
|
|
13
13
|
import { Code } from '@shelamkoff/rector/plugins/code'
|
|
14
|
-
import '@shelamkoff/rector/styles/editor.css'
|
|
15
14
|
|
|
16
15
|
const editor = createEditor({
|
|
17
16
|
holder: document.querySelector('#editor'),
|
|
@@ -11,7 +11,6 @@ npm install @shelamkoff/rector
|
|
|
11
11
|
```js
|
|
12
12
|
import { createEditor } from '@shelamkoff/rector'
|
|
13
13
|
import { Code } from '@shelamkoff/rector/plugins/code'
|
|
14
|
-
import '@shelamkoff/rector/styles/editor.css'
|
|
15
14
|
|
|
16
15
|
const editor = createEditor({
|
|
17
16
|
holder: document.querySelector('#editor'),
|
|
@@ -11,7 +11,6 @@ npm install @shelamkoff/rector
|
|
|
11
11
|
```js
|
|
12
12
|
import { createEditor } from '@shelamkoff/rector'
|
|
13
13
|
import { Columns } from '@shelamkoff/rector/plugins/columns'
|
|
14
|
-
import '@shelamkoff/rector/styles/editor.css'
|
|
15
14
|
|
|
16
15
|
const editor = createEditor({
|
|
17
16
|
holder: document.querySelector('#editor'),
|
|
@@ -11,7 +11,6 @@ npm install @shelamkoff/rector
|
|
|
11
11
|
```js
|
|
12
12
|
import { createEditor } from '@shelamkoff/rector'
|
|
13
13
|
import { Columns } from '@shelamkoff/rector/plugins/columns'
|
|
14
|
-
import '@shelamkoff/rector/styles/editor.css'
|
|
15
14
|
|
|
16
15
|
const editor = createEditor({
|
|
17
16
|
holder: document.querySelector('#editor'),
|
|
@@ -11,7 +11,6 @@ npm install @shelamkoff/rector
|
|
|
11
11
|
```js
|
|
12
12
|
import { createEditor } from '@shelamkoff/rector'
|
|
13
13
|
import { Delimiter } from '@shelamkoff/rector/plugins/delimiter'
|
|
14
|
-
import '@shelamkoff/rector/styles/editor.css'
|
|
15
14
|
|
|
16
15
|
const editor = createEditor({
|
|
17
16
|
holder: document.querySelector('#editor'),
|
|
@@ -11,7 +11,6 @@ npm install @shelamkoff/rector
|
|
|
11
11
|
```js
|
|
12
12
|
import { createEditor } from '@shelamkoff/rector'
|
|
13
13
|
import { Delimiter } from '@shelamkoff/rector/plugins/delimiter'
|
|
14
|
-
import '@shelamkoff/rector/styles/editor.css'
|
|
15
14
|
|
|
16
15
|
const editor = createEditor({
|
|
17
16
|
holder: document.querySelector('#editor'),
|
|
@@ -11,7 +11,6 @@ npm install @shelamkoff/rector
|
|
|
11
11
|
```js
|
|
12
12
|
import { createEditor } from '@shelamkoff/rector'
|
|
13
13
|
import { Embed } from '@shelamkoff/rector/plugins/embed'
|
|
14
|
-
import '@shelamkoff/rector/styles/editor.css'
|
|
15
14
|
|
|
16
15
|
const editor = createEditor({
|
|
17
16
|
holder: document.querySelector('#editor'),
|
|
@@ -11,7 +11,6 @@ npm install @shelamkoff/rector
|
|
|
11
11
|
```js
|
|
12
12
|
import { createEditor } from '@shelamkoff/rector'
|
|
13
13
|
import { Embed } from '@shelamkoff/rector/plugins/embed'
|
|
14
|
-
import '@shelamkoff/rector/styles/editor.css'
|
|
15
14
|
|
|
16
15
|
const editor = createEditor({
|
|
17
16
|
holder: document.querySelector('#editor'),
|
|
@@ -11,7 +11,6 @@ npm install @shelamkoff/rector
|
|
|
11
11
|
```js
|
|
12
12
|
import { createEditor } from '@shelamkoff/rector'
|
|
13
13
|
import { Gallery } from '@shelamkoff/rector/plugins/gallery'
|
|
14
|
-
import '@shelamkoff/rector/styles/editor.css'
|
|
15
14
|
|
|
16
15
|
const editor = createEditor({
|
|
17
16
|
holder: document.querySelector('#editor'),
|
|
@@ -11,7 +11,6 @@ npm install @shelamkoff/rector
|
|
|
11
11
|
```js
|
|
12
12
|
import { createEditor } from '@shelamkoff/rector'
|
|
13
13
|
import { Gallery } from '@shelamkoff/rector/plugins/gallery'
|
|
14
|
-
import '@shelamkoff/rector/styles/editor.css'
|
|
15
14
|
|
|
16
15
|
const editor = createEditor({
|
|
17
16
|
holder: document.querySelector('#editor'),
|
|
@@ -11,7 +11,6 @@ npm install @shelamkoff/rector
|
|
|
11
11
|
```js
|
|
12
12
|
import { createEditor } from '@shelamkoff/rector'
|
|
13
13
|
import { Heading } from '@shelamkoff/rector/plugins/heading'
|
|
14
|
-
import '@shelamkoff/rector/styles/editor.css'
|
|
15
14
|
|
|
16
15
|
const editor = createEditor({
|
|
17
16
|
holder: document.querySelector('#editor'),
|
|
@@ -11,7 +11,6 @@ npm install @shelamkoff/rector
|
|
|
11
11
|
```js
|
|
12
12
|
import { createEditor } from '@shelamkoff/rector'
|
|
13
13
|
import { Heading } from '@shelamkoff/rector/plugins/heading'
|
|
14
|
-
import '@shelamkoff/rector/styles/editor.css'
|
|
15
14
|
|
|
16
15
|
const editor = createEditor({
|
|
17
16
|
holder: document.querySelector('#editor'),
|
|
@@ -11,7 +11,6 @@ npm install @shelamkoff/rector
|
|
|
11
11
|
```js
|
|
12
12
|
import { createEditor } from '@shelamkoff/rector'
|
|
13
13
|
import { Image } from '@shelamkoff/rector/plugins/image'
|
|
14
|
-
import '@shelamkoff/rector/styles/editor.css'
|
|
15
14
|
|
|
16
15
|
const editor = createEditor({
|
|
17
16
|
holder: document.querySelector('#editor'),
|
|
@@ -11,7 +11,6 @@ npm install @shelamkoff/rector
|
|
|
11
11
|
```js
|
|
12
12
|
import { createEditor } from '@shelamkoff/rector'
|
|
13
13
|
import { Image } from '@shelamkoff/rector/plugins/image'
|
|
14
|
-
import '@shelamkoff/rector/styles/editor.css'
|
|
15
14
|
|
|
16
15
|
const editor = createEditor({
|
|
17
16
|
holder: document.querySelector('#editor'),
|
|
@@ -11,7 +11,6 @@ npm install @shelamkoff/rector
|
|
|
11
11
|
```js
|
|
12
12
|
import { createEditor } from '@shelamkoff/rector'
|
|
13
13
|
import { LinkPreview } from '@shelamkoff/rector/plugins/link-preview'
|
|
14
|
-
import '@shelamkoff/rector/styles/editor.css'
|
|
15
14
|
|
|
16
15
|
const editor = createEditor({
|
|
17
16
|
holder: document.querySelector('#editor'),
|
|
@@ -11,7 +11,6 @@ npm install @shelamkoff/rector
|
|
|
11
11
|
```js
|
|
12
12
|
import { createEditor } from '@shelamkoff/rector'
|
|
13
13
|
import { LinkPreview } from '@shelamkoff/rector/plugins/link-preview'
|
|
14
|
-
import '@shelamkoff/rector/styles/editor.css'
|
|
15
14
|
|
|
16
15
|
const editor = createEditor({
|
|
17
16
|
holder: document.querySelector('#editor'),
|
|
@@ -11,7 +11,6 @@ npm install @shelamkoff/rector
|
|
|
11
11
|
```js
|
|
12
12
|
import { createEditor } from '@shelamkoff/rector'
|
|
13
13
|
import { List } from '@shelamkoff/rector/plugins/list'
|
|
14
|
-
import '@shelamkoff/rector/styles/editor.css'
|
|
15
14
|
|
|
16
15
|
const editor = createEditor({
|
|
17
16
|
holder: document.querySelector('#editor'),
|
|
@@ -11,7 +11,6 @@ npm install @shelamkoff/rector
|
|
|
11
11
|
```js
|
|
12
12
|
import { createEditor } from '@shelamkoff/rector'
|
|
13
13
|
import { List } from '@shelamkoff/rector/plugins/list'
|
|
14
|
-
import '@shelamkoff/rector/styles/editor.css'
|
|
15
14
|
|
|
16
15
|
const editor = createEditor({
|
|
17
16
|
holder: document.querySelector('#editor'),
|
|
@@ -11,7 +11,6 @@ npm install @shelamkoff/rector
|
|
|
11
11
|
```js
|
|
12
12
|
import { createEditor } from '@shelamkoff/rector'
|
|
13
13
|
import { Paragraph } from '@shelamkoff/rector/plugins/paragraph'
|
|
14
|
-
import '@shelamkoff/rector/styles/editor.css'
|
|
15
14
|
|
|
16
15
|
const editor = createEditor({
|
|
17
16
|
holder: document.querySelector('#editor'),
|
|
@@ -11,7 +11,6 @@ npm install @shelamkoff/rector
|
|
|
11
11
|
```js
|
|
12
12
|
import { createEditor } from '@shelamkoff/rector'
|
|
13
13
|
import { Paragraph } from '@shelamkoff/rector/plugins/paragraph'
|
|
14
|
-
import '@shelamkoff/rector/styles/editor.css'
|
|
15
14
|
|
|
16
15
|
const editor = createEditor({
|
|
17
16
|
holder: document.querySelector('#editor'),
|
|
@@ -11,7 +11,6 @@ npm install @shelamkoff/rector @shelamkoff/cropper
|
|
|
11
11
|
```js
|
|
12
12
|
import { createEditor } from '@shelamkoff/rector'
|
|
13
13
|
import { Person } from '@shelamkoff/rector/plugins/person'
|
|
14
|
-
import '@shelamkoff/rector/styles/editor.css'
|
|
15
14
|
|
|
16
15
|
const editor = createEditor({
|
|
17
16
|
holder: document.querySelector('#editor'),
|
|
@@ -11,7 +11,6 @@ npm install @shelamkoff/rector @shelamkoff/cropper
|
|
|
11
11
|
```js
|
|
12
12
|
import { createEditor } from '@shelamkoff/rector'
|
|
13
13
|
import { Person } from '@shelamkoff/rector/plugins/person'
|
|
14
|
-
import '@shelamkoff/rector/styles/editor.css'
|
|
15
14
|
|
|
16
15
|
const editor = createEditor({
|
|
17
16
|
holder: document.querySelector('#editor'),
|
|
@@ -11,7 +11,6 @@ npm install @shelamkoff/rector
|
|
|
11
11
|
```js
|
|
12
12
|
import { createEditor } from '@shelamkoff/rector'
|
|
13
13
|
import { Poll } from '@shelamkoff/rector/plugins/poll'
|
|
14
|
-
import '@shelamkoff/rector/styles/editor.css'
|
|
15
14
|
|
|
16
15
|
const editor = createEditor({
|
|
17
16
|
holder: document.querySelector('#editor'),
|
|
@@ -11,7 +11,6 @@ npm install @shelamkoff/rector
|
|
|
11
11
|
```js
|
|
12
12
|
import { createEditor } from '@shelamkoff/rector'
|
|
13
13
|
import { Poll } from '@shelamkoff/rector/plugins/poll'
|
|
14
|
-
import '@shelamkoff/rector/styles/editor.css'
|
|
15
14
|
|
|
16
15
|
const editor = createEditor({
|
|
17
16
|
holder: document.querySelector('#editor'),
|
|
@@ -11,7 +11,6 @@ npm install @shelamkoff/rector
|
|
|
11
11
|
```js
|
|
12
12
|
import { createEditor } from '@shelamkoff/rector'
|
|
13
13
|
import { Quote } from '@shelamkoff/rector/plugins/quote'
|
|
14
|
-
import '@shelamkoff/rector/styles/editor.css'
|
|
15
14
|
|
|
16
15
|
const editor = createEditor({
|
|
17
16
|
holder: document.querySelector('#editor'),
|