@ckeditor/ckeditor5-enter 48.8.1-alpha.4 → 49.0.0-alpha.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (161) hide show
  1. package/dist/augmentation.d.ts +13 -13
  2. package/dist/enter.d.ts +21 -21
  3. package/dist/entercommand.d.ts +44 -44
  4. package/dist/enterobserver.d.ts +34 -34
  5. package/dist/index-content.css +3 -0
  6. package/dist/index-content.css.map +1 -0
  7. package/dist/index-editor.css +3 -0
  8. package/dist/index-editor.css.map +1 -0
  9. package/dist/index.d.ts +12 -12
  10. package/dist/index.js +347 -393
  11. package/dist/index.js.map +1 -1
  12. package/dist/shiftenter.d.ts +19 -19
  13. package/dist/shiftentercommand.d.ts +26 -26
  14. package/dist/translations/af.js +1 -1
  15. package/dist/translations/af.umd.js +5 -3
  16. package/dist/translations/ar.js +1 -1
  17. package/dist/translations/ar.umd.js +5 -3
  18. package/dist/translations/ast.js +1 -1
  19. package/dist/translations/ast.umd.js +5 -3
  20. package/dist/translations/az.js +1 -1
  21. package/dist/translations/az.umd.js +5 -3
  22. package/dist/translations/be.js +1 -1
  23. package/dist/translations/be.umd.js +5 -3
  24. package/dist/translations/bg.js +1 -1
  25. package/dist/translations/bg.umd.js +5 -3
  26. package/dist/translations/bn.js +1 -1
  27. package/dist/translations/bn.umd.js +5 -3
  28. package/dist/translations/bs.js +1 -1
  29. package/dist/translations/bs.umd.js +5 -3
  30. package/dist/translations/ca.js +1 -1
  31. package/dist/translations/ca.umd.js +5 -3
  32. package/dist/translations/cs.js +1 -1
  33. package/dist/translations/cs.umd.js +5 -3
  34. package/dist/translations/da.js +1 -1
  35. package/dist/translations/da.umd.js +5 -3
  36. package/dist/translations/de-ch.js +1 -1
  37. package/dist/translations/de-ch.umd.js +5 -3
  38. package/dist/translations/de.js +1 -1
  39. package/dist/translations/de.umd.js +5 -3
  40. package/dist/translations/el.js +1 -1
  41. package/dist/translations/el.umd.js +5 -3
  42. package/dist/translations/en-au.js +1 -1
  43. package/dist/translations/en-au.umd.js +5 -3
  44. package/dist/translations/en-gb.js +1 -1
  45. package/dist/translations/en-gb.umd.js +5 -3
  46. package/dist/translations/en.js +1 -1
  47. package/dist/translations/en.umd.js +5 -3
  48. package/dist/translations/eo.js +1 -1
  49. package/dist/translations/eo.umd.js +5 -3
  50. package/dist/translations/es-co.js +1 -1
  51. package/dist/translations/es-co.umd.js +5 -3
  52. package/dist/translations/es.js +1 -1
  53. package/dist/translations/es.umd.js +5 -3
  54. package/dist/translations/et.js +1 -1
  55. package/dist/translations/et.umd.js +5 -3
  56. package/dist/translations/eu.js +1 -1
  57. package/dist/translations/eu.umd.js +5 -3
  58. package/dist/translations/fa.js +1 -1
  59. package/dist/translations/fa.umd.js +5 -3
  60. package/dist/translations/fi.js +1 -1
  61. package/dist/translations/fi.umd.js +5 -3
  62. package/dist/translations/fr.js +1 -1
  63. package/dist/translations/fr.umd.js +5 -3
  64. package/dist/translations/gl.js +1 -1
  65. package/dist/translations/gl.umd.js +5 -3
  66. package/dist/translations/gu.js +1 -1
  67. package/dist/translations/gu.umd.js +5 -3
  68. package/dist/translations/he.js +1 -1
  69. package/dist/translations/he.umd.js +5 -3
  70. package/dist/translations/hi.js +1 -1
  71. package/dist/translations/hi.umd.js +5 -3
  72. package/dist/translations/hr.js +1 -1
  73. package/dist/translations/hr.umd.js +5 -3
  74. package/dist/translations/hu.js +1 -1
  75. package/dist/translations/hu.umd.js +5 -3
  76. package/dist/translations/hy.js +1 -1
  77. package/dist/translations/hy.umd.js +5 -3
  78. package/dist/translations/id.js +1 -1
  79. package/dist/translations/id.umd.js +5 -3
  80. package/dist/translations/it.js +1 -1
  81. package/dist/translations/it.umd.js +5 -3
  82. package/dist/translations/ja.js +1 -1
  83. package/dist/translations/ja.umd.js +5 -3
  84. package/dist/translations/jv.js +1 -1
  85. package/dist/translations/jv.umd.js +5 -3
  86. package/dist/translations/kk.js +1 -1
  87. package/dist/translations/kk.umd.js +5 -3
  88. package/dist/translations/km.js +1 -1
  89. package/dist/translations/km.umd.js +5 -3
  90. package/dist/translations/kn.js +1 -1
  91. package/dist/translations/kn.umd.js +5 -3
  92. package/dist/translations/ko.js +1 -1
  93. package/dist/translations/ko.umd.js +5 -3
  94. package/dist/translations/ku.js +1 -1
  95. package/dist/translations/ku.umd.js +5 -3
  96. package/dist/translations/lt.js +1 -1
  97. package/dist/translations/lt.umd.js +5 -3
  98. package/dist/translations/lv.js +1 -1
  99. package/dist/translations/lv.umd.js +5 -3
  100. package/dist/translations/ms.js +1 -1
  101. package/dist/translations/ms.umd.js +5 -3
  102. package/dist/translations/nb.js +1 -1
  103. package/dist/translations/nb.umd.js +5 -3
  104. package/dist/translations/ne.js +1 -1
  105. package/dist/translations/ne.umd.js +5 -3
  106. package/dist/translations/nl.js +1 -1
  107. package/dist/translations/nl.umd.js +5 -3
  108. package/dist/translations/no.js +1 -1
  109. package/dist/translations/no.umd.js +5 -3
  110. package/dist/translations/oc.js +1 -1
  111. package/dist/translations/oc.umd.js +5 -3
  112. package/dist/translations/pl.js +1 -1
  113. package/dist/translations/pl.umd.js +5 -3
  114. package/dist/translations/pt-br.js +1 -1
  115. package/dist/translations/pt-br.umd.js +5 -3
  116. package/dist/translations/pt.js +1 -1
  117. package/dist/translations/pt.umd.js +5 -3
  118. package/dist/translations/ro.js +1 -1
  119. package/dist/translations/ro.umd.js +5 -3
  120. package/dist/translations/ru.js +1 -1
  121. package/dist/translations/ru.umd.js +5 -3
  122. package/dist/translations/si.js +1 -1
  123. package/dist/translations/si.umd.js +5 -3
  124. package/dist/translations/sk.js +1 -1
  125. package/dist/translations/sk.umd.js +5 -3
  126. package/dist/translations/sl.js +1 -1
  127. package/dist/translations/sl.umd.js +5 -3
  128. package/dist/translations/sq.js +1 -1
  129. package/dist/translations/sq.umd.js +5 -3
  130. package/dist/translations/sr-latn.js +1 -1
  131. package/dist/translations/sr-latn.umd.js +5 -3
  132. package/dist/translations/sr.js +1 -1
  133. package/dist/translations/sr.umd.js +5 -3
  134. package/dist/translations/sv.js +1 -1
  135. package/dist/translations/sv.umd.js +5 -3
  136. package/dist/translations/th.js +1 -1
  137. package/dist/translations/th.umd.js +5 -3
  138. package/dist/translations/ti.js +1 -1
  139. package/dist/translations/ti.umd.js +5 -3
  140. package/dist/translations/tk.js +1 -1
  141. package/dist/translations/tk.umd.js +5 -3
  142. package/dist/translations/tr.js +1 -1
  143. package/dist/translations/tr.umd.js +5 -3
  144. package/dist/translations/tt.js +1 -1
  145. package/dist/translations/tt.umd.js +5 -3
  146. package/dist/translations/ug.js +1 -1
  147. package/dist/translations/ug.umd.js +5 -3
  148. package/dist/translations/uk.js +1 -1
  149. package/dist/translations/uk.umd.js +5 -3
  150. package/dist/translations/ur.js +1 -1
  151. package/dist/translations/ur.umd.js +5 -3
  152. package/dist/translations/uz.js +1 -1
  153. package/dist/translations/uz.umd.js +5 -3
  154. package/dist/translations/vi.js +1 -1
  155. package/dist/translations/vi.umd.js +5 -3
  156. package/dist/translations/zh-cn.js +1 -1
  157. package/dist/translations/zh-cn.umd.js +5 -3
  158. package/dist/translations/zh.js +1 -1
  159. package/dist/translations/zh.umd.js +5 -3
  160. package/dist/utils.d.ts +15 -15
  161. package/package.json +4 -4
package/dist/index.js CHANGED
@@ -2,427 +2,381 @@
2
2
  * @license Copyright (c) 2003-2026, CKSource Holding sp. z o.o. All rights reserved.
3
3
  * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-licensing-options
4
4
  */
5
- import { Command, Plugin } from '@ckeditor/ckeditor5-core/dist/index.js';
6
- import { Observer, BubblingEventInfo, ViewDocumentDomEventData } from '@ckeditor/ckeditor5-engine/dist/index.js';
7
- import { env } from '@ckeditor/ckeditor5-utils/dist/index.js';
5
+ import { Command, Plugin } from "@ckeditor/ckeditor5-core";
6
+ import { BubblingEventInfo, Observer, ViewDocumentDomEventData } from "@ckeditor/ckeditor5-engine";
7
+ import { env } from "@ckeditor/ckeditor5-utils";
8
8
 
9
9
  /**
10
- * @license Copyright (c) 2003-2026, CKSource Holding sp. z o.o. All rights reserved.
11
- * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-licensing-options
12
- */ /**
13
- * @module enter/utils
14
- */ /**
15
- * Returns attributes that should be preserved on the enter keystroke.
16
- *
17
- * Filtering is realized based on `copyOnEnter` attribute property. Read more about attribute properties
18
- * {@link module:engine/model/schema~ModelSchema#setAttributeProperties here}.
19
- *
20
- * @param schema Model's schema.
21
- * @param allAttributes Attributes to filter.
22
- * @internal
23
- */ function* getCopyOnEnterAttributes(schema, allAttributes) {
24
- for (const attribute of allAttributes){
25
- if (attribute && schema.getAttributeProperties(attribute[0]).copyOnEnter) {
26
- yield attribute;
27
- }
28
- }
10
+ * @license Copyright (c) 2003-2026, CKSource Holding sp. z o.o. All rights reserved.
11
+ * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-licensing-options
12
+ */
13
+ /**
14
+ * Returns attributes that should be preserved on the enter keystroke.
15
+ *
16
+ * Filtering is realized based on `copyOnEnter` attribute property. Read more about attribute properties
17
+ * {@link module:engine/model/schema~ModelSchema#setAttributeProperties here}.
18
+ *
19
+ * @param schema Model's schema.
20
+ * @param allAttributes Attributes to filter.
21
+ * @internal
22
+ */
23
+ function* getCopyOnEnterAttributes(schema, allAttributes) {
24
+ for (const attribute of allAttributes) if (attribute && schema.getAttributeProperties(attribute[0]).copyOnEnter) yield attribute;
29
25
  }
30
26
 
31
27
  /**
32
- * Enter command used by the {@link module:enter/enter~Enter Enter feature} to handle the <kbd>Enter</kbd> keystroke.
33
- */ class EnterCommand extends Command {
34
- /**
35
- * @inheritDoc
36
- */ execute() {
37
- this.editor.model.change((writer)=>{
38
- this.enterBlock(writer);
39
- this.fire('afterExecute', {
40
- writer
41
- });
42
- });
43
- }
44
- /**
45
- * Splits a block where the document selection is placed, in the way how the <kbd>Enter</kbd> key is expected to work:
46
- *
47
- * ```
48
- * <p>Foo[]bar</p> -> <p>Foo</p><p>[]bar</p>
49
- * <p>Foobar[]</p> -> <p>Foobar</p><p>[]</p>
50
- * <p>Fo[ob]ar</p> -> <p>Fo</p><p>[]ar</p>
51
- * ```
52
- *
53
- * In some cases, the split will not happen:
54
- *
55
- * ```
56
- * // The selection parent is a limit element:
57
- * <figcaption>A[bc]d</figcaption> -> <figcaption>A[]d</figcaption>
58
- *
59
- * // The selection spans over multiple elements:
60
- * <h>x[x</h><p>y]y<p> -> <h>x</h><p>[]y</p>
61
- * ```
62
- *
63
- * @param writer Writer to use when performing the enter action.
64
- * @returns Boolean indicating if the block was split.
65
- */ enterBlock(writer) {
66
- const model = this.editor.model;
67
- const selection = model.document.selection;
68
- const schema = model.schema;
69
- const isSelectionEmpty = selection.isCollapsed;
70
- const range = selection.getFirstRange();
71
- const startElement = range.start.parent;
72
- const endElement = range.end.parent;
73
- // Don't touch the roots and other limit elements.
74
- if (schema.isLimit(startElement) || schema.isLimit(endElement)) {
75
- // Delete the selected content but only if inside a single limit element.
76
- // Abort, when crossing limit elements boundary (e.g. <limit1>x[x</limit1>donttouchme<limit2>y]y</limit2>).
77
- // This is an edge case and it's hard to tell what should actually happen because such a selection
78
- // is not entirely valid.
79
- if (!isSelectionEmpty && startElement == endElement) {
80
- model.deleteContent(selection);
81
- }
82
- return false;
83
- }
84
- if (isSelectionEmpty) {
85
- const attributesToCopy = getCopyOnEnterAttributes(writer.model.schema, selection.getAttributes());
86
- splitBlock(writer, range.start);
87
- writer.setSelectionAttribute(attributesToCopy);
88
- return true;
89
- } else {
90
- const leaveUnmerged = !(range.start.isAtStart && range.end.isAtEnd);
91
- const isContainedWithinOneElement = startElement == endElement;
92
- model.deleteContent(selection, {
93
- leaveUnmerged
94
- });
95
- if (leaveUnmerged) {
96
- // Partially selected elements.
97
- //
98
- // <h>x[xx]x</h> -> <h>x^x</h> -> <h>x</h><h>^x</h>
99
- if (isContainedWithinOneElement) {
100
- splitBlock(writer, selection.focus);
101
- return true;
102
- } else {
103
- writer.setSelection(endElement, 0);
104
- }
105
- }
106
- }
107
- return false;
108
- }
109
- }
28
+ * @license Copyright (c) 2003-2026, CKSource Holding sp. z o.o. All rights reserved.
29
+ * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-licensing-options
30
+ */
31
+ /**
32
+ * @module enter/entercommand
33
+ */
34
+ /**
35
+ * Enter command used by the {@link module:enter/enter~Enter Enter feature} to handle the <kbd>Enter</kbd> keystroke.
36
+ */
37
+ var EnterCommand = class extends Command {
38
+ /**
39
+ * @inheritDoc
40
+ */
41
+ execute() {
42
+ this.editor.model.change((writer) => {
43
+ this.enterBlock(writer);
44
+ this.fire("afterExecute", { writer });
45
+ });
46
+ }
47
+ /**
48
+ * Splits a block where the document selection is placed, in the way how the <kbd>Enter</kbd> key is expected to work:
49
+ *
50
+ * ```
51
+ * <p>Foo[]bar</p> -> <p>Foo</p><p>[]bar</p>
52
+ * <p>Foobar[]</p> -> <p>Foobar</p><p>[]</p>
53
+ * <p>Fo[ob]ar</p> -> <p>Fo</p><p>[]ar</p>
54
+ * ```
55
+ *
56
+ * In some cases, the split will not happen:
57
+ *
58
+ * ```
59
+ * // The selection parent is a limit element:
60
+ * <figcaption>A[bc]d</figcaption> -> <figcaption>A[]d</figcaption>
61
+ *
62
+ * // The selection spans over multiple elements:
63
+ * <h>x[x</h><p>y]y<p> -> <h>x</h><p>[]y</p>
64
+ * ```
65
+ *
66
+ * @param writer Writer to use when performing the enter action.
67
+ * @returns Boolean indicating if the block was split.
68
+ */
69
+ enterBlock(writer) {
70
+ const model = this.editor.model;
71
+ const selection = model.document.selection;
72
+ const schema = model.schema;
73
+ const isSelectionEmpty = selection.isCollapsed;
74
+ const range = selection.getFirstRange();
75
+ const startElement = range.start.parent;
76
+ const endElement = range.end.parent;
77
+ if (schema.isLimit(startElement) || schema.isLimit(endElement)) {
78
+ if (!isSelectionEmpty && startElement == endElement) model.deleteContent(selection);
79
+ return false;
80
+ }
81
+ if (isSelectionEmpty) {
82
+ const attributesToCopy = getCopyOnEnterAttributes(writer.model.schema, selection.getAttributes());
83
+ splitBlock(writer, range.start);
84
+ writer.setSelectionAttribute(attributesToCopy);
85
+ return true;
86
+ } else {
87
+ const leaveUnmerged = !(range.start.isAtStart && range.end.isAtEnd);
88
+ const isContainedWithinOneElement = startElement == endElement;
89
+ model.deleteContent(selection, { leaveUnmerged });
90
+ if (leaveUnmerged) {
91
+ if (isContainedWithinOneElement) {
92
+ splitBlock(writer, selection.focus);
93
+ return true;
94
+ } else writer.setSelection(endElement, 0);
95
+ }
96
+ }
97
+ return false;
98
+ }
99
+ };
110
100
  function splitBlock(writer, splitPos) {
111
- writer.split(splitPos);
112
- writer.setSelection(splitPos.parent.nextSibling, 0);
101
+ writer.split(splitPos);
102
+ writer.setSelection(splitPos.parent.nextSibling, 0);
113
103
  }
114
104
 
105
+ /**
106
+ * @license Copyright (c) 2003-2026, CKSource Holding sp. z o.o. All rights reserved.
107
+ * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-licensing-options
108
+ */
109
+ /**
110
+ * @module enter/enterobserver
111
+ */
115
112
  const ENTER_EVENT_TYPES = {
116
- insertParagraph: {
117
- isSoft: false
118
- },
119
- insertLineBreak: {
120
- isSoft: true
121
- }
113
+ insertParagraph: { isSoft: false },
114
+ insertLineBreak: { isSoft: true }
122
115
  };
123
116
  /**
124
- * Enter observer introduces the {@link module:engine/view/document~ViewDocument#event:enter `Document#enter`} event.
125
- */ class EnterObserver extends Observer {
126
- /**
127
- * @inheritDoc
128
- */ constructor(view){
129
- super(view);
130
- const doc = this.document;
131
- let shiftPressed = false;
132
- doc.on('keydown', (evt, data)=>{
133
- shiftPressed = data.shiftKey;
134
- });
135
- doc.on('beforeinput', (evt, data)=>{
136
- if (!this.isEnabled) {
137
- return;
138
- }
139
- let inputType = data.inputType;
140
- // See https://github.com/ckeditor/ckeditor5/issues/13321.
141
- if (env.isSafari && shiftPressed && inputType == 'insertParagraph') {
142
- inputType = 'insertLineBreak';
143
- }
144
- const domEvent = data.domEvent;
145
- const enterEventSpec = ENTER_EVENT_TYPES[inputType];
146
- if (!enterEventSpec) {
147
- return;
148
- }
149
- const event = new BubblingEventInfo(doc, 'enter', data.targetRanges[0]);
150
- doc.fire(event, new ViewDocumentDomEventData(view, domEvent, {
151
- isSoft: enterEventSpec.isSoft
152
- }));
153
- // Stop `beforeinput` event if `enter` event was stopped.
154
- // https://github.com/ckeditor/ckeditor5/issues/753
155
- if (event.stop.called) {
156
- evt.stop();
157
- }
158
- });
159
- }
160
- /**
161
- * @inheritDoc
162
- */ observe() {}
163
- /**
164
- * @inheritDoc
165
- */ stopObserving() {}
166
- }
117
+ * Enter observer introduces the {@link module:engine/view/document~ViewDocument#event:enter `Document#enter`} event.
118
+ */
119
+ var EnterObserver = class extends Observer {
120
+ /**
121
+ * @inheritDoc
122
+ */
123
+ constructor(view) {
124
+ super(view);
125
+ const doc = this.document;
126
+ let shiftPressed = false;
127
+ doc.on("keydown", (evt, data) => {
128
+ shiftPressed = data.shiftKey;
129
+ });
130
+ doc.on("beforeinput", (evt, data) => {
131
+ if (!this.isEnabled) return;
132
+ let inputType = data.inputType;
133
+ if (env.isSafari && shiftPressed && inputType == "insertParagraph") inputType = "insertLineBreak";
134
+ const domEvent = data.domEvent;
135
+ const enterEventSpec = ENTER_EVENT_TYPES[inputType];
136
+ if (!enterEventSpec) return;
137
+ const event = new BubblingEventInfo(doc, "enter", data.targetRanges[0]);
138
+ doc.fire(event, new ViewDocumentDomEventData(view, domEvent, { isSoft: enterEventSpec.isSoft }));
139
+ if (event.stop.called) evt.stop();
140
+ });
141
+ }
142
+ /**
143
+ * @inheritDoc
144
+ */
145
+ observe() {}
146
+ /**
147
+ * @inheritDoc
148
+ */
149
+ stopObserving() {}
150
+ };
167
151
 
168
152
  /**
169
- * This plugin handles the <kbd>Enter</kbd> keystroke (hard line break) in the editor.
170
- *
171
- * See also the {@link module:enter/shiftenter~ShiftEnter} plugin.
172
- *
173
- * For more information about this feature see the {@glink api/enter package page}.
174
- */ class Enter extends Plugin {
175
- /**
176
- * @inheritDoc
177
- */ static get pluginName() {
178
- return 'Enter';
179
- }
180
- /**
181
- * @inheritDoc
182
- */ static get isOfficialPlugin() {
183
- return true;
184
- }
185
- init() {
186
- const editor = this.editor;
187
- const view = editor.editing.view;
188
- const viewDocument = view.document;
189
- const t = this.editor.t;
190
- view.addObserver(EnterObserver);
191
- editor.commands.add('enter', new EnterCommand(editor));
192
- this.listenTo(viewDocument, 'enter', (evt, data)=>{
193
- // When not in composition, we handle the action, so prevent the default one.
194
- // When in composition, it's the browser who modify the DOM (renderer is disabled).
195
- if (!viewDocument.isComposing) {
196
- data.preventDefault();
197
- }
198
- // The soft enter key is handled by the ShiftEnter plugin.
199
- if (data.isSoft) {
200
- return;
201
- }
202
- editor.execute('enter');
203
- view.scrollToTheSelection();
204
- }, {
205
- priority: 'low'
206
- });
207
- // Add the information about the keystroke to the accessibility database.
208
- editor.accessibility.addKeystrokeInfos({
209
- keystrokes: [
210
- {
211
- label: t('Insert a hard break (a new paragraph)'),
212
- keystroke: 'Enter'
213
- }
214
- ]
215
- });
216
- }
217
- }
153
+ * @license Copyright (c) 2003-2026, CKSource Holding sp. z o.o. All rights reserved.
154
+ * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-licensing-options
155
+ */
156
+ /**
157
+ * @module enter/enter
158
+ */
159
+ /**
160
+ * This plugin handles the <kbd>Enter</kbd> keystroke (hard line break) in the editor.
161
+ *
162
+ * See also the {@link module:enter/shiftenter~ShiftEnter} plugin.
163
+ *
164
+ * For more information about this feature see the {@glink api/enter package page}.
165
+ */
166
+ var Enter = class extends Plugin {
167
+ /**
168
+ * @inheritDoc
169
+ */
170
+ static get pluginName() {
171
+ return "Enter";
172
+ }
173
+ /**
174
+ * @inheritDoc
175
+ */
176
+ static get isOfficialPlugin() {
177
+ return true;
178
+ }
179
+ init() {
180
+ const editor = this.editor;
181
+ const view = editor.editing.view;
182
+ const viewDocument = view.document;
183
+ const t = this.editor.t;
184
+ view.addObserver(EnterObserver);
185
+ editor.commands.add("enter", new EnterCommand(editor));
186
+ this.listenTo(viewDocument, "enter", (evt, data) => {
187
+ if (!viewDocument.isComposing) data.preventDefault();
188
+ if (data.isSoft) return;
189
+ editor.execute("enter");
190
+ view.scrollToTheSelection();
191
+ }, { priority: "low" });
192
+ editor.accessibility.addKeystrokeInfos({ keystrokes: [{
193
+ label: t("Insert a hard break (a new paragraph)"),
194
+ keystroke: "Enter"
195
+ }] });
196
+ }
197
+ };
218
198
 
219
199
  /**
220
- * ShiftEnter command. It is used by the {@link module:enter/shiftenter~ShiftEnter ShiftEnter feature} to handle
221
- * the <kbd>Shift</kbd>+<kbd>Enter</kbd> keystroke.
222
- */ class ShiftEnterCommand extends Command {
223
- /**
224
- * @inheritDoc
225
- */ execute() {
226
- const model = this.editor.model;
227
- const doc = model.document;
228
- model.change((writer)=>{
229
- softBreakAction(model, writer, doc.selection);
230
- this.fire('afterExecute', {
231
- writer
232
- });
233
- });
234
- }
235
- /**
236
- * @inheritDoc
237
- */ refresh() {
238
- const model = this.editor.model;
239
- const doc = model.document;
240
- this.isEnabled = isEnabled(model.schema, doc.selection);
241
- }
242
- }
200
+ * @license Copyright (c) 2003-2026, CKSource Holding sp. z o.o. All rights reserved.
201
+ * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-licensing-options
202
+ */
203
+ /**
204
+ * @module enter/shiftentercommand
205
+ */
206
+ /**
207
+ * ShiftEnter command. It is used by the {@link module:enter/shiftenter~ShiftEnter ShiftEnter feature} to handle
208
+ * the <kbd>Shift</kbd>+<kbd>Enter</kbd> keystroke.
209
+ */
210
+ var ShiftEnterCommand = class extends Command {
211
+ /**
212
+ * @inheritDoc
213
+ */
214
+ execute() {
215
+ const model = this.editor.model;
216
+ const doc = model.document;
217
+ model.change((writer) => {
218
+ softBreakAction(model, writer, doc.selection);
219
+ this.fire("afterExecute", { writer });
220
+ });
221
+ }
222
+ /**
223
+ * @inheritDoc
224
+ */
225
+ refresh() {
226
+ const model = this.editor.model;
227
+ const doc = model.document;
228
+ this.isEnabled = isEnabled(model.schema, doc.selection);
229
+ }
230
+ };
243
231
  /**
244
- * Checks whether the ShiftEnter command should be enabled in the specified selection.
245
- */ function isEnabled(schema, selection) {
246
- // At this moment it is okay to support single range selections only.
247
- // But in the future we may need to change that.
248
- if (selection.rangeCount > 1) {
249
- return false;
250
- }
251
- const anchorPos = selection.anchor;
252
- // Check whether the break element can be inserted in the current selection anchor.
253
- if (!anchorPos || !schema.checkChild(anchorPos, 'softBreak')) {
254
- return false;
255
- }
256
- const range = selection.getFirstRange();
257
- const startElement = range.start.parent;
258
- const endElement = range.end.parent;
259
- // Do not modify the content if selection is cross-limit elements.
260
- if ((isInsideLimitElement(startElement, schema) || isInsideLimitElement(endElement, schema)) && startElement !== endElement) {
261
- return false;
262
- }
263
- return true;
232
+ * Checks whether the ShiftEnter command should be enabled in the specified selection.
233
+ */
234
+ function isEnabled(schema, selection) {
235
+ if (selection.rangeCount > 1) return false;
236
+ const anchorPos = selection.anchor;
237
+ if (!anchorPos || !schema.checkChild(anchorPos, "softBreak")) return false;
238
+ const range = selection.getFirstRange();
239
+ const startElement = range.start.parent;
240
+ const endElement = range.end.parent;
241
+ if ((isInsideLimitElement(startElement, schema) || isInsideLimitElement(endElement, schema)) && startElement !== endElement) return false;
242
+ return true;
264
243
  }
265
244
  /**
266
- * Creates a break in the way that the <kbd>Shift</kbd>+<kbd>Enter</kbd> keystroke is expected to work.
267
- */ function softBreakAction(model, writer, selection) {
268
- const isSelectionEmpty = selection.isCollapsed;
269
- const range = selection.getFirstRange();
270
- const startElement = range.start.parent;
271
- const endElement = range.end.parent;
272
- const isContainedWithinOneElement = startElement == endElement;
273
- if (isSelectionEmpty) {
274
- insertBreak(model, writer, range.end, selection.getAttributes());
275
- } else {
276
- const leaveUnmerged = !(range.start.isAtStart && range.end.isAtEnd);
277
- model.deleteContent(selection, {
278
- leaveUnmerged
279
- });
280
- // Selection within one element:
281
- //
282
- // <h>x[xx]x</h> -> <h>x^x</h> -> <h>x<br>^x</h>
283
- if (isContainedWithinOneElement) {
284
- insertBreak(model, writer, selection.focus, selection.getAttributes());
285
- } else {
286
- // Move the selection to the 2nd element (last step of the example above).
287
- if (leaveUnmerged) {
288
- writer.setSelection(endElement, 0);
289
- }
290
- }
291
- }
245
+ * Creates a break in the way that the <kbd>Shift</kbd>+<kbd>Enter</kbd> keystroke is expected to work.
246
+ */
247
+ function softBreakAction(model, writer, selection) {
248
+ const isSelectionEmpty = selection.isCollapsed;
249
+ const range = selection.getFirstRange();
250
+ const startElement = range.start.parent;
251
+ const endElement = range.end.parent;
252
+ const isContainedWithinOneElement = startElement == endElement;
253
+ if (isSelectionEmpty) insertBreak(model, writer, range.end, selection.getAttributes());
254
+ else {
255
+ const leaveUnmerged = !(range.start.isAtStart && range.end.isAtEnd);
256
+ model.deleteContent(selection, { leaveUnmerged });
257
+ if (isContainedWithinOneElement) insertBreak(model, writer, selection.focus, selection.getAttributes());
258
+ else if (leaveUnmerged) writer.setSelection(endElement, 0);
259
+ }
292
260
  }
293
261
  /**
294
- * Inserts a softBreak with applicable attributes.
295
- */ function insertBreak(model, writer, position, selectionAttributes) {
296
- const attributes = Array.from(getCopyOnEnterAttributes(model.schema, selectionAttributes));
297
- const breakLineElement = writer.createElement('softBreak', attributes);
298
- model.insertContent(breakLineElement, position);
299
- writer.setSelection(breakLineElement, 'after');
262
+ * Inserts a softBreak with applicable attributes.
263
+ */
264
+ function insertBreak(model, writer, position, selectionAttributes) {
265
+ const attributes = Array.from(getCopyOnEnterAttributes(model.schema, selectionAttributes));
266
+ const breakLineElement = writer.createElement("softBreak", attributes);
267
+ model.insertContent(breakLineElement, position);
268
+ writer.setSelection(breakLineElement, "after");
300
269
  }
301
270
  /**
302
- * Checks whether the specified `element` is a child of the limit element.
303
- *
304
- * Checking whether the `<p>` element is inside a limit element:
305
- * - `<$root><p>Text.</p></$root> => false`
306
- * - `<$root><limitElement><p>Text</p></limitElement></$root> => true`
307
- */ function isInsideLimitElement(element, schema) {
308
- // `$root` is a limit element but in this case is an invalid element.
309
- if (element.is('rootElement')) {
310
- return false;
311
- }
312
- return schema.isLimit(element) || isInsideLimitElement(element.parent, schema);
271
+ * Checks whether the specified `element` is a child of the limit element.
272
+ *
273
+ * Checking whether the `<p>` element is inside a limit element:
274
+ * - `<$root><p>Text.</p></$root> => false`
275
+ * - `<$root><limitElement><p>Text</p></limitElement></$root> => true`
276
+ */
277
+ function isInsideLimitElement(element, schema) {
278
+ if (element.is("rootElement")) return false;
279
+ return schema.isLimit(element) || isInsideLimitElement(element.parent, schema);
313
280
  }
314
281
 
315
282
  /**
316
- * This plugin handles the <kbd>Shift</kbd>+<kbd>Enter</kbd> keystroke (soft line break) in the editor.
317
- *
318
- * See also the {@link module:enter/enter~Enter} plugin.
319
- *
320
- * For more information about this feature see the {@glink api/enter package page}.
321
- */ class ShiftEnter extends Plugin {
322
- /**
323
- * @inheritDoc
324
- */ static get pluginName() {
325
- return 'ShiftEnter';
326
- }
327
- /**
328
- * @inheritDoc
329
- */ static get isOfficialPlugin() {
330
- return true;
331
- }
332
- init() {
333
- const editor = this.editor;
334
- const schema = editor.model.schema;
335
- const conversion = editor.conversion;
336
- const view = editor.editing.view;
337
- const viewDocument = view.document;
338
- const t = this.editor.t;
339
- // Configure the schema.
340
- schema.register('softBreak', {
341
- allowWhere: '$text',
342
- allowAttributesOf: '$text',
343
- isInline: true
344
- });
345
- // Configure converters.
346
- conversion.for('upcast').elementToElement({
347
- model: 'softBreak',
348
- view: 'br'
349
- });
350
- conversion.for('downcast').elementToElement({
351
- model: 'softBreak',
352
- view: (modelElement, { writer })=>writer.createEmptyElement('br')
353
- });
354
- view.addObserver(EnterObserver);
355
- editor.commands.add('shiftEnter', new ShiftEnterCommand(editor));
356
- editor.model.document.registerPostFixer((writer)=>removeStaleSoftBreakAttributes(writer));
357
- this.listenTo(viewDocument, 'enter', (evt, data)=>{
358
- // When not in composition, we handle the action, so prevent the default one.
359
- // When in composition, it's the browser who modify the DOM (renderer is disabled).
360
- if (!viewDocument.isComposing) {
361
- data.preventDefault();
362
- }
363
- // The hard enter key is handled by the Enter plugin.
364
- if (!data.isSoft) {
365
- return;
366
- }
367
- editor.execute('shiftEnter');
368
- view.scrollToTheSelection();
369
- }, {
370
- priority: 'low'
371
- });
372
- // Add the information about the keystroke to the accessibility database.
373
- editor.accessibility.addKeystrokeInfos({
374
- keystrokes: [
375
- {
376
- label: t('Insert a soft break (a <code>&lt;br&gt;</code> element)'),
377
- keystroke: 'Shift+Enter'
378
- }
379
- ]
380
- });
381
- }
382
- }
283
+ * @license Copyright (c) 2003-2026, CKSource Holding sp. z o.o. All rights reserved.
284
+ * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-licensing-options
285
+ */
286
+ /**
287
+ * @module enter/shiftenter
288
+ */
289
+ /**
290
+ * This plugin handles the <kbd>Shift</kbd>+<kbd>Enter</kbd> keystroke (soft line break) in the editor.
291
+ *
292
+ * See also the {@link module:enter/enter~Enter} plugin.
293
+ *
294
+ * For more information about this feature see the {@glink api/enter package page}.
295
+ */
296
+ var ShiftEnter = class extends Plugin {
297
+ /**
298
+ * @inheritDoc
299
+ */
300
+ static get pluginName() {
301
+ return "ShiftEnter";
302
+ }
303
+ /**
304
+ * @inheritDoc
305
+ */
306
+ static get isOfficialPlugin() {
307
+ return true;
308
+ }
309
+ init() {
310
+ const editor = this.editor;
311
+ const schema = editor.model.schema;
312
+ const conversion = editor.conversion;
313
+ const view = editor.editing.view;
314
+ const viewDocument = view.document;
315
+ const t = this.editor.t;
316
+ schema.register("softBreak", {
317
+ allowWhere: "$text",
318
+ allowAttributesOf: "$text",
319
+ isInline: true
320
+ });
321
+ conversion.for("upcast").elementToElement({
322
+ model: "softBreak",
323
+ view: "br"
324
+ });
325
+ conversion.for("downcast").elementToElement({
326
+ model: "softBreak",
327
+ view: (modelElement, { writer }) => writer.createEmptyElement("br")
328
+ });
329
+ view.addObserver(EnterObserver);
330
+ editor.commands.add("shiftEnter", new ShiftEnterCommand(editor));
331
+ editor.model.document.registerPostFixer((writer) => removeStaleSoftBreakAttributes(writer));
332
+ this.listenTo(viewDocument, "enter", (evt, data) => {
333
+ if (!viewDocument.isComposing) data.preventDefault();
334
+ if (!data.isSoft) return;
335
+ editor.execute("shiftEnter");
336
+ view.scrollToTheSelection();
337
+ }, { priority: "low" });
338
+ editor.accessibility.addKeystrokeInfos({ keystrokes: [{
339
+ label: t("Insert a soft break (a <code>&lt;br&gt;</code> element)"),
340
+ keystroke: "Shift+Enter"
341
+ }] });
342
+ }
343
+ };
383
344
  /**
384
- * The post-fixer that removes attributes from stale soft-break elements.
385
- */ function removeStaleSoftBreakAttributes(writer) {
386
- const parentsToCheck = new Set();
387
- for (const change of writer.model.document.differ.getChanges()){
388
- if (change.type == 'insert' || change.type == 'remove') {
389
- if (change.position.parent.is('element')) {
390
- parentsToCheck.add(change.position.parent);
391
- }
392
- } else if (change.type == 'attribute') {
393
- if (change.range.start.parent.is('element')) {
394
- parentsToCheck.add(change.range.start.parent);
395
- }
396
- }
397
- }
398
- let wasChanged = false;
399
- for (const parent of parentsToCheck){
400
- // Just a sibling nodes check. We do not need to check attributes of nested elements.
401
- for (const child of parent.getChildren()){
402
- // Find a softBreak element.
403
- if (!child.is('element', 'softBreak')) {
404
- continue;
405
- }
406
- const nextSibling = child.nextSibling;
407
- // Do not remove attributes when softBreak is the last element or there is some element after it.
408
- if (!nextSibling || nextSibling.is('element')) {
409
- continue;
410
- }
411
- // Remove the attribute if the next sibling does not have the same attribute.
412
- const attributesToRemove = Array.from(child.getAttributes()).filter(([key, value])=>!hasSameAttribute(nextSibling, key, value));
413
- for (const [key] of attributesToRemove){
414
- writer.removeAttribute(key, child);
415
- wasChanged = true;
416
- }
417
- }
418
- }
419
- return wasChanged;
345
+ * The post-fixer that removes attributes from stale soft-break elements.
346
+ */
347
+ function removeStaleSoftBreakAttributes(writer) {
348
+ const parentsToCheck = /* @__PURE__ */ new Set();
349
+ for (const change of writer.model.document.differ.getChanges()) if (change.type == "insert" || change.type == "remove") {
350
+ /* v8 ignore else -- @preserve */
351
+ if (change.position.parent.is("element")) parentsToCheck.add(change.position.parent);
352
+ } else if (change.type == "attribute") {
353
+ /* v8 ignore else -- @preserve */
354
+ if (change.range.start.parent.is("element")) parentsToCheck.add(change.range.start.parent);
355
+ }
356
+ let wasChanged = false;
357
+ for (const parent of parentsToCheck) for (const child of parent.getChildren()) {
358
+ if (!child.is("element", "softBreak")) continue;
359
+ const nextSibling = child.nextSibling;
360
+ if (!nextSibling || nextSibling.is("element")) continue;
361
+ const attributesToRemove = Array.from(child.getAttributes()).filter(([key, value]) => !hasSameAttribute(nextSibling, key, value));
362
+ for (const [key] of attributesToRemove) {
363
+ writer.removeAttribute(key, child);
364
+ wasChanged = true;
365
+ }
366
+ }
367
+ return wasChanged;
420
368
  }
421
369
  /**
422
- * Returns `true` if the given node has the same attribute as the one provided in the parameters.
423
- */ function hasSameAttribute(node, key, value) {
424
- return node?.getAttribute(key) === value;
370
+ * Returns `true` if the given node has the same attribute as the one provided in the parameters.
371
+ */
372
+ function hasSameAttribute(node, key, value) {
373
+ return node?.getAttribute(key) === value;
425
374
  }
426
375
 
376
+ /**
377
+ * @license Copyright (c) 2003-2026, CKSource Holding sp. z o.o. All rights reserved.
378
+ * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-licensing-options
379
+ */
380
+
427
381
  export { Enter, EnterCommand, EnterObserver, ShiftEnter, ShiftEnterCommand, getCopyOnEnterAttributes as _getCopyOnEnterAttributes };
428
- //# sourceMappingURL=index.js.map
382
+ //# sourceMappingURL=index.js.map