@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.
Files changed (103) hide show
  1. package/README.md +11 -5
  2. package/dist/core/PopupManager.js +2 -2
  3. package/dist/core/index.js +38 -24
  4. package/dist/core/types.d.ts +7 -3
  5. package/dist/inline-plugins/color/README.md +1 -3
  6. package/dist/inline-plugins/color/README.ru.md +1 -3
  7. package/dist/inline-plugins/color.js +3 -2
  8. package/dist/inline-plugins/mention/README.md +1 -2
  9. package/dist/inline-plugins/mention/README.ru.md +1 -2
  10. package/dist/inline-plugins/mention/index.js +5 -10
  11. package/dist/plugins/attaches/README.md +0 -1
  12. package/dist/plugins/attaches/README.ru.md +0 -1
  13. package/dist/plugins/carousel/README.md +0 -1
  14. package/dist/plugins/carousel/README.ru.md +0 -1
  15. package/dist/plugins/checklist/README.md +0 -1
  16. package/dist/plugins/checklist/README.ru.md +0 -1
  17. package/dist/plugins/code/README.md +0 -1
  18. package/dist/plugins/code/README.ru.md +0 -1
  19. package/dist/plugins/columns/README.md +0 -1
  20. package/dist/plugins/columns/README.ru.md +0 -1
  21. package/dist/plugins/delimiter/README.md +0 -1
  22. package/dist/plugins/delimiter/README.ru.md +0 -1
  23. package/dist/plugins/embed/README.md +0 -1
  24. package/dist/plugins/embed/README.ru.md +0 -1
  25. package/dist/plugins/gallery/README.md +0 -1
  26. package/dist/plugins/gallery/README.ru.md +0 -1
  27. package/dist/plugins/heading/README.md +0 -1
  28. package/dist/plugins/heading/README.ru.md +0 -1
  29. package/dist/plugins/image/README.md +0 -1
  30. package/dist/plugins/image/README.ru.md +0 -1
  31. package/dist/plugins/link-preview/README.md +0 -1
  32. package/dist/plugins/link-preview/README.ru.md +0 -1
  33. package/dist/plugins/list/README.md +0 -1
  34. package/dist/plugins/list/README.ru.md +0 -1
  35. package/dist/plugins/paragraph/README.md +0 -1
  36. package/dist/plugins/paragraph/README.ru.md +0 -1
  37. package/dist/plugins/person/README.md +0 -1
  38. package/dist/plugins/person/README.ru.md +0 -1
  39. package/dist/plugins/poll/README.md +0 -1
  40. package/dist/plugins/poll/README.ru.md +0 -1
  41. package/dist/plugins/quote/README.md +0 -1
  42. package/dist/plugins/quote/README.ru.md +0 -1
  43. package/dist/plugins/raw/README.md +0 -1
  44. package/dist/plugins/raw/README.ru.md +0 -1
  45. package/dist/plugins/spoiler/README.md +0 -1
  46. package/dist/plugins/spoiler/README.ru.md +0 -1
  47. package/dist/plugins/table/README.md +0 -1
  48. package/dist/plugins/table/README.ru.md +0 -1
  49. package/dist/plugins/toggle/README.md +0 -1
  50. package/dist/plugins/toggle/README.ru.md +0 -1
  51. package/dist/plugins/warning/README.md +0 -1
  52. package/dist/plugins/warning/README.ru.md +0 -1
  53. package/dist/renderer/index.js +71 -26
  54. package/dist/renderer/types.d.ts +4 -2
  55. package/dist/shared/cloneEditorData.js +14 -7
  56. package/dist/shared/styleRegistry.js +8 -3
  57. package/dist/styles/inline-plugins/color.css +1 -0
  58. package/dist/styles/inline-plugins/mention.css +1 -0
  59. package/dist/styles/plugins/attaches.css +2 -0
  60. package/dist/styles/plugins/carousel.css +2 -0
  61. package/dist/styles/plugins/checklist.css +1 -0
  62. package/dist/styles/plugins/code.css +1 -0
  63. package/dist/styles/plugins/columns.css +1 -0
  64. package/dist/styles/plugins/delimiter.css +1 -0
  65. package/dist/styles/plugins/embed.css +1 -0
  66. package/dist/styles/plugins/gallery.css +2 -0
  67. package/dist/styles/plugins/heading.css +1 -0
  68. package/dist/styles/plugins/image.css +2 -0
  69. package/dist/styles/plugins/link-preview.css +1 -0
  70. package/dist/styles/plugins/list.css +1 -0
  71. package/dist/styles/plugins/paragraph.css +1 -0
  72. package/dist/styles/plugins/person.css +2 -0
  73. package/dist/styles/plugins/poll.css +1 -0
  74. package/dist/styles/plugins/quote.css +1 -0
  75. package/dist/styles/plugins/raw.css +1 -0
  76. package/dist/styles/plugins/spoiler.css +1 -0
  77. package/dist/styles/plugins/table.css +1 -0
  78. package/dist/styles/plugins/toggle.css +1 -0
  79. package/dist/styles/plugins/warning.css +1 -0
  80. package/dist/styles/renderer.css +1 -0
  81. package/dist/styles/renderers/attaches.css +1 -0
  82. package/dist/styles/renderers/carousel.css +2 -0
  83. package/dist/styles/renderers/checklist.css +1 -0
  84. package/dist/styles/renderers/code.css +1 -0
  85. package/dist/styles/renderers/columns.css +1 -0
  86. package/dist/styles/renderers/delimiter.css +1 -0
  87. package/dist/styles/renderers/embed.css +1 -0
  88. package/dist/styles/renderers/gallery.css +2 -0
  89. package/dist/styles/renderers/heading.css +1 -0
  90. package/dist/styles/renderers/image.css +1 -0
  91. package/dist/styles/renderers/link-preview.css +1 -0
  92. package/dist/styles/renderers/list.css +1 -0
  93. package/dist/styles/renderers/paragraph.css +1 -0
  94. package/dist/styles/renderers/person.css +2 -0
  95. package/dist/styles/renderers/poll.css +1 -0
  96. package/dist/styles/renderers/quote.css +1 -0
  97. package/dist/styles/renderers/raw.css +1 -0
  98. package/dist/styles/renderers/spoiler.css +1 -0
  99. package/dist/styles/renderers/table.css +1 -0
  100. package/dist/styles/renderers/toggle.css +1 -0
  101. package/dist/styles/renderers/warning.css +1 -0
  102. package/dist/styles.css +46 -0
  103. 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
@@ -182,18 +182,25 @@ function wireInputTracking(rootEl, blocks, events) {
182
182
  }
183
183
 
184
184
  /**
185
- * Collect and inject plugin stylesheets via <link> tags (reference-counted).
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
- * @returns {{ destroy(): void } | null}
193
- */
194
- function injectPluginStyles(plugins) {
195
- /** @type {string[]} */
196
- const styleUrls = []
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
- return styleUrls.length > 0 ? injectStyleUrls(styleUrls) : null
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 = injectPluginStyles(plugins)
674
+ const styleCleanup = injectEditorStyles(plugins, inlinePluginRegistry, injectStyles)
661
675
  if (styleCleanup) facade.registerDestroyable(styleCleanup)
662
676
 
663
677
  if (config.autofocus && !readOnly) {
@@ -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
- Import the color-picker stylesheet in addition to the Rector editor stylesheet. 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.
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
- Кроме стилей редактора импортируйте таблицу стилей средства выбора цвета. Корневой элемент использует `.oe-ip.oe-ip--color`, а точка и подпись — `.oe-ip__dot` и `.oe-ip__label`. Ограничивайте переопределения контейнером редактора или рендерера.
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, and a reference-counted stylesheet handle. `editor.destroy()` releases all of them. Register one separately created mention plugin per editor; mounting the same instance twice is rejected.
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
- Плагин владеет одним окном, обработчиками документа и окна браузера, таймером задержки, контроллером запросов и таблицей стилей с подсчётом владельцев. `editor.destroy()` освобождает все эти ресурсы. Для каждого редактора создавайте отдельный экземпляр плагина: повторное подключение одного экземпляра отклоняется.
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 acquired through the shared style
21
- * registry while the owning editor is mounted.
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. Ref-counted via `injectStyleUrls`. */
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 the shared stylesheet ref.
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'),