@ebl-vue/editor-full 1.0.8

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 (101) hide show
  1. package/.postcssrc.yml +33 -0
  2. package/LICENSE +21 -0
  3. package/README.md +1 -0
  4. package/dist/index.d.ts +5 -0
  5. package/dist/index.mjs +2565 -0
  6. package/dist/index.mjs.map +1 -0
  7. package/package.json +55 -0
  8. package/postcss.config.js +15 -0
  9. package/src/components/Editor/Editor.vue +209 -0
  10. package/src/components/index.ts +27 -0
  11. package/src/constants/index.ts +1 -0
  12. package/src/i18n/zh-cn.ts +151 -0
  13. package/src/icons/index.ts +78 -0
  14. package/src/index.ts +11 -0
  15. package/src/installer.ts +22 -0
  16. package/src/plugins/alert/index.css +150 -0
  17. package/src/plugins/alert/index.ts +463 -0
  18. package/src/plugins/block-alignment/index.css +9 -0
  19. package/src/plugins/block-alignment/index.ts +116 -0
  20. package/src/plugins/block-alignment/readme.md +1 -0
  21. package/src/plugins/code/LICENSE +21 -0
  22. package/src/plugins/code/index.css +120 -0
  23. package/src/plugins/code/index.ts +530 -0
  24. package/src/plugins/code/utils/string.ts +34 -0
  25. package/src/plugins/color-picker/index.ts +138 -0
  26. package/src/plugins/color-picker/styles.css +27 -0
  27. package/src/plugins/delimiter/index.css +14 -0
  28. package/src/plugins/delimiter/index.ts +122 -0
  29. package/src/plugins/drag-drop/index.css +19 -0
  30. package/src/plugins/drag-drop/index.ts +151 -0
  31. package/src/plugins/drag-drop/readme.md +1 -0
  32. package/src/plugins/header/H1.ts +405 -0
  33. package/src/plugins/header/H2.ts +403 -0
  34. package/src/plugins/header/H3.ts +404 -0
  35. package/src/plugins/header/H4.ts +405 -0
  36. package/src/plugins/header/H5.ts +405 -0
  37. package/src/plugins/header/H6.ts +406 -0
  38. package/src/plugins/header/index.css +20 -0
  39. package/src/plugins/header/index.ts +15 -0
  40. package/src/plugins/header/types.d.ts +46 -0
  41. package/src/plugins/indent/index.css +86 -0
  42. package/src/plugins/indent/index.ts +697 -0
  43. package/src/plugins/inline-code/index.css +11 -0
  44. package/src/plugins/inline-code/index.ts +205 -0
  45. package/src/plugins/list/ListRenderer/ChecklistRenderer.ts +211 -0
  46. package/src/plugins/list/ListRenderer/ListRenderer.ts +73 -0
  47. package/src/plugins/list/ListRenderer/OrderedListRenderer.ts +123 -0
  48. package/src/plugins/list/ListRenderer/UnorderedListRenderer.ts +123 -0
  49. package/src/plugins/list/ListRenderer/index.ts +6 -0
  50. package/src/plugins/list/ListTabulator/index.ts +1179 -0
  51. package/src/plugins/list/index.ts +502 -0
  52. package/src/plugins/list/styles/CssPrefix.ts +4 -0
  53. package/src/plugins/list/styles/icons/index.ts +10 -0
  54. package/src/plugins/list/styles/input.css +36 -0
  55. package/src/plugins/list/styles/list.css +165 -0
  56. package/src/plugins/list/types/Elements.ts +14 -0
  57. package/src/plugins/list/types/ItemMeta.ts +40 -0
  58. package/src/plugins/list/types/ListParams.ts +102 -0
  59. package/src/plugins/list/types/ListRenderer.ts +6 -0
  60. package/src/plugins/list/types/OlCounterType.ts +63 -0
  61. package/src/plugins/list/types/index.ts +14 -0
  62. package/src/plugins/list/utils/focusItem.ts +18 -0
  63. package/src/plugins/list/utils/getChildItems.ts +40 -0
  64. package/src/plugins/list/utils/getItemChildWrapper.ts +10 -0
  65. package/src/plugins/list/utils/getItemContentElement.ts +10 -0
  66. package/src/plugins/list/utils/getSiblings.ts +52 -0
  67. package/src/plugins/list/utils/isLastItem.ts +9 -0
  68. package/src/plugins/list/utils/itemHasSublist.ts +10 -0
  69. package/src/plugins/list/utils/normalizeData.ts +84 -0
  70. package/src/plugins/list/utils/removeChildWrapperIfEmpty.ts +31 -0
  71. package/src/plugins/list/utils/renderToolboxInput.ts +105 -0
  72. package/src/plugins/list/utils/stripNumbers.ts +7 -0
  73. package/src/plugins/list/utils/type-guards.ts +8 -0
  74. package/src/plugins/list.md +15 -0
  75. package/src/plugins/marker/index.css +4 -0
  76. package/src/plugins/marker/index.ts +187 -0
  77. package/src/plugins/paragraph/index.css +23 -0
  78. package/src/plugins/paragraph/index.ts +380 -0
  79. package/src/plugins/paragraph/types/icons.d.ts +4 -0
  80. package/src/plugins/paragraph/utils/makeFragment.ts +17 -0
  81. package/src/plugins/quote/index.css +26 -0
  82. package/src/plugins/quote/index.ts +206 -0
  83. package/src/plugins/table/index.ts +4 -0
  84. package/src/plugins/table/plugin.ts +254 -0
  85. package/src/plugins/table/style.css +388 -0
  86. package/src/plugins/table/table.ts +1192 -0
  87. package/src/plugins/table/toolbox.ts +165 -0
  88. package/src/plugins/table/utils/dom.ts +128 -0
  89. package/src/plugins/table/utils/popover.ts +172 -0
  90. package/src/plugins/table/utils/throttled.ts +22 -0
  91. package/src/plugins/underline/index.css +3 -0
  92. package/src/plugins/underline/index.ts +216 -0
  93. package/src/plugins/undo/index.ts +509 -0
  94. package/src/plugins/undo/observer.ts +101 -0
  95. package/src/style.css +89 -0
  96. package/src/utils/index.ts +15 -0
  97. package/src/utils/install.ts +19 -0
  98. package/tsconfig.json +37 -0
  99. package/types/index.d.ts +13 -0
  100. package/types/plugins/index.d.ts +0 -0
  101. package/vite.config.ts +79 -0
@@ -0,0 +1,380 @@
1
+ /**
2
+ * Build styles
3
+ */
4
+ import './index.css';
5
+
6
+ import makeFragment from './utils/makeFragment';
7
+ import type { BlockToolConstructorOptions } from '@ebl-vue/editorjs';
8
+ export type ToolConstructorOptions = BlockToolConstructorOptions<ParagraphData>;
9
+
10
+
11
+ import type {
12
+ API,
13
+ ConversionConfig,
14
+ HTMLPasteEvent,
15
+ PasteConfig,
16
+ SanitizerConfig,
17
+ ToolConfig,
18
+ ToolboxConfig,
19
+ } from '@ebl-vue/editorjs';
20
+
21
+ /**
22
+ * Base Paragraph Block for the Editor.js.
23
+ * Represents a regular text block
24
+ *
25
+ * @author CodeX (team@codex.so)
26
+ * @copyright CodeX 2018
27
+ * @license The MIT License (MIT)
28
+ */
29
+
30
+ /**
31
+ * @typedef {object} ParagraphConfig
32
+ * @property {string} placeholder - placeholder for the empty paragraph
33
+ * @property {boolean} preserveBlank - Whether or not to keep blank paragraphs when saving editor data
34
+ */
35
+ export interface ParagraphConfig extends ToolConfig {
36
+ /**
37
+ * Placeholder for the empty paragraph
38
+ */
39
+ placeholder?: string;
40
+
41
+ /**
42
+ * Whether or not to keep blank paragraphs when saving editor data
43
+ */
44
+ preserveBlank?: boolean;
45
+ }
46
+
47
+ /**
48
+ * @typedef {object} ParagraphData
49
+ * @description Tool's input and output data format
50
+ * @property {string} text — Paragraph's content. Can include HTML tags: <a><b><i>
51
+ */
52
+ export interface ParagraphData {
53
+ /**
54
+ * Paragraph's content
55
+ */
56
+ text: string;
57
+ }
58
+
59
+ /**
60
+ * @typedef {object} ParagraphParams
61
+ * @description Constructor params for the Paragraph tool, use to pass initial data and settings
62
+ * @property {ParagraphData} data - Preload data for the paragraph.
63
+ * @property {ParagraphConfig} config - The configuration for the paragraph.
64
+ * @property {API} api - The Editor.js API.
65
+ * @property {boolean} readOnly - Is paragraph is read-only.
66
+ */
67
+ // interface ParagraphParams {
68
+ // /**
69
+ // * Initial data for the paragraph
70
+ // */
71
+ // data: ParagraphData;
72
+ // /**
73
+ // * Paragraph tool configuration
74
+ // */
75
+ // config: ParagraphConfig;
76
+ // /**
77
+ // * Editor.js API
78
+ // */
79
+ // api: API;
80
+ // /**
81
+ // * Is paragraph read-only.
82
+ // */
83
+ // readOnly: boolean;
84
+ // }
85
+
86
+ /**
87
+ * @typedef {object} ParagraphCSS
88
+ * @description CSS classes names
89
+ * @property {string} block - Editor.js CSS Class for block
90
+ * @property {string} wrapper - Paragraph CSS Class
91
+ */
92
+ interface ParagraphCSS {
93
+ /**
94
+ * Editor.js CSS Class for block
95
+ */
96
+ block: string;
97
+ /**
98
+ * Paragraph CSS Class
99
+ */
100
+ wrapper: string;
101
+ }
102
+
103
+ export default class Paragraph {
104
+ /**
105
+ * Default placeholder for Paragraph Tool
106
+ *
107
+ * @returns {string}
108
+ * @class
109
+ */
110
+ static get DEFAULT_PLACEHOLDER() {
111
+ return '';
112
+ }
113
+
114
+ /**
115
+ * The Editor.js API
116
+ */
117
+ api: API;
118
+
119
+ /**
120
+ * Is Paragraph Tool read-only
121
+ */
122
+ readOnly: boolean;
123
+
124
+ /**
125
+ * Paragraph Tool's CSS classes
126
+ */
127
+ private _CSS: ParagraphCSS;
128
+
129
+ /**
130
+ * Placeholder for Paragraph Tool
131
+ */
132
+ private _placeholder: string;
133
+
134
+ /**
135
+ * Paragraph's data
136
+ */
137
+ private _data: ParagraphData;
138
+
139
+ /**
140
+ * Paragraph's main Element
141
+ */
142
+ private _element: HTMLDivElement | null;
143
+
144
+ /**
145
+ * Whether or not to keep blank paragraphs when saving editor data
146
+ */
147
+ private _preserveBlank: boolean;
148
+
149
+ /**
150
+ * Render plugin`s main Element and fill it with saved data
151
+ *
152
+ * @param {object} params - constructor params
153
+ * @param {ParagraphData} params.data - previously saved data
154
+ * @param {ParagraphConfig} params.config - user config for Tool
155
+ * @param {object} params.api - editor.js api
156
+ * @param {boolean} readOnly - read only mode flag
157
+ */
158
+ constructor({ data, config, api, readOnly }: ToolConstructorOptions) {
159
+ this.api = api;
160
+ this.readOnly = readOnly;
161
+
162
+ this._CSS = {
163
+ block: this.api.styles.block,
164
+ wrapper: 'ce-paragraph',
165
+ };
166
+
167
+ if (!this.readOnly) {
168
+ this.onKeyUp = this.onKeyUp.bind(this);
169
+ }
170
+
171
+ /**
172
+ * Placeholder for paragraph if it is first Block
173
+ *
174
+ * @type {string}
175
+ */
176
+ this._placeholder = config.placeholder
177
+ ? config.placeholder
178
+ : Paragraph.DEFAULT_PLACEHOLDER;
179
+ this._data = data ?? {};
180
+ this._element = null;
181
+ this._preserveBlank = config.preserveBlank ?? false;
182
+ }
183
+
184
+ /**
185
+ * Check if text content is empty and set empty string to inner html.
186
+ * We need this because some browsers (e.g. Safari) insert <br> into empty contenteditanle elements
187
+ *
188
+ * @param {KeyboardEvent} e - key up event
189
+ */
190
+ onKeyUp(e: KeyboardEvent): void {
191
+ if (e.code !== 'Backspace' && e.code !== 'Delete') {
192
+ return;
193
+ }
194
+
195
+ if (!this._element) {
196
+ return;
197
+ }
198
+
199
+ const { textContent } = this._element;
200
+
201
+ if (textContent === '') {
202
+ this._element.innerHTML = '';
203
+ }
204
+ }
205
+
206
+ /**
207
+ * Create Tool's view
208
+ *
209
+ * @returns {HTMLDivElement}
210
+ * @private
211
+ */
212
+ drawView(): HTMLDivElement {
213
+ const div = document.createElement('DIV');
214
+
215
+ div.classList.add(this._CSS.wrapper, this._CSS.block);
216
+ div.contentEditable = 'false';
217
+ div.dataset.placeholderActive = this.api.i18n.t(this._placeholder);
218
+
219
+ if (this._data.text) {
220
+ div.innerHTML = this._data.text;
221
+ }
222
+
223
+ if (!this.readOnly) {
224
+ div.contentEditable = 'true';
225
+ div.addEventListener('keyup', this.onKeyUp);
226
+ }
227
+
228
+ /**
229
+ * bypass property 'align' required in html div element
230
+ */
231
+ return div as HTMLDivElement;
232
+ }
233
+
234
+ /**
235
+ * Return Tool's view
236
+ *
237
+ * @returns {HTMLDivElement}
238
+ */
239
+ render(): HTMLDivElement {
240
+ this._element = this.drawView();
241
+
242
+ return this._element;
243
+ }
244
+
245
+
246
+
247
+ /**
248
+ * Method that specified how to merge two Text blocks.
249
+ * Called by Editor.js by backspace at the beginning of the Block
250
+ *
251
+ * @param {ParagraphData} data
252
+ * @public
253
+ */
254
+ merge(data: ParagraphData): void {
255
+ if (!this._element) {
256
+ return;
257
+ }
258
+
259
+ this._data.text += data.text;
260
+
261
+ /**
262
+ * We use appendChild instead of innerHTML to keep the links of the existing nodes
263
+ * (for example, shadow caret)
264
+ */
265
+ const fragment = makeFragment(data.text);
266
+
267
+ this._element.appendChild(fragment);
268
+
269
+ this._element.normalize();
270
+ }
271
+
272
+ /**
273
+ * Validate Paragraph block data:
274
+ * - check for emptiness
275
+ *
276
+ * @param {ParagraphData} savedData — data received after saving
277
+ * @returns {boolean} false if saved data is not correct, otherwise true
278
+ * @public
279
+ */
280
+ validate(savedData: ParagraphData): boolean {
281
+ if (savedData.text.trim() === '' && !this._preserveBlank) {
282
+ return false;
283
+ }
284
+
285
+ return true;
286
+ }
287
+
288
+ /**
289
+ * Extract Tool's data from the view
290
+ *
291
+ * @param {HTMLDivElement} toolsContent - Paragraph tools rendered view
292
+ * @returns {ParagraphData} - saved data
293
+ * @public
294
+ */
295
+ save(toolsContent: HTMLDivElement): ParagraphData {
296
+ return {
297
+ text: toolsContent.innerHTML,
298
+ };
299
+ }
300
+
301
+ /**
302
+ * On paste callback fired from Editor.
303
+ *
304
+ * @param {HTMLPasteEvent} event - event with pasted data
305
+ */
306
+ onPaste(event: HTMLPasteEvent): void {
307
+ const data = {
308
+ text: event.detail.data.innerHTML,
309
+ };
310
+
311
+ this._data = data;
312
+
313
+ /**
314
+ * We use requestAnimationFrame for performance purposes
315
+ */
316
+ window.requestAnimationFrame(() => {
317
+ if (!this._element) {
318
+ return;
319
+ }
320
+ this._element.innerHTML = this._data.text || '';
321
+ });
322
+ }
323
+
324
+ /**
325
+ * Enable Conversion Toolbar. Paragraph can be converted to/from other tools
326
+ * @returns {ConversionConfig}
327
+ */
328
+ static get conversionConfig(): ConversionConfig {
329
+ return {
330
+ export: 'text', // to convert Paragraph to other block, use 'text' property of saved data
331
+ import: 'text', // to covert other block's exported string to Paragraph, fill 'text' property of tool data
332
+ };
333
+ }
334
+
335
+ /**
336
+ * Sanitizer rules
337
+ * @returns {SanitizerConfig} - Edtior.js sanitizer config
338
+ */
339
+ static get sanitize(): SanitizerConfig {
340
+ return {
341
+ text: {
342
+ br: true,
343
+ },
344
+ };
345
+ }
346
+
347
+ /**
348
+ * Returns true to notify the core that read-only mode is supported
349
+ *
350
+ * @returns {boolean}
351
+ */
352
+ static get isReadOnlySupported(): boolean {
353
+ return true;
354
+ }
355
+
356
+ /**
357
+ * Used by Editor paste handling API.
358
+ * Provides configuration to handle P tags.
359
+ *
360
+ * @returns {PasteConfig} - Paragraph Paste Setting
361
+ */
362
+ static get pasteConfig(): PasteConfig {
363
+ return {
364
+ tags: ['P'],
365
+ };
366
+ }
367
+
368
+ /**
369
+ * Icon and title for displaying at the Toolbox
370
+ *
371
+ * @returns {ToolboxConfig} - Paragraph Toolbox Setting
372
+ */
373
+ static get toolbox(): ToolboxConfig {
374
+ return {
375
+ icon: `<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="none" viewBox="0 0 24 24"><path stroke="currentColor" stroke-linecap="round" stroke-width="2" d="M8 9V7.2C8 7.08954 8.08954 7 8.2 7L12 7M16 9V7.2C16 7.08954 15.9105 7 15.8 7L12 7M12 7L12 17M12 17H10M12 17H14"/></svg>`,
376
+ title: 'Text',
377
+
378
+ };
379
+ }
380
+ }
@@ -0,0 +1,4 @@
1
+ // temporary fix for the missing types
2
+ declare module "@codexteam/icons" {
3
+ export const IconText: string;
4
+ }
@@ -0,0 +1,17 @@
1
+ /**
2
+ * Create a DocumentFragment and fill it with HTML from a string
3
+ *
4
+ * @param {string} htmlString - A string of valid HTML
5
+ * @returns {DocumentFragment}
6
+ */
7
+ export default function makeFragment(htmlString: string): DocumentFragment {
8
+ const tempDiv = document.createElement('div');
9
+
10
+ tempDiv.innerHTML = htmlString.trim();
11
+
12
+ const fragment = document.createDocumentFragment();
13
+
14
+ fragment.append(...Array.from(tempDiv.childNodes));
15
+
16
+ return fragment;
17
+ }
@@ -0,0 +1,26 @@
1
+
2
+ .cdx-quote {
3
+ overflow: hidden;
4
+ overflow-wrap: break-word;
5
+ margin: 0;
6
+ box-sizing: border-box;
7
+ word-wrap: break-word;
8
+ word-break: break-all;
9
+ }
10
+ .cdx-quote blockquote{
11
+ margin: 0;
12
+ }
13
+
14
+
15
+
16
+
17
+ .cdx-block-quote{
18
+ border: solid #acacac;
19
+ border-width: 0 0 0 3px;
20
+ box-shadow: none;
21
+ color: #666;
22
+ line-height: 1.6em;
23
+ padding: 1px 0 0 12px;
24
+ text-align: left;
25
+ }
26
+
@@ -0,0 +1,206 @@
1
+ import "./index.css";
2
+
3
+
4
+ import { make } from "@editorjs/dom";
5
+ import type { API, BlockAPI, BlockTool } from "@ebl-vue/editorjs";
6
+
7
+
8
+ const IconQuote = `<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
9
+ <path d="M10 10.8182L9 10.8182C8.80222 10.8182 8.60888 10.7649 8.44443 10.665C8.27998 10.5651 8.15181 10.4231 8.07612 10.257C8.00043 10.0909 7.98063 9.90808 8.01922 9.73174C8.0578 9.55539 8.15304 9.39341 8.29289 9.26627C8.43275 9.13913 8.61093 9.05255 8.80491 9.01747C8.99889 8.98239 9.19996 9.00039 9.38268 9.0692C9.56541 9.13801 9.72159 9.25453 9.83147 9.40403C9.94135 9.55353 10 9.72929 10 9.90909L10 12.1818C10 12.664 9.78929 13.1265 9.41421 13.4675C9.03914 13.8084 8.53043 14 8 14" stroke="black" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
10
+ <path d="M16 10.8182L15 10.8182C14.8022 10.8182 14.6089 10.7649 14.4444 10.665C14.28 10.5651 14.1518 10.4231 14.0761 10.257C14.0004 10.0909 13.9806 9.90808 14.0192 9.73174C14.0578 9.55539 14.153 9.39341 14.2929 9.26627C14.4327 9.13913 14.6109 9.05255 14.8049 9.01747C14.9989 8.98239 15.2 9.00039 15.3827 9.0692C15.5654 9.13801 15.7216 9.25453 15.8315 9.40403C15.9414 9.55353 16 9.72929 16 9.90909L16 12.1818C16 12.664 15.7893 13.1265 15.4142 13.4675C15.0391 13.8084 14.5304 14 14 14" stroke="black" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
11
+ </svg>`;
12
+
13
+
14
+
15
+ /**
16
+ * Data structure for the Quote block.
17
+ */
18
+ export interface QuoteData {
19
+ text: string;
20
+ }
21
+
22
+ /**
23
+ * Parameters for the Quote constructor.
24
+ */
25
+ interface QuoteParams {
26
+ data: QuoteData;
27
+ api: API;
28
+ readOnly: boolean;
29
+ block: BlockAPI;
30
+ }
31
+
32
+ /**
33
+ * CSS class names used in the Quote block.
34
+ */
35
+ interface QuoteCSS {
36
+ baseClass: string;
37
+ wrapper: string;
38
+ input: string;
39
+ text: string;
40
+ }
41
+
42
+
43
+
44
+ /**
45
+ * Quote class representing a customizable quote block for Editor.js.
46
+ */
47
+ export default class Quote implements BlockTool {
48
+ api: API;
49
+ readOnly: boolean;
50
+
51
+
52
+ private _data: QuoteData;
53
+ private _CSS: QuoteCSS;
54
+ private _quoteElement!: HTMLElement;
55
+
56
+ /**
57
+ * Creates an instance of the Quote block.
58
+ * @param params - The parameters for the Quote block.
59
+ */
60
+ constructor({ data, api, readOnly }: QuoteParams) {
61
+
62
+
63
+ this.api = api;
64
+ this.readOnly = readOnly;
65
+
66
+ this._data = {
67
+ text: data.text || ""
68
+ };
69
+
70
+ this._CSS = {
71
+ baseClass: this.api.styles.block,
72
+ wrapper: "cdx-quote",
73
+ text: "cdx-quote__text",
74
+ input: this.api.styles.input,
75
+ };
76
+
77
+ }
78
+
79
+ static get isReadOnlySupported(): boolean {
80
+ return true;
81
+ }
82
+
83
+ static get toolbox() {
84
+ return {
85
+ icon: IconQuote,
86
+ title: "Quote",
87
+ };
88
+ }
89
+
90
+ static get contentless(): boolean {
91
+ return true;
92
+ }
93
+
94
+ static get enableLineBreaks(): boolean {
95
+ return true;
96
+ }
97
+
98
+
99
+
100
+ static get conversionConfig() {
101
+ return {
102
+ import: "text",
103
+
104
+ export: function (quoteData: QuoteData): string {
105
+ return quoteData.text;
106
+ },
107
+ };
108
+ }
109
+
110
+
111
+ get CSS(): QuoteCSS {
112
+ return {
113
+ baseClass: this.api.styles.block,
114
+ wrapper: "cdx-quote",
115
+ text: "cdx-quote__text",
116
+ input: this.api.styles.input,
117
+ };
118
+ }
119
+
120
+
121
+
122
+ render(): HTMLElement {
123
+ const container = make("div", [this._CSS.baseClass, this._CSS.wrapper]);
124
+ this._quoteElement = make(
125
+ "blockquote",
126
+ [this._CSS.input, this._CSS.text, "cdx-block-quote"],
127
+ {
128
+ contentEditable: !this.readOnly,
129
+ innerHTML: this._data.text,
130
+ }
131
+ );
132
+
133
+ this._quoteElement.addEventListener("keydown", (event: KeyboardEvent) =>
134
+ this.handleKeydown(event)
135
+ );
136
+
137
+ container.appendChild(this._quoteElement);
138
+ return container;
139
+ }
140
+
141
+
142
+ get currentItem(): HTMLElement {
143
+ let currentNode = window.getSelection()!.anchorNode;
144
+
145
+ if (currentNode!.nodeType !== Node.ELEMENT_NODE) {
146
+ currentNode = currentNode!.parentNode;
147
+ }
148
+
149
+ return (currentNode as Element).closest(`.${this.CSS.text}`) as HTMLElement;
150
+ }
151
+
152
+
153
+ handleKeydown(event: KeyboardEvent) {
154
+ const currentItem = this._quoteElement;
155
+
156
+ if (event.key === "Enter") {
157
+ if (!event.shiftKey) {
158
+ event.preventDefault();
159
+ this.getOutOfQuote();
160
+ }
161
+ }
162
+
163
+ if (
164
+ event.key === "Backspace" &&
165
+ currentItem.textContent?.trim().length === 0
166
+ ) {
167
+ event.preventDefault();
168
+
169
+ const currentBlockIndex = this.api.blocks.getCurrentBlockIndex();
170
+ this.api.blocks.delete(currentBlockIndex);
171
+ this.api.blocks.insert("paragraph", { text: "" });
172
+ this.api.caret.setToBlock(currentBlockIndex);
173
+
174
+ return;
175
+ }
176
+ }
177
+
178
+
179
+ getOutOfQuote() {
180
+ this.api.blocks.insert();
181
+ this.api.caret.setToBlock(this.api.blocks.getCurrentBlockIndex());
182
+ }
183
+
184
+
185
+
186
+
187
+ save(quoteElement: HTMLDivElement): QuoteData {
188
+ const text = quoteElement.querySelector(`.${this._CSS.text}`);
189
+
190
+ return Object.assign(this._data, {
191
+ text: text?.innerHTML ?? "",
192
+ });
193
+ }
194
+
195
+ static get sanitize() {
196
+ return {
197
+ text: {
198
+ br: true,
199
+ },
200
+ };
201
+ }
202
+
203
+
204
+
205
+
206
+ }
@@ -0,0 +1,4 @@
1
+ import Plugin from './plugin';
2
+ import './style.css';
3
+
4
+ export default Plugin;