@shelamkoff/rector 1.0.0 → 1.0.2

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 (94) hide show
  1. package/README.md +25 -23
  2. package/dist/core/clipboard/Clipboard.d.ts +2 -0
  3. package/dist/core/clipboard/Clipboard.js +52 -24
  4. package/dist/core/index.js +195 -194
  5. package/dist/core/locale/en.d.ts +1 -0
  6. package/dist/core/locale/en.js +1 -0
  7. package/dist/core/locale/ru.d.ts +1 -0
  8. package/dist/core/locale/ru.js +1 -0
  9. package/dist/core/themes/light.css +1 -1
  10. package/dist/core/themes/variables.css +72 -10
  11. package/dist/inline-plugins/mention/index.js +1 -2
  12. package/dist/locale/en.d.ts +41 -0
  13. package/dist/locale/ru.d.ts +41 -0
  14. package/dist/plugins/attaches/attaches.css +16 -14
  15. package/dist/plugins/attaches/index.js +997 -921
  16. package/dist/plugins/attaches/locale/en.d.ts +9 -0
  17. package/dist/plugins/attaches/locale/en.js +11 -2
  18. package/dist/plugins/attaches/locale/ru.d.ts +9 -0
  19. package/dist/plugins/attaches/locale/ru.js +11 -2
  20. package/dist/plugins/carousel/carousel.css +213 -49
  21. package/dist/plugins/carousel/index.js +918 -859
  22. package/dist/plugins/carousel/locale/en.d.ts +15 -0
  23. package/dist/plugins/carousel/locale/en.js +18 -3
  24. package/dist/plugins/carousel/locale/ru.d.ts +15 -0
  25. package/dist/plugins/carousel/locale/ru.js +18 -3
  26. package/dist/plugins/checklist/index.js +1 -2
  27. package/dist/plugins/code/index.js +1 -2
  28. package/dist/plugins/columns/index.js +1 -2
  29. package/dist/plugins/delimiter/index.js +1 -2
  30. package/dist/plugins/embed/index.js +1 -2
  31. package/dist/plugins/gallery/gallery.css +6 -1
  32. package/dist/plugins/gallery/index.js +375 -355
  33. package/dist/plugins/gallery/locale/en.d.ts +8 -0
  34. package/dist/plugins/gallery/locale/en.js +11 -3
  35. package/dist/plugins/gallery/locale/ru.d.ts +8 -0
  36. package/dist/plugins/gallery/locale/ru.js +11 -3
  37. package/dist/plugins/gallery/view-empty.d.ts +2 -0
  38. package/dist/plugins/gallery/view-empty.js +21 -15
  39. package/dist/plugins/gallery/view-filled.d.ts +2 -2
  40. package/dist/plugins/gallery/view-filled.js +61 -56
  41. package/dist/plugins/heading/index.js +1 -2
  42. package/dist/plugins/image/image.css +7 -2
  43. package/dist/plugins/image/index.js +365 -346
  44. package/dist/plugins/image/locale/en.d.ts +8 -0
  45. package/dist/plugins/image/locale/en.js +11 -3
  46. package/dist/plugins/image/locale/ru.d.ts +8 -0
  47. package/dist/plugins/image/locale/ru.js +11 -3
  48. package/dist/plugins/image/view-empty.d.ts +2 -0
  49. package/dist/plugins/image/view-empty.js +21 -15
  50. package/dist/plugins/image/view-filled.d.ts +2 -2
  51. package/dist/plugins/image/view-filled.js +77 -72
  52. package/dist/plugins/link-preview/index.js +1 -2
  53. package/dist/plugins/list/index.js +1 -2
  54. package/dist/plugins/paragraph/index.js +1 -2
  55. package/dist/plugins/person/index.js +1 -2
  56. package/dist/plugins/poll/index.js +1 -2
  57. package/dist/plugins/quote/index.js +1 -2
  58. package/dist/plugins/raw/index.js +1 -2
  59. package/dist/plugins/shared/dropzone.d.ts +6 -0
  60. package/dist/plugins/shared/dropzone.js +47 -36
  61. package/dist/plugins/shared/layer.d.ts +13 -0
  62. package/dist/plugins/shared/layer.js +45 -0
  63. package/dist/plugins/shared/sourceEditor.css +165 -0
  64. package/dist/plugins/shared/sourceEditor.d.ts +97 -0
  65. package/dist/plugins/shared/sourceEditor.js +260 -0
  66. package/dist/plugins/spoiler/index.js +1 -2
  67. package/dist/plugins/table/index.js +1 -2
  68. package/dist/plugins/toggle/index.js +1 -2
  69. package/dist/plugins/warning/index.js +1 -2
  70. package/dist/renderer/index.js +1 -2
  71. package/dist/renderer/renderers/attaches/index.js +1 -2
  72. package/dist/renderer/renderers/carousel/index.js +24 -24
  73. package/dist/renderer/renderers/carousel/styles.css +8 -2
  74. package/dist/renderer/renderers/checklist/index.js +1 -2
  75. package/dist/renderer/renderers/code/index.js +1 -2
  76. package/dist/renderer/renderers/columns/index.js +1 -2
  77. package/dist/renderer/renderers/delimiter/index.js +1 -2
  78. package/dist/renderer/renderers/embed/index.js +1 -2
  79. package/dist/renderer/renderers/gallery/index.js +1 -2
  80. package/dist/renderer/renderers/heading/index.js +1 -2
  81. package/dist/renderer/renderers/image/index.js +1 -2
  82. package/dist/renderer/renderers/link-preview/index.js +1 -2
  83. package/dist/renderer/renderers/list/index.js +1 -2
  84. package/dist/renderer/renderers/paragraph/index.js +1 -2
  85. package/dist/renderer/renderers/person/index.js +1 -2
  86. package/dist/renderer/renderers/poll/index.js +1 -2
  87. package/dist/renderer/renderers/quote/index.js +1 -2
  88. package/dist/renderer/renderers/spoiler/index.js +1 -2
  89. package/dist/renderer/renderers/table/index.js +1 -2
  90. package/dist/renderer/renderers/toggle/index.js +1 -2
  91. package/dist/renderer/renderers/warning/index.js +1 -2
  92. package/package.json +27 -29
  93. package/dist/shared/resolvePath.d.ts +0 -8
  94. package/dist/shared/resolvePath.js +0 -10
package/README.md CHANGED
@@ -1,23 +1,25 @@
1
- # @shelamkoff/rector
2
-
3
- Rector is an extensible browser-native block editor with atomic undo and redo, versioned JSON documents, inline formatting, block plugins, and document rendering.
4
-
5
- ## Documentation
6
-
7
- The complete guides, API reference, extension contracts, plugin catalog, and live demo are published with VitePress:
8
-
9
- - [English documentation](https://shelamkoff.github.io/editor/)
10
- - [Документация на русском](https://shelamkoff.github.io/editor/ru/)
11
-
12
- ## Installation
13
-
14
- ```bash
15
- npm install @shelamkoff/rector
16
- ```
17
-
18
- See the [getting started guide](https://shelamkoff.github.io/editor/guide/getting-started) for setup, required styles, plugin registration, document persistence, and lifecycle management.
19
-
20
- ## Project
21
-
22
- - [Source code and issues](https://github.com/Shelamkoff/editor)
23
- - [MIT License](./LICENSE)
1
+ # @shelamkoff/rector
2
+
3
+ Rector is an extensible browser-native block editor with atomic undo and redo, versioned JSON documents, inline formatting, block plugins, and document rendering.
4
+ ![Editor demo](https://github.com/Shelamkoff/editor/blob/master/docs/public/editor.png)
5
+
6
+ ## Documentation
7
+
8
+ The complete guides, API reference, extension contracts, plugin catalog, and live demo are published with VitePress:
9
+
10
+ - [English documentation](https://shelamkoff.github.io/editor/)
11
+ - [Документация на русском](https://shelamkoff.github.io/editor/ru/)
12
+ - [Live demo](https://shelamkoff.github.io/editor/#demo)
13
+
14
+ ## Installation
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.
21
+
22
+ ## Project
23
+
24
+ - [Source code and issues](https://github.com/Shelamkoff/editor)
25
+ - [MIT License](./LICENSE)
@@ -22,6 +22,7 @@ export class Clipboard {
22
22
  * @property {import('../types.js').InlinePluginContext} inlinePluginCtx
23
23
  * @property {import('../Diagnostics.js').Diagnostics} [diagnostics]
24
24
  * @property {(() => boolean)} [uiActivePredicate]
25
+ * @property {string} [pendingPasteLabel]
25
26
  */
26
27
  /**
27
28
  * @param {HTMLElement} rootEl
@@ -41,6 +42,7 @@ export class Clipboard {
41
42
  inlinePluginCtx: import("../types.js").InlinePluginContext;
42
43
  diagnostics?: import("../Diagnostics.js").Diagnostics;
43
44
  uiActivePredicate?: (() => boolean);
45
+ pendingPasteLabel?: string;
44
46
  });
45
47
  destroy(): void;
46
48
  #private;
@@ -8,6 +8,27 @@ import { cloneEditorData } from '../../shared/cloneEditorData.js'
8
8
 
9
9
  const MIME_TYPE = 'application/x-rector-editor'
10
10
 
11
+ /**
12
+ * Core-owned progress UI for asynchronous file pastes. The plugin's pending
13
+ * element stays mounted so its upload lifecycle can continue, but is hidden
14
+ * until the completed block is committed to the document.
15
+ *
16
+ * @param {string} label
17
+ * @returns {HTMLElement}
18
+ */
19
+ function createPendingPasteIndicator(label) {
20
+ const indicator = document.createElement('div')
21
+ indicator.className = 'oe-pending-paste__indicator'
22
+ indicator.setAttribute('role', 'status')
23
+ indicator.setAttribute('aria-label', label)
24
+
25
+ const spinner = document.createElement('span')
26
+ spinner.className = 'oe-pending-paste__spinner'
27
+ spinner.setAttribute('aria-hidden', 'true')
28
+ indicator.appendChild(spinner)
29
+ return indicator
30
+ }
31
+
11
32
  /**
12
33
  * Extract plain text and HTML from a DOM Range.
13
34
  * @param {Range} range
@@ -118,6 +139,9 @@ export class Clipboard {
118
139
  /** @type {boolean} */
119
140
  #destroyed = false
120
141
 
142
+ /** @type {string} */
143
+ #pendingPasteLabel = 'Processing file'
144
+
121
145
  /**
122
146
  * @typedef {Object} ClipboardConfig
123
147
  * @property {import('../types').IBlockManager} blocks
@@ -133,6 +157,7 @@ export class Clipboard {
133
157
  * @property {import('../types').InlinePluginContext} inlinePluginCtx
134
158
  * @property {import('../Diagnostics').Diagnostics} [diagnostics]
135
159
  * @property {(() => boolean)} [uiActivePredicate]
160
+ * @property {string} [pendingPasteLabel]
136
161
  */
137
162
 
138
163
  /**
@@ -143,7 +168,7 @@ export class Clipboard {
143
168
  const {
144
169
  blocks, selection, plugins, defaultBlockType, crossBlockSelection,
145
170
  events, commands, blockOps, captureSnapshot, inlinePluginRegistry,
146
- inlinePluginCtx, diagnostics, uiActivePredicate,
171
+ inlinePluginCtx, diagnostics, uiActivePredicate, pendingPasteLabel,
147
172
  } = config
148
173
  this.#rootEl = rootEl
149
174
  this.#blocks = blocks
@@ -158,6 +183,7 @@ export class Clipboard {
158
183
  this.#inlinePluginRegistry = inlinePluginRegistry
159
184
  this.#inlinePluginCtx = inlinePluginCtx
160
185
  this.#isUIActive = uiActivePredicate ?? null
186
+ this.#pendingPasteLabel = pendingPasteLabel || this.#pendingPasteLabel
161
187
 
162
188
  this.#blockOps = blockOps
163
189
  this.#router = new PasteRouter(plugins.values())
@@ -248,10 +274,10 @@ export class Clipboard {
248
274
  const blocksData = selectedBlocks.map(block => canonical.get(block.id) ?? block.save())
249
275
  const html = selectedBlocks.map((b) => b.contentElement.innerHTML).join('\n')
250
276
  const text = selectedBlocks.map((b) => b.contentElement.textContent).join('\n')
251
- e.clipboardData?.setData('text/plain', text)
252
- e.clipboardData?.setData('text/html', html)
253
- e.clipboardData?.setData(MIME_TYPE, JSON.stringify(blocksData))
254
- }
277
+ e.clipboardData?.setData('text/plain', text)
278
+ e.clipboardData?.setData('text/html', html)
279
+ e.clipboardData?.setData(MIME_TYPE, JSON.stringify(blocksData))
280
+ }
255
281
 
256
282
  }
257
283
 
@@ -280,10 +306,10 @@ export class Clipboard {
280
306
  this.#selection.setCaretToBlock(focusBlock.id, 'start')
281
307
  }
282
308
  }
283
- } finally {
284
- this.#events.emit(EditorEvent.UNDO_BATCH_END)
285
- }
286
- }
309
+ } finally {
310
+ this.#events.emit(EditorEvent.UNDO_BATCH_END)
311
+ }
312
+ }
287
313
 
288
314
  }
289
315
 
@@ -555,21 +581,23 @@ export class Clipboard {
555
581
  const initialData = plugin.onPaste({ type: 'file', file })
556
582
  if (!initialData) return null
557
583
 
558
- element = plugin.render(initialData, {
559
- mutate: (operation) => operation(),
560
- splitBlock: () => {},
561
- exitEmptyBlock: () => false,
562
- readOnly: false,
563
- })
564
- if (!(element instanceof HTMLElement)) {
565
- console.error(`[Clipboard] File paste plugin "${plugin.type}" did not return an HTMLElement`)
566
- return null
584
+ element = plugin.render(initialData, {
585
+ mutate: (operation) => operation(),
586
+ splitBlock: () => {},
587
+ exitEmptyBlock: () => false,
588
+ readOnly: false,
589
+ })
590
+ if (!(element instanceof HTMLElement)) {
591
+ console.error(`[Clipboard] File paste plugin "${plugin.type}" did not return an HTMLElement`)
592
+ return null
567
593
  }
568
594
 
569
595
  shell = document.createElement('div')
570
596
  shell.className = 'oe-block oe-block--pending-paste'
571
597
  shell.dataset.blockType = plugin.type
572
- shell.appendChild(element)
598
+ shell.setAttribute('aria-busy', 'true')
599
+ element.hidden = true
600
+ shell.append(createPendingPasteIndicator(this.#pendingPasteLabel), element)
573
601
  pendingHost.appendChild(shell)
574
602
 
575
603
  let cleaned = false
@@ -590,11 +618,11 @@ export class Clipboard {
590
618
  await plugin.waitForPaste?.(element)
591
619
  if (this.#destroyed || pending.cancelled) return null
592
620
 
593
- const saved = plugin.save(element)
594
- if (!saved || typeof saved !== 'object' || Array.isArray(saved)) {
595
- console.error(`[Clipboard] File paste plugin "${plugin.type}" returned invalid data`)
596
- return null
597
- }
621
+ const saved = plugin.save(element)
622
+ if (!saved || typeof saved !== 'object' || Array.isArray(saved)) {
623
+ console.error(`[Clipboard] File paste plugin "${plugin.type}" returned invalid data`)
624
+ return null
625
+ }
598
626
  if (plugin.validate && !plugin.validate(saved)) return null
599
627
  return { type: plugin.type, data: cloneEditorData(saved) }
600
628
  } catch (error) {